nri-prelude-0.1.0.2: A Prelude inspired by the Elm programming language

Safe HaskellNone
LanguageHaskell2010

Expect

Contents

Description

A library to create Expectations, which describe a claim to be tested.

Quick Reference

Synopsis

Basic Expectations

type Expectation = Expectation TestResult Source #

The result of a single test run: either a pass or a fail.

equal :: (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 :: (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 :: 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
-}

concat :: List Expectation -> Expectation Source #

Combine multiple expectations into one. The resulting expectation is a failure if any of the original expectations are a failure.

Numeric Comparisons

lessThan :: (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 :: (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 :: (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 :: (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 :: 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 :: 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 :: 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 :: 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

These functions will let you build your own expectations.

pass :: 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 :: 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 :: 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"

Fancy Expectations

equalToContentsOf :: 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.

withIO :: (a -> Expectation) -> IO a -> Expectation Source #

Run some IO and assert the value it produces.

If the IO throws an exception the test will fail.