diff --git a/core/modules/user/src/Plugin/Validation/Constraint/ProtectedUserFieldConstraintValidator.php b/core/modules/user/src/Plugin/Validation/Constraint/ProtectedUserFieldConstraintValidator.php index 3198ea7..5b7e43b 100644 --- a/core/modules/user/src/Plugin/Validation/Constraint/ProtectedUserFieldConstraintValidator.php +++ b/core/modules/user/src/Plugin/Validation/Constraint/ProtectedUserFieldConstraintValidator.php @@ -85,7 +85,8 @@ public function validate($items, Constraint $constraint) { // Special case for the password, it being empty means that the existing // password should not be changed, ignore empty password fields. - if ($field->getName() != 'pass' || !$items->isEmpty()) { + $value = $items->value; + if ($field->getName() != 'pass' || !empty($value)) { // Compare the values of the field this is being validated on. $changed = $items->getValue() != $account_unchanged->get($field->getName())->getValue(); } diff --git a/core/modules/user/tests/src/Unit/Plugin/Validation/Constraint/ProtectedUserFieldConstraintValidatorTest.php b/core/modules/user/tests/src/Unit/Plugin/Validation/Constraint/ProtectedUserFieldConstraintValidatorTest.php index 1a81ed7..46dfa25 100644 --- a/core/modules/user/tests/src/Unit/Plugin/Validation/Constraint/ProtectedUserFieldConstraintValidatorTest.php +++ b/core/modules/user/tests/src/Unit/Plugin/Validation/Constraint/ProtectedUserFieldConstraintValidatorTest.php @@ -57,16 +57,28 @@ public function setUp() { /** * @covers ::validate + * + * @dataProvider providerTestValidate */ - public function testValidate() { - // The validation method should not add a violation in any of the following. + public function testValidate($items, $expected_violation) { + // If a violation is expected, then the context's addViolation method will + // be called, otherwise it should not be called. $context = $this->getMock('Symfony\Component\Validator\ExecutionContextInterface'); - $context->expects($this->never()) + $context->expects($expected_violation ? $this->once() : $this->never()) ->method('addViolation'); $this->validator->initialize($context); + $this->validator->validate($items, $this->constraint); + } + + /** + * Data provider for ::testValidate(). + */ + public function providerTestValidate() { + $cases = []; + // Case 1: Validation context should not be touched if no items are passed. - $this->validator->validate(NULL, $this->constraint); + $cases[] = [NULL, FALSE]; // Case 2: Empty user should be ignored. $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface'); @@ -77,7 +89,7 @@ public function testValidate() { $items->expects($this->once()) ->method('getEntity') ->willReturn(NULL); - $this->validator->validate($items, $this->constraint); + $cases[] = [$items, FALSE]; // Case 3: Account flagged to skip protected user should be ignored. $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface'); @@ -90,7 +102,7 @@ public function testValidate() { $items->expects($this->once()) ->method('getEntity') ->willReturn($account); - $this->validator->validate($items, $this->constraint); + $cases[] = [$items, FALSE]; // Case 4: New user should be ignored. $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface'); @@ -105,7 +117,7 @@ public function testValidate() { $items->expects($this->once()) ->method('getEntity') ->willReturn($account); - $this->validator->validate($items, $this->constraint); + $cases[] = [$items, FALSE]; // Case 5: Mismatching user IDs should also be ignored. $account = $this->getMock('Drupal\user\UserInterface'); @@ -122,7 +134,7 @@ public function testValidate() { $items->expects($this->once()) ->method('getEntity') ->willReturn($account); - $this->validator->validate($items, $this->constraint); + $cases[] = [$items, FALSE]; // Case 6: Non-password fields that have not changed should be ignored. $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface'); @@ -148,7 +160,7 @@ public function testValidate() { $items->expects($this->once()) ->method('getValue') ->willReturn('unchanged-value'); - $this->validator->validate($items, $this->constraint); + $cases[] = [$items, FALSE]; // Case 7: Password field with no value set should be ignored. $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface'); @@ -171,11 +183,7 @@ public function testValidate() { $items->expects($this->once()) ->method('getEntity') ->willReturn($account); - $items->expects($this->once()) - ->method('isEmpty') - ->willReturn(TRUE); - $items->value = NULL; - $this->validator->validate($items, $this->constraint); + $cases[] = [$items, FALSE]; // Case 8: Non-password field changed, but user has passed provided current // password. @@ -203,9 +211,9 @@ public function testValidate() { $items->expects($this->once()) ->method('getValue') ->willReturn('changed-value'); - $this->validator->validate($items, $this->constraint); + $cases[] = [$items, FALSE]; - // Case 10: Password field changed, current password confirmed. + // Case 9: Password field changed, current password confirmed. $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface'); $field_definition->expects($this->exactly(2)) ->method('getName') @@ -227,21 +235,18 @@ public function testValidate() { $items->expects($this->once()) ->method('getEntity') ->willReturn($account); - $items->expects($this->once()) + $items->expects($this->any()) ->method('getValue') ->willReturn('changed-value'); $items->expects($this->once()) - ->method('isEmpty') - ->willReturn(FALSE); - $this->validator->validate($items, $this->constraint); + ->method('__get') + ->with('value') + ->willReturn('changed-value'); + $cases[] = [$items, FALSE]; // The below calls should result in a violation. - $context = $this->getMock('Symfony\Component\Validator\ExecutionContextInterface'); - $context->expects($this->once()) - ->method('addViolation'); - $this->validator->initialize($context); - // Case 11: Password field changed, current password not confirmed. + // Case 10: Password field changed, current password not confirmed. $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface'); $field_definition->expects($this->exactly(2)) ->method('getName') @@ -267,15 +272,12 @@ public function testValidate() { ->method('getValue') ->willReturn('changed-value'); $items->expects($this->once()) - ->method('isEmpty') - ->willReturn(FALSE); - $this->validator->validate($items, $this->constraint); + ->method('__get') + ->with('value') + ->willReturn('changed-value'); + $cases[] = [$items, TRUE]; - // Case 12: Non-password field changed, current password not confirmed. - $context = $this->getMock('Symfony\Component\Validator\ExecutionContextInterface'); - $context->expects($this->once()) - ->method('addViolation'); - $this->validator->initialize($context); + // Case 11: Non-password field changed, current password not confirmed. $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface'); $field_definition->expects($this->exactly(2)) ->method('getName') @@ -300,7 +302,9 @@ public function testValidate() { $items->expects($this->once()) ->method('getValue') ->willReturn('changed-value'); - $this->validator->validate($items, $this->constraint); + $cases[] = [$items, TRUE]; + + return $cases; } }