This commit is contained in:
2020-10-06 14:27:47 +07:00
commit 586be80cf6
16613 changed files with 3274099 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Loader;
/**
* Abstract filesystem loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class AbstractFileLoader implements FileLoaderInterface
{
protected $basePath;
/**
* Sets base features path.
*
* @param string $path Base loader path
*/
public function setBasePath($path)
{
$this->basePath = realpath($path);
}
/**
* Finds relative path for provided absolute (relative to base features path).
*
* @param string $path Absolute path
*
* @return string
*/
protected function findRelativePath($path)
{
if (null !== $this->basePath) {
return strtr($path, array($this->basePath . DIRECTORY_SEPARATOR => ''));
}
return $path;
}
/**
* Finds absolute path for provided relative (relative to base features path).
*
* @param string $path Relative path
*
* @return string
*/
protected function findAbsolutePath($path)
{
if (is_file($path) || is_dir($path)) {
return realpath($path);
}
if (null === $this->basePath) {
return false;
}
if (is_file($this->basePath . DIRECTORY_SEPARATOR . $path)
|| is_dir($this->basePath . DIRECTORY_SEPARATOR . $path)) {
return realpath($this->basePath . DIRECTORY_SEPARATOR . $path);
}
return false;
}
}

View File

@@ -0,0 +1,269 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Loader;
use Behat\Gherkin\Node\BackgroundNode;
use Behat\Gherkin\Node\ExampleTableNode;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Node\OutlineNode;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\ScenarioNode;
use Behat\Gherkin\Node\StepNode;
use Behat\Gherkin\Node\TableNode;
/**
* From-array loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class ArrayLoader implements LoaderInterface
{
/**
* Checks if current loader supports provided resource.
*
* @param mixed $resource Resource to load
*
* @return Boolean
*/
public function supports($resource)
{
return is_array($resource) && (isset($resource['features']) || isset($resource['feature']));
}
/**
* Loads features from provided resource.
*
* @param mixed $resource Resource to load
*
* @return FeatureNode[]
*/
public function load($resource)
{
$features = array();
if (isset($resource['features'])) {
foreach ($resource['features'] as $iterator => $hash) {
$feature = $this->loadFeatureHash($hash, $iterator);
$features[] = $feature;
}
} elseif (isset($resource['feature'])) {
$feature = $this->loadFeatureHash($resource['feature']);
$features[] = $feature;
}
return $features;
}
/**
* Loads feature from provided feature hash.
*
* @param array $hash Feature hash
* @param integer $line
*
* @return FeatureNode
*/
protected function loadFeatureHash(array $hash, $line = 0)
{
$hash = array_merge(
array(
'title' => null,
'description' => null,
'tags' => array(),
'keyword' => 'Feature',
'language' => 'en',
'line' => $line,
'scenarios' => array(),
),
$hash
);
$background = isset($hash['background']) ? $this->loadBackgroundHash($hash['background']) : null;
$scenarios = array();
foreach ((array) $hash['scenarios'] as $scenarioIterator => $scenarioHash) {
if (isset($scenarioHash['type']) && 'outline' === $scenarioHash['type']) {
$scenarios[] = $this->loadOutlineHash($scenarioHash, $scenarioIterator);
} else {
$scenarios[] = $this->loadScenarioHash($scenarioHash, $scenarioIterator);
}
}
return new FeatureNode($hash['title'], $hash['description'], $hash['tags'], $background, $scenarios, $hash['keyword'], $hash['language'], null, $hash['line']);
}
/**
* Loads background from provided hash.
*
* @param array $hash Background hash
*
* @return BackgroundNode
*/
protected function loadBackgroundHash(array $hash)
{
$hash = array_merge(
array(
'title' => null,
'keyword' => 'Background',
'line' => 0,
'steps' => array(),
),
$hash
);
$steps = $this->loadStepsHash($hash['steps']);
return new BackgroundNode($hash['title'], $steps, $hash['keyword'], $hash['line']);
}
/**
* Loads scenario from provided scenario hash.
*
* @param array $hash Scenario hash
* @param integer $line Scenario definition line
*
* @return ScenarioNode
*/
protected function loadScenarioHash(array $hash, $line = 0)
{
$hash = array_merge(
array(
'title' => null,
'tags' => array(),
'keyword' => 'Scenario',
'line' => $line,
'steps' => array(),
),
$hash
);
$steps = $this->loadStepsHash($hash['steps']);
return new ScenarioNode($hash['title'], $hash['tags'], $steps, $hash['keyword'], $hash['line']);
}
/**
* Loads outline from provided outline hash.
*
* @param array $hash Outline hash
* @param integer $line Outline definition line
*
* @return OutlineNode
*/
protected function loadOutlineHash(array $hash, $line = 0)
{
$hash = array_merge(
array(
'title' => null,
'tags' => array(),
'keyword' => 'Scenario Outline',
'line' => $line,
'steps' => array(),
'examples' => array(),
),
$hash
);
$steps = $this->loadStepsHash($hash['steps']);
if (isset($hash['examples']['keyword'])) {
$examplesKeyword = $hash['examples']['keyword'];
unset($hash['examples']['keyword']);
} else {
$examplesKeyword = 'Examples';
}
$examples = new ExampleTableNode($hash['examples'], $examplesKeyword);
return new OutlineNode($hash['title'], $hash['tags'], $steps, $examples, $hash['keyword'], $hash['line']);
}
/**
* Loads steps from provided hash.
*
* @param array $hash
*
* @return StepNode[]
*/
private function loadStepsHash(array $hash)
{
$steps = array();
foreach ($hash as $stepIterator => $stepHash) {
$steps[] = $this->loadStepHash($stepHash, $stepIterator);
}
return $steps;
}
/**
* Loads step from provided hash.
*
* @param array $hash Step hash
* @param integer $line Step definition line
*
* @return StepNode
*/
protected function loadStepHash(array $hash, $line = 0)
{
$hash = array_merge(
array(
'keyword_type' => 'Given',
'type' => 'Given',
'text' => null,
'keyword' => 'Scenario',
'line' => $line,
'arguments' => array(),
),
$hash
);
$arguments = array();
foreach ($hash['arguments'] as $argumentHash) {
if ('table' === $argumentHash['type']) {
$arguments[] = $this->loadTableHash($argumentHash['rows']);
} elseif ('pystring' === $argumentHash['type']) {
$arguments[] = $this->loadPyStringHash($argumentHash, $hash['line'] + 1);
}
}
return new StepNode($hash['type'], $hash['text'], $arguments, $hash['line'], $hash['keyword_type']);
}
/**
* Loads table from provided hash.
*
* @param array $hash Table hash
*
* @return TableNode
*/
protected function loadTableHash(array $hash)
{
return new TableNode($hash);
}
/**
* Loads PyString from provided hash.
*
* @param array $hash PyString hash
* @param integer $line
*
* @return PyStringNode
*/
protected function loadPyStringHash(array $hash, $line = 0)
{
$line = isset($hash['line']) ? $hash['line'] : $line;
$strings = array();
foreach (explode("\n", $hash['text']) as $string) {
$strings[] = $string;
}
return new PyStringNode($strings, $line);
}
}

