Completed
Push — master ( 0f4167...4d5f71 )
by Kevin
13s queued 12s
created

TaskTest::cannot_set_invalid_cron_expression()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 6
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Zenstruck\ScheduleBundle\Tests\Schedule;
4
5
use PHPUnit\Framework\TestCase;
0 ignored issues
show
Bug introduced by
The type PHPUnit\Framework\TestCase was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Symfony\Component\Lock\LockFactory;
7
use Symfony\Component\Lock\Store\FlockStore;
8
use Symfony\Component\Mime\Email;
9
use Symfony\Contracts\HttpClient\HttpClientInterface;
10
use Zenstruck\ScheduleBundle\Event\AfterTaskEvent;
11
use Zenstruck\ScheduleBundle\Event\BeforeScheduleEvent;
12
use Zenstruck\ScheduleBundle\Event\BeforeTaskEvent;
13
use Zenstruck\ScheduleBundle\Schedule;
14
use Zenstruck\ScheduleBundle\Schedule\Exception\SkipTask;
15
use Zenstruck\ScheduleBundle\Schedule\Extension;
16
use Zenstruck\ScheduleBundle\Schedule\Task;
17
use Zenstruck\ScheduleBundle\Schedule\Task\Result;
18
use Zenstruck\ScheduleBundle\Tests\Fixture\MockTask;
19
20
/**
21
 * @author Kevin Bond <[email protected]>
22
 */
