Differences Between: [Versions 310 and 311] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
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 (some of) mod/book/lib.php. 19 * 20 * @package mod_book 21 * @category phpunit 22 * @copyright 2015 Juan Leyva <juan@moodle.com> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 namespace mod_book; 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 global $CFG; 30 require_once($CFG->dirroot . '/mod/book/lib.php'); 31 32 /** 33 * Unit tests for (some of) mod/book/lib.php. 34 * 35 * @package mod_book 36 * @category phpunit 37 * @copyright 2015 Juan Leyva <juan@moodle.com> 38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 */ 40 class lib_test extends \advanced_testcase { 41 42 public function setUp(): void { 43 $this->resetAfterTest(); 44 $this->setAdminUser(); 45 } 46 47 public function test_export_contents() { 48 global $DB, $CFG; 49 require_once($CFG->dirroot . '/course/externallib.php'); 50 51 $user = $this->getDataGenerator()->create_user(); 52 $teacher = $this->getDataGenerator()->create_user(); 53 $course = $this->getDataGenerator()->create_course(array('enablecomment' => 1)); 54 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 55 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 56 57 $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id); 58 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id); 59 60 // Test book with 3 chapters. 61 $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id)); 62 $cm = get_coursemodule_from_id('book', $book->cmid); 63 64 $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book'); 65 $chapter1 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 1, 66 'tags' => array('Cats', 'Dogs'))); 67 $tag = \core_tag_tag::get_by_name(0, 'Cats'); 68 69 $chapter2 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 2)); 70 $subchapter = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 3, "subchapter" => 1)); 71 $chapter3 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 4, "hidden" => 1)); 72 73 $this->setUser($user); 74 75 $contents = book_export_contents($cm, ''); 76 // The hidden chapter must not be included, and additional page with the structure must be included. 77 $this->assertCount(4, $contents); 78 79 $this->assertEquals('structure', $contents[0]['filename']); 80 $this->assertEquals('index.html', $contents[1]['filename']); 81 $this->assertEquals('Chapter 1', $contents[1]['content']); 82 $this->assertCount(2, $contents[1]['tags']); 83 $this->assertEquals('Cats', $contents[1]['tags'][0]['rawname']); 84 $this->assertEquals($tag->id, $contents[1]['tags'][0]['id']); 85 $this->assertEquals('Dogs', $contents[1]['tags'][1]['rawname']); 86 $this->assertEquals('index.html', $contents[2]['filename']); 87 $this->assertEquals('Chapter 2', $contents[2]['content']); 88 $this->assertEquals('index.html', $contents[3]['filename']); 89 $this->assertEquals('Chapter 3', $contents[3]['content']); 90 91 // Now, test the function via the external API. 92 $contents = \core_course_external::get_course_contents($course->id, array()); 93 $contents = \external_api::clean_returnvalue(\core_course_external::get_course_contents_returns(), $contents); 94 95 $this->assertCount(4, $contents[0]['modules'][0]['contents']); 96 97 $this->assertEquals('content', $contents[0]['modules'][0]['contents'][0]['type']); 98 $this->assertEquals('structure', $contents[0]['modules'][0]['contents'][0]['filename']); 99 100 $this->assertEquals('file', $contents[0]['modules'][0]['contents'][1]['type']); 101 $this->assertEquals('Chapter 1', $contents[0]['modules'][0]['contents'][1]['content']); 102 103 $this->assertEquals('file', $contents[0]['modules'][0]['contents'][2]['type']); 104 $this->assertEquals('Chapter 2', $contents[0]['modules'][0]['contents'][2]['content']); 105 106 $this->assertEquals('file', $contents[0]['modules'][0]['contents'][3]['type']); 107 $this->assertEquals('Chapter 3', $contents[0]['modules'][0]['contents'][3]['content']); 108 109 $this->assertEquals('book', $contents[0]['modules'][0]['modname']); 110 $this->assertEquals($cm->id, $contents[0]['modules'][0]['id']); 111 $this->assertCount(2, $contents[0]['modules'][0]['contents'][1]['tags']); 112 $this->assertEquals('Cats', $contents[0]['modules'][0]['contents'][1]['tags'][0]['rawname']); 113 $this->assertEquals('Dogs', $contents[0]['modules'][0]['contents'][1]['tags'][1]['rawname']); 114 115 // As a teacher. 116 $this->setUser($teacher); 117 118 $contents = book_export_contents($cm, ''); 119 // As a teacher, the hidden chapter must be included in the structure. 120 $this->assertCount(5, $contents); 121 122 $this->assertEquals('structure', $contents[0]['filename']); 123 // Check structure is correct. 124 $foundhiddenchapter = false; 125 $chapters = json_decode($contents[0]['content']); 126 foreach ($chapters as $chapter) { 127 if ($chapter->title == 'Chapter 4' && $chapter->hidden == 1) { 128 $foundhiddenchapter = true; 129 } 130 } 131 $this->assertTrue($foundhiddenchapter); 132 133 $this->assertEquals('index.html', $contents[1]['filename']); 134 $this->assertEquals('Chapter 1', $contents[1]['content']); 135 $this->assertCount(2, $contents[1]['tags']); 136 $this->assertEquals('Cats', $contents[1]['tags'][0]['rawname']); 137 $this->assertEquals($tag->id, $contents[1]['tags'][0]['id']); 138 $this->assertEquals('Dogs', $contents[1]['tags'][1]['rawname']); 139 $this->assertEquals('index.html', $contents[2]['filename']); 140 $this->assertEquals('Chapter 2', $contents[2]['content']); 141 $this->assertEquals('index.html', $contents[3]['filename']); 142 $this->assertEquals('Chapter 3', $contents[3]['content']); 143 $this->assertEquals('index.html', $contents[4]['filename']); 144 $this->assertEquals('Chapter 4', $contents[4]['content']); 145 146 // Now, test the function via the external API. 147 $contents = \core_course_external::get_course_contents($course->id, array()); 148 $contents = \external_api::clean_returnvalue(\core_course_external::get_course_contents_returns(), $contents); 149 150 $this->assertCount(5, $contents[0]['modules'][0]['contents']); 151 152 $this->assertEquals('content', $contents[0]['modules'][0]['contents'][0]['type']); 153 $this->assertEquals('structure', $contents[0]['modules'][0]['contents'][0]['filename']); 154 // Check structure is correct. 155 $foundhiddenchapter = false; 156 $chapters = json_decode($contents[0]['modules'][0]['contents'][0]['content']); 157 foreach ($chapters as $chapter) { 158 if ($chapter->title == 'Chapter 4' && $chapter->hidden == 1) { 159 $foundhiddenchapter = true; 160 } 161 } 162 $this->assertTrue($foundhiddenchapter); 163 164 $this->assertEquals('file', $contents[0]['modules'][0]['contents'][1]['type']); 165 $this->assertEquals('Chapter 1', $contents[0]['modules'][0]['contents'][1]['content']); 166 167 $this->assertEquals('file', $contents[0]['modules'][0]['contents'][2]['type']); 168 $this->assertEquals('Chapter 2', $contents[0]['modules'][0]['contents'][2]['content']); 169 170 $this->assertEquals('file', $contents[0]['modules'][0]['contents'][3]['type']); 171 $this->assertEquals('Chapter 3', $contents[0]['modules'][0]['contents'][3]['content']); 172 173 $this->assertEquals('file', $contents[0]['modules'][0]['contents'][4]['type']); 174 $this->assertEquals('Chapter 4', $contents[0]['modules'][0]['contents'][4]['content']); 175 176 $this->assertEquals('book', $contents[0]['modules'][0]['modname']); 177 $this->assertEquals($cm->id, $contents[0]['modules'][0]['id']); 178 $this->assertCount(2, $contents[0]['modules'][0]['contents'][1]['tags']); 179 $this->assertEquals('Cats', $contents[0]['modules'][0]['contents'][1]['tags'][0]['rawname']); 180 $this->assertEquals('Dogs', $contents[0]['modules'][0]['contents'][1]['tags'][1]['rawname']); 181 182 // Test empty book. 183 $emptybook = $this->getDataGenerator()->create_module('book', array('course' => $course->id)); 184 $cm = get_coursemodule_from_id('book', $emptybook->cmid); 185 $contents = book_export_contents($cm, ''); 186 187 $this->assertCount(1, $contents); 188 $this->assertEquals('structure', $contents[0]['filename']); 189 $this->assertEquals(json_encode(array()), $contents[0]['content']); 190 191 } 192 193 /** 194 * Test book_view 195 * @return void 196 */ 197 public function test_book_view() { 198 global $CFG, $DB; 199 200 $CFG->enablecompletion = 1; 201 202 // Setup test data. 203 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 204 $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id), 205 array('completion' => 2, 'completionview' => 1)); 206 $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book'); 207 $chapter = $bookgenerator->create_chapter(array('bookid' => $book->id)); 208 209 $context = \context_module::instance($book->cmid); 210 $cm = get_coursemodule_from_instance('book', $book->id); 211 212 // Trigger and capture the event. 213 $sink = $this->redirectEvents(); 214 215 // Check just opening the book. 216 book_view($book, 0, false, $course, $cm, $context); 217 218 $events = $sink->get_events(); 219 $this->assertCount(1, $events); 220 $event = array_shift($events); 221 222 // Checking that the event contains the expected values. 223 $this->assertInstanceOf('\mod_book\event\course_module_viewed', $event); 224 $this->assertEquals($context, $event->get_context()); 225 $moodleurl = new \moodle_url('/mod/book/view.php', array('id' => $cm->id)); 226 $this->assertEquals($moodleurl, $event->get_url()); 227 $this->assertEventContextNotUsed($event); 228 $this->assertNotEmpty($event->get_name()); 229 230 // Check viewing one book chapter (the only one so it will be the first and last). 231 book_view($book, $chapter, true, $course, $cm, $context); 232 233 $events = $sink->get_events(); 234 // We expect a total of 4 events. One for module viewed, one for chapter viewed and two belonging to completion. 235 $this->assertCount(4, $events); 236 237 // Check completion status. 238 $completion = new \completion_info($course); 239 $completiondata = $completion->get_data($cm); 240 $this->assertEquals(1, $completiondata->completionstate); 241 } 242 243 public function test_book_core_calendar_provide_event_action() { 244 // Create the activity. 245 $course = $this->getDataGenerator()->create_course(); 246 $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id)); 247 248 // Create a calendar event. 249 $event = $this->create_action_event($course->id, $book->id, 250 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 251 252 // Create an action factory. 253 $factory = new \core_calendar\action_factory(); 254 255 // Decorate action event. 256 $actionevent = mod_book_core_calendar_provide_event_action($event, $factory); 257 258 // Confirm the event was decorated. 259 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 260 $this->assertEquals(get_string('view'), $actionevent->get_name()); 261 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 262 $this->assertEquals(1, $actionevent->get_item_count()); 263 $this->assertTrue($actionevent->is_actionable()); 264 } 265 266 public function test_book_core_calendar_provide_event_action_in_hidden_section() { 267 // Create the activity. 268 $course = $this->getDataGenerator()->create_course(); 269 $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id)); 270 271 // Enrol a student in the course. 272 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 273 274 // Create a calendar event. 275 $event = $this->create_action_event($course->id, $book->id, 276 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 277 278 // Set sections 0 as hidden. 279 set_section_visible($course->id, 0, 0); 280 281 // Now, log out. 282 $this->setUser(); 283 284 // Create an action factory. 285 $factory = new \core_calendar\action_factory(); 286 287 // Decorate action event for the student. 288 $actionevent = mod_book_core_calendar_provide_event_action($event, $factory, $student->id); 289 290 // Confirm the event is not shown at all. 291 $this->assertNull($actionevent); 292 } 293 294 public function test_book_core_calendar_provide_event_action_for_user() { 295 // Create the activity. 296 $course = $this->getDataGenerator()->create_course(); 297 $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id)); 298 299 // Enrol a student in the course. 300 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 301 302 // Create a calendar event. 303 $event = $this->create_action_event($course->id, $book->id, 304 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 305 306 // Now, log out. 307 $this->setUser(); 308 309 // Create an action factory. 310 $factory = new \core_calendar\action_factory(); 311 312 // Decorate action event for the student. 313 $actionevent = mod_book_core_calendar_provide_event_action($event, $factory, $student->id); 314 315 // Confirm the event was decorated. 316 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 317 $this->assertEquals(get_string('view'), $actionevent->get_name()); 318 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 319 $this->assertEquals(1, $actionevent->get_item_count()); 320 $this->assertTrue($actionevent->is_actionable()); 321 } 322 323 public function test_book_core_calendar_provide_event_action_as_non_user() { 324 global $CFG; 325 326 // Create the activity. 327 $course = $this->getDataGenerator()->create_course(); 328 $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id)); 329 330 // Create a calendar event. 331 $event = $this->create_action_event($course->id, $book->id, 332 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 333 334 // Log out the user and set force login to true. 335 \core\session\manager::init_empty_session(); 336 $CFG->forcelogin = true; 337 338 // Create an action factory. 339 $factory = new \core_calendar\action_factory(); 340 341 // Decorate action event. 342 $actionevent = mod_book_core_calendar_provide_event_action($event, $factory); 343 344 // Ensure result was null. 345 $this->assertNull($actionevent); 346 } 347 348 public function test_book_core_calendar_provide_event_action_already_completed() { 349 global $CFG; 350 351 $CFG->enablecompletion = 1; 352 353 // Create the activity. 354 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 355 $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id), 356 array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); 357 358 // Get some additional data. 359 $cm = get_coursemodule_from_instance('book', $book->id); 360 361 // Create a calendar event. 362 $event = $this->create_action_event($course->id, $book->id, 363 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 364 365 // Mark the activity as completed. 366 $completion = new \completion_info($course); 367 $completion->set_module_viewed($cm); 368 369 // Create an action factory. 370 $factory = new \core_calendar\action_factory(); 371 372 // Decorate action event. 373 $actionevent = mod_book_core_calendar_provide_event_action($event, $factory); 374 375 // Ensure result was null. 376 $this->assertNull($actionevent); 377 } 378 379 public function test_book_core_calendar_provide_event_action_already_completed_for_user() { 380 global $CFG; 381 382 $CFG->enablecompletion = 1; 383 384 // Create the activity. 385 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 386 $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id), 387 array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); 388 389 // Enrol a student in the course. 390 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 391 392 // Get some additional data. 393 $cm = get_coursemodule_from_instance('book', $book->id); 394 395 // Create a calendar event. 396 $event = $this->create_action_event($course->id, $book->id, 397 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 398 399 // Mark the activity as completed for the student. 400 $completion = new \completion_info($course); 401 $completion->set_module_viewed($cm, $student->id); 402 403 // Create an action factory. 404 $factory = new \core_calendar\action_factory(); 405 406 // Decorate action event for the student. 407 $actionevent = mod_book_core_calendar_provide_event_action($event, $factory, $student->id); 408 409 // Ensure result was null. 410 $this->assertNull($actionevent); 411 } 412 413 /** 414 * Creates an action event. 415 * 416 * @param int $courseid The course id. 417 * @param int $instanceid The instance id. 418 * @param string $eventtype The event type. 419 * @return bool|calendar_event 420 */ 421 private function create_action_event($courseid, $instanceid, $eventtype) { 422 $event = new \stdClass(); 423 $event->name = 'Calendar event'; 424 $event->modulename = 'book'; 425 $event->courseid = $courseid; 426 $event->instance = $instanceid; 427 $event->type = CALENDAR_EVENT_TYPE_ACTION; 428 $event->eventtype = $eventtype; 429 $event->timestart = time(); 430 431 return \calendar_event::create($event); 432 } 433 434 public function test_mod_book_get_tagged_chapters() { 435 global $DB; 436 437 $this->resetAfterTest(); 438 $this->setAdminUser(); 439 440 // Setup test data. 441 $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book'); 442 $course3 = $this->getDataGenerator()->create_course(); 443 $course2 = $this->getDataGenerator()->create_course(); 444 $course1 = $this->getDataGenerator()->create_course(); 445 $book1 = $this->getDataGenerator()->create_module('book', array('course' => $course1->id)); 446 $book2 = $this->getDataGenerator()->create_module('book', array('course' => $course2->id)); 447 $book3 = $this->getDataGenerator()->create_module('book', array('course' => $course3->id)); 448 $chapter11 = $bookgenerator->create_content($book1, array('tags' => array('Cats', 'Dogs'))); 449 $chapter12 = $bookgenerator->create_content($book1, array('tags' => array('Cats', 'mice'))); 450 $chapter13 = $bookgenerator->create_content($book1, array('tags' => array('Cats'))); 451 $chapter14 = $bookgenerator->create_content($book1); 452 $chapter15 = $bookgenerator->create_content($book1, array('tags' => array('Cats'))); 453 $chapter16 = $bookgenerator->create_content($book1, array('tags' => array('Cats'), 'hidden' => true)); 454 $chapter21 = $bookgenerator->create_content($book2, array('tags' => array('Cats'))); 455 $chapter22 = $bookgenerator->create_content($book2, array('tags' => array('Cats', 'Dogs'))); 456 $chapter23 = $bookgenerator->create_content($book2, array('tags' => array('mice', 'Cats'))); 457 $chapter31 = $bookgenerator->create_content($book3, array('tags' => array('mice', 'Cats'))); 458 459 $tag = \core_tag_tag::get_by_name(0, 'Cats'); 460 461 // Admin can see everything. 462 $res = mod_book_get_tagged_chapters($tag, /*$exclusivemode = */false, 463 /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$chapter = */0); 464 $this->assertMatchesRegularExpression('/'.$chapter11->title.'</', $res->content); 465 $this->assertMatchesRegularExpression('/'.$chapter12->title.'</', $res->content); 466 $this->assertMatchesRegularExpression('/'.$chapter13->title.'</', $res->content); 467 $this->assertDoesNotMatchRegularExpression('/'.$chapter14->title.'</', $res->content); 468 $this->assertMatchesRegularExpression('/'.$chapter15->title.'</', $res->content); 469 $this->assertMatchesRegularExpression('/'.$chapter16->title.'</', $res->content); 470 $this->assertDoesNotMatchRegularExpression('/'.$chapter21->title.'</', $res->content); 471 $this->assertDoesNotMatchRegularExpression('/'.$chapter22->title.'</', $res->content); 472 $this->assertDoesNotMatchRegularExpression('/'.$chapter23->title.'</', $res->content); 473 $this->assertDoesNotMatchRegularExpression('/'.$chapter31->title.'</', $res->content); 474 $this->assertEmpty($res->prevpageurl); 475 $this->assertNotEmpty($res->nextpageurl); 476 $res = mod_book_get_tagged_chapters($tag, /*$exclusivemode = */false, 477 /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$chapter = */1); 478 $this->assertDoesNotMatchRegularExpression('/'.$chapter11->title.'</', $res->content); 479 $this->assertDoesNotMatchRegularExpression('/'.$chapter12->title.'</', $res->content); 480 $this->assertDoesNotMatchRegularExpression('/'.$chapter13->title.'</', $res->content); 481 $this->assertDoesNotMatchRegularExpression('/'.$chapter14->title.'</', $res->content); 482 $this->assertDoesNotMatchRegularExpression('/'.$chapter15->title.'</', $res->content); 483 $this->assertDoesNotMatchRegularExpression('/'.$chapter16->title.'</', $res->content); 484 $this->assertMatchesRegularExpression('/'.$chapter21->title.'</', $res->content); 485 $this->assertMatchesRegularExpression('/'.$chapter22->title.'</', $res->content); 486 $this->assertMatchesRegularExpression('/'.$chapter23->title.'</', $res->content); 487 $this->assertMatchesRegularExpression('/'.$chapter31->title.'</', $res->content); 488 $this->assertNotEmpty($res->prevpageurl); 489 $this->assertEmpty($res->nextpageurl); 490 491 // Create and enrol a user. 492 $student = self::getDataGenerator()->create_user(); 493 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 494 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); 495 $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); 496 $this->setUser($student); 497 \core_tag_index_builder::reset_caches(); 498 499 // User can not see chapters in course 3 because he is not enrolled. 500 $res = mod_book_get_tagged_chapters($tag, /*$exclusivemode = */false, 501 /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$chapter = */1); 502 $this->assertMatchesRegularExpression('/'.$chapter22->title.'/', $res->content); 503 $this->assertMatchesRegularExpression('/'.$chapter23->title.'/', $res->content); 504 $this->assertDoesNotMatchRegularExpression('/'.$chapter31->title.'/', $res->content); 505 506 // User can search book chapters inside a course. 507 $coursecontext = \context_course::instance($course1->id); 508 $res = mod_book_get_tagged_chapters($tag, /*$exclusivemode = */false, 509 /*$fromctx = */0, /*$ctx = */$coursecontext->id, /*$rec = */1, /*$chapter = */0); 510 $this->assertMatchesRegularExpression('/'.$chapter11->title.'/', $res->content); 511 $this->assertMatchesRegularExpression('/'.$chapter12->title.'/', $res->content); 512 $this->assertMatchesRegularExpression('/'.$chapter13->title.'/', $res->content); 513 $this->assertDoesNotMatchRegularExpression('/'.$chapter14->title.'/', $res->content); 514 $this->assertMatchesRegularExpression('/'.$chapter15->title.'/', $res->content); 515 $this->assertDoesNotMatchRegularExpression('/'.$chapter21->title.'/', $res->content); 516 $this->assertDoesNotMatchRegularExpression('/'.$chapter22->title.'/', $res->content); 517 $this->assertDoesNotMatchRegularExpression('/'.$chapter23->title.'/', $res->content); 518 $this->assertEmpty($res->nextpageurl); 519 520 // User cannot see hidden chapters. 521 $this->assertDoesNotMatchRegularExpression('/'.$chapter16->title.'/', $res->content); 522 } 523 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body