From 58c0ea1f4d734b46410fa188f0e5c30556c254e8 Mon Sep 17 00:00:00 2001 From: Andrey Stukalin Date: Thu, 10 Nov 2016 13:51:07 +0100 Subject: [PATCH] Multiple example tables and tags support #117 --- .gitignore | 1 + src/Behat/Gherkin/Filter/LineFilter.php | 78 ++++++------ src/Behat/Gherkin/Filter/LineRangeFilter.php | 75 ++++++----- src/Behat/Gherkin/Filter/TagFilter.php | 57 ++++++++- src/Behat/Gherkin/Loader/ArrayLoader.php | 38 +++++- src/Behat/Gherkin/Node/ExampleTableNode.php | 20 ++- src/Behat/Gherkin/Node/OutlineNode.php | 120 +++++++++++------- src/Behat/Gherkin/Node/TableNode.php | 24 ++++ src/Behat/Gherkin/Parser.php | 49 ++++++- tests/Behat/Gherkin/Filter/FilterTest.php | 16 ++- tests/Behat/Gherkin/Filter/LineFilterTest.php | 31 +++-- .../Gherkin/Filter/LineRangeFilterTest.php | 55 ++++++-- tests/Behat/Gherkin/Filter/TagFilterTest.php | 85 +++++++++++++ .../outline_with_multiple_examples.yml | 55 ++++++++ .../Gherkin/Fixtures/etalons/tags_sample.yml | 36 +++++- .../outline_with_multiple_examples.feature | 36 ++++++ .../Fixtures/features/tags_sample.feature | 41 ++++-- tests/Behat/Gherkin/Keywords/KeywordsTest.php | 2 +- .../Behat/Gherkin/Loader/ArrayLoaderTest.php | 18 +-- tests/Behat/Gherkin/Node/ExampleNodeTest.php | 4 +- tests/Behat/Gherkin/Node/OutlineNodeTest.php | 74 +++++++++-- tests/Behat/Gherkin/Node/TableNodeTest.php | 86 +++++++++++++ tests/Behat/Gherkin/ParserTest.php | 5 +- 23 files changed, 807 insertions(+), 199 deletions(-) create mode 100644 tests/Behat/Gherkin/Fixtures/etalons/outline_with_multiple_examples.yml create mode 100644 tests/Behat/Gherkin/Fixtures/features/outline_with_multiple_examples.feature diff --git a/.gitignore b/.gitignore index 33b7c658..a26d81a0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ vendor composer.phar composer.lock +.idea/* diff --git a/src/Behat/Gherkin/Filter/LineFilter.php b/src/Behat/Gherkin/Filter/LineFilter.php index 455e9ac3..3638fd16 100644 --- a/src/Behat/Gherkin/Filter/LineFilter.php +++ b/src/Behat/Gherkin/Filter/LineFilter.php @@ -46,27 +46,6 @@ public function isFeatureMatch(FeatureNode $feature) return $this->filterLine === $feature->getLine(); } - /** - * Checks if scenario or outline matches specified filter. - * - * @param ScenarioInterface $scenario Scenario or Outline node instance - * - * @return Boolean - */ - public function isScenarioMatch(ScenarioInterface $scenario) - { - if ($this->filterLine === $scenario->getLine()) { - return true; - } - - if ($scenario instanceof OutlineNode && $scenario->hasExamples()) { - return $this->filterLine === $scenario->getLine() - || in_array($this->filterLine, $scenario->getExampleTable()->getLines()); - } - - return false; - } - /** * Filters feature according to the filter and returns new one. * @@ -83,24 +62,26 @@ public function filterFeature(FeatureNode $feature) } if ($scenario instanceof OutlineNode && $scenario->hasExamples()) { - $table = $scenario->getExampleTable()->getTable(); - $lines = array_keys($table); - - if (in_array($this->filterLine, $lines)) { - $filteredTable = array($lines[0] => $table[$lines[0]]); - - if ($lines[0] !== $this->filterLine) { - $filteredTable[$this->filterLine] = $table[$this->filterLine]; + foreach ($scenario->getExampleTables() as $exampleTable) { + $table = $exampleTable->getTable(); + $lines = array_keys($table); + + if (in_array($this->filterLine, $lines)) { + $filteredTable = array($lines[0] => $table[$lines[0]]); + + if ($lines[0] !== $this->filterLine) { + $filteredTable[$this->filterLine] = $table[$this->filterLine]; + } + + $scenario = new OutlineNode( + $scenario->getTitle(), + $scenario->getTags(), + $scenario->getSteps(), + [new ExampleTableNode($filteredTable, $scenario->getExampleTables()[0]->getKeyword(), $exampleTable->getTags())], + $scenario->getKeyword(), + $scenario->getLine() + ); } - - $scenario = new OutlineNode( - $scenario->getTitle(), - $scenario->getTags(), - $scenario->getSteps(), - new ExampleTableNode($filteredTable, $scenario->getExampleTable()->getKeyword()), - $scenario->getKeyword(), - $scenario->getLine() - ); } } @@ -119,4 +100,25 @@ public function filterFeature(FeatureNode $feature) $feature->getLine() ); } + + /** + * Checks if scenario or outline matches specified filter. + * + * @param ScenarioInterface $scenario Scenario or Outline node instance + * + * @return Boolean + */ + public function isScenarioMatch(ScenarioInterface $scenario) + { + if ($this->filterLine === $scenario->getLine()) { + return true; + } + + if ($scenario instanceof OutlineNode && $scenario->hasExamples()) { + return $this->filterLine === $scenario->getLine() + || in_array($this->filterLine, $scenario->getExampleTable()->getLines()); + } + + return false; + } } diff --git a/src/Behat/Gherkin/Filter/LineRangeFilter.php b/src/Behat/Gherkin/Filter/LineRangeFilter.php index b8062bed..86aeeec6 100644 --- a/src/Behat/Gherkin/Filter/LineRangeFilter.php +++ b/src/Behat/Gherkin/Filter/LineRangeFilter.php @@ -54,30 +54,6 @@ public function isFeatureMatch(FeatureNode $feature) && $this->filterMaxLine >= $feature->getLine(); } - /** - * Checks if scenario or outline matches specified filter. - * - * @param ScenarioInterface $scenario Scenario or Outline node instance - * - * @return Boolean - */ - public function isScenarioMatch(ScenarioInterface $scenario) - { - if ($this->filterMinLine <= $scenario->getLine() && $this->filterMaxLine >= $scenario->getLine()) { - return true; - } - - if ($scenario instanceof OutlineNode && $scenario->hasExamples()) { - foreach ($scenario->getExampleTable()->getLines() as $line) { - if ($this->filterMinLine <= $line && $this->filterMaxLine >= $line) { - return true; - } - } - } - - return false; - } - /** * Filters feature according to the filter. * @@ -87,22 +63,31 @@ public function isScenarioMatch(ScenarioInterface $scenario) */ public function filterFeature(FeatureNode $feature) { - $scenarios = array(); + $scenarios = []; foreach ($feature->getScenarios() as $scenario) { if (!$this->isScenarioMatch($scenario)) { continue; } if ($scenario instanceof OutlineNode && $scenario->hasExamples()) { - $table = $scenario->getExampleTable()->getTable(); - $lines = array_keys($table); + // first accumulate examples and then create scenario + $exampleTableNodes = []; + + foreach ($scenario->getExampleTables() as $exampleTable) { + $table = $exampleTable->getTable(); + $lines = array_keys($table); - $filteredTable = array($lines[0] => $table[$lines[0]]); - unset($table[$lines[0]]); + $filteredTable = [$lines[0] => $table[$lines[0]]]; + unset($table[$lines[0]]); - foreach ($table as $line => $row) { - if ($this->filterMinLine <= $line && $this->filterMaxLine >= $line) { - $filteredTable[$line] = $row; + foreach ($table as $line => $row) { + if ($this->filterMinLine <= $line && $this->filterMaxLine >= $line) { + $filteredTable[$line] = $row; + } + } + + if (count($filteredTable) > 1) { + $exampleTableNodes[] = new ExampleTableNode($filteredTable, $scenario->getExampleTables()[0]->getKeyword(), $exampleTable->getTags()); } } @@ -110,7 +95,7 @@ public function filterFeature(FeatureNode $feature) $scenario->getTitle(), $scenario->getTags(), $scenario->getSteps(), - new ExampleTableNode($filteredTable, $scenario->getExampleTable()->getKeyword()), + $exampleTableNodes, $scenario->getKeyword(), $scenario->getLine() ); @@ -131,4 +116,28 @@ public function filterFeature(FeatureNode $feature) $feature->getLine() ); } + + /** + * Checks if scenario or outline matches specified filter. + * + * @param ScenarioInterface $scenario Scenario or Outline node instance + * + * @return Boolean + */ + public function isScenarioMatch(ScenarioInterface $scenario) + { + if ($this->filterMinLine <= $scenario->getLine() && $this->filterMaxLine >= $scenario->getLine()) { + return true; + } + + if ($scenario instanceof OutlineNode && $scenario->hasExamples()) { + foreach ($scenario->getExampleTable()->getLines() as $line) { + if ($this->filterMinLine <= $line && $this->filterMaxLine >= $line) { + return true; + } + } + } + + return false; + } } diff --git a/src/Behat/Gherkin/Filter/TagFilter.php b/src/Behat/Gherkin/Filter/TagFilter.php index fed6c1af..3209b6d4 100644 --- a/src/Behat/Gherkin/Filter/TagFilter.php +++ b/src/Behat/Gherkin/Filter/TagFilter.php @@ -11,6 +11,7 @@ namespace Behat\Gherkin\Filter; use Behat\Gherkin\Node\FeatureNode; +use Behat\Gherkin\Node\OutlineNode; use Behat\Gherkin\Node\ScenarioInterface; /** @@ -32,6 +33,50 @@ public function __construct($filterString) $this->filterString = trim($filterString); } + public function filterFeature(FeatureNode $feature) + { + $scenarios = []; + foreach ($feature->getScenarios() as $scenario) { + if (!$this->isScenarioMatch($feature, $scenario)) { + continue; + } + + if ($scenario instanceof OutlineNode && $scenario->hasExamples()) { + + $exampleTables = []; + + foreach ($scenario->getExampleTables() as $exampleTable) { + if ($this->isTagsMatchCondition(array_merge($feature->getTags(), $scenario->getTags(), $exampleTable->getTags()))) { + $exampleTables[] = $exampleTable; + } + } + + $scenario = new OutlineNode( + $scenario->getTitle(), + $scenario->getTags(), + $scenario->getSteps(), + $exampleTables, + $scenario->getKeyword(), + $scenario->getLine() + ); + } + + $scenarios[] = $scenario; + } + + return new FeatureNode( + $feature->getTitle(), + $feature->getDescription(), + $feature->getTags(), + $feature->getBackground(), + $scenarios, + $feature->getKeyword(), + $feature->getLanguage(), + $feature->getFile(), + $feature->getLine() + ); + } + /** * Checks if Feature matches specified filter. * @@ -47,13 +92,23 @@ public function isFeatureMatch(FeatureNode $feature) /** * Checks if scenario or outline matches specified filter. * - * @param FeatureNode $feature Feature node instance + * @param FeatureNode $feature Feature node instance * @param ScenarioInterface $scenario Scenario or Outline node instance * * @return Boolean */ public function isScenarioMatch(FeatureNode $feature, ScenarioInterface $scenario) { + if ($scenario instanceof OutlineNode && $scenario->hasExamples()) { + foreach ($scenario->getExampleTables() as $example) { + if ($this->isTagsMatchCondition(array_merge($feature->getTags(), $scenario->getTags(), $example->getTags()))) { + return true; + } + } + + return false; + } + return $this->isTagsMatchCondition(array_merge($feature->getTags(), $scenario->getTags())); } diff --git a/src/Behat/Gherkin/Loader/ArrayLoader.php b/src/Behat/Gherkin/Loader/ArrayLoader.php index 3492d6e6..083a60f8 100644 --- a/src/Behat/Gherkin/Loader/ArrayLoader.php +++ b/src/Behat/Gherkin/Loader/ArrayLoader.php @@ -179,7 +179,43 @@ protected function loadOutlineHash(array $hash, $line = 0) $examplesKeyword = 'Examples'; } - $examples = new ExampleTableNode($hash['examples'], $examplesKeyword); + $exHash = $hash['examples']; + $examples = []; + + // there are 3 cases + // first is examples as a single table - we create an array with the only one element + // examples + // 11: abc + // 12: cde + // + // second is array of arrays + // examples + // - + // 11: abc + // 12: cde + // + // and the 3rd is array of objects + // examples + // - + // tags: [] + // table: + // 11: abc + // 12: cde + + if (isset($exHash[0])) { + // cases #2 & 3 + for ($i = 0; $i < count($exHash); $i++) { + if (isset($exHash[$i]['table'])) { + // we have examples as objects + $exHashTags = isset($exHash[$i]['tags']) ? $exHash[$i]['tags'] : array(); + $examples[] = new ExampleTableNode($exHash[$i]['table'], $examplesKeyword, $exHashTags); + } else { + $examples[] = new ExampleTableNode($exHash[$i], $examplesKeyword); + } + } + } else { + $examples[] = new ExampleTableNode($exHash, $examplesKeyword);; + } return new OutlineNode($hash['title'], $hash['tags'], $steps, $examples, $hash['keyword'], $hash['line']); } diff --git a/src/Behat/Gherkin/Node/ExampleTableNode.php b/src/Behat/Gherkin/Node/ExampleTableNode.php index 805e659e..45ef65ae 100644 --- a/src/Behat/Gherkin/Node/ExampleTableNode.php +++ b/src/Behat/Gherkin/Node/ExampleTableNode.php @@ -17,6 +17,11 @@ */ class ExampleTableNode extends TableNode { + /** + * @var string[] + */ + private $tags; + /** * @var string */ @@ -25,12 +30,14 @@ class ExampleTableNode extends TableNode /** * Initializes example table. * - * @param array $table Table in form of [$rowLineNumber => [$val1, $val2, $val3]] + * @param array $table Table in form of [$rowLineNumber => [$val1, $val2, $val3]] * @param string $keyword + * @param string[] $tags */ - public function __construct(array $table, $keyword) + public function __construct(array $table, $keyword, array $tags = []) { $this->keyword = $keyword; + $this->tags = $tags; parent::__construct($table); } @@ -45,6 +52,15 @@ public function getNodeType() return 'ExampleTable'; } + /** + * Returns attached tags + * @return \string[] + */ + public function getTags() + { + return $this->tags; + } + /** * Returns example table keyword. * diff --git a/src/Behat/Gherkin/Node/OutlineNode.php b/src/Behat/Gherkin/Node/OutlineNode.php index 083b411f..039d1c17 100644 --- a/src/Behat/Gherkin/Node/OutlineNode.php +++ b/src/Behat/Gherkin/Node/OutlineNode.php @@ -10,6 +10,8 @@ namespace Behat\Gherkin\Node; +use DeepCopy\DeepCopy; + /** * Represents Gherkin Outline. * @@ -30,9 +32,9 @@ class OutlineNode implements ScenarioInterface */ private $steps; /** - * @var ExampleTableNode + * @var ExampleTableNode[] */ - private $table; + private $tables; /** * @var string */ @@ -52,7 +54,7 @@ class OutlineNode implements ScenarioInterface * @param null|string $title * @param string[] $tags * @param StepNode[] $steps - * @param ExampleTableNode $table + * @param ExampleTableNode[] $tables * @param string $keyword * @param integer $line */ @@ -60,14 +62,14 @@ public function __construct( $title, array $tags, array $steps, - ExampleTableNode $table, + array $tables, $keyword, $line ) { $this->title = $title; $this->tags = $tags; $this->steps = $steps; - $this->table = $table; + $this->tables = $tables; $this->keyword = $keyword; $this->line = $line; } @@ -104,16 +106,6 @@ public function hasTag($tag) return in_array($tag, $this->getTags()); } - /** - * Checks if outline has tags (both inherited from feature and own). - * - * @return Boolean - */ - public function hasTags() - { - return 0 < count($this->getTags()); - } - /** * Returns outline tags (including inherited from feature). * @@ -125,23 +117,23 @@ public function getTags() } /** - * Checks if outline has steps. + * Checks if outline has tags (both inherited from feature and own). * * @return Boolean */ - public function hasSteps() + public function hasTags() { - return 0 < count($this->steps); + return 0 < count($this->getTags()); } /** - * Returns outline steps. + * Checks if outline has steps. * - * @return StepNode[] + * @return Boolean */ - public function getSteps() + public function hasSteps() { - return $this->steps; + return 0 < count($this->steps); } /** @@ -151,27 +143,80 @@ public function getSteps() */ public function hasExamples() { - return 0 < count($this->table->getColumnsHash()); + return 0 < count($this->tables); } /** - * Returns examples table. + * Builds and returns examples table for the outline. + * + * WARNING: it returns a merged table with tags lost. * + * @deprecated use getExampleTables instead * @return ExampleTableNode */ public function getExampleTable() { - return $this->table; + $cp = new DeepCopy(); + $table = $cp->copy($this->tables[0]->getTable()); + /** @var ExampleTableNode $exampleTableNode */ + $exampleTableNode = new ExampleTableNode($table, $this->tables[0]->getKeyword()); + for ($i = 1; $i < count($this->tables); $i++) { + $exampleTableNode->mergeRowsFromTable($this->tables[$i]); + } + + return $exampleTableNode; } /** * Returns list of examples for the outline. - * * @return ExampleNode[] */ public function getExamples() { - return $this->examples = $this->examples ? : $this->createExamples(); + return $this->examples = $this->examples ?: $this->createExamples(); + } + + /** + * Creates examples for this outline using examples table. + * + * @return ExampleNode[] + */ + protected function createExamples() + { + $examples = []; + + foreach ($this->getExampleTables() as $exampleTable) { + foreach ($exampleTable->getColumnsHash() as $rowNum => $row) { + $examples[] = new ExampleNode( + $exampleTable->getRowAsString($rowNum + 1), + array_merge($this->tags, $exampleTable->getTags()), + $this->getSteps(), + $row, + $exampleTable->getRowLine($rowNum + 1) + ); + } + } + + return $examples; + } + + /** + * Returns examples tables array for the outline. + * @return ExampleTableNode[] + */ + public function getExampleTables() + { + return $this->tables; + } + + /** + * Returns outline steps. + * + * @return StepNode[] + */ + public function getSteps() + { + return $this->steps; } /** @@ -193,25 +238,4 @@ public function getLine() { return $this->line; } - - /** - * Creates examples for this outline using examples table. - * - * @return ExampleNode[] - */ - protected function createExamples() - { - $examples = array(); - foreach ($this->table->getColumnsHash() as $rowNum => $row) { - $examples[] = new ExampleNode( - $this->table->getRowAsString($rowNum + 1), - $this->tags, - $this->getSteps(), - $row, - $this->table->getRowLine($rowNum + 1) - ); - } - - return $examples; - } } diff --git a/src/Behat/Gherkin/Node/TableNode.php b/src/Behat/Gherkin/Node/TableNode.php index 9e5d1740..b06aab12 100644 --- a/src/Behat/Gherkin/Node/TableNode.php +++ b/src/Behat/Gherkin/Node/TableNode.php @@ -294,6 +294,30 @@ public function getIterator() return new ArrayIterator($this->getHash()); } + /** + * Obtains and adds rows from another table to the current table. + * The second table should have the same structure as the current one. + * @param TableNode $node + * + * @deprecated remove together with OutlineNode::getExampleTable + */ + public function mergeRowsFromTable(TableNode $node) + { + // check structure + if ($this->getRow(0) !== $node->getRow(0)) { + throw new NodeException("Tables have different structure. Cannot merge one into another"); + } + + $firstLine = $node->getLine(0); + foreach ($node->getTable() as $line => $value) { + if ($line === $firstLine) { + continue; + } + + $this->table[$line] = $value; + } + } + /** * Pads string right. * diff --git a/src/Behat/Gherkin/Parser.php b/src/Behat/Gherkin/Parser.php index 5cc85424..edbc659d 100644 --- a/src/Behat/Gherkin/Parser.php +++ b/src/Behat/Gherkin/Parser.php @@ -39,6 +39,8 @@ class Parser private $tags = array(); private $languageSpecifierLine; + private $stack = array(); + /** * Initializes parser. * @@ -236,6 +238,8 @@ protected function parseFeature() $file = $this->file; $line = $token['line']; + array_push($this->stack, 'Feature'); + // Parse description, background, scenarios & outlines while ('EOS' !== $this->predictTokenType()) { $node = $this->parseExpression(); @@ -369,6 +373,8 @@ protected function parseScenario() $keyword = $token['keyword']; $line = $token['line']; + array_push($this->stack, 'Scenario'); + // Parse description and steps $steps = array(); while (in_array($this->predictTokenType(), array('Step', 'Newline', 'Text', 'Comment'))) { @@ -407,6 +413,8 @@ protected function parseScenario() } } + array_pop($this->stack); + return new ScenarioNode(rtrim($title) ?: null, $tags, $steps, $keyword, $line); } @@ -424,12 +432,17 @@ protected function parseOutline() $title = trim($token['value']); $tags = $this->popTags(); $keyword = $token['keyword']; - $examples = null; + + /** @var ExampleTableNode $examples */ + $examples = []; $line = $token['line']; // Parse description, steps and examples $steps = array(); - while (in_array($this->predictTokenType(), array('Step', 'Examples', 'Newline', 'Text', 'Comment'))) { + + array_push($this->stack, 'Outline'); + + while (in_array($this->predictTokenType(), array('Step', 'Examples', 'Newline', 'Text', 'Comment', 'Tag'))) { $node = $this->parseExpression(); if ($node instanceof StepNode) { @@ -438,7 +451,8 @@ protected function parseOutline() } if ($node instanceof ExampleTableNode) { - $examples = $node; + $examples[] = $node; + continue; } @@ -470,7 +484,7 @@ protected function parseOutline() } } - if (null === $examples) { + if (empty($examples)) { throw new ParserException(sprintf( 'Outline should have examples table, but got none for outline "%s" on line: %d%s', rtrim($title), @@ -496,6 +510,8 @@ protected function parseStep() $text = trim($token['text']); $line = $token['line']; + array_push($this->stack, 'Step'); + $arguments = array(); while (in_array($predicted = $this->predictTokenType(), array('PyStringOp', 'TableRow', 'Newline', 'Comment'))) { if ('Comment' === $predicted || 'Newline' === $predicted) { @@ -510,6 +526,8 @@ protected function parseStep() } } + array_pop($this->stack); + return new StepNode($keyword, $text, $arguments, $line, $keywordType); } @@ -524,7 +542,9 @@ protected function parseExamples() $keyword = $token['keyword']; - return new ExampleTableNode($this->parseTableRows(), $keyword); + $tags = empty($this->tags) ? [] : $this->popTags(); + + return new ExampleTableNode($this->parseTableRows(), $keyword, $tags); } /** @@ -570,7 +590,24 @@ protected function parseTags() $token = $this->expectTokenType('Tag'); $this->tags = array_merge($this->tags, $token['tags']); - return $this->parseExpression(); + $possibleTransitions = [ + 'Outline' => [ + 'Examples', + 'Step' + ] + ]; + + $currentType = '-1'; + // check if that is ok to go inside: + if (!empty($this->stack)) { + $currentType = $this->stack[count($this->stack) - 1]; + } + $nextType = $this->predictTokenType(); + if (!isset($possibleTransitions[$currentType]) || in_array($nextType, $possibleTransitions[$currentType])) { + return $this->parseExpression(); + } + + return "\n"; } /** diff --git a/tests/Behat/Gherkin/Filter/FilterTest.php b/tests/Behat/Gherkin/Filter/FilterTest.php index 994e6564..03e2fd9f 100644 --- a/tests/Behat/Gherkin/Filter/FilterTest.php +++ b/tests/Behat/Gherkin/Filter/FilterTest.php @@ -8,6 +8,11 @@ abstract class FilterTest extends \PHPUnit_Framework_TestCase { + protected function getParsedFeature() + { + return $this->getParser()->parse($this->getGherkinFeature()); + } + protected function getParser() { return new Parser( @@ -49,16 +54,17 @@ protected function getGherkinFeature() When occurs Then should be visible + @etag1 Examples: | action | outcome | | act#1 | out#1 | | act#2 | out#2 | + + @etag2 + Examples: + | action | outcome | | act#3 | out#3 | -GHERKIN; - } - protected function getParsedFeature() - { - return $this->getParser()->parse($this->getGherkinFeature()); +GHERKIN; } } diff --git a/tests/Behat/Gherkin/Filter/LineFilterTest.php b/tests/Behat/Gherkin/Filter/LineFilterTest.php index 846a719d..c35eaa97 100644 --- a/tests/Behat/Gherkin/Filter/LineFilterTest.php +++ b/tests/Behat/Gherkin/Filter/LineFilterTest.php @@ -37,7 +37,7 @@ public function testIsScenarioMatchFilter() $filter = new LineFilter(5); $this->assertFalse($filter->isScenarioMatch($scenario)); - $outline = new OutlineNode(null, array(), array(), new ExampleTableNode(array(), null), null, 20); + $outline = new OutlineNode(null, array(), array(), [new ExampleTableNode(array(), null)], null, 20); $filter = new LineFilter(5); $this->assertFalse($filter->isScenarioMatch($outline)); @@ -67,37 +67,40 @@ public function testFilterFeatureOutline() { $filter = new LineFilter(13); $feature = $filter->filterFeature($this->getParsedFeature()); + /** @var OutlineNode[] $scenarios */ $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); $this->assertCount(4, $scenarios[0]->getExampleTable()->getRows()); - $filter = new LineFilter(19); + $filter = new LineFilter(20); $feature = $filter->filterFeature($this->getParsedFeature()); $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); - $this->assertCount(2, $scenarios[0]->getExampleTable()->getRows()); + $this->assertEquals(1, count($scenarios[0]->getExampleTables())); + $this->assertCount(2, $scenarios[0]->getExampleTables()[0]->getRows()); $this->assertSame(array( array('action', 'outcome'), array('act#1', 'out#1'), - ), $scenarios[0]->getExampleTable()->getRows()); + ), $scenarios[0]->getExampleTables()[0]->getRows()); + $this->assertEquals(['etag1'], $scenarios[0]->getExampleTables()[0]->getTags()); - $filter = new LineFilter(21); + $filter = new LineFilter(26); $feature = $filter->filterFeature($this->getParsedFeature()); $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); - $this->assertCount(2, $scenarios[0]->getExampleTable()->getRows()); - $this->assertSame(array( - array('action', 'outcome'), - array('act#3', 'out#3'), - ), $scenarios[0]->getExampleTable()->getRows()); + $this->assertEquals(1, count($scenarios[0]->getExampleTables())); + $this->assertCount(2, $scenarios[0]->getExampleTables()[0]->getRows()); + $this->assertSame([ + ['action', 'outcome'], + ['act#3', 'out#3'], + ], $scenarios[0]->getExampleTables()[0]->getRows()); + $this->assertEquals(['etag2'], $scenarios[0]->getExampleTables()[0]->getTags()); - $filter = new LineFilter(18); + $filter = new LineFilter(19); $feature = $filter->filterFeature($this->getParsedFeature()); $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); $this->assertCount(1, $scenarios[0]->getExampleTable()->getRows()); - $this->assertSame(array( - array('action', 'outcome'), - ), $scenarios[0]->getExampleTable()->getRows()); + $this->assertSame([['action', 'outcome']], $scenarios[0]->getExampleTable()->getRows()); } } diff --git a/tests/Behat/Gherkin/Filter/LineRangeFilterTest.php b/tests/Behat/Gherkin/Filter/LineRangeFilterTest.php index fb8abe1c..bca6e621 100644 --- a/tests/Behat/Gherkin/Filter/LineRangeFilterTest.php +++ b/tests/Behat/Gherkin/Filter/LineRangeFilterTest.php @@ -53,7 +53,7 @@ public function scenarioLineRangeProvider() public function testIsScenarioMatchFilter($filterMinLine, $filterMaxLine, $expectedNumberOfMatches) { $scenario = new ScenarioNode(null, array(), array(), null, 2); - $outline = new OutlineNode(null, array(), array(), new ExampleTableNode(array(), null), null, 3); + $outline = new OutlineNode(null, array(), array(), [new ExampleTableNode(array(), null)], null, 3); $filter = new LineRangeFilter($filterMinLine, $filterMaxLine); $this->assertEquals( @@ -83,19 +83,56 @@ public function testFilterFeatureOutline() { $filter = new LineRangeFilter(12, 14); $feature = $filter->filterFeature($this->getParsedFeature()); + /** @var OutlineNode[] $scenarios */ $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); - $this->assertCount(1, $scenarios[0]->getExampleTable()->getRows()); + $this->assertFalse($scenarios[0]->hasExamples()); - $filter = new LineRangeFilter(15, 20); + $filter = new LineRangeFilter(16, 21); $feature = $filter->filterFeature($this->getParsedFeature()); $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); - $this->assertCount(3, $scenarios[0]->getExampleTable()->getRows()); - $this->assertSame(array( - array('action', 'outcome'), - array('act#1', 'out#1'), - array('act#2', 'out#2'), - ), $scenarios[0]->getExampleTable()->getRows()); + $this->assertEquals(1, count($scenarios[0]->getExampleTables())); + $this->assertCount(3, $scenarios[0]->getExampleTables()[0]->getRows()); + $this->assertSame([ + ['action', 'outcome'], + ['act#1', 'out#1'], + ['act#2', 'out#2'], + ], $scenarios[0]->getExampleTables()[0]->getRows()); + $this->assertEquals(['etag1'], $scenarios[0]->getExampleTables()[0]->getTags()); + + $filter = new LineRangeFilter(16, 26); + $feature = $filter->filterFeature($this->getParsedFeature()); + $this->assertCount(1, $scenarios = $feature->getScenarios()); + $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); + $this->assertEquals(2, count($scenarios[0]->getExampleTables())); + + $this->assertCount(3, $scenarios[0]->getExampleTables()[0]->getRows()); + $this->assertSame([ + ['action', 'outcome'], + ['act#1', 'out#1'], + ['act#2', 'out#2'], + ], $scenarios[0]->getExampleTables()[0]->getRows()); + $this->assertEquals(['etag1'], $scenarios[0]->getExampleTables()[0]->getTags()); + + $this->assertCount(2, $scenarios[0]->getExampleTables()[1]->getRows()); + $this->assertSame([ + ['action', 'outcome'], + ['act#3', 'out#3'] + ], $scenarios[0]->getExampleTables()[1]->getRows()); + + $this->assertEquals(['etag2'], $scenarios[0]->getExampleTables()[1]->getTags()); + + $filter = new LineRangeFilter(25, 26); + $feature = $filter->filterFeature($this->getParsedFeature()); + $this->assertCount(1, $scenarios = $feature->getScenarios()); + $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); + $this->assertEquals(1, count($scenarios[0]->getExampleTables())); + $this->assertCount(2, $scenarios[0]->getExampleTables()[0]->getRows()); + $this->assertSame([ + ['action', 'outcome'], + ['act#3', 'out#3'], + ], $scenarios[0]->getExampleTables()[0]->getRows()); + $this->assertEquals(['etag2'], $scenarios[0]->getExampleTables()[0]->getTags()); } } diff --git a/tests/Behat/Gherkin/Filter/TagFilterTest.php b/tests/Behat/Gherkin/Filter/TagFilterTest.php index 5c6c9ab2..b532e649 100644 --- a/tests/Behat/Gherkin/Filter/TagFilterTest.php +++ b/tests/Behat/Gherkin/Filter/TagFilterTest.php @@ -3,7 +3,9 @@ namespace Tests\Behat\Gherkin\Filter; use Behat\Gherkin\Filter\TagFilter; +use Behat\Gherkin\Node\ExampleTableNode; use Behat\Gherkin\Node\FeatureNode; +use Behat\Gherkin\Node\OutlineNode; use Behat\Gherkin\Node\ScenarioNode; class TagFilterTest extends \PHPUnit_Framework_TestCase @@ -140,5 +142,88 @@ public function testIsScenarioMatchFilter() $filter = new TagFilter('@feature-tag&&@user'); $scenario = new ScenarioNode(null, array('wip'), array(), null, 2); $this->assertFalse($filter->isScenarioMatch($feature, $scenario)); + + $scenario = new OutlineNode(null, ['wip'], [], [ + new ExampleTableNode([], null, ['etag1', 'etag2']), + new ExampleTableNode([], null, ['etag2', 'etag3']), + ], null, 2); + + $this->assertTrue((new TagFilter('@etag3'))->isScenarioMatch($feature, $scenario)); + $this->assertTrue((new TagFilter('~@etag3'))->isScenarioMatch($feature, $scenario)); + $this->assertTrue((new TagFilter('@wip'))->isScenarioMatch($feature, $scenario)); + $this->assertTrue((new TagFilter('@wip&&@etag3'))->isScenarioMatch($feature, $scenario)); + $this->assertTrue((new TagFilter('@feature-tag&&@etag1&&@wip'))->isScenarioMatch($feature, $scenario)); + $this->assertTrue((new TagFilter('@feature-tag&&~@etag11111&&@wip'))->isScenarioMatch($feature, $scenario)); + $this->assertTrue((new TagFilter('@feature-tag&&~@etag1&&@wip'))->isScenarioMatch($feature, $scenario)); + $this->assertTrue((new TagFilter('@feature-tag&&@etag2'))->isScenarioMatch($feature, $scenario)); + $this->assertFalse((new TagFilter('~@etag1&&~@etag3'))->isScenarioMatch($feature, $scenario)); + $this->assertFalse((new TagFilter('@etag1&&@etag3'))->isScenarioMatch($feature, $scenario), "Tags from different examples tables"); + } + + public function testFilterFeatureWithTaggedExamples() + { + $exampleTableNode1 = new ExampleTableNode([], null, ['etag1', 'etag2']); + $exampleTableNode2 = new ExampleTableNode([], null, ['etag2', 'etag3']); + $scenario = new OutlineNode(null, ['wip'], [], [ + $exampleTableNode1, + $exampleTableNode2, + ], null, 2); + $feature = new FeatureNode(null, null, array('feature-tag'), null, [$scenario], null, null, null, 1); + + $matched = (new TagFilter('@etag2'))->filterFeature($feature); + $this->assertEquals($scenario, $matched->getScenarios()[0]); + + $matched = (new TagFilter('@etag1'))->filterFeature($feature); + /** @noinspection PhpUndefinedMethodInspection */ + $this->assertEquals([$exampleTableNode1], $matched->getScenarios()[0]->getExampleTables()); + + $matched = (new TagFilter('~@etag3'))->filterFeature($feature); + /** @noinspection PhpUndefinedMethodInspection */ + $this->assertEquals([$exampleTableNode1], $matched->getScenarios()[0]->getExampleTables()); + + $matched = (new TagFilter('@wip'))->filterFeature($feature); + $this->assertEquals($scenario, $matched->getScenarios()[0]); + + $matched = (new TagFilter('@wip&&@etag3'))->filterFeature($feature); + /** @noinspection PhpUndefinedMethodInspection */ + $this->assertEquals([$exampleTableNode2], $matched->getScenarios()[0]->getExampleTables()); + + $matched = (new TagFilter('@feature-tag&&@etag1&&@wip'))->filterFeature($feature); + /** @noinspection PhpUndefinedMethodInspection */ + $this->assertEquals([$exampleTableNode1], $matched->getScenarios()[0]->getExampleTables()); + + $matched = (new TagFilter('@feature-tag&&~@etag11111&&@wip'))->filterFeature($feature); + $this->assertEquals($scenario, $matched->getScenarios()[0]); + + $matched = (new TagFilter('@feature-tag&&~@etag1&&@wip'))->filterFeature($feature); + /** @noinspection PhpUndefinedMethodInspection */ + $this->assertEquals([$exampleTableNode2], $matched->getScenarios()[0]->getExampleTables()); + + $matched = (new TagFilter('@feature-tag&&@etag2'))->filterFeature($feature); + $this->assertEquals($scenario, $matched->getScenarios()[0]); + + $exampleTableNode1 = new ExampleTableNode([], null, ['etag1', 'etag']); + $exampleTableNode2 = new ExampleTableNode([], null, ['etag2', 'etag22', 'etag']); + $exampleTableNode3 = new ExampleTableNode([], null, ['etag3', 'etag22', 'etag']); + $exampleTableNode4 = new ExampleTableNode([], null, ['etag4', 'etag']); + $scenario1 = new OutlineNode(null, ['wip'], [], [ + $exampleTableNode1, + $exampleTableNode2, + ], null, 2); + $scenario2 = new OutlineNode(null, ['wip'], [], [ + $exampleTableNode3, + $exampleTableNode4, + ], null, 2); + $feature = new FeatureNode(null, null, array('feature-tag'), null, [$scenario1, $scenario2], null, null, null, 1); + + $matched = (new TagFilter('@etag'))->filterFeature($feature); + $this->assertEquals([$scenario1, $scenario2], $matched->getScenarios()); + + $matched = (new TagFilter('@etag22'))->filterFeature($feature); + $this->assertEquals(2, count($matched->getScenarios())); + /** @noinspection PhpUndefinedMethodInspection */ + $this->assertEquals([$exampleTableNode2], $matched->getScenarios()[0]->getExampleTables()); + /** @noinspection PhpUndefinedMethodInspection */ + $this->assertEquals([$exampleTableNode3], $matched->getScenarios()[1]->getExampleTables()); } } diff --git a/tests/Behat/Gherkin/Fixtures/etalons/outline_with_multiple_examples.yml b/tests/Behat/Gherkin/Fixtures/etalons/outline_with_multiple_examples.yml new file mode 100644 index 00000000..e980b297 --- /dev/null +++ b/tests/Behat/Gherkin/Fixtures/etalons/outline_with_multiple_examples.yml @@ -0,0 +1,55 @@ +feature: + title: Unsubstituted argument placeholder + language: en + line: 1 + description: ~ + + scenarios: + - + type: outline + title: 'See Annual Leave Details (as Management & Human Resource)' + line: 3 + steps: + - + keyword_type: Given + type: Given + text: the exist in the system + line: 4 + examples: + - + 7: [ role, name ] + 8: [ HUMAN RESOURCE, abc ] + - + 11: [ role, name ] + 12: [ MANAGER, cde ] + - + 15: [ role, name ] + 16: [ CEO, qqq ] + 17: [ CTO, xxx ] + - + type: outline + title: 'See Annual Leave Details (as Management & Human Resource)' + line: 20 + steps: + - + keyword_type: Given + type: Given + text: the exist in the system + line: 21 + examples: + - + tags: [tag1, tag2] + table: + 25: [ role, name ] + 26: [ HUMAN RESOURCE, abc ] + - + tags: [tag1, tag3] + table: + 30: [ role, name ] + 31: [ MANAGER, cde ] + - + tags: [tag4] + table: + 34: [ role, name ] + 35: [ CEO, qqq ] + 36: [ CTO, xxx ] \ No newline at end of file diff --git a/tests/Behat/Gherkin/Fixtures/etalons/tags_sample.yml b/tests/Behat/Gherkin/Fixtures/etalons/tags_sample.yml index 486d9585..82f25e1a 100644 --- a/tests/Behat/Gherkin/Fixtures/etalons/tags_sample.yml +++ b/tests/Behat/Gherkin/Fixtures/etalons/tags_sample.yml @@ -23,13 +23,41 @@ feature: - { keyword_type: 'Given', type: 'Given', text: '', line: 10 } examples: - 12: [state] - 13: [missing] + - + tags: [examples_tag, examples_tag2] + table: + 13: [state] + 14: [missing] - type: scenario title: Skipped tags: [sample_three, sample_four] - line: 16 + line: 17 steps: - - { keyword_type: 'Given', type: 'Given', text: 'missing', line: 17 } + - { keyword_type: 'Given', type: 'Given', text: 'missing', line: 18 } + + - + type: outline + title: passing + tags: [sample_5] + line: 22 + steps: + - { keyword_type: 'Given', type: 'Given', text: '', line: 23 } + examples: + 25: [state] + 26: [missing] + + - + type: outline + title: passing + tags: [sample_6, sample_7] + line: 29 + steps: + - { keyword_type: 'Given', type: 'Given', text: '', line: 30 } + examples: + - + tags: [examples_tag3, examples_tag4] + table: + 33: [state] + 34: [missing] \ No newline at end of file diff --git a/tests/Behat/Gherkin/Fixtures/features/outline_with_multiple_examples.feature b/tests/Behat/Gherkin/Fixtures/features/outline_with_multiple_examples.feature new file mode 100644 index 00000000..a40c3164 --- /dev/null +++ b/tests/Behat/Gherkin/Fixtures/features/outline_with_multiple_examples.feature @@ -0,0 +1,36 @@ +Feature: Unsubstituted argument placeholder + + Scenario Outline: See Annual Leave Details (as Management & Human Resource) + Given the exist in the system + + Examples: + | role | name | + | HUMAN RESOURCE | abc | + + Examples: + | role | name | + | MANAGER | cde | + + Examples: + | role | name | + | CEO | qqq | + | CTO | xxx | + + + Scenario Outline: See Annual Leave Details (as Management & Human Resource) + Given the exist in the system + + @tag1 @tag2 + Examples: + | role | name | + | HUMAN RESOURCE | abc | + + @tag1 @tag3 + Examples: + | role | name | + | MANAGER | cde | + @tag4 + Examples: + | role | name | + | CEO | qqq | + | CTO | xxx | \ No newline at end of file diff --git a/tests/Behat/Gherkin/Fixtures/features/tags_sample.feature b/tests/Behat/Gherkin/Fixtures/features/tags_sample.feature index 21eaaab1..ef3bd626 100644 --- a/tests/Behat/Gherkin/Fixtures/features/tags_sample.feature +++ b/tests/Behat/Gherkin/Fixtures/features/tags_sample.feature @@ -1,17 +1,34 @@ @sample_one Feature: Tag samples - @sample_two @sample_four - Scenario: Passing - Given missing + @sample_two @sample_four + Scenario: Passing + Given missing - @sample_three - Scenario Outline: - Given - Examples: - |state| - |missing| + @sample_three + Scenario Outline: + Given + @examples_tag @examples_tag2 + Examples: + | state | + | missing | - @sample_three @sample_four - Scenario: Skipped - Given missing \ No newline at end of file + @sample_three @sample_four + Scenario: Skipped + Given missing + + + @sample_5 + Scenario Outline: passing + Given + Examples: + | state | + | missing | + + @sample_6 @sample_7 + Scenario Outline: passing + Given + @examples_tag3 @examples_tag4 + Examples: + | state | + | missing | diff --git a/tests/Behat/Gherkin/Keywords/KeywordsTest.php b/tests/Behat/Gherkin/Keywords/KeywordsTest.php index fdfc65e2..02d37c42 100644 --- a/tests/Behat/Gherkin/Keywords/KeywordsTest.php +++ b/tests/Behat/Gherkin/Keywords/KeywordsTest.php @@ -87,7 +87,7 @@ public function translationTestDataProvider() ), $keywords[0]); $line += 1; - $scenarios[] = new OutlineNode('Erasing other agents\' memory', array(), $steps, $table, $outlineKeyword, $outlineLine); + $scenarios[] = new OutlineNode('Erasing other agents\' memory', array(), $steps, [$table], $outlineKeyword, $outlineLine); $line += 1; } diff --git a/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php b/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php index 697d1d3d..c8bba8bd 100644 --- a/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php +++ b/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php @@ -3,16 +3,12 @@ namespace Tests\Behat\Gherkin\Loader; use Behat\Gherkin\Loader\ArrayLoader; +use Behat\Gherkin\Node\OutlineNode; class ArrayLoaderTest extends \PHPUnit_Framework_TestCase { private $loader; - protected function setUp() - { - $this->loader = new ArrayLoader(); - } - public function testSupports() { $this->assertFalse($this->loader->supports(__DIR__)); @@ -157,9 +153,9 @@ public function testOutlineExamples() 'title' => 'First outline', 'line' => 2, 'examples' => array( - array('user', 'pass'), - array('ever', 'sdsd'), - array('anto', 'fdfd') + 11 => array('user', 'pass'), + 12 => array('ever', 'sdsd'), + 13 => array('anto', 'fdfd') ) ), array( @@ -173,6 +169,7 @@ public function testOutlineExamples() $this->assertEquals(1, count($features)); + /** @var OutlineNode[] $scenarios */ $scenarios = $features[0]->getScenarios(); $scenario = $scenarios[0]; @@ -376,4 +373,9 @@ public function testSingleFeatureArray() $this->assertEquals(1, count($features)); $this->assertEquals('Some feature', $features[0]->getTitle()); } + + protected function setUp() + { + $this->loader = new ArrayLoader(); + } } diff --git a/tests/Behat/Gherkin/Node/ExampleNodeTest.php b/tests/Behat/Gherkin/Node/ExampleNodeTest.php index c6f46be5..dc0c073d 100644 --- a/tests/Behat/Gherkin/Node/ExampleNodeTest.php +++ b/tests/Behat/Gherkin/Node/ExampleNodeTest.php @@ -25,7 +25,7 @@ public function testCreateExampleSteps() array('example', 'example@example.com') ), 'Examples'); - $outline = new OutlineNode(null, array(), $steps, $table, null, null); + $outline = new OutlineNode(null, array(), $steps, [$table], null, null); $examples = $outline->getExamples(); $this->assertCount(4, $steps = $examples[0]->getSteps()); @@ -78,7 +78,7 @@ public function testCreateExampleStepsWithArguments() array('example', 'example@example.com', 'other page') ), 'Examples'); - $outline = new OutlineNode(null, array(), $steps, $table, null, null); + $outline = new OutlineNode(null, array(), $steps, [$table], null, null); $examples = $outline->getExamples(); $steps = $examples[0]->getSteps(); diff --git a/tests/Behat/Gherkin/Node/OutlineNodeTest.php b/tests/Behat/Gherkin/Node/OutlineNodeTest.php index 1e889b80..58d30995 100644 --- a/tests/Behat/Gherkin/Node/OutlineNodeTest.php +++ b/tests/Behat/Gherkin/Node/OutlineNodeTest.php @@ -14,22 +14,68 @@ public function testCreatesExamplesForExampleTable() new StepNode('Gangway!', 'I am ', array(), null, 'Given'), new StepNode('Aye!', 'my email is ', array(), null, 'And'), new StepNode('Blimey!', 'I open homepage', array(), null, 'When'), - new StepNode('Let go and haul', 'website should recognise me', array(), null, 'Then'), + new StepNode('Let go and haul', 'website should recognise me', array(), null, 'Then'), ); - $table = new ExampleTableNode(array( - array('name', 'email'), - array('everzet', 'ever.zet@gmail.com'), - array('example', 'example@example.com') - ), 'Examples'); + $table = new ExampleTableNode([ + 2 => ['name', 'email'], + 22 => ['everzet', 'ever.zet@gmail.com'], + 23 => ['example', 'example@example.com'] + ], 'Examples'); - $outline = new OutlineNode(null, array(), $steps, $table, null, null); + $outline = new OutlineNode(null, array(), $steps, [$table], null, null); $this->assertCount(2, $examples = $outline->getExamples()); - $this->assertEquals(1, $examples[0]->getLine()); - $this->assertEquals(2, $examples[1]->getLine()); + $this->assertEquals(22, $examples[0]->getLine()); + $this->assertEquals(23, $examples[1]->getLine()); $this->assertEquals(array('name' => 'everzet', 'email' => 'ever.zet@gmail.com'), $examples[0]->getTokens()); - $this->assertEquals(array('name' => 'example', 'email' => 'example@example.com'), $examples[1]->getTokens()); + $this->assertEquals(array('name' => 'example', 'email' => 'example@example.com'), $examples[1]->getTokens()); + } + + public function testCreatesExamplesForExampleTableWithSeveralExamplesAndTags() + { + $steps = array( + new StepNode('Gangway!', 'I am ', array(), null, 'Given'), + new StepNode('Aye!', 'my email is ', array(), null, 'And'), + new StepNode('Blimey!', 'I open homepage', array(), null, 'When'), + new StepNode('Let go and haul', 'website should recognise me', array(), null, 'Then'), + ); + + $table = new ExampleTableNode([ + 2 => ['name', 'email'], + 22 => ['everzet', 'ever.zet@gmail.com'], + 23 => ['example', 'example@example.com'] + ], 'Examples', []); + + $table2 = new ExampleTableNode([ + 3 => ['name', 'email'], + 32 => ['everzet2', 'ever.zet2@gmail.com'], + 33 => ['example2', 'example2@example.com'] + ], 'Examples', ['etag1', 'etag2']); + + $outline = new OutlineNode(null, ['otag1', 'otag2'], $steps, [$table, $table2], null, null); + + $this->assertCount(4, $examples = $outline->getExamples()); + $this->assertEquals(22, $examples[0]->getLine()); + $this->assertEquals(23, $examples[1]->getLine()); + $this->assertEquals(32, $examples[2]->getLine()); + $this->assertEquals(33, $examples[3]->getLine()); + $this->assertEquals(['name' => 'everzet', 'email' => 'ever.zet@gmail.com'], $examples[0]->getTokens()); + $this->assertEquals(['name' => 'example', 'email' => 'example@example.com'], $examples[1]->getTokens()); + $this->assertEquals(['name' => 'everzet2', 'email' => 'ever.zet2@gmail.com'], $examples[2]->getTokens()); + $this->assertEquals(['name' => 'example2', 'email' => 'example2@example.com'], $examples[3]->getTokens()); + + for ($i = 0; $i < 2; $i++) { + foreach (['otag1', 'otag2'] as $tag) { + $this->assertTrue($examples[$i]->hasTag($tag), "there is no tag " . $tag . " in example #" . $i); + } + } + + for ($i = 2; $i < 4; $i++) { + foreach (['otag1', 'otag2', 'etag1', 'etag2'] as $tag) { + $this->assertTrue($examples[$i]->hasTag($tag), "there is no tag " . $tag . " in example #" . $i); + } + } } public function testCreatesEmptyExamplesForEmptyExampleTable() @@ -38,14 +84,14 @@ public function testCreatesEmptyExamplesForEmptyExampleTable() new StepNode('Gangway!', 'I am ', array(), null, 'Given'), new StepNode('Aye!', 'my email is ', array(), null, 'And'), new StepNode('Blimey!', 'I open homepage', array(), null, 'When'), - new StepNode('Let go and haul', 'website should recognise me', array(), null, 'Then'), + new StepNode('Let go and haul', 'website should recognise me', array(), null, 'Then'), ); $table = new ExampleTableNode(array( array('name', 'email') ), 'Examples'); - $outline = new OutlineNode(null, array(), $steps, $table, null, null); + $outline = new OutlineNode(null, array(), $steps, [$table], null, null); $this->assertCount(0, $examples = $outline->getExamples()); } @@ -56,12 +102,12 @@ public function testCreatesEmptyExamplesForNoExampleTable() new StepNode('Gangway!', 'I am ', array(), null, 'Given'), new StepNode('Aye!', 'my email is ', array(), null, 'And'), new StepNode('Blimey!', 'I open homepage', array(), null, 'When'), - new StepNode('Let go and haul', 'website should recognise me', array(), null, 'Then'), + new StepNode('Let go and haul', 'website should recognise me', array(), null, 'Then'), ); $table = new ExampleTableNode(array(), 'Examples'); - $outline = new OutlineNode(null, array(), $steps, $table, null, null); + $outline = new OutlineNode(null, array(), $steps, [$table], null, null); $this->assertCount(0, $examples = $outline->getExamples()); } diff --git a/tests/Behat/Gherkin/Node/TableNodeTest.php b/tests/Behat/Gherkin/Node/TableNodeTest.php index 43dfff22..505a51f9 100644 --- a/tests/Behat/Gherkin/Node/TableNodeTest.php +++ b/tests/Behat/Gherkin/Node/TableNodeTest.php @@ -219,4 +219,90 @@ public function testGetTableAsString() TABLE; $this->assertEquals($expected, $table->getTableAsString()); } + + public function testMergeRowsFromTablePassSeveralTablesShouldBeMerged() + { + $table = new TableNode(array( + 5 => array('id', 'username', 'password'), + 10 => array('42', 'everzet', 'qwerty'), + 13 => array('2', 'antono', 'pa$sword') + )); + + $new = new TableNode(array( + 25 => array('id', 'username', 'password'), + 210 => array('242', '2everzet', '2qwerty'), + 213 => array('22', '2antono', '2pa$sword') + )); + + $new2 = new TableNode(array( + 35 => array('id', 'username', 'password'), + 310 => array('342', '3everzet', '3qwerty'), + 313 => array('32', '3antono', '3pa$sword') + )); + + $table->mergeRowsFromTable($new); + $table->mergeRowsFromTable($new2); + + $this->assertEquals(array('id', 'username', 'password'), $table->getRow(0)); + $this->assertEquals(array('2', 'antono', 'pa$sword'), $table->getRow(2)); + $this->assertEquals(array('242', '2everzet', '2qwerty'), $table->getRow(3)); + $this->assertEquals(array('32', '3antono', '3pa$sword'), $table->getRow(6)); + } + + /** + * @expectedException \Behat\Gherkin\Exception\NodeException + */ + public function testMergeRowsFromTableWrongHeaderNameExceptionThrown() + { + $table = new TableNode(array( + 5 => array('id', 'username', 'password'), + 10 => array('42', 'everzet', 'qwerty'), + 13 => array('2', 'antono', 'pa$sword') + )); + + $new = new TableNode(array( + 25 => array('id', 'QWE', 'password'), + 210 => array('242', '2everzet', '2qwerty') + )); + + $table->mergeRowsFromTable($new); + } + + /** + * @expectedException \Behat\Gherkin\Exception\NodeException + */ + public function testMergeRowsFromTableWrongHeaderOrderExceptionThrown() + { + $table = new TableNode(array( + 5 => array('id', 'username', 'password'), + 10 => array('42', 'everzet', 'qwerty'), + 13 => array('2', 'antono', 'pa$sword') + )); + + $new = new TableNode(array( + 25 => array('id', 'password', 'username'), + 210 => array('242', '2everzet', '2qwerty') + )); + + $table->mergeRowsFromTable($new); + } + + /** + * @expectedException \Behat\Gherkin\Exception\NodeException + */ + public function testMergeRowsFromTableWrongHeaderSizeExceptionThrown() + { + $table = new TableNode(array( + 5 => array('id', 'username', 'password'), + 10 => array('42', 'everzet', 'qwerty'), + 13 => array('2', 'antono', 'pa$sword') + )); + + $new = new TableNode(array( + 25 => array('id', 'username'), + 210 => array('242', '2everzet') + )); + + $table->mergeRowsFromTable($new); + } } diff --git a/tests/Behat/Gherkin/ParserTest.php b/tests/Behat/Gherkin/ParserTest.php index aff585cd..d9d2e582 100644 --- a/tests/Behat/Gherkin/ParserTest.php +++ b/tests/Behat/Gherkin/ParserTest.php @@ -28,11 +28,14 @@ public function parserTestDataProvider() /** * @dataProvider parserTestDataProvider - * * @param string $fixtureName name of the fixture */ public function testParser($fixtureName) +// public function testParser() { + //$fixtureName = 'outline_with_multiple_examples'; + + echo $fixtureName . "\n"; $etalon = $this->parseEtalon($fixtureName . '.yml'); $features = $this->parseFixture($fixtureName . '.feature');