Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
16591 anikendra 1
<?php
2
/**
3
 * ModelValidationTest file
4
 *
5
 * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
6
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7
 *
8
 * Licensed under The MIT License
9
 * For full copyright and license information, please see the LICENSE.txt
10
 * Redistributions of files must retain the above copyright notice
11
 *
12
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
13
 * @link          http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
14
 * @package       Cake.Test.Case.Model
15
 * @since         CakePHP(tm) v 1.2.0.4206
16
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
17
 */
18
 
19
require_once dirname(__FILE__) . DS . 'ModelTestBase.php';
20
 
21
/**
22
 * ModelValidationTest
23
 *
24
 * @package       Cake.Test.Case.Model
25
 */
26
class ModelValidationTest extends BaseModelTest {
27
 
28
/**
29
 * override locale to the default (eng).
30
 *
31
 * @return void
32
 */
33
	public function setUp() {
34
		parent::setUp();
35
		Configure::write('Config.language', 'eng');
36
	}
37
 
38
/**
39
 * Tests validation parameter order in custom validation methods
40
 *
41
 * @return void
42
 */
43
	public function testValidationParams() {
44
		$TestModel = new ValidationTest1();
45
		$TestModel->validate['title'] = array(
46
			'rule' => 'customValidatorWithParams',
47
			'required' => true
48
		);
49
		$TestModel->create(array('title' => 'foo'));
50
		$TestModel->invalidFields();
51
 
52
		$expected = array(
53
			'data' => array(
54
				'title' => 'foo'
55
			),
56
			'validator' => array(
57
				'rule' => 'customValidatorWithParams',
58
				'on' => null,
59
				'last' => true,
60
				'allowEmpty' => false,
61
				'required' => true,
62
				'message' => null
63
			),
64
			'or' => true,
65
			'ignoreOnSame' => 'id'
66
		);
67
		$this->assertEquals($expected, $TestModel->validatorParams);
68
 
69
		$TestModel->validate['title'] = array(
70
			'rule' => 'customValidatorWithMessage',
71
			'required' => true
72
		);
73
		$expected = array(
74
			'title' => array('This field will *never* validate! Muhahaha!')
75
		);
76
 
77
		$this->assertEquals($expected, $TestModel->invalidFields());
78
 
79
		$TestModel->validate['title'] = array(
80
			'rule' => array('customValidatorWithSixParams', 'one', 'two', null, 'four'),
81
			'required' => true
82
		);
83
		$TestModel->create(array('title' => 'foo'));
84
		$TestModel->invalidFields();
85
		$expected = array(
86
			'data' => array(
87
				'title' => 'foo'
88
			),
89
			'one' => 'one',
90
			'two' => 'two',
91
			'three' => null,
92
			'four' => 'four',
93
			'five' => array(
94
				'rule' => array(1 => 'one', 2 => 'two', 3 => null, 4 => 'four'),
95
				'on' => null,
96
				'last' => true,
97
				'allowEmpty' => false,
98
				'required' => true,
99
				'message' => null
100
			),
101
			'six' => 6
102
		);
103
		$this->assertEquals($expected, $TestModel->validatorParams);
104
 
105
		$TestModel->validate['title'] = array(
106
			'rule' => array('customValidatorWithSixParams', 'one', array('two'), null, 'four', array('five' => 5)),
107
			'required' => true
108
		);
109
		$TestModel->create(array('title' => 'foo'));
110
		$TestModel->invalidFields();
111
		$expected = array(
112
			'data' => array(
113
				'title' => 'foo'
114
			),
115
			'one' => 'one',
116
			'two' => array('two'),
117
			'three' => null,
118
			'four' => 'four',
119
			'five' => array('five' => 5),
120
			'six' => array(
121
				'rule' => array(1 => 'one', 2 => array('two'), 3 => null, 4 => 'four', 5 => array('five' => 5)),
122
				'on' => null,
123
				'last' => true,
124
				'allowEmpty' => false,
125
				'required' => true,
126
				'message' => null
127
			)
128
		);
129
		$this->assertEquals($expected, $TestModel->validatorParams);
130
	}
131
 
132
/**
133
 * Tests validation parameter fieldList in invalidFields
134
 *
135
 * @return void
136
 */
137
	public function testInvalidFieldsWithFieldListParams() {
138
		$TestModel = new ValidationTest1();
139
		$TestModel->validate = $validate = array(
140
			'title' => array(
141
				'rule' => 'alphaNumeric',
142
				'required' => true
143
			),
144
			'name' => array(
145
				'rule' => 'alphaNumeric',
146
				'required' => true
147
		));
148
		$TestModel->set(array('title' => '$$', 'name' => '##'));
149
		$TestModel->invalidFields(array('fieldList' => array('title')));
150
		$expected = array(
151
			'title' => array('This field cannot be left blank')
152
		);
153
		$this->assertEquals($expected, $TestModel->validationErrors);
154
		$TestModel->validationErrors = array();
155
 
156
		$TestModel->invalidFields(array('fieldList' => array('name')));
157
		$expected = array(
158
			'name' => array('This field cannot be left blank')
159
		);
160
		$this->assertEquals($expected, $TestModel->validationErrors);
161
		$TestModel->validationErrors = array();
162
 
163
		$TestModel->invalidFields(array('fieldList' => array('name', 'title')));
164
		$expected = array(
165
			'name' => array('This field cannot be left blank'),
166
			'title' => array('This field cannot be left blank')
167
		);
168
		$this->assertEquals($expected, $TestModel->validationErrors);
169
		$TestModel->validationErrors = array();
170
 
171
		$TestModel->whitelist = array('name');
172
		$TestModel->invalidFields();
173
		$expected = array('name' => array('This field cannot be left blank'));
174
		$this->assertEquals($expected, $TestModel->validationErrors);
175
 
176
		$this->assertEquals($TestModel->validate, $validate);
177
	}
178
 
179
/**
180
 * Test that invalidFields() integrates well with save(). And that fieldList can be an empty type.
181
 *
182
 * @return void
183
 */
184
	public function testInvalidFieldsWhitelist() {
185
		$TestModel = new ValidationTest1();
186
		$TestModel->validate = array(
187
			'title' => array(
188
				'rule' => 'alphaNumeric',
189
				'required' => true
190
			),
191
			'name' => array(
192
				'rule' => 'alphaNumeric',
193
				'required' => true
194
		));
195
 
196
		$TestModel->whitelist = array('name');
197
		$TestModel->save(array('name' => '#$$#', 'title' => '$$$$'));
198
 
199
		$expected = array('name' => array('This field cannot be left blank'));
200
		$this->assertEquals($expected, $TestModel->validationErrors);
201
	}
202
 
203
/**
204
 * testValidates method
205
 *
206
 * @return void
207
 */
208
	public function testValidates() {
209
		$TestModel = new TestValidate();
210
 
211
		$TestModel->validate = array(
212
			'user_id' => 'numeric',
213
			'title' => array('allowEmpty' => false, 'rule' => 'notBlank'),
214
			'body' => 'notBlank'
215
		);
216
 
217
		$data = array('TestValidate' => array(
218
			'user_id' => '1',
219
			'title' => '',
220
			'body' => 'body'
221
		));
222
		$result = $TestModel->create($data);
223
		$this->assertEquals($data, $result);
224
		$result = $TestModel->validates();
225
		$this->assertFalse($result);
226
 
227
		$data = array('TestValidate' => array(
228
			'user_id' => '1',
229
			'title' => 'title',
230
			'body' => 'body'
231
		));
232
		$result = $TestModel->create($data) && $TestModel->validates();
233
		$this->assertTrue($result);
234
 
235
		$data = array('TestValidate' => array(
236
			'user_id' => '1',
237
			'title' => '0',
238
			'body' => 'body'
239
		));
240
		$result = $TestModel->create($data);
241
		$this->assertEquals($data, $result);
242
		$result = $TestModel->validates();
243
		$this->assertTrue($result);
244
 
245
		$data = array('TestValidate' => array(
246
			'user_id' => '1',
247
			'title' => 0,
248
			'body' => 'body'
249
		));
250
		$result = $TestModel->create($data);
251
		$this->assertEquals($data, $result);
252
		$result = $TestModel->validates();
253
		$this->assertTrue($result);
254
 
255
		$TestModel->validate['modified'] = array('allowEmpty' => true, 'rule' => 'date');
256
 
257
		$data = array('TestValidate' => array(
258
			'user_id' => '1',
259
			'title' => 0,
260
			'body' => 'body',
261
			'modified' => ''
262
		));
263
		$result = $TestModel->create($data);
264
		$this->assertEquals($data, $result);
265
		$result = $TestModel->validates();
266
		$this->assertTrue($result);
267
 
268
		$data = array('TestValidate' => array(
269
			'user_id' => '1',
270
			'title' => 0,
271
			'body' => 'body',
272
			'modified' => '2007-05-01'
273
		));
274
		$result = $TestModel->create($data);
275
		$this->assertEquals($data, $result);
276
		$result = $TestModel->validates();
277
		$this->assertTrue($result);
278
 
279
		$data = array('TestValidate' => array(
280
			'user_id' => '1',
281
			'title' => 0,
282
			'body' => 'body',
283
			'modified' => 'invalid-date-here'
284
		));
285
		$result = $TestModel->create($data);
286
		$this->assertEquals($data, $result);
287
		$result = $TestModel->validates();
288
		$this->assertFalse($result);
289
 
290
		$data = array('TestValidate' => array(
291
			'user_id' => '1',
292
			'title' => 0,
293
			'body' => 'body',
294
			'modified' => 0
295
		));
296
		$result = $TestModel->create($data);
297
		$this->assertEquals($data, $result);
298
		$result = $TestModel->validates();
299
		$this->assertFalse($result);
300
 
301
		$data = array('TestValidate' => array(
302
			'user_id' => '1',
303
			'title' => 0,
304
			'body' => 'body',
305
			'modified' => '0'
306
		));
307
		$result = $TestModel->create($data);
308
		$this->assertEquals($data, $result);
309
		$result = $TestModel->validates();
310
		$this->assertFalse($result);
311
 
312
		$TestModel->validate['modified'] = array('allowEmpty' => false, 'rule' => 'date');
313
 
314
		$data = array('TestValidate' => array('modified' => null));
315
		$result = $TestModel->create($data);
316
		$this->assertEquals($data, $result);
317
		$result = $TestModel->validates();
318
		$this->assertFalse($result);
319
 
320
		$data = array('TestValidate' => array('modified' => false));
321
		$result = $TestModel->create($data);
322
		$this->assertEquals($data, $result);
323
		$result = $TestModel->validates();
324
		$this->assertFalse($result);
325
 
326
		$data = array('TestValidate' => array('modified' => ''));
327
		$result = $TestModel->create($data);
328
		$this->assertEquals($data, $result);
329
		$result = $TestModel->validates();
330
		$this->assertFalse($result);
331
 
332
		$data = array('TestValidate' => array(
333
			'modified' => '2007-05-01'
334
		));
335
		$result = $TestModel->create($data);
336
		$this->assertEquals($data, $result);
337
		$result = $TestModel->validates();
338
		$this->assertTrue($result);
339
 
340
		$TestModel->validate['slug'] = array('allowEmpty' => false, 'rule' => array('maxLength', 45));
341
 
342
		$data = array('TestValidate' => array(
343
			'user_id' => '1',
344
			'title' => 0,
345
			'body' => 'body',
346
			'slug' => ''
347
		));
348
		$result = $TestModel->create($data);
349
		$this->assertEquals($data, $result);
350
		$result = $TestModel->validates();
351
		$this->assertFalse($result);
352
 
353
		$data = array('TestValidate' => array(
354
			'user_id' => '1',
355
			'title' => 0,
356
			'body' => 'body',
357
			'slug' => 'slug-right-here'
358
		));
359
		$result = $TestModel->create($data);
360
		$this->assertEquals($data, $result);
361
		$result = $TestModel->validates();
362
		$this->assertTrue($result);
363
 
364
		$data = array('TestValidate' => array(
365
			'user_id' => '1',
366
			'title' => 0,
367
			'body' => 'body',
368
			'slug' => 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
369
		));
370
		$result = $TestModel->create($data);
371
		$this->assertEquals($data, $result);
372
		$result = $TestModel->validates();
373
		$this->assertFalse($result);
374
 
375
		$TestModel->validate = array(
376
			'number' => array(
377
				'rule' => 'validateNumber',
378
				'min' => 3,
379
				'max' => 5
380
			),
381
			'title' => array(
382
				'allowEmpty' => false,
383
				'rule' => 'notBlank'
384
		));
385
 
386
		$data = array('TestValidate' => array(
387
			'title' => 'title',
388
			'number' => '0'
389
		));
390
		$result = $TestModel->create($data);
391
		$this->assertEquals($data, $result);
392
		$result = $TestModel->validates();
393
		$this->assertFalse($result);
394
 
395
		$data = array('TestValidate' => array(
396
			'title' => 'title',
397
			'number' => 0
398
		));
399
		$result = $TestModel->create($data);
400
		$this->assertEquals($data, $result);
401
		$result = $TestModel->validates();
402
		$this->assertFalse($result);
403
 
404
		$data = array('TestValidate' => array(
405
			'title' => 'title',
406
			'number' => '3'
407
		));
408
		$result = $TestModel->create($data);
409
		$this->assertEquals($data, $result);
410
		$result = $TestModel->validates();
411
		$this->assertTrue($result);
412
 
413
		$data = array('TestValidate' => array(
414
			'title' => 'title',
415
			'number' => 3
416
		));
417
		$result = $TestModel->create($data);
418
		$this->assertEquals($data, $result);
419
		$result = $TestModel->validates();
420
		$this->assertTrue($result);
421
 
422
		$TestModel->validate = array(
423
			'number' => array(
424
				'rule' => 'validateNumber',
425
				'min' => 5,
426
				'max' => 10
427
			),
428
			'title' => array(
429
				'allowEmpty' => false,
430
				'rule' => 'notBlank'
431
		));
432
 
433
		$data = array('TestValidate' => array(
434
			'title' => 'title',
435
			'number' => '3'
436
		));
437
		$result = $TestModel->create($data);
438
		$this->assertEquals($data, $result);
439
		$result = $TestModel->validates();
440
		$this->assertFalse($result);
441
 
442
		$data = array('TestValidate' => array(
443
			'title' => 'title',
444
			'number' => 3
445
		));
446
		$result = $TestModel->create($data);
447
		$this->assertEquals($data, $result);
448
		$result = $TestModel->validates();
449
		$this->assertFalse($result);
450
 
451
		$TestModel->validate = array(
452
			'title' => array(
453
				'allowEmpty' => false,
454
				'rule' => 'validateTitle'
455
		));
456
 
457
		$data = array('TestValidate' => array('title' => ''));
458
		$result = $TestModel->create($data);
459
		$this->assertEquals($data, $result);
460
		$result = $TestModel->validates();
461
		$this->assertFalse($result);
462
 
463
		$data = array('TestValidate' => array('title' => 'new title'));
464
		$result = $TestModel->create($data);
465
		$this->assertEquals($data, $result);
466
		$result = $TestModel->validates();
467
		$this->assertFalse($result);
468
 
469
		$data = array('TestValidate' => array('title' => 'title-new'));
470
		$result = $TestModel->create($data);
471
		$this->assertEquals($data, $result);
472
		$result = $TestModel->validates();
473
		$this->assertTrue($result);
474
 
475
		$TestModel->validate = array('title' => array(
476
			'allowEmpty' => true,
477
			'rule' => 'validateTitle'
478
		));
479
		$data = array('TestValidate' => array('title' => ''));
480
		$result = $TestModel->create($data);
481
		$this->assertEquals($data, $result);
482
		$result = $TestModel->validates();
483
		$this->assertTrue($result);
484
 
485
		$TestModel->validate = array(
486
			'title' => array(
487
				'length' => array(
488
					'allowEmpty' => true,
489
					'rule' => array('maxLength', 10)
490
		)));
491
		$data = array('TestValidate' => array('title' => ''));
492
		$result = $TestModel->create($data);
493
		$this->assertEquals($data, $result);
494
		$result = $TestModel->validates();
495
		$this->assertTrue($result);
496
 
497
		$TestModel->validate = array(
498
			'title' => array(
499
				'rule' => array('userDefined', 'Article', 'titleDuplicate')
500
		));
501
		$data = array('TestValidate' => array('title' => 'My Article Title'));
502
		$result = $TestModel->create($data);
503
		$this->assertEquals($data, $result);
504
		$result = $TestModel->validates();
505
		$this->assertFalse($result);
506
 
507
		$data = array('TestValidate' => array(
508
			'title' => 'My Article With a Different Title'
509
		));
510
		$result = $TestModel->create($data);
511
		$this->assertEquals($data, $result);
512
		$result = $TestModel->validates();
513
		$this->assertTrue($result);
514
 
515
		$TestModel->validate = array(
516
			'title' => array(
517
				'tooShort' => array('rule' => array('minLength', 50)),
518
				'onlyLetters' => array('rule' => '/^[a-z]+$/i')
519
			),
520
		);
521
		$data = array('TestValidate' => array(
522
			'title' => 'I am a short string'
523
		));
524
		$TestModel->create($data);
525
		$result = $TestModel->validates();
526
		$this->assertFalse($result);
527
		$result = $TestModel->validationErrors;
528
		$expected = array(
529
			'title' => array('tooShort')
530
		);
531
		$this->assertEquals($expected, $result);
532
 
533
		$TestModel->validate = array(
534
			'title' => array(
535
				'tooShort' => array(
536
					'rule' => array('minLength', 50),
537
					'last' => false
538
				),
539
				'onlyLetters' => array('rule' => '/^[a-z]+$/i')
540
			),
541
		);
542
		$data = array('TestValidate' => array(
543
			'title' => 'I am a short string'
544
		));
545
		$TestModel->create($data);
546
		$result = $TestModel->validates();
547
		$this->assertFalse($result);
548
		$result = $TestModel->validationErrors;
549
		$expected = array(
550
			'title' => array('tooShort', 'onlyLetters')
551
		);
552
		$this->assertEquals($expected, $result);
553
		$result = $TestModel->validationErrors;
554
		$this->assertEquals($expected, $result);
555
	}
556
 
557
/**
558
 * test that validates() still performs correctly when useTable = false on the model.
559
 *
560
 * @return void
561
 */
562
	public function testValidatesWithNoTable() {
563
		$TestModel = new TheVoid();
564
		$TestModel->validate = array(
565
			'title' => array(
566
				'notEmpty' => array(
567
					'rule' => array('notBlank'),
568
					'required' => true,
569
				),
570
				'tooShort' => array(
571
					'rule' => array('minLength', 10),
572
				),
573
			),
574
		);
575
		$data = array(
576
			'TheVoid' => array(
577
				'title' => 'too short',
578
			),
579
		);
580
		$TestModel->create($data);
581
		$result = $TestModel->validates();
582
		$this->assertFalse($result);
583
 
584
		$data = array(
585
			'TheVoid' => array(
586
				'id' => '1',
587
				'title' => 'A good title',
588
			),
589
		);
590
		$TestModel->create($data);
591
		$result = $TestModel->validates();
592
		$this->assertTrue($result);
593
	}
594
 
595
/**
596
 * test that validates() checks all the 'with' associations as well for validation
597
 * as this can cause partial/wrong data insertion.
598
 *
599
 * @return void
600
 */
601
	public function testValidatesWithAssociations() {
602
		$this->loadFixtures('Something', 'SomethingElse', 'JoinThing');
603
		$data = array(
604
			'Something' => array(
605
				'id' => 5,
606
				'title' => 'Extra Fields',
607
				'body' => 'Extra Fields Body',
608
				'published' => '1'
609
			),
610
			'SomethingElse' => array(
611
				array('something_else_id' => 1, 'doomed' => '')
612
			)
613
		);
614
 
615
		$Something = new Something();
616
		$JoinThing = $Something->JoinThing;
617
 
618
		$JoinThing->validate = array('doomed' => array('rule' => 'notBlank'));
619
 
620
		$expectedError = array('doomed' => array('This field cannot be left blank'));
621
 
622
		$Something->create();
623
		$result = $Something->save($data);
624
		$this->assertFalse($result, 'Save occurred even when with models failed. %s');
625
		$this->assertEquals($expectedError, $JoinThing->validationErrors);
626
		$count = $Something->find('count', array('conditions' => array('Something.id' => $data['Something']['id'])));
627
		$this->assertSame(0, $count);
628
 
629
		$data = array(
630
			'Something' => array(
631
				'id' => 5,
632
				'title' => 'Extra Fields',
633
				'body' => 'Extra Fields Body',
634
				'published' => '1'
635
			),
636
			'SomethingElse' => array(
637
				array('something_else_id' => 1, 'doomed' => 1),
638
				array('something_else_id' => 1, 'doomed' => '')
639
			)
640
		);
641
		$Something->create();
642
		$result = $Something->save($data);
643
		$this->assertFalse($result, 'Save occurred even when with models failed. %s');
644
 
645
		$joinRecords = $JoinThing->find('count', array(
646
			'conditions' => array('JoinThing.something_id' => $data['Something']['id'])
647
		));
648
		$this->assertEquals(0, $joinRecords, 'Records were saved on the join table. %s');
649
	}
650
 
651
/**
652
 * Test that if a behavior modifies the model's whitelist validation gets triggered
653
 * properly for those fields.
654
 *
655
 * @return void
656
 */
657
	public function testValidateWithFieldListAndBehavior() {
658
		$TestModel = new ValidationTest1();
659
		$TestModel->validate = array(
660
			'title' => array(
661
				'rule' => 'notBlank',
662
			),
663
			'name' => array(
664
				'rule' => 'notBlank',
665
		));
666
		$TestModel->Behaviors->attach('ValidationRule', array('fields' => array('name')));
667
 
668
		$data = array(
669
			'title' => '',
670
			'name' => '',
671
		);
672
		$result = $TestModel->save($data, array('fieldList' => array('title')));
673
		$this->assertFalse($result);
674
 
675
		$expected = array('title' => array('This field cannot be left blank'), 'name' => array('This field cannot be left blank'));
676
		$this->assertEquals($expected, $TestModel->validationErrors);
677
	}
678
 
679
/**
680
 * test that saveAll and with models with validation interact well
681
 *
682
 * @return void
683
 */
684
	public function testValidatesWithModelsAndSaveAll() {
685
		$this->loadFixtures('Something', 'SomethingElse', 'JoinThing');
686
		$data = array(
687
			'Something' => array(
688
				'id' => 5,
689
				'title' => 'Extra Fields',
690
				'body' => 'Extra Fields Body',
691
				'published' => '1'
692
			),
693
			'SomethingElse' => array(
694
				array('something_else_id' => 1, 'doomed' => '')
695
			)
696
		);
697
		$Something = new Something();
698
		$JoinThing = $Something->JoinThing;
699
 
700
		$JoinThing->validate = array('doomed' => array('rule' => 'notBlank'));
701
		$expectedError = array('doomed' => array('This field cannot be left blank'));
702
 
703
		$Something->create();
704
		$result = $Something->saveAll($data, array('validate' => 'only'));
705
		$this->assertFalse($result);
706
		$result = $Something->validateAssociated($data);
707
		$this->assertFalse($result);
708
		$this->assertEquals($expectedError, $JoinThing->validationErrors);
709
		$result = $Something->validator()->validateAssociated($data);
710
		$this->assertFalse($result);
711
 
712
		$Something->create();
713
		$result = $Something->saveAll($data, array('validate' => 'first'));
714
		$this->assertFalse($result);
715
		$this->assertEquals($expectedError, $JoinThing->validationErrors);
716
 
717
		$count = $Something->find('count', array('conditions' => array('Something.id' => $data['Something']['id'])));
718
		$this->assertSame(0, $count);
719
 
720
		$joinRecords = $JoinThing->find('count', array(
721
			'conditions' => array('JoinThing.something_id' => $data['Something']['id'])
722
		));
723
		$this->assertEquals(0, $joinRecords, 'Records were saved on the join table. %s');
724
	}
725
 
726
/**
727
 * test that saveAll and with models at initial insert (no id has set yet)
728
 * with validation interact well
729
 *
730
 * @return void
731
 */
732
	public function testValidatesWithModelsAndSaveAllWithoutId() {
733
		$this->loadFixtures('Post', 'Author');
734
 
735
		$data = array(
736
			'Author' => array(
737
				'name' => 'Foo Bar',
738
			),
739
			'Post' => array(
740
				array('title' => 'Hello'),
741
				array('title' => 'World'),
742
			)
743
		);
744
		$Author = new Author();
745
		$Post = $Author->Post;
746
 
747
		$Post->validate = array('author_id' => array('rule' => 'numeric'));
748
 
749
		$Author->create();
750
		$result = $Author->saveAll($data, array('validate' => 'only'));
751
		$this->assertTrue($result);
752
		$result = $Author->validateAssociated($data);
753
		$this->assertTrue($result);
754
		$this->assertTrue($result);
755
 
756
		$Author->create();
757
		$result = $Author->saveAll($data, array('validate' => 'first'));
758
		$this->assertTrue($result);
759
		$this->assertNotNull($Author->id);
760
 
761
		$id = $Author->id;
762
		$count = $Author->find('count', array('conditions' => array('Author.id' => $id)));
763
		$this->assertSame(1, $count);
764
 
765
		$count = $Post->find('count', array(
766
			'conditions' => array('Post.author_id' => $id)
767
		));
768
		$this->assertEquals($count, count($data['Post']));
769
	}
770
 
771
/**
772
 * Test that missing validation methods trigger errors in development mode.
773
 * Helps to make development easier.
774
 *
775
 * @expectedException PHPUnit_Framework_Error
776
 * @return void
777
 */
778
	public function testMissingValidationErrorTriggering() {
779
		Configure::write('debug', 2);
780
 
781
		$TestModel = new ValidationTest1();
782
		$TestModel->create(array('title' => 'foo'));
783
		$TestModel->validate = array(
784
			'title' => array(
785
				'rule' => array('thisOneBringsThePain'),
786
				'required' => true
787
			)
788
		);
789
		$TestModel->invalidFields(array('fieldList' => array('title')));
790
	}
791
 
792
/**
793
 * Test placeholder replacement when validation message is an array
794
 *
795
 * @return void
796
 */
797
	public function testValidationMessageAsArray() {
798
		$TestModel = new ValidationTest1();
799
		$TestModel->validate = array(
800
			'title' => array(
801
				'minLength' => array(
802
					'rule' => array('minLength', 6),
803
					'required' => true,
804
					'message' => 'Minimum length allowed is %d chars',
805
					'last' => false
806
				),
807
				'between' => array(
808
					'rule' => array('lengthBetween', 5, 15),
809
					'message' => array('You may enter up to %s chars (minimum is %s chars)', 14, 6)
810
				)
811
			)
812
		);
813
 
814
		$TestModel->create();
815
		$expected = array(
816
			'title' => array(
817
				'Minimum length allowed is 6 chars',
818
			)
819
		);
820
		$TestModel->invalidFields();
821
		$this->assertEquals($expected, $TestModel->validationErrors);
822
 
823
		$TestModel->create(array('title' => 'foo'));
824
		$expected = array(
825
			'title' => array(
826
				'Minimum length allowed is 6 chars',
827
				'You may enter up to 14 chars (minimum is 6 chars)'
828
			)
829
		);
830
		$TestModel->invalidFields();
831
		$this->assertEquals($expected, $TestModel->validationErrors);
832
	}
833
 
834
/**
835
 * Test validation message translation
836
 *
837
 * @return void
838
 */
839
	public function testValidationMessageTranslation() {
840
		$lang = Configure::read('Config.language');
841
		Configure::write('Config.language', 'en');
842
		App::build(array(
843
			'Locale' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Locale' . DS),
844
		), App::RESET);
845
 
846
		$TestModel = new ValidationTest1();
847
		$TestModel->validationDomain = 'validation_messages';
848
		$TestModel->validate = array(
849
			'title' => array(
850
				array(
851
					'rule' => array('customValidationMethod', 'arg1'),
852
					'required' => true,
853
					'message' => 'Validation failed: %s'
854
				)
855
			)
856
		);
857
 
858
		$TestModel->create();
859
		$expected = array(
860
			'title' => array(
861
				'Translated validation failed: Translated arg1',
862
			)
863
		);
864
		$TestModel->invalidFields();
865
		$this->assertEquals($expected, $TestModel->validationErrors);
866
 
867
		$TestModel->validationDomain = 'default';
868
		Configure::write('Config.language', $lang);
869
		App::build();
870
	}
871
 
872
/**
873
 * Test for 'on' => [create|update] in validation rules.
874
 *
875
 * @return void
876
 */
877
	public function testStateValidation() {
878
		$this->loadFixtures('Article');
879
		$Article = new Article();
880
 
881
		$data = array(
882
			'Article' => array(
883
				'title' => '',
884
				'body' => 'Extra Fields Body',
885
				'published' => '1'
886
			)
887
		);
888
 
889
		$Article->validate = array(
890
			'title' => array(
891
				'notBlank' => array(
892
					'rule' => 'notBlank',
893
					'on' => 'create'
894
				)
895
			)
896
		);
897
 
898
		$Article->create($data);
899
		$this->assertFalse($Article->validates());
900
 
901
		$Article->save(null, array('validate' => false));
902
		$data['Article']['id'] = $Article->id;
903
		$Article->set($data);
904
		$this->assertTrue($Article->validates());
905
 
906
		unset($data['Article']['id']);
907
		$Article->validate = array(
908
			'title' => array(
909
				'notBlank' => array(
910
					'rule' => 'notBlank',
911
					'on' => 'update'
912
				)
913
			)
914
		);
915
 
916
		$Article->create($data);
917
		$this->assertTrue($Article->validates());
918
 
919
		$Article->save(null, array('validate' => false));
920
		$data['Article']['id'] = $Article->id;
921
		$Article->set($data);
922
		$this->assertFalse($Article->validates());
923
	}
924
 
925
/**
926
 * Test for 'required' => [create|update] in validation rules.
927
 *
928
 * @return void
929
 */
930
	public function testStateRequiredValidation() {
931
		$this->loadFixtures('Article');
932
		$Article = new Article();
933
 
934
		// no title field present
935
		$data = array(
936
			'Article' => array(
937
				'body' => 'Extra Fields Body',
938
				'published' => '1'
939
			)
940
		);
941
 
942
		$Article->validate = array(
943
			'title' => array(
944
				'notBlank' => array(
945
					'rule' => 'notBlank',
946
					'required' => 'create'
947
				)
948
			)
949
		);
950
 
951
		$Article->create($data);
952
		$this->assertFalse($Article->validates());
953
 
954
		$Article->save(null, array('validate' => false));
955
		$data['Article']['id'] = $Article->id;
956
		$Article->set($data);
957
		$this->assertTrue($Article->validates());
958
 
959
		unset($data['Article']['id']);
960
		$Article->validate = array(
961
			'title' => array(
962
				'notBlank' => array(
963
					'rule' => 'notBlank',
964
					'required' => 'update'
965
				)
966
			)
967
		);
968
 
969
		$Article->create($data);
970
		$this->assertTrue($Article->validates());
971
 
972
		$Article->save(null, array('validate' => false));
973
		$data['Article']['id'] = $Article->id;
974
		$Article->set($data);
975
		$this->assertFalse($Article->validates());
976
	}
977
 
978
/**
979
 * Test that 'required' and 'on' are not conflicting
980
 *
981
 * @return void
982
 */
983
	public function testOnRequiredConflictValidation() {
984
		$this->loadFixtures('Article');
985
		$Article = new Article();
986
 
987
		// no title field present
988
		$data = array(
989
			'Article' => array(
990
				'body' => 'Extra Fields Body',
991
				'published' => '1'
992
			)
993
		);
994
 
995
		$Article->validate = array(
996
			'title' => array(
997
				'notBlank' => array(
998
					'rule' => 'notBlank',
999
					'required' => 'create',
1000
					'on' => 'create'
1001
				)
1002
			)
1003
		);
1004
 
1005
		$Article->create($data);
1006
		$this->assertFalse($Article->validates());
1007
 
1008
		$Article->validate = array(
1009
			'title' => array(
1010
				'notBlank' => array(
1011
					'rule' => 'notBlank',
1012
					'required' => 'update',
1013
					'on' => 'create'
1014
				)
1015
			)
1016
		);
1017
 
1018
		$Article->create($data);
1019
		$this->assertTrue($Article->validates());
1020
 
1021
		$Article->validate = array(
1022
			'title' => array(
1023
				'notBlank' => array(
1024
					'rule' => 'notBlank',
1025
					'required' => 'create',
1026
					'on' => 'update'
1027
				)
1028
			)
1029
		);
1030
 
1031
		$Article->create($data);
1032
		$this->assertTrue($Article->validates());
1033
 
1034
		$Article->validate = array(
1035
			'title' => array(
1036
				'notBlank' => array(
1037
					'rule' => 'notBlank',
1038
					'required' => 'update',
1039
					'on' => 'update'
1040
				)
1041
			)
1042
		);
1043
 
1044
		$Article->create($data);
1045
		$this->assertTrue($Article->validates());
1046
 
1047
		$Article->validate = array(
1048
			'title' => array(
1049
				'notBlank' => array(
1050
					'rule' => 'notBlank',
1051
					'required' => 'create',
1052
					'on' => 'create'
1053
				)
1054
			)
1055
		);
1056
 
1057
		$Article->save(null, array('validate' => false));
1058
		$data['Article']['id'] = $Article->id;
1059
		$Article->set($data);
1060
		$this->assertTrue($Article->validates());
1061
 
1062
		$Article->validate = array(
1063
			'title' => array(
1064
				'notBlank' => array(
1065
					'rule' => 'notBlank',
1066
					'required' => 'update',
1067
					'on' => 'create'
1068
				)
1069
			)
1070
		);
1071
 
1072
		$Article->set($data);
1073
		$this->assertTrue($Article->validates());
1074
 
1075
		$Article->validate = array(
1076
			'title' => array(
1077
				'notBlank' => array(
1078
					'rule' => 'notBlank',
1079
					'required' => 'create',
1080
					'on' => 'update'
1081
				)
1082
			)
1083
		);
1084
 
1085
		$Article->set($data);
1086
		$this->assertTrue($Article->validates());
1087
 
1088
		$Article->validate = array(
1089
			'title' => array(
1090
				'notBlank' => array(
1091
					'rule' => 'notBlank',
1092
					'required' => 'update',
1093
					'on' => 'update'
1094
				)
1095
			)
1096
		);
1097
 
1098
		$Article->set($data);
1099
		$this->assertFalse($Article->validates());
1100
	}
1101
 
1102
/**
1103
 * testSaveAllDeepValidateOnly
1104
 * tests the validate methods with deeper recursive data
1105
 *
1106
 * @return void
1107
 */
1108
	public function testSaveAllDeepValidateOnly() {
1109
		$this->loadFixtures('Article', 'Comment', 'User', 'Attachment');
1110
		$TestModel = new Article();
1111
		$TestModel->hasMany['Comment']['order'] = array('Comment.created' => 'ASC');
1112
		$TestModel->hasAndBelongsToMany = array();
1113
		$TestModel->Comment->Attachment->validate['attachment'] = 'notBlank';
1114
		$TestModel->Comment->validate['comment'] = 'notBlank';
1115
 
1116
		$data = array(
1117
			'Article' => array('id' => 2),
1118
			'Comment' => array(
1119
				array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => 'newuser', 'password' => 'newuserpass')),
1120
				array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
1121
			)
1122
		);
