ValidatorTest.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Validation;
  16. use Cake\TestSuite\TestCase;
  17. use Cake\Validation\ValidationSet;
  18. use Cake\Validation\Validator;
  19. /**
  20. * Tests Validator class
  21. *
  22. */
  23. class ValidatorTest extends TestCase
  24. {
  25. /**
  26. * Testing you can dynamically add rules to a field
  27. *
  28. * @return void
  29. */
  30. public function testAddingRulesToField()
  31. {
  32. $validator = new Validator;
  33. $validator->add('title', 'not-blank', ['rule' => 'notBlank']);
  34. $set = $validator->field('title');
  35. $this->assertInstanceOf('Cake\Validation\ValidationSet', $set);
  36. $this->assertCount(1, $set);
  37. $validator->add('title', 'another', ['rule' => 'alphanumeric']);
  38. $this->assertCount(2, $set);
  39. $validator->add('body', 'another', ['rule' => 'crazy']);
  40. $this->assertCount(1, $validator->field('body'));
  41. $this->assertCount(2, $validator);
  42. }
  43. /**
  44. * Testing addNested field rules
  45. *
  46. * @return void
  47. */
  48. public function testAddNestedSingle()
  49. {
  50. $validator = new Validator();
  51. $inner = new Validator();
  52. $inner->add('username', 'not-blank', ['rule' => 'notBlank']);
  53. $this->assertSame($validator, $validator->addNested('user', $inner));
  54. $this->assertCount(1, $validator->field('user'));
  55. }
  56. /**
  57. * Testing addNested connects providers
  58. *
  59. * @return void
  60. */
  61. public function testAddNestedSingleProviders()
  62. {
  63. $validator = new Validator();
  64. $validator->provider('test', $this);
  65. $inner = new Validator();
  66. $inner->add('username', 'not-blank', ['rule' => function () use ($inner, $validator) {
  67. $this->assertSame($validator->providers(), $inner->providers(), 'Providers should match');
  68. return false;
  69. }]);
  70. $validator->addNested('user', $inner);
  71. $result = $validator->errors(['user' => ['username' => 'example']]);
  72. $this->assertNotEmpty($result, 'Validation should fail');
  73. }
  74. /**
  75. * Testing addNestedMany field rules
  76. *
  77. * @return void
  78. */
  79. public function testAddNestedMany()
  80. {
  81. $validator = new Validator();
  82. $inner = new Validator();
  83. $inner->add('comment', 'not-blank', ['rule' => 'notBlank']);
  84. $this->assertSame($validator, $validator->addNestedMany('comments', $inner));
  85. $this->assertCount(1, $validator->field('comments'));
  86. }
  87. /**
  88. * Testing addNestedMany connects providers
  89. *
  90. * @return void
  91. */
  92. public function testAddNestedManyProviders()
  93. {
  94. $validator = new Validator();
  95. $validator->provider('test', $this);
  96. $inner = new Validator();
  97. $inner->add('comment', 'not-blank', ['rule' => function () use ($inner, $validator) {
  98. $this->assertSame($validator->providers(), $inner->providers(), 'Providers should match');
  99. return false;
  100. }]);
  101. $validator->addNestedMany('comments', $inner);
  102. $result = $validator->errors(['comments' => [['comment' => 'example']]]);
  103. $this->assertNotEmpty($result, 'Validation should fail');
  104. }
  105. /**
  106. * Tests that calling field will create a default validation set for it
  107. *
  108. * @return void
  109. */
  110. public function testFieldDefault()
  111. {
  112. $validator = new Validator;
  113. $this->assertFalse($validator->hasField('foo'));
  114. $field = $validator->field('foo');
  115. $this->assertInstanceOf('Cake\Validation\ValidationSet', $field);
  116. $this->assertCount(0, $field);
  117. $this->assertTrue($validator->hasField('foo'));
  118. }
  119. /**
  120. * Tests that field method can be used as a setter
  121. *
  122. * @return void
  123. */
  124. public function testFieldSetter()
  125. {
  126. $validator = new Validator;
  127. $validationSet = new ValidationSet;
  128. $validator->field('thing', $validationSet);
  129. $this->assertSame($validationSet, $validator->field('thing'));
  130. }
  131. /**
  132. * Tests the remove method
  133. *
  134. * @return void
  135. */
  136. public function testRemove()
  137. {
  138. $validator = new Validator;
  139. $validator->add('title', 'not-blank', ['rule' => 'notBlank']);
  140. $validator->add('title', 'foo', ['rule' => 'bar']);
  141. $this->assertCount(2, $validator->field('title'));
  142. $validator->remove('title');
  143. $this->assertCount(0, $validator->field('title'));
  144. $validator->remove('title');
  145. $validator->add('title', 'not-blank', ['rule' => 'notBlank']);
  146. $validator->add('title', 'foo', ['rule' => 'bar']);
  147. $this->assertCount(2, $validator->field('title'));
  148. $validator->remove('title', 'foo');
  149. $this->assertCount(1, $validator->field('title'));
  150. $this->assertNull($validator->field('title')->rule('foo'));
  151. }
  152. /**
  153. * Tests the requirePresence method
  154. *
  155. * @return void
  156. */
  157. public function testRequirePresence()
  158. {
  159. $validator = new Validator;
  160. $this->assertSame($validator, $validator->requirePresence('title'));
  161. $this->assertTrue($validator->field('title')->isPresenceRequired());
  162. $validator->requirePresence('title', false);
  163. $this->assertFalse($validator->field('title')->isPresenceRequired());
  164. $validator->requirePresence('title', 'create');
  165. $this->assertEquals('create', $validator->field('title')->isPresenceRequired());
  166. $validator->requirePresence('title', 'update');
  167. $this->assertEquals('update', $validator->field('title')->isPresenceRequired());
  168. }
  169. /**
  170. * Tests the isPresenceRequired method
  171. *
  172. * @return void
  173. */
  174. public function testIsPresenceRequired()
  175. {
  176. $validator = new Validator;
  177. $this->assertSame($validator, $validator->requirePresence('title'));
  178. $this->assertTrue($validator->isPresenceRequired('title', true));
  179. $this->assertTrue($validator->isPresenceRequired('title', false));
  180. $validator->requirePresence('title', false);
  181. $this->assertFalse($validator->isPresenceRequired('title', true));
  182. $this->assertFalse($validator->isPresenceRequired('title', false));
  183. $validator->requirePresence('title', 'create');
  184. $this->assertTrue($validator->isPresenceRequired('title', true));
  185. $this->assertFalse($validator->isPresenceRequired('title', false));
  186. $validator->requirePresence('title', 'update');
  187. $this->assertTrue($validator->isPresenceRequired('title', false));
  188. $this->assertFalse($validator->isPresenceRequired('title', true));
  189. }
  190. /**
  191. * Tests errors generated when a field presence is required
  192. *
  193. * @return void
  194. */
  195. public function testErrorsWithPresenceRequired()
  196. {
  197. $validator = new Validator;
  198. $validator->requirePresence('title');
  199. $errors = $validator->errors(['foo' => 'something']);
  200. $expected = ['title' => ['_required' => 'This field is required']];
  201. $this->assertEquals($expected, $errors);
  202. $this->assertEmpty($validator->errors(['title' => 'bar']));
  203. $validator->requirePresence('title', false);
  204. $this->assertEmpty($validator->errors(['foo' => 'bar']));
  205. }
  206. /**
  207. * Test that errors() can work with nested data.
  208. *
  209. * @return void
  210. */
  211. public function testErrorsWithNestedFields()
  212. {
  213. $validator = new Validator();
  214. $user = new Validator();
  215. $user->add('username', 'letter', ['rule' => 'alphanumeric']);
  216. $comments = new Validator();
  217. $comments->add('comment', 'letter', ['rule' => 'alphanumeric']);
  218. $validator->addNested('user', $user);
  219. $validator->addNestedMany('comments', $comments);
  220. $data = [
  221. 'user' => [
  222. 'username' => 'is wrong'
  223. ],
  224. 'comments' => [
  225. ['comment' => 'is wrong']
  226. ]
  227. ];
  228. $errors = $validator->errors($data);
  229. $expected = [
  230. 'user' => [
  231. 'username' => ['letter' => 'The provided value is invalid']
  232. ],
  233. 'comments' => [
  234. 0 => ['comment' => ['letter' => 'The provided value is invalid']]
  235. ]
  236. ];
  237. $this->assertEquals($expected, $errors);
  238. }
  239. /**
  240. * Test nested fields with many, but invalid data.
  241. *
  242. * @return void
  243. */
  244. public function testErrorsWithNestedSingleInvalidType()
  245. {
  246. $validator = new Validator();
  247. $user = new Validator();
  248. $user->add('user', 'letter', ['rule' => 'alphanumeric']);
  249. $validator->addNested('user', $user);
  250. $data = [
  251. 'user' => 'a string',
  252. ];
  253. $errors = $validator->errors($data);
  254. $expected = [
  255. 'user' => ['_nested' => 'The provided value is invalid'],
  256. ];
  257. $this->assertEquals($expected, $errors);
  258. }
  259. /**
  260. * Test nested fields with many, but invalid data.
  261. *
  262. * @return void
  263. */
  264. public function testErrorsWithNestedManyInvalidType()
  265. {
  266. $validator = new Validator();
  267. $comments = new Validator();
  268. $comments->add('comment', 'letter', ['rule' => 'alphanumeric']);
  269. $validator->addNestedMany('comments', $comments);
  270. $data = [
  271. 'comments' => 'a string',
  272. ];
  273. $errors = $validator->errors($data);
  274. $expected = [
  275. 'comments' => ['_nested' => 'The provided value is invalid'],
  276. ];
  277. $this->assertEquals($expected, $errors);
  278. }
  279. /**
  280. * Test nested fields with many, but invalid data.
  281. *
  282. * @return void
  283. */
  284. public function testErrorsWithNestedManySomeInvalid()
  285. {
  286. $validator = new Validator();
  287. $comments = new Validator();
  288. $comments->add('comment', 'letter', ['rule' => 'alphanumeric']);
  289. $validator->addNestedMany('comments', $comments);
  290. $data = [
  291. 'comments' => [
  292. 'a string',
  293. ['comment' => 'letters'],
  294. ['comment' => 'more invalid']
  295. ]
  296. ];
  297. $errors = $validator->errors($data);
  298. $expected = [
  299. 'comments' => [
  300. '_nested' => 'The provided value is invalid',
  301. ],
  302. ];
  303. $this->assertEquals($expected, $errors);
  304. }
  305. /**
  306. * Tests custom error messages generated when a field presence is required
  307. *
  308. * @return void
  309. */
  310. public function testCustomErrorsWithPresenceRequired()
  311. {
  312. $validator = new Validator;
  313. $validator->requirePresence('title', true, 'Custom message');
  314. $errors = $validator->errors(['foo' => 'something']);
  315. $expected = ['title' => ['_required' => 'Custom message']];
  316. $this->assertEquals($expected, $errors);
  317. }
  318. /**
  319. * Tests the allowEmpty method
  320. *
  321. * @return void
  322. */
  323. public function testAllowEmpty()
  324. {
  325. $validator = new Validator;
  326. $this->assertSame($validator, $validator->allowEmpty('title'));
  327. $this->assertTrue($validator->field('title')->isEmptyAllowed());
  328. $validator->allowEmpty('title', 'create');
  329. $this->assertEquals('create', $validator->field('title')->isEmptyAllowed());
  330. $validator->allowEmpty('title', 'update');
  331. $this->assertEquals('update', $validator->field('title')->isEmptyAllowed());
  332. }
  333. /**
  334. * Tests the allowEmpty method with date/time fields.
  335. *
  336. * @return void
  337. */
  338. public function testAllowEmptyDateTime()
  339. {
  340. $validator = new Validator;
  341. $validator->allowEmpty('created')
  342. ->add('created', 'date', ['rule' => 'date']);
  343. $data = [
  344. 'created' => [
  345. 'year' => '',
  346. 'month' => '',
  347. 'day' => ''
  348. ]
  349. ];
  350. $result = $validator->errors($data);
  351. $this->assertEmpty($result, 'No errors on empty date');
  352. $data = [
  353. 'created' => [
  354. 'year' => '',
  355. 'month' => '',
  356. 'day' => '',
  357. 'hour' => '',
  358. 'minute' => '',
  359. 'second' => '',
  360. 'meridian' => '',
  361. ]
  362. ];
  363. $result = $validator->errors($data);
  364. $this->assertEmpty($result, 'No errors on empty datetime');
  365. $data = [
  366. 'created' => [
  367. 'hour' => '',
  368. 'minute' => '',
  369. 'meridian' => '',
  370. ]
  371. ];
  372. $result = $validator->errors($data);
  373. $this->assertEmpty($result, 'No errors on empty time');
  374. }
  375. /**
  376. * Tests the allowEmpty method with file fields.
  377. *
  378. * @return void
  379. */
  380. public function testAllowEmptyFileFields()
  381. {
  382. $validator = new Validator;
  383. $validator->allowEmpty('picture')
  384. ->add('picture', 'file', ['rule' => 'uploadedFile']);
  385. $data = [
  386. 'picture' => [
  387. 'name' => '',
  388. 'type' => '',
  389. 'tmp_name' => '',
  390. 'error' => UPLOAD_ERR_NO_FILE,
  391. ]
  392. ];
  393. $result = $validator->errors($data);
  394. $this->assertEmpty($result, 'No errors on empty date');
  395. $data = [
  396. 'picture' => [
  397. 'name' => 'fake.png',
  398. 'type' => '',
  399. 'tmp_name' => '',
  400. 'error' => UPLOAD_ERR_OK,
  401. ]
  402. ];
  403. $result = $validator->errors($data);
  404. $this->assertNotEmpty($result, 'Invalid file should be caught still.');
  405. }
  406. /**
  407. * Test the notEmpty() method.
  408. *
  409. * @return void
  410. */
  411. public function testNotEmpty()
  412. {
  413. $validator = new Validator;
  414. $validator->notEmpty('title');
  415. $this->assertFalse($validator->field('title')->isEmptyAllowed());
  416. $validator->allowEmpty('title');
  417. $this->assertTrue($validator->field('title')->isEmptyAllowed());
  418. }
  419. /**
  420. * Test the notEmpty() method.
  421. *
  422. * @return void
  423. */
  424. public function testNotEmptyModes()
  425. {
  426. $validator = new Validator;
  427. $validator->notEmpty('title', 'Need a title', 'create');
  428. $this->assertFalse($validator->isEmptyAllowed('title', true));
  429. $this->assertTrue($validator->isEmptyAllowed('title', false));
  430. $validator->notEmpty('title', 'Need a title', 'update');
  431. $this->assertTrue($validator->isEmptyAllowed('title', true));
  432. $this->assertFalse($validator->isEmptyAllowed('title', false));
  433. $validator->notEmpty('title', 'Need a title');
  434. $this->assertFalse($validator->isEmptyAllowed('title', true));
  435. $this->assertFalse($validator->isEmptyAllowed('title', false));
  436. $validator->notEmpty('title');
  437. $this->assertFalse($validator->isEmptyAllowed('title', true));
  438. $this->assertFalse($validator->isEmptyAllowed('title', false));
  439. }
  440. /**
  441. * Test interactions between notEmpty() and isAllowed().
  442. *
  443. * @return void
  444. */
  445. public function testNotEmptyAndIsAllowed()
  446. {
  447. $validator = new Validator;
  448. $validator->allowEmpty('title')
  449. ->notEmpty('title', 'Need it', 'update');
  450. $this->assertTrue($validator->isEmptyAllowed('title', true));
  451. $this->assertFalse($validator->isEmptyAllowed('title', false));
  452. $validator->allowEmpty('title')
  453. ->notEmpty('title');
  454. $this->assertFalse($validator->isEmptyAllowed('title', true));
  455. $this->assertFalse($validator->isEmptyAllowed('title', false));
  456. $validator->notEmpty('title')
  457. ->allowEmpty('title', 'create');
  458. $this->assertTrue($validator->isEmptyAllowed('title', true));
  459. $this->assertFalse($validator->isEmptyAllowed('title', false));
  460. }
  461. /**
  462. * Tests the allowEmpty method when passing a callback
  463. *
  464. * @return void
  465. */
  466. public function testAllowEmptyCallback()
  467. {
  468. $validator = new Validator;
  469. $allow = true;
  470. $validator->allowEmpty('title', function ($context) use (&$allow) {
  471. $this->assertEquals([], $context['data']);
  472. $this->assertEquals([], $context['providers']);
  473. $this->assertTrue($context['newRecord']);
  474. return $allow;
  475. });
  476. $this->assertTrue($validator->isEmptyAllowed('title', true));
  477. $allow = false;
  478. $this->assertFalse($validator->isEmptyAllowed('title', true));
  479. }
  480. /**
  481. * Tests the notEmpty method when passing a callback
  482. *
  483. * @return void
  484. */
  485. public function testNotEmptyCallback()
  486. {
  487. $validator = new Validator;
  488. $prevent = true;
  489. $validator->notEmpty('title', 'error message', function ($context) use (&$prevent) {
  490. $this->assertEquals([], $context['data']);
  491. $this->assertEquals([], $context['providers']);
  492. $this->assertFalse($context['newRecord']);
  493. return $prevent;
  494. });
  495. $this->assertFalse($validator->isEmptyAllowed('title', false));
  496. $prevent = false;
  497. $this->assertTrue($validator->isEmptyAllowed('title', false));
  498. }
  499. /**
  500. * Tests the isEmptyAllowed method
  501. *
  502. * @return void
  503. */
  504. public function testIsEmptyAllowed()
  505. {
  506. $validator = new Validator;
  507. $this->assertSame($validator, $validator->allowEmpty('title'));
  508. $this->assertTrue($validator->isEmptyAllowed('title', true));
  509. $this->assertTrue($validator->isEmptyAllowed('title', false));
  510. $validator->notEmpty('title');
  511. $this->assertFalse($validator->isEmptyAllowed('title', true));
  512. $this->assertFalse($validator->isEmptyAllowed('title', false));
  513. $validator->allowEmpty('title', 'create');
  514. $this->assertTrue($validator->isEmptyAllowed('title', true));
  515. $this->assertFalse($validator->isEmptyAllowed('title', false));
  516. $validator->allowEmpty('title', 'update');
  517. $this->assertTrue($validator->isEmptyAllowed('title', false));
  518. $this->assertFalse($validator->isEmptyAllowed('title', true));
  519. }
  520. /**
  521. * Tests errors generated when a field is not allowed to be empty
  522. *
  523. * @return void
  524. */
  525. public function testErrorsWithEmptyNotAllowed()
  526. {
  527. $validator = new Validator;
  528. $validator->notEmpty('title');
  529. $errors = $validator->errors(['title' => '']);
  530. $expected = ['title' => ['_empty' => 'This field cannot be left empty']];
  531. $this->assertEquals($expected, $errors);
  532. $errors = $validator->errors(['title' => []]);
  533. $expected = ['title' => ['_empty' => 'This field cannot be left empty']];
  534. $this->assertEquals($expected, $errors);
  535. $errors = $validator->errors(['title' => null]);
  536. $expected = ['title' => ['_empty' => 'This field cannot be left empty']];
  537. $this->assertEquals($expected, $errors);
  538. $errors = $validator->errors(['title' => 0]);
  539. $this->assertEmpty($errors);
  540. $errors = $validator->errors(['title' => '0']);
  541. $this->assertEmpty($errors);
  542. $errors = $validator->errors(['title' => false]);
  543. $this->assertEmpty($errors);
  544. }
  545. /**
  546. * Tests custom error mesages generated when a field is not allowed to be empty
  547. *
  548. * @return void
  549. */
  550. public function testCustomErrorsWithEmptyNotAllowed()
  551. {
  552. $validator = new Validator;
  553. $validator->notEmpty('title', 'Custom message');
  554. $errors = $validator->errors(['title' => '']);
  555. $expected = ['title' => ['_empty' => 'Custom message']];
  556. $this->assertEquals($expected, $errors);
  557. }
  558. /**
  559. * Tests errors generated when a field is allowed to be empty
  560. *
  561. * @return void
  562. */
  563. public function testErrorsWithEmptyAllowed()
  564. {
  565. $validator = new Validator;
  566. $validator->allowEmpty('title');
  567. $errors = $validator->errors(['title' => '']);
  568. $this->assertEmpty($errors);
  569. $errors = $validator->errors(['title' => []]);
  570. $this->assertEmpty($errors);
  571. $errors = $validator->errors(['title' => null]);
  572. $this->assertEmpty($errors);
  573. $errors = $validator->errors(['title' => 0]);
  574. $this->assertEmpty($errors);
  575. $errors = $validator->errors(['title' => 0.0]);
  576. $this->assertEmpty($errors);
  577. $errors = $validator->errors(['title' => '0']);
  578. $this->assertEmpty($errors);
  579. $errors = $validator->errors(['title' => false]);
  580. $this->assertEmpty($errors);
  581. }
  582. /**
  583. * Test the provider() method
  584. *
  585. * @return void
  586. */
  587. public function testProvider()
  588. {
  589. $validator = new Validator;
  590. $object = new \stdClass;
  591. $this->assertSame($validator, $validator->provider('foo', $object));
  592. $this->assertSame($object, $validator->provider('foo'));
  593. $this->assertNull($validator->provider('bar'));
  594. $another = new \stdClass;
  595. $this->assertSame($validator, $validator->provider('bar', $another));
  596. $this->assertSame($another, $validator->provider('bar'));
  597. $this->assertEquals(new \Cake\Validation\RulesProvider, $validator->provider('default'));
  598. }
  599. /**
  600. * Tests errors() method when using validators from the default provider, this proves
  601. * that it returns a default validation message and the custom one set in the rule
  602. *
  603. * @return void
  604. */
  605. public function testErrorsFromDefaultProvider()
  606. {
  607. $validator = new Validator;
  608. $validator
  609. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  610. ->add('email', 'notBlank', ['rule' => 'notBlank'])
  611. ->add('email', 'email', ['rule' => 'email', 'message' => 'Y u no write email?']);
  612. $errors = $validator->errors(['email' => 'not an email!']);
  613. $expected = [
  614. 'email' => [
  615. 'alpha' => 'The provided value is invalid',
  616. 'email' => 'Y u no write email?'
  617. ]
  618. ];
  619. $this->assertEquals($expected, $errors);
  620. }
  621. /**
  622. * Tests using validation methods from different providers and returning the error
  623. * as a string
  624. *
  625. * @return void
  626. */
  627. public function testErrorsFromCustomProvider()
  628. {
  629. $validator = new Validator;
  630. $validator
  631. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  632. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  633. $thing = $this->getMock('\stdClass', ['isCool']);
  634. $thing->expects($this->once())->method('isCool')
  635. ->will($this->returnCallback(function ($data, $context) use ($thing) {
  636. $this->assertEquals('bar', $data);
  637. $expected = [
  638. 'default' => new \Cake\Validation\RulesProvider,
  639. 'thing' => $thing
  640. ];
  641. $expected = [
  642. 'newRecord' => true,
  643. 'providers' => $expected,
  644. 'data' => [
  645. 'email' => '!',
  646. 'title' => 'bar'
  647. ],
  648. 'field' => 'title'
  649. ];
  650. $this->assertEquals($expected, $context);
  651. return "That ain't cool, yo";
  652. }));
  653. $validator->provider('thing', $thing);
  654. $errors = $validator->errors(['email' => '!', 'title' => 'bar']);
  655. $expected = [
  656. 'email' => ['alpha' => 'The provided value is invalid'],
  657. 'title' => ['cool' => "That ain't cool, yo"]
  658. ];
  659. $this->assertEquals($expected, $errors);
  660. }
  661. /**
  662. * Tests that it is possible to pass extra arguments to the validation function
  663. * and it still gets the providers as last argument
  664. *
  665. * @return void
  666. */
  667. public function testMethodsWithExtraArguments()
  668. {
  669. $validator = new Validator;
  670. $validator->add('title', 'cool', [
  671. 'rule' => ['isCool', 'and', 'awesome'],
  672. 'provider' => 'thing'
  673. ]);
  674. $thing = $this->getMock('\stdClass', ['isCool']);
  675. $thing->expects($this->once())->method('isCool')
  676. ->will($this->returnCallback(function ($data, $a, $b, $context) use ($thing) {
  677. $this->assertEquals('bar', $data);
  678. $this->assertEquals('and', $a);
  679. $this->assertEquals('awesome', $b);
  680. $expected = [
  681. 'default' => new \Cake\Validation\RulesProvider,
  682. 'thing' => $thing
  683. ];
  684. $expected = [
  685. 'newRecord' => true,
  686. 'providers' => $expected,
  687. 'data' => [
  688. 'email' => '!',
  689. 'title' => 'bar'
  690. ],
  691. 'field' => 'title'
  692. ];
  693. $this->assertEquals($expected, $context);
  694. return "That ain't cool, yo";
  695. }));
  696. $validator->provider('thing', $thing);
  697. $errors = $validator->errors(['email' => '!', 'title' => 'bar']);
  698. $expected = [
  699. 'title' => ['cool' => "That ain't cool, yo"]
  700. ];
  701. $this->assertEquals($expected, $errors);
  702. }
  703. /**
  704. * Tests that it is possible to use a closure as a rule
  705. *
  706. * @return void
  707. */
  708. public function testUsingClosureAsRule()
  709. {
  710. $validator = new Validator;
  711. $validator->add('name', 'myRule', [
  712. 'rule' => function ($data, $provider) {
  713. $this->assertEquals('foo', $data);
  714. return 'You fail';
  715. }
  716. ]);
  717. $expected = ['name' => ['myRule' => 'You fail']];
  718. $this->assertEquals($expected, $validator->errors(['name' => 'foo']));
  719. }
  720. /**
  721. * Tests that setting last to a rule will stop validating the rest of the rules
  722. *
  723. * @return void
  724. */
  725. public function testErrorsWithLastRule()
  726. {
  727. $validator = new Validator;
  728. $validator
  729. ->add('email', 'alpha', ['rule' => 'alphanumeric', 'last' => true])
  730. ->add('email', 'email', ['rule' => 'email', 'message' => 'Y u no write email?']);
  731. $errors = $validator->errors(['email' => 'not an email!']);
  732. $expected = [
  733. 'email' => [
  734. 'alpha' => 'The provided value is invalid'
  735. ]
  736. ];
  737. $this->assertEquals($expected, $errors);
  738. }
  739. /**
  740. * Tests it is possible to get validation sets for a field using an array interface
  741. *
  742. * @return void
  743. */
  744. public function testArrayAccessGet()
  745. {
  746. $validator = new Validator;
  747. $validator
  748. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  749. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  750. $this->assertSame($validator['email'], $validator->field('email'));
  751. $this->assertSame($validator['title'], $validator->field('title'));
  752. }
  753. /**
  754. * Tests it is possible to check for validation sets for a field using an array inteface
  755. *
  756. * @return void
  757. */
  758. public function testArrayAccessExists()
  759. {
  760. $validator = new Validator;
  761. $validator
  762. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  763. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  764. $this->assertTrue(isset($validator['email']));
  765. $this->assertTrue(isset($validator['title']));
  766. $this->assertFalse(isset($validator['foo']));
  767. }
  768. /**
  769. * Tests it is possible to set validation rules for a field using an array inteface
  770. *
  771. * @return void
  772. */
  773. public function testArrayAccessSet()
  774. {
  775. $validator = new Validator;
  776. $validator
  777. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  778. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  779. $validator['name'] = $validator->field('title');
  780. $this->assertSame($validator->field('title'), $validator->field('name'));
  781. $validator['name'] = ['alpha' => ['rule' => 'alphanumeric']];
  782. $this->assertEquals($validator->field('email'), $validator->field('email'));
  783. }
  784. /**
  785. * Tests it is possible to unset validation rules
  786. *
  787. * @return void
  788. */
  789. public function testArrayAccessUset()
  790. {
  791. $validator = new Validator;
  792. $validator
  793. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  794. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  795. $this->assertTrue(isset($validator['title']));
  796. unset($validator['title']);
  797. $this->assertFalse(isset($validator['title']));
  798. }
  799. /**
  800. * Tests the countable interface
  801. *
  802. * @return void
  803. */
  804. public function testCount()
  805. {
  806. $validator = new Validator;
  807. $validator
  808. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  809. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  810. $this->assertCount(2, $validator);
  811. }
  812. /**
  813. * Tests adding rules via alternative syntax
  814. *
  815. * @return void
  816. */
  817. public function testAddMulitple()
  818. {
  819. $validator = new Validator;
  820. $validator->add('title', [
  821. 'notBlank' => [
  822. 'rule' => 'notBlank'
  823. ],
  824. 'length' => [
  825. 'rule' => ['minLength', 10],
  826. 'message' => 'Titles need to be at least 10 characters long'
  827. ]
  828. ]);
  829. $set = $validator->field('title');
  830. $this->assertInstanceOf('Cake\Validation\ValidationSet', $set);
  831. $this->assertCount(2, $set);
  832. }
  833. /**
  834. * Integration test for compareWith validator.
  835. *
  836. * @return void
  837. */
  838. public function testCompareWithIntegration()
  839. {
  840. $validator = new Validator;
  841. $validator->add('password', [
  842. 'compare' => [
  843. 'rule' => ['compareWith', 'password_compare']
  844. ],
  845. ]);
  846. $data = [
  847. 'password' => 'test',
  848. 'password_compare' => 'not the same'
  849. ];
  850. $this->assertNotEmpty($validator->errors($data), 'Validation should fail.');
  851. }
  852. /**
  853. * Test debugInfo helper method.
  854. *
  855. * @return void
  856. */
  857. public function testDebugInfo()
  858. {
  859. $validator = new Validator();
  860. $validator->provider('test', $this);
  861. $validator->add('title', 'not-empty', ['rule' => 'notEmpty']);
  862. $validator->requirePresence('body');
  863. $validator->allowEmpty('published');
  864. $result = $validator->__debugInfo();
  865. $expected = [
  866. '_providers' => ['test'],
  867. '_fields' => [
  868. 'title' => [
  869. 'isPresenceRequired' => false,
  870. 'isEmptyAllowed' => false,
  871. 'rules' => ['not-empty'],
  872. ],
  873. 'body' => [
  874. 'isPresenceRequired' => true,
  875. 'isEmptyAllowed' => false,
  876. 'rules' => [],
  877. ],
  878. 'published' => [
  879. 'isPresenceRequired' => false,
  880. 'isEmptyAllowed' => true,
  881. 'rules' => [],
  882. ],
  883. ],
  884. '_presenceMessages' => [],
  885. '_allowEmptyMessages' => [],
  886. '_useI18n' => true,
  887. ];
  888. $this->assertEquals($expected, $result);
  889. }
  890. }