View File

@@ -0,0 +1,80 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Loader;
use Behat\Gherkin\Gherkin;
use Behat\Gherkin\Node\FeatureNode;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
/**
* Directory contents loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class DirectoryLoader extends AbstractFileLoader
{
protected $gherkin;
/**
* Initializes loader.
*
* @param Gherkin $gherkin Gherkin manager
*/
public function __construct(Gherkin $gherkin)
{
$this->gherkin = $gherkin;
}
/**
* Checks if current loader supports provided resource.
*
* @param mixed $path Resource to load
*
* @return Boolean
*/
public function supports($path)
{
return is_string($path)
&& is_dir($this->findAbsolutePath($path));
}
/**
* Loads features from provided resource.
*
* @param string $path Resource to load
*
* @return FeatureNode[]
*/
public function load($path)
{
$path = $this->findAbsolutePath($path);
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS)
);
$paths = array_map('strval', iterator_to_array($iterator));
uasort($paths, 'strnatcasecmp');
$features = array();
foreach ($paths as $path) {
$path = (string) $path;
$loader = $this->gherkin->resolveLoader($path);
if (null !== $loader) {
$features = array_merge($features, $loader->load($path));
}
}
return $features;
}
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Loader;
/**
* File Loader interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface FileLoaderInterface extends LoaderInterface
{
/**
* Sets base features path.
*
* @param string $path Base loader path
*/
public function setBasePath($path);
}

