DateTimeIso8601NormalizerTest.php

Same filename in other branches
  1. 9 core/modules/serialization/tests/src/Unit/Normalizer/DateTimeIso8601NormalizerTest.php
  2. 10 core/modules/serialization/tests/src/Unit/Normalizer/DateTimeIso8601NormalizerTest.php
  3. 11.x core/modules/serialization/tests/src/Unit/Normalizer/DateTimeIso8601NormalizerTest.php

Namespace

Drupal\Tests\serialization\Unit\Normalizer

File

core/modules/serialization/tests/src/Unit/Normalizer/DateTimeIso8601NormalizerTest.php

View source
<?php

namespace Drupal\Tests\serialization\Unit\Normalizer;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\Plugin\DataType\DateTimeIso8601;
use Drupal\Core\TypedData\Plugin\DataType\IntegerData;
use Drupal\Core\TypedData\Type\DateTimeInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
use Drupal\serialization\Normalizer\DateTimeIso8601Normalizer;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;

/**
 * Unit test coverage for the "datetime_iso8601" @DataType.
 *
 * @coversDefaultClass \Drupal\serialization\Normalizer\DateTimeIso8601Normalizer
 * @group serialization
 * @see \Drupal\Core\TypedData\Plugin\DataType\DateTimeIso8601
 * @see \Drupal\datetime\Plugin\Field\FieldType\DateTimeItem::DATETIME_TYPE_DATE
 */
class DateTimeIso8601NormalizerTest extends UnitTestCase {
    
    /**
     * The tested data type's normalizer.
     *
     * @var \Drupal\serialization\Normalizer\DateTimeIso8601Normalizer
     */
    protected $normalizer;
    
    /**
     * The tested data type.
     *
     * @var \Drupal\Core\TypedData\Plugin\DataType\DateTimeIso8601
     */
    protected $data;
    
    /**
     * {@inheritdoc}
     */
    protected function setUp() {
        parent::setUp();
        $system_date_config = $this->prophesize(ImmutableConfig::class);
        $system_date_config->get('timezone.default')
            ->willReturn('Australia/Sydney');
        $config_factory = $this->prophesize(ConfigFactoryInterface::class);
        $config_factory->get('system.date')
            ->willReturn($system_date_config->reveal());
        $this->normalizer = new DateTimeIso8601Normalizer($config_factory->reveal());
        $this->data = $this->prophesize(DateTimeIso8601::class);
    }
    
    /**
     * @covers ::supportsNormalization
     */
    public function testSupportsNormalization() {
        $this->assertTrue($this->normalizer
            ->supportsNormalization($this->data
            ->reveal()));
        $datetime = $this->prophesize(DateTimeInterface::class);
        $this->assertFalse($this->normalizer
            ->supportsNormalization($datetime->reveal()));
        $integer = $this->prophesize(IntegerData::class);
        $this->assertFalse($this->normalizer
            ->supportsNormalization($integer->reveal()));
    }
    
    /**
     * @covers ::supportsDenormalization
     */
    public function testSupportsDenormalization() {
        $this->assertTrue($this->normalizer
            ->supportsDenormalization($this->data
            ->reveal(), DateTimeIso8601::class));
    }
    
    /**
     * @covers ::normalize
     * @dataProvider providerTestNormalize
     */
    public function testNormalize($parent_field_item_class, $datetime_type, $expected_format) {
        $formatted_string = $this->randomMachineName();
        $field_item = $this->prophesize($parent_field_item_class);
        if ($parent_field_item_class === DateTimeItem::class) {
            $field_storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
            $field_storage_definition->getSetting('datetime_type')
                ->willReturn($datetime_type);
            $field_definition = $this->prophesize(FieldDefinitionInterface::class);
            $field_definition->getFieldStorageDefinition()
                ->willReturn($field_storage_definition);
            $field_item->getFieldDefinition()
                ->willReturn($field_definition);
        }
        else {
            $field_item->getFieldDefinition(Argument::any())
                ->shouldNotBeCalled();
        }
        $this->data
            ->getParent()
            ->willReturn($field_item);
        $drupal_date_time = $this->prophesize(DateTimeIso8601NormalizerTestDrupalDateTime::class);
        $drupal_date_time->setTimezone(new \DateTimeZone('Australia/Sydney'))
            ->willReturn($drupal_date_time->reveal());
        $drupal_date_time->format($expected_format)
            ->willReturn($formatted_string);
        $this->data
            ->getDateTime()
            ->willReturn($drupal_date_time->reveal());
        $normalized = $this->normalizer
            ->normalize($this->data
            ->reveal());
        $this->assertSame($formatted_string, $normalized);
    }
    
