Projet

Général

Profil

Paste
Télécharger (92 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / entity / entity.test @ 3aa14731

1
<?php
2

    
3
/**
4
 * @file
5
 * Entity CRUD API tests.
6
 */
7

    
8
/**
9
 * Common parent class containing common helpers.
10
 */
11
abstract class EntityWebTestCase extends DrupalWebTestCase {
12

    
13
  /**
14
   * Creates a new vocabulary.
15
   */
16
  protected function createVocabulary() {
17
    $vocab = entity_create('taxonomy_vocabulary', array(
18
      'name' => $this->randomName(),
19
      'machine_name' => drupal_strtolower($this->randomName()),
20
      'description' => $this->randomName(),
21
    ));
22
    entity_save('taxonomy_vocabulary', $vocab);
23
    return $vocab;
24
  }
25

    
26
  /**
27
   * Creates a random file of the given type.
28
   */
29
  protected function createFile($file_type = 'text') {
30
    // Create a managed file.
31
    $file = current($this->drupalGetTestFiles($file_type));
32

    
33
    // Set additional file properties and save it.
34
    $file->filemime = file_get_mimetype($file->filename);
35
    $file->uid = 1;
36
    $file->timestamp = REQUEST_TIME;
37
    $file->filesize = filesize($file->uri);
38
    $file->status = 0;
39
    file_save($file);
40
    return $file;
41
  }
42
}
43

    
44
/**
45
 * Test basic API.
46
 */
47
class EntityAPITestCase extends EntityWebTestCase {
48

    
49
  public static function getInfo() {
50
    return array(
51
      'name' => 'Entity CRUD',
52
      'description' => 'Tests basic CRUD API functionality.',
53
      'group' => 'Entity API',
54
    );
55
  }
56

    
57
  function setUp() {
58
    parent::setUp('entity', 'entity_test');
59
  }
60

    
61
  /**
62
   * Tests CRUD.
63
   */
64
  function testCRUD() {
65
    module_enable(array('entity_feature'));
66

    
67
    $user1 = $this->drupalCreateUser();
68
    // Create test entities for the user1 and unrelated to a user.
69
    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
70
    $entity->save();
71
    $entity = entity_create('entity_test', array('name' => 'test2', 'uid' => $user1->uid));
72
    $entity->save();
73
    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => NULL));
74
    $entity->save();
75

    
76
    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test')));
77

    
78
    $this->assertEqual($entities[0]->name, 'test', 'Created and loaded entity.');
79
    $this->assertEqual($entities[1]->name, 'test', 'Created and loaded entity.');
80

    
81
    $results = entity_test_load_multiple(array($entity->pid));
82
    $loaded = array_pop($results);
83
    $this->assertEqual($loaded->pid, $entity->pid, 'Loaded the entity unrelated to a user.');
84

    
85
    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
86
    $entities[0]->delete();
87
    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
88
    $this->assertEqual($entities, array(), 'Entity successfully deleted.');
89

    
90
    $entity->save();
91
    $this->assertEqual($entity->pid, $loaded->pid, 'Entity successfully updated.');
92

    
93
    // Try deleting multiple test entities by deleting all.
94
    $pids = array_keys(entity_test_load_multiple(FALSE));
95
    entity_test_delete_multiple($pids);
96
  }
97

    
98
  /**
99
   * Tests CRUD for entities supporting revisions.
100
   */
101
  function testCRUDRevisisions() {
102
    module_enable(array('entity_feature'));
103

    
104
    // Add text field to entity.
105
    $field_info = array(
106
      'field_name' => 'field_text',
107
      'type' => 'text',
108
      'entity_types' => array('entity_test2'),
109
    );
110
    field_create_field($field_info);
111

    
112
    $instance = array(
113
      'label' => 'Text Field',
114
      'field_name' => 'field_text',
115
      'entity_type' => 'entity_test2',
116
      'bundle' => 'entity_test2',
117
      'settings' => array(),
118
      'required' => FALSE,
119
    );
120
    field_create_instance($instance);
121

    
122
    // Create a test entity.
123
    $entity_first_revision = entity_create('entity_test2', array('title' => 'first revision', 'name' => 'main', 'uid' => 1));
124
    $entity_first_revision->field_text[LANGUAGE_NONE][0]['value'] = 'first revision text';
125
    entity_save('entity_test2', $entity_first_revision);
126

    
127
    $entities = array_values(entity_load('entity_test2', FALSE));
128
    $this->assertEqual(count($entities), 1, 'Entity created.');
129
    $this->assertTrue($entities[0]->default_revision, 'Initial entity revision is marked as default revision.');
130

    
131
    // Saving the entity in revision mode should create a new revision.
132
    $entity_second_revision = clone $entity_first_revision;
133
    $entity_second_revision->title = 'second revision';
134
    $entity_second_revision->is_new_revision = TRUE;
135
    $entity_second_revision->default_revision = TRUE;
136
    $entity_second_revision->field_text[LANGUAGE_NONE][0]['value'] = 'second revision text';
137

    
138
    entity_save('entity_test2', $entity_second_revision);
139
    $this->assertNotEqual($entity_second_revision->revision_id, $entity_first_revision->revision_id, 'Saving an entity in new revision mode creates a revision.');
140
    $this->assertTrue($entity_second_revision->default_revision, 'New entity revision is marked as default revision.');
141

    
142
    // Check the saved entity.
143
    $entity = current(entity_load('entity_test2', array($entity_first_revision->pid), array(), TRUE));
144
    $this->assertNotEqual($entity->title, $entity_first_revision->title, 'Default revision was changed.');
145

    
146
    // Create third revision that is not default.
147
    $entity_third_revision = clone $entity_first_revision;
148
    $entity_third_revision->title = 'third revision';
149
    $entity_third_revision->is_new_revision = TRUE;
150
    $entity_third_revision->default_revision = FALSE;
151
    $entity_third_revision->field_text[LANGUAGE_NONE][0]['value'] = 'third revision text';
152
    entity_save('entity_test2', $entity_third_revision);
153
    $this->assertNotEqual($entity_second_revision->revision_id, $entity_third_revision->revision_id, 'Saving an entity in revision mode creates a revision.');
154
    $this->assertFalse($entity_third_revision->default_revision, 'Entity revision is not marked as default revision.');
155

    
156
    $entity = current(entity_load('entity_test2', array($entity_first_revision->pid), array(), TRUE));
157
    $this->assertEqual($entity->title, $entity_second_revision->title, 'Default revision was not changed.');
158
    $this->assertEqual($entity->field_text[LANGUAGE_NONE][0]['value'], $entity_second_revision->field_text[LANGUAGE_NONE][0]['value'], 'Default revision text field was not changed.');
159

    
160
    // Load not default revision.
161
    $revision = entity_revision_load('entity_test2', $entity_third_revision->revision_id);
162
    $this->assertEqual($revision->revision_id, $entity_third_revision->revision_id, 'Revision successfully loaded.');
163
    $this->assertFalse($revision->default_revision, 'Entity revision is not marked as default revision after loading.');
164

    
165
    // Save not default revision.
166
    $entity_third_revision->title = 'third revision updated';
167
    $entity_third_revision->field_text[LANGUAGE_NONE][0]['value'] = 'third revision text updated';
168
    entity_save('entity_test2', $entity_third_revision);
169

    
170
    // Ensure that not default revision has been changed.
171
    $entity = entity_revision_load('entity_test2', $entity_third_revision->revision_id);
172
    $this->assertEqual($entity->title, 'third revision updated', 'Not default revision was updated successfully.');
173
    $this->assertEqual($entity->field_text[LANGUAGE_NONE][0]['value'], 'third revision text updated', 'Not default revision field was updated successfully.');
174

    
175
    // Ensure that default revision has not been changed.
176
    $entity = current(entity_load('entity_test2', array($entity_first_revision->pid), array(), TRUE));
177
    $this->assertEqual($entity->title, $entity_second_revision->title, 'Default revision was not changed.');
178

    
179
    // Try to delete default revision.
180
    $result = entity_revision_delete('entity_test2', $entity_second_revision->revision_id);
181
    $this->assertFalse($result, 'Default revision cannot be deleted.');
182

    
183
    // Make sure default revision is still set after trying to delete it.
184
    $entity = current(entity_load('entity_test2', array($entity_first_revision->pid), array(), TRUE));
185
    $this->assertEqual($entity->revision_id, $entity_second_revision->revision_id, 'Second revision is still default.');
186

    
187
    // Delete first revision.
188
    $result = entity_revision_delete('entity_test2', $entity_first_revision->revision_id);
189
    $this->assertTrue($result, 'Not default revision deleted.');
190

    
191
    $entity = entity_revision_load('entity_test2', $entity_first_revision->revision_id);
192
    $this->assertFalse($entity, 'First revision deleted.');
193

    
194
    // Delete the entity and make sure third revision has been deleted as well.
195
    entity_delete('entity_test2', $entity_second_revision->pid);
196
    $entity_info = entity_get_info('entity_test2');
197
    $result = db_select($entity_info['revision table'])
198
      ->condition('revision_id', $entity_third_revision->revision_id)
199
      ->countQuery()
200
      ->execute()
201
      ->fetchField();
202
    $this->assertEqual($result, 0, 'Entity deleted with its all revisions.');
203
  }
204

    
205
  /**
206
   * Tests CRUD API functions: entity_(create|delete|save)
207
   */
208
  function testCRUDAPIfunctions() {
209
    module_enable(array('entity_feature'));
210

    
211
    $user1 = $this->drupalCreateUser();
212
    // Create test entities for the user1 and unrelated to a user.
213
    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
214
    entity_save('entity_test', $entity);
215
    $entity = entity_create('entity_test', array('name' => 'test2', 'uid' => $user1->uid));
216
    entity_save('entity_test', $entity);
217
    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => NULL));
218
    entity_save('entity_test', $entity);
219

    
220
    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test')));
221
    $this->assertEqual($entities[0]->name, 'test', 'Created and loaded entity.');
222
    $this->assertEqual($entities[1]->name, 'test', 'Created and loaded entity.');
223

    
224
    // Test getting the entity label, which is the used test-type's label.
225
    $label = entity_label('entity_test', $entities[0]);
226
    $this->assertEqual($label, 'label', 'Default label returned.');
227

    
228
    $results = entity_test_load_multiple(array($entity->pid));
229
    $loaded = array_pop($results);
230
    $this->assertEqual($loaded->pid, $entity->pid, 'Loaded the entity unrelated to a user.');
231

    
232
    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
233

    
234
    entity_delete('entity_test', $entities[0]->pid);
235
    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
236
    $this->assertEqual($entities, array(), 'Entity successfully deleted.');
237

    
238
    entity_save('entity_test', $entity);
239
    $this->assertEqual($entity->pid, $loaded->pid, 'Entity successfully updated.');
240

    
241
    // Try deleting multiple test entities by deleting all.
242
    $pids = array_keys(entity_test_load_multiple(FALSE));
243
    entity_delete_multiple('entity_test', $pids);
244
  }
245

    
246
  /**
247
   * Test loading entities defined in code.
248
   */
249
  function testExportables() {
250
    module_enable(array('entity_feature'));
251

    
252
    $types = entity_load_multiple_by_name('entity_test_type', array('test2', 'test'));
253

    
254
    $this->assertEqual(array_keys($types), array('test2', 'test'), 'Entities have been loaded in the order as specified.');
255
    $this->assertEqual($types['test']->label, 'label', 'Default type loaded.');
256
    $this->assertTrue($types['test']->status & ENTITY_IN_CODE && !($types['test']->status & ENTITY_CUSTOM), 'Default type status is correct.');
257

    
258
    // Test using a condition, which has to be applied on the defaults.
259
    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'label'));
260
    $this->assertEqual($types['test']->label, 'label', 'Condition to default type applied.');
261

    
262
    $types['test']->label = 'modified';
263
    $types['test']->save();
264

    
265
    // Ensure loading the changed entity works.
266
    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'modified'));
267
    $this->assertEqual($types['test']->label, 'modified', 'Modified type loaded.');
268

    
269
    // Clear the cache to simulate a new page load.
270
    entity_get_controller('entity_test_type')->resetCache();
271

    
272
    // Test loading using a condition again, now they default may not appear any
273
    // more as it's overridden by an entity with another label.
274
    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'label'));
275
    $this->assertTrue(empty($types), 'Conditions are applied to the overridden entity only.');
276

    
277
    // But the overridden entity has to appear with another condition.
278
    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'modified'));
279
    $this->assertEqual($types['test']->label, 'modified', 'Modified default type loaded by condition.');
280

    
281
    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
282
    $this->assertEqual($types['test']->label, 'modified', 'Modified default type loaded by id.');
283
    $this->assertTrue(entity_has_status('entity_test_type', $types['test'], ENTITY_OVERRIDDEN), 'Status of overridden type is correct.');
