MenuItemTreeTest.php 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <?php
  2. namespace Knp\Menu\Tests;
  3. use Knp\Menu\Iterator\CurrentItemFilterIterator;
  4. use Knp\Menu\MenuItem;
  5. use Knp\Menu\MenuFactory;
  6. class TestMenuItem extends MenuItem {}
  7. class MenuItemTreeTest extends TestCase
  8. {
  9. public function testSampleTreeIntegrity()
  10. {
  11. $this->assertCount(2, $this->menu);
  12. $this->assertCount(3, $this->menu['Parent 1']);
  13. $this->assertCount(1, $this->menu['Parent 2']);
  14. $this->assertCount(1, $this->menu['Parent 2']['Child 4']);
  15. $this->assertEquals('Grandchild 1', $this->menu['Parent 2']['Child 4']['Grandchild 1']->getName());
  16. }
  17. public function testGetLevel()
  18. {
  19. $this->assertEquals(0, $this->menu->getLevel());
  20. $this->assertEquals(1, $this->pt1->getLevel());
  21. $this->assertEquals(1, $this->pt2->getLevel());
  22. $this->assertEquals(2, $this->ch4->getLevel());
  23. $this->assertEquals(3, $this->gc1->getLevel());
  24. }
  25. public function testGetRoot()
  26. {
  27. $this->assertSame($this->menu, $this->menu->getRoot());
  28. $this->assertSame($this->menu, $this->pt1->getRoot());
  29. $this->assertSame($this->menu, $this->gc1->getRoot());
  30. }
  31. public function testIsRoot()
  32. {
  33. $this->assertTrue($this->menu->isRoot());
  34. $this->assertFalse($this->pt1->isRoot());
  35. $this->assertFalse($this->ch3->isRoot());
  36. }
  37. public function testGetParent()
  38. {
  39. $this->assertNull($this->menu->getParent());
  40. $this->assertSame($this->menu, $this->pt1->getParent());
  41. $this->assertSame($this->ch4, $this->gc1->getParent());
  42. }
  43. public function testMoveSampleMenuToNewRoot()
  44. {
  45. $newRoot = new TestMenuItem("newRoot", $this->getMock('Knp\Menu\FactoryInterface'));
  46. $newRoot->addChild($this->menu);
  47. $this->assertEquals(1, $this->menu->getLevel());
  48. $this->assertEquals(2, $this->pt1->getLevel());
  49. $this->assertSame($newRoot, $this->menu->getRoot());
  50. $this->assertSame($newRoot, $this->pt1->getRoot());
  51. $this->assertFalse($this->menu->isRoot());
  52. $this->assertTrue($newRoot->isRoot());
  53. $this->assertSame($newRoot, $this->menu->getParent());
  54. }
  55. public function testIsFirst()
  56. {
  57. $this->assertFalse($this->menu->isFirst(), 'The root item is not considered as first');
  58. $this->assertTrue($this->pt1->isFirst());
  59. $this->assertFalse($this->pt2->isFirst());
  60. $this->assertTrue($this->ch4->isFirst());
  61. }
  62. public function testActsLikeFirst()
  63. {
  64. $this->ch1->setDisplay(false);
  65. $this->assertFalse($this->menu->actsLikeFirst(), 'The root item is not considered as first');
  66. $this->assertFalse($this->ch1->actsLikeFirst(), 'A hidden item does not acts like first');
  67. $this->assertTrue($this->ch2->actsLikeFirst());
  68. $this->assertFalse($this->ch3->actsLikeFirst());
  69. $this->assertTrue($this->ch4->actsLikeFirst());
  70. }
  71. public function testActsLikeFirstWithNoDisplayedItem()
  72. {
  73. $this->pt1->setDisplay(false);
  74. $this->pt2->setDisplay(false);
  75. $this->assertFalse($this->pt1->actsLikeFirst());
  76. $this->assertFalse($this->pt2->actsLikeFirst());
  77. }
  78. public function testIsLast()
  79. {
  80. $this->assertFalse($this->menu->isLast(), 'The root item is not considered as last');
  81. $this->assertFalse($this->pt1->isLast());
  82. $this->assertTrue($this->pt2->isLast());
  83. $this->assertTrue($this->ch4->isLast());
  84. }
  85. public function testActsLikeLast()
  86. {
  87. $this->ch3->setDisplay(false);
  88. $this->assertFalse($this->menu->actsLikeLast(), 'The root item is not considered as last');
  89. $this->assertFalse($this->ch1->actsLikeLast());
  90. $this->assertTrue($this->ch2->actsLikeLast());
  91. $this->assertFalse($this->ch3->actsLikeLast(), 'A hidden item does not acts like last');
  92. $this->assertTrue($this->ch4->actsLikeLast());
  93. }
  94. public function testActsLikeLastWithNoDisplayedItem()
  95. {
  96. $this->pt1->setDisplay(false);
  97. $this->pt2->setDisplay(false);
  98. $this->assertFalse($this->pt1->actsLikeLast());
  99. $this->assertFalse($this->pt2->actsLikeLast());
  100. }
  101. public function testArrayAccess()
  102. {
  103. $this->menu->addChild('Child Menu');
  104. $this->assertEquals('Child Menu', $this->menu['Child Menu']->getName());
  105. $this->assertNull($this->menu['Fake']);
  106. $this->menu['New Child'] = 'New Label';
  107. $this->assertEquals('Knp\Menu\MenuItem', get_class($this->menu['New Child']));
  108. $this->assertEquals('New Child', $this->menu['New Child']->getName());
  109. $this->assertEquals('New Label', $this->menu['New Child']->getLabel());
  110. unset($this->menu['New Child']);
  111. $this->assertNull($this->menu['New Child']);
  112. }
  113. public function testCountable()
  114. {
  115. $this->assertCount(2, $this->menu);
  116. $this->menu->addChild('New Child');
  117. $this->assertCount(3, $this->menu);
  118. unset($this->menu['New Child']);
  119. $this->assertCount(2, $this->menu);
  120. }
  121. public function testGetChildren()
  122. {
  123. $children = $this->ch4->getChildren();
  124. $this->assertCount(1, $children);
  125. $this->assertEquals($this->gc1->getName(), $children['Grandchild 1']->getName());
  126. }
  127. public function testGetFirstChild()
  128. {
  129. $this->assertSame($this->pt1, $this->menu->getFirstChild());
  130. // test for bug in getFirstChild implementation (when internal array pointer is changed getFirstChild returns wrong child)
  131. foreach ($this->menu->getChildren() as $c);
  132. $this->assertSame($this->pt1, $this->menu->getFirstChild());
  133. }
  134. public function testGetLastChild()
  135. {
  136. $this->assertSame($this->pt2, $this->menu->getLastChild());
  137. // test for bug in getFirstChild implementation (when internal array pointer is changed getLastChild returns wrong child)
  138. foreach ($this->menu->getChildren() as $c);
  139. $this->assertSame($this->pt2, $this->menu->getLastChild());
  140. }
  141. public function testAddChildDoesNotUSeTheFactoryIfItem()
  142. {
  143. $factory = $this->getMock('Knp\Menu\FactoryInterface');
  144. $factory->expects($this->never())
  145. ->method('createItem');
  146. $menu = new MenuItem('Root li', $factory);
  147. $menu->addChild(new MenuItem('Child 3', $factory));
  148. }
  149. /**
  150. * @expectedException LogicException
  151. */
  152. public function testAddChildFailsIfInAnotherMenu()
  153. {
  154. $factory = $this->getMock('Knp\Menu\FactoryInterface');
  155. $menu = new MenuItem('Root li', $factory);
  156. $child = new MenuItem('Child 3', $factory);
  157. $menu->addChild($child);
  158. $menu2 = new MenuItem('Second menu', $factory);
  159. $menu2->addChild($child);
  160. }
  161. public function testGetChild()
  162. {
  163. $this->assertSame($this->gc1, $this->ch4->getChild('Grandchild 1'));
  164. $this->assertNull($this->ch4->getChild('nonexistentchild'));
  165. }
  166. public function testRemoveChild()
  167. {
  168. $gc2 = $this->ch4->addChild('gc2');
  169. $gc3 = $this->ch4->addChild('gc3');
  170. $gc4 = $this->ch4->addChild('gc4');
  171. $this->assertCount(4, $this->ch4);
  172. $this->ch4->removeChild('gc4');
  173. $this->assertCount(3, $this->ch4);
  174. $this->assertTrue($this->ch4->getChild('Grandchild 1')->isFirst());
  175. $this->assertTrue($this->ch4->getChild('gc3')->isLast());
  176. }
  177. public function testRemoveFakeChild()
  178. {
  179. $this->menu->removeChild('fake');
  180. $this->assertCount(2, $this->menu);
  181. }
  182. public function testReAddRemovedChild()
  183. {
  184. $gc2 = $this->ch4->addChild('gc2');
  185. $this->ch4->removeChild('gc2');
  186. $this->menu->addChild($gc2);
  187. $this->assertCount(3, $this->menu);
  188. $this->assertTrue($gc2->isLast());
  189. $this->assertFalse($this->pt2->isLast());
  190. }
  191. public function testUpdateChildAfterRename()
  192. {
  193. $this->pt1->setName('Temp name');
  194. $this->assertSame($this->pt1, $this->menu->getChild('Temp name'));
  195. $this->assertEquals(array('Temp name', 'Parent 2'), array_keys($this->menu->getChildren()));
  196. $this->assertNull($this->menu->getChild('Parent 1'));
  197. }
  198. /**
  199. * @expectedException InvalidArgumentException
  200. */
  201. public function testRenameToExistingSiblingNameThrowAnException()
  202. {
  203. $this->pt1->setName('Parent 2');
  204. }
  205. public function testGetSetCurrentUri()
  206. {
  207. $this->addChildWithExternalUrl();
  208. $this->assertNull($this->menu->getCurrentUri());
  209. $this->menu->setCurrentUri('http://symfony-reloaded.org/');
  210. $this->assertEquals('http://symfony-reloaded.org/', $this->menu->getCurrentUri());
  211. $this->assertEquals('http://symfony-reloaded.org/', $this->menu['child']->getCurrentUri());
  212. }
  213. public function testChildrenCurrentUri()
  214. {
  215. $this->addChildWithExternalUrl();
  216. $this->menu->setCurrentUri('http://symfony-reloaded.org/');
  217. $this->menu->addChild('test_child', array('uri' => 'http://php.net/'));
  218. $this->assertEquals('http://symfony-reloaded.org/', $this->menu['test_child']->getCurrentUri());
  219. }
  220. public function testGetIsCurrentWhenCurrentUriIsNotSet()
  221. {
  222. $this->addChildWithExternalUrl();
  223. $this->assertFalse($this->menu['child']->isCurrent());
  224. }
  225. public function testGetIsCurrentWhenCurrentUriIsSet()
  226. {
  227. $this->addChildWithExternalUrl();
  228. $this->menu->setCurrentUri('http://www.symfony-reloaded.org');
  229. $this->assertTrue($this->menu['child']->isCurrent());
  230. $this->assertFalse($this->pt1->isCurrent());
  231. }
  232. public function testGetIsCurrentAncestor()
  233. {
  234. $this->addChildWithExternalUrl();
  235. $this->menu->setCurrentUri('http://php.net');
  236. $this->pt1->setUri('http://php.net');
  237. $this->assertFalse($this->pt1->isCurrentAncestor());
  238. $this->assertTrue($this->menu->isCurrentAncestor());
  239. }
  240. public function testDeepGetIsCurrentAncestor()
  241. {
  242. $this->addChildWithExternalUrl();
  243. $this->menu->setCurrentUri('http://php.net');
  244. $this->gc1->setUri('http://php.net');
  245. $this->assertFalse($this->pt1->isCurrentAncestor());
  246. $this->assertTrue($this->menu->isCurrentAncestor());
  247. $this->assertTrue($this->pt2->isCurrentAncestor());
  248. $this->assertTrue($this->ch4->isCurrentAncestor());
  249. }
  250. public function testGetCurrentItem()
  251. {
  252. $this->ch4->setCurrent(true);
  253. $this->assertSame($this->ch4, $this->ch4->getCurrentItem());
  254. $this->assertSame($this->ch4, $this->menu->getCurrentItem());
  255. $this->assertNull($this->pt1->getCurrentItem());
  256. }
  257. public function testGetUri()
  258. {
  259. $this->addChildWithExternalUrl();
  260. $this->assertNull($this->pt1->getUri());
  261. $this->assertEquals('http://www.symfony-reloaded.org', $this->menu['child']->getUri());
  262. }
  263. /**
  264. * @dataProvider getSliceData
  265. */
  266. public function testSlice($offset, $length, $count, $keys)
  267. {
  268. $sliced = $this->pt1->slice($offset, $length);
  269. $this->assertCount($count, $sliced);
  270. $this->assertEquals($keys, array_keys($sliced->getChildren()));
  271. }
  272. public function getSliceData()
  273. {
  274. $this->setUp();
  275. return array(
  276. 'numeric offset and numeric length' => array(0, 2, 2, array($this->ch1->getName(), $this->ch2->getName())),
  277. 'numeric offset and no length' => array(0, null, 3, array($this->ch1->getName(), $this->ch2->getName(), $this->ch3->getName())),
  278. 'named offset and no length' => array('Child 2', null, 2, array($this->ch2->getName(), $this->ch3->getName())),
  279. 'child offset and no length' => array($this->ch3, null, 1, array($this->ch3->getName())),
  280. 'numeric offset and named length' => array(0, 'Child 3', 2, array($this->ch1->getName(), $this->ch2->getName())),
  281. 'numeric offset and child length' => array(0, $this->ch3, 2, array($this->ch1->getName(), $this->ch2->getName())),
  282. );
  283. }
  284. /**
  285. * @dataProvider getSplitData
  286. */
  287. public function testSplit($length, $count, $keys)
  288. {
  289. $splitted = $this->pt1->split($length);
  290. $this->assertArrayHasKey('primary', $splitted);
  291. $this->assertArrayHasKey('secondary', $splitted);
  292. $this->assertCount($count, $splitted['primary']);
  293. $this->assertCount(3 - $count, $splitted['secondary']);
  294. $this->assertEquals($keys, array_keys($splitted['primary']->getChildren()));
  295. }
  296. public function getSplitData()
  297. {
  298. $this->setUp();
  299. return array(
  300. 'numeric length' => array(1, 1, array($this->ch1->getName())),
  301. 'named length' => array('Child 3', 2, array($this->ch1->getName(), $this->ch2->getName())),
  302. 'child length' => array($this->ch3, 2, array($this->ch1->getName(), $this->ch2->getName())),
  303. );
  304. }
  305. public function testPathAsString()
  306. {
  307. $this->assertEquals('Root li > Parent 2 > Child 4', $this->ch4->getPathAsString(), 'Path with default separator');
  308. $this->assertEquals('Root li / Parent 1 / Child 2', $this->ch2->getPathAsString(' / '), 'Path with custom separator');
  309. }
  310. public function testBreadcrumbsArray()
  311. {
  312. $this->addChildWithExternalUrl();
  313. $this->menu->addChild('123', array('uri' => 'http://www.symfony-reloaded.org'));
  314. $this->assertEquals(array('Root li' => null, 'Parent 1' => null), $this->pt1->getBreadcrumbsArray());
  315. $this->assertEquals(array('Root li' => null, 'child' => 'http://www.symfony-reloaded.org'), $this->menu['child']->getBreadcrumbsArray());
  316. $this->assertEquals(array('Root li' => null, 'child' => 'http://www.symfony-reloaded.org', 'subitem1' => null), $this->menu['child']->getBreadcrumbsArray('subitem1'));
  317. $this->assertEquals(
  318. array('Root li' => null, 'child' => 'http://www.symfony-reloaded.org', 'subitem1' => null, 'subitem2' => null, 'subitem3' => 'http://php.net'),
  319. $this->menu['child']->getBreadcrumbsArray(array('subitem1', 'subitem2' => null, 'subitem3' => 'http://php.net'))
  320. );
  321. $this->assertEquals(array('Root li' => null, '123' => 'http://www.symfony-reloaded.org'), $this->menu['123']->getBreadcrumbsArray());
  322. }
  323. protected function addChildWithExternalUrl()
  324. {
  325. $this->menu->addChild('child', array('uri' => 'http://www.symfony-reloaded.org'));
  326. }
  327. }