Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
15403 manish.sha 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
 * @package       Cake.Utility
13
 * @since         CakePHP(tm) v 2.2.0
14
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
15
 */
16
 
17
App::uses('Hash', 'Utility');
18
 
19
/**
20
 * Class HashTest
21
 *
22
 * @package       Cake.Utility
23
 */
24
class HashTest extends CakeTestCase {
25
 
26
/**
27
 * Data provider
28
 *
29
 * @return array
30
 */
31
	public static function articleData() {
32
		return array(
33
			array(
34
				'Article' => array(
35
					'id' => '1',
36
					'user_id' => '1',
37
					'title' => 'First Article',
38
					'body' => 'First Article Body'
39
				),
40
				'User' => array(
41
					'id' => '1',
42
					'user' => 'mariano',
43
					'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
44
				),
45
				'Comment' => array(
46
					array(
47
						'id' => '1',
48
						'article_id' => '1',
49
						'user_id' => '2',
50
						'comment' => 'First Comment for First Article',
51
					),
52
					array(
53
						'id' => '2',
54
						'article_id' => '1',
55
						'user_id' => '4',
56
						'comment' => 'Second Comment for First Article',
57
					),
58
				),
59
				'Tag' => array(
60
					array(
61
						'id' => '1',
62
						'tag' => 'tag1',
63
					),
64
					array(
65
						'id' => '2',
66
						'tag' => 'tag2',
67
					)
68
				),
69
				'Deep' => array(
70
					'Nesting' => array(
71
						'test' => array(
72
							1 => 'foo',
73
							2 => array(
74
								'and' => array('more' => 'stuff')
75
							)
76
						)
77
					)
78
				)
79
			),
80
			array(
81
				'Article' => array(
82
					'id' => '2',
83
					'user_id' => '1',
84
					'title' => 'Second Article',
85
					'body' => 'Second Article Body',
86
					'published' => 'Y',
87
				),
88
				'User' => array(
89
					'id' => '2',
90
					'user' => 'mariano',
91
					'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
92
				),
93
				'Comment' => array(),
94
				'Tag' => array()
95
			),
96
			array(
97
				'Article' => array(
98
					'id' => '3',
99
					'user_id' => '1',
100
					'title' => 'Third Article',
101
					'body' => 'Third Article Body',
102
				),
103
				'User' => array(
104
					'id' => '3',
105
					'user' => 'mariano',
106
					'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
107
				),
108
				'Comment' => array(),
109
				'Tag' => array()
110
			),
111
			array(
112
				'Article' => array(
113
					'id' => '4',
114
					'user_id' => '1',
115
					'title' => 'Fourth Article',
116
					'body' => 'Fourth Article Body',
117
				),
118
				'User' => array(
119
					'id' => '4',
120
					'user' => 'mariano',
121
					'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
122
				),
123
				'Comment' => array(),
124
				'Tag' => array()
125
			),
126
			array(
127
				'Article' => array(
128
					'id' => '5',
129
					'user_id' => '1',
130
					'title' => 'Fifth Article',
131
					'body' => 'Fifth Article Body',
132
				),
133
				'User' => array(
134
					'id' => '5',
135
					'user' => 'mariano',
136
					'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
137
					),
138
				'Comment' => array(),
139
				'Tag' => array()
140
			)
141
		);
142
	}
143
 
144
/**
145
 * Data provider
146
 *
147
 * @return array
148
 */
149
	public static function userData() {
150
		return array(
151
			array(
152
				'User' => array(
153
					'id' => 2,
154
					'group_id' => 1,
155
					'Data' => array(
156
						'user' => 'mariano.iglesias',
157
						'name' => 'Mariano Iglesias'
158
					)
159
				)
160
			),
161
			array(
162
				'User' => array(
163
					'id' => 14,
164
					'group_id' => 2,
165
					'Data' => array(
166
						'user' => 'phpnut',
167
						'name' => 'Larry E. Masters'
168
					)
169
				)
170
			),
171
			array(
172
				'User' => array(
173
					'id' => 25,
174
					'group_id' => 1,
175
					'Data' => array(
176
						'user' => 'gwoo',
177
						'name' => 'The Gwoo'
178
					)
179
				)
180
			)
181
		);
182
	}
183
 
184
/**
185
 * Test get()
186
 *
187
 * @return void
188
 */
189
	public function testGet() {
190
		$data = array('abc', 'def');
191
 
192
		$result = Hash::get($data, '0');
193
		$this->assertEquals('abc', $result);
194
 
195
		$result = Hash::get($data, 0);
196
		$this->assertEquals('abc', $result);
197
 
198
		$result = Hash::get($data, '1');
199
		$this->assertEquals('def', $result);
200
 
201
		$data = self::articleData();
202
 
203
		$result = Hash::get(array(), '1.Article.title');
204
		$this->assertNull($result);
205
 
206
		$result = Hash::get($data, '');
207
		$this->assertNull($result);
208
 
209
		$result = Hash::get($data, '0.Article.title');
210
		$this->assertEquals('First Article', $result);
211
 
212
		$result = Hash::get($data, '1.Article.title');
213
		$this->assertEquals('Second Article', $result);
214
 
215
		$result = Hash::get($data, '5.Article.title');
216
		$this->assertNull($result);
217
 
218
		$default = array('empty');
219
		$this->assertEquals($default, Hash::get($data, '5.Article.title', $default));
220
		$this->assertEquals($default, Hash::get(array(), '5.Article.title', $default));
221
 
222
		$result = Hash::get($data, '1.Article.title.not_there');
223
		$this->assertNull($result);
224
 
225
		$result = Hash::get($data, '1.Article');
226
		$this->assertEquals($data[1]['Article'], $result);
227
 
228
		$result = Hash::get($data, array('1', 'Article'));
229
		$this->assertEquals($data[1]['Article'], $result);
230
	}
231
 
232
/**
233
 * Test get() with an invalid path
234
 *
235
 * @expectedException InvalidArgumentException
236
 * @return void
237
 */
238
	public function testGetInvalidPath() {
239
		Hash::get(array('one' => 'two'), true);
240
	}
241
 
242
/**
243
 * Test testGetNullPath()
244
 *
245
 * @return void
246
 */
247
	public function testGetNullPath() {
248
		$result = Hash::get(array('one' => 'two'), null, '-');
249
		$this->assertEquals('-', $result);
250
 
251
		$result = Hash::get(array('one' => 'two'), '', '-');
252
		$this->assertEquals('-', $result);
253
	}
254
 
255
/**
256
 * Test dimensions.
257
 *
258
 * @return void
259
 */
260
	public function testDimensions() {
261
		$result = Hash::dimensions(array());
262
		$this->assertEquals($result, 0);
263
 
264
		$data = array('one', '2', 'three');
265
		$result = Hash::dimensions($data);
266
		$this->assertEquals($result, 1);
267
 
268
		$data = array('1' => '1.1', '2', '3');
269
		$result = Hash::dimensions($data);
270
		$this->assertEquals($result, 1);
271
 
272
		$data = array('1' => array('1.1' => '1.1.1'), '2', '3' => array('3.1' => '3.1.1'));
273
		$result = Hash::dimensions($data);
274
		$this->assertEquals($result, 2);
275
 
276
		$data = array('1' => '1.1', '2', '3' => array('3.1' => '3.1.1'));
277
		$result = Hash::dimensions($data);
278
		$this->assertEquals($result, 1);
279
 
280
		$data = array('1' => array('1.1' => '1.1.1'), '2', '3' => array('3.1' => array('3.1.1' => '3.1.1.1')));
281
		$result = Hash::dimensions($data);
282
		$this->assertEquals($result, 2);
283
	}
284
 
285
/**
286
 * Test maxDimensions
287
 *
288
 * @return void
289
 */
290
	public function testMaxDimensions() {
291
		$data = array();
292
		$result = Hash::maxDimensions($data);
293
		$this->assertEquals(0, $result);
294
 
295
		$data = array('a', 'b');
296
		$result = Hash::maxDimensions($data);
297
		$this->assertEquals(1, $result);
298
 
299
		$data = array('1' => '1.1', '2', '3' => array('3.1' => '3.1.1'));
300
		$result = Hash::maxDimensions($data);
301
		$this->assertEquals($result, 2);
302
 
303
		$data = array('1' => array('1.1' => '1.1.1'), '2', '3' => array('3.1' => array('3.1.1' => '3.1.1.1')));
304
		$result = Hash::maxDimensions($data);
305
		$this->assertEquals($result, 3);
306
 
307
		$data = array(
308
			'1' => array('1.1' => '1.1.1'),
309
			array('2' => array('2.1' => array('2.1.1' => '2.1.1.1'))),
310
			'3' => array('3.1' => array('3.1.1' => '3.1.1.1'))
311
		);
312
		$result = Hash::maxDimensions($data);
313
		$this->assertEquals($result, 4);
314
 
315
		$data = array(
316
			'1' => array('1.1' => '1.1.1'),
317
			array('2' => array('2.1' => array('2.1.1' => array('2.1.1.1')))),
318
			'3' => array('3.1' => array('3.1.1' => '3.1.1.1'))
319
		);
320
		$result = Hash::maxDimensions($data);
321
		$this->assertEquals($result, 5);
322
 
323
		$data = array(
324
			'1' => array('1.1' => '1.1.1'),
325
			array('2' => array('2.1' => array('2.1.1' => array('2.1.1.1' => '2.1.1.1.1')))),
326
			'3' => array('3.1' => array('3.1.1' => '3.1.1.1'))
327
		);
328
		$result = Hash::maxDimensions($data);
329
		$this->assertEquals($result, 5);
330
 
331
		$data = array(
332
			'1' => array('1.1' => '1.1.1'),
333
			array('2' => array('2.1' => array('2.1.1' => array('2.1.1.1' => '2.1.1.1.1')))),
334
			'3' => array('3.1' => array('3.1.1' => '3.1.1.1'))
335
		);
336
		$result = Hash::maxDimensions($data);
337
		$this->assertEquals($result, 5);
338
	}
339
 
340
/**
341
 * Tests Hash::flatten
342
 *
343
 * @return void
344
 */
345
	public function testFlatten() {
346
		$data = array('Larry', 'Curly', 'Moe');
347
		$result = Hash::flatten($data);
348
		$this->assertEquals($result, $data);
349
 
350
		$data[9] = 'Shemp';
351
		$result = Hash::flatten($data);
352
		$this->assertEquals($result, $data);
353
 
354
		$data = array(
355
			array(
356
				'Post' => array('id' => '1', 'author_id' => '1', 'title' => 'First Post'),
357
				'Author' => array('id' => '1', 'user' => 'nate', 'password' => 'foo'),
358
			),
359
			array(
360
				'Post' => array('id' => '2', 'author_id' => '3', 'title' => 'Second Post', 'body' => 'Second Post Body'),
361
				'Author' => array('id' => '3', 'user' => 'larry', 'password' => null),
362
			)
363
		);
364
		$result = Hash::flatten($data);
365
		$expected = array(
366
			'0.Post.id' => '1',
367
			'0.Post.author_id' => '1',
368
			'0.Post.title' => 'First Post',
369
			'0.Author.id' => '1',
370
			'0.Author.user' => 'nate',
371
			'0.Author.password' => 'foo',
372
			'1.Post.id' => '2',
373
			'1.Post.author_id' => '3',
374
			'1.Post.title' => 'Second Post',
375
			'1.Post.body' => 'Second Post Body',
376
			'1.Author.id' => '3',
377
			'1.Author.user' => 'larry',
378
			'1.Author.password' => null
379
		);
380
		$this->assertEquals($expected, $result);
381
 
382
		$data = array(
383
			array(
384
				'Post' => array('id' => '1', 'author_id' => null, 'title' => 'First Post'),
385
				'Author' => array(),
386
			)
387
		);
388
		$result = Hash::flatten($data);
389
		$expected = array(
390
			'0.Post.id' => '1',
391
			'0.Post.author_id' => null,
392
			'0.Post.title' => 'First Post',
393
			'0.Author' => array()
394
		);
395
		$this->assertEquals($expected, $result);
396
 
397
		$data = array(
398
			array('Post' => array('id' => 1)),
399
			array('Post' => array('id' => 2)),
400
		);
401
		$result = Hash::flatten($data, '/');
402
		$expected = array(
403
			'0/Post/id' => '1',
404
			'1/Post/id' => '2',
405
		);
406
		$this->assertEquals($expected, $result);
407
	}
408
 
409
/**
410
 * Test diff();
411
 *
412
 * @return void
413
 */
414
	public function testDiff() {
415
		$a = array(
416
 
417
			1 => array('name' => 'about')
418
		);
419
		$b = array(
420
 
421
			1 => array('name' => 'about'),
422
			2 => array('name' => 'contact')
423
		);
424
 
425
		$result = Hash::diff($a, array());
426
		$expected = $a;
427
		$this->assertEquals($expected, $result);
428
 
429
		$result = Hash::diff(array(), $b);
430
		$expected = $b;
431
		$this->assertEquals($expected, $result);
432
 
433
		$result = Hash::diff($a, $b);
434
		$expected = array(
435
			2 => array('name' => 'contact')
436
		);
437
		$this->assertEquals($expected, $result);
438
 
439
		$b = array(
440
 
441
			1 => array('name' => 'about')
442
		);
443
 
444
		$result = Hash::diff($a, $b);
445
		$expected = array(
446
 
447
		);
448
		$this->assertEquals($expected, $result);
449
 
450
		$a = array();
451
		$b = array('name' => 'bob', 'address' => 'home');
452
		$result = Hash::diff($a, $b);
453
		$this->assertEquals($result, $b);
454
 
455
		$a = array('name' => 'bob', 'address' => 'home');
456
		$b = array();
457
		$result = Hash::diff($a, $b);
458
		$this->assertEquals($result, $a);
459
 
460
		$a = array('key' => true, 'another' => false, 'name' => 'me');
461
		$b = array('key' => 1, 'another' => 0);
462
		$expected = array('name' => 'me');
463
		$result = Hash::diff($a, $b);
464
		$this->assertEquals($expected, $result);
465
 
466
		$a = array('key' => 'value', 'another' => null, 'name' => 'me');
467
		$b = array('key' => 'differentValue', 'another' => null);
468
		$expected = array('key' => 'value', 'name' => 'me');
469
		$result = Hash::diff($a, $b);
470
		$this->assertEquals($expected, $result);
471
 
472
		$a = array('key' => 'value', 'another' => null, 'name' => 'me');
473
		$b = array('key' => 'differentValue', 'another' => 'value');
474
		$expected = array('key' => 'value', 'another' => null, 'name' => 'me');
475
		$result = Hash::diff($a, $b);
476
		$this->assertEquals($expected, $result);
477
 
478
		$a = array('key' => 'value', 'another' => null, 'name' => 'me');
479
		$b = array('key' => 'differentValue', 'another' => 'value');
480
		$expected = array('key' => 'differentValue', 'another' => 'value', 'name' => 'me');
481
		$result = Hash::diff($b, $a);
482
		$this->assertEquals($expected, $result);
483
 
484
		$a = array('key' => 'value', 'another' => null, 'name' => 'me');
485
		$b = array(0 => 'differentValue', 1 => 'value');
486
		$expected = $a + $b;
487
		$result = Hash::diff($a, $b);
488
		$this->assertEquals($expected, $result);
489
	}
490
 
491
/**
492
 * Test merge()
493
 *
494
 * @return void
495
 */
496
	public function testMerge() {
497
		$result = Hash::merge(array('foo'), array('bar'));
498
		$this->assertEquals($result, array('foo', 'bar'));
499
 
500
		$result = Hash::merge(array('foo'), array('user' => 'bob', 'no-bar'), 'bar');
501
		$this->assertEquals($result, array('foo', 'user' => 'bob', 'no-bar', 'bar'));
502
 
503
		$a = array('foo', 'foo2');
504
		$b = array('bar', 'bar2');
505
		$expected = array('foo', 'foo2', 'bar', 'bar2');
506
		$this->assertEquals($expected, Hash::merge($a, $b));
507
 
508
		$a = array('foo' => 'bar', 'bar' => 'foo');
509
		$b = array('foo' => 'no-bar', 'bar' => 'no-foo');
510
		$expected = array('foo' => 'no-bar', 'bar' => 'no-foo');
511
		$this->assertEquals($expected, Hash::merge($a, $b));
512
 
513
		$a = array('users' => array('bob', 'jim'));
514
		$b = array('users' => array('lisa', 'tina'));
515
		$expected = array('users' => array('bob', 'jim', 'lisa', 'tina'));
516
		$this->assertEquals($expected, Hash::merge($a, $b));
517
 
518
		$a = array('users' => array('jim', 'bob'));
519
		$b = array('users' => 'none');
520
		$expected = array('users' => 'none');
521
		$this->assertEquals($expected, Hash::merge($a, $b));
522
 
523
		$a = array('users' => array('lisa' => array('id' => 5, 'pw' => 'secret')), 'cakephp');
524
		$b = array('users' => array('lisa' => array('pw' => 'new-pass', 'age' => 23)), 'ice-cream');
525
		$expected = array(
526
			'users' => array('lisa' => array('id' => 5, 'pw' => 'new-pass', 'age' => 23)),
527
			'cakephp',
528
			'ice-cream'
529
		);
530
		$result = Hash::merge($a, $b);
531
		$this->assertEquals($expected, $result);
532
 
533
		$c = array(
534
			'users' => array('lisa' => array('pw' => 'you-will-never-guess', 'age' => 25, 'pet' => 'dog')),
535
			'chocolate'
536
		);
537
		$expected = array(
538
			'users' => array('lisa' => array('id' => 5, 'pw' => 'you-will-never-guess', 'age' => 25, 'pet' => 'dog')),
539
			'cakephp',
540
			'ice-cream',
541
			'chocolate'
542
		);
543
		$this->assertEquals($expected, Hash::merge($a, $b, $c));
544
 
545
		$this->assertEquals($expected, Hash::merge($a, $b, array(), $c));
546
 
547
		$a = array(
548
			'Tree',
549
			'CounterCache',
550
			'Upload' => array(
551
				'folder' => 'products',
552
				'fields' => array('image_1_id', 'image_2_id', 'image_3_id', 'image_4_id', 'image_5_id')
553
			)
554
		);
555
		$b = array(
556
			'Cacheable' => array('enabled' => false),
557
			'Limit',
558
			'Bindable',
559
			'Validator',
560
			'Transactional'
561
		);
562
		$expected = array(
563
			'Tree',
564
			'CounterCache',
565
			'Upload' => array(
566
				'folder' => 'products',
567
				'fields' => array('image_1_id', 'image_2_id', 'image_3_id', 'image_4_id', 'image_5_id')
568
			),
569
			'Cacheable' => array('enabled' => false),
570
			'Limit',
571
			'Bindable',
572
			'Validator',
573
			'Transactional'
574
		);
575
		$this->assertEquals($expected, Hash::merge($a, $b));
576
	}
577
 
578
/**
579
 * test normalizing arrays
580
 *
581
 * @return void
582
 */
583
	public function testNormalize() {
584
		$result = Hash::normalize(array('one', 'two', 'three'));
585
		$expected = array('one' => null, 'two' => null, 'three' => null);
586
		$this->assertEquals($expected, $result);
587
 
588
		$result = Hash::normalize(array('one', 'two', 'three'), false);
589
		$expected = array('one', 'two', 'three');
590
		$this->assertEquals($expected, $result);
591
 
592
		$result = Hash::normalize(array('one' => 1, 'two' => 2, 'three' => 3, 'four'), false);
593
		$expected = array('one' => 1, 'two' => 2, 'three' => 3, 'four' => null);
594
		$this->assertEquals($expected, $result);
595
 
596
		$result = Hash::normalize(array('one' => 1, 'two' => 2, 'three' => 3, 'four'));
597
		$expected = array('one' => 1, 'two' => 2, 'three' => 3, 'four' => null);
598
		$this->assertEquals($expected, $result);
599
 
600
		$result = Hash::normalize(array('one' => array('a', 'b', 'c' => 'cee'), 'two' => 2, 'three'));
601
		$expected = array('one' => array('a', 'b', 'c' => 'cee'), 'two' => 2, 'three' => null);
602
		$this->assertEquals($expected, $result);
603
	}
604
 
605
/**
606
 * testContains method
607
 *
608
 * @return void
609
 */
610
	public function testContains() {
611
		$data = array('apple', 'bee', 'cyclops');
612
		$this->assertTrue(Hash::contains($data, array('apple')));
613
		$this->assertFalse(Hash::contains($data, array('data')));
614
 
615
		$a = array(
616
 
617
			1 => array('name' => 'about')
618
		);
619
		$b = array(
620
 
621
			1 => array('name' => 'about'),
622
			2 => array('name' => 'contact'),
623
			'a' => 'b'
624
		);
625
 
626
		$this->assertTrue(Hash::contains($a, $a));
627
		$this->assertFalse(Hash::contains($a, $b));
628
		$this->assertTrue(Hash::contains($b, $a));
629
 
630
		$a = array(
631
			array('User' => array('id' => 1)),
632
			array('User' => array('id' => 2)),
633
		);
634
		$b = array(
635
			array('User' => array('id' => 1)),
636
			array('User' => array('id' => 2)),
637
			array('User' => array('id' => 3))
638
		);
639
		$this->assertTrue(Hash::contains($b, $a));
640
		$this->assertFalse(Hash::contains($a, $b));
641
 
642
		$a = array(0 => 'test', 'string' => null);
643
		$this->assertTrue(Hash::contains($a, array('string' => null)));
644
 
645
		$a = array(0 => 'test', 'string' => null);
646
		$this->assertTrue(Hash::contains($a, array('test')));
647
	}
648
 
649
/**
650
 * testFilter method
651
 *
652
 * @return void
653
 */
654
	public function testFilter() {
655
		$result = Hash::filter(array('0', false, true, 0, array('one thing', 'I can tell you', 'is you got to be', false)));
656
		$expected = array('0', 2 => true, 3 => 0, 4 => array('one thing', 'I can tell you', 'is you got to be'));
657
		$this->assertSame($expected, $result);
658
 
659
		$result = Hash::filter(array(1, array(false)));
660
		$expected = array(1);
661
		$this->assertEquals($expected, $result);
662
 
663
		$result = Hash::filter(array(1, array(false, false)));
664
		$expected = array(1);
665
		$this->assertEquals($expected, $result);
666
 
667
		$result = Hash::filter(array(1, array('empty', false)));
668
		$expected = array(1, array('empty'));
669
		$this->assertEquals($expected, $result);
670
 
671
		$result = Hash::filter(array(1, array('2', false, array(3, null))));
672
		$expected = array(1, array('2', 2 => array(3)));
673
		$this->assertEquals($expected, $result);
674
 
675
		$this->assertSame(array(), Hash::filter(array()));
676
	}
677
 
678
/**
679
 * testNumericArrayCheck method
680
 *
681
 * @return void
682
 */
683
	public function testNumeric() {
684
		$data = array('one');
685
		$this->assertTrue(Hash::numeric(array_keys($data)));
686
 
687
		$data = array(1 => 'one');
688
		$this->assertFalse(Hash::numeric($data));
689
 
690
		$data = array('one');
691
		$this->assertFalse(Hash::numeric($data));
692
 
693
		$data = array('one' => 'two');
694
		$this->assertFalse(Hash::numeric($data));
695
 
696
		$data = array('one' => 1);
697
		$this->assertTrue(Hash::numeric($data));
698
 
699
		$data = array(0);
700
		$this->assertTrue(Hash::numeric($data));
701
 
702
		$data = array('one', 'two', 'three', 'four', 'five');
703
		$this->assertTrue(Hash::numeric(array_keys($data)));
704
 
705
		$data = array(1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five');
706
		$this->assertTrue(Hash::numeric(array_keys($data)));
707
 
708
		$data = array('1' => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five');
709
		$this->assertTrue(Hash::numeric(array_keys($data)));
710
 
711
		$data = array('one', 2 => 'two', 3 => 'three', 4 => 'four', 'a' => 'five');
712
		$this->assertFalse(Hash::numeric(array_keys($data)));
713
 
714
		$data = array(2.4, 1, 0, -1, -2);
715
		$this->assertTrue(Hash::numeric($data));
716
	}
717
 
718
/**
719
 * Test simple paths.
720
 *
721
 * @return void
722
 */
723
	public function testExtractBasic() {
724
		$data = self::articleData();
725
 
726
		$result = Hash::extract($data, '');
727
		$this->assertEquals($data, $result);
728
 
729
		$result = Hash::extract($data, '0.Article.title');
730
		$this->assertEquals(array('First Article'), $result);
731
 
732
		$result = Hash::extract($data, '1.Article.title');
733
		$this->assertEquals(array('Second Article'), $result);
734
 
735
		$result = Hash::extract(array(false), '{n}.Something.another_thing');
736
		$this->assertEquals(array(), $result);
737
	}
738
 
739
/**
740
 * Test the {n} selector
741
 *
742
 * @return void
743
 */
744
	public function testExtractNumericKey() {
745
		$data = self::articleData();
746
		$result = Hash::extract($data, '{n}.Article.title');
747
		$expected = array(
748
			'First Article', 'Second Article',
749
			'Third Article', 'Fourth Article',
750
			'Fifth Article'
751
		);
752
		$this->assertEquals($expected, $result);
753
 
754
		$result = Hash::extract($data, '0.Comment.{n}.user_id');
755
		$expected = array(
756
			'2', '4'
757
		);
758
		$this->assertEquals($expected, $result);
759
	}
760
 
761
/**
762
 * Test the {n} selector with inconsistent arrays
763
 *
764
 * @return void
765
 */
766
	public function testExtractNumericMixedKeys() {
767
		$data = array(
768
			'User' => array(
769
 
770
					'id' => 4,
771
					'name' => 'Neo'
772
				),
773
				1 => array(
774
					'id' => 5,
775
					'name' => 'Morpheus'
776
				),
777
				'stringKey' => array(
778
					'name' => 'Fail'
779
				)
780
			)
781
		);
782
		$result = Hash::extract($data, 'User.{n}.name');
783
		$expected = array('Neo', 'Morpheus');
784
		$this->assertEquals($expected, $result);
785
	}
786
 
787
/**
788
 * Test the {n} selector with non-zero based arrays
789
 *
790
 * @return void
791
 */
792
	public function testExtractNumericNonZero() {
793
		$data = array(
794
			1 => array(
795
				'User' => array(
796
					'id' => 1,
797
					'name' => 'John',
798
				)
799
			),
800
			2 => array(
801
				'User' => array(
802
					'id' => 2,
803
					'name' => 'Bob',
804
				)
805
			),
806
			3 => array(
807
				'User' => array(
808
					'id' => 3,
809
					'name' => 'Tony',
810
				)
811
			)
812
		);
813
		$result = Hash::extract($data, '{n}.User.name');
814
		$expected = array('John', 'Bob', 'Tony');
815
		$this->assertEquals($expected, $result);
816
	}
817
 
818
/**
819
 * Test the {s} selector.
820
 *
821
 * @return void
822
 */
823
	public function testExtractStringKey() {
824
		$data = self::articleData();
825
		$result = Hash::extract($data, '{n}.{s}.user');
826
		$expected = array(
827
			'mariano',
828
			'mariano',
829
			'mariano',
830
			'mariano',
831
			'mariano'
832
		);
833
		$this->assertEquals($expected, $result);
834
 
835
		$result = Hash::extract($data, '{n}.{s}.Nesting.test.1');
836
		$this->assertEquals(array('foo'), $result);
837
	}
838
 
839
/**
840
 * Test the attribute presense selector.
841
 *
842
 * @return void
843
 */
844
	public function testExtractAttributePresence() {
845
		$data = self::articleData();
846
 
847
		$result = Hash::extract($data, '{n}.Article[published]');
848
		$expected = array($data[1]['Article']);
849
		$this->assertEquals($expected, $result);
850
 
851
		$result = Hash::extract($data, '{n}.Article[id][published]');
852
		$expected = array($data[1]['Article']);
853
		$this->assertEquals($expected, $result);
854
	}
855
 
856
/**
857
 * Test = and != operators.
858
 *
859
 * @return void
860
 */
861
	public function testExtractAttributeEquality() {
862
		$data = self::articleData();
863
 
864
		$result = Hash::extract($data, '{n}.Article[id=3]');
865
		$expected = array($data[2]['Article']);
866
		$this->assertEquals($expected, $result);
867
 
868
		$result = Hash::extract($data, '{n}.Article[id = 3]');
869
		$expected = array($data[2]['Article']);
870
		$this->assertEquals($expected, $result, 'Whitespace should not matter.');
871
 
872
		$result = Hash::extract($data, '{n}.Article[id!=3]');
873
		$this->assertEquals(1, $result[0]['id']);
874
		$this->assertEquals(2, $result[1]['id']);
875
		$this->assertEquals(4, $result[2]['id']);
876
		$this->assertEquals(5, $result[3]['id']);
877
	}
878
 
879
/**
880
 * Test extracting based on attributes with boolean values.
881
 *
882
 * @return void
883
 */
884
	public function testExtractAttributeBoolean() {
885
		$users = array(
886
			array(
887
				'id' => 2,
888
				'username' => 'johndoe',
889
				'active' => true
890
			),
891
			array(
892
				'id' => 5,
893
				'username' => 'kevin',
894
				'active' => true
895
			),
896
			array(
897
				'id' => 9,
898
				'username' => 'samantha',
899
				'active' => false
900
			),
901
		);
902
		$result = Hash::extract($users, '{n}[active=0]');
903
		$this->assertCount(1, $result);
904
		$this->assertEquals($users[2], $result[0]);
905
 
906
		$result = Hash::extract($users, '{n}[active=false]');
907
		$this->assertCount(1, $result);
908
		$this->assertEquals($users[2], $result[0]);
909
 
910
		$result = Hash::extract($users, '{n}[active=1]');
911
		$this->assertCount(2, $result);
912
		$this->assertEquals($users[0], $result[0]);
913
		$this->assertEquals($users[1], $result[1]);
914
 
915
		$result = Hash::extract($users, '{n}[active=true]');
916
		$this->assertCount(2, $result);
917
		$this->assertEquals($users[0], $result[0]);
918
		$this->assertEquals($users[1], $result[1]);
919
	}
920
 
921
/**
922
 * Test that attribute matchers don't cause errors on scalar data.
923
 *
924
 * @return void
925
 */
926
	public function testExtractAttributeEqualityOnScalarValue() {
927
		$data = array(
928
			'Entity' => array(
929
				'id' => 1,
930
				'data1' => 'value',
931
			)
932
		);
933
		$result = Hash::extract($data, 'Entity[id=1].data1');
934
		$this->assertEquals(array('value'), $result);
935
 
936
		$data = array('Entity' => false );
937
		$result = Hash::extract($data, 'Entity[id=1].data1');
938
		$this->assertEquals(array(), $result);
939
	}
940
 
941
/**
942
 * Test comparison operators.
943
 *
944
 * @return void
945
 */
946
	public function testExtractAttributeComparison() {
947
		$data = self::articleData();
948
 
949
		$result = Hash::extract($data, '{n}.Comment.{n}[user_id > 2]');
950
		$expected = array($data[0]['Comment'][1]);
951
		$this->assertEquals($expected, $result);
952
		$this->assertEquals(4, $expected[0]['user_id']);
953
 
954
		$result = Hash::extract($data, '{n}.Comment.{n}[user_id >= 4]');
955
		$expected = array($data[0]['Comment'][1]);
956
		$this->assertEquals($expected, $result);
957
		$this->assertEquals(4, $expected[0]['user_id']);
958
 
959
		$result = Hash::extract($data, '{n}.Comment.{n}[user_id < 3]');
960
		$expected = array($data[0]['Comment'][0]);
961
		$this->assertEquals($expected, $result);
962
		$this->assertEquals(2, $expected[0]['user_id']);
963
 
964
		$result = Hash::extract($data, '{n}.Comment.{n}[user_id <= 2]');
965
		$expected = array($data[0]['Comment'][0]);
966
		$this->assertEquals($expected, $result);
967
		$this->assertEquals(2, $expected[0]['user_id']);
968
	}
969
 
970
/**
971
 * Test multiple attributes with conditions.
972
 *
973
 * @return void
974
 */
975
	public function testExtractAttributeMultiple() {
976
		$data = self::articleData();
977
 
978
		$result = Hash::extract($data, '{n}.Comment.{n}[user_id > 2][id=1]');
979
		$this->assertEmpty($result);
980
 
981
		$result = Hash::extract($data, '{n}.Comment.{n}[user_id > 2][id=2]');
982
		$expected = array($data[0]['Comment'][1]);
983
		$this->assertEquals($expected, $result);
984
		$this->assertEquals(4, $expected[0]['user_id']);
985
	}
986
 
987
/**
988
 * Test attribute pattern matching.
989
 *
990
 * @return void
991
 */
992
	public function testExtractAttributePattern() {
993
		$data = self::articleData();
994
 
995
		$result = Hash::extract($data, '{n}.Article[title=/^First/]');
996
		$expected = array($data[0]['Article']);
997
		$this->assertEquals($expected, $result);
998
 
999
		$result = Hash::extract($data, '{n}.Article[title=/^Fir[a-z]+/]');
1000
		$expected = array($data[0]['Article']);
1001
		$this->assertEquals($expected, $result);
1002
	}
1003
 
1004
/**
1005
 * Test that extract() + matching can hit null things.
1006
 *
1007
 * @return void
1008
 */
1009
	public function testExtractMatchesNull() {
1010
		$data = array(
1011
			'Country' => array(
1012
				array('name' => 'Canada'),
1013
				array('name' => 'Australia'),
1014
				array('name' => null),
1015
			)
1016
		);
1017
		$result = Hash::extract($data, 'Country.{n}[name=/Canada|^$/]');
1018
		$expected = array(
1019
			array(
1020
				'name' => 'Canada',
1021
			),
1022
			array(
1023
				'name' => null,
1024
			),
1025
		);
1026
		$this->assertEquals($expected, $result);
1027
	}
1028
 
1029
/**
1030
 * Test that uneven keys are handled correctly.
1031
 *
1032
 * @return void
1033
 */
1034
	public function testExtractUnevenKeys() {
1035
		$data = array(
1036
			'Level1' => array(
1037
				'Level2' => array('test1', 'test2'),
1038
				'Level2bis' => array('test3', 'test4')
1039
			)
1040
		);
1041
		$this->assertEquals(
1042
			array('test1', 'test2'),
1043
			Hash::extract($data, 'Level1.Level2')
1044
		);
1045
		$this->assertEquals(
1046
			array('test3', 'test4'),
1047
			Hash::extract($data, 'Level1.Level2bis')
1048
		);
1049
 
1050
		$data = array(
1051
			'Level1' => array(
1052
				'Level2bis' => array(
1053
					array('test3', 'test4'),
1054
					array('test5', 'test6')
1055
				)
1056
			)
1057
		);
1058
		$expected = array(
1059
			array('test3', 'test4'),
1060
			array('test5', 'test6')
1061
		);
1062
		$this->assertEquals($expected, Hash::extract($data, 'Level1.Level2bis'));
1063
 
1064
		$data['Level1']['Level2'] = array('test1', 'test2');
1065
		$this->assertEquals($expected, Hash::extract($data, 'Level1.Level2bis'));
1066
	}
1067
 
1068
/**
1069
 * testSort method
1070
 *
1071
 * @return void
1072
 */
1073
	public function testSort() {
1074
		$result = Hash::sort(array(), '{n}.name');
1075
		$this->assertEquals(array(), $result);
1076
 
1077
		$a = array(
1078
 
1079
				'Person' => array('name' => 'Jeff'),
1080
				'Friend' => array(array('name' => 'Nate'))
1081
			),
1082
			1 => array(
1083
				'Person' => array('name' => 'Tracy'),
1084
				'Friend' => array(array('name' => 'Lindsay'))
1085
			)
1086
		);
1087
		$b = array(
1088
 
1089
				'Person' => array('name' => 'Tracy'),
1090
				'Friend' => array(array('name' => 'Lindsay'))
1091
			),
1092
			1 => array(
1093
				'Person' => array('name' => 'Jeff'),
1094
				'Friend' => array(array('name' => 'Nate'))
1095
			)
1096
		);
1097
		$a = Hash::sort($a, '{n}.Friend.{n}.name');
1098
		$this->assertEquals($a, $b);
1099
 
1100
		$b = array(
1101
 
1102
				'Person' => array('name' => 'Jeff'),
1103
				'Friend' => array(array('name' => 'Nate'))
1104
			),
1105
			1 => array(
1106
				'Person' => array('name' => 'Tracy'),
1107
				'Friend' => array(array('name' => 'Lindsay'))
1108
			)
1109
		);
