{-# LANGUAGE ExistentialQuantification #-}

-- |
-- Module      : Test.Dwergaz
-- Description : A minimal testing library
-- Copyright   : (c) 2017-2024, Henry Till
-- License     : ISC
-- Maintainer  : henrytill@gmail.com
-- Stability   : experimental
--
-- = Usage:
--
-- See the <https://github.com/henrytill/dwergaz/blob/master/test/Main.hs tests> for a usage example.
module Test.Dwergaz
  ( Test (..),
    assertFailure,
    assertBool,
    assertEqual,
    Result,
    resultToString,
    resultIsPassed,
    runTest,
  )
where

import Text.PrettyPrint

data Test
  = forall a b.
    (Show a, Show b) =>
    Expect
      -- | Test description
      String
      -- | Test function
      (a -> b -> Bool)
      -- | Expected value
      a
      -- | Actual value
      b
  | Predicate
      -- | Test description
      String
      -- | Condition
      Bool

assertFailure ::
  -- | Test description
  String ->
  Test
assertFailure :: String -> Test
assertFailure = (String -> Bool -> Test) -> Bool -> String -> Test
forall a b c. (a -> b -> c) -> b -> a -> c
flip String -> Bool -> Test
Predicate Bool
False

assertBool ::
  -- | Test description
  String ->
  -- | Condition to test
  Bool ->
  Test
assertBool :: String -> Bool -> Test
assertBool = String -> Bool -> Test
Predicate

assertEqual ::
  (Eq a, Show a) =>
  -- | Test description
  String ->
  -- | Expected value
  a ->
  -- | Actual value
  a ->
  Test
assertEqual :: forall a. (Eq a, Show a) => String -> a -> a -> Test
assertEqual String
desc = String -> (a -> a -> Bool) -> a -> a -> Test
forall a b.
(Show a, Show b) =>
String -> (a -> b -> Bool) -> a -> b -> Test
Expect String
desc a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(==)

data Result
  = forall a b. (Show a, Show b) => FailedExpect String a b
  | Failed String
  | Passed String

prettyResult :: Result -> Doc
prettyResult :: Result -> Doc
prettyResult (FailedExpect String
n a
e b
a) =
  [Doc] -> Doc
vcat
    [ String -> Doc
text String
"FAILED:" Doc -> Doc -> Doc
<+> String -> Doc
text String
n,
      Int -> Doc -> Doc
nest Int
2 (String -> Doc
text String
"EXPECTED:") Doc -> Doc -> Doc
<+> String -> Doc
text (a -> String
forall a. Show a => a -> String
show a
e),
      Int -> Doc -> Doc
nest Int
2 (String -> Doc
text String
"ACTUAL:") Doc -> Doc -> Doc
<+> String -> Doc
text (b -> String
forall a. Show a => a -> String
show b
a)
    ]
prettyResult (Failed String
n) = String -> Doc
text String
"FAILED:" Doc -> Doc -> Doc
<+> String -> Doc
text String
n
prettyResult (Passed String
n) = String -> Doc
text String
"PASSED:" Doc -> Doc -> Doc
<+> String -> Doc
text String
n

resultToString :: Result -> String
resultToString :: Result -> String
resultToString = Doc -> String
render (Doc -> String) -> (Result -> Doc) -> Result -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Result -> Doc
prettyResult

resultIsPassed :: Result -> Bool
resultIsPassed :: Result -> Bool
resultIsPassed (Passed String
_) = Bool
True
resultIsPassed Result
_ = Bool
False

runTest :: Test -> Result
runTest :: Test -> Result
runTest (Expect String
n a -> b -> Bool
f a
e b
a)
  | a -> b -> Bool
f a
e b
a = String -> Result
Passed String
n
  | Bool
otherwise = String -> a -> b -> Result
forall a b. (Show a, Show b) => String -> a -> b -> Result
FailedExpect String
n a
e b
a
runTest (Predicate String
n Bool
c)
  | Bool
c = String -> Result
Passed String
n
  | Bool
otherwise = String -> Result
Failed String
n