23
final class TaskTest extends TestCase
24
{
25
    /**
26
     * @test
27
     */
28
    public function can_set_description()
29
    {
30
        $task = self::createTask()->description('my description');
31
32
        $this->assertSame('my description', $task->getDescription());
33
        $this->assertSame('my description', (string) $task);
34
    }
35
36
    /**
37
     * @test
38
     */
39
    public function can_set_timezone()
40
    {
41
        $task = self::createTask();
42
43
        $this->assertNull($task->getTimezone());
44
45
        $task->timezone('UTC');
46
47
        $this->assertSame('UTC', $task->getTimezone()->getName());
48
49
        $task->timezone(new \DateTimeZone('America/Los_Angeles'));
50
51
        $this->assertSame('America/Los_Angeles', $task->getTimezone()->getName());
52
    }
53
54
    /**
55
     * @test
56
     */
57
    public function can_get_next_run()
58
    {
59
        $this->assertSame(
60
            (new \DateTime('1st Jan next year'))->getTimestamp(),
61
            self::createTask()->yearly()->getNextRun()->getTimestamp()
62
        );
63
    }
64
65
    /**
66
     * @test
67
     */
68
    public function can_determine_if_due()
69
    {
70
        $this->assertTrue(self::createTask()->everyMinute()->isDue());
71
    }
72
73
    /**
74
     * @test
75
     * @dataProvider frequencyProvider
76
     */
77
    public function can_fluently_create_frequency(callable $createTask, string $expectedExpression)
78
    {
79
        $this->assertSame($expectedExpression, (string) $createTask()->getExpression());
80
    }
81
82
    public static function frequencyProvider(): array
83
    {
84
        return [
85
            [function () { return self::createTask()->daily(); }, '0 0 * * *'],
86
            [function () { return self::createTask()->cron('0 0 * * *')->everyMinute(); }, '* 0 * * *'],
87
            [function () { return self::createTask()->everyFiveMinutes(); }, '*/5 * * * *'],
88
            [function () { return self::createTask()->everyTenMinutes(); }, '*/10 * * * *'],
89
            [function () { return self::createTask()->everyFifteenMinutes(); }, '*/15 * * * *'],
90
            [function () { return self::createTask()->everyThirtyMinutes(); }, '0,30 * * * *'],
91
            [function () { return self::createTask()->hourly(); }, '0 * * * *'],
92
            [function () { return self::createTask()->hourlyAt(6); }, '6 * * * *'],
93
            [function () { return self::createTask()->at('3'); }, '0 3 * * *'],
94
            [function () { return self::createTask()->at('3:16'); }, '16 3 * * *'],
95
            [function () { return self::createTask()->dailyAt('3'); }, '0 3 * * *'],
96
            [function () { return self::createTask()->twiceDaily(); }, '0 1,13 * * *'],
97
            [function () { return self::createTask()->twiceDaily(2, 14); }, '0 2,14 * * *'],
98
            [function () { return self::createTask()->weekdays(); }, '* * * * 1-5'],
99
            [function () { return self::createTask()->weekdays()->at(2); }, '0 2 * * 1-5'],
100
            [function () { return self::createTask()->weekends(); }, '* * * * 0,6'],
101
            [function () { return self::createTask()->mondays(); }, '* * * * 1'],
102
            [function () { return self::createTask()->tuesdays(); }, '* * * * 2'],
103
            [function () { return self::createTask()->wednesdays(); }, '* * * * 3'],
104
            [function () { return self::createTask()->thursdays(); }, '* * * * 4'],
105
            [function () { return self::createTask()->fridays(); }, '* * * * 5'],
106
            [function () { return self::createTask()->saturdays(); }, '* * * * 6'],
107
            [function () { return self::createTask()->sundays(); }, '* * * * 0'],
108
            [function () { return self::createTask()->days(1, 2, 3); }, '* * * * 1,2,3'],
109
            [function () { return self::createTask()->weekly(); }, '0 0 * * 0'],
110
            [function () { return self::createTask()->weekly()->at('3:15'); }, '15 3 * * 0'],
111
            [function () { return self::createTask()->monthly(); }, '0 0 1 * *'],
112
            [function () { return self::createTask()->monthlyOn(3); }, '0 0 3 * *'],
113
            [function () { return self::createTask()->monthlyOn(3, '4:15'); }, '15 4 3 * *'],
114
            [function () { return self::createTask()->twiceMonthly(); }, '0 0 1,16 * *'],
115
            [function () { return self::createTask()->twiceMonthly(3, 17); }, '0 0 3,17 * *'],
116
            [function () { return self::createTask()->twiceMonthly()->at('3:15'); }, '15 3 1,16 * *'],
117
            [function () { return self::createTask()->quarterly(); }, '0 0 1 1-12/3 *'],
118
            [function () { return self::createTask()->yearly(); }, '0 0 1 1 *'],
119
            [function () { return self::createTask('my task')->cron('H 0 * * *'); }, '56 0 * * *'],
120
            [function () { return self::createTask('my task')->cron('@daily'); }, '56 20 * * *'],
121
            [function () { return self::createTask('my task')->cron('@midnight'); }, '56 2 * * *'],
122
            [function () { return self::createTask('my task')->cron('@midnight')->daily(); }, '0 0 * * *'],
123
        ];
124
    }
125
126
    /**
127
     * @test
128
     */
129
    public function has_unique_id_based_on_description_and_frequency()
130
    {
131
        $this->assertSame(self::createTask()->getId(), self::createTask()->getId());
132
        $this->assertNotSame(self::createTask()->daily()->getId(), self::createTask()->getId());
133
        $this->assertNotSame(self::createTask('task1')->getId(), self::createTask('task2')->getId());
134
        $this->assertNotSame((new class('task') extends Task {
135
        })->getId(), self::createTask('task')->getId());
136
    }
137
138
    /**
139
     * @test
140
     */
141
    public function false_when_filter_skips_task()
142
    {
143
        $task = self::createTask();
144
145
        $task->when('boolean value', false);
146
147
        $this->expectException(SkipTask::class);
148
        $this->expectExceptionMessage('boolean value');
149
150
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
0 ignored issues
show
Bug introduced by
The method filterTask() does not exist on Zenstruck\ScheduleBundle\Schedule\Extension. It seems like you code against a sub-type of Zenstruck\ScheduleBundle\Schedule\Extension such as Zenstruck\ScheduleBundle...n\SelfHandlingExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

150
        $task->getExtensions()[0]->/** @scrutinizer ignore-call */ 
151
                                   filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
Loading history...
151
    }
152
153
    /**
154
     * @test
155
     */
156
    public function callback_returning_false_when_filter_skips_task()
157
    {
158
        $task = self::createTask();
159
160
        $task->when('callback value', function () { return false; });
161
162
        $this->expectException(SkipTask::class);
163
        $this->expectExceptionMessage('callback value');
164
165
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
166
    }
167
168
    /**
169
     * @test
170
     */
171
    public function true_when_filter_allows_task_to_run()
172
    {
173
        $task = self::createTask();
174
175
        $task->when('boolean value', true);
176
177
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
178
179
        $this->assertTrue(true);
180
    }
181
182
    /**
183
     * @test
184
     */
185
    public function callback_returning_true_when_filter_allows_task_to_run()
186
    {
187
        $task = self::createTask();
188
189
        $task->when('callback value', function () { return true; });
190
191
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
192
193
        $this->assertTrue(true);
194
    }
195
196
    /**
197
     * @test
198
     */
199
    public function true_skip_filter_skips_task()
200
    {
201
        $task = self::createTask();
202
203
        $task->skip('boolean value', true);
204
205
        $this->expectException(SkipTask::class);
206
        $this->expectExceptionMessage('boolean value');
207
208
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
209
    }
210
211
    /**
212
     * @test
213
     */
214
    public function callback_returning_true_skip_filter_skips_task()
215
    {
216
        $task = self::createTask();
217
218
        $task->skip('callback value', function () { return true; });
219
220
        $this->expectException(SkipTask::class);
221
        $this->expectExceptionMessage('callback value');
222
223
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
224
    }
225
226
    /**
227
     * @test
228
     */
229
    public function false_skip_filter_allows_task_to_run()
230
    {
231
        $task = self::createTask();
232
233
        $task->skip('boolean value', false);
234
235
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
236
237
        $this->assertTrue(true);
238
    }
239
240
    /**
241
     * @test
242
     */
243
    public function callback_returning_false_skip_filter_allows_task_to_run()
244
    {
245
        $task = self::createTask();
246
247
        $task->skip('callback value', function () { return false; });
248
249
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
250
251
        $this->assertTrue(true);
252
    }
253
254
    /**
255
     * @test
256
     */
257
    public function can_add_callback_extensions()
258
    {
259
        $task = self::createTask();
260
        $calls = [];
261
262
        $task->filter(function () use (&$calls) { $calls[] = 'filter'; });
263
        $task->before(function () use (&$calls) { $calls[] = 'before'; });
264
        $task->after(function () use (&$calls) { $calls[] = 'after'; });
265
        $task->then(function () use (&$calls) { $calls[] = 'then'; });
266
        $task->onSuccess(function () use (&$calls) { $calls[] = 'onSuccess'; });
267
        $task->onFailure(function () use (&$calls) { $calls[] = 'onFailure'; });
268
269
        $task->getExtensions()[0]->filterTask($event = new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
270
        $task->getExtensions()[1]->beforeTask($event);
0 ignored issues
show
Bug introduced by
The method beforeTask() does not exist on Zenstruck\ScheduleBundle\Schedule\Extension. It seems like you code against a sub-type of Zenstruck\ScheduleBundle\Schedule\Extension such as Zenstruck\ScheduleBundle...n\SelfHandlingExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

270
        $task->getExtensions()[1]->/** @scrutinizer ignore-call */ 
271
                                   beforeTask($event);
Loading history...
271
        $task->getExtensions()[2]->afterTask($event = new AfterTaskEvent($event, Result::successful($task)));
0 ignored issues
show
Bug introduced by
The method afterTask() does not exist on Zenstruck\ScheduleBundle\Schedule\Extension. It seems like you code against a sub-type of Zenstruck\ScheduleBundle\Schedule\Extension such as Zenstruck\ScheduleBundle...n\SelfHandlingExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

271
        $task->getExtensions()[2]->/** @scrutinizer ignore-call */ 
272
                                   afterTask($event = new AfterTaskEvent($event, Result::successful($task)));
Loading history...
272
        $task->getExtensions()[3]->afterTask($event);
273
        $task->getExtensions()[4]->onTaskSuccess($event);
0 ignored issues
show
Bug introduced by
The method onTaskSuccess() does not exist on Zenstruck\ScheduleBundle\Schedule\Extension. It seems like you code against a sub-type of Zenstruck\ScheduleBundle\Schedule\Extension such as Zenstruck\ScheduleBundle...n\SelfHandlingExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

273
        $task->getExtensions()[4]->/** @scrutinizer ignore-call */ 
274
                                   onTaskSuccess($event);
Loading history...
274
        $task->getExtensions()[5]->onTaskFailure($event);
0 ignored issues
show
Bug introduced by
The method onTaskFailure() does not exist on Zenstruck\ScheduleBundle\Schedule\Extension. It seems like you code against a sub-type of Zenstruck\ScheduleBundle\Schedule\Extension such as Zenstruck\ScheduleBundle...n\SelfHandlingExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

274
        $task->getExtensions()[5]->/** @scrutinizer ignore-call */ 
275
                                   onTaskFailure($event);
Loading history...
275
276
        $this->assertSame([
277
            'filter',
278
            'before',
279
            'after',
280
            'then',
281
            'onSuccess',
282
            'onFailure',
283
        ], $calls);
284
    }
285
286
    /**
287
     * @test
288
     */
289
    public function can_add_ping_extensions()
290
    {
291
        $task = self::createTask();
292
293
        $task->pingBefore('http://before.com');
294
        $task->pingAfter('http://after.com', 'POST');
295
        $task->thenPing('http://then.com');
296
        $task->pingOnSuccess('http://success.com');
297
        $task->pingOnFailure('http://failure.com');
298
299
        $client = $this->createMock(HttpClientInterface::class);
300
        $client->expects($this->exactly(5))->method('request')->withConsecutive(
301
            [$this->equalTo('GET'), $this->equalTo('http://before.com'), $this->isType('array')],
302
            [$this->equalTo('POST'), $this->equalTo('http://after.com'), $this->isType('array')],
303
            [$this->equalTo('GET'), $this->equalTo('http://then.com'), $this->isType('array')],
304
            [$this->equalTo('GET'), $this->equalTo('http://success.com'), $this->isType('array')],
305
            [$this->equalTo('GET'), $this->equalTo('http://failure.com'), $this->isType('array')]
306
        );
307
308
        $task->getExtensions()[0]->setHttpClient($client)->beforeTask($event = new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
0 ignored issues
show
Bug introduced by
The method setHttpClient() does not exist on Zenstruck\ScheduleBundle\Schedule\Extension. It seems like you code against a sub-type of Zenstruck\ScheduleBundle\Schedule\Extension such as Zenstruck\ScheduleBundle...Extension\PingExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

308
        $task->getExtensions()[0]->/** @scrutinizer ignore-call */ 
309
                                   setHttpClient($client)->beforeTask($event = new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
Loading history...
309
        $task->getExtensions()[1]->setHttpClient($client)->afterTask($event = new AfterTaskEvent($event, Result::successful($task)));
310
        $task->getExtensions()[2]->setHttpClient($client)->afterTask($event);
311
        $task->getExtensions()[3]->setHttpClient($client)->onTaskSuccess($event);
312
        $task->getExtensions()[4]->setHttpClient($client)->onTaskFailure($event);
313
    }
314
315
    /**
316
     * @test
317
     * @dataProvider emailAfterMethodProvider
318
     */
319
    public function can_add_email_after_extension($method)
320
    {
321
        $task = self::createTask();
322
        $task->{$method}('[email protected]', 'my subject', function (Email $email) {
323
            $email->cc('[email protected]');
324
        });
325
326
        $this->assertTrue($task->getExtensions()[0]->isHook(Extension::TASK_AFTER));
0 ignored issues
show
Bug introduced by
The method isHook() does not exist on Zenstruck\ScheduleBundle\Schedule\Extension. It seems like you code against a sub-type of Zenstruck\ScheduleBundle\Schedule\Extension such as Zenstruck\ScheduleBundle...xtension\EmailExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

326
        $this->assertTrue($task->getExtensions()[0]->/** @scrutinizer ignore-call */ isHook(Extension::TASK_AFTER));
Loading history...
327
        $this->assertSame('[email protected]', $task->getExtensions()[0]->getEmail()->getTo()[0]->toString());
0 ignored issues
show
Bug introduced by
The method getEmail() does not exist on Zenstruck\ScheduleBundle\Schedule\Extension. It seems like you code against a sub-type of Zenstruck\ScheduleBundle\Schedule\Extension such as Zenstruck\ScheduleBundle...xtension\EmailExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

327
        $this->assertSame('[email protected]', $task->getExtensions()[0]->/** @scrutinizer ignore-call */ getEmail()->getTo()[0]->toString());
Loading history...
328
        $this->assertSame('[email protected]', $task->getExtensions()[0]->getEmail()->getCc()[0]->toString());
329
        $this->assertSame('my subject', $task->getExtensions()[0]->getEmail()->getSubject());
330
    }
331
332
    public static function emailAfterMethodProvider()
333
    {
334
        return [
335
            ['emailAfter'],
336
            ['thenEmail'],
337
        ];
338
    }
339
340
    /**
341
     * @test
342
     */
343
    public function can_add_email_on_failure_extension()
344
    {
345
        $task = self::createTask();
346
        $task->emailOnFailure('[email protected]', 'my subject', function (Email $email) {
347
            $email->cc('[email protected]');
348
        });
349
350
        $this->assertTrue($task->getExtensions()[0]->isHook(Extension::TASK_FAILURE));
351
        $this->assertSame('[email protected]', $task->getExtensions()[0]->getEmail()->getTo()[0]->toString());
352
        $this->assertSame('[email protected]', $task->getExtensions()[0]->getEmail()->getCc()[0]->toString());
353
        $this->assertSame('my subject', $task->getExtensions()[0]->getEmail()->getSubject());
354
    }
355
356
    /**
357
     * @test
358
     */
359
    public function can_add_single_server_extension()
360
    {
361
        $task1 = self::createTask('task')->onSingleServer();
362
        $task2 = self::createTask('task')->onSingleServer();
363
364
        $lockFactory = new LockFactory(new FlockStore());
365
366
        $task1->getExtensions()[0]->aquireTaskLock($lockFactory, $task1, \time());
0 ignored issues
show
Bug introduced by
The method aquireTaskLock() does not exist on Zenstruck\ScheduleBundle\Schedule\Extension. It seems like you code against a sub-type of Zenstruck\ScheduleBundle\Schedule\Extension such as Zenstruck\ScheduleBundle...n\SingleServerExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

366
        $task1->getExtensions()[0]->/** @scrutinizer ignore-call */ 
367
                                    aquireTaskLock($lockFactory, $task1, \time());
Loading history...
367
368
        $this->expectException(SkipTask::class);
369
        $this->expectExceptionMessage('Task running on another server.');
370
371
        $task2->getExtensions()[0]->aquireTaskLock($lockFactory, $task2, \time());
372
    }
373
374
    /**
375
     * @test
376
     */
377
    public function can_add_without_overlapping_extension()
378
    {
379
        $task1 = self::createTask('task')->withoutOverlapping();
380
        $task2 = self::createTask('task')->withoutOverlapping();
381
382
        $task1->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task1));
383
384
        $this->expectException(SkipTask::class);
385
        $this->expectExceptionMessage('Task running in another process.');
386
387
        $task2->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task2));
388
    }
