| Current Path : /var/www/www.indacotrentino.com/www/vendor/codeception/codeception/src/Codeception/Lib/ |
| Current File : /var/www/www.indacotrentino.com/www/vendor/codeception/codeception/src/Codeception/Lib/Parser.php |
<?php
declare(strict_types=1);
namespace Codeception\Lib;
use Codeception\Exception\TestParseException;
use Codeception\Scenario;
use Codeception\Step\Action;
use Codeception\Step\Comment;
use Codeception\Test\Metadata;
use Exception;
use ParseError;
class Parser
{
protected string $code;
public function __construct(protected Scenario $scenario, protected Metadata $metadata)
{
}
public function prepareToRun(string $code): void
{
$this->parseFeature($code);
$this->parseScenarioOptions($code);
}
public function parseFeature(string $code): void
{
$matches = [];
$code = $this->stripComments($code);
$res = preg_match("#\\\$I->wantTo\\(\\s*?['\"](.*?)['\"]\\s*?\\);#", $code, $matches);
if ($res) {
$this->scenario->setFeature($matches[1]);
return;
}
$res = preg_match("#\\\$I->wantToTest\\(['\"](.*?)['\"]\\);#", $code, $matches);
if ($res) {
$this->scenario->setFeature("test " . $matches[1]);
}
}
public function parseScenarioOptions(string $code): void
{
$this->metadata->setParamsFromAnnotations($this->matchComments($code));
}
public function parseSteps(string $code): void
{
// parse per line
$friends = [];
$lines = explode("\n", $code);
$isFriend = false;
foreach ($lines as $line) {
// friends
if (preg_match("#\\\$I->haveFriend\\((.*?)\\);#", $line, $matches)) {
$friends[] = trim($matches[1], '\'"');
}
// friend's section start
if (preg_match("#\\\$(.*?)->does\\(#", $line, $matches)) {
$friend = $matches[1];
if (!in_array($friend, $friends)) {
continue;
}
$isFriend = true;
$this->addCommentStep("\n----- {$friend} does -----");
continue;
}
// actions
if (preg_match("#\\\$I->(.*)\\((.*?)\\);#", $line, $matches)) {
$this->addStep($matches);
}
// friend's section ends
if ($isFriend && str_contains($line, '}')) {
$this->addCommentStep("-------- back to me\n");
$isFriend = false;
}
}
}
protected function addStep(array $matches): void
{
[$m, $action, $params] = $matches;
if (in_array($action, ['wantTo', 'wantToTest'])) {
return;
}
$this->scenario->addStep(new Action($action, explode(',', $params)));
}
protected function addCommentStep(string $comment): void
{
$this->scenario->addStep(new Comment($comment, []));
}
public static function load(string $file): void
{
try {
self::includeFile($file);
} catch (ParseError $e) {
throw new TestParseException($file, $e->getMessage(), $e->getLine());
} catch (Exception) {
// file is valid otherwise
}
}
/**
* @return string[]
*/
public static function getClassesFromFile(string $file): array
{
$sourceCode = file_get_contents($file);
$classes = [];
$tokens = token_get_all($sourceCode, TOKEN_PARSE);
$tokenCount = count($tokens);
$namespace = '';
for ($i = 0; $i < $tokenCount; ++$i) {
if ($tokens[$i][0] === T_NAMESPACE) {
$namespace = '';
for ($j = $i + 1; $j < $tokenCount; ++$j) {
if ($tokens[$j] === '{' || $tokens[$j] === ';') {
break;
}
if ($tokens[$j][0] === T_STRING || $tokens[$j][0] === T_NAME_QUALIFIED) {
$namespace .= $tokens[$j][1] . '\\';
}
}
}
if ($tokens[$i][0] === T_CLASS) {
// class at the beginning of file
if (!isset($tokens[$i - 2])) {
$classes[] = $namespace . $tokens[$i + 2][1];
continue;
}
// new class
if ($tokens[$i - 2][0] === T_NEW) {
continue;
}
// :: class
if ($tokens[$i - 1][0] === T_WHITESPACE && $tokens[$i - 2][0] === T_DOUBLE_COLON) {
continue;
}
// ::class
if ($tokens[$i - 1][0] === T_DOUBLE_COLON) {
continue;
}
// class{
if (isset($tokens[$i + 1]) && ($tokens[$i + 1] === '{')) {
continue;
}
// class {
if (isset($tokens[$i + 2]) && $tokens[$i + 1][0] === T_WHITESPACE && $tokens[$i + 2] === '{') {
continue;
}
$classes[] = $namespace . $tokens[$i + 2][1];
}
}
$tokens = null;
gc_mem_caches();
return $classes;
}
/*
* Include in different scope to prevent included file from affecting $file variable
*/
private static function includeFile(string $file): void
{
include_once $file;
}
protected function stripComments(string $code): string
{
$code = preg_replace('#//.*?$#m', '', $code); // remove inline comments
return preg_replace('#/*\*.*?\*/#ms', '', $code); // remove block comment
}
protected function matchComments(string $code): string
{
$matches = [];
$comments = '';
$hasLineComment = preg_match_all('#//(.*?)$#m', $code, $matches);
if ($hasLineComment) {
foreach ($matches[1] as $line) {
$comments .= $line . "\n";
}
}
$hasBlockComment = preg_match('#/*\*(.*?)\*/#ms', $code, $matches);
if ($hasBlockComment) {
$comments .= $matches[1] . "\n";
}
return $comments;
}
}