2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Unit tests for the {@link \mod_quiz\local\structure\slot_random} class.
22 * @copyright 2018 Shamim Rezaie <shamim@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
29 * Class mod_quiz_local_structure_slot_random_test
30 * Class for tests related to the {@link \mod_quiz\local\structure\slot_random} class.
32 * @copyright 2018 Shamim Rezaie <shamim@moodle.com>
33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 class mod_quiz_local_structure_slot_random_test extends advanced_testcase {
39 public function test_constructor() {
42 $this->resetAfterTest();
43 $this->setAdminUser();
46 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
47 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
49 // Create a question category in the system context.
50 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
51 $category = $questiongenerator->create_question_category();
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;
59 $form->defaultmark = 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);
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;
73 $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
75 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
76 $rcp = $rc->getProperty('record');
77 $rcp->setAccessible(true);
78 $record = $rcp->getValue($randomslot);
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);
87 public function test_get_quiz_quiz() {
90 $this->resetAfterTest();
91 $this->setAdminUser();
94 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
95 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
97 // Create a question category in the system context.
98 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
99 $category = $questiongenerator->create_question_category();
101 quiz_add_random_questions($quiz, 0, $category->id, 1, false);
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));
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;
113 $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
115 // The create_instance had injected an additional cmid propery to the quiz. Let's remove that.
118 $this->assertEquals($quiz, $randomslot->get_quiz());
121 public function test_set_quiz() {
124 $this->resetAfterTest();
125 $this->setAdminUser();
128 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
129 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
131 // Create a question category in the system context.
132 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
133 $category = $questiongenerator->create_question_category();
135 quiz_add_random_questions($quiz, 0, $category->id, 1, false);
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));
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;
147 $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
149 // The create_instance had injected an additional cmid propery to the quiz. Let's remove that.
152 $randomslot->set_quiz($quiz);
154 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
155 $rcp = $rc->getProperty('quiz');
156 $rcp->setAccessible(true);
157 $quizpropery = $rcp->getValue($randomslot);
159 $this->assertEquals($quiz, $quizpropery);
162 private function setup_for_test_tags($tagnames) {
166 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
167 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
169 // Create a question category in the system context.
170 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
171 $category = $questiongenerator->create_question_category();
173 quiz_add_random_questions($quiz, 0, $category->id, 1, false);
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));
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;
185 $randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
188 foreach ($tagnames as $tagname) {
192 'rawname' => $tagname,
193 'description' => $tagname . ' desc'
195 $tags[$tagname] = $this->getDataGenerator()->create_tag($tagrecord);
198 return array($randomslot, $tags);
201 public function test_set_tags() {
202 $this->resetAfterTest();
203 $this->setAdminUser();
205 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar']);
206 $randomslot->set_tags([$tags['foo'], $tags['bar']]);
208 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
209 $rcp = $rc->getProperty('tags');
210 $rcp->setAccessible(true);
211 $tagspropery = $rcp->getValue($randomslot);
213 $this->assertEquals([
214 $tags['foo']->id => $tags['foo'],
215 $tags['bar']->id => $tags['bar'],
219 public function test_set_tags_twice() {
220 $this->resetAfterTest();
221 $this->setAdminUser();
223 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
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']]);
230 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
231 $rcp = $rc->getProperty('tags');
232 $rcp->setAccessible(true);
233 $tagspropery = $rcp->getValue($randomslot);
235 $this->assertEquals([
236 $tags['baz']->id => $tags['baz'],
240 public function test_set_tags_duplicates() {
241 $this->resetAfterTest();
242 $this->setAdminUser();
244 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
246 $randomslot->set_tags([$tags['foo'], $tags['bar'], $tags['foo']]);
248 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
249 $rcp = $rc->getProperty('tags');
250 $rcp->setAccessible(true);
251 $tagspropery = $rcp->getValue($randomslot);
253 $this->assertEquals([
254 $tags['foo']->id => $tags['foo'],
255 $tags['bar']->id => $tags['bar'],
259 public function test_set_tags_by_id() {
260 $this->resetAfterTest();
261 $this->setAdminUser();
263 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
265 $randomslot->set_tags_by_id([$tags['foo']->id, $tags['bar']->id]);
267 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
268 $rcp = $rc->getProperty('tags');
269 $rcp->setAccessible(true);
270 $tagspropery = $rcp->getValue($randomslot);
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);
277 (object)['id' => $tags['foo']->id, 'name' => $tags['foo']->name],
278 $tagspropery[$tags['foo']->id]->to_object()
281 (object)['id' => $tags['bar']->id, 'name' => $tags['bar']->name],
282 $tagspropery[$tags['bar']->id]->to_object()
286 public function test_set_tags_by_id_twice() {
287 $this->resetAfterTest();
288 $this->setAdminUser();
290 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
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]);
297 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
298 $rcp = $rc->getProperty('tags');
299 $rcp->setAccessible(true);
300 $tagspropery = $rcp->getValue($randomslot);
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);
306 (object)['id' => $tags['baz']->id, 'name' => $tags['baz']->name],
307 $tagspropery[$tags['baz']->id]->to_object()
311 public function test_set_tags_by_id_duplicates() {
312 $this->resetAfterTest();
313 $this->setAdminUser();
315 list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
317 $randomslot->set_tags_by_id([$tags['foo']->id, $tags['bar']->id], $tags['foo']->id);
319 $rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
320 $rcp = $rc->getProperty('tags');
321 $rcp->setAccessible(true);
322 $tagspropery = $rcp->getValue($randomslot);
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);
329 (object)['id' => $tags['foo']->id, 'name' => $tags['foo']->name],
330 $tagspropery[$tags['foo']->id]->to_object()
333 (object)['id' => $tags['bar']->id, 'name' => $tags['bar']->name],
334 $tagspropery[$tags['bar']->id]->to_object()
338 public function test_insert() {
341 $this->resetAfterTest();
342 $this->setAdminUser();
345 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
346 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
348 // Create a question category in the system context.
349 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
350 $category = $questiongenerator->create_question_category();
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;
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);
369 'description' => 'foo desc'
371 $footag = $this->getDataGenerator()->create_tag($tagrecord);
376 'description' => 'bar desc'
378 $bartag = $this->getDataGenerator()->create_tag($tagrecord);
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;
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.
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));
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);
402 $this->assertCount(2, $quizslottags);
405 ['tagid' => $footag->id, 'tagname' => $footag->name],
406 ['tagid' => $bartag->id, 'tagname' => $bartag->name]
408 array_map(function($slottag) {
409 return ['tagid' => $slottag->tagid, 'tagname' => $slottag->tagname];