Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 1441
Línea 14... Línea 14...
14
// You should have received a copy of the GNU General Public License
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
15
// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
Línea 16... Línea 16...
16
 
16
 
Línea -... Línea 17...
-
 
17
namespace tool_generator\local\testscenario;
17
namespace tool_generator\local\testscenario;
18
 
-
 
19
use behat_admin;
-
 
20
use behat_data_generators;
-
 
21
use behat_base;
-
 
22
use behat_course;
-
 
23
use behat_general;
18
 
24
use behat_user;
19
use behat_data_generators;
25
use core\attribute_helper;
20
use Behat\Gherkin\Parser;
26
use Behat\Gherkin\Parser;
-
 
27
use Behat\Gherkin\Lexer;
21
use Behat\Gherkin\Lexer;
28
use Behat\Gherkin\Keywords\ArrayKeywords;
22
use Behat\Gherkin\Keywords\ArrayKeywords;
29
use Behat\Gherkin\Node\OutlineNode;
-
 
30
use ReflectionClass;
Línea 23... Línea 31...
23
use ReflectionClass;
31
use ReflectionMethod;
24
use ReflectionMethod;
32
use stdClass;
25
 
33
 
26
/**
34
/**
Línea 43... Línea 51...
43
     */
51
     */
44
    public function init() {
52
    public function init() {
45
        $this->include_composer_libraries();
53
        $this->include_composer_libraries();
46
        $this->include_behat_libraries();
54
        $this->include_behat_libraries();
47
        $this->load_generator();
55
        $this->load_generator();
-
 
56
        $this->load_cleanup();
48
    }
57
    }
Línea 49... Línea 58...
49
 
58
 
50
    /**
59
    /**
51
     * Include composer autload.
60
     * Include composer autload.
Línea 65... Línea 74...
65
    public function include_behat_libraries() {
74
    public function include_behat_libraries() {
66
        global $CFG;
75
        global $CFG;
67
        if (!class_exists('Behat\Gherkin\Lexer')) {
76
        if (!class_exists('Behat\Gherkin\Lexer')) {
68
            throw new \moodle_exception('Missing behat classes.');
77
            throw new \moodle_exception('Missing behat classes.');
69
        }
78
        }
-
 
79
 
-
 
80
        // Behat constant.
-
 
81
        if (!defined('BEHAT_TEST')) {
-
 
82
            define('BEHAT_TEST', 1);
-
 
83
        }
-
 
84
 
70
        // Behat utilities.
85
        // Behat utilities.
71
        require_once($CFG->libdir . '/behat/classes/util.php');
86
        require_once($CFG->libdir . '/behat/classes/util.php');
72
        require_once($CFG->libdir . '/behat/classes/behat_command.php');
87
        require_once($CFG->libdir . '/behat/classes/behat_command.php');
73
        require_once($CFG->libdir . '/behat/behat_base.php');
88
        require_once($CFG->libdir . '/behat/behat_base.php');
74
        require_once("{$CFG->libdir}/tests/behat/behat_data_generators.php");
89
        require_once("{$CFG->libdir}/tests/behat/behat_data_generators.php");
-
 
90
        require_once("{$CFG->dirroot}/admin/tests/behat/behat_admin.php");
-
 
91
        require_once("{$CFG->dirroot}/course/lib.php");
-
 
92
        require_once("{$CFG->dirroot}/course/tests/behat/behat_course.php");
-
 
93
        require_once("{$CFG->dirroot}/lib/tests/behat/behat_general.php");
-
 
94
        require_once("{$CFG->dirroot}/user/tests/behat/behat_user.php");
75
        return true;
95
        return true;
76
    }
96
    }
Línea 77... Línea 97...
77
 
97
 
78
    /**
98
    /**
79
     * Load all generators.
99
     * Load all generators.
80
     */
100
     */
