Newer
Older
Alex Pott
committed
<?php
namespace Drupal\Tests\Core\Entity;
catch
committed
use Drupal\Core\Access\AccessResult;
Alex Pott
committed
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\ContentEntityInterface;
Alex Pott
committed
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\TypedData\TypedDataManagerInterface;
Alex Pott
committed
use Drupal\Tests\UnitTestCase;
use Drupal\Core\Language\Language;
use Symfony\Component\Validator\Validator\ValidatorInterface;
Alex Pott
committed
/**
* @coversDefaultClass \Drupal\Core\Entity\ContentEntityBase
* @group Entity
catch
committed
* @group Access
Alex Pott
committed
*/
class ContentEntityBaseUnitTest extends UnitTestCase {
/**
* The bundle of the entity under test.
*
* @var string
*/
protected $bundle;
/**
* The entity under test.
*
* @var \Drupal\Core\Entity\ContentEntityBase|\PHPUnit_Framework_MockObject_MockObject
*/
protected $entity;
/**
* An entity with no defined language to test.
*
* @var \Drupal\Core\Entity\ContentEntityBase|\PHPUnit_Framework_MockObject_MockObject
*/
protected $entityUnd;
Alex Pott
committed
/**
* 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 type ID of the entity under test.
*
* @var string
*/
protected $entityTypeId;
/**
* The typed data manager used for testing.
*
* @var \Drupal\Core\TypedData\TypedDataManager|\PHPUnit_Framework_MockObject_MockObject
*/
protected $typedDataManager;
catch
committed
/**
* The field type manager used for testing.
*
* @var \Drupal\Core\Field\FieldTypePluginManager|\PHPUnit_Framework_MockObject_MockObject
*/
protected $fieldTypePluginManager;
Alex Pott
committed
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $languageManager;
/**
* The UUID generator used for testing.
*
* @var \Drupal\Component\Uuid\UuidInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $uuid;
/**
* The entity ID.
*
* @var int
*/
protected $id;
Alex Pott
committed
/**
* Field definitions.
*
Alex Pott
committed
* @var \Drupal\Core\Field\BaseFieldDefinition[]
Alex Pott
committed
*/
protected $fieldDefinitions;
Alex Pott
committed
/**
* {@inheritdoc}
*/
Alex Pott
committed
protected function setUp() {
Alex Pott
committed
$this->id = 1;
$values = array(
'id' => $this->id,
'uuid' => '3bb9ee60-bea5-4622-b89b-a63319d10b3a',
'defaultLangcode' => array(LanguageInterface::LANGCODE_DEFAULT => 'en'),
Alex Pott
committed
);
Alex Pott
committed
$this->entityTypeId = $this->randomMachineName();
$this->bundle = $this->randomMachineName();
Alex Pott
committed
$this->entityType = $this->getMock('\Drupal\Core\Entity\EntityTypeInterface');
Alex Pott
committed
$this->entityType->expects($this->any())
->method('getKeys')
->will($this->returnValue(array(
'id' => 'id',
'uuid' => 'uuid',
)));
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->typedDataManager = $this->getMock(TypedDataManagerInterface::class);
Angie Byron
committed
$this->typedDataManager->expects($this->any())
->method('getDefinition')
->with('entity')
->will($this->returnValue(['class' => '\Drupal\Core\Entity\Plugin\DataType\EntityAdapter']));
Alex Pott
committed
$english = new Language(array('id' => 'en'));
$not_specified = new Language(array('id' => LanguageInterface::LANGCODE_NOT_SPECIFIED, 'locked' => TRUE));
Alex Pott
committed
$this->languageManager = $this->getMock('\Drupal\Core\Language\LanguageManagerInterface');
$this->languageManager->expects($this->any())
->method('getLanguages')
->will($this->returnValue(array('en' => $english, LanguageInterface::LANGCODE_NOT_SPECIFIED => $not_specified)));
Alex Pott
committed
$this->languageManager->expects($this->any())
->method('getLanguage')
->with('en')
->will($this->returnValue($english));
$this->languageManager->expects($this->any())
->method('getLanguage')
->with(LanguageInterface::LANGCODE_NOT_SPECIFIED)
->will($this->returnValue($not_specified));
Alex Pott
committed
catch
committed
$this->fieldTypePluginManager = $this->getMockBuilder('\Drupal\Core\Field\FieldTypePluginManager')
->disableOriginalConstructor()
->getMock();
$this->fieldTypePluginManager->expects($this->any())
->method('getDefaultStorageSettings')
catch
committed
->will($this->returnValue(array()));
$this->fieldTypePluginManager->expects($this->any())
->method('getDefaultFieldSettings')
catch
committed
->will($this->returnValue(array()));
Alex Pott
committed
$this->fieldTypePluginManager->expects($this->any())
->method('createFieldItemList')
->will($this->returnValue($this->getMock('Drupal\Core\Field\FieldItemListInterface')));
catch
committed
Alex Pott
committed
$container = new ContainerBuilder();
$container->set('entity.manager', $this->entityManager);
$container->set('uuid', $this->uuid);
$container->set('typed_data_manager', $this->typedDataManager);
$container->set('language_manager', $this->languageManager);
catch
committed
$container->set('plugin.manager.field.field_type', $this->fieldTypePluginManager);
Alex Pott
committed
\Drupal::setContainer($container);
Alex Pott
committed
$this->fieldDefinitions = array(
Alex Pott
committed
'id' => BaseFieldDefinition::create('integer'),
'revision_id' => BaseFieldDefinition::create('integer'),
catch
committed
);
$this->entityManager->expects($this->any())
->method('getFieldDefinitions')
->with($this->entityTypeId, $this->bundle)
Alex Pott
committed
->will($this->returnValue($this->fieldDefinitions));
Alex Pott
committed
$this->entity = $this->getMockForAbstractClass('\Drupal\Core\Entity\ContentEntityBase', array($values, $this->entityTypeId, $this->bundle));
$values['defaultLangcode'] = array(LanguageInterface::LANGCODE_DEFAULT => LanguageInterface::LANGCODE_NOT_SPECIFIED);
$this->entityUnd = $this->getMockForAbstractClass('\Drupal\Core\Entity\ContentEntityBase', array($values, $this->entityTypeId, $this->bundle));
Alex Pott
committed
}
/**
* @covers ::isNewRevision
* @covers ::setNewRevision
*/
public function testIsNewRevision() {
// Set up the entity type so that on the first call there is no revision key
// and on the second call there is one.
$this->entityType->expects($this->at(0))
->method('hasKey')
->with('revision')
->will($this->returnValue(FALSE));
$this->entityType->expects($this->at(1))
->method('hasKey')
->with('revision')
->will($this->returnValue(TRUE));
catch
committed
$this->entityType->expects($this->at(2))
->method('hasKey')
->with('revision')
->will($this->returnValue(TRUE));
$this->entityType->expects($this->at(3))
->method('getKey')
->with('revision')
->will($this->returnValue('revision_id'));
Alex Pott
committed
$this->entityType->expects($this->at(4))
->method('hasKey')
->with('revision')
->will($this->returnValue(TRUE));
$this->entityType->expects($this->at(5))
->method('getKey')
->with('revision')
->will($this->returnValue('revision_id'));
catch
committed
$field_item_list = $this->getMockBuilder('\Drupal\Core\Field\FieldItemList')
->disableOriginalConstructor()
->getMock();
Alex Pott
committed
$field_item = $this->getMockBuilder('\Drupal\Core\Field\FieldItemBase')
->disableOriginalConstructor()
->getMockForAbstractClass();
Alex Pott
committed
Alex Pott
committed
$this->fieldTypePluginManager->expects($this->any())
->method('createFieldItemList')
->with($this->entity, 'revision_id', NULL)
catch
committed
->will($this->returnValue($field_item_list));
Alex Pott
committed
Alex Pott
committed
$this->fieldDefinitions['revision_id']->getItemDefinition()->setClass(get_class($field_item));
Alex Pott
committed
$this->assertFalse($this->entity->isNewRevision());
$this->assertTrue($this->entity->isNewRevision());
$this->entity->setNewRevision(TRUE);
$this->assertTRUE($this->entity->isNewRevision());
}
Alex Pott
committed
/**
* @covers ::setNewRevision
*/
public function testSetNewRevisionException() {
$this->entityType->expects($this->once())
->method('hasKey')
->with('revision')
->will($this->returnValue(FALSE));
$this->setExpectedException('LogicException', 'Entity type ' . $this->entityTypeId . ' does not support revisions.');
$this->entity->setNewRevision();
}
Alex Pott
committed
/**
* @covers ::isDefaultRevision
*/
public function testIsDefaultRevision() {
// The default value is TRUE.
$this->assertTrue($this->entity->isDefaultRevision());
// Change the default revision, verify that the old value is returned.
$this->assertTrue($this->entity->isDefaultRevision(FALSE));
// The last call changed the return value for this call.
$this->assertFalse($this->entity->isDefaultRevision());
}
/**
* @covers ::getRevisionId
*/
public function testGetRevisionId() {
// The default getRevisionId() implementation returns NULL.
$this->assertNull($this->entity->getRevisionId());
}
/**
* @covers ::isTranslatable
*/
public function testIsTranslatable() {
$this->entityManager->expects($this->any())
Alex Pott
committed
->method('getBundleInfo')
->with($this->entityTypeId)
->will($this->returnValue(array(
$this->bundle => array(
'translatable' => TRUE,
),
)));
$this->languageManager->expects($this->any())
->method('isMultilingual')
->will($this->returnValue(TRUE));
$this->assertTrue($this->entity->language()->getId() == 'en');
Alex Pott
committed
$this->assertFalse($this->entity->language()->isLocked());
Alex Pott
committed
$this->assertTrue($this->entity->isTranslatable());
$this->assertTrue($this->entityUnd->language()->getId() == LanguageInterface::LANGCODE_NOT_SPECIFIED);
Alex Pott
committed
$this->assertTrue($this->entityUnd->language()->isLocked());
$this->assertFalse($this->entityUnd->isTranslatable());
}
/**
* @covers ::isTranslatable
*/
public function testIsTranslatableForMonolingual() {
$this->languageManager->expects($this->any())
->method('isMultilingual')
->will($this->returnValue(FALSE));
Alex Pott
committed
$this->assertFalse($this->entity->isTranslatable());
}
/**
* @covers ::preSaveRevision
*/
public function testPreSaveRevision() {
// This method is internal, so check for errors on calling it only.
catch
committed
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
Alex Pott
committed
$record = new \stdClass();
// Our mocked entity->preSaveRevision() returns NULL, so assert that.
$this->assertNull($this->entity->preSaveRevision($storage, $record));
Alex Pott
committed
}
/**
* @covers ::validate
*/
public function testValidate() {
$validator = $this->getMock(ValidatorInterface::class);
Alex Pott
committed
/** @var \Symfony\Component\Validator\ConstraintViolationList|\PHPUnit_Framework_MockObject_MockObject $empty_violation_list */
$empty_violation_list = $this->getMockBuilder('\Symfony\Component\Validator\ConstraintViolationList')
->setMethods(NULL)
->getMock();
$non_empty_violation_list = clone $empty_violation_list;
$violation = $this->getMock('\Symfony\Component\Validator\ConstraintViolationInterface');
$non_empty_violation_list->add($violation);
$validator->expects($this->at(0))
->method('validate')
Angie Byron
committed
->with($this->entity->getTypedData())
Alex Pott
committed
->will($this->returnValue($empty_violation_list));
$validator->expects($this->at(1))
->method('validate')
Angie Byron
committed
->with($this->entity->getTypedData())
Alex Pott
committed
->will($this->returnValue($non_empty_violation_list));
$this->typedDataManager->expects($this->exactly(2))
->method('getValidator')
->will($this->returnValue($validator));
$this->assertSame(0, count($this->entity->validate()));
$this->assertSame(1, count($this->entity->validate()));
}
/**
* Tests required validation.
*
* @covers ::validate
* @covers ::isValidationRequired
* @covers ::setValidationRequired
* @covers ::save
* @covers ::preSave
*
* @expectedException \LogicException
* @expectedExceptionMessage Entity validation was skipped.
*/
public function testRequiredValidation() {
$validator = $this->getMock(ValidatorInterface::class);
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
/** @var \Symfony\Component\Validator\ConstraintViolationList|\PHPUnit_Framework_MockObject_MockObject $empty_violation_list */
$empty_violation_list = $this->getMockBuilder('\Symfony\Component\Validator\ConstraintViolationList')
->setMethods(NULL)
->getMock();
$validator->expects($this->at(0))
->method('validate')
->with($this->entity->getTypedData())
->will($this->returnValue($empty_violation_list));
$this->typedDataManager->expects($this->any())
->method('getValidator')
->will($this->returnValue($validator));
/** @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit_Framework_MockObject_MockObject $storage */
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
$storage->expects($this->any())
->method('save')
->willReturnCallback(function (ContentEntityInterface $entity) use ($storage) {
$entity->preSave($storage);
});
$this->entityManager->expects($this->any())
->method('getStorage')
->with($this->entityTypeId)
->will($this->returnValue($storage));
// Check that entities can be saved normally when validation is not
// required.
$this->assertFalse($this->entity->isValidationRequired());
$this->entity->save();
// Make validation required and check that if the entity is validated, it
// can be saved normally.
$this->entity->setValidationRequired(TRUE);
$this->assertTrue($this->entity->isValidationRequired());
$this->entity->validate();
$this->entity->save();
// Check that the "validated" status is reset after saving the entity and
// that trying to save a non-validated entity when validation is required
// results in an exception.
$this->assertTrue($this->entity->isValidationRequired());
$this->entity->save();
}
Alex Pott
committed
/**
* @covers ::bundle
*/
public function testBundle() {
$this->assertSame($this->bundle, $this->entity->bundle());
}
/**
* @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)
->will($this->returnValue(TRUE));
$access->expects($this->at(1))
catch
committed
->method('access')
->with($this->entity, $operation)
->will($this->returnValue(AccessResult::allowed()));
$access->expects($this->at(2))
Alex Pott
committed
->method('createAccess')
->will($this->returnValue(TRUE));
catch
committed
$access->expects($this->at(3))
->method('createAccess')
->will($this->returnValue(AccessResult::allowed()));
$this->entityManager->expects($this->exactly(4))
->method('getAccessControlHandler')
Alex Pott
committed
->will($this->returnValue($access));
$this->assertTrue($this->entity->access($operation));
catch
committed
$this->assertEquals(AccessResult::allowed(), $this->entity->access($operation, NULL, TRUE));
Alex Pott
committed
$this->assertTrue($this->entity->access('create'));
catch
committed
$this->assertEquals(AccessResult::allowed(), $this->entity->access('create', NULL, TRUE));
Alex Pott
committed
}
/**
* @covers ::label
*/
public function testLabel() {
// Make a mock with one method that we use as the entity's label 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();
Alex Pott
committed
$callback_container = $this->getMock(get_class());
$callback_container->expects($this->once())
->method(__FUNCTION__)
->will($this->returnValue($callback_label));
$this->entityType->expects($this->once())
->method('getLabelCallback')
->will($this->returnValue(array($callback_container, __FUNCTION__)));
$this->assertSame($callback_label, $this->entity->label());
}
Angie Byron
committed
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
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
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
/**
* Data provider for testGet().
*
* @returns
* - Expected output from get().
* - Field name parameter to get().
* - Language code for $activeLanguage.
* - Fields array for $fields.
*/
public function providerGet() {
return [
// Populated fields array.
['result', 'field_name', 'langcode', ['field_name' => ['langcode' => 'result']]],
// Incomplete fields array.
['getTranslatedField_result', 'field_name', 'langcode', ['field_name' => 'no_langcode']],
// Empty fields array.
['getTranslatedField_result', 'field_name', 'langcode', []],
];
}
/**
* @covers ::get
* @dataProvider providerGet
*/
public function testGet($expected, $field_name, $active_langcode, $fields) {
// Mock ContentEntityBase.
$mock_base = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase')
->disableOriginalConstructor()
->setMethods(array('getTranslatedField'))
->getMockForAbstractClass();
// Set up expectations for getTranslatedField() method. In get(),
// getTranslatedField() is only called if the field name and language code
// are not present as keys in the fields array.
if (isset($fields[$field_name][$active_langcode])) {
$mock_base->expects($this->never())
->method('getTranslatedField');
}
else {
$mock_base->expects($this->once())
->method('getTranslatedField')
->with(
$this->equalTo($field_name),
$this->equalTo($active_langcode)
)
->willReturn($expected);
}
// Poke in activeLangcode.
$ref_langcode = new \ReflectionProperty($mock_base, 'activeLangcode');
$ref_langcode->setAccessible(TRUE);
$ref_langcode->setValue($mock_base, $active_langcode);
// Poke in fields.
$ref_fields = new \ReflectionProperty($mock_base, 'fields');
$ref_fields->setAccessible(TRUE);
$ref_fields->setValue($mock_base, $fields);
// Exercise get().
$this->assertEquals($expected, $mock_base->get($field_name));
}
/**
* Data provider for testGetFields().
*
* @returns array
* - Expected output from getFields().
* - $include_computed value to pass to getFields().
* - Value to mock from all field definitions for isComputed().
* - Array of field names to return from mocked getFieldDefinitions(). A
* Drupal\Core\Field\FieldDefinitionInterface object will be mocked for
* each name.
*/
public function providerGetFields() {
return [
[[], FALSE, FALSE, []],
[['field' => 'field', 'field2' => 'field2'], TRUE, FALSE, ['field', 'field2']],
[['field3' => 'field3'], TRUE, TRUE, ['field3']],
[[], FALSE, TRUE, ['field4']],
];
}
/**
* @covers ::getFields
* @dataProvider providerGetFields
*/
public function testGetFields($expected, $include_computed, $is_computed, $field_definitions) {
// Mock ContentEntityBase.
$mock_base = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase')
->disableOriginalConstructor()
->setMethods(array('getFieldDefinitions', 'get'))
->getMockForAbstractClass();
// Mock field definition objects for each element of $field_definitions.
$mocked_field_definitions = array();
foreach ($field_definitions as $name) {
$mock_definition = $this->getMockBuilder('Drupal\Core\Field\FieldDefinitionInterface')
->setMethods(array('isComputed'))
->getMockForAbstractClass();
// Set expectations for isComputed(). isComputed() gets called whenever
// $include_computed is FALSE, but not otherwise. It returns the value of
// $is_computed.
$mock_definition->expects($this->exactly(
$include_computed ? 0 : 1
))
->method('isComputed')
->willReturn($is_computed);
$mocked_field_definitions[$name] = $mock_definition;
}
// Set up expectations for getFieldDefinitions().
$mock_base->expects($this->once())
->method('getFieldDefinitions')
->willReturn($mocked_field_definitions);
// How many time will we call get()? Since we are rigging all defined fields
// to be computed based on $is_computed, then if $include_computed is FALSE,
// get() will never be called.
$get_count = 0;
if ($include_computed) {
$get_count = count($field_definitions);
}
// Set up expectations for get(). It simply returns the name passed in.
$mock_base->expects($this->exactly($get_count))
->method('get')
->willReturnArgument(0);
// Exercise getFields().
$this->assertArrayEquals(
$expected,
$mock_base->getFields($include_computed)
);
}
Alex Pott
committed
/**
* @covers ::set
*/
public function testSet() {
// Exercise set(), check if it returns $this
$this->assertSame(
$this->entity,
$this->entity->set('id', 0)
);
}