module Test.GenCheck.Generator.Generator ( Generator , generate , genTake , enumGenerator , StandardGens(..) , Testable(..) , stdEnumGens , enumGens ) where import System.Random (StdGen) import Data.List (genericTake) import Test.GenCheck.Base.Base (Rank, Count) import Test.GenCheck.Generator.Enumeration as Enum(Enumeration, Enumerated(..), counter, getUnsafe,Label) import Test.GenCheck.Generator.EnumStrat\end{code} The Generator type is defined to be a function from rank to a list of values. Generators are not obliged to provide all possible values of a type, nor are they obliged to provide only one occurence of the type in the list. Although those are useful properties for a generator to have, in some cases the flexibility is desirable, such as random value generators. Note that even though the rank partitions the type into finite discrete subsets, there is no restriction against duplicating values in the list, so the list may infinite. Any function that satisfies the Generator type can be used with GenCheck compatible systems, as long as they are total over non-negative ranks. The generate function generates values of multiple ranks in a flat list. \begin{code}

type Generator a = Rank -> [a] generate :: Generator a -> [(Rank, Count)] -> [a] generate g = concatMap $ uncurry (genTake g) genTake :: Generator a -> Rank -> Count -> [a] genTake g r n = genericTake n (g r)\end{code} Enumerated generators use an enumeration (Generator.Enumeration) and an enumerative strategy (a type independent list of indices, Generator.EnumStrat) to order the generated values by mapping the selection order over the enumeration. The strategy is assumed to provide indices in the domain of the enumeration, given the size of the enumeration at that rank. \begin{code}

enumGenerator :: EnumStrat -> Enumeration c a -> Generator (c a) enumGenerator strat e rnk = fmap (Enum.getUnsafe e rnk) (strat (Enum.counter e rnk))\end{code} Four enumerative strategies form the standard approach to generating test values, and these generators are grouped into the StandardGens structure for use in the test programs and test suite building functions. The standard generators are: \begin{definition} \item[allGen] an exhaustive generator \item[xtrmGen] extreme / boundary condition generator \item[uniGen] picks a fixed number of uniformly separated elements \item[randGen] random generator (infinitely many elements) \end{definition} The generators can be restricted to an interval of the total set of values by providing a range of indices (low index, high index) into the enumeration. A set of standard generators can be defined from the enumeration, (the random generator requires an integer seed and uses the System.Random module) or overridden with more efficient implementations. The StandardGens structure is just a convenient way to pass them around. stdGenList fills in the uniform spacing provides the standard ordering in a list format. \begin{code}

class Show a => Testable a where stdTestGens :: StandardGens a data StandardGens a = StdGens { genAll :: Generator a , genXtrm :: Generator a , genUni :: Int -> Generator a , genRand :: StdGen -> Generator a } | UnrankedGen (Generator a) enumGens :: Enumeration c Label -> StandardGens (c Label) enumGens e = StdGens allGen xtrmGen uniGen randGen where allGen = enumGenerator exhaustG e xtrmGen = enumGenerator extreme e uniGen = \m' -> enumGenerator (uniform m') e randGen = \s' -> enumGenerator (randG s') e stdEnumGens :: Enumerated c => StandardGens (c Label) stdEnumGens = enumGens enumeration\end{code}