From c5088d1cf2c748af8b4bf730b21a6de9c375cdb1 Mon Sep 17 00:00:00 2001 From: martinjonas Date: Sun, 9 Jul 2017 13:15:02 +0200 Subject: [PATCH 1/2] Custom object formatters --- library/Mockery.php | 27 ++- library/Mockery/Configuration.php | 33 ++++ .../WithCustomFormatterExpectationTest.php | 187 ++++++++++++++++++ 3 files changed, 243 insertions(+), 4 deletions(-) create mode 100644 tests/Mockery/WithCustomFormatterExpectationTest.php diff --git a/library/Mockery.php b/library/Mockery.php index 05a384b4e..52663edea 100644 --- a/library/Mockery.php +++ b/library/Mockery.php @@ -662,10 +662,25 @@ private static function objectToArray($object, $nesting = 3) return array('...'); } - return array( - 'class' => get_class($object), - 'properties' => self::extractInstancePublicProperties($object, $nesting) + $class = get_class($object); + $customFormatterClass = self::getConfiguration()->findObjectFormatter($class); + + $array = array( + 'class' => $class, + 'identity' => '#' . md5(spl_object_hash($object)) ); + + if ($customFormatterClass) { + $customFormatter = self::getConfiguration()->getObjectFormatter($customFormatterClass); + $array = array_merge($array, $customFormatter($object)); + } else { + $array = array_merge( + $array, + array('properties' => self::extractInstancePublicProperties($object, $nesting)) + ); + } + + return $array; } /** @@ -685,7 +700,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(); + } } } diff --git a/library/Mockery/Configuration.php b/library/Mockery/Configuration.php index 23e897cdd..8e4c47685 100644 --- a/library/Mockery/Configuration.php +++ b/library/Mockery/Configuration.php @@ -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 * @@ -211,4 +218,30 @@ public function reflectionCacheEnabled() { return $this->_reflectionCacheEnabled; } + + public function setObjectFormatter($class, $formatterCallback) + { + $this->_objectFormatters[$class] = $formatterCallback; + } + + public function findObjectFormatter($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->_objectFormatters[$type])) { + return $type; + } + } + return null; + } + + public function getObjectFormatter($class) + { + return $this->_objectFormatters[$class]; + } } diff --git a/tests/Mockery/WithCustomFormatterExpectationTest.php b/tests/Mockery/WithCustomFormatterExpectationTest.php new file mode 100644 index 000000000..080ca874b --- /dev/null +++ b/tests/Mockery/WithCustomFormatterExpectationTest.php @@ -0,0 +1,187 @@ +setObjectFormatter( + 'ClassWithCustomFormatter', + function ($object) { + return array( + "properties" => array( + "stringProperty" => $object->stringProperty + ), + "getters" => array( + "gettedProperty" => $object->getArrayProperty() + ) + ); + } + ); + \Mockery::getConfiguration()->setObjectFormatter( + 'InterfaceWithCustomFormatter', + function ($object) { + return array( + "properties" => array( + "stringProperty" => $object->stringProperty + ), + "getters" => array( + "gettedProperty" => $object->getArrayProperty() + ) + ); + } + ); + } + + /** + * @dataProvider findObjectFormatterDataProvider + */ + public function testFindObjectFormatter($object, $expected) + { + $this->assertEquals( + $expected, + \Mockery::getConfiguration()->findObjectFormatter(get_class($object)) + ); + } + + public function findObjectFormatterDataProvider() + { + 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; + } +} From 80300813fb4c6aff1d0f829c786cdda124554671 Mon Sep 17 00:00:00 2001 From: Martin Jonas Date: Sun, 24 Jan 2021 22:08:40 +0100 Subject: [PATCH 2/2] Custom formatters refactoring --- library/Mockery.php | 17 +++++++-------- library/Mockery/Configuration.php | 11 +++------- .../WithCustomFormatterExpectationTest.php | 21 +++++++++++++------ 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/library/Mockery.php b/library/Mockery.php index 52663edea..44a5a4b8d 100644 --- a/library/Mockery.php +++ b/library/Mockery.php @@ -662,23 +662,20 @@ private static function objectToArray($object, $nesting = 3) return array('...'); } + $defaultFormatter = function ($object, $nesting) { + return array('properties' => self::extractInstancePublicProperties($object, $nesting)); + }; + $class = get_class($object); - $customFormatterClass = self::getConfiguration()->findObjectFormatter($class); + + $formatter = self::getConfiguration()->getObjectFormatter($class, $defaultFormatter); $array = array( 'class' => $class, 'identity' => '#' . md5(spl_object_hash($object)) ); - if ($customFormatterClass) { - $customFormatter = self::getConfiguration()->getObjectFormatter($customFormatterClass); - $array = array_merge($array, $customFormatter($object)); - } else { - $array = array_merge( - $array, - array('properties' => self::extractInstancePublicProperties($object, $nesting)) - ); - } + $array = array_merge($array, $formatter($object, $nesting)); return $array; } diff --git a/library/Mockery/Configuration.php b/library/Mockery/Configuration.php index 8e4c47685..e5272874a 100644 --- a/library/Mockery/Configuration.php +++ b/library/Mockery/Configuration.php @@ -224,7 +224,7 @@ public function setObjectFormatter($class, $formatterCallback) $this->_objectFormatters[$class] = $formatterCallback; } - public function findObjectFormatter($class) + public function getObjectFormatter($class, $defaultFormatter) { $parentClass = $class; do { @@ -234,14 +234,9 @@ public function findObjectFormatter($class) $classesAndInterfaces = array_merge($classes, class_implements($class)); foreach ($classesAndInterfaces as $type) { if (isset($this->_objectFormatters[$type])) { - return $type; + return $this->_objectFormatters[$type]; } } - return null; - } - - public function getObjectFormatter($class) - { - return $this->_objectFormatters[$class]; + return $defaultFormatter; } } diff --git a/tests/Mockery/WithCustomFormatterExpectationTest.php b/tests/Mockery/WithCustomFormatterExpectationTest.php index 080ca874b..13c3a37e7 100644 --- a/tests/Mockery/WithCustomFormatterExpectationTest.php +++ b/tests/Mockery/WithCustomFormatterExpectationTest.php @@ -27,8 +27,9 @@ public function setUp(): void { \Mockery::getConfiguration()->setObjectFormatter( 'ClassWithCustomFormatter', - function ($object) { + function ($object, $nesting) { return array( + "formatter" => 'ClassWithCustomFormatter', "properties" => array( "stringProperty" => $object->stringProperty ), @@ -40,8 +41,9 @@ function ($object) { ); \Mockery::getConfiguration()->setObjectFormatter( 'InterfaceWithCustomFormatter', - function ($object) { + function ($object, $nesting) { return array( + "formatter" => 'InterfaceWithCustomFormatter', "properties" => array( "stringProperty" => $object->stringProperty ), @@ -54,17 +56,24 @@ function ($object) { } /** - * @dataProvider findObjectFormatterDataProvider + * @dataProvider getObjectFormatterDataProvider */ - public function testFindObjectFormatter($object, $expected) + 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, - \Mockery::getConfiguration()->findObjectFormatter(get_class($object)) + $formatted ? $formatted['formatter'] : null ); } - public function findObjectFormatterDataProvider() + public function getObjectFormatterDataProvider() { return array( array(