Skip to content

Commit 3220890

Browse files
committed
OPTION_NUMERIC_INDEX_GAPS implemented and supported with tests
1 parent b5b0145 commit 3220890

File tree

3 files changed

+279
-10
lines changed

3 files changed

+279
-10
lines changed

src/Pointer.php

+9-6
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@ class Pointer
1717
* arbitrary numeric indices will break them. But PHP arrays support
1818
* arrays with "gaps" between indices, and this option enables writing
1919
* to array at any index.
20-
*
21-
* @todo Implement this option.
2220
*/
23-
const OPTION_WRITE_ANY_INDEX = 0x02;
21+
const OPTION_NUMERIC_INDEX_GAPS = 0x02;
2422

2523
/**
2624
* Bit-packed options.
@@ -142,8 +140,9 @@ public function unsetData()
142140

143141
public function test()
144142
{
143+
$nonNumericIndices = $this->hasOption(self::OPTION_NON_NUMERIC_INDICES);
145144
return Pointer\Evaluate\Test::factory()
146-
->setNonNumericIndices($this->hasOption(self::OPTION_NON_NUMERIC_INDICES))
145+
->setNonNumericIndices($nonNumericIndices)
147146
->setLocator($this->getLocator())
148147
->setData($this->getData())
149148
->perform()
@@ -152,8 +151,9 @@ public function test()
152151

153152
public function &read()
154153
{
154+
$nonNumericIndices = $this->hasOption(self::OPTION_NON_NUMERIC_INDICES);
155155
return Pointer\Evaluate\Read::factory()
156-
->setNonNumericIndices($this->hasOption(self::OPTION_NON_NUMERIC_INDICES))
156+
->setNonNumericIndices($nonNumericIndices)
157157
->setLocator($this->getLocator())
158158
->setData($this->getData())
159159
->perform()
@@ -163,8 +163,11 @@ public function &read()
163163

164164
public function write($value)
165165
{
166+
$nonNumericIndices = $this->hasOption(self::OPTION_NON_NUMERIC_INDICES);
167+
$numericIndexGaps = $this->hasOption(self::OPTION_NUMERIC_INDEX_GAPS);
166168
Pointer\Evaluate\Write::factory()
167-
->setNonNumericIndices($this->hasOption(self::OPTION_NON_NUMERIC_INDICES))
169+
->setNonNumericIndices($nonNumericIndices)
170+
->setNumericIndexGaps($numericIndexGaps)
168171
->setLocator($this->getLocator())
169172
->setData($this->getData())
170173
->setValue($value)

src/Pointer/Evaluate/Write.php

+19-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class Write extends \Remorhaz\JSONPointer\Pointer\Evaluate
1111

1212
protected $isValueSet = false;
1313

14+
protected $numericIndexGaps = false;
15+
1416

1517
public function setValue($value)
1618
{
@@ -29,6 +31,15 @@ protected function getValue()
2931
}
3032

3133

34+
public function setNumericIndexGaps($allow = true)
35+
{
36+
if (!is_bool($allow)) {
37+
throw new InvalidArgumentException("Write any index flag must be boolean");
38+
}
39+
$this->numericIndexGaps = $allow;
40+
return $this;
41+
}
42+
3243
protected function processCursor()
3344
{
3445
$this->cursor = $this->getValue();
@@ -63,9 +74,14 @@ protected function processNonExistingArrayIndex(Reference $reference)
6374
{
6475
$index = $this->getArrayIndex($reference);
6576
if ($reference->isLast()) {
66-
$this->cursor[$index] = $this->getValue();
67-
$result = null;
68-
return $this->setResult($result);
77+
$canWrite = is_int($index)
78+
? 0 == $index || array_key_exists($index - 1, $this->cursor) || $this->numericIndexGaps
79+
: $this->nonNumericIndices;
80+
if ($canWrite) {
81+
$this->cursor[$index] = $this->getValue();
82+
$result = null;
83+
return $this->setResult($result);
84+
}
6985
}
7086
$indexText = is_int($index) ? "{$index}" : "'{$index}'";
7187
throw new EvaluateException("Accessing non-existing index {$indexText} in array");

tests/Pointer/Evaluate/WriteTest.php

+251-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function testWriteDataWithValidLokator($text, $data, $value, $expectedDat
7676
->setLocator($locator)
7777
->setValue($value)
7878
->perform();
79-
$this->assertEquals($expectedData, $data, "Incorrect data after modification");
79+
$this->assertEquals($expectedData, $data, "Incorrect data after writing");
8080
}
8181

8282

@@ -128,6 +128,12 @@ public function providerDataWithValidLokator()
128128
4,
129129
[1, 2, 3, 4],
130130
],
131+
'rootArrayNewIndex' => [
132+
'/3',
133+
[1, 2, 3],
134+
4,
135+
[1, 2, 3, 4],
136+
],
131137
'nestedArrayExistingIndex' => [
132138
'/1/0',
133139
[1, [3, 4], 5],
@@ -140,6 +146,250 @@ public function providerDataWithValidLokator()
140146
6,
141147
[1, [3, 4, 6], 5],
142148
],
149+
'nestedArrayNewIndex' => [
150+
'/1/2',
151+
[1, [3, 4], 5],
152+
6,
153+
[1, [3, 4, 6], 5],
154+
],
155+
];
156+
}
157+
158+
159+
/**
160+
* @param string $text
161+
* @param mixed $data
162+
* @param mixed $value
163+
* @dataProvider providerDataWithNonNumericIndexLocator
164+
* @expectedException \Remorhaz\JSONPointer\Pointer\Evaluate\Exception
165+
*/
166+
public function testAccessNonNumericIndexThrowsException($text, $data, $value)
167+
{
168+
$locator = Parser::factory()
169+
->setText($text)
170+
->getLocator();
171+
Write::factory()
172+
->setData($data)
173+
->setLocator($locator)
174+
->setValue($value)
175+
->perform();
176+
}
177+
178+
179+
/**
180+
* @param string $text
181+
* @param mixed $data
182+
* @param mixed $value
183+
* @dataProvider providerDataWithNonNumericIndexLocator
184+
* @expectedException \Remorhaz\JSONPointer\EvaluateException
185+
*/
186+
public function testAccessNonNumericIndexThrowsEvalueateException($text, $data, $value)
187+
{
188+
$locator = Parser::factory()
189+
->setText($text)
190+
->getLocator();
191+
Write::factory()
192+
->setData($data)
193+
->setLocator($locator)
194+
->setValue($value)
195+
->perform();
196+
}
197+
198+
199+
/**
200+
* @param string $text
201+
* @param mixed $data
202+
* @param mixed $value
203+
* @dataProvider providerDataWithNonNumericIndexLocator
204+
* @expectedException \RuntimeException
205+
*/
206+
public function testAccessNonNumericIndexThrowsSplException($text, $data, $value)
207+
{
208+
$locator = Parser::factory()
209+
->setText($text)
210+
->getLocator();
211+
Write::factory()
212+
->setData($data)
213+
->setLocator($locator)
214+
->setValue($value)
215+
->perform();
216+
}
217+
218+
219+
/**
220+
* @param string $text
221+
* @param mixed $data
222+
* @param mixed $value
223+
* @param mixed $expectedData
224+
* @dataProvider providerDataWithNonNumericIndexLocator
225+
*/
226+
public function testWriteAllowedNonNumericIndex($text, $data, $value, $expectedData)
227+
{
228+
$locator = Parser::factory()
229+
->setText($text)
230+
->getLocator();
231+
Write::factory()
232+
->setData($data)
233+
->setLocator($locator)
234+
->setValue($value)
235+
->setNonNumericIndices()
236+
->perform();
237+
$this->assertEquals($expectedData, $data, "Incorrect data after writing to non-numeric index");
238+
}
239+
240+
241+
public function providerDataWithNonNumericIndexLocator()
242+
{
243+
return [
244+
'rootEmptyArray' => [
245+
'/a',
246+
[],
247+
1,
248+
['a' => 1],
249+
],
250+
'rootArrayExistingIndex' => [
251+
'/a',
252+
[1, 'a' => 2, 3],
253+
4,
254+
[1, 'a' => 4, 3],
255+
],
256+
'rootArrayNewIndex' => [
257+
'/a',
258+
[1, 2, 3],
259+
4,
260+
[1, 2, 3, 'a' => 4],
261+
],
262+
'nestedEmptyArray' => [
263+
'/1/a',
264+
[1, [], 2],
265+
3,
266+
[1, ['a' => 3], 2],
267+
],
268+
'nestedArrayExistingIndex' => [
269+
'/1/a',
270+
[1, ['a' => 2], 3],
271+
4,
272+
[1, ['a' => 4], 3],
273+
],
274+
'nestedArrayNewIndex' => [
275+
'/1/a',
276+
[1, [2, 3], 4],
277+
5,
278+
[1, [2, 3, 'a' => 5], 4],
279+
],
280+
];
281+
}
282+
283+
284+
/**
285+
* @param string $text
286+
* @param mixed $data
287+
* @param mixed $value
288+
* @dataProvider providerDataWithNumericIndexGapsLocator
289+
* @expectedException \Remorhaz\JSONPointer\Pointer\Evaluate\Exception
290+
*/
291+
public function testWriteNumericIndexGapsThrowsException($text, $data, $value)
292+
{
293+
$locator = Parser::factory()
294+
->setText($text)
295+
->getLocator();
296+
Write::factory()
297+
->setData($data)
298+
->setLocator($locator)
299+
->setValue($value)
300+
->perform();
301+
}
302+
303+
304+
/**
305+
* @param string $text
306+
* @param mixed $data
307+
* @param mixed $value
308+
* @dataProvider providerDataWithNumericIndexGapsLocator
309+
* @expectedException \Remorhaz\JSONPointer\EvaluateException
310+
*/
311+
public function testWriteNumericIndexGapsThrowsEvaluateException($text, $data, $value)
312+
{
313+
$locator = Parser::factory()
314+
->setText($text)
315+
->getLocator();
316+
Write::factory()
317+
->setData($data)
318+
->setLocator($locator)
319+
->setValue($value)
320+
->perform();
321+
}
322+
323+
324+
/**
325+
* @param string $text
326+
* @param mixed $data
327+
* @param mixed $value
328+
* @dataProvider providerDataWithNumericIndexGapsLocator
329+
* @expectedException \RuntimeException
330+
*/
331+
public function testWriteNumericIndexGapsThrowsSplException($text, $data, $value)
332+
{
333+
$locator = Parser::factory()
334+
->setText($text)
335+
->getLocator();
336+
Write::factory()
337+
->setData($data)
338+
->setLocator($locator)
339+
->setValue($value)
340+
->perform();
341+
}
342+
343+
344+
/**
345+
* @param string $text
346+
* @param mixed $data
347+
* @param mixed $value
348+
* @param mixed $expectedData
349+
* @dataProvider providerDataWithNumericIndexGapsLocator
350+
*/
351+
public function testWriteAllowedNumericIndexGaps($text, $data, $value, $expectedData)
352+
{
353+
$locator = Parser::factory()
354+
->setText($text)
355+
->getLocator();
356+
Write::factory()
357+
->setData($data)
358+
->setLocator($locator)
359+
->setValue($value)
360+
->setNumericIndexGaps()
361+
->perform();
362+
$this->assertEquals($expectedData, $data, "Incorrect data after writing to index with gap");
363+
}
364+
365+
366+
public function providerDataWithNumericIndexGapsLocator()
367+
{
368+
return [
369+
'rootEmptyArray' => [
370+
'/1',
371+
[],
372+
1,
373+
[1 => 1],
374+
],
375+
'rootArray' => [
376+
'/2',
377+
[1],
378+
2,
379+
[1, 2 => 2],
380+
],
381+
'nestedEmptyArray' => [
382+
'/1/1',
383+
[1, []],
384+
2,
385+
[1, [1 => 2]],
386+
],
387+
'nestedArray' => [
388+
'/1/2',
389+
[1, [2]],
390+
3,
391+
[1, [2, 2 => 3]],
392+
],
143393
];
144394
}
145395
}

0 commit comments

Comments
 (0)