    /**
     * @covers ::normalize
     * @dataProvider providerTestNormalize
     */
    public function testNormalizeWhenNull($parent_field_item_class, $datetime_type, $expected_format) {
        $field_item = $this->prophesize($parent_field_item_class);
        if ($parent_field_item_class === DateTimeItem::class) {
            $field_storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
            $field_storage_definition->getSetting('datetime_type')
                ->willReturn($datetime_type);
            $field_definition = $this->prophesize(FieldDefinitionInterface::class);
            $field_definition->getFieldStorageDefinition()
                ->willReturn($field_storage_definition);
            $field_item->getFieldDefinition()
                ->willReturn($field_definition);
        }
        else {
            $field_item->getFieldDefinition(Argument::any())
                ->shouldNotBeCalled();
        }
        $this->data
            ->getParent()
            ->willReturn($field_item);
        $this->data
            ->getDateTime()
            ->willReturn(NULL);
        $normalized = $this->normalizer
            ->normalize($this->data
            ->reveal());
        $this->assertNull($normalized);
    }
    
    /**
     * Data provider for testNormalize.
     *
     * @return array
     */
    public function providerTestNormalize() {
        return [
            // @see \Drupal\datetime\Plugin\Field\FieldType\DateTimeItem::DATETIME_TYPE_DATE
'datetime field, configured to store only date: must be handled by DateTimeIso8601Normalizer' => [
                DateTimeItem::class,
                DateTimeItem::DATETIME_TYPE_DATE,
                // This expected format call proves that normalization is handled by \Drupal\serialization\Normalizer\DateTimeIso8601Normalizer::normalize().
'Y-m-d',
            ],
            // @see \Drupal\datetime\Plugin\Field\FieldType\DateTimeItem::DATETIME_TYPE_DATETIME
'datetime field, configured to store date and time; must be handled by the parent normalizer' => [
                DateTimeItem::class,
                DateTimeItem::DATETIME_TYPE_DATETIME,
                \DateTime::RFC3339,
            ],
            'non-datetime field; must be handled by the parent normalizer' => [
                FieldItemBase::class,
                NULL,
                \DateTime::RFC3339,
            ],
        ];
    }
    
    /**
     * Tests the denormalize function with good data.
     *
     * @covers ::denormalize
     * @dataProvider providerTestDenormalizeValidFormats
     */
    public function testDenormalizeValidFormats($type, $normalized, $expected) {
        $field_definition = $this->prophesize(FieldDefinitionInterface::class);
        $field_definition->getSetting('datetime_type')
            ->willReturn($type === 'date-only' ? DateTimeItem::DATETIME_TYPE_DATE : DateTimeItem::DATETIME_TYPE_DATETIME);
        $denormalized = $this->normalizer
            ->denormalize($normalized, DateTimeIso8601::class, NULL, [
            'field_definition' => $field_definition->reveal(),
        ]);
        $this->assertSame($expected, $denormalized);
    }
    
    /**
     * Data provider for testDenormalizeValidFormats.
     *
     * @return array
     */
    public function providerTestDenormalizeValidFormats() {
        $data = [];
        $data['just a date'] = [
            'date-only',
            '2016-11-06',
            '2016-11-06',
        ];
        $data['RFC3339'] = [
            'date+time',
            '2016-11-06T09:02:00+00:00',
            '2016-11-06T09:02:00',
        ];
        $data['RFC3339 +0100'] = [
            'date+time',
            '2016-11-06T09:02:00+01:00',
            '2016-11-06T08:02:00',
        ];
        $data['RFC3339 -0600'] = [
            'date+time',
            '2016-11-06T09:02:00-06:00',
            '2016-11-06T15:02:00',
        ];
        $data['ISO8601'] = [
            'date+time',
            '2016-11-06T09:02:00+0000',
            '2016-11-06T09:02:00',
        ];
        $data['ISO8601 +0100'] = [
            'date+time',
            '2016-11-06T09:02:00+0100',
            '2016-11-06T08:02:00',
        ];
        $data['ISO8601 -0600'] = [
            'date+time',
            '2016-11-06T09:02:00-0600',
            '2016-11-06T15:02:00',
        ];
        return $data;
    }
    
