Newer
Older
Alex Pott
committed
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Entity\EntityUnitTest.
*/
namespace Drupal\Tests\Core\Entity;
catch
committed
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\Cache;
Alex Pott
committed
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\Entity;
Alex Pott
committed
use Drupal\Core\Entity\Exception\NoCorrespondingEntityClassException;
Alex Pott
committed
use Drupal\Core\Language\Language;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\entity_test\Entity\EntityTestMul;
Alex Pott
committed
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Entity\Entity
* @group Entity
catch
committed
* @group Access
Alex Pott
committed
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
*/
class EntityUnitTest extends UnitTestCase {
/**
* The entity under test.
*
* @var \Drupal\Core\Entity\Entity|\PHPUnit_Framework_MockObject_MockObject
*/
protected $entity;
/**
* The entity type used for testing.
*
* @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $entityType;
/**
* The entity manager used for testing.
*
* @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $entityManager;
/**
* The ID of the type of the entity under test.
*
* @var string
*/
protected $entityTypeId;
/**
* The route provider used for testing.
*
* @var \Drupal\Core\Routing\RouteProvider|\PHPUnit_Framework_MockObject_MockObject
*/
protected $routeProvider;
/**
* The UUID generator used for testing.
*
* @var \Drupal\Component\Uuid\UuidInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $uuid;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $languageManager;
Alex Pott
committed
/**
catch
committed
* The mocked cache tags invalidator.
Alex Pott
committed
*
catch
committed
* @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject
Alex Pott
committed
*/
catch
committed
protected $cacheTagsInvalidator;
Alex Pott
committed
Alex Pott
committed
/**
* The entity values.
*
* @var array
*/
protected $values;
/**
* {@inheritdoc}
*/
Alex Pott
committed
protected function setUp() {
Alex Pott
committed
$this->values = array(
'id' => 1,
'langcode' => 'en',
'uuid' => '3bb9ee60-bea5-4622-b89b-a63319d10b3a',
);
Alex Pott
committed
$this->entityTypeId = $this->randomMachineName();
Alex Pott
committed
$this->entityType = $this->getMock('\Drupal\Core\Entity\EntityTypeInterface');
$this->entityType->expects($this->any())
->method('getListCacheTags')
->willReturn(array($this->entityTypeId . '_list'));
Alex Pott
committed
$this->entityManager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface');
$this->entityManager->expects($this->any())
->method('getDefinition')
->with($this->entityTypeId)
->will($this->returnValue($this->entityType));
$this->uuid = $this->getMock('\Drupal\Component\Uuid\UuidInterface');
$this->languageManager = $this->getMock('\Drupal\Core\Language\LanguageManagerInterface');
$this->languageManager->expects($this->any())
->method('getLanguage')
->with('en')
->will($this->returnValue(new Language(array('id' => 'en'))));
catch
committed
$this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidator');
Alex Pott
committed
Alex Pott
committed
$container = new ContainerBuilder();
$container->set('entity.manager', $this->entityManager);
$container->set('uuid', $this->uuid);
$container->set('language_manager', $this->languageManager);
catch
committed
$container->set('cache_tags.invalidator', $this->cacheTagsInvalidator);
Alex Pott
committed
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
\Drupal::setContainer($container);
$this->entity = $this->getMockForAbstractClass('\Drupal\Core\Entity\Entity', array($this->values, $this->entityTypeId));
}
/**
* @covers ::id
*/
public function testId() {
$this->assertSame($this->values['id'], $this->entity->id());
}
/**
* @covers ::uuid
*/
public function testUuid() {
$this->assertSame($this->values['uuid'], $this->entity->uuid());
}
/**
* @covers ::isNew
* @covers ::enforceIsNew
*/
public function testIsNew() {
// We provided an ID, so the entity is not new.
$this->assertFalse($this->entity->isNew());
// Force it to be new.
$this->assertSame($this->entity, $this->entity->enforceIsNew());
$this->assertTrue($this->entity->isNew());
}
/**
* @covers ::getEntityType
*/
public function testGetEntityType() {
$this->assertSame($this->entityType, $this->entity->getEntityType());
}
/**
* @covers ::bundle
*/
public function testBundle() {
$this->assertSame($this->entityTypeId, $this->entity->bundle());
}
/**
* @covers ::label
*/
public function testLabel() {
// Make a mock with one method that we use as the entity's uri_callback. We
// check that it is called, and that the entity's label is the callback's
// return value.
Alex Pott
committed
$callback_label = $this->randomMachineName();
$property_label = $this->randomMachineName();
Alex Pott
committed
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
$callback_container = $this->getMock(get_class());
$callback_container->expects($this->once())
->method(__FUNCTION__)
->will($this->returnValue($callback_label));
$this->entityType->expects($this->at(0))
->method('getLabelCallback')
->will($this->returnValue(array($callback_container, __FUNCTION__)));
$this->entityType->expects($this->at(1))
->method('getLabelCallback')
->will($this->returnValue(NULL));
$this->entityType->expects($this->at(2))
->method('getKey')
->with('label')
->will($this->returnValue('label'));
// Set a dummy property on the entity under test to test that the label can
// be returned form a property if there is no callback.
$this->entityManager->expects($this->at(1))
->method('getDefinition')
->with($this->entityTypeId)
->will($this->returnValue(array(
'entity_keys' => array(
'label' => 'label',
),
)));
$this->entity->label = $property_label;
$this->assertSame($callback_label, $this->entity->label());
$this->assertSame($property_label, $this->entity->label());
}
/**
* @covers ::access
*/
public function testAccess() {
$access = $this->getMock('\Drupal\Core\Entity\EntityAccessControlHandlerInterface');
Alex Pott
committed
$operation = $this->randomMachineName();
Alex Pott
committed
$access->expects($this->at(0))
->method('access')
->with($this->entity, $operation)
catch
committed
->will($this->returnValue(AccessResult::allowed()));
Alex Pott
committed
$access->expects($this->at(1))
->method('createAccess')
catch
committed
->will($this->returnValue(AccessResult::allowed()));
Alex Pott
committed
$this->entityManager->expects($this->exactly(2))
->method('getAccessControlHandler')
Alex Pott
committed
->will($this->returnValue($access));
catch
committed
$this->assertEquals(AccessResult::allowed(), $this->entity->access($operation));
$this->assertEquals(AccessResult::allowed(), $this->entity->access('create'));
Alex Pott
committed
}
/**
* @covers ::language
*/
public function testLanguage() {
$this->entityType->expects($this->any())
->method('getKey')
->will($this->returnValueMap(array(
array('langcode', 'langcode'),
)));
$this->assertSame('en', $this->entity->language()->getId());
Alex Pott
committed
}
/**
* Setup for the tests of the ::load() method.
*/
function setupTestLoad() {
// Base our mocked entity on a real entity class so we can test if calling
// Entity::load() on the base class will bubble up to an actual entity.
$this->entityTypeId = 'entity_test_mul';
$methods = get_class_methods('Drupal\entity_test\Entity\EntityTestMul');
unset($methods[array_search('load', $methods)]);
unset($methods[array_search('loadMultiple', $methods)]);
Angie Byron
committed
unset($methods[array_search('create', $methods)]);
$this->entity = $this->getMockBuilder('Drupal\entity_test\Entity\EntityTestMul')
->disableOriginalConstructor()
->setMethods($methods)
->getMock();
}
/**
* @covers ::load
*
Alex Pott
committed
* Tests Entity::load() when called statically on a subclass of Entity.
*/
public function testLoad() {
$this->setupTestLoad();
Alex Pott
committed
$class_name = get_class($this->entity);
$this->entityManager->expects($this->once())
Alex Pott
committed
->method('getEntityTypeFromClass')
->with($class_name)
->willReturn($this->entityTypeId);
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
$storage->expects($this->once())
->method('load')
->with(1)
->will($this->returnValue($this->entity));
$this->entityManager->expects($this->once())
->method('getStorage')
->with($this->entityTypeId)
->will($this->returnValue($storage));
Alex Pott
committed
// Call Entity::load statically and check that it returns the mock entity.
$this->assertSame($this->entity, $class_name::load(1));
}
/**
* @covers ::loadMultiple
*
Alex Pott
committed
* Tests Entity::loadMultiple() when called statically on a subclass of
* Entity.
*/
public function testLoadMultiple() {
$this->setupTestLoad();
Alex Pott
committed
$class_name = get_class($this->entity);
Alex Pott
committed
$this->entityManager->expects($this->once())
->method('getEntityTypeFromClass')
->with($class_name)
->willReturn($this->entityTypeId);
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
$storage->expects($this->once())
->method('loadMultiple')
->with(array(1))
->will($this->returnValue(array(1 => $this->entity)));
$this->entityManager->expects($this->once())
->method('getStorage')
->with($this->entityTypeId)
->will($this->returnValue($storage));
// Call Entity::loadMultiple statically and check that it returns the mock
// entity.
Alex Pott
committed
$this->assertSame(array(1 => $this->entity), $class_name::loadMultiple(array(1)));
Angie Byron
committed
/**
* @covers ::create
*/
public function testCreate() {
$this->setupTestLoad();
Alex Pott
committed
$class_name = get_class($this->entity);
$this->entityManager->expects($this->once())
->method('getEntityTypeFromClass')
->with($class_name)
->willReturn($this->entityTypeId);
Angie Byron
committed
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
$storage->expects($this->once())
->method('create')
->with(array())
->will($this->returnValue($this->entity));
$this->entityManager->expects($this->once())
->method('getStorage')
->with($this->entityTypeId)
->will($this->returnValue($storage));
// Call Entity::create() statically and check that it returns the mock
// entity.
Alex Pott
committed
$this->assertSame($this->entity, $class_name::create(array()));
Angie Byron
committed
}
Alex Pott
committed
/**
* @covers ::save
*/
public function testSave() {
catch
committed
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
Alex Pott
committed
$storage->expects($this->once())
->method('save')
->with($this->entity);
$this->entityManager->expects($this->once())
catch
committed
->method('getStorage')
Alex Pott
committed
->with($this->entityTypeId)
->will($this->returnValue($storage));
$this->entity->save();
}
/**
* @covers ::delete
*/
public function testDelete() {
Alex Pott
committed
$this->entity->id = $this->randomMachineName();
catch
committed
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
Alex Pott
committed
// Testing the argument of the delete() method consumes too much memory.
$storage->expects($this->once())
->method('delete');
$this->entityManager->expects($this->once())
catch
committed
->method('getStorage')
Alex Pott
committed
->with($this->entityTypeId)
->will($this->returnValue($storage));
$this->entity->delete();
}
/**
* @covers ::getEntityTypeId
*/
public function testGetEntityTypeId() {
$this->assertSame($this->entityTypeId, $this->entity->getEntityTypeId());
}
/**
* @covers ::preSave
*/
public function testPreSave() {
// This method is internal, so check for errors on calling it only.
catch
committed
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
// Our mocked entity->preSave() returns NULL, so assert that.
$this->assertNull($this->entity->preSave($storage));
Alex Pott
committed
}
/**
* @covers ::postSave
*/
public function testPostSave() {
catch
committed
$this->cacheTagsInvalidator->expects($this->at(0))
Alex Pott
committed
->method('invalidateTags')
->with(array(
$this->entityTypeId . '_list', // List cache tag.
Alex Pott
committed
));
catch
committed
$this->cacheTagsInvalidator->expects($this->at(1))
Alex Pott
committed
->method('invalidateTags')
->with(array(
$this->entityTypeId . ':' . $this->values['id'], // Own cache tag.
$this->entityTypeId . '_list', // List cache tag.
Alex Pott
committed
));
Alex Pott
committed
// This method is internal, so check for errors on calling it only.
catch
committed
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
Alex Pott
committed
// A creation should trigger the invalidation of the "list" cache tag.
$this->entity->postSave($storage, FALSE);
// An update should trigger the invalidation of both the "list" and the
// "own" cache tags.
$this->entity->postSave($storage, TRUE);
Alex Pott
committed
}
/**
* @covers ::preCreate
*/
public function testPreCreate() {
// This method is internal, so check for errors on calling it only.
catch
committed
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
Alex Pott
committed
$values = array();
// Our mocked entity->preCreate() returns NULL, so assert that.
$this->assertNull($this->entity->preCreate($storage, $values));
Alex Pott
committed
}
/**
* @covers ::postCreate
*/
public function testPostCreate() {
// This method is internal, so check for errors on calling it only.
catch
committed
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
// Our mocked entity->postCreate() returns NULL, so assert that.
$this->assertNull($this->entity->postCreate($storage));
Alex Pott
committed
}
/**
* @covers ::preDelete
*/
public function testPreDelete() {
// This method is internal, so check for errors on calling it only.
catch
committed
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
// Our mocked entity->preDelete() returns NULL, so assert that.
$this->assertNull($this->entity->preDelete($storage, array($this->entity)));
Alex Pott
committed
}
/**
* @covers ::postDelete
*/
public function testPostDelete() {
catch
committed
$this->cacheTagsInvalidator->expects($this->once())
Alex Pott
committed
->method('invalidateTags')
->with(array(
$this->entityTypeId . ':' . $this->values['id'],
$this->entityTypeId . '_list',
Alex Pott
committed
));
catch
committed
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
$storage->expects($this->once())
->method('getEntityType')
->willReturn($this->entityType);
Alex Pott
committed
$entities = array($this->values['id'] => $this->entity);
Alex Pott
committed
$this->entity->postDelete($storage, $entities);
Alex Pott
committed
}
/**
* @covers ::postLoad
*/
public function testPostLoad() {
// This method is internal, so check for errors on calling it only.
catch
committed
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
Alex Pott
committed
$entities = array($this->entity);
// Our mocked entity->postLoad() returns NULL, so assert that.
$this->assertNull($this->entity->postLoad($storage, $entities));
Alex Pott
committed
}
/**
* @covers ::referencedEntities
*/
public function testReferencedEntities() {
$this->assertSame(array(), $this->entity->referencedEntities());
}
/**
* @covers ::getCacheTags
* @covers ::getCacheTagsToInvalidate
* @covers ::addCacheTags
*/
public function testCacheTags() {
// Ensure that both methods return the same by default.
$this->assertEquals([$this->entityTypeId . ':' . 1], $this->entity->getCacheTags());
$this->assertEquals([$this->entityTypeId . ':' . 1], $this->entity->getCacheTagsToInvalidate());
// Add an additional cache tag and make sure only getCacheTags() returns
// that.
$this->entity->addCacheTags(['additional_cache_tag']);
// EntityTypeId is random so it can shift order. We need to duplicate the
// sort from \Drupal\Core\Cache\Cache::mergeTags().
$tags = ['additional_cache_tag', $this->entityTypeId . ':' . 1];
sort($tags);
$this->assertEquals($tags, $this->entity->getCacheTags());
$this->assertEquals([$this->entityTypeId . ':' . 1], $this->entity->getCacheTagsToInvalidate());
}
/**
* @covers ::getCacheContexts
* @covers ::addCacheContexts
*/
public function testCacheContexts() {
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
->disableOriginalConstructor()
->getMock();
$cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
$container = new ContainerBuilder();
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
// There are no cache contexts by default.
$this->assertEquals([], $this->entity->getCacheContexts());
// Add an additional cache context.
$this->entity->addCacheContexts(['user']);
$this->assertEquals(['user'], $this->entity->getCacheContexts());
}
/**
* @covers ::getCacheMaxAge
* @covers ::mergeCacheMaxAge
*/
public function testCacheMaxAge() {
// Cache max age is permanent by default.
$this->assertEquals(Cache::PERMANENT, $this->entity->getCacheMaxAge());
// Set two cache max ages, the lower value is the one that needs to be
// returned.
$this->entity->mergeCacheMaxAge(600);
$this->entity->mergeCacheMaxAge(1800);
$this->assertEquals(600, $this->entity->getCacheMaxAge());
}