Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

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