# assert4hs

 This library aims to provide a set of combinators to assert arbitrary nested data structures.
 The inspiration of this library is AssertJ for Java, the composition of assertions was inspired by `lens` library.

 New assertions can be easily written and composed with other assertions. All failed assertions are gathered and presented to the user.

```haskell
  data Foo = Foo {name :: String, age :: Int} deriving (Show, Eq)

  assertThat (Foo "someName" 15) $
       isEqualTo (Foo "someN1ame" 15)
       . focus age
       . tag "age"
       . isGreaterThan 20
```

 result in

```haskell
  given Foo {name = "someName", age = 15} should be equal to Foo {name = "someN1ame", age = 15}
  Foo {name = "someName", age = 15}
  ╷
  │
  ╵
  Foo {name = "someN1ame", age = 15}
                    ▲
  [age] given 15 should be greater than 20
```

#### Examples

##### Simple assertion

```haskell
  result = 10
  assertThat result $ isEqual 10
```

##### Composing assertion

 Assertions are composable, this allows verifying multiple conditions during one test case.

```haskell
  result = 10
  assertThat result $ 
      isGreaterThan 5 
      . isLowerThan 20
 
 
 >>> given 4 should be greater than 5
```

##### Focusing on part of data structure

 Sometimes it is convenient to transform the subject under test and execute assertions on the extracted part of it. For this purpose, we have a `focus` function.

```haskell
  data Foo = Foo {name :: String, age :: Int} deriving (Show, Eq)

  assertThat (Foo "someName" 15) $
      isEqualTo (Foo "someName" 15)
      . focus age
      . isGreaterThan 20
      . isLowerEqualThan 5

  >>> given 15 should be greater than 20 
  >>> given 15 should be lower or equal to 5
```

##### Changing subject uder test

The `focus` function allows to transform the subject under test, but the original subject is lost. Function `inside` is similar to the function `focus`, but preserve theoriginal subject under test.

```haskell
data Foo = Foo {name :: String, age :: Int} deriving (Show, Eq)

assertThat (Foo "someName" 15) $
    inside age (isGreaterThan 20 . isLowerEqualThan 5)
    . focus name 
    . isEqualTo "someName1" 

>>> given 15 should be greater than 20
>>> 
>>> given 15 should be lower or equal to 5
>>> 
>>> given "someName" should be equal to "someName1"
>>> "someName"
>>> ╷
>>> │
>>> ╵
>>> "someName1"
>>>          ▲
```

##### Tagging assertions

Once our test grows, it is hard to spot which assertions failed and why. That is why function `tag` exists, one can name assertion and give it a more readable name for failure message.

```haskell

data Foo = Foo {name :: String, age :: Int} deriving (Show, Eq)

assertThat (Foo "someName" 15) $
  inside age (tag "age" . isGreaterThan 20 . isLowerEqualThan 5)
    . tag "name"
    . focus name
    . isEqualTo "someName1"
    . tag "should not be equal"
    . isNotEqualTo "someName"

>>> [age] given 15 should be greater than 20
>>> 
>>> [age] given 15 should be lower or equal to 5
>>> 
>>> [name] given "someName" should be equal to "someName1"
>>> "someName"
>>> ╷
>>> │
>>> ╵
>>> "someName1"
>>>          ▲
>>> 
>>> [name.should not be equal] given "someName" should be not equal to "someName"
```

##### Custom assertions

 It is sometimes convenient to create a custom assertion which explicitly describes what is testing. For this purpose we have `simpleAssertion` function

```haskell
isSuitableForEmployment :: Assertion Foo
isSuitableForEmployment =
    simpleAssertion (\a -> age a > 17) (\a -> "new employee must be 18 years or older, but it has " <> show (age a))
    . simpleAssertion (\a -> age a < 70) (\a -> "must be younger than 70 years old, but it has " <> show (age a))

assertThat (Foo "someName" 15) isSuitableForEmployment

>>> new employee must be 18 years or older, but it has 15

assertThat (Foo "someName" 76) isSuitableForEmployment

>>> must be younger than 70 years old, but it has 76

```

#### Related projects

[assert4hs-hspec](https://github.com/paweln1986/assert4hs-hspec) - integration point of assert4hs and [hspec](https://hackage.haskell.org/package/hspec)

[assert4hs-tasty](https://github.com/paweln1986/assert4hs-tasty) - integration point of assert4hs and [tasty](https://hackage.haskell.org/package/tasty)