public function addSnippet(StepNode $step)
 {
     $args = [];
     $pattern = $step->getText();
     // match numbers (not in quotes)
     if (preg_match_all('~([\\d\\.])(?=([^"]*"[^"]*")*[^"]*$)~', $pattern, $matches)) {
         foreach ($matches[1] as $num => $param) {
             $num++;
             $args[] = '$num' . $num;
             $pattern = str_replace($param, ":num{$num}", $pattern);
         }
     }
     // match quoted string
     if (preg_match_all('~"(.*?)"~', $pattern, $matches)) {
         foreach ($matches[1] as $num => $param) {
             $num++;
             $args[] = '$arg' . $num;
             $pattern = str_replace('"' . $param . '"', ":arg{$num}", $pattern);
         }
     }
     if (in_array($pattern, $this->processed)) {
         return;
     }
     $methodName = preg_replace('~(\\s+?|\'|\\"|\\W)~', '', ucwords(preg_replace('~"(.*?)"|\\d+~', '', $step->getText())));
     $this->snippets[] = (new Template($this->template))->place('type', $step->getKeywordType())->place('text', $pattern)->place('methodName', lcfirst($methodName))->place('params', implode(', ', $args))->produce();
     $this->processed[] = $pattern;
 }
Пример #2
0
 /**
  * Checks if Feature matches specified filter.
  *
  * @param StepNode $step
  * @param string   $filterString
  *
  * @return Boolean
  */
 private function isStepMatch(StepNode $step, $filterString)
 {
     if ('/' === $filterString[0]) {
         return 1 === preg_match($filterString, $step->getText());
     }
     return false !== mb_strpos($step->getText(), $filterString, 0, 'utf8');
 }
Пример #3
0
 public function testTokens()
 {
     $step = new StepNode('When', 'Some "<text>" in <string>');
     $step->setTokens(array('text' => 'change'));
     $this->assertEquals('Some "change" in <string>', $step->getText());
     $this->assertEquals('Some "<text>" in <string>', $step->getCleanText());
     $step->setTokens(array('text' => 'change', 'string' => 'browser'));
     $this->assertEquals('Some "change" in browser', $step->getText());
     $this->assertEquals('Some "<text>" in <string>', $step->getCleanText());
 }
 /**
  * Loads definitions and translations from provided context.
  *
  * @param ContextInterface $context
  * @param StepNode         $step
  *
  * @return DefinitionSnippet
  */
 public function propose(ContextInterface $context, StepNode $step)
 {
     $contextRefl = new \ReflectionObject($context);
     $contextClass = $contextRefl->getName();
     $replacePatterns = array("/(?<= |^)\\\\'(?:((?!\\').)*)\\\\'(?= |\$)/", '/(?<= |^)\\"(?:[^\\"]*)\\"(?= |$)/', '/(\\d+)/');
     $text = $step->getText();
     $text = preg_replace('/([\\/\\[\\]\\(\\)\\\\^\\$\\.\\|\\?\\*\\+\'])/', '\\\\$1', $text);
     $regex = preg_replace($replacePatterns, array("\\'([^\\']*)\\'", "\"([^\"]*)\"", "(\\d+)"), $text);
     preg_match('/' . $regex . '/', $step->getText(), $matches);
     $count = count($matches) - 1;
     $methodName = preg_replace($replacePatterns, '', $text);
     $methodName = Transliterator::transliterate($methodName, ' ');
     $methodName = preg_replace('/[^a-zA-Z\\_\\ ]/', '', $methodName);
     $methodName = str_replace(' ', '', ucwords($methodName));
     if (0 !== strlen($methodName)) {
         $methodName[0] = strtolower($methodName[0]);
     } else {
         $methodName = 'stepDefinition1';
     }
     // get method number from method name
     $methodNumber = 2;
     if (preg_match('/(\\d+)$/', $methodName, $matches)) {
         $methodNumber = intval($matches[1]);
     }
     // check that proposed method name isn't arelady defined in context
     while ($contextRefl->hasMethod($methodName)) {
         $methodName = preg_replace('/\\d+$/', '', $methodName);
         $methodName .= $methodNumber++;
     }
     // check that proposed method name haven't been proposed earlier
     if (isset(self::$proposedMethods[$contextClass])) {
         foreach (self::$proposedMethods[$contextClass] as $proposedRegex => $proposedMethod) {
             if ($proposedRegex !== $regex) {
                 while ($proposedMethod === $methodName) {
                     $methodName = preg_replace('/\\d+$/', '', $methodName);
                     $methodName .= $methodNumber++;
                 }
             }
         }
     }
     self::$proposedMethods[$contextClass][$regex] = $methodName;
     $args = array();
     for ($i = 0; $i < $count; $i++) {
         $args[] = "\$arg" . ($i + 1);
     }
     foreach ($step->getArguments() as $argument) {
         if ($argument instanceof PyStringNode) {
             $args[] = "PyStringNode \$string";
         } elseif ($argument instanceof TableNode) {
             $args[] = "TableNode \$table";
         }
     }
     $description = $this->generateSnippet($regex, $methodName, $args);
     return new DefinitionSnippet($step, $description);
 }
