Test Failed
Push — master ( 614ce5...540a9b )
by Hannes
02:11
created

TestCommand::execute()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 31
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 18
nc 24
nop 2
dl 0
loc 31
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace hanneskod\readmetester\Console;
6
7
use Symfony\Component\Console\Command\Command;
8
use Symfony\Component\Console\Input\InputArgument;
9
use Symfony\Component\Console\Input\InputOption;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Output\OutputInterface;
12
use hanneskod\readmetester\EngineFactory;
13
use hanneskod\readmetester\SourceFileIterator;
14
use hanneskod\readmetester\Example\RegexpFilter;
15
use hanneskod\readmetester\Example\UnnamedFilter;
16
use hanneskod\readmetester\Example\NullFilter;
17
18
/**
19
 * CLI command to run test
20
 */
21
class TestCommand extends Command
22
{
23
    /**
24
     * Path to default bootstrap file
25
     */
26
    const DEFAULT_BOOTSTRAP = 'vendor/autoload.php';
27
28
    protected function configure()
29
    {
30
        $this->setName('test')
31
            ->setDescription('Test examples in readme file')
32
            ->addArgument(
33
                'source',
34
                InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
35
                'One or more files or directories to test',
36
                ['README.md']
37
            )
38
            ->addOption(
39
                'filter',
40
                null,
41
                InputOption::VALUE_REQUIRED,
42
                'Filter which examples to test using a regular expression'
43
            )
44
            ->addOption(
45
                'format',
46
                null,
47
                InputOption::VALUE_REQUIRED,
48
                "One of 'std' or 'json'"
49
            )
50
            ->addOption(
51
                'named-only',
52
                null,
53
                InputOption::VALUE_NONE,
54
                'Test only named examples'
55
            )
56
            ->addOption(
57
                'bootstrap',
58
                null,
59
                InputOption::VALUE_REQUIRED,
60
                'A "bootstrap" PHP file that is run before testing'
61
            )
62
            ->addOption(
63
                'no-auto-bootstrap',
64
                null,
65
                InputOption::VALUE_NONE,
66
                "Don't try to load a local composer autoloader when boostrap is not definied"
67
            )
68
        ;
69
    }
70
71
    protected function execute(InputInterface $input, OutputInterface $output): int
72
    {
73
        $filter = $input->getOption('filter')
74
            ? new RegexpFilter($input->getOption('filter'))
75
            : ($input->getOption('named-only') ? new UnnamedFilter : new NullFilter);
76
77
        $engine = (new EngineFactory)->createEngine($filter);
78
79
        $exitStatus = new ExitStatusListener;
80
        $engine->registerListener($exitStatus);
81
82
        $formatter = $input->getOption('format') == 'json'
83
            ? new JsonFormatter($output)
84
            : new DefaultFormatter($output);
85
86
        $engine->registerListener($formatter);
87
88
        $formatter->onInvokationStart();
89
90
        $this->bootstrap($input, $formatter);
91
92
        foreach ($input->getArgument('source') as $source) {
93
            foreach (new SourceFileIterator($source) as $filename => $contents) {
94
                $formatter->onFile($filename);
95
                $engine->testFile($contents);
96
            }
97
        }
98
99
        $formatter->onInvokationEnd();
100
101
        return $exitStatus->getStatusCode();
102
    }
103
104
    private function bootstrap(InputInterface $input, $formatter)
105
    {
106
        if ($filename = $input->getOption('bootstrap')) {
107
            if (!file_exists($filename) || !is_readable($filename)) {
108
                throw new \RuntimeException("Unable to bootstrap $filename");
109
            }
110
111
            require_once $filename;
112
            $formatter->onBootstrap($filename);
113
            return;
114
        }
115
116
        if (!$input->getOption('no-auto-bootstrap') && is_readable(self::DEFAULT_BOOTSTRAP)) {
117
            require_once self::DEFAULT_BOOTSTRAP;
118
            $formatter->onBootstrap(self::DEFAULT_BOOTSTRAP);
119
        }
120
    }
121
}
122