284

    
285
    // Test rebuilding the defaults and make sure overridden entities stay.
286
    entity_defaults_rebuild();
287
    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
288
    $this->assertEqual($types['test']->label, 'modified', 'Overridden entity is still overridden.');
289
    $this->assertTrue(entity_has_status('entity_test_type', $types['test'], ENTITY_OVERRIDDEN), 'Status of overridden type is correct.');
290

    
291
    // Test reverting.
292
    $types['test']->delete();
293
    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
294
    $this->assertEqual($types['test']->label, 'label', 'Entity has been reverted.');
295

    
296
    // Test loading an exportable by its numeric id.
297
    $result = entity_load_multiple_by_name('entity_test_type', array($types['test']->id));
298
    $this->assertTrue(isset($result['test']), 'Exportable entity loaded by the numeric id.');
299

    
300
    // Test exporting an entity to JSON.
301
    $serialized_string = $types['test']->export();
302
    $data = drupal_json_decode($serialized_string);
303
    $this->assertNotNull($data, 'Exported entity is valid JSON.');
304
    $import = entity_import('entity_test_type', $serialized_string);
305
    $this->assertTrue(get_class($import) == get_class($types['test']) && $types['test']->label == $import->label, 'Successfully exported entity to code.');
306
    $this->assertTrue(!isset($import->status), 'Exportable status has not been exported to code.');
307

    
308
    // Test disabling the module providing the defaults in code.
309
    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
310
    $types['test']->label = 'modified';
311
    $types['test']->save();
312

    
313
    module_disable(array('entity_feature'));
314

    
315
    // Make sure the overridden entity stays and the other one is deleted.
316
    entity_get_controller('entity_test_type')->resetCache();
317
    $test = entity_load_single('entity_test_type', 'test');
318
    $this->assertTrue(!empty($test) && $test->label == 'modified', 'Overidden entity is still available.');
319
    $this->assertTrue(!empty($test) && !entity_has_status('entity_test_type', $test, ENTITY_IN_CODE) && entity_has_status('entity_test_type', $test, ENTITY_CUSTOM), 'Overidden entity is now marked as custom.');
320

    
321
    $test2 = entity_load_single('entity_test_type', 'test2');
322
    $this->assertFalse($test2, 'Default entity has disappeared.');
323
  }
324

    
325
  /**
326
   * Make sure insert() and update() hooks for exportables are invoked.
327
   */
328
  function testExportableHooks() {
329
    $_SESSION['entity_hook_test'] = array();
330
    // Enabling the module should invoke the enabled hook for the other
331
    // entities provided in code.
332
    module_enable(array('entity_feature'));
333

    
334
    $insert = array('main', 'test', 'test2');
335
    $this->assertTrue($_SESSION['entity_hook_test']['entity_insert'] == $insert, 'Hook entity_insert has been invoked.');
336
    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_insert'] == $insert, 'Hook entity_test_type_insert has been invoked.');
337

    
338
    // Load a default entity and make sure the rebuilt logic only ran once.
339
    entity_load_single('entity_test_type', 'test');
340
    $this->assertTrue(!isset($_SESSION['entity_hook_test']['entity_test_type_update']), '"Entity-test-type" defaults have been rebuilt only once.');
341

    
342
    // Add a new test entity in DB and make sure the hook is invoked too.
343
    $test3 = entity_create('entity_test_type', array(
344
      'name' => 'test3',
345
      'label' => 'label',
346
      'weight' => 0,
347
    ));
348
    $test3->save();
349

    
350
    $insert[] = 'test3';
351
    $this->assertTrue($_SESSION['entity_hook_test']['entity_insert'] == $insert, 'Hook entity_insert has been invoked.');
352
    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_insert'] == $insert, 'Hook entity_test_type_insert has been invoked.');
353

    
354
    // Now override the 'test' entity and make sure it invokes the update hook.
355
    $result = entity_load_multiple_by_name('entity_test_type', array('test'));
356
    $result['test']->label = 'modified';
357
    $result['test']->save();
358

    
359
    $this->assertTrue($_SESSION['entity_hook_test']['entity_update'] == array('test'), 'Hook entity_update has been invoked.');
360
    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_update'] == array('test'), 'Hook entity_test_type_update has been invoked.');
361

    
362
    // 'test' has to remain enabled, as it has been overridden.
363
    $delete = array('main', 'test2');
364
    module_disable(array('entity_feature'));
365

    
366
    $this->assertTrue($_SESSION['entity_hook_test']['entity_delete'] == $delete, 'Hook entity_deleted has been invoked.');
367
    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_delete'] == $delete, 'Hook entity_test_type_deleted has been invoked.');
368

    
369
    // Now make sure 'test' is not overridden any more, but custom.
370
    $result = entity_load_multiple_by_name('entity_test_type', array('test'));
371
    $this->assertTrue(!$result['test']->hasStatus(ENTITY_OVERRIDDEN), 'Entity is not marked as overridden any more.');
372
    $this->assertTrue(entity_has_status('entity_test_type', $result['test'], ENTITY_CUSTOM), 'Entity is marked as custom.');
373

    
374
    // Test deleting the remaining entities from DB.
375
    entity_delete_multiple('entity_test_type', array('test', 'test3'));
376
    $delete[] = 'test';
377
    $delete[] = 'test3';
378
    $this->assertTrue($_SESSION['entity_hook_test']['entity_delete'] == $delete, 'Hook entity_deleted has been invoked.');
379
    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_delete'] == $delete, 'Hook entity_test_type_deleted has been invoked.');
380
  }
381

    
382
  /**
383
   * Tests determining changes.
384
   */
385
  function testChanges() {
386
    module_enable(array('entity_feature'));
387
    $types = entity_load_multiple_by_name('entity_test_type');
388

    
389
    // Override the default entity, such it gets saved in the DB.
390
    $types['test']->label ='test_changes';
391
    $types['test']->save();
392

    
393
    // Now test an update without applying any changes.
394
    $types['test']->save();
395
    $this->assertEqual($types['test']->label, 'test_changes', 'No changes have been determined.');
396

    
397
    // Apply changes.
398
    $types['test']->label = 'updated';
399
    $types['test']->save();
400

    
401
    // The hook implementations entity_test_entity_test_type_presave() and
402
    // entity_test_entity_test_type_update() determine changes and change the
403
    // label.
404
    $this->assertEqual($types['test']->label, 'updated_presave_update', 'Changes have been determined.');
405

    
406
    // Test the static load cache to be cleared.
407
    $types = entity_load_multiple_by_name('entity_test_type');
408
    $this->assertEqual($types['test']->label, 'updated_presave', 'Static cache has been cleared.');
409
  }
410

    
411

    
412
  /**
413
   * Tests viewing entites.
414
   */
415
  function testRendering() {
416
    module_enable(array('entity_feature'));
417

    
418
    $user1 = $this->drupalCreateUser();
419
    // Create test entities for the user1 and unrelated to a user.
420
    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
421

    
422
    $render = $entity->view();
423
    $output = drupal_render($render);
424
    // The entity class adds the user name to the output. Verify it is there.
425
    $this->assertTrue(strpos($output, format_username($user1)) !== FALSE, 'Entity has been rendered');
426
  }
427

    
428
  /**
429
   * Test uninstall of the entity_test module.
430
   */
431
  function testUninstall() {
432
    // Add a test type and add a field instance, uninstall, then re-install and
433
    // make sure the field instance can be re-created.
434
    $test_type = entity_create('entity_test_type', array(
435
      'name' => 'test',
436
      'label' => 'label',
437
      'weight' => 0,
438
    ));
439
    $test_type->save();
440

    
441
    $field = array(
442
      'field_name' => 'field_test_fullname',
443
      'type' => 'text',
444
      'cardinality' => 1,
445
      'translatable' => FALSE,
446
    );
447
    field_create_field($field);
448

    
449
    $instance = array(
450
      'entity_type' => 'entity_test',
451
      'field_name' => 'field_test_fullname',
452
      'bundle' => 'test',
453
      'label' => 'Full name',
454
      'description' => 'Specify your first and last name.',
455
      'widget' => array(
456
        'type' => 'text_textfield',
457
        'weight' => 0,
458
      ),
459
    );
460
    field_create_instance($instance);
461

    
462
    // Uninstallation has to remove all bundles, thus also field instances.
463
    module_disable(array('entity_test'));
464
    require_once DRUPAL_ROOT . '/includes/install.inc';
465
    drupal_uninstall_modules(array('entity_test'));
466

    
467
    // Make sure the instance has been deleted.
468
    $instance_read = field_read_instance('entity_test', 'field_test_fullname', 'test', array('include_inactive' => 1));
469
    $this->assertFalse((bool) $instance_read, 'Field instance has been deleted.');
470

    
471
    // Ensure re-creating the same instance now works.
472
    module_enable(array('entity_test'));
473
    $test_type = entity_create('entity_test_type', array(
474
      'name' => 'test',
475
      'label' => 'label',
476
      'weight' => 0,
477
    ));
478
    $test_type->save();
479
    field_create_field($field);
480
    field_create_instance($instance);
481

    
482
    $instance_read = field_info_instance('entity_test', 'field_test_fullname', 'test');
483
    $this->assertTrue((bool) $instance_read, 'Field instance has been re-created.');
484
  }
485
}
486

    
487
/**
488
 * Test the generated Rules integration.
489
 */
490
class EntityAPIRulesIntegrationTestCase extends EntityWebTestCase {
491

    
492
  public static function getInfo() {
493
    return array(
494
      'name' => 'Entity CRUD Rules integration',
495
      'description' => 'Tests the Rules integration provided by the Entity CRUD API.',
496
      'group' => 'Entity API',
497
      'dependencies' => array('rules'),
498
    );
499
  }
500

    
501
  function setUp() {
502
    parent::setUp('entity', 'entity_test', 'rules');
503
    // Make sure the logger is enabled so the debug log is saved.
504
    variable_set('rules_debug_log', 1);
505
  }
506

    
507
  /**
508
   * Test the events.
509
   */
510
  function testEvents() {
511
    $rule = rules_reaction_rule();
512
    $rule->event('entity_test_presave');
513
    $rule->event('entity_test_insert');
514
    $rule->event('entity_test_update');
515
    $rule->event('entity_test_delete');
516
    $rule->action('drupal_message', array('message' => 'hello!'));
517
    $rule->save();
518
    rules_clear_cache(TRUE);
519

    
520
    // Let the events occur.
521
    $user1 = $this->drupalCreateUser();
522
    RulesLog::logger()->clear();
523

    
524
    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
525
    $entity->save();
526
    $entity->name = 'update';
527
    $entity->save();
528
    $entity->delete();
529

    
530
    // Now there should have been 5 events, 2 times presave and once insert,
531
    // update and delete.
532
    $count = substr_count(RulesLog::logger()->render(), '0 ms Reacting on event');
533
    $this->assertTrue($count == 5, 'Events have been properly invoked.');
534
    RulesLog::logger()->checkLog();
535
  }
536
}
537

    
538
/**
539
 * Tests comments with node access.
540
 */
541
class EntityAPICommentNodeAccessTestCase extends CommentHelperCase {
542

    
543
  public static function getInfo() {
544
    return array(
545
      'name' => 'Entity API comment node access',
546
      'description' => 'Test viewing comments on nodes with node access.',
547
      'group' => 'Entity API',
548
    );
549
  }
550

    
551
  function setUp() {
552
    DrupalWebTestCase::setUp('comment', 'entity', 'node_access_test');
553
    node_access_rebuild();
554

    
555
    // Create test node and user with simple node access permission. The
556
    // 'node test view' permission is implemented and granted by the
557
    // node_access_test module.
558
    $this->accessUser = $this->drupalCreateUser(array('access comments', 'post comments', 'edit own comments', 'node test view'));
559
    $this->noAccessUser = $this->drupalCreateUser(array('administer comments'));
560
    $this->node = $this->drupalCreateNode(array('type' => 'article', 'uid' => $this->accessUser->uid));
561
  }
562

    
563
  /**
564
   * Tests comment access when node access is enabled.
565
   */
566
  function testCommentNodeAccess() {
567
    // Post comment.
568
    $this->drupalLogin($this->accessUser);
569
    $comment_text = $this->randomName();
570
    $comment = $this->postComment($this->node, $comment_text);
571
    $comment_loaded = comment_load($comment->id);
572
    $this->assertTrue($this->commentExists($comment), 'Comment found.');
573
    $this->drupalLogout();
574

    
575
    // Check access to node and associated comment for access user.
576
    $this->assertTrue(entity_access('view', 'node', $this->node, $this->accessUser), 'Access to view node was granted for access user');
577
    $this->assertTrue(entity_access('view', 'comment', $comment_loaded, $this->accessUser), 'Access to view comment was granted for access user');
578
    $this->assertTrue(entity_access('update', 'comment', $comment_loaded, $this->accessUser), 'Access to update comment was granted for access user');
579
    $this->assertFalse(entity_access('delete', 'comment', $comment_loaded, $this->accessUser), 'Access to delete comment was denied for access user');
580

    
581
    // Check access to node and associated comment for no access user.
582
    $this->assertFalse(entity_access('view', 'node', $this->node, $this->noAccessUser), 'Access to view node was denied for no access user');
583
    $this->assertFalse(entity_access('view', 'comment', $comment_loaded, $this->noAccessUser), 'Access to view comment was denied for no access user');
584
    $this->assertFalse(entity_access('update', 'comment', $comment_loaded, $this->noAccessUser), 'Access to update comment was denied for no access user');
585
    $this->assertFalse(entity_access('delete', 'comment', $comment_loaded, $this->noAccessUser), 'Access to delete comment was denied for no access user');
586
  }
587
}
588

    
589
/**
590
 * Test the i18n integration.
591
 */
