Passed
Pull Request — master (#7)
by Alex
12:05
created

DateTimeFactoryTest::testCreateDateTimeZone()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 3
c 1
b 1
f 0
dl 0
loc 7
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ArpTest\DateTime;
6
7
use Arp\DateTime\DateIntervalFactoryInterface;
8
use Arp\DateTime\DateTimeFactory;
9
use Arp\DateTime\DateTimeFactoryInterface;
10
use Arp\DateTime\Exception\DateTimeFactoryException;
11
use PHPUnit\Framework\MockObject\MockObject;
12
use PHPUnit\Framework\TestCase;
13
14
/**
15
 * @author  Alex Patterson <[email protected]>
16
 * @package ArpTest\DateTime
17
 */
18
class DateTimeFactoryTest extends TestCase
19
{
20
    /**
21
     * @var DateIntervalFactoryInterface|MockObject
22
     */
23
    private $dateIntervalFactory;
24
25
    /**
26
     * Prepare the test case dependencies
27
     */
28
    public function setUp(): void
29
    {
30
        $this->dateIntervalFactory = $this->getMockForAbstractClass(DateIntervalFactoryInterface::class);
31
    }
32
33
    /**
34
     * Ensure that the factory implements DateTimeFactoryInterface.
35
     *
36
     * @covers \Arp\DateTime\DateTimeFactory
37
     */
38
    public function testImplementsDateTimeTimeFactoryInterface(): void
39
    {
40
        $factory = new DateTimeFactory();
41
42
        $this->assertInstanceOf(DateTimeFactoryInterface::class, $factory);
43
    }
44
45
    /**
46
     * Ensure that calls to createDateTime() will return the valid configured \DateTime instance.
47
     *
48
     * @param string                    $spec     The date and time specification.
49
     * @param \DateTimeZone|string|null $timeZone The optional date time zone to test.
50
     *
51
     * @dataProvider getCreateDateTimeData
52
     *
53
     * @covers       \Arp\DateTime\DateTimeFactory::createDateTime
54
     * @covers       \Arp\DateTime\DateTimeFactory::resolveDateTimeZone
55
     *
56
     * @throws DateTimeFactoryException
57
     */
58
    public function testCreateDateTime(string $spec, $timeZone = null): void
59
    {
60
        $factory = new DateTimeFactory();
61
62
        $dateTime = $factory->createDateTime($spec, $timeZone);
63
64
        $this->assertSame($spec, $dateTime->format('Y-m-d H:i:s'));
65
    }
66
67
    /**
68
     * @return array
69
     */
70
    public function getCreateDateTimeData(): array
71
    {
72
        return [
73
            [
74
                '2019-05-14 12:33:00',
75
            ],
76
77
            [
78
                '2019-08-14 17:34:55',
79
                'UTC',
80
            ],
81
82
            [
83
                '2020-08-22 14:43:12',
84
                null,
85
            ],
86
87
            [
88
                '2020-08-22 14:44:37',
89
                new \DateTimeZone('Europe/London'),
90
            ],
91
        ];
92
    }
93
94
    /**
95
     * Ensure that if the DateTime cannot be create a new DateTimeFactoryException will be thrown.
96
     *
97
     * @covers \Arp\DateTime\DateTimeFactory::createDateTime
98
     *
99
     * @throws DateTimeFactoryException
100
     */
101
    public function testCreateDateTimeWillThrowDateTimeFactoryException(): void
102
    {
103
        $factory = new DateTimeFactory();
104
105
        $spec = 'foo'; // invalid argument
106
107
        $exceptionMessage = sprintf(
108
            'DateTime::__construct(): Failed to parse time string (%s) at position 0 (%s)',
109
            $spec,
110
            $spec[0]
111
        );
112
113
        $this->expectException(DateTimeFactoryException::class);
114
        $this->expectExceptionMessage(
115
            sprintf(
116
                'Failed to create a valid \DateTime instance using \'%s\': %s',
117
                $spec,
118
                $exceptionMessage
119
            )
120
        );
121
122
        $factory->createDateTime($spec);
123
    }
124
125
    /**
126
     * Ensure that a createFromFormat() will throw a DateTimeFactoryException if a \DateTime instance cannot be created.
127
     *
128
     * @param string                    $spec
129
     * @param string                    $format
130
     * @param \DateTimeZone|string|null $timeZone
131
     *
132
     * @dataProvider getCreateFromFormatWillThrowDateTimeFactoryExceptionData
133
     *
134
     * @covers       \Arp\DateTime\DateTimeFactory::createFromFormat
135
     *
136
     * @throws DateTimeFactoryException
137
     */
138
    public function testCreateFromFormatWillThrowDateTimeFactoryException(
139
        string $spec,
140
        string $format,
141
        $timeZone = null
142
    ): void {
143
        $factory = new DateTimeFactory();
144
145
        $this->expectException(DateTimeFactoryException::class);
146
        $this->expectExceptionMessage(
147
            sprintf(
148
                'Failed to create a valid \DateTime instance using \'%s\' and format \'%s\'',
149
                $spec,
150
                $format
151
            )
152
        );
153
154
        $factory->createFromFormat($spec, $format, $timeZone);
155
    }
156
157
    /**
158
     * @return array
159
     */
160
    public function getCreateFromFormatWillThrowDateTimeFactoryExceptionData(): array
161
    {
162
        return [
163
            [
164
                'test',
165
                'Y-m-d',
166
            ],
167
        ];
168
    }
169
170
    /**
171
     * Ensure that a \DateTime instance can be created from the provided format.
172
     *
173
     * @param string                    $spec
174
     * @param string                    $format
175
     * @param string|\DateTimeZone|null $timeZone
176
     *
177
     * @dataProvider getCreateFromFormatData
178
     *
179
     * @covers       \Arp\DateTime\DateTimeFactory::createFromFormat
180
     * @covers       \Arp\DateTime\DateTimeFactory::resolveDateTimeZone
181
     *
182
     * @throws DateTimeFactoryException
183
     */
184
    public function testCreateFromFormat(string $spec, string $format, $timeZone = null): void
185
    {
186
        $factory = new DateTimeFactory($this->dateIntervalFactory);
187
188
        $dateTime = $factory->createFromFormat($spec, $format, $timeZone);
189
190
        $this->assertSame($spec, $dateTime->format($format));
191
192
        if (null !== $timeZone) {
193
            $this->assertSame($timeZone, $dateTime->getTimezone()->getName());
194
        }
195
    }
196
197
    /**
198
     * @see https://www.php.net/manual/en/timezones.europe.php
199
     *
200
     * @return array
201
     */
202
    public function getCreateFromFormatData(): array
203
    {
204
        return [
205
            [
206
                '2019-04-01',
207
                'Y-m-d',
208
            ],
209
            [
210
                '1976/01/14',
211
                'Y/m/d',
212
            ],
213
            [
214
                '2019-08-14 17:34:55',
215
                'Y-m-d H:i:s',
216
                'UTC',
217
            ],
218
            [
219
                '2010-10-26 11:19:32',
220
                'Y-m-d H:i:s',
221
                'Europe/London',
222
            ],
223
        ];
224
    }
225
226
    /**
227
     * Ensure a \DateTimeZone instance is returned according to the provided $spec and $options.
228
     *
229
     * @param string $spec
230
     *
231
     * @dataProvider getCreateDateTimeZoneData
232
     *
233
     * @covers       \Arp\DateTime\DateTimeFactory::createDateTimeZone
234
     *
235
     * @throws DateTimeFactoryException
236
     */
237
    public function testCreateDateTimeZone(string $spec): void
238
    {
239
        $factory = new DateTimeFactory();
240
241
        $dateTimeZone = $factory->createDateTimeZone($spec);
242
243
        $this->assertSame($spec, $dateTimeZone->getName());
244
    }
245
246
    /**
247
     * @see https://www.php.net/manual/en/timezones.europe.php
248
     *
249
     * @return array
250
     */
251
    public function getCreateDateTimeZoneData(): array
252
    {
253
        return [
254
            [
255
                'Europe/London',
256
            ],
257
            [
258
                'Europe/Amsterdam',
259
            ],
260
            [
261
                'Europe/Rome',
262
            ],
263
            [
264
                'Atlantic/Bermuda',
265
            ],
266
            [
267
                'Atlantic/Azores',
268
            ],
269
            [
270
                'Antarctica/DumontDUrville',
271
            ],
272
        ];
273
    }
274
275
    /**
276
     * Ensure that if providing an invalid $spec argument to createDateTimeZone() a new DateTimeFactoryException
277
     * is thrown.
278
     *
279
     * @param string $spec The invalid timezone specification.
280
     *
281
     * @throws DateTimeFactoryException
282
     *
283
     * @dataProvider getCreateDateTimeZoneWillThrowDateTimeFactoryExceptionIfSpecIsInvalidData
284
     *
285
     * @covers       \Arp\DateTime\DateTimeFactory::createDateTimeZone
286
     */
287
    public function testCreateDateTimeZoneWillThrowDateTimeFactoryExceptionIfSpecIsInvalid(string $spec): void
288
    {
289
        $factory = new DateTimeFactory();
290
291
        $exceptionMessage = sprintf('DateTimeZone::__construct(): Unknown or bad timezone (%s)', $spec);
292
293
        $this->expectException(DateTimeFactoryException::class);
294
        $this->expectExceptionMessage(
295
            sprintf(
296
                'Failed to create a valid \DateTimeZone instance using \'%s\': %s',
297
                $spec,
298
                $exceptionMessage
299
            )
300
        );
301
302
        $factory->createDateTimeZone($spec);
303
    }
304
305
    /**
306
     * @return array
307
     */
308
    public function getCreateDateTimeZoneWillThrowDateTimeFactoryExceptionIfSpecIsInvalidData(): array
309
    {
310
        return [
311
            [
312
                'skjdvbnksd',
313
            ],
314
            [
315
                '2345234',
316
            ],
317
            [
318
                'Europe/MyEmpire',
319
            ],
320
        ];
321
    }
322
}
323