1 |
efrain |
1 |
<?php
|
|
|
2 |
// This file is part of Moodle - http://moodle.org/
|
|
|
3 |
//
|
|
|
4 |
// Moodle is free software: you can redistribute it and/or modify
|
|
|
5 |
// it under the terms of the GNU General Public License as published by
|
|
|
6 |
// the Free Software Foundation, either version 3 of the License, or
|
|
|
7 |
// (at your option) any later version.
|
|
|
8 |
//
|
|
|
9 |
// Moodle is distributed in the hope that it will be useful,
|
|
|
10 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
11 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
12 |
// GNU General Public License for more details.
|
|
|
13 |
//
|
|
|
14 |
// You should have received a copy of the GNU General Public License
|
|
|
15 |
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
16 |
|
|
|
17 |
/**
|
|
|
18 |
* Data generators for acceptance testing.
|
|
|
19 |
*
|
|
|
20 |
* @package core
|
|
|
21 |
* @category test
|
|
|
22 |
* @copyright 2012 David Monllaó
|
|
|
23 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
24 |
*/
|
|
|
25 |
|
|
|
26 |
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
|
|
27 |
|
|
|
28 |
require_once(__DIR__ . '/../../behat/behat_base.php');
|
|
|
29 |
|
|
|
30 |
use Behat\Gherkin\Node\TableNode as TableNode;
|
|
|
31 |
use Behat\Behat\Tester\Exception\PendingException as PendingException;
|
|
|
32 |
|
|
|
33 |
/**
|
|
|
34 |
* Class to set up quickly a Given environment.
|
|
|
35 |
*
|
|
|
36 |
* The entry point is the Behat steps:
|
|
|
37 |
* the following "entity types" exist:
|
|
|
38 |
* | test | data |
|
|
|
39 |
*
|
|
|
40 |
* Entity type will either look like "users" or "activities" for core entities, or
|
|
|
41 |
* "mod_forum > subscription" or "core_message > message" for entities belonging
|
|
|
42 |
* to components.
|
|
|
43 |
*
|
|
|
44 |
* Generally, you only need to specify properties relevant to your test,
|
|
|
45 |
* and everything else gets set to sensible defaults.
|
|
|
46 |
*
|
|
|
47 |
* The actual generation of entities is done by {@link behat_generator_base}.
|
|
|
48 |
* There is one subclass for each component, e.g. {@link behat_core_generator}
|
|
|
49 |
* or {@link behat_mod_quiz_generator}. To see the types of entity
|
|
|
50 |
* that can be created for each component, look at the arrays returned
|
|
|
51 |
* by the get_creatable_entities() method in each class.
|
|
|
52 |
*
|
|
|
53 |
* @package core
|
|
|
54 |
* @category test
|
|
|
55 |
* @copyright 2012 David Monllaó
|
|
|
56 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
57 |
*/
|
|
|
58 |
class behat_data_generators extends behat_base {
|
|
|
59 |
|
|
|
60 |
/**
|
|
|
61 |
* Convert legacy entity names to the new component-specific form.
|
|
|
62 |
*
|
|
|
63 |
* In the past, there was no support for plugins, and everything that
|
|
|
64 |
* could be created was handled by the core generator. Now, we can
|
|
|
65 |
* support plugins, and so some thing should probably be moved.
|
|
|
66 |
*
|
|
|
67 |
* For example, in the future we should probably add
|
|
|
68 |
* 'message contacts' => 'core_message > contact'] to
|
|
|
69 |
* this array, and move generation of message contact
|
|
|
70 |
* from core to core_message.
|
|
|
71 |
*
|
|
|
72 |
* @var array old entity type => new entity type.
|
|
|
73 |
*/
|
|
|
74 |
protected $movedentitytypes = [
|
|
|
75 |
];
|
|
|
76 |
|
|
|
77 |
/**
|
|
|
78 |
* Creates the specified elements.
|
|
|
79 |
*
|
|
|
80 |
* See the class comment for an overview.
|
|
|
81 |
*
|
|
|
82 |
* @Given /^the following "(?P<element_string>(?:[^"]|\\")*)" exist:$/
|
|
|
83 |
*
|
|
|
84 |
* @param string $entitytype The name of the type entity to add
|
|
|
85 |
* @param TableNode $data
|
|
|
86 |
*/
|
|
|
87 |
public function the_following_entities_exist($entitytype, TableNode $data) {
|
|
|
88 |
if (isset($this->movedentitytypes[$entitytype])) {
|
|
|
89 |
$entitytype = $this->movedentitytypes[$entitytype];
|
|
|
90 |
}
|
|
|
91 |
list($component, $entity) = $this->parse_entity_type($entitytype);
|
|
|
92 |
$this->get_instance_for_component($component)->generate_items($entity, $data);
|
|
|
93 |
}
|
|
|
94 |
|
|
|
95 |
/**
|
|
|
96 |
* Create multiple entities of one entity type.
|
|
|
97 |
*
|
|
|
98 |
* @Given :count :entitytype exist with the following data:
|
|
|
99 |
*
|
|
|
100 |
* @param string $entitytype The name of the type entity to add
|
|
|
101 |
* @param int $count
|
|
|
102 |
* @param TableNode $data
|
|
|
103 |
*/
|
|
|
104 |
public function the_following_repeated_entities_exist(string $entitytype, int $count, TableNode $data): void {
|
|
|
105 |
$rows = $data->getRowsHash();
|
|
|
106 |
|
|
|
107 |
$tabledata = [array_keys($rows)];
|
|
|
108 |
for ($current = 1; $current < $count + 1; $current++) {
|
|
|
109 |
$rowdata = [];
|
|
|
110 |
foreach ($rows as $fieldname => $fieldtemplate) {
|
|
|
111 |
$rowdata[$fieldname] = str_replace('[count]', $current, $fieldtemplate);
|
|
|
112 |
}
|
|
|
113 |
$tabledata[] = $rowdata;
|
|
|
114 |
}
|
|
|
115 |
|
|
|
116 |
if (isset($this->movedentitytypes[$entitytype])) {
|
|
|
117 |
$entitytype = $this->movedentitytypes[$entitytype];
|
|
|
118 |
}
|
|
|
119 |
list($component, $entity) = $this->parse_entity_type($entitytype);
|
|
|
120 |
$this->get_instance_for_component($component)->generate_items($entity, new TableNode($tabledata), false);
|
|
|
121 |
}
|
|
|
122 |
|
|
|
123 |
/**
|
|
|
124 |
* Creates the specified (singular) element.
|
|
|
125 |
*
|
|
|
126 |
* See the class comment for an overview.
|
|
|
127 |
*
|
|
|
128 |
* @Given the following :entitytype exists:
|
|
|
129 |
*
|
|
|
130 |
* @param string $entitytype The name of the type entity to add
|
|
|
131 |
* @param TableNode $data
|
|
|
132 |
*/
|
|
|
133 |
public function the_following_entity_exists($entitytype, TableNode $data) {
|
|
|
134 |
if (isset($this->movedentitytypes[$entitytype])) {
|
|
|
135 |
$entitytype = $this->movedentitytypes[$entitytype];
|
|
|
136 |
}
|
|
|
137 |
list($component, $entity) = $this->parse_entity_type($entitytype);
|
|
|
138 |
$this->get_instance_for_component($component)->generate_items($entity, $data, true);
|
|
|
139 |
}
|
|
|
140 |
|
|
|
141 |
/**
|
|
|
142 |
* Parse a full entity type like 'users' or 'mod_forum > subscription'.
|
|
|
143 |
*
|
|
|
144 |
* E.g. parsing 'course' gives ['core', 'course'] and
|
|
|
145 |
* parsing 'core_message > message' gives ['core_message', 'message'].
|
|
|
146 |
*
|
|
|
147 |
* @param string $entitytype the entity type
|
|
|
148 |
* @return string[] with two elements, component and entity type.
|
|
|
149 |
*/
|
|
|
150 |
protected function parse_entity_type(string $entitytype): array {
|
|
|
151 |
$dividercount = substr_count($entitytype, ' > ');
|
|
|
152 |
if ($dividercount === 0) {
|
|
|
153 |
return ['core', $entitytype];
|
|
|
154 |
} else if ($dividercount === 1) {
|
|
|
155 |
list($component, $type) = explode(' > ', $entitytype);
|
|
|
156 |
if ($component === 'core') {
|
|
|
157 |
throw new coding_exception('Do not specify the component "core > ..." for entity types.');
|
|
|
158 |
}
|
|
|
159 |
return [$component, $type];
|
|
|
160 |
} else {
|
|
|
161 |
throw new coding_exception('The entity type must be in the form ' .
|
|
|
162 |
'"{entity-type}" for core entities, or "{component} > {entity-type}" ' .
|
|
|
163 |
'for entities belonging to other components. ' .
|
|
|
164 |
'For example "users" or "mod_forum > subscriptions".');
|
|
|
165 |
}
|
|
|
166 |
}
|
|
|
167 |
|
|
|
168 |
/**
|
|
|
169 |
* Get an instance of the appropriate subclass of this class for a given component.
|
|
|
170 |
*
|
|
|
171 |
* @param string $component The name of the component to generate entities for.
|
|
|
172 |
* @return behat_generator_base the subclass of this class for the requested component.
|
|
|
173 |
*/
|
|
|
174 |
protected function get_instance_for_component(string $component): behat_generator_base {
|
|
|
175 |
global $CFG;
|
|
|
176 |
|
|
|
177 |
// Ensure the generator class is loaded.
|
|
|
178 |
require_once($CFG->libdir . '/behat/classes/behat_generator_base.php');
|
|
|
179 |
if ($component === 'core') {
|
|
|
180 |
$lib = $CFG->libdir . '/behat/classes/behat_core_generator.php';
|
|
|
181 |
} else {
|
|
|
182 |
$dir = core_component::get_component_directory($component);
|
|
|
183 |
$lib = $dir . '/tests/generator/behat_' . $component . '_generator.php';
|
|
|
184 |
if (!$dir || !is_readable($lib)) {
|
|
|
185 |
throw new coding_exception("Component {$component} does not support " .
|
|
|
186 |
"behat generators yet. Missing {$lib}.");
|
|
|
187 |
}
|
|
|
188 |
}
|
|
|
189 |
require_once($lib);
|
|
|
190 |
|
|
|
191 |
// Create an instance.
|
|
|
192 |
$componentclass = "behat_{$component}_generator";
|
|
|
193 |
if (!class_exists($componentclass)) {
|
|
|
194 |
throw new PendingException($component .
|
|
|
195 |
' does not yet support the Behat data generator mechanism. Class ' .
|
|
|
196 |
$componentclass . ' not found in file ' . $lib . '.');
|
|
|
197 |
}
|
|
|
198 |
$instance = new $componentclass($component);
|
|
|
199 |
return $instance;
|
|
|
200 |
}
|
|
|
201 |
|
|
|
202 |
/**
|
|
|
203 |
* Get all entities that can be created in all components using the_following_entities_exist()
|
|
|
204 |
*
|
|
|
205 |
* @return array
|
|
|
206 |
* @throws coding_exception
|
|
|
207 |
*/
|
|
|
208 |
public function get_all_entities(): array {
|
|
|
209 |
global $CFG;
|
|
|
210 |
// Ensure the generator class is loaded.
|
|
|
211 |
require_once($CFG->libdir . '/behat/classes/behat_generator_base.php');
|
|
|
212 |
$componenttypes = core_component::get_component_list();
|
|
|
213 |
$coregenerator = $this->get_instance_for_component('core');
|
|
|
214 |
$pluginswithentities = ['core' => array_keys($coregenerator->get_available_generators())];
|
|
|
215 |
foreach ($componenttypes as $components) {
|
|
|
216 |
foreach ($components as $component => $componentdir) {
|
|
|
217 |
try {
|
|
|
218 |
$plugingenerator = $this->get_instance_for_component($component);
|
|
|
219 |
$entities = array_keys($plugingenerator->get_available_generators());
|
|
|
220 |
if (!empty($entities)) {
|
|
|
221 |
$pluginswithentities[$component] = $entities;
|
|
|
222 |
}
|
|
|
223 |
} catch (Exception $e) {
|
|
|
224 |
// The component has no generator, skip it.
|
|
|
225 |
continue;
|
|
|
226 |
}
|
|
|
227 |
}
|
|
|
228 |
}
|
|
|
229 |
return $pluginswithentities;
|
|
|
230 |
}
|
|
|
231 |
|
|
|
232 |
/**
|
|
|
233 |
* Get the required fields for a specific creatable entity.
|
|
|
234 |
*
|
|
|
235 |
* @param string $entitytype
|
|
|
236 |
* @return mixed
|
|
|
237 |
* @throws coding_exception
|
|
|
238 |
*/
|
|
|
239 |
public function get_entity(string $entitytype): array {
|
|
|
240 |
[$component, $entity] = $this->parse_entity_type($entitytype);
|
|
|
241 |
$generator = $this->get_instance_for_component($component);
|
|
|
242 |
$entities = $generator->get_available_generators();
|
|
|
243 |
if (!array_key_exists($entity, $entities)) {
|
|
|
244 |
throw new coding_exception('No generator for ' . $entity . ' in component ' . $component);
|
|
|
245 |
}
|
|
|
246 |
return $entities[$entity];
|
|
|
247 |
}
|
|
|
248 |
}
|