PageRenderTime 26ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Codeception/Lib/Generator/GherkinSnippets.php

http://github.com/Codeception/Codeception
PHP | 152 lines | 128 code | 16 blank | 8 comment | 15 complexity | 6f25da8ec91ebabeee89d5e2da40b245 MD5 | raw file
  1. <?php
  2. namespace Codeception\Lib\Generator;
  3. use Behat\Gherkin\Node\StepNode;
  4. use Codeception\Test\Loader\Gherkin;
  5. use Codeception\Util\Template;
  6. use Symfony\Component\Finder\Finder;
  7. class GherkinSnippets
  8. {
  9. protected $template = <<<EOF
  10. /**
  11. * @{{type}} {{text}}
  12. */
  13. public function {{methodName}}({{params}})
  14. {
  15. throw new \PHPUnit\Framework\IncompleteTestError("Step `{{text}}` is not defined");
  16. }
  17. EOF;
  18. protected $snippets = [];
  19. protected $processed = [];
  20. protected $features = [];
  21. public function __construct($settings, $test = null)
  22. {
  23. $loader = new Gherkin($settings);
  24. $pattern = $loader->getPattern();
  25. $path = $settings['path'];
  26. if (!empty($test)) {
  27. $path = $settings['path'].'/'.$test;
  28. if (preg_match($pattern, $test)) {
  29. $path = dirname($path);
  30. $pattern = basename($test);
  31. }
  32. }
  33. $finder = Finder::create()
  34. ->files()
  35. ->sortByName()
  36. ->in($path)
  37. ->followLinks()
  38. ->name($pattern);
  39. foreach ($finder as $file) {
  40. $pathname = str_replace("//", "/", $file->getPathname());
  41. $loader->loadTests($pathname);
  42. }
  43. $availableSteps = $loader->getSteps();
  44. $allSteps = [];
  45. foreach ($availableSteps as $stepGroup) {
  46. $allSteps = array_merge($allSteps, $stepGroup);
  47. }
  48. foreach ($loader->getTests() as $test) {
  49. /** @var $test \Codeception\Test\Gherkin **/
  50. $steps = $test->getScenarioNode()->getSteps();
  51. if ($test->getFeatureNode()->hasBackground()) {
  52. $steps = array_merge($steps, $test->getFeatureNode()->getBackground()->getSteps());
  53. }
  54. foreach ($steps as $step) {
  55. $matched = false;
  56. $text = $step->getText();
  57. if (self::stepHasPyStringArgument($step)) {
  58. // pretend it is inline argument
  59. $text .= ' ""';
  60. }
  61. foreach (array_keys($allSteps) as $pattern) {
  62. if (preg_match($pattern, $text)) {
  63. $matched = true;
  64. break;
  65. }
  66. }
  67. if (!$matched) {
  68. $this->addSnippet($step);
  69. $file = str_ireplace($settings['path'], '', $test->getFeatureNode()->getFile());
  70. if (!in_array($file, $this->features)) {
  71. $this->features[] = $file;
  72. }
  73. }
  74. }
  75. }
  76. }
  77. public function addSnippet(StepNode $step)
  78. {
  79. $args = [];
  80. $pattern = $step->getText();
  81. // match numbers (not in quotes)
  82. if (preg_match_all('~([\d\.])(?=([^"]*"[^"]*")*[^"]*$)~', $pattern, $matches)) {
  83. foreach ($matches[1] as $num => $param) {
  84. $num++;
  85. $args[] = '$num' . $num;
  86. $pattern = str_replace($param, ":num$num", $pattern);
  87. }
  88. }
  89. // match quoted string
  90. if (preg_match_all('~"(.*?)"~', $pattern, $matches)) {
  91. foreach ($matches[1] as $num => $param) {
  92. $num++;
  93. $args[] = '$arg' . $num;
  94. $pattern = str_replace('"'.$param.'"', ":arg$num", $pattern);
  95. }
  96. }
  97. // Has multiline argument at the end of step?
  98. if (self::stepHasPyStringArgument($step)) {
  99. $num = count($args) + 1;
  100. $pattern .= " :arg$num";
  101. $args[] = '$arg' . $num;
  102. }
  103. if (in_array($pattern, $this->processed)) {
  104. return;
  105. }
  106. $methodName = preg_replace('~(\s+?|\'|\"|\W)~', '', ucwords(preg_replace('~"(.*?)"|\d+~', '', $step->getText())));
  107. if (empty($methodName)) {
  108. $methodName = 'step_' . substr(sha1($pattern), 0, 9);
  109. }
  110. $this->snippets[] = (new Template($this->template))
  111. ->place('type', $step->getKeywordType())
  112. ->place('text', $pattern)
  113. ->place('methodName', lcfirst($methodName))
  114. ->place('params', implode(', ', $args))
  115. ->produce();
  116. $this->processed[] = $pattern;
  117. }
  118. public function getSnippets()
  119. {
  120. return $this->snippets;
  121. }
  122. public function getFeatures()
  123. {
  124. return $this->features;
  125. }
  126. public static function stepHasPyStringArgument(StepNode $step)
  127. {
  128. if ($step->hasArguments()) {
  129. $stepArgs = $step->getArguments();
  130. if ($stepArgs[count($stepArgs) - 1]->getNodeType() == "PyString") {
  131. return true;
  132. }
  133. }
  134. return false;
  135. }
  136. }