592
class EntityAPIi18nItegrationTestCase extends EntityWebTestCase {
593

    
594
  public static function getInfo() {
595
    return array(
596
      'name' => 'Entity CRUD i18n integration',
597
      'description' => 'Tests the i18n integration provided by the Entity CRUD API.',
598
      'group' => 'Entity API',
599
      'dependencies' => array('i18n_string'),
600
    );
601
  }
602

    
603
  function setUp() {
604
    parent::setUp('entity_test_i18n');
605
    $this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages'));
606
    $this->drupalLogin($this->admin_user);
607
    $this->addLanguage('de');
608
  }
609

    
610
  /**
611
   * Copied from i18n module (class Drupali18nTestCase).
612
   *
613
   * We cannot extend from Drupali18nTestCase as else the test-bot would die.
614
   */
615
  public function addLanguage($language_code) {
616
    // Check to make sure that language has not already been installed.
617
    $this->drupalGet('admin/config/regional/language');
618

    
619
    if (strpos($this->drupalGetContent(), 'enabled[' . $language_code . ']') === FALSE) {
620
      // Doesn't have language installed so add it.
621
      $edit = array();
622
      $edit['langcode'] = $language_code;
623
      $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
624

    
625
      // Make sure we are not using a stale list.
626
      drupal_static_reset('language_list');
627
      $languages = language_list('language');
628
      $this->assertTrue(array_key_exists($language_code, $languages), t('Language was installed successfully.'));
629

    
630
      if (array_key_exists($language_code, $languages)) {
631
        $this->assertRaw(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => $languages[$language_code]->name, '@locale-help' => url('admin/help/locale'))), t('Language has been created.'));
632
      }
633
    }
634
    elseif ($this->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(':name' => 'enabled[' . $language_code . ']'))) {
635
      // It's installed and enabled. No need to do anything.
636
      $this->assertTrue(true, 'Language [' . $language_code . '] already installed and enabled.');
637
    }
638
    else {
639
      // It's installed but not enabled. Enable it.
640
      $this->assertTrue(true, 'Language [' . $language_code . '] already installed.');
641
      $this->drupalPost(NULL, array('enabled[' . $language_code . ']' => TRUE), t('Save configuration'));
642
      $this->assertRaw(t('Configuration saved.'), t('Language successfully enabled.'));
643
    }
644
  }
645

    
646
  /**
647
   * Tests the provided default controller.
648
   */
649
  function testDefaultController() {
650
    // Create test entities for the user1 and unrelated to a user.
651
    $entity = entity_create('entity_test_type', array(
652
      'name' => 'test',
653
      'uid' => $GLOBALS['user']->uid,
654
      'label' => 'label-en',
655
    ));
656
    $entity->save();
657

    
658
    // Add a translation.
659
    i18n_string_textgroup('entity_test')->update_translation("entity_test_type:{$entity->name}:label", 'de', 'label-de');
660

    
661
    $default = entity_i18n_string("entity_test:entity_test_type:{$entity->name}:label", 'label-en');
662
    $translation = entity_i18n_string("entity_test:entity_test_type:{$entity->name}:label", 'label-en', 'de');
663

    
664
    $this->assertEqual($translation, 'label-de', 'Label has been translated.');
665
    $this->assertEqual($default, 'label-en', 'Default label retrieved.');
666

    
667
    // Test the helper method.
668
    $translation = $entity->getTranslation('label', 'de');
669
    $default = $entity->getTranslation('label');
670
    $this->assertEqual($translation, 'label-de', 'Label has been translated via the helper method.');
671
    $this->assertEqual($default, 'label-en', 'Default label retrieved via the helper method.');
672

    
673
    // Test updating and make sure the translation stays.
674
    $entity->name = 'test2';
675
    $entity->save();
676
    $translation = $entity->getTranslation('label', 'de');
677
    $this->assertEqual($translation, 'label-de', 'Translation survives a name change.');
678

    
679
    // Test using the wrapper to retrieve a translation.
680
    $wrapper = entity_metadata_wrapper('entity_test_type', $entity);
681
    $translation = $wrapper->language('de')->label->value();
682
    $this->assertEqual($translation, 'label-de', 'Translation retrieved via the wrapper.');
683

    
684
    // Test deleting.
685
    $entity->delete();
686
    $translation = entity_i18n_string("entity_test:entity_test_type:{$entity->name}:label", 'label-en', 'de');
687
    $this->assertEqual($translation, 'label-en', 'Translation has been deleted.');
688
  }
689
}
690

    
691
/**
692
 * Tests metadata wrappers.
693
 */
694
class EntityMetadataTestCase extends EntityWebTestCase {
695

    
696
  public static function getInfo() {
697
    return array(
698
      'name' => 'Metadata Wrapper',
699
      'description' => 'Makes sure metadata wrapper are working right.',
700
      'group' => 'Entity API',
701
    );
702
  }
703

    
704
  function setUp() {
705
    parent::setUp('entity', 'entity_test', 'locale');
706
    // Create a field having 4 values for testing multiple value support.
707
    $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
708
    $this->field = array('field_name' => $this->field_name, 'type' => 'text', 'cardinality' => 4);
709
    $this->field = field_create_field($this->field);
710
    $this->field_id = $this->field['id'];
711
    $this->instance = array(
712
      'field_name' => $this->field_name,
713
      'entity_type' => 'node',
714
      'bundle' => 'page',
715
      'label' => $this->randomName() . '_label',
716
      'description' => $this->randomName() . '_description',
717
      'weight' => mt_rand(0, 127),
718
      'settings' => array(
719
        'text_processing' => FALSE,
720
      ),
721
      'widget' => array(
722
        'type' => 'text_textfield',
723
        'label' => 'Test Field',
724
        'settings' => array(
725
          'size' => 64,
726
        )
727
      )
728
    );
729
    field_create_instance($this->instance);
730

    
731
    // Make the body field and the node type 'page' translatable.
732
    $field = field_info_field('body');
733
    $field['translatable'] = TRUE;
734
    field_update_field($field);
735
    variable_set('language_content_type_page', 1);
736
  }
737

    
738
  /**
739
   * Creates a user and a node, then tests getting the properties.
740
   */
741
  function testEntityMetadataWrapper() {
742
    $account = $this->drupalCreateUser();
743
    // For testing sanitizing give the user a malicious user name
744
    $account = user_save($account, array('name' => '<b>BadName</b>'));
745
    $title = '<b>Is it bold?<b>';
746
    $body[LANGUAGE_NONE][0] = array('value' => '<b>The body & nothing.</b>', 'summary' => '<b>The body.</b>');
747
    $node = $this->drupalCreateNode(array('uid' => $account->uid, 'name' => $account->name, 'body' => $body, 'title' => $title, 'summary' => '', 'type' => 'page'));
748

    
749
    // First test without sanitizing.
750
    $wrapper = entity_metadata_wrapper('node', $node);
751

    
752
    $this->assertEqual('<b>Is it bold?<b>', $wrapper->title->value(), 'Getting a field value.');
753
    $this->assertEqual($node->title, $wrapper->title->raw(), 'Getting a raw property value.');
754

    
755
    // Test chaining.
756
    $this->assertEqual($account->mail, $wrapper->author->mail->value(), 'Testing chained usage.');
757
    $this->assertEqual($account->name, $wrapper->author->name->value(), 'Testing chained usage with callback and sanitizing.');
758

    
759
    // Test sanitized output.
760
    $options = array('sanitize' => TRUE);
761
    $this->assertEqual(check_plain('<b>Is it bold?<b>'), $wrapper->title->value($options), 'Getting sanitized field.');
762
    $this->assertEqual(filter_xss($node->name), $wrapper->author->name->value($options), 'Getting sanitized property with getter callback.');
763

    
764
    // Test getting an not existing property.
765
    try {
766
      echo $wrapper->dummy;
767
      $this->fail('Getting an not existing property.');
768
    }
769
    catch (EntityMetadataWrapperException $e) {
770
      $this->pass('Getting an not existing property.');
771
    }
772

    
773
    // Test setting.
774
    $wrapper->author = 0;
775
    $this->assertEqual(0, $wrapper->author->uid->value(), 'Setting a property.');
776
    try {
777
      $wrapper->url = 'dummy';
778
      $this->fail('Setting an unsupported property.');
779
    }
780
    catch (EntityMetadataWrapperException $e) {
781
      $this->pass('Setting an unsupported property.');
782
    }
783

    
784
    // Test value validation.
785
    $this->assertFalse($wrapper->author->name->validate(array(3)), 'Validation correctly checks for valid data types.');
786
    try {
787
      $wrapper->author->mail = 'foo';
788
      $this->fail('An invalid mail address has been set.');
789
    }
790
    catch (EntityMetadataWrapperException $e) {
791
      $this->pass('Setting an invalid mail address throws exception.');
792
    }
793
    // Test unsetting a required property.
794
    try {
795
      $wrapper->author = NULL;
796
      $this->fail('The required node author has been unset.');
797
    }
798
    catch (EntityMetadataWrapperException $e) {
799
      $this->pass('Unsetting the required node author throws an exception.');
800
    }
801

    
802
    // Test setting a referenced entity by id.
803
    $wrapper->author->set($GLOBALS['user']->uid);
804
    $this->assertEqual($wrapper->author->getIdentifier(), $GLOBALS['user']->uid, 'Get the identifier of a referenced entity.');
805
    $this->assertEqual($wrapper->author->uid->value(), $GLOBALS['user']->uid, 'Successfully set referenced entity using the identifier.');
806
    // Set by object.
807
    $wrapper->author->set($GLOBALS['user']);
808
    $this->assertEqual($wrapper->author->uid->value(), $GLOBALS['user']->uid, 'Successfully set referenced entity using the entity.');
809

    
810

    
811
    // Test getting by the field API processed values like the node body.
812
    $body_value = $wrapper->body->value;
813
    $this->assertEqual("<p>The body &amp; nothing.</p>\n", $body_value->value(), "Getting processed value.");
814
    $this->assertEqual("The body & nothing.\n", $body_value->value(array('decode' => TRUE)), "Decoded value.");
815
    $this->assertEqual("<b>The body & nothing.</b>", $body_value->raw(), "Raw body returned.");
816

    
817
    // Test getting the summary.
818
    $this->assertEqual("<p>The body.</p>\n", $wrapper->body->summary->value(), "Getting body summary.");
819

    
820
    $wrapper->body->set(array('value' => "<b>The second body.</b>"));
821
    $this->assertEqual("<p>The second body.</p>\n", $wrapper->body->value->value(), "Setting a processed field value and reading it again.");
822
    $this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], "<b>The second body.</b>", 'Update appears in the wrapped entity.');
823
    $this->assert(isset($node->body[LANGUAGE_NONE][0]['safe_value']), 'Formatted text has been processed.');
824

    
825
    // Test translating the body on an English node.
826
    locale_add_language('de');
827
    $body['en'][0] = array('value' => '<b>English body.</b>', 'summary' => '<b>The body.</b>');
828
    $node = $this->drupalCreateNode(array('body' => $body, 'language' => 'en', 'type' => 'page'));
829
    $wrapper = entity_metadata_wrapper('node', $node);
830

    
831
    $wrapper->language('de');
832

    
833
    $languages = language_list();
834
    $this->assertEqual($wrapper->getPropertyLanguage(), $languages['de'], 'Wrapper language has been set to German');
835
    $this->assertEqual($wrapper->body->value->value(), "<p>English body.</p>\n", 'Language fallback on default language.');
836

    
837
    // Set a German text using the wrapper.
838
    $wrapper->body->set(array('value' => "<b>Der zweite Text.</b>"));
839
    $this->assertEqual($wrapper->body->value->value(), "<p>Der zweite Text.</p>\n", 'German body set and retrieved.');
