Newer
Older
Alex Pott
committed
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Form\FormBuilderTest.
*/
namespace Drupal\Tests\Core\Form {
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Form\FormInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Tests the form builder.
Angie Byron
committed
*
Angie Byron
committed
* @coversDefaultClass \Drupal\Core\Form\FormBuilder
*
Angie Byron
committed
* @group Drupal
* @group Form
Alex Pott
committed
*/
Angie Byron
committed
class FormBuilderTest extends FormTestBase {
Alex Pott
committed
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => 'Form builder test',
'description' => 'Tests the form builder.',
'group' => 'Form API',
);
}
/**
* Tests the getFormId() method with a string based form ID.
*/
public function testGetFormIdWithString() {
$form_arg = 'foo';
$form_state = array();
$form_id = $this->formBuilder->getFormId($form_arg, $form_state);
$this->assertSame($form_arg, $form_id);
$this->assertEmpty($form_state);
}
/**
* Tests the getFormId() method with a class name form ID.
*/
public function testGetFormIdWithClassName() {
$form_arg = 'Drupal\Tests\Core\Form\TestForm';
$form_state = array();
$form_id = $this->formBuilder->getFormId($form_arg, $form_state);
$this->assertSame('test_form', $form_id);
$this->assertSame($form_arg, get_class($form_state['build_info']['callback_object']));
}
/**
* Tests the getFormId() method with an injected class name form ID.
*/
public function testGetFormIdWithInjectedClassName() {
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
\Drupal::setContainer($container);
$form_arg = 'Drupal\Tests\Core\Form\TestFormInjected';
$form_state = array();
$form_id = $this->formBuilder->getFormId($form_arg, $form_state);
$this->assertSame('test_form', $form_id);
$this->assertSame($form_arg, get_class($form_state['build_info']['callback_object']));
}
/**
* Tests the getFormId() method with a form object.
*/
public function testGetFormIdWithObject() {
$expected_form_id = 'my_module_form_id';
Angie Byron
committed
$form_arg = $this->getMockForm($expected_form_id);
Alex Pott
committed
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
$form_state = array();
$form_id = $this->formBuilder->getFormId($form_arg, $form_state);
$this->assertSame($expected_form_id, $form_id);
$this->assertSame($form_arg, $form_state['build_info']['callback_object']);
}
/**
* Tests the getFormId() method with a base form object.
*/
public function testGetFormIdWithBaseForm() {
$expected_form_id = 'my_module_form_id';
$base_form_id = 'my_module';
$form_arg = $this->getMock('Drupal\Core\Form\BaseFormIdInterface');
$form_arg->expects($this->once())
->method('getFormId')
->will($this->returnValue($expected_form_id));
$form_arg->expects($this->once())
->method('getBaseFormId')
->will($this->returnValue($base_form_id));
$form_state = array();
$form_id = $this->formBuilder->getFormId($form_arg, $form_state);
$this->assertSame($expected_form_id, $form_id);
$this->assertSame($form_arg, $form_state['build_info']['callback_object']);
$this->assertSame($base_form_id, $form_state['build_info']['base_form_id']);
}
Alex Pott
committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/**
* Tests the handling of $form_state['response'].
*
* @dataProvider formStateResponseProvider
*/
public function testHandleFormStateResponse($class, $form_state_key) {
$form_id = 'test_form_id';
$expected_form = $form_id();
$response = $this->getMockBuilder($class)
->disableOriginalConstructor()
->getMock();
$response->expects($this->any())
->method('prepare')
->will($this->returnValue($response));
$form_arg = $this->getMockForm($form_id, $expected_form);
$form_arg->expects($this->any())
->method('submitForm')
->will($this->returnCallback(function ($form, &$form_state) use ($response, $form_state_key) {
$form_state[$form_state_key] = $response;
}));
$form_state = array();
$this->formBuilder->getFormId($form_arg, $form_state);
try {
$form_state['values'] = array();
$form_state['input']['form_id'] = $form_id;
$this->simulateFormSubmission($form_id, $form_arg, $form_state, FALSE);
$this->fail('TestFormBuilder::sendResponse() was not triggered.');
}
catch (\Exception $e) {
$this->assertSame('exit', $e->getMessage());
}
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $form_state['response']);
}
/**
* Provides test data for testHandleFormStateResponse().
*/
public function formStateResponseProvider() {
return array(
array('Symfony\Component\HttpFoundation\Response', 'response'),
array('Symfony\Component\HttpFoundation\RedirectResponse', 'redirect'),
);
}
/**
* Tests the handling of a redirect when $form_state['response'] exists.
*/
public function testHandleRedirectWithResponse() {
$form_id = 'test_form_id';
$expected_form = $form_id();
// Set up a response that will be used.
$response = $this->getMockBuilder('Symfony\Component\HttpFoundation\Response')
->disableOriginalConstructor()
->getMock();
$response->expects($this->once())
->method('prepare')
->will($this->returnValue($response));
// Set up a redirect that will not be called.
$redirect = $this->getMockBuilder('Symfony\Component\HttpFoundation\RedirectResponse')
->disableOriginalConstructor()
->getMock();
$redirect->expects($this->never())
->method('prepare');
$form_arg = $this->getMockForm($form_id, $expected_form);
$form_arg->expects($this->any())
->method('submitForm')
->will($this->returnCallback(function ($form, &$form_state) use ($response, $redirect) {
// Set both the response and the redirect.
$form_state['response'] = $response;
$form_state['redirect'] = $redirect;
}));
$form_state = array();
$this->formBuilder->getFormId($form_arg, $form_state);
try {
$form_state['values'] = array();
$form_state['input']['form_id'] = $form_id;
$this->simulateFormSubmission($form_id, $form_arg, $form_state, FALSE);
$this->fail('TestFormBuilder::sendResponse() was not triggered.');
}
catch (\Exception $e) {
$this->assertSame('exit', $e->getMessage());
}
$this->assertSame($response, $form_state['response']);
}
Alex Pott
committed
/**
* Tests the getForm() method with a string based form ID.
*/
public function testGetFormWithString() {
$form_id = 'test_form_id';
$expected_form = $form_id();
$form = $this->formBuilder->getForm($form_id);
$this->assertFormElement($expected_form, $form, 'test');
$this->assertSame($form_id, $form['#id']);
}
/**
* Tests the getForm() method with a form object.
*/
public function testGetFormWithObject() {
$form_id = 'test_form_id';
$expected_form = $form_id();
Angie Byron
committed
$form_arg = $this->getMockForm($form_id, $expected_form);
Alex Pott
committed
$form = $this->formBuilder->getForm($form_arg);
$this->assertFormElement($expected_form, $form, 'test');
$this->assertSame($form_id, $form['#id']);
}
/**
Angie Byron
committed
* Tests the getForm() method with a class name based form ID.
Alex Pott
committed
*/
Angie Byron
committed
public function testGetFormWithClassString() {
$form_id = '\Drupal\Tests\Core\Form\TestForm';
$object = new TestForm();
$form = array();
$form_state = array();
$expected_form = $object->buildForm($form, $form_state);
$form = $this->formBuilder->getForm($form_id);
$this->assertFormElement($expected_form, $form, 'test');
$this->assertSame('test_form', $form['#id']);
}
/**
* Tests the buildForm() method with a string based form ID.
*/
public function testBuildFormWithString() {
Alex Pott
committed
$form_id = 'test_form_id';
$expected_form = $form_id();
Angie Byron
committed
$form = $this->formBuilder->getForm($form_id);
$this->assertFormElement($expected_form, $form, 'test');
$this->assertSame($form_id, $form['#id']);
}
Alex Pott
committed
Angie Byron
committed
/**
* Tests the buildForm() method with a class name based form ID.
*/
public function testBuildFormWithClassString() {
$form_id = '\Drupal\Tests\Core\Form\TestForm';
$object = new TestForm();
$form = array();
$form_state = array();
$expected_form = $object->buildForm($form, $form_state);
Alex Pott
committed
$form = $this->formBuilder->buildForm($form_id, $form_state);
$this->assertFormElement($expected_form, $form, 'test');
Angie Byron
committed
$this->assertSame('test_form', $form['#id']);
}
/**
* Tests the buildForm() method with a form object.
*/
public function testBuildFormWithObject() {
$form_id = 'test_form_id';
$expected_form = $form_id();
$form_arg = $this->getMockForm($form_id, $expected_form);
$form_state = array();
$form = $this->formBuilder->buildForm($form_arg, $form_state);
$this->assertFormElement($expected_form, $form, 'test');
Alex Pott
committed
$this->assertSame($form_id, $form_state['build_info']['form_id']);
$this->assertSame($form_id, $form['#id']);
}
/**
* Tests the rebuildForm() method.
*/
public function testRebuildForm() {
$form_id = 'test_form_id';
$expected_form = $form_id();
Angie Byron
committed
// The form will be built four times.
Angie Byron
committed
$form_arg = $this->getMock('Drupal\Core\Form\FormInterface');
$form_arg->expects($this->exactly(2))
->method('getFormId')
->will($this->returnValue($form_id));
$form_arg->expects($this->exactly(4))
->method('buildForm')
->will($this->returnValue($expected_form));
Alex Pott
committed
// Do an initial build of the form and track the build ID.
$form_state = array();
Angie Byron
committed
$form = $this->formBuilder->buildForm($form_arg, $form_state);
Alex Pott
committed
$original_build_id = $form['#build_id'];
// Rebuild the form, and assert that the build ID has not changed.
$form_state['rebuild'] = TRUE;
$form_state['input']['form_id'] = $form_id;
$form_state['rebuild_info']['copy']['#build_id'] = TRUE;
$this->formBuilder->processForm($form_id, $form, $form_state);
$this->assertSame($original_build_id, $form['#build_id']);
// Rebuild the form again, and assert that there is a new build ID.
$form_state['rebuild_info'] = array();
Angie Byron
committed
$form = $this->formBuilder->buildForm($form_arg, $form_state);
Alex Pott
committed
$this->assertNotSame($original_build_id, $form['#build_id']);
}
/**
* Tests the getCache() method.
*/
public function testGetCache() {
$form_id = 'test_form_id';
$expected_form = $form_id();
Angie Byron
committed
$expected_form['#token'] = FALSE;
Alex Pott
committed
Angie Byron
committed
// FormBuilder::buildForm() will be called twice, but the form object will
// only be called once due to caching.
$form_arg = $this->getMockForm($form_id, $expected_form, 1);
Alex Pott
committed
Angie Byron
committed
// The CSRF token is checked each time.
$this->csrfToken->expects($this->exactly(2))
Alex Pott
committed
->method('get')
->will($this->returnValue('csrf_token'));
Angie Byron
committed
// The CSRF token is validated only when retrieving from the cache.
$this->csrfToken->expects($this->once())
->method('validate')
->with('csrf_token')
->will($this->returnValue(TRUE));
// The user is checked for authentication once for the form building and
// twice for each cache set.
Alex Pott
committed
$this->account->expects($this->exactly(3))
->method('isAuthenticated')
->will($this->returnValue(TRUE));
// Do an initial build of the form and track the build ID.
$form_state = array();
$form_state['build_info']['args'] = array();
$form_state['build_info']['files'] = array(array('module' => 'node', 'type' => 'pages.inc'));
$form_state['cache'] = TRUE;
Angie Byron
committed
$form = $this->formBuilder->buildForm($form_arg, $form_state);
Alex Pott
committed
$cached_form = $form;
$cached_form['#cache_token'] = 'csrf_token';
// The form cache, form_state cache, and CSRF token validation will only be
// called on the cached form.
Angie Byron
committed
$this->formCache->expects($this->once())
->method('setWithExpire');
Alex Pott
committed
$this->formCache->expects($this->once())
->method('get')
->will($this->returnValue($cached_form));
$this->formStateCache->expects($this->once())
->method('get')
->will($this->returnValue($form_state));
// The final form build will not trigger any actual form building, but will
// use the form cache.
Angie Byron
committed
$form_state['input']['form_id'] = $form_id;
$form_state['input']['form_build_id'] = $form['#build_id'];
Alex Pott
committed
$this->formBuilder->buildForm($form_id, $form_state);
Alex Pott
committed
$this->assertEmpty($form_state['errors']);
Alex Pott
committed
}
Angie Byron
committed
/**
* Tests the sendResponse() method.
*
* @expectedException \Exception
*/
public function testSendResponse() {
$form_id = 'test_form_id';
$expected_form = $this->getMockBuilder('Symfony\Component\HttpFoundation\Response')
->disableOriginalConstructor()
->getMock();
$expected_form->expects($this->once())
->method('prepare')
->will($this->returnValue($expected_form));
Angie Byron
committed
$form_arg = $this->getMockForm($form_id, $expected_form);
Angie Byron
committed
// Do an initial build of the form and track the build ID.
$form_state = array();
Angie Byron
committed
$this->formBuilder->buildForm($form_arg, $form_state);
Angie Byron
committed
}
Alex Pott
committed
/**
* Tests that HTML IDs are unique when rebuilding a form with errors.
*/
public function testUniqueHtmlId() {
$form_id = 'test_form_id';
$expected_form = $form_id();
$expected_form['test']['#required'] = TRUE;
// Mock a form object that will be built two times.
$form_arg = $this->getMock('Drupal\Core\Form\FormInterface');
$form_arg->expects($this->exactly(2))
->method('buildForm')
->will($this->returnValue($expected_form));
$form_state = array();
$form = $this->simulateFormSubmission($form_id, $form_arg, $form_state);
$this->assertSame($form_id, $form['#id']);
$form_state = array();
$form = $this->simulateFormSubmission($form_id, $form_arg, $form_state);
$this->assertSame("$form_id--2", $form['#id']);
}
Alex Pott
committed
}
class TestForm implements FormInterface {
public function getFormId() {
return 'test_form';
}
Angie Byron
committed
public function buildForm(array $form, array &$form_state) {
return test_form_id();
}
Alex Pott
committed
public function validateForm(array &$form, array &$form_state) { }
public function submitForm(array &$form, array &$form_state) { }
}
class TestFormInjected extends TestForm implements ContainerInjectionInterface {
public static function create(ContainerInterface $container) {
return new static();
}
}
}
namespace {
Angie Byron
committed
function test_form_id_custom_submit(array &$form, array &$form_state) {
}