first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,84 @@
@mod @mod_book @core_completion
Feature: View activity completion information in the book activity
In order to have visibility of book completion requirements
As a student
I need to be able to view my book completion progress
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Vinnie | Student1 | student1@example.com |
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | enablecompletion | showcompletionconditions |
| Course 1 | C1 | 1 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following "activity" exists:
| activity | book |
| course | C1 |
| idnumber | mh1 |
| name | Music history |
| completion | 2 |
| completionview | 1 |
Scenario: View automatic completion items
Given the following "mod_book > chapter" exists:
| book | Music history |
| title | Drum theory |
| content | Rudiments are important |
And I am on the "Music history" "book activity" page logged in as teacher1
And "Music history" should have the "View" completion condition
# Student view.
When I am on the "Music history" "book activity" page logged in as student1
Then the "View" completion condition of "Music history" is displayed as "done"
Scenario: View automatic completion items with last section hidden
Given the following "activity" exists:
| activity | book |
| course | C1 |
| idnumber | arth1 |
| name | Art history |
| completion | 2 |
| completionview | 1 |
And the following "mod_book > chapters" exist:
| book | title | content | pagenum | subchapter | hidden |
| Art history | First chapter | First chapter | 1 | 0 | 0 |
| Art history | Second chapter | Second chapter | 2 | 0 | 0 |
| Art history | Sub chapter 1 | Sub chapter | 3 | 1 | 0 |
| Art history | Sub chapter 2 | Sub chapter | 4 | 1 | 0 |
| Art history | Sub chapter 3 | Sub chapter | 5 | 1 | 1 |
When I am on the "Art history" "book activity" page logged in as student1
And I should see "First chapter"
And the "View" completion condition of "Art history" is displayed as "todo"
And I follow "Next"
And I should see "Second chapter"
And the "View" completion condition of "Art history" is displayed as "todo"
And I follow "Next"
And I should see "Sub chapter 1"
And the "View" completion condition of "Art history" is displayed as "todo"
And I follow "Next"
And I should see "Sub chapter 2"
And I should not see "Next"
Then the "View" completion condition of "Art history" is displayed as "done"
@javascript
Scenario: Use manual completion
Given I am on the "Music history" "book activity editing" page logged in as teacher1
And I expand all fieldsets
And I set the field "Students must manually mark the activity as done" to "1"
And I press "Save and display"
And I set the following fields to these values:
| Chapter title | Drum theory |
| Content | Rudiments are important |
And I press "Save changes"
And I am on the "Music history" "book activity" page
# Teacher view.
And the manual completion button for "Music history" should be disabled
# Student view.
Given I am on the "Music history" "book activity" page logged in as student1
Then the manual completion button of "Music history" is displayed as "Mark as done"
And I toggle the manual completion state of "Music history"
And the manual completion button of "Music history" is displayed as "Done"
@@ -0,0 +1,88 @@
@mod @mod_book
Feature: In a book, create chapters and sub chapters
In order to create chapters and subchapters
As a teacher
I need to add chapters and subchapters to a book.
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "course" exists:
| fullname | Course 1 |
| shortname | C1 |
| format | topics |
| numsections | 1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | course | section |
| book | Test book | C1 | 1 |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
Scenario: Create chapters and sub chapters and navigate between them
Given the following "mod_book > chapter" exists:
| book | Test book |
| title | Dummy first chapter |
| content | Dream is the start of a journey |
And I am on the "Test book" "book activity" page
And I should not see "No content has been added to this book yet."
And I should see "1. Dummy first chapter" in the "Table of contents" "block"
And I click on "Add new chapter after \"Dummy first chapter\"" "link" in the "Table of contents" "block"
And I should see "Dummy first chapter"
And I set the following fields to these values:
| Chapter title | Dummy second chapter |
| Content | The path is the second part |
And I press "Save changes"
And I should see "2. Dummy second chapter" in the "Table of contents" "block"
And I click on "Add new chapter after \"Dummy first chapter\"" "link" in the "Table of contents" "block"
And I should see "Dummy first chapter"
And I set the following fields to these values:
| Chapter title | Dummy first subchapter |
| Content | The path is the second part |
| Subchapter | true |
And I press "Save changes"
And I should see "1.1. Dummy first subchapter" in the "Table of contents" "block"
And I should see "1. Dummy first chapter" in the ".book_content" "css_element"
And I should see "1.1. Dummy first subchapter" in the ".book_content" "css_element"
And I click on "Next" "link"
And I should see "2. Dummy second chapter" in the ".book_content" "css_element"
And I should see "2. Dummy second chapter" in the "strong" "css_element"
And I should not see "Next" in the ".book_content" "css_element"
And I am on "Course 1" course homepage
And I should see "Test book" in the "New section" "section"
And I click on "Test book" "link" in the "New section" "section"
And I should not see "Previous" in the ".book_content" "css_element"
And I should see "1. Dummy first chapter" in the "strong" "css_element"
When I click on "Next" "link"
Then I should see "1.1. Dummy first subchapter" in the ".book_content" "css_element"
And I should see "1.1. Dummy first subchapter" in the "strong" "css_element"
And I click on "Previous" "link"
And I should see "1. Dummy first chapter" in the ".book_content" "css_element"
And I should see "1. Dummy first chapter" in the "strong" "css_element"
Scenario: Change editing mode for an individual chapter
Given the following "mod_book > chapter" exists:
| book | Test book |
| title | Dummy first chapter |
| content | Dream is the start of a journey |
And I am on the "Test book" "book activity" page
And I should see "1. Dummy first chapter" in the "Table of contents" "block"
And "Edit chapter \"1. Dummy first chapter\"" "link" should exist in the "Table of contents" "block"
And "Delete chapter \"1. Dummy first chapter\"" "link" should exist in the "Table of contents" "block"
And "Hide chapter \"1. Dummy first chapter\"" "link" should exist in the "Table of contents" "block"
And "Add new chapter" "link" should exist in the "Table of contents" "block"
When I turn editing mode off
Then "Edit chapter \"1. Dummy first chapter\"" "link" should not exist in the "Table of contents" "block"
And "Delete chapter \"1. Dummy first chapter\"" "link" should not exist in the "Table of contents" "block"
And "Hide chapter \"1. Dummy first chapter\"" "link" should not exist in the "Table of contents" "block"
And "Add new chapter after \"Dummy first chapter\"" "link" should not exist in the "Table of contents" "block"
Scenario: When chapters are not created yet, students can see a notification in the book activity
Given I am on the "Test book" "book activity" page logged in as student1
Then I should see "No content has been added to this book yet." in the ".alert-info" "css_element"
And I should not see "Table of contents"
@@ -0,0 +1,55 @@
@mod @mod_book
Feature: Display the book description in the book and optionally in the course
In order to display the the book description in the course
As a teacher
I need to enable the 'Display description on course page' setting.
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| book | Test book | A book about dreams! | C1 | book1 |
And the following "mod_book > chapter" exists:
| book | Test book |
| title | Dummy first chapter |
| content | Dream is the start of a journey |
Scenario: Description is displayed in the book
When I am on the "Test book" "book activity" page logged in as teacher1
Then I should see "A book about dreams!"
Scenario: Show book description in the course homepage
Given I am on the "Test book" "book activity editing" page logged in as teacher1
And the following fields match these values:
| Display description on course page | |
And I set the following fields to these values:
| Display description on course page | 1 |
When I press "Save and return to course"
Then I should see "A book about dreams!"
Scenario: Hide book description in the course homepage
Given I am on the "Test book" "book activity editing" page logged in as teacher1
And the following fields match these values:
| Display description on course page | |
When I press "Save and return to course"
Then I should not see "A book about dreams!"
@javascript
Scenario: Description is displayed in the book for students when there are no chapters added yet
Given I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I am on the "Test book" "book activity" page
And I click on "Delete chapter \"1. Dummy first chapter\"" "link" in the "Table of contents" "block"
And I click on "Yes" "button" in the "Confirmation" "dialogue"
And I am on the "Test book" "book activity" page logged in as student1
Then I should see "A book about dreams!"
@@ -0,0 +1,43 @@
@mod @mod_book
Feature: In a book, change the navigation options
In order to change the way a book's chapters can be traversed
As a teacher
I need to change navigation options on a book
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And I log in as "teacher1"
# The option to "Style of navigation" is removed from the settings.
Scenario: Change navigation options
Given the following "activities" exist:
| activity | name | course | idnumber | navstyle |
| book | Test book | C1 | book1 | 0 |
And I am on "Course 1" course homepage with editing mode on
And I follow "Test book"
And I should see "Add new chapter"
And I set the following fields to these values:
| Chapter title | Test chapter 1 |
| Content | Lorem ipsum dolor sit amet |
And I press "Save changes"
And I should see "Test book"
And I should see "1. Test chapter 1"
And I click on "Add new chapter" "link" in the "Table of contents" "block"
And I set the following fields to these values:
| Chapter title | Test chapter 2 |
| Content | consectetur adipiscing elit |
And I press "Save changes"
And I should see "Test book"
And I should see "2. Test chapter 2"
And I click on "1. Test chapter 1" "link" in the "Table of contents" "block"
And "Next" "link" should exist
And I click on "2. Test chapter 2" "link" in the "Table of contents" "block"
And "Previous" "link" should exist
+65
View File
@@ -0,0 +1,65 @@
@mod @mod_book @core_tag @javascript
Feature: Edited book chapters handle tags correctly
In order to get book chapters properly labelled
As a user
I need to introduce the tags while editing
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "activity" exists:
| activity | book |
| course | C1 |
| idnumber | book1 |
| name | Test book |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
Scenario: Book chapter edition of custom tags works as expected
Given I am on the "Test book" "book activity" page logged in as teacher1
And I set the following fields to these values:
| Chapter title | Dummy first chapter |
| Content | Dream is the start of a journey |
| Tags | Example, Chapter, Cool |
And I press "Save changes"
Then I should see "Example" in the ".book-tags" "css_element"
And I should see "Chapter" in the ".book-tags" "css_element"
And I should see "Cool" in the ".book-tags" "css_element"
And I turn editing mode on
And I follow "Edit chapter \"1. Dummy first chapter\""
Then I should see "Example" in the ".form-autocomplete-selection" "css_element"
Then I should see "Chapter" in the ".form-autocomplete-selection" "css_element"
Then I should see "Cool" in the ".form-autocomplete-selection" "css_element"
@javascript
Scenario: Book chapter edition of standard tags works as expected
Given the following "tags" exist:
| name | isstandard |
| OT1 | 1 |
| OT2 | 1 |
| OT3 | 1 |
And I am on the "Test book" "book activity" page logged in as teacher1
And I open the autocomplete suggestions list
And I should see "OT1" in the ".form-autocomplete-suggestions" "css_element"
And I should see "OT2" in the ".form-autocomplete-suggestions" "css_element"
And I should see "OT3" in the ".form-autocomplete-suggestions" "css_element"
When I set the following fields to these values:
| Chapter title | Dummy first chapter |
| Content | Dream is the start of a journey |
| Tags | OT1, OT3 |
And I press "Save changes"
Then I should see "OT1" in the ".book-tags" "css_element"
And I should see "OT3" in the ".book-tags" "css_element"
And I should not see "OT2" in the ".book-tags" "css_element"
And I turn editing mode on
And I follow "Edit chapter \"1. Dummy first chapter\""
And I should see "OT1" in the ".form-autocomplete-selection" "css_element"
And I should see "OT3" in the ".form-autocomplete-selection" "css_element"
And I should not see "OT2" in the ".form-autocomplete-selection" "css_element"
+69
View File
@@ -0,0 +1,69 @@
@mod @mod_book
Feature: In a book, verify log entries
In order to create log entries
As an admin
I need to perform various actions in a book.
@javascript @_switch_window
Scenario: perform various book actions and verify log entries.
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "activity" exists:
| course | C1 |
| activity | book |
| name | Test book |
And I am on the "Course 1" course page logged in as admin
And I turn editing mode on
And I am on the "Test book" "book activity" page
And I set the following fields to these values:
| Chapter title | First chapter |
| Content | First chapter |
And I press "Save changes"
And I click on "Add new chapter" "link" in the "Table of contents" "block"
And I set the following fields to these values:
| Chapter title | Second chapter |
| Content | Second chapter |
And I press "Save changes"
And I click on "Edit" "link" in the "Table of contents" "block"
And I set the following fields to these values:
| Chapter title | First chapter edited |
| Content | First chapter edited |
And I press "Save changes"
And I click on "Next" "link"
And I click on "Previous" "link"
And I navigate to "Print book" in current page administration
And I am on the "Test book" "book activity" page
And I navigate to "Download IMS CP" in current page administration
And I navigate to "Reports > Logs" in site administration
And I set the field "menuid" to "Course 1"
And I press "Get these logs"
Then I should see "Book exported"
And I should see "Book printed"
And I should see "Chapter viewed" in the "#report_log_r4_c5" "css_element"
And I should see "Chapter viewed" in the "#report_log_r5_c5" "css_element"
And I should see "Chapter viewed" in the "#report_log_r6_c5" "css_element"
And I should see "Chapter updated" in the "#report_log_r7_c5" "css_element"
And I should see "Chapter viewed" in the "#report_log_r8_c5" "css_element"
And I should see "Chapter created" in the "#report_log_r9_c5" "css_element"
And I click on "Chapter viewed" "link" in the "#report_log_r4_c5" "css_element"
And I switch to "action" window
And I change window size to "large"
And I should see "1. First chapter edited" in the ".book_content" "css_element"
And I switch to the main window
And I click on "Chapter viewed" "link" in the "#report_log_r5_c5" "css_element"
And I switch to "action" window
And I should see "2. Second chapter" in the ".book_content" "css_element"
And I switch to the main window
And I click on "Chapter updated" "link" in the "#report_log_r7_c5" "css_element"
And I switch to "action" window
And I should see "1. First chapter edited" in the ".book_content" "css_element"
And I switch to the main window
And I click on "Chapter created" "link" in the "#report_log_r9_c5" "css_element"
And I switch to "action" window
And I should see "2. Second chapter" in the ".book_content" "css_element"
And I switch to the main window
And I click on "Chapter created" "link" in the "#report_log_r11_c5" "css_element"
And I switch to "action" window
And I should see "1. First chapter edited" in the ".book_content" "css_element"
And I switch to the main window
@@ -0,0 +1,75 @@
@mod @mod_book
Feature: In a book, chapters and subchapters can be rearranged
In order to rearrange chapters and subchapters
As a teacher
I need to move chapters and subchapters up and down.
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| book | Test book | C1 | book1 |
And the following "mod_book > chapters" exist:
| book | title | content | pagenum |subchapter |
| Test book | Originally first chapter | #1 chapter content | 1 | 0 |
| Test book | A great second chapter | #2 chapter content | 2 | 0 |
| Test book | Second chapter, subchapter 1 | #21 subchapter content | 3 | 1 |
| Test book | Second chapter, subchapter 2 | #22 subchapter content | 4 | 1 |
| Test book | There aren't 2 without 3 | #3 subchapter content | 5 | 0 |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I follow "Test book"
Scenario: Moving chapters down rearranges them properly
Given I click on "Move chapter down \"1. Originally first chapter\"" "link"
When I am on the "Test book" "book activity" page
Then I should see "1. A great second chapter"
And I should see "#2 chapter content"
And I should see "1.1. Second chapter, subchapter 1"
And I should see "1.2. Second chapter, subchapter 2"
And I should see "2. Originally first chapter"
And I should see "3. There aren't 2 without 3"
Scenario: Moving chapters up rearranges them properly
Given I click on "Move chapter up \"3. There aren't 2 without 3\"" "link"
When I am on the "Test book" "book activity" page
Then I should see "1. Originally first chapter"
And I should see "#1 chapter content"
And I should see "2. There aren't 2 without 3"
And I should see "3. A great second chapter"
And I should see "3.1. Second chapter, subchapter 1"
And I should see "3.2. Second chapter, subchapter 2"
Scenario: Moving subchapters down within chapter rearranges them properly
Given I click on "Move chapter down \"2.1. Second chapter, subchapter 1\"" "link"
When I should see "2.1. Second chapter, subchapter 2"
Then I should see "2.2. Second chapter, subchapter 1"
Scenario: Moving subchapters down out of chapter rearranges them properly
Given I click on "Move chapter down \"2.2. Second chapter, subchapter 2\"" "link"
When I should see "3.1. Second chapter, subchapter 2"
Then I click on "Move chapter down \"3. There aren't 2 without 3\"" "link"
And I should not see "4. There aren't 2 without 3"
And I should see "3. There aren't 2 without 3"
And I should see "3.1. Second chapter, subchapter 2"
Scenario: Moving subchapters up within chapter rearranges them properly
Given I click on "Move chapter up \"2.2. Second chapter, subchapter 2\"" "link"
When I should see "2.1. Second chapter, subchapter 2"
Then I should see "2.2. Second chapter, subchapter 1"
Scenario: Moving subchapters up out of chapter rearranges them properly
Given I click on "Move chapter up \"2.1. Second chapter, subchapter 1\"" "link"
When I should see "1.1. Second chapter, subchapter 1"
Then I click on "Move chapter up \"1.1. Second chapter, subchapter 1\"" "link"
And I should not see "1.1. Second chapter, subchapter 1"
And I should see "1. Second chapter, subchapter 1"
And I should see "2. Originally first chapter"
@@ -0,0 +1,59 @@
@mod @mod_book
Feature: Book activity chapter visibility management
In order to properly manage chapters in a book activity
As a teacher
I need to be able to show or hide chapters.
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 2 | student1@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activity" exists:
| course | C1 |
| activity | book |
| name | Test book |
And the following "mod_book > chapters" exist:
| book | title | content | pagenum |subchapter |
| Test book | First chapter | First chapter | 1 | 0 |
| Test book | Second chapter | Second chapter | 2 | 0 |
| Test book | Sub chapter | Sub chapter | 3 | 1 |
| Test book | Third chapter | Third chapter | 4 | 0 |
| Test book | Fourth chapter | Fourth chapter | 5 | 0 |
And I am on the "Course 1" course page logged in as teacher1
And I turn editing mode on
And I am on the "Test book" "book activity" page
And I click on "4. Fourth chapter" "link" in the "Table of contents" "block"
@javascript
Scenario: Show/hide chapters and subchapters
When I follow "Hide chapter \"2. Second chapter\""
And I follow "Hide chapter \"2. Third chapter\""
And I am on the "Test book" "book activity" page
And I am on "Course 1" course homepage
And I turn editing mode off
And I click on "Test book" "link" in the "region-main" "region"
Then the "class" attribute of "a[title='Second chapter']" "css_element" should contain "dimmed_text"
And the "class" attribute of "a[title='Third chapter']" "css_element" should contain "dimmed_text"
And I am on "Course 1" course homepage with editing mode on
And I click on "Test book" "link" in the "region-main" "region"
And I follow "Next"
And I should see "Second chapter" in the ".book_content" "css_element"
And I follow "Next"
And I should see "Sub chapter" in the ".book_content" "css_element"
And I follow "Next"
And I should see "Third chapter" in the ".book_content" "css_element"
And I follow "Next"
And I should see "Fourth chapter" in the ".book_content" "css_element"
And I am on the "Test book" "book activity" page logged in as student1
And I should not see "Second chapter" in the "Table of contents" "block"
And I should not see "Third chapter" in the "Table of contents" "block"
And I follow "Next"
And I should see "Fourth chapter" in the ".book_content" "css_element"
+196
View File
@@ -0,0 +1,196 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Events tests.
*
* @package mod_book
* @category phpunit
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_book\event;
/**
* Events tests class.
*
* @package mod_book
* @category phpunit
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class events_test extends \advanced_testcase {
public function setUp(): void {
$this->resetAfterTest();
}
public function test_chapter_created(): void {
// There is no proper API to call to generate chapters for a book, so what we are
// doing here is simply making sure that the events returns the right information.
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$context = \context_module::instance($book->cmid);
$chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
$event = \mod_book\event\chapter_created::create_from_chapter($book, $context, $chapter);
// Triggering and capturing the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_book\event\chapter_created', $event);
$this->assertEquals(\context_module::instance($book->cmid), $event->get_context());
$this->assertEquals($chapter->id, $event->objectid);
}
public function test_chapter_updated(): void {
// There is no proper API to call to generate chapters for a book, so what we are
// doing here is simply making sure that the events returns the right information.
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$context = \context_module::instance($book->cmid);
$chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
$event = \mod_book\event\chapter_updated::create_from_chapter($book, $context, $chapter);
// Triggering and capturing the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_book\event\chapter_updated', $event);
$this->assertEquals(\context_module::instance($book->cmid), $event->get_context());
$this->assertEquals($chapter->id, $event->objectid);
}
public function test_chapter_deleted(): void {
// There is no proper API to call to delete chapters for a book, so what we are
// doing here is simply making sure that the events returns the right information.
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$context = \context_module::instance($book->cmid);
$chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
$event = \mod_book\event\chapter_deleted::create_from_chapter($book, $context, $chapter);
$legacy = array($course->id, 'book', 'update', 'view.php?id='.$book->cmid, $book->id, $book->cmid);
// Triggering and capturing the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_book\event\chapter_deleted', $event);
$this->assertEquals(\context_module::instance($book->cmid), $event->get_context());
$this->assertEquals($chapter->id, $event->objectid);
$this->assertEquals($chapter, $event->get_record_snapshot('book_chapters', $chapter->id));
}
public function test_course_module_instance_list_viewed(): void {
// There is no proper API to call to trigger this event, so what we are
// doing here is simply making sure that the events returns the right information.
$course = $this->getDataGenerator()->create_course();
$params = array(
'context' => \context_course::instance($course->id)
);
$event = \mod_book\event\course_module_instance_list_viewed::create($params);
// Triggering and capturing the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_book\event\course_module_instance_list_viewed', $event);
$this->assertEquals(\context_course::instance($course->id), $event->get_context());
}
public function test_course_module_viewed(): void {
// There is no proper API to call to trigger this event, so what we are
// doing here is simply making sure that the events returns the right information.
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$params = array(
'context' => \context_module::instance($book->cmid),
'objectid' => $book->id
);
$event = \mod_book\event\course_module_viewed::create($params);
// Triggering and capturing the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_book\event\course_module_viewed', $event);
$this->assertEquals(\context_module::instance($book->cmid), $event->get_context());
$this->assertEquals($book->id, $event->objectid);
}
public function test_chapter_viewed(): void {
// There is no proper API to call to trigger this event, so what we are
// doing here is simply making sure that the events returns the right information.
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$context = \context_module::instance($book->cmid);
$chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
$event = \mod_book\event\chapter_viewed::create_from_chapter($book, $context, $chapter);
// Triggering and capturing the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_book\event\chapter_viewed', $event);
$this->assertEquals(\context_module::instance($book->cmid), $event->get_context());
$this->assertEquals($chapter->id, $event->objectid);
}
}
+198
View File
@@ -0,0 +1,198 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_book;
use core_external\external_api;
use externallib_advanced_testcase;
use mod_book_external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
/**
* External mod_book functions unit tests
*
* @package mod_book
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
class externallib_test extends externallib_advanced_testcase {
/**
* Test view_book
*/
public function test_view_book(): void {
global $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
// Setup test data.
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
$chapterhidden = $bookgenerator->create_chapter(array('bookid' => $book->id, 'hidden' => 1));
$context = \context_module::instance($book->cmid);
$cm = get_coursemodule_from_instance('book', $book->id);
// Test invalid instance id.
try {
mod_book_external::view_book(0);
$this->fail('Exception expected due to invalid mod_book instance id.');
} catch (\moodle_exception $e) {
$this->assertEquals('invalidrecord', $e->errorcode);
}
// Test not-enrolled user.
$user = self::getDataGenerator()->create_user();
$this->setUser($user);
try {
mod_book_external::view_book($book->id, 0);
$this->fail('Exception expected due to not enrolled user.');
} catch (\moodle_exception $e) {
$this->assertEquals('requireloginerror', $e->errorcode);
}
// Test user with full capabilities.
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
// Trigger and capture the event.
$sink = $this->redirectEvents();
$result = mod_book_external::view_book($book->id, 0);
$result = external_api::clean_returnvalue(mod_book_external::view_book_returns(), $result);
$events = $sink->get_events();
$this->assertCount(2, $events);
$event = array_shift($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_book\event\course_module_viewed', $event);
$this->assertEquals($context, $event->get_context());
$moodleurl = new \moodle_url('/mod/book/view.php', array('id' => $cm->id));
$this->assertEquals($moodleurl, $event->get_url());
$this->assertEventContextNotUsed($event);
$this->assertNotEmpty($event->get_name());
$event = array_shift($events);
$this->assertInstanceOf('\mod_book\event\chapter_viewed', $event);
$this->assertEquals($chapter->id, $event->objectid);
$result = mod_book_external::view_book($book->id, $chapter->id);
$result = external_api::clean_returnvalue(mod_book_external::view_book_returns(), $result);
$events = $sink->get_events();
// We expect a total of 3 events.
$this->assertCount(3, $events);
// Try to view a hidden chapter.
try {
mod_book_external::view_book($book->id, $chapterhidden->id);
$this->fail('Exception expected due to missing capability.');
} catch (\moodle_exception $e) {
$this->assertEquals('errorchapter', $e->errorcode);
}
// Test user with no capabilities.
// We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
assign_capability('mod/book:read', CAP_PROHIBIT, $studentrole->id, $context->id);
accesslib_clear_all_caches_for_unit_testing();
try {
mod_book_external::view_book($book->id, 0);
$this->fail('Exception expected due to missing capability.');
} catch (\moodle_exception $e) {
$this->assertEquals('nopermissions', $e->errorcode);
}
}
/**
* Test get_books_by_courses
*/
public function test_get_books_by_courses(): void {
global $DB, $USER;
$this->resetAfterTest(true);
$this->setAdminUser();
$course1 = self::getDataGenerator()->create_course();
$bookoptions1 = array(
'course' => $course1->id,
'name' => 'First Book'
);
$book1 = self::getDataGenerator()->create_module('book', $bookoptions1);
$course2 = self::getDataGenerator()->create_course();
$bookoptions2 = array(
'course' => $course2->id,
'name' => 'Second Book'
);
$book2 = self::getDataGenerator()->create_module('book', $bookoptions2);
$student1 = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
// Enroll Student1 in Course1.
self::getDataGenerator()->enrol_user($student1->id, $course1->id, $studentrole->id);
$this->setUser($student1);
$books = mod_book_external::get_books_by_courses();
// We need to execute the return values cleaning process to simulate the web service server.
$books = external_api::clean_returnvalue(mod_book_external::get_books_by_courses_returns(), $books);
$this->assertCount(1, $books['books']);
$this->assertEquals('First Book', $books['books'][0]['name']);
// We see 10 fields.
$this->assertCount(11, $books['books'][0]);
// As Student you cannot see some book properties like 'section'.
$this->assertFalse(isset($books['books'][0]['section']));
// Student1 is not enrolled in course2. The webservice will return a warning!
$books = mod_book_external::get_books_by_courses(array($course2->id));
// We need to execute the return values cleaning process to simulate the web service server.
$books = external_api::clean_returnvalue(mod_book_external::get_books_by_courses_returns(), $books);
$this->assertCount(0, $books['books']);
$this->assertEquals(1, $books['warnings'][0]['warningcode']);
// Now as admin.
$this->setAdminUser();
// As Admin we can see this book.
$books = mod_book_external::get_books_by_courses(array($course2->id));
// We need to execute the return values cleaning process to simulate the web service server.
$books = external_api::clean_returnvalue(mod_book_external::get_books_by_courses_returns(), $books);
$this->assertCount(1, $books['books']);
$this->assertEquals('Second Book', $books['books'][0]['name']);
// We see 17 fields.
$this->assertCount(18, $books['books'][0]);
// As an Admin you can see some book properties like 'section'.
$this->assertEquals(0, $books['books'][0]['section']);
// Enrol student in the second course.
self::getDataGenerator()->enrol_user($student1->id, $course2->id, $studentrole->id);
$this->setUser($student1);
$books = mod_book_external::get_books_by_courses();
$books = external_api::clean_returnvalue(mod_book_external::get_books_by_courses_returns(), $books);
$this->assertCount(2, $books['books']);
}
}
@@ -0,0 +1,58 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Behat data generator for mod_book.
*
* @package mod_book
* @category test
* @copyright 2021 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Behat data generator for mod_book.
*
* @copyright 2019 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_mod_book_generator extends behat_generator_base {
protected function get_creatable_entities(): array {
return [
'chapters' => [
'singular' => 'chapter',
'datagenerator' => 'chapter',
'required' => ['book', 'title', 'content'],
'switchids' => ['book' => 'bookid'],
],
];
}
/**
* Look up the id of a book from its name.
*
* @param string $bookname the book name, for example 'Test book'.
* @return int corresponding id.
*/
protected function get_book_id(string $bookname): int {
global $DB;
$cm = $this->get_cm_by_activity_name('book', $bookname);
return $cm->instance;
}
}
+138
View File
@@ -0,0 +1,138 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* mod_book data generator.
*
* @package mod_book
* @category test
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* mod_book data generator class.
*
* @package mod_book
* @category test
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_book_generator extends testing_module_generator {
/**
* @var int keep track of how many chapters have been created.
*/
protected $chaptercount = 0;
/**
* To be called from data reset code only,
* do not use in tests.
* @return void
*/
public function reset() {
$this->chaptercount = 0;
parent::reset();
}
public function create_instance($record = null, array $options = null) {
global $CFG;
require_once("$CFG->dirroot/mod/book/locallib.php");
$record = (object)(array)$record;
if (!isset($record->numbering)) {
$record->numbering = BOOK_NUM_NUMBERS;
}
if (!isset($record->customtitles)) {
$record->customtitles = 0;
}
return parent::create_instance($record, (array)$options);
}
public function create_chapter($record = null, array $options = null) {
global $DB;
$record = (object) (array) $record;
$options = (array) $options;
$this->chaptercount++;
if (empty($record->bookid)) {
throw new coding_exception('Chapter generator requires $record->bookid');
}
if (empty($record->title)) {
$record->title = "Chapter {$this->chaptercount}";
}
if (empty($record->pagenum)) {
$record->pagenum = 1;
}
if (!isset($record->subchapter)) {
$record->subchapter = 0;
}
if (!isset($record->hidden)) {
$record->hidden = 0;
}
if (!isset($record->importsrc)) {
$record->importsrc = '';
}
if (!isset($record->content)) {
$record->content = "Chapter {$this->chaptercount} content";
}
if (!isset($record->contentformat)) {
$record->contentformat = FORMAT_MOODLE;
}
if (!isset($record->timecreated)) {
$record->timecreated = time();
}
if (!isset($record->timemodified)) {
$record->timemodified = time();
}
// Make room for new page.
$sql = "UPDATE {book_chapters}
SET pagenum = pagenum + 1
WHERE bookid = ? AND pagenum >= ?";
$DB->execute($sql, array($record->bookid, $record->pagenum));
$record->id = $DB->insert_record('book_chapters', $record);
$sql = "UPDATE {book}
SET revision = revision + 1
WHERE id = ?";
$DB->execute($sql, array($record->bookid));
if (property_exists($record, 'tags')) {
$cm = get_coursemodule_from_instance('book', $record->bookid);
$tags = is_array($record->tags) ? $record->tags : preg_split('/,/', $record->tags);
core_tag_tag::set_item_tags('mod_book', 'book_chapters', $record->id,
context_module::instance($cm->id), $tags);
}
return $record;
}
public function create_content($instance, $record = array()) {
$record = (array)$record + array(
'bookid' => $instance->id
);
return $this->create_chapter($record);
}
}
+71
View File
@@ -0,0 +1,71 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_book;
/**
* Generator tests class.
*
* @package mod_book
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class generator_test extends \advanced_testcase {
public function test_create_instance(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$this->assertFalse($DB->record_exists('book', array('course' => $course->id)));
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$this->assertEquals(1, $DB->count_records('book', array('course' => $course->id)));
$this->assertTrue($DB->record_exists('book', array('course' => $course->id, 'id' => $book->id)));
$params = array('course' => $course->id, 'name' => 'One more book');
$book = $this->getDataGenerator()->create_module('book', $params);
$this->assertEquals(2, $DB->count_records('book', array('course' => $course->id)));
$this->assertEquals('One more book', $DB->get_field_select('book', 'name', 'id = :id', array('id' => $book->id)));
}
public function test_create_chapter(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$this->assertFalse($DB->record_exists('book_chapters', array('bookid' => $book->id)));
$bookgenerator->create_chapter(array('bookid' => $book->id));
$this->assertTrue($DB->record_exists('book_chapters', array('bookid' => $book->id)));
$chapter = $bookgenerator->create_chapter(
array('bookid' => $book->id, 'content' => 'Yay!', 'title' => 'Oops', 'tags' => array('Cats', 'mice')));
$this->assertEquals(2, $DB->count_records('book_chapters', array('bookid' => $book->id)));
$this->assertEquals('Oops', $DB->get_field_select('book_chapters', 'title', 'id = :id', array('id' => $chapter->id)));
$this->assertEquals('Yay!', $DB->get_field_select('book_chapters', 'content', 'id = :id', array('id' => $chapter->id)));
$this->assertEquals(array('Cats', 'mice'),
array_values(\core_tag_tag::get_item_tags_array('mod_book', 'book_chapters', $chapter->id)));
$chapter = $bookgenerator->create_content($book);
$this->assertEquals(3, $DB->count_records('book_chapters', array('bookid' => $book->id)));
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_book;
/**
* Helper test class
*
* @package mod_book
* @copyright 2023 Laurent David <laurent.david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper_test extends \advanced_testcase {
/**
* Test view_book
* @covers \mod_book\helper::is_last_visible_chapter
*/
public function test_is_last_chapter(): void {
$this->resetAfterTest(true);
$this->setAdminUser();
// Setup test data.
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$firstchapter =
$bookgenerator->create_chapter(array('bookid' => $book->id, 'pagenum' => 1)); // Create a first chapter to check that
// viewing the last chapter is enough for completing the activity.
$chapterhidden = $bookgenerator->create_chapter(array('bookid' => $book->id, 'hidden' => 1, 'pagenum' => 2));
$lastchapter = $bookgenerator->create_chapter(array('bookid' => $book->id, 'pagenum' => 3));
$chapters = book_preload_chapters($book);
$this->assertFalse(helper::is_last_visible_chapter($firstchapter->id, $chapters));
$this->assertFalse(helper::is_last_visible_chapter($chapterhidden->id, $chapters));
$this->assertTrue(helper::is_last_visible_chapter($lastchapter->id, $chapters));
}
}
+525
View File
@@ -0,0 +1,525 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for (some of) mod/book/lib.php.
*
* @package mod_book
* @category phpunit
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_book;
use core_external\external_api;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/book/lib.php');
/**
* Unit tests for (some of) mod/book/lib.php.
*
* @package mod_book
* @category phpunit
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class lib_test extends \advanced_testcase {
public function setUp(): void {
$this->resetAfterTest();
$this->setAdminUser();
}
public function test_export_contents(): void {
global $DB, $CFG;
require_once($CFG->dirroot . '/course/externallib.php');
$user = $this->getDataGenerator()->create_user();
$teacher = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course(array('enablecomment' => 1));
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
$this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
$this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
// Test book with 3 chapters.
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$cm = get_coursemodule_from_id('book', $book->cmid);
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$chapter1 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 1,
'tags' => array('Cats', 'Dogs')));
$tag = \core_tag_tag::get_by_name(0, 'Cats');
$chapter2 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 2));
$subchapter = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 3, "subchapter" => 1));
$chapter3 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 4, "hidden" => 1));
$this->setUser($user);
$contents = book_export_contents($cm, '');
// The hidden chapter must not be included, and additional page with the structure must be included.
$this->assertCount(4, $contents);
$this->assertEquals('structure', $contents[0]['filename']);
$this->assertEquals('index.html', $contents[1]['filename']);
$this->assertEquals('Chapter 1', $contents[1]['content']);
$this->assertCount(2, $contents[1]['tags']);
$this->assertEquals('Cats', $contents[1]['tags'][0]['rawname']);
$this->assertEquals($tag->id, $contents[1]['tags'][0]['id']);
$this->assertEquals('Dogs', $contents[1]['tags'][1]['rawname']);
$this->assertEquals('index.html', $contents[2]['filename']);
$this->assertEquals('Chapter 2', $contents[2]['content']);
$this->assertEquals('index.html', $contents[3]['filename']);
$this->assertEquals('Chapter 3', $contents[3]['content']);
// Now, test the function via the external API.
$contents = \core_course_external::get_course_contents($course->id, array());
$contents = external_api::clean_returnvalue(\core_course_external::get_course_contents_returns(), $contents);
$this->assertCount(4, $contents[0]['modules'][0]['contents']);
$this->assertEquals('content', $contents[0]['modules'][0]['contents'][0]['type']);
$this->assertEquals('structure', $contents[0]['modules'][0]['contents'][0]['filename']);
$this->assertEquals('file', $contents[0]['modules'][0]['contents'][1]['type']);
$this->assertEquals('Chapter 1', $contents[0]['modules'][0]['contents'][1]['content']);
$this->assertEquals('file', $contents[0]['modules'][0]['contents'][2]['type']);
$this->assertEquals('Chapter 2', $contents[0]['modules'][0]['contents'][2]['content']);
$this->assertEquals('file', $contents[0]['modules'][0]['contents'][3]['type']);
$this->assertEquals('Chapter 3', $contents[0]['modules'][0]['contents'][3]['content']);
$this->assertEquals('book', $contents[0]['modules'][0]['modname']);
$this->assertEquals($cm->id, $contents[0]['modules'][0]['id']);
$this->assertCount(2, $contents[0]['modules'][0]['contents'][1]['tags']);
$this->assertEquals('Cats', $contents[0]['modules'][0]['contents'][1]['tags'][0]['rawname']);
$this->assertEquals('Dogs', $contents[0]['modules'][0]['contents'][1]['tags'][1]['rawname']);
// As a teacher.
$this->setUser($teacher);
$contents = book_export_contents($cm, '');
// As a teacher, the hidden chapter must be included in the structure.
$this->assertCount(5, $contents);
$this->assertEquals('structure', $contents[0]['filename']);
// Check structure is correct.
$foundhiddenchapter = false;
$chapters = json_decode($contents[0]['content']);
foreach ($chapters as $chapter) {
if ($chapter->title == 'Chapter 4' && $chapter->hidden == 1) {
$foundhiddenchapter = true;
}
}
$this->assertTrue($foundhiddenchapter);
$this->assertEquals('index.html', $contents[1]['filename']);
$this->assertEquals('Chapter 1', $contents[1]['content']);
$this->assertCount(2, $contents[1]['tags']);
$this->assertEquals('Cats', $contents[1]['tags'][0]['rawname']);
$this->assertEquals($tag->id, $contents[1]['tags'][0]['id']);
$this->assertEquals('Dogs', $contents[1]['tags'][1]['rawname']);
$this->assertEquals('index.html', $contents[2]['filename']);
$this->assertEquals('Chapter 2', $contents[2]['content']);
$this->assertEquals('index.html', $contents[3]['filename']);
$this->assertEquals('Chapter 3', $contents[3]['content']);
$this->assertEquals('index.html', $contents[4]['filename']);
$this->assertEquals('Chapter 4', $contents[4]['content']);
// Now, test the function via the external API.
$contents = \core_course_external::get_course_contents($course->id, array());
$contents = external_api::clean_returnvalue(\core_course_external::get_course_contents_returns(), $contents);
$this->assertCount(5, $contents[0]['modules'][0]['contents']);
$this->assertEquals('content', $contents[0]['modules'][0]['contents'][0]['type']);
$this->assertEquals('structure', $contents[0]['modules'][0]['contents'][0]['filename']);
// Check structure is correct.
$foundhiddenchapter = false;
$chapters = json_decode($contents[0]['modules'][0]['contents'][0]['content']);
foreach ($chapters as $chapter) {
if ($chapter->title == 'Chapter 4' && $chapter->hidden == 1) {
$foundhiddenchapter = true;
}
}
$this->assertTrue($foundhiddenchapter);
$this->assertEquals('file', $contents[0]['modules'][0]['contents'][1]['type']);
$this->assertEquals('Chapter 1', $contents[0]['modules'][0]['contents'][1]['content']);
$this->assertEquals('file', $contents[0]['modules'][0]['contents'][2]['type']);
$this->assertEquals('Chapter 2', $contents[0]['modules'][0]['contents'][2]['content']);
$this->assertEquals('file', $contents[0]['modules'][0]['contents'][3]['type']);
$this->assertEquals('Chapter 3', $contents[0]['modules'][0]['contents'][3]['content']);
$this->assertEquals('file', $contents[0]['modules'][0]['contents'][4]['type']);
$this->assertEquals('Chapter 4', $contents[0]['modules'][0]['contents'][4]['content']);
$this->assertEquals('book', $contents[0]['modules'][0]['modname']);
$this->assertEquals($cm->id, $contents[0]['modules'][0]['id']);
$this->assertCount(2, $contents[0]['modules'][0]['contents'][1]['tags']);
$this->assertEquals('Cats', $contents[0]['modules'][0]['contents'][1]['tags'][0]['rawname']);
$this->assertEquals('Dogs', $contents[0]['modules'][0]['contents'][1]['tags'][1]['rawname']);
// Test empty book.
$emptybook = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$cm = get_coursemodule_from_id('book', $emptybook->cmid);
$contents = book_export_contents($cm, '');
$this->assertCount(1, $contents);
$this->assertEquals('structure', $contents[0]['filename']);
$this->assertEquals(json_encode(array()), $contents[0]['content']);
}
/**
* Test book_view
* @return void
*/
public function test_book_view(): void {
global $CFG, $DB;
$CFG->enablecompletion = 1;
// Setup test data.
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id),
array('completion' => 2, 'completionview' => 1));
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$chapter = $bookgenerator->create_chapter(array('bookid' => $book->id));
$context = \context_module::instance($book->cmid);
$cm = get_coursemodule_from_instance('book', $book->id);
// Trigger and capture the event.
$sink = $this->redirectEvents();
// Check just opening the book.
book_view($book, 0, false, $course, $cm, $context);
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = array_shift($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_book\event\course_module_viewed', $event);
$this->assertEquals($context, $event->get_context());
$moodleurl = new \moodle_url('/mod/book/view.php', array('id' => $cm->id));
$this->assertEquals($moodleurl, $event->get_url());
$this->assertEventContextNotUsed($event);
$this->assertNotEmpty($event->get_name());
// Check viewing one book chapter (the only one so it will be the first and last).
book_view($book, $chapter, true, $course, $cm, $context);
$events = $sink->get_events();
// We expect a total of 4 events. One for module viewed, one for chapter viewed and two belonging to completion.
$this->assertCount(4, $events);
// Check completion status.
$completion = new \completion_info($course);
$completiondata = $completion->get_data($cm);
$this->assertEquals(1, $completiondata->completionstate);
}
public function test_book_core_calendar_provide_event_action(): void {
// Create the activity.
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
// Create a calendar event.
$event = $this->create_action_event($course->id, $book->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_book_core_calendar_provide_event_action($event, $factory);
// Confirm the event was decorated.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
$this->assertEquals(get_string('view'), $actionevent->get_name());
$this->assertInstanceOf('moodle_url', $actionevent->get_url());
$this->assertEquals(1, $actionevent->get_item_count());
$this->assertTrue($actionevent->is_actionable());
}
public function test_book_core_calendar_provide_event_action_in_hidden_section(): void {
// Create the activity.
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
// Enrol a student in the course.
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Create a calendar event.
$event = $this->create_action_event($course->id, $book->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Set sections 0 as hidden.
set_section_visible($course->id, 0, 0);
// Now, log out.
$this->setUser();
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for the student.
$actionevent = mod_book_core_calendar_provide_event_action($event, $factory, $student->id);
// Confirm the event is not shown at all.
$this->assertNull($actionevent);
}
public function test_book_core_calendar_provide_event_action_for_user(): void {
// Create the activity.
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
// Enrol a student in the course.
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Create a calendar event.
$event = $this->create_action_event($course->id, $book->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Now, log out.
$this->setUser();
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for the student.
$actionevent = mod_book_core_calendar_provide_event_action($event, $factory, $student->id);
// Confirm the event was decorated.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
$this->assertEquals(get_string('view'), $actionevent->get_name());
$this->assertInstanceOf('moodle_url', $actionevent->get_url());
$this->assertEquals(1, $actionevent->get_item_count());
$this->assertTrue($actionevent->is_actionable());
}
public function test_book_core_calendar_provide_event_action_as_non_user(): void {
global $CFG;
// Create the activity.
$course = $this->getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
// Create a calendar event.
$event = $this->create_action_event($course->id, $book->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Log out the user and set force login to true.
\core\session\manager::init_empty_session();
$CFG->forcelogin = true;
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_book_core_calendar_provide_event_action($event, $factory);
// Ensure result was null.
$this->assertNull($actionevent);
}
public function test_book_core_calendar_provide_event_action_already_completed(): void {
global $CFG;
$CFG->enablecompletion = 1;
// Create the activity.
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id),
array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
// Get some additional data.
$cm = get_coursemodule_from_instance('book', $book->id);
// Create a calendar event.
$event = $this->create_action_event($course->id, $book->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Mark the activity as completed.
$completion = new \completion_info($course);
$completion->set_module_viewed($cm);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_book_core_calendar_provide_event_action($event, $factory);
// Ensure result was null.
$this->assertNull($actionevent);
}
public function test_book_core_calendar_provide_event_action_already_completed_for_user(): void {
global $CFG;
$CFG->enablecompletion = 1;
// Create the activity.
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$book = $this->getDataGenerator()->create_module('book', array('course' => $course->id),
array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
// Enrol a student in the course.
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Get some additional data.
$cm = get_coursemodule_from_instance('book', $book->id);
// Create a calendar event.
$event = $this->create_action_event($course->id, $book->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Mark the activity as completed for the student.
$completion = new \completion_info($course);
$completion->set_module_viewed($cm, $student->id);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for the student.
$actionevent = mod_book_core_calendar_provide_event_action($event, $factory, $student->id);
// Ensure result was null.
$this->assertNull($actionevent);
}
/**
* Creates an action event.
*
* @param int $courseid The course id.
* @param int $instanceid The instance id.
* @param string $eventtype The event type.
* @return bool|calendar_event
*/
private function create_action_event($courseid, $instanceid, $eventtype) {
$event = new \stdClass();
$event->name = 'Calendar event';
$event->modulename = 'book';
$event->courseid = $courseid;
$event->instance = $instanceid;
$event->type = CALENDAR_EVENT_TYPE_ACTION;
$event->eventtype = $eventtype;
$event->timestart = time();
return \calendar_event::create($event);
}
public function test_mod_book_get_tagged_chapters(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$course3 = $this->getDataGenerator()->create_course();
$course2 = $this->getDataGenerator()->create_course();
$course1 = $this->getDataGenerator()->create_course();
$book1 = $this->getDataGenerator()->create_module('book', array('course' => $course1->id));
$book2 = $this->getDataGenerator()->create_module('book', array('course' => $course2->id));
$book3 = $this->getDataGenerator()->create_module('book', array('course' => $course3->id));
$chapter11 = $bookgenerator->create_content($book1, array('tags' => array('Cats', 'Dogs')));
$chapter12 = $bookgenerator->create_content($book1, array('tags' => array('Cats', 'mice')));
$chapter13 = $bookgenerator->create_content($book1, array('tags' => array('Cats')));
$chapter14 = $bookgenerator->create_content($book1);
$chapter15 = $bookgenerator->create_content($book1, array('tags' => array('Cats')));
$chapter16 = $bookgenerator->create_content($book1, array('tags' => array('Cats'), 'hidden' => true));
$chapter21 = $bookgenerator->create_content($book2, array('tags' => array('Cats')));
$chapter22 = $bookgenerator->create_content($book2, array('tags' => array('Cats', 'Dogs')));
$chapter23 = $bookgenerator->create_content($book2, array('tags' => array('mice', 'Cats')));
$chapter31 = $bookgenerator->create_content($book3, array('tags' => array('mice', 'Cats')));
$tag = \core_tag_tag::get_by_name(0, 'Cats');
// Admin can see everything.
$res = mod_book_get_tagged_chapters($tag, /*$exclusivemode = */false,
/*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$chapter = */0);
$this->assertMatchesRegularExpression('/'.$chapter11->title.'</', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter12->title.'</', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter13->title.'</', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter14->title.'</', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter15->title.'</', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter16->title.'</', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter21->title.'</', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter22->title.'</', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter23->title.'</', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter31->title.'</', $res->content);
$this->assertEmpty($res->prevpageurl);
$this->assertNotEmpty($res->nextpageurl);
$res = mod_book_get_tagged_chapters($tag, /*$exclusivemode = */false,
/*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$chapter = */1);
$this->assertDoesNotMatchRegularExpression('/'.$chapter11->title.'</', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter12->title.'</', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter13->title.'</', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter14->title.'</', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter15->title.'</', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter16->title.'</', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter21->title.'</', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter22->title.'</', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter23->title.'</', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter31->title.'</', $res->content);
$this->assertNotEmpty($res->prevpageurl);
$this->assertEmpty($res->nextpageurl);
// Create and enrol a user.
$student = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
$this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual');
$this->setUser($student);
\core_tag_index_builder::reset_caches();
// User can not see chapters in course 3 because he is not enrolled.
$res = mod_book_get_tagged_chapters($tag, /*$exclusivemode = */false,
/*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$chapter = */1);
$this->assertMatchesRegularExpression('/'.$chapter22->title.'/', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter23->title.'/', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter31->title.'/', $res->content);
// User can search book chapters inside a course.
$coursecontext = \context_course::instance($course1->id);
$res = mod_book_get_tagged_chapters($tag, /*$exclusivemode = */false,
/*$fromctx = */0, /*$ctx = */$coursecontext->id, /*$rec = */1, /*$chapter = */0);
$this->assertMatchesRegularExpression('/'.$chapter11->title.'/', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter12->title.'/', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter13->title.'/', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter14->title.'/', $res->content);
$this->assertMatchesRegularExpression('/'.$chapter15->title.'/', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter21->title.'/', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter22->title.'/', $res->content);
$this->assertDoesNotMatchRegularExpression('/'.$chapter23->title.'/', $res->content);
$this->assertEmpty($res->nextpageurl);
// User cannot see hidden chapters.
$this->assertDoesNotMatchRegularExpression('/'.$chapter16->title.'/', $res->content);
}
}
+182
View File
@@ -0,0 +1,182 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Book search unit tests.
*
* @package mod_book
* @category test
* @copyright 2016 Eric Merrill {@link http://www.merrilldigital.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_book\search;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/search/tests/fixtures/testable_core_search.php');
/**
* Provides the unit tests for book search.
*
* @package mod_book
* @category test
* @copyright 2016 Eric Merrill {@link http://www.merrilldigital.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class search_test extends \advanced_testcase {
/**
* @var string Area id
*/
protected $bookchapterareaid = null;
public function setUp(): void {
$this->resetAfterTest(true);
set_config('enableglobalsearch', true);
$this->bookchapterareaid = \core_search\manager::generate_areaid('mod_book', 'chapter');
// Set \core_search::instance to the mock_search_engine as we don't require the search engine to be working to test this.
$search = \testable_core_search::instance();
}
/**
* Availability.
*
* @return void
*/
public function test_search_enabled(): void {
$searcharea = \core_search\manager::get_search_area($this->bookchapterareaid);
list($componentname, $varname) = $searcharea->get_config_var_name();
// Enabled by default once global search is enabled.
$this->assertTrue($searcharea->is_enabled());
set_config($varname . '_enabled', 0, $componentname);
$this->assertFalse($searcharea->is_enabled());
set_config($varname . '_enabled', 1, $componentname);
$this->assertTrue($searcharea->is_enabled());
}
/**
* Indexing chapter contents.
*
* @return void
*/
public function test_chapters_indexing(): void {
global $DB;
// Returns the instance as long as the area is supported.
$searcharea = \core_search\manager::get_search_area($this->bookchapterareaid);
$this->assertInstanceOf('\mod_book\search\chapter', $searcharea);
$course1 = self::getDataGenerator()->create_course();
$book = $this->getDataGenerator()->create_module('book', array('course' => $course1->id));
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$chapter1 = $bookgenerator->create_chapter(array('bookid' => $book->id, 'content' => 'Chapter1', 'title' => 'Title1'));
$chapter2 = $bookgenerator->create_chapter(array('bookid' => $book->id, 'content' => 'Chapter2', 'title' => 'Title2'));
// All records.
$recordset = $searcharea->get_recordset_by_timestamp(0);
$this->assertTrue($recordset->valid());
$nrecords = 0;
foreach ($recordset as $record) {
$this->assertInstanceOf('stdClass', $record);
$doc = $searcharea->get_document($record);
$this->assertInstanceOf('\core_search\document', $doc);
// Static caches are working.
$dbreads = $DB->perf_get_reads();
$doc = $searcharea->get_document($record);
$this->assertEquals($dbreads, $DB->perf_get_reads());
$this->assertInstanceOf('\core_search\document', $doc);
$nrecords++;
}
// If there would be an error/failure in the foreach above the recordset would be closed on shutdown.
$recordset->close();
$this->assertEquals(2, $nrecords);
// The +2 is to prevent race conditions.
$recordset = $searcharea->get_recordset_by_timestamp(time() + 2);
// No new records.
$this->assertFalse($recordset->valid());
$recordset->close();
// Create another book and chapter.
$book2 = $this->getDataGenerator()->create_module('book', array('course' => $course1->id));
$bookgenerator->create_chapter(array('bookid' => $book2->id,
'content' => 'Chapter3', 'title' => 'Title3'));
// Query by context, first book.
$recordset = $searcharea->get_document_recordset(0, \context_module::instance($book->cmid));
$this->assertEquals(2, iterator_count($recordset));
$recordset->close();
// Second book.
$recordset = $searcharea->get_document_recordset(0, \context_module::instance($book2->cmid));
$this->assertEquals(1, iterator_count($recordset));
$recordset->close();
// Course.
$recordset = $searcharea->get_document_recordset(0, \context_course::instance($course1->id));
$this->assertEquals(3, iterator_count($recordset));
$recordset->close();
}
/**
* Document contents.
*
* @return void
*/
public function test_check_access(): void {
global $DB;
// Returns the instance as long as the area is supported.
$searcharea = \core_search\manager::get_search_area($this->bookchapterareaid);
$this->assertInstanceOf('\mod_book\search\chapter', $searcharea);
$user1 = self::getDataGenerator()->create_user();
$course1 = self::getDataGenerator()->create_course();
$this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student');
$book = $this->getDataGenerator()->create_module('book', array('course' => $course1->id));
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$chapter = array('bookid' => $book->id, 'content' => 'Chapter1', 'title' => 'Title1');
$chapter1 = $bookgenerator->create_chapter($chapter);
$chapter['content'] = 'Chapter2';
$chapter['title'] = 'Title2';
$chapter['hidden'] = 1;
$chapter2 = $bookgenerator->create_chapter($chapter);
$this->setAdminUser();
$this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($chapter1->id));
$this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($chapter2->id));
$this->setUser($user1);
$this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($chapter1->id));
$this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($chapter2->id));
$this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access($chapter2->id + 10));
}
}