1110
		$a = array(
1111
 
1112
				'Person' => array('name' => 'Tracy'),
1113
				'Friend' => array(array('name' => 'Lindsay'))
1114
			),
1115
			1 => array(
1116
				'Person' => array('name' => 'Jeff'),
1117
				'Friend' => array(array('name' => 'Nate'))
1118
			)
1119
		);
1120
		$a = Hash::sort($a, '{n}.Friend.{n}.name', 'desc');
1121
		$this->assertEquals($a, $b);
1122
 
1123
		$a = array(
1124
 
1125
				'Person' => array('name' => 'Jeff'),
1126
				'Friend' => array(array('name' => 'Nate'))
1127
			),
1128
			1 => array(
1129
				'Person' => array('name' => 'Tracy'),
1130
				'Friend' => array(array('name' => 'Lindsay'))
1131
			),
1132
			2 => array(
1133
				'Person' => array('name' => 'Adam'),
1134
				'Friend' => array(array('name' => 'Bob'))
1135
			)
1136
		);
1137
		$b = array(
1138
 
1139
				'Person' => array('name' => 'Adam'),
1140
				'Friend' => array(array('name' => 'Bob'))
1141
			),
1142
			1 => array(
1143
				'Person' => array('name' => 'Jeff'),
1144
				'Friend' => array(array('name' => 'Nate'))
1145
			),
