# module Spec::Methods

##
Defined in:

spec/helpers/iterate.cr
spec/helpers/string.cr
spec/methods.cr

##
Macro Summary

- assert_iterates_iterator(expected, method, *, infinite = false)

  Calls method expecting an iterator and compares iterated values with expected.

- assert_iterates_yielding(expected, method, *, infinite = false, tuple = false)

  Calls method with a block and compares yielded values with expected.

- assert_prints(call, *, should expectation, file = __FILE__, line = __LINE__)

  Asserts that the given call and its `IO`-accepting variant both match the given expectation, used to test string printing.

- assert_prints(call, str, *, file = __FILE__, line = __LINE__)

  Asserts that the given call and its `IO`-accepting variant both produce the given string str.

- it_iterates(description, expected, method, *, infinite = false, tuple = false, file = __FILE__, line = __LINE__)

  Spec helper for generic iteration methods which tests both yielding and iterator overloads.

##
Instance Method Summary

- #after_all(&block)

  Executes the given block after the last spec in the current context runs.

- #after_each(&block)

  Executes the given block after each spec in the current context runs.

- #around_all(&block : ExampleGroup::Procsy -> )

  Executes the given block when the current context runs.

- #around_each(&block : Example::Procsy -> )

  Executes the given block when each spec in the current context runs.

- #before_all(&block)

  Executes the given block before the first spec in the current context runs.

- #before_each(&block)

  Executes the given block before each spec in the current context runs.

- #context(description = nil, file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil, &block)

  Defines an example group that establishes a specific context, like empty array versus array with elements.

- #describe(description = nil, file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil, &block)

  Defines an example group that describes a unit to be tested.

- #fail(msg, file = __FILE__, line = __LINE__)

  Fails an example.

- #it(description = "assert", file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil, &block)

  Defines a concrete test case.

- #pending(description = "assert", file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil, &)

  Defines a pending test case.

- #pending(description = "assert", file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil)

  Defines a yet-to-be-implemented pending test case

- #pending!(msg = "Cannot run example", file = __FILE__, line = __LINE__)

  Marks the current example pending

##
Macro Detail

macro assert_iterates_iterator(expected, method, *, infinite = false) #

Calls method expecting an iterator and compares iterated values with expected.

See `.it_iterates` for details.

macro assert_iterates_yielding(expected, method, *, infinite = false, tuple = false) #

Calls method with a block and compares yielded values with expected.

See `.it_iterates` for details.

macro assert_prints(call, *, should expectation, file = __FILE__, line = __LINE__) #

Asserts that the given call and its `IO`-accepting variant both match the given expectation, used to test string printing.

Given a call of the form `foo.bar(*args, **opts)`, this tests the following cases:

- The call itself. Additionally this call must return a `String`.
- `String.build { |io| foo.bar(io, *args, **opts) }`, which constructs a `String` via an `IO` overload.
- `io = ...; foo.bar(io, *args, **opts); io.to_s`, where `io` is an `IO` configured to use the UTF-16 encoding, and contents written to it are decoded back into a UTF-8 `String`. This case ensures that the `IO` overload does not produce malformed UTF-8 byte sequences via a non-default encoding. This case is skipped if the `without_iconv` flag is set.

The overload that accepts a str argument is usually easier to work with.

macro assert_prints(call, str, *, file = __FILE__, line = __LINE__) #

Asserts that the given call and its `IO`-accepting variant both produce the given string str.

Equivalent to `assert_prints call, should: eq(str)`. str must be validly encoded in UTF-8.

    require "spec"
    require "spec/helpers/string"

    it "prints integers with `Int#to_s`" do
      assert_prints 123.to_s, "123"
      assert_prints 123.to_s(16), "7b"
    end

Methods that do not follow the convention of `IO`-accepting and `String`-returning overloads can also be tested as long as suitable wrapper methods are defined:

    require "spec"
    require "spec/helpers/string"

    private def fprintf(format, *args)
      sprintf(format, *args)
    end

    private def fprintf(io : IO, format, *args)
      io.printf(format, *args)
    end

    it "prints with `sprintf` and `IO#printf`" do
      assert_prints fprintf("%d", 123), "123"
      assert_prints fprintf("%x %b", 123, 6), "7b 110"
    end

macro it_iterates(description, expected, method, *, infinite = false, tuple = false, file = __FILE__, line = __LINE__) #

Spec helper for generic iteration methods which tests both yielding and iterator overloads.

This helper creates two spec examples named description with suffixes `" yielding"` and `" iterator"`. The yielding example calls method with a block and expects the iteration elements to be yielded to the block. The iterator example calls method without a block and expects it to return an `Iterator` which it then consumes.

The iterated elements are collected in an array and compared to expected, ensuring type-equality of the elements.

By default, both examples make sure that the iteration is finished after iterating all elements from expected. If the iteration is infinite, passing `infinite: true` skips that check and allows to test a finite sample of an infinite iteration.

    require "spec/helpers/iterate"

    it_iterates "Array#each", [1, 2, 3], (1..3).each
    it_iterates "infinite #cycle", [1, 2, 3, 1, 2, 3, 1], (1..3).cycle, infinite: true

If the iteration elements are tuples (i.e. multiple values), the yielding variant by default only catches the first value because of the block argument mechanics. Passing `tuple: true` ensures all yielded arguments are collected using a splat.

    require "spec/helpers/iterate"

    it_iterates "Array#each_with_index", [{1, 0}, {2, 1}, {3, 2}], (1..3).each_with_index, tuple: true

##
Instance Method Detail

