Security update for permissions_by_term
[yaffs-website] / vendor / drupal / drupal-extension / features / bootstrap / FeatureContext.php
1 <?php
2
3 use Behat\Behat\Context\Context;
4 use Behat\Gherkin\Node\PyStringNode;
5 use Behat\Gherkin\Node\TableNode;
6 use Drupal\DrupalExtension\Hook\Scope\BeforeNodeCreateScope;
7 use Drupal\DrupalExtension\Hook\Scope\EntityScope;
8 use Symfony\Component\Process\PhpExecutableFinder;
9 use Symfony\Component\Process\Process;
10
11 /**
12  * Features context for testing the Drupal Extension.
13  *
14  * @todo we are duplicating code from Behat's FeatureContext here for the
15  * purposes of testing since we can't easily run that as a context due to naming
16  * conflicts.
17  */
18 class FeatureContext implements Context {
19   /**
20    * Hook into node creation to test `@beforeNodeCreate`
21    *
22    * @beforeNodeCreate
23    */
24   public static function alterNodeParameters(BeforeNodeCreateScope $scope) {
25     call_user_func('\Drupal\DrupalExtension\Context\RawDrupalContext::alterNodeParameters', $scope);
26     // @see `features/api.feature`
27     // Change 'published on' to the expected 'created'.
28     $node = $scope->getEntity();
29     if (isset($node->{"published on"})) {
30       $node->created = $node->{"published on"};
31       unset($node->{"published on"});
32     }
33   }
34
35   /**
36    * Hook into term creation to test `@beforeTermCreate`
37    *
38    * @beforeTermCreate
39    */
40   public static function alterTermParameters(EntityScope $scope) {
41     // @see `features/api.feature`
42     // Change 'Label' to expected 'name'.
43     $term = $scope->getEntity();
44     if (isset($term->{'Label'})) {
45       $term->name = $term->{'Label'};
46       unset($term->{'Label'});
47     }
48   }
49
50   /**
51    * Hook into user creation to test `@beforeUserCreate`
52    *
53    * @beforeUserCreate
54    */
55   public static function alterUserParameters(EntityScope $scope) {
56     // @see `features/api.feature`
57     // Concatenate 'First name' and 'Last name' to form user name.
58     $user = $scope->getEntity();
59     if (isset($user->{"First name"}) && isset($user->{"Last name"})) {
60       $user->name = $user->{"First name"} . ' ' . $user->{"Last name"};
61       unset($user->{"First name"}, $user->{"Last name"});
62     }
63     // Transform custom 'E-mail' to 'mail'.
64     if (isset($user->{"E-mail"})) {
65       $user->mail = $user->{"E-mail"};
66       unset($user->{"E-mail"});
67     }
68   }
69
70   /**
71    * Test that a node is returned after node create.
72    *
73    * @afterNodeCreate
74    */
75   public static function afterNodeCreate(EntityScope $scope) {
76     if (!$node = $scope->getEntity()) {
77       throw new \Exception('Failed to find a node in @afterNodeCreate hook.');
78     }
79   }
80
81   /**
82    * Test that a term is returned after term create.
83    *
84    * @afterTermCreate
85    */
86   public static function afterTermCreate(EntityScope $scope) {
87     if (!$term = $scope->getEntity()) {
88       throw new \Exception('Failed to find a term in @afterTermCreate hook.');
89     }
90   }
91
92   /**
93    * Test that a user is returned after user create.
94    *
95    * @afterUserCreate
96    */
97   public static function afterUserCreate(EntityScope $scope) {
98     if (!$user = $scope->getEntity()) {
99       throw new \Exception('Failed to find a user in @afterUserCreate hook.');
100     }
101   }
102
103   /**
104    * Transforms long address field columns into shorter aliases.
105    *
106    * This is used in field_handlers.feature for testing if lengthy field:column
107    * combinations can be shortened to more human friendly aliases.
108    *
109    * @Transform table:name,mail,street,city,postcode,country
110    */
111   public function castUsersTable(TableNode $user_table) {
112     $aliases = array(
113       'country' => 'field_post_address:country',
114       'city' => 'field_post_address:locality',
115       'street' => 'field_post_address:thoroughfare',
116       'postcode' => 'field_post_address:postal_code',
117     );
118
119     // The first row of the table contains the field names.
120     $table = $user_table->getTable();
121     reset($table);
122     $first_row = key($table);
123
124     // Replace the aliased field names with the actual ones.
125     foreach ($table[$first_row] as $key => $alias) {
126       if (array_key_exists($alias, $aliases)) {
127         $table[$first_row][$key] = $aliases[$alias];
128       }
129     }
130
131     return new TableNode($table);
132   }
133
134   /**
135    * Transforms human readable field names into machine names.
136    *
137    * This is used in field_handlers.feature for testing if human readable names
138    * can be used instead of machine names in tests.
139    *
140    * @param TableNode $post_table
141    *   The original table.
142    *
143    * @return TableNode
144    *   The transformed table.
145    *
146    * @Transform rowtable:title,body,reference,date,links,select,address
147    */
148   public function transformPostContentTable(TableNode $post_table) {
149     $aliases = array(
150       'reference' => 'field_post_reference',
151       'date' => 'field_post_date',
152       'links' => 'field_post_links',
153       'select' => 'field_post_select',
154       'address' => 'field_post_address',
155     );
156
157     $table = $post_table->getTable();
158     array_walk($table, function (&$row) use ($aliases) {
159       // The first column of the row contains the field names. Replace the
160       // human readable field name with the machine name if it exists.
161       if (array_key_exists($row[0], $aliases)) {
162         $row[0] = $aliases[$row[0]];
163       }
164     });
165
166     return new TableNode($table);
167   }
168
169   /**
170    * From here down is the Behat FeatureContext.
171    *
172    * @defgroup Behat FeatureContext
173    * @{
174    */
175
176     /**
177      * @var string
178      */
179     private $phpBin;
180     /**
181      * @var Process
182      */
183     private $process;
184     /**
185      * @var string
186      */
187     private $workingDir;
188
189     /**
190      * Cleans test folders in the temporary directory.
191      *
192      * @BeforeSuite
193      * @AfterSuite
194      */
195     public static function cleanTestFolders()
196     {
197         if (is_dir($dir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'behat')) {
198             self::clearDirectory($dir);
199         }
200     }
201
202     /**
203      * Prepares test folders in the temporary directory.
204      *
205      * @BeforeScenario
206      */
207     public function prepareTestFolders()
208     {
209         do {
210             $random_name = md5((int) microtime(true) * rand(0, 100000));
211             $dir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'behat' . DIRECTORY_SEPARATOR . $random_name;
212         } while (is_dir($dir));
213
214         mkdir($dir . '/features/bootstrap/i18n', 0777, true);
215
216         $phpFinder = new PhpExecutableFinder();
217         if (false === $php = $phpFinder->find()) {
218             throw new \RuntimeException('Unable to find the PHP executable.');
219         }
220         $this->workingDir = $dir;
221         $this->phpBin = $php;
222         $this->process = new Process(null);
223     }
224
225     /**
226      * Creates a file with specified name and context in current workdir.
227      *
228      * @Given /^(?:there is )?a file named "([^"]*)" with:$/
229      *
230      * @param   string       $filename name of the file (relative path)
231      * @param   PyStringNode $content  PyString string instance
232      */
233     public function aFileNamedWith($filename, PyStringNode $content)
234     {
235         $content = strtr((string) $content, array("'''" => '"""'));
236         $this->createFile($this->workingDir . '/' . $filename, $content);
237     }
238
239     /**
240      * Moves user to the specified path.
241      *
242      * @Given /^I am in the "([^"]*)" path$/
243      *
244      * @param   string $path
245      */
246     public function iAmInThePath($path)
247     {
248         $this->moveToNewPath($path);
249     }
250
251     /**
252      * Checks whether a file at provided path exists.
253      *
254      * @Given /^file "([^"]*)" should exist$/
255      *
256      * @param   string $path
257      */
258     public function fileShouldExist($path)
259     {
260         PHPUnit_Framework_Assert::assertFileExists($this->workingDir . DIRECTORY_SEPARATOR . $path);
261     }
262
263     /**
264      * Sets specified ENV variable
265      *
266      * @When /^"BEHAT_PARAMS" environment variable is set to:$/
267      *
268      * @param PyStringNode $value
269      */
270     public function iSetEnvironmentVariable(PyStringNode $value)
271     {
272         $this->process->setEnv(array('BEHAT_PARAMS' => (string) $value));
273     }
274
275     /**
276      * Runs behat command with provided parameters
277      *
278      * @When /^I run "behat(?: ((?:\"|[^"])*))?"$/
279      *
280      * @param   string $argumentsString
281      */
282     public function iRunBehat($argumentsString = '')
283     {
284         $argumentsString = strtr($argumentsString, array('\'' => '"'));
285
286         $this->process->setWorkingDirectory($this->workingDir);
287         $this->process->setCommandLine(
288             sprintf(
289                 '%s %s %s %s',
290                 $this->phpBin,
291                 escapeshellarg(BEHAT_BIN_PATH),
292                 $argumentsString,
293                 strtr('--format-settings=\'{"timer": false}\'', array('\'' => '"', '"' => '\"'))
294             )
295         );
296         $this->process->start();
297         $this->process->wait();
298     }
299
300     /**
301      * Checks whether previously ran command passes|fails with provided output.
302      *
303      * @Then /^it should (fail|pass) with:$/
304      *
305      * @param   string       $success "fail" or "pass"
306      * @param   PyStringNode $text    PyString text instance
307      */
308     public function itShouldPassWith($success, PyStringNode $text)
309     {
310         $this->itShouldFail($success);
311         $this->theOutputShouldContain($text);
312     }
313
314     /**
315      * Checks whether specified file exists and contains specified string.
316      *
317      * @Then /^"([^"]*)" file should contain:$/
318      *
319      * @param   string       $path file path
320      * @param   PyStringNode $text file content
321      */
322     public function fileShouldContain($path, PyStringNode $text)
323     {
324         $path = $this->workingDir . '/' . $path;
325         PHPUnit_Framework_Assert::assertFileExists($path);
326
327         $fileContent = trim(file_get_contents($path));
328         // Normalize the line endings in the output
329         if ("\n" !== PHP_EOL) {
330             $fileContent = str_replace(PHP_EOL, "\n", $fileContent);
331         }
332
333         PHPUnit_Framework_Assert::assertEquals($this->getExpectedOutput($text), $fileContent);
334     }
335
336     /**
337      * Checks whether last command output contains provided string.
338      *
339      * @Then the output should contain:
340      *
341      * @param   PyStringNode $text PyString text instance
342      */
343     public function theOutputShouldContain(PyStringNode $text)
344     {
345         PHPUnit_Framework_Assert::assertContains($this->getExpectedOutput($text), $this->getOutput());
346     }
347
348     private function getExpectedOutput(PyStringNode $expectedText)
349     {
350         $text = strtr($expectedText, array('\'\'\'' => '"""', '%%TMP_DIR%%' => sys_get_temp_dir() . DIRECTORY_SEPARATOR));
351
352         // windows path fix
353         if ('/' !== DIRECTORY_SEPARATOR) {
354             $text = preg_replace_callback(
355                 '/ features\/[^\n ]+/', function ($matches) {
356                     return str_replace('/', DIRECTORY_SEPARATOR, $matches[0]);
357                 }, $text
358             );
359             $text = preg_replace_callback(
360                 '/\<span class\="path"\>features\/[^\<]+/', function ($matches) {
361                     return str_replace('/', DIRECTORY_SEPARATOR, $matches[0]);
362                 }, $text
363             );
364             $text = preg_replace_callback(
365                 '/\+[fd] [^ ]+/', function ($matches) {
366                     return str_replace('/', DIRECTORY_SEPARATOR, $matches[0]);
367                 }, $text
368             );
369         }
370
371         return $text;
372     }
373
374     /**
375      * Checks whether previously ran command failed|passed.
376      *
377      * @Then /^it should (fail|pass)$/
378      *
379      * @param   string $success "fail" or "pass"
380      */
381     public function itShouldFail($success)
382     {
383         if ('fail' === $success) {
384             if (0 === $this->getExitCode()) {
385                 echo 'Actual output:' . PHP_EOL . PHP_EOL . $this->getOutput();
386             }
387
388             PHPUnit_Framework_Assert::assertNotEquals(0, $this->getExitCode());
389         } else {
390             if (0 !== $this->getExitCode()) {
391                 echo 'Actual output:' . PHP_EOL . PHP_EOL . $this->getOutput();
392             }
393
394             PHPUnit_Framework_Assert::assertEquals(0, $this->getExitCode());
395         }
396     }
397
398     private function getExitCode()
399     {
400         return $this->process->getExitCode();
401     }
402
403     private function getOutput()
404     {
405         $output = $this->process->getErrorOutput() . $this->process->getOutput();
406
407         // Normalize the line endings in the output
408         if ("\n" !== PHP_EOL) {
409             $output = str_replace(PHP_EOL, "\n", $output);
410         }
411
412         // Replace wrong warning message of HHVM
413         $output = str_replace('Notice: Undefined index: ', 'Notice: Undefined offset: ', $output);
414
415         return trim(preg_replace("/ +$/m", '', $output));
416     }
417
418     private function createFile($filename, $content)
419     {
420         $path = dirname($filename);
421         if (!is_dir($path)) {
422             mkdir($path, 0777, true);
423         }
424
425         file_put_contents($filename, $content);
426     }
427
428     private function moveToNewPath($path)
429     {
430         $newWorkingDir = $this->workingDir .'/' . $path;
431         if (!file_exists($newWorkingDir)) {
432             mkdir($newWorkingDir, 0777, true);
433         }
434
435         $this->workingDir = $newWorkingDir;
436     }
437
438     private static function clearDirectory($path)
439     {
440         $files = scandir($path);
441         array_shift($files);
442         array_shift($files);
443
444         foreach ($files as $file) {
445             $file = $path . DIRECTORY_SEPARATOR . $file;
446             if (is_dir($file)) {
447                 self::clearDirectory($file);
448             } else {
449                 unlink($file);
450             }
451         }
452
453         rmdir($path);
454     }
455
456   /**
457    * @} End of defgroup Behat FeatureContext.
458    */
459
460 }