1146
			2 => array(
1147
				'Person' => array('name' => 'Tracy'),
1148
				'Friend' => array(array('name' => 'Lindsay'))
1149
			)
1150
		);
1151
		$a = Hash::sort($a, '{n}.Person.name', 'asc');
1152
		$this->assertEquals($a, $b);
1153
 
1154
		$a = array(
1155
 
1156
			1 => array('Shirt' => array('color' => 'black'))
1157
		);
1158
		$b = array(
1159
 
1160
			1 => array('Person' => array('name' => 'Jeff')),
1161
		);
1162
		$a = Hash::sort($a, '{n}.Person.name', 'ASC', 'STRING');
1163
		$this->assertSame($a, $b);
1164
 
1165
		$names = array(
1166
			array('employees' => array(
1167
				array('name' => array('first' => 'John', 'last' => 'Doe')))
1168
			),
1169
			array('employees' => array(
1170
				array('name' => array('first' => 'Jane', 'last' => 'Doe')))
1171
			),
1172
			array('employees' => array(array('name' => array()))),
1173
			array('employees' => array(array('name' => array())))
1174
		);
1175
		$result = Hash::sort($names, '{n}.employees.0.name', 'asc');
1176
		$expected = array(
1177
			array('employees' => array(
1178
				array('name' => array('first' => 'John', 'last' => 'Doe')))
1179
			),
1180
			array('employees' => array(
1181
				array('name' => array('first' => 'Jane', 'last' => 'Doe')))
1182
			),
1183
			array('employees' => array(array('name' => array()))),
1184
			array('employees' => array(array('name' => array())))
1185
		);