1123
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'deep' => true));
1124
		$this->assertTrue($result);
1125
		$result = $TestModel->validateAssociated($data, array('deep' => true));
1126
		$this->assertTrue($result);
1127
 
1128
		$data = array(
1129
			'Article' => array('id' => 2),
1130
			'Comment' => array(
1131
				array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'newuserpass')),
1132
				array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
1133
			)
1134
		);
1135
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'deep' => true));
1136
		$this->assertFalse($result);
1137
		$result = $TestModel->validateAssociated($data, array('deep' => true));
1138
		$this->assertFalse($result);
1139
 
1140
		$data = array(
1141
			'Article' => array('id' => 2),
1142
			'Comment' => array(
1143
				array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => 'newuser', 'password' => 'newuserpass')),
1144
				array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
1145
			)
1146
		);
1147
		$expected = array(
1148
			'Article' => true,
1149
			'Comment' => array(
1150
				true,
1151
				true
1152
			)
1153
		);
1154
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
1155
		$this->assertSame($expected, $result);
1156
		$result = $TestModel->validateAssociated($data, array('atomic' => false, 'deep' => true));
1157
		$this->assertSame($expected, $result);
1158
 
1159
		$data = array(
1160
			'Article' => array('id' => 2),
1161
			'Comment' => array(
1162
				array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'newuserpass')),
