# Matchers

Verde uses matchers to validate the expected.

# Methods

# Not

Negates the assertion that follows in the chain.

<?php

use function Verde\expect;

expect(43)->not()->toBe(42);

# Reference

# toBe(value)

toBe compares the received and expected values using the === identical operator.

<?php

use function Verde\expect;

test('The Answer to Everything is 42', function() {
    $answer = 42;
    $everything = [
        'answer' => 42,
    ];

    expect($answer)->toBe(42);
    expect($everything)->toBe(['answer' => 42]);
});

NOTE: Don't use toBe with floating-point numbers. For example, due to rounding, in PHP 0.2 + 0.1 is not strictly equal to 0.3. If you have floating-point numbers, try toBeCloseTo instead.

# toBeCloseTo(number, ?digits)

Use toBeCloseTo to compare floating-point numbers for approximate equality.

The optional digits argument limits the number of digits to check after the decimal point. For the default value 2, the test criterion is Math.abs(expected - received) < 0.005 (that is, 10 ** -2 / 2). Intuitive equality comparisons often fail, because arithmetic on decimal (base 10) values often have rounding errors in limited precision binary (base 2) representation. For example, this test fails:

<?php

expect(0.2 + 0.1)->toBe(0.3); // Fails!

It fails because of the Floating point precision So, toBeCloseTo solve this kind of problem by comparing the error between the expected and received number.

<?php

expect(0.2 + 0.1)->toBeCloseTo(0.3); // pass
expect(0.5 / 0.6)->toBeCloseTo(0.83, 3); // pass (we limit the check to the first 3 digits)

# toBeCountable()

Use toBeCountable to check that the received value is coutable. This matcher uses is_coutable underneath.

<?php

use function Verde\expect;

expect([1, 2, 3]])->toBeCountable();
expect(new ArrayIterator(['foo', 'bar', 'baz']))->toBeCountable();

# toBeFalse()

Use toBeFalse to check that the received value is identical to false.

<?php

use function Verde\expect;

expect(false)->toBeFalse();
expect(0)->not()->toBeFalse();
expect("")->not()->toBeFalse();

# toBeFalsy()

Use toBeFalsy to loosely compare if received == false.

<?php

use function Verde\expect;

expect(0)->toBeFalsy();
expect("")->toBeFalsy();
expect(false)->toBeFalsy();

For more info: PHP type comparison tables

# toBeFinite()

Use toBeFinite to check whether the received value is a legal finite number or not.

<?php

use function Verde\expect;

$finite = 42;
$infinite = log(0);
$nan = acos(2);

expect($finite)->toBeFinite();
expect($infinite)->not()->toBeFinite();
expect($nan)->not()->toBeFinite();

# toBeGreaterThan(value)

Use toBeGreaterThan to compare received > expected for number values.

<?php

use function Verde\expect;

test('ounces per can is at least 10', function() {
    expect(ouncesPerCan())->toBeGreaterThan(10);
});

# toBeGreaterThanOrEqual(value)

Use toBeGreaterThan to compare received >= expected for number values.

<?php

use function Verde\expect;

test('ounces per can is at least 12', function() {
    expect(ouncesPerCan())->toBeGreaterThanOrEqual(12);
});

# toBeInstanceOf(class)

Use toBeInstanceOf(class) to check that the received value is an instance of class. This matcher uses instanceof underneath.

<?php

use function Verde\expect;

class A {}

expect(new A())->toBeInstanceOf(A::class);

# toBeLessThan(value)

Use toBeLessThan to compare received < expected for number values.

<?php

use function Verde\expect;

test('ounces per can is at least 20', function() {
    expect(ouncesPerCan())->toBeLessThan(20);
});

# toBeLessThanOrEqual(value)

Use toBeLessThanOrEqual to compare received <= expected for number values.

<?php

use function Verde\expect;

test('ounces per can is at least 12', function() {
    expect(ouncesPerCan())->toBeLessThanOrEqual(12);
});

# toBeNaN()

Use toBeNaN to check that the received value is a NaN. This matcher uses is_nan underneath.

<?php

use function Verde\expect;

expect(asin(2))->toBeNaN();

# toBeNegativeInfinity()

Use toBeNegativeInfinity() to check that received === -INF

<?php

