Completed
Push — master ( 89c0fb...943241 )
by Paul
01:57
created

TestGenerator::writeDir()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 44
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 25
nc 6
nop 2
dl 0
loc 44
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of PHPUnit Generator.
5
 *
6
 * (c) Paul Thébaud <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace PHPUnitGenerator\Generator;
13
14
use PHPUnitGenerator\CLI\Application;
15
use PHPUnitGenerator\Config\ConfigInterface\ConfigInterface;
16
use PHPUnitGenerator\Exception\ExceptionInterface\ExceptionInterface;
17
use PHPUnitGenerator\Exception\FileExistsException;
18
use PHPUnitGenerator\Exception\InvalidRegexException;
19
use PHPUnitGenerator\Exception\IsInterfaceException;
20
use PHPUnitGenerator\FileSystem\FileSystemInterface\FileSystemInterface;
21
use PHPUnitGenerator\FileSystem\LocalFileSystem;
22
use PHPUnitGenerator\Generator\GeneratorInterface\TestGeneratorInterface;
23
use PHPUnitGenerator\Parser\CodeParser;
24
use PHPUnitGenerator\Parser\DocumentationParser;
25
use PHPUnitGenerator\Parser\ParserInterface\CodeParserInterface;
26
use PHPUnitGenerator\Parser\ParserInterface\DocumentationParserInterface;
27
use PHPUnitGenerator\Renderer\RendererInterface\TestRendererInterface;
28
use PHPUnitGenerator\Renderer\TwigTestRenderer;
29
30
/**
31
 * Class TestGenerator
32
 *
33
 *      An implementation of TestGenerator to generate tests with
34
 *      CodeParserInterface, DocumentationParserInterface and
35
 *      TestRendererInterface
36
 *
37
 * @package PHPUnitGenerator\Generator
38
 */
