Custom Matchers¶
One of the goals of Counterpart is to make it easy to create custom matchers. The Counterpart\Matcher interface only contains two methods: matches and __toString.
Let’s make a custom matcher that checks to see if a value is in a range.
<?php
namespace Acme\CounterpartExample;
use Counterpart\Matcher;
/**
* Matches a value if its between $min and $max
*/
class RangeMatcher implements Matcher
{
private $min;
private $max;
public function __construct($min, $max)
{
$this->min = $min;
$this->max = $max;
}
/**
* Matches checks an actual value against the expectations.
*/
public function matches($actual)
{
return $actual > $this->min && $actual < $this->max;
}
/**
* This should return a textual description of the what the matcher
* is trying to accomplish.
*/
public function __toString()
{
return sprintf('is a value between %d and %d', $this->min, $this->max);
}
}
Better Negation Messages¶
By default Counterpart’s LogicalNot will replace the starting is in a matchers description with is not. That’s not always so great for generating a negation error message.
For a more customized negative message, a matcher can implement Counterpart\Negative.
<?php
namespace Acme\CounterpartExample;
use Counterpart\Matcher;
use Counterpart\Negative;
/**
* Matches a value if its between $min and $max
*/
class RangeMatcher implements Matcher, Negative
{
// all the stuff above
/**
* `LogicalNot` will call this this to generate a nice negative message.
*/
public function negativeMessage()
{
// this is what Counterpart would have done anyway
return sprintf('is not a value between %d and %d', $this->min, $this->max);
}
}
Mismatch Descriptions¶
When Counterpart does assertions it will call a matchers __toString method as part of the error description. Sometimes this isn’t enough – sometimes it doesn’t provide enough context for the user or developer to take action.
Custom matchers may implement Counterpart\Describer to generate a more thorough description of a mismatch.
<?php
namespace Acme\CounterpartExample;
use Counterpart\Matcher;
use Counterpart\Negative;
use Counterpart\Describer;
/**
* Matches a value if its between $min and $max
*/
class RangeMatcher implements Matcher, Negative, Describer
{
// all the stuff above
/**
* `Counterpart\Assert::assertThat` will call this method to to generate
* a more thorough error description.
*/
public function describeMismatch($actual)
{
if ($actual < $this->min) {
return 'the value was below the minimum';
}
if ($actual > $this->max) {
return 'the value was above the maximum';
}
// the method doesn't know what to do, so decline to do anything.
return Describer::DECLINE_DESCRIPTION;
}
}
Using Custom Matchers for Assertions¶
Simply pass an instance of the custom matcher as the first argument to Counterpart\Assert::assertThat.
<?php
use Counterpart\Assert;
use Acme\CounterpartExample\RangeMatcher;
$actualValue = 9;
Assert::assertThat(new RangeMatcher(1, 10), $actualValue);