840

    
841
    $wrapper->language(LANGUAGE_NONE);
842
    $this->assertEqual($wrapper->body->value->value(), "<p>English body.</p>\n", 'Default language text is still there.');
843

    
844
    // Test iterator.
845
    $type_info = entity_get_property_info('node');
846
    $this->assertFalse(array_diff_key($type_info['properties'], iterator_to_array($wrapper->getIterator())), 'Iterator is working.');
847
    foreach ($wrapper as $property) {
848
      $this->assertTrue($property instanceof EntityMetadataWrapper, 'Iterate over wrapper properties.');
849
    }
850

    
851
    // Test setting a new node.
852
    $node->title = 'foo';
853
    $wrapper->set($node);
854
    $this->assertEqual($wrapper->title->value(), 'foo', 'Changed the wrapped node.');
855

    
856
    // Test getting options lists.
857
    $this->assertEqual($wrapper->type->optionsList(), node_type_get_names(), 'Options list returned.');
858

    
859
    // Test making use of a generic 'entity' reference property the
860
    // 'entity_test' module provides. The property defaults to the node author.
861
    $this->assertEqual($wrapper->reference->uid->value(), $wrapper->author->getIdentifier(), 'Used generic entity reference property.');
862
    // Test updating a property of the generic entity reference.
863
    $wrapper->reference->name->set('foo');
864
    $this->assertEqual($wrapper->reference->name->value(), 'foo', 'Updated property of generic entity reference');
865
    // For testing, just point the reference to the node itself now.
866
    $wrapper->reference->set($wrapper);
867
    $this->assertEqual($wrapper->reference->nid->value(), $wrapper->getIdentifier(), 'Correctly updated the generic entity referenced property.');
868

    
869
    // Test saving and deleting.
870
    $wrapper->save();
871
    $wrapper->delete();
872
    $return = node_load($wrapper->getIdentifier());
873
    $this->assertFalse($return, "Node has been successfully deleted.");
874

    
875
    // Ensure changing the bundle changes available wrapper properties.
876
    $wrapper->type->set('article');
877
    $this->assertTrue(isset($wrapper->field_tags), 'Changing bundle changes available wrapper properties.');
878

    
879
    // Test labels.
880
    $user = $this->drupalCreateUser();
881
    user_save($user, array('roles' => array()));
882
    $wrapper->author = $user->uid;
883
    $this->assertEqual($wrapper->label(), $node->title, 'Entity label returned.');
884
    $this->assertEqual($wrapper->author->roles[0]->label(), t('authenticated user'), 'Label from options list returned');
885
    $this->assertEqual($wrapper->author->roles->label(), t('authenticated user'), 'Label for a list from options list returned');
886
  }
887

    
888
  /**
889
   * Test supporting multi-valued fields.
890
   */
891
  function testListMetadataWrappers() {
892
    $property = $this->field_name;
893
    $values = array();
894
    $values[LANGUAGE_NONE][0] = array('value' => '<b>2009-09-05</b>');
895
    $values[LANGUAGE_NONE][1] = array('value' => '2009-09-05');
896
    $values[LANGUAGE_NONE][2] = array('value' => '2009-08-05');
897

    
898
    $node = $this->drupalCreateNode(array('type' => 'page', $property => $values));
899
    $wrapper = entity_metadata_wrapper('node', $node);
900

    
901
    $this->assertEqual('<b>2009-09-05</b>', $wrapper->{$property}[0]->value(), 'Getting array entry.');
902
    $this->assertEqual('2009-09-05', $wrapper->{$property}->get(1)->value(), 'Getting array entry.');
903
    $this->assertEqual(3, count($wrapper->{$property}->value()), 'Getting the whole array.');
904

    
905
    // Test sanitizing
906
    $this->assertEqual(check_plain('<b>2009-09-05</b>'), $wrapper->{$property}[0]->value(array('sanitize' => TRUE)), 'Getting array entry.');
907

    
908
    // Test iterator
909
    $this->assertEqual(array_keys(iterator_to_array($wrapper->$property->getIterator())), array_keys($wrapper->$property->value()), 'Iterator is working.');
910
    foreach ($wrapper->$property as $p) {
911
      $this->assertTrue($p instanceof EntityMetadataWrapper, 'Iterate over list wrapper properties.');
912
    }
913

    
914
    // Make sure changing the array changes the actual entity property.
915
    $wrapper->{$property}[0] = '2009-10-05';
916
    unset($wrapper->{$property}[1], $wrapper->{$property}[2]);
917
    $this->assertEqual($wrapper->{$property}->value(), array('2009-10-05'), 'Setting multiple property values.');
918

    
919
    // Test setting an arbitrary list item.
920
    $list = array(0 => REQUEST_TIME);
921
    $wrapper = entity_metadata_wrapper('list<date>', $list);
922
    $wrapper[1] = strtotime('2009-09-05');
923
    $this->assertEqual($wrapper->value(), array(REQUEST_TIME, strtotime('2009-09-05')), 'Setting a list item.');
924
    $this->assertEqual($wrapper->count(), 2, 'List count is correct.');
925

    
926
    // Test using a list wrapper without data.
927
    $wrapper = entity_metadata_wrapper('list<date>');
928
    $info = array();
929
    foreach ($wrapper as $item) {
930
      $info[] = $item->info();
931
    }
932
    $this->assertTrue($info[0]['type'] == 'date', 'Iterated over empty list wrapper.');
933

    
934
    // Test using a list of entities with a list of term objects.
935
    $list = array();
936
    $list[] = entity_property_values_create_entity('taxonomy_term', array(
937
      'name' => 'term 1',
938
      'vocabulary' => 1,
939
    ))->save()->value();
940
    $list[] = entity_property_values_create_entity('taxonomy_term', array(
941
      'name' => 'term 2',
942
      'vocabulary' => 1,
943
    ))->save()->value();
944
    $wrapper = entity_metadata_wrapper('list<taxonomy_term>', $list);
945
    $this->assertTrue($wrapper[0]->name->value() == 'term 1', 'Used a list of entities.');
946
    // Test getting a list of identifiers.
947
    $ids = $wrapper->value(array('identifier' => TRUE));
948
    $this->assertTrue(!is_object($ids[0]), 'Get a list of entity ids.');
949

    
950
    $wrapper = entity_metadata_wrapper('list<taxonomy_term>', $ids);
951
    $this->assertTrue($wrapper[0]->name->value() == 'term 1', 'Created a list of entities with ids.');
952

    
953
    // Test with a list of generic entities. The list is expected to be a list
954
    // of entity wrappers, otherwise the entity type is unknown.
955
    $node = $this->drupalCreateNode(array('title' => 'node 1'));
956
    $list = array();
957
    $list[] = entity_metadata_wrapper('node', $node);
958
    $wrapper = entity_metadata_wrapper('list<entity>', $list);
959
    $this->assertEqual($wrapper[0]->title->value(), 'node 1', 'Wrapped node was found in generic list of entities.');
960
  }
961

    
962
  /**
963
   * Tests using the wrapper without any data.
964
   */
965
  function testWithoutData() {
966
    $wrapper = entity_metadata_wrapper('node', NULL, array('bundle' => 'page'));
967
    $this->assertTrue(isset($wrapper->title), 'Bundle properties have been added.');
968
    $info = $wrapper->author->mail->info();
969
    $this->assertTrue(!empty($info) && is_array($info) && isset($info['label']), 'Property info returned.');
970
  }
971

    
972
  /**
973
   * Test using access() method.
974
   */
975
  function testAccess() {
976
    // Test without data.
977
    $account = $this->drupalCreateUser(array('bypass node access'));
978
    $this->assertTrue(entity_access('view', 'node', NULL, $account), 'Access without data checked.');
979

    
980
    // Test with actual data.
981
    $values[LANGUAGE_NONE][0] = array('value' => '<b>2009-09-05</b>');
982
    $values[LANGUAGE_NONE][1] = array('value' => '2009-09-05');
983
    $node = $this->drupalCreateNode(array('type' => 'page', $this->field_name => $values));
984
    $this->assertTrue(entity_access('delete', 'node', $node, $account), 'Access with data checked.');
985

    
986
    // Test per property access without data.
987
    $account2 = $this->drupalCreateUser(array('bypass node access', 'administer nodes'));
988
    $wrapper = entity_metadata_wrapper('node', NULL, array('bundle' => 'page'));
989
    $this->assertTrue($wrapper->access('edit', $account), 'Access to node granted.');
990
    $this->assertFalse($wrapper->status->access('edit', $account), 'Access for admin property denied.');
991
    $this->assertTrue($wrapper->status->access('edit', $account2), 'Access for admin property allowed for the admin.');
992

    
993
    // Test per property access with data.
994
    $wrapper = entity_metadata_wrapper('node', $node, array('bundle' => 'page'));
995
    $this->assertFalse($wrapper->status->access('edit', $account), 'Access for admin property denied.');
996
    $this->assertTrue($wrapper->status->access('edit', $account2), 'Access for admin property allowed for the admin.');
997

    
998
    // Test field level access.
999
    $this->assertTrue($wrapper->{$this->field_name}->access('view'), 'Field access granted.');
1000

    
1001
    // Create node owned by anonymous and test access() method on each of its
1002
    // properties.
1003
    $node = $this->drupalCreateNode(array('type' => 'page', 'uid' => 0));
1004
    $wrapper = entity_metadata_wrapper('node', $node->nid);
1005
    foreach ($wrapper as $name => $property) {
1006
      $property->access('view');
1007
    }
1008

    
1009
    // Property access of entity references takes entity access into account.
1010
    $node = $this->drupalCreateNode(array('type' => 'article'));
1011
    $wrapper = entity_metadata_wrapper('node', $node);
1012
    $unprivileged_user = $this->drupalCreateUser();
1013
    $privileged_user = $this->drupalCreateUser(array('access user profiles'));
1014

    
1015
    $this->assertTrue($wrapper->author->access('view', $privileged_user));
1016
    $this->assertFalse($wrapper->author->access('view', $unprivileged_user));
1017

    
1018
    // Ensure the same works with multiple entity references by testing the
1019
    // $node->field_tags example.
1020
    $privileged_user = $this->drupalCreateUser(array('administer taxonomy'));
1021
    // Terms are view-able with access content, so make sure to remove this
1022
    // permission first.
1023
    user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access content'));
1024
    $unprivileged_user = drupal_anonymous_user();
1025

    
1026
    $this->assertTrue($wrapper->field_tags->access('view', $privileged_user), 'Privileged user has access.');
1027
    $this->assertTrue($wrapper->field_tags->access('view', $unprivileged_user), 'Unprivileged user has access.');
1028
    $this->assertTrue($wrapper->field_tags[0]->access('view', $privileged_user), 'Privileged user has access.');
1029
    $this->assertFalse($wrapper->field_tags[0]->access('view', $unprivileged_user), 'Unprivileged user has no access.');
1030
  }
1031

    
1032
  /**
1033
   * Tests using a data structure with passed in metadata.
1034
   */
1035
  function testDataStructureWrapper() {
1036
    $log_entry = array(
1037
      'type'        => 'entity',
1038
      'message'     => $this->randomName(8),
1039
      'variables'   => array(),
1040
      'severity'    => WATCHDOG_NOTICE,
1041
      'link'        => '',
1042
      'user'        => $GLOBALS['user'],
1043
    );
1044
    $info['property info'] = array(
1045
      'type' => array('type' => 'text', 'label' => 'The category to which this message belongs.'),
1046
      'message' => array('type' => 'text', 'label' => 'The log message.'),
1047
      'user' => array('type' => 'user', 'label' => 'The user causing the log entry.'),
1048
    );
1049
    $wrapper = entity_metadata_wrapper('log_entry', $log_entry, $info);
1050
    $this->assertEqual($wrapper->user->name->value(), $GLOBALS['user']->name, 'Wrapped custom entity.');
1051
  }
1052

    
1053
  /**
1054
   * Tests using entity_property_query().
1055
   */
