123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- <?php
- namespace Drupal\Tests\Core\Form;
- use Drupal\Core\Form\FormState;
- use Drupal\Tests\UnitTestCase;
- use Symfony\Component\HttpFoundation\Request;
- use Symfony\Component\HttpFoundation\RequestStack;
- /**
- * @coversDefaultClass \Drupal\Core\Form\FormValidator
- * @group Form
- */
- class FormValidatorTest extends UnitTestCase {
- /**
- * A logger instance.
- *
- * @var \Psr\Log\LoggerInterface|\PHPUnit\Framework\MockObject\MockObject
- */
- protected $logger;
- /**
- * The CSRF token generator to validate the form token.
- *
- * @var \Drupal\Core\Access\CsrfTokenGenerator|\PHPUnit\Framework\MockObject\MockObject
- */
- protected $csrfToken;
- /**
- * The form error handler.
- *
- * @var \Drupal\Core\Form\FormErrorHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
- */
- protected $formErrorHandler;
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
- $this->logger = $this->createMock('Psr\Log\LoggerInterface');
- $this->csrfToken = $this->getMockBuilder('Drupal\Core\Access\CsrfTokenGenerator')
- ->disableOriginalConstructor()
- ->getMock();
- $this->formErrorHandler = $this->createMock('Drupal\Core\Form\FormErrorHandlerInterface');
- }
- /**
- * Tests the 'validation_complete' $form_state flag.
- *
- * @covers ::validateForm
- * @covers ::finalizeValidation
- */
- public function testValidationComplete() {
- $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
- ->setConstructorArgs([new RequestStack(), $this->getStringTranslationStub(), $this->csrfToken, $this->logger, $this->formErrorHandler])
- ->setMethods(NULL)
- ->getMock();
- $form = [];
- $form_state = new FormState();
- $this->assertFalse($form_state->isValidationComplete());
- $form_validator->validateForm('test_form_id', $form, $form_state);
- $this->assertTrue($form_state->isValidationComplete());
- }
- /**
- * Tests the 'must_validate' $form_state flag.
- *
- * @covers ::validateForm
- */
- public function testPreventDuplicateValidation() {
- $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
- ->setConstructorArgs([new RequestStack(), $this->getStringTranslationStub(), $this->csrfToken, $this->logger, $this->formErrorHandler])
- ->setMethods(['doValidateForm'])
- ->getMock();
- $form_validator->expects($this->never())
- ->method('doValidateForm');
- $form = [];
- $form_state = (new FormState())
- ->setValidationComplete();
- $form_validator->validateForm('test_form_id', $form, $form_state);
- $this->assertArrayNotHasKey('#errors', $form);
- }
- /**
- * Tests the 'must_validate' $form_state flag.
- *
- * @covers ::validateForm
- */
- public function testMustValidate() {
- $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
- ->setConstructorArgs([new RequestStack(), $this->getStringTranslationStub(), $this->csrfToken, $this->logger, $this->formErrorHandler])
- ->setMethods(['doValidateForm'])
- ->getMock();
- $form_validator->expects($this->once())
- ->method('doValidateForm');
- $this->formErrorHandler->expects($this->once())
- ->method('handleFormErrors');
- $form = [];
- $form_state = (new FormState())
- ->setValidationComplete()
- ->setValidationEnforced();
- $form_validator->validateForm('test_form_id', $form, $form_state);
- }
- /**
- * @covers ::validateForm
- */
- public function testValidateInvalidFormToken() {
- $request_stack = new RequestStack();
- $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/test/example?foo=bar']);
- $request_stack->push($request);
- $this->csrfToken->expects($this->once())
- ->method('validate')
- ->will($this->returnValue(FALSE));
- $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
- ->setConstructorArgs([$request_stack, $this->getStringTranslationStub(), $this->csrfToken, $this->logger, $this->formErrorHandler])
- ->setMethods(['doValidateForm'])
- ->getMock();
- $form_validator->expects($this->never())
- ->method('doValidateForm');
- $form['#token'] = 'test_form_id';
- $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
- ->setMethods(['setErrorByName'])
- ->getMock();
- $form_state->expects($this->once())
- ->method('setErrorByName')
- ->with('form_token', 'The form has become outdated. Press the back button, copy any unsaved work in the form, and then reload the page.');
- $form_state->setValue('form_token', 'some_random_token');
- $form_validator->validateForm('test_form_id', $form, $form_state);
- $this->assertTrue($form_state->isValidationComplete());
- }
- /**
- * @covers ::validateForm
- */
- public function testValidateValidFormToken() {
- $request_stack = new RequestStack();
- $this->csrfToken->expects($this->once())
- ->method('validate')
- ->will($this->returnValue(TRUE));
- $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
- ->setConstructorArgs([$request_stack, $this->getStringTranslationStub(), $this->csrfToken, $this->logger, $this->formErrorHandler])
- ->setMethods(['doValidateForm'])
- ->getMock();
- $form_validator->expects($this->once())
- ->method('doValidateForm');
- $form['#token'] = 'test_form_id';
- $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
- ->setMethods(['setErrorByName'])
- ->getMock();
- $form_state->expects($this->never())
- ->method('setErrorByName');
- $form_state->setValue('form_token', 'some_random_token');
- $form_validator->validateForm('test_form_id', $form, $form_state);
- $this->assertTrue($form_state->isValidationComplete());
- }
- /**
- * @covers ::handleErrorsWithLimitedValidation
- *
- * @dataProvider providerTestHandleErrorsWithLimitedValidation
- */
- public function testHandleErrorsWithLimitedValidation($sections, $triggering_element, $values, $expected) {
- $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
- ->setConstructorArgs([new RequestStack(), $this->getStringTranslationStub(), $this->csrfToken, $this->logger, $this->formErrorHandler])
- ->setMethods(NULL)
- ->getMock();
- $triggering_element['#limit_validation_errors'] = $sections;
- $form = [];
- $form_state = (new FormState())
- ->setValues($values)
- ->setTriggeringElement($triggering_element);
- $form_validator->validateForm('test_form_id', $form, $form_state);
- $this->assertSame($expected, $form_state->getValues());
- }
- public function providerTestHandleErrorsWithLimitedValidation() {
- return [
- // Test with a non-existent section.
- [
- [['test1'], ['test3']],
- [],
- [
- 'test1' => 'foo',
- 'test2' => 'bar',
- ],
- [
- 'test1' => 'foo',
- ],
- ],
- // Test with buttons in a non-validated section.
- [
- [['test1']],
- [
- '#is_button' => TRUE,
- '#value' => 'baz',
- '#name' => 'op',
- '#parents' => ['submit'],
- ],
- [
- 'test1' => 'foo',
- 'test2' => 'bar',
- 'op' => 'baz',
- 'submit' => 'baz',
- ],
- [
- 'test1' => 'foo',
- 'submit' => 'baz',
- 'op' => 'baz',
- ],
- ],
- // Test with a matching button #value and $form_state value.
- [
- [['submit']],
- [
- '#is_button' => TRUE,
- '#value' => 'baz',
- '#name' => 'op',
- '#parents' => ['submit'],
- ],
- [
- 'test1' => 'foo',
- 'test2' => 'bar',
- 'op' => 'baz',
- 'submit' => 'baz',
- ],
- [
- 'submit' => 'baz',
- 'op' => 'baz',
- ],
- ],
- // Test with a mismatched button #value and $form_state value.
- [
- [['submit']],
- [
- '#is_button' => TRUE,
- '#value' => 'bar',
- '#name' => 'op',
- '#parents' => ['submit'],
- ],
- [
- 'test1' => 'foo',
- 'test2' => 'bar',
- 'op' => 'baz',
- 'submit' => 'baz',
- ],
- [
- 'submit' => 'baz',
- ],
- ],
- ];
- }
- /**
- * @covers ::executeValidateHandlers
- */
- public function testExecuteValidateHandlers() {
- $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
- ->setConstructorArgs([new RequestStack(), $this->getStringTranslationStub(), $this->csrfToken, $this->logger, $this->formErrorHandler])
- ->setMethods(NULL)
- ->getMock();
- $mock = $this->getMockBuilder('stdClass')
- ->setMethods(['validate_handler', 'hash_validate'])
- ->getMock();
- $mock->expects($this->once())
- ->method('validate_handler')
- ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'));
- $mock->expects($this->once())
- ->method('hash_validate')
- ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'));
- $form = [];
- $form_state = new FormState();
- $form_validator->executeValidateHandlers($form, $form_state);
- $form['#validate'][] = [$mock, 'hash_validate'];
- $form_validator->executeValidateHandlers($form, $form_state);
- // $form_state validate handlers will supersede $form handlers.
- $validate_handlers[] = [$mock, 'validate_handler'];
- $form_state->setValidateHandlers($validate_handlers);
- $form_validator->executeValidateHandlers($form, $form_state);
- }
- /**
- * @covers ::doValidateForm
- *
- * @dataProvider providerTestRequiredErrorMessage
- */
- public function testRequiredErrorMessage($element, $expected_message) {
- $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
- ->setConstructorArgs([new RequestStack(), $this->getStringTranslationStub(), $this->csrfToken, $this->logger, $this->formErrorHandler])
- ->setMethods(['executeValidateHandlers'])
- ->getMock();
- $form_validator->expects($this->once())
- ->method('executeValidateHandlers');
- $form = [];
- $form['test'] = $element + [
- '#type' => 'textfield',
- '#value' => '',
- '#needs_validation' => TRUE,
- '#required' => TRUE,
- '#parents' => ['test'],
- ];
- $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
- ->setMethods(['setError'])
- ->getMock();
- $form_state->expects($this->once())
- ->method('setError')
- ->with($this->isType('array'), $expected_message);
- $form_validator->validateForm('test_form_id', $form, $form_state);
- }
- public function providerTestRequiredErrorMessage() {
- return [
- [
- // Use the default message with a title.
- ['#title' => 'Test'],
- 'Test field is required.',
- ],
- // Use a custom message.
- [
- ['#required_error' => 'FAIL'],
- 'FAIL',
- ],
- // No title or custom message.
- [
- [],
- '',
- ],
- ];
- }
- /**
- * @covers ::doValidateForm
- */
- public function testElementValidate() {
- $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
- ->setConstructorArgs([new RequestStack(), $this->getStringTranslationStub(), $this->csrfToken, $this->logger, $this->formErrorHandler])
- ->setMethods(['executeValidateHandlers'])
- ->getMock();
- $form_validator->expects($this->once())
- ->method('executeValidateHandlers');
- $mock = $this->getMockBuilder('stdClass')
- ->setMethods(['element_validate'])
- ->getMock();
- $mock->expects($this->once())
- ->method('element_validate')
- ->with($this->isType('array'), $this->isInstanceOf('Drupal\Core\Form\FormStateInterface'), NULL);
- $form = [];
- $form['test'] = [
- '#type' => 'textfield',
- '#title' => 'Test',
- '#parents' => ['test'],
- '#element_validate' => [[$mock, 'element_validate']],
- ];
- $form_state = new FormState();
- $form_validator->validateForm('test_form_id', $form, $form_state);
- }
- /**
- * @covers ::performRequiredValidation
- *
- * @dataProvider providerTestPerformRequiredValidation
- */
- public function testPerformRequiredValidation($element, $expected_message, $call_watchdog) {
- $form_validator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
- ->setConstructorArgs([new RequestStack(), $this->getStringTranslationStub(), $this->csrfToken, $this->logger, $this->formErrorHandler])
- ->setMethods(['setError'])
- ->getMock();
- if ($call_watchdog) {
- $this->logger->expects($this->once())
- ->method('error')
- ->with($this->isType('string'), $this->isType('array'));
- }
- $form = [];
- $form['test'] = $element + [
- '#title' => 'Test',
- '#needs_validation' => TRUE,
- '#required' => FALSE,
- '#parents' => ['test'],
- ];
- $form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
- ->setMethods(['setError'])
- ->getMock();
- $form_state->expects($this->once())
- ->method('setError')
- ->with($this->isType('array'), $expected_message);
- $form_validator->validateForm('test_form_id', $form, $form_state);
- }
- public function providerTestPerformRequiredValidation() {
- return [
- [
- [
- '#type' => 'select',
- '#options' => [
- 'foo' => 'Foo',
- 'bar' => 'Bar',
- ],
- '#required' => TRUE,
- '#value' => 'baz',
- '#empty_value' => 'baz',
- '#multiple' => FALSE,
- ],
- 'Test field is required.',
- FALSE,
- ],
- [
- [
- '#type' => 'select',
- '#options' => [
- 'foo' => 'Foo',
- 'bar' => 'Bar',
- ],
- '#value' => 'baz',
- '#multiple' => FALSE,
- ],
- 'An illegal choice has been detected. Please contact the site administrator.',
- TRUE,
- ],
- [
- [
- '#type' => 'checkboxes',
- '#options' => [
- 'foo' => 'Foo',
- 'bar' => 'Bar',
- ],
- '#value' => ['baz'],
- '#multiple' => TRUE,
- ],
- 'An illegal choice has been detected. Please contact the site administrator.',
- TRUE,
- ],
- [
- [
- '#type' => 'select',
- '#options' => [
- 'foo' => 'Foo',
- 'bar' => 'Bar',
- ],
- '#value' => ['baz'],
- '#multiple' => TRUE,
- ],
- 'An illegal choice has been detected. Please contact the site administrator.',
- TRUE,
- ],
- [
- [
- '#type' => 'textfield',
- '#maxlength' => 7,
- '#value' => $this->randomMachineName(8),
- ],
- 'Test cannot be longer than <em class="placeholder">7</em> characters but is currently <em class="placeholder">8</em> characters long.',
- FALSE,
- ],
- ];
- }
- }
|