Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

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