MDL-37659 behat: Adding data generator definition
[moodle.git] / lib / tests / behat / behat_data_generators.php
CommitLineData
f0200d14
DM
1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * Data generators for acceptance testing.
20 *
21 * @package core
22 * @category test
23 * @copyright 2012 David MonllaĆ³
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 */
26
27// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
28
29require_once(__DIR__ . '/../../behat/behat_base.php');
30require_once(__DIR__ . '/../../testing/generator/lib.php');
31
32use Behat\Gherkin\Node\TableNode as TableNode;
33use Behat\Behat\Exception\PendingException as PendingException;
34
35/**
36 * Class to set up quickly a Given environment.
37 *
38 * Acceptance tests are block-boxed, so this steps definitions should only
39 * be used to set up the test environment as we are not replicating user steps.
40 *
41 * All data generators should be in lib/testing/generator/* and shared between phpunit
42 * and behat and they should be called from here, if possible using the standard
43 * 'create_$elementname($options)' and if not possible (data generators arguments will not be
44 * always the same) create an adapter 'adapt_$elementname($options)' that uses the data generator.
45 *
46 * @todo If the available elements list grows too much this class must be split into smaller pieces
47 * @package core
48 * @category test
49 * @copyright 2012 David MonllaĆ³
50 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
51 */
52class behat_data_generators extends behat_base {
53
54 protected $datagenerator;
55
56 /**
57 * Each element specifies:
58 * - The data generator sufix used.
59 * - The required fields.
60 * - The mapping between other elements references and database field names.
61 * @var array
62 */
63 protected static $elements = array(
64 'users' => array(
65 'datagenerator' => 'user',
66 'required' => array('username')
67 ),
68 'categories' => array(
69 'datagenerator' => 'category',
70 'required' => array('idnumber'),
71 'switchids' => array('category' => 'parent')
72 ),
73 'courses' => array(
74 'datagenerator' => 'course',
75 'required' => array('shortname'),
76 'switchids' => array('category' => 'category')
77 ),
78 'groups' => array(
79 'datagenerator' => 'group',
80 'required' => array('idnumber', 'course'),
81 'switchids' => array('course' => 'courseid')
82 ),
83 'groupings' => array(
84 'datagenerator' => 'grouping',
85 'required' => array('idnumber', 'course'),
86 'switchids' => array('course' => 'courseid')
87 ),
88 'course enrolments' => array(
89 'datagenerator' => 'enrol_user',
90 'required' => array('user', 'course', 'role'),
91 'switchids' => array('user' => 'userid', 'course' => 'courseid', 'role' => 'roleid')
92
93 ),
94 'group members' => array(
95 'datagenerator' => 'group_member',
96 'required' => array('user', 'group'),
97 'switchids' => array('user' => 'userid', 'group' => 'groupid')
98 ),
99 'grouping groups' => array(
100 'datagenerator' => 'grouping_group',
101 'required' => array('grouping', 'group'),
102 'switchids' => array('grouping' => 'groupingid', 'group' => 'groupid')
103 )
104 );
105
106 /**
107 * Creates the specified element. More info about available elements in http://docs.moodle.org/dev/Acceptance_testing#Fixtures.
108 *
109 * @Given /^the following "(?P<element_string>(?:[^"]|\\")*)" exists:$/
110 *
111 * @throws Exception
112 * @throws PendingException
113 * @param string $elementname The name of the entity to add
114 * @param TableNode $data
115 */
116 public function the_following_exists($elementname, TableNode $data) {
117
118 if (empty(self::$elements[$elementname])) {
119 throw new PendingException($elementname . ' data generator is not implemented');
120 }
121
122 $this->datagenerator = testing_util::get_data_generator();
123
124 $elementdatagenerator = self::$elements[$elementname]['datagenerator'];
125 $requiredfields = self::$elements[$elementname]['required'];
126 if (!empty(self::$elements[$elementname]['switchids'])) {
127 $switchids = self::$elements[$elementname]['switchids'];
128 }
129
130 foreach ($data->getHash() as $elementdata) {
131
132 // Check if all the required fields are there.
133 foreach ($requiredfields as $requiredfield) {
134 if (!isset($elementdata[$requiredfield])) {
135 throw new Exception($elementname . ' requires the field ' . $requiredfield . ' to be specified');
136 }
137 }
138
139 // Switch from human-friendly references to ids.
140 if (isset($switchids)) {
141 foreach ($switchids as $element => $field) {
142 $methodname = 'get_' . $element . '_id';
143
144 // Not all the switch fields are required, default vars will be assigned by data generators.
145 if (isset($elementdata[$element])) {
146 // Temp $id var to avoid problems when $element == $field.
147 $id = $this->{$methodname}($elementdata[$element]);
148 unset($elementdata[$element]);
149 $elementdata[$field] = $id;
150 }
151 }
152 }
153
154 // Preprocess the entities that requires a special treatment.
155 if (method_exists($this, 'preprocess_' . $elementdatagenerator)) {
156 $elementdata = $this->{'preprocess_' . $elementdatagenerator}($elementdata);
157 }
158
159 // Creates element.
160 $methodname = 'create_' . $elementdatagenerator;
161 if (method_exists($this->datagenerator, $methodname)) {
162 // Using data generators directly.
163 $this->datagenerator->{$methodname}($elementdata);
164
165 } else if (method_exists($this, 'adapt_' . $elementdatagenerator)) {
166 // Using an adaptor to use the data generator.
167 $this->{'adapt_' . $elementdatagenerator}($elementdata);
168 } else {
169 throw new PendingException($elementname . ' data generator is not implemented');
170 }
171 }
172
173 }
174
175 /**
176 * If password is not set it uses the username.
177 * @param array $data
178 * @return array
179 */
180 protected function preprocess_user($data) {
181 if (!isset($data['password'])) {
182 $data['password'] = $data['username'];
183 }
184 return $data;
185 }
186
187
188 /**
189 * Adapter to enrol_user() data generator.
190 * @throws Exception
191 * @param mixed $data
192 * @return void
193 */
194 protected function adapt_enrol_user($data) {
195
196 if (empty($data['roleid'])) {
197 throw new Exception('\'course enrolments\' requires the field \'role\' to be specified');
198 }
199
200 if (!isset($data['userid'])) {
201 throw new Exception('\'course enrolments\' requires the field \'user\' to be specified');
202 }
203
204 if (!isset($data['courseid'])) {
205 throw new Exception('\'course enrolments\' requires the field \'course\' to be specified');
206 }
207
208 if (!isset($data['enrol'])) {
209 $data['enrol'] = 'manual';
210 }
211
212 $this->datagenerator->enrol_user($data['userid'], $data['courseid'], $data['roleid'], $data['enrol']);
213 }
214
215 /**
216 * Gets the user id from it's username.
217 * @throws Exception
218 * @param string $idnumber
219 * @return int
220 */
221 protected function get_user_id($username) {
222 global $DB;
223
224 if (!$id = $DB->get_field('user', 'id', array('username' => $username))) {
225 throw new Exception('The specified user with username "' . $username . '" does not exists');
226 }
227 return $id;
228 }
229
230 /**
231 * Gets the role id from it's shortname.
232 * @throws Exception
233 * @param string $idnumber
234 * @return int
235 */
236 protected function get_role_id($roleshortname) {
237 global $DB;
238
239 if (!$id = $DB->get_field('role', 'id', array('shortname' => $roleshortname))) {
240 throw new Exception('The specified role with shortname"' . $roleshortname . '" does not exists');
241 }
242
243 return $id;
244 }
245
246 /**
247 * Gets the category id from it's idnumber.
248 * @throws Exception
249 * @param string $idnumber
250 * @return int
251 */
252 protected function get_category_id($idnumber) {
253 global $DB;
254
255 // If no category was specified use the data generator one.
256 if ($idnumber == false) {
257 return null;
258 }
259
260 if (!$id = $DB->get_field('course_categories', 'id', array('idnumber' => $idnumber))) {
261 throw new Exception('The specified category with idnumber "' . $idnumber . '" does not exists');
262 }
263
264 return $id;
265 }
266
267 /**
268 * Gets the course id from it's shortname.
269 * @throws Exception
270 * @param string $shortname
271 * @return int
272 */
273 protected function get_course_id($shortname) {
274 global $DB;
275
276 if (!$id = $DB->get_field('course', 'id', array('shortname' => $shortname))) {
277 throw new Exception('The specified course with shortname"' . $shortname . '" does not exists');
278 }
279 return $id;
280 }
281
282 /**
283 * Gets the group id from it's idnumber.
284 * @throws Exception
285 * @param string $idnumber
286 * @return int
287 */
288 protected function get_group_id($idnumber) {
289 global $DB;
290
291 if (!$id = $DB->get_field('groups', 'id', array('idnumber' => $idnumber))) {
292 throw new Exception('The specified group with idnumber "' . $idnumber . '" does not exists');
293 }
294 return $id;
295 }
296
297 /**
298 * Gets the grouping id from it's idnumber.
299 * @throws Exception
300 * @param string $idnumber
301 * @return int
302 */
303 protected function get_grouping_id($idnumber) {
304 global $DB;
305
306 if (!$id = $DB->get_field('groupings', 'id', array('idnumber' => $idnumber))) {
307 throw new Exception('The specified grouping with idnumber "' . $idnumber . '" does not exists');
308 }
309 return $id;
310 }
311}