NOBUG: Fixed file access permissions
[moodle.git] / mod / quiz / tests / local_structure_slot_random_test.php
CommitLineData
d62793fd
SR
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 * Unit tests for the {@link \mod_quiz\local\structure\slot_random} class.
19 *
20 * @package mod_quiz
21 * @category test
22 * @copyright 2018 Shamim Rezaie <shamim@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26defined('MOODLE_INTERNAL') || die();
27
28/**
29 * Class mod_quiz_local_structure_slot_random_test
30 * Class for tests related to the {@link \mod_quiz\local\structure\slot_random} class.
31 *
32 * @copyright 2018 Shamim Rezaie <shamim@moodle.com>
33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34 */
35class mod_quiz_local_structure_slot_random_test extends advanced_testcase {
36 /**
37 * Constructor test.
38 */
39 public function test_constructor() {
40 global $SITE;
41
42 $this->resetAfterTest();
43 $this->setAdminUser();
44
45 // Create a quiz.
46 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
47 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
48
49 // Create a question category in the system context.
50 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
51 $category = $questiongenerator->create_question_category();
52
53 // Create a random question without adding it to a quiz.
54 // We don't want to use quiz_add_random_questions because that itself, instantiates an object from the slot_random class.
55 $form = new stdClass();
56 $form->category = $category->id . ',' . $category->contextid;
57 $form->includesubcategories = true;
58 $form->fromtags = [];
59 $form->defaultmark = 1;
60 $form->hidden = 1;
61 $form->stamp = make_unique_id_code();
62 $question = new stdClass();
63 $question->qtype = 'random';
64 $question = question_bank::get_qtype('random')->save_question($question, $form);
65
66 $randomslotdata = new stdClass();
67 $randomslotdata->quizid = $quiz->id;
68 $randomslotdata->questionid = $question->id;
69 $randomslotdata->questioncategoryid = $category->id;
70 $randomslotdata->includingsubcategories = 1;
71 $randomslotdata->maxmark = 1;
72
73 $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
74
75 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
76 $rcp = $rc->getProperty('record');
77 $rcp->setAccessible(true);
78 $record = $rcp->getValue($randomslot);
79
80 $this->assertEquals($quiz->id, $record->quizid);
81 $this->assertEquals($question->id, $record->questionid);
82 $this->assertEquals($category->id, $record->questioncategoryid);
83 $this->assertEquals(1, $record->includingsubcategories);
84 $this->assertEquals(1, $record->maxmark);
85 }
86
87 public function test_get_quiz_quiz() {
88 global $SITE, $DB;
89
90 $this->resetAfterTest();
91 $this->setAdminUser();
92
93 // Create a quiz.
94 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
95 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
96
97 // Create a question category in the system context.
98 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
99 $category = $questiongenerator->create_question_category();
100
101 quiz_add_random_questions($quiz, 0, $category->id, 1, false);
102
103 // Get the random question's id. It is at the first slot.
104 $questionid = $DB->get_field('quiz_slots', 'questionid', array('quizid' => $quiz->id, 'slot' => 1));
105
106 $randomslotdata = new stdClass();
107 $randomslotdata->quizid = $quiz->id;
108 $randomslotdata->questionid = $questionid;
109 $randomslotdata->questioncategoryid = $category->id;
110 $randomslotdata->includingsubcategories = 1;
111 $randomslotdata->maxmark = 1;
112
113 $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
114
115 // The create_instance had injected an additional cmid propery to the quiz. Let's remove that.
116 unset($quiz->cmid);
117
118 $this->assertEquals($quiz, $randomslot->get_quiz());
119 }
120
121 public function test_set_quiz() {
122 global $SITE, $DB;
123
124 $this->resetAfterTest();
125 $this->setAdminUser();
126
127 // Create a quiz.
128 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
129 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
130
131 // Create a question category in the system context.
132 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
133 $category = $questiongenerator->create_question_category();
134
135 quiz_add_random_questions($quiz, 0, $category->id, 1, false);
136
137 // Get the random question's id. It is at the first slot.
138 $questionid = $DB->get_field('quiz_slots', 'questionid', array('quizid' => $quiz->id, 'slot' => 1));
139
140 $randomslotdata = new stdClass();
141 $randomslotdata->quizid = $quiz->id;
142 $randomslotdata->questionid = $questionid;
143 $randomslotdata->questioncategoryid = $category->id;
144 $randomslotdata->includingsubcategories = 1;
145 $randomslotdata->maxmark = 1;
146
147 $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
148
149 // The create_instance had injected an additional cmid propery to the quiz. Let's remove that.
150 unset($quiz->cmid);
151
152 $randomslot->set_quiz($quiz);
153
154 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
155 $rcp = $rc->getProperty('quiz');
156 $rcp->setAccessible(true);
157 $quizpropery = $rcp->getValue($randomslot);
158
159 $this->assertEquals($quiz, $quizpropery);
160 }
161
162 private function setup_for_test_tags($tagnames) {
163 global $SITE, $DB;
164
165 // Create a quiz.
166 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
167 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
168
169 // Create a question category in the system context.
170 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
171 $category = $questiongenerator->create_question_category();
172
173 quiz_add_random_questions($quiz, 0, $category->id, 1, false);
174
175 // Get the random question's id. It is at the first slot.
176 $questionid = $DB->get_field('quiz_slots', 'questionid', array('quizid' => $quiz->id, 'slot' => 1));
177
178 $randomslotdata = new stdClass();
179 $randomslotdata->quizid = $quiz->id;
180 $randomslotdata->questionid = $questionid;
181 $randomslotdata->questioncategoryid = $category->id;
182 $randomslotdata->includingsubcategories = 1;
183 $randomslotdata->maxmark = 1;
184
185 $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
186
187 // Create tags.
188 foreach ($tagnames as $tagname) {
189 $tagrecord = array(
190 'isstandard' => 1,
191 'flag' => 0,
192 'rawname' => $tagname,
193 'description' => $tagname . ' desc'
194 );
195 $tags[$tagname] = $this->getDataGenerator()->create_tag($tagrecord);
196 }
197
198 return array($randomslot, $tags);
199 }
200
201 public function test_set_tags() {
202 $this->resetAfterTest();
203 $this->setAdminUser();
204
205 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar']);
206 $randomslot->set_tags([$tags['foo'], $tags['bar']]);
207
208 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
209 $rcp = $rc->getProperty('tags');
210 $rcp->setAccessible(true);
211 $tagspropery = $rcp->getValue($randomslot);
212
213 $this->assertEquals([
214 $tags['foo']->id => $tags['foo'],
215 $tags['bar']->id => $tags['bar'],
216 ], $tagspropery);
217 }
218
219 public function test_set_tags_twice() {
220 $this->resetAfterTest();
221 $this->setAdminUser();
222
223 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
224
225 // Set tags for the first time.
226 $randomslot->set_tags([$tags['foo'], $tags['bar']]);
227 // Now set the tags again.
228 $randomslot->set_tags([$tags['baz']]);
229
230 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
231 $rcp = $rc->getProperty('tags');
232 $rcp->setAccessible(true);
233 $tagspropery = $rcp->getValue($randomslot);
234
235 $this->assertEquals([
236 $tags['baz']->id => $tags['baz'],
237 ], $tagspropery);
238 }
239
240 public function test_set_tags_duplicates() {
241 $this->resetAfterTest();
242 $this->setAdminUser();
243
244 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
245
246 $randomslot->set_tags([$tags['foo'], $tags['bar'], $tags['foo']]);
247
248 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
249 $rcp = $rc->getProperty('tags');
250 $rcp->setAccessible(true);
251 $tagspropery = $rcp->getValue($randomslot);
252
253 $this->assertEquals([
254 $tags['foo']->id => $tags['foo'],
255 $tags['bar']->id => $tags['bar'],
256 ], $tagspropery);
257 }
258
259 public function test_set_tags_by_id() {
260 $this->resetAfterTest();
261 $this->setAdminUser();
262
263 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
264
265 $randomslot->set_tags_by_id([$tags['foo']->id, $tags['bar']->id]);
266
267 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
268 $rcp = $rc->getProperty('tags');
269 $rcp->setAccessible(true);
270 $tagspropery = $rcp->getValue($randomslot);
271
272 // The set_tags_by_id function only retrieves id and name fields of the tag object.
273 $this->assertCount(2, $tagspropery);
274 $this->assertArrayHasKey($tags['foo']->id, $tagspropery);
275 $this->assertArrayHasKey($tags['bar']->id, $tagspropery);
276 $this->assertEquals(
277 (object)['id' => $tags['foo']->id, 'name' => $tags['foo']->name],
278 $tagspropery[$tags['foo']->id]->to_object()
279 );
280 $this->assertEquals(
281 (object)['id' => $tags['bar']->id, 'name' => $tags['bar']->name],
282 $tagspropery[$tags['bar']->id]->to_object()
283 );
284 }
285
286 public function test_set_tags_by_id_twice() {
287 $this->resetAfterTest();
288 $this->setAdminUser();
289
290 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
291
292 // Set tags for the first time.
293 $randomslot->set_tags_by_id([$tags['foo']->id, $tags['bar']->id]);
294 // Now set the tags again.
295 $randomslot->set_tags_by_id([$tags['baz']->id]);
296
297 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
298 $rcp = $rc->getProperty('tags');
299 $rcp->setAccessible(true);
300 $tagspropery = $rcp->getValue($randomslot);
301
302 // The set_tags_by_id function only retrieves id and name fields of the tag object.
303 $this->assertCount(1, $tagspropery);
304 $this->assertArrayHasKey($tags['baz']->id, $tagspropery);
305 $this->assertEquals(
306 (object)['id' => $tags['baz']->id, 'name' => $tags['baz']->name],
307 $tagspropery[$tags['baz']->id]->to_object()
308 );
309 }
310
311 public function test_set_tags_by_id_duplicates() {
312 $this->resetAfterTest();
313 $this->setAdminUser();
314
315 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
316
317 $randomslot->set_tags_by_id([$tags['foo']->id, $tags['bar']->id], $tags['foo']->id);
318
319 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
320 $rcp = $rc->getProperty('tags');
321 $rcp->setAccessible(true);
322 $tagspropery = $rcp->getValue($randomslot);
323
324 // The set_tags_by_id function only retrieves id and name fields of the tag object.
325 $this->assertCount(2, $tagspropery);
326 $this->assertArrayHasKey($tags['foo']->id, $tagspropery);
327 $this->assertArrayHasKey($tags['bar']->id, $tagspropery);
328 $this->assertEquals(
329 (object)['id' => $tags['foo']->id, 'name' => $tags['foo']->name],
330 $tagspropery[$tags['foo']->id]->to_object()
331 );
332 $this->assertEquals(
333 (object)['id' => $tags['bar']->id, 'name' => $tags['bar']->name],
334 $tagspropery[$tags['bar']->id]->to_object()
335 );
336 }
337
338 public function test_insert() {
339 global $SITE, $DB;
340
341 $this->resetAfterTest();
342 $this->setAdminUser();
343
344 // Create a quiz.
345 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
346 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
347
348 // Create a question category in the system context.
349 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
350 $category = $questiongenerator->create_question_category();
351
352 // Create a random question without adding it to a quiz.
353 $form = new stdClass();
354 $form->category = $category->id . ',' . $category->contextid;
355 $form->includesubcategories = true;
356 $form->fromtags = [];
357 $form->defaultmark = 1;
358 $form->hidden = 1;
359 $form->stamp = make_unique_id_code();
360 $question = new stdClass();
361 $question->qtype = 'random';
362 $question = question_bank::get_qtype('random')->save_question($question, $form);
363
364 // Prepare 2 tags.
365 $tagrecord = array(
366 'isstandard' => 1,
367 'flag' => 0,
368 'rawname' => 'foo',
369 'description' => 'foo desc'
370 );
371 $footag = $this->getDataGenerator()->create_tag($tagrecord);
372 $tagrecord = array(
373 'isstandard' => 1,
374 'flag' => 0,
375 'rawname' => 'bar',
376 'description' => 'bar desc'
377 );
378 $bartag = $this->getDataGenerator()->create_tag($tagrecord);
379
380 $randomslotdata = new stdClass();
381 $randomslotdata->quizid = $quiz->id;
382 $randomslotdata->questionid = $question->id;
383 $randomslotdata->questioncategoryid = $category->id;
384 $randomslotdata->includingsubcategories = 1;
385 $randomslotdata->maxmark = 1;
386
387 // Insert the random question to the quiz.
388 $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
389 $randomslot->set_tags([$footag, $bartag]);
390 $randomslot->insert(1); // Put the question on the first page of the quiz.
391
392 // Get the random question's quiz_slot. It is at the first slot.
393 $quizslot = $DB->get_record('quiz_slots', array('quizid' => $quiz->id, 'slot' => 1));
394 // Get the random question's tags from quiz_slot_tags. It is at the first slot.
395 $quizslottags = $DB->get_records('quiz_slot_tags', array('slotid' => $quizslot->id));
396
397 $this->assertEquals($question->id, $quizslot->questionid);
398 $this->assertEquals($category->id, $quizslot->questioncategoryid);
399 $this->assertEquals(1, $quizslot->includingsubcategories);
400 $this->assertEquals(1, $quizslot->maxmark);
401
402 $this->assertCount(2, $quizslottags);
403 $this->assertEquals(
404 [
405 ['tagid' => $footag->id, 'tagname' => $footag->name],
406 ['tagid' => $bartag->id, 'tagname' => $bartag->name]
407 ],
408 array_map(function($slottag) {
409 return ['tagid' => $slottag->tagid, 'tagname' => $slottag->tagname];
410 }, $quizslottags),
411 '', 0.0, 10, true);
412 }
413}