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

testImplementsDateTimeTimeFactoryInterface()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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