filepather-0.8.0.0: test/Gens.hs
{-# OPTIONS_GHC -Wall #-}
-- | Generators shared by the property tests.
module Gens (
genInt,
genString,
genPath,
genIntList,
genFnInt,
pathKey,
genFilePatherList,
genFilePatherListFn,
genFilePatherMaybe,
toFilePather,
toFilePatherFn,
-- * Data types
genName,
genStep,
genTrail,
genRepetition,
genReproducesInput,
genRepeatsStep,
genCycle,
) where
import Control.Lens (review)
import Data.Char (ord)
import Hedgehog (Gen)
import Hedgehog.Function (Fn, apply, fn)
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import System.FilePather
genInt :: Gen Int
genInt =
Gen.int (Range.linear (-100) 100)
genString :: Gen String
genString =
Gen.string (Range.linear 0 30) Gen.unicode
{- | An 'Int' that is determined by a file path, so that a generated function of
'Int' is a function of file paths. hedgehog-fn cannot generate functions of
'String', as it has no instance for 'Char'.
-}
pathKey :: FilePath -> Int
pathKey =
foldr (\c k -> (k * 31 + ord c) `mod` 1000003) 7
-- | A file path, such as @src/a/report.fodt@.
genPath :: Gen FilePath
genPath =
let part = Gen.string (Range.linear 1 6) Gen.alphaNum
in (\ds f e -> concatMap (<> "/") ds <> f <> "." <> e)
<$> Gen.list (Range.linear 0 3) part
<*> part
<*> Gen.element ["fodt", "md", "pdf", "png", "txt"]
genIntList :: Gen [Int]
genIntList =
Gen.list (Range.linear 0 4) genInt
genFnInt :: Gen (Fn Int Int)
genFnInt =
fn genInt
{- | A function from file paths to lists of 'Int', to make a 'FilePather'
with 'toFilePather'.
-}
genFilePatherList :: Gen (Fn Int [Int])
genFilePatherList =
fn genIntList
{- | A function from file paths to lists of functions, to make a
'FilePather' with 'toFilePatherFn'.
-}
genFilePatherListFn :: Gen (Fn Int [Fn Int Int])
genFilePatherListFn =
fn (Gen.list (Range.linear 0 3) genFnInt)
-- | A function from file paths to 'Maybe' 'Int'.
genFilePatherMaybe :: Gen (Fn Int (Maybe Int))
genFilePatherMaybe =
fn (Gen.maybe genInt)
toFilePather :: Fn Int (f a) -> FilePather f a
toFilePather f =
FilePather (apply f . pathKey)
toFilePatherFn :: (Functor f) => Fn Int (f (Fn Int Int)) -> FilePather f (Int -> Int)
toFilePatherFn f =
FilePather (fmap apply . apply f . pathKey)
-- | The name of a step.
genName :: Gen String
genName =
Gen.element ["prepare", "pdf page 1", "libreoffice pdf", "image png", "book"]
{- | A 'Step': a product, so its constructor applied to a generator of each
field, in the shape of its manifest.
-}
genStep :: Gen Step
genStep =
Step <$> genName <*> genPath
genTrail :: Gen Trail
genTrail =
Trail <$> Gen.list (Range.linear 0 3) genStep
{- | A 'Repetition': a sum, so one alternative for each constructor, through
its name.
-}
genRepetition :: Gen Repetition
genRepetition =
Gen.choice [pure (review once ()), pure (review repeatable ())]
genReproducesInput :: Gen ReproducesInput
genReproducesInput =
ReproducesInput <$> genPath <*> genStep <*> genTrail
genRepeatsStep :: Gen RepeatsStep
genRepeatsStep =
RepeatsStep <$> genStep <*> genTrail
genCycle :: Gen Cycle
genCycle =
Gen.choice [review reproducesInput <$> genReproducesInput, review repeatsStep <$> genRepeatsStep]