    /**
     * Tests the denormalize function with the date+time deprecated format.
     *
     * @covers ::denormalize
     * @group legacy
     * @expectedDeprecation The provided datetime string format (Y-m-d\TH:i:s) is deprecated and will be removed before Drupal 9.0.0. Use the RFC3339 format instead (Y-m-d\TH:i:sP).
     */
    public function testDenormalizeDateAndTimeDeprecatedFormat() {
        $normalized = '2016-11-06T08:00:00';
        $field_definition = $this->prophesize(FieldDefinitionInterface::class);
        $field_definition->getSetting('datetime_type')
            ->willReturn(DateTimeItem::DATETIME_TYPE_DATETIME);
        $this->normalizer
            ->denormalize($normalized, DateTimeIso8601::class, NULL, [
            'field_definition' => $field_definition->reveal(),
        ]);
    }
    
    /**
     * Tests the denormalize function with bad data for the date-only case.
     *
     * @covers ::denormalize
     */
    public function testDenormalizeDateOnlyException() {
        $this->expectException(UnexpectedValueException::class);
        $this->expectExceptionMessage('The specified date "2016/11/06" is not in an accepted format: "Y-m-d" (date-only).');
        $normalized = '2016/11/06';
        $field_definition = $this->prophesize(FieldDefinitionInterface::class);
        $field_definition->getSetting('datetime_type')
            ->willReturn(DateTimeItem::DATETIME_TYPE_DATE);
        $this->normalizer
            ->denormalize($normalized, DateTimeIso8601::class, NULL, [
            'field_definition' => $field_definition->reveal(),
        ]);
    }
    
    /**
     * Tests the denormalize function with bad data for the date+time case.
     *
     * @covers ::denormalize
     */
    public function testDenormalizeDateAndTimeException() {
        $this->expectException(UnexpectedValueException::class);
        $this->expectExceptionMessage('The specified date "on a rainy day" is not in an accepted format: "Y-m-d\\TH:i:sP" (RFC 3339), "Y-m-d\\TH:i:sO" (ISO 8601), "Y-m-d\\TH:i:s" (backward compatibility — deprecated).');
        $normalized = 'on a rainy day';
        $field_definition = $this->prophesize(FieldDefinitionInterface::class);
        $field_definition->getSetting('datetime_type')
            ->willReturn(DateTimeItem::DATETIME_TYPE_DATETIME);
        $this->normalizer
            ->denormalize($normalized, DateTimeIso8601::class, NULL, [
            'field_definition' => $field_definition->reveal(),
        ]);
    }
    
    /**
     * Tests the denormalize function with incomplete serialization context.
     *
     * @covers ::denormalize
     */
    public function testDenormalizeNoTargetInstanceOrFieldDefinitionException() {
        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('$context[\'target_instance\'] or $context[\'field_definition\'] must be set to denormalize with the DateTimeIso8601Normalizer');
        $this->normalizer
            ->denormalize('', DateTimeIso8601::class, NULL, []);
    }

}

/**
 * Note: Prophecy does not support magic methods. By subclassing and specifying
 * an explicit method, Prophecy works.
 * @see https://github.com/phpspec/prophecy/issues/338
 * @see https://github.com/phpspec/prophecy/issues/34
 * @see https://github.com/phpspec/prophecy/issues/80
 */
class DateTimeIso8601NormalizerTestDrupalDateTime extends DrupalDateTime {
    public function setTimezone(\DateTimeZone $timezone) {
        parent::setTimezone($timezone);
    }

}

Classes

Title Deprecated Summary
DateTimeIso8601NormalizerTest Unit test coverage for the "datetime_iso8601" @DataType.
DateTimeIso8601NormalizerTestDrupalDateTime Note: Prophecy does not support magic methods. By subclassing and specifying an explicit method, Prophecy works.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.