1<?php
2
3declare(strict_types=1);
4
5namespace JMS\Serializer\Tests\Handler;
6
7use JMS\Serializer\Handler\DateHandler;
8use JMS\Serializer\JsonDeserializationVisitor;
9use JMS\Serializer\SerializationContext;
10use JMS\Serializer\Visitor\SerializationVisitorInterface;
11use PHPUnit\Framework\TestCase;
12
13class DateHandlerTest extends TestCase
14{
15    /**
16     * @var DateHandler
17     */
18    private $handler;
19    /**
20     * @var \DateTimeZone
21     */
22    private $timezone;
23
24    public function setUp()
25    {
26        $this->handler = new DateHandler();
27        $this->timezone = new \DateTimeZone('UTC');
28    }
29
30    public function getParams()
31    {
32        return [
33            [['Y-m-d']],
34            [['Y-m-d', '', 'Y-m-d|']],
35            [['Y-m-d', '', 'Y']],
36        ];
37    }
38
39    /**
40     * @param array $params
41     *
42     * @doesNotPerformAssertions
43     * @dataProvider getParams
44     */
45    public function testSerializeDate(array $params)
46    {
47        $context = $this->getMockBuilder(SerializationContext::class)->getMock();
48
49        $visitor = $this->getMockBuilder(SerializationVisitorInterface::class)->getMock();
50        $visitor->method('visitString')->with('2017-06-18');
51
52        $datetime = new \DateTime('2017-06-18 14:30:59', $this->timezone);
53        $type = ['name' => 'DateTime', 'params' => $params];
54        $this->handler->serializeDateTime($visitor, $datetime, $type, $context);
55    }
56
57    public function testTimePartGetsRemoved()
58    {
59        $visitor = new JsonDeserializationVisitor();
60
61        $type = ['name' => 'DateTime', 'params' => ['Y-m-d', '', 'Y-m-d|']];
62        self::assertEquals(
63            \DateTime::createFromFormat('Y-m-d|', '2017-06-18', $this->timezone),
64            $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type)
65        );
66    }
67
68    public function testTimePartGetsPreserved()
69    {
70        $visitor = new JsonDeserializationVisitor();
71
72        $expectedDateTime = \DateTime::createFromFormat('Y-m-d', '2017-06-18', $this->timezone);
73        // if the test is executed exactly at midnight, it might not detect a possible failure since the time component will be "00:00:00
74        // I know, this is a bit paranoid
75        if ('00:00:00' === $expectedDateTime->format('H:i:s')) {
76            sleep(1);
77            $expectedDateTime = \DateTime::createFromFormat('Y-m-d', '2017-06-18', $this->timezone);
78        }
79
80        // no custom deserialization format specified
81        $type = ['name' => 'DateTime', 'params' => ['Y-m-d']];
82        self::assertEquals(
83            $expectedDateTime,
84            $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type)
85        );
86
87        // custom deserialization format specified
88        $type = ['name' => 'DateTime', 'params' => ['Y-m-d', '', 'Y-m-d']];
89        self::assertEquals(
90            $expectedDateTime,
91            $this->handler->deserializeDateTimeFromJson($visitor, '2017-06-18', $type)
92        );
93    }
94
95    public function testTimeZoneGetsPreservedWithUnixTimestamp()
96    {
97        $visitor = new JsonDeserializationVisitor();
98
99        $timestamp = (string) time();
100        $timezone = 'Europe/Brussels';
101        $type = ['name' => 'DateTime', 'params' => ['U', $timezone]];
102
103        $expectedDateTime = \DateTime::createFromFormat('U', $timestamp);
104        $expectedDateTime->setTimezone(new \DateTimeZone($timezone));
105
106        $actualDateTime = $this->handler->deserializeDateTimeFromJson($visitor, $timestamp, $type);
107
108        self::assertEquals(
109            $expectedDateTime->format(\DateTime::RFC3339),
110            $actualDateTime->format(\DateTime::RFC3339)
111        );
112    }
113
114    public function testImmutableTimeZoneGetsPreservedWithUnixTimestamp()
115    {
116        $visitor = new JsonDeserializationVisitor();
117
118        $timestamp = (string) time();
119        $timezone = 'Europe/Brussels';
120        $type = ['name' => 'DateTimeImmutable', 'params' => ['U', $timezone]];
121
122        $expectedDateTime = \DateTime::createFromFormat('U', $timestamp);
123        $expectedDateTime->setTimezone(new \DateTimeZone($timezone));
124
125        $actualDateTime = $this->handler->deserializeDateTimeImmutableFromJson($visitor, $timestamp, $type);
126
127        self::assertEquals(
128            $expectedDateTime->format(\DateTime::RFC3339),
129            $actualDateTime->format(\DateTime::RFC3339)
130        );
131    }
132}
133