Skip to content

Commit 58a6348

Browse files
committed
Merge pull request #20 from norzechowicz/unbounded_array
Fixed unbouded array to work with objects & iterateMatch matehod refactoring
2 parents f8d46c8 + 2820b95 commit 58a6348

File tree

2 files changed

+117
-53
lines changed

2 files changed

+117
-53
lines changed

src/Coduo/PHPMatcher/Matcher/ArrayMatcher.php

Lines changed: 103 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ class ArrayMatcher extends Matcher
1919
*/
2020
private $accessor;
2121

22+
/**
23+
* @param PropertyMatcher $propertyMatcher
24+
*/
2225
public function __construct(PropertyMatcher $propertyMatcher)
2326
{
2427
$this->propertyMatcher = $propertyMatcher;
@@ -49,68 +52,109 @@ public function canMatch($pattern)
4952
}
5053

5154
/**
52-
* @param array $value
53-
* @param array $pattern
55+
* @param array $values
56+
* @param array $patterns
5457
* @param string $parentPath
5558
* @return bool
5659
*/
57-
private function iterateMatch(array $value, array $pattern, $parentPath = "")
60+
private function iterateMatch(array $values, array $patterns, $parentPath = "")
5861
{
59-
$lastPattern = array_values($pattern);
60-
$unboundedMode = end($lastPattern) === self::UNBOUNDED_PATTERN;
62+
$pattern = null;
63+
foreach ($values as $key => $value) {
64+
$path = $this->formatAccessPath($key);
6165

62-
if ($unboundedMode) {
63-
$unboundedPattern = prev($lastPattern);
64-
array_pop($pattern);
65-
}
66-
67-
foreach ($value as $key => $element) {
68-
$path = sprintf("[%s]", $key);
66+
if ($this->shouldSkippValueMatchingFor($pattern)) {
67+
continue;
68+
}
6969

70-
if ($this->hasValue($pattern, $path)) {
71-
$elementPattern = $this->getValue($pattern, $path);
72-
} else if ($unboundedMode) {
73-
$elementPattern = $unboundedPattern;
70+
if ($this->valueExist($path, $patterns)) {
71+
$pattern = $this->getValueByPath($patterns, $path);
7472
} else {
75-
$this->error = sprintf('There is no element under path %s%s in pattern.', $parentPath, $path);
73+
$this->setMissingElementInError('pattern', $this->formatFullPath($parentPath, $path));
7674
return false;
7775
}
7876

79-
if ($this->propertyMatcher->canMatch($elementPattern)) {
80-
if (true === $this->propertyMatcher->match($element, $elementPattern)) {
81-
continue;
82-
}
77+
if ($this->shouldSkippValueMatchingFor($pattern)) {
78+
continue;
8379
}
8480

85-
if (!is_array($element) || !is_array($elementPattern)) {
86-
$this->error = $this->propertyMatcher->getError();
81+
if ($this->valueMatchPattern($value, $pattern)) {
82+
continue;
83+
}
84+
85+
if (!is_array($value) || !$this->canMatch($pattern)) {
8786
return false;
8887
}
8988

90-
if (false === $this->iterateMatch($element, $elementPattern, $parentPath . $path)) {
89+
if (false === $this->iterateMatch($value, $pattern, $this->formatFullPath($parentPath, $path))) {
9190
return false;
9291
}
9392
}
9493

95-
return $this->checkIfPathsFromPatternExistInValue($value, $pattern, $parentPath);
94+
if (!$this->isPatternValid($patterns, $values, $parentPath)) {
95+
return false;
96+
}
97+
98+
return true;
99+
}
100+
101+
/**
102+
* Check if pattern elements exist in value array
103+
*
104+
* @param array $pattern
105+
* @param array $values
106+
* @param $parentPath
107+
* @return bool
108+
*/
109+
private function isPatternValid(array $pattern, array $values, $parentPath)
110+
{
111+
if (is_array($pattern)) {
112+
$notExistingKeys = array_diff_key($pattern, $values);
113+
114+
if (count($notExistingKeys) > 0) {
115+
$keyNames = array_keys($notExistingKeys);
116+
$path = $this->formatFullPath($parentPath, $this->formatAccessPath($keyNames[0]));
117+
$this->setMissingElementInError('value', $path);
118+
return false;
119+
}
120+
}
121+
122+
return true;
123+
}
124+
125+
/**
126+
* @param $value
127+
* @param $pattern
128+
* @return bool
129+
*/
130+
private function valueMatchPattern($value, $pattern)
131+
{
132+
$match = $this->propertyMatcher->canMatch($pattern) &&
133+
true === $this->propertyMatcher->match($value, $pattern);
134+
135+
if (!$match) {
136+
$this->error = $this->propertyMatcher->getError();
137+
}
138+
139+
return $match;
96140
}
97141

98142
/**
99-
* @param $array
100143
* @param $path
144+
* @param $haystack
101145
* @return bool
102146
*/
103-
private function hasValue($array, $path)
147+
private function valueExist($path, array $haystack)
104148
{
105-
return null !== $this->getPropertyAccessor()->getValue($array, $path);
149+
return null !== $this->getPropertyAccessor()->getValue($haystack, $path);
106150
}
107151

108152
/**
109153
* @param $array
110154
* @param $path
111155
* @return mixed
112156
*/
113-
private function getValue($array, $path)
157+
private function getValueByPath($array, $path)
114158
{
115159
return $this->getPropertyAccessor()->getValue($array, $path);
116160
}
@@ -131,23 +175,39 @@ private function getPropertyAccessor()
131175
}
132176

133177
/**
134-
* @param array $value
135-
* @param array $pattern
136-
* @param $parentPath
137-
* @return bool
178+
* @param $place
179+
* @param $path
138180
*/
139-
private function checkIfPathsFromPatternExistInValue(array $value, array $pattern, $parentPath)
181+
private function setMissingElementInError($place, $path)
140182
{
141-
if (is_array($pattern)) {
142-
$notExistingKeys = array_diff_key($pattern, $value);
183+
$this->error = sprintf('There is no element under path %s in %s.', $path, $place);
184+
}
143185

144-
if (count($notExistingKeys) > 0) {
145-
$keyNames = array_keys($notExistingKeys);
146-
$this->error = sprintf('There is no element under path %s[%s] in value.', $parentPath, $keyNames[0]);
147-
return false;
148-
}
149-
}
186+
/**
187+
* @param $key
188+
* @return string
189+
*/
190+
private function formatAccessPath($key)
191+
{
192+
return sprintf("[%s]", $key);;
193+
}
150194

151-
return true;
195+
/**
196+
* @param $parentPath
197+
* @param $path
198+
* @return string
199+
*/
200+
private function formatFullPath($parentPath, $path)
201+
{
202+
return sprintf("%s%s", $parentPath, $path);
203+
}
204+
205+
/**
206+
* @param $lastPattern
207+
* @return bool
208+
*/
209+
private function shouldSkippValueMatchingFor($lastPattern)
210+
{
211+
return $lastPattern === self::UNBOUNDED_PATTERN;
152212
}
153213
}

tests/Coduo/PHPMatcher/Matcher/JsonMatcherTest.php

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,25 @@ public function test_positive_can_match($pattern)
4141
/**
4242
* @dataProvider negativePatterns
4343
*/
44-
public function test_negative_can_match()
44+
public function test_negative_can_match($pattern)
4545
{
46-
$this->assertFalse($this->matcher->canMatch('*'));
46+
$this->assertFalse($this->matcher->canMatch($pattern));
4747
}
4848

4949
/**
5050
* @dataProvider positiveMatches
5151
*/
5252
public function test_positive_matches($value, $pattern)
5353
{
54-
$this->assertTrue($this->matcher->match($value, $pattern));
54+
$this->assertTrue($this->matcher->match($value, $pattern), $this->matcher->getError());
5555
}
5656

5757
/**
5858
* @dataProvider negativeMatches
5959
*/
6060
public function test_negative_matches($value, $pattern)
6161
{
62-
$this->assertFalse($this->matcher->match($value, $pattern));
62+
$this->assertFalse($this->matcher->match($value, $pattern), $this->matcher->getError());
6363
}
6464

6565
public function test_error_when_matching_fail()
@@ -113,7 +113,7 @@ public static function positivePatterns()
113113
public static function negativePatterns()
114114
{
115115
return array(
116-
array('["Norbert",@string@]'),
116+
array('@string@'),
117117
array('["Norbert", '),
118118
);
119119
}
@@ -145,10 +145,18 @@ public static function positiveMatches()
145145
'{"null":[null]}',
146146
'{"null":[@null@]}'
147147
),
148+
array(
149+
'{"users":["Norbert","Michał",[]]}',
150+
'{"users":["Norbert","@string@",@...@]}'
151+
),
148152
array(
149153
'{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":["ROLE_USER", "ROLE_DEVELOPER"]}]}',
150154
'{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":"@wildcard@"}]}'
151-
)
155+
),
156+
array(
157+
'[{"name": "Norbert"},{"name":"Michał"},{"name":"Bob"},{"name":"Martin"}]',
158+
'[{"name": "Norbert"},@...@]'
159+
),
152160
);
153161
}
154162

@@ -163,10 +171,6 @@ public static function negativeMatches()
163171
'{"users":["Norbert","Michał", "John"], "stuff": [1, 2, 3]}',
164172
'{"users":["@string@", @...@], "stuff": [1, 2]}'
165173
),
166-
array(
167-
'{"users":["Norbert","Michał", []]}',
168-
'{"users":["@string@", @...@]}'
169-
),
170174
array(
171175
'{this_is_not_valid_json',
172176
'{"users":["Michał","@string@"]}'

0 commit comments

Comments
 (0)