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 |