This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types = 1); |
||
4 | |||
5 | namespace PHPChunkit; |
||
6 | |||
7 | use Doctrine\Common\Inflector\Inflector; |
||
8 | use PHPUnit\Framework\TestCase; |
||
9 | use ReflectionClass; |
||
10 | use ReflectionMethod; |
||
11 | |||
12 | /** |
||
13 | * @testClass PHPChunkit\Test\GenerateTestClassTest |
||
14 | */ |
||
15 | class GenerateTestClass |
||
16 | { |
||
17 | const CLASS_TEMPLATE = <<<EOF |
||
18 | <?php |
||
19 | |||
20 | namespace {{ namespace }}; |
||
21 | |||
22 | {{ useStatements }} |
||
23 | |||
24 | class {{ shortName }} extends TestCase |
||
25 | { |
||
26 | {{ properties }} |
||
27 | |||
28 | {{ setUpCode }} |
||
29 | |||
30 | {{ methods }} |
||
31 | } |
||
32 | |||
33 | EOF; |
||
34 | |||
35 | const COMMAND_TEMPLATE = <<<EOF |
||
36 | <?php |
||
37 | |||
38 | namespace {{ namespace }}; |
||
39 | |||
40 | {{ useStatements }} |
||
41 | use OpenSky\Bundle\MainBundle\Tests\OpenSkyCommandTestCase; |
||
42 | use Symfony\Component\DependencyInjection\Container; |
||
43 | |||
44 | class {{ shortName }} extends OpenSkyCommandTestCase |
||
45 | { |
||
46 | private \$command; |
||
47 | private \$container; |
||
48 | |||
49 | protected function setUp() |
||
50 | { |
||
51 | \$this->container = new Container(); |
||
52 | \$this->command = new {{ classShortName }}(); |
||
53 | \$this->command->setContainer(\$this->container); |
||
54 | } |
||
55 | |||
56 | public function testExecute() |
||
57 | { |
||
58 | } |
||
59 | } |
||
60 | |||
61 | EOF; |
||
62 | |||
63 | /** |
||
64 | * @var ReflectionClass |
||
65 | */ |
||
66 | private $reflectionClass; |
||
67 | |||
68 | /** |
||
69 | * @var string |
||
70 | */ |
||
71 | private $classShortName; |
||
72 | |||
73 | /** |
||
74 | * @var string |
||
75 | */ |
||
76 | private $classCamelCaseName; |
||
77 | |||
78 | /** |
||
79 | * @var string |
||
80 | */ |
||
81 | private $testNamespace; |
||
82 | |||
83 | /** |
||
84 | * @var string |
||
85 | */ |
||
86 | private $testClassShortName; |
||
87 | |||
88 | /** |
||
89 | * @var string |
||
90 | */ |
||
91 | private $useStatementsCode; |
||
92 | |||
93 | /** |
||
94 | * @var string |
||
95 | */ |
||
96 | private $testPropertiesCode; |
||
97 | |||
98 | /** |
||
99 | * @var string |
||
100 | */ |
||
101 | private $setUpCode; |
||
102 | |||
103 | /** |
||
104 | * @var string |
||
105 | */ |
||
106 | private $testMethodsCode; |
||
107 | |||
108 | 2 | public function generate(string $className) : string |
|
109 | { |
||
110 | 2 | $this->reflectionClass = new ReflectionClass($className); |
|
111 | |||
112 | 2 | $this->classShortName = $this->reflectionClass->getShortName(); |
|
113 | 2 | $this->classCamelCaseName = Inflector::camelize($this->classShortName); |
|
114 | 2 | $this->testNamespace = preg_replace('/(.*)Bundle/', '$0\Tests', $this->reflectionClass->getNamespaceName()); |
|
115 | 2 | $this->testClassShortName = $this->classShortName.'Test'; |
|
116 | |||
117 | 2 | $this->useStatementsCode = $this->generateUseStatements(); |
|
118 | 2 | $this->testPropertiesCode = $this->generateClassProperties(); |
|
119 | 2 | $this->setUpCode = $this->generateSetUp(); |
|
120 | 2 | $this->testMethodsCode = $this->generateTestMethods(); |
|
121 | |||
122 | 2 | $twig = new \Twig_Environment(new \Twig_Loader_String(), [ |
|
123 | 2 | 'autoescape' => false, |
|
124 | ]); |
||
125 | |||
126 | 2 | $template = self::CLASS_TEMPLATE; |
|
127 | |||
128 | 2 | return $twig->render($template, [ |
|
129 | 2 | 'classShortName' => $this->classShortName, |
|
130 | 2 | 'classCamelCaseName' => $this->classCamelCaseName, |
|
131 | 2 | 'namespace' => $this->testNamespace, |
|
132 | 2 | 'shortName' => $this->testClassShortName, |
|
133 | 2 | 'methods' => $this->testMethodsCode, |
|
134 | 2 | 'properties' => $this->testPropertiesCode, |
|
135 | 2 | 'useStatements' => $this->useStatementsCode, |
|
136 | 2 | 'setUpCode' => $this->setUpCode, |
|
137 | ]); |
||
138 | } |
||
139 | |||
140 | 2 | private function generateClassProperties() : string |
|
141 | { |
||
142 | 2 | $testPropertiesCode = []; |
|
143 | |||
144 | 2 | if ($parameters = $this->getConstructorParameters()) { |
|
145 | 1 | foreach ($parameters as $key => $parameter) { |
|
146 | 1 | $isLast = $key === count($parameters) - 1; |
|
147 | |||
148 | 1 | if ($parameterClass = $parameter->getClass()) { |
|
149 | 1 | $testPropertiesCode[] = ' /**'; |
|
150 | 1 | $testPropertiesCode[] = ' * @var '.$parameterClass->getShortName(); |
|
151 | 1 | $testPropertiesCode[] = ' */'; |
|
152 | 1 | $testPropertiesCode[] = ' private $'.$parameter->name.';'; |
|
153 | |||
154 | 1 | if (!$isLast) { |
|
155 | 1 | $testPropertiesCode[] = ''; |
|
156 | } |
||
157 | } else { |
||
158 | 1 | $testPropertiesCode[] = ' /**'; |
|
159 | 1 | $testPropertiesCode[] = ' * @var TODO'; |
|
160 | 1 | $testPropertiesCode[] = ' */'; |
|
161 | 1 | $testPropertiesCode[] = ' private $'.$parameter->name.';'; |
|
162 | |||
163 | 1 | if (!$isLast) { |
|
164 | 1 | $testPropertiesCode[] = ''; |
|
165 | } |
||
166 | } |
||
167 | } |
||
168 | } |
||
169 | |||
170 | 2 | if (!empty($parameters)) { |
|
171 | 1 | $testPropertiesCode[] = ''; |
|
172 | } |
||
173 | |||
174 | 2 | $testPropertiesCode[] = ' /**'; |
|
175 | 2 | $testPropertiesCode[] = ' * @var '.$this->classShortName; |
|
176 | 2 | $testPropertiesCode[] = ' */'; |
|
177 | 2 | $testPropertiesCode[] = ' private $'.$this->classCamelCaseName.';'; |
|
178 | |||
179 | 2 | return implode("\n", $testPropertiesCode); |
|
180 | } |
||
181 | |||
182 | 2 | private function generateSetUp() : string |
|
183 | { |
||
184 | 2 | $classShortName = $this->reflectionClass->getShortName(); |
|
185 | 2 | $classCamelCaseName = Inflector::camelize($classShortName); |
|
186 | |||
187 | 2 | $setUpCode = []; |
|
188 | 2 | $setUpCode[] = ' protected function setUp()'; |
|
189 | 2 | $setUpCode[] = ' {'; |
|
190 | |||
191 | 2 | if ($parameters = $this->getConstructorParameters()) { |
|
192 | 1 | View Code Duplication | foreach ($parameters as $parameter) { |
193 | 1 | if ($parameterClass = $parameter->getClass()) { |
|
194 | 1 | $setUpCode[] = sprintf(' $this->%s = $this->%s(%s::class);', |
|
195 | 1 | $parameter->name, |
|
196 | 1 | $this->getPHPUnitMockMethod(), |
|
197 | 1 | $parameterClass->getShortName() |
|
198 | ); |
||
199 | } else { |
||
200 | 1 | $setUpCode[] = sprintf(" \$this->%s = ''; // TODO", |
|
201 | 1 | $parameter->name |
|
202 | ); |
||
203 | } |
||
204 | } |
||
205 | |||
206 | 1 | $setUpCode[] = ''; |
|
207 | 1 | $setUpCode[] = sprintf(' $this->%s = new %s(', $classCamelCaseName, $classShortName); |
|
208 | |||
209 | // arguments for class being tested |
||
210 | 1 | $setUpCodeArguments = []; |
|
211 | 1 | foreach ($parameters as $parameter) { |
|
212 | 1 | $setUpCodeArguments[] = sprintf(' $this->%s', $parameter->name); |
|
213 | } |
||
214 | 1 | $setUpCode[] = implode(",\n", $setUpCodeArguments); |
|
215 | |||
216 | 1 | $setUpCode[] = ' );'; |
|
217 | } else { |
||
218 | 1 | $setUpCode[] = sprintf(' $this->%s = new %s();', $classCamelCaseName, $classShortName); |
|
219 | } |
||
220 | |||
221 | 2 | $setUpCode[] = ' }'; |
|
222 | |||
223 | 2 | return implode("\n", $setUpCode); |
|
224 | } |
||
225 | |||
226 | 2 | private function getConstructorParameters() : array |
|
227 | { |
||
228 | 2 | $constructor = $this->reflectionClass->getConstructor(); |
|
229 | |||
230 | 2 | if ($constructor) { |
|
231 | 1 | return $constructor->getParameters(); |
|
232 | } |
||
233 | |||
234 | 1 | return []; |
|
235 | } |
||
236 | |||
237 | 2 | private function generateTestMethods() : string |
|
238 | { |
||
239 | 2 | $testMethodsCode = []; |
|
240 | |||
241 | 2 | foreach ($this->reflectionClass->getMethods() as $method) { |
|
242 | 2 | if (!$this->isMethodTestable($method)) { |
|
243 | 1 | continue; |
|
244 | } |
||
245 | |||
246 | 2 | $testMethodsCode[] = sprintf(' public function test%s()', ucfirst($method->name)); |
|
247 | 2 | $testMethodsCode[] = ' {'; |
|
248 | 2 | $testMethodsCode[] = $this->generateTestMethodBody($method); |
|
249 | 2 | $testMethodsCode[] = ' }'; |
|
250 | 2 | $testMethodsCode[] = ''; |
|
251 | } |
||
252 | |||
253 | 2 | return ' '.trim(implode("\n", $testMethodsCode)); |
|
254 | } |
||
255 | |||
256 | 2 | private function generateTestMethodBody(ReflectionMethod $method) : string |
|
257 | { |
||
258 | 2 | $parameters = $method->getParameters(); |
|
259 | |||
260 | 2 | $testMethodBodyCode = []; |
|
261 | |||
262 | 2 | if (!empty($parameters)) { |
|
263 | 1 | View Code Duplication | foreach ($parameters as $parameter) { |
264 | 1 | if ($parameterClass = $parameter->getClass()) { |
|
265 | 1 | $testMethodBodyCode[] = sprintf( |
|
266 | 1 | ' $%s = $this->%s(%s::class);', |
|
267 | 1 | $parameter->name, |
|
268 | 1 | $this->getPHPUnitMockMethod(), |
|
269 | 1 | $parameterClass->getShortName() |
|
270 | ); |
||
271 | } else { |
||
272 | 1 | $testMethodBodyCode[] = sprintf(" \$%s = '';", $parameter->name); |
|
273 | } |
||
274 | } |
||
275 | |||
276 | 1 | $testMethodBodyCode[] = ''; |
|
277 | 1 | $testMethodBodyCode[] = sprintf(' $this->%s->%s(', $this->classCamelCaseName, $method->name); |
|
278 | |||
279 | 1 | $testMethodParameters = []; |
|
280 | 1 | foreach ($parameters as $parameter) { |
|
281 | 1 | $testMethodParameters[] = sprintf('$%s', $parameter->name); |
|
282 | } |
||
283 | |||
284 | 1 | $testMethodBodyCode[] = ' '.implode(",\n ", $testMethodParameters); |
|
285 | 1 | $testMethodBodyCode[] = ' );'; |
|
286 | } else { |
||
287 | 1 | $testMethodBodyCode[] = sprintf(' $this->%s->%s();', $this->classCamelCaseName, $method->name); |
|
288 | } |
||
289 | |||
290 | 2 | return implode("\n", $testMethodBodyCode); |
|
291 | } |
||
292 | |||
293 | 2 | private function generateUseStatements() : string |
|
294 | { |
||
295 | 2 | $dependencies = []; |
|
296 | 2 | $dependencies[] = $this->reflectionClass->name; |
|
297 | 2 | $dependencies[] = TestCase::class; |
|
298 | |||
299 | 2 | if ($parameters = $this->getConstructorParameters()) { |
|
300 | 1 | foreach ($parameters as $parameter) { |
|
301 | 1 | if (!$parameterClass = $parameter->getClass()) { |
|
302 | 1 | continue; |
|
303 | } |
||
304 | |||
305 | 1 | $dependencies[] = $parameterClass->getName(); |
|
306 | } |
||
307 | } |
||
308 | |||
309 | 2 | foreach ($this->reflectionClass->getMethods() as $method) { |
|
310 | 2 | if (!$this->isMethodTestable($method)) { |
|
311 | 1 | continue; |
|
312 | } |
||
313 | |||
314 | 2 | foreach ($method->getParameters() as $parameter) { |
|
315 | 1 | if (!$parameterClass = $parameter->getClass()) { |
|
316 | 1 | continue; |
|
317 | } |
||
318 | |||
319 | 2 | $dependencies[] = $parameterClass->getName(); |
|
320 | } |
||
321 | } |
||
322 | |||
323 | 2 | sort($dependencies); |
|
324 | |||
325 | 2 | $dependencies = array_unique($dependencies); |
|
326 | |||
327 | 2 | $useStatementsCode = array_map(function($dependency) { |
|
328 | 2 | return sprintf('use %s;', $dependency); |
|
329 | 2 | }, $dependencies); |
|
330 | |||
331 | 2 | return implode("\n", $useStatementsCode); |
|
332 | } |
||
333 | |||
334 | 2 | private function isMethodTestable(ReflectionMethod $method) : bool |
|
335 | { |
||
336 | 2 | if ($this->reflectionClass->name !== $method->class) { |
|
337 | return false; |
||
338 | } |
||
339 | |||
340 | 2 | return substr($method->name, 0, 2) !== '__' && $method->isPublic(); |
|
341 | } |
||
342 | |||
343 | /** |
||
344 | * @return string |
||
345 | */ |
||
346 | 1 | private function getPHPUnitMockMethod() |
|
347 | { |
||
348 | 1 | foreach (['createMock', 'getMock'] as $method) { |
|
349 | try { |
||
350 | 1 | new \ReflectionMethod(TestCase::class, $method); |
|
351 | 1 | return $method; |
|
352 | } catch (\ReflectionException $e) { |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
![]() |
|||
353 | } |
||
354 | } |
||
355 | |||
356 | throw new \RuntimeException('Unable to detect PHPUnit version'); |
||
357 | } |
||
358 | } |
||
359 |