Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - https://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <https://www.gnu.org/licenses/>.namespace tool_generator\local\testscenario;use behat_data_generators;use Behat\Gherkin\Parser;use Behat\Gherkin\Lexer;use Behat\Gherkin\Keywords\ArrayKeywords;use ReflectionClass;use ReflectionMethod;/*** Class to process a scenario generator file.** @package tool_generator* @copyright 2023 Ferran Recio <ferran@moodle.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/class runner {/** @var behat_data_generators the behat data generator instance. */private behat_data_generators $generator;/** @var array of valid steps indexed by given expression tag. */private array $validsteps;/*** Initi all composer, behat libraries and load the valid steps.*/public function init() {$this->include_composer_libraries();$this->include_behat_libraries();$this->load_generator();}/*** Include composer autload.*/public function include_composer_libraries() {global $CFG;if (!file_exists($CFG->dirroot . '/vendor/autoload.php')) {throw new \moodle_exception('Missing composer.');}require_once($CFG->dirroot . '/vendor/autoload.php');return true;}/*** Include all necessary behat libraries.*/public function include_behat_libraries() {global $CFG;if (!class_exists('Behat\Gherkin\Lexer')) {throw new \moodle_exception('Missing behat classes.');}// Behat utilities.require_once($CFG->libdir . '/behat/classes/util.php');require_once($CFG->libdir . '/behat/classes/behat_command.php');require_once($CFG->libdir . '/behat/behat_base.php');require_once("{$CFG->libdir}/tests/behat/behat_data_generators.php");return true;}/*** Load all generators.*/private function load_generator() {$this->generator = new behat_data_generators();$this->validsteps = $this->scan_generator($this->generator);}/*** Scan a generator to get all valid steps.* @param behat_data_generators $generator the generator to scan.* @return array the valid steps.*/private function scan_generator(behat_data_generators $generator): array {$result = [];$class = new ReflectionClass($generator);$methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);foreach ($methods as $method) {$given = $this->get_method_given($method);if ($given) {$result[$given] = $method->getName();}}return $result;}/*** Get the given expression tag of a method.** @param ReflectionMethod $method the method to get the given expression tag.* @return string|null the given expression tag or null if not found.*/private function get_method_given(ReflectionMethod $method): ?string {$doccomment = $method->getDocComment();$doccomment = str_replace("\r\n", "\n", $doccomment);$doccomment = str_replace("\r", "\n", $doccomment);$doccomment = explode("\n", $doccomment);foreach ($doccomment as $line) {$matches = [];if (preg_match('/.*\@(given|when|then)\s+(.+)$/i', $line, $matches)) {return $matches[2];}}return null;}/*** Parse a feature file.* @param string $content the feature file content.* @return parsedfeature*/public function parse_feature(string $content): parsedfeature {$result = new parsedfeature();$parser = $this->get_parser();$feature = $parser->parse($content);// No need for background in testing scenarios because scenarios can only contain generators.// In the future the background can be used to define clean up steps (when clean up methods// are implemented).if ($feature->hasScenarios()) {$scenarios = $feature->getScenarios();foreach ($scenarios as $scenario) {if ($scenario->getNodeType() == 'Outline') {$result->add_scenario($scenario->getNodeType(), $scenario->getTitle());$result->add_error(get_string('testscenario_outline', 'tool_generator'));continue;}$result->add_scenario($scenario->getNodeType(), $scenario->getTitle());$steps = $scenario->getSteps();foreach ($steps as $step) {$result->add_step(new steprunner($this->generator, $this->validsteps, $step));}}}return $result;}/*** Get the parser.* @return Parser*/private function get_parser(): Parser {$keywords = new ArrayKeywords(['en' => ['feature' => 'Feature',// If in the future we have clean up steps, background will be renamed to "Clean up".'background' => 'Background','scenario' => 'Scenario','scenario_outline' => 'Scenario Outline|Scenario Template','examples' => 'Examples|Scenarios','given' => 'Given','when' => 'When','then' => 'Then','and' => 'And','but' => 'But',],]);$lexer = new Lexer($keywords);$parser = new Parser($lexer);return $parser;}/*** Execute a parsed feature.* @param parsedfeature $parsedfeature the parsed feature to execute.* @return bool true if all steps were executed successfully.*/public function execute(parsedfeature $parsedfeature): bool {if (!$parsedfeature->is_valid()) {return false;}$result = true;$steps = $parsedfeature->get_all_steps();foreach ($steps as $step) {$result = $step->execute() && $result;}return $result;}}