def after_all(&block) #

Executes the given block after the last spec in the current context runs.

A context is defined by `#describe` or `#context` blocks, or outside of them it's the root context. This is independent of the source location the specs and this hook are defined.

If multiple blocks are registered on the same context, they are executed in order of definition.

    require "spec"

    it "sample_a" { }

    describe "nested_context" do
      after_all do
        puts "runs at end of nested_context"
      end

      it "sample_b" { }
    end

def after_each(&block) #

Executes the given block after each spec in the current context runs.

A context is defined by `#describe` or `#context` blocks, or outside of them it's the root context. Nested contexts inherit the `*_each` blocks of their ancestors.

If multiple blocks are registered for the same spec, the blocks defined in the outermost context go first. Blocks on the same context are executed in order of definition.

    require "spec"

    it "sample_a" { }

    describe "nested_context" do
      after_each do
        puts "runs after sample_b"
      end

      it "sample_b" { }
    end

def around_all(&block : ExampleGroup::Procsy -> ) #

Executes the given block when the current context runs.

The block must call `run` on the given `Context::Procsy` object.

This is essentially a `#before_all` and `#after_all` hook combined into one. It is useful for example when setup and teardown steps need shared state.

A context is defined by `#describe` or `#context` blocks. This hook does not work outside such a block (i.e. in the root context).

If multiple blocks are registered for the same spec, the blocks defined in the outermost context go first. Blocks on the same context are executed in order of definition.

    require "spec"

    describe "main_context" do
      around_each do |example|
        puts "runs at beginning of main_context"
        example.run
        puts "runs at end of main_context"
      end

      it "sample_a" { }

      describe "nested_context" do
        around_each do |example|
          puts "runs at beginning of nested_context"
          example.run
          puts "runs at end of nested_context"
        end

        it "sample_b" { }
      end
    end

def around_each(&block : Example::Procsy -> ) #

Executes the given block when each spec in the current context runs.

The block must call `run` on the given `Example::Procsy` object.

This is essentially a `#before_each` and `#after_each` hook combined into one. It is useful for example when setup and teardown steps need shared state.

A context is defined by `#describe` or `#context` blocks, or outside of them it's the root context. Nested contexts inherit the `*_each` blocks of their ancestors.

If multiple blocks are registered for the same spec, the blocks defined in the outermost context go first. Blocks on the same context are executed in order of definition.

    require "spec"

    it "sample_a" { }

    describe "nested_context" do
      around_each do |example|
        puts "runs before sample_b"
        example.run
        puts "runs after sample_b"
      end

      it "sample_b" { }
    end

def before_all(&block) #

Executes the given block before the first spec in the current context runs.

A context is defined by `#describe` or `#context` blocks, or outside of them it's the root context. This is independent of the source location the specs and this hook are defined.

If multiple blocks are registered on the same context, they are executed in order of definition.

    require "spec"

    it "sample_a" { }

    describe "nested_context" do
      before_all do
        puts "runs at start of nested_context"
      end

      it "sample_b" { }
    end

def before_each(&block) #

Executes the given block before each spec in the current context runs.

A context is defined by `#describe` or `#context` blocks, or outside of them it's the root context. Nested contexts inherit the `*_each` blocks of their ancestors.

If multiple blocks are registered for the same spec, the blocks defined in the outermost context go first. Blocks on the same context are executed in order of definition.

    require "spec"

    it "sample_a" { }

    describe "nested_context" do
      before_each do
        puts "runs before sample_b"
      end

      it "sample_b" { }
    end

def context(description = nil, file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil, &block) #

Defines an example group that establishes a specific context, like empty array versus array with elements. Inside &block examples are defined by `#it` or `#pending`.

It is functionally equivalent to `#describe`.

If `focus` is `true`, only this `#context`, and others marked with `focus: true`, will run.

def describe(description = nil, file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil, &block) #

Defines an example group that describes a unit to be tested. Inside &block examples are defined by `#it` or `#pending`.

Several `#describe` blocks can be nested.

Example:

    require "spec"

    describe "Int32" do
      describe "+" do
        it "adds" { (1 + 1).should eq 2 }
      end
    end

If `focus` is `true`, only this `#describe`, and others marked with `focus: true`, will run.

def fail(msg, file = __FILE__, line = __LINE__) #

Fails an example.

This method can be used to manually fail an example defined in an `#it` block.

def it(description = "assert", file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil, &block) #

Defines a concrete test case.

The test is performed by the block supplied to &block.

Example:

    require "spec"

    it "adds" { (1 + 1).should eq 2 }

It is usually used inside a `#describe` or `#context` section.

If `focus` is `true`, only this test, and others marked with `focus: true`, will run.

def pending(description = "assert", file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil, &) #

Defines a pending test case.

&block is never evaluated. It can be used to describe behaviour that is not yet implemented.

Example:

    require "spec"

    pending "check cat" { cat.alive? }

It is usually used inside a `#describe` or `#context` section.

If `focus` is `true`, only this test, and others marked with `focus: true`, will run.

def pending(description = "assert", file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil) #

Defines a yet-to-be-implemented pending test case

If `focus` is `true`, only this test, and others marked with `focus: true`, will run.

def pending!(msg = "Cannot run example", file = __FILE__, line = __LINE__) #

Marks the current example pending

In case an example needs to be pending on some condition that requires executing it, this allows to mark it as such rather than letting it fail or never run.

    require "spec"

    it "test git" do
      cmd = Process.find_executable("git")
      pending!("git is not available") unless cmd
      cmd.should end_with("git")
    end