Completed
Push — master ( af643a...1f0d30 )
by Russell
02:42
created

JSONTextQueryTest::testQueryWithMatchOnPath()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 139
Code Lines 77

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 139
rs 8.2857
cc 1
eloc 77
nc 1
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @package silverstripe-jsontext
5
 * @subpackage fields
6
 * @author Russell Michell <[email protected]>
7
 * @todo Add tests where source data is a JSON array, not just a JSON object
8
 * @todo $this->clearFixtures(); in setUp()
9
 * @todo Use same source data instead of repeating for each test
10
 * @todo See the PHPUnit @dataProvider annotaton ala
11
 * 
12
 *
13
 */
14
15
/**
16
 * @dataProvider additionProvider
17
 */
18
/*public function testAdd($a, $b, $expected)
19
{
20
    $this->assertEquals($expected, $a + $b);
21
}
22
23
public function additionProvider()
24
{
25
    return [
26
        [0, 0, 0],
27
        [0, 1, 1],
28
        [1, 0, 1],
29
        [1, 1, 3]
30
    ];
31
}*/
32
33
use JSONText\Fields;
34
use JSONText\Exceptions;
35
36
class JSONTextQueryTest extends SapphireTest
37
{
38
    /**
39
     * @var array
40
     */
41
    protected $fixtures = [
42
        'array'     => 'tests/fixtures/json/array.json',
43
        'object'    => 'tests/fixtures/json/object.json',
44
        'invalid'   => 'tests/fixtures/json/invalid.json'
45
    ];
46
47
    /**
48
     * JSONTextTest constructor.
49
     * 
50
     * Modify fixtures property to be able to run on PHP <5.6 without use of constant in class property which 5.6+ allows
51
     */
52
    public function __construct()
53
    {
54
        foreach($this->fixtures as $name => $path) {
55
            $this->fixtures[$name] = MODULE_DIR . '/' . $path;
56
        }
57
    }
58
59
    /**
60
     * Tests query() by means of the integer Postgres Int match operator: '->'
61
     * 
62
     * @todo Use same source data instead of repeating..
63
     */
64
    public function testQueryWithMatchOnInt()
65
    {
66
        // Data Source: Array
67
        // Return Type: ARRAY
68
        // Operator: "->" (Int)
69
        $field = JSONText\Fields\JSONText::create('MyJSON');
70
        $field->setReturnType('array');
71
        $field->setValue($this->getFixture('array'));
72
        $this->assertEquals([2 => 'trabant'], $field->query('->', 2));
73
        
74
        // Data Source: Array
75
        // Return Type: JSON
76
        // Operator: "->" (Int)
77
        $field = JSONText\Fields\JSONText::create('MyJSON');
78
        $field->setReturnType('json');
79
        $field->setValue($this->getFixture('array'));
80
        $this->assertEquals('{"2":"trabant"}', $field->query('->', 2));
81
        $this->assertEquals('{"5":101}', $field->query('->', 5));
82
        
83
        // Data Source: Array
84
        // Return Type: SILVERSTRIPE
85
        // Operator: "->" (Int)
86
        // SS Type: Float
87
        $field = JSONText\Fields\JSONText::create('MyJSON');
88
        $field->setReturnType('silverstripe');
89
        $field->setValue($this->getFixture('array'));
90
        $this->assertInternalType('array', $field->query('->', 3));
91
        $this->assertInstanceOf('Float', $field->query('->', 3)[3]);
92
        $this->assertEquals(44.6, $field->query('->', 3)[3]->getValue());
93
94
        // Data Source: Array
95
        // Return Type: SILVERSTRIPE
96
        // Operator: "->" (Int)
97
        // SS Type: Boolean
98
        $field = JSONText\Fields\JSONText::create('MyJSON');
99
        $field->setReturnType('silverstripe');
100
        $field->setValue($this->getFixture('array'));
101
        $this->assertInternalType('array', $field->query('->', 1));
102
        $this->assertInstanceOf('Boolean', $field->query('->', 1)[1]);
103
        $this->assertEquals(1, $field->query('->', 1)[1]->getValue());
104
105
        // Data Source: Array
106
        // Return Type: SILVERSTRIPE
107
        // Operator: "->" (Int)
108
        // SS Type: Int
109
        $field = JSONText\Fields\JSONText::create('MyJSON');
110
        $field->setReturnType('silverstripe');
111
        $field->setValue($this->getFixture('array'));
112
        $this->assertInternalType('array', $field->query('->', 5));
113
        $this->assertInstanceOf('Int', $field->query('->', 5)[5]);
114
        $this->assertEquals(101, $field->query('->', 5)[5]->getValue());
115
116
        // Data Source: Array
117
        // Return Type: SILVERSTRIPE
118
        // Operator: "->" (Int)
119
        // SS Type: Varchar
120
        $field = JSONText\Fields\JSONText::create('MyJSON');
121
        $field->setReturnType('silverstripe');
122
        $field->setValue($this->getFixture('array'));
123
        $this->assertInternalType('array', $field->query('->', 4));
124
        $this->assertInstanceOf('Varchar', $field->query('->', 4)[4]);
125
        $this->assertEquals('buick', $field->query('->', 4)[4]->getValue());
126
127
        // Test: Empty #1
128
        $field = JSONText\Fields\JSONText::create('MyJSON');
129
        $field->setReturnType('array');
130
        $field->setValue('');
131
        $this->assertInternalType('array', $field->query('->', 3));
132
        $this->assertCount(0, $field->query('->', 3));
133
134
        // Test: Empty #2
135
        $field = JSONText\Fields\JSONText::create('MyJSON');
136
        $field->setReturnType('array');
137
        $field->setValue('["morris"]');
138
        $this->assertEquals([], $field->query('->', 17));
139
140
        // Test: Invalid #1
141
        $field = JSONText\Fields\JSONText::create('MyJSON');
142
        $field->setReturnType('array');
143
        $field->setValue('["trabant"]');
144
        $this->assertEquals([], $field->query('->', 1));
145
146
        // Test: Invalid #2
147
        $field = JSONText\Fields\JSONText::create('MyJSON');
148
        $field->setReturnType('array');
149
        $field->setValue('{');
150
        $this->setExpectedException('\JSONText\Exceptions\JSONTextException');
151
        $field->query('->', 3);
152
    }
153
154
    /**
155
     * Tests query() by means of the integer Postgres String match operator: '->>'
156
     */
157
    public function testQueryWithMatchOnStr()
158
    {
159
        // Data Source: Object
160
        // Return Type: ARRAY
161
        // Operator: "->>" (String)
162
        $field = JSONText\Fields\JSONText::create('MyJSON');
163
        $field->setReturnType('array');
164
        $field->setValue($this->getFixture('object'));
165
        $this->assertEquals(['Subaru' => 'Impreza'], $field->query('->>', 'Subaru'));
166
        $this->assertEquals(
167
            ['japanese' => ['fast' => ['Subaru' => 'Impreza'], 'slow' => ['Honda' => 'Civic']]],
168
            $field->query('->>', 'japanese')
169
        );
170
171
        // Data Source: Object
172
        // Return Type: JSON
173
        // Operator: "->>" (String)
174
        $field = JSONText\Fields\JSONText::create('MyJSON');
175
        $field->setReturnType('json');
176
        $field->setValue($this->getFixture('object'));
177
        $this->assertEquals('{"Subaru":"Impreza"}', $field->query('->>', 'Subaru'));
178
        $this->assertEquals(
179
            '{"japanese":{"fast":{"Subaru":"Impreza"},"slow":{"Honda":"Civic"}}}',
180
            $field->query('->>', 'japanese')
181
        );
182
183
        // Data Source: Object
184
        // Return Type: SilverStripe
185
        // Operator: "->>" (String)
186
        // SS Type: Varchar
187
        $field = JSONText\Fields\JSONText::create('MyJSON');
188
        $field->setReturnType('silverstripe');
189
        $field->setValue($this->getFixture('object'));
190
        $this->assertInternalType('array', $field->query('->>', 'Subaru'));
191
        $this->assertInstanceOf('Varchar', $field->query('->>', 'Subaru')['Subaru']);
192
        $this->assertEquals('Impreza', $field->query('->>', 'Subaru')['Subaru']->getValue());
193
194
        // Data Source: Object
195
        // Return Type: SilverStripe
196
        // Operator: "->>" (String)
197
        // SS Type: Boolean
198
        $field = JSONText\Fields\JSONText::create('MyJSON');
199
        $field->setReturnType('silverstripe');
200
        $field->setValue($this->getFixture('object'));
201
        $this->assertInternalType('array', $field->query('->>', 'beer tastes good'));
202
        $this->assertInstanceOf('Boolean', $field->query('->>', 'beer tastes good')['beer tastes good']);
203
        $this->assertEquals(1, $field->query('->>', 'beer tastes good')['beer tastes good']->getValue());
204
205
        // Data Source: Object
206
        // Return Type: SilverStripe
207
        // Operator: "->>" (String)
208
        // SS Type: Float
209
        $field = JSONText\Fields\JSONText::create('MyJSON');
210
        $field->setReturnType('silverstripe');
211
        $field->setValue($this->getFixture('object'));
212
        $this->assertInternalType('array', $field->query('->>', 'how sure are you'));
213
        $this->assertInstanceOf('Float', $field->query('->>', 'how sure are you')['how sure are you']);
214
        $this->assertEquals(99.99, $field->query('->>', 'how sure are you')['how sure are you']->getValue());
215
216
        // Data Source: Object
217
        // Return Type: SilverStripe
218
        // Operator: "->>" (String)
219
        // SS Type: Int
220
        $field = JSONText\Fields\JSONText::create('MyJSON');
221
        $field->setReturnType('silverstripe');
222
        $field->setValue($this->getFixture('object'));
223
        $this->assertInternalType('array', $field->query('->>', 'how high'));
224
        $this->assertInstanceOf('Int', $field->query('->>', 'how high')['how high']);
225
        $this->assertEquals(6, $field->query('->>', 'how high')['how high']->getValue());
226
227
        // Data Source: Object
228
        // Return Type: SilverStripe
229
        // Operator: "->>" (String)
230
        // SS Type: N/A Nested sub-array example, expect an array
231
        $field = JSONText\Fields\JSONText::create('MyJSON');
232
        $field->setReturnType('silverstripe');
233
        $field->setValue($this->getFixture('object'));
234
        $this->assertInternalType('array', $field->query('->>', 'planes')['planes']);
235
        $this->assertInternalType('array', $field->query('->>', 'planes')['planes']['russian']);
236
        $this->assertCount(2, $field->query('->>', 'planes')['planes']['russian']);
237
        $this->assertInstanceOf('Varchar', $field->query('->>', 'planes')['planes']['russian'][0]);
238
        $this->assertInstanceOf('Varchar', $field->query('->>', 'planes')['planes']['russian'][1]);
239
240
        // Test: Empty #1
241
        $field = JSONText\Fields\JSONText::create('MyJSON');
242
        $field->setReturnType('array');
243
        $field->setValue('');
244
        $this->assertInternalType('array', $field->query('->>', 'planes'));
245
        $this->assertCount(0, $field->query('->', 3));
246
247
        // Test: Empty #2
248
        $field = JSONText\Fields\JSONText::create('MyJSON');
249
        $field->setReturnType('array');
250
        $field->setValue('["morris"]');
251
        $this->assertEquals([], $field->query('->', 17));
252
253
        // Test: Invalid #1
254
        $field = JSONText\Fields\JSONText::create('MyJSON');
255
        $field->setReturnType('array');
256
        $field->setValue('["trabant"]');
257
        $this->assertEquals([], $field->query('->', 1));
258
259
        // Test: Invalid #2
260
        $field = JSONText\Fields\JSONText::create('MyJSON');
261
        $field->setReturnType('array');
262
        $field->setValue('{');
263
        $this->setExpectedException('\JSONText\Exceptions\JSONTextException');
264
        $field->query('->', 3);
265
    }
266
267
    /**
268
     * Tests query() by means of the Postgres path-match operator: '#>'
269
     */
270
    public function testQueryWithMatchOnPath()
271
    {
272
        // Data Source: Object
273
        // Return Type: ARRAY
274
        // Operator: "#>" (Path)
275
        // Expect: Array due to duplicate keys in different parts of the source data
276
        $field = JSONText\Fields\JSONText::create('MyJSON');
277
        $field->setReturnType('array');
278
        $field->setValue($this->getFixture('object'));
279
        $this->assertEquals(
280
            [['Subaru' => 'Impreza'],['Kawasaki' => 'KR1S250']],
281
            $field->query('#>', '{"japanese":"fast"}')
282
        );
283
284
        // Data Source: Object
285
        // Return Type: JSON
286
        // Operator: "#>" (Path)
287
        // Expect: Array due to duplicate keys in different parts of the source data
288
        $field = JSONText\Fields\JSONText::create('MyJSON');
289
        $field->setReturnType('json');
290
        $field->setValue($this->getFixture('object'));
291
        $this->assertEquals(
292
            '[{"Subaru":"Impreza"},{"Kawasaki":"KR1S250"}]',
293
            $field->query('#>', '{"japanese":"fast"}')
294
        );
295
296
        // Data Source: Object
297
        // Return Type: SILVERSTRIPE
298
        // Operator: "#>" (Path)
299
        // Expect: Array due to duplicate keys in different parts of the source data
300
        $field = JSONText\Fields\JSONText::create('MyJSON');
301
        $field->setReturnType('silverstripe');
302
        $field->setValue($this->getFixture('object'));
303
        $this->assertInternalType('array', $field->query('#>', '{"japanese":"fast"}'));
304
        $this->assertCount(2, $field->query('#>', '{"japanese":"fast"}'));
305
        
306
        $one = $field->query('#>', '{"japanese":"fast"}')[0];
307
        $two = $field->query('#>', '{"japanese":"fast"}')[1];
308
        
309
        $this->assertInternalType('array', $one);
310
        $this->assertInternalType('array', $two);
311
        $this->assertInstanceOf('Varchar', array_values($one)[0]);
312
        $this->assertInstanceOf('Varchar', array_values($two)[0]);
313
        $this->assertEquals('Impreza', array_values($one)[0]->getValue());
314
        $this->assertEquals('KR1S250', array_values($two)[0]->getValue());
315
316
        // Data Source: Object
317
        // Return Type: ARRAY
318
        // Operator: "#>" (Path)
319
        // Expect: Direct scalar comparison assertion
320
        $field = JSONText\Fields\JSONText::create('MyJSON');
321
        $field->setReturnType('array');
322
        $field->setValue($this->getFixture('object'));
323
        $this->assertEquals(['airbus'], $field->query('#>', '{"planes":"french"}'));
324
325
        // Data Source: Object
326
        // Return Type: JSON
327
        // Operator: "#>" (Path)
328
        // Expect: Direct scalar comparison assertion
329
        $field = JSONText\Fields\JSONText::create('MyJSON');
330
        $field->setReturnType('json');
331
        $field->setValue($this->getFixture('object'));
332
        $this->assertEquals('["airbus"]', $field->query('#>', '{"planes":"french"}'));
333
334
        // Data Source: Object
335
        // Return Type: SILVERSTRIPE
336
        // Operator: "#>" (Path)
337
        // Expect: Direct scalar comparison assertion (Varchar)
338
        $field = JSONText\Fields\JSONText::create('MyJSON');
339
        $field->setReturnType('silverstripe');
340
        $field->setValue($this->getFixture('object'));
341
        $this->assertInternalType('array', $field->query('#>', '{"planes":"french"}'));
342
        $this->assertInstanceOf('Varchar', $field->query('#>', '{"planes":"french"}')[0]);
343
        $this->assertEquals('airbus', $field->query('#>', '{"planes":"french"}')[0]->getValue());
344
345
        // Data Source: Object
346
        // Return Type: SILVERSTRIPE
347
        // Operator: "#>" (Path)
348
        // Expect: Direct scalar comparison assertion (Float)
349
        $field = JSONText\Fields\JSONText::create('MyJSON');
350
        $field->setReturnType('silverstripe');
351
        $field->setValue($this->getFixture('object'));
352
        
353
        $res = $field->query('#>', '{"floats":"0"}');
354
        
355
        $this->assertInternalType('array', $res);
356
        $this->assertInternalType('array', $res[0]); // Why? Because value of "floats" key is a JSON array
357
        $this->assertInstanceOf('Float', array_values($res[0])[0]);
358
        $this->assertEquals(99.99, array_values($res[0])[0]->getValue());
359
360
        // Data Source: Object
361
        // Return Type: SILVERSTRIPE
362
        // Operator: "#>" (Path)
363
        // Expect: Direct scalar comparison assertion (Int)
364
        $field = JSONText\Fields\JSONText::create('MyJSON');
365
        $field->setReturnType('silverstripe');
366
        $field->setValue($this->getFixture('object'));
367
368
        $res = $field->query('#>', '{"ints":"0"}');
369
370
        $this->assertInternalType('array', $res);
371
        $this->assertInternalType('array', $res[0]); // Why? Because value of "floats" key is a JSON array
372
        $this->assertInstanceOf('Int', array_values($res[0])[1]);
373
        $this->assertEquals(6, array_values($res[0])[1]->getValue());
374
375
        // Data Source: Object
376
        // Return Type: SILVERSTRIPE
377
        // Operator: "#>" (Path)
378
        // Expect: Direct scalar comparison assertion (Boolean)
379
        $field = JSONText\Fields\JSONText::create('MyJSON');
380
        $field->setReturnType('silverstripe');
381
        $field->setValue($this->getFixture('object'));
382
383
        $res = $field->query('#>', '{"booleans":"0"}');
384
385
        $this->assertInternalType('array', $res);
386
        $this->assertInternalType('array', $res[0]); // Why? Because value of "booleans" key is a JSON array
387
        $this->assertInstanceOf('Boolean', array_values($res[0])[0]);
388
        $this->assertEquals(1, array_values($res[0])[0]->getValue());
389
390
        // #1 Empty source data
391
        $field = JSONText\Fields\JSONText::create('MyJSON');
392
        $field->setReturnType('array');
393
        $field->setValue('');
394
        $this->assertEquals([], $field->query('#>', '{"japanese":"fast"}'));
395
396
        // #2 JSON path not found
397
        $field = JSONText\Fields\JSONText::create('MyJSON');
398
        $field->setReturnType('silverstripe');
399
        $field->setValue($this->getFixture('object'));
400
        $this->assertNull($field->query('#>', '{"ints":"1"}')); // The "ints" key only has a single array as a value
401
402
        // #3 Invalid operand on RHS
403
        $this->setExpectedException('\JSONText\Exceptions\JSONTextException');
404
        $field = JSONText\Fields\JSONText::create('MyJSON');
405
        $field->setReturnType('array');
406
        $field->setValue($this->getFixture('object'));
407
        $this->assertEquals(['Kawasaki' => 'KR1S250'], $field->query('#>', '{"japanese":"fast"'));
408
    }
409
410
    /**
411
     * Tests query() by means of JSONPath expressions.
412
     * N.b. only a minimum no. tests should be required, given that the 3rd party lib via which this functionality
413
     * is derived, is itself well tested.
414
     */
415
    public function testQueryWithMatchOnExpr()
416
    {
417
        // Data Source: Object
418
        // Return Type: ARRAY
419
        // Expression: "$.." (Everything)
420
        // Expect: Array, obviously due to no. nodes in the source JSON
421
        $field = JSONText\Fields\JSONText::create('MyJSON');
422
        $field->setReturnType('array');
423
        $field->setValue($this->getFixture('object'));
424
        $this->assertInternalType('array', $field->query('$..'));
425
        $this->assertCount(25, $field->query('$..'));
426
427
        // Data Source: Object
428
        // Return Type: ARRAY
429
        // Expression: "$..japanese[*]" (An array of children of all keys matching "japanese")
430
        // Expect: Array
431
        $field = JSONText\Fields\JSONText::create('MyJSON');
432
        $field->setReturnType('array');
433
        $field->setValue($this->getFixture('object'));
434
        $this->assertCount(4, $field->query('$..japanese[*]'));
435
        $this->assertEquals([
436
            ['Subaru' => 'Impreza'],
437
            ['Honda' => 'Civic'],
438
            ['Kawasaki' => 'KR1S250'],
439
            ['Honda' => 'FS1']
440
        ], $field->query('$..japanese[*]'));
441
442
        // Data Source: Object
443
        // Return Type: JSON
444
        // Expression: "$..japanese[*]" (An array of children of all keys matching "japanese")
445
        // Expect: JSON Array of JSON objects
446
        $field = JSONText\Fields\JSONText::create('MyJSON');
447
        $field->setReturnType('json');
448
        $field->setValue($this->getFixture('object'));
449
        $this->assertEquals(
450
            '[{"Subaru":"Impreza"},{"Honda":"Civic"},{"Kawasaki":"KR1S250"},{"Honda":"FS1"}]',
451
            $field->query('$..japanese[*]')
452
        );
453
454
        // Data Source: Object
455
        // Return Type: Array
456
        // Expression: "$.cars.american[*]" (All entries in the american cars node)
457
        // Expect: Array
458
        $field = JSONText\Fields\JSONText::create('MyJSON');
459
        $field->setReturnType('array');
460
        $field->setValue($this->getFixture('object'));
461
        $this->assertEquals(['buick', 'oldsmobile'], $field->query('$.cars.american[*]'));
462
        $this->assertEquals(['buick'], $field->query('$.cars.american[0]'));
463
464
        // Data Source: Object
465
        // Return Type: Array
466
        // Expression: "$.cars.american[*]" (All entries in the american cars node)
467
        // Expect: Array 0f SilverStripe types
468
        $field = JSONText\Fields\JSONText::create('MyJSON');
469
        $field->setReturnType('silverstripe');
470
        $field->setValue($this->getFixture('object'));
471
        $this->assertInternalType('array', $field->query('$.cars.american[*]'));
472
        $this->assertCount(2, $field->query('$.cars.american[*]'));
473
        $this->assertInstanceOf('Varchar', $field->query('$.cars.american[*]')[0]);
474
        $this->assertEquals('buick', $field->query('$.cars.american[*]')[0]->getValue());
475
    }
476
    
477
    /**
478
     * Get the contents of a fixture
479
     * 
480
     * @param string $fixture
481
     * @return string
482
     */
483
    private function getFixture($fixture)
484
    {
485
        $files = $this->fixtures;
486
        return file_get_contents($files[$fixture]);
487
    }
488
489
}
490