1163
				array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
1164
			)
1165
		);
1166
		$expected = array(
1167
			'Article' => true,
1168
			'Comment' => array(
1169
				false,
1170
				true
1171
			)
1172
		);
1173
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
1174
		$this->assertSame($expected, $result);
1175
		$result = $TestModel->validateAssociated($data, array('atomic' => false, 'deep' => true));
1176
		$this->assertSame($expected, $result);
1177
 
1178
		$data = array(
1179
			'Article' => array('id' => 2),
1180
			'Comment' => array(
1181
				array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
1182
				array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => 'deepsaved'))
1183
			)
1184
		);
1185
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'deep' => true));
1186
		$this->assertTrue($result);
1187
		$result = $TestModel->validateAssociated($data, array('deep' => true));
1188
		$this->assertTrue($result);
1189
 
1190
		$data = array(
1191
			'Article' => array('id' => 2),
1192
			'Comment' => array(
1193
				array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
1194
				array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => ''))
1195
			)
1196
		);
1197
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'deep' => true));
1198
		$this->assertFalse($result);
1199
		$result = $TestModel->validateAssociated($data, array('deep' => true));
1200
		$this->assertFalse($result);
1201
 
1202
		$data = array(
1203
			'Article' => array('id' => 2),
1204
			'Comment' => array(
1205
				array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
1206
				array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => 'deepsave'))
