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 |
||
| 8 | class QuadTreeTest extends \PHPUnit_Framework_TestCase |
||
| 9 | { |
||
| 10 | public function testConstructor() |
||
| 11 | { |
||
| 12 | $bounds = new Box(0, 0, 800, 600); |
||
| 13 | $tree = new QuadTree($bounds); |
||
| 14 | $this->assertInstanceOf(QuadTree::class, $tree); |
||
| 15 | $this->assertAttributeEquals($bounds, 'bounds', $tree); |
||
| 16 | $this->assertAttributeEquals(0, 'level', $tree); |
||
| 17 | $this->assertAttributeEquals(null, 'nodes', $tree); |
||
| 18 | $this->assertEquals(0, $tree->count()); |
||
| 19 | } |
||
| 20 | |||
| 21 | public function testSplit() |
||
| 22 | { |
||
| 23 | $bounds = new Box(0, 0, 800, 600); |
||
| 24 | $tree = new QuadTree($bounds); |
||
| 25 | $tree->split(); |
||
| 26 | |||
| 27 | $nodes = $this->readAttribute($tree, 'nodes'); |
||
| 28 | $this->assertInternalType('array', $nodes); |
||
| 29 | $this->assertCount(4, $nodes); |
||
| 30 | |||
| 31 | foreach ($nodes as $node) { |
||
| 32 | $this->assertInstanceOf(QuadTree::class, $node); |
||
| 33 | $this->assertAttributeEquals(null, 'nodes', $node); |
||
| 34 | $nodeBounds = $this->readAttribute($node, 'bounds'); |
||
| 35 | $this->assertContains($nodeBounds->getX(), array(0, 400)); |
||
| 36 | $this->assertContains($nodeBounds->getY(), array(0, 300)); |
||
| 37 | $this->assertEquals(400, $nodeBounds->getWidth()); |
||
| 38 | $this->assertEquals(300, $nodeBounds->getHeight()); |
||
| 39 | } |
||
| 40 | } |
||
| 41 | |||
| 42 | /** |
||
| 43 | * @dataProvider getIndexProvider |
||
| 44 | */ |
||
| 45 | public function testGetIndex($expectedIndex, $box) |
||
| 46 | { |
||
| 47 | $bounds = new Box(0, 0, 800, 600); |
||
| 48 | $tree = new QuadTree($bounds); |
||
| 49 | |||
| 50 | $this->assertEquals($expectedIndex, $tree->getIndex($box)); |
||
| 51 | } |
||
| 52 | |||
| 53 | /** |
||
| 54 | * @return array |
||
| 55 | */ |
||
| 56 | public function getIndexProvider() |
||
| 57 | { |
||
| 58 | return array( |
||
| 59 | array(-1, new Box(0, 0, 800, 600)), |
||
| 60 | array(-1, (new Box(0, 0, 400, 300))->resize(1)), |
||
| 61 | array(-1, new Box(300, 200, 200, 200)), |
||
| 62 | array(0, new Box(0, 0, 400, 300)), |
||
| 63 | array(0, (new Box(0, 0, 400, 300))->resize(-1)), |
||
| 64 | array(1, new Box(400, 0, 400, 300)), |
||
| 65 | array(1, new Box(750, 100, 50, 50)), |
||
| 66 | array(2, new Box(0, 300, 400, 300)), |
||
| 67 | array(2, new Box(250, 310, 50, 50)), |
||
| 68 | array(3, new Box(400, 300, 400, 300)), |
||
| 69 | array(3, new Box(700, 500, 50, 50)), |
||
| 70 | ); |
||
| 71 | } |
||
| 72 | |||
| 73 | public function testInsert() |
||
| 74 | { |
||
| 75 | $bounds = new Box(0, 0, 800, 600); |
||
| 76 | $tree = new QuadTree($bounds); |
||
| 77 | |||
| 78 | for ($i = 0; $i < 10; $i++) { |
||
| 79 | $tree->insert(new Box(10, $i * 10, 10, 10)); |
||
| 80 | $this->assertEquals($i + 1, $tree->count()); |
||
| 81 | } |
||
| 82 | |||
| 83 | $this->assertAttributeEquals(false, 'isSplit', $tree); |
||
| 84 | |||
| 85 | $tree->insert(new Box(10, 110, 10, 10)); |
||
| 86 | |||
| 87 | $this->assertAttributeEquals(true, 'isSplit', $tree); |
||
| 88 | } |
||
| 89 | |||
| 90 | public function testRetrieve() |
||
| 91 | { |
||
| 92 | $bounds = new Box(0, 0, 80, 80); |
||
| 93 | $tree = new QuadTree($bounds); |
||
| 94 | |||
| 95 | for ($i = 0; $i < 80; $i += 10) { |
||
| 96 | for ($j = 0; $j < 80; $j += 10) { |
||
| 97 | $tree->insert(new Box($i, $j, 10, 10)); |
||
| 98 | } |
||
| 99 | } |
||
| 100 | |||
| 101 | $nodes = $tree->retrieve(new Box(5, 5, 10, 10)); |
||
| 102 | $expectedNodes = array( |
||
| 103 | new Box(0, 0, 10, 10), |
||
| 104 | new Box(10, 0, 10, 10), |
||
| 105 | new Box(0, 10, 10, 10), |
||
| 106 | new Box(10, 10, 10, 10), |
||
| 107 | ); |
||
| 108 | $this->assertCount(4, $nodes); |
||
| 109 | |||
| 110 | for ($i = 0; $i < 4; $i++) { |
||
| 111 | $this->assertTrue(in_array($nodes[$i], $expectedNodes)); |
||
| 112 | } |
||
| 113 | } |
||
| 114 | |||
| 115 | public function testRetrieve1() |
||
| 116 | { |
||
| 117 | $count = 1000; |
||
| 118 | $bounds = new Box(0, 0, 100, 100); |
||
| 119 | $tree = new QuadTree($bounds); |
||
| 120 | $this->fillTreeWithRandomBoxes($tree, $count); |
||
| 121 | $this->assertEquals($count, count($tree->retrieve($bounds))); |
||
| 122 | $this->assertEquals($tree->getAllObjects(), $tree->retrieve($bounds)); |
||
| 123 | } |
||
| 124 | |||
| 125 | public function testCollides() |
||
| 126 | { |
||
| 127 | $bounds = new Box(0, 0, 80, 80); |
||
| 128 | $tree = new QuadTree($bounds); |
||
| 129 | |||
| 130 | for ($i = 0; $i < 80; $i += 10) { |
||
| 131 | for ($j = 0; $j < 80; $j += 10) { |
||
| 132 | $tree->insert(new Box($i, $j, 10, 10)); |
||
| 133 | } |
||
| 134 | } |
||
| 135 | |||
| 136 | $this->assertTrue($tree->collides(new Box(0, 0, 10, 10))); |
||
| 137 | $this->assertTrue($tree->collides(new Box(5, 5, 10, 10))); |
||
| 138 | $this->assertTrue($tree->collides(new Box(25, 25, 10, 10))); |
||
| 139 | $this->assertTrue($tree->collides(new Box(50, 50, 10, 10))); |
||
| 140 | $this->assertTrue($tree->collides(new Box(0, 0, 10, 10))); |
||
| 141 | $this->assertTrue($tree->collides(new Box(70, 0, 10, 10))); |
||
| 142 | |||
| 143 | $this->assertFalse($tree->collides(new Box(1000, 1000, 10, 10))); |
||
| 144 | } |
||
| 145 | |||
| 146 | public function testCollides1() |
||
| 147 | { |
||
| 148 | $bounds = new Box(0, 0, 100, 100); |
||
| 149 | $tree = new QuadTree($bounds); |
||
| 150 | $tree->insert(new Box(25, 25, 50, 50)); |
||
| 151 | |||
| 152 | $this->assertTrue($tree->collides(new Box(0, 0, 50, 50))); |
||
| 153 | $this->assertTrue($tree->collides(new Box(25, 25, 10, 10))); |
||
| 154 | $this->assertTrue($tree->collides(new Box(50, 50, 10, 10))); |
||
| 155 | |||
| 156 | $this->assertFalse($tree->collides(new Box(0, 0, 10, 10))); |
||
| 157 | $this->assertFalse($tree->collides(new Box(80, 80, 10, 10))); |
||
| 158 | $this->assertFalse($tree->collides(new Box(1000, 1000, 10, 10))); |
||
| 159 | } |
||
| 160 | |||
| 161 | public function testCount() |
||
| 162 | { |
||
| 163 | $bounds = new Box(0, 0, 10000, 10000); |
||
| 164 | $tree = new QuadTree($bounds); |
||
| 165 | $this->fillTreeWithRandomBoxes($tree, 1000); |
||
| 166 | $this->assertEquals(1000, $tree->count()); |
||
| 167 | } |
||
| 168 | |||
| 169 | public function testGetAllObjects() |
||
| 170 | { |
||
| 171 | $bounds = new Box(0, 0, 10000, 10000); |
||
| 172 | $tree = new QuadTree($bounds); |
||
| 173 | $this->fillTreeWithRandomBoxes($tree, 1000); |
||
| 174 | $this->assertCount(1000, $tree->getAllObjects()); |
||
| 175 | } |
||
| 176 | |||
| 177 | /** |
||
| 178 | * @param QuadTree $tree |
||
| 179 | * @param int $count |
||
| 180 | */ |
||
| 181 | protected function fillTreeWithRandomBoxes(QuadTree $tree, $count) |
||
| 182 | { |
||
| 183 | $treeWidth = $tree->getBounds()->getWidth(); |
||
| 184 | $treeHeight = $tree->getBounds()->getHeight(); |
||
| 185 | |||
| 186 | for ($i = 0; $i < $count; $i++) { |
||
| 187 | $w = rand(0, 10); |
||
| 188 | $h = rand(0, 10); |
||
| 189 | $box = new Box(rand(0, $treeWidth - $w), rand(0, $treeHeight - $h), $w, $h); |
||
| 190 | $tree->insert($box); |
||
| 191 | } |
||
| 192 | } |
||
| 193 | } |
||
| 194 |