81
    private function load_generator() {
101
    private function load_generator() {
82
        $this->generator = new behat_data_generators();
102
        $this->generator = new behat_data_generators();
-
 
103
        $this->validsteps = $this->scan_generator($this->generator);
-
 
104
 
-
 
105
        // Add some extra steps from other classes.
-
 
106
        $extrasteps = [
-
 
107
            [behat_admin::class, 'the_following_config_values_are_set_as_admin'],
-
 
108
            [behat_general::class, 'i_enable_plugin'],
-
 
109
            [behat_general::class, 'i_disable_plugin'],
-
 
110
        ];
-
 
111
        foreach ($extrasteps as $callable) {
-
 
112
            $classname = $callable[0];
-
 
113
            $method = $callable[1];
-
 
114
            $extra = $this->scan_method(
-
 
115
                new ReflectionMethod($classname, $method),
-
 
116
                new $classname(),
-
 
117
            );
-
 
118
            if ($extra) {
-
 
119
                $this->validsteps[$extra->given] = $extra;
-
 
120
            }
-
 
121
        }
-
 
122
    }
-
 
123
 
-
 
124
    /**
-
 
125
     * Load all cleanup steps.
-
 
126
     */
-
 
127
    private function load_cleanup() {
-
 
128
        $extra = $this->scan_method(
-
 
129
            new ReflectionMethod(behat_course::class, 'the_course_is_deleted'),
-
 
130
            new behat_course(),
-
 
131
        );
-
 
132
        if ($extra) {
-
 
133
            $this->validsteps[$extra->given] = $extra;
-
 
134
        }
-
 
135
 
-
 
136
        $extra = $this->scan_method(
-
 
137
            new ReflectionMethod(behat_user::class, 'the_user_is_deleted'),
-
 
138
            new behat_user(),
-
 
139
        );
-
 
140
        if ($extra) {
-
 
141
            $this->validsteps[$extra->given] = $extra;
-
 
142
        }
-
 
143
    }
-
 
144
 
-
 
145
    /**
-
 
146
     * Get all valid steps.
-
 
147
     * @return array the valid steps.
-
 
148
     */
-
 
149
    public function get_valid_steps(): array {
83
        $this->validsteps = $this->scan_generator($this->generator);
150
        return array_values($this->validsteps);
Línea 84... Línea 151...
84
    }
151
    }
85
 
152
 
86
    /**
153
    /**
Línea 91... Línea 158...
91
    private function scan_generator(behat_data_generators $generator): array {
158
    private function scan_generator(behat_data_generators $generator): array {
92
        $result = [];
159
        $result = [];
93
        $class = new ReflectionClass($generator);
160
        $class = new ReflectionClass($generator);
94
        $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);
161
        $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);
95
        foreach ($methods as $method) {
162
        foreach ($methods as $method) {
96
            $given = $this->get_method_given($method);
163
            $scan = $this->scan_method($method, $generator);
97
            if ($given) {
164
            if ($scan) {
98
                $result[$given] = $method->getName();
165
                $result[$scan->given] = $scan;
99
            }
166
            }
100
        }
167
        }
101
        return $result;
168
        return $result;
102
    }
169
    }
Línea 103... Línea 170...
103
 
170
 
-
 
171
    /**
-
 
172
     * Scan a method to get the given expression tag.
-
 
173
     * @param ReflectionMethod $method the method to scan.
-
 
174
     * @param behat_base $behatclass the behat class instance to use.
-
 
175
     * @return stdClass|null the method data (given, name, class).
-
 
176
     */
-
 
177
    private function scan_method(ReflectionMethod $method, behat_base $behatclass): ?stdClass {
-
 
178
        $given = $this->get_method_given($method);
-
 
179
        if (!$given) {
-
 
180
            return null;
-
 
181
        }
-
 
182
        $result = (object)[
-
 
183
            'given' => $given,
-
 
184
            'name' => $method->getName(),
-
 
185
            'generator' => $behatclass,
-
 
186
            'example' => null,
-
 
187
        ];
-
 
188
        $reference = $method->getDeclaringClass()->getName() . '::' . $method->getName();
-
 
189
        if ($attribute = attribute_helper::instance($reference, \core\attribute\example::class)) {
-
 
190
            $result->example = (string) $attribute->example;
-
 
191
        }
-
 
192
        return $result;
-
 
193
    }
-
 
194
 
104
    /**
195
    /**
105
     * Get the given expression tag of a method.
196
     * Get the given expression tag of a method.
106
     *
197
     *
107
     * @param ReflectionMethod $method the method to get the given expression tag.
198
     * @param ReflectionMethod $method the method to get the given expression tag.
108
     * @return string|null the given expression tag or null if not found.
199
     * @return string|null the given expression tag or null if not found.
Línea 125... Línea 216...
125
     * Parse a feature file.
216
     * Parse a feature file.
126
     * @param string $content the feature file content.
217
     * @param string $content the feature file content.
127
     * @return parsedfeature
218
     * @return parsedfeature
128
     */
219
     */