1186
		$this->assertSame($expected, $result);
1187
 
1188
		$a = array(
1189
			'SU' => array(
1190
				'total_fulfillable' => 2
1191
			),
1192
			'AA' => array(
1193
				'total_fulfillable' => 1
1194
			),
1195
			'LX' => array(
1196
				'total_fulfillable' => 0
1197
			),
1198
			'BL' => array(
1199
				'total_fulfillable' => 3
1200
			),
1201
		);
1202
		$expected = array(
1203
			'LX' => array(
1204
				'total_fulfillable' => 0
1205
			),
1206
			'AA' => array(
1207
				'total_fulfillable' => 1
1208
			),
1209
			'SU' => array(
1210
				'total_fulfillable' => 2
1211
			),
1212
			'BL' => array(
1213
				'total_fulfillable' => 3
1214
			),
1215
		);
1216
		$result = Hash::sort($a, '{s}.total_fulfillable', 'asc');
1217
		$this->assertSame($expected, $result);
1218
	}
1219
 
1220
/**
1221
 * Test sort() with numeric option.
1222
 *
1223
 * @return void
1224
 */
1225
	public function testSortNumeric() {
1226
		$items = array(
1227
			array('Item' => array('price' => '155,000')),
1228
			array('Item' => array('price' => '139,000')),
1229
			array('Item' => array('price' => '275,622')),
1230
			array('Item' => array('price' => '230,888')),
1231
			array('Item' => array('price' => '66,000')),
1232
		);
1233
		$result = Hash::sort($items, '{n}.Item.price', 'asc', 'numeric');
1234
		$expected = array(
1235
			array('Item' => array('price' => '66,000')),
1236
			array('Item' => array('price' => '139,000')),
1237
			array('Item' => array('price' => '155,000')),
1238
			array('Item' => array('price' => '230,888')),
1239
			array('Item' => array('price' => '275,622')),
1240
		);
1241
		$this->assertEquals($expected, $result);
1242
 
1243
		$result = Hash::sort($items, '{n}.Item.price', 'desc', 'numeric');
1244
		$expected = array(
1245
			array('Item' => array('price' => '275,622')),
1246
			array('Item' => array('price' => '230,888')),
1247
			array('Item' => array('price' => '155,000')),
1248
			array('Item' => array('price' => '139,000')),
1249
			array('Item' => array('price' => '66,000')),
1250
		);
1251
		$this->assertEquals($expected, $result);
1252
	}
1253
 
1254
/**
1255
 * Test natural sorting.
1256
 *
1257
 * @return void
1258
 */
1259
	public function testSortNatural() {
1260
		if (version_compare(PHP_VERSION, '5.4.0', '<')) {
1261
			$this->markTestSkipped('SORT_NATURAL is available since PHP 5.4.');
1262
		}
1263
		$items = array(
1264
			array('Item' => array('image' => 'img1.jpg')),
1265
			array('Item' => array('image' => 'img99.jpg')),
1266
			array('Item' => array('image' => 'img12.jpg')),
1267
			array('Item' => array('image' => 'img10.jpg')),
1268
			array('Item' => array('image' => 'img2.jpg')),
1269
		);
1270
		$result = Hash::sort($items, '{n}.Item.image', 'desc', 'natural');
1271
		$expected = array(
1272
			array('Item' => array('image' => 'img99.jpg')),
1273
			array('Item' => array('image' => 'img12.jpg')),
1274
			array('Item' => array('image' => 'img10.jpg')),
1275
			array('Item' => array('image' => 'img2.jpg')),
1276
			array('Item' => array('image' => 'img1.jpg')),
1277
		);
1278
		$this->assertEquals($expected, $result);
1279
 
1280
		$result = Hash::sort($items, '{n}.Item.image', 'asc', 'natural');
1281
		$expected = array(
1282
			array('Item' => array('image' => 'img1.jpg')),
1283
			array('Item' => array('image' => 'img2.jpg')),
1284
			array('Item' => array('image' => 'img10.jpg')),
1285
			array('Item' => array('image' => 'img12.jpg')),
1286
			array('Item' => array('image' => 'img99.jpg')),
1287
		);
1288
		$this->assertEquals($expected, $result);
1289
	}
1290
 
1291
/**
1292
 * Test that sort() with 'natural' type will fallback to 'regular' as SORT_NATURAL is introduced in PHP 5.4
1293
 *
1294
 * @return void
1295
 */
1296
	public function testSortNaturalFallbackToRegular() {
1297
		if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
1298
			$this->markTestSkipped('Skipping SORT_NATURAL fallback test on PHP >= 5.4');
1299
		}
1300
 
1301
		$a = array(
1302
 
1303
			1 => array('Shirt' => array('color' => 'black'))
1304
		);
1305
		$b = array(
1306
 
1307
			1 => array('Person' => array('name' => 'Jeff')),
1308
		);
1309
		$sorted = Hash::sort($a, '{n}.Person.name', 'asc', 'natural');
1310
		$this->assertEquals($sorted, $b);
1311
	}
1312
 
1313
/**
1314
 * test sorting with out of order keys.
1315
 *
1316
 * @return void
1317
 */
1318
	public function testSortWithOutOfOrderKeys() {
1319
		$data = array(
1320
			9 => array('class' => 510, 'test2' => 2),
1321
			1 => array('class' => 500, 'test2' => 1),
1322
			2 => array('class' => 600, 'test2' => 2),
1323
			5 => array('class' => 625, 'test2' => 4),
1324
 
1325
		);
1326
		$expected = array(
1327
			array('class' => 500, 'test2' => 1),
1328
			array('class' => 510, 'test2' => 2),
1329
			array('class' => 600, 'test2' => 2),
1330
			array('class' => 605, 'test2' => 3),
1331
			array('class' => 625, 'test2' => 4),
1332
		);
1333
		$result = Hash::sort($data, '{n}.class', 'asc');
1334
		$this->assertEquals($expected, $result);
1335
 
1336
		$result = Hash::sort($data, '{n}.test2', 'asc');
1337
		$this->assertEquals($expected, $result);
1338
	}
1339
 
1340
/**
1341
 * test sorting with string keys.
1342
 *
1343
 * @return void
1344
 */
