From 191b4618ebc43e2140fd6d512657b3c4bc7ca8ad Mon Sep 17 00:00:00 2001 From: Norbert Orzechowicz Date: Thu, 17 Apr 2014 11:08:35 +0200 Subject: [PATCH 1/4] Removed useless file --- src/autoload.php | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 src/autoload.php diff --git a/src/autoload.php b/src/autoload.php deleted file mode 100644 index f55914de..00000000 --- a/src/autoload.php +++ /dev/null @@ -1,26 +0,0 @@ - Date: Thu, 17 Apr 2014 11:25:56 +0200 Subject: [PATCH 2/4] Rename wildcard matcher pattern --- src/JsonMatcher/Matcher/WildcardMatcher.php | 2 +- .../Matcher/WildcardMatcherTest.php | 25 ++++++++++++++++++- tests/JsonMatcher/MatcherTest.php | 2 +- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/JsonMatcher/Matcher/WildcardMatcher.php b/src/JsonMatcher/Matcher/WildcardMatcher.php index 1c16c027..72d474d4 100644 --- a/src/JsonMatcher/Matcher/WildcardMatcher.php +++ b/src/JsonMatcher/Matcher/WildcardMatcher.php @@ -17,7 +17,7 @@ public function match($matcher, $pattern) */ public function canMatch($pattern) { - return '*' === $pattern; + return is_string($pattern) && 0 !== preg_match("/^@(\*|wildcard)@$/", $pattern); } } diff --git a/tests/JsonMatcher/Matcher/WildcardMatcherTest.php b/tests/JsonMatcher/Matcher/WildcardMatcherTest.php index f48d0a39..528eb2cf 100644 --- a/tests/JsonMatcher/Matcher/WildcardMatcherTest.php +++ b/tests/JsonMatcher/Matcher/WildcardMatcherTest.php @@ -9,12 +9,27 @@ class WildcardMatcherTest extends \PHPUnit_Framework_TestCase /** * @dataProvider data */ - public function test_type_placeholders($pattern) + public function test_positive_match($pattern) { $matcher = new WildcardMatcher(); $this->assertTrue($matcher->match('*', $pattern)); } + /** + * @dataProvider positivePatterns + */ + public function test_positive_can_match($pattern) + { + $matcher = new WildcardMatcher(); + $this->assertTrue($matcher->canMatch($pattern)); + } + + public function test_negative_can_match() + { + $matcher = new WildcardMatcher(); + $this->assertFalse($matcher->canMatch('*')); + } + public static function data() { return array( @@ -26,4 +41,12 @@ public static function data() array(new \stdClass), ); } + + public static function positivePatterns() + { + return array( + array("@*@"), + array("@wildcard@"), + ); + } } diff --git a/tests/JsonMatcher/MatcherTest.php b/tests/JsonMatcher/MatcherTest.php index ab9f061a..87cecfcf 100644 --- a/tests/JsonMatcher/MatcherTest.php +++ b/tests/JsonMatcher/MatcherTest.php @@ -66,7 +66,7 @@ public function test_matcher_with_array_value() ) ), 'readyToUse' => true, - 'data' => '*', + 'data' => '@wildcard@', ) )); } From 5fd095daa6470a9c91e6de0609f40da034abbf13 Mon Sep 17 00:00:00 2001 From: Norbert Orzechowicz Date: Thu, 17 Apr 2014 12:09:18 +0200 Subject: [PATCH 3/4] Added json matcher --- src/JsonMatcher/Matcher/JsonMatcher.php | 45 +++++++ tests/JsonMatcher/Matcher/JsonMatcherTest.php | 111 ++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 src/JsonMatcher/Matcher/JsonMatcher.php create mode 100644 tests/JsonMatcher/Matcher/JsonMatcherTest.php diff --git a/src/JsonMatcher/Matcher/JsonMatcher.php b/src/JsonMatcher/Matcher/JsonMatcher.php new file mode 100644 index 00000000..88798b3d --- /dev/null +++ b/src/JsonMatcher/Matcher/JsonMatcher.php @@ -0,0 +1,45 @@ +matcher = $matcher; + } + + /** + * {@inheritDoc} + */ + public function match($value, $pattern) + { + if (!is_string($value) || !$this->isValidJson($value)) { + return false; + } + + return $this->matcher->match(json_decode($value, true), json_decode($pattern, true)); + } + + /** + * {@inheritDoc} + */ + public function canMatch($pattern) + { + return is_string($pattern) && $this->isValidJson($pattern); + } + + private function isValidJson($string) + { + @json_decode($string, true); + return (json_last_error() == JSON_ERROR_NONE); + } +} diff --git a/tests/JsonMatcher/Matcher/JsonMatcherTest.php b/tests/JsonMatcher/Matcher/JsonMatcherTest.php new file mode 100644 index 00000000..b24ca1d1 --- /dev/null +++ b/tests/JsonMatcher/Matcher/JsonMatcherTest.php @@ -0,0 +1,111 @@ +matcher = new JsonMatcher(new ChainMatcher(array( + $scalarMatchers, + new ArrayMatcher($scalarMatchers) + ))); + } + + /** + * @dataProvider positivePatterns + */ + public function test_positive_can_match($pattern) + { + $this->assertTrue($this->matcher->canMatch($pattern)); + } + + /** + * @dataProvider negativePatterns + */ + public function test_negative_can_match() + { + $this->assertFalse($this->matcher->canMatch('*')); + } + + /** + * @dataProvider positiveMatches + */ + public function test_positive_matches($value, $pattern) + { + $this->assertTrue($this->matcher->match($value, $pattern)); + } + + /** + * @dataProvider negativeMatches + */ + public function test_negative_matches($value, $pattern) + { + $this->assertFalse($this->matcher->match($value, $pattern)); + } + + public static function positivePatterns() + { + return array( + array(json_encode(array('Norbert', 'Michał'))), + array(json_encode(array('Norbert', '@string@'))), + array(json_encode('test')), + ); + } + + public static function negativePatterns() + { + return array( + array('["Norbert",@string@]'), + array('["Norbert", '), + ); + } + + public static function positiveMatches() + { + return array( + array( + '{"users":["Norbert","Michał"]}', + '{"users":["@string@","@string@"]}' + ), + array( + '{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":["ROLE_USER"]}]}', + '{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":["@wildcard@"]}]}' + ) + ); + } + + public static function negativeMatches() + { + return array( + array( + '{"users":["Norbert","Michał"]}', + '{"users":["Michał","@string@"]}' + ), + array( + '{this_is_not_valid_json', + '{"users":["Michał","@string@"]}' + ), + array( + array(), + '[]' + ) + ); + } +} From a5c39142b80a9b2fdb5959583a82075436bb4e69 Mon Sep 17 00:00:00 2001 From: Norbert Orzechowicz Date: Thu, 17 Apr 2014 13:37:07 +0200 Subject: [PATCH 4/4] JsonMatcher introduction --- src/JsonMatcher/Matcher/ArrayMatcher.php | 102 ++++++++++++------ src/JsonMatcher/Matcher/TypeMatcher.php | 4 +- .../JsonMatcher/Matcher/ArrayMatcherTest.php | 25 ++++- tests/JsonMatcher/Matcher/JsonMatcherTest.php | 4 +- tests/JsonMatcher/Matcher/TypeMatcherTest.php | 9 +- 5 files changed, 100 insertions(+), 44 deletions(-) diff --git a/src/JsonMatcher/Matcher/ArrayMatcher.php b/src/JsonMatcher/Matcher/ArrayMatcher.php index 0886d6b2..f7887f7d 100644 --- a/src/JsonMatcher/Matcher/ArrayMatcher.php +++ b/src/JsonMatcher/Matcher/ArrayMatcher.php @@ -4,6 +4,7 @@ use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException; +use Symfony\Component\PropertyAccess\PropertyAccessor; class ArrayMatcher implements PropertyMatcher { @@ -14,6 +15,11 @@ class ArrayMatcher implements PropertyMatcher private $paths; + /** + * @var PropertyAccessor + */ + private $accessor; + public function __construct(PropertyMatcher $propertyMatcher) { $this->propertyMatcher = $propertyMatcher; @@ -24,60 +30,94 @@ public function __construct(PropertyMatcher $propertyMatcher) */ public function match($value, $pattern) { - $accessorBuilder = PropertyAccess::createPropertyAccessorBuilder(); - $accessorBuilder->enableExceptionOnInvalidIndex(); - $accessor = $accessorBuilder->getPropertyAccessor(); + if (!is_array($value)) { + return false; + } + + if (false === $this->iterateMatch($value, $pattern)) { + return false; + } + + return true; + } - $this->paths = array(); + /** + * {@inheritDoc} + */ + public function canMatch($pattern) + { + return is_array($pattern); + } + + /** + * @param array $value + * @param array $pattern + * @return bool + */ + private function iterateMatch(array $value, array $pattern) + { foreach ($value as $key => $element) { $path = sprintf("[%s]", $key); - if (is_array($element)) { - $this->buildPath($element, $path); - continue; + if (!$this->hasValue($pattern, $path)) { + return false; + } + $elementPattern = $this->getValue($pattern, $path); + if ($this->propertyMatcher->canMatch($elementPattern)) { + if (true === $this->propertyMatcher->match($element, $elementPattern)) { + continue; + } } - $this->paths[] = $path; - } - - foreach ($this->paths as $path) { - $elementValue = $accessor->getValue($value, $path); - try { - $patternValue = $accessor->getValue($pattern, $path); - } catch (NoSuchIndexException $e) { + if (!is_array($element)) { return false; } - if ($this->propertyMatcher->canMatch($patternValue)) { - if (false === $this->propertyMatcher->match($elementValue, $patternValue)) { - return false; - } + if (false === $this->iterateMatch($element, $elementPattern)) { + return false; } + } + } + /** + * @param $array + * @param $path + * @return bool + */ + private function hasValue($array, $path) + { + try { + $this->getPropertyAccessor()->getValue($array, $path); + } catch (NoSuchIndexException $e) { + return false; } return true; } /** - * {@inheritDoc} + * @param $array + * @param $path + * @return mixed */ - public function canMatch($pattern) + private function getValue($array, $path) { - return is_array($pattern); + return $this->getPropertyAccessor()->getValue($array, $path); } - private function buildPath(array $array, $parentPath) + /** + * @return \Symfony\Component\PropertyAccess\PropertyAccessorInterface + */ + private function getPropertyAccessor() { - foreach ($array as $key => $element) { - $path = sprintf("%s[%s]", $parentPath, $key); + if (isset($this->accessor)) { + return $this->accessor; + } - if (is_array($element)) { - $this->buildPath($element, $path); - continue; - } + $accessorBuilder = PropertyAccess::createPropertyAccessorBuilder(); + $accessorBuilder->enableExceptionOnInvalidIndex(); + $this->accessor = $accessorBuilder->getPropertyAccessor(); - $this->paths[] = $path; - } + return $this->accessor; } } diff --git a/src/JsonMatcher/Matcher/TypeMatcher.php b/src/JsonMatcher/Matcher/TypeMatcher.php index e358abe4..171fbf70 100644 --- a/src/JsonMatcher/Matcher/TypeMatcher.php +++ b/src/JsonMatcher/Matcher/TypeMatcher.php @@ -4,7 +4,6 @@ class TypeMatcher implements PropertyMatcher { - /** * {@inheritDoc} */ @@ -18,12 +17,11 @@ public function match($value, $pattern) */ public function canMatch($pattern) { - return is_string($pattern) && 0 !== preg_match("/^@(string|integer|boolean|double)@$/", $pattern); + return is_string($pattern) && 0 !== preg_match("/^@(string|integer|boolean|double|array)@$/", $pattern); } private function extractType($pattern) { return str_replace("@", "", $pattern); } - } diff --git a/tests/JsonMatcher/Matcher/ArrayMatcherTest.php b/tests/JsonMatcher/Matcher/ArrayMatcherTest.php index 6e17def4..da31498d 100644 --- a/tests/JsonMatcher/Matcher/ArrayMatcherTest.php +++ b/tests/JsonMatcher/Matcher/ArrayMatcherTest.php @@ -4,16 +4,31 @@ use JsonMatcher\Matcher\ArrayMatcher; use JsonMatcher\Matcher\ChainMatcher; use JsonMatcher\Matcher\ScalarMatcher; +use JsonMatcher\Matcher\WildcardMatcher; class ArrayMatcherTest extends \PHPUnit_Framework_TestCase { + /** + * @var ArrayMatcher + */ + private $matcher; + + public function setUp() + { + $this->matcher = new ArrayMatcher( + new ChainMatcher(array( + new ScalarMatcher(), + new WildcardMatcher() + )) + ); + } + /** * @dataProvider positiveMatchData */ public function test_positive_match_arrays($value, $pattern) { - $matcher = new ArrayMatcher(new ScalarMatcher()); - $this->assertTrue($matcher->match($value, $pattern)); + $this->assertTrue($this->matcher->match($value, $pattern)); } /** @@ -21,8 +36,7 @@ public function test_positive_match_arrays($value, $pattern) */ public function test_negative_match_arrays($value, $pattern) { - $matcher = new ArrayMatcher(new ScalarMatcher()); - $this->assertFalse($matcher->match($value, $pattern)); + $this->assertFalse($this->matcher->match($value, $pattern)); } public static function positiveMatchData() @@ -48,7 +62,8 @@ public static function positiveMatchData() array($simpleArr, $simpleArr), array(array(), array()), array(array('key' => 'val'), array('key' => 'val')), - array(array(1), array(1)) + array(array(1), array(1)), + array(array('roles' => array('ROLE_ADMIN', 'ROLE_DEVELOPER')), array('roles' => '@wildcard@')) ); } diff --git a/tests/JsonMatcher/Matcher/JsonMatcherTest.php b/tests/JsonMatcher/Matcher/JsonMatcherTest.php index b24ca1d1..8967cd0c 100644 --- a/tests/JsonMatcher/Matcher/JsonMatcherTest.php +++ b/tests/JsonMatcher/Matcher/JsonMatcherTest.php @@ -85,8 +85,8 @@ public static function positiveMatches() '{"users":["@string@","@string@"]}' ), array( - '{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":["ROLE_USER"]}]}', - '{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":["@wildcard@"]}]}' + '{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":["ROLE_USER", "ROLE_DEVELOPER"]}]}', + '{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":"@wildcard@"}]}' ) ); } diff --git a/tests/JsonMatcher/Matcher/TypeMatcherTest.php b/tests/JsonMatcher/Matcher/TypeMatcherTest.php index b424e152..52a51280 100644 --- a/tests/JsonMatcher/Matcher/TypeMatcherTest.php +++ b/tests/JsonMatcher/Matcher/TypeMatcherTest.php @@ -47,7 +47,8 @@ public static function positiveCanMatchData() array("@integer@"), array("@string@"), array("@boolean@"), - array("@double@") + array("@double@"), + array("@array@") ); } @@ -57,7 +58,8 @@ public static function positiveMatchData() array(false, "@boolean@"), array("Norbert", "@string@"), array(1, "@integer@"), - array(6.66, "@double@") + array(6.66, "@double@"), + array(array('test'), '@array@') ); } @@ -79,7 +81,8 @@ public static function negativeMatchData() array("test", "@boolean@"), array(new \stdClass, "@string@"), array(1.1, "@integer@"), - array(false, "@double@") + array(false, "@double@"), + array(1, "@array@") ); } }