129
    public function parse_feature(string $content): parsedfeature {
220
    public function parse_feature(string $content): parsedfeature {
-
 
221
        return $this->parse_selected_scenarios($content);
-
 
222
    }
-
 
223
 
-
 
224
    /**
-
 
225
     * Parse all feature file scenarios.
-
 
226
     *
-
 
227
     * Note: if no filter is passed, it will execute only the scenarios that are not tagged.
-
 
228
     *
-
 
229
     * @param string $content the feature file content.
-
 
230
     * @param string $filtertag the tag to filter the scenarios.
-
 
231
     * @return parsedfeature
-
 
232
     */
-
 
233
    private function parse_selected_scenarios(string $content, ?string $filtertag = null): parsedfeature {
130
        $result = new parsedfeature();
234
        $result = new parsedfeature();
Línea 131... Línea 235...
131
 
235
 
132
        $parser = $this->get_parser();
236
        $parser = $this->get_parser();
Línea 136... Línea 240...
136
        // In the future the background can be used to define clean up steps (when clean up methods
240
        // In the future the background can be used to define clean up steps (when clean up methods
137
        // are implemented).
241
        // are implemented).
138
        if ($feature->hasScenarios()) {
242
        if ($feature->hasScenarios()) {
139
            $scenarios = $feature->getScenarios();
243
            $scenarios = $feature->getScenarios();
140
            foreach ($scenarios as $scenario) {
244
            foreach ($scenarios as $scenario) {
-
 
245
                // By default, we only execute scenaros that are not tagged.
-
 
246
                if (empty($filtertag) && !empty($scenario->getTags())) {
-
 
247
                    continue;
-
 
248
                }
-
 
249
                if ($filtertag && !in_array($filtertag, $scenario->getTags())) {
-
 
250
                    continue;
-
 
251
                }
141
                if ($scenario->getNodeType() == 'Outline') {
252
                if ($scenario->getNodeType() == 'Outline') {
142
                    $result->add_scenario($scenario->getNodeType(), $scenario->getTitle());
253
                    $this->parse_scenario_outline($scenario, $result);
143
                    $result->add_error(get_string('testscenario_outline', 'tool_generator'));
-
 
144
                    continue;
254
                    continue;
145
                }
255
                }
146
                $result->add_scenario($scenario->getNodeType(), $scenario->getTitle());
256
                $result->add_scenario($scenario->getNodeType(), $scenario->getTitle());
147
                $steps = $scenario->getSteps();
257
                $steps = $scenario->getSteps();
148
                foreach ($steps as $step) {
258
                foreach ($steps as $step) {
149
                    $result->add_step(new steprunner($this->generator, $this->validsteps, $step));
259
                    $result->add_step(new steprunner(null, $this->validsteps, $step));
150
                }
260
                }
151
            }
261
            }
152
        }
262
        }
153
        return $result;
263
        return $result;
154
    }
264
    }
Línea 155... Línea 265...
155
 
265
 
-
 
266
    /**
-
 
267
     * Parse a feature file using only the scenarios with cleanup tag.
-
 
268
     * @param string $content the feature file content.
-
 
269
     * @return parsedfeature
-
 
270
     */
-
 
271
    public function parse_cleanup(string $content): parsedfeature {
-
 
272
        return $this->parse_selected_scenarios($content, 'cleanup');
-
 
273
    }
-
 
274
 
-
 
275
    /**
-
 
276
     * Parse a scenario outline.
-
 
277
     * @param OutlineNode $scenario the scenario outline to parse.
-
 
278
     * @param parsedfeature $result the parsed feature to add the scenario.
-
 
279
     */
-
 
280
    private function parse_scenario_outline(OutlineNode $scenario, parsedfeature $result) {
-
 
281
        $count = 1;
-
 
282
        foreach ($scenario->getExamples() as $example) {
-
 
283
            $result->add_scenario($example->getNodeType(), $example->getOutlineTitle() . " ($count)");
-
 
284
            $steps = $example->getSteps();
-
 
285
            foreach ($steps as $step) {
-
 
286
                $result->add_step(new steprunner(null, $this->validsteps, $step));
-
 
287
            }
-
 
288
            $count++;
-
 
289
        }
-
 
290
    }
-
 
291
 
156
    /**
292
    /**
157
     * Get the parser.
293
     * Get the parser.
158
     * @return Parser
294
     * @return Parser
159
     */
295
     */
160
    private function get_parser(): Parser {
296
    private function get_parser(): Parser {
161
        $keywords = new ArrayKeywords([
297
        $keywords = new ArrayKeywords([
162
            'en' => [
298
            'en' => [
163
                'feature' => 'Feature',
-
 
164
                // If in the future we have clean up steps, background will be renamed to "Clean up".
299
                'feature' => 'Feature',
165
                'background' => 'Background',
300
                'background' => 'Background',
166
                'scenario' => 'Scenario',
301
                'scenario' => 'Scenario',
167
                'scenario_outline' => 'Scenario Outline|Scenario Template',
302
                'scenario_outline' => 'Scenario Outline|Scenario Template',
168
                'examples' => 'Examples|Scenarios',
303
                'examples' => 'Examples|Scenarios',