multiarg-0.30.0.0: tests/Multiarg/Maddash/Tests.hs
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
module Multiarg.Maddash.Tests where
import Control.Applicative
import Multiarg.Types
import Multiarg.Maddash
import Test.QuickCheck
( Gen, Arbitrary(..), CoArbitrary(..),
suchThat, listOf, oneof, forAll, Property,
(==>), choose, vectorOf )
import Prelude.Generators (function1, function2, function3)
import qualified Prelude.Generators as G
import Makeopt
genInt :: Gen Int
genInt = arbitrary
genStringF1 :: Gen (String -> Int)
genStringF1 = function1 coarbitrary arbitrary
genStringF2 :: Gen (String -> String -> Int)
genStringF2 = function2 coarbitrary coarbitrary arbitrary
genStringF3 :: Gen (String -> String -> String -> Int)
genStringF3 = function3 coarbitrary coarbitrary coarbitrary arbitrary
genShortName :: Gen ShortName
genShortName = do
c <- arbitrary
case shortName c of
Nothing -> genShortName
Just n -> return n
genLongName :: Gen LongName
genLongName = do
c1 <- arbitrary `suchThat` (\c -> c /= '-' && c /= '=')
cs <- listOf (arbitrary `suchThat` (/= '='))
case longName (c1 : cs) of
Nothing -> error $ "could not generate long name: " ++ (c1:cs)
Just n -> return n
genOptName :: Gen OptName
genOptName = fmap OptName $ G.either genShortName genLongName
genArgSpec :: Gen (ArgSpec Int)
genArgSpec = oneof
[ fmap ZeroArg arbitrary
, fmap OneArg (function1 coarbitrary arbitrary)
, fmap TwoArg (function2 coarbitrary coarbitrary arbitrary)
, fmap ThreeArg (function3 coarbitrary coarbitrary coarbitrary
arbitrary)
]
genWord :: Gen Word
genWord = fmap Word arbitrary
singleDash :: Word
singleDash = Word "-"
stopper :: Word
stopper = Word "--"
genNonOptWord :: Gen Word
genNonOptWord = oneof
[ return singleDash
, return stopper
, do
c1 <- arbitrary `suchThat` (/= '-')
cs <- listOf arbitrary
return $ Word (c1 : cs)
]
coaWord :: Word -> Gen b -> Gen b
coaWord (Word s) = coarbitrary s
genOptArg :: Gen OptArg
genOptArg = fmap OptArg arbitrary
genOptionError :: Gen OptionError
genOptionError = oneof
[ fmap BadOption genOptName
, LongArgumentForZeroArgumentOption <$> genLongName <*> genOptArg
]
genOutput :: Gen (Output Int)
genOutput = oneof
[ fmap Good arbitrary
, fmap OptionError genOptionError
]
genPallet :: Gen (Pallet Int)
genPallet = oneof
[ return NotAnOption
, fmap Full $ listOf genOutput
]
genPending :: Gen (State Int)
genPending = Pending <$> genOptName <*> genF
where
genF = function1 coaWord
((,) <$> listOf genOutput <*> genState)
genState :: Gen (State Int)
genState = oneof
[ return Ready
, genPending
]
genShortArgSpecs :: Gen [(ShortName, ArgSpec Int)]
genShortArgSpecs = listOf ((,) <$> genShortName <*> genArgSpec)
genLongArgSpecs :: Gen [(LongName, ArgSpec Int)]
genLongArgSpecs = listOf ((,) <$> genLongName <*> genArgSpec)
-- * Properties
-- | Non-option token always returns NotAnOption if State is Ready
prop_nonOptWordNotAnOptionIfStateIsReady :: Property
prop_nonOptWordNotAnOptionIfStateIsReady =
forAll genShortArgSpecs $ \shorts ->
forAll genLongArgSpecs $ \longs ->
forAll genNonOptWord $ \token ->
let (pallet, _) = processWord shorts longs Ready token
in pallet == NotAnOption
-- | Stopper always returns NotAnOption if State is Ready
prop_stopperNotAnOptionIfStateIsReady :: Property
prop_stopperNotAnOptionIfStateIsReady =
forAll genShortArgSpecs $ \shorts ->
forAll genLongArgSpecs $ \longs ->
let (pallet, _) = processWord shorts longs Ready stopper
in pallet == NotAnOption
-- | Single dash always returns NotAnOption if State is Ready
prop_singleDashNotAnOptionIfStateIsReady :: Property
prop_singleDashNotAnOptionIfStateIsReady =
forAll genShortArgSpecs $ \shorts ->
forAll genLongArgSpecs $ \longs ->
let (pallet, _) = processWord shorts longs Ready singleDash
in pallet == NotAnOption
-- | processWord never returns NotAnOption when input is Pending
prop_processWordNeverReturnsNotAnOptionOnPending =
forAll genShortArgSpecs $ \shorts ->
forAll genLongArgSpecs $ \longs ->
forAll genPending $ \state ->
forAll genWord $ \token ->
let (pallet, _) = processWord shorts longs state token
in pallet /= NotAnOption
-- | NotAnOption is always returned with Ready
prop_processWordNotAnOptionWithReady =
forAll genShortArgSpecs $ \shorts ->
forAll genLongArgSpecs $ \longs ->
forAll genState $ \state ->
forAll genWord $ \token ->
let (pallet, state') = processWord shorts longs state token
in pallet == NotAnOption ==> isReady state'
pickOne :: [a] -> Gen a
pickOne ls
| null ls = error "pickOne: null list"
| otherwise = fmap (\ix -> ls !! ix) (choose (0, length ls - 1))
data OptionWithToks = OptionWithToks
{ owtOptName :: OptName
, owtArgSpec :: ArgSpec Int
, owtArgs :: [String]
, owtWords :: [Word]
, owtResultOuts :: [[Output Int]]
, owtResultToks :: Maybe [Word]
, owtExpected :: Int
} deriving Show
instance Arbitrary OptionWithToks where
arbitrary = do
OptName on <- genOptName
as <- genArgSpec
(args, expected) <- case as of
ZeroArg a -> return ([], a)
OneArg f -> do
s <- arbitrary
return ([s], f s)
TwoArg f -> do
s1:s2:[] <- vectorOf 2 arbitrary
return ([s1,s2], f s1 s2)
ThreeArg f -> do
s1:s2:s3:[] <- vectorOf 3 arbitrary
return ([s1,s2,s3], f s1 s2 s3)
let strings = case on of
Left shrt -> processShortOptions [] (shrt, args)
Right lng -> processLongOption lng args
toks <- fmap (map Word) $ pickOne strings
let (shrts, lngs) = case on of
Left shrt -> ([(shrt, as)], [])
Right lng -> ([], [(lng, as)])
(procRslts, procEi) = processWords shrts lngs toks
mayToks = either (const Nothing) Just procEi
return $ OptionWithToks (OptName on) as args toks procRslts
mayToks expected
prop_optionWithToksResultToksEmpty = (== Just []) . owtResultToks
prop_optionWithToksResultIsExpected owt
= concat (owtResultOuts owt) == [Good . owtExpected $ owt]