Skip to content

Commit

Permalink
Merge pull request #766 from MartinMystikJonas/custom-object-formatters
Browse files Browse the repository at this point in the history
Custom object formatters
  • Loading branch information
davedevelopment committed Feb 24, 2021
2 parents 59a0cd9 + 8030081 commit 4198c03
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 4 deletions.
24 changes: 20 additions & 4 deletions library/Mockery.php
Expand Up @@ -662,10 +662,22 @@ private static function objectToArray($object, $nesting = 3)
return array('...');
}

return array(
'class' => get_class($object),
'properties' => self::extractInstancePublicProperties($object, $nesting)
$defaultFormatter = function ($object, $nesting) {
return array('properties' => self::extractInstancePublicProperties($object, $nesting));
};

$class = get_class($object);

$formatter = self::getConfiguration()->getObjectFormatter($class, $defaultFormatter);

$array = array(
'class' => $class,
'identity' => '#' . md5(spl_object_hash($object))
);

$array = array_merge($array, $formatter($object, $nesting));

return $array;
}

/**
Expand All @@ -685,7 +697,11 @@ private static function extractInstancePublicProperties($object, $nesting)
foreach ($properties as $publicProperty) {
if (!$publicProperty->isStatic()) {
$name = $publicProperty->getName();
$cleanedProperties[$name] = self::cleanupNesting($object->$name, $nesting);
try {
$cleanedProperties[$name] = self::cleanupNesting($object->$name, $nesting);
} catch (\Exception $exception) {
$cleanedProperties[$name] = $exception->getMessage();
}
}
}

Expand Down
28 changes: 28 additions & 0 deletions library/Mockery/Configuration.php
Expand Up @@ -67,6 +67,13 @@ public function __construct()
$this->_quickDefinitionsConfiguration = new QuickDefinitionsConfiguration();
}

/**
* Custom object formatters
*
* @var array
*/
protected $_objectFormatters = array();

/**
* Set boolean to allow/prevent mocking of non-existent methods
*
Expand Down Expand Up @@ -211,4 +218,25 @@ public function reflectionCacheEnabled()
{
return $this->_reflectionCacheEnabled;
}

public function setObjectFormatter($class, $formatterCallback)
{
$this->_objectFormatters[$class] = $formatterCallback;
}

public function getObjectFormatter($class, $defaultFormatter)
{
$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->_objectFormatters[$type])) {
return $this->_objectFormatters[$type];
}
}
return $defaultFormatter;
}
}
196 changes: 196 additions & 0 deletions tests/Mockery/WithCustomFormatterExpectationTest.php
@@ -0,0 +1,196 @@
<?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 PHPUnit\Framework\TestCase;

class WithCustomFormatterExpectationTest extends TestCase
{
public function setUp(): void
{
\Mockery::getConfiguration()->setObjectFormatter(
'ClassWithCustomFormatter',
function ($object, $nesting) {
return array(
"formatter" => 'ClassWithCustomFormatter',
"properties" => array(
"stringProperty" => $object->stringProperty
),
"getters" => array(
"gettedProperty" => $object->getArrayProperty()
)
);
}
);
\Mockery::getConfiguration()->setObjectFormatter(
'InterfaceWithCustomFormatter',
function ($object, $nesting) {
return array(
"formatter" => 'InterfaceWithCustomFormatter',
"properties" => array(
"stringProperty" => $object->stringProperty
),
"getters" => array(
"gettedProperty" => $object->getArrayProperty()
)
);
}
);
}

/**
* @dataProvider getObjectFormatterDataProvider
*/
public function testGetObjectFormatter($object, $expected)
{
$defaultFormatter = function ($class, $nesting) {
return null;
};

$formatter = \Mockery::getConfiguration()->getObjectFormatter(get_class($object), $defaultFormatter);
$formatted = $formatter($object, 1);

$this->assertEquals(
$expected,
$formatted ? $formatted['formatter'] : null
);
}

public function getObjectFormatterDataProvider()
{
return array(
array(
new \StdClass(),
null
),
array(
new ClassWithoutCustomFormatter(),
null
),
array(
new ClassWithCustomFormatter(),
'ClassWithCustomFormatter'
),
array(
new ClasschildOfWithCustomFormatter(),
'ClassWithCustomFormatter'
),
array(
new ClassImplementsWithCustomFormatter(),
'InterfaceWithCustomFormatter'
)
);
}

/**
* @dataProvider formatObjectsDataProvider
*/
public function testFormatObjects($obj, $shouldContains, $shouldNotContains)
{
$string = Mockery::formatObjects(array($obj));
foreach ($shouldContains as $containString) {
$this->assertStringContainsString($containString, $string);
}
foreach ($shouldNotContains as $containString) {
$this->assertStringNotContainsString($containString, $string);
}
}

public function formatObjectsDataProvider()
{
return array(
array(
new ClassWithoutCustomFormatter(),
array(
'stringProperty',
'numberProperty',
'arrayProperty'
),
array(
'privateProperty'
)
),
array(
new ClassWithCustomFormatter(),
array(
'stringProperty',
'gettedProperty'
),
array(
'numberProperty',
'privateProperty'
)
),
array(
new ClassImplementsWithCustomFormatter(),
array(
'stringProperty',
'gettedProperty'
),
array(
'numberProperty',
'privateProperty'
)
),
);
}
}

class ClassWithoutCustomFormatter
{
public $stringProperty = "a string";
public $numberProperty = 123;
public $arrayProperty = array('a', 'nother', 'array');
private $privateProperty = "private";
}

class ClassWithCustomFormatter
{
public $stringProperty = "a string";
public $numberProperty = 123;
private $arrayProperty = array('a', 'nother', 'array');
private $privateProperty = "private";

public function getArrayProperty()
{
return $this->arrayProperty;
}
}

class ClassChildOfWithCustomFormatter extends ClassWithCustomFormatter
{
}

interface InterfaceWithCustomFormatter
{
}

class ClassImplementsWithCustomFormatter implements InterfaceWithCustomFormatter
{
public $stringProperty = "a string";
public $numberProperty = 123;
private $privateProperty = "private";
private $arrayProperty = array('a', 'nother', 'array');

public function getArrayProperty()
{
return $this->arrayProperty;
}
}

0 comments on commit 4198c03

Please sign in to comment.