Safe Haskell | None |
---|---|
Language | Haskell2010 |
Synopsis
- type Expectation = Expectation' ()
- equal :: (HasCallStack, Show a, Eq a) => a -> a -> Expectation
- notEqual :: (HasCallStack, Show a, Eq a) => a -> a -> Expectation
- all :: HasCallStack => List (subject -> Expectation) -> subject -> Expectation
- equalToContentsOf :: HasCallStack => Text -> Text -> Expectation
- data FloatingPointTolerance
- within :: HasCallStack => FloatingPointTolerance -> Float -> Float -> Expectation
- notWithin :: HasCallStack => FloatingPointTolerance -> Float -> Float -> Expectation
- lessThan :: (HasCallStack, Show a, Ord a) => a -> a -> Expectation
- atMost :: (HasCallStack, Show a, Ord a) => a -> a -> Expectation
- greaterThan :: (HasCallStack, Show a, Ord a) => a -> a -> Expectation
- atLeast :: (HasCallStack, Show a, Ord a) => a -> a -> Expectation
- true :: HasCallStack => Bool -> Expectation
- false :: HasCallStack => Bool -> Expectation
- ok :: (HasCallStack, Show b) => Result b a -> Expectation
- err :: (HasCallStack, Show a) => Result b a -> Expectation
- pass :: HasCallStack => Expectation
- fail :: HasCallStack => Text -> Expectation
- onFail :: HasCallStack => Text -> Expectation -> Expectation
- fromResult :: (HasCallStack, Show b) => Result b a -> Expectation' a
- succeeds :: (HasCallStack, Show err) => Task err a -> Expectation' a
- fails :: (HasCallStack, Show a) => Task err a -> Expectation' err
- andCheck :: (HasCallStack, Show err) => (a -> Expectation) -> Task err a -> Expectation
- fromIO :: IO a -> Expectation' a
- data Expectation' a
- around :: (forall e a. (arg -> Task e a) -> Task e a) -> (arg -> Expectation) -> Expectation
Basic Expectations
type Expectation = Expectation' () Source #
The result of a single test run: either a pass
or a fail
.
equal :: (HasCallStack, Show a, Eq a) => a -> a -> Expectation Source #
Passes if the arguments are equal.
Expect.equal 0 (List.length []) -- Passes because (0 == 0) is True
Failures resemble code written in pipeline style, so you can tell which argument is which:
-- Fails because the expected value didn't split the space in "Betty Botter" Text.split " " "Betty Botter bought some butter" |> Expect.equal [ "Betty Botter", "bought", "some", "butter" ] {- [ "Betty", "Botter", "bought", "some", "butter" ] ╷ │ Expect.equal ╵ [ "Betty Botter", "bought", "some", "butter" ] -}
notEqual :: (HasCallStack, Show a, Eq a) => a -> a -> Expectation Source #
Passes if the arguments are not equal.
-- Passes because (11 /= 100) is True 90 + 10 |> Expect.notEqual 11 -- Fails because (100 /= 100) is False 90 + 10 |> Expect.notEqual 100 {- 100 ╷ │ Expect.notEqual ╵ 100 -}
all :: HasCallStack => List (subject -> Expectation) -> subject -> Expectation Source #
Passes if each of the given functions passes when applied to the subject.
Passing an empty list is assumed to be a mistake, so Expect.all [] will always return a failed expectation no matter what else it is passed.
Expect.all [ Expect.greaterThan -2 , Expect.lessThan 5 ] (List.length []) -- Passes because (0 > -2) is True and (0 < 5) is also True
Failures resemble code written in pipeline style, so you can tell which argument is which:
-- Fails because (0 < -10) is False List.length [] |> Expect.all [ Expect.greaterThan -2 , Expect.lessThan -10 , Expect.equal 0 ] {- 0 ╷ │ Expect.lessThan ╵ -10 -}
equalToContentsOf :: HasCallStack => Text -> Text -> Expectation Source #
Check if a string is equal to the contents of a file.
Debug.toString complicatedObject |> Expect.equalToContentsOf "golden-results/complicated-object.txt"
If the file does not exist it will be created and the test will pass. Subsequent runs will check the test output matches the now existing file.
This can be useful when checking big strings, like for example JSON
encodings. When a test fails we can throw away the file, rerun the test, and
use git diff golden-results/complicated-object.txt
to check whether the
changes are acceptable.
Floating Point Comparisons
data FloatingPointTolerance Source #
A type to describe how close a floating point number must be to the expected value for the test to pass. This may be specified as absolute or relative.
AbsoluteOrRelative
tolerance uses a logical OR between the absolute
(specified first) and relative tolerance. If you want a logical AND, use
all
.
Instances
Show FloatingPointTolerance Source # | |
Defined in Expect showsPrec :: Int -> FloatingPointTolerance -> ShowS # show :: FloatingPointTolerance -> String # showList :: [FloatingPointTolerance] -> ShowS # |
within :: HasCallStack => FloatingPointTolerance -> Float -> Float -> Expectation Source #
Passes if the second and third arguments are equal within a tolerance specified by the first argument. This is intended to avoid failing because of minor inaccuracies introduced by floating point arithmetic.
-- Fails because 0.1 + 0.2 == 0.30000000000000004 (0.1 is non-terminating in base 2) 0.1 + 0.2 |> Expect.equal 0.3 -- So instead write this test, which passes 0.1 + 0.2 |> Expect.within (Absolute 0.000000001) 0.3
Failures resemble code written in pipeline style, so you can tell which argument is which:
-- Fails because 3.14 is not close enough to pi 3.14 |> Expect.within (Absolute 0.0001) pi {- 3.14 ╷ │ Expect.within Absolute 0.0001 ╵ 3.141592653589793 -}
notWithin :: HasCallStack => FloatingPointTolerance -> Float -> Float -> Expectation Source #
Passes if (and only if) a call to within with the same arguments would have failed.
Numeric Comparisons
lessThan :: (HasCallStack, Show a, Ord a) => a -> a -> Expectation Source #
Passes if the second argument is less than the first.
Expect.lessThan 1 (List.length []) -- Passes because (0 < 1) is True
Failures resemble code written in pipeline style, so you can tell which argument is which:
-- Fails because (0 < -1) is False List.length [] |> Expect.lessThan -1 {- 0 ╷ │ Expect.lessThan ╵ -1 -}
atMost :: (HasCallStack, Show a, Ord a) => a -> a -> Expectation Source #
Passes if the second argument is less than or equal to the first.
Expect.atMost 1 (List.length []) -- Passes because (0 <= 1) is True
Failures resemble code written in pipeline style, so you can tell which argument is which:
-- Fails because (0 <= -3) is False List.length [] |> Expect.atMost -3 {- 0 ╷ │ Expect.atMost ╵ -3 -}
greaterThan :: (HasCallStack, Show a, Ord a) => a -> a -> Expectation Source #
Passes if the second argument is greater than the first.
Expect.greaterThan -2 List.length [] -- Passes because (0 > -2) is True
Failures resemble code written in pipeline style, so you can tell which argument is which:
-- Fails because (0 > 1) is False List.length [] |> Expect.greaterThan 1 {- 0 ╷ │ Expect.greaterThan ╵ 1 -}
atLeast :: (HasCallStack, Show a, Ord a) => a -> a -> Expectation Source #
Passes if the second argument is greater than or equal to the first.
Expect.atLeast -2 (List.length []) -- Passes because (0 >= -2) is True
Failures resemble code written in pipeline style, so you can tell which argument is which:
-- Fails because (0 >= 3) is False List.length [] |> Expect.atLeast 3 {- 0 ╷ │ Expect.atLeast ╵ 3 -}
Booleans
true :: HasCallStack => Bool -> Expectation Source #
Passes if the argument is True
, and otherwise fails with the given message.
Expect.true "Expected the list to be empty." (List.isEmpty []) -- Passes because (List.isEmpty []) is True
Failures resemble code written in pipeline style, so you can tell which argument is which:
-- Fails because List.isEmpty returns False, but we expect True. List.isEmpty [ 42 ] |> Expect.true "Expected the list to be empty." {- Expected the list to be empty. -}
false :: HasCallStack => Bool -> Expectation Source #
Passes if the argument is False
, and otherwise fails with the given message.
Expect.false "Expected the list not to be empty." (List.isEmpty [ 42 ]) -- Passes because (List.isEmpty [ 42 ]) is False
Failures resemble code written in pipeline style, so you can tell which argument is which:
-- Fails because (List.isEmpty []) is True List.isEmpty [] |> Expect.false "Expected the list not to be empty." {- Expected the list not to be empty. -}
Collections
ok :: (HasCallStack, Show b) => Result b a -> Expectation Source #
Passes if the Result is an Ok rather than Err. This is useful for tests where you expect not to see an error, but you don't care what the actual result is.
(Tip: If your function returns a Maybe instead, consider Expect.notEqual Nothing.)
-- Passes String.toInt "not an int" |> Expect.err
Test failures will be printed with the unexpected Ok value contrasting with any Err.
-- Fails String.toInt "20" |> Expect.err {- Ok 20 ╷ │ Expect.err ╵ Err _ -}
err :: (HasCallStack, Show a) => Result b a -> Expectation Source #
Passes if the Result is an Err rather than Ok. This is useful for tests where you expect to get an error but you don't care what the actual error is.
(Tip: If your function returns a Maybe instead, consider Expect.equal Nothing.)
-- Passes String.toInt "not an int" |> Expect.err
Test failures will be printed with the unexpected Ok value contrasting with any Err.
-- Fails String.toInt "20" |> Expect.err {- Ok 20 ╷ │ Expect.err ╵ Err _ -}
Customizing
pass :: HasCallStack => Expectation Source #
Always passes.
import Json.Decode exposing (decodeString, int) import Test exposing (test) import Expect test "Json.Decode.int can decode the number 42." <| \_ -> case decodeString int "42" of Ok _ -> Expect.pass Err err -> Expect.fail err
fail :: HasCallStack => Text -> Expectation Source #
Fails with the given message.
import Json.Decode exposing (decodeString, int) import Test exposing (test) import Expect test "Json.Decode.int can decode the number 42." <| \_ -> case decodeString int "42" of Ok _ -> Expect.pass Err err -> Expect.fail err
onFail :: HasCallStack => Text -> Expectation -> Expectation Source #
If the given expectation fails, replace its failure message with a custom one.
"something" |> Expect.equal "something else" |> Expect.onFail "thought those two strings would be the same"
fromResult :: (HasCallStack, Show b) => Result b a -> Expectation' a Source #
Used for making matchers expectOneItem :: Expectation' [a] -> Expectation' a expectOneItem t = do xs <- t case xs of [x] -> Ok x _ -> Err ("Expected one item, but got " ++ Debug.toString (List.length xs) ++ ".") |> Expect.fromResult
Testing tasks
succeeds :: (HasCallStack, Show err) => Task err a -> Expectation' a Source #
Check a task succeeds.
test "solve rubicskube" <| \_ -> do solveRubicsKube |> succeeds
fails :: (HasCallStack, Show a) => Task err a -> Expectation' err Source #
Check a task fails.
test "chemistry experiment" <| \_ -> do mixRedAndGreenLiquids |> fails
andCheck :: (HasCallStack, Show err) => (a -> Expectation) -> Task err a -> Expectation Source #
Check a task returns an expected value.
test "Greetings are friendly" <| \_ -> do getGreeting |> andCheck (Expect.equal "Hi!")
Fancy Expectations
fromIO :: IO a -> Expectation' a Source #
Convert an IO type to an expectation. Useful if you need to call a function in Haskell's base library or an external library in a test.
data Expectation' a Source #
The type of a test that runs some script with multiple expectations in between.
Instances
Monad Expectation' Source # | |
Defined in Test.Internal (>>=) :: Expectation' a -> (a -> Expectation' b) -> Expectation' b # (>>) :: Expectation' a -> Expectation' b -> Expectation' b # return :: a -> Expectation' a # | |
Functor Expectation' Source # | |
Defined in Test.Internal fmap :: (a -> b) -> Expectation' a -> Expectation' b # (<$) :: a -> Expectation' b -> Expectation' a # | |
Applicative Expectation' Source # | |
Defined in Test.Internal pure :: a -> Expectation' a # (<*>) :: Expectation' (a -> b) -> Expectation' a -> Expectation' b # liftA2 :: (a -> b -> c) -> Expectation' a -> Expectation' b -> Expectation' c # (*>) :: Expectation' a -> Expectation' b -> Expectation' b # (<*) :: Expectation' a -> Expectation' b -> Expectation' a # |
around :: (forall e a. (arg -> Task e a) -> Task e a) -> (arg -> Expectation) -> Expectation Source #
This can be used to create custom test functions that contain some setup and teardown logic, for example to make tests run in a database transaction that gets rolled back afterwards.
dbTest :: Stack.HasCallStack => Text -> (Db.Connection -> Expect.Expectation) -> Test.Test dbTest description body = Stack.withFrozenCallStack Test.test description <| \_ -> do Expect.around ( \task' -> do conn <- Db.getConnection Platform.finally (task' conn) (Db.rollback conn) ) body