AppControllerTest   A
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 976
Duplicated Lines 6.56 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 4
dl 64
loc 976
rs 9.144
c 0
b 0
f 0

34 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 12 1
A testFindAll() 0 29 1
A testGeneratedPagingHeadersNoRql() 0 28 1
A testGetAppWithFilteringAndPaging() 23 23 1
B testGetAppPagingWithRql() 0 83 1
A testInvalidPagingPageSize() 0 8 1
A invalidPagingPageSizeProvider() 0 7 1
A testRqlIsParsedOnlyOnGetRequest() 0 51 1
A testOnlyRqlSelectIsAllowedOnGetOne() 0 28 2
A testFindAllEmptyCollection() 15 15 1
A testGetApp() 0 20 1
A testPostApp() 0 30 1
A testPostEmptyApp() 0 16 1
A testPostNonObjectApp() 0 9 1
A testPostMalformedApp() 0 29 2
A testPostWithId() 0 15 1
A testPutApp() 0 28 1
A testPatchAppRequestApplyChanges() 0 39 1
A testMalformedPatchAppRequest() 0 29 1
A testNonMatchingIdPutApp() 0 20 1
A testPutAppNoIdInPayload() 0 21 1
A testUpsertApp() 0 13 1
A testDeleteApp() 0 20 1
A testFailingBooleanValidationOnAppUpdate() 0 18 1
A testGetAppSchemaInformation() 0 9 1
A testNoRecordsAreGeneratedOnPreRequests() 12 12 1
A testGetAppSchemaInformationCanonical() 0 8 1
A testGetAppCollectionSchemaInformation() 0 28 1
A testSearchableTranslations() 0 14 1
A testUpdateTranslatableOnlySecondaryLocale() 0 27 1
A searchableTranslationDataProvider() 0 11 1
A testRqlSyntaxError() 14 14 1
A assertIsSchemaResponse() 0 5 1
A assertIsAppSchema() 0 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 /core/app
4
 */
5
6
namespace Graviton\CoreBundle\Tests\Controller;
7
8
use Graviton\TestBundle\Test\RestTestCase;
9
use Symfony\Component\HttpFoundation\Response;
10
11
/**
12
 * Basic functional test for /core/app.
13
 *
14
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
15
 * @license  https://opensource.org/licenses/MIT MIT License
16
 * @link     http://swisscom.ch
17
 */