1207
			)
1208
		);
1209
		$expected = array(
1210
			'Article' => true,
1211
			'Comment' => array(
1212
				true,
1213
				true
1214
			)
1215
		);
1216
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
1217
		$this->assertSame($expected, $result);
1218
		$result = $TestModel->validateAssociated($data, array('atomic' => false, 'deep' => true));
1219
		$this->assertSame($expected, $result);
1220
 
1221
		$data = array(
1222
			'Article' => array('id' => 2),
1223
			'Comment' => array(
1224
				array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
1225
				array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => ''))
1226
			)
1227
		);
1228
		$expected = array(
1229
			'Article' => true,
1230
			'Comment' => array(
1231
				true,
1232
				false
1233
			)
1234
		);
1235
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
1236
		$this->assertSame($expected, $result);
1237
		$result = $TestModel->validateAssociated($data, array('atomic' => false, 'deep' => true));
1238
		$this->assertSame($expected, $result);
1239
 
1240
		$expected = array(
1241
			'Comment' => array(
1242
				1 => array(
1243
					'Attachment' => array(
1244
						'attachment' => array('This field cannot be left blank')
1245
					)
1246
				)
1247
			)
1248
		);
1249
		$result = $TestModel->validationErrors;
1250
		$this->assertSame($expected, $result);
1251
 
1252
		$data = array(
1253
			'Attachment' => array(
1254
				'attachment' => 'deepsave insert',
1255
			),
1256
			'Comment' => array(
1257
				'comment' => 'First comment deepsave insert',
1258
				'published' => 'Y',
1259
				'user_id' => 5,
1260
				'Article' => array(
1261
					'title' => 'First Article deepsave insert',
1262
					'body' => 'First Article Body deepsave insert',
1263
					'User' => array(
1264
						'user' => 'deepsave',
1265
						'password' => 'magic'
1266
					),
1267
				),
1268
			)
1269
		);
1270
 
1271
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => true));
1272
		$this->assertTrue($result);
1273
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('deep' => true));
1274
		$this->assertTrue($result);
1275
 
1276
		$expected = array(
1277
			'Attachment' => true,
1278
			'Comment' => true
1279
		);
1280
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
1281
		$this->assertSame($expected, $result);
1282
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('atomic' => false, 'deep' => true));
1283
		$this->assertSame($expected, $result);
1284
 
1285
		$data = array(
1286
			'Attachment' => array(
1287
				'attachment' => 'deepsave insert',
1288
			),
1289
			'Comment' => array(
1290
				'comment' => 'First comment deepsave insert',
1291
				'published' => 'Y',
1292
				'user_id' => 5,
1293
				'Article' => array(
1294
					'title' => 'First Article deepsave insert',
1295
					'body' => 'First Article Body deepsave insert',
1296
					'User' => array(
1297
						'user' => '',
1298
						'password' => 'magic'
1299
					),
1300
				),
1301
			)
1302
		);
1303
 
1304
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => true));
1305
		$this->assertFalse($result);
1306
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('deep' => true));
1307
		$this->assertFalse($result);
1308
 
1309
		$result = $TestModel->Comment->Attachment->validationErrors;
1310
		$expected = array(
1311
			'Comment' => array(
1312
				'Article' => array(
1313
					'User' => array(
1314
						'user' => array('This field cannot be left blank')
1315
					)
1316
				)
1317
			)
1318
		);
1319
		$this->assertSame($expected, $result);
1320
 
1321
		$expected = array(
1322
			'Attachment' => true,
1323
			'Comment' => false
1324
		);
1325
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
1326
		$this->assertEquals($expected, $result);
1327
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('atomic' => false, 'deep' => true));
1328
		$this->assertEquals($expected, $result);
1329
 
1330
		$data['Comment']['Article']['body'] = '';
1331
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => true));
1332
		$this->assertFalse($result);
1333
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('deep' => true));
1334
		$this->assertFalse($result);
1335
 
1336
		$result = $TestModel->Comment->Attachment->validationErrors;
1337
		$expected = array(
1338
			'Comment' => array(
1339
				'Article' => array(
1340
					'body' => array('This field cannot be left blank'),
1341
					'User' => array(
1342
						'user' => array('This field cannot be left blank')
1343
					)
1344
				)
1345
			)
1346
		);
