ShowcaseControllerTest   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 980
Duplicated Lines 18.47 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 33
lcom 1
cbo 3
dl 181
loc 980
rs 9.3798
c 0
b 0
f 0

32 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 9 1
A testGetEmptyObject() 0 39 1
A testMissingFields() 0 26 1
A testEmptyAllFields() 0 51 1
A testHiddenFieldNotExposed() 0 6 1
A testEmptyFields() 0 43 1
A testWrongChoiceValue() 0 19 1
A testWrongExtRef() 0 30 1
A testPost() 0 29 1
A postCreationDataProvider() 0 9 1
A testFreeFormExtRefs() 0 40 1
A testExtraFieldPost() 0 29 1
A testRqlSelect() 0 44 2
A testLikeSearchOnIdentifierField() 0 14 1
A testPatchDeepNestedProperty() 26 26 1
A testPatchSuccessResponseHeaderContainsResourceLink() 0 21 1
A testPatchRemoveAndChangeIdNotAllowed() 0 15 1
A testPatchAddPropertyToFreeObject() 26 26 1
A testApplyPatchForRefAttribute() 0 28 1
A testPatchToInvalidShowcase() 0 22 1
A testRemoveFromArrayPatch() 23 23 1
A testAddElementToSpecificIndexInArrayPatch() 0 28 1
A testPatchAddComplexObjectToSpecificIndexInArray() 28 28 1
A testPatchAddComplexObjectToTheEndOfArray() 28 28 1
A testPatchTestOperationToUndefinedIndexThrowsException() 0 17 1
A testPatchAddElementToUndefinedIndexResponseAsBadRequest() 0 24 1
A encodeRqlString() 12 12 1
A testTrigger301() 0 7 1
A rqlDataProvider() 0 7 1
A testCorrectIdExposingInSchema() 0 17 1
A testFindByExtref() 13 13 1
A findByExtrefProvider() 25 25 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * functional test for /hans/showcase
4
 */
5
6
namespace Graviton\CoreBundle\Tests\Controller;
7
8
use Graviton\I18nBundle\DataFixtures\MongoDB\LoadLanguageData;
9
use Graviton\TestBundle\Test\RestTestCase;
10
use GravitonDyn\ShowCaseBundle\DataFixtures\MongoDB\LoadShowCaseData;
11
use Symfony\Component\HttpFoundation\Response;
12
13
/**
14
 * Functional test for /hans/showcase
15
 *
16
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
17
 * @license  https://opensource.org/licenses/MIT MIT License
18
 * @link     http://swisscom.ch
19
 */