Пример #5
0
 public function testText()
 {
     $step = new StepNode('When');
     $this->assertNull($step->getText());
     $step->setText('Some definition');
     $this->assertEquals('Some definition', $step->getText());
     $step = new StepNode('When', 'Some action');
     $this->assertEquals('Some action', $step->getText());
     $step->setText('Some "<text>" in <string>');
     $this->assertEquals('Some "<text>" in <string>', $step->getText());
 }
Пример #6
0
 public function addSnippet(StepNode $step)
 {
     $args = [];
     $pattern = $step->getText();
     if (preg_match_all('~"(.*?)"~', $pattern, $matches)) {
         foreach ($matches[1] as $num => $param) {
             $num++;
             $args[] = '$arg' . $num;
             $pattern = str_replace('"' . $param . '"', ":arg{$num}", $pattern);
         }
     }
     $methodName = preg_replace('~(\\s+?|\'|\\")~', '', ucwords(preg_replace('~"(.*?)"~', '', $step->getText())));
     $this->snippets[] = (new Template($this->template))->place('type', $step->getKeywordType())->place('text', $pattern)->place('methodName', lcfirst($methodName))->place('params', implode(', ', $args))->produce();
 }
    /**
     * Loads definitions and translations from provided context.
     *
     * @param ContextInterface $context
     * @param StepNode         $step
     *
     * @return DefinitionSnippet
     */
    public function propose(ContextInterface $context, StepNode $step)
    {
        $text = $step->getText();
        $regex = preg_replace('/([\\/\\[\\]\\(\\)\\\\^\\$\\.\\|\\?\\*\\+\'])/', '\\\\$1', $text);
        $regex = preg_replace(array("/(?<= |^)\\\\'(?:((?!\\').)*)\\\\'(?= |\$)/", '/(?<= |^)\\"(?:[^\\"]*)\\"(?= |$)/', '/(\\d+)/'), array("\\'([^\\']*)\\'", "\"([^\"]*)\"", "(\\d+)"), $regex);
        preg_match('/' . $regex . '/', $text, $matches);
        $count = count($matches) - 1;
        $args = array("\$world");
        for ($i = 0; $i < $count; $i++) {
            $args[] = "\$arg" . ($i + 1);
        }
        foreach ($step->getArguments() as $argument) {
            if ($argument instanceof PyStringNode) {
                $args[] = "\$string";
            } elseif ($argument instanceof TableNode) {
                $args[] = "\$table";
            }
        }
        $description = sprintf(<<<PHP
\$steps->%s('/^%s\$/', function(%s) {
    throw new \\Behat\\Behat\\Exception\\PendingException();
});
PHP
, '%s', $regex, implode(', ', $args));
        return new DefinitionSnippet($step, $description);
    }
Пример #8
0
 /**
  * {@inheritdoc}
  */
 public function printStep(Formatter $formatter, Scenario $scenario, StepNode $step, StepResult $result)
 {
     $this->printText($formatter->getOutputPrinter(), $step->getKeyword(), $step->getText(), $result);
     $this->pathPrinter->printStepPath($formatter, $scenario, $step, $result, mb_strlen($this->indentText, 'utf8'));
     $this->printArguments($formatter, $step->getArguments(), $result);
     $this->printStdOut($formatter->getOutputPrinter(), $result);
     $this->printException($formatter->getOutputPrinter(), $result);
 }
