Skip to content

Commit

Permalink
Configurable default matchers
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinMystikJonas committed Jul 16, 2021
1 parent b02619d commit f637498
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,7 @@

## 1.4.4 (TBC)
* Add method that allows defining a set of arguments the mock should yield #1133
* Added option to configure default matchers for objects `\Mockery::getConfiguration()->setDefaultMatcher($class, $matcherClass)` #1120

## 1.4.3 (2021-02-24)
* Fixes calls to fetchMock before initialisation #1113
Expand Down
41 changes: 41 additions & 0 deletions library/Mockery/Configuration.php
Expand Up @@ -74,6 +74,13 @@ public function __construct()
*/
protected $_objectFormatters = array();

/**
* Default argument matchers
*
* @var array
*/
protected $_defaultMatchers = array();

/**
* Set boolean to allow/prevent mocking of non-existent methods
*
Expand Down Expand Up @@ -239,4 +246,38 @@ public function getObjectFormatter($class, $defaultFormatter)
}
return $defaultFormatter;
}

/**
* @param string $class
* @param string $matcherClass
*/
public function setDefaultMatcher($class, $matcherClass)
{
if (!is_a($matcherClass, \Mockery\Matcher\MatcherAbstract::class, true) &&
!is_a($matcherClass, \Hamcrest\Matcher::class, true) &&
!is_a($matcherClass, \Hamcrest_Matcher::class, true)
) {
throw new \InvalidArgumentException(
"Matcher class must be either Hamcrest matcher or extend \Mockery\Matcher\MatcherAbstract, " .
"'$matcherClass' given."
);
}
$this->_defaultMatchers[$class] = $matcherClass;
}

public function getDefaultMatcher($class)
{
$parentClass = $class;
do {
$classes[] = $parentClass;
$parentClass = get_parent_class($parentClass);
} while ($parentClass);
$classesAndInterfaces = array_merge($classes, class_implements($class));
foreach ($classesAndInterfaces as $type) {
if (isset($this->_defaultMatchers[$type])) {
return $this->_defaultMatchers[$type];
}
}
return null;
}
}
6 changes: 6 additions & 0 deletions library/Mockery/Expectation.php
Expand Up @@ -389,6 +389,12 @@ protected function _matchArg($expected, &$actual)
return true;
}
}
if (is_object($expected)) {
$matcher = \Mockery::getConfiguration()->getDefaultMatcher(get_class($expected));
if ($matcher !== null) {
$expected = new $matcher($expected);
}
}
if ($expected instanceof \Mockery\Matcher\MatcherAbstract) {
return $expected->match($actual);
}
Expand Down
88 changes: 88 additions & 0 deletions tests/Mockery/DefaultMatchersTest.php
@@ -0,0 +1,88 @@
<?php
/**
* Mockery
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://github.com/padraic/mockery/master/LICENSE
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to padraic@php.net so we can send you a copy immediately.
*
* @category Mockery
* @package Mockery
* @subpackage UnitTests
* @copyright Copyright (c) 2010 Pádraic Brady (http://blog.astrumfutura.com)
* @license http://github.com/padraic/mockery/blob/master/LICENSE New BSD License
*/

use Mockery\Adapter\Phpunit\MockeryTestCase;

class CustomValueObjectMatcher extends \Mockery\Matcher\MatcherAbstract
{
public function match(&$actual)
{
return $actual->value === $this->_expected->value;
}

public function __toString()
{
return "<customMatcher>";
}
}

interface CustomValueObjectInterface
{
}

class CustomValueObject implements CustomValueObjectInterface
{
public $value;

public function __construct($value)
{
$this->value = $value;
}
}

class DefaultMatchersTest extends MockeryTestCase
{
public function mockeryTestSetUp()
{
parent::mockeryTestSetUp();
$this->mock = mock('foo');
}


public function mockeryTestTearDown()
{
\Mockery::getConfiguration()->allowMockingNonExistentMethods(true);
parent::mockeryTestTearDown();
}

/** Just a quickie roundup of a few Hamcrest matchers to check nothing obvious out of place **/

public function testDefaultMatcherHamcrest()
{
\Mockery::getConfiguration()->setDefaultMatcher(\DateTime::class, \Hamcrest\Core\IsEqual::class);
$this->mock->shouldReceive('foo')->with(new DateTime("2000-01-01"))->once();
$this->mock->foo(new DateTime("2000-01-01"));
}

public function testDefaultMatcherClass()
{
\Mockery::getConfiguration()->setDefaultMatcher(CustomValueObject::class, CustomValueObjectMatcher::class);
$this->mock->shouldReceive('foo')->with(new CustomValueObject("expected"))->once();
$this->mock->foo(new CustomValueObject("expected"));
}

public function testDefaultMatcherInterface()
{
\Mockery::getConfiguration()->setDefaultMatcher(CustomValueObjectInterface::class, CustomValueObjectMatcher::class);
$this->mock->shouldReceive('foo')->with(new CustomValueObject("expected2"))->once();
$this->mock->foo(new CustomValueObject("expected2"));
}
}

0 comments on commit f637498

Please sign in to comment.