389
390
    /**
391
     * @test
392
     * @dataProvider betweenExtensionSkipProvider
393
     */
394
    public function between_extension_skip($start, $end, $inclusive)
395
    {
396
        $start = (new \DateTime($start))->format('H:i');
397
        $end = (new \DateTime($end))->format('H:i');
398
399
        $task = self::createTask()->between($start, $end, $inclusive);
400
401
        $this->expectException(SkipTask::class);
402
        $this->expectExceptionMessage("Only runs between {$start} and {$end}");
403
404
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
405
    }
406
407
    public static function betweenExtensionSkipProvider()
408
    {
409
        return [
410
            ['+2 minutes', '+3 minutes', true],
411
            ['now', '+3 minutes', false],
412
            ['+5 minutes', '+23 hours', true],
413
        ];
414
    }
415
416
    /**
417
     * @test
418
     * @dataProvider betweenExtensionRunProvider
419
     */
420
    public function between_extension_run($start, $end, $inclusive)
421
    {
422
        $start = (new \DateTime($start))->format('H:i');
423
        $end = (new \DateTime($end))->format('H:i');
424
425
        $task = self::createTask()->between($start, $end, $inclusive);
426
427
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
428
429
        $this->assertTrue(true);
430
    }
431
432
    public static function betweenExtensionRunProvider()
