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