1<?php
2
3namespace Drupal\Tests\serialization\Unit\Normalizer;
4
5use Drupal\Core\Entity\EntityFieldManagerInterface;
6use Drupal\Core\Entity\EntityTypeManagerInterface;
7use Drupal\Core\Entity\EntityTypeRepositoryInterface;
8use Drupal\Core\Entity\FieldableEntityInterface;
9use Drupal\Core\Field\FieldItemListInterface;
10use Drupal\serialization\Normalizer\EntityNormalizer;
11use Drupal\Tests\UnitTestCase;
12use Symfony\Component\Serializer\Exception\UnexpectedValueException;
13
14/**
15 * @coversDefaultClass \Drupal\serialization\Normalizer\EntityNormalizer
16 * @group serialization
17 */
18class EntityNormalizerTest extends UnitTestCase {
19
20  /**
21   * The mock entity field manager.
22   *
23   * @var \Drupal\Core\Entity\EntityFieldManagerInterface|\PHPUnit\Framework\MockObject\MockObject
24   */
25  protected $entityFieldManager;
26
27  /**
28   * The mock entity type manager.
29   *
30   * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
31   */
32  protected $entityTypeManager;
33
34  /**
35   * The mock entity type repository.
36   *
37   * @var \Drupal\Core\Entity\EntityTypeRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject
38   */
39  protected $entityTypeRepository;
40
41  /**
42   * The mock serializer.
43   *
44   * @var \Symfony\Component\Serializer\SerializerInterface|\PHPUnit\Framework\MockObject\MockObject
45   */
46  protected $serializer;
47
48  /**
49   * The entity normalizer.
50   *
51   * @var \Drupal\serialization\Normalizer\EntityNormalizer
52   */
53  protected $entityNormalizer;
54
55  /**
56   * {@inheritdoc}
57   */
58  protected function setUp() {
59    $this->entityFieldManager = $this->createMock(EntityFieldManagerInterface::class);
60    $this->entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);
61    $this->entityTypeRepository = $this->createMock(EntityTypeRepositoryInterface::class);
62
63    $this->entityNormalizer = new EntityNormalizer(
64      $this->entityTypeManager,
65      $this->entityTypeRepository,
66      $this->entityFieldManager
67    );
68  }
69
70  /**
71   * Tests the normalize() method.
72   *
73   * @covers ::normalize
74   */
75  public function testNormalize() {
76    $list_item_1 = $this->createMock('Drupal\Core\TypedData\TypedDataInterface');
77    $list_item_2 = $this->createMock('Drupal\Core\TypedData\TypedDataInterface');
78
79    $definitions = [
80      'field_1' => $list_item_1,
81      'field_2' => $list_item_2,
82    ];
83
84    $content_entity = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase')
85      ->disableOriginalConstructor()
86      ->setMethods(['getFields'])
87      ->getMockForAbstractClass();
88    $content_entity->expects($this->once())
89      ->method('getFields')
90      ->will($this->returnValue($definitions));
91
92    $serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer')
93      ->disableOriginalConstructor()
94      ->setMethods(['normalize'])
95      ->getMock();
96    $serializer->expects($this->at(0))
97      ->method('normalize')
98      ->with($list_item_1, 'test_format');
99    $serializer->expects($this->at(1))
100      ->method('normalize')
101      ->with($list_item_2, 'test_format');
102
103    $this->entityNormalizer->setSerializer($serializer);
104
105    $this->entityNormalizer->normalize($content_entity, 'test_format');
106  }
107
108  /**
109   * Tests the denormalize() method with no entity type provided in context.
110   *
111   * @covers ::denormalize
112   */
113  public function testDenormalizeWithNoEntityType() {
114    $this->expectException(UnexpectedValueException::class);
115    $this->entityNormalizer->denormalize([], 'Drupal\Core\Entity\ContentEntityBase');
116  }
117
118  /**
119   * Tests the denormalize method with a bundle property.
120   *
121   * @covers ::denormalize
122   */
123  public function testDenormalizeWithValidBundle() {
124    $test_data = [
125      'key_1' => 'value_1',
126      'key_2' => 'value_2',
127      'test_type' => [
128        ['name' => 'test_bundle'],
129      ],
130    ];
131
132    $entity_type = $this->createMock('Drupal\Core\Entity\EntityTypeInterface');
133
134    $entity_type->expects($this->once())
135      ->method('id')
136      ->willReturn('test');
137    $entity_type->expects($this->once())
138      ->method('hasKey')
139      ->with('bundle')
140      ->will($this->returnValue(TRUE));
141    $entity_type->expects($this->once())
142      ->method('getKey')
143      ->with('bundle')
144      ->will($this->returnValue('test_type'));
145    $entity_type->expects($this->once())
146      ->method('entityClassImplements')
147      ->with(FieldableEntityInterface::class)
148      ->willReturn(TRUE);
149
150    $entity_type->expects($this->once())
151      ->method('getBundleEntityType')
152      ->will($this->returnValue('test_bundle'));
153
154    $entity_type_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
155    $entity_type_storage_definition->expects($this->once())
156      ->method('getMainPropertyName')
157      ->will($this->returnValue('name'));
158
159    $entity_type_definition = $this->createMock('Drupal\Core\Field\FieldDefinitionInterface');
160    $entity_type_definition->expects($this->once())
161      ->method('getFieldStorageDefinition')
162      ->will($this->returnValue($entity_type_storage_definition));
163
164    $base_definitions = [
165      'test_type' => $entity_type_definition,
166    ];
167
168    $this->entityTypeManager->expects($this->at(0))
169      ->method('getDefinition')
170      ->with('test')
171      ->will($this->returnValue($entity_type));
172    $this->entityFieldManager->expects($this->at(0))
173      ->method('getBaseFieldDefinitions')
174      ->with('test')
175      ->will($this->returnValue($base_definitions));
176
177    $entity_query_mock = $this->createMock('Drupal\Core\Entity\Query\QueryInterface');
178    $entity_query_mock->expects($this->once())
179      ->method('execute')
180      ->will($this->returnValue(['test_bundle' => 'test_bundle']));
181
182    $entity_type_storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface');
183    $entity_type_storage->expects($this->once())
184      ->method('getQuery')
185      ->will($this->returnValue($entity_query_mock));
186
187    $this->entityTypeManager->expects($this->at(1))
188      ->method('getStorage')
189      ->with('test_bundle')
190      ->will($this->returnValue($entity_type_storage));
191
192    $key_1 = $this->createMock(FieldItemListInterface::class);
193    $key_2 = $this->createMock(FieldItemListInterface::class);
194
195    $entity = $this->createMock(FieldableEntityInterface::class);
196    $entity->expects($this->at(0))
197      ->method('get')
198      ->with('key_1')
199      ->willReturn($key_1);
200    $entity->expects($this->at(1))
201      ->method('get')
202      ->with('key_2')
203      ->willReturn($key_2);
204
205    $storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface');
206    // Create should only be called with the bundle property at first.
207    $expected_test_data = [
208      'test_type' => 'test_bundle',
209    ];
210
211    $storage->expects($this->once())
212      ->method('create')
213      ->with($expected_test_data)
214      ->will($this->returnValue($entity));
215
216    $this->entityTypeManager->expects($this->at(2))
217      ->method('getStorage')
218      ->with('test')
219      ->will($this->returnValue($storage));
220
221    // Setup expectations for the serializer. This will be called for each field
222    // item.
223    $serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer')
224      ->disableOriginalConstructor()
225      ->setMethods(['denormalize'])
226      ->getMock();
227    $serializer->expects($this->at(0))
228      ->method('denormalize')
229      ->with('value_1', get_class($key_1), NULL, ['target_instance' => $key_1, 'entity_type' => 'test']);
230    $serializer->expects($this->at(1))
231      ->method('denormalize')
232      ->with('value_2', get_class($key_2), NULL, ['target_instance' => $key_2, 'entity_type' => 'test']);
233
234    $this->entityNormalizer->setSerializer($serializer);
235
236    $this->assertNotNull($this->entityNormalizer->denormalize($test_data, 'Drupal\Core\Entity\ContentEntityBase', NULL, ['entity_type' => 'test']));
237  }
238
239  /**
240   * Tests the denormalize method with a bundle property.
241   *
242   * @covers ::denormalize
243   */
244  public function testDenormalizeWithInvalidBundle() {
245    $test_data = [
246      'key_1' => 'value_1',
247      'key_2' => 'value_2',
248      'test_type' => [
249        ['name' => 'test_bundle'],
250      ],
251    ];
252
253    $entity_type = $this->createMock('Drupal\Core\Entity\EntityTypeInterface');
254
255    $entity_type->expects($this->once())
256      ->method('id')
257      ->willReturn('test');
258    $entity_type->expects($this->once())
259      ->method('hasKey')
260      ->with('bundle')
261      ->will($this->returnValue(TRUE));
262    $entity_type->expects($this->once())
263      ->method('getKey')
264      ->with('bundle')
265      ->will($this->returnValue('test_type'));
266    $entity_type->expects($this->once())
267      ->method('entityClassImplements')
268      ->with(FieldableEntityInterface::class)
269      ->willReturn(TRUE);
270
271    $entity_type->expects($this->once())
272      ->method('getBundleEntityType')
273      ->will($this->returnValue('test_bundle'));
274
275    $entity_type_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
276    $entity_type_storage_definition->expects($this->once())
277      ->method('getMainPropertyName')
278      ->will($this->returnValue('name'));
279
280    $entity_type_definition = $this->createMock('Drupal\Core\Field\FieldDefinitionInterface');
281    $entity_type_definition->expects($this->once())
282      ->method('getFieldStorageDefinition')
283      ->will($this->returnValue($entity_type_storage_definition));
284
285    $base_definitions = [
286      'test_type' => $entity_type_definition,
287    ];
288
289    $this->entityTypeManager->expects($this->at(0))
290      ->method('getDefinition')
291      ->with('test')
292      ->will($this->returnValue($entity_type));
293    $this->entityFieldManager->expects($this->at(0))
294      ->method('getBaseFieldDefinitions')
295      ->with('test')
296      ->will($this->returnValue($base_definitions));
297
298    $entity_query_mock = $this->createMock('Drupal\Core\Entity\Query\QueryInterface');
299    $entity_query_mock->expects($this->once())
300      ->method('execute')
301      ->will($this->returnValue(['test_bundle_other' => 'test_bundle_other']));
302
303    $entity_type_storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface');
304    $entity_type_storage->expects($this->once())
305      ->method('getQuery')
306      ->will($this->returnValue($entity_query_mock));
307
308    $this->entityTypeManager->expects($this->at(1))
309      ->method('getStorage')
310      ->with('test_bundle')
311      ->will($this->returnValue($entity_type_storage));
312
313    $this->expectException(UnexpectedValueException::class);
314    $this->entityNormalizer->denormalize($test_data, 'Drupal\Core\Entity\ContentEntityBase', NULL, ['entity_type' => 'test']);
315  }
316
317  /**
318   * Tests the denormalize method with no bundle defined.
319   *
320   * @covers ::denormalize
321   */
322  public function testDenormalizeWithNoBundle() {
323    $test_data = [
324      'key_1' => 'value_1',
325      'key_2' => 'value_2',
326    ];
327
328    $entity_type = $this->createMock('Drupal\Core\Entity\EntityTypeInterface');
329    $entity_type->expects($this->once())
330      ->method('entityClassImplements')
331      ->with(FieldableEntityInterface::class)
332      ->willReturn(TRUE);
333    $entity_type->expects($this->once())
334      ->method('hasKey')
335      ->with('bundle')
336      ->will($this->returnValue(FALSE));
337    $entity_type->expects($this->never())
338      ->method('getKey');
339
340    $this->entityTypeManager->expects($this->once())
341      ->method('getDefinition')
342      ->with('test')
343      ->will($this->returnValue($entity_type));
344
345    $key_1 = $this->createMock(FieldItemListInterface::class);
346    $key_2 = $this->createMock(FieldItemListInterface::class);
347
348    $entity = $this->createMock(FieldableEntityInterface::class);
349    $entity->expects($this->at(0))
350      ->method('get')
351      ->with('key_1')
352      ->willReturn($key_1);
353    $entity->expects($this->at(1))
354      ->method('get')
355      ->with('key_2')
356      ->willReturn($key_2);
357
358    $storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface');
359    $storage->expects($this->once())
360      ->method('create')
361      ->with([])
362      ->will($this->returnValue($entity));
363
364    $this->entityTypeManager->expects($this->once())
365      ->method('getStorage')
366      ->with('test')
367      ->will($this->returnValue($storage));
368
369    $this->entityFieldManager->expects($this->never())
370      ->method('getBaseFieldDefinitions');
371
372    // Setup expectations for the serializer. This will be called for each field
373    // item.
374    $serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer')
375      ->disableOriginalConstructor()
376      ->setMethods(['denormalize'])
377      ->getMock();
378    $serializer->expects($this->at(0))
379      ->method('denormalize')
380      ->with('value_1', get_class($key_1), NULL, ['target_instance' => $key_1, 'entity_type' => 'test']);
381    $serializer->expects($this->at(1))
382      ->method('denormalize')
383      ->with('value_2', get_class($key_2), NULL, ['target_instance' => $key_2, 'entity_type' => 'test']);
384
385    $this->entityNormalizer->setSerializer($serializer);
386
387    $this->assertNotNull($this->entityNormalizer->denormalize($test_data, 'Drupal\Core\Entity\ContentEntityBase', NULL, ['entity_type' => 'test']));
388  }
389
390  /**
391   * Tests the denormalize method with no bundle defined.
392   *
393   * @covers ::denormalize
394   */
395  public function testDenormalizeWithNoFieldableEntityType() {
396    $test_data = [
397      'key_1' => 'value_1',
398      'key_2' => 'value_2',
399    ];
400
401    $entity_type = $this->createMock('Drupal\Core\Entity\EntityTypeInterface');
402    $entity_type->expects($this->once())
403      ->method('entityClassImplements')
404      ->with(FieldableEntityInterface::class)
405      ->willReturn(FALSE);
406
407    $entity_type->expects($this->never())
408      ->method('getKey');
409
410    $this->entityTypeManager->expects($this->once())
411      ->method('getDefinition')
412      ->with('test')
413      ->will($this->returnValue($entity_type));
414
415    $storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface');
416    $storage->expects($this->once())
417      ->method('create')
418      ->with($test_data)
419      ->will($this->returnValue($this->createMock('Drupal\Core\Entity\EntityInterface')));
420
421    $this->entityTypeManager->expects($this->once())
422      ->method('getStorage')
423      ->with('test')
424      ->will($this->returnValue($storage));
425
426    $this->entityFieldManager->expects($this->never())
427      ->method('getBaseFieldDefinitions');
428
429    $this->assertNotNull($this->entityNormalizer->denormalize($test_data, 'Drupal\Core\Entity\ContentEntityBase', NULL, ['entity_type' => 'test']));
430  }
431
432}
433