Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]

   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  namespace mod_lesson;
  18  
  19  /**
  20   * Genarator tests class for mod_lesson.
  21   *
  22   * @package    mod_lesson
  23   * @category   test
  24   * @copyright  2013 Marina Glancy
  25   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  26   * @covers     \mod_lesson_generator
  27   */
  28  class generator_test extends \advanced_testcase {
  29  
  30      public function test_create_instance() {
  31          global $DB;
  32          $this->resetAfterTest();
  33          $this->setAdminUser();
  34  
  35          $course = $this->getDataGenerator()->create_course();
  36  
  37          $this->assertFalse($DB->record_exists('lesson', array('course' => $course->id)));
  38          $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course));
  39          $records = $DB->get_records('lesson', array('course' => $course->id), 'id');
  40          $this->assertEquals(1, count($records));
  41          $this->assertTrue(array_key_exists($lesson->id, $records));
  42  
  43          $params = array('course' => $course->id, 'name' => 'Another lesson');
  44          $lesson = $this->getDataGenerator()->create_module('lesson', $params);
  45          $records = $DB->get_records('lesson', array('course' => $course->id), 'id');
  46          $this->assertEquals(2, count($records));
  47          $this->assertEquals('Another lesson', $records[$lesson->id]->name);
  48      }
  49  
  50      public function test_create_content() {
  51          global $DB;
  52          $this->resetAfterTest();
  53          $this->setAdminUser();
  54  
  55          $course = $this->getDataGenerator()->create_course();
  56          $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course));
  57          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
  58  
  59          $page1 = $lessongenerator->create_content($lesson);
  60          $page2 = $lessongenerator->create_content($lesson, array('title' => 'Custom title'));
  61          $records = $DB->get_records('lesson_pages', array('lessonid' => $lesson->id), 'id');
  62          $this->assertEquals(2, count($records));
  63          $this->assertEquals($page1->id, $records[$page1->id]->id);
  64          $this->assertEquals($page2->id, $records[$page2->id]->id);
  65          $this->assertEquals('Custom title', $records[$page2->id]->title);
  66      }
  67  
  68      /**
  69       * This tests the true/false question generator.
  70       */
  71      public function test_create_question_truefalse() {
  72          global $DB;
  73          $this->resetAfterTest();
  74          $this->setAdminUser();
  75  
  76          $course = $this->getDataGenerator()->create_course();
  77          $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course));
  78          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
  79  
  80          $page1 = $lessongenerator->create_question_truefalse($lesson);
  81          $page2 = $lessongenerator->create_question_truefalse($lesson, array('title' => 'Custom title'));
  82          $records = $DB->get_records('lesson_pages', array('lessonid' => $lesson->id), 'id');
  83          $p1answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page1->id), 'id');
  84          $p2answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page2->id), 'id');
  85          $this->assertCount(2, $records);
  86          $this->assertCount(2, $p1answers); // True/false only supports 2 answer records.
  87          $this->assertCount(2, $p2answers);
  88          $this->assertEquals($page1->id, $records[$page1->id]->id);
  89          $this->assertEquals($page2->id, $records[$page2->id]->id);
  90          $this->assertEquals($page2->title, $records[$page2->id]->title);
  91      }
  92  
  93      /**
  94       * This tests the multichoice question generator.
  95       */
  96      public function test_create_question_multichoice() {
  97          global $DB;
  98          $this->resetAfterTest();
  99          $this->setAdminUser();
 100  
 101          $course = $this->getDataGenerator()->create_course();
 102          $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course));
 103          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 104  
 105          $page1 = $lessongenerator->create_question_multichoice($lesson);
 106          $page2 = $lessongenerator->create_question_multichoice($lesson, array('title' => 'Custom title'));
 107          $records = $DB->get_records('lesson_pages', array('lessonid' => $lesson->id), 'id');
 108          $p1answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page1->id), 'id');
 109          $p2answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page2->id), 'id');
 110          $this->assertCount(2, $records);
 111          $this->assertCount(2, $p1answers); // Multichoice requires at least 2 records.
 112          $this->assertCount(2, $p2answers);
 113          $this->assertEquals($page1->id, $records[$page1->id]->id);
 114          $this->assertEquals($page2->id, $records[$page2->id]->id);
 115          $this->assertEquals($page2->title, $records[$page2->id]->title);
 116      }
 117  
 118      /**
 119       * This tests the essay question generator.
 120       */
 121      public function test_create_question_essay() {
 122          global $DB;
 123          $this->resetAfterTest();
 124          $this->setAdminUser();
 125  
 126          $course = $this->getDataGenerator()->create_course();
 127          $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course));
 128          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 129  
 130          $page1 = $lessongenerator->create_question_essay($lesson);
 131          $page2 = $lessongenerator->create_question_essay($lesson, array('title' => 'Custom title'));
 132          $records = $DB->get_records('lesson_pages', array('lessonid' => $lesson->id), 'id');
 133          $p1answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page1->id), 'id');
 134          $p2answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page2->id), 'id');
 135          $this->assertCount(2, $records);
 136          $this->assertCount(1, $p1answers); // Essay creates a single (empty) answer record.
 137          $this->assertCount(1, $p2answers);
 138          $this->assertEquals($page1->id, $records[$page1->id]->id);
 139          $this->assertEquals($page2->id, $records[$page2->id]->id);
 140          $this->assertEquals($page2->title, $records[$page2->id]->title);
 141      }
 142  
 143      /**
 144       * This tests the matching question generator.
 145       */
 146      public function test_create_question_matching() {
 147          global $DB;
 148          $this->resetAfterTest();
 149          $this->setAdminUser();
 150  
 151          $course = $this->getDataGenerator()->create_course();
 152          $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course));
 153          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 154  
 155          $page1 = $lessongenerator->create_question_matching($lesson);
 156          $page2 = $lessongenerator->create_question_matching($lesson, array('title' => 'Custom title'));
 157          $records = $DB->get_records('lesson_pages', array('lessonid' => $lesson->id), 'id');
 158          $p1answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page1->id), 'id');
 159          $p2answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page2->id), 'id');
 160          $this->assertCount(2, $records);
 161          $this->assertCount(4, $p1answers); // Matching creates two extra records plus 1 for each answer value.
 162          $this->assertCount(4, $p2answers);
 163          $this->assertEquals($page1->id, $records[$page1->id]->id);
 164          $this->assertEquals($page2->id, $records[$page2->id]->id);
 165          $this->assertEquals($page2->title, $records[$page2->id]->title);
 166      }
 167  
 168      /**
 169       * This tests the numeric question generator.
 170       */
 171      public function test_create_question_numeric() {
 172          global $DB;
 173          $this->resetAfterTest();
 174          $this->setAdminUser();
 175  
 176          $course = $this->getDataGenerator()->create_course();
 177          $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course));
 178          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 179  
 180          $page1 = $lessongenerator->create_question_numeric($lesson);
 181          $page2 = $lessongenerator->create_question_numeric($lesson, array('title' => 'Custom title'));
 182          $records = $DB->get_records('lesson_pages', array('lessonid' => $lesson->id), 'id');
 183          $p1answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page1->id), 'id');
 184          $p2answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page2->id), 'id');
 185          $this->assertCount(2, $records);
 186          $this->assertCount(1, $p1answers); // Numeric only requires 1 answer.
 187          $this->assertCount(1, $p2answers);
 188          $this->assertEquals($page1->id, $records[$page1->id]->id);
 189          $this->assertEquals($page2->id, $records[$page2->id]->id);
 190          $this->assertEquals($page2->title, $records[$page2->id]->title);
 191      }
 192  
 193      /**
 194       * This tests the shortanswer question generator.
 195       */
 196      public function test_create_question_shortanswer() {
 197          global $DB;
 198          $this->resetAfterTest();
 199          $this->setAdminUser();
 200  
 201          $course = $this->getDataGenerator()->create_course();
 202          $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course));
 203          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 204  
 205          $page1 = $lessongenerator->create_question_shortanswer($lesson);
 206          $page2 = $lessongenerator->create_question_shortanswer($lesson, array('title' => 'Custom title'));
 207          $records = $DB->get_records('lesson_pages', array('lessonid' => $lesson->id), 'id');
 208          $p1answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page1->id), 'id');
 209          $p2answers = $DB->get_records('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page2->id), 'id');
 210          $this->assertCount(2, $records);
 211          $this->assertCount(1, $p1answers); // Shortanswer only requires 1 answer.
 212          $this->assertCount(1, $p2answers);
 213          $this->assertEquals($page1->id, $records[$page1->id]->id);
 214          $this->assertEquals($page2->id, $records[$page2->id]->id);
 215          $this->assertEquals($page2->title, $records[$page2->id]->title);
 216      }
 217  
 218      /**
 219       * This tests the generators for cluster, endofcluster and endofbranch pages.
 220       *
 221       * @covers ::create_cluster
 222       * @covers ::create_endofcluster
 223       * @covers ::create_endofbranch
 224       * @dataProvider create_cluster_pages_provider
 225       *
 226       * @param string $type Type of page to test: LESSON_PAGE_CLUSTER, LESSON_PAGE_ENDOFCLUSTER or LESSON_PAGE_ENDOFBRANCH.
 227       */
 228      public function test_create_cluster_pages(string $type): void {
 229          global $DB;
 230          $this->resetAfterTest();
 231          $this->setAdminUser();
 232  
 233          $course = $this->getDataGenerator()->create_course();
 234          $lesson = $this->getDataGenerator()->create_module('lesson', ['course' => $course]);
 235          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 236  
 237          $page2data = [
 238              'title' => 'Custom title',
 239              'contents_editor' => [
 240                  'text' => 'Custom content',
 241                  'format' => FORMAT_MOODLE,
 242                  'itemid' => 0,
 243              ],
 244              'jumpto' => [LESSON_EOL],
 245          ];
 246  
 247          switch ($type) {
 248              case LESSON_PAGE_CLUSTER:
 249                  $page1 = $lessongenerator->create_cluster($lesson);
 250                  $page2 = $lessongenerator->create_cluster($lesson, $page2data);
 251                  break;
 252              case LESSON_PAGE_ENDOFCLUSTER:
 253                  $page1 = $lessongenerator->create_endofcluster($lesson);
 254                  $page2 = $lessongenerator->create_endofcluster($lesson, $page2data);
 255                  break;
 256              case LESSON_PAGE_ENDOFBRANCH:
 257                  $page1 = $lessongenerator->create_endofbranch($lesson);
 258                  $page2 = $lessongenerator->create_endofbranch($lesson, $page2data);
 259                  break;
 260              default:
 261                  throw new coding_exception('Cluster page type not valid: ' . $type);
 262          }
 263  
 264          $records = $DB->get_records('lesson_pages', ['lessonid' => $lesson->id], 'id');
 265          $p1answers = $DB->get_records('lesson_answers', ['lessonid' => $lesson->id, 'pageid' => $page1->id], 'id');
 266          $p2answers = $DB->get_records('lesson_answers', ['lessonid' => $lesson->id, 'pageid' => $page2->id], 'id');
 267  
 268          $this->assertCount(2, $records);
 269          $this->assertEquals($page1->id, $records[$page1->id]->id);
 270          $this->assertEquals($type, $records[$page1->id]->qtype);
 271          $this->assertEquals($page2->id, $records[$page2->id]->id);
 272          $this->assertEquals($type, $records[$page2->id]->qtype);
 273          $this->assertEquals($page2->title, $records[$page2->id]->title);
 274          $this->assertEquals($page2data['contents_editor']['text'], $records[$page2->id]->contents);
 275          $this->assertCount(1, $p1answers);
 276          $this->assertCount(1, $p2answers);
 277          $this->assertEquals(LESSON_THISPAGE, array_pop($p1answers)->jumpto);
 278          $this->assertEquals(LESSON_EOL, array_pop($p2answers)->jumpto);
 279      }
 280  
 281      /**
 282       * Data provider for test_create_cluster_pages().
 283       *
 284       * @return array
 285       */
 286      public static function create_cluster_pages_provider(): array {
 287          // Using the page constants here throws an error: Undefined constant "mod_lesson\LESSON_PAGE_CLUSTER".
 288          return [
 289              'Cluster' => [
 290                  'type' => '30',
 291              ],
 292              'End of cluster' => [
 293                  'type' => '31',
 294              ],
 295              'End of branch' => [
 296                  'type' => '21',
 297              ],
 298          ];
 299      }
 300  
 301      /**
 302       * Test create some pages and their answers.
 303       *
 304       * @covers ::create_page
 305       * @covers ::create_answer
 306       * @covers ::finish_generate_answer
 307       */
 308      public function test_create_page_and_answers(): void {
 309          global $DB;
 310          $this->resetAfterTest();
 311          $this->setAdminUser();
 312  
 313          $course = $this->getDataGenerator()->create_course();
 314          $lesson = $this->getDataGenerator()->create_module('lesson', ['course' => $course]);
 315          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 316  
 317          // Define the pages. Only a couple pages will be created since each page type has their own unit tests.
 318          $contentpage = [
 319              'title' => 'First page name',
 320              'content' => 'First page contents',
 321              'qtype' => 'content',
 322              'lessonid' => $lesson->id,
 323          ];
 324          $multichoicepage = [
 325              'title' => 'Multichoice question',
 326              'content' => 'What animal is an amphibian?',
 327              'qtype' => 'multichoice',
 328              'lessonid' => $lesson->id,
 329          ];
 330  
 331          $lessongenerator->create_page($contentpage);
 332          $lessongenerator->create_page($multichoicepage);
 333  
 334          // Check that pages haven't been generated yet because no answers were added.
 335          $pages = $DB->get_records('lesson_pages', ['lessonid' => $lesson->id], 'id');
 336          $this->assertEquals(0, count($pages));
 337  
 338          // Now add answers to the pages.
 339          $contentpagecontinueanswer = [
 340              'page' => $contentpage['title'],
 341              'answer' => 'Continue',
 342              'jumpto' => 'Next page',
 343              'score' => 1,
 344          ];
 345          $contentpagestayanswer = [
 346              'page' => $contentpage['title'],
 347              'answer' => 'Stay',
 348              'jumpto' => 'This page',
 349              'score' => 0,
 350          ];
 351          $multichoicepagefroganswer = [
 352              'page' => $multichoicepage['title'],
 353              'answer' => 'Frog',
 354              'response' => 'Correct answer',
 355              'jumpto' => 'Next page',
 356              'score' => 1,
 357          ];
 358          $multichoicepagecatanswer = [
 359              'page' => $multichoicepage['title'],
 360              'answer' => 'Cat',
 361              'response' => 'Incorrect answer',
 362              'jumpto' => 'This page',
 363              'score' => 0,
 364          ];
 365          $multichoicepagedoganswer = [
 366              'page' => $multichoicepage['title'],
 367              'answer' => 'Dog',
 368              'response' => 'Incorrect answer',
 369              'jumpto' => 'This page',
 370              'score' => 0,
 371          ];
 372  
 373          $lessongenerator->create_answer($contentpagecontinueanswer);
 374          $lessongenerator->create_answer($contentpagestayanswer);
 375          $lessongenerator->create_answer($multichoicepagefroganswer);
 376          $lessongenerator->create_answer($multichoicepagecatanswer);
 377          $lessongenerator->create_answer($multichoicepagedoganswer);
 378  
 379          // Check that pages and answers haven't been generated yet because maybe not all answers have been added yet.
 380          $pages = $DB->get_records('lesson_pages', ['lessonid' => $lesson->id], 'id');
 381          $answers = $DB->get_records('lesson_answers', ['lessonid' => $lesson->id], 'id');
 382          $this->assertEquals(0, count($pages));
 383          $this->assertEquals(0, count($answers));
 384  
 385          // Notify that all answers have been added, so pages can be created.
 386          $lessongenerator->finish_generate_answer();
 387  
 388          // Check that pages and answers have been created.
 389          $pages = $DB->get_records('lesson_pages', ['lessonid' => $lesson->id], $DB->sql_order_by_text('title') . ' DESC');
 390          $this->assertEquals(2, count($pages));
 391  
 392          $contentpagedb = array_pop($pages);
 393          $multichoicepagedb = array_pop($pages);
 394          $this->assertEquals($contentpage['title'], $contentpagedb->title);
 395          $this->assertEquals($contentpage['content'], $contentpagedb->contents);
 396          $this->assertEquals(LESSON_PAGE_BRANCHTABLE, $contentpagedb->qtype);
 397          $this->assertEquals($multichoicepage['title'], $multichoicepagedb->title);
 398          $this->assertEquals($multichoicepage['content'], $multichoicepagedb->contents);
 399          $this->assertEquals(LESSON_PAGE_MULTICHOICE, $multichoicepagedb->qtype);
 400  
 401          $answers = $DB->get_records('lesson_answers', ['lessonid' => $lesson->id], $DB->sql_order_by_text('answer') . ' DESC');
 402          $this->assertEquals(5, count($answers));
 403  
 404          $multichoicepagecatanswerdb = array_pop($answers);
 405          $contentpagecontinueanswerdb = array_pop($answers);
 406          $multichoicepagedoganswerdb = array_pop($answers);
 407          $multichoicepagefroganswerdb = array_pop($answers);
 408          $contentpagestayanswerdb = array_pop($answers);
 409          $this->assertEquals($contentpagedb->id, $contentpagecontinueanswerdb->pageid);
 410          $this->assertEquals($contentpagecontinueanswer['answer'], $contentpagecontinueanswerdb->answer);
 411          $this->assertEquals(LESSON_NEXTPAGE, $contentpagecontinueanswerdb->jumpto);
 412          $this->assertEquals($contentpagecontinueanswer['score'], $contentpagecontinueanswerdb->score);
 413          $this->assertEquals($contentpagedb->id, $contentpagestayanswerdb->pageid);
 414          $this->assertEquals($contentpagestayanswer['answer'], $contentpagestayanswerdb->answer);
 415          $this->assertEquals(LESSON_THISPAGE, $contentpagestayanswerdb->jumpto);
 416          $this->assertEquals($contentpagestayanswer['score'], $contentpagestayanswerdb->score);
 417          $this->assertEquals($multichoicepagedb->id, $multichoicepagefroganswerdb->pageid);
 418          $this->assertEquals($multichoicepagefroganswer['answer'], $multichoicepagefroganswerdb->answer);
 419          $this->assertEquals($multichoicepagefroganswer['response'], $multichoicepagefroganswerdb->response);
 420          $this->assertEquals(LESSON_NEXTPAGE, $multichoicepagefroganswerdb->jumpto);
 421          $this->assertEquals($multichoicepagefroganswer['score'], $multichoicepagefroganswerdb->score);
 422          $this->assertEquals($multichoicepagedb->id, $multichoicepagedoganswerdb->pageid);
 423          $this->assertEquals($multichoicepagedoganswer['answer'], $multichoicepagedoganswerdb->answer);
 424          $this->assertEquals($multichoicepagedoganswer['response'], $multichoicepagedoganswerdb->response);
 425          $this->assertEquals(LESSON_THISPAGE, $multichoicepagedoganswerdb->jumpto);
 426          $this->assertEquals($multichoicepagedoganswer['score'], $multichoicepagedoganswerdb->score);
 427          $this->assertEquals($multichoicepagedb->id, $multichoicepagecatanswerdb->pageid);
 428          $this->assertEquals($multichoicepagecatanswer['answer'], $multichoicepagecatanswerdb->answer);
 429          $this->assertEquals($multichoicepagecatanswer['response'], $multichoicepagecatanswerdb->response);
 430          $this->assertEquals(LESSON_THISPAGE, $multichoicepagecatanswerdb->jumpto);
 431          $this->assertEquals($multichoicepagecatanswer['score'], $multichoicepagecatanswerdb->score);
 432      }
 433  
 434      /**
 435       * Test creating pages defining the previous pages.
 436       *
 437       * @covers ::create_page
 438       */
 439      public function test_create_page_with_previouspage(): void {
 440          global $DB;
 441          $this->resetAfterTest();
 442          $this->setAdminUser();
 443  
 444          $course = $this->getDataGenerator()->create_course();
 445          $lesson = $this->getDataGenerator()->create_module('lesson', ['course' => $course]);
 446          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 447  
 448          $firstpage = [
 449              'title' => 'First page name',
 450              'content' => 'First page contents',
 451              'qtype' => 'content',
 452              'lessonid' => $lesson->id,
 453              'previouspage' => 0, // No previous page, this will be the first page.
 454          ];
 455          $secondpage = [
 456              'title' => 'Second page name',
 457              'content' => 'Second page contents',
 458              'qtype' => 'content',
 459              'lessonid' => $lesson->id,
 460              'previouspage' => 'First page name',
 461          ];
 462          $thirdpage = [
 463              'title' => 'Third page name',
 464              'content' => 'Third page contents',
 465              'qtype' => 'content',
 466              'lessonid' => $lesson->id,
 467              'previouspage' => 'Second page name',
 468          ];
 469  
 470          // Create the third page first to check that the added order is not important, the order will still be calculated right.
 471          $lessongenerator->create_page($thirdpage);
 472          $lessongenerator->create_page($firstpage);
 473          $lessongenerator->create_page($secondpage);
 474  
 475          // Don't define any answers, the default answers will be added.
 476          $lessongenerator->finish_generate_answer();
 477  
 478          $pages = $DB->get_records('lesson_pages', ['lessonid' => $lesson->id], $DB->sql_order_by_text('title') . ' DESC');
 479          $this->assertEquals(3, count($pages));
 480  
 481          $firstpagedb = array_pop($pages);
 482          $secondpagedb = array_pop($pages);
 483          $thirdpagedb = array_pop($pages);
 484          $this->assertEquals($firstpage['title'], $firstpagedb->title);
 485          $this->assertEquals(0, $firstpagedb->prevpageid);
 486          $this->assertEquals($secondpagedb->id, $firstpagedb->nextpageid);
 487          $this->assertEquals($secondpage['title'], $secondpagedb->title);
 488          $this->assertEquals($firstpagedb->id, $secondpagedb->prevpageid);
 489          $this->assertEquals($thirdpagedb->id, $secondpagedb->nextpageid);
 490          $this->assertEquals($thirdpage['title'], $thirdpagedb->title);
 491          $this->assertEquals($secondpagedb->id, $thirdpagedb->prevpageid);
 492          $this->assertEquals(0, $thirdpagedb->nextpageid);
 493      }
 494  
 495      /**
 496       * Test creating a page with a previous page that doesn't exist.
 497       *
 498       * @covers ::create_page
 499       */
 500      public function test_create_page_invalid_previouspage(): void {
 501          $this->resetAfterTest();
 502          $this->setAdminUser();
 503  
 504          $course = $this->getDataGenerator()->create_course();
 505          $lesson = $this->getDataGenerator()->create_module('lesson', ['course' => $course]);
 506          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 507  
 508          $this->expectException('coding_exception');
 509          $lessongenerator->create_page([
 510              'title' => 'First page name',
 511              'content' => 'First page contents',
 512              'qtype' => 'content',
 513              'lessonid' => $lesson->id,
 514              'previouspage' => 'Invalid page',
 515          ]);
 516          $lessongenerator->finish_generate_answer();
 517      }
 518  
 519      /**
 520       * Test that circular dependencies are not allowed in previous pages.
 521       *
 522       * @covers ::create_page
 523       */
 524      public function test_create_page_previouspage_circular_dependency(): void {
 525          $this->resetAfterTest();
 526          $this->setAdminUser();
 527  
 528          $course = $this->getDataGenerator()->create_course();
 529          $lesson = $this->getDataGenerator()->create_module('lesson', ['course' => $course]);
 530          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 531  
 532          $this->expectException('coding_exception');
 533          $lessongenerator->create_page([
 534              'title' => 'First page name',
 535              'content' => 'First page contents',
 536              'qtype' => 'content',
 537              'lessonid' => $lesson->id,
 538              'previouspage' => 'Second page name',
 539          ]);
 540          $lessongenerator->create_page([
 541              'title' => 'Second page name',
 542              'content' => 'Second page contents',
 543              'qtype' => 'content',
 544              'lessonid' => $lesson->id,
 545              'previouspage' => 'First page name',
 546          ]);
 547          $lessongenerator->finish_generate_answer();
 548      }
 549  
 550      /**
 551       * Test creating an answer in a page that doesn't exist.
 552       *
 553       * @covers ::create_answer
 554       */
 555      public function test_create_answer_invalid_page(): void {
 556          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 557  
 558          $this->expectException('coding_exception');
 559          $lessongenerator->create_answer([
 560              'page' => 'Invalid page',
 561          ]);
 562      }
 563  
 564      /**
 565       * Test that all the possible values of jumpto work as expected when creating an answer.
 566       *
 567       * @covers ::create_answer
 568       */
 569      public function test_create_answer_jumpto(): void {
 570          global $DB;
 571          $this->resetAfterTest();
 572          $this->setAdminUser();
 573  
 574          $course = $this->getDataGenerator()->create_course();
 575          $lesson = $this->getDataGenerator()->create_module('lesson', ['course' => $course]);
 576          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 577  
 578          $contentpage = [
 579              'title' => 'First page name',
 580              'content' => 'First page contents',
 581              'qtype' => 'content',
 582              'lessonid' => $lesson->id,
 583          ];
 584          $secondcontentpage = [
 585              'title' => 'Second page name',
 586              'content' => 'Second page contents',
 587              'qtype' => 'content',
 588              'lessonid' => $lesson->id,
 589          ];
 590          $thirdcontentpage = [
 591              'title' => 'Third page name',
 592              'content' => 'Third page contents',
 593              'qtype' => 'content',
 594              'lessonid' => $lesson->id,
 595          ];
 596          $lessongenerator->create_page($contentpage);
 597          $lessongenerator->create_page($secondcontentpage);
 598          $lessongenerator->create_page($thirdcontentpage);
 599  
 600          $lessongenerator->create_answer([
 601              'page' => $contentpage['title'],
 602              'answer' => 'A',
 603              'jumpto' => 'This page',
 604          ]);
 605          $lessongenerator->create_answer([
 606              'page' => $contentpage['title'],
 607              'answer' => 'B',
 608              'jumpto' => 'Next page',
 609          ]);
 610          $lessongenerator->create_answer([
 611              'page' => $contentpage['title'],
 612              'answer' => 'C',
 613              'jumpto' => 'Previous page',
 614          ]);
 615          $lessongenerator->create_answer([
 616              'page' => $secondcontentpage['title'],
 617              'answer' => 'D',
 618              'jumpto' => 'End of lesson',
 619          ]);
 620          $lessongenerator->create_answer([
 621              'page' => $secondcontentpage['title'],
 622              'answer' => 'E',
 623              'jumpto' => 'Unseen question within a content page',
 624          ]);
 625          $lessongenerator->create_answer([
 626              'page' => $secondcontentpage['title'],
 627              'answer' => 'F',
 628              'jumpto' => 'Random question within a content page',
 629          ]);
 630          $lessongenerator->create_answer([
 631              'page' => $thirdcontentpage['title'],
 632              'answer' => 'G',
 633              'jumpto' => 'Random content page',
 634          ]);
 635          $lessongenerator->create_answer([
 636              'page' => $thirdcontentpage['title'],
 637              'answer' => 'H',
 638              'jumpto' => 'Unseen question within a cluster',
 639          ]);
 640          $lessongenerator->create_answer([
 641              'page' => $thirdcontentpage['title'],
 642              'answer' => 'I',
 643              'jumpto' => 1234, // A page ID, it doesn't matter that it doesn't exist.
 644          ]);
 645          $lessongenerator->create_answer([
 646              'page' => $contentpage['title'],
 647              'answer' => 'J',
 648              'jumpto' => 'Third page name',
 649          ]);
 650          $lessongenerator->create_answer([
 651              'page' => $thirdcontentpage['title'],
 652              'answer' => 'K',
 653              'jumpto' => 'Second page name',
 654          ]);
 655  
 656          $lessongenerator->finish_generate_answer();
 657  
 658          $secondcontentpagedb = $DB->get_record('lesson_pages', ['lessonid' => $lesson->id, 'title' => $secondcontentpage['title']]);
 659          $thirdcontentpagedb = $DB->get_record('lesson_pages', ['lessonid' => $lesson->id, 'title' => $thirdcontentpage['title']]);
 660          $answers = $DB->get_records('lesson_answers', ['lessonid' => $lesson->id], $DB->sql_order_by_text('answer') . ' DESC');
 661          $this->assertEquals(11, count($answers));
 662  
 663          $this->assertEquals(LESSON_THISPAGE, array_pop($answers)->jumpto);
 664          $this->assertEquals(LESSON_NEXTPAGE, array_pop($answers)->jumpto);
 665          $this->assertEquals(LESSON_PREVIOUSPAGE, array_pop($answers)->jumpto);
 666          $this->assertEquals(LESSON_EOL, array_pop($answers)->jumpto);
 667          $this->assertEquals(LESSON_UNSEENBRANCHPAGE, array_pop($answers)->jumpto);
 668          $this->assertEquals(LESSON_RANDOMPAGE, array_pop($answers)->jumpto);
 669          $this->assertEquals(LESSON_RANDOMBRANCH, array_pop($answers)->jumpto);
 670          $this->assertEquals(LESSON_CLUSTERJUMP, array_pop($answers)->jumpto);
 671          $this->assertEquals(1234, array_pop($answers)->jumpto);
 672          $this->assertEquals($thirdcontentpagedb->id, array_pop($answers)->jumpto);
 673          $this->assertEquals($secondcontentpagedb->id, array_pop($answers)->jumpto);
 674      }
 675  
 676      /**
 677       * Test invalid jumpto when creating answers.
 678       *
 679       * @covers ::create_answer
 680       */
 681      public function test_create_answer_invalid_jumpto(): void {
 682          $this->resetAfterTest();
 683          $this->setAdminUser();
 684  
 685          $course = $this->getDataGenerator()->create_course();
 686          $lesson = $this->getDataGenerator()->create_module('lesson', ['course' => $course]);
 687          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 688  
 689          $contentpage = [
 690              'title' => 'First page name',
 691              'content' => 'First page contents',
 692              'qtype' => 'content',
 693              'lessonid' => $lesson->id,
 694          ];
 695          $lessongenerator->create_page($contentpage);
 696  
 697          $lessongenerator->create_answer([
 698              'page' => $contentpage['title'],
 699              'answer' => 'Next',
 700              'jumpto' => 'Invalid page',
 701          ]);
 702  
 703          $this->expectException('coding_exception');
 704          $lessongenerator->finish_generate_answer();
 705      }
 706  
 707      /**
 708       * Test that circular dependencies are not allowed when creating answers.
 709       *
 710       * @covers ::create_answer
 711       */
 712      public function test_create_answer_jumpto_circular_dependency(): void {
 713          $this->resetAfterTest();
 714          $this->setAdminUser();
 715  
 716          $course = $this->getDataGenerator()->create_course();
 717          $lesson = $this->getDataGenerator()->create_module('lesson', ['course' => $course]);
 718          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 719  
 720          $contentpage = [
 721              'title' => 'First page name',
 722              'content' => 'First page contents',
 723              'qtype' => 'content',
 724              'lessonid' => $lesson->id,
 725          ];
 726          $secondcontentpage = [
 727              'title' => 'Second page name',
 728              'content' => 'Second page contents',
 729              'qtype' => 'content',
 730              'lessonid' => $lesson->id,
 731          ];
 732          $lessongenerator->create_page($contentpage);
 733          $lessongenerator->create_page($secondcontentpage);
 734  
 735          $lessongenerator->create_answer([
 736              'page' => $contentpage['title'],
 737              'answer' => 'Next',
 738              'jumpto' => 'Second page name',
 739          ]);
 740          $lessongenerator->create_answer([
 741              'page' => $contentpage['title'],
 742              'answer' => 'Back',
 743              'jumpto' => 'First page name',
 744          ]);
 745  
 746          $this->expectException('coding_exception');
 747          $lessongenerator->finish_generate_answer();
 748      }
 749  
 750  }