1345
	public function testSortString() {
1346
		$toSort = array(
1347
			'four' => array('number' => 4, 'some' => 'foursome'),
1348
			'six' => array('number' => 6, 'some' => 'sixsome'),
1349
			'five' => array('number' => 5, 'some' => 'fivesome'),
1350
			'two' => array('number' => 2, 'some' => 'twosome'),
1351
			'three' => array('number' => 3, 'some' => 'threesome')
1352
		);
1353
		$sorted = Hash::sort($toSort, '{s}.number', 'asc');
1354
		$expected = array(
1355
			'two' => array('number' => 2, 'some' => 'twosome'),
1356
			'three' => array('number' => 3, 'some' => 'threesome'),
1357
			'four' => array('number' => 4, 'some' => 'foursome'),
1358
			'five' => array('number' => 5, 'some' => 'fivesome'),
1359
			'six' => array('number' => 6, 'some' => 'sixsome')
1360
		);
1361
		$this->assertEquals($expected, $sorted);
1362
 
1363
		$menus = array(
1364
			'blogs' => array('title' => 'Blogs', 'weight' => 3),
1365
			'comments' => array('title' => 'Comments', 'weight' => 2),
1366
			'users' => array('title' => 'Users', 'weight' => 1),
1367
		);
1368
		$expected = array(
1369
			'users' => array('title' => 'Users', 'weight' => 1),
1370
			'comments' => array('title' => 'Comments', 'weight' => 2),
1371
			'blogs' => array('title' => 'Blogs', 'weight' => 3),
1372
		);
1373
		$result = Hash::sort($menus, '{s}.weight', 'ASC');
1374
		$this->assertEquals($expected, $result);
1375
	}
1376
 
1377
/**
1378
 * Test insert()
1379
 *
1380
 * @return void
1381
 */
1382
	public function testInsertSimple() {
1383
		$a = array(
1384
			'pages' => array('name' => 'page')
1385
		);
1386
		$result = Hash::insert($a, 'files', array('name' => 'files'));
1387
		$expected = array(
1388
			'pages' => array('name' => 'page'),
1389
			'files' => array('name' => 'files')
1390
		);
1391
		$this->assertEquals($expected, $result);
1392
 
1393
		$a = array(
1394
			'pages' => array('name' => 'page')
1395
		);
1396
		$result = Hash::insert($a, 'pages.name', array());
1397
		$expected = array(
1398
			'pages' => array('name' => array()),
1399
		);
1400
		$this->assertEquals($expected, $result);
1401
 
1402
		$a = array(
1403
			'foo' => array('bar' => 'baz')
1404
		);
1405
		$result = Hash::insert($a, 'some.0123.path', array('foo' => array('bar' => 'baz')));
1406
		$expected = array('foo' => array('bar' => 'baz'));
1407
		$this->assertEquals($expected, Hash::get($result, 'some.0123.path'));
1408
	}
1409
 
1410
/**
1411
 * Test inserting with multiple values.
1412
 *
1413
 * @return void
1414
 */
1415
	public function testInsertMulti() {
1416
		$data = self::articleData();
1417
 
1418
		$result = Hash::insert($data, '{n}.Article.insert', 'value');
1419
		$this->assertEquals('value', $result[0]['Article']['insert']);
1420
		$this->assertEquals('value', $result[1]['Article']['insert']);
1421
 
1422
		$result = Hash::insert($data, '{n}.Comment.{n}.insert', 'value');
1423
		$this->assertEquals('value', $result[0]['Comment'][0]['insert']);
1424
		$this->assertEquals('value', $result[0]['Comment'][1]['insert']);
1425
 
1426
		$data = array(
1427
 
1428
			1 => array('Item' => array('id' => 2, 'title' => 'second')),
1429
			2 => array('Item' => array('id' => 3, 'title' => 'third')),
1430
			3 => array('Item' => array('id' => 4, 'title' => 'fourth')),
1431
			4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
1432
		);
1433
		$result = Hash::insert($data, '{n}.Item[id=/\b2|\b4/]', array('test' => 2));
1434
		$expected = array(
1435
 
1436
			1 => array('Item' => array('id' => 2, 'title' => 'second', 'test' => 2)),
1437
			2 => array('Item' => array('id' => 3, 'title' => 'third')),
1438
			3 => array('Item' => array('id' => 4, 'title' => 'fourth', 'test' => 2)),
1439
			4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
1440
		);
1441
		$this->assertEquals($expected, $result);
1442
	}
1443
 
1444
/**
1445
 * Test that insert() can insert data over a string value.
1446
 *
1447
 * @return void
1448
 */
1449
	public function testInsertOverwriteStringValue() {
1450
		$data = array(
1451
			'Some' => array(
1452
				'string' => 'value'
1453
			)
1454
		);
1455
		$result = Hash::insert($data, 'Some.string.value', array('values'));
1456
		$expected = array(
1457
			'Some' => array(
1458
				'string' => array(
1459
					'value' => array('values')
1460
				)
1461
			)
1462
		);
1463
		$this->assertEquals($expected, $result);
1464
	}
1465
 
1466
/**
1467
 * Test remove() method.
1468
 *
1469
 * @return void
1470
 */
1471
	public function testRemove() {
1472
		$a = array(
1473
			'pages' => array('name' => 'page'),
1474
			'files' => array('name' => 'files')
1475
		);
1476
 
1477
		$result = Hash::remove($a, 'files');
1478
		$expected = array(
1479
			'pages' => array('name' => 'page')
1480
		);
1481
		$this->assertEquals($expected, $result);
1482
 
1483
		$a = array(
1484
			'pages' => array(
1485
 
1486
				1 => array(
1487
					'name' => 'about',
1488
					'vars' => array('title' => 'page title')
1489
				)
1490
			)
1491
		);
1492
 
1493
		$result = Hash::remove($a, 'pages.1.vars');
1494
		$expected = array(
1495
			'pages' => array(
1496
 
1497
				1 => array('name' => 'about')
1498
			)
1499
		);
1500
		$this->assertEquals($expected, $result);
1501
 
1502
		$result = Hash::remove($a, 'pages.2.vars');
1503
		$expected = $a;
1504
		$this->assertEquals($expected, $result);
1505
 
1506
		$a = array(
1507
 
1508
				'name' => 'pages'
1509
			),
1510
			1 => array(
1511
				'name' => 'files'
1512
			)
1513
		);
1514
 
1515
		$result = Hash::remove($a, '{n}[name=files]');
1516
		$expected = array(
1517
 
1518
				'name' => 'pages'
1519
			)
1520
		);
1521
		$this->assertEquals($expected, $result);
1522
 
1523
		$array = array(
1524
 
1525
			1 => array(
1526
 
1527
			)
1528
		);
1529
		$expected = $array;
1530
		$result = Hash::remove($array, '{n}.part');
1531
		$this->assertEquals($expected, $result);
1532
		$result = Hash::remove($array, '{n}.{n}.part');
1533
		$this->assertEquals($expected, $result);
1534
	}
1535
 
1536
/**
1537
 * Test removing multiple values.
1538
 *
1539
 * @return void
1540
 */
1541
	public function testRemoveMulti() {
1542
		$data = self::articleData();
1543
 
1544
		$result = Hash::remove($data, '{n}.Article.title');
1545
		$this->assertFalse(isset($result[0]['Article']['title']));
1546
		$this->assertFalse(isset($result[1]['Article']['title']));
1547
 
1548
		$result = Hash::remove($data, '{n}.Article.{s}');
1549
		$this->assertFalse(isset($result[0]['Article']['id']));
1550
		$this->assertFalse(isset($result[0]['Article']['user_id']));
1551
		$this->assertFalse(isset($result[0]['Article']['title']));
1552
		$this->assertFalse(isset($result[0]['Article']['body']));
1553
 
1554
		$data = array(
1555
 
1556
			1 => array('Item' => array('id' => 2, 'title' => 'second')),
1557
			2 => array('Item' => array('id' => 3, 'title' => 'third')),
1558
			3 => array('Item' => array('id' => 4, 'title' => 'fourth')),
1559
			4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
1560
		);
1561
 
1562
		$result = Hash::remove($data, '{n}.Item[id=/\b2|\b4/]');
1563
		$expected = array(
1564
 
1565
			2 => array('Item' => array('id' => 3, 'title' => 'third')),
1566
			4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
1567
		);
1568
		$this->assertEquals($expected, $result);
1569
	}
1570
 
1571
/**
1572
 * testCheck method
1573
 *
1574
 * @return void
1575
 */
1576
	public function testCheck() {
1577
		$set = array(
1578
			'My Index 1' => array('First' => 'The first item')
1579
		);
1580
		$this->assertTrue(Hash::check($set, 'My Index 1.First'));
1581
		$this->assertTrue(Hash::check($set, 'My Index 1'));
1582
 
1583
		$set = array(
1584
			'My Index 1' => array(
1585
				'First' => array(
1586
					'Second' => array(
1587
						'Third' => array(
1588
							'Fourth' => 'Heavy. Nesting.'
1589
						)
1590
					)
1591
				)
1592
			)
1593
		);
1594
		$this->assertTrue(Hash::check($set, 'My Index 1.First.Second'));
1595
		$this->assertTrue(Hash::check($set, 'My Index 1.First.Second.Third'));
1596
		$this->assertTrue(Hash::check($set, 'My Index 1.First.Second.Third.Fourth'));
1597
		$this->assertFalse(Hash::check($set, 'My Index 1.First.Seconds.Third.Fourth'));
1598
	}
1599
 
1600
/**
1601
 * testCombine method
1602
 *
1603
 * @return void
1604
 */
1605
	public function testCombine() {
1606
		$result = Hash::combine(array(), '{n}.User.id', '{n}.User.Data');
1607
		$this->assertTrue(empty($result));
1608
 
1609
		$a = self::userData();
1610
 
1611
		$result = Hash::combine($a, '{n}.User.id');
1612
		$expected = array(2 => null, 14 => null, 25 => null);
1613
		$this->assertEquals($expected, $result);
1614
 
1615
		$result = Hash::combine($a, '{n}.User.id', '{n}.User.non-existant');
1616
		$expected = array(2 => null, 14 => null, 25 => null);
1617
		$this->assertEquals($expected, $result);
1618
 
1619
		$result = Hash::combine($a, '{n}.User.id', '{n}.User.Data');
1620
		$expected = array(
1621
			2 => array('user' => 'mariano.iglesias', 'name' => 'Mariano Iglesias'),
1622
			14 => array('user' => 'phpnut', 'name' => 'Larry E. Masters'),
1623
			25 => array('user' => 'gwoo', 'name' => 'The Gwoo'));
1624
		$this->assertEquals($expected, $result);
1625
 
1626
		$result = Hash::combine($a, '{n}.User.id', '{n}.User.Data.name');
1627
		$expected = array(
1628
			2 => 'Mariano Iglesias',
1629
			14 => 'Larry E. Masters',
1630
			25 => 'The Gwoo');
1631
		$this->assertEquals($expected, $result);
1632
	}
1633
 
1634
/**
1635
 * test combine() giving errors on key/value length mismatches.
1636
 *
1637
 * @expectedException CakeException
1638
 * @return void
1639
 */
1640
	public function testCombineErrorMissingValue() {
1641
		$data = array(
1642
			array('User' => array('id' => 1, 'name' => 'mark')),
1643
			array('User' => array('name' => 'jose')),
1644
		);
1645
		Hash::combine($data, '{n}.User.id', '{n}.User.name');
1646
	}
1647
 
1648
/**
1649
 * test combine() giving errors on key/value length mismatches.
1650
 *
1651
 * @expectedException CakeException
1652
 * @return void
1653
 */
1654
	public function testCombineErrorMissingKey() {
1655
		$data = array(
1656
			array('User' => array('id' => 1, 'name' => 'mark')),
1657
			array('User' => array('id' => 2)),
1658
		);
1659
		Hash::combine($data, '{n}.User.id', '{n}.User.name');
1660
	}
1661
 
1662
/**
1663
 * test combine() with a group path.
1664
 *
1665
 * @return void
1666
 */
