ObjectCollectionTest.php 16 KB

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