1347
		$this->assertSame($expected, $result);
1348
 
1349
		$expected = array(
1350
			'Attachment' => true,
1351
			'Comment' => false
1352
		);
1353
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
1354
		$this->assertEquals($expected, $result);
1355
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('atomic' => false, 'deep' => true));
1356
		$this->assertEquals($expected, $result);
1357
 
1358
		$data['Comment']['comment'] = '';
1359
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => true));
1360
		$this->assertFalse($result);
1361
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('deep' => true));
1362
		$this->assertFalse($result);
1363
 
1364
		$result = $TestModel->Comment->Attachment->validationErrors;
1365
		$expected = array(
1366
			'Comment' => array(
1367
				'comment' => array('This field cannot be left blank'),
1368
				'Article' => array(
1369
					'body' => array('This field cannot be left blank'),
1370
					'User' => array(
1371
						'user' => array('This field cannot be left blank')
1372
					)
1373
				)
1374
			)
1375
		);
1376
		$this->assertSame($expected, $result);
1377
 
1378
		$expected = array(
1379
			'Attachment' => true,
1380
			'Comment' => false
1381
		);
1382
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
1383
		$this->assertEquals($expected, $result);
1384
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('atomic' => false, 'deep' => true));
1385
		$this->assertEquals($expected, $result);
1386
 
1387
		$data['Attachment']['attachment'] = '';
1388
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => true));
1389
		$this->assertFalse($result);
1390
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('deep' => true));
1391
		$this->assertFalse($result);
1392
 
1393
		$result = $TestModel->Comment->Attachment->validationErrors;
1394
		$expected = array(
1395
			'attachment' => array('This field cannot be left blank'),
1396
			'Comment' => array(
1397
				'comment' => array('This field cannot be left blank'),
1398
				'Article' => array(
1399
					'body' => array('This field cannot be left blank'),
1400
					'User' => array(
1401
						'user' => array('This field cannot be left blank')
1402
					)
1403
				)
1404
			)
1405
		);
1406
		$this->assertSame($expected, $result);
1407
 
1408
		$result = $TestModel->Comment->validationErrors;
1409
		$expected = array(
1410
			'comment' => array('This field cannot be left blank'),
1411
			'Article' => array(
1412
					'body' => array('This field cannot be left blank'),
1413
					'User' => array(
1414
						'user' => array('This field cannot be left blank')
1415
					)
1416
				)
1417
		);
1418
		$this->assertSame($expected, $result);
1419
 
1420
		$expected = array(
1421
			'Attachment' => false,
1422
			'Comment' => false
1423
		);
1424
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => true));
1425
		$this->assertEquals($expected, $result);
1426
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('atomic' => false, 'deep' => true));
1427
		$this->assertEquals($expected, $result);
1428
	}
1429
 
1430
/**
1431
 * testSaveAllNotDeepValidateOnly
1432
 * tests the validate methods to not validate deeper recursive data
1433
 *
1434
 * @return void
1435
 */
1436
	public function testSaveAllNotDeepValidateOnly() {
1437
		$this->loadFixtures('Article', 'Comment', 'User', 'Attachment');
1438
		$TestModel = new Article();
1439
		$TestModel->hasMany['Comment']['order'] = array('Comment.created' => 'ASC');
1440
		$TestModel->hasAndBelongsToMany = array();
1441
		$TestModel->Comment->Attachment->validate['attachment'] = 'notBlank';
1442
		$TestModel->Comment->validate['comment'] = 'notBlank';
1443
 
1444
		$data = array(
1445
			'Article' => array('id' => 2, 'body' => ''),
1446
			'Comment' => array(
1447
				array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'newuserpass')),
1448
				array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
1449
			)
1450
		);
1451
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'deep' => false));
1452
		$this->assertFalse($result);
1453
		$result = $TestModel->validateAssociated($data, array('deep' => false));
1454
		$this->assertFalse($result);
1455
 
1456
		$expected = array('body' => array('This field cannot be left blank'));
1457
		$result = $TestModel->validationErrors;
1458
		$this->assertSame($expected, $result);
1459
 
1460
		$data = array(
1461
			'Article' => array('id' => 2, 'body' => 'Ignore invalid user data'),
1462
			'Comment' => array(
1463
				array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'newuserpass')),
1464
				array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
1465
			)
1466
		);
1467
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'deep' => false));
1468
		$this->assertTrue($result);
1469
		$result = $TestModel->validateAssociated($data, array('deep' => false));
1470
		$this->assertTrue($result);
1471
 
1472
		$data = array(
1473
			'Article' => array('id' => 2, 'body' => 'Ignore invalid user data'),
1474
			'Comment' => array(
1475
				array('comment' => 'First new comment', 'published' => 'Y', 'User' => array('user' => '', 'password' => 'newuserpass')),
1476
				array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
1477
			)
1478
		);
1479
		$expected = array(
1480
			'Article' => true,
1481
			'Comment' => array(
1482
				true,
1483
				true
1484
			)
1485
		);
1486
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => false));
1487
		$this->assertSame($expected, $result);
1488
		$result = $TestModel->validateAssociated($data, array('atomic' => false, 'deep' => false));
1489
		$this->assertSame($expected, $result);
1490
 
1491
		$data = array(
1492
			'Article' => array('id' => 2, 'body' => 'Ignore invalid attachment data'),
1493
			'Comment' => array(
1494
				array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
1495
				array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => ''))
1496
			)
1497
		);
1498
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'deep' => false));
1499
		$this->assertTrue($result);
1500
		$result = $TestModel->validateAssociated($data, array('deep' => false));
1501
		$this->assertTrue($result);
1502
 
1503
		$data = array(
1504
			'Article' => array('id' => 2, 'body' => 'Ignore invalid attachment data'),
1505
			'Comment' => array(
1506
				array('comment' => 'Third new comment', 'published' => 'Y', 'user_id' => 5),
1507
				array('comment' => 'Fourth new comment', 'published' => 'Y', 'user_id' => 2, 'Attachment' => array('attachment' => ''))
1508
			)
1509
		);
1510
		$expected = array(
1511
			'Article' => true,
1512
			'Comment' => array(
1513
				true,
1514
				true
1515
			)
1516
		);
1517
		$result = $TestModel->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => false));
1518
		$this->assertSame($expected, $result);
1519
		$result = $TestModel->validateAssociated($data, array('atomic' => false, 'deep' => false));
1520
		$this->assertSame($expected, $result);
1521
 
1522
		$expected = array();
1523
		$result = $TestModel->validationErrors;
1524
		$this->assertSame($expected, $result);
1525
 
1526
		$data = array(
1527
			'Attachment' => array(
1528
				'attachment' => 'deepsave insert',
1529
			),
1530
			'Comment' => array(
1531
				'comment' => 'First comment deepsave insert',
1532
				'published' => 'Y',
1533
				'user_id' => 5,
1534
				'Article' => array(
1535
					'title' => 'First Article deepsave insert ignored',
1536
					'body' => 'First Article Body deepsave insert',
1537
					'User' => array(
1538
						'user' => '',
1539
						'password' => 'magic'
1540
					),
1541
				),
1542
			)
1543
		);
1544
 
1545
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => false));
1546
		$this->assertTrue($result);
1547
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('deep' => false));
1548
		$this->assertTrue($result);
1549
 
1550
		$result = $TestModel->Comment->Attachment->validationErrors;
1551
		$expected = array();
1552
		$this->assertSame($expected, $result);
1553
 
1554
		$expected = array(
1555
			'Attachment' => true,
1556
			'Comment' => true
1557
		);
1558
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => false));
1559
		$this->assertEquals($expected, $result);
1560
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('atomic' => false, 'deep' => false));
1561
		$this->assertEquals($expected, $result);
1562
 
1563
		$data['Comment']['Article']['body'] = '';
1564
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'deep' => false));
1565
		$this->assertTrue($result);
1566
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('deep' => false));
1567
		$this->assertTrue($result);
1568
 
1569
		$result = $TestModel->Comment->Attachment->validationErrors;
1570
		$expected = array();
1571
		$this->assertSame($expected, $result);
1572
 
1573
		$expected = array(
1574
			'Attachment' => true,
1575
			'Comment' => true
1576
		);
1577
		$result = $TestModel->Comment->Attachment->saveAll($data, array('validate' => 'only', 'atomic' => false, 'deep' => false));
1578
		$this->assertEquals($expected, $result);
1579
		$result = $TestModel->Comment->Attachment->validateAssociated($data, array('atomic' => false, 'deep' => false));
1580
		$this->assertEquals($expected, $result);
1581
	}
1582
 
1583
/**
1584
 * testValidateAssociated method
1585
 *
1586
 * @return void
1587
 */
