Completed
Push — master ( 3e4489...bae9a2 )
by Łukasz
02:05 queued 11s
created

TestContext::standardSymfonyAutoloaderConfigured()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.7666
c 0
b 0
f 0
cc 1
nc 1
nop 0
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
    /**
28
     * @BeforeFeature
29
     */
30
    public static function beforeFeature(): void
31
    {
32
        self::$workingDir = sprintf('%s/%s/', sys_get_temp_dir(), uniqid('', true));
33
        self::$filesystem = new Filesystem();
34
        self::$phpBin = self::findPhpBinary();
35
    }
36
37
    /**
38
     * @BeforeScenario
39
     */
40
    public function beforeScenario(): void
41
    {
42
        self::$filesystem->remove(self::$workingDir);
43
        self::$filesystem->mkdir(self::$workingDir, 0777);
44
    }
45
46
    /**
47
     * @AfterScenario
48
     */
49
    public function afterScenario(): void
50
    {
51
        self::$filesystem->remove(self::$workingDir);
52
    }
53
54
    /**
55
     * @Given a standard Symfony autoloader configured
56
     */
57
    public function standardSymfonyAutoloaderConfigured(): void
58
    {
59
        $this->thereIsFile('vendor/autoload.php', sprintf(<<<'CON'
60
<?php
61
62
declare(strict_types=1);
63
64
$loader = require '%s';
65
$loader->addPsr4('App\\', __DIR__ . '/../src/');
66
$loader->addPsr4('App\\Tests\\', __DIR__ . '/../tests/');
67
68
return $loader; 
69
CON
70
            , __DIR__ . '/../../../vendor/autoload.php'));
71
    }
72
73
    /**
74
     * @Given a working Symfony application with SymfonyExtension configured
75
     */
76
    public function workingSymfonyApplicationWithExtension(): void
77
    {
78
        $this->thereIsConfiguration(<<<'CON'
79
default:
80
    extensions:
81
        FriendsOfBehat\SymfonyExtension:
82
            kernel:
83
                class: App\Kernel
84
CON
85
        );
86
87
        $this->standardSymfonyAutoloaderConfigured();
88
89
        $this->thereIsFile('src/Kernel.php', <<<'CON'
90
<?php
91
92
namespace App;
93
94
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
95
use Symfony\Component\Config\Loader\LoaderInterface;
96
use Symfony\Component\DependencyInjection\ContainerBuilder;
97
use Symfony\Component\HttpFoundation\Response;
98
use Symfony\Component\HttpKernel\Kernel as HttpKernel;
99
use Symfony\Component\Routing\RouteCollectionBuilder;
100
101
class Kernel extends HttpKernel
102
{
103
    use MicroKernelTrait;
104
105
    public function helloWorld(): Response
106
    {
107
        return new Response('Hello world!');
108
    }
109
110
    public function registerBundles(): iterable
111
    {
112
        return [
113
            new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
114
            new \FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle(),
115
        ];
116
    }
117
118
    protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
119
    {
120
        $container->loadFromExtension('framework', [
121
            'test' => $this->getEnvironment() === 'test',
122
            'secret' => 'Pigeon',
123
        ]);
124
        
125
        $loader->load(__DIR__ . '/../config/services.yaml');
126
    }
127
    
128
    protected function configureRoutes(RouteCollectionBuilder $routes)
129
    {
130
        $routes->add('/hello-world', 'kernel:helloWorld');
131
    }
132
}
133
CON
134
        );
135
136
        $this->thereIsFile('config/services.yaml', '');
137
    }
138
139
    /**
140
     * @Given /^a YAML services file containing:$/
141
     */
142
    public function yamlServicesFile($content): void
143
    {
144
        $this->thereIsFile('config/services.yaml', (string) $content);
145
    }
146
147
    /**
148
     * @Given /^a Behat configuration containing(?: "([^"]+)"|:)$/
149
     */
150
    public function thereIsConfiguration($content): void
151
    {
152
        $mainConfigFile = sprintf('%s/behat.yml', self::$workingDir);
153
        $newConfigFile = sprintf('%s/behat-%s.yml', self::$workingDir, md5((string) $content));
154
155
        self::$filesystem->dumpFile($newConfigFile, (string) $content);
156
157
        if (!file_exists($mainConfigFile)) {
158
            self::$filesystem->dumpFile($mainConfigFile, Yaml::dump(['imports' => []]));
159
        }
160
161
        $mainBehatConfiguration = Yaml::parseFile($mainConfigFile);
162
        $mainBehatConfiguration['imports'][] = $newConfigFile;
163
164
        self::$filesystem->dumpFile($mainConfigFile, Yaml::dump($mainBehatConfiguration));
165
    }