Пример #9
0
 /**
  * {@inheritdoc}
  */
 public function generateSnippet(Environment $environment, StepNode $step)
 {
     if (!$environment instanceof ContextEnvironment) {
         throw new EnvironmentSnippetGenerationException(sprintf('ContextSnippetGenerator does not support `%s` environment.', get_class($environment)), $environment);
     }
     $contextClass = $this->getSnippetAcceptingContextClass($environment);
     $patternType = $this->getPatternType($contextClass);
     $stepText = $step->getText();
     $pattern = $this->patternTransformer->generatePattern($patternType, $stepText);
     $methodName = $this->getMethodName($contextClass, $pattern->getCanonicalText(), $pattern->getPattern());
     $methodArguments = $this->getMethodArguments($step, $pattern->getPlaceholderCount());
     $snippetTemplate = $this->getSnippetTemplate($pattern->getPattern(), $methodName, $methodArguments);
     return new ContextSnippet($step, $snippetTemplate, $contextClass);
 }
Пример #10
0
 /**
  * {@inheritdoc}
  *
  * @throws AmbiguousMatchException
  */
 public function searchDefinition(Environment $environment, FeatureNode $feature, StepNode $step)
 {
     $suite = $environment->getSuite();
     $language = $feature->getLanguage();
     $stepText = $step->getText();
     $multi = $step->getArguments();
     $definitions = array();
     $result = null;
     foreach ($this->repository->getEnvironmentDefinitions($environment) as $definition) {
         $definition = $this->translator->translateDefinition($suite, $definition, $language);
         if (!($newResult = $this->match($definition, $stepText, $multi))) {
             continue;
         }
         $result = $newResult;
         $definitions[] = $newResult->getMatchedDefinition();
     }
     if (count($definitions) > 1) {
         throw new AmbiguousMatchException($result->getMatchedText(), $definitions);
     }
     return $result;
 }
Пример #11
0
 /**
  * Prints step using provided printer.
  *
  * @param Formatter  $formatter
  * @param Scenario   $scenario
  * @param StepNode   $step
  * @param StepResult $result
  */
 public function printStep(Formatter $formatter, Scenario $scenario, StepNode $step, StepResult $result)
 {
     /** @var JUnitOutputPrinter $outputPrinter */
     $outputPrinter = $formatter->getOutputPrinter();
     $message = $step->getKeyword() . ' ' . $step->getText();
     if ($result instanceof ExceptionResult && $result->hasException()) {
         $message .= ': ' . $this->exceptionPresenter->presentException($result->getException());
     }
     $attributes = array('message' => $message);
     switch ($result->getResultCode()) {
         case TestResult::FAILED:
             $outputPrinter->addTestcaseChild('failure', $attributes);
             break;
         case TestResult::PENDING:
             $attributes['type'] = 'pending';
             $outputPrinter->addTestcaseChild('error', $attributes);
             break;
         case StepResult::UNDEFINED:
             $attributes['type'] = 'undefined';
             $outputPrinter->addTestcaseChild('error', $attributes);
             break;
     }
 }
Пример #12
0
 protected function runStep(StepNode $stepNode)
 {
     $params = [];
     if ($stepNode->hasArguments()) {
         $args = $stepNode->getArguments();
         $table = $args[0];
         if ($table instanceof TableNode) {
             $params = [$table->getTableAsString()];
         }
     }
     $meta = new Meta($stepNode->getText(), $params);
     $meta->setPrefix($stepNode->getKeyword());
     $this->scenario->setMetaStep($meta);
     // enable metastep
     $stepText = $stepNode->getText();
     $this->getScenario()->comment(null);
     // make metastep to be printed even if no steps
     foreach ($this->steps as $pattern => $context) {
         $matches = [];
         if (!preg_match($pattern, $stepText, $matches)) {
             continue;
         }
         array_shift($matches);
         if ($stepNode->hasArguments()) {
             $matches = array_merge($matches, $stepNode->getArguments());
         }
         call_user_func_array($context, $matches);
         // execute the step
         break;
     }
     $this->scenario->setMetaStep(null);
     // disable metastep
 }