1588
	public function testValidateAssociated() {
1589
		$this->loadFixtures('Comment', 'Attachment', 'Article', 'User');
1590
		$TestModel = new Comment();
1591
		$TestModel->Attachment->validate = array('attachment' => 'notBlank');
1592
 
1593
		$data = array(
1594
			'Comment' => array(
1595
				'comment' => 'This is the comment'
1596
			),
1597
			'Attachment' => array(
1598
				'attachment' => ''
1599
			)
1600
		);
1601
		$result = $TestModel->saveAll($data, array('validate' => 'only'));
1602
		$this->assertFalse($result);
1603
		$result = $TestModel->validateAssociated($data);
1604
		$this->assertFalse($result);
1605
 
1606
		$fieldList = array(
1607
			'Attachment' => array('comment_id')
1608
		);
1609
		$result = $TestModel->saveAll($data, array(
1610
			'fieldList' => $fieldList, 'validate' => 'only'
1611
		));
1612
		$this->assertTrue($result);
1613
		$this->assertEmpty($TestModel->validationErrors);
1614
		$result = $TestModel->validateAssociated($data, array('fieldList' => $fieldList));
1615
		$this->assertTrue($result);
1616
		$this->assertEmpty($TestModel->validationErrors);
1617
 
1618
		$TestModel->validate = array('comment' => 'notBlank');
1619
		$record = array(
1620
			'Comment' => array(
1621
				'user_id' => 1,
1622
				'article_id' => 1,
1623
				'comment' => '',
1624
			),
1625
			'Attachment' => array(
1626
				'attachment' => ''
1627
			)
1628
		);
1629
		$result = $TestModel->saveAll($record, array('validate' => 'only'));
1630
		$this->assertFalse($result);
1631
		$result = $TestModel->validateAssociated($record);
1632
		$this->assertFalse($result);
1633
 
1634
		$fieldList = array(
1635
			'Comment' => array('id', 'article_id', 'user_id'),
1636
			'Attachment' => array('comment_id')
1637
		);
1638
		$result = $TestModel->saveAll($record, array(
1639
			'fieldList' => $fieldList, 'validate' => 'only'
1640
		));
1641
		$this->assertTrue($result);
1642
		$this->assertEmpty($TestModel->validationErrors);
1643
		$result = $TestModel->validateAssociated($record, array('fieldList' => $fieldList));
1644
		$this->assertTrue($result);
1645
		$this->assertEmpty($TestModel->validationErrors);
1646
 
1647
		$TestModel = new Article();
1648
		$TestModel->belongsTo = $TestModel->hasAndBelongsToMany = array();
1649
		$TestModel->Comment->validate = array('comment' => 'notBlank');
1650
		$data = array(
1651
			'Article' => array('id' => 2),
1652
			'Comment' => array(
1653
				array(
1654
					'id' => 1,
1655
					'comment' => '',
1656
					'published' => 'Y',
1657
					'user_id' => 1,
1658
				),
1659
				array(
1660
					'id' => 2,
1661
					'comment' =>
1662
					'comment',
1663
					'published' => 'Y',
1664
					'user_id' => 1
1665
				),
1666
				array(
1667
					'id' => 3,
1668
					'comment' => '',
1669
					'published' => 'Y',
1670
					'user_id' => 1
1671
		)));
1672
		$result = $TestModel->saveAll($data, array('validate' => 'only'));
1673
		$this->assertFalse($result);
1674
		$result = $TestModel->validateAssociated($data);
1675
		$this->assertFalse($result);
1676
 
1677
		$expected = array(
1678
			'Article' => true,
1679
			'Comment' => array(false, true, false)
1680
		);
1681
		$result = $TestModel->saveAll($data, array('atomic' => false, 'validate' => 'only'));
1682
		$this->assertSame($expected, $result);
1683
		$result = $TestModel->validateAssociated($data, array('atomic' => false));
1684
		$this->assertSame($expected, $result);
1685
 
1686
		$expected = array('Comment' => array(
1687
 
1688
			2 => array('comment' => array('This field cannot be left blank'))
1689
		));
1690
		$this->assertEquals($expected['Comment'], $TestModel->Comment->validationErrors);
1691
 
1692
		$model = new Comment();
1693
		$model->deleteAll(true);
1694
		$model->validate = array('comment' => 'notBlank');
1695
		$model->Attachment->validate = array('attachment' => 'notBlank');
1696
		$model->Attachment->bindModel(array('belongsTo' => array('Comment')));
1697
		$expected = array(
1698
			'comment' => array('This field cannot be left blank'),
1699
			'Attachment' => array(
1700
				'attachment' => array('This field cannot be left blank')
1701
			)
1702
		);
1703
 
1704
		$data = array(
1705
			'Comment' => array('comment' => '', 'article_id' => 1, 'user_id' => 1),
1706
			'Attachment' => array('attachment' => '')
1707
		);
1708
		$result = $model->saveAll($data, array('validate' => 'only'));
1709
		$this->assertFalse($result);
1710
		$result = $model->validateAssociated($data);
1711
		$this->assertFalse($result);
1712
		$this->assertEquals($expected, $model->validationErrors);
1713
		$this->assertEquals($expected['Attachment'], $model->Attachment->validationErrors);
1714
	}
1715
 
1716
/**
1717
 * testValidateMany method
1718
 *
1719
 * @return void
1720
 */
1721
	public function testValidateMany() {
1722
		$TestModel = new Article();
1723
		$TestModel->validate = array('title' => 'notBlank');
1724
		$data = array(
1725
 
1726
			1 => array('title' => 'title 1'),
1727
			2 => array('title' => 'title 2'),
1728
		);
1729
		$expected = array(
1730
 
1731
		);
1732
 
1733
		$result = $TestModel->saveAll($data, array('validate' => 'only'));
1734
		$this->assertFalse($result);
1735
		$this->assertEquals($expected, $TestModel->validationErrors);
1736
		$result = $TestModel->validateMany($data);
1737
		$this->assertFalse($result);
1738
		$this->assertEquals($expected, $TestModel->validationErrors);
1739
 
1740
		$data = array(
1741
 
1742
			1 => array('title' => ''),
1743
			2 => array('title' => 'title 2'),
1744
		);
1745
		$expected = array(
1746
			1 => array('title' => array('This field cannot be left blank')),
1747
		);
1748
		$result = $TestModel->saveAll($data, array('validate' => 'only'));
1749
		$this->assertFalse($result);
1750
		$this->assertEquals($expected, $TestModel->validationErrors);
1751
		$result = $TestModel->validateMany($data);
1752
		$this->assertFalse($result);
1753
		$this->assertEquals($expected, $TestModel->validationErrors);
1754
	}
1755
 
1756
/**
1757
 * testGetMethods method
1758
 *
1759
 * @return void
1760
 */
1761
	public function testGetMethods() {
1762
		$this->loadFixtures('Article', 'Comment');
1763
		$TestModel = new Article();
1764
		$Validator = $TestModel->validator();
1765
 
1766
		$result = $Validator->getMethods();
1767
 
1768
		$expected = array_map('strtolower', get_class_methods('Article'));
1769
		$this->assertEquals($expected, array_keys($result));
1770
	}
1771
 
1772
/**
1773
 *  Tests that methods are refreshed when the list of behaviors change
1774
 *
1775
 * @return void
1776
 */
1777
	public function testGetMethodsRefresh() {
1778
		$this->loadFixtures('Article', 'Comment');
1779
		$TestModel = new Article();
1780
		$Validator = $TestModel->validator();
1781
 
1782
		$result = $Validator->getMethods();
1783
 
1784
		$expected = array_map('strtolower', get_class_methods('Article'));
1785
		$this->assertEquals($expected, array_keys($result));
1786
 
1787
		$TestModel->Behaviors->load('Containable');
1788
		$newList = array(
1789
			'contain',
1790
			'resetbindings',
1791
			'containments',
1792
			'fielddependencies',
1793
			'containmentsmap'
1794
		);
1795
		$this->assertEquals(array_merge($expected, $newList), array_keys($Validator->getMethods()));
1796
 
1797
		$TestModel->Behaviors->unload('Containable');
1798
		$this->assertEquals($expected, array_keys($Validator->getMethods()));
1799
	}
1800
 
1801
/**
1802
 * testSetValidationDomain method
1803
 *
1804
 * @return void
1805
 */
1806
	public function testSetValidationDomain() {
1807
		$this->loadFixtures('Article', 'Comment');
1808
		$TestModel = new Article();
1809
		$Validator = $TestModel->validator();
1810
 
1811
		$result = $Validator->setValidationDomain('default');
1812
		$this->assertEquals('default', $TestModel->validationDomain);
1813
 
1814
		$result = $Validator->setValidationDomain('other');
1815
		$this->assertEquals('other', $TestModel->validationDomain);
1816
	}
1817
 
1818
/**
1819
 * testGetModel method
1820
 *
1821
 * @return void
1822
 */
1823
	public function testGetModel() {
1824
		$TestModel = new Article();
1825
		$Validator = $TestModel->validator();
1826
 
1827
		$result = $Validator->getModel();
1828
		$this->assertInstanceOf('Article', $result);
1829
	}
1830
 
1831
/**
1832
 * Tests it is possible to get validation sets for a field using an array inteface
1833
 *
1834
 * @return void
1835
 */
1836
	public function testArrayAccessGet() {
1837
		$TestModel = new Article();
1838
		$Validator = $TestModel->validator();
1839
 
1840
		$titleValidator = $Validator['title'];
1841
		$this->assertEquals('title', $titleValidator->field);
1842
		$this->assertCount(1, $titleValidator->getRules());
1843
		$rule = current($titleValidator->getRules());
1844
		$this->assertEquals('notBlank', $rule->rule);
1845
 
1846
		$titleValidator = $Validator['body'];
1847
		$this->assertEquals('body', $titleValidator->field);
1848
		$this->assertCount(1, $titleValidator->getRules());
1849
		$rule = current($titleValidator->getRules());
1850
		$this->assertEquals('notBlank', $rule->rule);
1851
 
1852
		$titleValidator = $Validator['user_id'];
1853
		$this->assertEquals('user_id', $titleValidator->field);
1854
		$this->assertCount(1, $titleValidator->getRules());
1855
		$rule = current($titleValidator->getRules());
1856
		$this->assertEquals('numeric', $rule->rule);
1857
	}
1858
 
1859
/**
1860
 * Tests it is possible to check for validation sets for a field using an array inteface
1861
 *
1862
 * @return void
1863
 */
1864
	public function testArrayAccessExists() {
1865
		$TestModel = new Article();
1866
		$Validator = $TestModel->validator();
1867
 
1868
		$this->assertTrue(isset($Validator['title']));
1869
		$this->assertTrue(isset($Validator['body']));
1870
		$this->assertTrue(isset($Validator['user_id']));
1871
		$this->assertFalse(isset($Validator['other']));
1872
	}
1873
 
1874
/**
1875
 * Tests it is possible to set validation rules for a field using an array inteface
1876
 *
1877
 * @return void
1878
 */
1879
	public function testArrayAccessSet() {
1880
		$TestModel = new Article();
1881
		$Validator = $TestModel->validator();
1882
 
1883
		$set = array(
1884
			'numeric' => array('rule' => 'numeric', 'allowEmpty' => false),
1885
			'between' => array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false),
1886
		);
1887
		$Validator['other'] = $set;
1888
		$rules = $Validator['other'];
1889
		$this->assertEquals('other', $rules->field);
1890
 
1891
		$validators = $rules->getRules();
1892
		$this->assertCount(2, $validators);
1893
		$this->assertEquals('numeric', $validators['numeric']->rule);
1894
		$this->assertEquals(array('lengthBetween', 1, 5), $validators['between']->rule);
1895
 
1896
		$Validator['new'] = new CakeValidationSet('new', $set, array());
1897
		$rules = $Validator['new'];
1898
		$this->assertEquals('new', $rules->field);
1899
 
1900
		$validators = $rules->getRules();
1901
		$this->assertCount(2, $validators);
1902
		$this->assertEquals('numeric', $validators['numeric']->rule);
1903
		$this->assertEquals(array('lengthBetween', 1, 5), $validators['between']->rule);
1904
	}
1905
 
1906
/**
1907
 * Tests it is possible to unset validation rules
1908
 *
1909
 * @return void
1910
 */
1911
	public function testArrayAccessUset() {
1912
		$TestModel = new Article();
1913
		$Validator = $TestModel->validator();
1914
 
1915
		$this->assertTrue(isset($Validator['title']));
1916
		unset($Validator['title']);
1917
		$this->assertFalse(isset($Validator['title']));
1918
	}
