packages feed

moonlight-pale-0.1.0.0: src-test-laws/Moonlight/Pale/Test/Laws/Suite.hs

{-| A test-tree algebra for QuickCheck, Hedgehog, HUnit, and nested laws. -}
module Moonlight.Pale.Test.Laws.Suite
  ( LawSuite,
    quickCheckLaw,
    namedQuickCheckLaw,
    hedgehogLaw,
    namedHedgehogLaw,
    hUnitLaw,
    testTreeLaw,
    lawGroup,
    renderLawSuite,
  )
where

import Data.Kind (Type)
import qualified Hedgehog as HH
import Moonlight.Core (IsLawName (..))
import Prelude (Bool, Show, String, map, (.), (>>=))
import Test.Tasty (TestTree, testGroup)
import qualified Test.Tasty.Hedgehog as TH
import Test.Tasty.HUnit (Assertion, testCase)
import qualified Test.Tasty.QuickCheck as QC

type LawSuite :: Type
data LawSuite
  = QuickCheckLaw !String !QC.Property
  | HedgehogLaw !String !HH.Property
  | HUnitLaw !String !Assertion
  | EmbeddedTest !TestTree
  | LawGroup !String ![LawSuite]

quickCheckLaw :: QC.Testable property => String -> property -> LawSuite
quickCheckLaw lawLabel lawProperty =
  QuickCheckLaw lawLabel (QC.property lawProperty)

namedQuickCheckLaw ::
  (IsLawName lawName, QC.Testable property) =>
  lawName ->
  property ->
  LawSuite
namedQuickCheckLaw lawName =
  quickCheckLaw (lawNameText lawName)

hedgehogLaw :: Show value => String -> HH.Gen value -> (value -> Bool) -> LawSuite
hedgehogLaw lawLabel generator predicate =
  HedgehogLaw lawLabel (HH.property (HH.forAll generator >>= HH.assert . predicate))

namedHedgehogLaw ::
  (IsLawName lawName, Show value) =>
  lawName ->
  HH.Gen value ->
  (value -> Bool) ->
  LawSuite
namedHedgehogLaw lawName =
  hedgehogLaw (lawNameText lawName)

hUnitLaw :: String -> Assertion -> LawSuite
hUnitLaw = HUnitLaw

testTreeLaw :: TestTree -> LawSuite
testTreeLaw = EmbeddedTest

lawGroup :: String -> [LawSuite] -> LawSuite
lawGroup = LawGroup

renderLawSuite :: LawSuite -> TestTree
renderLawSuite lawSuite =
  case lawSuite of
    QuickCheckLaw lawLabel lawProperty ->
      QC.testProperty lawLabel lawProperty
    HedgehogLaw lawLabel lawProperty ->
      TH.testProperty lawLabel lawProperty
    HUnitLaw lawLabel assertion ->
      testCase lawLabel assertion
    EmbeddedTest testTree ->
      testTree
    LawGroup groupLabel nestedLaws ->
      testGroup groupLabel (map renderLawSuite nestedLaws)