1056
  function testEntityQuery() {
1057
    // Creat a test node.
1058
    $title = '<b>Is it bold?<b>';
1059
    $values[LANGUAGE_NONE][0] = array('value' => 'foo');
1060
    $node = $this->drupalCreateNode(array($this->field_name => $values, 'title' => $title, 'uid' => $GLOBALS['user']->uid));
1061

    
1062
    $results = entity_property_query('node', 'title', $title);
1063
    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given title.');
1064

    
1065
    $results = entity_property_query('node', $this->field_name, 'foo');
1066
    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given field value.');
1067

    
1068
    $results = entity_property_query('node', $this->field_name, array('foo', 'bar'));
1069
    $this->assertEqual($results, array($node->nid), 'Queried nodes with a list of possible values.');
1070

    
1071
    $results = entity_property_query('node', 'author', $GLOBALS['user']);
1072
    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given auhtor.');
1073

    
1074
    // Create another test node and try querying for tags.
1075
    $tag = entity_property_values_create_entity('taxonomy_term', array(
1076
          'name' => $this->randomName(),
1077
          'vocabulary' => 1,
1078
    ))->save();
1079
    $field_tag_value[LANGUAGE_NONE][0]['tid'] = $tag->getIdentifier();
1080
    $node = $this->drupalCreateNode(array('type' => 'article', 'field_tags' => $field_tag_value));
1081

    
1082
    // Try query-ing with a single value.
1083
    $results = entity_property_query('node', 'field_tags', $tag->getIdentifier());
1084
    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given term id.');
1085

    
1086
    $results = entity_property_query('node', 'field_tags', $tag->value());
1087
    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given term object.');
1088

    
1089
    // Try query-ing with a list of possible values.
1090
    $results = entity_property_query('node', 'field_tags', array($tag->getIdentifier()));
1091
    $this->assertEqual($results, array($node->nid), 'Queried nodes with a list of term ids.');
1092
  }
1093

    
1094
  /**
1095
   * Tests serializing data wrappers, in particular for EntityDrupalWrapper.
1096
   */
1097
  function testWrapperSerialization() {
1098
    $node = $this->drupalCreateNode();
1099
    $wrapper = entity_metadata_wrapper('node', $node);
1100
    $this->assertTrue($wrapper->value() == $node, 'Data correctly wrapped.');
1101

    
1102
    // Test serializing and make sure only the node id is stored.
1103
    $this->assertTrue(strpos(serialize($wrapper), $node->title) === FALSE, 'Node has been correctly serialized.');
1104
    $this->assertEqual(unserialize(serialize($wrapper))->title->value(), $node->title, 'Serializing works right.');
1105

    
1106
    $wrapper2 = unserialize(serialize($wrapper));
1107
    // Test serializing the unloaded wrapper.
1108
    $this->assertEqual(unserialize(serialize($wrapper2))->title->value(), $node->title, 'Serializing works right.');
1109

    
1110
    // Test loading a not more existing node.
1111
    $s = serialize($wrapper2);
1112
    node_delete($node->nid);
1113
    $this->assertFalse(node_load($node->nid), 'Node deleted.');
1114

    
1115
    $value = unserialize($s)->value();
1116
    $this->assertNull($value, 'Tried to load not existing node.');
1117
  }
1118
}
1119

    
1120
/**
1121
 * Tests basic entity_access() functionality for nodes.
1122
 *
1123
 * This code is a modified version of NodeAccessTestCase.
1124
 *
1125
 * @see NodeAccessTestCase
1126
 */
1127
class EntityMetadataNodeAccessTestCase extends EntityWebTestCase {
1128
  public static function getInfo() {
1129
    return array(
1130
      'name' => 'Entity Metadata Node Access',
1131
      'description' => 'Test entity_access() for nodes',
1132
      'group' => 'Entity API',
1133
    );
1134
  }
1135

    
1136
  /**
1137
   * Asserts node_access() correctly grants or denies access.
1138
   */
1139
  function assertNodeMetadataAccess($ops, $node, $account) {
1140
    foreach ($ops as $op => $result) {
1141
      $msg = t("entity_access() returns @result with operation '@op'.", array('@result' => $result ? 'TRUE' : 'FALSE', '@op' => $op));
1142
      $access = entity_access($op, 'node', $node, $account);
1143
      $this->assertEqual($result, $access, $msg);
1144
    }
1145
  }
1146

    
1147
  function setUp() {
1148
    parent::setUp('entity', 'node');
1149
    // Clear permissions for authenticated users.
1150
    db_delete('role_permission')
1151
      ->condition('rid', DRUPAL_AUTHENTICATED_RID)
1152
      ->execute();
1153
  }
1154

    
1155
  /**
1156
   * Runs basic tests for entity_access() function.
1157
   */
1158
  function testNodeMetadataAccess() {
1159
    // Author user.
1160
    $node_author_account = $this->drupalCreateUser(array());
1161
    // Make a node object.
1162
    $settings = array(
1163
      'uid' => $node_author_account->uid,
1164
      'type' => 'page',
1165
      'title' => 'Node ' . $this->randomName(32),
1166
    );
1167
    $node = $this->drupalCreateNode($settings);
1168

    
1169
    // Ensures user without 'access content' permission can do nothing.
1170
    $web_user1 = $this->drupalCreateUser(array('create page content', 'edit any page content', 'delete any page content'));
1171
    $this->assertNodeMetadataAccess(array('create' => FALSE, 'view' => FALSE, 'update' => FALSE, 'delete' => FALSE), $node, $web_user1);
1172

    
1173
    // Ensures user with 'bypass node access' permission can do everything.
1174
    $web_user2 = $this->drupalCreateUser(array('bypass node access'));
1175
    $this->assertNodeMetadataAccess(array('create' => TRUE, 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE), $node, $web_user2);
1176

    
1177
    // User cannot 'view own unpublished content'.
1178
    $web_user3 = $this->drupalCreateUser(array('access content'));
1179
    // Create an unpublished node.
1180
    $settings = array('type' => 'page', 'status' => 0, 'uid' => $web_user3->uid);
1181
    $node_unpublished = $this->drupalCreateNode($settings);
1182
    $this->assertNodeMetadataAccess(array('view' => FALSE), $node_unpublished, $web_user3);
1183
    // User cannot create content without permission.
1184
    $this->assertNodeMetadataAccess(array('create' => FALSE), $node, $web_user3);
1185

    
1186
    // User can 'view own unpublished content', but another user cannot.
1187
    $web_user4 = $this->drupalCreateUser(array('access content', 'view own unpublished content'));
1188
    $web_user5 = $this->drupalCreateUser(array('access content', 'view own unpublished content'));
1189
    $node4 = $this->drupalCreateNode(array('status' => 0, 'uid' => $web_user4->uid));
1190
    $this->assertNodeMetadataAccess(array('view' => TRUE, 'update' => FALSE), $node4, $web_user4);
1191
    $this->assertNodeMetadataAccess(array('view' => FALSE), $node4, $web_user5);
1192

    
1193
    // Tests the default access provided for a published node.
1194
    $node5 = $this->drupalCreateNode();
1195
    $this->assertNodeMetadataAccess(array('view' => TRUE, 'update' => FALSE, 'delete' => FALSE, 'create' => FALSE), $node5, $web_user3);
1196
  }
1197
}
1198

    
1199
/**
1200
 * Test user permissions for node creation.
1201
 */
1202
class EntityMetadataNodeCreateAccessTestCase extends EntityWebTestCase {
1203
  public static function getInfo() {
1204
    return array(
1205
      'name' => 'Entity Metadata Node Create Access',
1206
      'description' => 'Test entity_access() for nodes',
1207
      'group' => 'Entity API',
1208
    );
1209
  }
1210

    
1211
  function setUp() {
1212
    parent::setUp('entity', 'node');
1213
  }
1214

    
1215
  /**
1216
   * Addresses the special case of 'create' access for nodes.
1217
   */
1218
  public function testNodeMetadataCreateAccess() {
1219
    // Create some users. One with super-powers, one with create perms,
1220
    // and one with no perms, and a different one to author the node.
1221
    $admin_account = $this->drupalCreateUser(array(
1222
      'bypass node access',
1223
    ));
1224
    $creator_account = $this->drupalCreateUser(array(
1225
      'create page content',
1226
    ));
1227
    $auth_only_account = $this->drupalCreateUser(array());
1228
    $node_author_account = $this->drupalCreateUser(array());
1229

    
1230
    // Make a node object with Entity API (contrib)
1231
    $settings = array(
1232
      'uid' => $node_author_account->uid,
1233
      'type' => 'page',
1234
      'title' => $this->randomName(32),
1235
      'body' => array(LANGUAGE_NONE => array(array($this->randomName(64)))),
1236
    );
1237
    $node = entity_create('node', $settings);
1238

    
1239
    // Test the populated wrapper.
1240
    $wrapper = entity_metadata_wrapper('node', $node);
1241
    $this->assertTrue($wrapper->entityAccess('create', $admin_account), 'Create access allowed for ADMIN, for populated wrapper.');
1242
    $this->assertTrue($wrapper->entityAccess('create', $creator_account), 'Create access allowed for CREATOR, for populated wrapper.');
1243
    $this->assertFalse($wrapper->entityAccess('create', $auth_only_account), 'Create access denied for USER, for populated wrapper.');
1244

    
1245
    // Test entity_acces().
1246
    $this->assertTrue(entity_access('create', 'node', $node, $admin_account), 'Create access allowed for ADMIN, for entity_access().');
1247
    $this->assertTrue(entity_access('create', 'node', $node, $creator_account), 'Create access allowed for CREATOR, for entity_access().');
1248
    $this->assertFalse(entity_access('create', 'node', $node, $auth_only_account), 'Create access denied for USER, for entity_access().');
1249
  }
1250
}
1251

    
1252
/**
1253
 * Tests user permissions for node revisions.
1254
 *
1255
 * Based almost entirely on NodeRevisionPermissionsTestCase.
1256
 */
1257
class EntityMetadataNodeRevisionAccessTestCase extends DrupalWebTestCase {
1258
  protected $node_revisions = array();
1259
  protected $accounts = array();
1260

    
1261
  // Map revision permission names to node revision access ops.
1262
  protected $map = array(
1263
    'view' => 'view revisions',
1264
    'update' => 'revert revisions',
1265
    'delete' => 'delete revisions',
1266
  );
1267

    
1268
  public static function getInfo() {
1269
    return array(
1270
      'name' => 'Entity Metadata Node Revision Access',
1271
      'description' => 'Tests user permissions for node revision operations.',
1272
      'group' => 'Entity API',
1273
    );
1274
  }
1275

    
1276
  function setUp() {
1277
    parent::setUp('entity', 'node');
1278

    
1279
    // Create a node with several revisions.
1280
    $node = $this->drupalCreateNode();
1281
    $this->node_revisions[] = $node;
1282

    
1283
    for ($i = 0; $i < 3; $i++) {
1284
      // Create a revision for the same nid and settings with a random log.
1285
      $revision = node_load($node->nid);
1286
      $revision->revision = 1;
1287
      $revision->log = $this->randomName(32);
1288
      node_save($revision);
1289
      $this->node_revisions[] = node_load($revision->nid);
1290
    }
1291

    
1292
    // Create three users, one with each revision permission.
1293
    foreach ($this->map as $op => $permission) {
1294
      // Create the user.
1295
      $account = $this->drupalCreateUser(
1296
        array(
1297
          'access content',
1298
          'edit any page content',
1299
          'delete any page content',
1300
          $permission,
1301
        )
1302
      );
1303
      $account->op = $op;
1304
      $this->accounts[] = $account;
1305
    }
1306

    
1307
    // Create an admin account (returns TRUE for all revision permissions).
1308
    $admin_account = $this->drupalCreateUser(array('access content', 'administer nodes'));
1309
    $admin_account->is_admin = TRUE;
1310
    $this->accounts['admin'] = $admin_account;
1311

    
1312
    // Create a normal account (returns FALSE for all revision permissions).
1313
    $normal_account = $this->drupalCreateUser();
1314
    $normal_account->op = FALSE;
1315
    $this->accounts[] = $normal_account;
1316
  }
1317

    
1318
  /**
1319
   * Tests the entity_access() function for revisions.
1320
   */
1321
  function testNodeRevisionAccess() {
1322
    // $node_revisions[1] won't be the latest revision.
1323
    $revision = $this->node_revisions[1];
1324

    
1325
    $parameters = array(
1326
      'op' => array_keys($this->map),
1327
      'account' => $this->accounts,
1328
    );
1329

    
1330
    $permutations = $this->generatePermutations($parameters);
1331
    $entity_type = 'node';
1332
    foreach ($permutations as $case) {
1333
      if (!empty($case['account']->is_admin) || $case['op'] == $case['account']->op) {
1334
        $access = entity_access($case['op'], $entity_type, $revision, $case['account']);
1335
        $this->assertTrue($access, "{$this->map[$case['op']]} granted on $entity_type.");
1336
      }
1337
      else {
1338
        $access = entity_access($case['op'], $entity_type, $revision, $case['account']);
1339
        $this->assertFalse($access, "{$this->map[$case['op']]} NOT granted on $entity_type.");
1340
      }
1341
    }
1342
  }
1343
}
1344

    
1345
/**
1346
 * Tests basic entity_access() functionality for taxonomy terms.
1347
 */
