Completed
Push — master ( 77b1ae...45f18f )
by Kamil
10s
created

thereIsFeatureFileWithScenarioWithPendingStep()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 21
rs 9.3142
cc 1
eloc 7
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the TestContext package.
5
 *
6
 * (c) FriendsOfBehat
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 FriendsOfBehat\TestContext\Context;
13
14
use Behat\Behat\Context\Context;
15
use Symfony\Component\Filesystem\Filesystem;
16
use Symfony\Component\Process\PhpExecutableFinder;
17
use Symfony\Component\Process\Process;
18
19
/**
20
 * @author Kamil Kokot <[email protected]>
21
 */
22
final class TestContext implements Context
23
{
24
    /**
25
     * @var string
26
     */
27
    private static $workingDir;
28
29
    /**
30
     * @var Filesystem
31
     */
32
    private static $filesystem;
33
34
    /**
35
     * @var string
36
     */
37
    private static $phpBin;
38
39
    /**
40
     * @var Process
41
     */
42
    private $process;
43
44
    /**
45
     * @BeforeFeature
46
     */
47
    public static function beforeFeature()
48
    {
49
        self::$workingDir = sprintf('%s/%s/', sys_get_temp_dir(), uniqid('', true));
50
        self::$filesystem = new Filesystem();
51
        self::$phpBin = self::findPhpBinary();
52
    }
53
54
    /**
55
     * @BeforeScenario
56
     */
57
    public function beforeScenario()
58
    {
59
        self::$filesystem->remove(self::$workingDir);
60
        self::$filesystem->mkdir(self::$workingDir, 0777);
61
    }
62
63
    /**
64
     * @AfterScenario
65
     */
66
    public function afterScenario()
67
    {
68
        self::$filesystem->remove(self::$workingDir);
69
    }
70
71
    /**
72
     * @Given /^a Behat configuration containing(?: "([^"]+)"|:)$/
73
     */
74
    public function thereIsConfiguration($content)
75
    {
76
        $this->thereIsFile('behat.yml', $content);
77
    }
78
79
    /**
80
     * @Given /^a (?:.+ |)file "([^"]+)" containing(?: "([^"]+)"|:)$/
81
     */
82
    public function thereIsFile($file, $content)
83
    {
84
        self::$filesystem->dumpFile(self::$workingDir . '/' . $file, (string) $content);
85
    }
86
87
    /**
88
     * @Given /^a feature file containing(?: "([^"]+)"|:)$/
89
     */
90
    public function thereIsFeatureFile($content)
91
    {
92
        $this->thereIsFile(sprintf('features/%s.feature', md5(uniqid(null, true))), $content);
93
    }
94
95
    /**
96
     * @Given /^a feature file with passing scenario$/
97
     */
98
    public function thereIsFeatureFileWithPassingScenario()
99
    {
100
        $this->thereIsFile('features/bootstrap/FeatureContext.php', <<<CON
101
<?php
102
103
class FeatureContext implements \Behat\Behat\Context\Context
104
{
105
    /** @Then it passes */
106
    public function itPasses() {}
107
}
108
CON
109
);
110
111
        $this->thereIsFeatureFile(<<<FEA
112
Feature: Passing feature
113
114
    Scenario: Passing scenario
115
        Then it passes
116
FEA
117
);
118
    }
119
120
    /**
121
     * @Given /^a feature file with failing scenario$/
122
     */
123
    public function thereIsFeatureFileWithFailingScenario()
124
    {
125
        $this->thereIsFile('features/bootstrap/FeatureContext.php', <<<CON
126
<?php
127
128
class FeatureContext implements \Behat\Behat\Context\Context
129
{
130
    /** @Then it fails */
131
    public function itFails() { throw new \RuntimeException(); }
132
}
133
CON
134
        );
135
136
        $this->thereIsFeatureFile(<<<FEA
137
Feature: Failing feature
138
139
    Scenario: Failing scenario
140
        Then it fails
141
FEA
142
        );
143
    }
144
145
    /**
146
     * @Given /^a feature file with scenario with missing step$/
147
     */
148
    public function thereIsFeatureFileWithScenarioWithMissingStep()
149
    {
150
        $this->thereIsFile('features/bootstrap/FeatureContext.php', <<<CON
151
<?php 
152
153
class FeatureContext implements \Behat\Behat\Context\Context {}
154
CON
155
        );
156
157
        $this->thereIsFeatureFile(<<<FEA
158
Feature: Feature with missing step
159
160
    Scenario: Scenario with missing step
161
        Then it does not have this step
162
FEA
163
        );
164
    }
165
166
    /**
167
     * @Given /^a feature file with scenario with pending step$/
168
     */
169
    public function thereIsFeatureFileWithScenarioWithPendingStep()
170
    {
171
        $this->thereIsFile('features/bootstrap/FeatureContext.php', <<<CON
172
<?php
173
174
class FeatureContext implements \Behat\Behat\Context\Context 
175
{
176
    /** @Then it has this step as pending */
177
    public function itFails() { throw new \Behat\Behat\Tester\Exception\PendingException(); }
178
}
179
CON
180
        );
181
182
        $this->thereIsFeatureFile(<<<FEA
183
Feature: Feature with pending step
184
185
    Scenario: Scenario with pending step
186
        Then it has this step as pending
187
FEA
188
        );
189
    }
190
191
    /**
192
     * @When /^I run Behat$/
193
     */
194
    public function iRunBehat()
195
    {
196
        $this->process = new Process(sprintf('%s %s --strict', self::$phpBin, escapeshellarg(BEHAT_BIN_PATH)));
197
        $this->process->setWorkingDirectory(self::$workingDir);
198
        $this->process->start();
199
        $this->process->wait();
200
    }
201
202
    /**
203
     * @Then /^it should pass$/
204
     */
205 View Code Duplication
    public function itShouldPass()
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...
206
    {
207
        if (0 === $this->getProcessExitCode()) {
208
            return;
209
        }
210
211
        throw new \DomainException(
212
            'Behat was expecting to pass, but failed with the following output:' . PHP_EOL . PHP_EOL . $this->getProcessOutput()
213
        );
214
    }
215
216
    /**
217
     * @Then /^it should pass with(?: "([^"]+)"|:)$/
218
     */
219
    public function itShouldPassWith($expectedOutput)
220
    {
221
        $this->itShouldPass();
222
        $this->assertOutputMatches((string) $expectedOutput);
223
    }
224
225
    /**
226
     * @Then /^it should fail$/
227
     */
228 View Code Duplication
    public function itShouldFail()
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...
229
    {
230
        if (0 !== $this->getProcessExitCode()) {
231
            return;
232
        }
233
234
        throw new \DomainException(
235
            'Behat was expecting to fail, but passed with the following output:' . PHP_EOL . PHP_EOL . $this->getProcessOutput()
236
        );
237
    }
238
239
    /**
240
     * @Then /^it should fail with(?: "([^"]+)"|:)$/
241
     */
242
    public function itShouldFailWith($expectedOutput)
243
    {
244
        $this->itShouldFail();
245
        $this->assertOutputMatches((string) $expectedOutput);
246
    }
247
248
    /**
249
     * @Then /^it should end with(?: "([^"]+)"|:)$/
250
     */
251
    public function itShouldEndWith($expectedOutput)
252
    {
253
        $this->assertOutputMatches((string) $expectedOutput);
254
    }
255
256
    /**
257
     * @param string $expectedOutput
258
     */
259
    private function assertOutputMatches($expectedOutput)
260
    {
261
        $pattern = '/' . preg_quote($expectedOutput, '/') . '/sm';
262
        $output = $this->getProcessOutput();
263
264
        $result = preg_match($pattern, $output);
265
        if (false === $result) {
266
            throw new \InvalidArgumentException('Invalid pattern given:' . $pattern);
267
        }
268
269
        if (0 === $result) {
270
            throw new \DomainException(sprintf(
271
                'Pattern "%s" does not match the following output:' . PHP_EOL . PHP_EOL . '%s',
272
                $pattern,
273
                $output
274
            ));
275
        }
276
    }
277
278
    /**
279
     * @return string
280
     */
281
    private function getProcessOutput()
282
    {
283
        $this->assertProcessIsAvailable();
284
285
        return $this->process->getErrorOutput() . $this->process->getOutput();
286
    }
287
288
    /**
289
     * @return int
290
     */
291
    private function getProcessExitCode()
292
    {
293
        $this->assertProcessIsAvailable();
294
295
        return $this->process->getExitCode();
296
    }
297
298
    /**
299
     * @throws \BadMethodCallException
300
     */
301
    private function assertProcessIsAvailable()
302
    {
303
        if (null === $this->process) {
304
            throw new \BadMethodCallException('Behat proccess cannot be found. Did you run it before making assertions?');
305
        }
306
    }
307
308
    /**
309
     * @return string
310
     *
311
     * @throws \RuntimeException
312
     */
313
    private static function findPhpBinary()
314
    {
315
        $phpBinary = (new PhpExecutableFinder())->find();
316
        if (false === $phpBinary) {
317
            throw new \RuntimeException('Unable to find the PHP executable.');
318
        }
319
320
        return $phpBinary;
321
    }
322
}
323