Пример #13
0
 /**
  * Changes step node type for types But, And to type of previous step if it exists else sets to Given
  *
  * @param StepNode   $node
  * @param StepNode[] $steps
  * @return StepNode
  */
 private function normalizeStepNodeKeywordType(StepNode $node, array $steps = array())
 {
     if (in_array($node->getKeywordType(), array('And', 'But'))) {
         if ($prev = end($steps)) {
             $keywordType = $prev->getKeywordType();
         } else {
             $keywordType = 'Given';
         }
         $node = new StepNode($node->getKeyword(), $node->getText(), $node->getArguments(), $node->getLine(), $keywordType);
     }
     return $node;
 }
 /**
  * @param FeatureNode $featureNode
  * @param StepNode $stepNode
  * @return ScenarioInterface|null
  */
 private function detectScenario(FeatureNode $featureNode, StepNode $stepNode)
 {
     foreach ($featureNode->getScenarios() as $scenario) {
         foreach ($scenario->getSteps() as $step) {
             if ($step->getLine() === $stepNode->getLine() && $step->getText() === $stepNode->getText()) {
                 return $scenario;
             }
         }
     }
     return null;
 }
Пример #15
0
 /**
  * Prints path to step.
  *
  * @param   Behat\Gherkin\Node\StepNode         $step           step node
  * @param   Behat\Behat\Definition\Definition   $definition     definition (if step defined)
  * @param   Exception                           $exception      exception (if step failed)
  */
 protected function printStepPath(StepNode $step, Definition $definition = null, \Exception $exception = null)
 {
     $color = $exception instanceof Pending ? 'pending' : 'failed';
     $type = $step->getType();
     $text = $step->getText();
     $stepPath = "In step `{$type} {$text}'.";
     $stepPathLn = mb_strlen($stepPath);
     $node = $step->getParent();
     if ($node instanceof BackgroundNode) {
         $scenarioPath = "From scenario background.";
     } else {
         $title = $node->getTitle();
         $title = $title ? "`{$title}'" : '***';
         $scenarioPath = "From scenario {$title}.";
     }
     $scenarioPathLn = mb_strlen($scenarioPath);
     $this->maxLineLength = max($this->maxLineLength, $stepPathLn);
     $this->maxLineLength = max($this->maxLineLength, $scenarioPathLn);
     $this->write("    {+{$color}}{$stepPath}{-{$color}}");
     if (null !== $definition) {
         $indentCount = $this->maxLineLength - $stepPathLn;
         $this->printPathComment($definition->getFile(), $definition->getLine(), $indentCount);
     } else {
         $this->writeln();
     }
     $this->write("    {+{$color}}{$scenarioPath}{-{$color}}");
     $indentCount = $this->maxLineLength - $scenarioPathLn;
     $this->printPathComment($node->getFile(), $node->getLine(), $indentCount);
     $this->writeln();
 }
Пример #16
0
 /**
  * Calculates step width.
  *
  * @param StepNode $step
  * @param integer  $indentation
  *
  * @return integer
  */
 public function calculateStepWidth(StepNode $step, $indentation)
 {
     $indentText = str_repeat(' ', intval($indentation));
     $text = sprintf('%s%s %s', $indentText, $step->getKeyword(), $step->getText());
     return mb_strlen($text, 'utf8');
 }
Пример #17
0
 /**
  * Dumps a step.
  *
  * @param StepNode $step Step node instance
  *
  * @return string
  *
  * @throws Exception if invalid step type providen
  */
 public function dumpStep(StepNode $step)
 {
     switch ($step->getType()) {
         case 'Given':
             $kw = $this->keywords->getGivenKeywords();
             break;
         case 'When':
             $kw = $this->keywords->getWhenKeywords();
             break;
         case 'Then':
             $kw = $this->keywords->getThenKeywords();
             break;
         case 'But':
             $kw = $this->keywords->getButKeywords();
             break;
         case 'And':
             $kw = $this->keywords->getAndKeywords();
             break;
         default:
             throw new Exception("invalid type given : " . $step->getType());
     }
     return $this->dumpText($kw . ' ' . $step->getText());
 }
Пример #18
0
 /**
  * @param StepNode $step
  *
  * @return string
  */
 private function getStepText(StepNode $step)
 {
     $spacesQuantity = $this->computeIndentationSpaces($step->getKeyword());
     return rtrim(sprintf('%s%s %s', $this->indent($spacesQuantity + self::INDENTATION), trim($step->getKeyword()), trim($step->getText()))) . "\n";
 }