1348
class EntityMetadataTaxonomyAccessTestCase extends EntityWebTestCase {
1349
  public static function getInfo() {
1350
    return array(
1351
      'name' => 'Entity Metadata Taxonomy Access',
1352
      'description' => 'Test entity_access() for taxonomy terms',
1353
      'group' => 'Entity API',
1354
    );
1355
  }
1356

    
1357
  /**
1358
   * Asserts entity_access() correctly grants or denies access.
1359
   */
1360
  function assertTaxonomyMetadataAccess($ops, $term, $account) {
1361
    foreach ($ops as $op => $result) {
1362
      $msg = t("entity_access() returns @result with operation '@op'.", array('@result' => $result ? 'TRUE' : 'FALSE', '@op' => $op));
1363
      $access = entity_access($op, 'taxonomy_term', $term, $account);
1364
      $this->assertEqual($result, $access, $msg);
1365
    }
1366
  }
1367

    
1368
  /**
1369
   * @inheritdoc
1370
   */
1371
  function setUp() {
1372
    parent::setUp('entity', 'taxonomy');
1373
    // Clear permissions for authenticated users.
1374
    db_delete('role_permission')
1375
      ->condition('rid', DRUPAL_AUTHENTICATED_RID)
1376
      ->execute();
1377
  }
1378

    
1379
  /**
1380
   * Runs basic tests for entity_access() function.
1381
   */
1382
  function testTaxonomyMetadataAccess() {
1383
    $vocab = $this->createVocabulary();
1384
    $term = entity_property_values_create_entity('taxonomy_term', array(
1385
      'name' => $this->randomName(),
1386
      'vocabulary' => $vocab,
1387
    ))->save()->value();
1388
    // Clear permissions static cache to get new taxonomy permissions.
1389
    drupal_static_reset('checkPermissions');
1390

    
1391
    // Check assignment of view permissions.
1392
    $user1 = $this->drupalCreateUser(array('access content'));
1393
    $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => TRUE, 'update' => FALSE, 'delete' => FALSE), $term, $user1);
1394

    
1395
    // Check assignment of edit permissions.
1396
    $user2 = $this->drupalCreateUser(array('edit terms in ' . $vocab->vid));
1397
    $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => FALSE, 'update' => TRUE, 'delete' => FALSE), $term, $user2);
1398

    
1399
    // Check assignment of delete permissions.
1400
    $user3 = $this->drupalCreateUser(array('delete terms in ' . $vocab->vid));
1401
    $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => FALSE, 'update' => FALSE, 'delete' => TRUE), $term, $user3);
1402

    
1403
    // Check assignment of view, edit, delete permissions.
1404
    $user4 = $this->drupalCreateUser(array('access content', 'edit terms in ' . $vocab->vid, 'delete terms in ' . $vocab->vid));
1405
    $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE), $term, $user4);
1406

    
1407
    // Check assignment of administration permissions.
1408
    $user5 = $this->drupalCreateUser(array('administer taxonomy'));
1409
    $this->assertTaxonomyMetadataAccess(array('create' => TRUE, 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE), $term, $user5);
1410
  }
1411
}
1412

    
1413
/**
1414
 * Tests provided entity property info of the core modules.
1415
 */
1416
class EntityTokenTestCase extends EntityWebTestCase {
1417

    
1418
  public static function getInfo() {
1419
    return array(
1420
      'name' => 'Entity tokens',
1421
      'description' => 'Tests provided tokens for entity properties.',
1422
      'group' => 'Entity API',
1423
    );
1424
  }
1425

    
1426
  function setUp() {
1427
    parent::setUp('entity_token');
1428
  }
1429

    
1430
  /**
1431
   * Tests whether token support is basically working.
1432
   */
1433
  function testTokenSupport() {
1434
    // Test basic tokens.
1435
    $node = $this->drupalCreateNode(array('sticky' => TRUE, 'promote' => FALSE));
1436
    $text = "Sticky: [node:sticky] Promote: [node:promote] User: [site:current-user:name]";
1437
    $true = t('true');
1438
    $false = t('false');
1439
    $user_name = $GLOBALS['user']->name;
1440
    $target = "Sticky: $true Promote: $false User: $user_name";
1441
    $replace = token_replace($text, array('node' => $node));
1442
    $this->assertEqual($replace, $target, 'Provided tokens basically work.');
1443

    
1444
    // Test multiple-value tokens using the tags field of articles.
1445
    for ($i = 0; $i < 4; $i++) {
1446
      $tags[$i] = entity_property_values_create_entity('taxonomy_term', array(
1447
        'name' => $this->randomName(),
1448
        'vocabulary' => 1,
1449
      ))->save();
1450
      $field_value[LANGUAGE_NONE][$i]['tid'] = $tags[$i]->getIdentifier();
1451
      $labels[$i] = $tags[$i]->label();
1452
    }
1453
    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article', 'field_tags' => $field_value));
1454

    
1455
    $text = "Tags: [node:field-tags] First: [node:field-tags:0] 2nd name: [node:field-tags:1:name] 1st vocab [node:field-tags:0:vocabulary]";
1456
    $tag_labels = implode(', ', $labels);
1457
    $target = "Tags: $tag_labels First: $labels[0] 2nd name: $labels[1] 1st vocab {$tags[0]->vocabulary->label()}";
1458
    $replace = token_replace($text, array('node' => $node));
1459
    $this->assertEqual($replace, $target, 'Multiple-value token replacements have been replaced.');
1460

    
1461
    // Make sure not existing values are not handled.
1462
    $replace = token_replace("[node:field-tags:43]", array('node' => $node));
1463
    $this->assertEqual($replace, "[node:field-tags:43]", 'Not existing values are not replaced.');
1464

    
1465
    // Test data-structure tokens like [site:current-page:url].
1466
    $replace = token_replace("[site:current-page:url]", array());
1467
    $this->assertEqual($replace, $GLOBALS['base_root'] . request_uri(), 'Token replacements of data structure properties replaced.');
1468

    
1469
    // Test chaining of data-structure tokens using an image-field.
1470
    $file = $this->createFile('image');
1471
    $node = $this->drupalCreateNode(array('type' => 'article'));
1472
    $wrapper = entity_metadata_wrapper('node', $node);
1473

    
1474
    $wrapper->field_image = array('fid' => $file->fid);
1475
    $replace = token_replace("[node:field-image:file:name]", array('node' => $node));
1476
    $this->assertEqual($replace, $wrapper->field_image->file->name->value(), 'Token replacements of an image field have been replaced.');
1477
  }
1478
}
1479

    
1480
/**
1481
 * Tests provided entity property info of the core modules.
1482
 */
1483
class EntityMetadataIntegrationTestCase extends EntityWebTestCase {
1484

    
1485
  public static function getInfo() {
1486
    return array(
1487
      'name' => 'Property info core integration',
1488
      'description' => 'Tests using metadata wrapper for drupal core.',
1489
      'group' => 'Entity API',
1490
    );
1491
  }
1492

    
1493
  function setUp() {
1494
    parent::setUp('entity', 'book', 'statistics', 'locale');
1495
  }
1496

    
1497
  protected function assertException($wrapper, $name, $text = NULL) {
1498
    $this->assertTrue(isset($wrapper->$name), 'Property wrapper ' . check_plain($name) . ' exists.');
1499
    $text = isset($text) ? $text : 'Getting the not existing property ' . $name . ' throws exception.';
1500
    try {
1501
      $wrapper->$name->value();
1502
      $this->fail($text);
1503
    }
1504
    catch (EntityMetadataWrapperException $e) {
1505
      $this->pass($text);
1506
    }
1507
  }
1508

    
1509
  protected function assertEmpty($wrapper, $name) {
1510
    $this->assertTrue(isset($wrapper->$name), 'Property ' . check_plain($name) . ' exists.');
1511
    $this->assertTrue($wrapper->$name->value() === NULL, 'Property ' . check_plain($name) . ' is empty.');
1512
  }
1513

    
1514
  protected function assertEmptyArray($wrapper, $name) {
1515
    $this->assertTrue(isset($wrapper->$name), 'Property ' . check_plain($name) . ' exists.');
1516
    $this->assertTrue($wrapper->$name->value() === array(), 'Property ' . check_plain($name) . ' is an empty array.');
1517
  }
1518

    
1519
  protected function assertValue($wrapper, $key) {
1520
    $this->assertTrue($wrapper->$key->value() !== NULL, check_plain($key) . ' property returned.');
1521
    $info = $wrapper->$key->info();
1522
    if (!empty($info['raw getter callback'])) {
1523
      // Also test getting the raw value
1524
      $this->assertTrue($wrapper->$key->raw() !== NULL, check_plain($key) . ' raw value returned.');
1525
    }
1526
  }
1527

    
1528
  /**
1529
   * Test book module integration.
1530
   */
1531
  function testBookModule() {
1532
    $title = 'Book 1';
1533
    $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'book', 'book' => array('bid' => 'new')));
1534
    $book = array('bid' => $node->nid, 'plid' => $node->book['mlid']);
1535
    $node2 = $this->drupalCreateNode(array('type' => 'book', 'book' => $book));
1536
    $node3 = $this->drupalCreateNode(array('type' => 'page'));
1537
    $node4 = $this->drupalCreateNode(array('type' => 'book', 'book' => array('bid' => 0, 'plid' => -1)));
1538

    
1539
    // Test whether the properties work.
1540
    $wrapper = entity_metadata_wrapper('node', $node2);
1541
    $this->assertEqual($title, $wrapper->book->title->value(), "Book title returned.");
1542
    $this->assertEqual(array($node->nid), $wrapper->book_ancestors->value(array('identifier' => TRUE)), "Book ancestors returned.");
1543
    $this->assertEqual($node->nid, $wrapper->book->nid->value(), "Book id returned.");
1544

    
1545
    // Try using book properties for no book nodes.
1546
    $wrapper = entity_metadata_wrapper('node', $node3);
1547
    $this->assertEmpty($wrapper, 'book');
1548
    $this->assertEmptyArray($wrapper, 'book_ancestors');
1549

    
1550
    // Test a book node which is not contained in a hierarchy.
1551
    $wrapper = entity_metadata_wrapper('node', $node4);
1552
    $this->assertEmptyArray($wrapper, 'book_ancestors');
1553
  }
1554

    
1555
  /**
1556
   * Test properties of a comment.
1557
   */
1558
  function testComments() {
1559
    $title = 'Node 1';
1560
    $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'page'));
1561
    $author = $this->drupalCreateUser(array('access comments', 'post comments', 'edit own comments'));
1562
    $comment = (object)array(
1563
      'subject' => 'topic',
1564
      'nid' => $node->nid,
1565
      'uid' => $author->uid,
1566
      'cid' => FALSE,
1567
      'pid' => 0,
1568
      'homepage' => '',
1569
      'language' => LANGUAGE_NONE,
1570
      'hostname' => ip_address(),
1571
    );
1572
    $comment->comment_body[LANGUAGE_NONE][0] = array('value' => 'text', 'format' => 0);
1573
    comment_save($comment);
1574
    $wrapper = entity_metadata_wrapper('comment', $comment);
1575
    foreach ($wrapper as $key => $value) {
1576
      if ($key != 'parent') {
1577
        $this->assertValue($wrapper, $key);
1578
      }
1579
    }
1580
    $this->assertEmpty($wrapper, 'parent');
1581

    
1582
    // Test comment entity access.
1583
    $admin_user = $this->drupalCreateUser(array('access comments', 'administer comments', 'access user profiles'));
1584
    // Also grant access to view user accounts to test the comment author
1585
    // property.
1586
    $unprivileged_user = $this->drupalCreateUser(array('access comments', 'access user profiles'));
1587
    // Published comments can be viewed and edited by the author.
1588
    $this->assertTrue($wrapper->access('view', $author), 'Comment author is allowed to view the published comment.');
1589
    $this->assertTrue($wrapper->access('edit', $author), 'Comment author is allowed to edit the published comment.');
1590
    // We cannot use $wrapper->access('delete') here because it only understands
1591
    // view and edit.
1592
    $this->assertFalse(entity_access('delete', 'comment', $comment, $author), 'Comment author is not allowed to delete the published comment.');
1593

    
1594
    // Administrators can do anything with published comments.
1595
    $this->assertTrue($wrapper->access('view', $admin_user), 'Comment administrator is allowed to view the published comment.');
1596
    $this->assertTrue($wrapper->access('edit', $admin_user), 'Comment administrator is allowed to edit the published comment.');
1597
    $this->assertTrue(entity_access('delete', 'comment', $comment, $admin_user), 'Comment administrator is allowed to delete the published comment.');
1598

    
1599
    // Unpriviledged users can only view the published comment.
1600
    $this->assertTrue($wrapper->access('view', $unprivileged_user), 'Unprivileged user is allowed to view the published comment.');
1601
    $this->assertFalse($wrapper->access('edit', $unprivileged_user), 'Unprivileged user is not allowed to edit the published comment.');