39
class TestGenerator implements TestGeneratorInterface
40
{
41
    /**
42
     * @var ConfigInterface $config
43
     */
44
    protected $config;
45
46
    /**
47
     * @var CodeParserInterface $codeParser The code parser to use
48
     */
49
    protected $codeParser;
50
51
    /**
52
     * @var DocumentationParserInterface $documentationParser The documentation
53
     *      parser to use
54
     */
55
    protected $documentationParser;
56
57
    /**
58
     * @var TestRendererInterface $testRenderer The tests renderer to use
59
     */
60
    protected $testRenderer;
61
62
    /**
63
     * @var FileSystemInterface $fileSystem The file manager
64
     */
65
    protected $fileSystem;
66
67
    /**
68
     * {@inheritdoc}
69
     */
70
    public function __construct(ConfigInterface $config)
71
    {
72
        $this->config = $config;
73
74
        // By default, set dependencies to default interface implementation
75
        $this->setCodeParser(new CodeParser($config));
76
        $this->setDocumentationParser(new DocumentationParser($config));
77
        $this->setTestRenderer(new TwigTestRenderer());
78
        $this->setFileSystem(new LocalFileSystem());
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84
    public function generate(string $code): string
85
    {
86
        // Parse the PHP code
87
        $classModel = $this->codeParser->parse($code);
88
89
        if (true !== $this->config->getOption(ConfigInterface::OPTION_INTERFACE)
90
            && $classModel->isInterface()
91
        ) {
92
            throw new IsInterfaceException(IsInterfaceException::TEXT);
93
        }
94
95
        // Foreach methods, parse the documentation
96
        foreach ($classModel->getMethods() as $methodModel) {
97
            $methodModel->setAnnotations(
98
                $this->documentationParser->parse($methodModel)
99
            );
100
        }
101
102
        // Generate the test
103
        return $this->testRenderer->render($classModel);
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109
    public function writeFile(string $inFile, string $outFile): int
110
    {
111
        if ($this->fileSystem->fileExists($outFile)
112
            && true !== $this->config->getOption(ConfigInterface::OPTION_OVERWRITE)
113
        ) {
114
            throw new FileExistsException(sprintf(FileExistsException::TEXT, $outFile));
115
        }
116
117
        $testCode = $this->generate($this->fileSystem->read($inFile));
118
119
        $this->fileSystem->mkDir(dirname($outFile));
120
121
        $this->fileSystem->write($outFile, $testCode);
122
123
        Application::getPrinter()->info('"%s" tests generated', $inFile, $outFile);
0 ignored issues
show
Bug introduced by
$inFile of type string is incompatible with the type array<mixed,mixed> expected by parameter $args of PHPUnitGenerator\CLI\CLI...rinterInterface::info(). ( Ignorable by Annotation )

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

123
        Application::getPrinter()->info('"%s" tests generated', /** @scrutinizer ignore-type */ $inFile, $outFile);
Loading history...
Bug introduced by
$inFile of type string is incompatible with the type array expected by parameter $args of PHPUnitGenerator\CLI\ColoredPrinter::info(). ( Ignorable by Annotation )

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

123
        Application::getPrinter()->info('"%s" tests generated', /** @scrutinizer ignore-type */ $inFile, $outFile);
Loading history...
124
125
        return 1;
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131
    public function writeDir(string $inDir, string $outDir): int
132
    {
133
        // Check regex validity
134
        $this->checkRegexValidity(ConfigInterface::OPTION_INCLUDE);
135
        $this->checkRegexValidity(ConfigInterface::OPTION_EXCLUDE);
136
137
        // Fix $outDir name
138
        if (substr($outDir, -1) !== '\\' && substr($outDir, -1) !== '/') {
139
            $outDir .= '/';
140
        }
141
142
        // Check target dir
143
        $this->fileSystem->mkDir($outDir);
144
145
        $files = $this->fileSystem->filterFiles(
146
            $this->fileSystem->getFiles($inDir),
147
            $this->config->getOption(ConfigInterface::OPTION_INCLUDE),
148
            $this->config->getOption(ConfigInterface::OPTION_EXCLUDE)
149
        );
150
151
        // Foreach files
152
        $count = 0;
153
        foreach ($files as $inFile) {
154
            $outFile = str_replace($inDir, $outDir, $inFile);
155
            $outFile = preg_replace('/.php$/', 'Test.php', $outFile);
156
157
            try {
158
                $this->writeFile($inFile, $outFile);
159
160
                $count++;
161
            } catch (ExceptionInterface $exception) {
162
                if ($this->config->getOption(ConfigInterface::OPTION_IGNORE) !== true) {
163
                    throw $exception;
164
                } else {
165
                    Application::getPrinter()->warning(
166
                        "An error occurred during tests creation (for \"%s\"):\n\n\t%s",
167
                        $inFile,
0 ignored issues
show
Bug introduced by
$inFile of type string is incompatible with the type array<mixed,mixed> expected by parameter $args of PHPUnitGenerator\CLI\CLI...terInterface::warning(). ( Ignorable by Annotation )

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

167
                        /** @scrutinizer ignore-type */ $inFile,
Loading history...
Bug introduced by
$inFile of type string is incompatible with the type array expected by parameter $args of PHPUnitGenerator\CLI\ColoredPrinter::warning(). ( Ignorable by Annotation )

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

167
                        /** @scrutinizer ignore-type */ $inFile,
Loading history...
168
                        $exception->getMessage()
169
                    );
170
                }
171
            }
172
        }
173
174
        return $count;
175
    }
176
177
    /*
178
     **********************************************************************
179
     *
180
     * Setters to use custom parsers and renderer if needed
181
     *
182
     **********************************************************************
183
     */
184
185
    /**
186
     * @param CodeParserInterface $codeParser
187
     */
188
    public function setCodeParser(CodeParserInterface $codeParser)
189
    {
190
        $this->codeParser = $codeParser;
191
    }
192
193
    /**
194
     * @param DocumentationParserInterface $documentationParser
195
     */
196
    public function setDocumentationParser(
197
        DocumentationParserInterface $documentationParser
198
    ) {
199
        $this->documentationParser = $documentationParser;
200
    }
201
202
    /**
203
     * @param TestRendererInterface $testRenderer
204
     */
205
    public function setTestRenderer(TestRendererInterface $testRenderer)
206
    {
207
        $this->testRenderer = $testRenderer;
208
    }
209
210
    /**
211
     * @param FileSystemInterface $filesystem
212
     */
213
    public function setFileSystem(FileSystemInterface $filesystem)
214
    {
215
        $this->fileSystem = $filesystem;
216
    }
217
218
    /*
219
     **********************************************************************
220
     *
221
     * Protected methods
222
     *
223
     **********************************************************************
224
     */
225
226
    /**
227
     * Check the regex validity if set
228
     *
229
     * @param string $optionName
230
     *
231
     * @throws InvalidRegexException If a regex is invalid
232
     */
233
    protected function checkRegexValidity(string $optionName)
234
    {
235
        if ($this->config->getOption($optionName) !== null
236
            && @preg_match($this->config->getOption($optionName), '') === false
237
        ) {
238
            throw new InvalidRegexException(InvalidRegexException::TEXT);
239
        }
240
    }
241
}
242