View Source Moar.Assertions (Moar v1.54.0)

ExUnit assertions.

See also: siiibo/assert_match which is similar to this module's assert_eq function but with pattern matching.

Summary

Functions

Asserts that the left list or map contains all of the items in the right list or map, or contains the single right element if it's not a list or map. Returns left or raises ExUnit.AssertionError.

Asserts that the left and right values are equal. It returns the left value unless the assertion fails, or unless the :returning option is used. As a special case, if the first argument is a string and the second is a Regex, the comparison is done with the =~ operator instead of the == operator.

Asserts that datetime is within recency of now (in UTC), returning datetime if the assertion succeeeds.

Asserts that a pre-condition and a post-condition are true after performing an action, returning the result of the action.

Refute that a condition is changed after performing an action, returning the result of the action.

Types

Link to this type

assert_eq_opt_shortcut()

View Source
@type assert_eq_opt_shortcut() :: :downcase | :sort | :squish | :trim
@type assert_eq_opts() ::
  (any() -> any())
  | {:apply, (any() -> any()) | assert_eq_opt_shortcut()}
  | assert_eq_opt_shortcut()
  | {:except, list()}
  | :ignore_order
  | {:ignore_order, boolean()}
  | {:ignore_whitespace, :leading_and_trailing}
  | {:map, (any() -> any()) | assert_eq_opt_shortcut()}
  | {:only, list()}
  | {:returning, any()}
  | {:whitespace, :squish | :trim}
  | {:within, number() | {number(), Moar.Duration.time_unit()}}

Functions

Link to this function

assert_contains(left, right)

View Source
@spec assert_contains(map(), map()) :: map()
@spec assert_contains(list(), list() | any()) :: list()

Asserts that the left list or map contains all of the items in the right list or map, or contains the single right element if it's not a list or map. Returns left or raises ExUnit.AssertionError.

iex> assert_contains([1, 2, 3], [1, 3])
[1, 2, 3]

iex> assert_contains(%{a: 1, b: 2, c: 3}, %{a: 1, c: 3})
%{a: 1, b: 2, c: 3}

iex> assert_contains([1, 2, 3], 2)
[1, 2, 3]
Link to this function

assert_eq(left, right, opts \\ [])

View Source
@spec assert_eq(
  left :: any(),
  right :: any(),
  opts :: assert_eq_opts() | [assert_eq_opts()]
) :: any()

Asserts that the left and right values are equal. It returns the left value unless the assertion fails, or unless the :returning option is used. As a special case, if the first argument is a string and the second is a Regex, the comparison is done with the =~ operator instead of the == operator.

Style note: the authors prefer to use assert in most cases, using assert_eq only when the extra options are helpful or when they want to make assertions in a pipeline.

iex> import Moar.Assertions

# prefer regular `assert` when `assert_eq` is not necessary
iex> assert Map.put(%{a: 1}, :b, 2) == %{a: 1, b: 2}
true

# works nicely with pipes
iex> %{a: 1} |> Map.put(:b, 2) |> assert_eq(%{a: 1, b: 2})
%{a: 1, b: 2}

# returns an arbitrary value instead of the left value
iex> map = %{a: 1, b: 2}
iex> map |> Map.get(:a) |> assert_eq(1, returning: map)
%{a: 1, b: 2}

# compares using a regex if `left` is a string and `right` is a Regex
iex> assert_eq "the length is 10cm", ~r/.*length is \d{2}cm/

left and right can be transformed by passing in one or more functions (optionally using the apply: keyword). If left and right are lists, all their values can be transformed using the map: option.

iex> import Moar.Assertions

# apply a function
iex> assert_eq("hello", "heLLo", &String.downcase/1)
"hello"

# apply multiple functions (left to right)
iex> assert_eq("hello", "heLLo", [&String.downcase/1, &String.reverse/1])
"olleh"

# apply a function explicitly
iex> assert_eq("hello", "heLLo", apply: &String.downcase/1)
"hello"

# map all elements with a function
iex> assert_eq(["a", "B"], ["A", "b"], map: &String.downcase/1)
["a", "b"]

# combine apply and map (left to right)
iex> assert_eq(["a", "B", "C"], ["A", "b", "Z"], apply: &Enum.drop(&1, -1), map: &String.downcase/1)
["a", "b"]

If left and right are maps, only: <list> will only consider the given keys, and except: <list> will ignore certain keys.

iex> import Moar.Assertions

# ignore one or more keys of a map
iex> assert_eq(%{a: 1, b: 2, c: 3}, %{a: 1, b: 100, c: 3}, except: [:b])
%{a: 1, b: 2, c: 3}