18
class AppControllerTest extends RestTestCase
19
{
20
    /**
21
     * @const complete content type string expected on a resouce
22
     */
23
    const CONTENT_TYPE = 'application/json; charset=UTF-8';
24
25
    const SCHEMA_URL_ITEM = 'http://localhost/schema/core/app/item';
26
27
    const SCHEMA_URL_COLLECTION = 'http://localhost/schema/core/app/collection';
28
29
    /**
30
     * setup client and load fixtures
31
     *
32
     * @return void
33
     */
34
    public function setUp()
35
    {
36
        $this->loadFixturesLocal(
37
            array(
38
                'Graviton\CoreBundle\DataFixtures\MongoDB\LoadAppData',
39
                'Graviton\I18nBundle\DataFixtures\MongoDB\LoadLanguageData',
40
                'Graviton\I18nBundle\DataFixtures\MongoDB\LoadMultiLanguageData',
41
                'Graviton\I18nBundle\DataFixtures\MongoDB\LoadTranslationLanguageData',
42
                'Graviton\I18nBundle\DataFixtures\MongoDB\LoadTranslationAppData'
43
            )
44
        );
45
    }
46
    /**
47
     * check if all fixtures are returned on GET
48
     *
49
     * @return void
50
     */
51
    public function testFindAll()
52
    {
53
        $client = static::createRestClient();
54
        $client->request('GET', '/core/app/');
55
56
        $response = $client->getResponse();
57
        $results = $client->getResults();
58
59
        $this->assertResponseContentType(self::CONTENT_TYPE, $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 56 can be null; however, Graviton\TestBundle\Test...rtResponseContentType() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
60
        $this->assertResponseSchemaRel(self::SCHEMA_URL_COLLECTION, $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 56 can be null; however, Graviton\TestBundle\Test...sertResponseSchemaRel() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
61
        $this->assertEquals(2, count($results));
62
63
        $this->assertEquals('admin', $results[0]->id);
64
        $this->assertEquals('Administration', $results[0]->name->en);
65
        $this->assertEquals(true, $results[0]->showInMenu);
66
        $this->assertEquals(2, $results[0]->order);
67
68
        $this->assertEquals('tablet', $results[1]->id);
69
        $this->assertEquals('Tablet', $results[1]->name->en);
70
        $this->assertEquals(true, $results[1]->showInMenu);
71
        $this->assertEquals(1, $results[1]->order);
72
73
        $this->assertContains(
74
            '<http://localhost/core/app/>; rel="self"',
75
            $response->headers->get('Link')
76
        );
77
        $this->assertEquals('*', $response->headers->get('Access-Control-Allow-Origin'));
78
        $this->assertEquals('DENY', $response->headers->get('X-Frame-Options'));
79
    }
80
81
    /**
82
     * test that our paging headers are correct if client does NOT provide rql BUT
83
     * we have more records in the db then the default pagesize (= we will add limit() clauses to Link elements)
84
     *
85
     * @return void
86
     */
87
    public function testGeneratedPagingHeadersNoRql()
88
    {
89
        $this->loadFixturesLocal(
90
            [
91
                'Graviton\CoreBundle\DataFixtures\MongoDB\LoadAppDataExceedSinglePageLimit'
92
            ]
93
        );
94
95
        $client = static::createRestClient();
96
        $client->request('GET', '/core/app/');
97
98
        $response = $client->getResponse();
99
100
        $this->assertContains(
101
            '<http://localhost/core/app/?limit(10%2C0)>; rel="self"',
102
            $response->headers->get('Link')
103
        );
104
105
        $this->assertContains(
106
            '<http://localhost/core/app/?limit(10%2C10)>; rel="next"',
107
            $response->headers->get('Link')
108
        );
109
110
        $this->assertContains(
111
            '<http://localhost/core/app/?limit(10%2C10)>; rel="last"',
112
            $response->headers->get('Link')
113
        );
114
    }
115
116
    /**
117
     * test if we can get list of apps, paged and with filters..
118
     *
119
     * @return void
120
     */
121 View Code Duplication
    public function testGetAppWithFilteringAndPaging()
122
    {
123
        $client = static::createRestClient();
124
        $client->request('GET', '/core/app/?eq(showInMenu,true)&limit(1)');
125
        $response = $client->getResponse();
126
127
        $this->assertEquals(1, count($client->getResults()));
128
129
        $this->assertContains(
130
            '<http://localhost/core/app/?eq(showInMenu%2Ctrue)&limit(1)>; rel="self"',
131
            $response->headers->get('Link')
132
        );
133
134
        $this->assertContains(
135
            '<http://localhost/core/app/?eq(showInMenu%2Ctrue)&limit(1%2C1)>; rel="next"',
136
            $response->headers->get('Link')
137
        );
138
139
        $this->assertContains(
140
            '<http://localhost/core/app/?eq(showInMenu%2Ctrue)&limit(1%2C1)>; rel="last"',
141
            $response->headers->get('Link')
142
        );
143
    }
144
145
    /**
146
     * rql limit() should *never* be overwritten by default value
147
     *
148
     * @return void
149
     */
150
    public function testGetAppPagingWithRql()
151
    {
152
        // does limit work?
153
        $client = static::createRestClient();
154
        $client->request('GET', '/core/app/?limit(1)');
155
        $this->assertEquals(1, count($client->getResults()));
156
157
        $response = $client->getResponse();
158
159
        $this->assertContains(
160
            '<http://localhost/core/app/?limit(1)>; rel="self"',
161
            $response->headers->get('Link')
162
        );
163
164
        $this->assertContains(
165
            '<http://localhost/core/app/?limit(1%2C1)>; rel="next"',
166
            $response->headers->get('Link')
167
        );
168
169
        $this->assertContains(
170
            '<http://localhost/core/app/?limit(1%2C1)>; rel="last"',
171
            $response->headers->get('Link')
172
        );
173
174
        $this->assertSame('2', $response->headers->get('X-Total-Count'));
175
        $this->assertSame('1', $response->headers->get('X-Record-Count'));
176
177
        /*** pagination tests **/
178
        $client = static::createRestClient();
179
        $client->request('GET', '/core/app/?limit(1,1)');
180
        $this->assertEquals(1, count($client->getResults()));
181
182
        $response = $client->getResponse();
183
184
        $this->assertContains(
185
            '<http://localhost/core/app/?limit(1%2C1)>; rel="self"',
186
            $response->headers->get('Link')
187
        );
188
189
        $this->assertContains(
190
            '<http://localhost/core/app/?limit(1%2C0)>; rel="prev"',
191
            $response->headers->get('Link')
192
        );
193
194
        // we're on the 'last' page - so 'last' should not be in in Link header
195
        $this->assertNotContains(
196
            'rel="last"',
197
            $response->headers->get('Link')
198
        );
199
200
        $this->assertSame('2', $response->headers->get('X-Total-Count'));
201
        $this->assertSame('1', $response->headers->get('X-Record-Count'));
202
203
        /*** pagination with different rql test **/
204
        $client = static::createRestClient();
205
        $client->request('GET', '/core/app/?limit(1)&select(id)&sort(-order)');
206
        $this->assertEquals(1, count($client->getResults()));
207
208
        $response = $client->getResponse();
209
210
        $this->assertContains(
211
            'http://localhost/core/app/?limit(1)&select(id)&sort(-order)>; rel="self"',
212
            $response->headers->get('Link')
213
        );
214
215
        $this->assertContains(
216
            '<http://localhost/core/app/?limit(1%2C1)&select(id)&sort(-order)>; rel="next"',
217
            $response->headers->get('Link')
218
        );
219
220
        $this->assertContains(
221
            '<http://localhost/core/app/?limit(1%2C1)&select(id)&sort(-order)>; rel="last"',
222
            $response->headers->get('Link')
223
        );
224
225
        $this->assertNotContains(
226
            'rel="prev"',
227
            $response->headers->get('Link')
228
        );
229
230
        $this->assertSame('2', $response->headers->get('X-Total-Count'));
231
        $this->assertSame('1', $response->headers->get('X-Record-Count'));
232
    }
233
234
    /**
235
     * check for a client error if invalid limit value is provided
236
     *
237
     * @dataProvider invalidPagingPageSizeProvider
238
     *
239
     * @param integer $limit limit value that should fail
240
     * @return void
241
     */
242
    public function testInvalidPagingPageSize($limit)
243
    {
244
        $client = static::createRestClient();
245
        $client->request('GET', sprintf('/core/app/?limit(%s)', $limit));
246
247
        $this->assertEquals(Response::HTTP_BAD_REQUEST, $client->getResponse()->getStatusCode());
248
        $this->assertContains('invalid limit in rql', $client->getResults()->message);
249
    }
250
251
    /**
252
     * page size test provides
253
     *
254
     * @return array[]
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use 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...
255
     */
256
    public function invalidPagingPageSizeProvider()
257
    {
258
        return [
259
            [0],
260
            [-1],
261
        ];
262
    }
263
264
    /**
265
     * RQL is parsed only when we get apps
266
     *
267
     * @return void
268
     */
269
    public function testRqlIsParsedOnlyOnGetRequest()
270
    {
271
        $appData = [
272
            'showInMenu' => false,
273
            'order'      => 100,
274
            'name'      => ['en' => 'Administration'],
275
        ];
276
277
        $client = static::createRestClient();
278
        $client->request('GET', '/core/app/?invalidrqlquery');
279
        $this->assertEquals(Response::HTTP_BAD_REQUEST, $client->getResponse()->getStatusCode());
280
        $this->assertContains('syntax error in rql', $client->getResults()->message);
281
282
        $client = static::createRestClient();
283
        $client->request('GET', '/core/app/admin?invalidrqlquery');
284
        $this->assertEquals(Response::HTTP_BAD_REQUEST, $client->getResponse()->getStatusCode());
285
        $this->assertContains('syntax error in rql', $client->getResults()->message);
286
287
        $client = static::createRestClient();
288
        $client->request('OPTIONS', '/core/app/?invalidrqlquery');
289
        $this->assertEquals(Response::HTTP_NO_CONTENT, $client->getResponse()->getStatusCode());
290
291
        $client = static::createRestClient();
292
        $client->request('OPTIONS', '/schema/core/app/collection?invalidrqlquery');
293
        $this->assertEquals(Response::HTTP_NO_CONTENT, $client->getResponse()->getStatusCode());
294
295
        $client = static::createRestClient();
296
        $client->request('OPTIONS', '/schema/core/app/item?invalidrqlquery');
297
        $this->assertEquals(Response::HTTP_NO_CONTENT, $client->getResponse()->getStatusCode());
298
299
        $client = static::createRestClient();
300
        $client->request('GET', '/schema/core/app/collection?invalidrqlquery');
301
        $this->assertEquals(Response::HTTP_OK, $client->getResponse()->getStatusCode());
302
303
        $client = static::createRestClient();
304
        $client->request('GET', '/schema/core/app/item?invalidrqlquery');
305
        $this->assertEquals(Response::HTTP_OK, $client->getResponse()->getStatusCode());
306
307
308
        $client = static::createRestClient();
309
        $client->post('/core/app/?invalidrqlquery', $appData);
310
        $this->assertEquals(Response::HTTP_CREATED, $client->getResponse()->getStatusCode());
311
312
        $client = static::createRestClient();
313
        $client->put('/core/app/admin?invalidrqlquery', $appData);
314
        $this->assertEquals(Response::HTTP_NO_CONTENT, $client->getResponse()->getStatusCode());
315
316
        $client = static::createRestClient();
317
        $client->request('DELETE', '/core/app/admin?invalidrqlquery');
318
        $this->assertEquals(Response::HTTP_NO_CONTENT, $client->getResponse()->getStatusCode());
319
    }
320
321
    /**
322
     * Test only RQL select() operator is allowed for GET one
323
     *
324
     * @return void
325
     * @group tmp
326
     */
327
    public function testOnlyRqlSelectIsAllowedOnGetOne()
328
    {
329
        $client = static::createRestClient();
330
        $client->request('GET', '/core/app/?select(id)');
331
        $this->assertEquals(Response::HTTP_OK, $client->getResponse()->getStatusCode());
332
333
        $client = static::createRestClient();
334
        $client->request('GET', '/core/app/admin?select(id)');
335
        $this->assertEquals(Response::HTTP_OK, $client->getResponse()->getStatusCode());
336
337
        foreach ([
338
                     'limit' => 'limit(1)',
339
                     'sort'  => 'sort(+id)',
340
                     'eq'    => 'eq(id,a)',
341
                 ] as $extraRqlOperator => $extraRqlOperatorQuery) {
342
            $client = static::createRestClient();
343
            $client->request('GET', '/core/app/?select(id)&'.$extraRqlOperatorQuery);
344
            $this->assertEquals(Response::HTTP_OK, $client->getResponse()->getStatusCode());
345
346
            $client = static::createRestClient();
347
            $client->request('GET', '/core/app/admin?select(id)&'.$extraRqlOperatorQuery);
348
            $this->assertEquals(Response::HTTP_BAD_REQUEST, $client->getResponse()->getStatusCode());
349
            $this->assertEquals(
350
                sprintf('RQL operator "%s" is not allowed for this request', $extraRqlOperator),
351
                $client->getResults()->message
352
            );
353
        }
354
    }
355
356
    /**
357
     * check for empty collections when no fixtures are loaded
358
     *
359
     * @return void
360
     */
361 View Code Duplication
    public function testFindAllEmptyCollection()
362
    {
363
        // reset fixtures since we already have some from setUp
364
        $this->loadFixturesLocal([]);
365
        $client = static::createRestClient();
366
        $client->request('GET', '/core/app/');
367
368
        $response = $client->getResponse();
369
        $results = $client->getResults();
370
371
        $this->assertResponseContentType(self::CONTENT_TYPE, $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 368 can be null; however, Graviton\TestBundle\Test...rtResponseContentType() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
372
        $this->assertResponseSchemaRel(self::SCHEMA_URL_COLLECTION, $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 368 can be null; however, Graviton\TestBundle\Test...sertResponseSchemaRel() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
373
374
        $this->assertEquals([], $results);
375
    }
376
377
    /**
378
     * test if we can get an app by id
379
     *
380
     * @return void
381
     */
382
    public function testGetApp()
383
    {
384
        $client = static::createRestClient();
385
        $client->request('GET', '/core/app/admin');
386
        $response = $client->getResponse();
387
        $results = $client->getResults();
388
389
        $this->assertResponseContentType(self::CONTENT_TYPE, $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 386 can be null; however, Graviton\TestBundle\Test...rtResponseContentType() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
390
        $this->assertResponseSchemaRel(self::SCHEMA_URL_ITEM, $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 386 can be null; however, Graviton\TestBundle\Test...sertResponseSchemaRel() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
391
392
        $this->assertEquals('admin', $results->id);
393
        $this->assertEquals('Administration', $results->name->en);
394
        $this->assertEquals(true, $results->showInMenu);
395
396
        $this->assertContains(
397
            '<http://localhost/core/app/admin>; rel="self"',
398
            $response->headers->get('Link')
399
        );
400
        $this->assertEquals('*', $response->headers->get('Access-Control-Allow-Origin'));
401
    }
402
403
    /**
404
     * test if we can create an app through POST
405
     *
406
     * @return void
407
     */
408
    public function testPostApp()
409
    {
410
        $testApp = new \stdClass;
411
        $testApp->name = new \stdClass;
412
        $testApp->name->en = 'new Test App';
413
        $testApp->showInMenu = true;
414
415
        $client = static::createRestClient();
416
        $client->post('/core/app/', $testApp);
417
        $response = $client->getResponse();
418
        $results = $client->getResults();
419
420
        // we sent a location header so we don't want a body
421
        $this->assertNull($results);
422
        $this->assertContains('/core/app/', $response->headers->get('Location'));
423
424
        $client = static::createRestClient();
425
        $client->request('GET', $response->headers->get('Location'));
426
        $response = $client->getResponse();
427
        $results = $client->getResults();
428
429
        $this->assertResponseContentType(self::CONTENT_TYPE, $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 426 can be null; however, Graviton\TestBundle\Test...rtResponseContentType() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
430
        $this->assertResponseSchemaRel(self::SCHEMA_URL_ITEM, $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 426 can be null; however, Graviton\TestBundle\Test...sertResponseSchemaRel() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
431
        $this->assertEquals('new Test App', $results->name->en);
432
        $this->assertTrue($results->showInMenu);
433
        $this->assertContains(
434
            '<http://localhost/core/app/'.$results->id.'>; rel="self"',
435
            explode(',', $response->headers->get('Link'))
436
        );
437
    }
438
439
    /**
440
     * test if we get a correct return if we post empty.
441
     *
442
     * @return void
443
     */
444
    public function testPostEmptyApp()
445
    {
446
        $client = static::createRestClient();
447
448
        // send nothing really..
449
        $client->post('/core/app/', "", [], [], [], false);
450
451
        $response = $client->getResponse();
452
453
        $this->assertContains(
454
            'No input data',
455
            $response->getContent()
456
        );
457
458
        $this->assertEquals(400, $response->getStatusCode());
459
    }
460
461
    /**
462
     * test if we get a correct return if we post empty.
463
     *
464
     * @return void
465
     */
466
    public function testPostNonObjectApp()
467
    {
468
        $client = static::createRestClient();
469
        $client->post('/core/app/', "non-object value");
470
471
        $response = $client->getResponse();
472
        $this->assertContains('JSON request body must be an object', $response->getContent());
473
        $this->assertEquals(400, $response->getStatusCode());
474
    }
475
476
    /**
477
     * test if 500 error is reported when posting an malformed input
478
     *
479
     * @return void
480
     */
481
    public function testPostMalformedApp()
482
    {
483
        $testApp = new \stdClass;
484
        $testApp->name = new \stdClass;
485
        $testApp->name->en = 'new Test App';
486
        $testApp->showInMenu = true;
487
488
        // malform it ;-)
489
        $input = str_replace(":", ";", json_encode($testApp));
490
491
        $client = static::createRestClient();
492
493
        // make sure this is sent as 'raw' input (not json_encoded again)
494
        $client->post('/core/app/', $input, [], [], [], false);
495
496
        $response = $client->getResponse();
497
498
        // Check that error message contains detailed reason
499
        json_decode($input);
500
        $lastJsonError = function_exists('json_last_error_msg')
501
            ? json_last_error_msg()
502
            : 'Unable to decode JSON string';
503
        $this->assertContains(
504
            $lastJsonError,
505
            $client->getResults()->message
506
        );
507
508
        $this->assertEquals(400, $response->getStatusCode());
509
    }
510
511
    /**
512
     * Tests if an error is returned when an id is send in a post
513
     *
514
     * @return void
515
     */
516
    public function testPostWithId()
517
    {
518
        $helloApp = new \stdClass();
519
        $helloApp->id = 101;
520
        $helloApp->name = "tubel";
521
522
        $client = static::createRestClient();
523
        $client->post('/person/customer', $helloApp);
524
525
        $this->assertEquals(
526
            'Bad Request - "id" can not be given on a POST request. '.
527
            'Do a PUT request instead to update an existing record.',
528
            $client->getResults()->message
529
        );
530
    }
531
    /**
532
     * test updating apps
533
     *
534
     * @return void
535
     */
536
    public function testPutApp()
537
    {
538
        $helloApp = new \stdClass();
539
        $helloApp->id = "tablet";
540
        $helloApp->name = new \stdClass();
541
        $helloApp->name->en = "Tablet";
542
        $helloApp->showInMenu = false;
543
544
        $client = static::createRestClient();
545
        $client->put('/core/app/tablet', $helloApp);
546
547
        $this->assertNull($client->getResults());
548
        $this->assertNull($client->getResponse()->headers->get('Location'));
549
550
        $client = static::createRestClient();
551
        $client->request('GET', '/core/app/tablet');
552
        $response = $client->getResponse();
553
        $results = $client->getResults();
554
555
        $this->assertResponseContentType(self::CONTENT_TYPE, $response);
556
        $this->assertResponseSchemaRel(self::SCHEMA_URL_ITEM, $response);
557
        $this->assertEquals('Tablet', $results->name->en);
558
        $this->assertFalse($results->showInMenu);
559
        $this->assertContains(
560
            '<http://localhost/core/app/tablet>; rel="self"',
561
            explode(',', $response->headers->get('Link'))
562
        );
563
    }
564
565
    /**
566
     * Test for PATCH Request
567
     *
568
     * @return void
569
     */
570
    public function testPatchAppRequestApplyChanges()
571
    {
572
        $helloApp = new \stdClass();
573
        $helloApp->id = "testapp";
574
        $helloApp->name = new \stdClass();
575
        $helloApp->name->en = "Test App";
576
        $helloApp->showInMenu = false;
577
578
        // 1. Create some App
579
        $client = static::createRestClient();
580
        $client->put('/core/app/' . $helloApp->id, $helloApp);
581
582
        // 2. PATCH request
583
        $client = static::createRestClient();
584
        $patchJson = json_encode(
585
            [
586
                [
587
                    'op' => 'replace',
588
                    'path' => '/name/en',
589
                    'value' => 'Test App Patched'
590
                ]
591
            ]
592
        );
593
        $client->request('PATCH', '/core/app/' . $helloApp->id, [], [], [], $patchJson);
594
        $response = $client->getResponse();
595
596
        $this->assertEquals(200, $response->getStatusCode());
597
598
        // 3. Get changed App and check changed title
599
        $client = static::createRestClient();
600
        $client->request('GET', '/core/app/' . $helloApp->id);
601
602
        $response = $client->getResponse();
603
        $results = $client->getResults();
604
605
        $this->assertResponseContentType(self::CONTENT_TYPE, $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 602 can be null; however, Graviton\TestBundle\Test...rtResponseContentType() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
606
        $this->assertResponseSchemaRel(self::SCHEMA_URL_ITEM, $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 602 can be null; however, Graviton\TestBundle\Test...sertResponseSchemaRel() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
607
        $this->assertEquals('Test App Patched', $results->name->en);
608
    }
609
610
    /**
611
     * Test for Malformed PATCH Request
612
     *
613
     * @return void
614
     */
615
    public function testMalformedPatchAppRequest()
616
    {
617
        $helloApp = new \stdClass();
618
        $helloApp->id = "testapp";
619
        $helloApp->title = new \stdClass();
620
        $helloApp->title->en = "Test App";
621
        $helloApp->showInMenu = false;
622
623
        // 1. Create some App
624
        $client = static::createRestClient();
625
        $client->put('/core/app/' . $helloApp->id, $helloApp);
626
627
        // 2. PATCH request
628
        $client = static::createRestClient();
629
        $patchJson = json_encode(
630
            array(
631
                'op' => 'unknown',
632
                'path' => '/title/en'
633
            )
634
        );
635
        $client->request('PATCH', '/core/app/' . $helloApp->id, [], [], [], $patchJson);
636
        $response = $client->getResponse();
637
638
        $this->assertEquals(400, $response->getStatusCode());
639
        $this->assertContains(
640
            'Invalid JSON patch request',
641
            $response->getContent()
642
        );
643
    }
644
645
    /**
646
     * Try to update an app with a non matching ID in GET and req body
647
     *
648
     * @return void
649
     */
650
    public function testNonMatchingIdPutApp()
651
    {
652
        $helloApp = new \stdClass();
653
        $helloApp->id = "tablet";
654
        $helloApp->name = new \stdClass();
655
        $helloApp->name->en = "Tablet";
656
        $helloApp->showInMenu = false;
657
658
        $client = static::createRestClient();
659
        $client->put('/core/app/someotherapp', $helloApp);
660
661
        $response = $client->getResponse();
662
663
        $this->assertContains(
664
            'Record ID in your payload must be the same',
665
            $response->getContent()
666
        );
667
668
        $this->assertEquals(400, $response->getStatusCode());
669
    }
670
671
    /**
672
     * We had an issue when PUTing without ID would create a new record.
673
     * This test ensures that we don't do that, instead we should apply the ID from the GET req.
674
     *
675
     * @return void
676
     */
677
    public function testPutAppNoIdInPayload()
678
    {
679
        $helloApp = new \stdClass();
680
        $helloApp->name = new \stdClass();
681
        $helloApp->name->en = 'New tablet';
682
        $helloApp->showInMenu = false;
683
684
        $client = static::createRestClient();
685
        $client->put('/core/app/tablet', $helloApp);
686
687
        // we sent a location header so we don't want a body
688
        $this->assertNull($client->getResults());
689
690
        $client = static::createRestClient();
691
        $client->request('GET', '/core/app/tablet');
692
        $results = $client->getResults();
693
694
        $this->assertEquals('tablet', $results->id);
695
        $this->assertEquals('New tablet', $results->name->en);
696
        $this->assertFalse($results->showInMenu);
697
    }
698
699
    /**
700
     * test updating an inexistant document (upsert)
701
     *
702
     * @return void
703
     */
704
    public function testUpsertApp()
705
    {
706
        $isnogudApp = new \stdClass;
707
        $isnogudApp->id = 'isnogud';
708
        $isnogudApp->name = new \stdClass;
709
        $isnogudApp->name->en = 'I don\'t exist';
710
        $isnogudApp->showInMenu = true;
711
712
        $client = static::createRestClient();
713
        $client->put('/core/app/isnogud', $isnogudApp);
714
715
        $this->assertEquals(204, $client->getResponse()->getStatusCode());
716
    }
717
718
    /**
719
     * test deleting an app
720
     *
721
     * @return void
722
     */
723
    public function testDeleteApp()
724
    {
725
        $testApp = new \stdClass;
726
        $testApp->id = 'tablet';
727
        $testApp->name = 'Tablet';
728
        $testApp->showInMenu = true;
729
        $testApp->order = 1;
730
731
        $client = static::createRestClient();
732
        $client->request('DELETE', '/core/app/tablet');
733
734
        $response = $client->getResponse();
735
736
        $this->assertEquals(204, $response->getStatusCode());
737
        $this->assertEquals('*', $response->headers->get('Access-Control-Allow-Origin'));
738
        $this->assertEmpty($response->getContent());
739
740
        $client->request('GET', '/core/app/tablet');
741
        $this->assertEquals(404, $client->getResponse()->getStatusCode());
742
    }
743
744
    /**
745
     * test failing validation on boolean field
746
     *
747
     * @return void
748
     */
749
    public function testFailingBooleanValidationOnAppUpdate()
750
    {
751
        $helloApp = new \stdClass;
752
        $helloApp->id = 'tablet';
753
        $helloApp->name = new \stdClass;
754
        $helloApp->name->en = 'Tablet';
755
        $helloApp->showInMenu = 'false';
756
757
        $client = static::createRestClient();
758
        $client->put('/core/app/tablet', $helloApp);
759
760
        $results = $client->getResults();
761
762
        $this->assertEquals(400, $client->getResponse()->getStatusCode());
763
764
        $this->assertContains('showInMenu', $results[0]->propertyPath);
765
        $this->assertEquals('String value found, but a boolean is required', $results[0]->message);
766
    }
767
768
    /**
769
     * test getting schema information
770
     *
771
     * @return void
772
     */
773
    public function testGetAppSchemaInformation()
774
    {
775
        $client = static::createRestClient();
776
        $client->request('OPTIONS', '/core/app/hello');
777
778
        $response = $client->getResponse();
779
780
        $this->assertCorsHeaders('GET, POST, PUT, PATCH, DELETE, OPTIONS', $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 778 can be null; however, Graviton\TestBundle\Test...se::assertCorsHeaders() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
781
    }
782
783
    /**
784
     * requests on OPTIONS and HEAD shall not lead graviton to get any data from mongodb.
785
     * if we page limit(1) this will lead to presence of the x-total-count header if
786
     * data is generated (asserted by testGetAppPagingWithRql()). thus, if we don't
787
     * have this header, we can safely assume that no data has been processed in RestController.
788
     *
789
     * @return void
790
     */
791 View Code Duplication
    public function testNoRecordsAreGeneratedOnPreRequests()
792
    {
793
        $client = static::createRestClient();
794
        $client->request('OPTIONS', '/core/app/?limit(1)');
795
        $response = $client->getResponse();
796
        $this->assertArrayNotHasKey('x-total-count', $response->headers->all());
797
798
        $client = static::createRestClient();
799
        $client->request('HEAD', '/core/app/?limit(1)');
800
        $response = $client->getResponse();
801
        $this->assertArrayNotHasKey('x-total-count', $response->headers->all());
802
    }
803
804
    /**
805
     * test getting schema information from canonical url
806
     *
807
     * @return void
808
     */
809
    public function testGetAppSchemaInformationCanonical()
810
    {
811
        $client = static::createRestClient();
812
        $client->request('GET', '/schema/core/app/item');
813
814
        $this->assertIsSchemaResponse($client->getResponse());
0 ignored issues
show
Bug introduced by
It seems like $client->getResponse() can be null; however, assertIsSchemaResponse() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
815
        $this->assertIsAppSchema($client->getResults());
816
    }
817
818
    /**
819
     * test getting collection schema
820
     *
821
     * @return void
822
     */
823
    public function testGetAppCollectionSchemaInformation()
824
    {
825
        $client = static::createRestClient();
826
827
        $client->request('GET', '/schema/core/app/collection');
828
829
        $response = $client->getResponse();
830
        $results = $client->getResults();
831
832
        $this->assertResponseContentType('application/schema+json', $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 829 can be null; however, Graviton\TestBundle\Test...rtResponseContentType() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
833
        $this->assertEquals(200, $response->getStatusCode());
834
835
        $this->assertEquals('Array of app objects', $results->title);
836
        $this->assertEquals('array', $results->type);
837
        $this->assertIsAppSchema($results->items);
838
        $this->assertEquals('en', $results->items->properties->name->required[0]);
839
840
        $this->assertCorsHeaders('GET, POST, PUT, PATCH, DELETE, OPTIONS', $response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $client->getResponse() on line 829 can be null; however, Graviton\TestBundle\Test...se::assertCorsHeaders() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
841
        $this->assertContains(
842
            'Link',
843
            explode(',', $response->headers->get('Access-Control-Expose-Headers'))
844
        );
845
846
        $this->assertContains(
847
            '<http://localhost/schema/core/app/collection>; rel="self"',
848
            explode(',', $response->headers->get('Link'))
849
        );
850
    }
851
852
    /**
853
     * Test for searchable translations
854
     *
855
     * @dataProvider searchableTranslationDataProvider
856
     *
857
     * @param string $expr     expression
858
     * @param int    $expCount count
859
     *
860
     * @return void
861
     */
862
    public function testSearchableTranslations($expr, $expCount)
863
    {
864
        $client = static::createRestClient();
865
        $client->request(
866
            'GET',
867
            '/core/app/?'.$expr,
868
            [],
869
            [],
870
            array('HTTP_ACCEPT_LANGUAGE' => 'en, de')
871
        );
872
873
        $result = $client->getResults();
874
        $this->assertCount($expCount, $result);
875
    }
876
877
    /**
878
     * see that if primary locale is not in accept languages, that we ca apply
879
     * changes on translatables anyway..
880
     *
881
     * @return void
882
     */
883
    public function testUpdateTranslatableOnlySecondaryLocale()
884
    {
885
        // 2. PATCH request
886
        $client = static::createRestClient();
887
        $patchJson = json_encode(
888
            [
889
                [
890
                    'op' => 'replace',
891
                    'path' => '/name/de',
892
                    'value' => 'Mein neuer Name'
893
                ]
894
            ]
895
        );
896
        $client->request('PATCH', '/core/app/tablet', [], [], ['HTTP_ACCEPT_LANGUAGE' => 'de'], $patchJson);
897
        $response = $client->getResponse();
898
899
        $this->assertEquals(200, $response->getStatusCode());
900
901
        $client = static::createRestClient();
902
903
        $client->request('GET', '/core/app/tablet', [], [], ['HTTP_ACCEPT_LANGUAGE' => 'de,en']);
904
        $result = $client->getResults();
905
906
        $this->assertEquals(200, $response->getStatusCode());
907
        $this->assertEquals('Tablet', $result->name->en);
908
        $this->assertEquals('Mein neuer Name', $result->name->de);
909
    }
910
911
    /**
912
     * data provider for searchable translations
913
     *
914
     * @return array data
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...
915
     */
916
    public function searchableTranslationDataProvider()
917
    {
918
        return [
919
            'simple-de' => array('eq(name.de,Die%20Administration)', 1),
920
            'non-existent' => array('eq(name.de,Administration)', 0),
921
            'english' => array('eq(name.en,Administration)', 1),
922
            'no-lang' => array('eq(name,Administration)', 1),
923
            'glob' => array('like(name.de,*Administr*)', 1),
924
            'all-glob' => array('like(name.de,*a*)', 2)
925
        ];
926
    }
927
928
    /**
929
     * ensure we have nice parse error output in rql parse failure
930
     *
931
     * @return void
932
     */
933 View Code Duplication
    public function testRqlSyntaxError()
934
    {
935
        $client = static::createRestClient();
936
937
        $client->request('GET', '/core/app/?eq(name)');
938
939
        $response = $client->getResponse();
940
        $results = $client->getResults();
941
942
        $this->assertEquals(400, $response->getStatusCode());
943
944
        $this->assertContains('syntax error in rql: ', $results->message);
945
        $this->assertContains('Unexpected token', $results->message);
946
    }
947
948
    /**
949
     * check if response looks like schema
950
     *
951
     * @param object $response response
952
     *
953
     * @return void
954
     */
955
    private function assertIsSchemaResponse($response)
956
    {
957
        $this->assertResponseContentType('application/schema+json', $response);
958
        $this->assertEquals(200, $response->getStatusCode());
959
    }
960
961
    /**
962
     * check if a schema is of the app type
963
     *
964
     * @param \stdClass $schema schema from service to validate
965
     *
966
     * @return void
967
     */
968
    private function assertIsAppSchema(\stdClass $schema)
969
    {
970
        $this->assertEquals('App', $schema->title);
971
        $this->assertEquals('A graviton based app.', $schema->description);
972
        $this->assertEquals('object', $schema->type);
973
974
        $this->assertEquals('string', $schema->properties->id->type);
975
        $this->assertEquals('ID', $schema->properties->id->title);
976
        $this->assertEquals('Unique identifier for an app.', $schema->properties->id->description);
977
        $this->assertContains('id', $schema->required);
978
979
        $this->assertEquals('object', $schema->properties->name->type);
980
        $this->assertEquals('translatable', $schema->properties->name->format);
981
        $this->assertEquals('Name', $schema->properties->name->title);
982
        $this->assertEquals('Display name for an app.', $schema->properties->name->description);
983
        $this->assertEquals('string', $schema->properties->name->properties->en->type);
984
        $this->assertContains('name', $schema->required);
985
986
        $this->assertEquals('boolean', $schema->properties->showInMenu->type);
987
        $this->assertEquals('Show in Menu', $schema->properties->showInMenu->title);
988
        $this->assertEquals(
989
            'Define if an app should be exposed on the top level menu.',
990
            $schema->properties->showInMenu->description
991
        );
992
    }
993
}
994