ObjectCollectionTest.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. <?php
  2. /**
  3. * ObjectCollectionTest file
  4. *
  5. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  6. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  7. *
  8. * Licensed under The MIT License
  9. * For full copyright and license information, please see the LICENSE.txt
  10. * Redistributions of files must retain the above copyright notice.
  11. *
  12. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  13. * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
  14. * @package Cake.Test.Case.Utility
  15. * @since CakePHP(tm) v 2.0
  16. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  17. */
  18. App::uses('ObjectCollection', 'Utility');
  19. App::uses('CakeEvent', 'Event');
  20. /**
  21. * A generic object class
  22. */
  23. class GenericObject {
  24. /**
  25. * Constructor
  26. *
  27. * @param GenericObjectCollection $collection
  28. * @param array $settings
  29. */
  30. public function __construct(GenericObjectCollection $collection, $settings = array()) {
  31. $this->_Collection = $collection;
  32. $this->settings = $settings;
  33. }
  34. }
  35. /**
  36. * First Extension of Generic Object
  37. */
  38. class FirstGenericObject extends GenericObject {
  39. /**
  40. * A generic callback
  41. */
  42. public function callback() {
  43. }
  44. }
  45. /**
  46. * Second Extension of Generic Object
  47. */
  48. class SecondGenericObject extends GenericObject {
  49. public function callback() {
  50. }
  51. }
  52. /**
  53. * Third Extension of Generic Object
  54. */
  55. class ThirdGenericObject extends GenericObject {
  56. public function callback() {
  57. }
  58. }
  59. /**
  60. * A collection of Generic objects
  61. */
  62. class GenericObjectCollection extends ObjectCollection {
  63. /**
  64. * Loads a generic object
  65. *
  66. * @param string $object Object name
  67. * @param array $settings Settings array
  68. * @return array List of loaded objects
  69. */
  70. public function load($object, $settings = array()) {
  71. list(, $name) = pluginSplit($object);
  72. if (isset($this->_loaded[$name])) {
  73. return $this->_loaded[$name];
  74. }
  75. $objectClass = $name . 'GenericObject';
  76. $this->_loaded[$name] = new $objectClass($this, $settings);
  77. $enable = isset($settings['enabled']) ? $settings['enabled'] : true;
  78. if ($enable === true) {
  79. $this->enable($name);
  80. }
  81. return $this->_loaded[$name];
  82. }
  83. /**
  84. * Helper method for adding/overwriting enabled objects including
  85. * settings
  86. *
  87. * @param string $name Name of the object
  88. * @param Object $object The object to use
  89. * @param array $settings Settings to apply for the object
  90. * @return array Loaded objects
  91. */
  92. public function setObject($name, $object, $settings = array()) {
  93. $this->_loaded[$name] = $object;
  94. if (isset($settings['priority'])) {
  95. $this->setPriority($name, $settings['priority']);
  96. }
  97. $enable = isset($settings['enabled']) ? $settings['enabled'] : true;
  98. if ($enable === true) {
  99. $this->enable($name);
  100. }
  101. return $this->_loaded;
  102. }
  103. }
  104. class ObjectCollectionTest extends CakeTestCase {
  105. /**
  106. * setUp
  107. *
  108. * @return void
  109. */
  110. public function setUp() {
  111. parent::setUp();
  112. $this->Objects = new GenericObjectCollection();
  113. }
  114. /**
  115. * tearDown
  116. *
  117. * @return void
  118. */
  119. public function tearDown() {
  120. parent::tearDown();
  121. unset($this->Objects);
  122. }
  123. /**
  124. * test triggering callbacks on loaded helpers
  125. *
  126. * @return void
  127. */
  128. public function testLoad() {
  129. $result = $this->Objects->load('First');
  130. $this->assertInstanceOf('FirstGenericObject', $result);
  131. $this->assertInstanceOf('FirstGenericObject', $this->Objects->First);
  132. $result = $this->Objects->loaded();
  133. $this->assertEquals(array('First'), $result, 'loaded() results are wrong.');
  134. $this->assertTrue($this->Objects->enabled('First'));
  135. $result = $this->Objects->load('First');
  136. $this->assertSame($result, $this->Objects->First);
  137. }
  138. /**
  139. * test unload()
  140. *
  141. * @return void
  142. */
  143. public function testUnload() {
  144. $this->Objects->load('First');
  145. $this->Objects->load('Second');
  146. $result = $this->Objects->loaded();
  147. $this->assertEquals(array('First', 'Second'), $result, 'loaded objects are wrong');
  148. $this->Objects->unload('First');
  149. $this->assertFalse(isset($this->Objects->First));
  150. $this->assertTrue(isset($this->Objects->Second));
  151. $result = $this->Objects->loaded();
  152. $this->assertEquals(array('Second'), $result, 'loaded objects are wrong');
  153. $result = $this->Objects->loaded();
  154. $this->assertEquals(array('Second'), $result, 'enabled objects are wrong');
  155. }
  156. /**
  157. * Tests set()
  158. *
  159. * @return void
  160. */
  161. public function testSet() {
  162. $this->Objects->load('First');
  163. $result = $this->Objects->loaded();
  164. $this->assertEquals(array('First'), $result, 'loaded objects are wrong');
  165. $result = $this->Objects->set('First', new SecondGenericObject($this->Objects));
  166. $this->assertInstanceOf('SecondGenericObject', $result['First'], 'set failed');
  167. $result = $this->Objects->set('Second', new SecondGenericObject($this->Objects));
  168. $this->assertInstanceOf('SecondGenericObject', $result['Second'], 'set failed');
  169. $this->assertEquals(2, count($result));
  170. }
  171. /**
  172. * creates mock classes for testing
  173. *
  174. * @return void
  175. */
  176. protected function _makeMockClasses() {
  177. $this->FirstGenericObject = $this->getMock('FirstGenericObject', array(), array(), '', false);
  178. $this->SecondGenericObject = $this->getMock('SecondGenericObject', array(), array(), '', false);
  179. $this->ThirdGenericObject = $this->getMock('ThirdGenericObject', array(), array(), '', false);
  180. }
  181. /**
  182. * test triggering callbacks.
  183. *
  184. * @return void
  185. */
  186. public function testTrigger() {
  187. $this->_makeMockClasses();
  188. $this->Objects->setObject('TriggerMockFirst', $this->FirstGenericObject);
  189. $this->Objects->setObject('TriggerMockSecond', $this->SecondGenericObject);
  190. $this->Objects->TriggerMockFirst->expects($this->once())
  191. ->method('callback')
  192. ->will($this->returnValue(true));
  193. $this->Objects->TriggerMockSecond->expects($this->once())
  194. ->method('callback')
  195. ->will($this->returnValue(true));
  196. $this->assertTrue($this->Objects->trigger('callback'));
  197. }
  198. /**
  199. * test trigger and disabled objects
  200. *
  201. * @return void
  202. */
  203. public function testTriggerWithDisabledObjects() {
  204. $this->_makeMockClasses();
  205. $this->Objects->setObject('TriggerMockFirst', $this->FirstGenericObject);
  206. $this->Objects->setObject('TriggerMockSecond', $this->SecondGenericObject, array('enabled' => false));
  207. $this->Objects->TriggerMockFirst->expects($this->once())
  208. ->method('callback')
  209. ->will($this->returnValue(true));
  210. $this->Objects->TriggerMockSecond->expects($this->never())
  211. ->method('callback')
  212. ->will($this->returnValue(true));
  213. $this->assertTrue($this->Objects->trigger('callback', array()));
  214. }
  215. /**
  216. * test that the collectReturn option works.
  217. *
  218. * @return void
  219. */
  220. public function testTriggerWithCollectReturn() {
  221. $this->_makeMockClasses();
  222. $this->Objects->setObject('TriggerMockFirst', $this->FirstGenericObject);
  223. $this->Objects->setObject('TriggerMockSecond', $this->SecondGenericObject);
  224. $this->Objects->TriggerMockFirst->expects($this->once())
  225. ->method('callback')
  226. ->will($this->returnValue(array('one', 'two')));
  227. $this->Objects->TriggerMockSecond->expects($this->once())
  228. ->method('callback')
  229. ->will($this->returnValue(array('three', 'four')));
  230. $result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
  231. $expected = array(
  232. array('one', 'two'),
  233. array('three', 'four')
  234. );
  235. $this->assertEquals($expected, $result);
  236. }
  237. /**
  238. * test that trigger with break & breakOn works.
  239. *
  240. * @return void
  241. */
  242. public function testTriggerWithBreak() {
  243. $this->_makeMockClasses();
  244. $this->Objects->setObject('TriggerMockFirst', $this->FirstGenericObject);
  245. $this->Objects->setObject('TriggerMockSecond', $this->SecondGenericObject);
  246. $this->Objects->TriggerMockFirst->expects($this->once())
  247. ->method('callback')
  248. ->will($this->returnValue(false));
  249. $this->Objects->TriggerMockSecond->expects($this->never())
  250. ->method('callback');
  251. $result = $this->Objects->trigger(
  252. 'callback',
  253. array(),
  254. array('break' => true, 'breakOn' => false)
  255. );
  256. $this->assertFalse($result);
  257. }
  258. /**
  259. * test that trigger with modParams works.
  260. *
  261. * @return void
  262. */
  263. public function testTriggerWithModParams() {
  264. $this->_makeMockClasses();
  265. $this->Objects->setObject('TriggerMockFirst', $this->FirstGenericObject);
  266. $this->Objects->setObject('TriggerMockSecond', $this->SecondGenericObject);
  267. $this->Objects->TriggerMockFirst->expects($this->once())
  268. ->method('callback')
  269. ->with(array('value'))
  270. ->will($this->returnValue(array('new value')));
  271. $this->Objects->TriggerMockSecond->expects($this->once())
  272. ->method('callback')
  273. ->with(array('new value'))
  274. ->will($this->returnValue(array('newer value')));
  275. $result = $this->Objects->trigger(
  276. 'callback',
  277. array(array('value')),
  278. array('modParams' => 0)
  279. );
  280. $this->assertEquals(array('newer value'), $result);
  281. }
  282. /**
  283. * test that setting modParams to an index that doesn't exist doesn't cause errors.
  284. *
  285. * @expectedException CakeException
  286. * @return void
  287. */
  288. public function testTriggerModParamsInvalidIndex() {
  289. $this->_makeMockClasses();
  290. $this->Objects->setObject('TriggerMockFirst', $this->FirstGenericObject);
  291. $this->Objects->setObject('TriggerMockSecond', $this->SecondGenericObject);
  292. $this->Objects->TriggerMockFirst->expects($this->never())
  293. ->method('callback');
  294. $this->Objects->TriggerMockSecond->expects($this->never())
  295. ->method('callback');
  296. $this->Objects->trigger(
  297. 'callback',
  298. array(array('value')),
  299. array('modParams' => 2)
  300. );
  301. }
  302. /**
  303. * test that returning null doesn't modify parameters.
  304. *
  305. * @return void
  306. */
  307. public function testTriggerModParamsNullIgnored() {
  308. $this->_makeMockClasses();
  309. $this->Objects->setObject('TriggerMockFirst', $this->FirstGenericObject);
  310. $this->Objects->setObject('TriggerMockSecond', $this->SecondGenericObject);
  311. $this->Objects->TriggerMockFirst->expects($this->once())
  312. ->method('callback')
  313. ->with(array('value'))
  314. ->will($this->returnValue(null));
  315. $this->Objects->TriggerMockSecond->expects($this->once())
  316. ->method('callback')
  317. ->with(array('value'))
  318. ->will($this->returnValue(array('new value')));
  319. $result = $this->Objects->trigger(
  320. 'callback',
  321. array(array('value')),
  322. array('modParams' => 0)
  323. );
  324. $this->assertEquals(array('new value'), $result);
  325. }
  326. /**
  327. * test order of callbacks triggering based on priority.
  328. *
  329. * @return void
  330. */
  331. public function testTriggerPriority() {
  332. $this->_makeMockClasses();
  333. $this->Objects->setObject('TriggerMockFirst', $this->FirstGenericObject);
  334. $this->Objects->setObject('TriggerMockSecond', $this->SecondGenericObject, array('priority' => 5));
  335. $this->Objects->TriggerMockFirst->expects($this->any())
  336. ->method('callback')
  337. ->will($this->returnValue('1st'));
  338. $this->Objects->TriggerMockSecond->expects($this->any())
  339. ->method('callback')
  340. ->will($this->returnValue('2nd'));
  341. $result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
  342. $expected = array(
  343. '2nd',
  344. '1st'
  345. );
  346. $this->assertEquals($expected, $result);
  347. $this->Objects->setObject('TriggerMockThird', $this->ThirdGenericObject, array('priority' => 7));
  348. $this->Objects->TriggerMockThird->expects($this->any())
  349. ->method('callback')
  350. ->will($this->returnValue('3rd'));
  351. $result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
  352. $expected = array(
  353. '2nd',
  354. '3rd',
  355. '1st'
  356. );
  357. $this->assertEquals($expected, $result);
  358. $this->Objects->disable('TriggerMockFirst');
  359. $result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
  360. $expected = array(
  361. '2nd',
  362. '3rd'
  363. );
  364. $this->assertEquals($expected, $result);
  365. $this->Objects->enable('TriggerMockFirst');
  366. $result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
  367. $expected = array(
  368. '2nd',
  369. '3rd',
  370. '1st'
  371. );
  372. $this->assertEquals($expected, $result);
  373. $this->Objects->disable('TriggerMockThird');
  374. $result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
  375. $expected = array(
  376. '2nd',
  377. '1st'
  378. );
  379. $this->assertEquals($expected, $result);
  380. $this->Objects->enable('TriggerMockThird', false);
  381. $result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
  382. $expected = array(
  383. '2nd',
  384. '1st',
  385. '3rd'
  386. );
  387. $this->assertEquals($expected, $result);
  388. $this->Objects->setPriority('TriggerMockThird', 1);
  389. $result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
  390. $expected = array(
  391. '3rd',
  392. '2nd',
  393. '1st'
  394. );
  395. $this->assertEquals($expected, $result);
  396. $this->Objects->disable('TriggerMockThird');
  397. $this->Objects->setPriority('TriggerMockThird', 11);
  398. $result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
  399. $expected = array(
  400. '2nd',
  401. '1st'
  402. );
  403. $this->assertEquals($expected, $result);
  404. $this->Objects->enable('TriggerMockThird');
  405. $result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
  406. $expected = array(
  407. '2nd',
  408. '1st',
  409. '3rd'
  410. );
  411. $this->assertEquals($expected, $result);
  412. $this->Objects->setPriority('TriggerMockThird');
  413. $result = $this->Objects->trigger('callback', array(), array('collectReturn' => true));
  414. $expected = array(
  415. '2nd',
  416. '1st',
  417. '3rd'
  418. );
  419. $this->assertEquals($expected, $result);
  420. }
  421. /**
  422. * test normalizeObjectArray
  423. *
  424. * @return void
  425. */
  426. public function testnormalizeObjectArray() {
  427. $components = array(
  428. 'Html',
  429. 'Foo.Bar' => array('one', 'two'),
  430. 'Something',
  431. 'Banana.Apple' => array('foo' => 'bar')
  432. );
  433. $result = ObjectCollection::normalizeObjectArray($components);
  434. $expected = array(
  435. 'Html' => array('class' => 'Html', 'settings' => array()),
  436. 'Bar' => array('class' => 'Foo.Bar', 'settings' => array('one', 'two')),
  437. 'Something' => array('class' => 'Something', 'settings' => array()),
  438. 'Apple' => array('class' => 'Banana.Apple', 'settings' => array('foo' => 'bar')),
  439. );
  440. $this->assertEquals($expected, $result);
  441. // This is the result after Controller::_mergeVars
  442. $components = array(
  443. 'Html' => null,
  444. 'Foo.Bar' => array('one', 'two'),
  445. 'Something' => null,
  446. 'Banana.Apple' => array('foo' => 'bar')
  447. );
  448. $result = ObjectCollection::normalizeObjectArray($components);
  449. $this->assertEquals($expected, $result);
  450. }
  451. /**
  452. * tests that passing an instance of CakeEvent to trigger will prepend the subject to the list of arguments
  453. *
  454. * @return void
  455. */
  456. public function testDispatchEventWithSubject() {
  457. $this->_makeMockClasses();
  458. $this->Objects->setObject('TriggerMockFirst', $this->FirstGenericObject);
  459. $this->Objects->setObject('TriggerMockSecond', $this->SecondGenericObject);
  460. $subjectClass = new Object();
  461. $this->Objects->TriggerMockFirst->expects($this->once())
  462. ->method('callback')
  463. ->with($subjectClass, 'first argument')
  464. ->will($this->returnValue(true));
  465. $this->Objects->TriggerMockSecond->expects($this->once())
  466. ->method('callback')
  467. ->with($subjectClass, 'first argument')
  468. ->will($this->returnValue(true));
  469. $event = new CakeEvent('callback', $subjectClass, array('first argument'));
  470. $this->assertTrue($this->Objects->trigger($event));
  471. }
  472. /**
  473. * tests that passing an instance of CakeEvent to trigger with omitSubject property
  474. * will NOT prepend the subject to the list of arguments
  475. *
  476. * @return void
  477. */
  478. public function testDispatchEventNoSubject() {
  479. $this->_makeMockClasses();
  480. $this->Objects->setObject('TriggerMockFirst', $this->FirstGenericObject);
  481. $this->Objects->setObject('TriggerMockSecond', $this->SecondGenericObject);
  482. $subjectClass = new Object();
  483. $this->Objects->TriggerMockFirst->expects($this->once())
  484. ->method('callback')
  485. ->with('first argument')
  486. ->will($this->returnValue(true));
  487. $this->Objects->TriggerMockSecond->expects($this->once())
  488. ->method('callback')
  489. ->with('first argument')
  490. ->will($this->returnValue(true));
  491. $event = new CakeEvent('callback', $subjectClass, array('first argument'));
  492. $event->omitSubject = true;
  493. $this->assertTrue($this->Objects->trigger($event));
  494. }
  495. }