packages feed

filepather-0.7.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,
) where

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 (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/cv.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)