use function Verde\expect;

expect(log(0))->toBeNegativeInfinity();

# toBeNull()

Use toBeNull() to check that received === null. This matcher uses is_null underneath.

<?php

use function Verde\expect;

expect(doSomething())->toBeNull();

# toBePositiveInfinity()

Use toBePositiveInfinity() to check that received === +INF

<?php

use function Verde\expect;

expect(-log(0))->toBePositiveInfinity();

# toBeTrue()

Use toBeTrue to check that the received value is identical to true.

<?php

use function Verde\expect;

expect(true)->toBeTrue();
expect(1)->not()->toBeTrue();

# toBeTruthy()

Use toBeTruthy to loosely check if received == true.

<?php

use function Verde\expect;

expect(1)->toBeTruthy();
expect("-1")->toBeTruthy();
expect("php")->toBeTruthy();

# toContain(value)

Use toContain to check if the received string or array contains the expected value.

<?php

use function Verde\expect;

expect("hello world")->toContain("o w");
expect(['hello', 'world'])->toContain('hello');

# toCount(value)

Use toCount to compare to check that the size of received array.

<?php

use function Verde\expect;

expect(['hello', 'world'])->toCount(2);

# toHaveBeenCalled()

Use toHaveBeenCalled to ensure that the mock/spied function/method has been called.

So, let's say have a getPizzaIngredients(string $name, callable $getIngredients) function that takes a string and a callback as arguments. We might want to make sure that the callback gets called at least once whe the name is unknown.

<?php

use function Verde\expect;

function getPizzaIngredients(string $name, callable $getIngredients) {
    $pizze = [
        'Margherita' => ['Mozzarella', 'Pomodoro'],
        'Napolitana' => ['Origano', 'Mozzarella']
    ];

    return $pizze[$name] ?? $getIngredients();
}

test('gets the custom ingredients when the pizza is not in the menu', function() {
    $getIngredients = func();

    getPizzaIngredients('Diavola', $getIngredients->getCallable());

    expect($getIngredients)->toHaveBeenCalled();
});

NOTE: For more information about func have a look at mock function

# toHaveBeenCalledBefore(spy)

Use toHaveBeenCalledBefore to ensure that the mock/spiy function/method has been called before another spy.

So, let's say have a getPizzaIngredients(string $name, callable $getIngredients) function that takes a string and a callback as arguments. We might want to make sure that the callback gets called at least once whe the name is unknown.

<?php

use function Verde\expect;
use function Verde\spyOn;

function makePizza() {
    $ingredients = getPizzaIngredients();

    bakePizza($ingredients);
}

test('gets the pizza ingredients before baking it', function() {
    $getIngredients = spyOn('getIngredients');
    $bakePizza = spyOn('bakePizza');

    makePizza();

    expect($bakePizza)->toHaveBeenCalledBefore($getIngredients);
});

NOTE: For more information about spyOn have a look at Spies

# toHaveBeenCalledTimes(value)

Use toHaveBeenCalledTimes to ensure that a mock function got called exact number of times.

In this example we want be sure our mock function gets called only once:

<?php

use Verde\Func;
use function Verde\expect;

function getPizzaIngredients(string $name, callable $getIngredients) {
    $pizze = [
        'Margherita' => ['Mozzarella', 'Pomodoro'],
        'Napolitana' => ['Origano', 'Mozzarella']
    ];

    return $pizze[$name] ?? $getIngredients();
}

test('gets the custom ingredients when the pizza is not in the menu', function() {
    $getIngredients = func();

    getPizzaIngredients('Diavola', $getIngredients->getCallable());

    expect($getIngredients)->toHaveBeenCalledTimes(1);
});

# toHaveBeenCalledWith(...$arguments)

Use toHaveBeenCalledWith to ensure that a mock function got called, at least once, with specific arguments.

toHaveBeenCalledWith can be also used to make sure that the mock function has been called without any arguments:

<?php

use Verde\Func;
use function Verde\expect;

function getPizzaIngredients(string $name, callable $getIngredients) {
    $pizze = [
        'Margherita' => ['Mozzarella', 'Pomodoro'],
        'Napolitana' => ['Origano', 'Mozzarella']
    ];

    return $pizze[$name] ?? $getIngredients();
}

