multiarg-0.30.0.10: tests/Ernie.hs
-- | Functions to assist with testing.
module Ernie where
import Control.Applicative
import Makeopt
import Multiarg.Types
import Test.QuickCheck
-- | Generates words that start with a single hyphen.
startsWithOneHyphen :: Gen String
startsWithOneHyphen = fmap ('-':) (listOf1 arbitrary)
-- | Generates words that start with two hyphens.
startsWithTwoHyphens :: Gen String
startsWithTwoHyphens = fmap ("--" ++) arbitrary
-- | Generates words that do not start with a hyphen.
startsWithNonHyphen :: Gen String
startsWithNonHyphen = (:) <$> (arbitrary `suchThat` (/= '-'))
<*> arbitrary
-- | Generates words for option arguments. Ensures that some start
-- with hyphens (these are valid option arguments.)
optArg :: Gen String
optArg = oneof [ startsWithOneHyphen, startsWithNonHyphen ]
short :: Char -> [String] -> [[String]]
short c os = case shortName c of
Nothing -> error "Ernie.hs: error: could not create short name"
Just o -> processShortOptions [] (o, os)
long :: String -> [String] -> [[String]]
long s os = case longName s of
Nothing -> error "Ernie.hs: error: could not create long name"
Just o -> processLongOption o os
pickItem :: [a] -> Gen a
pickItem a
| null a = fail "pickItem: empty list"
| otherwise = fmap (a !!) (choose (0, length a - 1))
-- | Generates non-option positional arguments that appear to the
-- right of the stopper. This can be any word at all.
posArgRight :: Gen String
posArgRight = oneof
[ arbitrary, startsWithOneHyphen, startsWithTwoHyphens ]
-- | Generates non-option positional arguments that appear to the left
-- of the stopper. Cannot be preceded by a dash; can, however, be a
-- single hyphen only.
posArgLeft :: Gen String
posArgLeft =
frequency [ (5, startsWithNonHyphen)
, (1, return "-") ]
-- | Generates options, non-option positional arguments that are a
-- single hyphen only, and non-option positional arguments that do not
-- start with a hyphen; these may appear to the left of a stopper.
preStopper
:: Gen a
-- ^ Generates options
-> (String -> a)
-- ^ Creates non-option positional arguments
-> Gen [a]
preStopper genOpt fPos =
listOf (oneof [ genOpt, fmap fPos posArgLeft ])
-- | Generates any word at all, with a healthy mix of empty lists
-- (stoppers are unusual.)
postStopper
:: (String -> a)
-- ^ Creates non-option positional arguments
-> Gen [a]
postStopper fPos =
oneof [ return [], listOf (fmap fPos posArgRight) ]
-- | Generates a valid list of interspersed command-line options; that
-- is, a list that the user could have entered in the command line.
-- This list may be transformed into strings, which can then be parsed
-- and compared against this original value.
--
-- Returns a pair @(a, b)@, where @a@ is everything to the left of the
-- stopper, and @b@ (if non-empty) is everything to the right of the
-- stopper.
interspersedLine
:: Gen a
-- ^ Generates options
-> (String -> a)
-- ^ Creates non-option positional arguments
-> Gen ([a], [a])
interspersedLine genOpt fPos =
(,)
<$> preStopper genOpt fPos
<*> postStopper fPos
-- | Takes an interspersed line and creates a set of strings that
-- would, when parsed, yield the interspersed line.
interspersedLineToStrings
:: ([a], [a])
-- ^ @(a, b)@, where
--
-- @a@ is everything to the left of the stopper, and
--
-- @b@ is everything to the right of the stopper
-> (a -> [[String]])
-- ^ Converts a single item to a nested list of String. Each list
-- of String is a possible way to render this item. This list must
-- not be empty.
-> Gen [String]
interspersedLineToStrings (left, right) fConv = do
l <- fmap concat . mapM pickItem . map fConv $ left
r <- fmap concat . mapM pickItem . map fConv $ right
alwaysStopper <- arbitrary
let stop | not (null r) || alwaysStopper = ["--"]
| otherwise = []
return $ l ++ stop ++ r