CollectionTest.php 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Collection;
  16. use ArrayIterator;
  17. use ArrayObject;
  18. use Cake\Collection\Collection;
  19. use Cake\Collection\CollectionInterface;
  20. use Cake\Collection\CollectionTrait;
  21. use Cake\TestSuite\TestCase;
  22. use NoRewindIterator;
  23. class TestCollection extends \IteratorIterator implements CollectionInterface
  24. {
  25. use CollectionTrait;
  26. public function __construct($items)
  27. {
  28. if (is_array($items)) {
  29. $items = new \ArrayIterator($items);
  30. }
  31. if (!($items instanceof \Traversable)) {
  32. $msg = 'Only an array or \Traversable is allowed for Collection';
  33. throw new \InvalidArgumentException($msg);
  34. }
  35. parent::__construct($items);
  36. }
  37. }
  38. /**
  39. * CollectionTest
  40. */
  41. class CollectionTest extends TestCase
  42. {
  43. /**
  44. * Tests that it is possible to convert an array into a collection
  45. *
  46. * @return void
  47. */
  48. public function testArrayIsWrapped()
  49. {
  50. $items = [1, 2, 3];
  51. $collection = new Collection($items);
  52. $this->assertEquals($items, iterator_to_array($collection));
  53. }
  54. /**
  55. * Tests that it is possible to convert an iterator into a collection
  56. *
  57. * @return void
  58. */
  59. public function testIteratorIsWrapped()
  60. {
  61. $items = new \ArrayObject([1, 2, 3]);
  62. $collection = new Collection($items);
  63. $this->assertEquals(iterator_to_array($items), iterator_to_array($collection));
  64. }
  65. /**
  66. * Test running a method over all elements in the collection
  67. *
  68. * @return void
  69. */
  70. public function testEeach()
  71. {
  72. $items = ['a' => 1, 'b' => 2, 'c' => 3];
  73. $collection = new Collection($items);
  74. $callable = $this->getMockBuilder(\StdClass::class)
  75. ->setMethods(['__invoke'])
  76. ->getMock();
  77. $callable->expects($this->at(0))
  78. ->method('__invoke')
  79. ->with(1, 'a');
  80. $callable->expects($this->at(1))
  81. ->method('__invoke')
  82. ->with(2, 'b');
  83. $callable->expects($this->at(2))
  84. ->method('__invoke')
  85. ->with(3, 'c');
  86. $collection->each($callable);
  87. }
  88. /**
  89. * Test filter() with no callback.
  90. *
  91. * @return void
  92. */
  93. public function testFilterNoCallback()
  94. {
  95. $items = [1, 2, 0, 3, false, 4, null, 5, ''];
  96. $collection = new Collection($items);
  97. $result = $collection->filter()->toArray();
  98. $expected = [1, 2, 3, 4, 5];
  99. $this->assertEquals($expected, array_values($result));
  100. }
  101. /**
  102. * Tests that it is possible to chain filter() as it returns a collection object
  103. *
  104. * @return void
  105. */
  106. public function testFilterChaining()
  107. {
  108. $items = ['a' => 1, 'b' => 2, 'c' => 3];
  109. $collection = new Collection($items);
  110. $callable = $this->getMockBuilder(\StdClass::class)
  111. ->setMethods(['__invoke'])
  112. ->getMock();
  113. $callable->expects($this->once())
  114. ->method('__invoke')
  115. ->with(3, 'c');
  116. $filtered = $collection->filter(function ($value, $key, $iterator) {
  117. return $value > 2;
  118. });
  119. $this->assertInstanceOf('Cake\Collection\Collection', $filtered);
  120. $filtered->each($callable);
  121. }
  122. /**
  123. * Tests reject
  124. *
  125. * @return void
  126. */
  127. public function testReject()
  128. {
  129. $collection = new Collection([]);
  130. $result = $collection->reject(function ($v) {
  131. return false;
  132. });
  133. $this->assertSame([], iterator_to_array($result));
  134. $items = ['a' => 1, 'b' => 2, 'c' => 3];
  135. $collection = new Collection($items);
  136. $result = $collection->reject(function ($v, $k, $items) use ($collection) {
  137. $this->assertSame($collection->getInnerIterator(), $items);
  138. return $v > 2;
  139. });
  140. $this->assertEquals(['a' => 1, 'b' => 2], iterator_to_array($result));
  141. $this->assertInstanceOf('Cake\Collection\Collection', $result);
  142. }
  143. /**
  144. * Tests every when the callback returns true for all elements
  145. *
  146. * @return void
  147. */
  148. public function testEveryReturnTrue()
  149. {
  150. $items = ['a' => 1, 'b' => 2, 'c' => 3];
  151. $collection = new Collection($items);
  152. $callable = $this->getMockBuilder(\StdClass::class)
  153. ->setMethods(['__invoke'])
  154. ->getMock();
  155. $callable->expects($this->at(0))
  156. ->method('__invoke')
  157. ->with(1, 'a')
  158. ->will($this->returnValue(true));
  159. $callable->expects($this->at(1))
  160. ->method('__invoke')
  161. ->with(2, 'b')
  162. ->will($this->returnValue(true));
  163. $callable->expects($this->at(2))
  164. ->method('__invoke')
  165. ->with(3, 'c')
  166. ->will($this->returnValue(true));
  167. $this->assertTrue($collection->every($callable));
  168. }
  169. /**
  170. * Tests every when the callback returns false for one of the elements
  171. *
  172. * @return void
  173. */
  174. public function testEveryReturnFalse()
  175. {
  176. $items = ['a' => 1, 'b' => 2, 'c' => 3];
  177. $collection = new Collection($items);
  178. $callable = $this->getMockBuilder(\StdClass::class)
  179. ->setMethods(['__invoke'])
  180. ->getMock();
  181. $callable->expects($this->at(0))
  182. ->method('__invoke')
  183. ->with(1, 'a')
  184. ->will($this->returnValue(true));
  185. $callable->expects($this->at(1))
  186. ->method('__invoke')
  187. ->with(2, 'b')
  188. ->will($this->returnValue(false));
  189. $callable->expects($this->exactly(2))->method('__invoke');
  190. $this->assertFalse($collection->every($callable));
  191. $items = [];
  192. $collection = new Collection($items);
  193. $callable = $this->getMockBuilder(\StdClass::class)
  194. ->setMethods(['__invoke'])
  195. ->getMock();
  196. $callable->expects($this->never())
  197. ->method('__invoke');
  198. $this->assertTrue($collection->every($callable));
  199. }
  200. /**
  201. * Tests some() when one of the calls return true
  202. *
  203. * @return void
  204. */
  205. public function testSomeReturnTrue()
  206. {
  207. $collection = new Collection([]);
  208. $result = $collection->some(function ($v) {
  209. return true;
  210. });
  211. $this->assertFalse($result);
  212. $items = ['a' => 1, 'b' => 2, 'c' => 3];
  213. $collection = new Collection($items);
  214. $callable = $this->getMockBuilder(\StdClass::class)
  215. ->setMethods(['__invoke'])
  216. ->getMock();
  217. $callable->expects($this->at(0))
  218. ->method('__invoke')
  219. ->with(1, 'a')
  220. ->will($this->returnValue(false));
  221. $callable->expects($this->at(1))
  222. ->method('__invoke')
  223. ->with(2, 'b')
  224. ->will($this->returnValue(true));
  225. $callable->expects($this->exactly(2))->method('__invoke');
  226. $this->assertTrue($collection->some($callable));
  227. }
  228. /**
  229. * Tests some() when none of the calls return true
  230. *
  231. * @return void
  232. */
  233. public function testSomeReturnFalse()
  234. {
  235. $items = ['a' => 1, 'b' => 2, 'c' => 3];
  236. $collection = new Collection($items);
  237. $callable = $this->getMockBuilder(\StdClass::class)
  238. ->setMethods(['__invoke'])
  239. ->getMock();
  240. $callable->expects($this->at(0))
  241. ->method('__invoke')
  242. ->with(1, 'a')
  243. ->will($this->returnValue(false));
  244. $callable->expects($this->at(1))
  245. ->method('__invoke')
  246. ->with(2, 'b')
  247. ->will($this->returnValue(false));
  248. $callable->expects($this->at(2))
  249. ->method('__invoke')
  250. ->with(3, 'c')
  251. ->will($this->returnValue(false));
  252. $this->assertFalse($collection->some($callable));
  253. }
  254. /**
  255. * Tests contains
  256. *
  257. * @return void
  258. */
  259. public function testContains()
  260. {
  261. $collection = new Collection([]);
  262. $this->assertFalse($collection->contains('a'));
  263. $items = ['a' => 1, 'b' => 2, 'c' => 3];
  264. $collection = new Collection($items);
  265. $this->assertTrue($collection->contains(2));
  266. $this->assertTrue($collection->contains(1));
  267. $this->assertFalse($collection->contains(10));
  268. $this->assertFalse($collection->contains('2'));
  269. }
  270. /**
  271. * Tests map
  272. *
  273. * @return void
  274. */
  275. public function testMap()
  276. {
  277. $items = ['a' => 1, 'b' => 2, 'c' => 3];
  278. $collection = new Collection($items);
  279. $map = $collection->map(function ($v, $k, $it) use ($collection) {
  280. $this->assertSame($collection->getInnerIterator(), $it);
  281. return $v * $v;
  282. });
  283. $this->assertInstanceOf('Cake\Collection\Iterator\ReplaceIterator', $map);
  284. $this->assertEquals(['a' => 1, 'b' => 4, 'c' => 9], iterator_to_array($map));
  285. }
  286. /**
  287. * Tests reduce with initial value
  288. *
  289. * @return void
  290. */
  291. public function testReduceWithInitialValue()
  292. {
  293. $items = ['a' => 1, 'b' => 2, 'c' => 3];
  294. $collection = new Collection($items);
  295. $callable = $this->getMockBuilder(\StdClass::class)
  296. ->setMethods(['__invoke'])
  297. ->getMock();
  298. $callable->expects($this->at(0))
  299. ->method('__invoke')
  300. ->with(10, 1, 'a')
  301. ->will($this->returnValue(11));
  302. $callable->expects($this->at(1))
  303. ->method('__invoke')
  304. ->with(11, 2, 'b')
  305. ->will($this->returnValue(13));
  306. $callable->expects($this->at(2))
  307. ->method('__invoke')
  308. ->with(13, 3, 'c')
  309. ->will($this->returnValue(16));
  310. $this->assertEquals(16, $collection->reduce($callable, 10));
  311. }
  312. /**
  313. * Tests reduce without initial value
  314. *
  315. * @return void
  316. */
  317. public function testReduceWithoutInitialValue()
  318. {
  319. $items = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4];
  320. $collection = new Collection($items);
  321. $callable = $this->getMockBuilder(\StdClass::class)
  322. ->setMethods(['__invoke'])
  323. ->getMock();
  324. $callable->expects($this->at(0))
  325. ->method('__invoke')
  326. ->with(1, 2, 'b')
  327. ->will($this->returnValue(3));
  328. $callable->expects($this->at(1))
  329. ->method('__invoke')
  330. ->with(3, 3, 'c')
  331. ->will($this->returnValue(6));
  332. $callable->expects($this->at(2))
  333. ->method('__invoke')
  334. ->with(6, 4, 'd')
  335. ->will($this->returnValue(10));
  336. $this->assertEquals(10, $collection->reduce($callable));
  337. }
  338. /**
  339. * Tests extract
  340. *
  341. * @return void
  342. */
  343. public function testExtract()
  344. {
  345. $items = [['a' => ['b' => ['c' => 1]]], 2];
  346. $collection = new Collection($items);
  347. $map = $collection->extract('a.b.c');
  348. $this->assertInstanceOf('Cake\Collection\Iterator\ExtractIterator', $map);
  349. $this->assertEquals([1, null], iterator_to_array($map));
  350. }
  351. /**
  352. * Tests sort
  353. *
  354. * @return void
  355. */
  356. public function testSortString()
  357. {
  358. $items = [
  359. ['a' => ['b' => ['c' => 4]]],
  360. ['a' => ['b' => ['c' => 10]]],
  361. ['a' => ['b' => ['c' => 6]]]
  362. ];
  363. $collection = new Collection($items);
  364. $map = $collection->sortBy('a.b.c');
  365. $this->assertInstanceOf('Cake\Collection\Collection', $map);
  366. $expected = [
  367. ['a' => ['b' => ['c' => 10]]],
  368. ['a' => ['b' => ['c' => 6]]],
  369. ['a' => ['b' => ['c' => 4]]],
  370. ];
  371. $this->assertEquals($expected, $map->toList());
  372. }
  373. /**
  374. * Tests max
  375. *
  376. * @return void
  377. */
  378. public function testMax()
  379. {
  380. $items = [
  381. ['a' => ['b' => ['c' => 4]]],
  382. ['a' => ['b' => ['c' => 10]]],
  383. ['a' => ['b' => ['c' => 6]]]
  384. ];
  385. $collection = new Collection($items);
  386. $this->assertEquals(['a' => ['b' => ['c' => 10]]], $collection->max('a.b.c'));
  387. $callback = function ($e) {
  388. return $e['a']['b']['c'] * - 1;
  389. };
  390. $this->assertEquals(['a' => ['b' => ['c' => 4]]], $collection->max($callback));
  391. }
  392. /**
  393. * Tests min
  394. *
  395. * @return void
  396. */
  397. public function testMin()
  398. {
  399. $items = [
  400. ['a' => ['b' => ['c' => 4]]],
  401. ['a' => ['b' => ['c' => 10]]],
  402. ['a' => ['b' => ['c' => 6]]]
  403. ];
  404. $collection = new Collection($items);
  405. $this->assertEquals(['a' => ['b' => ['c' => 4]]], $collection->min('a.b.c'));
  406. }
  407. /**
  408. * Tests groupBy
  409. *
  410. * @return void
  411. */
  412. public function testGroupBy()
  413. {
  414. $items = [
  415. ['id' => 1, 'name' => 'foo', 'parent_id' => 10],
  416. ['id' => 2, 'name' => 'bar', 'parent_id' => 11],
  417. ['id' => 3, 'name' => 'baz', 'parent_id' => 10],
  418. ];
  419. $collection = new Collection($items);
  420. $grouped = $collection->groupBy('parent_id');
  421. $expected = [
  422. 10 => [
  423. ['id' => 1, 'name' => 'foo', 'parent_id' => 10],
  424. ['id' => 3, 'name' => 'baz', 'parent_id' => 10],
  425. ],
  426. 11 => [
  427. ['id' => 2, 'name' => 'bar', 'parent_id' => 11],
  428. ]
  429. ];
  430. $this->assertEquals($expected, iterator_to_array($grouped));
  431. $this->assertInstanceOf('Cake\Collection\Collection', $grouped);
  432. $grouped = $collection->groupBy(function ($element) {
  433. return $element['parent_id'];
  434. });
  435. $this->assertEquals($expected, iterator_to_array($grouped));
  436. }
  437. /**
  438. * Tests grouping by a deep key
  439. *
  440. * @return void
  441. */
  442. public function testGroupByDeepKey()
  443. {
  444. $items = [
  445. ['id' => 1, 'name' => 'foo', 'thing' => ['parent_id' => 10]],
  446. ['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]],
  447. ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]],
  448. ];
  449. $collection = new Collection($items);
  450. $grouped = $collection->groupBy('thing.parent_id');
  451. $expected = [
  452. 10 => [
  453. ['id' => 1, 'name' => 'foo', 'thing' => ['parent_id' => 10]],
  454. ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]],
  455. ],
  456. 11 => [
  457. ['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]],
  458. ]
  459. ];
  460. $this->assertEquals($expected, iterator_to_array($grouped));
  461. }
  462. /**
  463. * Tests indexBy
  464. *
  465. * @return void
  466. */
  467. public function testIndexBy()
  468. {
  469. $items = [
  470. ['id' => 1, 'name' => 'foo', 'parent_id' => 10],
  471. ['id' => 2, 'name' => 'bar', 'parent_id' => 11],
  472. ['id' => 3, 'name' => 'baz', 'parent_id' => 10],
  473. ];
  474. $collection = new Collection($items);
  475. $grouped = $collection->indexBy('id');
  476. $expected = [
  477. 1 => ['id' => 1, 'name' => 'foo', 'parent_id' => 10],
  478. 3 => ['id' => 3, 'name' => 'baz', 'parent_id' => 10],
  479. 2 => ['id' => 2, 'name' => 'bar', 'parent_id' => 11],
  480. ];
  481. $this->assertEquals($expected, iterator_to_array($grouped));
  482. $this->assertInstanceOf('Cake\Collection\Collection', $grouped);
  483. $grouped = $collection->indexBy(function ($element) {
  484. return $element['id'];
  485. });
  486. $this->assertEquals($expected, iterator_to_array($grouped));
  487. }
  488. /**
  489. * Tests indexBy with a deep property
  490. *
  491. * @return void
  492. */
  493. public function testIndexByDeep()
  494. {
  495. $items = [
  496. ['id' => 1, 'name' => 'foo', 'thing' => ['parent_id' => 10]],
  497. ['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]],
  498. ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]],
  499. ];
  500. $collection = new Collection($items);
  501. $grouped = $collection->indexBy('thing.parent_id');
  502. $expected = [
  503. 10 => ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]],
  504. 11 => ['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]],
  505. ];
  506. $this->assertEquals($expected, iterator_to_array($grouped));
  507. }
  508. /**
  509. * Tests countBy
  510. *
  511. * @return void
  512. */
  513. public function testCountBy()
  514. {
  515. $items = [
  516. ['id' => 1, 'name' => 'foo', 'parent_id' => 10],
  517. ['id' => 2, 'name' => 'bar', 'parent_id' => 11],
  518. ['id' => 3, 'name' => 'baz', 'parent_id' => 10],
  519. ];
  520. $collection = new Collection($items);
  521. $grouped = $collection->countBy('parent_id');
  522. $expected = [
  523. 10 => 2,
  524. 11 => 1
  525. ];
  526. $this->assertEquals($expected, iterator_to_array($grouped));
  527. $this->assertInstanceOf('Cake\Collection\Collection', $grouped);
  528. $grouped = $collection->countBy(function ($element) {
  529. return $element['parent_id'];
  530. });
  531. $this->assertEquals($expected, iterator_to_array($grouped));
  532. }
  533. /**
  534. * Tests shuffle
  535. *
  536. * @return void
  537. */
  538. public function testShuffle()
  539. {
  540. $data = [1, 2, 3, 4];
  541. $collection = (new Collection($data))->shuffle();
  542. $this->assertEquals(count($data), count(iterator_to_array($collection)));
  543. foreach ($collection as $value) {
  544. $this->assertContains($value, $data);
  545. }
  546. }
  547. /**
  548. * Tests sample
  549. *
  550. * @return void
  551. */
  552. public function testSample()
  553. {
  554. $data = [1, 2, 3, 4];
  555. $collection = (new Collection($data))->sample(2);
  556. $this->assertEquals(2, count(iterator_to_array($collection)));
  557. foreach ($collection as $value) {
  558. $this->assertContains($value, $data);
  559. }
  560. }
  561. /**
  562. * Test toArray method
  563. *
  564. * @return void
  565. */
  566. public function testToArray()
  567. {
  568. $data = [1, 2, 3, 4];
  569. $collection = new Collection($data);
  570. $this->assertEquals($data, $collection->toArray());
  571. }
  572. /**
  573. * Test toList method
  574. *
  575. * @return void
  576. */
  577. public function testToList()
  578. {
  579. $data = [100 => 1, 300 => 2, 500 => 3, 1 => 4];
  580. $collection = new Collection($data);
  581. $this->assertEquals(array_values($data), $collection->toList());
  582. }
  583. /**
  584. * Test json encoding
  585. *
  586. * @return void
  587. */
  588. public function testToJson()
  589. {
  590. $data = [1, 2, 3, 4];
  591. $collection = new Collection($data);
  592. $this->assertEquals(json_encode($data), json_encode($collection));
  593. }
  594. /**
  595. * Tests that only arrays and Traversables are allowed in the constructor
  596. *
  597. * @expectedException \InvalidArgumentException
  598. * @expectedExceptionMessage Only an array or \Traversable is allowed for Collection
  599. * @return void
  600. */
  601. public function testInvalidConstructorArgument()
  602. {
  603. new Collection('Derp');
  604. }
  605. /**
  606. * Tests that issuing a count will throw an exception
  607. *
  608. * @expectedException \LogicException
  609. * @return void
  610. */
  611. public function testCollectionCount()
  612. {
  613. $data = [1, 2, 3, 4];
  614. $collection = new Collection($data);
  615. $collection->count();
  616. }
  617. /**
  618. * Tests take method
  619. *
  620. * @return void
  621. */
  622. public function testTake()
  623. {
  624. $data = [1, 2, 3, 4];
  625. $collection = new Collection($data);
  626. $taken = $collection->take(2);
  627. $this->assertEquals([1, 2], $taken->toArray());
  628. $taken = $collection->take(3);
  629. $this->assertEquals([1, 2, 3], $taken->toArray());
  630. $taken = $collection->take(500);
  631. $this->assertEquals([1, 2, 3, 4], $taken->toArray());
  632. $taken = $collection->take(1);
  633. $this->assertEquals([1], $taken->toArray());
  634. $taken = $collection->take();
  635. $this->assertEquals([1], $taken->toArray());
  636. $taken = $collection->take(2, 2);
  637. $this->assertEquals([2 => 3, 3 => 4], $taken->toArray());
  638. }
  639. /**
  640. * Tests match
  641. *
  642. * @return void
  643. */
  644. public function testMatch()
  645. {
  646. $items = [
  647. ['id' => 1, 'name' => 'foo', 'thing' => ['parent_id' => 10]],
  648. ['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]],
  649. ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]],
  650. ];
  651. $collection = new Collection($items);
  652. $matched = $collection->match(['thing.parent_id' => 10, 'name' => 'baz']);
  653. $this->assertEquals([2 => $items[2]], $matched->toArray());
  654. $matched = $collection->match(['thing.parent_id' => 10]);
  655. $this->assertEquals(
  656. [0 => $items[0], 2 => $items[2]],
  657. $matched->toArray()
  658. );
  659. $matched = $collection->match(['thing.parent_id' => 500]);
  660. $this->assertEquals([], $matched->toArray());
  661. $matched = $collection->match(['parent_id' => 10, 'name' => 'baz']);
  662. $this->assertEquals([], $matched->toArray());
  663. }
  664. /**
  665. * Tests firstMatch
  666. *
  667. * @return void
  668. */
  669. public function testFirstMatch()
  670. {
  671. $items = [
  672. ['id' => 1, 'name' => 'foo', 'thing' => ['parent_id' => 10]],
  673. ['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]],
  674. ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]],
  675. ];
  676. $collection = new Collection($items);
  677. $matched = $collection->firstMatch(['thing.parent_id' => 10]);
  678. $this->assertEquals(
  679. ['id' => 1, 'name' => 'foo', 'thing' => ['parent_id' => 10]],
  680. $matched
  681. );
  682. $matched = $collection->firstMatch(['thing.parent_id' => 10, 'name' => 'baz']);
  683. $this->assertEquals(
  684. ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]],
  685. $matched
  686. );
  687. }
  688. /**
  689. * Tests the append method
  690. *
  691. * @return void
  692. */
  693. public function testAppend()
  694. {
  695. $collection = new Collection([1, 2, 3]);
  696. $combined = $collection->append([4, 5, 6]);
  697. $this->assertEquals([1, 2, 3, 4, 5, 6], $combined->toArray(false));
  698. $collection = new Collection(['a' => 1, 'b' => 2]);
  699. $combined = $collection->append(['c' => 3, 'a' => 4]);
  700. $this->assertEquals(['a' => 4, 'b' => 2, 'c' => 3], $combined->toArray());
  701. }
  702. /**
  703. * Tests the append method with iterator
  704. */
  705. public function testAppendIterator()
  706. {
  707. $collection = new Collection([1, 2, 3]);
  708. $iterator = new ArrayIterator([4, 5, 6]);
  709. $combined = $collection->append($iterator);
  710. $this->assertEquals([1, 2, 3, 4, 5, 6], $combined->toList());
  711. }
  712. public function testAppendNotCollectionInstance()
  713. {
  714. $collection = new TestCollection([1, 2, 3]);
  715. $combined = $collection->append([4, 5, 6]);
  716. $this->assertEquals([1, 2, 3, 4, 5, 6], $combined->toList());
  717. }
  718. /**
  719. * Tests that by calling compile internal iteration operations are not done
  720. * more than once
  721. *
  722. * @return void
  723. */
  724. public function testCompile()
  725. {
  726. $items = ['a' => 1, 'b' => 2, 'c' => 3];
  727. $collection = new Collection($items);
  728. $callable = $this->getMockBuilder(\StdClass::class)
  729. ->setMethods(['__invoke'])
  730. ->getMock();
  731. $callable->expects($this->at(0))
  732. ->method('__invoke')
  733. ->with(1, 'a')
  734. ->will($this->returnValue(4));
  735. $callable->expects($this->at(1))
  736. ->method('__invoke')
  737. ->with(2, 'b')
  738. ->will($this->returnValue(5));
  739. $callable->expects($this->at(2))
  740. ->method('__invoke')
  741. ->with(3, 'c')
  742. ->will($this->returnValue(6));
  743. $compiled = $collection->map($callable)->compile();
  744. $this->assertEquals(['a' => 4, 'b' => 5, 'c' => 6], $compiled->toArray());
  745. $this->assertEquals(['a' => 4, 'b' => 5, 'c' => 6], $compiled->toArray());
  746. }
  747. /**
  748. * Tests converting a non rewindable iterator into a rewindable one using
  749. * the buffered method.
  750. *
  751. * @return void
  752. */
  753. public function testBuffered()
  754. {
  755. $items = new NoRewindIterator(new ArrayIterator(['a' => 4, 'b' => 5, 'c' => 6]));
  756. $buffered = (new Collection($items))->buffered();
  757. $this->assertEquals(['a' => 4, 'b' => 5, 'c' => 6], $buffered->toArray());
  758. $this->assertEquals(['a' => 4, 'b' => 5, 'c' => 6], $buffered->toArray());
  759. }
  760. /**
  761. * Tests the combine method
  762. *
  763. * @return void
  764. */
  765. public function testCombine()
  766. {
  767. $items = [
  768. ['id' => 1, 'name' => 'foo', 'parent' => 'a'],
  769. ['id' => 2, 'name' => 'bar', 'parent' => 'b'],
  770. ['id' => 3, 'name' => 'baz', 'parent' => 'a']
  771. ];
  772. $collection = (new Collection($items))->combine('id', 'name');
  773. $expected = [1 => 'foo', 2 => 'bar', 3 => 'baz'];
  774. $this->assertEquals($expected, $collection->toArray());
  775. $expected = ['foo' => 1, 'bar' => 2, 'baz' => 3];
  776. $collection = (new Collection($items))->combine('name', 'id');
  777. $this->assertEquals($expected, $collection->toArray());
  778. $collection = (new Collection($items))->combine('id', 'name', 'parent');
  779. $expected = ['a' => [1 => 'foo', 3 => 'baz'], 'b' => [2 => 'bar']];
  780. $this->assertEquals($expected, $collection->toArray());
  781. $expected = [
  782. '0-1' => ['foo-0-1' => '0-1-foo'],
  783. '1-2' => ['bar-1-2' => '1-2-bar'],
  784. '2-3' => ['baz-2-3' => '2-3-baz']
  785. ];
  786. $collection = (new Collection($items))->combine(
  787. function ($value, $key) {
  788. return $value['name'] . '-' . $key;
  789. },
  790. function ($value, $key) {
  791. return $key . '-' . $value['name'];
  792. },
  793. function ($value, $key) {
  794. return $key . '-' . $value['id'];
  795. }
  796. );
  797. $this->assertEquals($expected, $collection->toArray());
  798. $collection = (new Collection($items))->combine('id', 'crazy');
  799. $this->assertEquals([1 => null, 2 => null, 3 => null], $collection->toArray());
  800. }
  801. /**
  802. * Tests the nest method with only one level
  803. *
  804. * @return void
  805. */
  806. public function testNest()
  807. {
  808. $items = [
  809. ['id' => 1, 'parent_id' => null],
  810. ['id' => 2, 'parent_id' => 1],
  811. ['id' => 3, 'parent_id' => 1],
  812. ['id' => 4, 'parent_id' => 1],
  813. ['id' => 5, 'parent_id' => 6],
  814. ['id' => 6, 'parent_id' => null],
  815. ['id' => 7, 'parent_id' => 1],
  816. ['id' => 8, 'parent_id' => 6],
  817. ['id' => 9, 'parent_id' => 6],
  818. ['id' => 10, 'parent_id' => 6]
  819. ];
  820. $collection = (new Collection($items))->nest('id', 'parent_id');
  821. $expected = [
  822. [
  823. 'id' => 1,
  824. 'parent_id' => null,
  825. 'children' => [
  826. ['id' => 2, 'parent_id' => 1, 'children' => []],
  827. ['id' => 3, 'parent_id' => 1, 'children' => []],
  828. ['id' => 4, 'parent_id' => 1, 'children' => []],
  829. ['id' => 7, 'parent_id' => 1, 'children' => []]
  830. ]
  831. ],
  832. [
  833. 'id' => 6,
  834. 'parent_id' => null,
  835. 'children' => [
  836. ['id' => 5, 'parent_id' => 6, 'children' => []],
  837. ['id' => 8, 'parent_id' => 6, 'children' => []],
  838. ['id' => 9, 'parent_id' => 6, 'children' => []],
  839. ['id' => 10, 'parent_id' => 6, 'children' => []]
  840. ]
  841. ]
  842. ];
  843. $this->assertEquals($expected, $collection->toArray());
  844. }
  845. /**
  846. * Tests the nest method with alternate nesting key
  847. *
  848. * @return void
  849. */
  850. public function testNestAlternateNestingKey()
  851. {
  852. $items = [
  853. ['id' => 1, 'parent_id' => null],
  854. ['id' => 2, 'parent_id' => 1],
  855. ['id' => 3, 'parent_id' => 1],
  856. ['id' => 4, 'parent_id' => 1],
  857. ['id' => 5, 'parent_id' => 6],
  858. ['id' => 6, 'parent_id' => null],
  859. ['id' => 7, 'parent_id' => 1],
  860. ['id' => 8, 'parent_id' => 6],
  861. ['id' => 9, 'parent_id' => 6],
  862. ['id' => 10, 'parent_id' => 6]
  863. ];
  864. $collection = (new Collection($items))->nest('id', 'parent_id', 'nodes');
  865. $expected = [
  866. [
  867. 'id' => 1,
  868. 'parent_id' => null,
  869. 'nodes' => [
  870. ['id' => 2, 'parent_id' => 1, 'nodes' => []],
  871. ['id' => 3, 'parent_id' => 1, 'nodes' => []],
  872. ['id' => 4, 'parent_id' => 1, 'nodes' => []],
  873. ['id' => 7, 'parent_id' => 1, 'nodes' => []]
  874. ]
  875. ],
  876. [
  877. 'id' => 6,
  878. 'parent_id' => null,
  879. 'nodes' => [
  880. ['id' => 5, 'parent_id' => 6, 'nodes' => []],
  881. ['id' => 8, 'parent_id' => 6, 'nodes' => []],
  882. ['id' => 9, 'parent_id' => 6, 'nodes' => []],
  883. ['id' => 10, 'parent_id' => 6, 'nodes' => []]
  884. ]
  885. ]
  886. ];
  887. $this->assertEquals($expected, $collection->toArray());
  888. }
  889. /**
  890. * Tests the nest method with more than one level
  891. *
  892. * @return void
  893. */
  894. public function testNestMultiLevel()
  895. {
  896. $items = [
  897. ['id' => 1, 'parent_id' => null],
  898. ['id' => 2, 'parent_id' => 1],
  899. ['id' => 3, 'parent_id' => 2],
  900. ['id' => 4, 'parent_id' => 2],
  901. ['id' => 5, 'parent_id' => 3],
  902. ['id' => 6, 'parent_id' => null],
  903. ['id' => 7, 'parent_id' => 3],
  904. ['id' => 8, 'parent_id' => 4],
  905. ['id' => 9, 'parent_id' => 6],
  906. ['id' => 10, 'parent_id' => 6]
  907. ];
  908. $collection = (new Collection($items))->nest('id', 'parent_id', 'nodes');
  909. $expected = [
  910. [
  911. 'id' => 1,
  912. 'parent_id' => null,
  913. 'nodes' => [
  914. [
  915. 'id' => 2,
  916. 'parent_id' => 1,
  917. 'nodes' => [
  918. [
  919. 'id' => 3,
  920. 'parent_id' => 2,
  921. 'nodes' => [
  922. ['id' => 5, 'parent_id' => 3, 'nodes' => []],
  923. ['id' => 7, 'parent_id' => 3, 'nodes' => []]
  924. ]
  925. ],
  926. [
  927. 'id' => 4,
  928. 'parent_id' => 2,
  929. 'nodes' => [
  930. ['id' => 8, 'parent_id' => 4, 'nodes' => []]
  931. ]
  932. ]
  933. ]
  934. ]
  935. ]
  936. ],
  937. [
  938. 'id' => 6,
  939. 'parent_id' => null,
  940. 'nodes' => [
  941. ['id' => 9, 'parent_id' => 6, 'nodes' => []],
  942. ['id' => 10, 'parent_id' => 6, 'nodes' => []]
  943. ]
  944. ]
  945. ];
  946. $this->assertEquals($expected, $collection->toArray());
  947. }
  948. /**
  949. * Tests the nest method with more than one level
  950. *
  951. * @return void
  952. */
  953. public function testNestMultiLevelAlternateNestingKey()
  954. {
  955. $items = [
  956. ['id' => 1, 'parent_id' => null],
  957. ['id' => 2, 'parent_id' => 1],
  958. ['id' => 3, 'parent_id' => 2],
  959. ['id' => 4, 'parent_id' => 2],
  960. ['id' => 5, 'parent_id' => 3],
  961. ['id' => 6, 'parent_id' => null],
  962. ['id' => 7, 'parent_id' => 3],
  963. ['id' => 8, 'parent_id' => 4],
  964. ['id' => 9, 'parent_id' => 6],
  965. ['id' => 10, 'parent_id' => 6]
  966. ];
  967. $collection = (new Collection($items))->nest('id', 'parent_id');
  968. $expected = [
  969. [
  970. 'id' => 1,
  971. 'parent_id' => null,
  972. 'children' => [
  973. [
  974. 'id' => 2,
  975. 'parent_id' => 1,
  976. 'children' => [
  977. [
  978. 'id' => 3,
  979. 'parent_id' => 2,
  980. 'children' => [
  981. ['id' => 5, 'parent_id' => 3, 'children' => []],
  982. ['id' => 7, 'parent_id' => 3, 'children' => []]
  983. ]
  984. ],
  985. [
  986. 'id' => 4,
  987. 'parent_id' => 2,
  988. 'children' => [
  989. ['id' => 8, 'parent_id' => 4, 'children' => []]
  990. ]
  991. ]
  992. ]
  993. ]
  994. ]
  995. ],
  996. [
  997. 'id' => 6,
  998. 'parent_id' => null,
  999. 'children' => [
  1000. ['id' => 9, 'parent_id' => 6, 'children' => []],
  1001. ['id' => 10, 'parent_id' => 6, 'children' => []]
  1002. ]
  1003. ]
  1004. ];
  1005. $this->assertEquals($expected, $collection->toArray());
  1006. }
  1007. /**
  1008. * Tests the nest method with more than one level
  1009. *
  1010. * @return void
  1011. */
  1012. public function testNestObjects()
  1013. {
  1014. $items = [
  1015. new ArrayObject(['id' => 1, 'parent_id' => null]),
  1016. new ArrayObject(['id' => 2, 'parent_id' => 1]),
  1017. new ArrayObject(['id' => 3, 'parent_id' => 2]),
  1018. new ArrayObject(['id' => 4, 'parent_id' => 2]),
  1019. new ArrayObject(['id' => 5, 'parent_id' => 3]),
  1020. new ArrayObject(['id' => 6, 'parent_id' => null]),
  1021. new ArrayObject(['id' => 7, 'parent_id' => 3]),
  1022. new ArrayObject(['id' => 8, 'parent_id' => 4]),
  1023. new ArrayObject(['id' => 9, 'parent_id' => 6]),
  1024. new ArrayObject(['id' => 10, 'parent_id' => 6])
  1025. ];
  1026. $collection = (new Collection($items))->nest('id', 'parent_id');
  1027. $expected = [
  1028. new ArrayObject([
  1029. 'id' => 1,
  1030. 'parent_id' => null,
  1031. 'children' => [
  1032. new ArrayObject([
  1033. 'id' => 2,
  1034. 'parent_id' => 1,
  1035. 'children' => [
  1036. new ArrayObject([
  1037. 'id' => 3,
  1038. 'parent_id' => 2,
  1039. 'children' => [
  1040. new ArrayObject(['id' => 5, 'parent_id' => 3, 'children' => []]),
  1041. new ArrayObject(['id' => 7, 'parent_id' => 3, 'children' => []])
  1042. ]
  1043. ]),
  1044. new ArrayObject([
  1045. 'id' => 4,
  1046. 'parent_id' => 2,
  1047. 'children' => [
  1048. new ArrayObject(['id' => 8, 'parent_id' => 4, 'children' => []])
  1049. ]
  1050. ])
  1051. ]
  1052. ])
  1053. ]
  1054. ]),
  1055. new ArrayObject([
  1056. 'id' => 6,
  1057. 'parent_id' => null,
  1058. 'children' => [
  1059. new ArrayObject(['id' => 9, 'parent_id' => 6, 'children' => []]),
  1060. new ArrayObject(['id' => 10, 'parent_id' => 6, 'children' => []])
  1061. ]
  1062. ])
  1063. ];
  1064. $this->assertEquals($expected, $collection->toArray());
  1065. }
  1066. /**
  1067. * Tests the nest method with more than one level
  1068. *
  1069. * @return void
  1070. */
  1071. public function testNestObjectsAlternateNestingKey()
  1072. {
  1073. $items = [
  1074. new ArrayObject(['id' => 1, 'parent_id' => null]),
  1075. new ArrayObject(['id' => 2, 'parent_id' => 1]),
  1076. new ArrayObject(['id' => 3, 'parent_id' => 2]),
  1077. new ArrayObject(['id' => 4, 'parent_id' => 2]),
  1078. new ArrayObject(['id' => 5, 'parent_id' => 3]),
  1079. new ArrayObject(['id' => 6, 'parent_id' => null]),
  1080. new ArrayObject(['id' => 7, 'parent_id' => 3]),
  1081. new ArrayObject(['id' => 8, 'parent_id' => 4]),
  1082. new ArrayObject(['id' => 9, 'parent_id' => 6]),
  1083. new ArrayObject(['id' => 10, 'parent_id' => 6])
  1084. ];
  1085. $collection = (new Collection($items))->nest('id', 'parent_id', 'nodes');
  1086. $expected = [
  1087. new ArrayObject([
  1088. 'id' => 1,
  1089. 'parent_id' => null,
  1090. 'nodes' => [
  1091. new ArrayObject([
  1092. 'id' => 2,
  1093. 'parent_id' => 1,
  1094. 'nodes' => [
  1095. new ArrayObject([
  1096. 'id' => 3,
  1097. 'parent_id' => 2,
  1098. 'nodes' => [
  1099. new ArrayObject(['id' => 5, 'parent_id' => 3, 'nodes' => []]),
  1100. new ArrayObject(['id' => 7, 'parent_id' => 3, 'nodes' => []])
  1101. ]
  1102. ]),
  1103. new ArrayObject([
  1104. 'id' => 4,
  1105. 'parent_id' => 2,
  1106. 'nodes' => [
  1107. new ArrayObject(['id' => 8, 'parent_id' => 4, 'nodes' => []])
  1108. ]
  1109. ])
  1110. ]
  1111. ])
  1112. ]
  1113. ]),
  1114. new ArrayObject([
  1115. 'id' => 6,
  1116. 'parent_id' => null,
  1117. 'nodes' => [
  1118. new ArrayObject(['id' => 9, 'parent_id' => 6, 'nodes' => []]),
  1119. new ArrayObject(['id' => 10, 'parent_id' => 6, 'nodes' => []])
  1120. ]
  1121. ])
  1122. ];
  1123. $this->assertEquals($expected, $collection->toArray());
  1124. }
  1125. /**
  1126. * Tests insert
  1127. *
  1128. * @return void
  1129. */
  1130. public function testInsert()
  1131. {
  1132. $items = [['a' => 1], ['b' => 2]];
  1133. $collection = new Collection($items);
  1134. $iterator = $collection->insert('c', [3, 4]);
  1135. $this->assertInstanceOf('Cake\Collection\Iterator\InsertIterator', $iterator);
  1136. $this->assertEquals(
  1137. [['a' => 1, 'c' => 3], ['b' => 2, 'c' => 4]],
  1138. iterator_to_array($iterator)
  1139. );
  1140. }
  1141. /**
  1142. * Provider for testing each of the directions for listNested
  1143. *
  1144. * @return void
  1145. */
  1146. public function nestedListProvider()
  1147. {
  1148. return [
  1149. ['desc', [1, 2, 3, 5, 7, 4, 8, 6, 9, 10]],
  1150. ['asc', [5, 7, 3, 8, 4, 2, 1, 9, 10, 6]],
  1151. ['leaves', [5, 7, 8, 9, 10]]
  1152. ];
  1153. }
  1154. /**
  1155. * Tests the listNested method with the default 'children' nesting key
  1156. *
  1157. * @dataProvider nestedListProvider
  1158. * @return void
  1159. */
  1160. public function testListNested($dir, $expected)
  1161. {
  1162. $items = [
  1163. ['id' => 1, 'parent_id' => null],
  1164. ['id' => 2, 'parent_id' => 1],
  1165. ['id' => 3, 'parent_id' => 2],
  1166. ['id' => 4, 'parent_id' => 2],
  1167. ['id' => 5, 'parent_id' => 3],
  1168. ['id' => 6, 'parent_id' => null],
  1169. ['id' => 7, 'parent_id' => 3],
  1170. ['id' => 8, 'parent_id' => 4],
  1171. ['id' => 9, 'parent_id' => 6],
  1172. ['id' => 10, 'parent_id' => 6]
  1173. ];
  1174. $collection = (new Collection($items))->nest('id', 'parent_id')->listNested($dir);
  1175. $this->assertEquals($expected, $collection->extract('id')->toArray(false));
  1176. }
  1177. /**
  1178. * Tests using listNested with a different nesting key
  1179. *
  1180. * @return void
  1181. */
  1182. public function testListNestedCustomKey()
  1183. {
  1184. $items = [
  1185. ['id' => 1, 'stuff' => [['id' => 2, 'stuff' => [['id' => 3]]]]],
  1186. ['id' => 4, 'stuff' => [['id' => 5]]]
  1187. ];
  1188. $collection = (new Collection($items))->listNested('desc', 'stuff');
  1189. $this->assertEquals(range(1, 5), $collection->extract('id')->toArray(false));
  1190. }
  1191. /**
  1192. * Tests flattening the collection using a custom callable function
  1193. *
  1194. * @return void
  1195. */
  1196. public function testListNestedWithCallable()
  1197. {
  1198. $items = [
  1199. ['id' => 1, 'stuff' => [['id' => 2, 'stuff' => [['id' => 3]]]]],
  1200. ['id' => 4, 'stuff' => [['id' => 5]]]
  1201. ];
  1202. $collection = (new Collection($items))->listNested('desc', function ($item) {
  1203. return isset($item['stuff']) ? $item['stuff'] : [];
  1204. });
  1205. $this->assertEquals(range(1, 5), $collection->extract('id')->toArray(false));
  1206. }
  1207. /**
  1208. * Tests the sumOf method
  1209. *
  1210. * @return void
  1211. */
  1212. public function testSumOf()
  1213. {
  1214. $items = [
  1215. ['invoice' => ['total' => 100]],
  1216. ['invoice' => ['total' => 200]]
  1217. ];
  1218. $this->assertEquals(300, (new Collection($items))->sumOf('invoice.total'));
  1219. $sum = (new Collection($items))->sumOf(function ($v) {
  1220. return $v['invoice']['total'] * 2;
  1221. });
  1222. $this->assertEquals(600, $sum);
  1223. }
  1224. /**
  1225. * Tests the stopWhen method with a callable
  1226. *
  1227. * @return void
  1228. */
  1229. public function testStopWhenCallable()
  1230. {
  1231. $items = [10, 20, 40, 10, 5];
  1232. $collection = (new Collection($items))->stopWhen(function ($v) {
  1233. return $v > 20;
  1234. });
  1235. $this->assertEquals([10, 20], $collection->toArray());
  1236. }
  1237. /**
  1238. * Tests the stopWhen method with a matching array
  1239. *
  1240. * @return void
  1241. */
  1242. public function testStopWhenWithArray()
  1243. {
  1244. $items = [
  1245. ['foo' => 'bar'],
  1246. ['foo' => 'baz'],
  1247. ['foo' => 'foo']
  1248. ];
  1249. $collection = (new Collection($items))->stopWhen(['foo' => 'baz']);
  1250. $this->assertEquals([['foo' => 'bar']], $collection->toArray());
  1251. }
  1252. /**
  1253. * Tests the unfold method
  1254. *
  1255. * @return void
  1256. */
  1257. public function testUnfold()
  1258. {
  1259. $items = [
  1260. [1, 2, 3, 4],
  1261. [5, 6],
  1262. [7, 8]
  1263. ];
  1264. $collection = (new Collection($items))->unfold();
  1265. $this->assertEquals(range(1, 8), $collection->toArray(false));
  1266. $items = [
  1267. [1, 2],
  1268. new Collection([3, 4])
  1269. ];
  1270. $collection = (new Collection($items))->unfold();
  1271. $this->assertEquals(range(1, 4), $collection->toArray(false));
  1272. }
  1273. /**
  1274. * Tests the unfold method with empty levels
  1275. *
  1276. * @return void
  1277. */
  1278. public function testUnfoldEmptyLevels()
  1279. {
  1280. $items = [[], [1, 2], []];
  1281. $collection = (new Collection($items))->unfold();
  1282. $this->assertEquals(range(1, 2), $collection->toArray(false));
  1283. $items = [];
  1284. $collection = (new Collection($items))->unfold();
  1285. $this->assertEmpty($collection->toArray(false));
  1286. }
  1287. /**
  1288. * Tests the unfold when passing a callable
  1289. *
  1290. * @return void
  1291. */
  1292. public function testUnfoldWithCallable()
  1293. {
  1294. $items = [1, 2, 3];
  1295. $collection = (new Collection($items))->unfold(function ($item) {
  1296. return range($item, $item * 2);
  1297. });
  1298. $expected = [1, 2, 2, 3, 4, 3, 4, 5, 6];
  1299. $this->assertEquals($expected, $collection->toArray(false));
  1300. }
  1301. /**
  1302. * Tests the through() method
  1303. *
  1304. * @return void
  1305. */
  1306. public function testThrough()
  1307. {
  1308. $items = [1, 2, 3];
  1309. $collection = (new Collection($items))->through(function ($collection) {
  1310. return $collection->append($collection->toList());
  1311. });
  1312. $this->assertEquals([1, 2, 3, 1, 2, 3], $collection->toList());
  1313. }
  1314. /**
  1315. * Tests the through method when it returns an array
  1316. *
  1317. * @return void
  1318. */
  1319. public function testThroughReturnArray()
  1320. {
  1321. $items = [1, 2, 3];
  1322. $collection = (new Collection($items))->through(function ($collection) {
  1323. $list = $collection->toList();
  1324. return array_merge($list, $list);
  1325. });
  1326. $this->assertEquals([1, 2, 3, 1, 2, 3], $collection->toList());
  1327. }
  1328. /**
  1329. * Tests that the sortBy method does not die when something that is not a
  1330. * collection is passed
  1331. *
  1332. * @return void
  1333. */
  1334. public function testComplexSortBy()
  1335. {
  1336. $results = collection([3, 7])
  1337. ->unfold(function ($value) {
  1338. return [
  1339. ['sorting' => $value * 2],
  1340. ['sorting' => $value * 2]
  1341. ];
  1342. })
  1343. ->sortBy('sorting')
  1344. ->extract('sorting')
  1345. ->toList();
  1346. $this->assertEquals([14, 14, 6, 6], $results);
  1347. }
  1348. /**
  1349. * Tests __debugInfo() or debug() usage
  1350. *
  1351. * @return void
  1352. */
  1353. public function testDebug()
  1354. {
  1355. $items = [1, 2, 3];
  1356. $collection = new Collection($items);
  1357. $result = $collection->__debugInfo();
  1358. $expected = [
  1359. 'count' => 3,
  1360. ];
  1361. $this->assertSame($expected, $result);
  1362. // Calling it again will rewind
  1363. $result = $collection->__debugInfo();
  1364. $expected = [
  1365. 'count' => 3,
  1366. ];
  1367. $this->assertSame($expected, $result);
  1368. // Make sure it also works with non rewindable iterators
  1369. $iterator = new NoRewindIterator(new ArrayIterator($items));
  1370. $collection = new Collection($iterator);
  1371. $result = $collection->__debugInfo();
  1372. $expected = [
  1373. 'count' => 3,
  1374. ];
  1375. $this->assertSame($expected, $result);
  1376. // Calling it again will in this case not rewind
  1377. $result = $collection->__debugInfo();
  1378. $expected = [
  1379. 'count' => 0,
  1380. ];
  1381. $this->assertSame($expected, $result);
  1382. }
  1383. /**
  1384. * Tests the isEmpty() method
  1385. *
  1386. * @return void
  1387. */
  1388. public function testIsEmpty()
  1389. {
  1390. $collection = new Collection([1, 2, 3]);
  1391. $this->assertFalse($collection->isEmpty());
  1392. $collection = $collection->map(function () {
  1393. return null;
  1394. });
  1395. $this->assertFalse($collection->isEmpty());
  1396. $collection = $collection->filter();
  1397. $this->assertTrue($collection->isEmpty());
  1398. }
  1399. /**
  1400. * Tests the isEmpty() method does not consume data
  1401. * from buffered iterators.
  1402. *
  1403. * @return void
  1404. */
  1405. public function testIsEmptyDoesNotConsume()
  1406. {
  1407. $array = new \ArrayIterator([1, 2, 3]);
  1408. $inner = new \Cake\Collection\Iterator\BufferedIterator($array);
  1409. $collection = new Collection($inner);
  1410. $this->assertFalse($collection->isEmpty());
  1411. $this->assertCount(3, $collection->toArray());
  1412. }
  1413. /**
  1414. * Tests the zip() method
  1415. *
  1416. * @return void
  1417. */
  1418. public function testZip()
  1419. {
  1420. $collection = new Collection([1, 2]);
  1421. $zipped = $collection->zip([3, 4]);
  1422. $this->assertEquals([[1, 3], [2, 4]], $zipped->toList());
  1423. $collection = new Collection([1, 2]);
  1424. $zipped = $collection->zip([3]);
  1425. $this->assertEquals([[1, 3]], $zipped->toList());
  1426. $collection = new Collection([1, 2]);
  1427. $zipped = $collection->zip([3, 4], [5, 6], [7, 8], [9, 10, 11]);
  1428. $this->assertEquals([
  1429. [1, 3, 5, 7, 9],
  1430. [2, 4, 6, 8, 10]
  1431. ], $zipped->toList());
  1432. }
  1433. /**
  1434. * Tests the zipWith() method
  1435. *
  1436. * @return void
  1437. */
  1438. public function testZipWith()
  1439. {
  1440. $collection = new Collection([1, 2]);
  1441. $zipped = $collection->zipWith([3, 4], function ($a, $b) {
  1442. return $a * $b;
  1443. });
  1444. $this->assertEquals([3, 8], $zipped->toList());
  1445. $zipped = $collection->zipWith([3, 4], [5, 6, 7], function (...$args) {
  1446. return array_sum($args);
  1447. });
  1448. $this->assertEquals([9, 12], $zipped->toList());
  1449. }
  1450. /**
  1451. * Tests the skip() method
  1452. *
  1453. * @return void
  1454. */
  1455. public function testSkip()
  1456. {
  1457. $collection = new Collection([1, 2, 3, 4, 5]);
  1458. $this->assertEquals([3, 4, 5], $collection->skip(2)->toList());
  1459. $this->assertEquals([5], $collection->skip(4)->toList());
  1460. }
  1461. /**
  1462. * Tests the last() method
  1463. *
  1464. * @return void
  1465. */
  1466. public function testLast()
  1467. {
  1468. $collection = new Collection([1, 2, 3]);
  1469. $this->assertEquals(3, $collection->last());
  1470. $collection = $collection->map(function ($e) {
  1471. return $e * 2;
  1472. });
  1473. $this->assertEquals(6, $collection->last());
  1474. }
  1475. /**
  1476. * Tests the last() method when on an empty collection
  1477. *
  1478. * @return void
  1479. */
  1480. public function testLAstWithEmptyCollection()
  1481. {
  1482. $collection = new Collection([]);
  1483. $this->assertNull($collection->last());
  1484. }
  1485. /**
  1486. * Tests sumOf with no parameters
  1487. *
  1488. * @return void
  1489. */
  1490. public function testSumOfWithIdentity()
  1491. {
  1492. $collection = new Collection([1, 2, 3]);
  1493. $this->assertEquals(6, $collection->sumOf());
  1494. $collection = new Collection(['a' => 1, 'b' => 4, 'c' => 6]);
  1495. $this->assertEquals(11, $collection->sumOf());
  1496. }
  1497. /**
  1498. * Tests using extract with the {*} notation
  1499. *
  1500. * @return void
  1501. */
  1502. public function testUnfoldedExtract()
  1503. {
  1504. $items = [
  1505. ['comments' => [['id' => 1], ['id' => 2]]],
  1506. ['comments' => [['id' => 3], ['id' => 4]]],
  1507. ['comments' => [['id' => 7], ['nope' => 8]]],
  1508. ];
  1509. $extracted = (new Collection($items))->extract('comments.{*}.id');
  1510. $this->assertEquals([1, 2, 3, 4, 7, null], $extracted->toArray());
  1511. $items = [
  1512. [
  1513. 'comments' => [
  1514. [
  1515. 'voters' => [['id' => 1], ['id' => 2]]
  1516. ]
  1517. ]
  1518. ],
  1519. [
  1520. 'comments' => [
  1521. [
  1522. 'voters' => [['id' => 3], ['id' => 4]]
  1523. ]
  1524. ]
  1525. ],
  1526. [
  1527. 'comments' => [
  1528. [
  1529. 'voters' => [['id' => 5], ['nope' => 'fail'], ['id' => 6]]
  1530. ]
  1531. ]
  1532. ],
  1533. [
  1534. 'comments' => [
  1535. [
  1536. 'not_voters' => [['id' => 5]]
  1537. ]
  1538. ]
  1539. ],
  1540. ['not_comments' => []]
  1541. ];
  1542. $extracted = (new Collection($items))->extract('comments.{*}.voters.{*}.id');
  1543. $expected = [1, 2, 3, 4, 5, null, 6];
  1544. $this->assertEquals($expected, $extracted->toArray());
  1545. $this->assertEquals($expected, $extracted->toList());
  1546. }
  1547. /**
  1548. * Tests serializing a simple collection
  1549. *
  1550. * @return void
  1551. */
  1552. public function testSerializeSimpleCollection()
  1553. {
  1554. $collection = new Collection([1, 2, 3]);
  1555. $selialized = serialize($collection);
  1556. $unserialized = unserialize($selialized);
  1557. $this->assertEquals($collection->toList(), $unserialized->toList());
  1558. $this->assertEquals($collection->toArray(), $unserialized->toArray());
  1559. }
  1560. /**
  1561. * Tests serialization when using append
  1562. *
  1563. * @return void
  1564. */
  1565. public function testSerializeWithAppendIterators()
  1566. {
  1567. $collection = new Collection([1, 2, 3]);
  1568. $collection = $collection->append(['a' => 4, 'b' => 5, 'c' => 6]);
  1569. $selialized = serialize($collection);
  1570. $unserialized = unserialize($selialized);
  1571. $this->assertEquals($collection->toList(), $unserialized->toList());
  1572. $this->assertEquals($collection->toArray(), $unserialized->toArray());
  1573. }
  1574. /**
  1575. * Tests serialization when using nested iterators
  1576. *
  1577. * @return void
  1578. */
  1579. public function testSerializeWithNestedIterators()
  1580. {
  1581. $collection = new Collection([1, 2, 3]);
  1582. $collection = $collection->map(function ($e) {
  1583. return $e * 3;
  1584. });
  1585. $collection = $collection->groupBy(function ($e) {
  1586. return $e % 2;
  1587. });
  1588. $selialized = serialize($collection);
  1589. $unserialized = unserialize($selialized);
  1590. $this->assertEquals($collection->toList(), $unserialized->toList());
  1591. $this->assertEquals($collection->toArray(), $unserialized->toArray());
  1592. }
  1593. /**
  1594. * Tests serializing a zip() call
  1595. *
  1596. * @return void
  1597. */
  1598. public function testSerializeWithZipIterator()
  1599. {
  1600. $collection = new Collection([4, 5]);
  1601. $collection = $collection->zip([1, 2]);
  1602. $selialized = serialize($collection);
  1603. $unserialized = unserialize($selialized);
  1604. $this->assertEquals($collection->toList(), $unserialized->toList());
  1605. }
  1606. /**
  1607. * Tests the chunk method with exact chunks
  1608. *
  1609. * @return void
  1610. */
  1611. public function testChunk()
  1612. {
  1613. $collection = new Collection(range(1, 10));
  1614. $chunked = $collection->chunk(2)->toList();
  1615. $expected = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]];
  1616. $this->assertEquals($expected, $chunked);
  1617. }
  1618. /**
  1619. * Tests the chunk method with overflowing chunk size
  1620. *
  1621. * @return void
  1622. */
  1623. public function testChunkOverflow()
  1624. {
  1625. $collection = new Collection(range(1, 11));
  1626. $chunked = $collection->chunk(2)->toList();
  1627. $expected = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11]];
  1628. $this->assertEquals($expected, $chunked);
  1629. }
  1630. /**
  1631. * Tests the chunk method with non-scalar items
  1632. *
  1633. * @return void
  1634. */
  1635. public function testChunkNested()
  1636. {
  1637. $collection = new Collection([1, 2, 3, [4, 5], 6, [7, [8, 9], 10], 11]);
  1638. $chunked = $collection->chunk(2)->toList();
  1639. $expected = [[1, 2], [3, [4, 5]], [6, [7, [8, 9], 10]], [11]];
  1640. $this->assertEquals($expected, $chunked);
  1641. }
  1642. /**
  1643. * Tests the chunkWithKeys method with exact chunks
  1644. *
  1645. * @return void
  1646. */
  1647. public function testChunkWithKeys()
  1648. {
  1649. $collection = new Collection(['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6]);
  1650. $chunked = $collection->chunkWithKeys(2)->toList();
  1651. $expected = [['a' => 1, 'b' => 2], ['c' => 3, 'd' => 4], ['e' => 5, 'f' => 6]];
  1652. $this->assertEquals($expected, $chunked);
  1653. }
  1654. /**
  1655. * Tests the chunkWithKeys method with overflowing chunk size
  1656. *
  1657. * @return void
  1658. */
  1659. public function testChunkWithKeysOverflow()
  1660. {
  1661. $collection = new Collection(['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6, 'g' => 7]);
  1662. $chunked = $collection->chunkWithKeys(2)->toList();
  1663. $expected = [['a' => 1, 'b' => 2], ['c' => 3, 'd' => 4], ['e' => 5, 'f' => 6], ['g' => 7]];
  1664. $this->assertEquals($expected, $chunked);
  1665. }
  1666. /**
  1667. * Tests the chunkWithKeys method with non-scalar items
  1668. *
  1669. * @return void
  1670. */
  1671. public function testChunkWithKeysNested()
  1672. {
  1673. $collection = new Collection(['a' => 1, 'b' => 2, 'c' => 3, 'd' => [4, 5], 'e' => 6, 'f' => [7, [8, 9], 10], 'g' => 11]);
  1674. $chunked = $collection->chunkWithKeys(2)->toList();
  1675. $expected = [['a' => 1, 'b' => 2], ['c' => 3, 'd' => [4, 5]], ['e' => 6, 'f' => [7, [8, 9], 10]], ['g' => 11]];
  1676. $this->assertEquals($expected, $chunked);
  1677. }
  1678. /**
  1679. * Tests the chunkWithKeys method without preserving keys
  1680. *
  1681. * @return void
  1682. */
  1683. public function testChunkWithKeysNoPreserveKeys()
  1684. {
  1685. $collection = new Collection(['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6, 'g' => 7]);
  1686. $chunked = $collection->chunkWithKeys(2, false)->toList();
  1687. $expected = [[0 => 1, 1 => 2], [0 => 3, 1 => 4], [0 => 5, 1 => 6], [0 => 7]];
  1688. $this->assertEquals($expected, $chunked);
  1689. }
  1690. /**
  1691. * Tests cartesianProduct
  1692. *
  1693. * @return void
  1694. */
  1695. public function testCartesianProduct()
  1696. {
  1697. $collection = new Collection([]);
  1698. $result = $collection->cartesianProduct();
  1699. $expected = [];
  1700. $this->assertEquals($expected, $result->toList());
  1701. $collection = new Collection([['A', 'B', 'C'], [1, 2, 3]]);
  1702. $result = $collection->cartesianProduct();
  1703. $expected = [
  1704. ['A', 1],
  1705. ['A', 2],
  1706. ['A', 3],
  1707. ['B', 1],
  1708. ['B', 2],
  1709. ['B', 3],
  1710. ['C', 1],
  1711. ['C', 2],
  1712. ['C', 3],
  1713. ];
  1714. $this->assertEquals($expected, $result->toList());
  1715. $collection = new Collection([[1, 2, 3], ['A', 'B', 'C'], ['a', 'b', 'c']]);
  1716. $result = $collection->cartesianProduct(function ($value) {
  1717. return [strval($value[0]) . $value[1] . $value[2]];
  1718. }, function ($value) {
  1719. return $value[0] >= 2;
  1720. });
  1721. $expected = [
  1722. ['2Aa'],
  1723. ['2Ab'],
  1724. ['2Ac'],
  1725. ['2Ba'],
  1726. ['2Bb'],
  1727. ['2Bc'],
  1728. ['2Ca'],
  1729. ['2Cb'],
  1730. ['2Cc'],
  1731. ['3Aa'],
  1732. ['3Ab'],
  1733. ['3Ac'],
  1734. ['3Ba'],
  1735. ['3Bb'],
  1736. ['3Bc'],
  1737. ['3Ca'],
  1738. ['3Cb'],
  1739. ['3Cc'],
  1740. ];
  1741. $this->assertEquals($expected, $result->toList());
  1742. $collection = new Collection([['1', '2', '3', '4'], ['A', 'B', 'C'], ['name', 'surname', 'telephone']]);
  1743. $result = $collection->cartesianProduct(function ($value) {
  1744. return [$value[0] => [$value[1] => $value[2]]];
  1745. }, function ($value) {
  1746. return $value[2] !== 'surname';
  1747. });
  1748. $expected = [
  1749. [1 => ['A' => 'name']],
  1750. [1 => ['A' => 'telephone']],
  1751. [1 => ['B' => 'name']],
  1752. [1 => ['B' => 'telephone']],
  1753. [1 => ['C' => 'name']],
  1754. [1 => ['C' => 'telephone']],
  1755. [2 => ['A' => 'name']],
  1756. [2 => ['A' => 'telephone']],
  1757. [2 => ['B' => 'name']],
  1758. [2 => ['B' => 'telephone']],
  1759. [2 => ['C' => 'name']],
  1760. [2 => ['C' => 'telephone']],
  1761. [3 => ['A' => 'name']],
  1762. [3 => ['A' => 'telephone']],
  1763. [3 => ['B' => 'name']],
  1764. [3 => ['B' => 'telephone']],
  1765. [3 => ['C' => 'name']],
  1766. [3 => ['C' => 'telephone']],
  1767. [4 => ['A' => 'name']],
  1768. [4 => ['A' => 'telephone']],
  1769. [4 => ['B' => 'name']],
  1770. [4 => ['B' => 'telephone']],
  1771. [4 => ['C' => 'name']],
  1772. [4 => ['C' => 'telephone']],
  1773. ];
  1774. $this->assertEquals($expected, $result->toList());
  1775. $collection = new Collection([
  1776. [
  1777. 'name1' => 'alex',
  1778. 'name2' => 'kostas',
  1779. 0 => 'leon',
  1780. ],
  1781. [
  1782. 'val1' => 'alex@example.com',
  1783. 24 => 'kostas@example.com',
  1784. 'val2' => 'leon@example.com',
  1785. ],
  1786. ]);
  1787. $result = $collection->cartesianProduct();
  1788. $expected = [
  1789. ['alex', 'alex@example.com'],
  1790. ['alex', 'kostas@example.com'],
  1791. ['alex', 'leon@example.com'],
  1792. ['kostas', 'alex@example.com'],
  1793. ['kostas', 'kostas@example.com'],
  1794. ['kostas', 'leon@example.com'],
  1795. ['leon', 'alex@example.com'],
  1796. ['leon', 'kostas@example.com'],
  1797. ['leon', 'leon@example.com'],
  1798. ];
  1799. $this->assertEquals($expected, $result->toList());
  1800. }
  1801. /**
  1802. * Tests that an exception is thrown if the cartesian product is called with multidimensional arrays
  1803. *
  1804. * @expectedException \LogicException
  1805. * @return void
  1806. */
  1807. public function testCartesianProductMultidimensionalArray()
  1808. {
  1809. $collection = new Collection([
  1810. [
  1811. 'names' => [
  1812. 'alex', 'kostas', 'leon'
  1813. ]
  1814. ],
  1815. [
  1816. 'locations' => [
  1817. 'crete', 'london', 'paris'
  1818. ]
  1819. ],
  1820. ]);
  1821. $result = $collection->cartesianProduct();
  1822. }
  1823. public function testTranspose()
  1824. {
  1825. $collection = new Collection([
  1826. ['Products', '2012', '2013', '2014'],
  1827. ['Product A', '200', '100', '50'],
  1828. ['Product B', '300', '200', '100'],
  1829. ['Product C', '400', '300', '200'],
  1830. ]);
  1831. $transposed = $collection->transpose();
  1832. $expected = [
  1833. ['Products', 'Product A', 'Product B', 'Product C'],
  1834. ['2012', '200', '300', '400'],
  1835. ['2013', '100', '200', '300'],
  1836. ['2014', '50', '100', '200'],
  1837. ];
  1838. $this->assertEquals($expected, $transposed->toList());
  1839. }
  1840. /**
  1841. * Tests that provided arrays do not have even length
  1842. *
  1843. * @expectedException \LogicException
  1844. * @return void
  1845. */
  1846. public function testTransposeUnEvenLengthShouldThrowException()
  1847. {
  1848. $collection = new Collection([
  1849. ['Products', '2012', '2013', '2014'],
  1850. ['Product A', '200', '100', '50'],
  1851. ['Product B', '300'],
  1852. ['Product C', '400', '300'],
  1853. ]);
  1854. $collection->transpose();
  1855. }
  1856. }