Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatibility layer for cucumber/gherkin #253

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
10 changes: 10 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ jobs:
symfony-version: '5.*'
- php: 8.0
symfony-version: '5.*'
- php: 8.1
cucumber: true

steps:
- uses: actions/checkout@v2
Expand All @@ -40,8 +42,16 @@ jobs:
if: matrix.symfony-version != ''
run: composer require --no-update "symfony/symfony:${{ matrix.symfony-version }}"

- name: Require cucumber
if: matrix.cucumber == true
run: composer require --no-update "cucumber/gherkin"

- name: Install dependencies
run: composer update ${{ matrix.composer-flags }}

- name: Run tests (phpunit)
run: ./vendor/bin/phpunit

- name: Run cucumber tests (phpunit)
if: matrix.cucumber == true
run: ./vendor/bin/phpunit --group=cucumber
4 changes: 4 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
"cucumber/cucumber": "dev-gherkin-24.0.0"
},

"conflict": {
"cucumber/messages": "<19.0.0"
},

"suggest": {
"symfony/yaml": "If you want to parse features, represented in YAML files"
},
Expand Down
6 changes: 6 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
stopOnFailure="false"
bootstrap="vendor/autoload.php"
>
<groups>
<exclude>
<group>cucumber</group>
</exclude>
</groups>

<testsuites>
<testsuite name="Behat Gherkin test suite">
<directory>./tests/Behat/Gherkin/</directory>
Expand Down
50 changes: 50 additions & 0 deletions src/Behat/Gherkin/Cucumber/BackgroundNodeMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Behat\Gherkin\Cucumber;

use Behat\Gherkin\Node\BackgroundNode;
use Cucumber\Messages\Background;
use Cucumber\Messages\FeatureChild;

final class BackgroundNodeMapper
{
/**
* @var StepNodeMapper
*/
private $stepNodeMapper;

public function __construct(StepNodeMapper $stepNodeMapper)
{
$this->stepNodeMapper = $stepNodeMapper;
}

/**
* @param FeatureChild[] $children
*
* @return BackgroundNode|null
*/
public function map(array $children) : ?BackgroundNode
{
foreach($children as $child) {
if ($child->background) {

$title = $child->background->name;
if ($child->background->description) {
$title .= "\n" . $child->background->description;
}

return new BackgroundNode(
MultilineStringFormatter::format(
$title,
$child->background->location
),
$this->stepNodeMapper->map($child->background->steps),
$child->background->keyword,
$child->background->location->line
);
}
}

return null;
}
}
65 changes: 65 additions & 0 deletions src/Behat/Gherkin/Cucumber/ExampleTableNodeMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace Behat\Gherkin\Cucumber;

use Behat\Gherkin\Node\ExampleTableNode;
use Cucumber\Messages\Examples;
use Cucumber\Messages\TableCell;

final class ExampleTableNodeMapper
{
/**
* @var TagMapper
*/
private $tagMapper;

public function __construct(TagMapper $tagMapper)
{
$this->tagMapper = $tagMapper;
}

/**
* @param Examples[] $exampleTables
*
* @return ExampleTableNode[]
*/
public function map(array $exampleTables) : array
{
$exampleTableNodes = [];

foreach ($exampleTables as $exampleTable) {
$exampleTableNodes[] = new ExampleTableNode(
$this->getTableArray($exampleTable),
$exampleTable->keyword,
$this->tagMapper->map($exampleTable->tags)
);
}

return $exampleTableNodes;
}

private function getTableArray(Examples $exampleTable) : array
{
$array = [];

if ($exampleTable->tableHeader) {
$array[$exampleTable->tableHeader->location->line] = array_map(
function (TableCell $cell) {
return $cell->value;
},
$exampleTable->tableHeader->cells
);
}

foreach ($exampleTable->tableBody as $row) {
$array[$row->location->line] = array_map(
function (TableCell $cell) {
return $cell->value;
},
$row->cells
);
}

return $array;
}
}
59 changes: 59 additions & 0 deletions src/Behat/Gherkin/Cucumber/FeatureNodeMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace Behat\Gherkin\Cucumber;

use Behat\Gherkin\Node\FeatureNode;
use Cucumber\Messages\Feature;
use Cucumber\Messages\GherkinDocument;

final class FeatureNodeMapper
{
/**
* @var TagMapper
*/
private $tagMapper;

/**
* @var BackgroundNodeMapper
*/
private $backgroundMapper;

/**
* @var ScenarioNodeMapper
*/
private $scenarioMapper;

public function __construct(
TagMapper $tagMapper,
BackgroundNodeMapper $backgroundMapper,
ScenarioNodeMapper $scenarioMapper
)
{
$this->tagMapper = $tagMapper;
$this->backgroundMapper = $backgroundMapper;
$this->scenarioMapper = $scenarioMapper;
}

function map(GherkinDocument $gherkinDocument) : ?FeatureNode
{
if (!$gherkinDocument->feature) {
return null;
}

return new FeatureNode(
$gherkinDocument->feature->name,
MultilineStringFormatter::format(
$gherkinDocument->feature->description,
$gherkinDocument->feature->location
) ?: null, // background has empty = null
$this->tagMapper->map($gherkinDocument->feature->tags),
$this->backgroundMapper->map($gherkinDocument->feature->children),
$this->scenarioMapper->map($gherkinDocument->feature->children),
$gherkinDocument->feature->keyword,
$gherkinDocument->feature->language,
$gherkinDocument->uri,
$gherkinDocument->feature->location->line
);
}

}
30 changes: 30 additions & 0 deletions src/Behat/Gherkin/Cucumber/KeywordTypeMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Behat\Gherkin\Cucumber;

use Cucumber\Messages\Step\KeywordType;

final class KeywordTypeMapper
{
public function map(?KeywordType $type, ?string $prevType) : string
{
if ($type == KeywordType::CONTEXT) {
return 'Given';
}

if ($type == KeywordType::ACTION) {
return 'When';
}

if ($type == KeywordType::OUTCOME) {
return 'Then';
}

if ($type == KeywordType::CONJUNCTION && $prevType != null) {
return $prevType;
}

return 'Given';
}

}
23 changes: 23 additions & 0 deletions src/Behat/Gherkin/Cucumber/MultilineStringFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php declare(strict_types=1);

namespace Behat\Gherkin\Cucumber;

use Cucumber\Messages\Location;

final class MultilineStringFormatter
{
public static function format(string $string, Location $keywordLocation = null): string
{
if (!$keywordLocation) {
$keywordLocation = new Location(0,1);
}

$maxIndent = ($keywordLocation->column-1 ?: 0) + 2;

return preg_replace(
["/^[^\n\S]{0,$maxIndent}/um", '/[^\n\S]+$/um'],
['', ''],
$string
);
}
}
33 changes: 33 additions & 0 deletions src/Behat/Gherkin/Cucumber/PyStringNodeMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Behat\Gherkin\Cucumber;

use Behat\Gherkin\Node\PyStringNode;
use Cucumber\Messages\DocString;

final class PyStringNodeMapper
{
/**
* @param DocString $docString
* @return PyStringNode[]
*/
public function map(?DocString $docString) : array
{
if (!$docString) {
return [];
}

return [
new PyStringNode(
$this->split($docString->content),
$docString->location->line
)
];
}

private function split(string $content) {
$content = strtr($content, array("\r\n" => "\n", "\r" => "\n"));

return explode("\n", $content);
}
}
Loading