PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/web/core/modules/user/tests/src/Kernel/UserValidationTest.php

https://gitlab.com/mohamed_hussein/prodt
PHP | 229 lines | 138 code | 26 blank | 65 comment | 1 complexity | b46a5d4ceadb2d434f374b711a61850c MD5 | raw file
  1. <?php
  2. namespace Drupal\Tests\user\Kernel;
  3. use Drupal\Core\Entity\EntityInterface;
  4. use Drupal\Core\Language\Language;
  5. use Drupal\Core\Render\Element\Email;
  6. use Drupal\KernelTests\KernelTestBase;
  7. use Drupal\user\Entity\Role;
  8. use Drupal\user\Entity\User;
  9. use Drupal\user\UserInterface;
  10. /**
  11. * Verify that user validity checks behave as designed.
  12. *
  13. * @group user
  14. */
  15. class UserValidationTest extends KernelTestBase {
  16. /**
  17. * Modules to enable.
  18. *
  19. * @var array
  20. */
  21. protected static $modules = ['field', 'user', 'system'];
  22. /**
  23. * {@inheritdoc}
  24. */
  25. protected function setUp(): void {
  26. parent::setUp();
  27. $this->installEntitySchema('user');
  28. $this->installSchema('system', ['sequences']);
  29. // Make sure that the default roles exist.
  30. $this->installConfig(['user']);
  31. }
  32. /**
  33. * Tests user name validation.
  34. */
  35. public function testUsernames() {
  36. // cSpell:disable
  37. $test_cases = [
  38. // '<username>' => ['<description>', 'assert<testName>'].
  39. 'foo' => ['Valid username', 'assertNull'],
  40. 'FOO' => ['Valid username', 'assertNull'],
  41. 'Foo O\'Bar' => ['Valid username', 'assertNull'],
  42. 'foo@bar' => ['Valid username', 'assertNull'],
  43. 'foo@example.com' => ['Valid username', 'assertNull'],
  44. // invalid domains are allowed in usernames.
  45. 'foo@-example.com' => ['Valid username', 'assertNull'],
  46. 'þòøÇߪř€' => ['Valid username', 'assertNull'],
  47. // '+' symbol is allowed.
  48. 'foo+bar' => ['Valid username', 'assertNull'],
  49. // runes.
  50. 'ᚠᛇᚻ᛫ᛒᛦᚦ' => ['Valid UTF8 username', 'assertNull'],
  51. ' foo' => ['Invalid username that starts with a space', 'assertNotNull'],
  52. 'foo ' => ['Invalid username that ends with a space', 'assertNotNull'],
  53. 'foo bar' => ['Invalid username that contains 2 spaces \'&nbsp;&nbsp;\'', 'assertNotNull'],
  54. '' => ['Invalid empty username', 'assertNotNull'],
  55. 'foo/' => ['Invalid username containing invalid chars', 'assertNotNull'],
  56. // NULL.
  57. 'foo' . chr(0) . 'bar' => ['Invalid username containing chr(0)', 'assertNotNull'],
  58. // CR.
  59. 'foo' . chr(13) . 'bar' => ['Invalid username containing chr(13)', 'assertNotNull'],
  60. str_repeat('x', UserInterface::USERNAME_MAX_LENGTH + 1) => ['Invalid excessively long username', 'assertNotNull'],
  61. ];
  62. // cSpell:enable
  63. foreach ($test_cases as $name => $test_case) {
  64. [$description, $test] = $test_case;
  65. $result = user_validate_name($name);
  66. $this->$test($result, $description . ' (' . $name . ')');
  67. }
  68. }
  69. /**
  70. * Runs entity validation checks.
  71. */
  72. public function testValidation() {
  73. $user = User::create([
  74. 'name' => 'test',
  75. 'mail' => 'test@example.com',
  76. ]);
  77. $violations = $user->validate();
  78. $this->assertCount(0, $violations, 'No violations when validating a default user.');
  79. // Only test one example invalid name here, the rest is already covered in
  80. // the testUsernames() method in this class.
  81. $name = $this->randomMachineName(61);
  82. $user->set('name', $name);
  83. $violations = $user->validate();
  84. $this->assertCount(1, $violations, 'Violation found when name is too long.');
  85. $this->assertEquals('name', $violations[0]->getPropertyPath());
  86. $this->assertEquals(t('The username %name is too long: it must be %max characters or less.', ['%name' => $name, '%max' => 60]), $violations[0]->getMessage());
  87. // Create a second test user to provoke a name collision.
  88. $user2 = User::create([
  89. 'name' => 'existing',
  90. 'mail' => 'existing@example.com',
  91. ]);
  92. $user2->save();
  93. $user->set('name', 'existing');
  94. $violations = $user->validate();
  95. $this->assertCount(1, $violations, 'Violation found on name collision.');
  96. $this->assertEquals('name', $violations[0]->getPropertyPath());
  97. $this->assertEquals(t('The username %name is already taken.', ['%name' => 'existing']), $violations[0]->getMessage());
  98. // Make the name valid.
  99. $user->set('name', $this->randomMachineName());
  100. $user->set('mail', 'invalid');
  101. $violations = $user->validate();
  102. $this->assertCount(1, $violations, 'Violation found when email is invalid');
  103. $this->assertEquals('mail.0.value', $violations[0]->getPropertyPath());
  104. $this->assertEquals('This value is not a valid email address.', $violations[0]->getMessage());
  105. $mail = $this->randomMachineName(Email::EMAIL_MAX_LENGTH - 11) . '@example.com';
  106. $user->set('mail', $mail);
  107. $violations = $user->validate();
  108. // @todo There are two violations because EmailItem::getConstraints()
  109. // overlaps with the implicit constraint of the 'email' property type used
  110. // in EmailItem::propertyDefinitions(). Resolve this in
  111. // https://www.drupal.org/node/2023465.
  112. $this->assertCount(2, $violations, 'Violations found when email is too long');
  113. $this->assertEquals('mail.0.value', $violations[0]->getPropertyPath());
  114. $this->assertEquals(t('%name: the email address can not be longer than @max characters.', ['%name' => $user->get('mail')->getFieldDefinition()->getLabel(), '@max' => Email::EMAIL_MAX_LENGTH]), $violations[0]->getMessage());
  115. $this->assertEquals('mail.0.value', $violations[1]->getPropertyPath());
  116. $this->assertEquals('This value is not a valid email address.', $violations[1]->getMessage());
  117. // Provoke an email collision with an existing user.
  118. $user->set('mail', 'existing@example.com');
  119. $violations = $user->validate();
  120. $this->assertCount(1, $violations, 'Violation found when email already exists.');
  121. $this->assertEquals('mail', $violations[0]->getPropertyPath());
  122. $this->assertEquals(t('The email address %mail is already taken.', ['%mail' => 'existing@example.com']), $violations[0]->getMessage());
  123. $user->set('mail', NULL);
  124. $violations = $user->validate();
  125. $this->assertCount(1, $violations, 'Email addresses may not be removed');
  126. $this->assertEquals('mail', $violations[0]->getPropertyPath());
  127. $this->assertEquals(t('@name field is required.', ['@name' => $user->getFieldDefinition('mail')->getLabel()]), $violations[0]->getMessage());
  128. $user->set('mail', 'someone@example.com');
  129. $user->set('timezone', $this->randomString(33));
  130. $this->assertLengthViolation($user, 'timezone', 32, 2, 1);
  131. $user->set('timezone', 'invalid zone');
  132. $this->assertAllowedValuesViolation($user, 'timezone');
  133. $user->set('timezone', NULL);
  134. $user->set('init', 'invalid');
  135. $violations = $user->validate();
  136. $this->assertCount(1, $violations, 'Violation found when init email is invalid');
  137. $user->set('init', NULL);
  138. $user->set('langcode', 'invalid');
  139. $this->assertAllowedValuesViolation($user, 'langcode');
  140. $user->set('langcode', NULL);
  141. // Only configurable langcodes are allowed for preferred languages.
  142. $user->set('preferred_langcode', Language::LANGCODE_NOT_SPECIFIED);
  143. $this->assertAllowedValuesViolation($user, 'preferred_langcode');
  144. $user->set('preferred_langcode', NULL);
  145. $user->set('preferred_admin_langcode', Language::LANGCODE_NOT_SPECIFIED);
  146. $this->assertAllowedValuesViolation($user, 'preferred_admin_langcode');
  147. $user->set('preferred_admin_langcode', NULL);
  148. Role::create(['id' => 'role1', 'label' => 'Role 1'])->save();
  149. Role::create(['id' => 'role2', 'label' => 'Role 2'])->save();
  150. // Test cardinality of user roles.
  151. $user = User::create([
  152. 'name' => 'role_test',
  153. 'mail' => 'test@example.com',
  154. 'roles' => ['role1', 'role2'],
  155. ]);
  156. $violations = $user->validate();
  157. $this->assertCount(0, $violations);
  158. $user->roles[1]->target_id = 'unknown_role';
  159. $violations = $user->validate();
  160. $this->assertCount(1, $violations);
  161. $this->assertEquals('roles.1.target_id', $violations[0]->getPropertyPath());
  162. $this->assertEquals(t('The referenced entity (%entity_type: %name) does not exist.', ['%entity_type' => 'user_role', '%name' => 'unknown_role']), $violations[0]->getMessage());
  163. }
  164. /**
  165. * Verifies that a length violation exists for the given field.
  166. *
  167. * @param \Drupal\Core\Entity\EntityInterface $entity
  168. * The entity object to validate.
  169. * @param string $field_name
  170. * The field that violates the maximum length.
  171. * @param int $length
  172. * Number of characters that was exceeded.
  173. * @param int $count
  174. * (optional) The number of expected violations. Defaults to 1.
  175. * @param int $expected_index
  176. * (optional) The index at which to expect the violation. Defaults to 0.
  177. *
  178. * @internal
  179. */
  180. protected function assertLengthViolation(EntityInterface $entity, string $field_name, int $length, int $count = 1, int $expected_index = 0): void {
  181. $violations = $entity->validate();
  182. $this->assertCount($count, $violations, "Violation found when $field_name is too long.");
  183. $this->assertEquals("{$field_name}.0.value", $violations[$expected_index]->getPropertyPath());
  184. $field_label = $entity->get($field_name)->getFieldDefinition()->getLabel();
  185. $this->assertEquals(t('%name: may not be longer than @max characters.', ['%name' => $field_label, '@max' => $length]), $violations[$expected_index]->getMessage());
  186. }
  187. /**
  188. * Verifies that an AllowedValues violation exists for the given field.
  189. *
  190. * @param \Drupal\Core\Entity\EntityInterface $entity
  191. * The entity object to validate.
  192. * @param string $field_name
  193. * The name of the field to verify.
  194. *
  195. * @internal
  196. */
  197. protected function assertAllowedValuesViolation(EntityInterface $entity, string $field_name): void {
  198. $violations = $entity->validate();
  199. $this->assertCount(1, $violations, "Allowed values violation for $field_name found.");
  200. $this->assertEquals($field_name === 'langcode' ? "{$field_name}.0" : "{$field_name}.0.value", $violations[0]->getPropertyPath());
  201. $this->assertEquals('The value you selected is not a valid choice.', $violations[0]->getMessage());
  202. }
  203. }