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
arrayas a return type and suggests a more specific type. This type is inferred from the actual code.