166
167
    /**
168
     * @Given /^a (?:.+ |)file "([^"]+)" containing(?: "([^"]+)"|:)$/
169
     */
170
    public function thereIsFile($file, $content): void
171
    {
172
        self::$filesystem->dumpFile(self::$workingDir . '/' . $file, (string) $content);
173
    }
174
175
    /**
176
     * @Given /^a feature file containing(?: "([^"]+)"|:)$/
177
     */
178
    public function thereIsFeatureFile($content): void
179
    {
180
        $this->thereIsFile(sprintf('features/%s.feature', md5(uniqid('', true))), $content);
181
    }
182
183
    /**
184
     * @When /^I run Behat$/
185
     */
186
    public function iRunBehat(): void
187
    {
188
        $this->process = new Process(sprintf('%s %s --strict -vvv --no-interaction --lang=en', self::$phpBin, escapeshellarg(BEHAT_BIN_PATH)));
189
        $this->process->setWorkingDirectory(self::$workingDir);
190
        $this->process->start();
191
        $this->process->wait();
192
    }
193
194
    /**
195
     * @Then /^it should pass$/
196
     */
197 View Code Duplication
    public function itShouldPass(): void
0 ignored issues
show
Duplication introduced by
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.

Loading history...
198
    {
199
        if (0 === $this->getProcessExitCode()) {
200
            return;
201
        }
202
203
        throw new \DomainException(
204
            'Behat was expecting to pass, but failed with the following output:' . \PHP_EOL . \PHP_EOL . $this->getProcessOutput()
205
        );
206
    }
207
208
    /**
209
     * @Then /^it should pass with(?: "([^"]+)"|:)$/
210
     */
211
    public function itShouldPassWith($expectedOutput): void
212
    {
213
        $this->itShouldPass();
214
        $this->assertOutputMatches((string) $expectedOutput);
215
    }
216
217
    /**
218
     * @Then /^it should fail$/
219
     */
220 View Code Duplication
    public function itShouldFail(): void
0 ignored issues
show
Duplication introduced by
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.

Loading history...
221
    {
222
        if (0 !== $this->getProcessExitCode()) {
223
            return;
224
        }
225
226
        throw new \DomainException(
227
            'Behat was expecting to fail, but passed with the following output:' . \PHP_EOL . \PHP_EOL . $this->getProcessOutput()
228
        );
229
    }
230
231
    /**
232
     * @Then /^it should fail with(?: "([^"]+)"|:)$/
233
     */
234
    public function itShouldFailWith($expectedOutput): void
235
    {
236
        $this->itShouldFail();
237
        $this->assertOutputMatches((string) $expectedOutput);
238
    }
239
240
    /**
241
     * @Then /^it should end with(?: "([^"]+)"|:)$/
242
     */
243
    public function itShouldEndWith($expectedOutput): void
244
    {
245
        $this->assertOutputMatches((string) $expectedOutput);
246
    }
247
248
    /**
249
     * @param string $expectedOutput
250
     */
251
    private function assertOutputMatches($expectedOutput): void
252
    {
253
        $pattern = '/' . preg_quote($expectedOutput, '/') . '/sm';
254
        $output = $this->getProcessOutput();
255
256
        $result = preg_match($pattern, $output);
257
        if (false === $result) {
258
            throw new \InvalidArgumentException('Invalid pattern given:' . $pattern);
259
        }
260
261
        if (0 === $result) {
262
            throw new \DomainException(sprintf(
263
                'Pattern "%s" does not match the following output:' . \PHP_EOL . \PHP_EOL . '%s',
264
                $pattern,
265
                $output
266
            ));
267
        }
268
    }
269
270
    private function getProcessOutput(): string
271
    {
272
        $this->assertProcessIsAvailable();
273
274
        return $this->process->getErrorOutput() . $this->process->getOutput();
275
    }
276
277
    private function getProcessExitCode(): int
278
    {
279
        $this->assertProcessIsAvailable();
280
281
        return $this->process->getExitCode();
282
    }
283
284
    /**
285
     * @throws \BadMethodCallException
286
     */
287
    private function assertProcessIsAvailable(): void
288
    {
289
        if (null === $this->process) {
290
            throw new \BadMethodCallException('Behat proccess cannot be found. Did you run it before making assertions?');
291
        }
292
    }
293
294
    /**
295
     * @throws \RuntimeException
296
     */
297
    private static function findPhpBinary(): string
298
    {
299
        $phpBinary = (new PhpExecutableFinder())->find();
300
        if (false === $phpBinary) {
301
            throw new \RuntimeException('Unable to find the PHP executable.');
302
        }
303
304
        return $phpBinary;
305
    }
306
}
307