ValidationPasswordRuleTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. <?php
  2. namespace Illuminate\Tests\Validation;
  3. use Illuminate\Container\Container;
  4. use Illuminate\Support\Facades\Facade;
  5. use Illuminate\Translation\ArrayLoader;
  6. use Illuminate\Translation\Translator;
  7. use Illuminate\Validation\Rules\Password;
  8. use Illuminate\Validation\ValidationServiceProvider;
  9. use Illuminate\Validation\Validator;
  10. use PHPUnit\Framework\TestCase;
  11. class ValidationPasswordRuleTest extends TestCase
  12. {
  13. public function testString()
  14. {
  15. $this->fails(Password::min(3), [['foo' => 'bar'], ['foo']], [
  16. 'validation.string',
  17. 'validation.min.string',
  18. ]);
  19. $this->fails(Password::min(3), [1234567, 545], [
  20. 'validation.string',
  21. ]);
  22. $this->passes(Password::min(3), ['abcd', '454qb^', '接2133手田']);
  23. }
  24. public function testMin()
  25. {
  26. $this->fails(new Password(8), ['a', 'ff', '12'], [
  27. 'validation.min.string',
  28. ]);
  29. $this->fails(Password::min(3), ['a', 'ff', '12'], [
  30. 'validation.min.string',
  31. ]);
  32. $this->passes(Password::min(3), ['333', 'abcd']);
  33. $this->passes(new Password(8), ['88888888']);
  34. }
  35. public function testConditional()
  36. {
  37. $is_privileged_user = true;
  38. $rule = (new Password(8))->when($is_privileged_user, function ($rule) {
  39. $rule->symbols();
  40. });
  41. $this->fails($rule, ['aaaaaaaa', '11111111'], [
  42. 'The my password must contain at least one symbol.',
  43. ]);
  44. $is_privileged_user = false;
  45. $rule = (new Password(8))->when($is_privileged_user, function ($rule) {
  46. $rule->symbols();
  47. });
  48. $this->passes($rule, ['aaaaaaaa', '11111111']);
  49. }
  50. public function testMixedCase()
  51. {
  52. $this->fails(Password::min(2)->mixedCase(), ['nn', 'MM'], [
  53. 'The my password must contain at least one uppercase and one lowercase letter.',
  54. ]);
  55. $this->passes(Password::min(2)->mixedCase(), ['Nn', 'Mn', 'âA']);
  56. }
  57. public function testLetters()
  58. {
  59. $this->fails(Password::min(2)->letters(), ['11', '22', '^^', '``', '**'], [
  60. 'The my password must contain at least one letter.',
  61. ]);
  62. $this->passes(Password::min(2)->letters(), ['1a', 'b2', 'â1', '1 京都府']);
  63. }
  64. public function testNumbers()
  65. {
  66. $this->fails(Password::min(2)->numbers(), ['aa', 'bb', ' a', '京都府'], [
  67. 'The my password must contain at least one number.',
  68. ]);
  69. $this->passes(Password::min(2)->numbers(), ['1a', 'b2', '00', '京都府 1']);
  70. }
  71. public function testDefaultRules()
  72. {
  73. $this->fails(Password::min(3), [null], [
  74. 'validation.string',
  75. 'validation.min.string',
  76. ]);
  77. }
  78. public function testSymbols()
  79. {
  80. $this->fails(Password::min(2)->symbols(), ['ab', '1v'], [
  81. 'The my password must contain at least one symbol.',
  82. ]);
  83. $this->passes(Password::min(2)->symbols(), ['n^d', 'd^!', 'âè$', '金廿土弓竹中;']);
  84. }
  85. // public function testUncompromised()
  86. // {
  87. // $this->fails(Password::min(2)->uncompromised(), [
  88. // '123456',
  89. // 'password',
  90. // 'welcome',
  91. // 'abc123',
  92. // '123456789',
  93. // '12345678',
  94. // 'nuno',
  95. // ], [
  96. // 'The given my password has appeared in a data leak. Please choose a different my password.',
  97. // ]);
  98. // $this->passes(Password::min(2)->uncompromised(9999999), [
  99. // 'nuno',
  100. // ]);
  101. // $this->passes(Password::min(2)->uncompromised(), [
  102. // '手田日尸Z難金木水口火女月土廿卜竹弓一十山',
  103. // '!p8VrB',
  104. // '&xe6VeKWF#n4',
  105. // '%HurHUnw7zM!',
  106. // 'rundeliekend',
  107. // '7Z^k5EvqQ9g%c!Jt9$ufnNpQy#Kf',
  108. // 'NRs*Gz2@hSmB$vVBSPDfqbRtEzk4nF7ZAbM29VMW$BPD%b2U%3VmJAcrY5eZGVxP%z%apnwSX',
  109. // ]);
  110. // }
  111. public function testMessagesOrder()
  112. {
  113. $makeRules = function () {
  114. return ['required', Password::min(8)->mixedCase()->numbers()];
  115. };
  116. $this->fails($makeRules(), [null], [
  117. 'validation.required',
  118. ]);
  119. $this->fails($makeRules(), ['foo', 'azdazd'], [
  120. 'validation.min.string',
  121. 'The my password must contain at least one uppercase and one lowercase letter.',
  122. 'The my password must contain at least one number.',
  123. ]);
  124. $this->fails($makeRules(), ['1231231'], [
  125. 'validation.min.string',
  126. 'The my password must contain at least one uppercase and one lowercase letter.',
  127. ]);
  128. $this->fails($makeRules(), ['4564654564564'], [
  129. 'The my password must contain at least one uppercase and one lowercase letter.',
  130. ]);
  131. $this->fails($makeRules(), ['aaaaaaaaa', 'TJQSJQSIUQHS'], [
  132. 'The my password must contain at least one uppercase and one lowercase letter.',
  133. 'The my password must contain at least one number.',
  134. ]);
  135. $this->passes($makeRules(), ['4564654564564Abc']);
  136. $makeRules = function () {
  137. return ['nullable', 'confirmed', Password::min(8)->letters()->symbols()->uncompromised()];
  138. };
  139. $this->passes($makeRules(), [null]);
  140. $this->fails($makeRules(), ['foo', 'azdazd'], [
  141. 'validation.min.string',
  142. 'The my password must contain at least one symbol.',
  143. ]);
  144. $this->fails($makeRules(), ['1231231'], [
  145. 'validation.min.string',
  146. 'The my password must contain at least one letter.',
  147. 'The my password must contain at least one symbol.',
  148. ]);
  149. $this->fails($makeRules(), ['aaaaaaaaa', 'TJQSJQSIUQHS'], [
  150. 'The my password must contain at least one symbol.',
  151. ]);
  152. $this->fails($makeRules(), ['4564654564564'], [
  153. 'The my password must contain at least one letter.',
  154. 'The my password must contain at least one symbol.',
  155. ]);
  156. $this->fails($makeRules(), ['abcabcabc!'], [
  157. 'The given my password has appeared in a data leak. Please choose a different my password.',
  158. ]);
  159. $v = new Validator(
  160. resolve('translator'),
  161. ['my_password' => 'Nuno'],
  162. ['my_password' => ['nullable', 'confirmed', Password::min(3)->letters()]]
  163. );
  164. $this->assertFalse($v->passes());
  165. $this->assertSame(
  166. ['my_password' => ['validation.confirmed']],
  167. $v->messages()->toArray()
  168. );
  169. }
  170. public function testItCanUseDefault()
  171. {
  172. $this->assertInstanceOf(Password::class, Password::default());
  173. }
  174. public function testItCanSetDefaultUsing()
  175. {
  176. $this->assertInstanceOf(Password::class, Password::default());
  177. $password = Password::min(3);
  178. $password2 = Password::min(2)->mixedCase();
  179. Password::defaults(function () use ($password) {
  180. return $password;
  181. });
  182. $this->passes(Password::default(), ['abcd', '454qb^', '接2133手田']);
  183. $this->assertSame($password, Password::default());
  184. $this->assertSame(['required', $password], Password::required());
  185. $this->assertSame(['sometimes', $password], Password::sometimes());
  186. Password::defaults($password2);
  187. $this->passes(Password::default(), ['Nn', 'Mn', 'âA']);
  188. $this->assertSame($password2, Password::default());
  189. $this->assertSame(['required', $password2], Password::required());
  190. $this->assertSame(['sometimes', $password2], Password::sometimes());
  191. }
  192. public function testItCannotSetDefaultUsingGivenString()
  193. {
  194. $this->expectException('InvalidArgumentException');
  195. $this->expectExceptionMessage('given callback should be callable');
  196. Password::defaults('required|password');
  197. }
  198. public function testItPassesWithValidDataIfTheSameValidationRulesAreReused()
  199. {
  200. $rules = [
  201. 'password' => Password::default(),
  202. ];
  203. $v = new Validator(
  204. resolve('translator'),
  205. ['password' => '1234'],
  206. $rules
  207. );
  208. $this->assertFalse($v->passes());
  209. $v1 = new Validator(
  210. resolve('translator'),
  211. ['password' => '12341234'],
  212. $rules
  213. );
  214. $this->assertTrue($v1->passes());
  215. }
  216. public function testPassesWithCustomRules()
  217. {
  218. $closureRule = function ($attribute, $value, $fail) {
  219. if ($value !== 'aa') {
  220. $fail('Custom rule closure failed');
  221. }
  222. };
  223. $ruleObject = new class implements \Illuminate\Contracts\Validation\Rule
  224. {
  225. public function passes($attribute, $value)
  226. {
  227. return $value === 'aa';
  228. }
  229. public function message()
  230. {
  231. return 'Custom rule object failed';
  232. }
  233. };
  234. $this->passes(Password::min(2)->rules($closureRule), ['aa']);
  235. $this->passes(Password::min(2)->rules([$closureRule]), ['aa']);
  236. $this->passes(Password::min(2)->rules($ruleObject), ['aa']);
  237. $this->passes(Password::min(2)->rules([$closureRule, $ruleObject]), ['aa']);
  238. $this->fails(Password::min(2)->rules($closureRule), ['ab'], [
  239. 'Custom rule closure failed',
  240. ]);
  241. $this->fails(Password::min(2)->rules($ruleObject), ['ab'], [
  242. 'Custom rule object failed',
  243. ]);
  244. }
  245. protected function passes($rule, $values)
  246. {
  247. $this->assertValidationRules($rule, $values, true, []);
  248. }
  249. protected function fails($rule, $values, $messages)
  250. {
  251. $this->assertValidationRules($rule, $values, false, $messages);
  252. }
  253. protected function assertValidationRules($rule, $values, $result, $messages)
  254. {
  255. foreach ($values as $value) {
  256. $v = new Validator(
  257. resolve('translator'),
  258. ['my_password' => $value, 'my_password_confirmation' => $value],
  259. ['my_password' => is_object($rule) ? clone $rule : $rule]
  260. );
  261. $this->assertSame($result, $v->passes());
  262. $this->assertSame(
  263. $result ? [] : ['my_password' => $messages],
  264. $v->messages()->toArray()
  265. );
  266. }
  267. }
  268. protected function setUp(): void
  269. {
  270. $container = Container::getInstance();
  271. $container->bind('translator', function () {
  272. return new Translator(
  273. new ArrayLoader, 'en'
  274. );
  275. });
  276. Facade::setFacadeApplication($container);
  277. (new ValidationServiceProvider($container))->register();
  278. }
  279. protected function tearDown(): void
  280. {
  281. Container::setInstance(null);
  282. Facade::clearResolvedInstances();
  283. Facade::setFacadeApplication(null);
  284. Password::$defaultCallback = null;
  285. }
  286. }