packages feed

prop-unit-0.2.0: test/Main.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE UndecidableInstances #-}

module Main (main) where

import Control.Monad (replicateM)
import Data.Proxy (Proxy (..))
import qualified Data.Set as Set
import GHC.Exts (IsList, IsString)
import GHC.Generics (Generic)
import Hedgehog (Gen)
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import PropUnit
  ( GenDefault (..)
  , Std
  , TestLimit
  , TestTree
  , assert
  , forAll
  , genDefaultEnum
  , genDefaultGeneric
  , genDefaultList
  , genDefaultString
  , genDefaultTag
  , testGroup
  , testMain
  , testProp
  , testUnit
  , (===)
  )

testAsUnit :: TestTree
testAsUnit = testUnit "as unit" $ do
  let actual = (1 + 1) :: Int
      expected = 2 :: Int
  actual === expected

testAsProp :: TestLimit -> TestTree
testAsProp lim = testProp "as gen" lim $ do
  x <- forAll (Gen.int (Range.constant 1 10))
  abs x * abs x === x * x

testBasic :: TestLimit -> TestTree
testBasic lim =
  testGroup
    "basic"
    [ testAsUnit
    , testAsProp lim
    ]

data Tag

instance GenDefault Tag Int where genDefault = genDefaultTag (Proxy @Std)

instance GenDefault Tag Char where genDefault = genDefaultTag (Proxy @Std)

newtype AList a = AList [a]
  deriving newtype (Eq, Ord, Show, IsList)

instance (GenDefault Tag a) => GenDefault Tag (AList a) where genDefault = genDefaultList (Proxy @0) (Proxy @2)

newtype AString = AString String
  deriving newtype (Eq, Ord, Show, IsString)

instance GenDefault Tag AString where genDefault = genDefaultString (Proxy @0) (Proxy @2)

data Choice = ChoiceA | ChoiceB
  deriving stock (Eq, Ord, Show, Enum, Bounded)

instance GenDefault Tag Choice where genDefault = genDefaultEnum

instance (GenDefault Tag a) => GenDefault Tag (Maybe a) where genDefault = genDefaultGeneric

data Record = Record !Int !(Maybe Record)
  deriving stock (Eq, Ord, Show, Generic)

instance GenDefault Tag Record where genDefault = genDefaultGeneric

data GenCase where
  GenCase :: (Ord a) => String -> Gen a -> GenCase

genDefaultByProxy :: (GenDefault Tag a) => Proxy a -> Gen a
genDefaultByProxy _ = genDefault (Proxy @Tag)

mkGenCase :: (Ord a, GenDefault Tag a) => String -> Proxy a -> GenCase
mkGenCase name = GenCase name . genDefaultByProxy

genCases :: [GenCase]
genCases =
  [ mkGenCase "Int" (Proxy @Int)
  , mkGenCase "Char" (Proxy @Char)
  , mkGenCase "Choice" (Proxy @Choice)
  , mkGenCase "AList" (Proxy @(AList Char))
  , mkGenCase "AString" (Proxy @AString)
  , mkGenCase "Record" (Proxy @Record)
  ]

testGenCase :: GenCase -> TestTree
testGenCase (GenCase name gen) = testUnit name $ do
  xs <- fmap Set.fromList (replicateM 10 (Gen.sample gen))
  assert (Set.size xs > 1)

testDerive :: TestTree
testDerive = testGroup "derive" (fmap testGenCase genCases)

main :: IO ()
main = testMain $ \lim ->
  testGroup
    "PropUnit"
    [ testBasic lim
    , testDerive
    ]