Пример #19
0
 /**
  * Prints step definition path.
  *
  * @param   Behat\Gherkin\Node\StepNode         $step       step node
  * @param   Behat\Behat\Definition\Definition   $definition definition (if found one)
  *
  * @uses    printPathComment()
  */
 protected function printStepDefinitionPath(StepNode $step, Definition $definition)
 {
     $type = $step->getType();
     $text = $this->inOutlineSteps ? $step->getCleanText() : $step->getText();
     $nameLength = mb_strlen("    {$type} {$text}");
     $indentCount = $nameLength > $this->maxLineLength ? 0 : $this->maxLineLength - $nameLength;
     $this->printPathComment($definition->getFile(), $definition->getLine(), $indentCount);
 }
Пример #20
0
 /**
  * add results for step tests
  * @param FeatureNode       $feature    object
  * @param ScenarioInterface $scenario   object
  * @param StepNode          $step       object
  * @param TestResult        $testResult object
  * @return  null
  */
 public function addStepResult(FeatureNode $feature, ScenarioInterface $scenario, StepNode $step, TestResult $testResult)
 {
     $featurePath = $feature->getFile();
     $scenarioLine = $scenario->getLine();
     $this->testResults[$featurePath]["scenarios"][$scenarioLine]["steps"][$step->getLine()] = ["name" => $step->getText(), "line" => $step->getLine(), "testResultCode" => $testResult->getResultCode(), "testResult" => self::RESULT_CODES_MAPPING[$testResult->getResultCode()]];
 }
 /**
  * Returns a valid filename without path
  *
  * @param StepNode $step
  *
  * @return string
  */
 public function convertStepToFileName(StepNode $step)
 {
     return preg_replace('/[^A-Za-z0-9\\-]/', '_', mb_strtolower($step->getText())) . '.png';
 }
Пример #22
0
 /**
  * Prints step.
  *
  * @param [StepNode]            $step       step node
  * @param [integer]             $result     step result code
  * @param [DefinitionInterface] $definition def instance (if step defined)
  * @param [string]              $snippet    snippet (if step is undefined)
  * @param [\Exception]          $exception  exception (if step is failed)
  * @return [void]
  *
  * @uses StepEvent
  */
 protected function printStep(StepNode $step, $result, DefinitionInterface $definition = null, $snippet = null, \Exception $exception = null)
 {
     $this->_feature_info = array('result' => $result, 'text' => $step->getText());
     if ($exception != null) {
         $this->_feature_info['message'] = $exception->getMessage();
     }
 }
Пример #23
0
    /**
     * @see     Behat\Behat\Definition\Proposal\DefinitionProposalInterface::propose()
     */
    public function propose(ContextInterface $context, StepNode $step)
    {
        $contextRefl = new \ReflectionObject($context);
        $contextClass = $contextRefl->getName();
        $text = $step->getText();
        $replacePatterns = array('/\'([^\']*)\'/', '/\\"([^\\"]*)\\"/', '/(\\d+)/');
        $regex = preg_replace('/([\\/\\[\\]\\(\\)\\\\^\\$\\.\\|\\?\\*\\+])/', '\\\\$1', $text);
        $regex = preg_replace($replacePatterns, array("\\'([^\\']*)\\'", "\"([^\"]*)\"", "(\\d+)"), $regex);
        // Single quotes without matching pair (escape in resulting regex):
        $regex = preg_replace('/\'.*(?<!\')/', '\\\\$0', $regex);
        preg_match('/' . $regex . '/', $text, $matches);
        $count = count($matches) - 1;
        $methodName = preg_replace($replacePatterns, '', $text);
        $methodName = Transliterator::transliterate($methodName, ' ');
        $methodName = preg_replace('/[^a-zA-Z\\_\\ ]/', '', $methodName);
        $methodName = str_replace(' ', '', ucwords($methodName));
        if (0 !== strlen($methodName)) {
            $methodName[0] = strtolower($methodName[0]);
        } else {
            $methodName = 'stepDefinition1';
        }
        // get method number from method name
        $methodNumber = 2;
        if (preg_match('/(\\d+)$/', $methodName, $matches)) {
            $methodNumber = intval($matches[1]);
        }
        // check that proposed method name isn't arelady defined in context
        while ($contextRefl->hasMethod($methodName)) {
            $methodName = preg_replace('/\\d+$/', '', $methodName);
            $methodName .= $methodNumber++;
        }
        // check that proposed method name haven't been proposed earlier
        if (isset(self::$proposedMethods[$contextClass])) {
            foreach (self::$proposedMethods[$contextClass] as $proposedRegex => $proposedMethod) {
                if ($proposedRegex !== $regex) {
                    while ($proposedMethod === $methodName) {
                        $methodName = preg_replace('/\\d+$/', '', $methodName);
                        $methodName .= $methodNumber++;
                    }
                }
            }
        }
        self::$proposedMethods[$contextClass][$regex] = $methodName;
        $args = array();
        for ($i = 0; $i < $count; $i++) {
            $args[] = "\$argument" . ($i + 1);
        }
        foreach ($step->getArguments() as $argument) {
            if ($argument instanceof PyStringNode) {
                $args[] = "PyStringNode \$string";
            } elseif ($argument instanceof TableNode) {
                $args[] = "TableNode \$table";
            }
        }
        $description = sprintf(<<<PHP
    /**
     * @%s /^%s\$/
     */
    public function %s(%s)
    {
        throw new PendingException();
    }
PHP
, '%s', $regex, $methodName, implode(', ', $args));
        return new DefinitionSnippet($step, $description);
    }
