multiarg-0.30.0.2: tests/Grover/Tests.hs
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
module Grover.Tests where
import Ernie
import Multiarg.Examples.Grover
import Control.Applicative
import Test.QuickCheck hiding (Result)
import Multiarg.Mode
genGlobal :: Gen Global
genGlobal = oneof
[ return Help
, Verbose <$> arbitrary
, return Version
]
data GroverOpts
= GOInts [GroverOpt Int]
| GOStrings [GroverOpt String]
| GOMaybes [GroverOpt (Maybe Int)]
deriving (Eq, Ord, Show)
instance Arbitrary GroverOpts where
arbitrary = oneof
[ fmap GOInts . listOf . genGroverOpt $ arbitrary
, fmap GOStrings . listOf . genGroverOpt $ arbitrary
, fmap GOMaybes . listOf . genGroverOpt $ arbitrary
]
-- | Generates a mode option. Does not generate positional arguments.
genGroverOpt
:: Gen a
-- ^ Generates arguments
-> Gen (GroverOpt a)
genGroverOpt g = oneof
[ return Zero
, Single <$> g
, Double <$> g <*> g
, Triple <$> g <*> g <*> g
]
globalToNestedList :: Global -> [[String]]
globalToNestedList glbl = case glbl of
Help -> long "help" [] ++ short 'h' []
Verbose i -> long "verbose" [show i] ++ short 'v' [show i]
Version -> long "version" []
groverOptToNestedList :: Show a => GroverOpt a -> [[String]]
groverOptToNestedList gvr = case gvr of
Zero -> long "zero" [] ++ short 'z' []
Single a -> long "single" ls ++ short 's' ls
where
ls = [show a]
Double a b -> long "double" ls ++ short 'd' ls
where
ls = [show a, show b]
Triple a b c -> long "triple" ls ++ short 't' ls
where
ls = [show a, show b, show c]
PosArg s -> [[s]]
-- | A valid Grover AST, combined with a set of strings that, when
-- parsed, should yield that AST.
data ValidGrover
= ValidGrover [Global] (Either [String] Result) [String]
-- ^ @ValidGrover a b c@, where
--
-- @a@ is the list of global options
--
-- @b@ is either a list of strings (indicates that the user entered
-- no mode), or the mode, and its associated options
--
-- @c@ is a list of strings that, when parsed, should return @a@ and @b@.
deriving (Eq, Ord, Show)
instance Arbitrary ValidGrover where
arbitrary = do
globals <- listOf genGlobal
glblStrings <- fmap concat . mapM pickItem
. map globalToNestedList $ globals
(ei, endStrings) <- oneof
[ resultAndStrings Ints "int"
, resultAndStrings Strings "string"
, resultAndStrings Maybes "maybe"
]
return $ ValidGrover globals ei (glblStrings ++ endStrings)
-- | Generates a list of String, where the first String will not be
-- interpreted as a mode.
genNonModePosArg :: Gen [String]
genNonModePosArg = frequency ([ (1, return []), (3, nonEmpty)])
where
nonEmpty = (:) <$> firstWord <*> listOf arbitrary
where
firstWord = arbitrary `suchThat`
(\s -> not (s `elem` ["int", "string", "maybe"])
&& not (startsWithHyphen s))
startsWithHyphen s = case s of
'-':_ -> True
_ -> False
resultAndStrings
:: (Arbitrary a, Show a)
=> ([Either String (GroverOpt a)] -> Result)
-- ^ Function that creates a Result
-> String
-- ^ Name of mode
-> Gen (Either [String] Result, [String])
resultAndStrings fRes modeName = frequency [(1, nonMode), (4, withMode)]
where
nonMode = fmap (\ls -> (Left ls, ls)) genNonModePosArg
withMode = do
ispLine <- interspersedLine (genGroverOpt arbitrary) PosArg
strings <- interspersedLineToStrings ispLine groverOptToNestedList
return ( Right . fRes . map Right $ fst ispLine ++ snd ispLine
, modeName : strings )
prop_ValidGrover (ValidGrover globals ei strings) = result === expected
where
result = parseModeLine globalOptSpecs modes strings
expected = Right (ModeResult (map Right globals) ei)
prop_alwaysTrue = True