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 |
||
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; profile=http://localhost/schema/core/app/item'; |
||
24 | |||
25 | /** |
||
26 | * @const corresponding vendorized schema mime type |
||
27 | */ |
||
28 | const COLLECTION_TYPE = 'application/json; charset=UTF-8; profile=http://localhost/schema/core/app/collection'; |
||
29 | |||
30 | /** |
||
31 | * setup client and load fixtures |
||
32 | * |
||
33 | * @return void |
||
34 | */ |
||
35 | public function setUp() |
||
49 | /** |
||
50 | * check if all fixtures are returned on GET |
||
51 | * |
||
52 | * @return void |
||
53 | */ |
||
54 | public function testFindAll() |
||
81 | |||
82 | /** |
||
83 | * test if we can get list of apps, paged and with filters.. |
||
84 | * |
||
85 | * @return void |
||
86 | */ |
||
87 | public function testGetAppWithFilteringAndPaging() |
||
113 | |||
114 | /** |
||
115 | * rql limit() should *never* be overwritten by default value |
||
116 | * |
||
117 | * @return void |
||
118 | */ |
||
119 | public function testGetAppPagingWithRql() |
||
170 | |||
171 | /** |
||
172 | * check for a client error if invalid limit value is provided |
||
173 | * |
||
174 | * @dataProvider invalidPagingPageSizeProvider |
||
175 | * |
||
176 | * @param integer $limit limit value that should fail |
||
177 | * @return void |
||
178 | */ |
||
179 | public function testInvalidPagingPageSize($limit) |
||
180 | { |
||
181 | $client = static::createRestClient(); |
||
182 | $client->request('GET', sprintf('/core/app/?limit(%s)', $limit)); |
||
183 | |||
184 | $this->assertEquals(Response::HTTP_BAD_REQUEST, $client->getResponse()->getStatusCode()); |
||
185 | $this->assertContains('negative or null limit in rql', $client->getResults()->message); |
||
186 | } |
||
187 | |||
188 | /** |
||
189 | * page size test provides |
||
190 | * |
||
191 | * @return array[] |
||
|
|||
192 | */ |
||
193 | public function invalidPagingPageSizeProvider() |
||
194 | { |
||
195 | return [ |
||
196 | [0], |
||
197 | [-1], |
||
198 | ]; |
||
199 | } |
||
200 | |||
201 | /** |
||
202 | * RQL is parsed only when we get apps |
||
203 | * |
||
204 | * @return void |
||
205 | */ |
||
206 | public function testRqlIsParsedOnlyOnGetRequest() |
||
207 | { |
||
208 | $appData = [ |
||
209 | 'showInMenu' => false, |
||
210 | 'order' => 100, |
||
211 | 'name' => ['en' => 'Administration'], |
||
212 | ]; |
||
213 | |||
214 | $client = static::createRestClient(); |
||
215 | $client->request('GET', '/core/app/?invalidrqlquery'); |
||
216 | $this->assertEquals(Response::HTTP_BAD_REQUEST, $client->getResponse()->getStatusCode()); |
||
217 | $this->assertContains('syntax error in rql', $client->getResults()->message); |
||
218 | |||
219 | $client = static::createRestClient(); |
||
220 | $client->request('GET', '/core/app/admin?invalidrqlquery'); |
||
221 | $this->assertEquals(Response::HTTP_BAD_REQUEST, $client->getResponse()->getStatusCode()); |
||
222 | $this->assertContains('syntax error in rql', $client->getResults()->message); |
||
223 | |||
224 | $client = static::createRestClient(); |
||
225 | $client->request('OPTIONS', '/core/app/?invalidrqlquery'); |
||
226 | $this->assertEquals(Response::HTTP_NO_CONTENT, $client->getResponse()->getStatusCode()); |
||
227 | |||
228 | $client = static::createRestClient(); |
||
229 | $client->request('OPTIONS', '/schema/core/app/collection?invalidrqlquery'); |
||
230 | $this->assertEquals(Response::HTTP_NO_CONTENT, $client->getResponse()->getStatusCode()); |
||
231 | |||
232 | $client = static::createRestClient(); |
||
233 | $client->request('OPTIONS', '/schema/core/app/item?invalidrqlquery'); |
||
234 | $this->assertEquals(Response::HTTP_NO_CONTENT, $client->getResponse()->getStatusCode()); |
||
235 | |||
236 | $client = static::createRestClient(); |
||
237 | $client->request('GET', '/schema/core/app/collection?invalidrqlquery'); |
||
238 | $this->assertEquals(Response::HTTP_OK, $client->getResponse()->getStatusCode()); |
||
239 | |||
240 | $client = static::createRestClient(); |
||
241 | $client->request('GET', '/schema/core/app/item?invalidrqlquery'); |
||
242 | $this->assertEquals(Response::HTTP_OK, $client->getResponse()->getStatusCode()); |
||
243 | |||
244 | |||
245 | $client = static::createRestClient(); |
||
246 | $client->post('/core/app/?invalidrqlquery', $appData); |
||
247 | $this->assertEquals(Response::HTTP_CREATED, $client->getResponse()->getStatusCode()); |
||
248 | |||
249 | $client = static::createRestClient(); |
||
250 | $client->put('/core/app/admin?invalidrqlquery', $appData); |
||
251 | $this->assertEquals(Response::HTTP_NO_CONTENT, $client->getResponse()->getStatusCode()); |
||
252 | |||
253 | $client = static::createRestClient(); |
||
254 | $client->request('DELETE', '/core/app/admin?invalidrqlquery'); |
||
255 | $this->assertEquals(Response::HTTP_NO_CONTENT, $client->getResponse()->getStatusCode()); |
||
256 | } |
||
257 | |||
258 | /** |
||
259 | * Test only RQL select() operator is allowed for GET one |
||
260 | * |
||
261 | * @return void |
||
262 | * @group tmp |
||
263 | */ |
||
264 | public function testOnlyRqlSelectIsAllowedOnGetOne() |
||
292 | |||
293 | /** |
||
294 | * check for empty collections when no fixtures are loaded |
||
295 | * |
||
296 | * @return void |
||
297 | */ |
||
298 | View Code Duplication | public function testFindAllEmptyCollection() |
|
312 | |||
313 | /** |
||
314 | * test if we can get an app by id |
||
315 | * |
||
316 | * @return void |
||
317 | */ |
||
318 | public function testGetApp() |
||
337 | |||
338 | /** |
||
339 | * test if we can create an app through POST |
||
340 | * |
||
341 | * @return void |
||
342 | */ |
||
343 | public function testPostApp() |
||
372 | |||
373 | /** |
||
374 | * test if we get a correct return if we post empty. |
||
375 | * |
||
376 | * @return void |
||
377 | */ |
||
378 | public function testPostEmptyApp() |
||
394 | |||
395 | /** |
||
396 | * test if we get a correct return if we post empty. |
||
397 | * |
||
398 | * @return void |
||
399 | */ |
||
400 | public function testPostNonObjectApp() |
||
409 | |||
410 | /** |
||
411 | * test if 500 error is reported when posting an malformed input |
||
412 | * |
||
413 | * @return void |
||
414 | */ |
||
415 | public function testPostMalformedApp() |
||
444 | |||
445 | /** |
||
446 | * Tests if an error is returned when an id is send in a post |
||
447 | * |
||
448 | * @return void |
||
449 | */ |
||
450 | public function testPostWithId() |
||
451 | { |
||
452 | $helloApp = new \stdClass(); |
||
453 | $helloApp->id = 101; |
||
454 | $helloApp->name = "tubel"; |
||
455 | |||
456 | $client = static::createRestClient(); |
||
457 | $client->post('/person/customer', $helloApp); |
||
458 | |||
459 | $this->assertEquals( |
||
460 | 'Bad Request - "id" can not be given on a POST request. '. |
||
461 | 'Do a PUT request instead to update an existing record.', |
||
462 | $client->getResults()->message |
||
463 | ); |
||
464 | } |
||
465 | /** |
||
466 | * test updating apps |
||
467 | * |
||
468 | * @return void |
||
469 | */ |
||
470 | public function testPutApp() |
||
498 | |||
499 | /** |
||
500 | * Test for PATCH Request |
||
501 | * |
||
502 | * @return void |
||
503 | */ |
||
504 | public function testPatchAppRequestApplyChanges() |
||
505 | { |
||
506 | $helloApp = new \stdClass(); |
||
507 | $helloApp->id = "testapp"; |
||
508 | $helloApp->name = new \stdClass(); |
||
509 | $helloApp->name->en = "Test App"; |
||
510 | $helloApp->showInMenu = false; |
||
511 | |||
512 | // 1. Create some App |
||
513 | $client = static::createRestClient(); |
||
514 | $client->put('/core/app/' . $helloApp->id, $helloApp); |
||
515 | |||
516 | // 2. PATCH request |
||
517 | $client = static::createRestClient(); |
||
518 | $patchJson = json_encode( |
||
519 | [ |
||
520 | [ |
||
521 | 'op' => 'replace', |
||
522 | 'path' => '/name/en', |
||
523 | 'value' => 'Test App Patched' |
||
524 | ] |
||
525 | ] |
||
526 | ); |
||
527 | $client->request('PATCH', '/core/app/' . $helloApp->id, array(), array(), array(), $patchJson); |
||
528 | $response = $client->getResponse(); |
||
529 | |||
530 | $this->assertEquals(200, $response->getStatusCode()); |
||
531 | |||
532 | // 3. Get changed App and check changed title |
||
533 | $client = static::createRestClient(); |
||
534 | $client->request('GET', '/core/app/' . $helloApp->id); |
||
535 | |||
536 | $response = $client->getResponse(); |
||
537 | $results = $client->getResults(); |
||
538 | |||
539 | $this->assertResponseContentType(self::CONTENT_TYPE, $response); |
||
540 | $this->assertEquals('Test App Patched', $results->name->en); |
||
541 | } |
||
542 | |||
543 | /** |
||
544 | * Test for Malformed PATCH Request |
||
545 | * |
||
546 | * @return void |
||
547 | */ |
||
548 | public function testMalformedPatchAppRequest() |
||
577 | |||
578 | /** |
||
579 | * Try to update an app with a non matching ID in GET and req body |
||
580 | * |
||
581 | * @return void |
||
582 | */ |
||
583 | public function testNonMatchingIdPutApp() |
||
603 | |||
604 | /** |
||
605 | * We had an issue when PUTing without ID would create a new record. |
||
606 | * This test ensures that we don't do that, instead we should apply the ID from the GET req. |
||
607 | * |
||
608 | * @return void |
||
609 | */ |
||
610 | public function testPutAppNoIdInPayload() |
||
631 | |||
632 | /** |
||
633 | * test updating an inexistant document (upsert) |
||
634 | * |
||
635 | * @return void |
||
636 | */ |
||
637 | public function testUpsertApp() |
||
650 | |||
651 | /** |
||
652 | * test deleting an app |
||
653 | * |
||
654 | * @return void |
||
655 | */ |
||
656 | public function testDeleteApp() |
||
676 | |||
677 | /** |
||
678 | * test failing validation on boolean field |
||
679 | * |
||
680 | * @return void |
||
681 | */ |
||
682 | public function testFailingBooleanValidationOnAppUpdate() |
||
700 | |||
701 | /** |
||
702 | * test getting schema information |
||
703 | * |
||
704 | * @return void |
||
705 | */ |
||
706 | View Code Duplication | public function testGetAppSchemaInformation() |
|
715 | |||
716 | /** |
||
717 | * requests on OPTIONS and HEAD shall not lead graviton to get any data from mongodb. |
||
718 | * if we page limit(1) this will lead to presence of the x-total-count header if |
||
719 | * data is generated (asserted by testGetAppPagingWithRql()). thus, if we don't |
||
720 | * have this header, we can safely assume that no data has been processed in RestController. |
||
721 | * |
||
722 | * @return void |
||
723 | */ |
||
724 | View Code Duplication | public function testNoRecordsAreGeneratedOnPreRequests() |
|
736 | |||
737 | /** |
||
738 | * test getting schema information from canonical url |
||
739 | * |
||
740 | * @return void |
||
741 | */ |
||
742 | View Code Duplication | public function testGetAppSchemaInformationCanonical() |
|
750 | |||
751 | /** |
||
752 | * test getting collection schema |
||
753 | * |
||
754 | * @return void |
||
755 | */ |
||
756 | public function testGetAppCollectionSchemaInformation() |
||
784 | |||
785 | /** |
||
786 | * Test for searchable translations |
||
787 | * |
||
788 | * @dataProvider searchableTranslationDataProvider |
||
789 | * |
||
790 | * @param string $expr expression |
||
791 | * @param int $expCount count |
||
792 | * |
||
793 | * @return void |
||
794 | */ |
||
795 | public function testSearchableTranslations($expr, $expCount) |
||
809 | |||
810 | /** |
||
811 | * data provider for searchable translations |
||
812 | * |
||
813 | * @return array data |
||
814 | */ |
||
815 | public function searchableTranslationDataProvider() |
||
826 | |||
827 | /** |
||
828 | * ensure we have nice parse error output in rql parse failure |
||
829 | * |
||
830 | * @return void |
||
831 | */ |
||
832 | View Code Duplication | public function testRqlSyntaxError() |
|
846 | |||
847 | /** |
||
848 | * check if response looks like schema |
||
849 | * |
||
850 | * @param object $response response |
||
851 | * |
||
852 | * @return void |
||
853 | */ |
||
854 | private function assertIsSchemaResponse($response) |
||
859 | |||
860 | /** |
||
861 | * check if a schema is of the app type |
||
862 | * |
||
863 | * @param \stdClass $schema schema from service to validate |
||
864 | * |
||
865 | * @return void |
||
866 | */ |
||
867 | private function assertIsAppSchema(\stdClass $schema) |
||
892 | } |
||
893 |
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.