1667
	public function testCombineWithGroupPath() {
1668
		$a = self::userData();
1669
 
1670
		$result = Hash::combine($a, '{n}.User.id', '{n}.User.Data', '{n}.User.group_id');
1671
		$expected = array(
1672
			1 => array(
1673
				2 => array('user' => 'mariano.iglesias', 'name' => 'Mariano Iglesias'),
1674
				25 => array('user' => 'gwoo', 'name' => 'The Gwoo')
1675
			),
1676
			2 => array(
1677
				14 => array('user' => 'phpnut', 'name' => 'Larry E. Masters')
1678
			)
1679
		);
1680
		$this->assertEquals($expected, $result);
1681
 
1682
		$result = Hash::combine($a, '{n}.User.id', '{n}.User.Data.name', '{n}.User.group_id');
1683
		$expected = array(
1684
			1 => array(
1685
				2 => 'Mariano Iglesias',
1686
				25 => 'The Gwoo'
1687
			),
1688
			2 => array(
1689
				14 => 'Larry E. Masters'
1690
			)
1691
		);
1692
		$this->assertEquals($expected, $result);
1693
 
1694
		$result = Hash::combine($a, '{n}.User.id', '{n}.User.Data', '{n}.User.group_id');
1695
		$expected = array(
1696
			1 => array(
1697
				2 => array('user' => 'mariano.iglesias', 'name' => 'Mariano Iglesias'),
1698
				25 => array('user' => 'gwoo', 'name' => 'The Gwoo')
1699
			),
1700
			2 => array(
1701
				14 => array('user' => 'phpnut', 'name' => 'Larry E. Masters')
1702
			)
1703
		);
1704
		$this->assertEquals($expected, $result);
1705
 
1706
		$result = Hash::combine($a, '{n}.User.id', '{n}.User.Data.name', '{n}.User.group_id');
1707
		$expected = array(
1708
			1 => array(
1709
				2 => 'Mariano Iglesias',
1710
				25 => 'The Gwoo'
1711
			),
1712
			2 => array(
1713
				14 => 'Larry E. Masters'
1714
			)
1715
		);
1716
		$this->assertEquals($expected, $result);
1717
	}
1718
 
1719
/**
1720
 * Test combine with formatting rules.
1721
 *
1722
 * @return void
1723
 */
1724
	public function testCombineWithFormatting() {
1725
		$a = self::userData();
1726
 
1727
		$result = Hash::combine(
1728
			$a,
1729
			'{n}.User.id',
1730
			array('%1$s: %2$s', '{n}.User.Data.user', '{n}.User.Data.name'),
1731
			'{n}.User.group_id'
1732
		);
1733
		$expected = array(
1734
			1 => array(
1735
				2 => 'mariano.iglesias: Mariano Iglesias',
1736
				25 => 'gwoo: The Gwoo'
1737
			),
1738
			2 => array(
1739
				14 => 'phpnut: Larry E. Masters'
1740
			)
1741
		);
1742
		$this->assertEquals($expected, $result);
1743
 
1744
		$result = Hash::combine(
1745
			$a,
1746
			array(
1747
				'%s: %s',
1748
				'{n}.User.Data.user',
1749
				'{n}.User.Data.name'
1750
			),
1751
			'{n}.User.id'
1752
		);
1753
		$expected = array(
1754
			'mariano.iglesias: Mariano Iglesias' => 2,
1755
			'phpnut: Larry E. Masters' => 14,
1756
			'gwoo: The Gwoo' => 25
1757
		);
1758
		$this->assertEquals($expected, $result);
1759
 
1760
		$result = Hash::combine(
1761
			$a,
1762
			array('%1$s: %2$d', '{n}.User.Data.user', '{n}.User.id'),
1763
			'{n}.User.Data.name'
1764
		);
1765
		$expected = array(
1766
			'mariano.iglesias: 2' => 'Mariano Iglesias',
1767
			'phpnut: 14' => 'Larry E. Masters',
1768
			'gwoo: 25' => 'The Gwoo'
1769
		);
1770
		$this->assertEquals($expected, $result);
1771
 
1772
		$result = Hash::combine(
1773
			$a,
1774
			array('%2$d: %1$s', '{n}.User.Data.user', '{n}.User.id'),
1775
			'{n}.User.Data.name'
1776
		);
1777
		$expected = array(
1778
			'2: mariano.iglesias' => 'Mariano Iglesias',
1779
			'14: phpnut' => 'Larry E. Masters',
1780
			'25: gwoo' => 'The Gwoo'
1781
		);
1782
		$this->assertEquals($expected, $result);
1783
	}
1784
 
1785
/**
1786
 * testFormat method
1787
 *
1788
 * @return void
1789
 */
1790
	public function testFormat() {
1791
		$data = self::userData();
1792
 
1793
		$result = Hash::format(
1794
			$data,
1795
			array('{n}.User.Data.user', '{n}.User.id'),
1796
			'%s, %s'
1797
		);
1798
		$expected = array(
1799
			'mariano.iglesias, 2',
1800
			'phpnut, 14',
1801
			'gwoo, 25'
1802
		);
1803
		$this->assertEquals($expected, $result);
1804
 
1805
		$result = Hash::format(
1806
			$data,
1807
			array('{n}.User.Data.user', '{n}.User.id'),
1808
			'%2$s, %1$s'
1809
		);
1810
		$expected = array(
1811
			'2, mariano.iglesias',
1812
			'14, phpnut',
1813
			'25, gwoo'
1814
		);
1815
		$this->assertEquals($expected, $result);
1816
	}
1817
 
1818
/**
1819
 * testFormattingNullValues method
1820
 *
1821
 * @return void
1822
 */
1823
	public function testFormatNullValues() {
1824
		$data = array(
1825
			array('Person' => array(
1826
				'first_name' => 'Nate', 'last_name' => 'Abele', 'city' => 'Boston', 'state' => 'MA', 'something' => '42'
1827
			)),
1828
			array('Person' => array(
1829
				'first_name' => 'Larry', 'last_name' => 'Masters', 'city' => 'Boondock', 'state' => 'TN', 'something' => null
1830
			)),
1831
			array('Person' => array(
1832
				'first_name' => 'Garrett', 'last_name' => 'Woodworth', 'city' => 'Venice Beach', 'state' => 'CA', 'something' => null
1833
			))
1834
		);
1835
 
1836
		$result = Hash::format($data, array('{n}.Person.something'), '%s');
1837
		$expected = array('42', '', '');
1838
		$this->assertEquals($expected, $result);
1839
 
1840
		$result = Hash::format($data, array('{n}.Person.city', '{n}.Person.something'), '%s, %s');
1841
		$expected = array('Boston, 42', 'Boondock, ', 'Venice Beach, ');
1842
		$this->assertEquals($expected, $result);
1843
	}
1844
 
1845
/**
1846
 * Test map()
1847
 *
1848
 * @return void
1849
 */
1850
	public function testMap() {
1851
		$data = self::articleData();
1852
 
1853
		$result = Hash::map($data, '{n}.Article.id', array($this, 'mapCallback'));
1854
		$expected = array(2, 4, 6, 8, 10);
1855
		$this->assertEquals($expected, $result);
1856
	}
1857
 
1858
/**
1859
 * testApply
1860
 *
1861
 * @return void
1862
 */
1863
	public function testApply() {
1864
		$data = self::articleData();
1865
 
1866
		$result = Hash::apply($data, '{n}.Article.id', 'array_sum');
1867
		$this->assertEquals(15, $result);
1868
	}
1869
 
1870
/**
1871
 * Test reduce()
1872
 *
1873
 * @return void
1874
 */
1875
	public function testReduce() {
1876
		$data = self::articleData();
1877
 
1878
		$result = Hash::reduce($data, '{n}.Article.id', array($this, 'reduceCallback'));
1879
		$this->assertEquals(15, $result);
1880
	}
1881
 
1882
/**
1883
 * testing method for map callbacks.
1884
 *
1885
 * @param mixed $value Value
1886
 * @return mixed
1887
 */
1888
	public function mapCallback($value) {
1889
		return $value * 2;
1890
	}
1891
 
1892
/**
1893
 * testing method for reduce callbacks.
1894
 *
1895
 * @param mixed $one First param
1896
 * @param mixed $two Second param
1897
 * @return mixed
1898
 */
1899
	public function reduceCallback($one, $two) {
1900
		return $one + $two;
1901
	}
1902
 
1903
/**
1904
 * test Hash nest with a normal model result set. For kicks rely on Hash nest detecting the key names
1905
 * automatically
1906
 *
1907
 * @return void
1908
 */
1909
	public function testNestModel() {
1910
		$input = array(
1911
			array(
1912
				'ModelName' => array(
1913
					'id' => 1,
1914
					'parent_id' => null
1915
				),
1916
			),
1917
			array(
1918
				'ModelName' => array(
1919
					'id' => 2,
1920
					'parent_id' => 1
1921
				),
1922
			),
1923
			array(
1924
				'ModelName' => array(
1925
					'id' => 3,
1926
					'parent_id' => 1
1927
				),
1928
			),
1929
			array(
1930
				'ModelName' => array(
1931
					'id' => 4,
1932
					'parent_id' => 1
1933
				),
1934
			),
1935
			array(
1936
				'ModelName' => array(
1937
					'id' => 5,
1938
					'parent_id' => 1
1939
				),
1940
			),
1941
			array(
1942
				'ModelName' => array(
1943
					'id' => 6,
1944
					'parent_id' => null
1945
				),
1946
			),
1947
			array(
1948
				'ModelName' => array(
1949
					'id' => 7,
1950
					'parent_id' => 6
1951
				),
1952
			),
1953
			array(
1954
				'ModelName' => array(
1955
					'id' => 8,
1956
					'parent_id' => 6
1957
				),
1958
			),
1959
			array(
1960
				'ModelName' => array(
1961
					'id' => 9,
1962
					'parent_id' => 6
1963
				),
1964
			),
1965
			array(
1966
				'ModelName' => array(
1967
					'id' => 10,
1968
					'parent_id' => 6
1969
				)
1970
			)
1971
		);
1972
		$expected = array(
1973
			array(
1974
				'ModelName' => array(
1975
					'id' => 1,
1976
					'parent_id' => null
1977
				),
1978
				'children' => array(
1979
					array(
1980
						'ModelName' => array(
1981
							'id' => 2,
1982
							'parent_id' => 1
1983
						),
1984
						'children' => array()
1985
					),
1986
					array(
1987
						'ModelName' => array(
1988
							'id' => 3,
1989
							'parent_id' => 1
1990
						),
1991
						'children' => array()
1992
					),
1993
					array(
1994
						'ModelName' => array(
1995
							'id' => 4,
1996
							'parent_id' => 1
1997
						),
1998
						'children' => array()
1999
					),
2000
					array(
2001
						'ModelName' => array(
2002
							'id' => 5,
2003
							'parent_id' => 1
2004
						),
2005
						'children' => array()
2006
					),
2007
 
2008
				)
2009
			),
2010
			array(
2011
				'ModelName' => array(
2012
					'id' => 6,
2013
					'parent_id' => null
2014
				),
2015
				'children' => array(
2016
					array(
2017
						'ModelName' => array(
2018
							'id' => 7,
2019
							'parent_id' => 6
2020
						),
2021
						'children' => array()
2022
					),
2023
					array(
2024
						'ModelName' => array(
2025
							'id' => 8,
2026
							'parent_id' => 6
2027
						),
2028
						'children' => array()
2029
					),
2030
					array(
2031
						'ModelName' => array(
2032
							'id' => 9,
2033
							'parent_id' => 6
2034
						),
2035
						'children' => array()
2036
					),
2037
					array(
2038
						'ModelName' => array(
2039
							'id' => 10,
2040
							'parent_id' => 6
2041
						),
2042
						'children' => array()
2043
					)
2044
				)
2045
			)
2046
		);
2047
		$result = Hash::nest($input);
2048
		$this->assertEquals($expected, $result);
2049
	}
2050
 
2051
/**
2052
 * test Hash nest with a normal model result set, and a nominated root id
2053
 *
2054
 * @return void
2055
 */