test('gets the custom ingredients when the pizza is not in the menu', function() {
    $getIngredients = func();

    getPizzaIngredients('Diavola', $getIngredients->getCallable());

    expect($getIngredients)->toHaveBeenCalledWith();
});

toHaveBeenCalledWith check through all the callback invocations to see if the parameters of any them matches the expectation:

<?php

use Verde\Func;
use function Verde\expect;

function doSomething(callable $callback, $customArgs = null) {
    return $callback($customArgs ?? ['hello', 'world']);
}

test('checks that the parameters of any callback invocation', function() {
    $callback = func();
    doSomething($callback->getCallable());
    doSomething($callback->getCallable(), 'This is custom');

    expect($callback)->toHaveBeenCalledWith(['hello', 'world']);
    expect($callback)->toHaveBeenCalledWith('This is custom');
});

toHaveBeenCalledWith you can also check that your mock function has been called with ANY function or array using a special constant:

<?php

use Verde\ANY;
use function Verde\expect;

function doSomething(callable $callback, $customArgs = null) {
    return $callback($customArgs);
}

test('checks that the mock is called with a function', function() {
    $callback = func();
    doSomething($callback->getCallable(), function() { return 42; });

    expect($callback)->toHaveBeenCalledWith(ANY::FUNCTION);
});

test('checks that the mock is called with an array', function() {
    $callback = func();
    doSomething($callback->getCallable(), [1, 2, 3]);

    expect($callback)->toHaveBeenCalledWith(ANY::ARRAY);
});

# toHaveBeenNthCalledWith(nthTime, ...$arguments)

If you have a mock function, you can use .toHaveBeenNthCalledWith to test what arguments it was nth called with.

<?php

$func = func();
$callable = $func->getCallable();

$callable(123);
$callable(42);

expect($func)->toHaveBeenNthCalledWith(1, 123);
expect($func)->toHaveBeenNthCalledWith(2, 42);

# toHaveLength(length)

Use toHaveLength to check that the size of an array, or the length of a string, is a certain numeric value.

<?php

expect("Ciao")->toHaveLength(4);
expect([1,2, 3])->toHaveLength(3);
expect("")->not()->toHaveLength(42);

# toHaveMethod(name)

Use toHaveMethod to check that the class method exists. This matcher uses method_exists underneath.

<?php

expect(Dummy::class)->toHaveMethod('doSomething');

# toThrow(?message)

Use toThrow to test that a function throws when it is called. For example, if we want to test that getPizzaIngredients throws an error when the pizza is unknown.

<?php

function getPizzaIngredients(string $name) {
    $pizze = [
        'Margherita' => ['Mozzarella', 'Pomodoro'],
        'Napolitana' => ['Origano', 'Mozzarella']
    ];

    return $pizze[$name] ?? throw new Error("Ingredients not found")
}

it("throws the error when we don't know the ingredients for the pizza requested", function() {
    expect(function() {
        return getPizzaIngredients('Diavola');
    })->toThrow();

    /**
     * You can provide an optional argument to test that a specific error  message is thrown:
     */
    expect(function() {
        return getPizzaIngredients('Diavola');
    })->toThrow("Ingredients not found");
})

NOTE: This method checks only the error message. If you want to check the type of Error thrown, use toThrowError.

# toThrowError(errorClass, ?message)

Use toThrowError to test that a function throws a specific error class when it is called. The difference with the toThrow is this method does also check that the error class thrown matches the expectation. For example, if we want to test that getPizzaIngredients throws an error when the pizza is unknown.

<?php

function getPizzaIngredients(string $name) {
    $pizze = [
        'Margherita' => ['Mozzarella', 'Pomodoro'],
        'Napolitana' => ['Origano', 'Mozzarella']
    ];

    return $pizze[$name] ?? throw new PizzaUnknown(name + " not found")
}

it("throws the IngredientsNotFound error when we don't know the ingredients for the pizza requested", function() {
    expect(function() {
        return getPizzaIngredients('Diavola');
    })->toThrowError(PizzaUnknown::class);

    /**
     * You can provide an optional argument to test that a specific error  message is thrown:
     */
    expect(function() {
        return getPizzaIngredients('Diavola');
    })->toThrowError(PizzaUnknown::class, "Diavola not found");
})