3 namespace Drupal\KernelTests\Core\TypedData;
5 use Drupal\Core\Datetime\DrupalDateTime;
6 use Drupal\Core\Field\BaseFieldDefinition;
7 use Drupal\Core\TypedData\DataDefinition;
8 use Drupal\Core\TypedData\ListDataDefinition;
9 use Drupal\Core\TypedData\MapDataDefinition;
10 use Drupal\Core\TypedData\Type\BinaryInterface;
11 use Drupal\Core\TypedData\Type\BooleanInterface;
12 use Drupal\Core\TypedData\Type\DateTimeInterface;
13 use Drupal\Core\TypedData\Type\DurationInterface;
14 use Drupal\Core\TypedData\Type\FloatInterface;
15 use Drupal\Core\TypedData\Type\IntegerInterface;
16 use Drupal\Core\TypedData\Type\StringInterface;
17 use Drupal\Core\TypedData\Type\UriInterface;
18 use Drupal\Core\TypedData\TypedDataInterface;
19 use Drupal\file\Entity\File;
20 use Drupal\KernelTests\KernelTestBase;
23 * Tests the functionality of all core data types.
27 class TypedDataTest extends KernelTestBase {
30 * The typed data manager to use.
32 * @var \Drupal\Core\TypedData\TypedDataManager
34 protected $typedDataManager;
41 public static $modules = ['system', 'field', 'file', 'user'];
43 protected function setUp() {
46 $this->installEntitySchema('file');
47 $this->typedDataManager = $this->container->get('typed_data_manager');
51 * Creates a typed data object and ensures it implements TypedDataInterface.
53 * @see \Drupal\Core\TypedData\TypedDataManager::create()
55 protected function createTypedData($definition, $value = NULL, $name = NULL) {
56 if (is_array($definition)) {
57 $definition = DataDefinition::create($definition['type']);
59 $data = $this->typedDataManager->create($definition, $value, $name);
60 $this->assertTrue($data instanceof TypedDataInterface, 'Typed data object is an instance of the typed data interface.');
65 * Tests the basics around constructing and working with typed data objects.
67 public function testGetAndSet() {
69 $typed_data = $this->createTypedData(['type' => 'boolean'], TRUE);
70 $this->assertTrue($typed_data instanceof BooleanInterface, 'Typed data object is an instance of BooleanInterface.');
71 $this->assertTrue($typed_data->getValue() === TRUE, 'Boolean value was fetched.');
72 $this->assertEqual($typed_data->validate()->count(), 0);
73 $typed_data->setValue(FALSE);
74 $this->assertTrue($typed_data->getValue() === FALSE, 'Boolean value was changed.');
75 $this->assertEqual($typed_data->validate()->count(), 0);
76 $this->assertTrue(is_string($typed_data->getString()), 'Boolean value was converted to string');
77 $typed_data->setValue(NULL);
78 $this->assertNull($typed_data->getValue(), 'Boolean wrapper is null-able.');
79 $this->assertEqual($typed_data->validate()->count(), 0);
80 $typed_data->setValue('invalid');
81 $this->assertEqual($typed_data->validate()->count(), 1, 'Validation detected invalid value.');
84 $value = $this->randomString();
85 $typed_data = $this->createTypedData(['type' => 'string'], $value);
86 $this->assertTrue($typed_data instanceof StringInterface, 'Typed data object is an instance of StringInterface.');
87 $this->assertTrue($typed_data->getValue() === $value, 'String value was fetched.');
88 $this->assertEqual($typed_data->validate()->count(), 0);
89 $new_value = $this->randomString();
90 $typed_data->setValue($new_value);
91 $this->assertTrue($typed_data->getValue() === $new_value, 'String value was changed.');
92 $this->assertEqual($typed_data->validate()->count(), 0);
94 $this->assertTrue(is_string($typed_data->getString()), 'String value was converted to string');
95 $typed_data->setValue(NULL);
96 $this->assertNull($typed_data->getValue(), 'String wrapper is null-able.');
97 $this->assertEqual($typed_data->validate()->count(), 0);
98 $typed_data->setValue(['no string']);
99 $this->assertEqual($typed_data->validate()->count(), 1, 'Validation detected invalid value.');
103 $typed_data = $this->createTypedData(['type' => 'integer'], $value);
104 $this->assertTrue($typed_data instanceof IntegerInterface, 'Typed data object is an instance of IntegerInterface.');
105 $this->assertTrue($typed_data->getValue() === $value, 'Integer value was fetched.');
106 $this->assertEqual($typed_data->validate()->count(), 0);
108 $typed_data->setValue($new_value);
109 $this->assertTrue($typed_data->getValue() === $new_value, 'Integer value was changed.');
110 $this->assertTrue(is_string($typed_data->getString()), 'Integer value was converted to string');
111 $this->assertEqual($typed_data->validate()->count(), 0);
112 $typed_data->setValue(NULL);
113 $this->assertNull($typed_data->getValue(), 'Integer wrapper is null-able.');
114 $this->assertEqual($typed_data->validate()->count(), 0);
115 $typed_data->setValue('invalid');
116 $this->assertEqual($typed_data->validate()->count(), 1, 'Validation detected invalid value.');
120 $typed_data = $this->createTypedData(['type' => 'float'], $value);
121 $this->assertTrue($typed_data instanceof FloatInterface, 'Typed data object is an instance of FloatInterface.');
122 $this->assertTrue($typed_data->getValue() === $value, 'Float value was fetched.');
123 $this->assertEqual($typed_data->validate()->count(), 0);
125 $typed_data->setValue($new_value);
126 $this->assertTrue($typed_data->getValue() === $new_value, 'Float value was changed.');
127 $this->assertTrue(is_string($typed_data->getString()), 'Float value was converted to string');
128 $this->assertEqual($typed_data->validate()->count(), 0);
129 $typed_data->setValue(NULL);
130 $this->assertNull($typed_data->getValue(), 'Float wrapper is null-able.');
131 $this->assertEqual($typed_data->validate()->count(), 0);
132 $typed_data->setValue('invalid');
133 $this->assertEqual($typed_data->validate()->count(), 1, 'Validation detected invalid value.');
136 $value = '2014-01-01T20:00:00+00:00';
137 $typed_data = $this->createTypedData(['type' => 'datetime_iso8601'], $value);
138 $this->assertTrue($typed_data instanceof DateTimeInterface, 'Typed data object is an instance of DateTimeInterface.');
139 $this->assertTrue($typed_data->getValue() == $value, 'Date value was fetched.');
140 $this->assertEqual($typed_data->getValue(), $typed_data->getDateTime()->format('c'), 'Value representation of a date is ISO 8601');
141 $this->assertEqual($typed_data->validate()->count(), 0);
142 $new_value = '2014-01-02T20:00:00+00:00';
143 $typed_data->setValue($new_value);
144 $this->assertTrue($typed_data->getDateTime()->format('c') === $new_value, 'Date value was changed and set by an ISO8601 date.');
145 $this->assertEqual($typed_data->validate()->count(), 0);
146 $this->assertTrue($typed_data->getDateTime()->format('Y-m-d') == '2014-01-02', 'Date value was changed and set by date string.');
147 $this->assertEqual($typed_data->validate()->count(), 0);
148 $typed_data->setValue(NULL);
149 $this->assertNull($typed_data->getDateTime(), 'Date wrapper is null-able.');
150 $this->assertEqual($typed_data->validate()->count(), 0);
151 $typed_data->setValue('invalid');
152 $this->assertEqual($typed_data->validate()->count(), 1, 'Validation detected invalid value.');
153 // Check implementation of DateTimeInterface.
154 $typed_data = $this->createTypedData(['type' => 'datetime_iso8601'], '2014-01-01T20:00:00+00:00');
155 $this->assertTrue($typed_data->getDateTime() instanceof DrupalDateTime);
156 $typed_data->setDateTime(new DrupalDateTime('2014-01-02T20:00:00+00:00'));
157 $this->assertEqual($typed_data->getValue(), '2014-01-02T20:00:00+00:00');
158 $typed_data->setValue(NULL);
159 $this->assertNull($typed_data->getDateTime());
162 $value = REQUEST_TIME;
163 $typed_data = $this->createTypedData(['type' => 'timestamp'], $value);
164 $this->assertTrue($typed_data instanceof DateTimeInterface, 'Typed data object is an instance of DateTimeInterface.');
165 $this->assertTrue($typed_data->getValue() == $value, 'Timestamp value was fetched.');
166 $this->assertEqual($typed_data->validate()->count(), 0);
167 $new_value = REQUEST_TIME + 1;
168 $typed_data->setValue($new_value);
169 $this->assertTrue($typed_data->getValue() === $new_value, 'Timestamp value was changed and set.');
170 $this->assertEqual($typed_data->validate()->count(), 0);
171 $typed_data->setValue(NULL);
172 $this->assertNull($typed_data->getDateTime(), 'Timestamp wrapper is null-able.');
173 $this->assertEqual($typed_data->validate()->count(), 0);
174 $typed_data->setValue('invalid');
175 $this->assertEqual($typed_data->validate()->count(), 1, 'Validation detected invalid value.');
176 // Check implementation of DateTimeInterface.
177 $typed_data = $this->createTypedData(['type' => 'timestamp'], REQUEST_TIME);
178 $this->assertTrue($typed_data->getDateTime() instanceof DrupalDateTime);
179 $typed_data->setDateTime(DrupalDateTime::createFromTimestamp(REQUEST_TIME + 1));
180 $this->assertEqual($typed_data->getValue(), REQUEST_TIME + 1);
181 $typed_data->setValue(NULL);
182 $this->assertNull($typed_data->getDateTime());
184 // DurationIso8601 type.
186 $typed_data = $this->createTypedData(['type' => 'duration_iso8601'], $value);
187 $this->assertTrue($typed_data instanceof DurationInterface, 'Typed data object is an instance of DurationInterface.');
188 $this->assertIdentical($typed_data->getValue(), $value, 'DurationIso8601 value was fetched.');
189 $this->assertEqual($typed_data->validate()->count(), 0);
190 $typed_data->setValue('P40D');
191 $this->assertEqual($typed_data->getDuration()->d, 40, 'DurationIso8601 value was changed and set by duration string.');
192 $this->assertTrue(is_string($typed_data->getString()), 'DurationIso8601 value was converted to string');
193 $this->assertEqual($typed_data->validate()->count(), 0);
194 $typed_data->setValue(NULL);
195 $this->assertNull($typed_data->getValue(), 'DurationIso8601 wrapper is null-able.');
196 $this->assertEqual($typed_data->validate()->count(), 0);
197 $typed_data->setValue('invalid');
198 $this->assertEqual($typed_data->validate()->count(), 1, 'Validation detected invalid value.');
199 // Check implementation of DurationInterface.
200 $typed_data = $this->createTypedData(['type' => 'duration_iso8601'], 'PT20S');
201 $this->assertTrue($typed_data->getDuration() instanceof \DateInterval);
202 $typed_data->setDuration(new \DateInterval('P40D'));
203 // @todo: Should we make this "nicer"?
204 $this->assertEqual($typed_data->getValue(), 'P0Y0M40DT0H0M0S');
205 $typed_data->setValue(NULL);
206 $this->assertNull($typed_data->getDuration());
210 $typed_data = $this->createTypedData(['type' => 'timespan'], $value);
211 $this->assertTrue($typed_data instanceof DurationInterface, 'Typed data object is an instance of DurationInterface.');
212 $this->assertIdentical($typed_data->getValue(), $value, 'Time span value was fetched.');
213 $this->assertEqual($typed_data->validate()->count(), 0);
214 $typed_data->setValue(60 * 60 * 4);
215 $this->assertEqual($typed_data->getDuration()->s, 14400, 'Time span was changed');
216 $this->assertTrue(is_string($typed_data->getString()), 'Time span value was converted to string');
217 $this->assertEqual($typed_data->validate()->count(), 0);
218 $typed_data->setValue(NULL);
219 $this->assertNull($typed_data->getValue(), 'Time span wrapper is null-able.');
220 $this->assertEqual($typed_data->validate()->count(), 0);
221 $typed_data->setValue('invalid');
222 $this->assertEqual($typed_data->validate()->count(), 1, 'Validation detected invalid value.');
223 // Check implementation of DurationInterface.
224 $typed_data = $this->createTypedData(['type' => 'timespan'], 20);
225 $this->assertTrue($typed_data->getDuration() instanceof \DateInterval);
226 $typed_data->setDuration(new \DateInterval('PT4H'));
227 $this->assertEqual($typed_data->getValue(), 60 * 60 * 4);
228 $typed_data->setValue(NULL);
229 $this->assertNull($typed_data->getDuration());
232 $uri = 'http://example.com/foo/';
233 $typed_data = $this->createTypedData(['type' => 'uri'], $uri);
234 $this->assertTrue($typed_data instanceof UriInterface, 'Typed data object is an instance of UriInterface.');
235 $this->assertTrue($typed_data->getValue() === $uri, 'URI value was fetched.');
236 $this->assertEqual($typed_data->validate()->count(), 0);
237 $typed_data->setValue($uri . 'bar.txt');
238 $this->assertTrue($typed_data->getValue() === $uri . 'bar.txt', 'URI value was changed.');
239 $this->assertTrue(is_string($typed_data->getString()), 'URI value was converted to string');
240 $this->assertEqual($typed_data->validate()->count(), 0);
241 $typed_data->setValue(NULL);
242 $this->assertNull($typed_data->getValue(), 'URI wrapper is null-able.');
243 $this->assertEqual($typed_data->validate()->count(), 0);
244 $typed_data->setValue('invalid');
245 $this->assertEqual($typed_data->validate()->count(), 1, 'Validation detected invalid value.');
246 $typed_data->setValue('public://field/image/Photo on 4-28-14 at 12.01 PM.jpg');
247 $this->assertEqual($typed_data->validate()->count(), 0, 'Filename with spaces is valid.');
249 // Generate some files that will be used to test the binary data type.
251 for ($i = 0; $i < 3; $i++) {
252 $path = "public://example_$i.png";
253 file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', $path);
254 $image = File::create(['uri' => $path]);
260 $value = $this->randomString();
261 $typed_data = $this->createTypedData(['type' => 'email'], $value);
262 $this->assertTrue($typed_data instanceof StringInterface, 'Typed data object is an instance of StringInterface.');
263 $this->assertIdentical($typed_data->getValue(), $value, 'Email value was fetched.');
264 $new_value = 'test@example.com';
265 $typed_data->setValue($new_value);
266 $this->assertIdentical($typed_data->getValue(), $new_value, 'Email value was changed.');
267 $this->assertTrue(is_string($typed_data->getString()), 'Email value was converted to string');
268 $this->assertEqual($typed_data->validate()->count(), 0);
269 $typed_data->setValue(NULL);
270 $this->assertNull($typed_data->getValue(), 'Email wrapper is null-able.');
271 $this->assertEqual($typed_data->validate()->count(), 0);
272 $typed_data->setValue('invalidATexample.com');
273 $this->assertEqual($typed_data->validate()->count(), 1, 'Validation detected invalid value.');
276 $typed_data = $this->createTypedData(['type' => 'binary'], $files[0]->getFileUri());
277 $this->assertTrue($typed_data instanceof BinaryInterface, 'Typed data object is an instance of BinaryInterface.');
278 $this->assertTrue(is_resource($typed_data->getValue()), 'Binary value was fetched.');
279 $this->assertEqual($typed_data->validate()->count(), 0);
280 // Try setting by URI.
281 $typed_data->setValue($files[1]->getFileUri());
282 $this->assertEqual(fgets($typed_data->getValue()), fgets(fopen($files[1]->getFileUri(), 'r')), 'Binary value was changed.');
283 $this->assertTrue(is_string($typed_data->getString()), 'Binary value was converted to string');
284 $this->assertEqual($typed_data->validate()->count(), 0);
285 // Try setting by resource.
286 $typed_data->setValue(fopen($files[2]->getFileUri(), 'r'));
287 $this->assertEqual(fgets($typed_data->getValue()), fgets(fopen($files[2]->getFileUri(), 'r')), 'Binary value was changed.');
288 $this->assertTrue(is_string($typed_data->getString()), 'Binary value was converted to string');
289 $this->assertEqual($typed_data->validate()->count(), 0);
290 $typed_data->setValue(NULL);
291 $this->assertNull($typed_data->getValue(), 'Binary wrapper is null-able.');
292 $this->assertEqual($typed_data->validate()->count(), 0);
293 $typed_data->setValue('invalid');
294 $this->assertEqual($typed_data->validate()->count(), 1, 'Validation detected invalid value.');
298 $typed_data = $this->createTypedData(['type' => 'any'], $value);
299 $this->assertIdentical($typed_data->getValue(), $value, 'Any value was fetched.');
300 $new_value = 'test@example.com';
301 $typed_data->setValue($new_value);
302 $this->assertIdentical($typed_data->getValue(), $new_value, 'Any value was changed.');
303 $this->assertTrue(is_string($typed_data->getString()), 'Any value was converted to string');
304 $this->assertEqual($typed_data->validate()->count(), 0);
305 $typed_data->setValue(NULL);
306 $this->assertNull($typed_data->getValue(), 'Any wrapper is null-able.');
307 $this->assertEqual($typed_data->validate()->count(), 0);
308 // We cannot test invalid values as everything is valid for the any type,
309 // but make sure an array or object value passes validation also.
310 $typed_data->setValue(['entry']);
311 $this->assertEqual($typed_data->validate()->count(), 0);
312 $typed_data->setValue((object) ['entry']);
313 $this->assertEqual($typed_data->validate()->count(), 0);
317 * Tests using typed data lists.
319 public function testTypedDataLists() {
320 // Test working with an existing list of strings.
321 $value = ['one', 'two', 'three'];
322 $typed_data = $this->createTypedData(ListDataDefinition::create('string'), $value);
323 $this->assertEqual($typed_data->getValue(), $value, 'List value has been set.');
326 foreach ($typed_data as $item) {
327 $this->assertTrue($item instanceof TypedDataInterface);
330 $this->assertEqual($count, 3);
332 // Test getting the string representation.
333 $this->assertEqual($typed_data->getString(), 'one, two, three');
335 $this->assertEqual($typed_data->getString(), 'one, three');
337 // Test using array access.
338 $this->assertEqual($typed_data[0]->getValue(), 'one');
339 $typed_data[] = 'four';
340 $this->assertEqual($typed_data[3]->getValue(), 'four');
341 $this->assertEqual($typed_data->count(), 4);
342 $this->assertTrue(isset($typed_data[0]));
343 $this->assertTrue(!isset($typed_data[6]));
345 // Test isEmpty and cloning.
346 $this->assertFalse($typed_data->isEmpty());
347 $clone = clone $typed_data;
348 $this->assertTrue($typed_data->getValue() === $clone->getValue());
349 $this->assertTrue($typed_data[0] !== $clone[0]);
350 $clone->setValue([]);
351 $this->assertTrue($clone->isEmpty());
353 // Make sure that resetting the value using NULL results in an empty array.
354 $clone->setValue([]);
355 $typed_data->setValue(NULL);
356 $this->assertIdentical($typed_data->getValue(), []);
357 $this->assertIdentical($clone->getValue(), []);
359 // Test dealing with NULL items.
360 $typed_data[] = NULL;
361 $this->assertTrue($typed_data->isEmpty());
362 $this->assertEqual(count($typed_data), 1);
364 $this->assertFalse($typed_data->isEmpty());
365 $this->assertEqual(count($typed_data), 2);
366 $typed_data[] = 'three';
367 $this->assertFalse($typed_data->isEmpty());
368 $this->assertEqual(count($typed_data), 3);
370 $this->assertEqual($typed_data->getValue(), [NULL, '', 'three']);
372 unset($typed_data[1]);
373 $this->assertEqual(count($typed_data), 2);
374 // Check that items were shifted.
375 $this->assertEqual($typed_data[1]->getValue(), 'three');
377 // Getting a not set list item returns NULL, and does not create a new item.
378 $this->assertNull($typed_data[2]);
379 $this->assertEqual(count($typed_data), 2);
381 // Test setting the list with less values.
382 $typed_data->setValue(['one']);
383 $this->assertEqual($typed_data->count(), 1);
385 // Test setting invalid values.
387 $typed_data->setValue('string');
388 $this->fail('No exception has been thrown when setting an invalid value.');
390 catch (\Exception $e) {
391 $this->pass('Exception thrown:' . $e->getMessage());
396 * Tests the filter() method on typed data lists.
398 public function testTypedDataListsFilter() {
399 // Check that an all-pass filter leaves the list untouched.
400 $value = ['zero', 'one'];
401 $typed_data = $this->createTypedData(ListDataDefinition::create('string'), $value);
402 $typed_data->filter(function(TypedDataInterface $item) {
405 $this->assertEqual($typed_data->count(), 2);
406 $this->assertEqual($typed_data[0]->getValue(), 'zero');
407 $this->assertEqual($typed_data[0]->getName(), 0);
408 $this->assertEqual($typed_data[1]->getValue(), 'one');
409 $this->assertEqual($typed_data[1]->getName(), 1);
411 // Check that a none-pass filter empties the list.
412 $value = ['zero', 'one'];
413 $typed_data = $this->createTypedData(ListDataDefinition::create('string'), $value);
414 $typed_data->filter(function(TypedDataInterface $item) {
417 $this->assertEqual($typed_data->count(), 0);
419 // Check that filtering correctly renumbers elements.
420 $value = ['zero', 'one', 'two'];
421 $typed_data = $this->createTypedData(ListDataDefinition::create('string'), $value);
422 $typed_data->filter(function(TypedDataInterface $item) {
423 return $item->getValue() !== 'one';
425 $this->assertEqual($typed_data->count(), 2);
426 $this->assertEqual($typed_data[0]->getValue(), 'zero');
427 $this->assertEqual($typed_data[0]->getName(), 0);
428 $this->assertEqual($typed_data[1]->getValue(), 'two');
429 $this->assertEqual($typed_data[1]->getName(), 1);
433 * Tests using a typed data map.
435 public function testTypedDataMaps() {
436 // Test working with a simple map.
442 $definition = MapDataDefinition::create()
443 ->setPropertyDefinition('one', DataDefinition::create('string'))
444 ->setPropertyDefinition('two', DataDefinition::create('string'))
445 ->setPropertyDefinition('three', DataDefinition::create('string'));
447 $typed_data = $this->createTypedData($definition, $value);
451 foreach ($typed_data as $item) {
452 $this->assertTrue($item instanceof TypedDataInterface);
455 $this->assertEqual($count, 3);
457 // Test retrieving metadata.
458 $this->assertEqual(array_keys($typed_data->getDataDefinition()->getPropertyDefinitions()), array_keys($value));
459 $definition = $typed_data->getDataDefinition()->getPropertyDefinition('one');
460 $this->assertEqual($definition->getDataType(), 'string');
461 $this->assertNull($typed_data->getDataDefinition()->getPropertyDefinition('invalid'));
463 // Test getting and setting properties.
464 $this->assertEqual($typed_data->get('one')->getValue(), 'eins');
465 $this->assertEqual($typed_data->toArray(), $value);
466 $typed_data->set('one', 'uno');
467 $this->assertEqual($typed_data->get('one')->getValue(), 'uno');
468 // Make sure the update is reflected in the value of the map also.
469 $value = $typed_data->getValue();
470 $this->assertEqual($value, [
476 $properties = $typed_data->getProperties();
477 $this->assertEqual(array_keys($properties), array_keys($value));
478 $this->assertIdentical($properties['one'], $typed_data->get('one'), 'Properties are identical.');
480 // Test setting a not defined property. It shouldn't show up in the
481 // properties, but be kept in the values.
482 $typed_data->setValue(['foo' => 'bar']);
483 $this->assertEqual(array_keys($typed_data->getProperties()), ['one', 'two', 'three']);
484 $this->assertEqual(array_keys($typed_data->getValue()), ['foo', 'one', 'two', 'three']);
486 // Test getting the string representation.
487 $typed_data->setValue(['one' => 'eins', 'two' => '', 'three' => 'drei']);
488 $this->assertEqual($typed_data->getString(), 'eins, drei');
490 // Test isEmpty and cloning.
491 $this->assertFalse($typed_data->isEmpty());
492 $clone = clone $typed_data;
493 $this->assertTrue($typed_data->getValue() === $clone->getValue());
494 $this->assertTrue($typed_data->get('one') !== $clone->get('one'));
495 $clone->setValue([]);
496 $this->assertTrue($clone->isEmpty());
498 // Make sure the difference between NULL (not set) and an empty array is
500 $typed_data->setValue(NULL);
501 $this->assertNull($typed_data->getValue());
502 $typed_data->setValue([]);
503 $value = $typed_data->getValue();
504 $this->assertTrue(isset($value) && is_array($value));
506 // Test accessing invalid properties.
507 $typed_data->setValue($value);
509 $typed_data->get('invalid');
510 $this->fail('No exception has been thrown when getting an invalid value.');
512 catch (\Exception $e) {
513 $this->pass('Exception thrown:' . $e->getMessage());
516 // Test setting invalid values.
518 $typed_data->setValue('invalid');
519 $this->fail('No exception has been thrown when setting an invalid value.');
521 catch (\Exception $e) {
522 $this->pass('Exception thrown:' . $e->getMessage());
525 // Test adding a new property to the map.
526 $typed_data->getDataDefinition()->setPropertyDefinition('zero', DataDefinition::create('any'));
527 $typed_data->set('zero', 'null');
528 $this->assertEqual($typed_data->get('zero')->getValue(), 'null');
529 $definition = $typed_data->get('zero')->getDataDefinition();
530 $this->assertEqual($definition->getDataType(), 'any', 'Definition for a new map entry returned.');
534 * Tests typed data validation.
536 public function testTypedDataValidation() {
537 $definition = DataDefinition::create('integer')
539 'Range' => ['min' => 5],
541 $violations = $this->typedDataManager->create($definition, 10)->validate();
542 $this->assertEqual($violations->count(), 0);
544 $integer = $this->typedDataManager->create($definition, 1);
545 $violations = $integer->validate();
546 $this->assertEqual($violations->count(), 1);
548 // Test translating violation messages.
549 $message = t('This value should be %limit or more.', ['%limit' => 5]);
550 $this->assertEqual($violations[0]->getMessage(), $message, 'Translated violation message retrieved.');
551 $this->assertEqual($violations[0]->getPropertyPath(), '');
552 $this->assertIdentical($violations[0]->getRoot(), $integer, 'Root object returned.');
554 // Test translating violation messages when pluralization is used.
555 $definition = DataDefinition::create('string')
557 'Length' => ['min' => 10],
559 $violations = $this->typedDataManager->create($definition, "short")->validate();
560 $this->assertEqual($violations->count(), 1);
561 $message = t('This value is too short. It should have %limit characters or more.', ['%limit' => 10]);
562 $this->assertEqual($violations[0]->getMessage(), $message, 'Translated violation message retrieved.');
564 // Test having multiple violations.
565 $definition = DataDefinition::create('integer')
567 'Range' => ['min' => 5],
570 $violations = $this->typedDataManager->create($definition, 10)->validate();
571 $this->assertEqual($violations->count(), 1);
572 $violations = $this->typedDataManager->create($definition, 1)->validate();
573 $this->assertEqual($violations->count(), 2);
575 // Test validating property containers and make sure the NotNull and Null
576 // constraints work with typed data containers.
577 $definition = BaseFieldDefinition::create('integer')
578 ->setConstraints(['NotNull' => []]);
579 $field_item = $this->typedDataManager->create($definition, ['value' => 10]);
580 $violations = $field_item->validate();
581 $this->assertEqual($violations->count(), 0);
583 $field_item = $this->typedDataManager->create($definition, ['value' => 'no integer']);
584 $violations = $field_item->validate();
585 $this->assertEqual($violations->count(), 1);
586 $this->assertEqual($violations[0]->getPropertyPath(), '0.value');
588 // Test that the field item may not be empty.
589 $field_item = $this->typedDataManager->create($definition);
590 $violations = $field_item->validate();
591 $this->assertEqual($violations->count(), 1);
593 // Test the Null constraint with typed data containers.
594 $definition = BaseFieldDefinition::create('float')
595 ->setConstraints(['Null' => []]);
596 $field_item = $this->typedDataManager->create($definition, ['value' => 11.5]);
597 $violations = $field_item->validate();
598 $this->assertEqual($violations->count(), 1);
599 $field_item = $this->typedDataManager->create($definition);
600 $violations = $field_item->validate();
601 $this->assertEqual($violations->count(), 0);
603 // Test getting constraint definitions by type.
604 $definitions = $this->typedDataManager->getValidationConstraintManager()->getDefinitionsByType('entity');
605 $this->assertTrue(isset($definitions['EntityType']), 'Constraint plugin found for type entity.');
606 $this->assertTrue(isset($definitions['Null']), 'Constraint plugin found for type entity.');
607 $this->assertTrue(isset($definitions['NotNull']), 'Constraint plugin found for type entity.');
609 $definitions = $this->typedDataManager->getValidationConstraintManager()->getDefinitionsByType('string');
610 $this->assertFalse(isset($definitions['EntityType']), 'Constraint plugin not found for type string.');
611 $this->assertTrue(isset($definitions['Null']), 'Constraint plugin found for type string.');
612 $this->assertTrue(isset($definitions['NotNull']), 'Constraint plugin found for type string.');
614 // Test automatic 'required' validation.
615 $definition = DataDefinition::create('integer')
617 $violations = $this->typedDataManager->create($definition)->validate();
618 $this->assertEqual($violations->count(), 1);
619 $violations = $this->typedDataManager->create($definition, 0)->validate();
620 $this->assertEqual($violations->count(), 0);
622 // Test validating a list of a values and make sure property paths starting
623 // with "0" are created.
624 $definition = BaseFieldDefinition::create('integer');
625 $violations = $this->typedDataManager->create($definition, [['value' => 10]])->validate();
626 $this->assertEqual($violations->count(), 0);
627 $violations = $this->typedDataManager->create($definition, [['value' => 'string']])->validate();
628 $this->assertEqual($violations->count(), 1);
630 $this->assertEqual($violations[0]->getInvalidValue(), 'string');
631 $this->assertIdentical($violations[0]->getPropertyPath(), '0.value');