aacef3d2b836572efbb8420d9378b6c1964d909c
[project/drupal.git] / modules / field / tests / field.test
1 <?php
2
3 /**
4 * @file
5 * Tests for field.module.
6 */
7
8 /**
9 * Parent class for Field API tests.
10 */
11 class FieldTestCase extends DrupalWebTestCase {
12 var $default_storage = 'field_sql_storage';
13
14 /**
15 * Set the default field storage backend for fields created during tests.
16 */
17 function setUp() {
18 // Since this is a base class for many test cases, support the same
19 // flexibility that DrupalWebTestCase::setUp() has for the modules to be
20 // passed in as either an array or a variable number of string arguments.
21 $modules = func_get_args();
22 if (isset($modules[0]) && is_array($modules[0])) {
23 $modules = $modules[0];
24 }
25 parent::setUp($modules);
26 // Set default storage backend.
27 variable_set('field_storage_default', $this->default_storage);
28 }
29
30 /**
31 * Generate random values for a field_test field.
32 *
33 * @param $cardinality
34 * Number of values to generate.
35 * @return
36 * An array of random values, in the format expected for field values.
37 */
38 function _generateTestFieldValues($cardinality) {
39 $values = array();
40 for ($i = 0; $i < $cardinality; $i++) {
41 // field_test fields treat 0 as 'empty value'.
42 $values[$i]['value'] = mt_rand(1, 127);
43 }
44 return $values;
45 }
46
47 /**
48 * Assert that a field has the expected values in an entity.
49 *
50 * This function only checks a single column in the field values.
51 *
52 * @param $entity
53 * The entity to test.
54 * @param $field_name
55 * The name of the field to test
56 * @param $langcode
57 * The language code for the values.
58 * @param $expected_values
59 * The array of expected values.
60 * @param $column
61 * (Optional) the name of the column to check.
62 */
63 function assertFieldValues($entity, $field_name, $langcode, $expected_values, $column = 'value') {
64 $e = clone $entity;
65 field_attach_load('test_entity', array($e->ftid => $e));
66 $values = isset($e->{$field_name}[$langcode]) ? $e->{$field_name}[$langcode] : array();
67 $this->assertEqual(count($values), count($expected_values), t('Expected number of values were saved.'));
68 foreach ($expected_values as $key => $value) {
69 $this->assertEqual($values[$key][$column], $value, t('Value @value was saved correctly.', array('@value' => $value)));
70 }
71 }
72 }
73
74 class FieldAttachTestCase extends FieldTestCase {
75 function setUp() {
76 // Since this is a base class for many test cases, support the same
77 // flexibility that DrupalWebTestCase::setUp() has for the modules to be
78 // passed in as either an array or a variable number of string arguments.
79 $modules = func_get_args();
80 if (isset($modules[0]) && is_array($modules[0])) {
81 $modules = $modules[0];
82 }
83 if (!in_array('field_test', $modules)) {
84 $modules[] = 'field_test';
85 }
86 parent::setUp($modules);
87
88 $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
89 $this->field = array('field_name' => $this->field_name, 'type' => 'test_field', 'cardinality' => 4);
90 $this->field = field_create_field($this->field);
91 $this->field_id = $this->field['id'];
92 $this->instance = array(
93 'field_name' => $this->field_name,
94 'entity_type' => 'test_entity',
95 'bundle' => 'test_bundle',
96 'label' => $this->randomName() . '_label',
97 'description' => $this->randomName() . '_description',
98 'weight' => mt_rand(0, 127),
99 'settings' => array(
100 'test_instance_setting' => $this->randomName(),
101 ),
102 'widget' => array(
103 'type' => 'test_field_widget',
104 'label' => 'Test Field',
105 'settings' => array(
106 'test_widget_setting' => $this->randomName(),
107 )
108 )
109 );
110 field_create_instance($this->instance);
111 }
112 }
113
114 /**
115 * Unit test class for storage-related field_attach_* functions.
116 *
117 * All field_attach_* test work with all field_storage plugins and
118 * all hook_field_attach_pre_{load,insert,update}() hooks.
119 */
120 class FieldAttachStorageTestCase extends FieldAttachTestCase {
121 public static function getInfo() {
122 return array(
123 'name' => 'Field attach tests (storage-related)',
124 'description' => 'Test storage-related Field Attach API functions.',
125 'group' => 'Field API',
126 );
127 }
128
129 /**
130 * Check field values insert, update and load.
131 *
132 * Works independently of the underlying field storage backend. Inserts or
133 * updates random field data and then loads and verifies the data.
134 */
135 function testFieldAttachSaveLoad() {
136 // Configure the instance so that we test hook_field_load() (see
137 // field_test_field_load() in field_test.module).
138 $this->instance['settings']['test_hook_field_load'] = TRUE;
139 field_update_instance($this->instance);
140 $langcode = LANGUAGE_NONE;
141
142 $entity_type = 'test_entity';
143 $values = array();
144
145 // TODO : test empty values filtering and "compression" (store consecutive deltas).
146
147 // Preparation: create three revisions and store them in $revision array.
148 for ($revision_id = 0; $revision_id < 3; $revision_id++) {
149 $revision[$revision_id] = field_test_create_stub_entity(0, $revision_id, $this->instance['bundle']);
150 // Note: we try to insert one extra value.
151 $values[$revision_id] = $this->_generateTestFieldValues($this->field['cardinality'] + 1);
152 $current_revision = $revision_id;
153 // If this is the first revision do an insert.
154 if (!$revision_id) {
155 $revision[$revision_id]->{$this->field_name}[$langcode] = $values[$revision_id];
156 field_attach_insert($entity_type, $revision[$revision_id]);
157 }
158 else {
159 // Otherwise do an update.
160 $revision[$revision_id]->{$this->field_name}[$langcode] = $values[$revision_id];
161 field_attach_update($entity_type, $revision[$revision_id]);
162 }
163 }
164
165 // Confirm current revision loads the correct data.
166 $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
167 field_attach_load($entity_type, array(0 => $entity));
168 // Number of values per field loaded equals the field cardinality.
169 $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], t('Current revision: expected number of values'));
170 for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
171 // The field value loaded matches the one inserted or updated.
172 $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'] , $values[$current_revision][$delta]['value'], t('Current revision: expected value %delta was found.', array('%delta' => $delta)));
173 // The value added in hook_field_load() is found.
174 $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['additional_key'], 'additional_value', t('Current revision: extra information for value %delta was found', array('%delta' => $delta)));
175 }
176
177 // Confirm each revision loads the correct data.
178 foreach (array_keys($revision) as $revision_id) {
179 $entity = field_test_create_stub_entity(0, $revision_id, $this->instance['bundle']);
180 field_attach_load_revision($entity_type, array(0 => $entity));
181 // Number of values per field loaded equals the field cardinality.
182 $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], t('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id)));
183 for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
184 // The field value loaded matches the one inserted or updated.
185 $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $values[$revision_id][$delta]['value'], t('Revision %revision_id: expected value %delta was found.', array('%revision_id' => $revision_id, '%delta' => $delta)));
186 // The value added in hook_field_load() is found.
187 $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['additional_key'], 'additional_value', t('Revision %revision_id: extra information for value %delta was found', array('%revision_id' => $revision_id, '%delta' => $delta)));
188 }
189 }
190 }
191
192 /**
193 * Test the 'multiple' load feature.
194 */
195 function testFieldAttachLoadMultiple() {
196 $entity_type = 'test_entity';
197 $langcode = LANGUAGE_NONE;
198
199 // Define 2 bundles.
200 $bundles = array(
201 1 => 'test_bundle_1',
202 2 => 'test_bundle_2',
203 );
204 field_test_create_bundle($bundles[1]);
205 field_test_create_bundle($bundles[2]);
206 // Define 3 fields:
207 // - field_1 is in bundle_1 and bundle_2,
208 // - field_2 is in bundle_1,
209 // - field_3 is in bundle_2.
210 $field_bundles_map = array(
211 1 => array(1, 2),
212 2 => array(1),
213 3 => array(2),
214 );
215 for ($i = 1; $i <= 3; $i++) {
216 $field_names[$i] = 'field_' . $i;
217 $field = array('field_name' => $field_names[$i], 'type' => 'test_field');
218 $field = field_create_field($field);
219 $field_ids[$i] = $field['id'];
220 foreach ($field_bundles_map[$i] as $bundle) {
221 $instance = array(
222 'field_name' => $field_names[$i],
223 'entity_type' => 'test_entity',
224 'bundle' => $bundles[$bundle],
225 'settings' => array(
226 // Configure the instance so that we test hook_field_load()
227 // (see field_test_field_load() in field_test.module).
228 'test_hook_field_load' => TRUE,
229 ),
230 );
231 field_create_instance($instance);
232 }
233 }
234
235 // Create one test entity per bundle, with random values.
236 foreach ($bundles as $index => $bundle) {
237 $entities[$index] = field_test_create_stub_entity($index, $index, $bundle);
238 $entity = clone($entities[$index]);
239 $instances = field_info_instances('test_entity', $bundle);
240 foreach ($instances as $field_name => $instance) {
241 $values[$index][$field_name] = mt_rand(1, 127);
242 $entity->$field_name = array($langcode => array(array('value' => $values[$index][$field_name])));
243 }
244 field_attach_insert($entity_type, $entity);
245 }
246
247 // Check that a single load correctly loads field values for both entities.
248 field_attach_load($entity_type, $entities);
249 foreach ($entities as $index => $entity) {
250 $instances = field_info_instances($entity_type, $bundles[$index]);
251 foreach ($instances as $field_name => $instance) {
252 // The field value loaded matches the one inserted.
253 $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], $values[$index][$field_name], t('Entity %index: expected value was found.', array('%index' => $index)));
254 // The value added in hook_field_load() is found.
255 $this->assertEqual($entity->{$field_name}[$langcode][0]['additional_key'], 'additional_value', t('Entity %index: extra information was found', array('%index' => $index)));
256 }
257 }
258
259 // Check that the single-field load option works.
260 $entity = field_test_create_stub_entity(1, 1, $bundles[1]);
261 field_attach_load($entity_type, array(1 => $entity), FIELD_LOAD_CURRENT, array('field_id' => $field_ids[1]));
262 $this->assertEqual($entity->{$field_names[1]}[$langcode][0]['value'], $values[1][$field_names[1]], t('Entity %index: expected value was found.', array('%index' => 1)));
263 $this->assertEqual($entity->{$field_names[1]}[$langcode][0]['additional_key'], 'additional_value', t('Entity %index: extra information was found', array('%index' => 1)));
264 $this->assert(!isset($entity->{$field_names[2]}), t('Entity %index: field %field_name is not loaded.', array('%index' => 2, '%field_name' => $field_names[2])));
265 $this->assert(!isset($entity->{$field_names[3]}), t('Entity %index: field %field_name is not loaded.', array('%index' => 3, '%field_name' => $field_names[3])));
266 }
267
268 /**
269 * Test saving and loading fields using different storage backends.
270 */
271 function testFieldAttachSaveLoadDifferentStorage() {
272 $entity_type = 'test_entity';
273 $langcode = LANGUAGE_NONE;
274
275 // Create two fields using different storage backends, and their instances.
276 $fields = array(
277 array(
278 'field_name' => 'field_1',
279 'type' => 'test_field',
280 'cardinality' => 4,
281 'storage' => array('type' => 'field_sql_storage')
282 ),
283 array(
284 'field_name' => 'field_2',
285 'type' => 'test_field',
286 'cardinality' => 4,
287 'storage' => array('type' => 'field_test_storage')
288 ),
289 );
290 foreach ($fields as $field) {
291 field_create_field($field);
292 $instance = array(
293 'field_name' => $field['field_name'],
294 'entity_type' => 'test_entity',
295 'bundle' => 'test_bundle',
296 );
297 field_create_instance($instance);
298 }
299
300 $entity_init = field_test_create_stub_entity();
301
302 // Create entity and insert random values.
303 $entity = clone($entity_init);
304 $values = array();
305 foreach ($fields as $field) {
306 $values[$field['field_name']] = $this->_generateTestFieldValues($this->field['cardinality']);
307 $entity->{$field['field_name']}[$langcode] = $values[$field['field_name']];
308 }
309 field_attach_insert($entity_type, $entity);
310
311 // Check that values are loaded as expected.
312 $entity = clone($entity_init);
313 field_attach_load($entity_type, array($entity->ftid => $entity));
314 foreach ($fields as $field) {
315 $this->assertEqual($values[$field['field_name']], $entity->{$field['field_name']}[$langcode], t('%storage storage: expected values were found.', array('%storage' => $field['storage']['type'])));
316 }
317 }
318
319 /**
320 * Test storage details alteration.
321 *
322 * @see field_test_storage_details_alter()
323 */
324 function testFieldStorageDetailsAlter() {
325 $field_name = 'field_test_change_my_details';
326 $field = array(
327 'field_name' => $field_name,
328 'type' => 'test_field',
329 'cardinality' => 4,
330 'storage' => array('type' => 'field_test_storage'),
331 );
332 $field = field_create_field($field);
333 $instance = array(
334 'field_name' => $field_name,
335 'entity_type' => 'test_entity',
336 'bundle' => 'test_bundle',
337 );
338 field_create_instance($instance);
339
340 $field = field_info_field($instance['field_name']);
341 $instance = field_info_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);
342
343 // The storage details are indexed by a storage engine type.
344 $this->assertTrue(array_key_exists('drupal_variables', $field['storage']['details']), t('The storage type is Drupal variables.'));
345
346 $details = $field['storage']['details']['drupal_variables'];
347
348 // The field_test storage details are indexed by variable name. The details
349 // are altered, so moon and mars are correct for this test.
350 $this->assertTrue(array_key_exists('moon', $details[FIELD_LOAD_CURRENT]), t('Moon is available in the instance array.'));
351 $this->assertTrue(array_key_exists('mars', $details[FIELD_LOAD_REVISION]), t('Mars is available in the instance array.'));
352
353 // Test current and revision storage details together because the columns
354 // are the same.
355 foreach ((array) $field['columns'] as $column_name => $attributes) {
356 $this->assertEqual($details[FIELD_LOAD_CURRENT]['moon'][$column_name], $column_name, t('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => 'moon[FIELD_LOAD_CURRENT]')));
357 $this->assertEqual($details[FIELD_LOAD_REVISION]['mars'][$column_name], $column_name, t('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => 'mars[FIELD_LOAD_REVISION]')));
358 }
359 }
360
361 /**
362 * Tests insert and update with missing or NULL fields.
363 */
364 function testFieldAttachSaveMissingData() {
365 $entity_type = 'test_entity';
366 $entity_init = field_test_create_stub_entity();
367 $langcode = LANGUAGE_NONE;
368
369 // Insert: Field is missing.
370 $entity = clone($entity_init);
371 field_attach_insert($entity_type, $entity);
372
373 $entity = clone($entity_init);
374 field_attach_load($entity_type, array($entity->ftid => $entity));
375 $this->assertTrue(empty($entity->{$this->field_name}), t('Insert: missing field results in no value saved'));
376
377 // Insert: Field is NULL.
378 field_cache_clear();
379 $entity = clone($entity_init);
380 $entity->{$this->field_name} = NULL;
381 field_attach_insert($entity_type, $entity);
382
383 $entity = clone($entity_init);
384 field_attach_load($entity_type, array($entity->ftid => $entity));
385 $this->assertTrue(empty($entity->{$this->field_name}), t('Insert: NULL field results in no value saved'));
386
387 // Add some real data.
388 field_cache_clear();
389 $entity = clone($entity_init);
390 $values = $this->_generateTestFieldValues(1);
391 $entity->{$this->field_name}[$langcode] = $values;
392 field_attach_insert($entity_type, $entity);
393
394 $entity = clone($entity_init);
395 field_attach_load($entity_type, array($entity->ftid => $entity));
396 $this->assertEqual($entity->{$this->field_name}[$langcode], $values, t('Field data saved'));
397
398 // Update: Field is missing. Data should survive.
399 field_cache_clear();
400 $entity = clone($entity_init);
401 field_attach_update($entity_type, $entity);
402
403 $entity = clone($entity_init);
404 field_attach_load($entity_type, array($entity->ftid => $entity));
405 $this->assertEqual($entity->{$this->field_name}[$langcode], $values, t('Update: missing field leaves existing values in place'));
406
407 // Update: Field is NULL. Data should be wiped.
408 field_cache_clear();
409 $entity = clone($entity_init);
410 $entity->{$this->field_name} = NULL;
411 field_attach_update($entity_type, $entity);
412
413 $entity = clone($entity_init);
414 field_attach_load($entity_type, array($entity->ftid => $entity));
415 $this->assertTrue(empty($entity->{$this->field_name}), t('Update: NULL field removes existing values'));
416
417 // Re-add some data.
418 field_cache_clear();
419 $entity = clone($entity_init);
420 $values = $this->_generateTestFieldValues(1);
421 $entity->{$this->field_name}[$langcode] = $values;
422 field_attach_update($entity_type, $entity);
423
424 $entity = clone($entity_init);
425 field_attach_load($entity_type, array($entity->ftid => $entity));
426 $this->assertEqual($entity->{$this->field_name}[$langcode], $values, t('Field data saved'));
427
428 // Update: Field is empty array. Data should be wiped.
429 field_cache_clear();
430 $entity = clone($entity_init);
431 $entity->{$this->field_name} = array();
432 field_attach_update($entity_type, $entity);
433
434 $entity = clone($entity_init);
435 field_attach_load($entity_type, array($entity->ftid => $entity));
436 $this->assertTrue(empty($entity->{$this->field_name}), t('Update: empty array removes existing values'));
437 }
438
439 /**
440 * Test insert with missing or NULL fields, with default value.
441 */
442 function testFieldAttachSaveMissingDataDefaultValue() {
443 // Add a default value function.
444 $this->instance['default_value_function'] = 'field_test_default_value';
445 field_update_instance($this->instance);
446
447 $entity_type = 'test_entity';
448 $entity_init = field_test_create_stub_entity();
449 $langcode = LANGUAGE_NONE;
450
451 // Insert: Field is NULL.
452 $entity = clone($entity_init);
453 $entity->{$this->field_name}[$langcode] = NULL;
454 field_attach_insert($entity_type, $entity);
455
456 $entity = clone($entity_init);
457 field_attach_load($entity_type, array($entity->ftid => $entity));
458 $this->assertTrue(empty($entity->{$this->field_name}[$langcode]), t('Insert: NULL field results in no value saved'));
459
460 // Insert: Field is missing.
461 field_cache_clear();
462 $entity = clone($entity_init);
463 field_attach_insert($entity_type, $entity);
464
465 $entity = clone($entity_init);
466 field_attach_load($entity_type, array($entity->ftid => $entity));
467 $values = field_test_default_value($entity_type, $entity, $this->field, $this->instance);
468 $this->assertEqual($entity->{$this->field_name}[$langcode], $values, t('Insert: missing field results in default value saved'));
469 }
470
471 /**
472 * Test field_attach_delete().
473 */
474 function testFieldAttachDelete() {
475 $entity_type = 'test_entity';
476 $langcode = LANGUAGE_NONE;
477 $rev[0] = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
478
479 // Create revision 0
480 $values = $this->_generateTestFieldValues($this->field['cardinality']);
481 $rev[0]->{$this->field_name}[$langcode] = $values;
482 field_attach_insert($entity_type, $rev[0]);
483
484 // Create revision 1
485 $rev[1] = field_test_create_stub_entity(0, 1, $this->instance['bundle']);
486 $rev[1]->{$this->field_name}[$langcode] = $values;
487 field_attach_update($entity_type, $rev[1]);
488
489 // Create revision 2
490 $rev[2] = field_test_create_stub_entity(0, 2, $this->instance['bundle']);
491 $rev[2]->{$this->field_name}[$langcode] = $values;
492 field_attach_update($entity_type, $rev[2]);
493
494 // Confirm each revision loads
495 foreach (array_keys($rev) as $vid) {
496 $read = field_test_create_stub_entity(0, $vid, $this->instance['bundle']);
497 field_attach_load_revision($entity_type, array(0 => $read));
498 $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
499 }
500
501 // Delete revision 1, confirm the other two still load.
502 field_attach_delete_revision($entity_type, $rev[1]);
503 foreach (array(0, 2) as $vid) {
504 $read = field_test_create_stub_entity(0, $vid, $this->instance['bundle']);
505 field_attach_load_revision($entity_type, array(0 => $read));
506 $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
507 }
508
509 // Confirm the current revision still loads
510 $read = field_test_create_stub_entity(0, 2, $this->instance['bundle']);
511 field_attach_load($entity_type, array(0 => $read));
512 $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field['cardinality'], "The test entity current revision has {$this->field['cardinality']} values.");
513
514 // Delete all field data, confirm nothing loads
515 field_attach_delete($entity_type, $rev[2]);
516 foreach (array(0, 1, 2) as $vid) {
517 $read = field_test_create_stub_entity(0, $vid, $this->instance['bundle']);
518 field_attach_load_revision($entity_type, array(0 => $read));
519 $this->assertIdentical($read->{$this->field_name}, array(), "The test entity revision $vid is deleted.");
520 }
521 $read = field_test_create_stub_entity(0, 2, $this->instance['bundle']);
522 field_attach_load($entity_type, array(0 => $read));
523 $this->assertIdentical($read->{$this->field_name}, array(), t('The test entity current revision is deleted.'));
524 }
525
526 /**
527 * Test field_attach_create_bundle() and field_attach_rename_bundle().
528 */
529 function testFieldAttachCreateRenameBundle() {
530 // Create a new bundle. This has to be initiated by the module so that its
531 // hook_entity_info() is consistent.
532 $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
533 field_test_create_bundle($new_bundle);
534
535 // Add an instance to that bundle.
536 $this->instance['bundle'] = $new_bundle;
537 field_create_instance($this->instance);
538
539 // Save an entity with data in the field.
540 $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
541 $langcode = LANGUAGE_NONE;
542 $values = $this->_generateTestFieldValues($this->field['cardinality']);
543 $entity->{$this->field_name}[$langcode] = $values;
544 $entity_type = 'test_entity';
545 field_attach_insert($entity_type, $entity);
546
547 // Verify the field data is present on load.
548 $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
549 field_attach_load($entity_type, array(0 => $entity));
550 $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], "Data is retrieved for the new bundle");
551
552 // Rename the bundle. This has to be initiated by the module so that its
553 // hook_entity_info() is consistent.
554 $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
555 field_test_rename_bundle($this->instance['bundle'], $new_bundle);
556
557 // Check that the instance definition has been updated.
558 $this->instance = field_info_instance($entity_type, $this->field_name, $new_bundle);
559 $this->assertIdentical($this->instance['bundle'], $new_bundle, "Bundle name has been updated in the instance.");
560
561 // Verify the field data is present on load.
562 $entity = field_test_create_stub_entity(0, 0, $new_bundle);
563 field_attach_load($entity_type, array(0 => $entity));
564 $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], "Bundle name has been updated in the field storage");
565 }
566
567 /**
568 * Test field_attach_delete_bundle().
569 */
570 function testFieldAttachDeleteBundle() {
571 // Create a new bundle. This has to be initiated by the module so that its
572 // hook_entity_info() is consistent.
573 $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
574 field_test_create_bundle($new_bundle);
575
576 // Add an instance to that bundle.
577 $this->instance['bundle'] = $new_bundle;
578 field_create_instance($this->instance);
579
580 // Create a second field for the test bundle
581 $field_name = drupal_strtolower($this->randomName() . '_field_name');
582 $field = array('field_name' => $field_name, 'type' => 'test_field', 'cardinality' => 1);
583 field_create_field($field);
584 $instance = array(
585 'field_name' => $field_name,
586 'entity_type' => 'test_entity',
587 'bundle' => $this->instance['bundle'],
588 'label' => $this->randomName() . '_label',
589 'description' => $this->randomName() . '_description',
590 'weight' => mt_rand(0, 127),
591 // test_field has no instance settings
592 'widget' => array(
593 'type' => 'test_field_widget',
594 'settings' => array(
595 'size' => mt_rand(0, 255))));
596 field_create_instance($instance);
597
598 // Save an entity with data for both fields
599 $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
600 $langcode = LANGUAGE_NONE;
601 $values = $this->_generateTestFieldValues($this->field['cardinality']);
602 $entity->{$this->field_name}[$langcode] = $values;
603 $entity->{$field_name}[$langcode] = $this->_generateTestFieldValues(1);
604 field_attach_insert('test_entity', $entity);
605
606 // Verify the fields are present on load
607 $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
608 field_attach_load('test_entity', array(0 => $entity));
609 $this->assertEqual(count($entity->{$this->field_name}[$langcode]), 4, 'First field got loaded');
610 $this->assertEqual(count($entity->{$field_name}[$langcode]), 1, 'Second field got loaded');
611
612 // Delete the bundle. This has to be initiated by the module so that its
613 // hook_entity_info() is consistent.
614 field_test_delete_bundle($this->instance['bundle']);
615
616 // Verify no data gets loaded
617 $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
618 field_attach_load('test_entity', array(0 => $entity));
619 $this->assertFalse(isset($entity->{$this->field_name}[$langcode]), 'No data for first field');
620 $this->assertFalse(isset($entity->{$field_name}[$langcode]), 'No data for second field');
621
622 // Verify that the instances are gone
623 $this->assertFalse(field_read_instance('test_entity', $this->field_name, $this->instance['bundle']), "First field is deleted");
624 $this->assertFalse(field_read_instance('test_entity', $field_name, $instance['bundle']), "Second field is deleted");
625 }
626 }
627
628 /**
629 * Unit test class for non-storage related field_attach_* functions.
630 */
631 class FieldAttachOtherTestCase extends FieldAttachTestCase {
632 public static function getInfo() {
633 return array(
634 'name' => 'Field attach tests (other)',
635 'description' => 'Test other Field Attach API functions.',
636 'group' => 'Field API',
637 );
638 }
639
640 /**
641 * Test field_attach_view() and field_attach_prepare_view().
642 */
643 function testFieldAttachView() {
644 $entity_type = 'test_entity';
645 $entity_init = field_test_create_stub_entity();
646 $langcode = LANGUAGE_NONE;
647
648 // Populate values to be displayed.
649 $values = $this->_generateTestFieldValues($this->field['cardinality']);
650 $entity_init->{$this->field_name}[$langcode] = $values;
651
652 // Simple formatter, label displayed.
653 $entity = clone($entity_init);
654 $formatter_setting = $this->randomName();
655 $this->instance['display'] = array(
656 'full' => array(
657 'label' => 'above',
658 'type' => 'field_test_default',
659 'settings' => array(
660 'test_formatter_setting' => $formatter_setting,
661 )
662 ),
663 );
664 field_update_instance($this->instance);
665 field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full');
666 $entity->content = field_attach_view($entity_type, $entity, 'full');
667 $output = drupal_render($entity->content);
668 $this->content = $output;
669 $this->assertRaw($this->instance['label'], "Label is displayed.");
670 foreach ($values as $delta => $value) {
671 $this->content = $output;
672 $this->assertRaw("$formatter_setting|{$value['value']}", "Value $delta is displayed, formatter settings are applied.");
673 }
674
675 // Label hidden.
676 $entity = clone($entity_init);
677 $this->instance['display']['full']['label'] = 'hidden';
678 field_update_instance($this->instance);
679 field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full');
680 $entity->content = field_attach_view($entity_type, $entity, 'full');
681 $output = drupal_render($entity->content);
682 $this->content = $output;
683 $this->assertNoRaw($this->instance['label'], "Hidden label: label is not displayed.");
684
685 // Field hidden.
686 $entity = clone($entity_init);
687 $this->instance['display'] = array(
688 'full' => array(
689 'label' => 'above',
690 'type' => 'hidden',
691 ),
692 );
693 field_update_instance($this->instance);
694 field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full');
695 $entity->content = field_attach_view($entity_type, $entity, 'full');
696 $output = drupal_render($entity->content);
697 $this->content = $output;
698 $this->assertNoRaw($this->instance['label'], "Hidden field: label is not displayed.");
699 foreach ($values as $delta => $value) {
700 $this->assertNoRaw($value['value'], "Hidden field: value $delta is not displayed.");
701 }
702
703 // Multiple formatter.
704 $entity = clone($entity_init);
705 $formatter_setting = $this->randomName();
706 $this->instance['display'] = array(
707 'full' => array(
708 'label' => 'above',
709 'type' => 'field_test_multiple',
710 'settings' => array(
711 'test_formatter_setting_multiple' => $formatter_setting,
712 )
713 ),
714 );
715 field_update_instance($this->instance);
716 field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full');
717 $entity->content = field_attach_view($entity_type, $entity, 'full');
718 $output = drupal_render($entity->content);
719 $display = $formatter_setting;
720 foreach ($values as $delta => $value) {
721 $display .= "|$delta:{$value['value']}";
722 }
723 $this->content = $output;
724 $this->assertRaw($display, "Multiple formatter: all values are displayed, formatter settings are applied.");
725
726 // Test a formatter that uses hook_field_formatter_prepare_view().
727 $entity = clone($entity_init);
728 $formatter_setting = $this->randomName();
729 $this->instance['display'] = array(
730 'full' => array(
731 'label' => 'above',
732 'type' => 'field_test_with_prepare_view',
733 'settings' => array(
734 'test_formatter_setting_additional' => $formatter_setting,
735 )
736 ),
737 );
738 field_update_instance($this->instance);
739 field_attach_prepare_view($entity_type, array($entity->ftid => $entity), 'full');
740 $entity->content = field_attach_view($entity_type, $entity, 'full');
741 $output = drupal_render($entity->content);
742 $this->content = $output;
743 foreach ($values as $delta => $value) {
744 $this->content = $output;
745 $expected = $formatter_setting . '|' . $value['value'] . '|' . ($value['value'] + 1);
746 $this->assertRaw($expected, "Value $delta is displayed, formatter settings are applied.");
747 }
748
749 // TODO:
750 // - check display order with several fields
751
752 // Preprocess template.
753 $variables = array();
754 field_attach_preprocess($entity_type, $entity, $entity->content, $variables);
755 $result = TRUE;
756 foreach ($values as $delta => $item) {
757 if ($variables[$this->field_name][$delta]['value'] !== $item['value']) {
758 $result = FALSE;
759 break;
760 }
761 }
762 $this->assertTrue($result, t('Variable $@field_name correctly populated.', array('@field_name' => $this->field_name)));
763 }
764
765 /**
766 * Tests the 'multiple entity' behavior of field_attach_prepare_view().
767 */
768 function testFieldAttachPrepareViewMultiple() {
769 $entity_type = 'test_entity';
770 $langcode = LANGUAGE_NONE;
771
772 // Set the instance to be hidden.
773 $this->instance['display']['full']['type'] = 'hidden';
774 field_update_instance($this->instance);
775
776 // Set up a second instance on another bundle, with a formatter that uses
777 // hook_field_formatter_prepare_view().
778 field_test_create_bundle('test_bundle_2');
779 $formatter_setting = $this->randomName();
780 $this->instance2 = $this->instance;
781 $this->instance2['bundle'] = 'test_bundle_2';
782 $this->instance2['display']['full'] = array(
783 'type' => 'field_test_with_prepare_view',
784 'settings' => array(
785 'test_formatter_setting_additional' => $formatter_setting,
786 )
787 );
788 field_create_instance($this->instance2);
789
790 // Create one entity in each bundle.
791 $entity1_init = field_test_create_stub_entity(1, 1, 'test_bundle');
792 $values1 = $this->_generateTestFieldValues($this->field['cardinality']);
793 $entity1_init->{$this->field_name}[$langcode] = $values1;
794
795 $entity2_init = field_test_create_stub_entity(2, 2, 'test_bundle_2');
796 $values2 = $this->_generateTestFieldValues($this->field['cardinality']);
797 $entity2_init->{$this->field_name}[$langcode] = $values2;
798
799 // Run prepare_view, and check that the entities come out as expected.
800 $entity1 = clone($entity1_init);
801 $entity2 = clone($entity2_init);
802 field_attach_prepare_view($entity_type, array($entity1->ftid => $entity1, $entity2->ftid => $entity2), 'full');
803 $this->assertFalse(isset($entity1->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 1 did not run through the prepare_view hook.');
804 $this->assertTrue(isset($entity2->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 2 ran through the prepare_view hook.');
805
806 // Same thing, reversed order.
807 $entity1 = clone($entity1_init);
808 $entity2 = clone($entity2_init);
809 field_attach_prepare_view($entity_type, array($entity2->ftid => $entity2, $entity1->ftid => $entity1), 'full');
810 $this->assertFalse(isset($entity1->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 1 did not run through the prepare_view hook.');
811 $this->assertTrue(isset($entity2->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 2 ran through the prepare_view hook.');
812 }
813
814 /**
815 * Test field cache.
816 */
817 function testFieldAttachCache() {
818 // Initialize random values and a test entity.
819 $entity_init = field_test_create_stub_entity(1, 1, $this->instance['bundle']);
820 $langcode = LANGUAGE_NONE;
821 $values = $this->_generateTestFieldValues($this->field['cardinality']);
822
823 // Non-cacheable entity type.
824 $entity_type = 'test_entity';
825 $cid = "field:$entity_type:{$entity_init->ftid}";
826
827 // Check that no initial cache entry is present.
828 $this->assertFalse(cache_get($cid, 'cache_field'), t('Non-cached: no initial cache entry'));
829
830 // Save, and check that no cache entry is present.
831 $entity = clone($entity_init);
832 $entity->{$this->field_name}[$langcode] = $values;
833 field_attach_insert($entity_type, $entity);
834 $this->assertFalse(cache_get($cid, 'cache_field'), t('Non-cached: no cache entry on insert'));
835
836 // Load, and check that no cache entry is present.
837 $entity = clone($entity_init);
838 field_attach_load($entity_type, array($entity->ftid => $entity));
839 $this->assertFalse(cache_get($cid, 'cache_field'), t('Non-cached: no cache entry on load'));
840
841
842 // Cacheable entity type.
843 $entity_type = 'test_cacheable_entity';
844 $cid = "field:$entity_type:{$entity_init->ftid}";
845 $instance = $this->instance;
846 $instance['entity_type'] = $entity_type;
847 field_create_instance($instance);
848
849 // Check that no initial cache entry is present.
850 $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no initial cache entry'));
851
852 // Save, and check that no cache entry is present.
853 $entity = clone($entity_init);
854 $entity->{$this->field_name}[$langcode] = $values;
855 field_attach_insert($entity_type, $entity);
856 $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on insert'));
857
858 // Load a single field, and check that no cache entry is present.
859 $entity = clone($entity_init);
860 field_attach_load($entity_type, array($entity->ftid => $entity), FIELD_LOAD_CURRENT, array('field_id' => $this->field_id));
861 $cache = cache_get($cid, 'cache_field');
862 $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on loading a single field'));
863
864 // Load, and check that a cache entry is present with the expected values.
865 $entity = clone($entity_init);
866 field_attach_load($entity_type, array($entity->ftid => $entity));
867 $cache = cache_get($cid, 'cache_field');
868 $this->assertEqual($cache->data[$this->field_name][$langcode], $values, t('Cached: correct cache entry on load'));
869
870 // Update with different values, and check that the cache entry is wiped.
871 $values = $this->_generateTestFieldValues($this->field['cardinality']);
872 $entity = clone($entity_init);
873 $entity->{$this->field_name}[$langcode] = $values;
874 field_attach_update($entity_type, $entity);
875 $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on update'));
876
877 // Load, and check that a cache entry is present with the expected values.
878 $entity = clone($entity_init);
879 field_attach_load($entity_type, array($entity->ftid => $entity));
880 $cache = cache_get($cid, 'cache_field');
881 $this->assertEqual($cache->data[$this->field_name][$langcode], $values, t('Cached: correct cache entry on load'));
882
883 // Create a new revision, and check that the cache entry is wiped.
884 $entity_init = field_test_create_stub_entity(1, 2, $this->instance['bundle']);
885 $values = $this->_generateTestFieldValues($this->field['cardinality']);
886 $entity = clone($entity_init);
887 $entity->{$this->field_name}[$langcode] = $values;
888 field_attach_update($entity_type, $entity);
889 $cache = cache_get($cid, 'cache_field');
890 $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry on new revision creation'));
891
892 // Load, and check that a cache entry is present with the expected values.
893 $entity = clone($entity_init);
894 field_attach_load($entity_type, array($entity->ftid => $entity));
895 $cache = cache_get($cid, 'cache_field');
896 $this->assertEqual($cache->data[$this->field_name][$langcode], $values, t('Cached: correct cache entry on load'));
897
898 // Delete, and check that the cache entry is wiped.
899 field_attach_delete($entity_type, $entity);
900 $this->assertFalse(cache_get($cid, 'cache_field'), t('Cached: no cache entry after delete'));
901 }
902
903 /**
904 * Test field_attach_validate().
905 *
906 * Verify that field_attach_validate() invokes the correct
907 * hook_field_validate.
908 */
909 function testFieldAttachValidate() {
910 $entity_type = 'test_entity';
911 $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
912 $langcode = LANGUAGE_NONE;
913
914 // Set up values to generate errors
915 $values = array();
916 for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
917 $values[$delta]['value'] = -1;
918 }
919 // Arrange for item 1 not to generate an error
920 $values[1]['value'] = 1;
921 $entity->{$this->field_name}[$langcode] = $values;
922
923 try {
924 field_attach_validate($entity_type, $entity);
925 }
926 catch (FieldValidationException $e) {
927 $errors = $e->errors;
928 }
929
930 foreach ($values as $delta => $value) {
931 if ($value['value'] != 1) {
932 $this->assertIdentical($errors[$this->field_name][$langcode][$delta][0]['error'], 'field_test_invalid', "Error set on value $delta");
933 $this->assertEqual(count($errors[$this->field_name][$langcode][$delta]), 1, "Only one error set on value $delta");
934 unset($errors[$this->field_name][$langcode][$delta]);
935 }
936 else {
937 $this->assertFalse(isset($errors[$this->field_name][$langcode][$delta]), "No error set on value $delta");
938 }
939 }
940 $this->assertEqual(count($errors[$this->field_name][$langcode]), 0, 'No extraneous errors set');
941
942 // Check that cardinality is validated.
943 $entity->{$this->field_name}[$langcode] = $this->_generateTestFieldValues($this->field['cardinality'] + 1);
944 try {
945 field_attach_validate($entity_type, $entity);
946 }
947 catch (FieldValidationException $e) {
948 $errors = $e->errors;
949 }
950 $this->assertEqual($errors[$this->field_name][$langcode][0][0]['error'], 'field_cardinality', t('Cardinality validation failed.'));
951
952 }
953
954 /**
955 * Test field_attach_form().
956 *
957 * This could be much more thorough, but it does verify that the correct
958 * widgets show up.
959 */
960 function testFieldAttachForm() {
961 $entity_type = 'test_entity';
962 $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
963
964 $form = array();
965 $form_state = form_state_defaults();
966 field_attach_form($entity_type, $entity, $form, $form_state);
967
968 $langcode = LANGUAGE_NONE;
969 $this->assertEqual($form[$this->field_name][$langcode]['#title'], $this->instance['label'], "Form title is {$this->instance['label']}");
970 for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
971 // field_test_widget uses 'textfield'
972 $this->assertEqual($form[$this->field_name][$langcode][$delta]['value']['#type'], 'textfield', "Form delta $delta widget is textfield");
973 }
974 }
975
976 /**
977 * Test field_attach_submit().
978 */
979 function testFieldAttachSubmit() {
980 $entity_type = 'test_entity';
981 $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
982
983 // Build the form.
984 $form = array();
985 $form_state = form_state_defaults();
986 field_attach_form($entity_type, $entity, $form, $form_state);
987
988 // Simulate incoming values.
989 $values = array();
990 $weights = array();
991 for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
992 $values[$delta]['value'] = mt_rand(1, 127);
993 // Assign random weight.
994 do {
995 $weight = mt_rand(0, $this->field['cardinality']);
996 } while (in_array($weight, $weights));
997 $weights[$delta] = $weight;
998 $values[$delta]['_weight'] = $weight;
999 }
1000 // Leave an empty value. 'field_test' fields are empty if empty().
1001 $values[1]['value'] = 0;
1002
1003 $langcode = LANGUAGE_NONE;
1004 // Pretend the form has been built.
1005 drupal_prepare_form('field_test_entity_form', $form, $form_state);
1006 drupal_process_form('field_test_entity_form', $form, $form_state);
1007 $form_state['values'][$this->field_name][$langcode] = $values;
1008 field_attach_submit($entity_type, $entity, $form, $form_state);
1009
1010 asort($weights);
1011 $expected_values = array();
1012 foreach ($weights as $key => $value) {
1013 if ($key != 1) {
1014 $expected_values[] = array('value' => $values[$key]['value']);
1015 }
1016 }
1017 $this->assertIdentical($entity->{$this->field_name}[$langcode], $expected_values, 'Submit filters empty values');
1018 }
1019 }
1020
1021 class FieldInfoTestCase extends FieldTestCase {
1022
1023 public static function getInfo() {
1024 return array(
1025 'name' => 'Field info tests',
1026 'description' => 'Get information about existing fields, instances and bundles.',
1027 'group' => 'Field API',
1028 );
1029 }
1030
1031 function setUp() {
1032 parent::setUp('field_test');
1033 }
1034
1035 /**
1036 * Test that field types and field definitions are correcly cached.
1037 */
1038 function testFieldInfo() {
1039 // Test that field_test module's fields, widgets, and formatters show up.
1040
1041 $field_test_info = field_test_field_info();
1042 // We need to account for the existence of user_field_info_alter().
1043 foreach (array_keys($field_test_info) as $name) {
1044 $field_test_info[$name]['instance_settings']['user_register_form'] = FALSE;
1045 }
1046 $info = field_info_field_types();
1047 foreach ($field_test_info as $t_key => $field_type) {
1048 foreach ($field_type as $key => $val) {
1049 $this->assertEqual($info[$t_key][$key], $val, t("Field type $t_key key $key is $val"));
1050 }
1051 $this->assertEqual($info[$t_key]['module'], 'field_test', t("Field type field_test module appears"));
1052 }
1053
1054 $formatter_info = field_test_field_formatter_info();
1055 $info = field_info_formatter_types();
1056 foreach ($formatter_info as $f_key => $formatter) {
1057 foreach ($formatter as $key => $val) {
1058 $this->assertEqual($info[$f_key][$key], $val, t("Formatter type $f_key key $key is $val"));
1059 }
1060 $this->assertEqual($info[$f_key]['module'], 'field_test', t("Formatter type field_test module appears"));
1061 }
1062
1063 $widget_info = field_test_field_widget_info();
1064 $info = field_info_widget_types();
1065 foreach ($widget_info as $w_key => $widget) {
1066 foreach ($widget as $key => $val) {
1067 $this->assertEqual($info[$w_key][$key], $val, t("Widget type $w_key key $key is $val"));
1068 }
1069 $this->assertEqual($info[$w_key]['module'], 'field_test', t("Widget type field_test module appears"));
1070 }
1071
1072 $storage_info = field_test_field_storage_info();
1073 $info = field_info_storage_types();
1074 foreach ($storage_info as $s_key => $storage) {
1075 foreach ($storage as $key => $val) {
1076 $this->assertEqual($info[$s_key][$key], $val, t("Storage type $s_key key $key is $val"));
1077 }
1078 $this->assertEqual($info[$s_key]['module'], 'field_test', t("Storage type field_test module appears"));
1079 }
1080
1081 // Verify that no unexpected instances exist.
1082 $core_fields = field_info_fields();
1083 $instances = field_info_instances('test_entity', 'test_bundle');
1084 $this->assertTrue(empty($instances), t('With no instances, info bundles is empty.'));
1085
1086 // Create a field, verify it shows up.
1087 $field = array(
1088 'field_name' => drupal_strtolower($this->randomName()),
1089 'type' => 'test_field',
1090 );
1091 field_create_field($field);
1092 $fields = field_info_fields();
1093 $this->assertEqual(count($fields), count($core_fields) + 1, t('One new field exists'));
1094 $this->assertEqual($fields[$field['field_name']]['field_name'], $field['field_name'], t('info fields contains field name'));
1095 $this->assertEqual($fields[$field['field_name']]['type'], $field['type'], t('info fields contains field type'));
1096 $this->assertEqual($fields[$field['field_name']]['module'], 'field_test', t('info fields contains field module'));
1097 $settings = array('test_field_setting' => 'dummy test string');
1098 foreach ($settings as $key => $val) {
1099 $this->assertEqual($fields[$field['field_name']]['settings'][$key], $val, t("Field setting $key has correct default value $val"));
1100 }
1101 $this->assertEqual($fields[$field['field_name']]['cardinality'], 1, t('info fields contains cardinality 1'));
1102 $this->assertEqual($fields[$field['field_name']]['active'], 1, t('info fields contains active 1'));
1103
1104 // Create an instance, verify that it shows up
1105 $instance = array(
1106 'field_name' => $field['field_name'],
1107 'entity_type' => 'test_entity',
1108 'bundle' => 'test_bundle',
1109 'label' => $this->randomName(),
1110 'description' => $this->randomName(),
1111 'weight' => mt_rand(0, 127),
1112 // test_field has no instance settings
1113 'widget' => array(
1114 'type' => 'test_field_widget',
1115 'settings' => array(
1116 'test_setting' => 999)));
1117 field_create_instance($instance);
1118
1119 $instances = field_info_instances('test_entity', $instance['bundle']);
1120 $this->assertEqual(count($instances), 1, t('One instance shows up in info when attached to a bundle.'));
1121 $this->assertTrue($instance < $instances[$instance['field_name']], t('Instance appears in info correctly'));
1122 }
1123
1124 /**
1125 * Test that cached field definitions are ready for current runtime context.
1126 */
1127 function testFieldPrepare() {
1128 $field_definition = array(
1129 'field_name' => 'field',
1130 'type' => 'test_field',
1131 );
1132 field_create_field($field_definition);
1133
1134 // Simulate a stored field definition missing a field setting (e.g. a
1135 // third-party module adding a new field setting has been enabled, and
1136 // existing fields do not know the setting yet).
1137 $data = db_query('SELECT data FROM {field_config} WHERE field_name = :field_name', array(':field_name' => $field_definition['field_name']))->fetchField();
1138 $data = unserialize($data);
1139 $data['settings'] = array();
1140 db_update('field_config')
1141 ->fields(array('data' => serialize($data)))
1142 ->condition('field_name', $field_definition['field_name'])
1143 ->execute();
1144
1145 field_cache_clear();
1146
1147 // Read the field back.
1148 $field = field_info_field($field_definition['field_name']);
1149
1150 // Check that all expected settings are in place.
1151 $field_type = field_info_field_types($field_definition['type']);
1152 $this->assertIdentical($field['settings'], $field_type['settings'], t('All expected default field settings are present.'));
1153 }
1154
1155 /**
1156 * Test that cached instance definitions are ready for current runtime context.
1157 */
1158 function testInstancePrepare() {
1159 $field_definition = array(
1160 'field_name' => 'field',
1161 'type' => 'test_field',
1162 );
1163 field_create_field($field_definition);
1164 $instance_definition = array(
1165 'field_name' => $field_definition['field_name'],
1166 'entity_type' => 'test_entity',
1167 'bundle' => 'test_bundle',
1168 );
1169 field_create_instance($instance_definition);
1170
1171 // Simulate a stored instance definition missing various settings (e.g. a
1172 // third-party module adding instance, widget or display settings has been
1173 // enabled, but existing instances do not know the new settings).
1174 $data = db_query('SELECT data FROM {field_config_instance} WHERE field_name = :field_name AND bundle = :bundle', array(':field_name' => $instance_definition['field_name'], ':bundle' => $instance_definition['bundle']))->fetchField();
1175 $data = unserialize($data);
1176 $data['settings'] = array();
1177 $data['widget']['settings'] = 'unavailable_widget';
1178 $data['widget']['settings'] = array();
1179 $data['display']['default']['type'] = 'unavailable_formatter';
1180 $data['display']['default']['settings'] = array();
1181 db_update('field_config_instance')
1182 ->fields(array('data' => serialize($data)))
1183 ->condition('field_name', $instance_definition['field_name'])
1184 ->condition('bundle', $instance_definition['bundle'])
1185 ->execute();
1186
1187 field_cache_clear();
1188
1189 // Read the instance back.
1190 $instance = field_info_instance($instance_definition['entity_type'], $instance_definition['field_name'], $instance_definition['bundle']);
1191
1192 // Check that all expected instance settings are in place.
1193 $field_type = field_info_field_types($field_definition['type']);
1194 $this->assertIdentical($instance['settings'], $field_type['instance_settings'] , t('All expected instance settings are present.'));
1195
1196 // Check that the default widget is used and expected settings are in place.
1197 $this->assertIdentical($instance['widget']['type'], $field_type['default_widget'], t('Unavailable widget replaced with default widget.'));
1198 $widget_type = field_info_widget_types($instance['widget']['type']);
1199 $this->assertIdentical($instance['widget']['settings'], $widget_type['settings'] , t('All expected widget settings are present.'));
1200
1201 // Check that display settings are set for the 'default' mode.
1202 $display = $instance['display']['default'];
1203 $this->assertIdentical($display['type'], $field_type['default_formatter'], t("Formatter is set for the 'default' view mode"));
1204 $formatter_type = field_info_formatter_types($display['type']);
1205 $this->assertIdentical($display['settings'], $formatter_type['settings'] , t("Formatter settings are set for the 'default' view mode"));
1206 }
1207
1208 /**
1209 * Test that instances on disabled entity types are filtered out.
1210 */
1211 function testInstanceDisabledEntityType() {
1212 // For this test the field type and the entity type must be exposed by
1213 // different modules.
1214 $field_definition = array(
1215 'field_name' => 'field',
1216 'type' => 'test_field',
1217 );
1218 field_create_field($field_definition);
1219 $instance_definition = array(
1220 'field_name' => 'field',
1221 'entity_type' => 'comment',
1222 'bundle' => 'comment_node_article',
1223 );
1224 field_create_instance($instance_definition);
1225
1226 // Disable coment module. This clears field_info cache.
1227 module_disable(array('comment'));
1228 $this->assertNull(field_info_instance('comment', 'field', 'comment_node_article'), t('No instances are returned on disabled entity types.'));
1229 }
1230
1231 /**
1232 * Test that the field_info settings convenience functions work.
1233 */
1234 function testSettingsInfo() {
1235 $info = field_test_field_info();
1236 // We need to account for the existence of user_field_info_alter().
1237 foreach (array_keys($info) as $name) {
1238 $info[$name]['instance_settings']['user_register_form'] = FALSE;
1239 }
1240 foreach ($info as $type => $data) {
1241 $this->assertIdentical(field_info_field_settings($type), $data['settings'], "field_info_field_settings returns {$type}'s field settings");
1242 $this->assertIdentical(field_info_instance_settings($type), $data['instance_settings'], "field_info_field_settings returns {$type}'s field instance settings");
1243 }
1244
1245 $info = field_test_field_widget_info();
1246 foreach ($info as $type => $data) {
1247 $this->assertIdentical(field_info_widget_settings($type), $data['settings'], "field_info_widget_settings returns {$type}'s widget settings");
1248 }
1249
1250 $info = field_test_field_formatter_info();
1251 foreach ($info as $type => $data) {
1252 $this->assertIdentical(field_info_formatter_settings($type), $data['settings'], "field_info_formatter_settings returns {$type}'s formatter settings");
1253 }
1254 }
1255 }
1256
1257 class FieldFormTestCase extends FieldTestCase {
1258 public static function getInfo() {
1259 return array(
1260 'name' => 'Field form tests',
1261 'description' => 'Test Field form handling.',
1262 'group' => 'Field API',
1263 );
1264 }
1265
1266 function setUp() {
1267 parent::setUp('field_test');
1268
1269 $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
1270 $this->drupalLogin($web_user);
1271
1272 $this->field_single = array('field_name' => 'field_single', 'type' => 'test_field');
1273 $this->field_multiple = array('field_name' => 'field_multiple', 'type' => 'test_field', 'cardinality' => 4);
1274 $this->field_unlimited = array('field_name' => 'field_unlimited', 'type' => 'test_field', 'cardinality' => FIELD_CARDINALITY_UNLIMITED);
1275
1276 $this->instance = array(
1277 'entity_type' => 'test_entity',
1278 'bundle' => 'test_bundle',
1279 'label' => $this->randomName() . '_label',
1280 'description' => $this->randomName() . '_description',
1281 'weight' => mt_rand(0, 127),
1282 'settings' => array(
1283 'test_instance_setting' => $this->randomName(),
1284 ),
1285 'widget' => array(
1286 'type' => 'test_field_widget',
1287 'label' => 'Test Field',
1288 'settings' => array(
1289 'test_widget_setting' => $this->randomName(),
1290 )
1291 )
1292 );
1293 }
1294
1295 function testFieldFormSingle() {
1296 $this->field = $this->field_single;
1297 $this->field_name = $this->field['field_name'];
1298 $this->instance['field_name'] = $this->field_name;
1299 field_create_field($this->field);
1300 field_create_instance($this->instance);
1301 $langcode = LANGUAGE_NONE;
1302
1303 // Display creation form.
1304 $this->drupalGet('test-entity/add/test-bundle');
1305 $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', 'Widget is displayed');
1306 $this->assertNoField("{$this->field_name}[$langcode][1][value]", 'No extraneous widget is displayed');
1307 // TODO : check that the widget is populated with default value ?
1308
1309 // Submit with invalid value (field-level validation).
1310 $edit = array("{$this->field_name}[$langcode][0][value]" => -1);
1311 $this->drupalPost(NULL, $edit, t('Save'));
1312 $this->assertRaw(t('%name does not accept the value -1.', array('%name' => $this->instance['label'])), 'Field validation fails with invalid input.');
1313 // TODO : check that the correct field is flagged for error.
1314
1315 // Create an entity
1316 $value = mt_rand(1, 127);
1317 $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
1318 $this->drupalPost(NULL, $edit, t('Save'));
1319 preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
1320 $id = $match[1];
1321 $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
1322 $entity = field_test_entity_test_load($id);
1323 $this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], $value, 'Field value was saved');
1324
1325 // Display edit form.
1326 $this->drupalGet('test-entity/manage/' . $id . '/edit');
1327 $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", $value, 'Widget is displayed with the correct default value');
1328 $this->assertNoField("{$this->field_name}[$langcode][1][value]", 'No extraneous widget is displayed');
1329
1330 // Update the entity.
1331 $value = mt_rand(1, 127);
1332 $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
1333 $this->drupalPost(NULL, $edit, t('Save'));
1334 $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
1335 $entity = field_test_entity_test_load($id);
1336 $this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], $value, 'Field value was updated');
1337
1338 // Empty the field.
1339 $value = '';
1340 $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
1341 $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
1342 $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
1343 $entity = field_test_entity_test_load($id);
1344 $this->assertIdentical($entity->{$this->field_name}, array(), 'Field was emptied');
1345
1346 }
1347
1348 function testFieldFormSingleRequired() {
1349 $this->field = $this->field_single;
1350 $this->field_name = $this->field['field_name'];
1351 $this->instance['field_name'] = $this->field_name;
1352 $this->instance['required'] = TRUE;
1353 field_create_field($this->field);
1354 field_create_instance($this->instance);
1355 $langcode = LANGUAGE_NONE;
1356
1357 // Submit with missing required value.
1358 $edit = array();
1359 $this->drupalPost('test-entity/add/test-bundle', $edit, t('Save'));
1360 $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation');
1361
1362 // Create an entity
1363 $value = mt_rand(1, 127);
1364 $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
1365 $this->drupalPost(NULL, $edit, t('Save'));
1366 preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
1367 $id = $match[1];
1368 $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
1369 $entity = field_test_entity_test_load($id);
1370 $this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], $value, 'Field value was saved');
1371
1372 // Edit with missing required value.
1373 $value = '';
1374 $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
1375 $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
1376 $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation');
1377 }
1378
1379 // function testFieldFormMultiple() {
1380 // $this->field = $this->field_multiple;
1381 // $this->field_name = $this->field['field_name'];
1382 // $this->instance['field_name'] = $this->field_name;
1383 // field_create_field($this->field);
1384 // field_create_instance($this->instance);
1385 // }
1386
1387 function testFieldFormUnlimited() {
1388 $this->field = $this->field_unlimited;
1389 $this->field_name = $this->field['field_name'];
1390 $this->instance['field_name'] = $this->field_name;
1391 field_create_field($this->field);
1392 field_create_instance($this->instance);
1393 $langcode = LANGUAGE_NONE;
1394
1395 // Display creation form -> 1 widget.
1396 $this->drupalGet('test-entity/add/test-bundle');
1397 $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', 'Widget 1 is displayed');
1398 $this->assertNoField("{$this->field_name}[$langcode][1][value]", 'No extraneous widget is displayed');
1399
1400 // Press 'add more' button -> 2 widgets.
1401 $this->drupalPost(NULL, array(), t('Add another item'));
1402 $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', 'Widget 1 is displayed');
1403 $this->assertFieldByName("{$this->field_name}[$langcode][1][value]", '', 'New widget is displayed');
1404 $this->assertNoField("{$this->field_name}[$langcode][2][value]", 'No extraneous widget is displayed');
1405 // TODO : check that non-field inpurs are preserved ('title')...
1406
1407 // Yet another time so that we can play with more values -> 3 widgets.
1408 $this->drupalPost(NULL, array(), t('Add another item'));
1409
1410 // Prepare values and weights.
1411 $count = 3;
1412 $delta_range = $count - 1;
1413 $values = $weights = $pattern = $expected_values = $edit = array();
1414 for ($delta = 0; $delta <= $delta_range; $delta++) {
1415 // Assign unique random values and weights.
1416 do {
1417 $value = mt_rand(1, 127);
1418 } while (in_array($value, $values));
1419 do {
1420 $weight = mt_rand(-$delta_range, $delta_range);
1421 } while (in_array($weight, $weights));
1422 $edit["$this->field_name[$langcode][$delta][value]"] = $value;
1423 $edit["$this->field_name[$langcode][$delta][_weight]"] = $weight;
1424 // We'll need three slightly different formats to check the values.
1425 $values[$delta] = $value;
1426 $weights[$delta] = $weight;
1427 $field_values[$weight]['value'] = (string) $value;
1428 $pattern[$weight] = "<input [^>]*value=\"$value\" [^>]*";
1429 }
1430
1431 // Press 'add more' button -> 4 widgets
1432 $this->drupalPost(NULL, $edit, t('Add another item'));
1433 for ($delta = 0; $delta <= $delta_range; $delta++) {
1434 $this->assertFieldByName("$this->field_name[$langcode][$delta][value]", $values[$delta], "Widget $delta is displayed and has the right value");
1435 $this->assertFieldByName("$this->field_name[$langcode][$delta][_weight]", $weights[$delta], "Widget $delta has the right weight");
1436 }
1437 ksort($pattern);
1438 $pattern = implode('.*', array_values($pattern));
1439 $this->assertPattern("|$pattern|s", 'Widgets are displayed in the correct order');
1440 $this->assertFieldByName("$this->field_name[$langcode][$delta][value]", '', "New widget is displayed");
1441 $this->assertFieldByName("$this->field_name[$langcode][$delta][_weight]", $delta, "New widget has the right weight");
1442 $this->assertNoField("$this->field_name[$langcode][" . ($delta + 1) . '][value]', 'No extraneous widget is displayed');
1443
1444 // Submit the form and create the entity.
1445 $this->drupalPost(NULL, $edit, t('Save'));
1446 preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
1447 $id = $match[1];
1448 $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
1449 $entity = field_test_entity_test_load($id);
1450 ksort($field_values);
1451 $field_values = array_values($field_values);
1452 $this->assertIdentical($entity->{$this->field_name}[$langcode], $field_values, 'Field values were saved in the correct order');
1453
1454 // Display edit form: check that the expected number of widgets is
1455 // displayed, with correct values change values, reorder, leave an empty
1456 // value in the middle.
1457 // Submit: check that the entity is updated with correct values
1458 // Re-submit: check that the field can be emptied.
1459
1460 // Test with several multiple fields in a form
1461 }
1462
1463 function testFieldFormJSAddMore() {
1464 $this->field = $this->field_unlimited;
1465 $this->field_name = $this->field['field_name'];
1466 $this->instance['field_name'] = $this->field_name;
1467 field_create_field($this->field);
1468 field_create_instance($this->instance);
1469 $langcode = LANGUAGE_NONE;
1470
1471 // Display creation form -> 1 widget.
1472 $this->drupalGet('test-entity/add/test-bundle');
1473
1474 // Press 'add more' button a couple times -> 3 widgets.
1475 // drupalPostAJAX() will not work iteratively, so we add those through
1476 // non-JS submission.
1477 $this->drupalPost(NULL, array(), t('Add another item'));
1478 $this->drupalPost(NULL, array(), t('Add another item'));
1479
1480 // Prepare values and weights.
1481 $count = 3;
1482 $delta_range = $count - 1;
1483 $values = $weights = $pattern = $expected_values = $edit = array();
1484 for ($delta = 0; $delta <= $delta_range; $delta++) {
1485 // Assign unique random values and weights.
1486 do {
1487 $value = mt_rand(1, 127);
1488 } while (in_array($value, $values));
1489 do {
1490 $weight = mt_rand(-$delta_range, $delta_range);
1491 } while (in_array($weight, $weights));
1492 $edit["$this->field_name[$langcode][$delta][value]"] = $value;
1493 $edit["$this->field_name[$langcode][$delta][_weight]"] = $weight;
1494 // We'll need three slightly different formats to check the values.
1495 $values[$delta] = $value;
1496 $weights[$delta] = $weight;
1497 $field_values[$weight]['value'] = (string) $value;
1498 $pattern[$weight] = "<input [^>]*value=\"$value\" [^>]*";
1499 }
1500 // Press 'add more' button through Ajax, and place the expected HTML result
1501 // as the tested content.
1502 $commands = $this->drupalPostAJAX(NULL, $edit, $this->field_name . '_add_more');
1503 $this->content = $commands[1]['data'];
1504
1505 for ($delta = 0; $delta <= $delta_range; $delta++) {
1506 $this->assertFieldByName("$this->field_name[$langcode][$delta][value]", $values[$delta], "Widget $delta is displayed and has the right value");
1507 $this->assertFieldByName("$this->field_name[$langcode][$delta][_weight]", $weights[$delta], "Widget $delta has the right weight");
1508 }
1509 ksort($pattern);
1510 $pattern = implode('.*', array_values($pattern));
1511 $this->assertPattern("|$pattern|s", 'Widgets are displayed in the correct order');
1512 $this->assertFieldByName("$this->field_name[$langcode][$delta][value]", '', "New widget is displayed");
1513 $this->assertFieldByName("$this->field_name[$langcode][$delta][_weight]", $delta, "New widget has the right weight");
1514 $this->assertNoField("$this->field_name[$langcode][" . ($delta + 1) . '][value]', 'No extraneous widget is displayed');
1515 }
1516
1517 /**
1518 * Tests widgets handling multiple values.
1519 */
1520 function testFieldFormMultipleWidget() {
1521 // Create a field with fixed cardinality and an instance using a multiple
1522 // widget.
1523 $this->field = $this->field_multiple;
1524 $this->field_name = $this->field['field_name'];
1525 $this->instance['field_name'] = $this->field_name;
1526 $this->instance['widget']['type'] = 'test_field_widget_multiple';
1527 field_create_field($this->field);
1528 field_create_instance($this->instance);
1529 $langcode = LANGUAGE_NONE;
1530
1531 // Display creation form.
1532 $this->drupalGet('test-entity/add/test-bundle');
1533 $this->assertFieldByName("{$this->field_name}[$langcode]", '', t('Widget is displayed.'));
1534
1535 // Create entity with three values.
1536 $edit = array("{$this->field_name}[$langcode]" => '1, 2, 3');
1537 $this->drupalPost(NULL, $edit, t('Save'));
1538 preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
1539 $id = $match[1];
1540
1541 // Check that the values were saved.
1542 $entity_init = field_test_create_stub_entity($id);
1543 $this->assertFieldValues($entity_init, $this->field_name, $langcode, array(1, 2, 3));
1544
1545 // Display the form, check that the values are correctly filled in.
1546 $this->drupalGet('test-entity/manage/' . $id . '/edit');
1547 $this->assertFieldByName("{$this->field_name}[$langcode]", '1, 2, 3', t('Widget is displayed.'));
1548
1549 // Submit the form with more values than the field accepts.
1550 $edit = array("{$this->field_name}[$langcode]" => '1, 2, 3, 4, 5');
1551 $this->drupalPost(NULL, $edit, t('Save'));
1552 $this->assertRaw('this field cannot hold more than 4 values', t('Form validation failed.'));
1553 // Check that the field values were not submitted.
1554 $this->assertFieldValues($entity_init, $this->field_name, $langcode, array(1, 2, 3));
1555 }
1556
1557 /**
1558 * Tests fields with no 'edit' access.
1559 */
1560 function testFieldFormAccess() {
1561 // Create a "regular" field.
1562 $field = $this->field_single;
1563 $field_name = $field['field_name'];
1564 $instance = $this->instance;
1565 $instance['field_name'] = $field_name;
1566 field_create_field($field);
1567 field_create_instance($instance);
1568
1569 // Create a field with no edit access - see field_test_field_access().
1570 $field_no_access = array(
1571 'field_name' => 'field_no_edit_access',
1572 'type' => 'test_field',
1573 );
1574 $field_name_no_access = $field_no_access['field_name'];
1575 $instance_no_access = array(
1576 'field_name' => $field_name_no_access,
1577 'entity_type' => 'test_entity',
1578 'bundle' => 'test_bundle',
1579 'default_value' => array(0 => array('value' => 99)),
1580 );
1581 field_create_field($field_no_access);
1582 field_create_instance($instance_no_access);
1583
1584 $langcode = LANGUAGE_NONE;
1585
1586 // Display creation form.
1587 $this->drupalGet('test-entity/add/test-bundle');
1588 $this->assertNoFieldByName("{$field_name_no_access}[$langcode][0][value]", '', t('Widget is not displayed if field access is denied.'));
1589
1590 // Create entity.
1591 $edit = array("{$field_name}[$langcode][0][value]" => 1);
1592 $this->drupalPost(NULL, $edit, t('Save'));
1593 preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
1594 $id = $match[1];
1595
1596 // Check that the default value was saved.
1597 $entity = field_test_entity_test_load($id);
1598 $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, t('Default value was saved for the field with no edit access.'));
1599 $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 1, t('Entered value vas saved for the field with edit access.'));
1600
1601 // Create a new revision.
1602 $edit = array("{$field_name}[$langcode][0][value]" => 2, 'revision' => TRUE);
1603 $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
1604
1605 // Check that the new revision has the expected values.
1606 $entity = field_test_entity_test_load($id);
1607 $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, t('New revision has the expected value for the field with no edit access.'));
1608 $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 2, t('New revision has the expected value for the field with edit access.'));
1609
1610 // Check that the revision is also saved in the revisions table.
1611 $entity = field_test_entity_test_load($id, $entity->ftvid);
1612 $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, t('New revision has the expected value for the field with no edit access.'));
1613 $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 2, t('New revision has the expected value for the field with edit access.'));
1614 }
1615
1616 /**
1617 * Tests Field API form integration within a subform.
1618 */
1619 function testNestedFieldForm() {
1620 // Add two instances on the 'test_bundle'
1621 field_create_field($this->field_single);
1622 field_create_field($this->field_unlimited);
1623 $this->instance['field_name'] = 'field_single';
1624 $this->instance['label'] = 'Single field';
1625 field_create_instance($this->instance);
1626 $this->instance['field_name'] = 'field_unlimited';
1627 $this->instance['label'] = 'Unlimited field';
1628 field_create_instance($this->instance);
1629
1630 // Create two entities.
1631 $entity_1 = field_test_create_stub_entity(1, 1);
1632 $entity_1->is_new = TRUE;
1633 $entity_1->field_single[LANGUAGE_NONE][] = array('value' => 0);
1634 $entity_1->field_unlimited[LANGUAGE_NONE][] = array('value' => 1);
1635 field_test_entity_save($entity_1);
1636
1637 $entity_2 = field_test_create_stub_entity(2, 2);
1638 $entity_2->is_new = TRUE;
1639 $entity_2->field_single[LANGUAGE_NONE][] = array('value' => 10);
1640 $entity_2->field_unlimited[LANGUAGE_NONE][] = array('value' => 11);
1641 field_test_entity_save($entity_2);
1642
1643 // Display the 'combined form'.
1644 $this->drupalGet('test-entity/nested/1/2');
1645 $this->assertFieldByName('field_single[und][0][value]', 0, t('Entity 1: field_single value appears correctly is the form.'));
1646 $this->assertFieldByName('field_unlimited[und][0][value]', 1, t('Entity 1: field_unlimited value 0 appears correctly is the form.'));
1647 $this->assertFieldByName('entity_2[field_single][und][0][value]', 10, t('Entity 2: field_single value appears correctly is the form.'));
1648 $this->assertFieldByName('entity_2[field_unlimited][und][0][value]', 11, t('Entity 2: field_unlimited value 0 appears correctly is the form.'));
1649
1650 // Submit the form and check that the entities are updated accordingly.
1651 $edit = array(
1652 'field_single[und][0][value]' => 1,
1653 'field_unlimited[und][0][value]' => 2,
1654 'field_unlimited[und][1][value]' => 3,
1655 'entity_2[field_single][und][0][value]' => 11,
1656 'entity_2[field_unlimited][und][0][value]' => 12,
1657 'entity_2[field_unlimited][und][1][value]' => 13,
1658 );
1659 $this->drupalPost(NULL, $edit, t('Save'));
1660 field_cache_clear();
1661 $entity_1 = field_test_create_stub_entity(1);
1662 $entity_2 = field_test_create_stub_entity(2);
1663 $this->assertFieldValues($entity_1, 'field_single', LANGUAGE_NONE, array(1));
1664 $this->assertFieldValues($entity_1, 'field_unlimited', LANGUAGE_NONE, array(2, 3));
1665 $this->assertFieldValues($entity_2, 'field_single', LANGUAGE_NONE, array(11));
1666 $this->assertFieldValues($entity_2, 'field_unlimited', LANGUAGE_NONE, array(12, 13));
1667
1668 // Submit invalid values and check that errors are reported on the
1669 // correct widgets.
1670 $edit = array(
1671 'field_unlimited[und][1][value]' => -1,
1672 );
1673 $this->drupalPost('test-entity/nested/1/2', $edit, t('Save'));
1674 $this->assertRaw(t('%label does not accept the value -1', array('%label' => 'Unlimited field')), t('Entity 1: the field validation error was reported.'));
1675 $error_field = $this->xpath('//input[@id=:id and contains(@class, "error")]', array(':id' => 'edit-field-unlimited-und-1-value'));
1676 $this->assertTrue($error_field, t('Entity 1: the error was flagged on the correct element.'));
1677 $edit = array(
1678 'entity_2[field_unlimited][und][1][value]' => -1,
1679 );
1680 $this->drupalPost('test-entity/nested/1/2', $edit, t('Save'));
1681 $this->assertRaw(t('%label does not accept the value -1', array('%label' => 'Unlimited field')), t('Entity 2: the field validation error was reported.'));
1682 $error_field = $this->xpath('//input[@id=:id and contains(@class, "error")]', array(':id' => 'edit-entity-2-field-unlimited-und-1-value'));
1683 $this->assertTrue($error_field, t('Entity 2: the error was flagged on the correct element.'));
1684
1685 // Test that reordering works on both entities.
1686 $edit = array(
1687 'field_unlimited[und][0][_weight]' => 0,
1688 'field_unlimited[und][1][_weight]' => -1,
1689 'entity_2[field_unlimited][und][0][_weight]' => 0,
1690 'entity_2[field_unlimited][und][1][_weight]' => -1,
1691 );
1692 $this->drupalPost('test-entity/nested/1/2', $edit, t('Save'));
1693 field_cache_clear();
1694 $this->assertFieldValues($entity_1, 'field_unlimited', LANGUAGE_NONE, array(3, 2));
1695 $this->assertFieldValues($entity_2, 'field_unlimited', LANGUAGE_NONE, array(13, 12));
1696
1697 // Test the 'add more' buttons. Only Ajax submission is tested, because
1698 // the two 'add more' buttons present in the form have the same #value,
1699 // which confuses drupalPost().
1700 // 'Add more' button in the first entity:
1701 $this->drupalGet('test-entity/nested/1/2');
1702 $this->drupalPostAJAX(NULL, array(), 'field_unlimited_add_more');
1703 $this->assertFieldByName('field_unlimited[und][0][value]', 3, t('Entity 1: field_unlimited value 0 appears correctly is the form.'));
1704 $this->assertFieldByName('field_unlimited[und][1][value]', 2, t('Entity 1: field_unlimited value 1 appears correctly is the form.'));
1705 $this->assertFieldByName('field_unlimited[und][2][value]', '', t('Entity 1: field_unlimited value 2 appears correctly is the form.'));
1706 $this->assertFieldByName('field_unlimited[und][3][value]', '', t('Entity 1: an empty widget was added for field_unlimited value 3.'));
1707 // 'Add more' button in the first entity (changing field values):
1708 $edit = array(
1709 'entity_2[field_unlimited][und][0][value]' => 13,
1710 'entity_2[field_unlimited][und][1][value]' => 14,
1711 'entity_2[field_unlimited][und][2][value]' => 15,
1712 );
1713 $this->drupalPostAJAX(NULL, $edit, 'entity_2_field_unlimited_add_more');
1714 $this->assertFieldByName('entity_2[field_unlimited][und][0][value]', 13, t('Entity 2: field_unlimited value 0 appears correctly is the form.'));
1715 $this->assertFieldByName('entity_2[field_unlimited][und][1][value]', 14, t('Entity 2: field_unlimited value 1 appears correctly is the form.'));
1716 $this->assertFieldByName('entity_2[field_unlimited][und][2][value]', 15, t('Entity 2: field_unlimited value 2 appears correctly is the form.'));
1717 $this->assertFieldByName('entity_2[field_unlimited][und][3][value]', '', t('Entity 2: an empty widget was added for field_unlimited value 3.'));
1718 // Save the form and check values are saved correclty.
1719 $this->drupalPost(NULL, array(), t('Save'));
1720 field_cache_clear();
1721 $this->assertFieldValues($entity_1, 'field_unlimited', LANGUAGE_NONE, array(3, 2));
1722 $this->assertFieldValues($entity_2, 'field_unlimited', LANGUAGE_NONE, array(13, 14, 15));
1723 }
1724 }
1725
1726 class FieldDisplayAPITestCase extends FieldTestCase {
1727 public static function getInfo() {
1728 return array(
1729 'name' => 'Field Display API tests',
1730 'description' => 'Test the display API.',
1731 'group' => 'Field API',
1732 );
1733 }
1734
1735 function setUp() {
1736 parent::setUp('field_test');
1737
1738 // Create a field and instance.
1739 $this->field_name = 'test_field';
1740 $this->label = $this->randomName();
1741 $this->cardinality = 4;
1742
1743 $this->field = array(
1744 'field_name' => $this->field_name,
1745 'type' => 'test_field',
1746 'cardinality' => $this->cardinality,
1747 );
1748 $this->instance = array(
1749 'field_name' => $this->field_name,
1750 'entity_type' => 'test_entity',
1751 'bundle' => 'test_bundle',
1752 'label' => $this->label,
1753 'display' => array(
1754 'default' => array(
1755 'type' => 'field_test_default',
1756 'settings' => array(
1757 'test_formatter_setting' => $this->randomName(),
1758 ),
1759 ),
1760 'teaser' => array(
1761 'type' => 'field_test_default',
1762 'settings' => array(
1763 'test_formatter_setting' => $this->randomName(),
1764 ),
1765 ),
1766 ),
1767 );
1768 field_create_field($this->field);
1769 field_create_instance($this->instance);
1770
1771 // Create an entity with values.
1772 $this->values = $this->_generateTestFieldValues($this->cardinality);
1773 $this->entity = field_test_create_stub_entity();
1774 $this->is_new = TRUE;
1775 $this->entity->{$this->field_name}[LANGUAGE_NONE] = $this->values;
1776 field_test_entity_save($this->entity);
1777 }
1778
1779 /**
1780 * Test the field_view_field() function.
1781 */
1782 function testFieldViewField() {
1783 // No display settings: check that default display settings are used.
1784 $output = field_view_field('test_entity', $this->entity, $this->field_name);
1785 $this->drupalSetContent(drupal_render($output));
1786 $settings = field_info_formatter_settings('field_test_default');
1787 $setting = $settings['test_formatter_setting'];
1788 $this->assertText($this->label, t('Label was displayed.'));
1789 foreach ($this->values as $delta => $value) {
1790 $this->assertText($setting . '|' . $value['value'], t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
1791 }
1792
1793 // Check that explicit display settings are used.
1794 $display = array(
1795 'label' => 'hidden',
1796 'type' => 'field_test_multiple',
1797 'settings' => array(
1798 'test_formatter_setting_multiple' => $this->randomName(),
1799 'alter' => TRUE,
1800 ),
1801 );
1802 $output = field_view_field('test_entity', $this->entity, $this->field_name, $display);
1803 $this->drupalSetContent(drupal_render($output));
1804 $setting = $display['settings']['test_formatter_setting_multiple'];
1805 $this->assertNoText($this->label, t('Label was not displayed.'));
1806 $this->assertText('field_test_field_attach_view_alter', t('Alter fired, display passed.'));
1807 $array = array();
1808 foreach ($this->values as $delta => $value) {
1809 $array[] = $delta . ':' . $value['value'];
1810 }
1811 $this->assertText($setting . '|' . implode('|', $array), t('Values were displayed with expected setting.'));
1812
1813 // Check the prepare_view steps are invoked.
1814 $display = array(
1815 'label' => 'hidden',
1816 'type' => 'field_test_with_prepare_view',
1817 'settings' => array(
1818 'test_formatter_setting_additional' => $this->randomName(),
1819 ),
1820 );
1821 $output = field_view_field('test_entity', $this->entity, $this->field_name, $display);
1822 $view = drupal_render($output);
1823 $this->drupalSetContent($view);
1824 $setting = $display['settings']['test_formatter_setting_additional'];
1825 $this->assertNoText($this->label, t('Label was not displayed.'));
1826 $this->assertNoText('field_test_field_attach_view_alter', t('Alter not fired.'));
1827 foreach ($this->values as $delta => $value) {
1828 $this->assertText($setting . '|' . $value['value'] . '|' . ($value['value'] + 1), t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
1829 }
1830
1831 // View mode: check that display settings specified in the instance are
1832 // used.
1833 $output = field_view_field('test_entity', $this->entity, $this->field_name, 'teaser');
1834 $this->drupalSetContent(drupal_render($output));
1835 $setting = $this->instance['display']['teaser']['settings']['test_formatter_setting'];
1836 $this->assertText($this->label, t('Label was displayed.'));
1837 foreach ($this->values as $delta => $value) {
1838 $this->assertText($setting . '|' . $value['value'], t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
1839 }
1840
1841 // Unknown view mode: check that display settings for 'default' view mode
1842 // are used.
1843 $output = field_view_field('test_entity', $this->entity, $this->field_name, 'unknown_view_mode');
1844 $this->drupalSetContent(drupal_render($output));
1845 $setting = $this->instance['display']['default']['settings']['test_formatter_setting'];
1846 $this->assertText($this->label, t('Label was displayed.'));
1847 foreach ($this->values as $delta => $value) {
1848 $this->assertText($setting . '|' . $value['value'], t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
1849 }
1850 }
1851
1852 /**
1853 * Test the field_view_value() function.
1854 */
1855 function testFieldViewValue() {
1856 // No display settings: check that default display settings are used.
1857 $settings = field_info_formatter_settings('field_test_default');
1858 $setting = $settings['test_formatter_setting'];
1859 foreach ($this->values as $delta => $value) {
1860 $item = $this->entity->{$this->field_name}[LANGUAGE_NONE][$delta];
1861 $output = field_view_value('test_entity', $this->entity, $this->field_name, $item);
1862 $this->drupalSetContent(drupal_render($output));
1863 $this->assertText($setting . '|' . $value['value'], t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
1864 }
1865
1866 // Check that explicit display settings are used.
1867 $display = array(
1868 'type' => 'field_test_multiple',
1869 'settings' => array(
1870 'test_formatter_setting_multiple' => $this->randomName(),
1871 ),
1872 );
1873 $setting = $display['settings']['test_formatter_setting_multiple'];
1874 $array = array();
1875 foreach ($this->values as $delta => $value) {
1876 $item = $this->entity->{$this->field_name}[LANGUAGE_NONE][$delta];
1877 $output = field_view_value('test_entity', $this->entity, $this->field_name, $item, $display);
1878 $this->drupalSetContent(drupal_render($output));
1879 $this->assertText($setting . '|0:' . $value['value'], t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
1880 }
1881
1882 // Check that prepare_view steps are invoked.
1883 $display = array(
1884 'type' => 'field_test_with_prepare_view',
1885 'settings' => array(
1886 'test_formatter_setting_additional' => $this->randomName(),
1887 ),
1888 );
1889 $setting = $display['settings']['test_formatter_setting_additional'];
1890 $array = array();
1891 foreach ($this->values as $delta => $value) {
1892 $item = $this->entity->{$this->field_name}[LANGUAGE_NONE][$delta];
1893 $output = field_view_value('test_entity', $this->entity, $this->field_name, $item, $display);
1894 $this->drupalSetContent(drupal_render($output));
1895 $this->assertText($setting . '|' . $value['value'] . '|' . ($value['value'] + 1), t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
1896 }
1897
1898 // View mode: check that display settings specified in the instance are
1899 // used.
1900 $setting = $this->instance['display']['teaser']['settings']['test_formatter_setting'];
1901 foreach ($this->values as $delta => $value) {
1902 $item = $this->entity->{$this->field_name}[LANGUAGE_NONE][$delta];
1903 $output = field_view_value('test_entity', $this->entity, $this->field_name, $item, 'teaser');
1904 $this->drupalSetContent(drupal_render($output));
1905 $this->assertText($setting . '|' . $value['value'], t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
1906 }
1907
1908 // Unknown view mode: check that display settings for 'default' view mode
1909 // are used.
1910 $setting = $this->instance['display']['default']['settings']['test_formatter_setting'];
1911 foreach ($this->values as $delta => $value) {
1912 $item = $this->entity->{$this->field_name}[LANGUAGE_NONE][$delta];
1913 $output = field_view_value('test_entity', $this->entity, $this->field_name, $item, 'unknown_view_mode');
1914 $this->drupalSetContent(drupal_render($output));
1915 $this->assertText($setting . '|' . $value['value'], t('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
1916 }
1917 }
1918 }
1919
1920 class FieldCrudTestCase extends FieldTestCase {
1921 public static function getInfo() {
1922 return array(
1923 'name' => 'Field CRUD tests',
1924 'description' => 'Test field create, read, update, and delete.',
1925 'group' => 'Field API',
1926 );
1927 }
1928
1929 function setUp() {
1930 // field_update_field() tests use number.module
1931 parent::setUp('field_test', 'number');
1932 }
1933
1934 // TODO : test creation with
1935 // - a full fledged $field structure, check that all the values are there
1936 // - a minimal $field structure, check all default values are set
1937 // defer actual $field comparison to a helper function, used for the two cases above
1938
1939 /**
1940 * Test the creation of a field.
1941 */
1942 function testCreateField() {
1943 $field_definition = array(
1944 'field_name' => 'field_2',
1945 'type' => 'test_field',
1946 );
1947 field_test_memorize();
1948 $field_definition = field_create_field($field_definition);
1949 $mem = field_test_memorize();
1950 $this->assertIdentical($mem['field_test_field_create_field'][0][0], $field_definition, 'hook_field_create_field() called with correct arguments.');
1951
1952 // Read the raw record from the {field_config_instance} table.
1953 $result = db_query('SELECT * FROM {field_config} WHERE field_name = :field_name', array(':field_name' => $field_definition['field_name']));
1954 $record = $result->fetchAssoc();
1955 $record['data'] = unserialize($record['data']);
1956
1957 // Ensure that basic properties are preserved.
1958 $this->assertEqual($record['field_name'], $field_definition['field_name'], t('The field name is properly saved.'));
1959 $this->assertEqual($record['type'], $field_definition['type'], t('The field type is properly saved.'));
1960
1961 // Ensure that cardinality defaults to 1.
1962 $this->assertEqual($record['cardinality'], 1, t('Cardinality defaults to 1.'));
1963
1964 // Ensure that default settings are present.
1965 $field_type = field_info_field_types($field_definition['type']);
1966 $this->assertIdentical($record['data']['settings'], $field_type['settings'], t('Default field settings have been written.'));
1967
1968 // Ensure that default storage was set.
1969 $this->assertEqual($record['storage_type'], variable_get('field_storage_default'), t('The field type is properly saved.'));
1970
1971 // Guarantee that the name is unique.
1972 try {
1973 field_create_field($field_definition);
1974 $this->fail(t('Cannot create two fields with the same name.'));
1975 }
1976 catch (FieldException $e) {
1977 $this->pass(t('Cannot create two fields with the same name.'));
1978 }
1979
1980 // Check that field type is required.
1981 try {
1982 $field_definition = array(
1983 'field_name' => 'field_1',
1984 );
1985 field_create_field($field_definition);
1986 $this->fail(t('Cannot create a field with no type.'));
1987 }
1988 catch (FieldException $e) {
1989 $this->pass(t('Cannot create a field with no type.'));
1990 }
1991
1992 // Check that field name is required.
1993 try {
1994 $field_definition = array(
1995 'type' => 'test_field'
1996 );
1997 field_create_field($field_definition);
1998 $this->fail(t('Cannot create an unnamed field.'));
1999 }
2000 catch (FieldException $e) {
2001 $this->pass(t('Cannot create an unnamed field.'));
2002 }
2003
2004 // Check that field name must start with a letter or _.
2005 try {
2006 $field_definition = array(
2007 'field_name' => '2field_2',
2008 'type' => 'test_field',
2009 );
2010 field_create_field($field_definition);
2011 $this->fail(t('Cannot create a field with a name starting with a digit.'));
2012 }
2013 catch (FieldException $e) {
2014 $this->pass(t('Cannot create a field with a name starting with a digit.'));
2015 }
2016
2017 // Check that field name must only contain lowercase alphanumeric or _.
2018 try {
2019 $field_definition = array(
2020 'field_name' => 'field#_3',
2021 'type' => 'test_field',
2022 );
2023 field_create_field($field_definition);
2024 $this->fail(t('Cannot create a field with a name containing an illegal character.'));
2025 }
2026 catch (FieldException $e) {
2027 $this->pass(t('Cannot create a field with a name containing an illegal character.'));
2028 }
2029
2030 // Check that field name cannot be longer than 32 characters long.
2031 try {
2032 $field_definition = array(
2033 'field_name' => '_12345678901234567890123456789012',
2034 'type' => 'test_field',
2035 );
2036 field_create_field($field_definition);
2037 $this->fail(t('Cannot create a field with a name longer than 32 characters.'));
2038 }
2039 catch (FieldException $e) {
2040 $this->pass(t('Cannot create a field with a name longer than 32 characters.'));
2041 }
2042
2043 // Check that field name can not be an entity key.
2044 // "ftvid" is known as an entity key from the "test_entity" type.
2045 try {
2046 $field_definition = array(
2047 'type' => 'test_field',
2048 'field_name' => 'ftvid',
2049 );
2050 $field = field_create_field($field_definition);
2051 $this->fail(t('Cannot create a field bearing the name of an entity key.'));
2052 }
2053 catch (FieldException $e) {
2054 $this->pass(t('Cannot create a field bearing the name of an entity key.'));
2055 }
2056 }
2057
2058 /**
2059 * Test failure to create a field.
2060 */
2061 function testCreateFieldFail() {
2062 $field_name = 'duplicate';
2063 $field_definition = array('field_name' => $field_name, 'type' => 'test_field', 'storage' => array('type' => 'field_test_storage_failure'));
2064 $query = db_select('field_config')->condition('field_name', $field_name)->countQuery();
2065
2066 // The field does not appear in field_config.
2067 $count = $query->execute()->fetchField();
2068 $this->assertEqual($count, 0, 'A field_config row for the field does not exist.');
2069
2070 // Try to create the field.
2071 try {
2072 $field = field_create_field($field_definition);
2073 $this->assertTrue(FALSE, 'Field creation (correctly) fails.');
2074 }
2075 catch (Exception $e) {
2076 $this->assertTrue(TRUE, 'Field creation (correctly) fails.');
2077 }
2078
2079 // The field does not appear in field_config.
2080 $count = $query->execute()->fetchField();
2081 $this->assertEqual($count, 0, 'A field_config row for the field does not exist.');
2082 }
2083
2084 /**
2085 * Test reading back a field definition.
2086 */
2087 function testReadField() {
2088 $field_definition = array(
2089 'field_name' => 'field_1',
2090 'type' => 'test_field',
2091 );
2092 field_create_field($field_definition);
2093
2094 // Read the field back.
2095 $field = field_read_field($field_definition['field_name']);
2096 $this->assertTrue($field_definition < $field, t('The field was properly read.'));
2097 }
2098
2099 /**
2100 * Test creation of indexes on data column.
2101 */
2102 function testFieldIndexes() {
2103 // Check that indexes specified by the field type are used by default.
2104 $field_definition = array(
2105 'field_name' => 'field_1',
2106 'type' => 'test_field',
2107 );
2108 field_create_field($field_definition);
2109 $field = field_read_field($field_definition['field_name']);
2110 $expected_indexes = array('value' => array('value'));
2111 $this->assertEqual($field['indexes'], $expected_indexes, t('Field type indexes saved by default'));
2112
2113 // Check that indexes specified by the field definition override the field
2114 // type indexes.
2115 $field_definition = array(
2116 'field_name' => 'field_2',
2117 'type' => 'test_field',
2118 'indexes' => array(
2119 'value' => array(),
2120 ),
2121 );
2122 field_create_field($field_definition);
2123 $field = field_read_field($field_definition['field_name']);
2124 $expected_indexes = array('value' => array());
2125 $this->assertEqual($field['indexes'], $expected_indexes, t('Field definition indexes override field type indexes'));
2126
2127 // Check that indexes specified by the field definition add to the field
2128 // type indexes.
2129 $field_definition = array(
2130 'field_name' => 'field_3',
2131 'type' => 'test_field',
2132 'indexes' => array(
2133 'value_2' => array('value'),
2134 ),
2135 );
2136 field_create_field($field_definition);
2137 $field = field_read_field($field_definition['field_name']);
2138 $expected_indexes = array('value' => array('value'), 'value_2' => array('value'));
2139 $this->assertEqual($field['indexes'], $expected_indexes, t('Field definition indexes are merged with field type indexes'));
2140 }
2141
2142 /**
2143 * Test the deletion of a field.
2144 */
2145 function testDeleteField() {
2146 // TODO: Also test deletion of the data stored in the field ?
2147
2148 // Create two fields (so we can test that only one is deleted).
2149 $this->field = array('field_name' => 'field_1', 'type' => 'test_field');
2150 field_create_field($this->field);
2151 $this->another_field = array('field_name' => 'field_2', 'type' => 'test_field');
2152 field_create_field($this->another_field);
2153
2154 // Create instances for each.
2155 $this->instance_definition = array(
2156 'field_name' => $this->field['field_name'],
2157 'entity_type' => 'test_entity',
2158 'bundle' => 'test_bundle',
2159 'widget' => array(
2160 'type' => 'test_field_widget',
2161 ),
2162 );
2163 field_create_instance($this->instance_definition);
2164 $this->another_instance_definition = $this->instance_definition;
2165 $this->another_instance_definition['field_name'] = $this->another_field['field_name'];
2166 field_create_instance($this->another_instance_definition);
2167
2168 // Test that the first field is not deleted, and then delete it.
2169 $field = field_read_field($this->field['field_name'], array('include_deleted' => TRUE));
2170 $this->assertTrue(!empty($field) && empty($field['deleted']), t('A new field is not marked for deletion.'));
2171 field_delete_field($this->field['field_name']);
2172
2173 // Make sure that the field is marked as deleted when it is specifically
2174 // loaded.
2175 $field = field_read_field($this->field['field_name'], array('include_deleted' => TRUE));
2176 $this->assertTrue(!empty($field['deleted']), t('A deleted field is marked for deletion.'));
2177
2178 // Make sure that this field's instance is marked as deleted when it is
2179 // specifically loaded.
2180 $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
2181 $this->assertTrue(!empty($instance['deleted']), t('An instance for a deleted field is marked for deletion.'));
2182
2183 // Try to load the field normally and make sure it does not show up.
2184 $field = field_read_field($this->field['field_name']);
2185 $this->assertTrue(empty($field), t('A deleted field is not loaded by default.'));
2186
2187 // Try to load the instance normally and make sure it does not show up.
2188 $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
2189 $this->assertTrue(empty($instance), t('An instance for a deleted field is not loaded by default.'));
2190
2191 // Make sure the other field (and its field instance) are not deleted.
2192 $another_field = field_read_field($this->another_field['field_name']);
2193 $this->assertTrue(!empty($another_field) && empty($another_field['deleted']), t('A non-deleted field is not marked for deletion.'));
2194 $another_instance = field_read_instance('test_entity', $this->another_instance_definition['field_name'], $this->another_instance_definition['bundle']);
2195 $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), t('An instance of a non-deleted field is not marked for deletion.'));
2196
2197 // Try to create a new field the same name as a deleted field and
2198 // write data into it.
2199 field_create_field($this->field);
2200 field_create_instance($this->instance_definition);
2201 $field = field_read_field($this->field['field_name']);
2202 $this->assertTrue(!empty($field) && empty($field['deleted']), t('A new field with a previously used name is created.'));
2203 $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
2204 $this->assertTrue(!empty($instance) && empty($instance['deleted']), t('A new instance for a previously used field name is created.'));
2205
2206 // Save an entity with data for the field
2207 $entity = field_test_create_stub_entity(0, 0, $instance['bundle']);
2208 $langcode = LANGUAGE_NONE;
2209 $values[0]['value'] = mt_rand(1, 127);
2210 $entity->{$field['field_name']}[$langcode] = $values;
2211 $entity_type = 'test_entity';
2212 field_attach_insert('test_entity', $entity);
2213
2214 // Verify the field is present on load
2215 $entity = field_test_create_stub_entity(0, 0, $this->instance_definition['bundle']);
2216 field_attach_load($entity_type, array(0 => $entity));
2217 $this->assertIdentical(count($entity->{$field['field_name']}[$langcode]), count($values), "Data in previously deleted field saves and loads correctly");
2218 foreach ($values as $delta => $value) {
2219 $this->assertEqual($entity->{$field['field_name']}[$langcode][$delta]['value'], $values[$delta]['value'], "Data in previously deleted field saves and loads correctly");
2220 }
2221 }
2222
2223 function testUpdateNonExistentField() {
2224 $test_field = array('field_name' => 'does_not_exist', 'type' => 'number_decimal');
2225 try {
2226 field_update_field($test_field);
2227 $this->fail(t('Cannot update a field that does not exist.'));
2228 }
2229 catch (FieldException $e) {
2230 $this->pass(t('Cannot update a field that does not exist.'));
2231 }
2232 }
2233
2234 function testUpdateFieldType() {
2235 $field = array('field_name' => 'field_type', 'type' => 'number_decimal');
2236 $field = field_create_field($field);
2237
2238 $test_field = array('field_name' => 'field_type', 'type' => 'number_integer');
2239 try {
2240 field_update_field($test_field);
2241 $this->fail(t('Cannot update a field to a different type.'));
2242 }
2243 catch (FieldException $e) {
2244 $this->pass(t('Cannot update a field to a different type.'));
2245 }
2246 }
2247
2248 /**
2249 * Test updating a field.
2250 */
2251 function testUpdateField() {
2252 // Create a field with a defined cardinality, so that we can ensure it's
2253 // respected. Since cardinality enforcement is consistent across database
2254 // systems, it makes a good test case.
2255 $cardinality = 4;
2256 $field_definition = array(
2257 'field_name' => 'field_update',
2258 'type' => 'test_field',
2259 'cardinality' => $cardinality,
2260 );
2261 $field_definition = field_create_field($field_definition);
2262 $instance = array(
2263 'field_name' => 'field_update',
2264 'entity_type' => 'test_entity',
2265 'bundle' => 'test_bundle',
2266 );
2267 $instance = field_create_instance($instance);
2268
2269 do {
2270 // We need a unique ID for our entity. $cardinality will do.
2271 $id = $cardinality;
2272 $entity = field_test_create_stub_entity($id, $id, $instance['bundle']);
2273 // Fill in the entity with more values than $cardinality.
2274 for ($i = 0; $i < 20; $i++) {
2275 $entity->field_update[LANGUAGE_NONE][$i]['value'] = $i;
2276 }
2277 // Save the entity.
2278 field_attach_insert('test_entity', $entity);
2279 // Load back and assert there are $cardinality number of values.
2280 $entity = field_test_create_stub_entity($id, $id, $instance['bundle']);
2281 field_attach_load('test_entity', array($id => $entity));
2282 $this->assertEqual(count($entity->field_update[LANGUAGE_NONE]), $field_definition['cardinality'], 'Cardinality is kept');
2283 // Now check the values themselves.
2284 for ($delta = 0; $delta < $cardinality; $delta++) {
2285 $this->assertEqual($entity->field_update[LANGUAGE_NONE][$delta]['value'], $delta, 'Value is kept');
2286 }
2287 // Increase $cardinality and set the field cardinality to the new value.
2288 $field_definition['cardinality'] = ++$cardinality;
2289 field_update_field($field_definition);
2290 } while ($cardinality < 6);
2291 }
2292
2293 /**
2294 * Test field type modules forbidding an update.
2295 */
2296 function testUpdateFieldForbid() {
2297 $field = array('field_name' => 'forbidden', 'type' => 'test_field', 'settings' => array('changeable' => 0, 'unchangeable' => 0));
2298 $field = field_create_field($field);
2299 $field['settings']['changeable']++;
2300 try {
2301 field_update_field($field);
2302 $this->pass(t("A changeable setting can be updated."));
2303 }
2304 catch (FieldException $e) {
2305 $this->fail(t("An unchangeable setting cannot be updated."));
2306 }
2307 $field['settings']['unchangeable']++;
2308 try {
2309 field_update_field($field);
2310 $this->fail(t("An unchangeable setting can be updated."));
2311 }
2312 catch (FieldException $e) {
2313 $this->pass(t("An unchangeable setting cannot be updated."));
2314 }
2315 }
2316
2317 /**
2318 * Test that fields are properly marked active or inactive.
2319 */
2320 function testActive() {
2321 $field_definition = array(
2322 'field_name' => 'field_1',
2323 'type' => 'test_field',
2324 // For this test, we need a storage backend provided by a different
2325 // module than field_test.module.
2326 'storage' => array(
2327 'type' => 'field_sql_storage',
2328 ),
2329 );
2330 field_create_field($field_definition);
2331
2332 // Test disabling and enabling:
2333 // - the field type module,
2334 // - the storage module,
2335 // - both.
2336 $this->_testActiveHelper($field_definition, array('field_test'));
2337 $this->_testActiveHelper($field_definition, array('field_sql_storage'));
2338 $this->_testActiveHelper($field_definition, array('field_test', 'field_sql_storage'));
2339 }
2340
2341 /**
2342 * Helper function for testActive().
2343 *
2344 * Test dependency between a field and a set of modules.
2345 *
2346 * @param $field_definition
2347 * A field definition.
2348 * @param $modules
2349 * An aray of module names. The field will be tested to be inactive as long
2350 * as any of those modules is disabled.
2351 */
2352 function _testActiveHelper($field_definition, $modules) {
2353 $field_name = $field_definition['field_name'];
2354
2355 // Read the field.
2356 $field = field_read_field($field_name);
2357 $this->assertTrue($field_definition <= $field, t('The field was properly read.'));
2358
2359 module_disable($modules, FALSE);
2360 drupal_flush_all_caches();
2361
2362 $fields = field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE));
2363 $this->assertTrue(isset($fields[$field_name]) && $field_definition < $field, t('The field is properly read when explicitly fetching inactive fields.'));
2364
2365 // Re-enable modules one by one, and check that the field is still inactive
2366 // while some modules remain disabled.
2367 while ($modules) {
2368 $field = field_read_field($field_name);
2369 $this->assertTrue(empty($field), t('%modules disabled. The field is marked inactive.', array('%modules' => implode(', ', $modules))));
2370
2371 $module = array_shift($modules);
2372 module_enable(array($module), FALSE);
2373 drupal_flush_all_caches();
2374 }
2375
2376 // Check that the field is active again after all modules have been
2377 // enabled.
2378 $field = field_read_field($field_name);
2379 $this->assertTrue($field_definition <= $field, t('The field was was marked active.'));
2380 }
2381 }
2382
2383 class FieldInstanceCrudTestCase extends FieldTestCase {
2384 protected $field;
2385
2386 public static function getInfo() {
2387 return array(
2388 'name' => 'Field instance CRUD tests',
2389 'description' => 'Create field entities by attaching fields to entities.',
2390 'group' => 'Field API',
2391 );
2392 }
2393
2394 function setUp() {
2395 parent::setUp('field_test');
2396
2397 $this->field = array(
2398 'field_name' => drupal_strtolower($this->randomName()),
2399 'type' => 'test_field',
2400 );
2401 field_create_field($this->field);
2402 $this->instance_definition = array(
2403 'field_name' => $this->field['field_name'],
2404 'entity_type' => 'test_entity',
2405 'bundle' => 'test_bundle',
2406 );
2407 }
2408
2409 // TODO : test creation with
2410 // - a full fledged $instance structure, check that all the values are there
2411 // - a minimal $instance structure, check all default values are set
2412 // defer actual $instance comparison to a helper function, used for the two cases above,
2413 // and for testUpdateFieldInstance
2414
2415 /**
2416 * Test the creation of a field instance.
2417 */
2418 function testCreateFieldInstance() {
2419 field_create_instance($this->instance_definition);
2420
2421 // Read the raw record from the {field_config_instance} table.
2422 $result = db_query('SELECT * FROM {field_config_instance} WHERE field_name = :field_name AND bundle = :bundle', array(':field_name' => $this->instance_definition['field_name'], ':bundle' => $this->instance_definition['bundle']));
2423 $record = $result->fetchAssoc();
2424 $record['data'] = unserialize($record['data']);
2425
2426 $field_type = field_info_field_types($this->field['type']);
2427 $widget_type = field_info_widget_types($field_type['default_widget']);
2428 $formatter_type = field_info_formatter_types($field_type['default_formatter']);
2429
2430 // Check that default values are set.
2431 $this->assertIdentical($record['data']['required'], FALSE, t('Required defaults to false.'));
2432 $this->assertIdentical($record['data']['label'], $this->instance_definition['field_name'], t('Label defaults to field name.'));
2433 $this->assertIdentical($record['data']['description'], '', t('Description defaults to empty string.'));
2434 $this->assertIdentical($record['data']['widget']['type'], $field_type['default_widget'], t('Default widget has been written.'));
2435 $this->assertTrue(isset($record['data']['display']['default']), t('Display for "full" view_mode has been written.'));
2436 $this->assertIdentical($record['data']['display']['default']['type'], $field_type['default_formatter'], t('Default formatter for "full" view_mode has been written.'));
2437
2438 // Check that default settings are set.
2439 $this->assertIdentical($record['data']['settings'], $field_type['instance_settings'] , t('Default instance settings have been written.'));
2440 $this->assertIdentical($record['data']['widget']['settings'], $widget_type['settings'] , t('Default widget settings have been written.'));
2441 $this->assertIdentical($record['data']['display']['default']['settings'], $formatter_type['settings'], t('Default formatter settings for "full" view_mode have been written.'));
2442
2443 // Guarantee that the field/bundle combination is unique.
2444 try {
2445 field_create_instance($this->instance_definition);
2446 $this->fail(t('Cannot create two instances with the same field / bundle combination.'));
2447 }
2448 catch (FieldException $e) {
2449 $this->pass(t('Cannot create two instances with the same field / bundle combination.'));
2450 }
2451
2452 // Check that the specified field exists.
2453 try {
2454 $this->instance_definition['field_name'] = $this->randomName();
2455 field_create_instance($this->instance_definition);
2456 $this->fail(t('Cannot create an instance of a non-existing field.'));
2457 }
2458 catch (FieldException $e) {
2459 $this->pass(t('Cannot create an instance of a non-existing field.'));
2460 }
2461
2462 // Create a field restricted to a specific entity type.
2463 $field_restricted = array(
2464 'field_name' => drupal_strtolower($this->randomName()),
2465 'type' => 'test_field',
2466 'entity_types' => array('test_cacheable_entity'),
2467 );
2468 field_create_field($field_restricted);
2469
2470 // Check that an instance can be added to an entity type allowed
2471 // by the field.
2472 try {
2473 $instance = $this->instance_definition;
2474 $instance['field_name'] = $field_restricted['field_name'];
2475 $instance['entity_type'] = 'test_cacheable_entity';
2476 field_create_instance($instance);
2477 $this->pass(t('Can create an instance on an entity type allowed by the field.'));
2478 }
2479 catch (FieldException $e) {
2480 $this->fail(t('Can create an instance on an entity type allowed by the field.'));
2481 }
2482
2483 // Check that an instance cannot be added to an entity type
2484 // forbidden by the field.
2485 try {
2486 $instance = $this->instance_definition;
2487 $instance['field_name'] = $field_restricted['field_name'];
2488 field_create_instance($instance);
2489 $this->fail(t('Cannot create an instance on an entity type forbidden by the field.'));
2490 }
2491 catch (FieldException $e) {
2492 $this->pass(t('Cannot create an instance on an entity type forbidden by the field.'));
2493 }
2494
2495 // TODO: test other failures.
2496 }
2497
2498 /**
2499 * Test reading back an instance definition.
2500 */
2501 function testReadFieldInstance() {
2502 field_create_instance($this->instance_definition);
2503
2504 // Read the instance back.
2505 $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
2506 $this->assertTrue($this->instance_definition < $instance, t('The field was properly read.'));
2507 }
2508
2509 /**
2510 * Test the update of a field instance.
2511 */
2512 function testUpdateFieldInstance() {
2513 field_create_instance($this->instance_definition);
2514 $field_type = field_info_field_types($this->field['type']);
2515
2516 // Check that basic changes are saved.
2517 $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
2518 $instance['required'] = !$instance['required'];
2519 $instance['label'] = $this->randomName();
2520 $instance['description'] = $this->randomName();
2521 $instance['settings']['test_instance_setting'] = $this->randomName();
2522 $instance['widget']['settings']['test_widget_setting'] =$this->randomName();
2523 $instance['widget']['weight']++;
2524 $instance['display']['default']['settings']['test_formatter_setting'] = $this->randomName();
2525 $instance['display']['default']['weight']++;
2526 field_update_instance($instance);
2527
2528 $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
2529 $this->assertEqual($instance['required'], $instance_new['required'], t('"required" change is saved'));
2530 $this->assertEqual($instance['label'], $instance_new['label'], t('"label" change is saved'));
2531 $this->assertEqual($instance['description'], $instance_new['description'], t('"description" change is saved'));
2532 $this->assertEqual($instance['widget']['settings']['test_widget_setting'], $instance_new['widget']['settings']['test_widget_setting'], t('Widget setting change is saved'));
2533 $this->assertEqual($instance['widget']['weight'], $instance_new['widget']['weight'], t('Widget weight change is saved'));
2534 $this->assertEqual($instance['display']['default']['settings']['test_formatter_setting'], $instance_new['display']['default']['settings']['test_formatter_setting'], t('Formatter setting change is saved'));
2535 $this->assertEqual($instance['display']['default']['weight'], $instance_new['display']['default']['weight'], t('Widget weight change is saved'));
2536
2537 // Check that changing widget and formatter types updates the default settings.
2538 $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
2539 $instance['widget']['type'] = 'test_field_widget_multiple';
2540 $instance['display']['default']['type'] = 'field_test_multiple';
2541 field_update_instance($instance);
2542
2543 $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
2544 $this->assertEqual($instance['widget']['type'], $instance_new['widget']['type'] , t('Widget type change is saved.'));
2545 $settings = field_info_widget_settings($instance_new['widget']['type']);
2546 $this->assertIdentical($settings, array_intersect_key($instance_new['widget']['settings'], $settings) , t('Widget type change updates default settings.'));
2547 $this->assertEqual($instance['display']['default']['type'], $instance_new['display']['default']['type'] , t('Formatter type change is saved.'));
2548 $info = field_info_formatter_types($instance_new['display']['default']['type']);
2549 $settings = $info['settings'];
2550 $this->assertIdentical($settings, array_intersect_key($instance_new['display']['default']['settings'], $settings) , t('Changing formatter type updates default settings.'));
2551
2552 // Check that adding a new view mode is saved and gets default settings.
2553 $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
2554 $instance['display']['teaser'] = array();
2555 field_update_instance($instance);
2556
2557 $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
2558 $this->assertTrue(isset($instance_new['display']['teaser']), t('Display for the new view_mode has been written.'));
2559 $this->assertIdentical($instance_new['display']['teaser']['type'], $field_type['default_formatter'], t('Default formatter for the new view_mode has been written.'));
2560 $info = field_info_formatter_types($instance_new['display']['teaser']['type']);
2561 $settings = $info['settings'];
2562 $this->assertIdentical($settings, $instance_new['display']['teaser']['settings'] , t('Default formatter settings for the new view_mode have been written.'));
2563
2564 // TODO: test failures.
2565 }
2566
2567 /**
2568 * Test the deletion of a field instance.
2569 */
2570 function testDeleteFieldInstance() {
2571 // TODO: Test deletion of the data stored in the field also.
2572 // Need to check that data for a 'deleted' field / instance doesn't get loaded
2573 // Need to check data marked deleted is cleaned on cron (not implemented yet...)
2574
2575 // Create two instances for the same field so we can test that only one
2576 // is deleted.
2577 field_create_instance($this->instance_definition);
2578 $this->another_instance_definition = $this->instance_definition;
2579 $this->another_instance_definition['bundle'] .= '_another_bundle';
2580 $instance = field_create_instance($this->another_instance_definition);
2581
2582 // Test that the first instance is not deleted, and then delete it.
2583 $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
2584 $this->assertTrue(!empty($instance) && empty($instance['deleted']), t('A new field instance is not marked for deletion.'));
2585 field_delete_instance($instance);
2586
2587 // Make sure the instance is marked as deleted when the instance is
2588 // specifically loaded.
2589 $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
2590 $this->assertTrue(!empty($instance['deleted']), t('A deleted field instance is marked for deletion.'));
2591
2592 // Try to load the instance normally and make sure it does not show up.
2593 $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
2594 $this->assertTrue(empty($instance), t('A deleted field instance is not loaded by default.'));
2595
2596 // Make sure the other field instance is not deleted.
2597 $another_instance = field_read_instance('test_entity', $this->another_instance_definition['field_name'], $this->another_instance_definition['bundle']);
2598 $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), t('A non-deleted field instance is not marked for deletion.'));
2599
2600 // Make sure the field is deleted when its last instance is deleted.
2601 field_delete_instance($another_instance);
2602 $field = field_read_field($another_instance['field_name'], array('include_deleted' => TRUE));
2603 $this->assertTrue(!empty($field['deleted']), t('A deleted field is marked for deletion after all its instances have been marked for deletion.'));
2604 }
2605 }
2606
2607 /**
2608 * Unit test class for the multilanguage fields logic.
2609 *
2610 * The following tests will check the multilanguage logic of _field_invoke() and
2611 * that only the correct values are returned by field_available_languages().
2612 */
2613 class FieldTranslationsTestCase extends FieldTestCase {
2614 public static function getInfo() {
2615 return array(
2616 'name' => 'Field translations tests',
2617 'description' => 'Test multilanguage fields logic.',
2618 'group' => 'Field API',
2619 );
2620 }
2621
2622 function setUp() {
2623 parent::setUp('locale', 'field_test');
2624
2625 $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
2626
2627 $this->entity_type = 'test_entity';
2628
2629 $field = array(
2630 'field_name' => $this->field_name,
2631 'type' => 'test_field',
2632 'cardinality' => 4,
2633 'translatable' => TRUE,
2634 );
2635 field_create_field($field);
2636 $this->field = field_read_field($this->field_name);
2637
2638 $instance = array(
2639 'field_name' => $this->field_name,
2640 'entity_type' => $this->entity_type,
2641 'bundle' => 'test_bundle',
2642 );
2643 field_create_instance($instance);
2644 $this->instance = field_read_instance('test_entity', $this->field_name, 'test_bundle');
2645
2646 require_once DRUPAL_ROOT . '/includes/locale.inc';
2647 for ($i = 0; $i < 3; ++$i) {
2648 locale_add_language('l' . $i, $this->randomString(), $this->randomString());
2649 }
2650 }
2651
2652 /**
2653 * Ensures that only valid values are returned by field_available_languages().
2654 */
2655 function testFieldAvailableLanguages() {
2656 // Test 'translatable' fieldable info.
2657 field_test_entity_info_translatable('test_entity', FALSE);
2658 $field = $this->field;
2659 $field['field_name'] .= '_untranslatable';
2660
2661 // Enable field translations for the entity.
2662 field_test_entity_info_translatable('test_entity', TRUE);
2663
2664 // Test hook_field_languages() invocation on a translatable field.
2665 variable_set('field_test_field_available_languages_alter', TRUE);
2666 $enabled_languages = field_content_languages();
2667 $available_languages = field_available_languages($this->entity_type, $this->field);
2668 foreach ($available_languages as $delta => $langcode) {
2669 if ($langcode != 'xx' && $langcode != 'en') {
2670 $this->assertTrue(in_array($langcode, $enabled_languages), t('%language is an enabled language.', array('%language' => $langcode)));
2671 }
2672 }
2673 $this->assertTrue(in_array('xx', $available_languages), t('%language was made available.', array('%language' => 'xx')));
2674 $this->assertFalse(in_array('en', $available_languages), t('%language was made unavailable.', array('%language' => 'en')));
2675
2676 // Test field_available_languages() behavior for untranslatable fields.
2677 $this->field['translatable'] = FALSE;
2678 field_update_field($this->field);
2679 $available_languages = field_available_languages($this->entity_type, $this->field);
2680 $this->assertTrue(count($available_languages) == 1 && $available_languages[0] === LANGUAGE_NONE, t('For untranslatable fields only LANGUAGE_NONE is available.'));
2681 }
2682
2683 /**
2684 * Test the multilanguage logic of _field_invoke().
2685 */
2686 function testFieldInvoke() {
2687 // Enable field translations for the entity.
2688 field_test_entity_info_translatable('test_entity', TRUE);
2689
2690 $entity_type = 'test_entity';
2691 $entity = field_test_create_stub_entity(0, 0, $this->instance['bundle']);
2692
2693 // Populate some extra languages to check if _field_invoke() correctly uses
2694 // the result of field_available_languages().
2695 $values = array();
2696 $extra_languages = mt_rand(1, 4);
2697 $languages = $available_languages = field_available_languages($this->entity_type, $this->field);
2698 for ($i = 0; $i < $extra_languages; ++$i) {
2699 $languages[] = $this->randomName(2);
2700 }
2701
2702 // For each given language provide some random values.
2703 foreach ($languages as $langcode) {
2704 for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
2705 $values[$langcode][$delta]['value'] = mt_rand(1, 127);
2706 }
2707 }
2708 $entity->{$this->field_name} = $values;
2709
2710 $results = _field_invoke('test_op', $entity_type, $entity);
2711 foreach ($results as $langcode => $result) {
2712 $hash = hash('sha256', serialize(array($entity_type, $entity, $this->field_name, $langcode, $values[$langcode])));
2713 // Check whether the parameters passed to _field_invoke() were correctly