ValidatorTest.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  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-empty', ['rule' => 'notEmpty']);
  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. * Tests that calling field will create a default validation set for it
  45. *
  46. * @return void
  47. */
  48. public function testFieldDefault()
  49. {
  50. $validator = new Validator;
  51. $this->assertFalse($validator->hasField('foo'));
  52. $field = $validator->field('foo');
  53. $this->assertInstanceOf('Cake\Validation\ValidationSet', $field);
  54. $this->assertCount(0, $field);
  55. $this->assertTrue($validator->hasField('foo'));
  56. }
  57. /**
  58. * Tests that field method can be used as a setter
  59. *
  60. * @return void
  61. */
  62. public function testFieldSetter()
  63. {
  64. $validator = new Validator;
  65. $validationSet = new ValidationSet;
  66. $validator->field('thing', $validationSet);
  67. $this->assertSame($validationSet, $validator->field('thing'));
  68. }
  69. /**
  70. * Tests the remove method
  71. *
  72. * @return void
  73. */
  74. public function testRemove()
  75. {
  76. $validator = new Validator;
  77. $validator->add('title', 'not-empty', ['rule' => 'notEmpty']);
  78. $validator->add('title', 'foo', ['rule' => 'bar']);
  79. $this->assertCount(2, $validator->field('title'));
  80. $validator->remove('title');
  81. $this->assertCount(0, $validator->field('title'));
  82. $validator->remove('title');
  83. $validator->add('title', 'not-empty', ['rule' => 'notEmpty']);
  84. $validator->add('title', 'foo', ['rule' => 'bar']);
  85. $this->assertCount(2, $validator->field('title'));
  86. $validator->remove('title', 'foo');
  87. $this->assertCount(1, $validator->field('title'));
  88. $this->assertNull($validator->field('title')->rule('foo'));
  89. }
  90. /**
  91. * Tests the requirePresence method
  92. *
  93. * @return void
  94. */
  95. public function testRequirePresence()
  96. {
  97. $validator = new Validator;
  98. $this->assertSame($validator, $validator->requirePresence('title'));
  99. $this->assertTrue($validator->field('title')->isPresenceRequired());
  100. $validator->requirePresence('title', false);
  101. $this->assertFalse($validator->field('title')->isPresenceRequired());
  102. $validator->requirePresence('title', 'create');
  103. $this->assertEquals('create', $validator->field('title')->isPresenceRequired());
  104. $validator->requirePresence('title', 'update');
  105. $this->assertEquals('update', $validator->field('title')->isPresenceRequired());
  106. }
  107. /**
  108. * Tests the isPresenceRequired method
  109. *
  110. * @return void
  111. */
  112. public function testIsPresenceRequired()
  113. {
  114. $validator = new Validator;
  115. $this->assertSame($validator, $validator->requirePresence('title'));
  116. $this->assertTrue($validator->isPresenceRequired('title', true));
  117. $this->assertTrue($validator->isPresenceRequired('title', false));
  118. $validator->requirePresence('title', false);
  119. $this->assertFalse($validator->isPresenceRequired('title', true));
  120. $this->assertFalse($validator->isPresenceRequired('title', false));
  121. $validator->requirePresence('title', 'create');
  122. $this->assertTrue($validator->isPresenceRequired('title', true));
  123. $this->assertFalse($validator->isPresenceRequired('title', false));
  124. $validator->requirePresence('title', 'update');
  125. $this->assertTrue($validator->isPresenceRequired('title', false));
  126. $this->assertFalse($validator->isPresenceRequired('title', true));
  127. }
  128. /**
  129. * Tests errors generated when a field presence is required
  130. *
  131. * @return void
  132. */
  133. public function testErrorsWithPresenceRequired()
  134. {
  135. $validator = new Validator;
  136. $validator->requirePresence('title');
  137. $errors = $validator->errors(['foo' => 'something']);
  138. $expected = ['title' => ['_required' => 'This field is required']];
  139. $this->assertEquals($expected, $errors);
  140. $this->assertEmpty($validator->errors(['title' => 'bar']));
  141. $validator->requirePresence('title', false);
  142. $this->assertEmpty($validator->errors(['foo' => 'bar']));
  143. }
  144. /**
  145. * Tests custom error messages generated when a field presence is required
  146. *
  147. * @return void
  148. */
  149. public function testCustomErrorsWithPresenceRequired()
  150. {
  151. $validator = new Validator;
  152. $validator->requirePresence('title', true, 'Custom message');
  153. $errors = $validator->errors(['foo' => 'something']);
  154. $expected = ['title' => ['_required' => 'Custom message']];
  155. $this->assertEquals($expected, $errors);
  156. }
  157. /**
  158. * Tests the allowEmpty method
  159. *
  160. * @return void
  161. */
  162. public function testAllowEmpty()
  163. {
  164. $validator = new Validator;
  165. $this->assertSame($validator, $validator->allowEmpty('title'));
  166. $this->assertTrue($validator->field('title')->isEmptyAllowed());
  167. $validator->allowEmpty('title', 'create');
  168. $this->assertEquals('create', $validator->field('title')->isEmptyAllowed());
  169. $validator->allowEmpty('title', 'update');
  170. $this->assertEquals('update', $validator->field('title')->isEmptyAllowed());
  171. }
  172. /**
  173. * Test the notEmpty() method.
  174. *
  175. * @return void
  176. */
  177. public function testNotEmpty()
  178. {
  179. $validator = new Validator;
  180. $validator->notEmpty('title');
  181. $this->assertFalse($validator->field('title')->isEmptyAllowed());
  182. $validator->allowEmpty('title');
  183. $this->assertTrue($validator->field('title')->isEmptyAllowed());
  184. }
  185. /**
  186. * Test the notEmpty() method.
  187. *
  188. * @return void
  189. */
  190. public function testNotEmptyModes()
  191. {
  192. $validator = new Validator;
  193. $validator->notEmpty('title', 'Need a title', 'create');
  194. $this->assertFalse($validator->isEmptyAllowed('title', true));
  195. $this->assertTrue($validator->isEmptyAllowed('title', false));
  196. $validator->notEmpty('title', 'Need a title', 'update');
  197. $this->assertTrue($validator->isEmptyAllowed('title', true));
  198. $this->assertFalse($validator->isEmptyAllowed('title', false));
  199. $validator->notEmpty('title', 'Need a title');
  200. $this->assertFalse($validator->isEmptyAllowed('title', true));
  201. $this->assertFalse($validator->isEmptyAllowed('title', false));
  202. $validator->notEmpty('title');
  203. $this->assertFalse($validator->isEmptyAllowed('title', true));
  204. $this->assertFalse($validator->isEmptyAllowed('title', false));
  205. }
  206. /**
  207. * Test interactions between notEmpty() and isAllowed().
  208. *
  209. * @return void
  210. */
  211. public function testNotEmptyAndIsAllowed()
  212. {
  213. $validator = new Validator;
  214. $validator->allowEmpty('title')
  215. ->notEmpty('title', 'Need it', 'update');
  216. $this->assertTrue($validator->isEmptyAllowed('title', true));
  217. $this->assertFalse($validator->isEmptyAllowed('title', false));
  218. $validator->allowEmpty('title')
  219. ->notEmpty('title');
  220. $this->assertFalse($validator->isEmptyAllowed('title', true));
  221. $this->assertFalse($validator->isEmptyAllowed('title', false));
  222. $validator->notEmpty('title')
  223. ->allowEmpty('title', 'create');
  224. $this->assertTrue($validator->isEmptyAllowed('title', true));
  225. $this->assertFalse($validator->isEmptyAllowed('title', false));
  226. }
  227. /**
  228. * Tests the allowEmpty method when passing a callback
  229. *
  230. * @return void
  231. */
  232. public function testAllowEmptyCallback()
  233. {
  234. $validator = new Validator;
  235. $allow = true;
  236. $validator->allowEmpty('title', function ($context) use (&$allow) {
  237. $this->assertEquals([], $context['data']);
  238. $this->assertEquals([], $context['providers']);
  239. $this->assertTrue($context['newRecord']);
  240. return $allow;
  241. });
  242. $this->assertTrue($validator->isEmptyAllowed('title', true));
  243. $allow = false;
  244. $this->assertFalse($validator->isEmptyAllowed('title', true));
  245. }
  246. /**
  247. * Tests the notEmpty method when passing a callback
  248. *
  249. * @return void
  250. */
  251. public function testNotEmptyCallback()
  252. {
  253. $validator = new Validator;
  254. $prevent = true;
  255. $validator->notEmpty('title', 'error message', function ($context) use (&$prevent) {
  256. $this->assertEquals([], $context['data']);
  257. $this->assertEquals([], $context['providers']);
  258. $this->assertFalse($context['newRecord']);
  259. return $prevent;
  260. });
  261. $this->assertFalse($validator->isEmptyAllowed('title', false));
  262. $prevent = false;
  263. $this->assertTrue($validator->isEmptyAllowed('title', false));
  264. }
  265. /**
  266. * Tests the isEmptyAllowed method
  267. *
  268. * @return void
  269. */
  270. public function testIsEmptyAllowed()
  271. {
  272. $validator = new Validator;
  273. $this->assertSame($validator, $validator->allowEmpty('title'));
  274. $this->assertTrue($validator->isEmptyAllowed('title', true));
  275. $this->assertTrue($validator->isEmptyAllowed('title', false));
  276. $validator->notEmpty('title');
  277. $this->assertFalse($validator->isEmptyAllowed('title', true));
  278. $this->assertFalse($validator->isEmptyAllowed('title', false));
  279. $validator->allowEmpty('title', 'create');
  280. $this->assertTrue($validator->isEmptyAllowed('title', true));
  281. $this->assertFalse($validator->isEmptyAllowed('title', false));
  282. $validator->allowEmpty('title', 'update');
  283. $this->assertTrue($validator->isEmptyAllowed('title', false));
  284. $this->assertFalse($validator->isEmptyAllowed('title', true));
  285. }
  286. /**
  287. * Tests errors generated when a field is not allowed to be empty
  288. *
  289. * @return void
  290. */
  291. public function testErrorsWithEmptyNotAllowed()
  292. {
  293. $validator = new Validator;
  294. $validator->notEmpty('title');
  295. $errors = $validator->errors(['title' => '']);
  296. $expected = ['title' => ['_empty' => 'This field cannot be left empty']];
  297. $this->assertEquals($expected, $errors);
  298. $errors = $validator->errors(['title' => []]);
  299. $expected = ['title' => ['_empty' => 'This field cannot be left empty']];
  300. $this->assertEquals($expected, $errors);
  301. $errors = $validator->errors(['title' => null]);
  302. $expected = ['title' => ['_empty' => 'This field cannot be left empty']];
  303. $this->assertEquals($expected, $errors);
  304. $errors = $validator->errors(['title' => 0]);
  305. $this->assertEmpty($errors);
  306. $errors = $validator->errors(['title' => '0']);
  307. $this->assertEmpty($errors);
  308. $errors = $validator->errors(['title' => false]);
  309. $this->assertEmpty($errors);
  310. }
  311. /**
  312. * Tests custom error mesages generated when a field is not allowed to be empty
  313. *
  314. * @return void
  315. */
  316. public function testCustomErrorsWithEmptyNotAllowed()
  317. {
  318. $validator = new Validator;
  319. $validator->notEmpty('title', 'Custom message');
  320. $errors = $validator->errors(['title' => '']);
  321. $expected = ['title' => ['_empty' => 'Custom message']];
  322. $this->assertEquals($expected, $errors);
  323. }
  324. /**
  325. * Tests errors generated when a field is allowed to be empty
  326. *
  327. * @return void
  328. */
  329. public function testErrorsWithEmptyAllowed()
  330. {
  331. $validator = new Validator;
  332. $validator->allowEmpty('title');
  333. $errors = $validator->errors(['title' => '']);
  334. $this->assertEmpty($errors);
  335. $errors = $validator->errors(['title' => []]);
  336. $this->assertEmpty($errors);
  337. $errors = $validator->errors(['title' => null]);
  338. $this->assertEmpty($errors);
  339. $errors = $validator->errors(['title' => 0]);
  340. $this->assertEmpty($errors);
  341. $errors = $validator->errors(['title' => 0.0]);
  342. $this->assertEmpty($errors);
  343. $errors = $validator->errors(['title' => '0']);
  344. $this->assertEmpty($errors);
  345. $errors = $validator->errors(['title' => false]);
  346. $this->assertEmpty($errors);
  347. }
  348. /**
  349. * Test the provider() method
  350. *
  351. * @return void
  352. */
  353. public function testProvider()
  354. {
  355. $validator = new Validator;
  356. $object = new \stdClass;
  357. $this->assertSame($validator, $validator->provider('foo', $object));
  358. $this->assertSame($object, $validator->provider('foo'));
  359. $this->assertNull($validator->provider('bar'));
  360. $another = new \stdClass;
  361. $this->assertSame($validator, $validator->provider('bar', $another));
  362. $this->assertSame($another, $validator->provider('bar'));
  363. $this->assertEquals(new \Cake\Validation\RulesProvider, $validator->provider('default'));
  364. }
  365. /**
  366. * Tests errors() method when using validators from the default provider, this proves
  367. * that it returns a default validation message and the custom one set in the rule
  368. *
  369. * @return void
  370. */
  371. public function testErrorsFromDefaultProvider()
  372. {
  373. $validator = new Validator;
  374. $validator
  375. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  376. ->add('email', 'notEmpty', ['rule' => 'notEmpty'])
  377. ->add('email', 'email', ['rule' => 'email', 'message' => 'Y u no write email?']);
  378. $errors = $validator->errors(['email' => 'not an email!']);
  379. $expected = [
  380. 'email' => [
  381. 'alpha' => 'The provided value is invalid',
  382. 'email' => 'Y u no write email?'
  383. ]
  384. ];
  385. $this->assertEquals($expected, $errors);
  386. }
  387. /**
  388. * Tests using validation methods from different providers and returning the error
  389. * as a string
  390. *
  391. * @return void
  392. */
  393. public function testErrorsFromCustomProvider()
  394. {
  395. $validator = new Validator;
  396. $validator
  397. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  398. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  399. $thing = $this->getMock('\stdClass', ['isCool']);
  400. $thing->expects($this->once())->method('isCool')
  401. ->will($this->returnCallback(function ($data, $context) use ($thing) {
  402. $this->assertEquals('bar', $data);
  403. $expected = [
  404. 'default' => new \Cake\Validation\RulesProvider,
  405. 'thing' => $thing
  406. ];
  407. $expected = [
  408. 'newRecord' => true,
  409. 'providers' => $expected,
  410. 'data' => [
  411. 'email' => '!',
  412. 'title' => 'bar'
  413. ],
  414. 'field' => 'title'
  415. ];
  416. $this->assertEquals($expected, $context);
  417. return "That ain't cool, yo";
  418. }));
  419. $validator->provider('thing', $thing);
  420. $errors = $validator->errors(['email' => '!', 'title' => 'bar']);
  421. $expected = [
  422. 'email' => ['alpha' => 'The provided value is invalid'],
  423. 'title' => ['cool' => "That ain't cool, yo"]
  424. ];
  425. $this->assertEquals($expected, $errors);
  426. }
  427. /**
  428. * Tests that it is possible to pass extra arguments to the validation function
  429. * and it still gets the providers as last argument
  430. *
  431. * @return void
  432. */
  433. public function testMethodsWithExtraArguments()
  434. {
  435. $validator = new Validator;
  436. $validator->add('title', 'cool', [
  437. 'rule' => ['isCool', 'and', 'awesome'],
  438. 'provider' => 'thing'
  439. ]);
  440. $thing = $this->getMock('\stdClass', ['isCool']);
  441. $thing->expects($this->once())->method('isCool')
  442. ->will($this->returnCallback(function ($data, $a, $b, $context) use ($thing) {
  443. $this->assertEquals('bar', $data);
  444. $this->assertEquals('and', $a);
  445. $this->assertEquals('awesome', $b);
  446. $expected = [
  447. 'default' => new \Cake\Validation\RulesProvider,
  448. 'thing' => $thing
  449. ];
  450. $expected = [
  451. 'newRecord' => true,
  452. 'providers' => $expected,
  453. 'data' => [
  454. 'email' => '!',
  455. 'title' => 'bar'
  456. ],
  457. 'field' => 'title'
  458. ];
  459. $this->assertEquals($expected, $context);
  460. return "That ain't cool, yo";
  461. }));
  462. $validator->provider('thing', $thing);
  463. $errors = $validator->errors(['email' => '!', 'title' => 'bar']);
  464. $expected = [
  465. 'title' => ['cool' => "That ain't cool, yo"]
  466. ];
  467. $this->assertEquals($expected, $errors);
  468. }
  469. /**
  470. * Tests that it is possible to use a closure as a rule
  471. *
  472. * @return void
  473. */
  474. public function testUsingClosureAsRule()
  475. {
  476. $validator = new Validator;
  477. $validator->add('name', 'myRule', [
  478. 'rule' => function ($data, $provider) {
  479. $this->assertEquals('foo', $data);
  480. return 'You fail';
  481. }
  482. ]);
  483. $expected = ['name' => ['myRule' => 'You fail']];
  484. $this->assertEquals($expected, $validator->errors(['name' => 'foo']));
  485. }
  486. /**
  487. * Tests that setting last to a rule will stop validating the rest of the rules
  488. *
  489. * @return void
  490. */
  491. public function testErrorsWithLastRule()
  492. {
  493. $validator = new Validator;
  494. $validator
  495. ->add('email', 'alpha', ['rule' => 'alphanumeric', 'last' => true])
  496. ->add('email', 'email', ['rule' => 'email', 'message' => 'Y u no write email?']);
  497. $errors = $validator->errors(['email' => 'not an email!']);
  498. $expected = [
  499. 'email' => [
  500. 'alpha' => 'The provided value is invalid'
  501. ]
  502. ];
  503. $this->assertEquals($expected, $errors);
  504. }
  505. /**
  506. * Tests it is possible to get validation sets for a field using an array interface
  507. *
  508. * @return void
  509. */
  510. public function testArrayAccessGet()
  511. {
  512. $validator = new Validator;
  513. $validator
  514. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  515. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  516. $this->assertSame($validator['email'], $validator->field('email'));
  517. $this->assertSame($validator['title'], $validator->field('title'));
  518. }
  519. /**
  520. * Tests it is possible to check for validation sets for a field using an array inteface
  521. *
  522. * @return void
  523. */
  524. public function testArrayAccessExists()
  525. {
  526. $validator = new Validator;
  527. $validator
  528. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  529. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  530. $this->assertTrue(isset($validator['email']));
  531. $this->assertTrue(isset($validator['title']));
  532. $this->assertFalse(isset($validator['foo']));
  533. }
  534. /**
  535. * Tests it is possible to set validation rules for a field using an array inteface
  536. *
  537. * @return void
  538. */
  539. public function testArrayAccessSet()
  540. {
  541. $validator = new Validator;
  542. $validator
  543. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  544. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  545. $validator['name'] = $validator->field('title');
  546. $this->assertSame($validator->field('title'), $validator->field('name'));
  547. $validator['name'] = ['alpha' => ['rule' => 'alphanumeric']];
  548. $this->assertEquals($validator->field('email'), $validator->field('email'));
  549. }
  550. /**
  551. * Tests it is possible to unset validation rules
  552. *
  553. * @return void
  554. */
  555. public function testArrayAccessUset()
  556. {
  557. $validator = new Validator;
  558. $validator
  559. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  560. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  561. $this->assertTrue(isset($validator['title']));
  562. unset($validator['title']);
  563. $this->assertFalse(isset($validator['title']));
  564. }
  565. /**
  566. * Tests the countable interface
  567. *
  568. * @return void
  569. */
  570. public function testCount()
  571. {
  572. $validator = new Validator;
  573. $validator
  574. ->add('email', 'alpha', ['rule' => 'alphanumeric'])
  575. ->add('title', 'cool', ['rule' => 'isCool', 'provider' => 'thing']);
  576. $this->assertCount(2, $validator);
  577. }
  578. /**
  579. * Tests adding rules via alternative syntax
  580. *
  581. * @return void
  582. */
  583. public function testAddMulitple()
  584. {
  585. $validator = new Validator;
  586. $validator->add('title', [
  587. 'notEmpty' => [
  588. 'rule' => 'notEmpty'
  589. ],
  590. 'length' => [
  591. 'rule' => ['minLength', 10],
  592. 'message' => 'Titles need to be at least 10 characters long'
  593. ]
  594. ]);
  595. $set = $validator->field('title');
  596. $this->assertInstanceOf('Cake\Validation\ValidationSet', $set);
  597. $this->assertCount(2, $set);
  598. }
  599. /**
  600. * Integration test for compareWith validator.
  601. *
  602. * @return void
  603. */
  604. public function testCompareWithIntegration()
  605. {
  606. $validator = new Validator;
  607. $validator->add('password', [
  608. 'compare' => [
  609. 'rule' => ['compareWith', 'password_compare']
  610. ],
  611. ]);
  612. $data = [
  613. 'password' => 'test',
  614. 'password_compare' => 'not the same'
  615. ];
  616. $this->assertNotEmpty($validator->errors($data), 'Validation should fail.');
  617. }
  618. }