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 Tests\Behat\Context; |
||
6 | |||
7 | use Behat\Behat\Context\Context; |
||
8 | use Symfony\Component\Filesystem\Filesystem; |
||
9 | use Symfony\Component\Process\PhpExecutableFinder; |
||
10 | use Symfony\Component\Process\Process; |
||
11 | use Symfony\Component\Yaml\Yaml; |
||
12 | |||
13 | final class TestContext implements Context |
||
14 | { |
||
15 | /** @var string */ |
||
16 | private static $workingDir; |
||
17 | |||
18 | /** @var Filesystem */ |
||
19 | private static $filesystem; |
||
20 | |||
21 | /** @var string */ |
||
22 | private static $phpBin; |
||
23 | |||
24 | /** @var Process */ |
||
25 | private $process; |
||
26 | |||
27 | /** @var array */ |
||
28 | private $variables = []; |
||
29 | |||
30 | /** |
||
31 | * @BeforeFeature |
||
32 | */ |
||
33 | public static function beforeFeature(): void |
||
34 | { |
||
35 | self::$workingDir = sprintf('%s/%s/', sys_get_temp_dir(), uniqid('', true)); |
||
36 | self::$filesystem = new Filesystem(); |
||
37 | self::$phpBin = self::findPhpBinary(); |
||
38 | } |
||
39 | |||
40 | /** |
||
41 | * @BeforeScenario |
||
42 | */ |
||
43 | public function beforeScenario(): void |
||
44 | { |
||
45 | self::$filesystem->remove(self::$workingDir); |
||
46 | self::$filesystem->mkdir(self::$workingDir, 0777); |
||
47 | } |
||
48 | |||
49 | /** |
||
50 | * @AfterScenario |
||
51 | */ |
||
52 | public function afterScenario(): void |
||
53 | { |
||
54 | self::$filesystem->remove(self::$workingDir); |
||
55 | } |
||
56 | |||
57 | /** |
||
58 | * @Given a standard Symfony autoloader configured |
||
59 | */ |
||
60 | public function standardSymfonyAutoloaderConfigured(): void |
||
61 | { |
||
62 | $this->thereIsFile('vendor/autoload.php', sprintf(<<<'CON' |
||
63 | <?php |
||
64 | |||
65 | declare(strict_types=1); |
||
66 | |||
67 | $loader = require '%s'; |
||
68 | $loader->addPsr4('App\\', __DIR__ . '/../src/'); |
||
69 | $loader->addPsr4('App\\Tests\\', __DIR__ . '/../tests/'); |
||
70 | |||
71 | return $loader; |
||
72 | CON |
||
73 | , __DIR__ . '/../../../vendor/autoload.php')); |
||
74 | } |
||
75 | |||
76 | /** |
||
77 | * @Given a working Symfony application with SymfonyExtension configured |
||
78 | */ |
||
79 | public function workingSymfonyApplicationWithExtension(): void |
||
80 | { |
||
81 | $this->thereIsConfiguration(<<<'CON' |
||
82 | default: |
||
83 | extensions: |
||
84 | FriendsOfBehat\SymfonyExtension: |
||
85 | kernel: |
||
86 | class: App\Kernel |
||
87 | CON |
||
88 | ); |
||
89 | |||
90 | $this->standardSymfonyAutoloaderConfigured(); |
||
91 | |||
92 | $this->thereIsFile('src/Kernel.php', <<<'CON' |
||
93 | <?php |
||
94 | |||
95 | declare(strict_types=1); |
||
96 | |||
97 | namespace App; |
||
98 | |||
99 | use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; |
||
100 | use Symfony\Component\Config\Loader\LoaderInterface; |
||
101 | use Symfony\Component\DependencyInjection\ContainerBuilder; |
||
102 | use Symfony\Component\HttpKernel\Kernel as HttpKernel; |
||
103 | use Symfony\Component\Routing\RouteCollectionBuilder; |
||
104 | |||
105 | class Kernel extends HttpKernel |
||
106 | { |
||
107 | use MicroKernelTrait; |
||
108 | |||
109 | public function registerBundles(): iterable |
||
110 | { |
||
111 | return [ |
||
112 | new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(), |
||
113 | new \FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle(), |
||
114 | ]; |
||
115 | } |
||
116 | |||
117 | protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void |
||
118 | { |
||
119 | $container->loadFromExtension('framework', [ |
||
120 | 'test' => $this->getEnvironment() === 'test', |
||
121 | 'secret' => 'Pigeon', |
||
122 | ]); |
||
123 | |||
124 | $loader->load(__DIR__ . '/../config/default.yaml'); |
||
125 | $loader->load(__DIR__ . '/../config/services.yaml'); |
||
126 | } |
||
127 | |||
128 | protected function configureRoutes(RouteCollectionBuilder $routes): void |
||
129 | { |
||
130 | $routes->add('/hello-world', 'App\Controller:helloWorld'); |
||
131 | } |
||
132 | } |
||
133 | CON |
||
134 | ); |
||
135 | |||
136 | $this->thereIsFile('src/Controller.php', <<<'CON' |
||
137 | <?php |
||
138 | |||
139 | declare(strict_types=1); |
||
140 | |||
141 | namespace App; |
||
142 | |||
143 | use Symfony\Component\HttpFoundation\Response; |
||
144 | |||
145 | final class Controller |
||
146 | { |
||
147 | private $counter; |
||
148 | |||
149 | public function __construct(Counter $counter) |
||
150 | { |
||
151 | $this->counter = $counter; |
||
152 | } |
||
153 | |||
154 | public function helloWorld(): Response |
||
155 | { |
||
156 | $this->counter->increase(); |
||
157 | |||
158 | return new Response('Hello world!'); |
||
159 | } |
||
160 | } |
||
161 | CON |
||
162 | ); |
||
163 | |||
164 | $this->thereIsFile('src/Counter.php', <<<'CON' |
||
165 | <?php |
||
166 | |||
167 | declare(strict_types=1); |
||
168 | |||
169 | namespace App; |
||
170 | |||
171 | final class Counter |
||
172 | { |
||
173 | private $counter = 0; |
||
174 | |||
175 | public function increase(): void |
||
176 | { |
||
177 | $this->counter++; |
||
178 | } |
||
179 | |||
180 | public function get(): int |
||
181 | { |
||
182 | return $this->counter; |
||
183 | } |
||
184 | } |
||
185 | CON |
||
186 | ); |
||
187 | |||
188 | $this->thereIsFile('config/default.yaml', <<<'YML' |
||
189 | services: |
||
190 | App\Controller: |
||
191 | arguments: |
||
192 | - '@App\Counter' |
||
193 | public: true |
||
194 | |||
195 | App\Counter: |
||
196 | public: false |
||
197 | YML |
||
198 | ); |
||
199 | |||
200 | $this->thereIsFile('config/services.yaml', ''); |
||
201 | } |
||
202 | |||
203 | /** |
||
204 | * @Given /^an? (server|environment) variable "([^"]++)" set to "([^"]++)"$/ |
||
205 | */ |
||
206 | public function variableSetTo(string $type, string $name, string $value): void |
||
207 | { |
||
208 | $this->variables[$type][$name] = $value; |
||
209 | } |
||
210 | |||
211 | /** |
||
212 | * @Given /^a YAML services file containing:$/ |
||
213 | */ |
||
214 | public function yamlServicesFile($content): void |
||
215 | { |
||
216 | $this->thereIsFile('config/services.yaml', (string) $content); |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * @Given /^a Behat configuration containing(?: "([^"]+)"|:)$/ |
||
221 | */ |
||
222 | public function thereIsConfiguration($content): void |
||
223 | { |
||
224 | $mainConfigFile = sprintf('%s/behat.yml', self::$workingDir); |
||
225 | $newConfigFile = sprintf('%s/behat-%s.yml', self::$workingDir, md5((string) $content)); |
||
226 | |||
227 | self::$filesystem->dumpFile($newConfigFile, (string) $content); |
||
228 | |||
229 | if (!file_exists($mainConfigFile)) { |
||
230 | self::$filesystem->dumpFile($mainConfigFile, Yaml::dump(['imports' => []])); |
||
231 | } |
||
232 | |||
233 | $mainBehatConfiguration = Yaml::parseFile($mainConfigFile); |
||
234 | $mainBehatConfiguration['imports'][] = $newConfigFile; |
||
235 | |||
236 | self::$filesystem->dumpFile($mainConfigFile, Yaml::dump($mainBehatConfiguration)); |
||
237 | } |
||
238 | |||
239 | /** |
||
240 | * @Given /^a (?:.+ |)file "([^"]+)" containing(?: "([^"]+)"|:)$/ |
||
241 | */ |
||
242 | public function thereIsFile($file, $content): string |
||
243 | { |
||
244 | $path = self::$workingDir . '/' . $file; |
||
245 | |||
246 | self::$filesystem->dumpFile($path, (string) $content); |
||
247 | |||
248 | return $path; |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * @Given /^a feature file containing(?: "([^"]+)"|:)$/ |
||
253 | */ |
||
254 | public function thereIsFeatureFile($content): void |
||
255 | { |
||
256 | $this->thereIsFile(sprintf('features/%s.feature', md5(uniqid('', true))), $content); |
||
257 | } |
||
258 | |||
259 | /** |
||
260 | * @When /^I run Behat$/ |
||
261 | */ |
||
262 | public function iRunBehat(): void |
||
263 | { |
||
264 | $executablePath = BEHAT_BIN_PATH; |
||
265 | |||
266 | if ($this->variables !== []) { |
||
267 | $content = '<?php '; |
||
268 | |||
269 | foreach ($this->variables['server'] ?? [] as $name => $value) { |
||
270 | $content .= sprintf('$_SERVER["%s"] = "%s"; ', $name, $value); |
||
271 | } |
||
272 | |||
273 | foreach ($this->variables['environment'] ?? [] as $name => $value) { |
||
274 | $content .= sprintf('$_ENV["%s"] = "%s"; ', $name, $value); |
||
275 | } |
||
276 | |||
277 | $content .= sprintf('require_once("%s"); ', $executablePath); |
||
278 | |||
279 | $executablePath = $this->thereIsFile('__executable.php', $content); |
||
280 | } |
||
281 | |||
282 | $this->process = new Process([self::$phpBin, $executablePath, '--strict', '-vvv', '--no-interaction', '--lang=en'], self::$workingDir); |
||
283 | $this->process->start(); |
||
284 | $this->process->wait(); |
||
285 | } |
||
286 | |||
287 | /** |
||
288 | * @Then /^it should pass$/ |
||
289 | */ |
||
290 | View Code Duplication | public function itShouldPass(): void |
|
0 ignored issues
–
show
|
|||
291 | { |
||
292 | if (0 === $this->getProcessExitCode()) { |
||
293 | return; |
||
294 | } |
||
295 | |||
296 | throw new \DomainException( |
||
297 | 'Behat was expecting to pass, but failed with the following output:' . \PHP_EOL . \PHP_EOL . $this->getProcessOutput() |
||
298 | ); |
||
299 | } |
||
300 | |||
301 | /** |
||
302 | * @Then /^it should pass with(?: "([^"]+)"|:)$/ |
||
303 | */ |
||
304 | public function itShouldPassWith($expectedOutput): void |
||
305 | { |
||
306 | $this->itShouldPass(); |
||
307 | $this->assertOutputMatches((string) $expectedOutput); |
||
308 | } |
||
309 | |||
310 | /** |
||
311 | * @Then /^it should fail$/ |
||
312 | */ |
||
313 | View Code Duplication | public function itShouldFail(): void |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
314 | { |
||
315 | if (0 !== $this->getProcessExitCode()) { |
||
316 | return; |
||
317 | } |
||
318 | |||
319 | throw new \DomainException( |
||
320 | 'Behat was expecting to fail, but passed with the following output:' . \PHP_EOL . \PHP_EOL . $this->getProcessOutput() |
||
321 | ); |
||
322 | } |
||
323 | |||
324 | /** |
||
325 | * @Then /^it should fail with(?: "([^"]+)"|:)$/ |
||
326 | */ |
||
327 | public function itShouldFailWith($expectedOutput): void |
||
328 | { |
||
329 | $this->itShouldFail(); |
||
330 | $this->assertOutputMatches((string) $expectedOutput); |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * @Then /^it should end with(?: "([^"]+)"|:)$/ |
||
335 | */ |
||
336 | public function itShouldEndWith($expectedOutput): void |
||
337 | { |
||
338 | $this->assertOutputMatches((string) $expectedOutput); |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * @param string $expectedOutput |
||
343 | */ |
||
344 | private function assertOutputMatches($expectedOutput): void |
||
345 | { |
||
346 | $pattern = '/' . preg_quote($expectedOutput, '/') . '/sm'; |
||
347 | $output = $this->getProcessOutput(); |
||
348 | |||
349 | $result = preg_match($pattern, $output); |
||
350 | if (false === $result) { |
||
351 | throw new \InvalidArgumentException('Invalid pattern given:' . $pattern); |
||
352 | } |
||
353 | |||
354 | if (0 === $result) { |
||
355 | throw new \DomainException(sprintf( |
||
356 | 'Pattern "%s" does not match the following output:' . \PHP_EOL . \PHP_EOL . '%s', |
||
357 | $pattern, |
||
358 | $output |
||
359 | )); |
||
360 | } |
||
361 | } |
||
362 | |||
363 | private function getProcessOutput(): string |
||
364 | { |
||
365 | $this->assertProcessIsAvailable(); |
||
366 | |||
367 | return $this->process->getErrorOutput() . $this->process->getOutput(); |
||
368 | } |
||
369 | |||
370 | private function getProcessExitCode(): int |
||
371 | { |
||
372 | $this->assertProcessIsAvailable(); |
||
373 | |||
374 | return $this->process->getExitCode(); |
||
375 | } |
||
376 | |||
377 | /** |
||
378 | * @throws \BadMethodCallException |
||
379 | */ |
||
380 | private function assertProcessIsAvailable(): void |
||
381 | { |
||
382 | if (null === $this->process) { |
||
383 | throw new \BadMethodCallException('Behat proccess cannot be found. Did you run it before making assertions?'); |
||
384 | } |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * @throws \RuntimeException |
||
389 | */ |
||
390 | private static function findPhpBinary(): string |
||
391 | { |
||
392 | $phpBinary = (new PhpExecutableFinder())->find(); |
||
393 | if (false === $phpBinary) { |
||
394 | throw new \RuntimeException('Unable to find the PHP executable.'); |
||
395 | } |
||
396 | |||
397 | return $phpBinary; |
||
398 | } |
||
399 | } |
||
400 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.