Пример #24
0
 /**
  * {@inheritdoc}
  */
 protected function printStepName(StepNode $step, DefinitionInterface $definition = null, $color)
 {
     $type = $step->getType();
     $text = $this->inOutlineSteps ? $step->getCleanText() : $step->getText();
     if (null !== $definition) {
         $text = $this->colorizeDefinitionArguments($text, $definition, $color);
     }
     $this->writeln('<span class="keyword">' . $type . ' </span>');
     $this->writeln('<span class="text">' . $text . '</span>');
 }
Пример #25
0
 /**
  * Finds step definition, that match specified step.
  *
  * @param   Behat\Gherkin\Node\StepNode     $step   found step
  *
  * @return  Behat\Behat\Definition\Definition
  *
  * @uses    loadDefinitions()
  *
  * @throws  Behat\Behat\Exception\Ambiguous  if step description is ambiguous
  * @throws  Behat\Behat\Exception\Undefined  if step definition not found
  */
 public function findDefinition(StepNode $step)
 {
     if (!count($this->definitions)) {
         $this->loadDefinitions();
     }
     $text = $step->getText();
     $multiline = $step->getArguments();
     $matches = array();
     // find step to match
     foreach ($this->definitions as $origRegex => $definition) {
         $transRegex = $this->translateDefinitionRegex($origRegex, $step->getLanguage());
         if (preg_match($origRegex, $text, $arguments) || $origRegex !== $transRegex && preg_match($transRegex, $text, $arguments)) {
             // prepare callback arguments
             $arguments = $this->prepareCallbackArguments($definition->getCallbackReflection(), array_slice($arguments, 1), $multiline);
             // transform arguments
             foreach ($arguments as $num => $argument) {
                 foreach ($this->transformations as $transformation) {
                     if ($newArgument = $transformation->transform($argument)) {
                         $arguments[$num] = $newArgument;
                     }
                 }
             }
             // set matched definition
             $definition->setMatchedText($text);
             $definition->setValues($arguments);
             $matches[] = $definition;
         }
     }
     if (count($matches) > 1) {
         throw new Ambiguous($text, $matches);
     }
     if (0 === count($matches)) {
         throw new Undefined($text);
     }
     return $matches[0];
 }
 function it_generates_a_sanitized_filename_for_a_scenario_step(StepNode $step)
 {
     $step->getText()->willReturn('When I 1st click the link wi-fi on "fsf.org".');
     $this->convertStepToFileName($step)->shouldReturn('when_i_1st_click_the_link_wi-fi_on__fsf_org__.png');
 }
