FeatureContext::fileShouldExist()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
use Behat\Behat\Context\Context;
4
use Behat\Gherkin\Node\PyStringNode;
5
use Symfony\Component\Process\PhpExecutableFinder;
6
use Symfony\Component\Process\Process;
7
8
/**
9
 * Behat test suite context.
10
 */
11
class FeatureContext implements Context
12
{
13
    /**
14
     * @var string
15
     */
16
    private $phpBin;
17
    /**
18
     * @var Process
19
     */
20
    private $process;
21
    /**
22
     * @var string
23
     */
24
    private $workingDir;
25
26
    /**
27
     * Cleans test folders in the temporary directory.
28
     *
29
     * @BeforeSuite
30
     * @AfterSuite
31
     */
32
    public static function cleanTestFolders()
33
    {
34
        if (is_dir($dir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'behat')) {
35
            self::clearDirectory($dir);
36
        }
37
    }
38
39
    /**
40
     * Prepares test folders in the temporary directory.
41
     *
42
     * @BeforeScenario
43
     */
44
    public function prepareTestFolders()
45
    {
46
        $dir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'behat' . DIRECTORY_SEPARATOR .
47
            md5(microtime() * rand(0, 10000));
48
49
        mkdir($dir . '/features/bootstrap/i18n', 0777, true);
50
        mkdir($dir . '/junit');
51
52
        $phpFinder = new PhpExecutableFinder();
53
        if (false === $php = $phpFinder->find()) {
54
            throw new \RuntimeException('Unable to find the PHP executable.');
55
        }
56
        $this->workingDir = $dir;
57
        $this->phpBin = $php;
58
        $this->process = new Process(null);
59
    }
60
61
    /**
62
     * Creates a file with specified name and context in current workdir.
63
     *
64
     * @Given /^(?:there is )?a file named "([^"]*)" with:$/
65
     *
66
     * @param string       $filename name of the file (relative path)
67
     * @param PyStringNode $content  PyString string instance
68
     */
69
    public function aFileNamedWith($filename, PyStringNode $content)
70
    {
71
        $content = strtr((string) $content, array("'''" => '"""'));
72
        $this->createFile($this->workingDir . '/' . $filename, $content);
73
    }
74
75
    /**
76
     * Moves user to the specified path.
77
     *
78
     * @Given /^I am in the "([^"]*)" path$/
79
     *
80
     * @param string $path
81
     */
82
    public function iAmInThePath($path)
83
    {
84
        $this->moveToNewPath($path);
85
    }
86
87
    /**
88
     * Checks whether a file at provided path exists.
89
     *
90
     * @Given /^file "([^"]*)" should exist$/
91
     *
92
     * @param   string $path
93
     */
94
    public function fileShouldExist($path)
95
    {
96
        PHPUnit_Framework_Assert::assertFileExists($this->workingDir . DIRECTORY_SEPARATOR . $path);
97
    }
98
99
    /**
100
     * Sets specified ENV variable
101
     *
102
     * @When /^"BEHAT_PARAMS" environment variable is set to:$/
103
     *
104
     * @param PyStringNode $value
105
     */
106
    public function iSetEnvironmentVariable(PyStringNode $value)
107
    {
108
        $this->process->setEnv(array('BEHAT_PARAMS' => (string) $value));
109
    }
110
111
    /**
112
     * Runs behat command with provided parameters
113
     *
114
     * @When /^I run "behat(?: ((?:\"|[^"])*))?"$/
115
     *
116
     * @param string $argumentsString
117
     */
118
    public function iRunBehat($argumentsString = '')
119
    {
120
        $argumentsString = strtr($argumentsString, array('\'' => '"'));
121
122
        $this->process->setWorkingDirectory($this->workingDir);
123
        $this->process->setCommandLine(
124
            sprintf(
125
                '%s %s %s %s',
126
                $this->phpBin,
127
                escapeshellarg(BEHAT_BIN_PATH),
128
                $argumentsString,
129
                strtr('--format-settings=\'{"timer": false}\'', array('\'' => '"', '"' => '\"'))
130
            )
131
        );
132
133
        // Don't reset the LANG variable on HHVM, because it breaks HHVM itself
134
        if (!defined('HHVM_VERSION')) {
135
            $env = $this->process->getEnv();
136
            $env['LANG'] = 'en'; // Ensures that the default language is en, whatever the OS locale is.
137
            $this->process->setEnv($env);
138
        }
139
140
        $this->process->start();
141
        $this->process->wait();
142
    }
143
144
    /**
145
     * Checks whether previously ran command passes|fails with provided output.
146
     *
147
     * @Then /^it should (fail|pass) with:$/
148
     *
149
     * @param string       $success "fail" or "pass"
150
     * @param PyStringNode $text    PyString text instance
151
     */
152
    public function itShouldPassWith($success, PyStringNode $text)
153
    {
154
        $this->itShouldFail($success);
155
        $this->theOutputShouldContain($text);
156
    }
157
158
    /**
159
     * Checks whether previously runned command passes|failes with no output.
160
     *
161
     * @Then /^it should (fail|pass) with no output$/
162
     *
163
     * @param string $success "fail" or "pass"
164
     */
165
    public function itShouldPassWithNoOutput($success)
166
    {
167
        $this->itShouldFail($success);
168
        PHPUnit_Framework_Assert::assertEmpty($this->getOutput());
169
    }
170
171
    /**
172
     * Checks whether specified file exists and contains specified string.
173
     *
174
     * @Then /^"([^"]*)" file should contain:$/
175
     *
176
     * @param string       $path file path
177
     * @param PyStringNode $text file content
178
     */
179
    public function fileShouldContain($path, PyStringNode $text)
180
    {
181
        $path = $this->workingDir . '/' . $path;
182
        PHPUnit_Framework_Assert::assertFileExists($path);
183
184
        $fileContent = trim(file_get_contents($path));
185
        // Normalize the line endings in the output
186
        if ("\n" !== PHP_EOL) {
187
            $fileContent = str_replace(PHP_EOL, "\n", $fileContent);
188
        }
189
190
        PHPUnit_Framework_Assert::assertEquals($this->getExpectedOutput($text), $fileContent);
191
    }
192
193
    /**
194
     * Checks whether specified content and structure of the xml is correct without worrying about layout.
195
     *
196
     * @Then /^"([^"]*)" file xml should be like:$/
197
     *
198
     * @param string       $path file path
199
     * @param PyStringNode $text file content
200
     */
201
    public function fileXmlShouldBeLike($path, PyStringNode $text)
202
    {
203
        $path = $this->workingDir . '/' . $path;
204
        PHPUnit_Framework_Assert::assertFileExists($path);
205
206
        $fileContent = trim(file_get_contents($path));
207
208
        $dom = new DOMDocument();
209
        $dom->loadXML($text);
210
        $dom->formatOutput = true;
211
212
        PHPUnit_Framework_Assert::assertEquals(trim($dom->saveXML(null, LIBXML_NOEMPTYTAG)), $fileContent);
213
    }
214
215
216
    /**
217
     * Checks whether last command output contains provided string.
218
     *
219
     * @Then the output should contain:
220
     *
221
     * @param PyStringNode $text PyString text instance
222
     */
223
    public function theOutputShouldContain(PyStringNode $text)
224
    {
225
        PHPUnit_Framework_Assert::assertContains($this->getExpectedOutput($text), $this->getOutput());
226
    }
227
228
    private function getExpectedOutput(PyStringNode $expectedText)
229
    {
230
        $text = strtr($expectedText, array('\'\'\'' => '"""', '%%TMP_DIR%%' => sys_get_temp_dir() . DIRECTORY_SEPARATOR));
231
232
        // windows path fix
233
        if ('/' !== DIRECTORY_SEPARATOR) {
234
            $text = preg_replace_callback(
235
                '/[ "]features\/[^\n "]+/', function ($matches) {
236
                    return str_replace('/', DIRECTORY_SEPARATOR, $matches[0]);
237
                }, $text
238
            );
239
            $text = preg_replace_callback(
240
                '/\<span class\="path"\>features\/[^\<]+/', function ($matches) {
241
                    return str_replace('/', DIRECTORY_SEPARATOR, $matches[0]);
242
                }, $text
243
            );
244
            $text = preg_replace_callback(
245
                '/\+[fd] [^ ]+/', function ($matches) {
246
                    return str_replace('/', DIRECTORY_SEPARATOR, $matches[0]);
247
                }, $text
248
            );
249
        }
250
251
        return $text;
252
    }
253
254
    /**
255
     * Checks whether previously ran command failed|passed.
256
     *
257
     * @Then /^it should (fail|pass)$/
258
     *
259
     * @param string $success "fail" or "pass"
260
     */
261
    public function itShouldFail($success)
262
    {
263
        if ('fail' === $success) {
264
            if (0 === $this->getExitCode()) {
265
                echo 'Actual output:' . PHP_EOL . PHP_EOL . $this->getOutput();
266
            }
267
268
            PHPUnit_Framework_Assert::assertNotEquals(0, $this->getExitCode());
269
        } else {
270
            if (0 !== $this->getExitCode()) {
271
                echo 'Actual output:' . PHP_EOL . PHP_EOL . $this->getOutput();
272
            }
273
274
            PHPUnit_Framework_Assert::assertEquals(0, $this->getExitCode());
275
        }
276
    }
277
278
    /**
279
     * Checks whether the file is valid according to an XML schema.
280
     *
281
     * @Then /^the file "([^"]+)" should be a valid document according to "([^"]+)"$/
282
     *
283
     * @param string $xmlFile
284
     * @param string $schemaPath relative to features/bootstrap/schema
285
     */
286
    public function xmlShouldBeValid($xmlFile, $schemaPath)
287
    {
288
        $dom = new DomDocument();
289
        $dom->load($this->workingDir . '/' . $xmlFile);
290
291
        $dom->schemaValidate(__DIR__ . '/schema/' . $schemaPath);
292
    }
293
294
    private function getExitCode()
295
    {
296
        return $this->process->getExitCode();
297
    }
298
299
    private function getOutput()
300
    {
301
        $output = $this->process->getErrorOutput() . $this->process->getOutput();
302
303
        // Normalize the line endings in the output
304
        if ("\n" !== PHP_EOL) {
305
            $output = str_replace(PHP_EOL, "\n", $output);
306
        }
307
308
        // Replace wrong warning message of HHVM
309
        $output = str_replace('Notice: Undefined index: ', 'Notice: Undefined offset: ', $output);
310
311
        return trim(preg_replace("/ +$/m", '', $output));
312
    }
313
314
    private function createFile($filename, $content)
315
    {
316
        $path = dirname($filename);
317
        $this->createDirectory($path);
318
319
        file_put_contents($filename, $content);
320
    }
321
322
    private function createDirectory($path)
323
    {
324
        if (!is_dir($path)) {
325
            mkdir($path, 0777, true);
326
        }
327
    }
328
329
    private function moveToNewPath($path)
330
    {
331
        $newWorkingDir = $this->workingDir .'/' . $path;
332
        if (!file_exists($newWorkingDir)) {
333
            mkdir($newWorkingDir, 0777, true);
334
        }
335
336
        $this->workingDir = $newWorkingDir;
337
    }
338
339
    private static function clearDirectory($path)
340
    {
341
        $files = scandir($path);
342
        array_shift($files);
343
        array_shift($files);
344
345
        foreach ($files as $file) {
346
            $file = $path . DIRECTORY_SEPARATOR . $file;
347
            if (is_dir($file)) {
348
                self::clearDirectory($file);
349
            } else {
350
                unlink($file);
351
            }
352
        }
353
354
        rmdir($path);
355
    }
356
}
357