2056
	public function testNestModelExplicitRoot() {
2057
		$input = array(
2058
			array(
2059
				'ModelName' => array(
2060
					'id' => 1,
2061
					'parent_id' => null
2062
				),
2063
			),
2064
			array(
2065
				'ModelName' => array(
2066
					'id' => 2,
2067
					'parent_id' => 1
2068
				),
2069
			),
2070
			array(
2071
				'ModelName' => array(
2072
					'id' => 3,
2073
					'parent_id' => 1
2074
				),
2075
			),
2076
			array(
2077
				'ModelName' => array(
2078
					'id' => 4,
2079
					'parent_id' => 1
2080
				),
2081
			),
2082
			array(
2083
				'ModelName' => array(
2084
					'id' => 5,
2085
					'parent_id' => 1
2086
				),
2087
			),
2088
			array(
2089
				'ModelName' => array(
2090
					'id' => 6,
2091
					'parent_id' => null
2092
				),
2093
			),
2094
			array(
2095
				'ModelName' => array(
2096
					'id' => 7,
2097
					'parent_id' => 6
2098
				),
2099
			),
2100
			array(
2101
				'ModelName' => array(
2102
					'id' => 8,
2103
					'parent_id' => 6
2104
				),
2105
			),
2106
			array(
2107
				'ModelName' => array(
2108
					'id' => 9,
2109
					'parent_id' => 6
2110
				),
2111
			),
2112
			array(
2113
				'ModelName' => array(
2114
					'id' => 10,
2115
					'parent_id' => 6
2116
				)
2117
			)
2118
		);
2119
		$expected = array(
2120
			array(
2121
				'ModelName' => array(
2122
					'id' => 6,
2123
					'parent_id' => null
2124
				),
2125
				'children' => array(
2126
					array(
2127
						'ModelName' => array(
2128
							'id' => 7,
2129
							'parent_id' => 6
2130
						),
2131
						'children' => array()
2132
					),
2133
					array(
2134
						'ModelName' => array(
2135
							'id' => 8,
2136
							'parent_id' => 6
2137
						),
2138
						'children' => array()
2139
					),
2140
					array(
2141
						'ModelName' => array(
2142
							'id' => 9,
2143
							'parent_id' => 6
2144
						),
2145
						'children' => array()
2146
					),
2147
					array(
2148
						'ModelName' => array(
2149
							'id' => 10,
2150
							'parent_id' => 6
2151
						),
2152
						'children' => array()
2153
					)
2154
				)
2155
			)
2156
		);
2157
		$result = Hash::nest($input, array('root' => 6));
2158
		$this->assertEquals($expected, $result);
2159
	}
2160
 
2161
/**
2162
 * test Hash nest with a 1d array - this method should be able to handle any type of array input
2163
 *
2164
 * @return void
2165
 */
2166
	public function testNest1Dimensional() {
2167
		$input = array(
2168
			array(
2169
				'id' => 1,
2170
				'parent_id' => null
2171
			),
2172
			array(
2173
				'id' => 2,
2174
				'parent_id' => 1
2175
			),
2176
			array(
2177
				'id' => 3,
2178
				'parent_id' => 1
2179
			),
2180
			array(
2181
				'id' => 4,
2182
				'parent_id' => 1
2183
			),
2184
			array(
2185
				'id' => 5,
2186
				'parent_id' => 1
2187
			),
2188
			array(
2189
				'id' => 6,
2190
				'parent_id' => null
2191
			),
2192
			array(
2193
				'id' => 7,
2194
				'parent_id' => 6
2195
			),
2196
			array(
2197
				'id' => 8,
2198
				'parent_id' => 6
2199
			),
2200
			array(
2201
				'id' => 9,
2202
				'parent_id' => 6
2203
			),
2204
			array(
2205
				'id' => 10,
2206
				'parent_id' => 6
2207
			)
2208
		);
2209
		$expected = array(
2210
			array(
2211
				'id' => 1,
2212
				'parent_id' => null,
2213
				'children' => array(
2214
					array(
2215
						'id' => 2,
2216
						'parent_id' => 1,
2217
						'children' => array()
2218
					),
2219
					array(
2220
						'id' => 3,
2221
						'parent_id' => 1,
2222
						'children' => array()
2223
					),
2224
					array(
2225
						'id' => 4,
2226
						'parent_id' => 1,
2227
						'children' => array()
2228
					),
2229
					array(
2230
						'id' => 5,
2231
						'parent_id' => 1,
2232
						'children' => array()
2233
					),
2234
 
2235
				)
2236
			),
2237
			array(
2238
				'id' => 6,
2239
				'parent_id' => null,
2240
				'children' => array(
2241
					array(
2242
						'id' => 7,
2243
						'parent_id' => 6,
2244
						'children' => array()
2245
					),
2246
					array(
2247
						'id' => 8,
2248
						'parent_id' => 6,
2249
						'children' => array()
2250
					),
2251
					array(
2252
						'id' => 9,
2253
						'parent_id' => 6,
2254
						'children' => array()
2255
					),
2256
					array(
2257
						'id' => 10,
2258
						'parent_id' => 6,
2259
						'children' => array()
2260
					)
2261
				)
2262
			)
2263
		);
2264
		$result = Hash::nest($input, array('idPath' => '{n}.id', 'parentPath' => '{n}.parent_id'));
2265
		$this->assertEquals($expected, $result);
2266
	}
2267
 
2268
/**
2269
 * test Hash nest with no specified parent data.
2270
 *
2271
 * The result should be the same as the input.
2272
 * For an easier comparison, unset all the empty children arrays from the result
2273
 *
2274
 * @return void
2275
 */
2276
	public function testMissingParent() {
2277
		$input = array(
2278
			array(
2279
				'id' => 1,
2280
			),
2281
			array(
2282
				'id' => 2,
2283
			),
2284
			array(
2285
				'id' => 3,
2286
			),
2287
			array(
2288
				'id' => 4,
2289
			),
2290
			array(
2291
				'id' => 5,
2292
			),
2293
			array(
2294
				'id' => 6,
2295
			),
2296
			array(
2297
				'id' => 7,
2298
			),
2299
			array(
2300
				'id' => 8,
2301
			),
2302
			array(
2303
				'id' => 9,
2304
			),
2305
			array(
2306
				'id' => 10,
2307
			)
2308
		);
2309
 
2310
		$result = Hash::nest($input, array('idPath' => '{n}.id', 'parentPath' => '{n}.parent_id'));
2311
		foreach ($result as &$row) {
2312
			if (empty($row['children'])) {
2313
				unset($row['children']);
2314
			}
2315
		}
2316
		$this->assertEquals($input, $result);
2317
	}
2318
 
2319
/**
2320
 * Tests that nest() throws an InvalidArgumentException when providing an invalid input.
2321
 *
2322
 * @expectedException InvalidArgumentException
2323
 * @return void
2324
 */
2325
	public function testNestInvalid() {
2326
		$input = array(
2327
			array(
2328
				'ParentCategory' => array(
2329
					'id' => '1',
2330
					'name' => 'Lorem ipsum dolor sit amet',
2331
					'parent_id' => '1'
2332
				)
2333
			)
2334
		);
2335
		Hash::nest($input);
2336
	}
2337
 
2338
/**
2339
 * testMergeDiff method
2340
 *
2341
 * @return void
2342
 */
2343
	public function testMergeDiff() {
2344
		$first = array(
2345
			'ModelOne' => array(
2346
				'id' => 1001,
2347
				'field_one' => 'a1.m1.f1',
2348
				'field_two' => 'a1.m1.f2'
2349
			)
2350
		);
2351
		$second = array(
2352
			'ModelTwo' => array(
2353
				'id' => 1002,
2354
				'field_one' => 'a2.m2.f1',
2355
				'field_two' => 'a2.m2.f2'
2356
			)
2357
		);
2358
		$result = Hash::mergeDiff($first, $second);
2359
		$this->assertEquals($result, $first + $second);
2360
 
2361
		$result = Hash::mergeDiff($first, array());
2362
		$this->assertEquals($result, $first);
2363
 
2364
		$result = Hash::mergeDiff(array(), $first);
2365
		$this->assertEquals($result, $first);
2366
 
2367
		$third = array(
2368
			'ModelOne' => array(
2369
				'id' => 1003,
2370
				'field_one' => 'a3.m1.f1',
2371
				'field_two' => 'a3.m1.f2',
2372
				'field_three' => 'a3.m1.f3'
2373
			)
2374
		);
2375
		$result = Hash::mergeDiff($first, $third);
2376
		$expected = array(
2377
			'ModelOne' => array(
2378
				'id' => 1001,
2379
				'field_one' => 'a1.m1.f1',
2380
				'field_two' => 'a1.m1.f2',
2381
				'field_three' => 'a3.m1.f3'
2382
			)
2383
		);
2384
		$this->assertEquals($expected, $result);
2385
 
2386
		$first = array(
2387
 
2388
			1 => array('ModelTwo' => array('id' => 1002, 'field_one' => 's1.1.m2.f2', 'field_two' => 's1.1.m2.f2'))
2389
		);
2390
		$second = array(
2391
 
2392
			1 => array('ModelTwo' => array('id' => 1002, 'field_one' => 's2.1.m2.f2', 'field_two' => 's2.1.m2.f2'))
2393
		);
2394
 
2395
		$result = Hash::mergeDiff($first, $second);
2396
		$this->assertEquals($result, $first);
2397
 
2398
		$third = array(
2399
 
2400
				'ModelThree' => array(
2401
					'id' => 1003,
2402
					'field_one' => 's3.0.m3.f1',
2403
					'field_two' => 's3.0.m3.f2'
2404
				)
2405
			)
2406
		);
2407
 
2408
		$result = Hash::mergeDiff($first, $third);
2409
		$expected = array(
2410
 
2411
				'ModelOne' => array(
2412
					'id' => 1001,
2413
					'field_one' => 's1.0.m1.f1',
2414
					'field_two' => 's1.0.m1.f2'
2415
				),
2416
				'ModelThree' => array(
2417
					'id' => 1003,
2418
					'field_one' => 's3.0.m3.f1',
2419
					'field_two' => 's3.0.m3.f2'
2420
				)
2421
			),
2422
			1 => array(
2423
				'ModelTwo' => array(
2424
					'id' => 1002,
2425
					'field_one' => 's1.1.m2.f2',
2426
					'field_two' => 's1.1.m2.f2'
2427
				)
2428
			)
2429
		);
2430
		$this->assertEquals($expected, $result);
2431
 
2432
		$result = Hash::mergeDiff($first, null);
2433
		$this->assertEquals($result, $first);
2434
 
2435
		$result = Hash::mergeDiff($first, $second);
2436
		$this->assertEquals($result, $first + $second);
2437
	}
2438
 
2439
/**
2440
 * Tests Hash::expand
2441
 *
2442
 * @return void
2443
 */