433
    {
434
        return [
435
            ['now', '+3 minutes', true],
436
            ['-1 minute', '+3 minutes', false],
437
            ['-1 minutes', '+23 hours', true],
438
        ];
439
    }
440
441
    /**
442
     * @test
443
     * @dataProvider unlessBetweenExtensionSkipProvider
444
     */
445
    public function unless_between_extension_skip($start, $end, $inclusive)
446
    {
447
        $start = (new \DateTime($start))->format('H:i');
448
        $end = (new \DateTime($end))->format('H:i');
449
450
        $task = self::createTask()->unlessBetween($start, $end, $inclusive);
451
452
        $this->expectException(SkipTask::class);
453
        $this->expectExceptionMessage("Only runs if not between {$start} and {$end}");
454
455
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
456
    }
457
458
    public static function unlessBetweenExtensionSkipProvider()
459
    {
460
        return [
461
            ['-1 minute', '+3 minutes', false],
462
            ['now', '+3 minutes', true],
463
            ['-1 minutes', '+23 hours', true],
464
        ];
465
    }
466
467
    /**
468
     * @test
469
     * @dataProvider unlessBetweenExtensionRunProvider
470
     */
471
    public function unless_between_extension_run($start, $end, $inclusive)
472
    {
473
        $start = (new \DateTime($start))->format('H:i');
474
        $end = (new \DateTime($end))->format('H:i');
475
476
        $task = self::createTask()->unlessBetween($start, $end, $inclusive);
477
478
        $task->getExtensions()[0]->filterTask(new BeforeTaskEvent(new BeforeScheduleEvent(new Schedule()), $task));
479
480
        $this->assertTrue(true);
481
    }
482
483
    public static function unlessBetweenExtensionRunProvider()
484
    {
485
        return [
486
            ['now', '+3 minutes', false],
487
            ['+1 minute', '+3 minutes', true],
488
            ['+5 minutes', '+23 hours', true],
489
        ];
490
    }
491
492
    private static function createTask(string $description = 'task description'): Task
493
    {
494
        return new MockTask($description);
495
    }
496
}
497