-
-
Notifications
You must be signed in to change notification settings - Fork 32
Expand file tree
/
Copy pathSliceFilterTest.php
More file actions
155 lines (137 loc) · 4.74 KB
/
Copy pathSliceFilterTest.php
File metadata and controls
155 lines (137 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
<?php
/**
* JSONPath implementation for PHP.
*
* @license https://github.com/SoftCreatR/JSONPath/blob/main/LICENSE MIT License
*/
declare(strict_types=1);
namespace Flow\JSONPath\Test;
use ArrayObject;
use Flow\JSONPath\Filters\SliceFilter;
use Flow\JSONPath\JSONPathToken;
use Flow\JSONPath\TokenType;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
#[CoversClass(SliceFilter::class)]
class SliceFilterTest extends TestCase
{
/**
* @param array<string, int|null> $slice
* @param array<array-key, mixed>|object $input
* @param array<int, mixed> $expected
*/
#[DataProvider('sliceProvider')]
public function testFilterHandlesNegativeAndNullBounds(array $slice, array|object $input, array $expected): void
{
$token = new JSONPathToken(TokenType::Slice, $slice);
$filter = new SliceFilter($token);
self::assertSame($expected, $filter->filter($input));
}
/**
* @return iterable<string, array{array<string, int|null>, array<array-key, mixed>|object, array<int, mixed>}>
*/
public static function edgeCaseProvider(): iterable
{
yield 'step zero returns empty' => [
['start' => 0, 'end' => null, 'step' => 0],
['a', 'b'],
[],
];
yield 'start beyond length yields empty' => [
['start' => 5, 'end' => null, 'step' => 1],
['a', 'b'],
[],
];
yield 'end beyond length clamps to length' => [
['start' => 0, 'end' => 10, 'step' => 1],
['a', 'b'],
['a', 'b'],
];
yield 'negative step with null bounds reverses' => [
['start' => null, 'end' => null, 'step' => -1],
['a', 'b', 'c'],
['c', 'b', 'a'],
];
yield 'positive step with end below zero yields empty' => [
['start' => 0, 'end' => -10, 'step' => 1],
['a', 'b', 'c'],
[],
];
yield 'negative step with start far below length clamps to -1' => [
['start' => -5, 'end' => null, 'step' => -1],
['a', 'b', 'c'],
[],
];
yield 'negative step with start beyond length clamps to last index' => [
['start' => 10, 'end' => null, 'step' => -1],
['a', 'b', 'c'],
['c', 'b', 'a'],
];
yield 'negative step with end beyond length clamps end' => [
['start' => 1, 'end' => 10, 'step' => -1],
['a', 'b', 'c'],
[],
];
yield 'negative step with very negative start clamps to -1 and high end clamps to length' => [
['start' => -5, 'end' => 10, 'step' => -1],
['a', 'b', 'c'],
[],
];
yield 'negative step with end far below zero still collects prefix' => [
['start' => 1, 'end' => -10, 'step' => -1],
['a', 'b', 'c'],
['b', 'a'],
];
yield 'non countable object yields empty' => [
['start' => 0, 'end' => null, 'step' => 1],
(object)['a' => 1],
[],
];
}
/**
* @param array<string, int|null> $slice
* @param array<array-key, mixed> $input
* @param array<int, mixed> $expected
*/
#[DataProvider('edgeCaseProvider')]
public function testEdgeCases(array $slice, array|object $input, array $expected): void
{
$token = new JSONPathToken(TokenType::Slice, $slice);
$filter = new SliceFilter($token);
self::assertSame($expected, $filter->filter($input));
}
/**
* @return array<string, array{array<string, int|null>, array<array-key, mixed>|object, array<int, mixed>}>
*/
public static function sliceProvider(): array
{
return [
'negative start clamps at zero' => [
['start' => -10, 'end' => 2, 'step' => 1],
['a', 'b', 'c'],
['a', 'b'],
],
'negative end wraps from length' => [
['start' => 0, 'end' => -1, 'step' => 1],
['a', 'b', 'c'],
['a', 'b'],
],
'nulls default to full length' => [
['start' => null, 'end' => null, 'step' => 2],
['a', 'b', 'c', 'd'],
['a', 'c'],
],
'negative step slices in reverse order' => [
['start' => 2, 'end' => 0, 'step' => -1],
['a', 'b', 'c'],
['c', 'b'],
],
'works with array object' => [
['start' => 0, 'end' => 2, 'step' => 1],
new ArrayObject(['a', 'b', 'c']),
['a', 'b'],
],
];
}
}