20
class ShowcaseControllerTest extends RestTestCase
21
{
22
    /**
23
     * @const complete content type string expected on a resouce
24
     */
25
    const CONTENT_TYPE = 'application/json; charset=UTF-8; profile=http://localhost/schema/hans/showcase/item';
26
27
    /**
28
     * @const corresponding vendorized schema mime type
29
     */
30
    const COLLECTION_TYPE = 'application/json; charset=UTF-8; profile=http://localhost/schema/hans/showcase/collection';
31
32
    /**
33
     * suppress setup client and load fixtures of parent class
34
     *
35
     * @return void
36
     */
37
    public function setUp()
38
    {
39
        $this->loadFixturesLocal(
40
            [
41
                LoadLanguageData::class,
42
                LoadShowCaseData::class
43
            ]
44
        );
45
    }
46
47
    /**
48
     * checks empty objects
49
     *
50
     * @return void
51
     */
52
    public function testGetEmptyObject()
53
    {
54
        $showCase = (object) [
55
            'anotherInt'            => 100,
56
            'aBoolean'              => true,
57
            'testField'             => ['en' => 'test'],
58
            'someOtherField'        => ['en' => 'other'],
59
            'contactCode'           => [
60
                'someDate'          => '2015-06-07T06:30:00+0000',
61
                'text'              => ['en' => 'text'],
62
            ],
63
            'contact'               => [
64
                'type'      => 'type',
65
                'value'     => 'value',
66
                'protocol'  => 'protocol',
67
                'uri'       => 'protocol:value',
68
            ],
69
70
            'nestedApps'            => [],
71
            'unstructuredObject'    => (object) [],
72
            'choices'               => "<>"
73
        ];
74
75
        $client = static::createRestClient();
76
        $client->post('/hans/showcase/', $showCase);
77
        $this->assertEquals(Response::HTTP_CREATED, $client->getResponse()->getStatusCode());
78
        $this->assertNull($client->getResults());
79
80
        $url = $client->getResponse()->headers->get('Location');
81
        $this->assertNotNull($url);
82
83
        $client = static::createRestClient();
84
        $client->request('GET', $url);
85
        $this->assertEquals(Response::HTTP_OK, $client->getResponse()->getStatusCode());
86
87
        $created = $client->getResults();
88
        $this->assertEquals($showCase->nestedApps, $created->nestedApps);
89
        $this->assertEquals($showCase->unstructuredObject, $created->unstructuredObject);
90
    }
91
92
    /**
93
     * see how our missing fields are explained to us
94
     *
95
     * @return void
96
     */
97
    public function testMissingFields()
98
    {
99
        $document = json_decode(
100
            file_get_contents(dirname(__FILE__).'/../resources/showcase-incomplete.json'),
101
            true
102
        );
103
104
        $client = static::createRestClient();
105
        $client->post('/hans/showcase', $document);
106
107
        $expectedErrors = [];
108
        $notNullError = new \stdClass();
109
        $notNullError->propertyPath = 'aBoolean';
110
        $notNullError->message = 'The property aBoolean is required';
111
        $expectedErrors[] = $notNullError;
112
        // test choices field (string should not be blank)
113
        $notNullErrorChoices = new \stdClass();
114
        $notNullErrorChoices->propertyPath = 'choices';
115
        $notNullErrorChoices->message = 'The property choices is required';
116
        $expectedErrors[] = $notNullErrorChoices;
117
118
        $this->assertJsonStringEqualsJsonString(
119
            json_encode($expectedErrors),
120
            json_encode($client->getResults())
121
        );
122
    }
123
124
    /**
125
     * see how our empty fields are explained to us
126
     *
127
     * @return void
128
     */
129
    public function testEmptyAllFields()
130
    {
131
        $document = [
132
            'anotherInt'  => 6555488894525,
133
            'testField'   => ['en' => 'a test string'],
134
            'aBoolean'    => '',
135
            'contactCode' => [
136
                'text'     => ['en' => 'Some Text'],
137
                'someDate' => '1984-05-01T00:00:00+0000',
138
            ],
139
            'contact'     => [
140
                'type'      => '',
141
                'value'     => '',
142
                'protocol'  => '',
143
            ],
144
        ];
145
146
        $client = static::createRestClient();
147
        $client->post('/hans/showcase', $document);
148
149
        $this->assertEquals(
150
            Response::HTTP_BAD_REQUEST,
151
            $client->getResponse()->getStatusCode()
152
        );
153
154
        $this->assertEquals(
155
            [
156
                (object) [
157
                    'propertyPath'  => 'choices',
158
                    'message'       => 'The property choices is required',
159
                ],
160
                (object) [
161
                    'propertyPath'  => 'aBoolean',
162
                    'message'       => 'String value found, but a boolean is required',
163
                ],
164
                (object) [
165
                    'propertyPath'  => 'contact.type',
166
                    'message'       => 'Must be at least 1 characters long',
167
                ],
168
                (object) [
169
                    'propertyPath'  => 'contact.protocol',
170
                    'message'       => 'Must be at least 1 characters long',
171
                ],
172
                (object) [
173
                    'propertyPath'  => 'contact.value',
174
                    'message'       => 'Must be at least 1 characters long',
175
                ]
176
            ],
177
            $client->getResults()
178
        );
179
    }
180
181
    /**
182
     * check that hiddenField is not rendered as it's marked as hidden.. it's filled via fixtures
183
     *
184
     * @return void
185
     */
186
    public function testHiddenFieldNotExposed()
187
    {
188
        $client = static::createRestClient();
189
        $client->request('GET', '/hans/showcase/500');
190
        $this->assertObjectNotHasAttribute('hiddenField', $client->getResults());
191
    }
192
193
    /**
194
     * see how our empty fields are explained to us
195
     *
196
     * @return void
197
     */
198
    public function testEmptyFields()
199
    {
200
        $document = [
201
            'anotherInt'  => 6555488894525,
202
            'testField'   => ['en' => 'a test string'],
203
            'aBoolean'    => true,
204
            'contactCode' => [
205
                'text'     => ['en' => 'Some Text'],
206
                'someDate' => '1984-05-01T00:00:00+0000',
207
            ],
208
            'contact'     => [
209
                'type'      => 'abc',
210
                'value'     => '',
211
                'protocol'  => '',
212
            ],
213
        ];
214
215
        $client = static::createRestClient();
216
        $client->post('/hans/showcase', $document);
217
218
        $this->assertEquals(
219
            Response::HTTP_BAD_REQUEST,
220
            $client->getResponse()->getStatusCode()
221
        );
222
223
        $this->assertEquals(
224
            [
225
                (object) [
226
                    'propertyPath'  => 'choices',
227
                    'message'       => 'The property choices is required',
228
                ],
229
                (object) [
230
                    'propertyPath'  => 'contact.protocol',
231
                    'message'       => 'Must be at least 1 characters long',
232
                ],
233
                (object) [
234
                    'propertyPath'  => 'contact.value',
235
                    'message'       => 'Must be at least 1 characters long',
236
                ],
237
            ],
238
            $client->getResults()
239
        );
240
    }
241
242
    /**
243
     * make sure an invalid choice value is detected
244
     *
245
     * @return void
246
     */
247
    public function testWrongChoiceValue()
248
    {
249
        $payload = json_decode(file_get_contents($this->postCreationDataProvider()['minimal'][0]));
250
        $payload->choices = 'invalidChoice';
251
252
        $client = static::createRestClient();
253
        $client->post('/hans/showcase', $payload);
254
        $this->assertEquals(400, $client->getResponse()->getStatusCode());
255
256
        $expectedErrors = [];
257
        $expectedErrors[0] = new \stdClass();
258
        $expectedErrors[0]->propertyPath = "choices";
259
        $expectedErrors[0]->message = 'Does not have a value in the enumeration ["<",">","=",">=","<=","<>"]';
260
261
        $this->assertJsonStringEqualsJsonString(
262
            json_encode($expectedErrors),
263
            json_encode($client->getResults())
264
        );
265
    }
266
267
    /**
268
     * make sure an invalid extref value is detected
269
     *
270
     * @return void
271
     */
272
    public function testWrongExtRef()
273
    {
274
        $payload = json_decode(file_get_contents($this->postCreationDataProvider()['minimal'][0]));
275
        $payload->nestedApps = [
276
            (object) ['$ref' => 'http://localhost/core/module/name'],
277
            (object) ['$ref' => 'unknown']
278
        ];
279
280
        $client = static::createRestClient();
281
        $client->post('/hans/showcase', $payload);
282
        $this->assertEquals(400, $client->getResponse()->getStatusCode());
283
284
        $expectedErrors = [
285
            (object) [
286
                'propertyPath' => "nestedApps[0].\$ref",
287
                'message' =>
288
                    'Value "http://localhost/core/module/name" does not refer to a correct collection for this extref.'
289
            ],
290
            (object) [
291
                'propertyPath' => "nestedApps[1].\$ref",
292
                'message' =>
293
                    'Does not match the regex pattern (\/core\/app\/)([a-zA-Z0-9\-_\+\040\'\.]+)$'
294
            ]
295
        ];
296
297
        $this->assertJsonStringEqualsJsonString(
298
            json_encode($expectedErrors),
299
            json_encode($client->getResults())
300
        );
301
    }
302
303
    /**
304
     * insert various formats to see if all works as expected
305
     *
306
     * @dataProvider postCreationDataProvider
307
     *
308
     * @param string $filename filename
309
     *
310
     * @return void
311
     */
312
    public function testPost($filename)
313
    {
314
        // showcase contains some datetime fields that we need rendered as UTC in the case of this test
315
        ini_set('date.timezone', 'UTC');
316
        $document = json_decode(
317
            file_get_contents($filename),
318
            false
319
        );
320
321
        $client = static::createRestClient();
322
        $client->post('/hans/showcase/', $document);
323
        $response = $client->getResponse();
324
325
        $this->assertEquals(Response::HTTP_CREATED, $response->getStatusCode());
326
327
        $client = static::createRestClient();
328
        $client->request('GET', $response->headers->get('Location'));
329
330
        $result = $client->getResults();
331
332
        // unset id as we cannot compare and don't care
333
        $this->assertNotNull($result->id);
334
        unset($result->id);
335
336
        $this->assertJsonStringEqualsJsonString(
337
            json_encode($document),
338
            json_encode($result)
339
        );
340
    }
341
342
    /**
343
     * Provides test sets for the testPost() test.
344
     *
345
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string[]>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
346
     */
347
    public function postCreationDataProvider()
348
    {
349
        $basePath = dirname(__FILE__).'/../resources/';
350
351
        return array(
352
            'minimal' => array($basePath.'showcase-minimal.json'),
353
            'complete' => array($basePath.'showcase-complete.json')
354
        );
355
    }
356
357
    /**
358
     * test if we can save & retrieve extrefs inside 'free form objects'
359
     *
360
     * @return void
361
     */
362
    public function testFreeFormExtRefs()
363
    {
364
        $minimalExample = $this->postCreationDataProvider()['minimal'][0];
365
366
        $document = json_decode(
367
            file_get_contents($minimalExample),
368
            false
369
        );
370
371
        $document->id = 'dynextreftest';
372
373
        // insert some refs!
374
        $document->unstructuredObject = new \stdClass();
375
        $document->unstructuredObject->testRef = new \stdClass();
376
        $document->unstructuredObject->testRef->{'$ref'} = 'http://localhost/hans/showcase/500';
377
378
        // let's go more deep..
379
        $document->unstructuredObject->go = new \stdClass();
380
        $document->unstructuredObject->go->more = new \stdClass();
381
        $document->unstructuredObject->go->more->deep = new \stdClass();
382
        $document->unstructuredObject->go->more->deep->{'$ref'} = 'http://localhost/hans/showcase/500';
383
384
        // array?
385
        $document->unstructuredObject->refArray = [];
386
        $document->unstructuredObject->refArray[0] = new \stdClass();
387
        $document->unstructuredObject->refArray[0]->{'$ref'} = 'http://localhost/core/app/dude';
388
        $document->unstructuredObject->refArray[1] = new \stdClass();
389
        $document->unstructuredObject->refArray[1]->{'$ref'} = 'http://localhost/core/app/dude2';
390
391
        $client = static::createRestClient();
392
        $client->put('/hans/showcase/'.$document->id, $document);
393
394
        $this->assertEquals(204, $client->getResponse()->getStatusCode());
395
396
        $client = static::createRestClient();
397
        $client->request('GET', '/hans/showcase/'.$document->id);
398
399
        // all still the same?
400
        $this->assertEquals($document, $client->getResults());
401
    }
402
403
    /**
404
     * are extra fields denied?
405
     *
406
     * @return void
407
     */
408
    public function testExtraFieldPost()
409
    {
410
        ini_set('date.timezone', 'UTC');
411
        $document = json_decode(
412
            file_get_contents(dirname(__FILE__).'/../resources/showcase-minimal.json'),
413
            false
414
        );
415
        $document->extraFields = "nice field";
416
        $document->anotherExtraField = "one more";
417
418
        $client = static::createRestClient();
419
        $client->post('/hans/showcase', $document);
420
        $this->assertEquals(400, $client->getResponse()->getStatusCode());
421
422
        $expectedErrors = [];
423
        $expectedErrors[0] = new \stdClass();
424
        $expectedErrors[0]->propertyPath = "";
425
        $expectedErrors[0]->message = 'The property extraFields is not defined and the definition '.
426
            'does not allow additional properties';
427
        $expectedErrors[1] = new \stdClass();
428
        $expectedErrors[1]->propertyPath = "";
429
        $expectedErrors[1]->message = 'The property anotherExtraField is not defined and the definition '.
430
            'does not allow additional properties';
431
432
        $this->assertJsonStringEqualsJsonString(
433
            json_encode($expectedErrors),
434
            json_encode($client->getResults())
435
        );
436
    }
437
438
    /**
439
     * Test RQL select statement
440
     *
441
     * @return void
442
     */
443
    public function testRqlSelect()
444
    {
445
        $filtred = json_decode(
446
            file_get_contents(dirname(__FILE__).'/../resources/showcase-rql-select-filtred.json'),
447
            false
448
        );
449
450
        $fields = [
451
            'someFloatyDouble',
452
            'contact',
453
            'contactCode.text',
454
            'unstructuredObject.booleanField',
455
            'unstructuredObject.hashField.someField',
456
            'unstructuredObject.nestedArrayField.anotherField',
457
            'nestedCustomers',
458
            'choices'
459
        ];
460
        $rqlSelect = 'select('.implode(',', array_map([$this, 'encodeRqlString'], $fields)).')';
461
462
        $client = static::createRestClient();
463
        $client->request('GET', '/hans/showcase/?'.$rqlSelect);
464
465
        /* expect empty arrays */
466
        $filtred = array_map(
467
            function ($entry) {
468
                $entry->contacts = [];
469
                $entry->nestedArray = [];
470
                $entry->nestedApps = [];
471
                return $entry;
472
            },
473
            $filtred
474
        );
475
476
        $this->assertEquals($filtred, $client->getResults());
477
478
        foreach ([
479
                     '500' => $filtred[0],
480
                     '600' => $filtred[1],
481
                 ] as $id => $item) {
482
            $client = static::createRestClient();
483
            $client->request('GET', '/hans/showcase/'.$id.'?'.$rqlSelect);
484
            $this->assertEquals($item, $client->getResults());
485
        }
486
    }
487
488
    /**
489
     * Test to see if we can do like() searches on identifier fields
490
     *
491
     * @return void
492
     */
493
    public function testLikeSearchOnIdentifierField()
494
    {
495
        $client = static::createRestClient();
496
        $client->request('GET', '/hans/showcase/?like(id,5*)');
497
498
        // we should only get 1 ;-)
499
        $this->assertEquals(1, count($client->getResults()));
500
501
        $client = static::createRestClient();
502
        $client->request('GET', '/hans/showcase/?like(id,*0)');
503
504
        // this should get both
505
        $this->assertEquals(2, count($client->getResults()));
506
    }
507
508
    /**
509
     * Test PATCH for deep nested attribute
510
     *
511
     * @return void
512
     */
513 View Code Duplication
    public function testPatchDeepNestedProperty()
514
    {
515
        // Apply PATCH request
516
        $client = static::createRestClient();
517
        $patchJson = json_encode(
518
            [
519
                [
520
                    'op' => 'replace',
521
                    'path' => '/unstructuredObject/hashField/anotherField',
522
                    'value' => 'changed nested hash field with patch'
523
                ]
524
            ]
525
        );
526
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
527
        $this->assertEquals(200, $client->getResponse()->getStatusCode());
528
529
        // Get changed showcase
530
        $client = static::createRestClient();
531
        $client->request('GET', '/hans/showcase/500');
532
533
        $result = $client->getResults();
534
        $this->assertEquals(
535
            'changed nested hash field with patch',
536
            $result->unstructuredObject->hashField->anotherField
537
        );
538
    }
539
540
    /**
541
     * Test success PATCH method - response headers contains link to resource
542
     *
543
     * @return void
544
     */
545
    public function testPatchSuccessResponseHeaderContainsResourceLink()
546
    {
547
        // Apply PATCH request
548
        $client = static::createRestClient();
549
        $patchJson = json_encode(
550
            [
551
                [
552
                    'op' => 'replace',
553
                    'path' => '/testField/en',
554
                    'value' => 'changed value'
555
                ]
556
            ]
557
        );
558
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
559
        $this->assertEquals(200, $client->getResponse()->getStatusCode());
560
561
        $this->assertEquals(
562
            '/hans/showcase/500',
563
            $client->getResponse()->headers->get('Content-Location')
564
        );
565
    }
566
567
    /**
568
     * Test PATCH method - remove/change ID not allowed
569
     *
570
     * @return void
571
     */
572
    public function testPatchRemoveAndChangeIdNotAllowed()
573
    {
574
        // Apply PATCH request
575
        $client = static::createRestClient();
576
        $patchJson = json_encode(
577
            [
578
                [
579
                    'op' => 'remove',
580
                    'path' => '/id'
581
                ]
582
            ]
583
        );
584
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
585
        $this->assertEquals(400, $client->getResponse()->getStatusCode());
586
    }
587
588
    /**
589
     * Test PATCH: add property to free object structure
590
     *
591
     * @return void
592
     */
593 View Code Duplication
    public function testPatchAddPropertyToFreeObject()
594
    {
595
        // Apply PATCH request
596
        $client = static::createRestClient();
597
        $patchJson = json_encode(
598
            [
599
                [
600
                    'op' => 'add',
601
                    'path' => '/unstructuredObject/hashField/newAddedField',
602
                    'value' => 'new field value'
603
                ]
604
            ]
605
        );
606
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
607
        $this->assertEquals(200, $client->getResponse()->getStatusCode());
608
609
        // Get changed showcase
610
        $client = static::createRestClient();
611
        $client->request('GET', '/hans/showcase/500');
612
613
        $result = $client->getResults();
614
        $this->assertEquals(
615
            'new field value',
616
            $result->unstructuredObject->hashField->newAddedField
617
        );
618
    }
619
620
    /**
621
     * Test PATCH for $ref attribute
622
     *
623
     * @return void
624
     * @incomplete
625
     */
626
    public function testApplyPatchForRefAttribute()
627
    {
628
        // Apply PATCH request
629
        $client = static::createRestClient();
630
        $patchJson = json_encode(
631
            [
632
                [
633
                    'op' => 'replace',
634
                    'path' => '/nestedApps/0',
635
                    'value' => [
636
                        '$ref' => 'http://localhost/core/app/admin'
637
                    ]
638
                ]
639
            ]
640
        );
641
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
642
        $this->assertEquals(200, $client->getResponse()->getStatusCode());
643
644
        // Check patched result
645
        $client = static::createRestClient();
646
        $client->request('GET', '/hans/showcase/500');
647
648
        $result = $client->getResults();
649
        $this->assertEquals(
650
            'http://localhost/core/app/admin',
651
            $result->nestedApps[0]->{'$ref'}
652
        );
653
    }
654
655
    /**
656
     * Test PATCH: apply patch which results to invalid Showcase schema
657
     *
658
     * @return void
659
     */
660
    public function testPatchToInvalidShowcase()
661
    {
662
        // Apply PATCH request, remove required field
663
        $client = static::createRestClient();
664
        $patchJson = json_encode(
665
            [
666
                [
667
                    'op' => 'remove',
668
                    'path' => '/anotherInt'
669
                ]
670
            ]
671
        );
672
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
673
        $this->assertEquals(400, $client->getResponse()->getStatusCode());
674
675
        // Check that Showcase has not been changed
676
        $client = static::createRestClient();
677
        $client->request('GET', '/hans/showcase/500');
678
679
        $result = $client->getResults();
680
        $this->assertObjectHasAttribute('anotherInt', $result);
681
    }
682
683
    /**
684
     * Test PATCH: remove element from array
685
     *
686
     * @return void
687
     */
688 View Code Duplication
    public function testRemoveFromArrayPatch()
689
    {
690
        // Apply PATCH request, remove nested app, initially there are 2 apps
691
        $client = static::createRestClient();
692
        $patchJson = json_encode(
693
            [
694
                [
695
                    'op' => 'remove',
696
                    'path' => '/nestedApps/0'
697
                ]
698
            ]
699
        );
700
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
701
        $this->assertEquals(200, $client->getResponse()->getStatusCode());
702
703
        // Check patched result
704
        $client = static::createRestClient();
705
        $client->request('GET', '/hans/showcase/500');
706
707
        $result = $client->getResults();
708
        $this->assertEquals(1, count($result->nestedApps));
709
        $this->assertEquals('http://localhost/core/app/admin', $result->nestedApps[0]->{'$ref'});
710
    }
711
712
    /**
713
     * Test PATCH: add new element to array
714
     *
715
     * @return void
716
     */
717
    public function testAddElementToSpecificIndexInArrayPatch()
718
    {
719
        // Apply PATCH request, add new element
720
        $client = static::createRestClient();
721
        $newElement = ['name' => 'element three'];
722
        $patchJson = json_encode(
723
            [
724
                [
725
                    'op' => 'add',
726
                    'path' => '/nestedArray/1',
727
                    'value' => $newElement
728
                ]
729
            ]
730
        );
731
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
732
        $this->assertEquals(200, $client->getResponse()->getStatusCode());
733
734
        // Check patched result
735
        $client = static::createRestClient();
736
        $client->request('GET', '/hans/showcase/500');
737
738
        $result = $client->getResults();
739
        $this->assertEquals(3, count($result->nestedArray));
740
        $this->assertJsonStringEqualsJsonString(
741
            json_encode($newElement),
742
            json_encode($result->nestedArray[1])
743
        );
744
    }
745
746
    /**
747
     * Test PATCH: add complex object App to array
748
     *
749
     * @group ref
750
     * @return void
751
     */
752 View Code Duplication
    public function testPatchAddComplexObjectToSpecificIndexInArray()
753
    {
754
        // Apply PATCH request, add new element
755
        $client = static::createRestClient();
756
        $newApp = ['$ref' => 'http://localhost/core/app/admin'];
757
        $patchJson = json_encode(
758
            [
759
                [
760
                    'op' => 'add',
761
                    'path' => '/nestedApps/0',
762
                    'value' => $newApp
763
                ]
764
            ]
765
        );
766
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
767
        $this->assertEquals(200, $client->getResponse()->getStatusCode());
768
769
        // Check patched result
770
        $client = static::createRestClient();
771
        $client->request('GET', '/hans/showcase/500');
772
773
        $result = $client->getResults();
774
        $this->assertEquals(3, count($result->nestedApps));
775
        $this->assertEquals(
776
            'http://localhost/core/app/admin',
777
            $result->nestedApps[0]->{'$ref'}
778
        );
779
    }
780
781
    /**
782
     * Test PATCH: add complex object App to array
783
     *
784
     * @group ref
785
     * @return void
786
     */
787 View Code Duplication
    public function testPatchAddComplexObjectToTheEndOfArray()
788
    {
789
        // Apply PATCH request, add new element
790
        $client = static::createRestClient();
791
        $newApp = ['$ref' => 'http://localhost/core/app/test'];
792
        $patchJson = json_encode(
793
            [
794
                [
795
                    'op' => 'add',
796
                    'path' => '/nestedApps/-',
797
                    'value' => $newApp
798
                ]
799
            ]
800
        );
801
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
802
        $this->assertEquals(200, $client->getResponse()->getStatusCode());
803
804
        // Check patched result
805
        $client = static::createRestClient();
806
        $client->request('GET', '/hans/showcase/500');
807
808
        $result = $client->getResults();
809
        $this->assertEquals(3, count($result->nestedApps));
810
        $this->assertEquals(
811
            'http://localhost/core/app/test',
812
            $result->nestedApps[2]->{'$ref'}
813
        );
814
    }
815
816
    /**
817
     * Test PATCH: test operation to undefined index
818
     *
819
     * @group ref
820
     * @return void
821
     */
822
    public function testPatchTestOperationToUndefinedIndexThrowsException()
823
    {
824
        // Apply PATCH request, add new element
825
        $client = static::createRestClient();
826
        $newApp = ['ref' => 'http://localhost/core/app/test'];
827
        $patchJson = json_encode(
828
            [
829
                [
830
                    'op' => 'test',
831
                    'path' => '/nestedApps/9',
832
                    'value' => $newApp
833
                ]
834
            ]
835
        );
836
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
837
        $this->assertEquals(400, $client->getResponse()->getStatusCode());
838
    }
839
840
    /**
841
     * Test PATCH: add complex object App to array
842
     *
843
     * @group ref
844
     * @return void
845
     */
846
    public function testPatchAddElementToUndefinedIndexResponseAsBadRequest()
847
    {
848
        // Apply PATCH request, add new element
849
        $client = static::createRestClient();
850
        $newApp = ['ref' => 'http://localhost/core/app/admin'];
851
        $patchJson = json_encode(
852
            [
853
                [
854
                    'op' => 'add',
855
                    'path' => '/nestedApps/9',
856
                    'value' => $newApp
857
                ]
858
            ]
859
        );
860
        $client->request('PATCH', '/hans/showcase/500', [], [], [], $patchJson);
861
        $this->assertEquals(400, $client->getResponse()->getStatusCode());
862
863
        // Check that patched document not changed
864
        $client = static::createRestClient();
865
        $client->request('GET', '/hans/showcase/500');
866
867
        $result = $client->getResults();
868
        $this->assertEquals(2, count($result->nestedApps));
869
    }
870
871
    /**
872
     * Encode string value in RQL
873
     *
874
     * @param string $value String value
875
     * @return string
876
     */
877 View Code Duplication
    private function encodeRqlString($value)
878
    {
879
        return strtr(
880
            rawurlencode($value),
881
            [
882
                '-' => '%2D',
883
                '_' => '%5F',
884
                '.' => '%2E',
885
                '~' => '%7E',
886
            ]
887
        );
888
    }
889
890
    /**
891
     * Trigger a 301 Status code
892
     *
893
     * @param string $url         requested url
894
     * @param string $redirectUrl redirected url
895
     * @dataProvider rqlDataProvider
896
     * @return void
897
     */
898
    public function testTrigger301($url, $redirectUrl)
899
    {
900
        $client = static::createRestClient();
901
        $client->request('GET', $url);
902
        $this->assertEquals(301, $client->getResponse()->getStatusCode());
903
        $this->assertEquals($redirectUrl, $client->getResponse()->headers->get('Location'));
904
    }
905
906
    /**
907
     * Provides urls for the testTrigger301() test.
908
     *
909
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,array<string,string>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
910
     */
911
    public function rqlDataProvider()
912
    {
913
        return [
914
            'rql' => ['url' => '/hans/showcase?id=blah' , 'redirect_url' => 'http://localhost/hans/showcase/?id=blah'],
915
            'noRql' => ['url' => '/hans/showcase' , 'redirect_url' => 'http://localhost/hans/showcase/']
916
        ];
917
    }
918
919
    /**
920
     * Here we test the client expectation in "id" property exposing in the json schema.
921
     *
922
     * They want
923
     * * "id" of an extref object should *not* be described/present in schema
924
     * * "id" of others, including embedded objects, *should* be described/present in schema
925
     *
926
     * @return void
927
     */
928
    public function testCorrectIdExposingInSchema()
929
    {
930
        // get the schema
931
        $client = static::createRestClient();
932
        $client->request('GET', '/schema/hans/showcase/item');
933
934
        $schema = $client->getResults();
935
936
        // make sure we have an extref field here
937
        $this->assertEquals('extref', $schema->properties->nestedApps->items->properties->{'$ref'}->format);
938
        // and that 'id' is not there
939
        $this->assertObjectNotHasAttribute('id', $schema->properties->nestedApps->items->properties);
940
941
        // embed case - check the embedded 'contactCode'
942
        $this->assertStringEndsWith('Embedded', $schema->properties->contactCode->{'x-documentClass'});
943
        $this->assertObjectHasAttribute('id', $schema->properties->contactCode->properties);
944
    }
945
946
    /**
947
     * test finding of showcases by ref
948
     *
949
     * @dataProvider findByExtrefProvider
950
     *
951
     * @param string  $field which reference to search in
952
     * @param mixed   $url   ref to search for
953
     * @param integer $count number of results to expect
954
     *
955
     * @return void
956
     */
957 View Code Duplication
    public function testFindByExtref($field, $url, $count)
958
    {
959
        $url = sprintf(
960
            '/hans/showcase/?%s=%s',
961
            $this->encodeRqlString($field),
962
            $this->encodeRqlString($url)
963
        );
964
965
        $client = static::createRestClient();
966
        $client->request('GET', $url);
967
        $this->assertEquals(Response::HTTP_OK, $client->getResponse()->getStatusCode());
968
        $this->assertCount($count, $client->getResults());
969
    }
970
971
    /**
972
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,array<string|integer>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
973
     */
974 View Code Duplication
    public function findByExtrefProvider()
975
    {
976
        return [
977
            'find a linked record when searching for "tablet" ref by array field' => [
978
                'nestedApps.0.$ref',
979
                'http://localhost/core/app/tablet',
980
                1
981
            ],
982
            'find a linked record when searching for "admin" ref by array field' => [
983
                'nestedApps.0.$ref',
984
                'http://localhost/core/app/admin',
985
                1
986
            ],
987
            'find nothing when searching for inextistant (and unlinked) ref by array field' => [
988
                'nestedApps.0.$ref',
989
                'http://localhost/core/app/inexistant',
990
                0
991
            ],
992
            'return nothing when searching with incomplete ref by array field' => [
993
                'nestedApps.0.$ref',
994
                'http://localhost/core/app',
995
                0
996
            ],
997
        ];
998
    }
999
}
1000