View File

@@ -0,0 +1,102 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Loader;
use Behat\Gherkin\Cache\CacheInterface;
use Behat\Gherkin\Node\FeatureNode;
use Behat\Gherkin\Parser;
/**
* Gherkin *.feature files loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class GherkinFileLoader extends AbstractFileLoader
{
protected $parser;
protected $cache;
/**
* Initializes loader.
*
* @param Parser $parser Parser
* @param CacheInterface $cache Cache layer
*/
public function __construct(Parser $parser, CacheInterface $cache = null)
{
$this->parser = $parser;
$this->cache = $cache;
}
/**
* Sets cache layer.
*
* @param CacheInterface $cache Cache layer
*/
public function setCache(CacheInterface $cache)
{
$this->cache = $cache;
}
/**
* Checks if current loader supports provided resource.
*
* @param mixed $path Resource to load
*
* @return Boolean
*/
public function supports($path)
{
return is_string($path)
&& is_file($absolute = $this->findAbsolutePath($path))
&& 'feature' === pathinfo($absolute, PATHINFO_EXTENSION);
}
/**
* Loads features from provided resource.
*
* @param string $path Resource to load
*
* @return FeatureNode[]
*/
public function load($path)
{
$path = $this->findAbsolutePath($path);
if ($this->cache) {
if ($this->cache->isFresh($path, filemtime($path))) {
$feature = $this->cache->read($path);
} elseif (null !== $feature = $this->parseFeature($path)) {
$this->cache->write($path, $feature);
}
} else {
$feature = $this->parseFeature($path);
}
return null !== $feature ? array($feature) : array();
}
/**
* Parses feature at provided absolute path.
*
* @param string $path Feature path
*
* @return FeatureNode
*/
protected function parseFeature($path)
{
$filename = $this->findRelativePath($path);
$content = file_get_contents($path);
$feature = $this->parser->parse($content, $filename);
return $feature;
}
}

View File

@@ -0,0 +1,39 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Loader;
use Behat\Gherkin\Node\FeatureNode;
/**
* Loader interface.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
interface LoaderInterface
{
/**
* Checks if current loader supports provided resource.
*
* @param mixed $resource Resource to load
*
* @return Boolean
*/
public function supports($resource);
/**
* Loads features from provided resource.
*
* @param mixed $resource Resource to load
*
* @return FeatureNode[]
*/
public function load($resource);
}

View File

@@ -0,0 +1,73 @@
<?php
/*
* This file is part of the Behat Gherkin.
* (c) Konstantin Kudryashov <ever.zet@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Behat\Gherkin\Loader;
use Behat\Gherkin\Node\FeatureNode;
use Symfony\Component\Yaml\Yaml;
/**
* Yaml files loader.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class YamlFileLoader extends AbstractFileLoader
{
private $loader;
public function __construct()
{
$this->loader = new ArrayLoader();
}
/**
* Checks if current loader supports provided resource.
*
* @param mixed $path Resource to load
*
* @return Boolean
*/
public function supports($path)
{
return is_string($path)
&& is_file($absolute = $this->findAbsolutePath($path))
&& 'yml' === pathinfo($absolute, PATHINFO_EXTENSION);
}
/**
* Loads features from provided resource.
*
* @param string $path Resource to load
*
* @return FeatureNode[]
*/
public function load($path)
{
$path = $this->findAbsolutePath($path);
$hash = Yaml::parse(file_get_contents($path));
$features = $this->loader->load($hash);
$filename = $this->findRelativePath($path);
return array_map(function (FeatureNode $feature) use ($filename) {
return new FeatureNode(
$feature->getTitle(),
$feature->getDescription(),
$feature->getTags(),
$feature->getBackground(),
$feature->getScenarios(),
$feature->getKeyword(),
$feature->getLanguage(),
$filename,
$feature->getLine()
);
}, $features);
}
}