content: {- | Generators for test data types.
  -}
  
  module Test.Gen
      ( Property
      , genValidation
      , genValidationList
      , genFunction
      , genFunction2
      , genInt
      , genSmallInt
      , genSmallText
      , genSmallList
      , genEither
      ) where
  
  import Data.Text (Text)
  import Hedgehog (Gen, MonadGen, PropertyT)
  import Validation (Validation (..))
  
  import qualified Hedgehog.Gen as Gen
  import qualified Hedgehog.Range as Range
  
  
  -- | Helper alias for tests.
  type Property = PropertyT IO ()
  
  -- | Generate a simple unary function from the list.
  genFunction :: Gen (Int -> Int)
  genFunction = genInt >>= \n -> Gen.element
      [ id
      , (+ n)
      , (* n)
      , const n
      , (n -)
      , subtract n
      ]
  
  -- | Generate a simple binary function from the list.
  genFunction2 :: Gen (Int -> Int -> Int)
  genFunction2 = Gen.element
      [ const
      , (+)
      , (*)
      , (-)
      , subtract
      ]
  
  -- | Generate an 'Int'.
  genInt :: Gen Int
  genInt = Gen.enumBounded
  
  -- | Generate a positive 'Int' within the range of @1-6@.
  genSmallInt :: Gen Int
  genSmallInt = Gen.int (Range.linear 1 6)
  
  -- | Generate a 'Text' of length @0-10@.
  genSmallText :: Gen Text
  genSmallText = Gen.text (Range.linear 0 10) Gen.unicode
  
  -- | Generate a small list of the given generated elements.
  genSmallList :: Gen a -> Gen [a]
  genSmallList = Gen.list (Range.linear 0 6)
  
  -- | Generate a 'Validation'.
  genValidation :: Gen a -> Gen (Validation [Text] a)
  genValidation gen = Gen.choice
      [ Success <$> gen
      , Failure <$> genSmallList genSmallText
      ]
  
  -- | Generate 'Either' with more frequent 'Right's.
  genEither :: MonadGen m => m e -> m a -> m (Either e a)
  genEither genE genA = Gen.sized $ \n -> Gen.frequency
      [ (2, Left <$> genE)
      , (1 + fromIntegral n, Right <$> genA)
      ]
  
  -- | Generate a list of 'Validation's.
  genValidationList :: Gen a -> Gen [Validation [Text] a]
  genValidationList = Gen.list (Range.linear 0 200) . genValidation
  