Issue #1858452 by Mile23: [meta] Examples projects without tests.
[project/examples.git] / field_permission_example / tests / field_permission_example.test
1 <?php
2 /**
3 * @file
4 * Tests for Field Permission Example.
5 *
6 * @ingroup field_permission_example
7 */
8
9 /**
10 * A generic field testing class.
11 *
12 * Subclass this one to test your specific field type
13 * and get some basic unit testing for free.
14 *
15 * Since Simpletest only looks through one class definition
16 * to find test functions, we define generic tests as
17 * 'code_testWhatever' or 'form_testWhatever'. Subclasses
18 * can then implement shim test methods that just call the
19 * generic tests.
20 *
21 * 'code_' and 'form_' prefixes denote the type of test:
22 * using code only, or through Drupal page forms.
23 *
24 * @ingroup field_permission_example
25 */
26 class GenericFieldTest extends DrupalWebTestCase {
27
28 // Our tests will generate some random field instance
29 // names. We store them here so many functions can act on them.
30 protected $instanceNames;
31
32 /**
33 * {@inheritdoc}
34 */
35 public static function getInfo() {
36 return array(
37 'name' => 'Generic Field Test',
38 'description' => 'Someone neglected to override GenericFieldTest::getInfo().',
39 'group' => 'Examples',
40 );
41 }
42
43 /**
44 * Supply the field types we wish to test.
45 *
46 * Return an array of field types to instantiate and test.
47 *
48 * @return array
49 * The field types we wish to use.
50 */
51 protected function getFieldTypes() {
52 return array('these_are_not', 'valid_field_types', 'please_override');
53 }
54
55 /**
56 * The module to enable.
57 *
58 * @return string
59 * Module machine name.
60 */
61 protected function getModule() {
62 return 'this-is-not-a-module-name-please-override';
63 }
64
65 /**
66 * Simpletest's setUp().
67 *
68 * We want to be able to subclass this class, so we jump
69 * through a few hoops in order to get the modules from args
70 * and add our own.
71 */
72 public function setUp() {
73 $this->instanceNames = array();
74 $modules = func_get_args();
75 if (isset($modules[0]) && is_array($modules[0])) {
76 $modules = $modules[0];
77 }
78 $modules[] = 'node';
79 $modules[] = 'field_ui';
80 parent::setUp($modules);
81 }
82
83 /**
84 * Verify that all required fields are specified in hook_field_info().
85 *
86 * The full list is label, description, settings, instance_settings,
87 * default_widget, default_formatter, no_ui.
88 *
89 * Some are optional, and we won't check for those.
90 *
91 * In a sane world, this would be a unit test, rather than a
92 * web test, but module_implements is unavailable to us
93 * in unit tests.
94 *
95 * @see hook_field_info()
96 */
97 public function runTestGenericFieldInfo() {
98 $field_types = $this->getFieldTypes();
99 $module = $this->getModule();
100 $info_keys = array(
101 'label',
102 'description',
103 'default_widget',
104 'default_formatter',
105 );
106 // We don't want to use field_info_field_types()
107 // because there is a hook_field_info_alter().
108 // We're testing the module here, not the rest of
109 // the system. So invoke hook_field_info() ourselves.
110 $modules = module_implements('field_info');
111 $this->assertTrue(in_array($module, $modules),
112 'Module ' . $module . ' implements hook_field_info()');
113
114 foreach ($field_types as $field_type) {
115 $field_info = module_invoke($module, 'field_info');
116 $this->assertTrue(isset($field_info[$field_type]),
117 'Module ' . $module . ' defines field type ' . $field_type);
118 $field_info = $field_info[$field_type];
119 foreach ($info_keys as $key) {
120 $this->assertTrue(
121 isset($field_info[$key]),
122 $field_type . "'s " . $key . ' is set.'
123 );
124 }
125 }
126 }
127
128 /**
129 * Add all testable fields as instances to a content type.
130 *
131 * As a side-effect: Store the names of the instances created
132 * in $this->$instance_names.
133 *
134 * @param object $node_type
135 * A content type object. If none is provided, one will be generated.
136 *
137 * @return object
138 * The content type object that has the fields attached.
139 */
140 public function codeTestGenericAddAllFields($node_type = NULL) {
141 $this->instanceNames = array();
142 if (!$node_type) {
143 $node_type = $this->drupalCreateContentType();
144 }
145 foreach ($this->getFieldTypes() as $field_type) {
146 $instance_name = drupal_strtolower($this->randomName(32));
147 $field = array(
148 'field_name' => $instance_name,
149 'type' => $field_type,
150 );
151 $field = field_create_field($field);
152 $instance = array(
153 'field_name' => $instance_name,
154 'entity_type' => 'node',
155 'bundle' => $node_type->name,
156 'label' => drupal_strtolower($this->randomName(20)),
157 );
158 // Finally create the instance.
159 $instance = field_create_instance($instance);
160 // Reset the caches...
161 _field_info_collate_fields(TRUE);
162 // Grab this instance.
163 $verify_instance = field_info_instance('node', $instance_name, $node_type->name);
164 $this->assertTrue($verify_instance, 'Instance object exists.');
165 $this->assertTrue(
166 $verify_instance != NULL,
167 'field_info_instance() says ' . $instance_name . ' (' . $node_type->name . ') was created.'
168 );
169 $this->instanceNames[] = $instance_name;
170 }
171 return $node_type;
172 }
173
174 /**
175 * Remove all fields in $this->field_names.
176 *
177 * @param mixed $node_type
178 * A content type object. If none is specified,
179 * the test fails.
180 */
181 public function codeTestGenericRemoveAllFields($node_type = NULL) {
182 if (!$node_type) {
183 $this->fail('No node type.');
184 }
185 if (count($this->instanceNames) < 1) {
186 $this->fail('There are no instances to remove.');
187 return;
188 }
189 foreach ($this->instanceNames as $instance_name) {
190 $instance = field_info_instance('node', $instance_name, $node_type->name);
191 $this->assertTrue($instance, "Instance exists, now we'll delete it.");
192 field_delete_field($instance_name);
193 $instance = field_info_instance('node', $instance_name, $node_type->name);
194 $this->assertFalse($instance, 'Instance was deleted.');
195 }
196 $this->instanceNames = array();
197 }
198
199 /**
200 * Add and delete all field types through Form API.
201 *
202 * @access public
203 */
204 public function formTestGenericFieldNodeAddDeleteForm() {
205 // Create and login user.
206 $account = $this->drupalCreateUser(array(
207 'administer content types',
208 ));
209 $this->drupalLogin($account);
210
211 // Add a content type.
212 $node_type = $this->drupalCreateContentType();
213
214 // Add all our testable fields.
215 $field_names = $this->formAddAllFields($node_type);
216
217 // Now let's delete all the fields.
218 foreach ($field_names as $field_name) {
219 // This is the path for the 'delete' link on field admin page.
220 $this->drupalGet('admin/structure/types/manage/' .
221 $node_type->name . '/fields/field_' . $field_name . '/delete');
222 // Click the 'delete' button.
223 $this->drupalPost(NULL, array(), t('Delete'));
224 $this->assertText(t('The field @field has been deleted from the @type content type.',
225 array('@field' => $field_name, '@type' => $node_type->name)));
226 }
227 }
228
229 /**
230 * Add all fields using Form API.
231 *
232 * @param mixed $node_type
233 * A content type object. If none is specified,
234 * the test fails.
235 */
236 protected function formAddAllFields($node_type = NULL) {
237 if (!$node_type) {
238 $this->fail('No content type specified.');
239 }
240 // Get all our field types.
241 $field_types = $this->getFieldTypes();
242 // Keep a list of no_ui fields so we can tell the user.
243 $unsafe_field_types = array();
244 $field_names = array();
245
246 $manage_path = 'admin/structure/types/manage/' . $node_type->name . '/fields';
247 foreach ($field_types as $field_type) {
248 // Get the field info.
249 $field_info = field_info_field_types($field_type);
250 // Exclude no_ui field types.
251 if (isset($field_info['no_ui']) && $field_info['no_ui']) {
252 $unsafe_field_types[] = $field_type;
253 }
254 else {
255 // Generate a name for our field.
256 // 26 is max length for field name.
257 $field_name = drupal_strtolower($this->randomName(26));
258 $field_names[$field_type] = $field_name;
259 // Create the field through Form API.
260 $this->formCreateField($manage_path, $field_type, $field_name,
261 $field_info['default_widget'], 1);
262 }
263 }
264
265 // Tell the user which fields we couldn't test.
266 if (!empty($unsafe_field_types)) {
267 debug(
268 'Unable to attach these no_ui fields: ' .
269 implode(', ', $unsafe_field_types)
270 );
271 }
272
273 // Somehow clicking "save" isn't enough, and we have to
274 // rebuild a few caches.
275 node_types_rebuild();
276 menu_rebuild();
277 return $field_names;
278 }
279
280 /**
281 * Create a field using the content type management form.
282 *
283 * @param mixed $manage_path
284 * Path to our content type management form.
285 * @param mixed $field_type
286 * The type of field we're adding.
287 * @param mixed $field_name
288 * The name of the field instance we want.
289 * @param mixed $widget_type
290 * Which widget would we like?
291 * @param mixed $cardinality
292 * Cardinality for this field instance.
293 */
294 protected function formCreateField($manage_path, $field_type, $field_name, $widget_type, $cardinality) {
295 // $manage_path is the field edit form for our content type.
296 $this->drupalGet($manage_path);
297 $edit = array(
298 'fields[_add_new_field][label]' => $field_name,
299 'fields[_add_new_field][field_name]' => $field_name,
300 'fields[_add_new_field][type]' => $field_type,
301 'fields[_add_new_field][widget_type]' => $widget_type,
302 );
303 $this->drupalPost(NULL, $edit, t('Save'));
304
305 // Assume there are no settings for this,
306 // so just press the button.
307 $this->drupalPost(NULL, array(), t('Save field settings'));
308
309 $edit = array('field[cardinality]' => (string) $cardinality);
310 $this->drupalPost(NULL, $edit, t('Save settings'));
311
312 debug(
313 t('Saved settings for field !field_name with widget !widget_type and cardinality !cardinality',
314 array(
315 '!field_name' => $field_name,
316 '!widget_type' => $widget_type,
317 '!cardinality' => $cardinality,
318 )
319 )
320 );
321
322 $this->assertText(t('Saved @name configuration.', array('@name' => $field_name)));
323 }
324
325 /**
326 * Create a node with some field content.
327 *
328 * @return object
329 * Node object for the created node.
330 */
331 public function createFieldContentForUser(
332 $account = NULL,
333 $content = 'testable_content',
334 $node_type = NULL,
335 $instance_name = '',
336 $column = NULL
337 ) {
338 if (!$column) {
339 $this->fail('No column name given.');
340 return NULL;
341 }
342 if (!$account) {
343 $account = $this->drupalCreateUser(array(
344 'bypass node access',
345 'administer content types',
346 ));
347 }
348 $this->drupalLogin($account);
349
350 if (!$node_type) {
351 $node_type = $this->codeTestGenericAddAllFields();
352 }
353
354 if (!$instance_name) {
355 $instance_name = reset($this->instanceNames);
356 }
357 $field = array();
358 $field[LANGUAGE_NONE][0][$column] = $content;
359
360 $settings = array(
361 'type' => $node_type->name,
362 $instance_name => $field,
363 );
364 $node = $this->drupalCreateNode($settings);
365
366 $this->assertTrue($node, 'Node of type ' . $node->type . ' allegedly created.');
367
368 $node = node_load($node->nid);
369 debug('Loaded node id: ' . $node->nid);
370 $this->assertTrue($node->$instance_name, 'Field actually created.');
371 $field = $node->$instance_name;
372 $this->assertTrue($field[LANGUAGE_NONE][0][$column] == $content,
373 'Content was stored properly on the field.');
374 return $node;
375 }
376
377 }
378
379 class FieldTestPermissionsExample extends GenericFieldTest {
380
381 /**
382 * {@inheritdoc}
383 */
384 public function setUp() {
385 parent::setUp(array('field_permission_example'));
386 }
387
388 /**
389 * {@inheritdoc}
390 */
391 public static function getInfo() {
392 return array(
393 'name' => 'Field Permission Example',
394 'description' => 'Various tests on the functionality of the Fieldnote field.',
395 'group' => 'Examples',
396 );
397 }
398
399 /**
400 * {@inheritdoc}
401 */
402 protected function getFieldTypes() {
403 return array('field_permission_example_fieldnote');
404 }
405
406 /**
407 * {@inheritdoc}
408 */
409 protected function getModule() {
410 return 'field_permission_example';
411 }
412
413 /**
414 * Override createFieldContentForUser().
415 *
416 * We override so we can make sure $column is set to 'notes'.
417 */
418 public function createFieldContentForUser(
419 $account = NULL,
420 $content = 'fieldnote_testable_content',
421 $node_type = NULL,
422 $instance_name = '',
423 $column = 'notes'
424 ) {
425 return parent::createFieldContentForUser($account, $content, $node_type, $instance_name, $column);
426 }
427
428
429 /**
430 * Test of hook_field_info() and other implementation requirements.
431 *
432 * @see GenericFieldTest::runTestGenericFieldInfo()
433 */
434 public function testFieldnoteInfo() {
435 $this->runTestGenericFieldInfo();
436 }
437
438 /**
439 * Add and remove the field through Form API.
440 */
441 public function testAddRemoveFieldnoteForm() {
442 $this->formTestGenericFieldNodeAddDeleteForm();
443 }
444
445 /**
446 * Add and remove the field through code.
447 */
448 public function testAddRemoveFieldnoteCode() {
449 $node_type = $this->codeTestGenericAddAllFields();
450 $this->codeTestGenericRemoveAllFields($node_type);
451 }
452
453 /**
454 * Test view permissions.
455 */
456 public function testFieldnoteViewPerms() {
457 // We create two sets of content so we can get a few
458 // test cases out of the way.
459 $view_own_content = $this->randomName(23);
460 $view_any_content = $this->randomName(23);
461 $view_own_node = $this->createFieldContentForUser(NULL, $view_own_content);
462 // Get the type of the node so we can create another one.
463 $node_type = node_type_load($view_own_node->type);
464 $view_any_node = $this->createFieldContentForUser(NULL, $view_any_content, $node_type);
465
466 // There should be a node now, with some lovely content, but it's the wrong
467 // user for the view-own test.
468 $view_own_account = $this->drupalCreateUser(array(
469 'view own fieldnote',
470 ));
471 debug("Created user with 'view own fieldnote' permission.");
472
473 // Now change the user id for the test node.
474 $view_own_node = node_load($view_own_node->nid);
475 $view_own_node->uid = $view_own_account->uid;
476 node_save($view_own_node);
477 $view_own_node = node_load($view_own_node->nid);
478 $this->assertTrue($view_own_node->uid == $view_own_account->uid, 'New user assigned to node.');
479
480 // Now we want to look at the page with the field and
481 // check that we can see it.
482 $this->drupalLogin($view_own_account);
483
484 $this->drupalGet('node/' . $view_own_node->nid);
485 // Check that the field content is present.
486 $output_strings = $this->xpath("//div[contains(@class,'stickynote')]/text()");
487 $this->assertEqual((string) reset($output_strings), $view_own_content);
488 debug("'view own fieldnote' can view own field.");
489
490 // This account shouldn't be able to see the field on the
491 // 'view any' node.
492 $this->drupalGet('node/' . $view_any_node->nid);
493 // Check that the field content is not present.
494 $output_strings = $this->xpath("//div[contains(@class,'stickynote')]/text()");
495 $this->assertNotEqual((string) reset($output_strings), $view_any_content);
496 debug("'view own fieldnote' cannot view other field.");
497
498 // Now, to test for 'view any fieldnote' we create another user
499 // with that permission, and try to look at the same node.
500 $view_any_account = $this->drupalCreateUser(array(
501 'view any fieldnote',
502 ));
503 debug("Created user with 'view any fieldnote' permission.");
504 $this->drupalLogin($view_any_account);
505 // This account should be able to see the field on the
506 // 'view any' node.
507 $this->drupalGet('node/' . $view_any_node->nid);
508 // Check that the field content is present.
509 $output_strings = $this->xpath("//div[contains(@class,'stickynote')]/text()");
510 $this->assertEqual((string) reset($output_strings), $view_any_content);
511 debug("'view any fieldnote' can view other field.");
512 }
513
514 /**
515 * Test edit permissions.
516 *
517 * Note that this is mostly identical to testFieldnoteViewPerms() and could
518 * probably be refactored.
519 */
520 public function testFieldnoteEditPerms() {
521 // We create two sets of content so we can get a few
522 // test cases out of the way.
523 $edit_own_content = $this->randomName(23);
524 $edit_any_content = $this->randomName(23);
525 $edit_own_node = $this->createFieldContentForUser(NULL, $edit_own_content);
526 // Get the type of the node so we can create another one.
527 $node_type = node_type_load($edit_own_node->type);
528 $edit_any_node = $this->createFieldContentForUser(NULL, $edit_any_content, $node_type);
529
530 $edit_own_account = $this->drupalCreateUser(array(
531 'edit own ' . $node_type->name . ' content',
532 'edit own fieldnote',
533 ));
534 debug("Created user with 'edit own fieldnote' permission.");
535
536 // Now change the user id for the test node.
537 $edit_own_node = node_load($edit_own_node->nid);
538 $edit_own_node->uid = $edit_own_account->uid;
539 node_save($edit_own_node);
540 $edit_own_node = node_load($edit_own_node->nid);
541 $this->assertTrue($edit_own_node->uid == $edit_own_account->uid, 'New edit test user assigned to node.');
542
543 // Now we want to look at the page with the field and
544 // check that we can see it.
545 $this->drupalLogin($edit_own_account);
546
547 $this->drupalGet('node/' . $edit_own_node->nid . '/edit');
548 $this->assertText($edit_own_content, "'edit own fieldnote' can edit own fieldnote.");
549
550 // This account shouldn't be able to edit the field on the
551 // 'edit any' node.
552 $this->drupalGet('node/' . $edit_any_node->nid . '/edit');
553 $this->assertNoText($edit_any_content, "'edit own fieldnote' can not edit any fieldnote.");
554
555 // Now, to test for 'edit any fieldnote' we create another user
556 // with that permission, and try to edit at the same node.
557 // We have to add the ability to edit any node content, as well
558 // or Drupal will deny us access to the page.
559 $edit_any_account = $this->drupalCreateUser(array(
560 'edit any ' . $node_type->name . ' content',
561 'edit any fieldnote',
562 ));
563 debug("Created user with 'edit any fieldnote' permission.");
564 $this->drupalLogin($edit_any_account);
565 // This account should be able to see the field on the
566 // 'edit any' node.
567 $this->drupalGet('node/' . $edit_any_node->nid . '/edit');
568 $this->assertText($edit_any_content, "'edit any fieldnote' can edit any fieldnote.");
569 }
570
571 }