Issues (300)

src/Cli/Kahlan.php (17 issues)

1
<?php
2
namespace Kahlan\Cli {
3
4
    use Kahlan\Jit\Patcher\FinalClass;
5
    use RecursiveDirectoryIterator;
6
    use RecursiveIteratorIterator;
7
    use Kahlan\Dir\Dir;
8
    use Kahlan\Jit\ClassLoader;
9
    use Kahlan\Filter\Filters;
10
    use Kahlan\Matcher;
11
    use Kahlan\Jit\Patcher\Pointcut;
12
    use Kahlan\Jit\Patcher\Monkey;
13
    use Kahlan\Jit\Patcher\Quit;
14
    use Kahlan\Plugin\Quit as QuitStatement;
15
    use Kahlan\Reporters;
16
    use Kahlan\Reporter\Terminal;
17
    use Kahlan\Reporter\Coverage;
18
    use Kahlan\Reporter\Coverage\Driver\Phpdbg;
19
    use Kahlan\Reporter\Coverage\Driver\Xdebug;
20
    use Kahlan\Reporter\Coverage\Exporter\Clover;
21
    use Kahlan\Reporter\Coverage\Exporter\Istanbul;
22
    use Kahlan\Reporter\Coverage\Exporter\Lcov;
23
24
    class Kahlan
25
    {
26
        public const VERSION = '5.2.7';
27
28
        /**
29
         * Starting time.
30
         *
31
         * @var float
32
         */
33
        protected $_start = 0;
34
35
        /**
36
         * The suite instance.
37
         *
38
         * @var object
39
         */
40
        protected $_suite = null;
41
42
        /**
43
         * The runtime autoloader.
44
         *
45
         * @var object
46
         */
47
        protected $_autoloader = null;
48
49
        /**
50
         * The reporter container.
51
         *
52
         * @var object
53
         */
54
        protected $_reporters = null;
55
56
        /**
57
         * The arguments.
58
         *
59
         * @var object
60
         */
61
        protected $_commandLine = null;
62
63
        /**
64
         * Warning !
65
         * This method should only be called by Composer as an attempt to auto clear up caches automatically
66
         * when the version of Kahlan is updated.
67
         * It will have no effect if the cache location is changed the default config file (i.e. `'kahlan-config.php'`).
68
         */
69
        public static function composerPostUpdate($event)
70
        {
71
            $cachePath = rtrim(realpath(sys_get_temp_dir()), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'kahlan';
72
            if (!file_exists($cachePath)) {
73
                return;
74
            }
75
76
            $dir = new RecursiveDirectoryIterator($cachePath, RecursiveDirectoryIterator::SKIP_DOTS);
77
            $files = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::CHILD_FIRST);
78
79
            foreach ($files as $file) {
80
                $path = $file->getRealPath();
81
                $file->isDir() ? rmdir($path) : unlink($path);
82
            }
83
            rmdir($cachePath);
84
        }
85
86
        /**
87
         * The Constructor.
88
         *
89
         * @param array $options Possible options are:
90
         *                       - `'autoloader'` _object_ : The autoloader instance.
91
         *                       - `'suite'`      _object_ : The suite instance.
92
         */
93
        public function __construct($options = [])
94
        {
95
            $defaults = ['autoloader' => null, 'suite' => null];
96
            $options += $defaults;
97
98
            $this->_autoloader = $options['autoloader'];
99
            $this->_suite = $options['suite'];
100
101
            $this->_reporters = new Reporters();
102
            $this->_commandLine = $commandLine = new CommandLine();
103
104
            $commandLine->option('src',       ['array'   => true, 'default' => ['src']]);
105
            $commandLine->option('spec',      ['array'   => true, 'default' => ['spec']]);
106
            $commandLine->option('reporter',  ['array'   => true, 'default' => ['dot']]);
107
            $commandLine->option('grep',      ['default' => ['*Spec.php', '*.spec.php']]);
108
            $commandLine->option('coverage',  ['type'    => 'string']);
109
            $commandLine->option('config',    ['default' => 'kahlan-config.php']);
110
            $commandLine->option('part',      ['type'    => 'string',  'default' => '1/1']);
111
            $commandLine->option('ff',        ['type'    => 'numeric', 'default' => 0]);
112
            $commandLine->option('cc',        ['type'    => 'boolean', 'default' => false]);
113
            $commandLine->option('no-colors', ['type'    => 'boolean', 'default' => false]);
114
            $commandLine->option('no-header', ['type'    => 'boolean', 'default' => false]);
115
            $commandLine->option('include',   [
116
                'array' => true,
117
                'default' => ['*'],
118
                'value' => function ($value) {
119
                    return array_filter($value);
120
                }
121
            ]);
122
            $commandLine->option('exclude',    [
123
                'array' => true,
124
                'default' => [],
125
                'value' => function ($value) {
126
                    return array_filter($value);
127
                }
128
            ]);
129
            $commandLine->option('persistent', ['type'  => 'boolean', 'default' => true]);
130
            $commandLine->option('autoclear',  ['array' => true, 'default' => [
131
                \Kahlan\Plugin\Monkey::class,
132
                \Kahlan\Plugin\Stub::class,
133
                QuitStatement::class,
134
                \Kahlan\Plugin\Call\Calls::class
135
            ]]);
136
        }
137
138
        /**
139
         * Get/set the attached autoloader instance.
140
         *
141
         * @return object
142
         */
143
        public function autoloader($autoloader = null)
144
        {
145
            if (!func_num_args()) {
146
                return $this->_autoloader;
147
            }
148
            $this->_autoloader = $autoloader;
149
            return $this;
150
        }
151
152
        /**
153
         * Returns arguments instance.
154
         *
155
         * @return object
156
         */
157
        public function commandLine()
158
        {
159
            return $this->_commandLine;
160
        }
161
162
        /**
163
         * Returns the suite instance.
164
         *
165
         * @return object
166
         */
167
        public function suite()
168
        {
169
            return $this->_suite;
170
        }
171
172
        /**
173
         * Returns the reporter container.
174
         *
175
         * @return object
176
         */
177
        public function reporters()
178
        {
179
            return $this->_reporters;
180
        }
181
182
        /**
183
         * Load the config.
184
         *
185
         * @param string $argv The command line string.
186
         */
187
        public function loadConfig($argv = [])
188
        {
189
            $commandLine = new CommandLine();
190
            $commandLine->option('config',  ['default'  => 'kahlan-config.php']);
191
            $commandLine->option('help',    ['type'     => 'boolean']);
192
            $commandLine->option('version', ['type'     => 'boolean']);
193
            $commandLine->parse($argv);
194
195
            $run = function ($commandLine) {
196
                if (file_exists($commandLine->get('config'))) {
197
                    require $commandLine->get('config');
198
                }
199
            };
200
            $run($commandLine);
201
            $this->_commandLine->parse($argv, false);
202
203
            if ($commandLine->get('help')) {
204
                $this->_help();
205
            } elseif ($commandLine->get('version')) {
206
                $this->_version();
207
            }
208
        }
209
210
        /**
211
         * Init patchers
212
         */
213
        public function initPatchers()
214
        {
215
            return Filters::run($this, 'patchers', [], function ($chain) {
216
                if (!$loader = ClassLoader::instance()) {
217
                    return;
218
                }
219
                $patchers = $loader->patchers();
220
                $patchers->add('final',    new FinalClass());
221
                $patchers->add('pointcut', new Pointcut());
222
                $patchers->add('monkey',   new Monkey());
223
                $patchers->add('quit',     new Quit());
224
            });
225
        }
226
227
        /**
228
         * Gets the default terminal console.
229
         *
230
         * @return object The default terminal console.
231
         */
232
        public function terminal()
233
        {
234
            return new Terminal([
235
                'colors' => !$this->commandLine()->get('no-colors'),
236
                'header' => !$this->commandLine()->get('no-header')
237
            ]);
238
        }
239
240
        /**
241
         * Echoes the Kahlan version.
242
         */
243
        protected function _version()
244
        {
245
            $terminal = $this->terminal();
246
            if (!$this->commandLine()->get('no-header')) {
247
                $terminal->write($terminal->kahlan() ."\n\n");
248
                $terminal->write($terminal->kahlanBaseline(), 'dark-grey');
249
                $terminal->write("\n\n");
250
            }
251
252
            $terminal->write("version ");
253
            $terminal->write(static::VERSION, 'green');
254
            $terminal->write("\n\n");
255
            $terminal->write("For additional help you must use ");
256
            $terminal->write("--help", 'green');
257
            $terminal->write("\n\n");
258
            QuitStatement::quit();
259
        }
260
261
        /**
262
         * Echoes the help message.
263
         */
264
        protected function _help()
265
        {
266
            $terminal = $this->terminal();
267
            if (!$this->commandLine()->get('no-header')) {
268
                $terminal->write($terminal->kahlan() ."\n\n");
269
                $terminal->write($terminal->kahlanBaseline(), 'dark-grey');
270
                $terminal->write("\n\n");
271
            }
272
            $help = <<<EOD
273
274
Usage: kahlan [options]
275
276
Configuration Options:
277
278
  --config=<file>                     The PHP configuration file to use (default: `'kahlan-config.php'`).
279
  --src=<path>                        Paths of source directories (default: `['src']`).
280
  --spec=<path>                       Paths of specification directories (default: `['spec']`).
281
  --grep=<pattern>                    A shell wildcard pattern (default: `['*Spec.php', '*.spec.php']`).
282
283
Reporter Options:
284
285
  --reporter=<name>[:<output_file>]   The name of the text reporter to use, the built-in text reporters
286
                                      are `'dot'`, `'bar'`, `'json'`, `'tap'`, `'tree'` & `'verbose'` (default: `'dot'`).
287
                                      You can optionally redirect the reporter output to a file by using the
288
                                      colon syntax (multiple --reporter options are also supported).
289
290
Code Coverage Options:
291
292
  --coverage=<integer|string>         Generate code coverage report. The value specify the level of
293
                                      detail for the code coverage report (0-4). If a namespace, class, or
294
                                      method definition is provided, it will generate a detailed code
295
                                      coverage of this specific scope (default `''`).
296
  --clover=<file>                     Export code coverage report into a Clover XML format.
297
  --istanbul=<file>                   Export code coverage report into an istanbul compatible JSON format.
298
  --lcov=<file>                       Export code coverage report into a lcov compatible text format.
299
300
Test Execution Options:
301
302
  --part=<integer>/<integer>          Part to execute, useful for parallel testing (default: `1/1`).
303
  --ff=<integer>                      Fast fail option. `0` mean unlimited (default: `0`).
304
  --no-colors=<boolean>               To turn off colors. (default: `false`).
305
  --no-header=<boolean>               To turn off header. (default: `false`).
306
  --include=<string>                  Paths to include for patching. (default: `['*']`).
307
  --exclude=<string>                  Paths to exclude from patching. (default: `[]`).
308
  --persistent=<boolean>              Cache patched files (default: `true`).
309
  --cc=<boolean>                      Clear cache before spec run. (default: `false`).
310
  --autoclear                         Classes to autoclear after each spec (default: [
311
                                          `'Kahlan\Plugin\Monkey'`,
312
                                          `'Kahlan\Plugin\Call'`,
313
                                          `'Kahlan\Plugin\Stub'`,
314
                                          `'Kahlan\Plugin\Quit'`
315
                                      ])
316
317
Miscellaneous Options:
318
319
  --help                 Prints this usage information.
320
  --version              Prints Kahlan version
321
322
Note: The `[]` notation in default values mean that the related option can accepts an array of values.
323
To add additional values, just repeat the same option many times in the command line.
324
325
326
EOD;
327
            $terminal->write($help);
328
            QuitStatement::quit();
329
        }
330
331
        /**
332
         * Regiter built-in matchers.
333
         */
334
        public static function registerMatchers()
335
        {
336
            Matcher::register('toBe',             \Kahlan\Matcher\ToBe::class);
337
            Matcher::register('toBeA',            \Kahlan\Matcher\ToBeA::class);
338
            Matcher::register('toBeAn',           \Kahlan\Matcher\ToBeA::class);
339
            Matcher::register('toBeAnInstanceOf', \Kahlan\Matcher\ToBeAnInstanceOf::class);
340
            Matcher::register('toBeCloseTo',      \Kahlan\Matcher\ToBeCloseTo::class);
341
            Matcher::register('toBeEmpty',        \Kahlan\Matcher\ToBeFalsy::class);
342
            Matcher::register('toBeFalsy',        \Kahlan\Matcher\ToBeFalsy::class);
343
            Matcher::register('toBeGreaterThan',  \Kahlan\Matcher\ToBeGreaterThan::class);
344
            Matcher::register('toBeLessThan',     \Kahlan\Matcher\ToBeLessThan::class);
345
            Matcher::register('toBeNull',         \Kahlan\Matcher\ToBeNull::class);
346
            Matcher::register('toBeTruthy',       \Kahlan\Matcher\ToBeTruthy::class);
347
            Matcher::register('toContain',        \Kahlan\Matcher\ToContain::class);
348
            Matcher::register('toContainKey',     \Kahlan\Matcher\ToContainKey::class);
349
            Matcher::register('toContainKeys',    \Kahlan\Matcher\ToContainKey::class);
350
            Matcher::register('toEcho',           \Kahlan\Matcher\ToEcho::class);
351
            Matcher::register('toEqual',          \Kahlan\Matcher\ToEqual::class);
352
            Matcher::register('toHaveLength',     \Kahlan\Matcher\ToHaveLength::class);
353
            Matcher::register('toMatch',          \Kahlan\Matcher\ToMatch::class);
354
            Matcher::register('toReceive',        \Kahlan\Matcher\ToReceive::class);
355
            Matcher::register('toBeCalled',       \Kahlan\Matcher\ToBeCalled::class);
356
            Matcher::register('toThrow',          \Kahlan\Matcher\ToThrow::class);
357
            Matcher::register('toMatchEcho',      \Kahlan\Matcher\ToMatchEcho::class);
358
        }
359
360
        /**
361
         * Run the workflow.
362
         */
363
        public function run()
364
        {
365
            if (!defined('KAHLAN_FUNCTIONS_EXIST') && (!defined('KAHLAN_DISABLE_FUNCTIONS') || !KAHLAN_DISABLE_FUNCTIONS)) {
0 ignored issues
show
The constant Kahlan\Cli\KAHLAN_DISABLE_FUNCTIONS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
366
                fwrite(STDERR, "Kahlan's global functions are missing because of some naming collisions with another library.\n");
367
                exit(1);
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
368
            }
369
370
            $this->_start = microtime(true);
371
            return Filters::run($this, 'workflow', [], function ($chain) {
372
                $this->_bootstrap();
373
374
                $this->_namespaces();
375
376
                $this->_load();
377
378
                $this->_reporters();
379
380
                $this->_matchers();
381
382
                $this->_run();
383
384
                $this->_reporting();
385
386
                $this->_stop();
387
388
                $this->_quit();
389
            });
390
        }
391
392
        /**
393
         * Returns the exit status.
394
         *
395
         * @return integer The exit status.
396
         */
397
        public function status()
398
        {
399
            return $this->suite()->status();
400
        }
401
402
        /**
403
         * The default `'bootstrap'` filter.
404
         */
405
        protected function _bootstrap()
406
        {
407
            return Filters::run($this, 'bootstrap', [], function ($chain) {
408
                $this->suite()->backtraceFocus($this->commandLine()->get('grep'));
409
                if (!$this->commandLine()->exists('coverage')) {
410
                    if ($this->commandLine()->exists('clover') || $this->commandLine()->exists('istanbul') || $this->commandLine()->exists('lcov')) {
411
                        $this->commandLine()->set('coverage', 1);
412
                    }
413
                }
414
            });
415
        }
416
417
        /**
418
         * The default `'namespace'` filter.
419
         */
420
        protected function _namespaces()
421
        {
422
            return Filters::run($this, 'namespaces', [], function ($chain) {
423
                $paths = $this->commandLine()->get('spec');
424
                foreach ($paths as $path) {
425
                    $path = realpath($path);
426
                    $namespace = basename($path) . '\\';
427
                    $this->autoloader()->add($namespace, dirname($path));
428
                }
429
            });
430
        }
431
432
        /**
433
         * The default `'load'` filter.
434
         */
435
        protected function _load()
436
        {
437
            return Filters::run($this, 'load', [], function ($chain) {
438
                $specDirs = $this->commandLine()->get('spec');
439
                foreach ($specDirs as $dir) {
440
                    if (!file_exists($dir)) {
441
                        fwrite(STDERR, "ERROR: unexisting `{$dir}` directory, use --spec option to set a valid one (ex: --spec=tests).\n");
442
                        exit(1);
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
443
                    }
444
                }
445
                $files = Dir::scan($specDirs, [
446
                    'include' => $this->commandLine()->get('grep'),
447
                    'exclude' => '*/.*',
448
                    'type' => 'file'
449
                ]);
450
                sort($files);
451
452
                foreach ($files as $file) {
453
                    require $file;
454
                }
455
            });
456
        }
457
458
        /**
459
         * The default `'reporters'` filter.
460
         */
461
        protected function _reporters()
462
        {
463
            return Filters::run($this, 'reporters', [], function ($chain) {
464
                $this->_console();
465
                $this->_coverage();
466
            });
467
        }
468
469
        /**
470
         * The default `'console'` filter.
471
         */
472
        protected function _console()
473
        {
474
            return Filters::run($this, 'console', [], function ($chain) {
475
                $collection = $this->reporters();
476
477
                $reporters = $this->commandLine()->get('reporter');
478
                if (!$reporters) {
479
                    return;
480
                }
481
482
                foreach ($reporters as $reporter) {
483
                    $parts = explode(":", $reporter);
484
                    $name = $parts[0];
485
                    $output = $parts[1] ?? null;
486
487
                    $args = $this->commandLine()->get('dot');
488
                    $args = $args ?: [];
489
490
                    if (!$name === null || $name === 'none') {
491
                        continue;
492
                    }
493
494
                    $params = $args + [
495
                        'start'  => $this->_start,
496
                        'colors' => !$this->commandLine()->get('no-colors'),
497
                        'header' => !$this->commandLine()->get('no-header'),
498
                        'src'    => $this->commandLine()->get('src'),
499
                        'spec'   => $this->commandLine()->get('spec'),
500
                    ];
501
502
                    if (isset($output) && strlen($output) > 0) {
503
                        if (file_exists($output) && !is_writable($output)) {
504
                            fwrite(STDERR, "Error: please check that file '{$output}' is writable\n");
505
                        } else {
506
                            $file = @fopen($output, 'w');
507
                            if (!$file) {
508
                                fwrite(STDERR, "Error: can't create file '{$output}' for write\n");
509
                            } else {
510
                                $params['output'] = $file;
511
                            }
512
                        }
513
                    }
514
515
                    $class = 'Kahlan\Reporter\\' . str_replace(' ', '', ucwords(str_replace(['_', '-'], ' ', trim($name))));
516
                    if (!class_exists($class)) {
517
                        fwrite(STDERR, "Error: unexisting reporter `'{$name}'` can't find class `$class`.\n");
518
                        exit(1);
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
519
                    }
520
                    $collection->add($name, new $class($params));
521
                }
522
            });
523
        }
524
525
        /**
526
         * The default `'coverage'` filter.
527
         */
528
        protected function _coverage()
529
        {
530
            return Filters::run($this, 'coverage', [], function ($chain) {
531
                if (!$this->commandLine()->exists('coverage')) {
532
                    return;
533
                }
534
                $reporters = $this->reporters();
535
                $driver = null;
536
537
                if (PHP_SAPI === 'phpdbg') {
538
                    $driver = new Phpdbg();
539
                } elseif (extension_loaded('xdebug')) {
540
                    $driver = new Xdebug();
541
                } else {
542
                    fwrite(STDERR, "ERROR: PHPDBG SAPI has not been detected and Xdebug is not installed, code coverage can't be used.\n");
543
                    exit(1);
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
544
                }
545
                $srcDirs = $this->commandLine()->get('src');
546
                foreach ($srcDirs as $dir) {
547
                    if (!file_exists($dir)) {
548
                        fwrite(STDERR, "ERROR: unexisting `{$dir}` directory, use --src option to set a valid one (ex: --src=app).\n");
549
                        exit(1);
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
550
                    }
551
                }
552
                $coverage = new Coverage([
553
                    'verbosity' => $this->commandLine()->get('coverage') ?? 1,
554
                    'driver' => $driver,
555
                    'path' => $srcDirs,
556
                    'colors' => !$this->commandLine()->get('no-colors')
557
                ]);
558
                $reporters->add('coverage', $coverage);
559
            });
560
        }
561
562
        /**
563
         * The default `'matchers'` filter.
564
         */
565
        protected function _matchers()
566
        {
567
            return Filters::run($this, 'matchers', [], function ($chain) {
568
                static::registerMatchers();
569
            });
570
        }
571
572
        /**
573
         * The default `'run'` filter.
574
         */
575
        protected function _run()
576
        {
577
            return Filters::run($this, 'run', [], function ($chain) {
578
                return $this->suite()->run([
579
                    'reporters' => $this->reporters(),
580
                    'autoclear' => $this->commandLine()->get('autoclear'),
581
                    'part'      => trim($this->commandLine()->get('part')),
582
                    'ff'        => $this->commandLine()->get('ff')
583
                ]);
584
            });
585
        }
586
587
        /**
588
         * The default `'reporting'` filter.
589
         */
590
        protected function _reporting()
591
        {
592
            return Filters::run($this, 'reporting', [], function ($chain) {
593
                $reporter = $this->reporters()->get('coverage');
594
                if (!$reporter) {
595
                    return;
596
                }
597
                if ($this->commandLine()->exists('clover')) {
598
                    Clover::write([
599
                        'collector' => $reporter,
600
                        'file' => $this->commandLine()->get('clover')
601
                    ]);
602
                }
603
                if ($this->commandLine()->exists('istanbul')) {
604
                    Istanbul::write([
605
                        'collector' => $reporter,
606
                        'file' => $this->commandLine()->get('istanbul')
607
                    ]);
608
                }
609
                if ($this->commandLine()->exists('lcov')) {
610
                    Lcov::write([
611
                        'collector' => $reporter,
612
                        'file' => $this->commandLine()->get('lcov')
613
                    ]);
614
                }
615
            });
616
        }
617
618
        /**
619
         * The default `'stop'` filter.
620
         */
621
        protected function _stop()
622
        {
623
            return Filters::run($this, 'stop', [], function ($chain) {
624
                $this->suite()->stop();
625
            });
626
        }
627
628
629
        /**
630
         * The default `'quit'` filter.
631
         */
632
        protected function _quit()
633
        {
634
            return Filters::run($this, 'quit', [$this->suite()->status()], function ($chain, $success) {
635
            });
636
        }
637
    }
638
639
    define('KAHLAN_VERSION', Kahlan::VERSION);
640
}
641
642
namespace {
643
644
    use Kahlan\Expectation;
645
    use Kahlan\Suite;
646
    use Kahlan\Allow;
647
648
    /**
649
     * Create global functions
650
     */
651
    function initKahlanGlobalFunctions()
652
    {
653
        if (getenv('KAHLAN_DISABLE_FUNCTIONS') || (defined('KAHLAN_DISABLE_FUNCTIONS') && KAHLAN_DISABLE_FUNCTIONS)) {
0 ignored issues
show
The constant KAHLAN_DISABLE_FUNCTIONS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
654
            return;
655
        }
656
        if (defined('KAHLAN_FUNCTIONS_EXIST') && KAHLAN_FUNCTIONS_EXIST) {
657
            return;
658
        }
659
        $error = false;
660
        $exit = function ($name) use (&$error) {
661
            fwrite(STDERR, "The Kahlan global function `{$name}()`s can't be created because of some naming collisions with another library.\n");
662
            $error = true;
663
        };
664
        define('KAHLAN_FUNCTIONS_EXIST', true);
665
        if (!function_exists('beforeAll')) {
666
            function beforeAll($closure)
667
            {
668
                return Suite::current()->beforeAll($closure);
0 ignored issues
show
The method beforeAll() does not exist on Kahlan\Scope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

668
                return Suite::current()->/** @scrutinizer ignore-call */ beforeAll($closure);
Loading history...
669
            }
670
        } else {
671
            $exit('beforeAll');
672
        }
673
        if (!function_exists('afterAll')) {
674
            function afterAll($closure)
675
            {
676
                return Suite::current()->afterAll($closure);
0 ignored issues
show
The method afterAll() does not exist on Kahlan\Scope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

676
                return Suite::current()->/** @scrutinizer ignore-call */ afterAll($closure);
Loading history...
677
            }
678
        } else {
679
            $exit('afterAll');
680
        }
681
        if (!function_exists('beforeEach')) {
682
            function beforeEach($closure)
683
            {
684
                return Suite::current()->beforeEach($closure);
0 ignored issues
show
The method beforeEach() does not exist on Kahlan\Scope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

684
                return Suite::current()->/** @scrutinizer ignore-call */ beforeEach($closure);
Loading history...
685
            }
686
        } else {
687
            $exit('beforeEach');
688
        }
689
        if (!function_exists('afterEach')) {
690
            function afterEach($closure)
691
            {
692
                return Suite::current()->afterEach($closure);
0 ignored issues
show
The method afterEach() does not exist on Kahlan\Scope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

692
                return Suite::current()->/** @scrutinizer ignore-call */ afterEach($closure);
Loading history...
693
            }
694
        } else {
695
            $exit('afterEach');
696
        }
697
        if (!function_exists('describe')) {
698
            function describe($message, $closure, $timeout = null, $type = 'normal')
699
            {
700
                if (!Suite::current()) {
701
                    $suite = \Kahlan\box('kahlan')->get('suite.global');
702
                    return $suite->root()->describe($message, $closure, $timeout, $type);
703
                }
704
                return Suite::current()->describe($message, $closure, $timeout, $type);
0 ignored issues
show
The method describe() does not exist on Kahlan\Scope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

704
                return Suite::current()->/** @scrutinizer ignore-call */ describe($message, $closure, $timeout, $type);
Loading history...
705
            }
706
        } else {
707
            $exit('describe');
708
        }
709
        if (!function_exists('context')) {
710
            function context($message, $closure, $timeout = null, $type = 'normal')
711
            {
712
                return Suite::current()->context($message, $closure, $timeout, $type);
0 ignored issues
show
The method context() does not exist on Kahlan\Scope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

712
                return Suite::current()->/** @scrutinizer ignore-call */ context($message, $closure, $timeout, $type);
Loading history...
713
            }
714
        } else {
715
            $exit('context');
716
        }
717
        if (!function_exists('given')) {
718
            function given($name, $value)
719
            {
720
                return Suite::current()->given($name, $value);
721
            }
722
        } else {
723
            $exit('given');
724
        }
725
        if (!function_exists('it')) {
726
            function it($message, $closure = null, $timeout = null, $type = 'normal')
727
            {
728
                return Suite::current()->it($message, $closure, $timeout, $type);
0 ignored issues
show
The method it() does not exist on Kahlan\Scope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

728
                return Suite::current()->/** @scrutinizer ignore-call */ it($message, $closure, $timeout, $type);
Loading history...
729
            }
730
        } else {
731
            $exit('it');
732
        }
733
        if (!function_exists('fdescribe')) {
734
            function fdescribe($message, $closure, $timeout = null)
735
            {
736
                return describe($message, $closure, $timeout, 'focus');
737
            }
738
        } else {
739
            $exit('fdescribe');
740
        }
741
        if (!function_exists('fcontext')) {
742
            function fcontext($message, $closure, $timeout = null)
743
            {
744
                return context($message, $closure, $timeout, 'focus');
745
            }
746
        } else {
747
            $exit('fcontext');
748
        }
749
        if (!function_exists('fit')) {
750
            function fit($message, $closure = null, $timeout = null)
751
            {
752
                return it($message, $closure, $timeout, 'focus');
753
            }
754
        } else {
755
            $exit('fit');
756
        }
757
        if (!function_exists('xdescribe')) {
758
            function xdescribe($message, $closure, $timeout = null)
759
            {
760
                return describe($message, $closure, $timeout, 'exclude');
761
            }
762
        } else {
763
            $exit('xdescribe');
764
        }
765
        if (!function_exists('xcontext')) {
766
            function xcontext($message, $closure, $timeout = null)
767
            {
768
                return context($message, $closure, $timeout, 'exclude');
769
            }
770
        } else {
771
            $exit('xcontext');
772
        }
773
        if (!function_exists('xit')) {
774
            function xit($message, $closure = null, $timeout = null)
775
            {
776
                return it($message, $closure, $timeout, 'exclude');
777
            }
778
        } else {
779
            $exit('xit');
780
        }
781
        if (!function_exists('waitsFor')) {
782
            function waitsFor($actual, $timeout = 60)
783
            {
784
                return Suite::current()->waitsFor($actual, $timeout);
0 ignored issues
show
The method waitsFor() does not exist on Kahlan\Scope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

784
                return Suite::current()->/** @scrutinizer ignore-call */ waitsFor($actual, $timeout);
Loading history...
785
            }
786
        } else {
787
            $exit('waitsFor');
788
        }
789
        if (!function_exists('skipIf')) {
790
            function skipIf($condition)
791
            {
792
                $current = Suite::current();
793
                $current->skipIf($condition);
794
            }
795
        } else {
796
            $exit('skipIf');
797
        }
798
        if (!function_exists('expect')) {
799
            /**
800
             * @param $actual
801
             *
802
             * @return Expectation
803
             */
804
            function expect($actual)
805
            {
806
                return Suite::current()->expect($actual);
0 ignored issues
show
The method expect() does not exist on Kahlan\Scope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

806
                return Suite::current()->/** @scrutinizer ignore-call */ expect($actual);
Loading history...
807
            }
808
        } else {
809
            $exit('expect');
810
        }
811
        if (!function_exists('allow')) {
812
            /**
813
             * @param $actual
814
             *
815
             * @return Allow
816
             */
817
            function allow($actual)
818
            {
819
                return new Allow($actual);
820
            }
821
        } else {
822
            $exit('allow');
823
        }
824
        if ($error) {
825
            exit(1);
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
826
        }
827
    }
828
}
829