Completed
Push — master ( 0a5640...f8ba2f )
by Kamil
03:10 queued 30s
created

TestContext::itShouldEndWith()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
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
     * @When /^I run Behat$/
89
     */
90
    public function iRunBehat()
91
    {
92
        $this->process = new Process(sprintf('%s %s --strict', self::$phpBin, escapeshellarg(BEHAT_BIN_PATH)));
93
        $this->process->setWorkingDirectory(self::$workingDir);
94
        $this->process->start();
95
        $this->process->wait();
96
    }
97
98
    /**
99
     * @Then /^it should pass$/
100
     */
101 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...
102
    {
103
        if (0 === $this->getProcessExitCode()) {
104
            return;
105
        }
106
107
        throw new \DomainException(
108
            'Behat was expecting to pass, but failed with the following output:' . PHP_EOL . PHP_EOL . $this->getProcessOutput()
109
        );
110
    }
111
112
    /**
113
     * @Then /^it should pass with(?: "([^"]+)"|:)$/
114
     */
115
    public function itShouldPassWith($expectedOutput)
116
    {
117
        $this->itShouldPass();
118
        $this->assertOutputMatches((string) $expectedOutput);
119
    }
120
121
    /**
122
     * @Then /^it should fail$/
123
     */
124 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...
125
    {
126
        if (0 !== $this->getProcessExitCode()) {
127
            return;
128
        }
129
130
        throw new \DomainException(
131
            'Behat was expecting to fail, but passed with the following output:' . PHP_EOL . PHP_EOL . $this->getProcessOutput()
132
        );
133
    }
134
135
    /**
136
     * @Then /^it should fail with(?: "([^"]+)"|:)$/
137
     */
138
    public function itShouldFailWith($expectedOutput)
139
    {
140
        $this->itShouldFail();
141
        $this->assertOutputMatches((string) $expectedOutput);
142
    }
143
144
    /**
145
     * @Then /^it should end with(?: "([^"]+)"|:)$/
146
     */
147
    public function itShouldEndWith($expectedOutput)
148
    {
149
        $this->assertOutputMatches((string) $expectedOutput);
150
    }
151
152
    /**
153
     * @param string $expectedOutput
154
     */
155
    private function assertOutputMatches($expectedOutput)
156
    {
157
        $pattern = '/' . preg_quote($expectedOutput, '/') . '/sm';
158
        $output = $this->getProcessOutput();
159
160
        $result = preg_match($pattern, $output);
161
        if (false === $result) {
162
            throw new \InvalidArgumentException('Invalid pattern given:' . $pattern);
163
        }
164
165
        if (0 === $result) {
166
            throw new \DomainException(sprintf(
167
                'Pattern "%s" does not match the following output:' . PHP_EOL . PHP_EOL . '%s',
168
                $pattern,
169
                $output
170
            ));
171
        }
172
    }
173
174
    /**
175
     * @return string
176
     */
177
    private function getProcessOutput()
178
    {
179
        $this->assertProcessIsAvailable();
180
181
        return $this->process->getErrorOutput() . $this->process->getOutput();
182
    }
183
184
    /**
185
     * @return int
186
     */
187
    private function getProcessExitCode()
188
    {
189
        $this->assertProcessIsAvailable();
190
191
        return $this->process->getExitCode();
192
    }
193
194
    /**
195
     * @throws \BadMethodCallException
196
     */
197
    private function assertProcessIsAvailable()
198
    {
199
        if (null === $this->process) {
200
            throw new \BadMethodCallException('Behat proccess cannot be found. Did you run it before making assertions?');
201
        }
202
    }
203
204
    /**
205
     * @return string
206
     *
207
     * @throws \RuntimeException
208
     */
209
    private static function findPhpBinary()
210
    {
211
        $phpBinary = (new PhpExecutableFinder())->find();
212
        if (false === $phpBinary) {
213
            throw new \RuntimeException('Unable to find the PHP executable.');
214
        }
215
216
        return $phpBinary;
217
    }
218
}
219