# only assert on one or more keys of a map
iex> assert_eq(%{a: 1, b: 2, c: 3}, %{a: 1, b: 100, c: 3}, only: [:a, :c])
%{a: 1, b: 2, c: 3}

If left and right are lists, their order can be ignored using :ignore_order.

iex> import Moar.Assertions

# ignoring order when comparing lists
iex> assert_eq(["a", "b"], ["b", "a"], :ignore_order)
["a", "b"]

For inexact numerical assertions, within: <delta> works like ExUnit.Assertions.assert_in_delta/4, and for inexact date and datetime assertions, within: {<delta>, <time-unit>} asserts that left and right are within some duration of each other. See Moar.Duration for more about time units, and also see Moar.Assertions.assert_recent/2. If left and right are strings, they are parsed as ISO8601 dates.

iex> import Moar.Assertions

# assert within a delta (this particular case could use ExUnit.Assertions.assert_in_delta/4).
iex> assert_eq(4/28, 0.14, within: 0.01)
0.14285714285714285

# assert within a time delta
iex> inserted_at = ~U[2022-01-02 03:00:00Z]
iex> updated_at = ~U[2022-01-02 03:04:00Z]
iex> assert_eq(inserted_at, updated_at, within: {10, :minute})
~U[2022-01-02 03:00:00Z]

# assert within a time delta when inputs are time strings
iex> inserted_at = "2022-01-02T03:00:00Z"
iex> updated_at = "2022-01-02T03:04:00Z"
iex> assert_eq(inserted_at, updated_at, within: {10, :minute})
"2022-01-02T03:00:00Z"

The following transformation shortcuts are supported:

  • :downcase - if left and right are strings, converts them to lowercase before comparing
  • :sort - the same as :ignore_order
  • :squish - if left and right are strings, trims the strings and replaces consecutive whitespace characters with a single space using Moar.String.squish/1 before comparing
  • :trim - if left and right are strings, trims the strings using String.trim/1 before comparing
iex> import Moar.Assertions

iex> assert_eq("FOO bar", "foo bar", :downcase)
"foo bar"

iex> assert_eq(" FOO   bar  ", "foo bar", [:downcase, :squish])
"foo bar"

The following options are deprecated:

  • ignore_order: <boolean> - use :ignore_order instead of ignore_order: true
  • ignore_whitespace: :leading_and_trailing - use :squish or :trim instead
  • whitespace: :squish - use :squish instead
  • whitespace: :trim - use :trim instead
Link to this function

assert_recent(datetime, recency \\ {10, :second})

View Source
@spec assert_recent(DateTime.t() | NaiveDateTime.t() | binary(), Moar.Duration.t()) ::
  DateTime.t() | NaiveDateTime.t() | binary()

Asserts that datetime is within recency of now (in UTC), returning datetime if the assertion succeeeds.

Uses assert_eq(datetime, now, within: recency) under the hood.

iex> five_seconds_ago = Moar.DateTime.add(DateTime.utc_now(), {-5, :second})
iex> assert_recent five_seconds_ago

iex> twenty_seconds_ago = Moar.DateTime.add(DateTime.utc_now(), {-20, :second})
iex> assert_recent twenty_seconds_ago, {25, :second}
Link to this macro

assert_that(command, list)

View Source (macro)
@spec assert_that(any(), changes: any(), from: any(), to: any()) :: Macro.t()

Asserts that a pre-condition and a post-condition are true after performing an action, returning the result of the action.

To use an anonymous function as the action, wrap it in parentheses and call it with .().

Examples

iex> {:ok, agent} = Agent.start(fn -> 0 end)
...>
iex> assert_that Agent.update(agent, fn s -> s + 1 end),
...>     changes: Agent.get(agent, fn s -> s end),
...>     from: 0,
...>     to: 1
:ok
...>
iex> assert_that Agent.update(agent, fn s -> s + 1 end),
...>     changes: Agent.get(agent, fn s -> s end),
...>     to: 2
:ok
...>
iex> assert_that (fn -> Agent.update(agent, fn s -> s + 1 end) end).(),
...>     changes: Agent.get(agent, fn s -> s end),
...>     to: 3
:ok
Link to this macro

refute_that(command, list)

View Source (macro)
@spec refute_that(any(), [{:changes, any()}]) :: Macro.t()

Refute that a condition is changed after performing an action, returning the result of the action.

Examples

iex> {:ok, agent} = Agent.start(fn -> 0 end)
...>
iex> refute_that Function.identity(1),
...>     changes: Agent.get(agent, fn s -> s end)
1

iex> refute_that Function.identity(5),
...>     changes: %{a: 1}
5