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:
Complex classes like ParserTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ParserTest, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 19 | class ParserTest extends PHPUnit_Framework_TestCase |
||
| 20 | { |
||
| 21 | public function testTriggerComplete() |
||
| 30 | |||
| 31 | /** |
||
| 32 | * @covers \Kint\Parser\Parser::__construct |
||
| 33 | * @covers \Kint\Parser\Parser::getDepthLimit |
||
| 34 | * @covers \Kint\Parser\Parser::getCallerClass |
||
| 35 | */ |
||
| 36 | public function testConstruct() |
||
| 53 | |||
| 54 | /** |
||
| 55 | * @covers \Kint\Parser\Parser::parse |
||
| 56 | * @covers \Kint\Parser\Parser::parseGeneric |
||
| 57 | */ |
||
| 58 | public function testParseInteger() |
||
| 75 | |||
| 76 | /** |
||
| 77 | * @covers \Kint\Parser\Parser::parse |
||
| 78 | * @covers \Kint\Parser\Parser::parseGeneric |
||
| 79 | */ |
||
| 80 | public function testParseBoolean() |
||
| 97 | |||
| 98 | /** |
||
| 99 | * @covers \Kint\Parser\Parser::parse |
||
| 100 | * @covers \Kint\Parser\Parser::parseGeneric |
||
| 101 | */ |
||
| 102 | public function testParseDouble() |
||
| 113 | |||
| 114 | /** |
||
| 115 | * @covers \Kint\Parser\Parser::parse |
||
| 116 | * @covers \Kint\Parser\Parser::parseGeneric |
||
| 117 | */ |
||
| 118 | public function testParseNull() |
||
| 129 | |||
| 130 | /** |
||
| 131 | * @covers \Kint\Parser\Parser::parse |
||
| 132 | * @covers \Kint\Parser\Parser::parseString |
||
| 133 | */ |
||
| 134 | public function testParseString() |
||
| 169 | |||
| 170 | /** |
||
| 171 | * @covers \Kint\Parser\Parser::parse |
||
| 172 | * @covers \Kint\Parser\Parser::parseResource |
||
| 173 | */ |
||
| 174 | public function testParseResource() |
||
| 191 | |||
| 192 | /** |
||
| 193 | * @covers \Kint\Parser\Parser::parse |
||
| 194 | * @covers \Kint\Parser\Parser::parseArray |
||
| 195 | */ |
||
| 196 | public function testParseArray() |
||
| 197 | { |
||
| 198 | $p = new Parser(); |
||
| 199 | $b = BasicObject::blank('$v'); |
||
| 200 | $v = array( |
||
| 201 | 1234, |
||
| 202 | 'key' => 'value', |
||
| 203 | 1234 => 5678, |
||
| 204 | ); |
||
| 205 | |||
| 206 | $o = $p->parse($v, clone $b); |
||
| 207 | |||
| 208 | $this->assertEquals('array', $o->type); |
||
| 209 | |||
| 210 | $val = array_values($o->value->contents); |
||
| 211 | |||
| 212 | $this->assertEquals(0, $val[0]->name); |
||
| 213 | $this->assertEquals(1234, $val[0]->value->contents); |
||
| 214 | $this->assertEquals('$v[0]', $val[0]->access_path); |
||
| 215 | $this->assertEquals(BasicObject::OPERATOR_ARRAY, $val[0]->operator); |
||
| 216 | $this->assertEquals('key', $val[1]->name); |
||
| 217 | $this->assertEquals('value', $val[1]->value->contents); |
||
| 218 | $this->assertEquals('$v[\'key\']', $val[1]->access_path); |
||
| 219 | $this->assertEquals(BasicObject::OPERATOR_ARRAY, $val[1]->operator); |
||
| 220 | $this->assertEquals(1234, $val[2]->name); |
||
| 221 | $this->assertEquals(5678, $val[2]->value->contents); |
||
| 222 | $this->assertEquals('$v[1234]', $val[2]->access_path); |
||
| 223 | $this->assertEquals(BasicObject::OPERATOR_ARRAY, $val[2]->operator); |
||
| 224 | |||
| 225 | $v = array(); |
||
| 226 | |||
| 227 | $o = $p->parse($v, clone $b); |
||
| 228 | |||
| 229 | $this->assertInstanceOf('Kint\\Object\\Representation\\Representation', $o->value); |
||
| 230 | $this->assertCount(0, $o->value->contents); |
||
| 231 | } |
||
| 232 | |||
| 233 | /** |
||
| 234 | * @covers \Kint\Parser\Parser::parse |
||
| 235 | * @covers \Kint\Parser\Parser::parseObject |
||
| 236 | */ |
||
| 237 | public function testParseObject() |
||
| 270 | |||
| 271 | /** |
||
| 272 | * @covers \Kint\Parser\Parser::parse |
||
| 273 | * @covers \Kint\Parser\Parser::parseUnknown |
||
| 274 | */ |
||
| 275 | public function testParseUnknown() |
||
| 287 | |||
| 288 | /** |
||
| 289 | * @covers \Kint\Parser\Parser::parseArray |
||
| 290 | * @covers \Kint\Parser\Parser::parseObject |
||
| 291 | */ |
||
| 292 | public function testParseReferences() |
||
| 313 | |||
| 314 | /** |
||
| 315 | * @covers \Kint\Parser\Parser::parseArray |
||
| 316 | * @covers \Kint\Parser\Parser::parseObject |
||
| 317 | */ |
||
| 318 | public function testParseRecursion() |
||
| 351 | |||
| 352 | /** |
||
| 353 | * @covers \Kint\Parser\Parser::parseDeep |
||
| 354 | * @covers \Kint\Parser\Parser::parseArray |
||
| 355 | * @covers \Kint\Parser\Parser::parseObject |
||
| 356 | */ |
||
| 357 | public function testParseDepthLimit() |
||
| 358 | { |
||
| 359 | $p = new Parser(1); |
||
| 360 | $b = BasicObject::blank('$v'); |
||
| 361 | $v = array(array(1234)); |
||
| 362 | |||
| 363 | $limit = false; |
||
| 364 | |||
| 365 | $pl = new ProxyPlugin( |
||
| 366 | array('array', 'object'), |
||
| 367 | Parser::TRIGGER_DEPTH_LIMIT, |
||
| 368 | function () use (&$limit) { |
||
| 369 | $limit = true; |
||
| 370 | } |
||
| 371 | ); |
||
| 372 | $p->addPlugin($pl); |
||
| 373 | |||
| 374 | $o = $p->parse($v, clone $b); |
||
| 375 | |||
| 376 | $this->assertContains('depth_limit', $o->value->contents[0]->hints); |
||
| 377 | $this->assertTrue($limit); |
||
| 378 | |||
| 379 | $limit = false; |
||
| 380 | |||
| 381 | $v = new stdClass(); |
||
| 382 | $v->v = 1234; |
||
| 383 | $v = array($v); |
||
| 384 | |||
| 385 | $o = $p->parse($v, clone $b); |
||
| 386 | |||
| 387 | $this->assertContains('depth_limit', $o->value->contents[0]->hints); |
||
| 388 | $this->assertTrue($limit); |
||
| 389 | |||
| 390 | $limit = false; |
||
| 391 | |||
| 392 | $o = $p->parseDeep($v, clone $b); |
||
| 393 | |||
| 394 | $this->assertNotContains('depth_limit', $o->value->contents[0]->hints); |
||
| 395 | $this->assertFalse($limit); |
||
| 396 | } |
||
| 397 | |||
| 398 | /** |
||
| 399 | * @covers \Kint\Parser\Parser::parseArray |
||
| 400 | * @covers \Kint\Parser\Parser::parseObject |
||
| 401 | */ |
||
| 402 | public function testParseCastKeys() |
||
| 556 | |||
| 557 | /** |
||
| 558 | * @covers \Kint\Parser\Parser::parseObject |
||
| 559 | * @covers \Kint\Parser\Parser::childHasPath |
||
| 560 | */ |
||
| 561 | public function testParseAccessPathAvailability() |
||
| 596 | |||
| 597 | /** |
||
| 598 | * @covers \Kint\Parser\Parser::applyPlugins |
||
| 599 | * @covers \Kint\Parser\Parser::addPlugin |
||
| 600 | * @covers \Kint\Parser\Parser::clearPlugins |
||
| 601 | */ |
||
| 602 | public function testPlugins() |
||
| 603 | { |
||
| 604 | $p = new Parser(); |
||
| 605 | $b = BasicObject::blank('$v'); |
||
| 606 | $v = 1234; |
||
| 607 | |||
| 608 | $o = $p->parse($v, clone $b); |
||
| 609 | |||
| 610 | $this->assertObjectNotHasAttribute('testPluginCorrectlyActivated', $o); |
||
| 611 | |||
| 612 | $pl = new ProxyPlugin( |
||
| 613 | array('integer'), |
||
| 614 | Parser::TRIGGER_SUCCESS, |
||
| 615 | function (&$var, &$o) { |
||
| 616 | $o->testPluginCorrectlyActivated = true; |
||
| 617 | } |
||
| 618 | ); |
||
| 619 | $p->addPlugin($pl); |
||
| 620 | |||
| 621 | $o = $p->parse($v, clone $b); |
||
| 622 | |||
| 623 | $this->assertObjectHasAttribute('testPluginCorrectlyActivated', $o); |
||
| 624 | |||
| 625 | $p->clearPlugins(); |
||
| 626 | |||
| 627 | $o = $p->parse($v, clone $b); |
||
| 628 | |||
| 629 | $this->assertObjectNotHasAttribute('testPluginCorrectlyActivated', $o); |
||
| 630 | |||
| 631 | $pl = new ProxyPlugin( |
||
| 632 | array(), |
||
| 633 | Parser::TRIGGER_SUCCESS, |
||
| 634 | function () {} |
||
| 635 | ); |
||
| 636 | $this->assertFalse($p->addPlugin($pl)); |
||
| 637 | |||
| 638 | $pl = new ProxyPlugin( |
||
| 639 | array('integer'), |
||
| 640 | Parser::TRIGGER_NONE, |
||
| 641 | function () {} |
||
| 642 | ); |
||
| 643 | $this->assertFalse($p->addPlugin($pl)); |
||
| 644 | } |
||
| 645 | |||
| 646 | /** |
||
| 647 | * @covers \Kint\Parser\Parser::applyPlugins |
||
| 648 | * @covers \Kint\Parser\Parser::addPlugin |
||
| 649 | */ |
||
| 650 | public function testTriggers() |
||
| 651 | { |
||
| 652 | $p = new Parser(1); |
||
| 653 | $b = BasicObject::blank('$v'); |
||
| 654 | $v = array(1234, array(1234)); |
||
| 655 | $v[] = &$v; |
||
| 656 | |||
| 657 | $triggers = array(); |
||
| 658 | |||
| 659 | $pl = new ProxyPlugin( |
||
| 660 | array('integer', 'array'), |
||
| 661 | Parser::TRIGGER_BEGIN | Parser::TRIGGER_COMPLETE, |
||
| 662 | function (&$var, &$o, $trig) use (&$triggers) { |
||
| 663 | $triggers[] = $trig; |
||
| 664 | } |
||
| 665 | ); |
||
| 666 | $p->addPlugin($pl); |
||
| 667 | |||
| 668 | $o = $p->parse($v, clone $b); |
||
| 669 | |||
| 670 | $this->assertEquals( |
||
| 671 | array( |
||
| 672 | Parser::TRIGGER_BEGIN, |
||
| 673 | Parser::TRIGGER_BEGIN, |
||
| 674 | Parser::TRIGGER_SUCCESS, |
||
| 675 | Parser::TRIGGER_BEGIN, |
||
| 676 | Parser::TRIGGER_DEPTH_LIMIT, |
||
| 677 | Parser::TRIGGER_BEGIN, |
||
| 678 | Parser::TRIGGER_RECURSION, |
||
| 679 | Parser::TRIGGER_SUCCESS, |
||
| 680 | ), |
||
| 681 | $triggers |
||
| 682 | ); |
||
| 683 | } |
||
| 684 | |||
| 685 | /** |
||
| 686 | * @covers \Kint\Parser\Parser::parse |
||
| 687 | * @covers \Kint\Parser\Parser::applyPlugins |
||
| 688 | * @covers \Kint\Parser\Parser::haltParse |
||
| 689 | */ |
||
| 690 | public function testHaltParse() |
||
| 691 | { |
||
| 692 | $p = new Parser(); |
||
| 693 | $b = BasicObject::blank('$v'); |
||
| 694 | $t = clone $b; |
||
| 695 | $t->type = 'integer'; |
||
| 696 | $v = 1234; |
||
| 697 | |||
| 698 | $pl = new ProxyPlugin( |
||
| 699 | array('integer'), |
||
| 700 | Parser::TRIGGER_BEGIN, |
||
| 701 | function (&$var, &$o, $trig, $parser) { |
||
| 702 | $parser->haltParse(); |
||
| 703 | } |
||
| 704 | ); |
||
| 705 | $p->addPlugin($pl); |
||
| 706 | |||
| 707 | $o = $p->parse($v, $t); |
||
| 708 | |||
| 709 | $this->assertSame($t, $o); |
||
| 710 | |||
| 711 | $p->clearPlugins(); |
||
| 712 | |||
| 713 | $pl = new ProxyPlugin( |
||
| 714 | array('integer'), |
||
| 715 | Parser::TRIGGER_SUCCESS, |
||
| 716 | function (&$var, &$o, $trig, $parser) { |
||
| 717 | $parser->haltParse(); |
||
| 718 | } |
||
| 719 | ); |
||
| 720 | $p->addPlugin($pl); |
||
| 721 | |||
| 722 | $pl = new ProxyPlugin( |
||
| 723 | array('integer'), |
||
| 724 | Parser::TRIGGER_SUCCESS, |
||
| 725 | function (&$var, &$o) { |
||
| 726 | $o->testPluginCorrectlyActivated = true; |
||
| 727 | } |
||
| 728 | ); |
||
| 729 | $p->addPlugin($pl); |
||
| 730 | |||
| 731 | $o = $p->parse($v, clone $b); |
||
| 732 | |||
| 733 | $this->assertObjectNotHasAttribute('testPluginCorrectlyActivated', $o); |
||
| 734 | } |
||
| 735 | |||
| 736 | /** |
||
| 737 | * @expectedException \PHPUnit_Framework_Error_Warning |
||
| 738 | * @covers \Kint\Parser\Parser::applyPlugins |
||
| 739 | */ |
||
| 740 | public function testPluginExceptionBecomesWarning() |
||
| 761 | |||
| 762 | public function childHasPathProvider() |
||
| 832 | |||
| 833 | /** |
||
| 834 | * @dataProvider childHasPathProvider |
||
| 835 | * @covers \Kint\Parser\Parser::childHasPath |
||
| 836 | */ |
||
| 837 | public function testChildHasPath($parser, $parent, $child, $expected) |
||
| 841 | |||
| 842 | /** |
||
| 843 | * @covers \Kint\Parser\Parser::sortObjectProperties |
||
| 844 | */ |
||
| 845 | public function testSortObjectProperties() |
||
| 881 | |||
| 882 | /** |
||
| 883 | * @covers \Kint\Parser\Parser::getCleanArray |
||
| 884 | */ |
||
| 885 | public function testGetCleanArray() |
||
| 918 | } |
||
| 919 |
Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.