ContentEntityBaseUnitTest.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. <?php
  2. namespace Drupal\Tests\Core\Entity;
  3. use Drupal\Core\Access\AccessResult;
  4. use Drupal\Core\DependencyInjection\ContainerBuilder;
  5. use Drupal\Core\Entity\ContentEntityBase;
  6. use Drupal\Core\Entity\ContentEntityInterface;
  7. use Drupal\Core\Entity\EntityFieldManagerInterface;
  8. use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
  9. use Drupal\Core\Entity\EntityTypeManagerInterface;
  10. use Drupal\Core\Field\BaseFieldDefinition;
  11. use Drupal\Core\Language\LanguageInterface;
  12. use Drupal\Core\TypedData\TypedDataManagerInterface;
  13. use Drupal\Tests\Traits\ExpectDeprecationTrait;
  14. use Drupal\Tests\UnitTestCase;
  15. use Drupal\Core\Language\Language;
  16. use Symfony\Component\Validator\Validator\ValidatorInterface;
  17. /**
  18. * @coversDefaultClass \Drupal\Core\Entity\ContentEntityBase
  19. * @group Entity
  20. * @group Access
  21. */
  22. class ContentEntityBaseUnitTest extends UnitTestCase {
  23. use ExpectDeprecationTrait;
  24. /**
  25. * The bundle of the entity under test.
  26. *
  27. * @var string
  28. */
  29. protected $bundle;
  30. /**
  31. * The entity under test.
  32. *
  33. * @var \Drupal\Core\Entity\ContentEntityBase|\PHPUnit\Framework\MockObject\MockObject
  34. */
  35. protected $entity;
  36. /**
  37. * An entity with no defined language to test.
  38. *
  39. * @var \Drupal\Core\Entity\ContentEntityBase|\PHPUnit\Framework\MockObject\MockObject
  40. */
  41. protected $entityUnd;
  42. /**
  43. * The entity type used for testing.
  44. *
  45. * @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit\Framework\MockObject\MockObject
  46. */
  47. protected $entityType;
  48. /**
  49. * The entity field manager used for testing.
  50. *
  51. * @var \Drupal\Core\Entity\EntityFieldManagerInterface|\PHPUnit\Framework\MockObject\MockObject
  52. */
  53. protected $entityFieldManager;
  54. /**
  55. * The entity type bundle manager used for testing.
  56. *
  57. * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface|\PHPUnit\Framework\MockObject\MockObject
  58. */
  59. protected $entityTypeBundleInfo;
  60. /**
  61. * The entity type manager used for testing.
  62. *
  63. * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
  64. */
  65. protected $entityTypeManager;
  66. /**
  67. * The type ID of the entity under test.
  68. *
  69. * @var string
  70. */
  71. protected $entityTypeId;
  72. /**
  73. * The typed data manager used for testing.
  74. *
  75. * @var \Drupal\Core\TypedData\TypedDataManager|\PHPUnit\Framework\MockObject\MockObject
  76. */
  77. protected $typedDataManager;
  78. /**
  79. * The field type manager used for testing.
  80. *
  81. * @var \Drupal\Core\Field\FieldTypePluginManager|\PHPUnit\Framework\MockObject\MockObject
  82. */
  83. protected $fieldTypePluginManager;
  84. /**
  85. * The language manager.
  86. *
  87. * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit\Framework\MockObject\MockObject
  88. */
  89. protected $languageManager;
  90. /**
  91. * The UUID generator used for testing.
  92. *
  93. * @var \Drupal\Component\Uuid\UuidInterface|\PHPUnit\Framework\MockObject\MockObject
  94. */
  95. protected $uuid;
  96. /**
  97. * The entity ID.
  98. *
  99. * @var int
  100. */
  101. protected $id;
  102. /**
  103. * Field definitions.
  104. *
  105. * @var \Drupal\Core\Field\BaseFieldDefinition[]
  106. */
  107. protected $fieldDefinitions;
  108. /**
  109. * {@inheritdoc}
  110. */
  111. protected function setUp() {
  112. $this->id = 1;
  113. $values = [
  114. 'id' => $this->id,
  115. 'uuid' => '3bb9ee60-bea5-4622-b89b-a63319d10b3a',
  116. 'defaultLangcode' => [LanguageInterface::LANGCODE_DEFAULT => 'en'],
  117. ];
  118. $this->entityTypeId = $this->randomMachineName();
  119. $this->bundle = $this->randomMachineName();
  120. $this->entityType = $this->createMock('\Drupal\Core\Entity\EntityTypeInterface');
  121. $this->entityType->expects($this->any())
  122. ->method('getKeys')
  123. ->will($this->returnValue([
  124. 'id' => 'id',
  125. 'uuid' => 'uuid',
  126. ]));
  127. $this->entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);
  128. $this->entityTypeManager->expects($this->any())
  129. ->method('getDefinition')
  130. ->with($this->entityTypeId)
  131. ->will($this->returnValue($this->entityType));
  132. $this->entityFieldManager = $this->createMock(EntityFieldManagerInterface::class);
  133. $this->entityTypeBundleInfo = $this->createMock(EntityTypeBundleInfoInterface::class);
  134. $this->uuid = $this->createMock('\Drupal\Component\Uuid\UuidInterface');
  135. $this->typedDataManager = $this->createMock(TypedDataManagerInterface::class);
  136. $this->typedDataManager->expects($this->any())
  137. ->method('getDefinition')
  138. ->with('entity')
  139. ->will($this->returnValue(['class' => '\Drupal\Core\Entity\Plugin\DataType\EntityAdapter']));
  140. $english = new Language(['id' => 'en']);
  141. $not_specified = new Language(['id' => LanguageInterface::LANGCODE_NOT_SPECIFIED, 'locked' => TRUE]);
  142. $this->languageManager = $this->createMock('\Drupal\Core\Language\LanguageManagerInterface');
  143. $this->languageManager->expects($this->any())
  144. ->method('getLanguages')
  145. ->will($this->returnValue(['en' => $english, LanguageInterface::LANGCODE_NOT_SPECIFIED => $not_specified]));
  146. $this->languageManager->expects($this->any())
  147. ->method('getLanguage')
  148. ->with('en')
  149. ->will($this->returnValue($english));
  150. $this->languageManager->expects($this->any())
  151. ->method('getLanguage')
  152. ->with(LanguageInterface::LANGCODE_NOT_SPECIFIED)
  153. ->will($this->returnValue($not_specified));
  154. $this->fieldTypePluginManager = $this->getMockBuilder('\Drupal\Core\Field\FieldTypePluginManager')
  155. ->disableOriginalConstructor()
  156. ->getMock();
  157. $this->fieldTypePluginManager->expects($this->any())
  158. ->method('getDefaultStorageSettings')
  159. ->will($this->returnValue([]));
  160. $this->fieldTypePluginManager->expects($this->any())
  161. ->method('getDefaultFieldSettings')
  162. ->will($this->returnValue([]));
  163. $this->fieldTypePluginManager->expects($this->any())
  164. ->method('createFieldItemList')
  165. ->will($this->returnValue($this->createMock('Drupal\Core\Field\FieldItemListInterface')));
  166. $container = new ContainerBuilder();
  167. $container->set('entity_field.manager', $this->entityFieldManager);
  168. $container->set('entity_type.bundle.info', $this->entityTypeBundleInfo);
  169. $container->set('entity_type.manager', $this->entityTypeManager);
  170. $container->set('uuid', $this->uuid);
  171. $container->set('typed_data_manager', $this->typedDataManager);
  172. $container->set('language_manager', $this->languageManager);
  173. $container->set('plugin.manager.field.field_type', $this->fieldTypePluginManager);
  174. \Drupal::setContainer($container);
  175. $this->fieldDefinitions = [
  176. 'id' => BaseFieldDefinition::create('integer'),
  177. 'revision_id' => BaseFieldDefinition::create('integer'),
  178. ];
  179. $this->entityFieldManager->expects($this->any())
  180. ->method('getFieldDefinitions')
  181. ->with($this->entityTypeId, $this->bundle)
  182. ->will($this->returnValue($this->fieldDefinitions));
  183. $this->entity = $this->getMockForAbstractClass(ContentEntityBase::class, [$values, $this->entityTypeId, $this->bundle], '', TRUE, TRUE, TRUE, ['isNew']);
  184. $values['defaultLangcode'] = [LanguageInterface::LANGCODE_DEFAULT => LanguageInterface::LANGCODE_NOT_SPECIFIED];
  185. $this->entityUnd = $this->getMockForAbstractClass(ContentEntityBase::class, [$values, $this->entityTypeId, $this->bundle]);
  186. }
  187. /**
  188. * @covers ::isNewRevision
  189. * @covers ::setNewRevision
  190. */
  191. public function testIsNewRevision() {
  192. // Set up the entity type so that on the first call there is no revision key
  193. // and on the second call there is one.
  194. $this->entityType->expects($this->at(0))
  195. ->method('hasKey')
  196. ->with('revision')
  197. ->will($this->returnValue(FALSE));
  198. $this->entityType->expects($this->at(1))
  199. ->method('hasKey')
  200. ->with('revision')
  201. ->will($this->returnValue(TRUE));
  202. $this->entityType->expects($this->at(2))
  203. ->method('hasKey')
  204. ->with('revision')
  205. ->will($this->returnValue(TRUE));
  206. $this->entityType->expects($this->at(3))
  207. ->method('getKey')
  208. ->with('revision')
  209. ->will($this->returnValue('revision_id'));
  210. $this->entityType->expects($this->at(4))
  211. ->method('hasKey')
  212. ->with('revision')
  213. ->will($this->returnValue(TRUE));
  214. $this->entityType->expects($this->at(5))
  215. ->method('getKey')
  216. ->with('revision')
  217. ->will($this->returnValue('revision_id'));
  218. $field_item_list = $this->getMockBuilder('\Drupal\Core\Field\FieldItemList')
  219. ->disableOriginalConstructor()
  220. ->getMock();
  221. $field_item = $this->getMockBuilder('\Drupal\Core\Field\FieldItemBase')
  222. ->disableOriginalConstructor()
  223. ->getMockForAbstractClass();
  224. $this->fieldTypePluginManager->expects($this->any())
  225. ->method('createFieldItemList')
  226. ->with($this->entity, 'revision_id', NULL)
  227. ->will($this->returnValue($field_item_list));
  228. $this->fieldDefinitions['revision_id']->getItemDefinition()->setClass(get_class($field_item));
  229. $this->assertFalse($this->entity->isNewRevision());
  230. $this->assertTrue($this->entity->isNewRevision());
  231. $this->entity->setNewRevision(TRUE);
  232. $this->assertTrue($this->entity->isNewRevision());
  233. }
  234. /**
  235. * @covers ::setNewRevision
  236. */
  237. public function testSetNewRevisionException() {
  238. $this->entityType->expects($this->once())
  239. ->method('hasKey')
  240. ->with('revision')
  241. ->will($this->returnValue(FALSE));
  242. $this->expectException('LogicException');
  243. $this->expectExceptionMessage('Entity type ' . $this->entityTypeId . ' does not support revisions.');
  244. $this->entity->setNewRevision();
  245. }
  246. /**
  247. * @covers ::isDefaultRevision
  248. */
  249. public function testIsDefaultRevision() {
  250. // The default value is TRUE.
  251. $this->assertTrue($this->entity->isDefaultRevision());
  252. // Change the default revision, verify that the old value is returned.
  253. $this->assertTrue($this->entity->isDefaultRevision(FALSE));
  254. // The last call changed the return value for this call.
  255. $this->assertFalse($this->entity->isDefaultRevision());
  256. // The revision for a new entity should always be the default revision.
  257. $this->entity->expects($this->any())
  258. ->method('isNew')
  259. ->will($this->returnValue(TRUE));
  260. $this->entity->isDefaultRevision(FALSE);
  261. $this->assertTrue($this->entity->isDefaultRevision());
  262. }
  263. /**
  264. * @covers ::getRevisionId
  265. */
  266. public function testGetRevisionId() {
  267. // The default getRevisionId() implementation returns NULL.
  268. $this->assertNull($this->entity->getRevisionId());
  269. }
  270. /**
  271. * @covers ::isTranslatable
  272. */
  273. public function testIsTranslatable() {
  274. $this->entityTypeBundleInfo->expects($this->any())
  275. ->method('getBundleInfo')
  276. ->with($this->entityTypeId)
  277. ->will($this->returnValue([
  278. $this->bundle => [
  279. 'translatable' => TRUE,
  280. ],
  281. ]));
  282. $this->languageManager->expects($this->any())
  283. ->method('isMultilingual')
  284. ->will($this->returnValue(TRUE));
  285. $this->assertTrue($this->entity->language()->getId() == 'en');
  286. $this->assertFalse($this->entity->language()->isLocked());
  287. $this->assertTrue($this->entity->isTranslatable());
  288. $this->assertTrue($this->entityUnd->language()->getId() == LanguageInterface::LANGCODE_NOT_SPECIFIED);
  289. $this->assertTrue($this->entityUnd->language()->isLocked());
  290. $this->assertFalse($this->entityUnd->isTranslatable());
  291. }
  292. /**
  293. * @covers ::isTranslatable
  294. */
  295. public function testIsTranslatableForMonolingual() {
  296. $this->languageManager->expects($this->any())
  297. ->method('isMultilingual')
  298. ->will($this->returnValue(FALSE));
  299. $this->assertFalse($this->entity->isTranslatable());
  300. }
  301. /**
  302. * @covers ::preSaveRevision
  303. */
  304. public function testPreSaveRevision() {
  305. // This method is internal, so check for errors on calling it only.
  306. $storage = $this->createMock('\Drupal\Core\Entity\EntityStorageInterface');
  307. $record = new \stdClass();
  308. // Our mocked entity->preSaveRevision() returns NULL, so assert that.
  309. $this->assertNull($this->entity->preSaveRevision($storage, $record));
  310. }
  311. /**
  312. * @covers ::validate
  313. */
  314. public function testValidate() {
  315. $validator = $this->createMock(ValidatorInterface::class);
  316. /** @var \Symfony\Component\Validator\ConstraintViolationList|\PHPUnit\Framework\MockObject\MockObject $empty_violation_list */
  317. $empty_violation_list = $this->getMockBuilder('\Symfony\Component\Validator\ConstraintViolationList')
  318. ->setMethods(NULL)
  319. ->getMock();
  320. $non_empty_violation_list = clone $empty_violation_list;
  321. $violation = $this->createMock('\Symfony\Component\Validator\ConstraintViolationInterface');
  322. $non_empty_violation_list->add($violation);
  323. $validator->expects($this->at(0))
  324. ->method('validate')
  325. ->with($this->entity->getTypedData())
  326. ->will($this->returnValue($empty_violation_list));
  327. $validator->expects($this->at(1))
  328. ->method('validate')
  329. ->with($this->entity->getTypedData())
  330. ->will($this->returnValue($non_empty_violation_list));
  331. $this->typedDataManager->expects($this->exactly(2))
  332. ->method('getValidator')
  333. ->will($this->returnValue($validator));
  334. $this->assertCount(0, $this->entity->validate());
  335. $this->assertCount(1, $this->entity->validate());
  336. }
  337. /**
  338. * Tests required validation.
  339. *
  340. * @covers ::validate
  341. * @covers ::isValidationRequired
  342. * @covers ::setValidationRequired
  343. * @covers ::save
  344. * @covers ::preSave
  345. */
  346. public function testRequiredValidation() {
  347. $validator = $this->createMock(ValidatorInterface::class);
  348. /** @var \Symfony\Component\Validator\ConstraintViolationList|\PHPUnit\Framework\MockObject\MockObject $empty_violation_list */
  349. $empty_violation_list = $this->getMockBuilder('\Symfony\Component\Validator\ConstraintViolationList')
  350. ->setMethods(NULL)
  351. ->getMock();
  352. $validator->expects($this->at(0))
  353. ->method('validate')
  354. ->with($this->entity->getTypedData())
  355. ->will($this->returnValue($empty_violation_list));
  356. $this->typedDataManager->expects($this->any())
  357. ->method('getValidator')
  358. ->will($this->returnValue($validator));
  359. /** @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit\Framework\MockObject\MockObject $storage */
  360. $storage = $this->createMock('\Drupal\Core\Entity\EntityStorageInterface');
  361. $storage->expects($this->any())
  362. ->method('save')
  363. ->willReturnCallback(function (ContentEntityInterface $entity) use ($storage) {
  364. $entity->preSave($storage);
  365. });
  366. $this->entityTypeManager->expects($this->any())
  367. ->method('getStorage')
  368. ->with($this->entityTypeId)
  369. ->will($this->returnValue($storage));
  370. // Check that entities can be saved normally when validation is not
  371. // required.
  372. $this->assertFalse($this->entity->isValidationRequired());
  373. $this->entity->save();
  374. // Make validation required and check that if the entity is validated, it
  375. // can be saved normally.
  376. $this->entity->setValidationRequired(TRUE);
  377. $this->assertTrue($this->entity->isValidationRequired());
  378. $this->entity->validate();
  379. $this->entity->save();
  380. // Check that the "validated" status is reset after saving the entity and
  381. // that trying to save a non-validated entity when validation is required
  382. // results in an exception.
  383. $this->assertTrue($this->entity->isValidationRequired());
  384. $this->expectException(\LogicException::class);
  385. $this->expectExceptionMessage('Entity validation was skipped.');
  386. $this->entity->save();
  387. }
  388. /**
  389. * @covers ::bundle
  390. */
  391. public function testBundle() {
  392. $this->assertSame($this->bundle, $this->entity->bundle());
  393. }
  394. /**
  395. * @covers ::access
  396. */
  397. public function testAccess() {
  398. $access = $this->createMock('\Drupal\Core\Entity\EntityAccessControlHandlerInterface');
  399. $operation = $this->randomMachineName();
  400. $access->expects($this->at(0))
  401. ->method('access')
  402. ->with($this->entity, $operation)
  403. ->will($this->returnValue(TRUE));
  404. $access->expects($this->at(1))
  405. ->method('access')
  406. ->with($this->entity, $operation)
  407. ->will($this->returnValue(AccessResult::allowed()));
  408. $access->expects($this->at(2))
  409. ->method('createAccess')
  410. ->will($this->returnValue(TRUE));
  411. $access->expects($this->at(3))
  412. ->method('createAccess')
  413. ->will($this->returnValue(AccessResult::allowed()));
  414. $this->entityTypeManager->expects($this->exactly(4))
  415. ->method('getAccessControlHandler')
  416. ->will($this->returnValue($access));
  417. $this->assertTrue($this->entity->access($operation));
  418. $this->assertEquals(AccessResult::allowed(), $this->entity->access($operation, NULL, TRUE));
  419. $this->assertTrue($this->entity->access('create'));
  420. $this->assertEquals(AccessResult::allowed(), $this->entity->access('create', NULL, TRUE));
  421. }
  422. /**
  423. * @covers ::label
  424. *
  425. * @group legacy
  426. */
  427. public function testLabel() {
  428. $this->addExpectedDeprecationMessage('Entity type ' . $this->entityTypeId . ' defines a label callback. Support for that is deprecated in drupal:8.0.0 and will be removed in drupal:9.0.0. Override the EntityInterface::label() method instead. See https://www.drupal.org/node/3050794');
  429. // Make a mock with one method that we use as the entity's label callback.
  430. // We check that it is called, and that the entity's label is the callback's
  431. // return value.
  432. $callback_label = $this->randomMachineName();
  433. $callback_container = $this->createMock(get_class());
  434. $callback_container->expects($this->once())
  435. ->method(__FUNCTION__)
  436. ->will($this->returnValue($callback_label));
  437. $this->entityType->expects($this->once())
  438. ->method('get')
  439. ->with('label_callback')
  440. ->will($this->returnValue([$callback_container, __FUNCTION__]));
  441. $this->assertSame($callback_label, $this->entity->label());
  442. }
  443. /**
  444. * Data provider for testGet().
  445. *
  446. * @returns
  447. * - Expected output from get().
  448. * - Field name parameter to get().
  449. * - Language code for $activeLanguage.
  450. * - Fields array for $fields.
  451. */
  452. public function providerGet() {
  453. return [
  454. // Populated fields array.
  455. ['result', 'field_name', 'langcode', ['field_name' => ['langcode' => 'result']]],
  456. // Incomplete fields array.
  457. ['getTranslatedField_result', 'field_name', 'langcode', ['field_name' => 'no_langcode']],
  458. // Empty fields array.
  459. ['getTranslatedField_result', 'field_name', 'langcode', []],
  460. ];
  461. }
  462. /**
  463. * @covers ::get
  464. * @dataProvider providerGet
  465. */
  466. public function testGet($expected, $field_name, $active_langcode, $fields) {
  467. // Mock ContentEntityBase.
  468. $mock_base = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase')
  469. ->disableOriginalConstructor()
  470. ->setMethods(['getTranslatedField'])
  471. ->getMockForAbstractClass();
  472. // Set up expectations for getTranslatedField() method. In get(),
  473. // getTranslatedField() is only called if the field name and language code
  474. // are not present as keys in the fields array.
  475. if (isset($fields[$field_name][$active_langcode])) {
  476. $mock_base->expects($this->never())
  477. ->method('getTranslatedField');
  478. }
  479. else {
  480. $mock_base->expects($this->once())
  481. ->method('getTranslatedField')
  482. ->with(
  483. $this->equalTo($field_name),
  484. $this->equalTo($active_langcode)
  485. )
  486. ->willReturn($expected);
  487. }
  488. // Poke in activeLangcode.
  489. $ref_langcode = new \ReflectionProperty($mock_base, 'activeLangcode');
  490. $ref_langcode->setAccessible(TRUE);
  491. $ref_langcode->setValue($mock_base, $active_langcode);
  492. // Poke in fields.
  493. $ref_fields = new \ReflectionProperty($mock_base, 'fields');
  494. $ref_fields->setAccessible(TRUE);
  495. $ref_fields->setValue($mock_base, $fields);
  496. // Exercise get().
  497. $this->assertEquals($expected, $mock_base->get($field_name));
  498. }
  499. /**
  500. * Data provider for testGetFields().
  501. *
  502. * @returns array
  503. * - Expected output from getFields().
  504. * - $include_computed value to pass to getFields().
  505. * - Value to mock from all field definitions for isComputed().
  506. * - Array of field names to return from mocked getFieldDefinitions(). A
  507. * Drupal\Core\Field\FieldDefinitionInterface object will be mocked for
  508. * each name.
  509. */
  510. public function providerGetFields() {
  511. return [
  512. [[], FALSE, FALSE, []],
  513. [['field' => 'field', 'field2' => 'field2'], TRUE, FALSE, ['field', 'field2']],
  514. [['field3' => 'field3'], TRUE, TRUE, ['field3']],
  515. [[], FALSE, TRUE, ['field4']],
  516. ];
  517. }
  518. /**
  519. * @covers ::getFields
  520. * @dataProvider providerGetFields
  521. */
  522. public function testGetFields($expected, $include_computed, $is_computed, $field_definitions) {
  523. // Mock ContentEntityBase.
  524. $mock_base = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase')
  525. ->disableOriginalConstructor()
  526. ->setMethods(['getFieldDefinitions', 'get'])
  527. ->getMockForAbstractClass();
  528. // Mock field definition objects for each element of $field_definitions.
  529. $mocked_field_definitions = [];
  530. foreach ($field_definitions as $name) {
  531. $mock_definition = $this->getMockBuilder('Drupal\Core\Field\FieldDefinitionInterface')
  532. ->setMethods(['isComputed'])
  533. ->getMockForAbstractClass();
  534. // Set expectations for isComputed(). isComputed() gets called whenever
  535. // $include_computed is FALSE, but not otherwise. It returns the value of
  536. // $is_computed.
  537. $mock_definition->expects($this->exactly(
  538. $include_computed ? 0 : 1
  539. ))
  540. ->method('isComputed')
  541. ->willReturn($is_computed);
  542. $mocked_field_definitions[$name] = $mock_definition;
  543. }
  544. // Set up expectations for getFieldDefinitions().
  545. $mock_base->expects($this->once())
  546. ->method('getFieldDefinitions')
  547. ->willReturn($mocked_field_definitions);
  548. // How many time will we call get()? Since we are rigging all defined fields
  549. // to be computed based on $is_computed, then if $include_computed is FALSE,
  550. // get() will never be called.
  551. $get_count = 0;
  552. if ($include_computed) {
  553. $get_count = count($field_definitions);
  554. }
  555. // Set up expectations for get(). It simply returns the name passed in.
  556. $mock_base->expects($this->exactly($get_count))
  557. ->method('get')
  558. ->willReturnArgument(0);
  559. // Exercise getFields().
  560. $this->assertArrayEquals(
  561. $expected,
  562. $mock_base->getFields($include_computed)
  563. );
  564. }
  565. /**
  566. * @covers ::set
  567. */
  568. public function testSet() {
  569. // Exercise set(), check if it returns $this
  570. $this->assertSame(
  571. $this->entity,
  572. $this->entity->set('id', 0)
  573. );
  574. }
  575. }