1602
    $this->assertFalse(entity_access('delete', 'comment', $comment, $unprivileged_user), 'Unprivileged user is not allowed to delete the published comment.');
1603

    
1604
    // Test property view access.
1605
    $view_access = array('name', 'homepage', 'subject', 'created', 'author', 'node', 'parent', 'url', 'edit_url');
1606
    foreach ($view_access as $property_name) {
1607
      $this->assertTrue($wrapper->{$property_name}->access('view', $unprivileged_user), "Unpriviledged user can view the $property_name property.");
1608
    }
1609

    
1610
    $view_denied = array('hostname', 'mail', 'status');
1611
    foreach ($view_denied as $property_name) {
1612
      $this->assertFalse($wrapper->{$property_name}->access('view', $unprivileged_user), "Unpriviledged user can not view the $property_name property.");
1613
      $this->assertTrue($wrapper->{$property_name}->access('view', $admin_user), "Admin user can view the $property_name property.");
1614
    }
1615

    
1616
    // The author is allowed to edit the comment subject if they have the
1617
    // 'edit own comments' permission.
1618
    $this->assertTrue($wrapper->subject->access('edit', $author), "Author can edit the subject property.");
1619
    $this->assertFalse($wrapper->subject->access('edit', $unprivileged_user), "Unpriviledged user cannot edit the subject property.");
1620
    $this->assertTrue($wrapper->subject->access('edit', $admin_user), "Admin user can edit the subject property.");
1621

    
1622
    $edit_denied = array('hostname', 'mail', 'status', 'name', 'homepage', 'created', 'parent', 'node', 'author');
1623
    foreach ($edit_denied as $property_name) {
1624
      $this->assertFalse($wrapper->{$property_name}->access('edit', $author), "Author cannot edit the $property_name property.");
1625
      $this->assertTrue($wrapper->{$property_name}->access('edit', $admin_user), "Admin user can edit the $property_name property.");
1626
    }
1627

    
1628
    // Test access to unpublished comments.
1629
    $comment->status = COMMENT_NOT_PUBLISHED;
1630
    comment_save($comment);
1631

    
1632
    // Unpublished comments cannot be accessed by the author.
1633
    $this->assertFalse($wrapper->access('view', $author), 'Comment author is not allowed to view the unpublished comment.');
1634
    $this->assertFalse($wrapper->access('edit', $author), 'Comment author is not allowed to edit the unpublished comment.');
1635
    $this->assertFalse(entity_access('delete', 'comment', $comment, $author), 'Comment author is not allowed to delete the unpublished comment.');
1636

    
1637
    // Administrators can do anything with unpublished comments.
1638
    $this->assertTrue($wrapper->access('view', $admin_user), 'Comment administrator is allowed to view the unpublished comment.');
1639
    $this->assertTrue($wrapper->access('edit', $admin_user), 'Comment administrator is allowed to edit the unpublished comment.');
1640
    $this->assertTrue(entity_access('delete', 'comment', $comment, $admin_user), 'Comment administrator is allowed to delete the unpublished comment.');
1641

    
1642
    // Unpriviledged users cannot access unpublished comments.
1643
    $this->assertFalse($wrapper->access('view', $unprivileged_user), 'Unprivileged user is not allowed to view the unpublished comment.');
1644
    $this->assertFalse($wrapper->access('edit', $unprivileged_user), 'Unprivileged user is not allowed to edit the unpublished comment.');
1645
    $this->assertFalse(entity_access('delete', 'comment', $comment, $unprivileged_user), 'Unprivileged user is not allowed to delete the unpublished comment.');
1646
  }
1647

    
1648
  /**
1649
   * Test all properties of a node.
1650
   */
1651
  function testNodeProperties() {
1652
    $title = 'Book 1';
1653
    $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'page'));
1654
    $wrapper = entity_metadata_wrapper('node', $node);
1655
    foreach ($wrapper as $key => $value) {
1656
      if ($key != 'book' && $key != 'book_ancestors' && $key != 'source' && $key != 'last_view') {
1657
        $this->assertValue($wrapper, $key);
1658
      }
1659
    }
1660
    $this->assertEmpty($wrapper, 'book');
1661
    $this->assertEmptyArray($wrapper, 'book_ancestors');
1662
    $this->assertEmpty($wrapper, 'source');
1663
    $this->assertException($wrapper->source, 'title');
1664
    $this->assertEmpty($wrapper, 'last_view');
1665

    
1666
    // Test statistics module integration access.
1667
    $unpriviledged_user = $this->drupalCreateUser(array('access content'));
1668
    $this->assertTrue($wrapper->access('view', $unpriviledged_user), 'Unpriviledged user can view the node.');
1669
    $this->assertFalse($wrapper->access('edit', $unpriviledged_user), 'Unpriviledged user can not edit the node.');
1670
    $count_access_user = $this->drupalCreateUser(array('view post access counter'));
1671
    $admin_user = $this->drupalCreateUser(array('access content', 'view post access counter', 'access statistics'));
1672

    
1673
    $this->assertFalse($wrapper->views->access('view', $unpriviledged_user), "Unpriviledged user cannot view the statistics counter property.");
1674
    $this->assertTrue($wrapper->views->access('view', $count_access_user), "Count access user can view the statistics counter property.");
1675
    $this->assertTrue($wrapper->views->access('view', $admin_user), "Admin user can view the statistics counter property.");
1676

    
1677
    $admin_properties = array('day_views', 'last_view');
1678
    foreach ($admin_properties as $property_name) {
1679
      $this->assertFalse($wrapper->{$property_name}->access('view', $unpriviledged_user), "Unpriviledged user cannot view the $property_name property.");
1680
      $this->assertFalse($wrapper->{$property_name}->access('view', $count_access_user), "Count access user cannot view the $property_name property.");
1681
      $this->assertTrue($wrapper->{$property_name}->access('view', $admin_user), "Admin user can view the $property_name property.");
1682
    }
1683
  }
1684

    
1685
  /**
1686
   * Tests properties provided by the taxonomy module.
1687
   */
1688
  function testTaxonomyProperties() {
1689
    $vocab = $this->createVocabulary();
1690
    $term_parent = entity_property_values_create_entity('taxonomy_term', array(
1691
      'name' => $this->randomName(),
1692
      'vocabulary' => $vocab,
1693
    ))->save()->value();
1694
    $term_parent2 = entity_property_values_create_entity('taxonomy_term', array(
1695
      'name' => $this->randomName(),
1696
      'vocabulary' => $vocab,
1697
    ))->save()->value();
1698
    $term = entity_property_values_create_entity('taxonomy_term', array(
1699
      'name' => $this->randomName(),
1700
      'vocabulary' => $vocab,
1701
      'description' => $this->randomString(),
1702
      'weight' => mt_rand(0, 10),
1703
      'parent' => array($term_parent->tid),
1704
    ))->save()->value();
1705

    
1706
    $wrapper = entity_metadata_wrapper('taxonomy_term', $term);
1707
    foreach ($wrapper as $key => $value) {
1708
      $this->assertValue($wrapper, $key);
1709
    }
1710
    // Test setting another parent using the full object.
1711
    $wrapper->parent[] = $term_parent2;
1712
    $this->assertEqual($wrapper->parent[1]->getIdentifier(), $term_parent2->tid, 'Term parent added.');
1713

    
1714
    $parents = $wrapper->parent->value();
1715
    $tids = $term_parent->tid . ':' . $term_parent2->tid;
1716
    $this->assertEqual($parents[0]->tid . ':' . $parents[1]->tid, $tids, 'Parents returned.');
1717
    $this->assertEqual(implode(':', $wrapper->parent->value(array('identifier' => TRUE))), $tids, 'Parent ids returned.');
1718

    
1719
    // Test vocabulary.
1720
    foreach ($wrapper->vocabulary as $key => $value) {
1721
      $this->assertValue($wrapper->vocabulary, $key);
1722
    }
1723
    // Test field integration.
1724
    $tags[LANGUAGE_NONE][0]['tid'] = $term->tid;
1725
    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article', 'field_tags' => $tags));
1726
    $wrapper = entity_metadata_wrapper('node', $node);
1727
    $this->assertEqual($wrapper->field_tags[0]->name->value(), $term->name, 'Get an associated tag of a node with the wrapper.');
1728

    
1729
    $wrapper->field_tags[1] = $term_parent;
1730
    $tags = $wrapper->field_tags->value();
1731
    $this->assertEqual($tags[1]->tid, $term_parent->tid, 'Associated a new tag with a node.');
1732
    $this->assertEqual($tags[0]->tid, $term->tid, 'Previsous set association kept.');
1733

    
1734
    // Test getting a list of identifiers.
1735
    $tags = $wrapper->field_tags->value(array('identifier' => TRUE));
1736
    $this->assertEqual($tags, array($term->tid, $term_parent->tid), 'List of referenced term identifiers returned.');
1737

    
1738
    // Test setting tags by using ids.
1739
    $wrapper->field_tags->set(array(2));
1740
    $this->assertEqual($wrapper->field_tags[0]->tid->value(), 2, 'Specified tags by a list of term ids.');
1741

    
1742
    // Test unsetting all tags.
1743
    $wrapper->field_tags = NULL;
1744
    $this->assertFalse($wrapper->field_tags->value(), 'Unset all tags from a node.');
1745

    
1746
    // Test setting entity references to NULL.
1747
    // Create a taxonomy term field for that purpose.
1748
    $field_name = drupal_strtolower($this->randomName() . '_field_name');
1749
    $field = array('field_name' => $field_name, 'type' => 'taxonomy_term_reference', 'cardinality' => 1);
1750
    $field = field_create_field($field);
1751
    $field_id = $field['id'];
1752
    $field_instance = array(
1753
      'field_name' => $field_name,
1754
      'entity_type' => 'node',
1755
      'bundle' => 'article',
1756
      'label' => $this->randomName() . '_label',
1757
      'description' => $this->randomName() . '_description',
1758
      'weight' => mt_rand(0, 127),
1759
      'widget' => array(
1760
        'type' => 'options_select',
1761
        'label' => 'Test term field',
1762
      )
1763
    );
1764
    field_create_instance($field_instance);
1765
    $term_field[LANGUAGE_NONE][0]['tid'] = $term->tid;
1766
    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article', $field_name => $term_field));
1767
    $wrapper = entity_metadata_wrapper('node', $node);
1768
    $wrapper->$field_name->set(NULL);
1769
    $termref = $wrapper->$field_name->value();
1770
    $this->assertNull($termref, 'Unset of a term reference successful.');
1771
  }
1772

    
1773
  /**
1774
   * Test all properties of a user.
1775
   */
1776
  function testUserProperties() {
1777
    $account = $this->drupalCreateUser(array('access user profiles', 'change own username'));
1778
    $account->login = REQUEST_TIME;
1779
    $account->access = REQUEST_TIME;
1780
    $wrapper = entity_metadata_wrapper('user', $account);
1781
    foreach ($wrapper as $key => $value) {
1782
      $this->assertValue($wrapper, $key);
1783
    }
1784

    
1785
    // Test property view access.
1786
    $unpriviledged_user = $this->drupalCreateUser(array('access user profiles'));
1787
    $admin_user = $this->drupalCreateUser(array('administer users'));
1788
    $this->assertTrue($wrapper->access('view', $unpriviledged_user), 'Unpriviledged account can view the user.');
1789
    $this->assertFalse($wrapper->access('edit', $unpriviledged_user), 'Unpriviledged account can not edit the user.');
1790

    
1791
    $view_access = array('name', 'url', 'edit_url', 'created');
1792
    foreach ($view_access as $property_name) {
1793
      $this->assertTrue($wrapper->{$property_name}->access('view', $unpriviledged_user), "Unpriviledged user can view the $property_name property.");
1794
    }
1795

    
1796
    $view_denied = array('mail', 'last_access', 'last_login', 'roles', 'status', 'theme');
1797
    foreach ($view_denied as $property_name) {
1798
      $this->assertFalse($wrapper->{$property_name}->access('view', $unpriviledged_user), "Unpriviledged user can not view the $property_name property.");
1799
      $this->assertTrue($wrapper->{$property_name}->access('view', $admin_user), "Admin user can view the $property_name property.");
1800
    }
1801

    
1802
    // Test property edit access.
1803
    $edit_own_allowed = array('name', 'mail');
1804
    foreach ($edit_own_allowed as $property_name) {
1805
      $this->assertTrue($wrapper->{$property_name}->access('edit', $account), "Account owner can edit the $property_name property.");
1806
    }
1807

    
1808
    $this->assertTrue($wrapper->roles->access('view', $account), "Account owner can view their own roles.");
1809

    
1810
    $edit_denied = array('last_access', 'last_login', 'created', 'roles', 'status', 'theme');
1811
    foreach ($edit_denied as $property_name) {
1812
      $this->assertFalse($wrapper->{$property_name}->access('edit', $account), "Account owner cannot edit the $property_name property.");
1813
      $this->assertTrue($wrapper->{$property_name}->access('edit', $admin_user), "Admin user can edit the $property_name property.");
1814
    }
1815
  }
