[TASK] Shorten the extend class in all unit tests
[Packages/TYPO3.CMS.git] / typo3 / sysext / scheduler / Tests / Unit / CronCommand / CronCommandTest.php
1 <?php
2 namespace TYPO3\CMS\Scheduler\Tests\Unit\CronCommand;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Scheduler\CronCommand\CronCommand;
18 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
19
20 /**
21 * Test case
22 */
23 class CronCommandTest extends UnitTestCase
24 {
25 /**
26 * @var int timestamp of 1.1.2010 0:00 (Friday), timezone UTC/GMT
27 */
28 const TIMESTAMP = 1262304000;
29
30 /**
31 * @var string Selected timezone backup
32 */
33 protected $timezoneBackup = '';
34
35 /**
36 * We're fiddling with hard timestamps in the tests, but time methods in
37 * the system under test do use timezone settings. Therefore we backup the
38 * current timezone setting, set it to UTC explicitly and reconstitute it
39 * again in tearDown()
40 */
41 protected function setUp()
42 {
43 $this->timezoneBackup = date_default_timezone_get();
44 date_default_timezone_set('UTC');
45 }
46
47 protected function tearDown()
48 {
49 date_default_timezone_set($this->timezoneBackup);
50 parent::tearDown();
51 }
52
53 /**
54 * @test
55 */
56 public function constructorSetsNormalizedCronCommandSections()
57 {
58 $instance = new CronCommand('2-3 * * * *');
59 $this->assertSame(['2,3', '*', '*', '*', '*'], $instance->getCronCommandSections());
60 }
61
62 /**
63 * @test
64 */
65 public function constructorThrowsExceptionForInvalidCronCommand()
66 {
67 $this->expectException(\InvalidArgumentException::class);
68 $this->expectExceptionCode(1291470170);
69 new CronCommand('61 * * * *');
70 }
71
72 /**
73 * @test
74 */
75 public function constructorSetsTimestampToNowPlusOneMinuteRoundedDownToSixtySeconds()
76 {
77 $instance = new CronCommand('* * * * *');
78 $currentTime = time();
79 $expectedTime = $currentTime - ($currentTime % 60) + 60;
80 $this->assertSame($expectedTime, $instance->getTimestamp());
81 }
82
83 /**
84 * @test
85 */
86 public function constructorSetsTimestampToGivenTimestampPlusSixtySeconds()
87 {
88 $instance = new CronCommand('* * * * *', self::TIMESTAMP);
89 $this->assertSame(self::TIMESTAMP + 60, $instance->getTimestamp());
90 }
91
92 /**
93 * @test
94 */
95 public function constructorSetsTimestampToGiveTimestampRoundedDownToSixtySeconds()
96 {
97 $instance = new CronCommand('* * * * *', self::TIMESTAMP + 1);
98 $this->assertSame(self::TIMESTAMP + 60, $instance->getTimestamp());
99 }
100
101 /**
102 * @return array
103 */
104 public static function expectedTimestampDataProvider()
105 {
106 return [
107 'every minute' => [
108 '* * * * *',
109 self::TIMESTAMP,
110 self::TIMESTAMP + 60,
111 self::TIMESTAMP + 120
112 ],
113 'once an hour at 1' => [
114 '1 * * * *',
115 self::TIMESTAMP,
116 self::TIMESTAMP + 60,
117 self::TIMESTAMP + 60 + 60 * 60
118 ],
119 'once an hour at 0' => [
120 '0 * * * *',
121 self::TIMESTAMP,
122 self::TIMESTAMP + 60 * 60,
123 self::TIMESTAMP + 60 * 60 + 60 * 60
124 ],
125 'once a day at 1:00' => [
126 '0 1 * * *',
127 self::TIMESTAMP,
128 self::TIMESTAMP + 60 * 60,
129 self::TIMESTAMP + 60 * 60 + 60 * 60 * 24
130 ],
131 'once a day at 0:00' => [
132 '0 0 * * *',
133 self::TIMESTAMP,
134 self::TIMESTAMP + 60 * 60 * 24,
135 self::TIMESTAMP + 60 * 60 * 24 * 2
136 ],
137 'once a month' => [
138 '0 0 4 * *',
139 self::TIMESTAMP,
140 self::TIMESTAMP + 60 * 60 * 24 * 3,
141 self::TIMESTAMP + 60 * 60 * 24 * 3 + 60 * 60 * 24 * 31
142 ],
143 'once every Saturday' => [
144 '0 0 * * sat',
145 self::TIMESTAMP,
146 self::TIMESTAMP + 60 * 60 * 24,
147 self::TIMESTAMP + 60 * 60 * 24 + 60 * 60 * 24 * 7
148 ],
149 'once every day in February' => [
150 '0 0 * feb *',
151 self::TIMESTAMP,
152 self::TIMESTAMP + 60 * 60 * 24 * 31,
153 self::TIMESTAMP + 60 * 60 * 24 * 31 + 60 * 60 * 24
154 ],
155 'day of week and day of month restricted, next match in day of month field' => [
156 '0 0 2 * sun',
157 self::TIMESTAMP,
158 self::TIMESTAMP + 60 * 60 * 24,
159 self::TIMESTAMP + 60 * 60 * 24 + 60 * 60 * 24
160 ],
161 'day of week and day of month restricted, next match in day of week field' => [
162 '0 0 3 * sat',
163 self::TIMESTAMP,
164 self::TIMESTAMP + 60 * 60 * 24,
165 self::TIMESTAMP + 60 * 60 * 24 + 60 * 60 * 24
166 ],
167 'list of minutes' => [
168 '2,4 * * * *',
169 self::TIMESTAMP,
170 self::TIMESTAMP + 120,
171 self::TIMESTAMP + 240
172 ],
173 'list of hours' => [
174 '0 2,4 * * *',
175 self::TIMESTAMP,
176 self::TIMESTAMP + 60 * 60 * 2,
177 self::TIMESTAMP + 60 * 60 * 4
178 ],
179 ];
180 }
181
182 /**
183 * @return array
184 */
185 public static function expectedCalculatedTimestampDataProvider()
186 {
187 return [
188 'every first day of month' => [
189 '0 0 1 * *',
190 self::TIMESTAMP,
191 '01-02-2010',
192 '01-03-2010',
193 ],
194 'once every February' => [
195 '0 0 1 feb *',
196 self::TIMESTAMP,
197 '01-02-2010',
198 '01-02-2011',
199 ],
200 'once every Friday February' => [
201 '0 0 * feb fri',
202 self::TIMESTAMP,
203 '05-02-2010',
204 '12-02-2010',
205 ],
206 'first day in February and every Friday' => [
207 '0 0 1 feb fri',
208 self::TIMESTAMP,
209 '01-02-2010',
210 '05-02-2010',
211 ],
212 '29th February leap year' => [
213 '0 0 29 feb *',
214 self::TIMESTAMP,
215 '29-02-2012',
216 '29-02-2016',
217 ],
218 'list of days in month' => [
219 '0 0 2,4 * *',
220 self::TIMESTAMP,
221 '02-01-2010',
222 '04-01-2010',
223 ],
224 'list of month' => [
225 '0 0 1 2,3 *',
226 self::TIMESTAMP,
227 '01-02-2010',
228 '01-03-2010',
229 ],
230 'list of days of weeks' => [
231 '0 0 * * 2,4',
232 self::TIMESTAMP,
233 '05-01-2010',
234 '07-01-2010',
235 ]
236 ];
237 }
238
239 /**
240 * @test
241 * @dataProvider expectedTimestampDataProvider
242 * @param string $cronCommand Cron command
243 * @param int $startTimestamp Timestamp for start of calculation
244 * @param int $expectedTimestamp Expected result (next time of execution)
245 */
246 public function calculateNextValueDeterminesCorrectNextTimestamp($cronCommand, $startTimestamp, $expectedTimestamp)
247 {
248 $instance = new CronCommand($cronCommand, $startTimestamp);
249 $instance->calculateNextValue();
250 $this->assertSame($expectedTimestamp, $instance->getTimestamp());
251 }
252
253 /**
254 * @test
255 * @dataProvider expectedCalculatedTimestampDataProvider
256 * @param string $cronCommand Cron command
257 * @param int $startTimestamp Timestamp for start of calculation
258 * @param string $expectedTimestamp Expected result (next time of execution), to be feeded to strtotime
259 */
260 public function calculateNextValueDeterminesCorrectNextCalculatedTimestamp($cronCommand, $startTimestamp, $expectedTimestamp)
261 {
262 $instance = new CronCommand($cronCommand, $startTimestamp);
263 $instance->calculateNextValue();
264 $this->assertSame(strtotime($expectedTimestamp), $instance->getTimestamp());
265 }
266
267 /**
268 * @test
269 * @dataProvider expectedTimestampDataProvider
270 * @param string $cronCommand Cron command
271 * @param int $startTimestamp [unused] Timestamp for start of calculation
272 * @param int $firstTimestamp Timestamp of the next execution
273 * @param int $secondTimestamp Timestamp of the further execution
274 */
275 public function calculateNextValueDeterminesCorrectNextTimestampOnConsecutiveCall($cronCommand, $startTimestamp, $firstTimestamp, $secondTimestamp)
276 {
277 $instance = new CronCommand($cronCommand, $firstTimestamp);
278 $instance->calculateNextValue();
279 $this->assertSame($secondTimestamp, $instance->getTimestamp());
280 }
281
282 /**
283 * @test
284 * @dataProvider expectedCalculatedTimestampDataProvider
285 * @param string $cronCommand Cron command
286 * @param int $startTimestamp [unused] Timestamp for start of calculation
287 * @param string $firstTimestamp Timestamp of the next execution, to be fed to strtotime
288 * @param string $secondTimestamp Timestamp of the further execution, to be fed to strtotime
289 */
290 public function calculateNextValueDeterminesCorrectNextCalculatedTimestampOnConsecutiveCall($cronCommand, $startTimestamp, $firstTimestamp, $secondTimestamp)
291 {
292 $instance = new CronCommand($cronCommand, strtotime($firstTimestamp));
293 $instance->calculateNextValue();
294 $this->assertSame(strtotime($secondTimestamp), $instance->getTimestamp());
295 }
296
297 /**
298 * @test
299 */
300 public function calculateNextValueDeterminesCorrectNextTimestampOnChangeToSummertime()
301 {
302 $backupTimezone = date_default_timezone_get();
303 date_default_timezone_set('Europe/Berlin');
304 $instance = new CronCommand('* 3 28 mar *', self::TIMESTAMP);
305 $instance->calculateNextValue();
306 date_default_timezone_set($backupTimezone);
307 $this->assertSame(1269741600, $instance->getTimestamp());
308 }
309
310 /**
311 * @test
312 */
313 public function calculateNextValueThrowsExceptionWithImpossibleCronCommand()
314 {
315 $this->expectException(\RuntimeException::class);
316 $this->expectExceptionCode(1291501280);
317 $instance = new CronCommand('* * 31 apr *', self::TIMESTAMP);
318 $instance->calculateNextValue();
319 }
320
321 /**
322 * @test
323 */
324 public function getTimestampReturnsInteger()
325 {
326 $instance = new CronCommand('* * * * *');
327 $this->assertInternalType(\PHPUnit\Framework\Constraint\IsType::TYPE_INT, $instance->getTimestamp());
328 }
329
330 /**
331 * @test
332 */
333 public function getCronCommandSectionsReturnsArray()
334 {
335 $instance = new CronCommand('* * * * *');
336 $this->assertInternalType(\PHPUnit\Framework\Constraint\IsType::TYPE_ARRAY, $instance->getCronCommandSections());
337 }
338 }