1

我是 Haskell 的新手。

我编写了以下代码,它将解析发送到脚本的参数;

module Billing.Options
  (
      GlobalOpts(..)
    , globalOptsParser
    , parseDb
  ) where

import Options.Applicative
import Options.Applicative.Simple
import Options.Applicative.Types
import System.FilePath.Posix
import Text.Regex.PCRE

-- ------------------------------------------------------------

data GlobalOpts = GlobalOpts
  {
    optDb          :: String,
    optSql         :: String
  } deriving Show

-- ------------------------------------------------------------

globalOptsParser :: Parser GlobalOpts
globalOptsParser = GlobalOpts
  <$> option (parseDb =<< readerAsk)
    (   long "db"
    <>  short 'd'
    <>  metavar "<DB name>"
    <>  help "dmt | report"
    )
  <*> option parseSql
    (   long "sql"
    <>  metavar "<SQL SELECT statement>"
    <>  help "sql select statement to use in order to generate JSON config file"
    )
-- ------------------------------------------------------------

matches :: String -> String -> Bool
matches = (=~)

-- ------------------------------------------------------------

parseDb :: String -> ReadM String
parseDb val = do
    if not (elem val ["dmt", "report"])
        then readerError $ "Unknown DB, '" ++ val ++ "'"
        else return val

-- ------------------------------------------------------------

parseSql :: ReadM String
parseSql = do
    val <- readerAsk
    if not (val `matches` "(?i)select .+ from .+")
        then readerError $ "Please provide a valid SQL SELECT statement"
        else return val

-- [EOF]

我想用 hspec 测试上面的“parseDb”函数。我想确保在指定未知数据库时会抛出“readerError”。因此,我想测试函数调用 parseDb "unknown" 生成一个 "readerError" 调用,根据我的说法,它应该引发异常。

我已经尝试了 hspec shouldThrow 函数,但它不起作用。似乎没有抛出异常。readerError 的返回类型是“ReadM a”。在花了几天时间阅读 monads 和 reader monads 之后,我仍然卡住(和困惑)并且不知道如何测试它,甚至不知道是否可以测试它。当我用谷歌搜索时,找不到任何相关的例子。

4

1 回答 1

2

以下是一些相关的类型标志:

parseDb :: String -> ReadM String

-- from Options.Applicative.Internal

runReadM :: MonadP m => ReadM a -> String -> m a
runP :: P a -> ParserPrefs -> (Either ParseError a, Context)

runReadM和的文档runP:(链接)

ParserPrefs只是一个简单的数据结构。

这类型检查:

 import Options.Applicative.Types
 import Options.Applicative.Internal

 parseDb :: String -> ReadM String
 parseDb val = do
     if not (elem val ["dmt", "report"])
         then readerError $ "Unknown DB, '" ++ val ++ "'"
         else return val

 foo :: (Either ParseError String, Context)     -- might be [Context] now
 foo =   runP (runReadM (parseDb "foo") "asd") opts
   where opts = ParserPrefs "suffix" False False False 80

评估fst foo回报:

*Main> fst foo
Left (ErrorMsg "Unknown DB, 'foo'")

更新

以下是如何测试Parser类似的globalOptsParser

import Options.Applicative.Common (runParser)
import Options.Applicative.Internal (runP)

bar = let mp = runParser AllowOpts globalOptsParser ["asd"]
          opts = ParserPrefs "suffix" False False False 80
      in fst $ runP mp opts

以下["asd"]是要测试的命令行参数。

检查是否ParserPrefs是您想要的 - 它们会影响选项处理。

于 2016-06-14T16:31:22.550 回答