1816

    
1817
  /**
1818
   * Test properties provided by system module.
1819
   */
1820
  function testSystemProperties() {
1821
    $wrapper = entity_metadata_site_wrapper();
1822
    foreach ($wrapper as $key => $value) {
1823
      $this->assertValue($wrapper, $key);
1824
    }
1825
    // Test page request related properties.
1826
    foreach ($wrapper->current_page as $key => $value) {
1827
      $this->assertValue($wrapper->current_page, $key);
1828
    }
1829

    
1830
    // Test files.
1831
    $file = $this->createFile();
1832

    
1833
    $wrapper = entity_metadata_wrapper('file', $file);
1834
    foreach ($wrapper as $key => $value) {
1835
      $this->assertValue($wrapper, $key);
1836
    }
1837
  }
1838

    
1839
  /**
1840
   * Runs some generic tests on each entity.
1841
   */
1842
  function testCRUDfunctions() {
1843
    $info = entity_get_info();
1844
    foreach ($info as $entity_type => $entity_info) {
1845
      // Test using access callback.
1846
      entity_access('view', $entity_type);
1847
      entity_access('update', $entity_type);
1848
      entity_access('create', $entity_type);
1849
      entity_access('delete', $entity_type);
1850

    
1851
      // Test creating the entity.
1852
      if (!isset($entity_info['creation callback'])) {
1853
        continue;
1854
      }
1855

    
1856
      // Populate $values with all values that are setable. They will be set
1857
      // with an metadata wrapper, so we also test setting that way.
1858
      $values = array();
1859
      foreach (entity_metadata_wrapper($entity_type) as $name => $wrapper) {
1860
        $info = $wrapper->info();
1861
        if (!empty($info['setter callback'])) {
1862
          $values[$name] = $this->createValue($wrapper);
1863
        }
1864
      }
1865
      $entity = entity_property_values_create_entity($entity_type, $values)->value();
1866
      $this->assertTrue($entity, "Created $entity_type and set all setable values.");
1867

    
1868
      // Save the new entity.
1869
      $return = entity_save($entity_type, $entity);
1870
      if ($return === FALSE) {
1871
        continue; // No support for saving.
1872
      }
1873
      $id = entity_metadata_wrapper($entity_type, $entity)->getIdentifier();
1874
      $this->assertTrue($id, "$entity_type has been successfully saved.");
1875

    
1876
      // And delete it.
1877
      $return = entity_delete($entity_type, $id);
1878
      if ($return === FALSE) {
1879
        continue; // No support for deleting.
1880
      }
1881
      $return = entity_load_single($entity_type, $id);
1882
      $this->assertFalse($return, "$entity_type has been successfully deleted.");
1883
    }
1884
  }
1885

    
1886
  /**
1887
   * Test making use of a text fields.
1888
   */
1889
  function testTextFields() {
1890
    // Create a simple text field without text processing.
1891
    $field = array(
1892
      'field_name' => 'field_text',
1893
      'type' => 'text',
1894
      'cardinality' => 2,
1895
    );
1896
    field_create_field($field);
1897
    $instance = array(
1898
      'field_name' => 'field_text',
1899
      'entity_type' => 'node',
1900
      'label' => 'test',
1901
      'bundle' => 'article',
1902
      'widget' => array(
1903
        'type' => 'text_textfield',
1904
        'weight' => -1,
1905
      ),
1906
    );
1907
    field_create_instance($instance);
1908

    
1909
    $node = $this->drupalCreateNode(array('type' => 'article'));
1910
    $wrapper = entity_metadata_wrapper('node', $node);
1911

    
1912
    $wrapper->field_text[0] = 'the text';
1913

    
1914
    // Try saving the node and make sure the information is still there after
1915
    // loading the node again, thus the correct data structure has been written.
1916
    node_save($node);
1917
    $node = node_load($node->nid, NULL, TRUE);
1918
    $wrapper = entity_metadata_wrapper('node', $node);
1919

    
1920
    $this->assertEqual('the text', $wrapper->field_text[0]->value(), 'Text has been specified.');
1921

    
1922
    // Now activate text processing.
1923
    $instance['settings']['text_processing'] = 1;
1924
    field_update_instance($instance);
1925

    
1926
    $node = $this->drupalCreateNode(array('type' => 'article'));
1927
    $wrapper = entity_metadata_wrapper('node', $node);
1928

    
1929
    $wrapper->field_text[0]->set(array('value' => "<b>The second body.</b>"));
1930
    $this->assertEqual("<p>The second body.</p>\n", $wrapper->field_text[0]->value->value(), "Setting a processed text field value and reading it again.");
1931

    
1932
    // Assert the summary property is correctly removed.
1933
    $this->assertFalse(isset($wrapper->field_text[0]->summary), 'Processed text has no summary.');
1934

    
1935
    // Create a text field with summary but without text processing.
1936
    $field = array(
1937
      'field_name' => 'field_text2',
1938
      'type' => 'text_with_summary',
1939
      'cardinality' => 1,
1940
    );
1941
    field_create_field($field);
1942
    $instance = array(
1943
      'field_name' => 'field_text2',
1944
      'entity_type' => 'node',
1945
      'label' => 'test',
1946
      'bundle' => 'article',
1947
      'settings' => array('text_processing' => 0),
1948
      'widget' => array(
1949
        'type' => 'text_textarea_with_summary',
1950
        'weight' => -1,
1951
      ),
1952
    );
1953
    field_create_instance($instance);
1954

    
1955
    $node = $this->drupalCreateNode(array('type' => 'article'));
1956
    $wrapper = entity_metadata_wrapper('node', $node);
1957

    
1958
    $wrapper->field_text2->summary = 'the summary';
1959
    $wrapper->field_text2->value = 'the text';
1960

    
1961
    // Try saving the node and make sure the information is still there after
1962
    // loading the node again, thus the correct data structure has been written.
1963
    node_save($node);
1964
    $node = node_load($node->nid, NULL, TRUE);
1965
    $wrapper = entity_metadata_wrapper('node', $node);
1966

    
1967
    $this->assertEqual('the text', $wrapper->field_text2->value->value(), 'Text has been specified.');
1968
    $this->assertEqual('the summary', $wrapper->field_text2->summary->value(), 'Summary has been specified.');
1969
  }
1970

    
1971
  /**
1972
   * Test making use of a file field.
1973
   */
1974
  function testFileFields() {
1975
    $file = $this->createFile();
1976

    
1977
    // Create a file field.
1978
    $field = array(
1979
      'field_name' => 'field_file',
1980
      'type' => 'file',
1981
      'cardinality' => 2,
1982
      'settings' => array('display_field' => TRUE),
1983
    );
1984
    field_create_field($field);
1985
    $instance = array(
1986
      'field_name' => 'field_file',
1987
      'entity_type' => 'node',
1988
      'label' => 'File',
1989
      'bundle' => 'article',
1990
      'settings' => array('description_field' => TRUE),
1991
      'required' => FALSE,
1992
      'widget' => array(
1993
        'type' => 'file_generic',
1994
        'weight' => -1,
1995
      ),
1996
    );
1997
    field_create_instance($instance);
1998

    
1999
    $node = $this->drupalCreateNode(array('type' => 'article'));
2000
    $wrapper = entity_metadata_wrapper('node', $node);
2001

    
2002
    $wrapper->field_file[0] = array('fid' => $file->fid, 'display' => FALSE);
2003
    $this->assertEqual($file->filename, $wrapper->field_file[0]->file->name->value(), 'File has been specified.');
2004

    
2005
    $wrapper->field_file[0]->description = 'foo';
2006
    $wrapper->field_file[0]->display = TRUE;
2007

    
2008
    $this->assertEqual($wrapper->field_file[0]->description->value(), 'foo', 'File description has been correctly set.');
2009

    
2010
    // Try saving the node and make sure the information is still there after
2011
    // loading the node again, thus the correct data structure has been written.
2012
    node_save($node);
2013
    $node = node_load($node->nid, NULL, TRUE);
2014
    $wrapper = entity_metadata_wrapper('node', $node);
2015

    
2016
    $this->assertEqual($wrapper->field_file[0]->description->value(), 'foo', 'File description has been correctly set.');
2017
    $this->assertEqual($wrapper->field_file[0]->display->value(), TRUE, 'File display value has been correctly set.');
2018

    
2019
    // Test adding a new file, the display-property has to be created
2020
    // automatically.
2021
    $wrapper->field_file[1]->file = $file;
2022
    node_save($node);
2023
    $node = node_load($node->nid, NULL, TRUE);
2024
    $this->assertEqual($file->fid, $wrapper->field_file[1]->file->getIdentifier(), 'New file has been added.');
2025

    
2026
    // Test adding an invalid file-field item, i.e. without any file.
2027
    try {
2028
      $wrapper->field_file[] = array('description' => 'test');
2029
      $this->fail('Exception not thrown.');
2030
    }
2031
    catch (EntityMetadataWrapperException $e) {
2032
      $this->pass('Not valid file-field item has thrown an exception.');
2033
    }
2034

    
2035
    // Test remove all file-field items.
2036
    $wrapper->field_file = NULL;
2037
    $this->assertFalse($wrapper->field_file->value(), 'Removed multiple file-field items.');
2038
  }
2039

    
2040
  /**
2041
   * Test making use of an image field.
2042
   */
2043
  function testImageFields() {
2044
    $file = $this->createFile('image');
2045

    
2046
    // Just use the image field on the article node.
2047
    $node = $this->drupalCreateNode(array('type' => 'article'));
2048
    $wrapper = entity_metadata_wrapper('node', $node);
2049

    
2050
    $wrapper->field_image = array('fid' => $file->fid);
2051
    $this->assertEqual($file->filename, $wrapper->field_image->file->name->value(), 'File has been specified.');
2052

    
2053
    $wrapper->field_image->alt = 'foo';
2054
    $this->assertEqual($wrapper->field_image->alt->value(), 'foo', 'Image alt attribute has been correctly set.');
2055

    
2056
    // Try saving the node and make sure the information is still there after
2057
    // loading the node again, thus the correct data structure has been written.
2058
    node_save($node);
2059
    $node = node_load($node->nid, NULL, TRUE);
2060
    $wrapper = entity_metadata_wrapper('node', $node);
2061

    
2062
    $this->assertEqual($wrapper->field_image->alt->value(), 'foo', 'File description has been correctly set.');
2063

    
2064
    // Test adding a new image.
2065
    $wrapper->field_image->file = $file;
2066
    node_save($node);
2067
    $node = node_load($node->nid, NULL, TRUE);
2068
    $this->assertEqual($file->fid, $wrapper->field_image->file->getIdentifier(), 'New file has been added.');
2069

    
2070
    // Test adding an invalid image-field item, i.e. without any file.
2071
    try {
2072
      $wrapper->field_image = array();
2073
      $this->fail('Exception not thrown.');
2074
    }
2075
    catch (EntityMetadataWrapperException $e) {
2076
      $this->pass('Not valid image-field item has thrown an exception.');
2077
    }
2078
  }
2079

    
2080
  /**
2081
   * Creates a value for the given property.
2082
   */
2083
  protected function createValue($wrapper) {
2084
    if (!isset($this->node)) {
2085
      $this->node = $this->drupalCreateNode(array('type' => 'page'));
2086
      $this->user = $this->drupalCreateUser();
2087
      $this->taxonomy_vocabulary = $this->createVocabulary();
2088
    }
2089

    
2090
    if ($options = $wrapper->optionsList()) {
2091
      $options = entity_property_options_flatten($options);
2092
      return $wrapper instanceof EntityListWrapper ? array(key($options)) : key($options);
2093
    }
2094

    
2095
    // For mail addresses properly pass an mail address.
2096
    $info = $wrapper->info();
2097
    if ($info['name'] == 'mail') {
2098
      return 'webmaster@example.com';
2099
    }
2100

    
2101
    switch ($wrapper->type()) {
2102
      case 'decimal':
2103
      case 'integer':
2104
      case 'duration':
2105
        return 1;
2106
      case 'date':
2107
        return REQUEST_TIME;
2108
      case 'boolean':
2109
        return TRUE;
2110
      case 'token':
2111
        return drupal_strtolower($this->randomName(8));
2112
      case 'text':
2113
        return $this->randomName(32);
2114
      case 'text_formatted':
2115
        return array('value' => $this->randomName(16));
2116
      case 'list<taxonomy_term>':
2117
        return array();
2118

    
2119
      default:
2120
        return $this->{$wrapper->type()};
2121
    }
2122
  }
2123
}