Пример #27
0
 /**
  * Prints step definition path.
  *
  * @param StepNode            $step       step node
  * @param DefinitionInterface $definition definition (if found one)
  *
  * @uses printPathComment()
  */
 protected function printStepDefinitionPath(StepNode $step, DefinitionInterface $definition)
 {
     if ($this->getParameter('paths')) {
         $type = $step->getType();
         $text = $this->inOutlineSteps ? $step->getCleanText() : $step->getText();
         $indent = $this->stepIndent;
         $nameLength = mb_strlen("{$indent}{$type} {$text}");
         $indentCount = $nameLength > $this->maxLineLength ? 0 : $this->maxLineLength - $nameLength;
         $this->printPathComment($this->relativizePathsInString($definition->getPath()), $indentCount);
         if ($this->getParameter('expand')) {
             $this->maxLineLength = max($this->maxLineLength, $nameLength);
         }
     } else {
         $this->writeln();
     }
 }
 /**
  * Executes steps chain (if there's one).
  *
  * Overwriten method to run behat hooks between chain steps.
  *
  * @param StepNode $step  step node
  * @param mixed    $chain chain
  *
  * @throws \Exception
  */
 private function executeStepsChainWithHooks(StepNode $step, $chain = null)
 {
     if (null === $chain) {
         // If there are no more chained steps below we will dispatch the
         // after step event, skipping the step that looks for exceptions here.
         if (strstr($step->getText(), self::EXCEPTIONS_STEP_TEXT) === false) {
             $this->dispatchafterstep = true;
         }
         return;
     }
     $chain = is_array($chain) ? $chain : array($chain);
     foreach ($chain as $chainItem) {
         if ($chainItem instanceof SubstepInterface) {
             $substepNode = $chainItem->getStepNode();
             $substepNode->setParent($step->getParent());
             // Replace by tokens when needed.
             if ($substepNode->getParent() instanceof OutlineNode) {
                 $substepNode = $substepNode->createExampleRowStep($this->tokens);
             }
             $this->dispatchafterstep = false;
             // Dispatch beforeStep event.
             $this->moodledispatcher->dispatch('beforeStep', new StepEvent($substepNode, $this->moodlelogicalParent, $this->moodlecontext));
             $substepEvent = $this->executeStep($substepNode);
             // Dispatch afterStep event.
             if ($this->dispatchafterstep === true) {
                 $this->moodledispatcher->dispatch('afterStep', $substepEvent);
                 $this->dispatchafterstep = false;
             }
             // Here we mark the step as failed so parent steps in the chain
             // will not continue dispatching the afterStep event.
             if (StepEvent::PASSED !== $substepEvent->getResult()) {
                 $this->failedstep = true;
                 throw $substepEvent->getException();
             }
         } elseif (is_callable($chainItem)) {
             $this->executeStepsChainWithHooks($step, call_user_func($chainItem));
         }
     }
 }
 /**
  * Finds step definition, that match specified step.
  *
  * @param ContextInterface $context
  * @param StepNode         $step
  * @param bool             $skip
  *
  * @return Definition
  *
  * @uses loadDefinitions()
  *
  * @throws AmbiguousException if step description is ambiguous
  * @throws UndefinedException if step definition not found
  */
 public function findDefinition(ContextInterface $context, StepNode $step, $skip = false)
 {
     $text = $step->getText();
     $multiline = $step->getArguments();
     $matches = array();
     // find step to match
     foreach ($this->getDefinitions() as $origRegex => $definition) {
         $transRegex = $this->translateDefinitionRegex($origRegex, $step->getLanguage());
         // if not regex really (string) - transform into it
         if (0 !== strpos($origRegex, '/')) {
             $origRegex = '/^' . preg_quote($origRegex, '/') . '$/';
             $transRegex = '/^' . preg_quote($transRegex, '/') . '$/';
         }
         if (preg_match($origRegex, $text, $arguments) || $origRegex !== $transRegex && preg_match($transRegex, $text, $arguments)) {
             // prepare callback arguments
             $arguments = $this->prepareCallbackArguments($context, $definition->getCallbackReflection(), array_slice($arguments, 1), $multiline);
             if (!$skip) {
                 // transform arguments
                 foreach ($arguments as &$argument) {
                     foreach ($this->getTransformations() as $trans) {
                         $transRegex = $this->translateDefinitionRegex($trans->getRegex(), $step->getLanguage());
                         $newArgument = $trans->transform($transRegex, $context, $argument);
                         if (null !== $newArgument) {
                             $argument = $newArgument;
                         }
                     }
                 }
             }
             // set matched definition
             $definition->setMatchedText($text);
             $definition->setValues($arguments);
             $matches[] = $definition;
         }
     }
     if (count($matches) > 1) {
         throw new AmbiguousException($text, $matches);
     }
     if (0 === count($matches)) {
         throw new UndefinedException($text);
     }
     return $matches[0];
 }
 /**
  * Returns the relative file path for the given step
  *
  * @param StepNode $step
  * @return string
  */
 protected function getFilepath($step)
 {
     return sprintf('%s/%s/%d-%s.png', $this->formatString($this->currentScenario->getFeature()->getTitle()), $this->formatString($this->currentScenario->getTitle()), $this->stepNumber, $this->formatString($step->getText()));
 }