Skip to content

Commit

Permalink
Add support for multiple Example Tables with tags (#161)
Browse files Browse the repository at this point in the history
* Multiple example tables and tags support #117

* #117 phpdoc and some rewording

* nesting reducing

* Fix the OutlineNode object for backward compatibility

Co-authored-by: Andrey Stukalin <Andrey.Stukalin@Vodafone.com>
Co-authored-by: Andrey Stukalin <apstukalin@gmail.com>
  • Loading branch information
3 people authored Jan 14, 2021
1 parent df4d097 commit dfc47a2
Show file tree
Hide file tree
Showing 20 changed files with 769 additions and 102 deletions.
36 changes: 19 additions & 17 deletions src/Behat/Gherkin/Filter/LineFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,24 +83,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(),
array(new ExampleTableNode($filteredTable, $exampleTable->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()
);
}
}

Expand Down
25 changes: 17 additions & 8 deletions src/Behat/Gherkin/Filter/LineRangeFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,23 +94,32 @@ public function filterFeature(FeatureNode $feature)
}

if ($scenario instanceof OutlineNode && $scenario->hasExamples()) {
$table = $scenario->getExampleTable()->getTable();
$lines = array_keys($table);
// first accumulate examples and then create scenario
$exampleTableNodes = array();

$filteredTable = array($lines[0] => $table[$lines[0]]);
unset($table[$lines[0]]);
foreach ($scenario->getExampleTables() as $exampleTable) {
$table = $exampleTable->getTable();
$lines = array_keys($table);

foreach ($table as $line => $row) {
if ($this->filterMinLine <= $line && $this->filterMaxLine >= $line) {
$filteredTable[$line] = $row;
$filteredTable = array($lines[0] => $table[$lines[0]]);
unset($table[$lines[0]]);

foreach ($table as $line => $row) {
if ($this->filterMinLine <= $line && $this->filterMaxLine >= $line) {
$filteredTable[$line] = $row;
}
}

if (count($filteredTable) > 1) {
$exampleTableNodes[] = new ExampleTableNode($filteredTable, $exampleTable->getKeyword(), $exampleTable->getTags());
}
}

$scenario = new OutlineNode(
$scenario->getTitle(),
$scenario->getTags(),
$scenario->getSteps(),
new ExampleTableNode($filteredTable, $scenario->getExampleTable()->getKeyword()),
$exampleTableNodes,
$scenario->getKeyword(),
$scenario->getLine()
);
Expand Down
64 changes: 63 additions & 1 deletion src/Behat/Gherkin/Filter/TagFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace Behat\Gherkin\Filter;

use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\OutlineNode;
use Behat\Gherkin\Node\ScenarioInterface;

/**
Expand All @@ -32,6 +33,57 @@ public function __construct($filterString)
$this->filterString = trim($filterString);
}

/**
* Filters feature according to the filter.
*
* @param FeatureNode $feature
*
* @return FeatureNode
*/
public function filterFeature(FeatureNode $feature)
{
$scenarios = array();
foreach ($feature->getScenarios() as $scenario) {
if (!$this->isScenarioMatch($feature, $scenario)) {
continue;
}

if ($scenario instanceof OutlineNode && $scenario->hasExamples()) {

$exampleTables = array();

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.
*
Expand All @@ -47,13 +99,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()));
}

Expand Down
45 changes: 44 additions & 1 deletion src/Behat/Gherkin/Loader/ArrayLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,15 @@ protected function loadOutlineHash(array $hash, $line = 0)
$examplesKeyword = 'Examples';
}

$examples = new ExampleTableNode($hash['examples'], $examplesKeyword);
$exHash = $hash['examples'];
$examples = array();

if ($this->examplesAreInArray($exHash)) {
$examples = $this->processExamplesArray($exHash, $examplesKeyword, $examples);
} else {
// examples as a single table - we create an array with the only one element
$examples[] = new ExampleTableNode($exHash, $examplesKeyword);;
}

return new OutlineNode($hash['title'], $hash['tags'], $steps, $examples, $hash['keyword'], $hash['line']);
}
Expand Down Expand Up @@ -266,4 +274,39 @@ protected function loadPyStringHash(array $hash, $line = 0)

return new PyStringNode($strings, $line);
}

/**
* Checks if examples node is an array
* @param $exHash object hash
* @return bool
*/
private function examplesAreInArray($exHash)
{
return isset($exHash[0]);
}

/**
* Processes cases when examples are in the form of array of arrays
* OR in the form of array of objects
*
* @param $exHash array hash
* @param $examplesKeyword string
* @param $examples array
* @return array
*/
private function processExamplesArray($exHash, $examplesKeyword, $examples)
{
for ($i = 0; $i < count($exHash); $i++) {
if (isset($exHash[$i]['table'])) {
// we have examples as objects, hence there could be tags
$exHashTags = isset($exHash[$i]['tags']) ? $exHash[$i]['tags'] : array();
$examples[] = new ExampleTableNode($exHash[$i]['table'], $examplesKeyword, $exHashTags);
} else {
// we have examples as arrays
$examples[] = new ExampleTableNode($exHash[$i], $examplesKeyword);
}
}

return $examples;
}
}
20 changes: 18 additions & 2 deletions src/Behat/Gherkin/Node/ExampleTableNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
*/
class ExampleTableNode extends TableNode
{
/**
* @var string[]
*/
private $tags;

/**
* @var string
*/
Expand All @@ -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 = array())
{
$this->keyword = $keyword;
$this->tags = $tags;

parent::__construct($table);
}
Expand All @@ -45,6 +52,15 @@ public function getNodeType()
return 'ExampleTable';
}

/**
* Returns attached tags
* @return \string[]
*/
public function getTags()
{
return $this->tags;
}

/**
* Returns example table keyword.
*
Expand Down
Loading

0 comments on commit dfc47a2

Please sign in to comment.