ModelValidationTest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. <?php
  2. /* SVN FILE: $Id: model.test.php 8225 2009-07-08 03:25:30Z mark_story $ */
  3. /**
  4. * ModelValidationTest file
  5. *
  6. * PHP 5
  7. *
  8. * CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
  9. * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  10. *
  11. * Licensed under The MIT License
  12. * Redistributions of files must retain the above copyright notice
  13. *
  14. * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  15. * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
  16. * @package cake.tests.cases.libs.model
  17. * @since CakePHP(tm) v 1.2.0.4206
  18. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  19. */
  20. require_once dirname(__FILE__) . DS . 'ModelTestBase.php';
  21. /**
  22. * ModelValidationTest
  23. *
  24. * @package cake.tests.cases.libs.model.operations
  25. */
  26. class ModelValidationTest extends BaseModelTest {
  27. /**
  28. * Tests validation parameter order in custom validation methods
  29. *
  30. * @access public
  31. * @return void
  32. */
  33. public function testValidationParams() {
  34. $TestModel = new ValidationTest1();
  35. $TestModel->validate['title'] = array(
  36. 'rule' => 'customValidatorWithParams',
  37. 'required' => true
  38. );
  39. $TestModel->create(array('title' => 'foo'));
  40. $TestModel->invalidFields();
  41. $expected = array(
  42. 'data' => array(
  43. 'title' => 'foo'
  44. ),
  45. 'validator' => array(
  46. 'rule' => 'customValidatorWithParams',
  47. 'on' => null,
  48. 'last' => true,
  49. 'allowEmpty' => false,
  50. 'required' => true
  51. ),
  52. 'or' => true,
  53. 'ignore_on_same' => 'id'
  54. );
  55. $this->assertEqual($TestModel->validatorParams, $expected);
  56. $TestModel->validate['title'] = array(
  57. 'rule' => 'customValidatorWithMessage',
  58. 'required' => true
  59. );
  60. $expected = array(
  61. 'title' => array('This field will *never* validate! Muhahaha!')
  62. );
  63. $this->assertEqual($TestModel->invalidFields(), $expected);
  64. $TestModel->validate['title'] = array(
  65. 'rule' => array('customValidatorWithSixParams', 'one', 'two', null, 'four'),
  66. 'required' => true
  67. );
  68. $TestModel->create(array('title' => 'foo'));
  69. $TestModel->invalidFields();
  70. $expected = array(
  71. 'data' => array(
  72. 'title' => 'foo'
  73. ),
  74. 'one' => 'one',
  75. 'two' => 'two',
  76. 'three' => null,
  77. 'four' => 'four',
  78. 'five' => array(
  79. 'rule' => array(1 => 'one', 2 => 'two', 3 => null, 4 => 'four'),
  80. 'on' => null,
  81. 'last' => true,
  82. 'allowEmpty' => false,
  83. 'required' => true
  84. ),
  85. 'six' => 6
  86. );
  87. $this->assertEqual($TestModel->validatorParams, $expected);
  88. $TestModel->validate['title'] = array(
  89. 'rule' => array('customValidatorWithSixParams', 'one', array('two'), null, 'four', array('five' => 5)),
  90. 'required' => true
  91. );
  92. $TestModel->create(array('title' => 'foo'));
  93. $TestModel->invalidFields();
  94. $expected = array(
  95. 'data' => array(
  96. 'title' => 'foo'
  97. ),
  98. 'one' => 'one',
  99. 'two' => array('two'),
  100. 'three' => null,
  101. 'four' => 'four',
  102. 'five' => array('five' => 5),
  103. 'six' => array(
  104. 'rule' => array(1 => 'one', 2 => array('two'), 3 => null, 4 => 'four', 5 => array('five' => 5)),
  105. 'on' => null,
  106. 'last' => true,
  107. 'allowEmpty' => false,
  108. 'required' => true
  109. )
  110. );
  111. $this->assertEqual($TestModel->validatorParams, $expected);
  112. }
  113. /**
  114. * Tests validation parameter fieldList in invalidFields
  115. *
  116. * @access public
  117. * @return void
  118. */
  119. public function testInvalidFieldsWithFieldListParams() {
  120. $TestModel = new ValidationTest1();
  121. $TestModel->validate = $validate = array(
  122. 'title' => array(
  123. 'rule' => 'alphaNumeric',
  124. 'required' => true
  125. ),
  126. 'name' => array(
  127. 'rule' => 'alphaNumeric',
  128. 'required' => true
  129. ));
  130. $TestModel->set(array('title' => '$$', 'name' => '##'));
  131. $TestModel->invalidFields(array('fieldList' => array('title')));
  132. $expected = array(
  133. 'title' => array('This field cannot be left blank')
  134. );
  135. $this->assertEqual($TestModel->validationErrors, $expected);
  136. $TestModel->validationErrors = array();
  137. $TestModel->invalidFields(array('fieldList' => array('name')));
  138. $expected = array(
  139. 'name' => array('This field cannot be left blank')
  140. );
  141. $this->assertEqual($TestModel->validationErrors, $expected);
  142. $TestModel->validationErrors = array();
  143. $TestModel->invalidFields(array('fieldList' => array('name', 'title')));
  144. $expected = array(
  145. 'name' => array('This field cannot be left blank'),
  146. 'title' => array('This field cannot be left blank')
  147. );
  148. $this->assertEqual($TestModel->validationErrors, $expected);
  149. $TestModel->validationErrors = array();
  150. $TestModel->whitelist = array('name');
  151. $TestModel->invalidFields();
  152. $expected = array('name' => array('This field cannot be left blank'));
  153. $this->assertEqual($TestModel->validationErrors, $expected);
  154. $this->assertEqual($TestModel->validate, $validate);
  155. }
  156. /**
  157. * Test that invalidFields() integrates well with save(). And that fieldList can be an empty type.
  158. *
  159. * @return void
  160. */
  161. public function testInvalidFieldsWhitelist() {
  162. $TestModel = new ValidationTest1();
  163. $TestModel->validate = array(
  164. 'title' => array(
  165. 'rule' => 'alphaNumeric',
  166. 'required' => true
  167. ),
  168. 'name' => array(
  169. 'rule' => 'alphaNumeric',
  170. 'required' => true
  171. ));
  172. $TestModel->whitelist = array('name');
  173. $TestModel->save(array('name' => '#$$#', 'title' => '$$$$'));
  174. $expected = array('name' => array('This field cannot be left blank'));
  175. $this->assertEqual($TestModel->validationErrors, $expected);
  176. }
  177. /**
  178. * testValidates method
  179. *
  180. * @access public
  181. * @return void
  182. */
  183. public function testValidates() {
  184. $TestModel = new TestValidate();
  185. $TestModel->validate = array(
  186. 'user_id' => 'numeric',
  187. 'title' => array('allowEmpty' => false, 'rule' => 'notEmpty'),
  188. 'body' => 'notEmpty'
  189. );
  190. $data = array('TestValidate' => array(
  191. 'user_id' => '1',
  192. 'title' => '',
  193. 'body' => 'body'
  194. ));
  195. $result = $TestModel->create($data);
  196. $this->assertEquals($result, $data);
  197. $result = $TestModel->validates();
  198. $this->assertFalse($result);
  199. $data = array('TestValidate' => array(
  200. 'user_id' => '1',
  201. 'title' => 'title',
  202. 'body' => 'body'
  203. ));
  204. $result = $TestModel->create($data) && $TestModel->validates();
  205. $this->assertTrue($result);
  206. $data = array('TestValidate' => array(
  207. 'user_id' => '1',
  208. 'title' => '0',
  209. 'body' => 'body'
  210. ));
  211. $result = $TestModel->create($data);
  212. $this->assertEquals($result, $data);
  213. $result = $TestModel->validates();
  214. $this->assertTrue($result);
  215. $data = array('TestValidate' => array(
  216. 'user_id' => '1',
  217. 'title' => 0,
  218. 'body' => 'body'
  219. ));
  220. $result = $TestModel->create($data);
  221. $this->assertEquals($result, $data);
  222. $result = $TestModel->validates();
  223. $this->assertTrue($result);
  224. $TestModel->validate['modified'] = array('allowEmpty' => true, 'rule' => 'date');
  225. $data = array('TestValidate' => array(
  226. 'user_id' => '1',
  227. 'title' => 0,
  228. 'body' => 'body',
  229. 'modified' => ''
  230. ));
  231. $result = $TestModel->create($data);
  232. $this->assertEquals($result, $data);
  233. $result = $TestModel->validates();
  234. $this->assertTrue($result);
  235. $data = array('TestValidate' => array(
  236. 'user_id' => '1',
  237. 'title' => 0,
  238. 'body' => 'body',
  239. 'modified' => '2007-05-01'
  240. ));
  241. $result = $TestModel->create($data);
  242. $this->assertEquals($result, $data);
  243. $result = $TestModel->validates();
  244. $this->assertTrue($result);
  245. $data = array('TestValidate' => array(
  246. 'user_id' => '1',
  247. 'title' => 0,
  248. 'body' => 'body',
  249. 'modified' => 'invalid-date-here'
  250. ));
  251. $result = $TestModel->create($data);
  252. $this->assertEquals($result, $data);
  253. $result = $TestModel->validates();
  254. $this->assertFalse($result);
  255. $data = array('TestValidate' => array(
  256. 'user_id' => '1',
  257. 'title' => 0,
  258. 'body' => 'body',
  259. 'modified' => 0
  260. ));
  261. $result = $TestModel->create($data);
  262. $this->assertEquals($result, $data);
  263. $result = $TestModel->validates();
  264. $this->assertFalse($result);
  265. $data = array('TestValidate' => array(
  266. 'user_id' => '1',
  267. 'title' => 0,
  268. 'body' => 'body',
  269. 'modified' => '0'
  270. ));
  271. $result = $TestModel->create($data);
  272. $this->assertEquals($result, $data);
  273. $result = $TestModel->validates();
  274. $this->assertFalse($result);
  275. $TestModel->validate['modified'] = array('allowEmpty' => false, 'rule' => 'date');
  276. $data = array('TestValidate' => array('modified' => null));
  277. $result = $TestModel->create($data);
  278. $this->assertEquals($result, $data);
  279. $result = $TestModel->validates();
  280. $this->assertFalse($result);
  281. $data = array('TestValidate' => array('modified' => false));
  282. $result = $TestModel->create($data);
  283. $this->assertEquals($result, $data);
  284. $result = $TestModel->validates();
  285. $this->assertFalse($result);
  286. $data = array('TestValidate' => array('modified' => ''));
  287. $result = $TestModel->create($data);
  288. $this->assertEquals($result, $data);
  289. $result = $TestModel->validates();
  290. $this->assertFalse($result);
  291. $data = array('TestValidate' => array(
  292. 'modified' => '2007-05-01'
  293. ));
  294. $result = $TestModel->create($data);
  295. $this->assertEquals($result, $data);
  296. $result = $TestModel->validates();
  297. $this->assertTrue($result);
  298. $TestModel->validate['slug'] = array('allowEmpty' => false, 'rule' => array('maxLength', 45));
  299. $data = array('TestValidate' => array(
  300. 'user_id' => '1',
  301. 'title' => 0,
  302. 'body' => 'body',
  303. 'slug' => ''
  304. ));
  305. $result = $TestModel->create($data);
  306. $this->assertEquals($result, $data);
  307. $result = $TestModel->validates();
  308. $this->assertFalse($result);
  309. $data = array('TestValidate' => array(
  310. 'user_id' => '1',
  311. 'title' => 0,
  312. 'body' => 'body',
  313. 'slug' => 'slug-right-here'
  314. ));
  315. $result = $TestModel->create($data);
  316. $this->assertEquals($result, $data);
  317. $result = $TestModel->validates();
  318. $this->assertTrue($result);
  319. $data = array('TestValidate' => array(
  320. 'user_id' => '1',
  321. 'title' => 0,
  322. 'body' => 'body',
  323. 'slug' => 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
  324. ));
  325. $result = $TestModel->create($data);
  326. $this->assertEquals($result, $data);
  327. $result = $TestModel->validates();
  328. $this->assertFalse($result);
  329. $TestModel->validate = array(
  330. 'number' => array(
  331. 'rule' => 'validateNumber',
  332. 'min' => 3,
  333. 'max' => 5
  334. ),
  335. 'title' => array(
  336. 'allowEmpty' => false,
  337. 'rule' => 'notEmpty'
  338. ));
  339. $data = array('TestValidate' => array(
  340. 'title' => 'title',
  341. 'number' => '0'
  342. ));
  343. $result = $TestModel->create($data);
  344. $this->assertEquals($result, $data);
  345. $result = $TestModel->validates();
  346. $this->assertFalse($result);
  347. $data = array('TestValidate' => array(
  348. 'title' => 'title',
  349. 'number' => 0
  350. ));
  351. $result = $TestModel->create($data);
  352. $this->assertEquals($result, $data);
  353. $result = $TestModel->validates();
  354. $this->assertFalse($result);
  355. $data = array('TestValidate' => array(
  356. 'title' => 'title',
  357. 'number' => '3'
  358. ));
  359. $result = $TestModel->create($data);
  360. $this->assertEquals($result, $data);
  361. $result = $TestModel->validates();
  362. $this->assertTrue($result);
  363. $data = array('TestValidate' => array(
  364. 'title' => 'title',
  365. 'number' => 3
  366. ));
  367. $result = $TestModel->create($data);
  368. $this->assertEquals($result, $data);
  369. $result = $TestModel->validates();
  370. $this->assertTrue($result);
  371. $TestModel->validate = array(
  372. 'number' => array(
  373. 'rule' => 'validateNumber',
  374. 'min' => 5,
  375. 'max' => 10
  376. ),
  377. 'title' => array(
  378. 'allowEmpty' => false,
  379. 'rule' => 'notEmpty'
  380. ));
  381. $data = array('TestValidate' => array(
  382. 'title' => 'title',
  383. 'number' => '3'
  384. ));
  385. $result = $TestModel->create($data);
  386. $this->assertEquals($result, $data);
  387. $result = $TestModel->validates();
  388. $this->assertFalse($result);
  389. $data = array('TestValidate' => array(
  390. 'title' => 'title',
  391. 'number' => 3
  392. ));
  393. $result = $TestModel->create($data);
  394. $this->assertEquals($result, $data);
  395. $result = $TestModel->validates();
  396. $this->assertFalse($result);
  397. $TestModel->validate = array(
  398. 'title' => array(
  399. 'allowEmpty' => false,
  400. 'rule' => 'validateTitle'
  401. ));
  402. $data = array('TestValidate' => array('title' => ''));
  403. $result = $TestModel->create($data);
  404. $this->assertEquals($result, $data);
  405. $result = $TestModel->validates();
  406. $this->assertFalse($result);
  407. $data = array('TestValidate' => array('title' => 'new title'));
  408. $result = $TestModel->create($data);
  409. $this->assertEquals($result, $data);
  410. $result = $TestModel->validates();
  411. $this->assertFalse($result);
  412. $data = array('TestValidate' => array('title' => 'title-new'));
  413. $result = $TestModel->create($data);
  414. $this->assertEquals($result, $data);
  415. $result = $TestModel->validates();
  416. $this->assertTrue($result);
  417. $TestModel->validate = array('title' => array(
  418. 'allowEmpty' => true,
  419. 'rule' => 'validateTitle'
  420. ));
  421. $data = array('TestValidate' => array('title' => ''));
  422. $result = $TestModel->create($data);
  423. $this->assertEquals($result, $data);
  424. $result = $TestModel->validates();
  425. $this->assertTrue($result);
  426. $TestModel->validate = array(
  427. 'title' => array(
  428. 'length' => array(
  429. 'allowEmpty' => true,
  430. 'rule' => array('maxLength', 10)
  431. )));
  432. $data = array('TestValidate' => array('title' => ''));
  433. $result = $TestModel->create($data);
  434. $this->assertEquals($result, $data);
  435. $result = $TestModel->validates();
  436. $this->assertTrue($result);
  437. $TestModel->validate = array(
  438. 'title' => array(
  439. 'rule' => array('userDefined', 'Article', 'titleDuplicate')
  440. ));
  441. $data = array('TestValidate' => array('title' => 'My Article Title'));
  442. $result = $TestModel->create($data);
  443. $this->assertEquals($result, $data);
  444. $result = $TestModel->validates();
  445. $this->assertFalse($result);
  446. $data = array('TestValidate' => array(
  447. 'title' => 'My Article With a Different Title'
  448. ));
  449. $result = $TestModel->create($data);
  450. $this->assertEquals($result, $data);
  451. $result = $TestModel->validates();
  452. $this->assertTrue($result);
  453. $TestModel->validate = array(
  454. 'title' => array(
  455. 'tooShort' => array('rule' => array('minLength', 50)),
  456. 'onlyLetters' => array('rule' => '/^[a-z]+$/i')
  457. ),
  458. );
  459. $data = array('TestValidate' => array(
  460. 'title' => 'I am a short string'
  461. ));
  462. $TestModel->create($data);
  463. $result = $TestModel->validates();
  464. $this->assertFalse($result);
  465. $result = $TestModel->validationErrors;
  466. $expected = array(
  467. 'title' => array('tooShort')
  468. );
  469. $this->assertEqual($expected, $result);
  470. $TestModel->validate = array(
  471. 'title' => array(
  472. 'tooShort' => array(
  473. 'rule' => array('minLength', 50),
  474. 'last' => false
  475. ),
  476. 'onlyLetters' => array('rule' => '/^[a-z]+$/i')
  477. ),
  478. );
  479. $data = array('TestValidate' => array(
  480. 'title' => 'I am a short string'
  481. ));
  482. $TestModel->create($data);
  483. $result = $TestModel->validates();
  484. $this->assertFalse($result);
  485. $result = $TestModel->validationErrors;
  486. $expected = array(
  487. 'title' => array('tooShort', 'onlyLetters')
  488. );
  489. $this->assertEqual($expected, $result);
  490. }
  491. /**
  492. * test that validates() checks all the 'with' associations as well for validation
  493. * as this can cause partial/wrong data insertion.
  494. *
  495. * @return void
  496. */
  497. public function testValidatesWithAssociations() {
  498. $this->loadFixtures('Something', 'SomethingElse', 'JoinThing');
  499. $data = array(
  500. 'Something' => array(
  501. 'id' => 5,
  502. 'title' => 'Extra Fields',
  503. 'body' => 'Extra Fields Body',
  504. 'published' => '1'
  505. ),
  506. 'SomethingElse' => array(
  507. array('something_else_id' => 1, 'doomed' => '')
  508. )
  509. );
  510. $Something = new Something();
  511. $JoinThing = $Something->JoinThing;
  512. $JoinThing->validate = array('doomed' => array('rule' => 'notEmpty'));
  513. $expectedError = array('doomed' => array('This field cannot be left blank'));
  514. $Something->create();
  515. $result = $Something->save($data);
  516. $this->assertFalse($result, 'Save occured even when with models failed. %s');
  517. $this->assertEqual($JoinThing->validationErrors, $expectedError);
  518. $count = $Something->find('count', array('conditions' => array('Something.id' => $data['Something']['id'])));
  519. $this->assertIdentical($count, 0);
  520. $data = array(
  521. 'Something' => array(
  522. 'id' => 5,
  523. 'title' => 'Extra Fields',
  524. 'body' => 'Extra Fields Body',
  525. 'published' => '1'
  526. ),
  527. 'SomethingElse' => array(
  528. array('something_else_id' => 1, 'doomed' => 1),
  529. array('something_else_id' => 1, 'doomed' => '')
  530. )
  531. );
  532. $Something->create();
  533. $result = $Something->save($data);
  534. $this->assertFalse($result, 'Save occured even when with models failed. %s');
  535. $joinRecords = $JoinThing->find('count', array(
  536. 'conditions' => array('JoinThing.something_id' => $data['Something']['id'])
  537. ));
  538. $this->assertEqual($joinRecords, 0, 'Records were saved on the join table. %s');
  539. }
  540. /**
  541. * test that saveAll and with models with validation interact well
  542. *
  543. * @return void
  544. */
  545. public function testValidatesWithModelsAndSaveAll() {
  546. $data = array(
  547. 'Something' => array(
  548. 'id' => 5,
  549. 'title' => 'Extra Fields',
  550. 'body' => 'Extra Fields Body',
  551. 'published' => '1'
  552. ),
  553. 'SomethingElse' => array(
  554. array('something_else_id' => 1, 'doomed' => '')
  555. )
  556. );
  557. $Something = new Something();
  558. $JoinThing = $Something->JoinThing;
  559. $JoinThing->validate = array('doomed' => array('rule' => 'notEmpty'));
  560. $expectedError = array('doomed' => array('This field cannot be left blank'));
  561. $Something->create();
  562. $result = $Something->saveAll($data, array('validate' => 'only'));
  563. $this->assertFalse($result);
  564. $this->assertEqual($JoinThing->validationErrors, $expectedError);
  565. $Something->create();
  566. $result = $Something->saveAll($data, array('validate' => 'first'));
  567. $this->assertFalse($result);
  568. $this->assertEqual($JoinThing->validationErrors, $expectedError);
  569. $count = $Something->find('count', array('conditions' => array('Something.id' => $data['Something']['id'])));
  570. $this->assertIdentical($count, 0);
  571. $joinRecords = $JoinThing->find('count', array(
  572. 'conditions' => array('JoinThing.something_id' => $data['Something']['id'])
  573. ));
  574. $this->assertEqual($joinRecords, 0, 'Records were saved on the join table. %s');
  575. }
  576. /**
  577. * Test that missing validation methods trigger errors in development mode.
  578. * Helps to make developement easier.
  579. *
  580. * @return void
  581. */
  582. public function testMissingValidationErrorTriggering() {
  583. Configure::write('debug', 2);
  584. $TestModel = new ValidationTest1();
  585. $TestModel->create(array('title' => 'foo'));
  586. $TestModel->validate = array(
  587. 'title' => array(
  588. 'rule' => array('thisOneBringsThePain'),
  589. 'required' => true
  590. )
  591. );
  592. $this->expectError();
  593. $TestModel->invalidFields(array('fieldList' => array('title')));
  594. }
  595. /**
  596. * Test that missing validation methods does not trigger errors in production mode.
  597. *
  598. * @return void
  599. */
  600. public function testMissingValidationErrorNoTriggering() {
  601. Configure::write('debug', 0);
  602. $TestModel = new ValidationTest1();
  603. $TestModel->create(array('title' => 'foo'));
  604. $TestModel->validate = array(
  605. 'title' => array(
  606. 'rule' => array('thisOneBringsThePain'),
  607. 'required' => true
  608. )
  609. );
  610. $TestModel->invalidFields(array('fieldList' => array('title')));
  611. $this->assertEquals($TestModel->validationErrors, array());
  612. }
  613. }