7dfeb95dcc1b1a91019a5c751dbb6234a0bba505
[moodle.git] / mod / quiz / tests / structure_test.php
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/>.
17 /**
18  * Quiz events tests.
19  *
20  * @package   mod_quiz
21  * @category  test
22  * @copyright 2013 Adrian Greeve
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->dirroot . '/mod/quiz/attemptlib.php');
31 /**
32  * Unit tests for quiz events.
33  *
34  * @copyright  2013 Adrian Greeve
35  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36  */
37 class mod_quiz_structure_testcase extends advanced_testcase {
39     /**
40      * Create a course with an empty quiz.
41      * @return array with three elements quiz, cm and course.
42      */
43     protected function prepare_quiz_data() {
45         $this->resetAfterTest(true);
47         // Create a course.
48         $course = $this->getDataGenerator()->create_course();
50         // Make a quiz.
51         $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
53         $quiz = $quizgenerator->create_instance(array('course' => $course->id, 'questionsperpage' => 0,
54             'grade' => 100.0, 'sumgrades' => 2, 'preferredbehaviour' => 'immediatefeedback'));
56         $cm = get_coursemodule_from_instance('quiz', $quiz->id, $course->id);
58         return array($quiz, $cm, $course);
59     }
61     /**
62      * Creat a test quiz.
63      *
64      * $layout looks like this:
65      * $layout = array(
66      *     'Heading 1'
67      *     array('TF1', 1, 'truefalse'),
68      *     'Heading 2*'
69      *     array('TF2', 2, 'truefalse'),
70      * );
71      * That is, either a string, which represents a section heading,
72      * or an array that represents a question.
73      *
74      * If the section heading ends with *, that section is shuffled.
75      *
76      * The elements in the question array are name, page number, and question type.
77      *
78      * @param array $layout as above.
79      * @return quiz the created quiz.
80      */
81     protected function create_test_quiz($layout) {
82         list($quiz, $cm, $course) = $this->prepare_quiz_data();
83         $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
84         $cat = $questiongenerator->create_question_category();
86         $headings = array();
87         $slot = 1;
88         $lastpage = 0;
89         foreach ($layout as $item) {
90             if (is_string($item)) {
91                 if (isset($headings[$lastpage + 1])) {
92                     throw new coding_exception('Sections cannot be empty.');
93                 }
94                 $headings[$lastpage + 1] = $item;
96             } else {
97                 list($name, $page, $qtype) = $item;
98                 if ($page < 1 || !($page == $lastpage + 1 ||
99                         (!isset($headings[$lastpage + 1]) && $page == $lastpage))) {
100                     throw new coding_exception('Page numbers wrong.');
101                 }
102                 $q = $questiongenerator->create_question($qtype, null,
103                         array('name' => $name, 'category' => $cat->id));
105                 quiz_add_quiz_question($q->id, $quiz, $page);
106                 $lastpage = $page;
107             }
108         }
110         $quizobj = new quiz($quiz, $cm, $course);
111         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
112         if (isset($headings[1])) {
113             list($heading, $shuffle) = $this->parse_section_name($headings[1]);
114             $sections = $structure->get_sections();
115             $firstsection = reset($sections);
116             $structure->set_section_heading($firstsection->id, $heading);
117             $structure->set_section_shuffle($firstsection->id, $shuffle);
118             unset($headings[1]);
119         }
121         foreach ($headings as $startpage => $heading) {
122             list($heading, $shuffle) = $this->parse_section_name($heading);
123             $id = $structure->add_section_heading($startpage, $heading);
124             $structure->set_section_shuffle($id, $shuffle);
125         }
127         return $quizobj;
128     }
130     /**
131      * Verify that the given layout matches that expected.
132      * @param array $expectedlayout as for $layout in {@link create_test_quiz()}.
133      * @param \mod_quiz\structure $structure the structure to test.
134      */
135     protected function assert_quiz_layout($expectedlayout, \mod_quiz\structure $structure) {
136         $sections = $structure->get_sections();
138         $slot = 1;
139         foreach ($expectedlayout as $item) {
140             if (is_string($item)) {
141                 list($heading, $shuffle) = $this->parse_section_name($item);
142                 $section = array_shift($sections);
144                 if ($slot > 1 && $section->heading == '' && $section->firstslot == 1) {
145                     // The array $expectedlayout did not contain default first quiz section, so skip over it.
146                     $section = array_shift($sections);
147                 }
149                 $this->assertEquals($slot, $section->firstslot);
150                 $this->assertEquals($heading, $section->heading);
151                 $this->assertEquals($shuffle, $section->shufflequestions);
153             } else {
154                 list($name, $page, $qtype) = $item;
155                 $question = $structure->get_question_in_slot($slot);
156                 $this->assertEquals($slot,  $question->slot);
157                 $this->assertEquals($name,  $question->name);
158                 $this->assertEquals($qtype, $question->qtype);
159                 $this->assertEquals($page,  $question->page);
161                 $slot += 1;
162             }
163         }
165         if ($slot - 1 != count($structure->get_slots())) {
166             $this->fail('The quiz contains more slots than expected.');
167         }
169         if (!empty($sections)) {
170             $section = array_shift($sections);
171             if ($section->heading != '' || $section->firstslot != 1) {
172                 $this->fail('Unexpected section (' . $section->heading .') found in the quiz.');
173             }
174         }
175     }
177     /**
178      * Parse the section name, optionally followed by a * to mean shuffle, as
179      * used by create_test_quiz as assert_quiz_layout.
180      * @param string $heading the heading.
181      * @return array with two elements, the heading and the shuffle setting.
182      */
183     protected function parse_section_name($heading) {
184         if (substr($heading, -1) == '*') {
185             return array(substr($heading, 0, -1), 1);
186         } else {
187             return array($heading, 0);
188         }
189     }
191     public function test_get_quiz_slots() {
192         $quizobj = $this->create_test_quiz(array(
193                 array('TF1', 1, 'truefalse'),
194                 array('TF2', 1, 'truefalse'),
195             ));
196         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
198         // Are the correct slots returned?
199         $slots = $structure->get_slots();
200         $this->assertCount(2, $structure->get_slots());
201     }
203     public function test_quiz_has_one_section_by_default() {
204         $quizobj = $this->create_test_quiz(array(
205                 array('TF1', 1, 'truefalse'),
206             ));
207         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
209         $sections = $structure->get_sections();
210         $this->assertCount(1, $sections);
212         $section = array_shift($sections);
213         $this->assertEquals(1, $section->firstslot);
214         $this->assertEquals('', $section->heading);
215         $this->assertEquals(0, $section->shufflequestions);
216     }
218     public function test_get_sections() {
219         $quizobj = $this->create_test_quiz(array(
220                 'Heading 1*',
221                 array('TF1', 1, 'truefalse'),
222                 'Heading 2*',
223                 array('TF2', 2, 'truefalse'),
224         ));
225         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
227         $sections = $structure->get_sections();
228         $this->assertCount(2, $sections);
230         $section = array_shift($sections);
231         $this->assertEquals(1, $section->firstslot);
232         $this->assertEquals('Heading 1', $section->heading);
233         $this->assertEquals(1, $section->shufflequestions);
235         $section = array_shift($sections);
236         $this->assertEquals(2, $section->firstslot);
237         $this->assertEquals('Heading 2', $section->heading);
238         $this->assertEquals(1, $section->shufflequestions);
239     }
241     public function test_remove_section_heading() {
242         $quizobj = $this->create_test_quiz(array(
243                 'Heading 1',
244                 array('TF1', 1, 'truefalse'),
245                 'Heading 2',
246                 array('TF2', 2, 'truefalse'),
247             ));
248         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
250         $sections = $structure->get_sections();
251         $section = end($sections);
252         $structure->remove_section_heading($section->id);
254         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
255         $this->assert_quiz_layout(array(
256                 'Heading 1',
257                 array('TF1', 1, 'truefalse'),
258                 array('TF2', 2, 'truefalse'),
259             ), $structure);
260     }
262     public function test_cannot_remove_first_section() {
263         $quizobj = $this->create_test_quiz(array(
264                 'Heading 1',
265                 array('TF1', 1, 'truefalse'),
266         ));
267         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
269         $sections = $structure->get_sections();
270         $section = reset($sections);
272         $this->setExpectedException('coding_exception');
273         $structure->remove_section_heading($section->id);
274     }
276     public function test_move_slot_to_the_same_place_does_nothing() {
277         $quizobj = $this->create_test_quiz(array(
278                 array('TF1', 1, 'truefalse'),
279                 array('TF2', 1, 'truefalse'),
280                 array('TF3', 2, 'truefalse'),
281             ));
282         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
284         $idtomove = $structure->get_question_in_slot(2)->slotid;
285         $idmoveafter = $structure->get_question_in_slot(1)->slotid;
286         $structure->move_slot($idtomove, $idmoveafter, '1');
288         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
289         $this->assert_quiz_layout(array(
290                 array('TF1', 1, 'truefalse'),
291                 array('TF2', 1, 'truefalse'),
292                 array('TF3', 2, 'truefalse'),
293             ), $structure);
294     }
296     public function test_move_slot_end_of_one_page_to_start_of_next() {
297         $quizobj = $this->create_test_quiz(array(
298                 array('TF1', 1, 'truefalse'),
299                 array('TF2', 1, 'truefalse'),
300                 array('TF3', 2, 'truefalse'),
301             ));
302         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
304         $idtomove = $structure->get_question_in_slot(2)->slotid;
305         $idmoveafter = $structure->get_question_in_slot(2)->slotid;
306         $structure->move_slot($idtomove, $idmoveafter, '2');
308         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
309         $this->assert_quiz_layout(array(
310                 array('TF1', 1, 'truefalse'),
311                 array('TF2', 2, 'truefalse'),
312                 array('TF3', 2, 'truefalse'),
313             ), $structure);
314     }
316     public function test_end_of_one_section_to_start_of_next() {
317         $quizobj = $this->create_test_quiz(array(
318                 array('TF1', 1, 'truefalse'),
319                 array('TF2', 1, 'truefalse'),
320                 'Heading',
321                 array('TF3', 2, 'truefalse'),
322             ));
323         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
325         $idtomove = $structure->get_question_in_slot(2)->slotid;
326         $idmoveafter = $structure->get_question_in_slot(2)->slotid;
327         $structure->move_slot($idtomove, $idmoveafter, '2');
329         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
330         $this->assert_quiz_layout(array(
331                 array('TF1', 1, 'truefalse'),
332                 'Heading',
333                 array('TF2', 2, 'truefalse'),
334                 array('TF3', 2, 'truefalse'),
335             ), $structure);
336     }
338     public function test_start_of_one_section_to_end_of_previous() {
339         $quizobj = $this->create_test_quiz(array(
340                 array('TF1', 1, 'truefalse'),
341                 'Heading',
342                 array('TF2', 2, 'truefalse'),
343                 array('TF3', 2, 'truefalse'),
344             ));
345         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
347         $idtomove = $structure->get_question_in_slot(2)->slotid;
348         $idmoveafter = $structure->get_question_in_slot(1)->slotid;
349         $structure->move_slot($idtomove, $idmoveafter, '1');
351         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
352         $this->assert_quiz_layout(array(
353                 array('TF1', 1, 'truefalse'),
354                 array('TF2', 1, 'truefalse'),
355                 'Heading',
356                 array('TF3', 2, 'truefalse'),
357             ), $structure);
358     }
359     public function test_move_slot_on_same_page() {
360         $quizobj = $this->create_test_quiz(array(
361                 array('TF1', 1, 'truefalse'),
362                 array('TF2', 1, 'truefalse'),
363                 array('TF3', 1, 'truefalse'),
364             ));
365         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
367         $idtomove = $structure->get_question_in_slot(2)->slotid;
368         $idmoveafter = $structure->get_question_in_slot(3)->slotid;
369         $structure->move_slot($idtomove, $idmoveafter, '1');
371         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
372         $this->assert_quiz_layout(array(
373                 array('TF1', 1, 'truefalse'),
374                 array('TF3', 1, 'truefalse'),
375                 array('TF2', 1, 'truefalse'),
376         ), $structure);
377     }
379     public function test_move_slot_up_onto_previous_page() {
380         $quizobj = $this->create_test_quiz(array(
381                 array('TF1', 1, 'truefalse'),
382                 array('TF2', 2, 'truefalse'),
383                 array('TF3', 2, 'truefalse'),
384         ));
385         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
387         $idtomove = $structure->get_question_in_slot(3)->slotid;
388         $idmoveafter = $structure->get_question_in_slot(1)->slotid;
389         $structure->move_slot($idtomove, $idmoveafter, '1');
391         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
392         $this->assert_quiz_layout(array(
393                 array('TF1', 1, 'truefalse'),
394                 array('TF3', 1, 'truefalse'),
395                 array('TF2', 2, 'truefalse'),
396         ), $structure);
397     }
399     public function test_move_slot_emptying_a_page_renumbers_pages() {
400         $quizobj = $this->create_test_quiz(array(
401                 array('TF1', 1, 'truefalse'),
402                 array('TF2', 2, 'truefalse'),
403                 array('TF3', 3, 'truefalse'),
404         ));
405         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
407         $idtomove = $structure->get_question_in_slot(2)->slotid;
408         $idmoveafter = $structure->get_question_in_slot(3)->slotid;
409         $structure->move_slot($idtomove, $idmoveafter, '3');
411         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
412         $this->assert_quiz_layout(array(
413                 array('TF1', 1, 'truefalse'),
414                 array('TF3', 2, 'truefalse'),
415                 array('TF2', 2, 'truefalse'),
416         ), $structure);
417     }
419     public function test_move_slot_too_small_page_number_detected() {
420         $quizobj = $this->create_test_quiz(array(
421                 array('TF1', 1, 'truefalse'),
422                 array('TF2', 2, 'truefalse'),
423                 array('TF3', 3, 'truefalse'),
424         ));
425         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
427         $idtomove = $structure->get_question_in_slot(3)->slotid;
428         $idmoveafter = $structure->get_question_in_slot(2)->slotid;
429         $this->setExpectedException('coding_exception');
430         $structure->move_slot($idtomove, $idmoveafter, '1');
431     }
433     public function test_move_slot_too_large_page_number_detected() {
434         $quizobj = $this->create_test_quiz(array(
435                 array('TF1', 1, 'truefalse'),
436                 array('TF2', 2, 'truefalse'),
437                 array('TF3', 3, 'truefalse'),
438         ));
439         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
441         $idtomove = $structure->get_question_in_slot(1)->slotid;
442         $idmoveafter = $structure->get_question_in_slot(2)->slotid;
443         $this->setExpectedException('coding_exception');
444         $structure->move_slot($idtomove, $idmoveafter, '4');
445     }
447     public function test_move_slot_within_section() {
448         $quizobj = $this->create_test_quiz(array(
449                 'Heading 1',
450                 array('TF1', 1, 'truefalse'),
451                 array('TF2', 1, 'truefalse'),
452                 'Heading 2',
453                 array('TF3', 2, 'truefalse'),
454             ));
455         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
457         $idtomove = $structure->get_question_in_slot(1)->slotid;
458         $idmoveafter = $structure->get_question_in_slot(2)->slotid;
459         $structure->move_slot($idtomove, $idmoveafter, '1');
461         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
462         $this->assert_quiz_layout(array(
463                 'Heading 1',
464                 array('TF2', 1, 'truefalse'),
465                 array('TF1', 1, 'truefalse'),
466                 'Heading 2',
467                 array('TF3', 2, 'truefalse'),
468             ), $structure);
469     }
471     public function test_move_slot_to_new_section() {
472         $quizobj = $this->create_test_quiz(array(
473                 'Heading 1',
474                 array('TF1', 1, 'truefalse'),
475                 array('TF2', 1, 'truefalse'),
476                 'Heading 2',
477                 array('TF3', 2, 'truefalse'),
478             ));
479         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
481         $idtomove = $structure->get_question_in_slot(2)->slotid;
482         $idmoveafter = $structure->get_question_in_slot(3)->slotid;
483         $structure->move_slot($idtomove, $idmoveafter, '2');
485         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
486         $this->assert_quiz_layout(array(
487                 'Heading 1',
488                 array('TF1', 1, 'truefalse'),
489                 'Heading 2',
490                 array('TF3', 2, 'truefalse'),
491                 array('TF2', 2, 'truefalse'),
492             ), $structure);
493     }
495     public function test_move_slot_to_start() {
496         $quizobj = $this->create_test_quiz(array(
497                 'Heading 1',
498                 array('TF1', 1, 'truefalse'),
499                 'Heading 2',
500                 array('TF2', 2, 'truefalse'),
501                 array('TF3', 2, 'truefalse'),
502             ));
503         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
505         $idtomove = $structure->get_question_in_slot(3)->slotid;
506         $structure->move_slot($idtomove, 0, '1');
508         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
509         $this->assert_quiz_layout(array(
510                 'Heading 1',
511                 array('TF3', 1, 'truefalse'),
512                 array('TF1', 1, 'truefalse'),
513                 'Heading 2',
514                 array('TF2', 2, 'truefalse'),
515             ), $structure);
516     }
518     public function test_move_slot_to_down_start_of_second_section() {
519         $quizobj = $this->create_test_quiz(array(
520                 'Heading 1',
521                 array('TF1', 1, 'truefalse'),
522                 array('TF2', 1, 'truefalse'),
523                 'Heading 2',
524                 array('TF3', 2, 'truefalse'),
525             ));
526         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
528         $idtomove = $structure->get_question_in_slot(2)->slotid;
529         $idmoveafter = $structure->get_question_in_slot(2)->slotid;
530         $structure->move_slot($idtomove, $idmoveafter, '2');
532         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
533         $this->assert_quiz_layout(array(
534                 'Heading 1',
535                 array('TF1', 1, 'truefalse'),
536                 'Heading 2',
537                 array('TF2', 2, 'truefalse'),
538                 array('TF3', 2, 'truefalse'),
539             ), $structure);
540     }
542     public function test_move_slot_up_to_start_of_second_section() {
543         $quizobj = $this->create_test_quiz(array(
544                 'Heading 1',
545                 array('TF1', 1, 'truefalse'),
546                 'Heading 2',
547                 array('TF2', 2, 'truefalse'),
548                 'Heading 3',
549                 array('TF3', 3, 'truefalse'),
550                 array('TF4', 3, 'truefalse'),
551             ));
552         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
554         $idtomove = $structure->get_question_in_slot(3)->slotid;
555         $idmoveafter = $structure->get_question_in_slot(1)->slotid;
556         $structure->move_slot($idtomove, $idmoveafter, '2');
558         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
559         $this->assert_quiz_layout(array(
560                 'Heading 1',
561                 array('TF1', 1, 'truefalse'),
562                 'Heading 2',
563                 array('TF3', 2, 'truefalse'),
564                 array('TF2', 2, 'truefalse'),
565                 'Heading 3',
566                 array('TF4', 3, 'truefalse'),
567             ), $structure);
568     }
570     public function test_quiz_remove_slot() {
571         $quizobj = $this->create_test_quiz(array(
572                 array('TF1', 1, 'truefalse'),
573                 array('TF2', 1, 'truefalse'),
574                 'Heading 2',
575                 array('TF3', 2, 'truefalse'),
576             ));
577         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
579         $structure->remove_slot(2);
581         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
582         $this->assert_quiz_layout(array(
583                 array('TF1', 1, 'truefalse'),
584                 'Heading 2',
585                 array('TF3', 2, 'truefalse'),
586             ), $structure);
587     }
589     public function test_quiz_removing_a_random_question_deletes_the_question() {
590         global $DB;
592         $this->resetAfterTest(true);
593         $this->setAdminUser();
595         $quizobj = $this->create_test_quiz(array(
596                 array('TF1', 1, 'truefalse'),
597             ));
599         $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
600         $cat = $questiongenerator->create_question_category();
601         quiz_add_random_questions($quizobj->get_quiz(), 1, $cat->id, 1, false);
602         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
603         $randomq = $DB->get_record('question', array('qtype' => 'random'));
605         $structure->remove_slot(2);
607         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
608         $this->assert_quiz_layout(array(
609                 array('TF1', 1, 'truefalse'),
610             ), $structure);
611         $this->assertFalse($DB->record_exists('question', array('id' => $randomq->id)));
612     }
614     public function test_cannot_remove_last_slot_in_a_section() {
615         $quizobj = $this->create_test_quiz(array(
616                 array('TF1', 1, 'truefalse'),
617                 array('TF2', 1, 'truefalse'),
618                 'Heading 2',
619                 array('TF3', 2, 'truefalse'),
620             ));
621         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
623         $this->setExpectedException('coding_exception');
624         $structure->remove_slot(3);
625     }
627     public function test_add_question_updates_headings() {
628         $quizobj = $this->create_test_quiz(array(
629                 array('TF1', 1, 'truefalse'),
630                 'Heading 2',
631                 array('TF2', 2, 'truefalse'),
632         ));
633         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
635         $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
636         $cat = $questiongenerator->create_question_category();
637         $q = $questiongenerator->create_question('truefalse', null,
638                 array('name' => 'TF3', 'category' => $cat->id));
640         quiz_add_quiz_question($q->id, $quizobj->get_quiz(), 1);
642         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
643         $this->assert_quiz_layout(array(
644                 array('TF1', 1, 'truefalse'),
645                 array('TF3', 1, 'truefalse'),
646                 'Heading 2',
647                 array('TF2', 2, 'truefalse'),
648         ), $structure);
649     }
651     public function test_add_question_and_end_does_not_update_headings() {
652         $quizobj = $this->create_test_quiz(array(
653                 array('TF1', 1, 'truefalse'),
654                 'Heading 2',
655                 array('TF2', 2, 'truefalse'),
656         ));
657         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
659         $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
660         $cat = $questiongenerator->create_question_category();
661         $q = $questiongenerator->create_question('truefalse', null,
662                 array('name' => 'TF3', 'category' => $cat->id));
664         quiz_add_quiz_question($q->id, $quizobj->get_quiz(), 0);
666         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
667         $this->assert_quiz_layout(array(
668                 array('TF1', 1, 'truefalse'),
669                 'Heading 2',
670                 array('TF2', 2, 'truefalse'),
671                 array('TF3', 2, 'truefalse'),
672         ), $structure);
673     }
675     public function test_remove_page_break() {
676         $quizobj = $this->create_test_quiz(array(
677                 array('TF1', 1, 'truefalse'),
678                 array('TF2', 2, 'truefalse'),
679             ));
680         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
682         $slotid = $structure->get_question_in_slot(2)->slotid;
683         $slots = $structure->update_page_break($slotid, \mod_quiz\repaginate::LINK);
685         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
686         $this->assert_quiz_layout(array(
687                 array('TF1', 1, 'truefalse'),
688                 array('TF2', 1, 'truefalse'),
689             ), $structure);
690     }
692     public function test_add_page_break() {
693         $quizobj = $this->create_test_quiz(array(
694                 array('TF1', 1, 'truefalse'),
695                 array('TF2', 1, 'truefalse'),
696         ));
697         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
699         $slotid = $structure->get_question_in_slot(2)->slotid;
700         $slots = $structure->update_page_break($slotid, \mod_quiz\repaginate::UNLINK);
702         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
703         $this->assert_quiz_layout(array(
704                 array('TF1', 1, 'truefalse'),
705                 array('TF2', 2, 'truefalse'),
706         ), $structure);
707     }
709     public function test_update_question_dependency() {
710         $quizobj = $this->create_test_quiz(array(
711                 array('TF1', 1, 'truefalse'),
712                 array('TF2', 1, 'truefalse'),
713         ));
714         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
716         // Test adding a dependency.
717         $slotid = $structure->get_slot_id_for_slot(2);
718         $structure->update_question_dependency($slotid, true);
720         // Having called update page break, we need to reload $structure.
721         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
722         $this->assertEquals(1, $structure->is_question_dependent_on_previous_slot(2));
724         // Test removing a dependency.
725         $structure->update_question_dependency($slotid, false);
727         // Having called update page break, we need to reload $structure.
728         $structure = \mod_quiz\structure::create_for_quiz($quizobj);
729         $this->assertEquals(0, $structure->is_question_dependent_on_previous_slot(2));
730     }