1919
 
1920
/**
1921
 * Tests it is possible to iterate a validation object
1922
 *
1923
 * @return void
1924
 */
1925
	public function testIterator() {
1926
		$TestModel = new Article();
1927
		$Validator = $TestModel->validator();
1928
 
1929
		$i = 0;
1930
		foreach ($Validator as $field => $rules) {
1931
			if ($i === 0) {
1932
				$this->assertEquals('user_id', $field);
1933
			}
1934
			if ($i === 1) {
1935
				$this->assertEquals('title', $field);
1936
			}
1937
			if ($i === 2) {
1938
				$this->assertEquals('body', $field);
1939
			}
1940
			$this->assertInstanceOf('CakeValidationSet', $rules);
1941
			$i++;
1942
		}
1943
		$this->assertEquals(3, $i);
1944
	}
1945
 
1946
/**
1947
 * Tests countable interface in ModelValidator
1948
 *
1949
 * @return void
1950
 */
1951
	public function testCount() {
1952
		$TestModel = new Article();
1953
		$Validator = $TestModel->validator();
1954
		$this->assertCount(3, $Validator);
1955
 
1956
		$set = array(
1957
			'numeric' => array('rule' => 'numeric', 'allowEmpty' => false),
1958
			'range' => array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false),
1959
		);
1960
		$Validator['other'] = $set;
1961
		$this->assertCount(4, $Validator);
1962
 
1963
		unset($Validator['title']);
1964
		$this->assertCount(3, $Validator);
1965
		unset($Validator['body']);
1966
		$this->assertCount(2, $Validator);
1967
	}
1968
 
1969
/**
1970
 * Tests it is possible to add validation rules
1971
 *
1972
 * @return void
1973
 */
1974
	public function testAddRule() {
1975
		$TestModel = new Article();
1976
		$Validator = $TestModel->validator();
1977
 
1978
		$Validator->add('other', 'numeric', array('rule' => 'numeric', 'allowEmpty' => false));
1979
		$Validator->add('other', 'between', array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false));
1980
		$rules = $Validator['other'];
1981
		$this->assertEquals('other', $rules->field);
1982
 
1983
		$validators = $rules->getRules();
1984
		$this->assertCount(2, $validators);
1985
		$this->assertEquals('numeric', $validators['numeric']->rule);
1986
		$this->assertEquals(array('lengthBetween', 1, 5), $validators['between']->rule);
1987
	}
1988
 
1989
/**
1990
 * Tests it is possible to remove validation rules
1991
 *
1992
 * @return void
1993
 */
1994
	public function testRemoveRule() {
1995
		$TestModel = new Article();
1996
		$Validator = $TestModel->validator();
1997
 
1998
		$this->assertTrue(isset($Validator['title']));
1999
		$Validator->remove('title');
2000
		$this->assertFalse(isset($Validator['title']));
2001
 
2002
		$Validator->add('other', 'numeric', array('rule' => 'numeric', 'allowEmpty' => false));
2003
		$Validator->add('other', 'between', array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false));
2004
		$this->assertTrue(isset($Validator['other']));
2005
 
2006
		$Validator->remove('other', 'numeric');
2007
		$this->assertTrue(isset($Validator['other']));
2008
		$this->assertFalse(isset($Validator['other']['numeric']));
2009
		$this->assertTrue(isset($Validator['other']['between']));
2010
	}
2011
 
2012
/**
2013
 * Tests validation callbacks are triggered
2014
 *
2015
 * @return void
2016
 */
2017
	public function testValidateCallbacks() {
2018
		$TestModel = $this->getMock('Article', array('beforeValidate', 'afterValidate'));
2019
		$TestModel->expects($this->once())->method('beforeValidate');
2020
		$TestModel->expects($this->once())->method('afterValidate');
2021
 
2022
		$TestModel->set(array('title' => '', 'body' => 'body'));
2023
		$TestModel->validates();
2024
	}
2025
 
2026
/**
2027
 * Tests that altering data in a beforeValidate callback will lead to saving those
2028
 * values in database
2029
 *
2030
 * @return void
2031
 */
2032
	public function testValidateFirstWithBeforeValidate() {
2033
		$this->loadFixtures('Article', 'User');
2034
		$model = new CustomArticle();
2035
		$model->validate = array(
2036
			'title' => array(
2037
				'notBlank' => array(
2038
					'rule' => 'notBlank',
2039
					'required' => true,
2040
					'allowEmpty' => false
2041
				)
2042
			)
2043
		);
2044
		$data = array(
2045
			'CustomArticle' => array(
2046
				'body' => 'foo0'
2047
			)
2048
		);
2049
		$result = $model->saveAll($data, array('validate' => 'first'));
2050
		$this->assertTrue($result);
2051
 
2052
		$this->assertFalse($model->findMethods['unPublished'], 'beforeValidate was run twice');
2053
 
2054
		$model->findMethods['unPublished'] = true;
2055
		$data = array(
2056
			'CustomArticle' => array(
2057
				'body' => 'foo1'
2058
			)
2059
		);
2060
		$result = $model->saveAll($data, array('validate' => 'first', 'deep' => true));
2061
		$this->assertTrue($result);
2062
		$title = $model->field('title', array('body' => 'foo1'));
2063
		$this->assertEquals('foo', $title);
2064
		$this->assertFalse($model->findMethods['unPublished'], 'beforeValidate was run twice');
2065
 
2066
		$data = array(
2067
			array('body' => 'foo2'),
2068
			array('body' => 'foo3'),
2069
			array('body' => 'foo4')
2070
		);
2071
 
2072
		$result = $model->saveAll($data, array('validate' => 'first', 'deep' => true));
2073
		$this->assertTrue($result);
2074
 
2075
		$this->assertEquals('foo', $model->field('title', array('body' => 'foo2')));
2076
		$this->assertEquals('foo', $model->field('title', array('body' => 'foo3')));
2077
		$this->assertEquals('foo', $model->field('title', array('body' => 'foo4')));
2078
	}
2079
 
2080
/**
2081
 * Tests that altering data in a beforeValidate callback will lead to saving those
2082
 * values in database
2083
 *
2084
 * @return void
2085
 */
2086
	public function testValidateFirstAssociatedWithBeforeValidate() {
2087
		$this->loadFixtures('Article', 'User');
2088
		$model = new CustomArticle();
2089
		$model->validate = array(
2090
			'title' => array(
2091
				'notBlank' => array(
2092
					'rule' => 'notBlank',
2093
					'required' => true
2094
				)
2095
			)
2096
		);
2097
		$articles = array(
2098
			array('body' => 'foo1'),
2099
			array('body' => 'foo2'),
2100
			array('body' => 'foo3')
2101
		);
2102
		$user = new User();
2103
		$user->bindModel(array('hasMany' => array('CustomArticle')));
2104
		$data = array(
2105
			'User' => array('user' => 'foo', 'password' => 'bar'),
2106
			'CustomArticle' => $articles
2107
		);
2108
		$result = $user->saveAll($data, array('validate' => 'first'));
2109
		$this->assertTrue($result);
2110
 
2111
		$this->assertEquals('foo', $model->field('title', array('body' => 'foo1')));
2112
		$this->assertEquals('foo', $model->field('title', array('body' => 'foo2')));
2113
		$this->assertEquals('foo', $model->field('title', array('body' => 'foo3')));
2114
	}
2115
 
2116
/**
2117
 * testValidateFirstWithDefaults method
2118
 *
2119
 * @return void
2120
 */
2121
	public function testFirstWithDefaults() {
2122
		$this->loadFixtures('Article', 'Tag', 'Comment', 'User', 'ArticlesTag');
2123
		$TestModel = new Article();
2124
 
2125
		$result = $TestModel->find('first', array(
2126
			'conditions' => array('Article.id' => 1)
2127
		));
2128
		$expected = array(
2129
			'Article' => array(
2130
				'id' => 1,
2131
				'user_id' => 1,
2132
				'title' => 'First Article',
2133
				'body' => 'First Article Body',
2134
				'published' => 'Y',
2135
				'created' => '2007-03-18 10:39:23'
2136
			),
2137
		);
2138
		unset($result['Article']['updated']);
2139
		$this->assertEquals($expected['Article'], $result['Article']);
2140
 
2141
		$data = array(
2142
			'Article' => array(
2143
				'id' => 1,
2144
				'title' => 'First Article (modified)'
2145
			),
2146
			'Comment' => array(
2147
				array('comment' => 'Article comment', 'user_id' => 1)
2148
			)
2149
		);
2150
		$result = $TestModel->saveAll($data, array('validate' => 'first'));
2151
		$this->assertTrue($result);
2152
 
2153
		$result = $TestModel->find('first', array(
2154
			'conditions' => array('Article.id' => 1)
2155
		));
2156
		$expected['Article']['title'] = 'First Article (modified)';
2157
		unset($result['Article']['updated']);
2158
		$this->assertEquals($expected['Article'], $result['Article']);
2159
	}
2160
 
2161
	public function testAddMultipleRules() {
2162
		$TestModel = new Article();
2163
		$Validator = $TestModel->validator();
2164
 
2165
		$set = array(
2166
			'numeric' => array('rule' => 'numeric', 'allowEmpty' => false),
2167
			'between' => array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false),
2168
		);
2169
 
2170
		$Validator->add('other', $set);
2171
		$rules = $Validator['other'];
2172
		$this->assertEquals('other', $rules->field);
2173
 
2174
		$validators = $rules->getRules();
2175
		$this->assertCount(2, $validators);
2176
		$this->assertEquals('numeric', $validators['numeric']->rule);
2177
		$this->assertEquals(array('lengthBetween', 1, 5), $validators['between']->rule);
2178
 
2179
		$set = new CakeValidationSet('other', array(
2180
			'a' => array('rule' => 'numeric', 'allowEmpty' => false),
2181
			'b' => array('rule' => array('lengthBetween', 1, 5), 'allowEmpty' => false),
2182
		));
2183
 
2184
		$Validator->add('other', $set);
2185
		$this->assertSame($set, $Validator->getField('other'));
2186
	}
2187
 
2188
/**
2189
 * Test that rules are parsed correctly when calling getField()
2190
 *
2191
 * @return void
2192
 */
2193
	public function testValidator() {
2194
		$TestModel = new Article();
2195
		$Validator = $TestModel->validator();
2196
 
2197
		$result = $Validator->getField();
2198
		$expected = array('user_id', 'title', 'body');
2199
		$this->assertEquals($expected, array_keys($result));
2200
		$this->assertTrue($result['user_id'] instanceof CakeValidationSet);
2201
 
2202
		$result = $TestModel->validator()->getField('title');
2203
		$this->assertTrue($result instanceof CakeValidationSet);
2204
	}