2444
	public function testExpand() {
2445
		$data = array('My', 'Array', 'To', 'Flatten');
2446
		$flat = Hash::flatten($data);
2447
		$result = Hash::expand($flat);
2448
		$this->assertEquals($data, $result);
2449
 
2450
		$data = array(
2451
			'0.Post.id' => '1', '0.Post.author_id' => '1', '0.Post.title' => 'First Post', '0.Author.id' => '1',
2452
			'0.Author.user' => 'nate', '0.Author.password' => 'foo', '1.Post.id' => '2', '1.Post.author_id' => '3',
2453
			'1.Post.title' => 'Second Post', '1.Post.body' => 'Second Post Body', '1.Author.id' => '3',
2454
			'1.Author.user' => 'larry', '1.Author.password' => null
2455
		);
2456
		$result = Hash::expand($data);
2457
		$expected = array(
2458
			array(
2459
				'Post' => array('id' => '1', 'author_id' => '1', 'title' => 'First Post'),
2460
				'Author' => array('id' => '1', 'user' => 'nate', 'password' => 'foo'),
2461
			),
2462
			array(
2463
				'Post' => array('id' => '2', 'author_id' => '3', 'title' => 'Second Post', 'body' => 'Second Post Body'),
2464
				'Author' => array('id' => '3', 'user' => 'larry', 'password' => null),
2465
			)
2466
		);
2467
		$this->assertEquals($expected, $result);
2468
 
2469
		$data = array(
2470
			'0/Post/id' => 1,
2471
			'0/Post/name' => 'test post'
2472
		);
2473
		$result = Hash::expand($data, '/');
2474
		$expected = array(
2475
			array(
2476
				'Post' => array(
2477
					'id' => 1,
2478
					'name' => 'test post'
2479
				)
2480
			)
2481
		);
2482
		$this->assertEquals($expected, $result);
2483
 
2484
		$data = array('a.b.100.a' => null, 'a.b.200.a' => null);
2485
		$expected = array(
2486
			'a' => array(
2487
				'b' => array(
2488
					100 => array('a' => null),
2489
					200 => array('a' => null)
2490
				)
2491
			)
2492
		);
2493
		$result = Hash::expand($data);
2494
		$this->assertEquals($expected, $result);
2495
	}
2496
 
2497
/**
2498
 * Test that flattening a large complex set doesn't loop forever.
2499
 *
2500
 * @return void
2501
 */
2502
	public function testFlattenInfiniteLoop() {
2503
		$data = array(
2504
			'Order.ASI' => '0',
2505
			'Order.Accounting' => '0',
2506
			'Order.Admin' => '0',
2507
			'Order.Art' => '0',
2508
			'Order.ArtChecker' => '0',
2509
			'Order.Canned' => '0',
2510
			'Order.Customer_Tags' => '',
2511
			'Order.Embroidery' => '0',
2512
			'Order.Item.0.Product.style_number' => 'a11222',
2513
			'Order.Item.0.Product.slug' => 'a11222',
2514
			'Order.Item.0.Product._id' => '4ff8b8d3d7bbe8ad30000000',
2515
			'Order.Item.0.Product.Color.slug' => 'kelly_green',
2516
			'Order.Item.0.Product.ColorSizes.0.Color.color' => 'Sport Grey',
2517
			'Order.Item.0.Product.ColorSizes.0.Color.slug' => 'sport_grey',
2518
			'Order.Item.0.Product.ColorSizes.1.Color.color' => 'Kelly Green',
2519
			'Order.Item.0.Product.ColorSizes.1.Color.slug' => 'kelly_green',
2520
			'Order.Item.0.Product.ColorSizes.2.Color.color' => 'Orange',
2521
			'Order.Item.0.Product.ColorSizes.2.Color.slug' => 'orange',
2522
			'Order.Item.0.Product.ColorSizes.3.Color.color' => 'Yellow Haze',
2523
			'Order.Item.0.Product.ColorSizes.3.Color.slug' => 'yellow_haze',
2524
			'Order.Item.0.Product.brand' => 'OUTER BANKS',
2525
			'Order.Item.0.Product.style' => 'T-shirt',
2526
			'Order.Item.0.Product.description' => 'uhiuhuih oin ooi ioo ioio',
2527
			'Order.Item.0.Product.sizes.0.Size.qty' => '',
2528
			'Order.Item.0.Product.sizes.0.Size.size' => '0-3mo',
2529
			'Order.Item.0.Product.sizes.0.Size.id' => '38',
2530
			'Order.Item.0.Product.sizes.1.Size.qty' => '',
2531
			'Order.Item.0.Product.sizes.1.Size.size' => '3-6mo',
2532
			'Order.Item.0.Product.sizes.1.Size.id' => '39',
2533
			'Order.Item.0.Product.sizes.2.Size.qty' => '78',
2534
			'Order.Item.0.Product.sizes.2.Size.size' => '6-9mo',
2535
			'Order.Item.0.Product.sizes.2.Size.id' => '40',
2536
			'Order.Item.0.Product.sizes.3.Size.qty' => '',
2537
			'Order.Item.0.Product.sizes.3.Size.size' => '6-12mo',
2538
			'Order.Item.0.Product.sizes.3.Size.id' => '41',
2539
			'Order.Item.0.Product.sizes.4.Size.qty' => '',
2540
			'Order.Item.0.Product.sizes.4.Size.size' => '12-18mo',
2541
			'Order.Item.0.Product.sizes.4.Size.id' => '42',
2542
			'Order.Item.0.Art.imprint_locations.0.id' => 2,
2543
			'Order.Item.0.Art.imprint_locations.0.name' => 'Left Chest',
2544
			'Order.Item.0.Art.imprint_locations.0.imprint_type.id' => 7,
2545
			'Order.Item.0.Art.imprint_locations.0.imprint_type.type' => 'Embroidery',
2546
			'Order.Item.0.Art.imprint_locations.0.art' => '',
2547
			'Order.Item.0.Art.imprint_locations.0.num_colors' => 3,
2548
			'Order.Item.0.Art.imprint_locations.0.description' => 'Wooo! This is Embroidery!!',
2549
			'Order.Item.0.Art.imprint_locations.0.lines.0' => 'Platen',
2550
			'Order.Item.0.Art.imprint_locations.0.lines.1' => 'Logo',
2551
			'Order.Item.0.Art.imprint_locations.0.height' => 4,
2552
			'Order.Item.0.Art.imprint_locations.0.width' => 5,
2553
			'Order.Item.0.Art.imprint_locations.0.stitch_density' => 'Light',
2554
			'Order.Item.0.Art.imprint_locations.0.metallic_thread' => true,
2555
			'Order.Item.0.Art.imprint_locations.1.id' => 4,
2556
			'Order.Item.0.Art.imprint_locations.1.name' => 'Full Back',
2557
			'Order.Item.0.Art.imprint_locations.1.imprint_type.id' => 6,
2558
			'Order.Item.0.Art.imprint_locations.1.imprint_type.type' => 'Screenprinting',
2559
			'Order.Item.0.Art.imprint_locations.1.art' => '',
2560
			'Order.Item.0.Art.imprint_locations.1.num_colors' => 3,
2561
			'Order.Item.0.Art.imprint_locations.1.description' => 'Wooo! This is Screenprinting!!',
2562
			'Order.Item.0.Art.imprint_locations.1.lines.0' => 'Platen',
2563
			'Order.Item.0.Art.imprint_locations.1.lines.1' => 'Logo',
2564
			'Order.Item.0.Art.imprint_locations.2.id' => 26,
2565
			'Order.Item.0.Art.imprint_locations.2.name' => 'HS - JSY Name Below',
2566
			'Order.Item.0.Art.imprint_locations.2.imprint_type.id' => 9,
2567
			'Order.Item.0.Art.imprint_locations.2.imprint_type.type' => 'Names',
2568
			'Order.Item.0.Art.imprint_locations.2.description' => 'Wooo! This is Names!!',
2569
			'Order.Item.0.Art.imprint_locations.2.sizes.S.0.active' => 1,
2570
			'Order.Item.0.Art.imprint_locations.2.sizes.S.0.name' => 'Benjamin Talavera',
2571
			'Order.Item.0.Art.imprint_locations.2.sizes.S.0.color' => 'Red',
2572
			'Order.Item.0.Art.imprint_locations.2.sizes.S.0.height' => '3',
2573
			'Order.Item.0.Art.imprint_locations.2.sizes.S.0.layout' => 'Arched',
2574
			'Order.Item.0.Art.imprint_locations.2.sizes.S.0.style' => 'Classic',
2575
			'Order.Item.0.Art.imprint_locations.2.sizes.S.1.active' => 0,
2576
			'Order.Item.0.Art.imprint_locations.2.sizes.S.1.name' => 'Rishi Narayan',
2577
			'Order.Item.0.Art.imprint_locations.2.sizes.S.1.color' => 'Cardinal',
2578
			'Order.Item.0.Art.imprint_locations.2.sizes.S.1.height' => '4',
2579
			'Order.Item.0.Art.imprint_locations.2.sizes.S.1.layout' => 'Straight',
2580
			'Order.Item.0.Art.imprint_locations.2.sizes.S.1.style' => 'Team US',
2581
			'Order.Item.0.Art.imprint_locations.2.sizes.M.0.active' => 1,
2582
			'Order.Item.0.Art.imprint_locations.2.sizes.M.0.name' => 'Brandon Plasters',
2583
			'Order.Item.0.Art.imprint_locations.2.sizes.M.0.color' => 'Red',
2584
			'Order.Item.0.Art.imprint_locations.2.sizes.M.0.height' => '3',
2585
			'Order.Item.0.Art.imprint_locations.2.sizes.M.0.layout' => 'Arched',
2586
			'Order.Item.0.Art.imprint_locations.2.sizes.M.0.style' => 'Classic',
2587
			'Order.Item.0.Art.imprint_locations.2.sizes.M.1.active' => 0,
2588
			'Order.Item.0.Art.imprint_locations.2.sizes.M.1.name' => 'Andrew Reed',
2589
			'Order.Item.0.Art.imprint_locations.2.sizes.M.1.color' => 'Cardinal',
2590
			'Order.Item.0.Art.imprint_locations.2.sizes.M.1.height' => '4',
2591
			'Order.Item.0.Art.imprint_locations.2.sizes.M.1.layout' => 'Straight',
2592
			'Order.Item.0.Art.imprint_locations.2.sizes.M.1.style' => 'Team US',
2593
			'Order.Job.0._id' => 'job-1',
2594
			'Order.Job.0.type' => 'screenprinting',
2595
			'Order.Job.0.postPress' => 'job-2',
2596
			'Order.Job.1._id' => 'job-2',
2597
			'Order.Job.1.type' => 'embroidery',
2598
			'Order.Postpress' => '0',
2599
			'Order.PriceAdjustment.0._id' => 'price-adjustment-1',
2600
			'Order.PriceAdjustment.0.adjustment' => '-20',
2601
			'Order.PriceAdjustment.0.adjustment_type' => 'percent',
2602
			'Order.PriceAdjustment.0.type' => 'grand_total',
2603
			'Order.PriceAdjustment.1.adjustment' => '20',
2604
			'Order.PriceAdjustment.1.adjustment_type' => 'flat',
2605
			'Order.PriceAdjustment.1.min-items' => '10',
2606
			'Order.PriceAdjustment.1.type' => 'min-items',
2607
			'Order.PriceAdjustment.1._id' => 'another-test-adjustment',
2608
			'Order.Purchasing' => '0',
2609
			'Order.QualityControl' => '0',
2610
			'Order.Receiving' => '0',
2611
			'Order.ScreenPrinting' => '0',
2612
			'Order.Stage.art_approval' => 0,
2613
			'Order.Stage.draft' => 1,
2614
			'Order.Stage.quote' => 1,
2615
			'Order.Stage.order' => 1,
2616
			'Order.StoreLiason' => '0',
2617
			'Order.Tag_UI_Email' => '',
2618
			'Order.Tags' => '',
2619
			'Order._id' => 'test-2',
2620
			'Order.add_print_location' => '',
2621
			'Order.created' => '2011-Dec-29 05:40:18',
2622
			'Order.force_admin' => '0',
2623
			'Order.modified' => '2012-Jul-25 01:24:49',
2624
			'Order.name' => 'towering power',
2625
			'Order.order_id' => '135961',
2626
			'Order.slug' => 'test-2',
2627
			'Order.title' => 'test job 2',
2628
			'Order.type' => 'ttt'
2629
		);
2630
		$expanded = Hash::expand($data);
2631
		$flattened = Hash::flatten($expanded);
2632
		$this->assertEquals($data, $flattened);
2633
	}
2634
 
2635
}