2205
 
2206
/**
2207
 * Test that validator override works as expected
2208
 *
2209
 * @return void
2210
 */
2211
	public function testValidatorOverride() {
2212
		$TestModel = new Article();
2213
		$ValidatorA = new ModelValidator($TestModel);
2214
		$ValidatorB = new ModelValidator($TestModel);
2215
 
2216
		$TestModel->validator($ValidatorA);
2217
		$TestModel->validator($ValidatorB);
2218
 
2219
		$this->assertSame($ValidatorB, $TestModel->validator());
2220
		$this->assertNotSame($ValidatorA, $TestModel->validator());
2221
	}
2222
 
2223
/**
2224
 * Test that type hint exception is thrown
2225
 *
2226
 * @expectedException PHPUnit_Framework_Error
2227
 * @return void
2228
 */
2229
	public function testValidatorTypehintException() {
2230
		new ModelValidator('asdasds');
2231
	}
2232
 
2233
/**
2234
 * Tests that altering data in a beforeValidate callback will lead to saving those
2235
 * values in database, this time with belongsTo associations
2236
 *
2237
 * @return void
2238
 */
2239
	public function testValidateFirstAssociatedWithBeforeValidate2() {
2240
		$this->loadFixtures('Article', 'User');
2241
		$model = new CustomArticle();
2242
		$model->validate = array(
2243
			'title' => array(
2244
				'notBlank' => array(
2245
					'rule' => 'notBlank',
2246
					'required' => true
2247
				)
2248
			)
2249
		);
2250
 
2251
		$data = array(
2252
			'User' => array('user' => 'foo', 'password' => 'bar'),
2253
			'CustomArticle' => array(
2254
				'body' => 'a test'
2255
			)
2256
		);
2257
		$result = $model->saveAll($data, array('validate' => 'first'));
2258
		$this->assertTrue($result);
2259
 
2260
		$this->assertEquals('foo', $model->field('title', array('body' => 'a test')));
2261
	}
2262
 
2263
/**
2264
 * Testing you can dynamically add rules to a field, added this to dispel doubts
2265
 * after a presentation made to show off this new feature
2266
 *
2267
 * @return void
2268
 */
2269
	public function testDynamicValidationRuleBuilding() {
2270
		$model = new Article;
2271
		$validator = $model->validator();
2272
		$validator->add('body', 'isSpecial', array('rule' => 'special'));
2273
		$rules = $validator['body']->getRules();
2274
		$this->assertCount(2, $rules);
2275
		$this->assertEquals('special', $rules['isSpecial']->rule);
2276
		$validator['body']->setRule('isAwesome', array('rule' => 'awesome'));
2277
		$rules = $validator['body']->getRules();
2278
		$this->assertCount(3, $rules);
2279
		$this->assertEquals('awesome', $rules['isAwesome']->rule);
2280
	}
2281
 
2282
/**
2283
 * Test to ensure custom validation methods work with CakeValidationSet
2284
 *
2285
 * @return void
2286
 */
2287
	public function testCustomMethodsWithCakeValidationSet() {
2288
		$TestModel = new TestValidate();
2289
		$Validator = $TestModel->validator();
2290
 
2291
		$Validator->add('title', 'validateTitle', array(
2292
			'rule' => 'validateTitle',
2293
			'message' => 'That aint right',
2294
		));
2295
		$data = array('title' => 'notatitle');
2296
		$result = $Validator->getField('title')->validate($data);
2297
		$expected = array(0 => 'That aint right');
2298
		$this->assertEquals($expected, $result);
2299
 
2300
		$data = array('title' => 'title-is-good');
2301
		$result = $Validator->getField('title')->validate($data);
2302
		$expected = array();
2303
		$this->assertEquals($expected, $result);
2304
	}
2305
 
2306
	public function testCustomMethodWithEmptyValue() {
2307
		$this->loadFixtures('Article');
2308
 
2309
		$model = $this->getMock('Article', array('isLegit'));
2310
		$model->validate = array(
2311
			'title' => array(
2312
				'custom' => array(
2313
					'rule' => array('isLegit'),
2314
					'message' => 'is no good'
2315
				)
2316
			)
2317
		);
2318
		$model->expects($this->once())
2319
			->method('isLegit')
2320
			->will($this->returnValue(false));
2321
 
2322
		$model->set(array('title' => ''));
2323
		$this->assertFalse($model->validates());
2324
	}
2325
 
2326
/**
2327
 * Test validateAssociated with atomic=false & deep=true
2328
 *
2329
 * @return void
2330
 */
2331
	public function testValidateAssociatedAtomicFalseDeepTrueWithErrors() {
2332
		$this->loadFixtures('Comment', 'Article', 'User', 'Attachment');
2333
		$Attachment = ClassRegistry::init('Attachment');
2334
		$Attachment->Comment->validator()->add('comment', array(
2335
			array('rule' => 'notBlank')
2336
		));
2337
		$Attachment->Comment->User->bindModel(array(
2338
			'hasMany' => array(
2339
				'Article',
2340
				'Comment'
2341
			)),
2342
			false
2343
		);
2344
 
2345
		$data = array(
2346
			'Attachment' => array(
2347
				'attachment' => 'text',
2348
				'Comment' => array(
2349
					'comment' => '',
2350
					'published' => 'N',
2351
					'User' => array(
2352
						'user' => 'Foo',
2353
						'password' => 'mypassword',
2354
						'Comment' => array(
2355
							array(
2356
								'comment' => ''
2357
							)
2358
						)
2359
					)
2360
				)
2361
			)
2362
		);
2363
		$result = $Attachment->validateAssociated($data, array('atomic' => false, 'deep' => true));
2364
 
2365
		$result = $Attachment->validationErrors;
2366
		$expected = array(
2367
			'Comment' => array(
2368
				'comment' => array(
2369
 
2370
				),
2371
				'User' => array(
2372
					'Comment' => array(
2373
 
2374
							'comment' => array(
2375
 
2376
							),
2377
						),
2378
					),
2379
				),
2380
			),
2381
		);
2382
		$this->assertEquals($expected, $result);
2383
	}
2384
 
2385
/**
2386
 * Test validateMany with atomic=false & deep=true
2387
 *
2388
 * @return void
2389
 */
2390
	public function testValidateManyAtomicFalseDeepTrueWithErrors() {
2391
		$this->loadFixtures('Comment', 'Article', 'User');
2392
		$Article = ClassRegistry::init('Article');
2393
		$Article->Comment->validator()->add('comment', array(
2394
			array('rule' => 'notBlank')
2395
		));
2396
 
2397
		$data = array(
2398
			array(
2399
				'Article' => array(
2400
					'user_id' => 1,
2401
					'title' => 'Foo',
2402
					'body' => 'text',
2403
					'published' => 'N'
2404
				),
2405
				'Comment' => array(
2406
					array(
2407
						'user_id' => 1,
2408
						'comment' => 'Baz',
2409
						'published' => 'N',
2410
					)
2411
				),
2412
			),
2413
			array(
2414
				'Article' => array(
2415
					'user_id' => 1,
2416
					'title' => 'Bar',
2417
					'body' => 'text',
2418
					'published' => 'N'
2419
				),
2420
				'Comment' => array(
2421
					array(
2422
						'user_id' => 1,
2423
						'comment' => '',
2424
						'published' => 'N',
2425
					)
2426
				),
2427
			),
2428
		);
2429
		$Article->validateMany($data, array('atomic' => false, 'deep' => true));
2430
 
2431
		$result = $Article->validationErrors;
2432
		$expected = array(
2433
			1 => array(
2434
				'Comment' => array(
2435
 
2436
						'comment' => array(
2437
 
2438
						),
2439
					),
2440
				),
2441
			),
2442
		);
2443
		$this->assertEquals($expected, $result);
2444
	}
2445
 
2446
/**
2447
 * Test the isUnique method when used as a validator for multiple fields.
2448
 *
2449
 * @return void
2450
 */
2451
	public function testIsUniqueValidator() {
2452
		$this->loadFixtures('Article');
2453
		$Article = ClassRegistry::init('Article');
2454
		$Article->validate = array(
2455
			'user_id' => array(
2456
				'duplicate' => array(
2457
					'rule' => array('isUnique', array('user_id', 'title'), false)
2458
				)
2459
			)
2460
		);
2461
		$data = array(
2462
			'user_id' => 1,
2463
			'title' => 'First Article',
2464
		);
2465
		$Article->create($data);
2466
		$this->assertFalse($Article->validates(), 'Contains a dupe');
2467
 
2468
		$data = array(
2469
			'user_id' => 1,
2470
			'title' => 'Unique Article',
2471
		);
2472
		$Article->create($data);
2473
		$this->assertTrue($Article->validates(), 'Should pass');
2474
 
2475
		$Article->validate = array(
2476
			'user_id' => array(
2477
				'duplicate' => array(
2478
					'rule' => array('isUnique', array('user_id', 'title'))
2479
				)
2480
			)
2481
		);
2482
		$data = array(
2483
			'user_id' => 1,
2484
			'title' => 'Unique Article',
2485
		);
2486
		$Article->create($data);
2487
		$this->assertFalse($Article->validates(), 'Should fail, conditions are combined with or');
2488
	}
2489
 
2490
/**
2491
 * Test backward compatibility of the isUnique method when used as a validator for a single field.
2492
 *
2493
 * @return void
2494
 */
2495
	public function testBackwardCompatIsUniqueValidator() {
2496
		$this->loadFixtures('Article');
2497
		$Article = ClassRegistry::init('Article');
2498
		$Article->validate = array(
2499
			'title' => array(
2500
				'duplicate' => array(
2501
					'rule' => 'isUnique',
2502
					'message' => 'Title must be unique',
2503
				),
2504
				'minLength' => array(
2505
					'rule' => array('minLength', 1),
2506
					'message' => 'Title cannot be empty',
2507
				),
2508
			)
2509
		);
2510
		$data = array(
2511
			'title' => 'First Article',
2512
		);
2513
		$data = $Article->create($data);
2514
		$this->assertFalse($Article->validates(), 'Contains a dupe');
2515
	}
2516
 
2517
}
2518
 
2519
/**
2520
 * Behavior for testing validation rules.
2521
 */
2522
class ValidationRuleBehavior extends ModelBehavior {
2523
 
2524
	public function setup(Model $Model, $config = array()) {
2525
		$this->settings[$Model->alias] = $config;
2526
	}
2527
 
2528
	public function beforeValidate(Model $Model, $options = array()) {
2529
		$fields = $this->settings[$Model->alias]['fields'];
2530
		foreach ($fields as $field) {
2531
			$Model->whitelist[] = $field;
2532
		}
2533
	}
2534
 
2535
}