01148a0816
While this change is not 100% required now, it's good habit and we are checking for it since Moodle 4.4. All the changes in this commit have been applied automatically using the moodle.PHPUnit.TestReturnType sniff and are, exclusively adding the ": void" return types when missing.
1423 lines
50 KiB
PHP
1423 lines
50 KiB
PHP
<?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 core_courseformat;
|
|
|
|
use course_modinfo;
|
|
use moodle_exception;
|
|
use stdClass;
|
|
|
|
/**
|
|
* Tests for the stateactions class.
|
|
*
|
|
* @package core_courseformat
|
|
* @category test
|
|
* @copyright 2021 Sara Arjona (sara@moodle.com)
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
* @coversDefaultClass \core_courseformat\stateactions
|
|
*/
|
|
class stateactions_test extends \advanced_testcase {
|
|
/**
|
|
* Helper method to create an activity into a section and add it to the $sections and $activities arrays.
|
|
*
|
|
* @param int $courseid Course identifier where the activity will be added.
|
|
* @param string $type Activity type ('forum', 'assign', ...).
|
|
* @param int $section Section number where the activity will be added.
|
|
* @param bool $visible Whether the activity will be visible or not.
|
|
* @return int the activity cm id
|
|
*/
|
|
private function create_activity(
|
|
int $courseid,
|
|
string $type,
|
|
int $section,
|
|
bool $visible = true
|
|
): int {
|
|
|
|
$activity = $this->getDataGenerator()->create_module(
|
|
$type,
|
|
['course' => $courseid],
|
|
[
|
|
'section' => $section,
|
|
'visible' => $visible
|
|
]
|
|
);
|
|
return $activity->cmid;
|
|
}
|
|
|
|
/**
|
|
* Helper to create a course and generate a section list.
|
|
*
|
|
* @param string $format the course format
|
|
* @param int $sections the number of sections
|
|
* @param int[] $hiddensections the section numbers to hide
|
|
* @return stdClass the course object
|
|
*/
|
|
private function create_course(string $format, int $sections, array $hiddensections): stdClass {
|
|
global $DB;
|
|
|
|
$course = $this->getDataGenerator()->create_course(['numsections' => $sections, 'format' => $format]);
|
|
foreach ($hiddensections as $section) {
|
|
set_section_visible($course->id, $section, 0);
|
|
}
|
|
|
|
return $course;
|
|
}
|
|
|
|
/**
|
|
* Return an array if the course references.
|
|
*
|
|
* This method is used to create alias to sections and other stuff in the dataProviders.
|
|
*
|
|
* @param stdClass $course the course object
|
|
* @return int[] a relation betwee all references and its element id
|
|
*/
|
|
private function course_references(stdClass $course): array {
|
|
global $DB;
|
|
|
|
$references = [];
|
|
|
|
$sectionrecords = $DB->get_records('course_sections', ['course' => $course->id]);
|
|
foreach ($sectionrecords as $id => $section) {
|
|
$references["section{$section->section}"] = $section->id;
|
|
}
|
|
$references['course'] = $course->id;
|
|
$references['invalidsection'] = -1;
|
|
$references['invalidcm'] = -1;
|
|
|
|
return $references;
|
|
}
|
|
|
|
/**
|
|
* Translate a references array into current ids.
|
|
*
|
|
* @param string[] $references the references list
|
|
* @param string[] $values the values to translate
|
|
* @return int[] the list of ids
|
|
*/
|
|
private function translate_references(array $references, array $values): array {
|
|
$result = [];
|
|
foreach ($values as $value) {
|
|
$result[] = $references[$value];
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Generate a sorted and summarized list of an state updates message.
|
|
*
|
|
* It is important to note that the order in the update messages are not important in a real scenario
|
|
* because each message affects a specific part of the course state. However, for the PHPUnit test
|
|
* have them sorted and classified simplifies the asserts.
|
|
*
|
|
* @param stateupdates $updateobj the state updates object
|
|
* @return array of all data updates.
|
|
*/
|
|
private function summarize_updates(stateupdates $updateobj): array {
|
|
// Check state returned after executing given action.
|
|
$updatelist = $updateobj->jsonSerialize();
|
|
|
|
// Initial summary structure.
|
|
$result = [
|
|
'create' => [
|
|
'course' => [],
|
|
'section' => [],
|
|
'cm' => [],
|
|
'count' => 0,
|
|
],
|
|
'put' => [
|
|
'course' => [],
|
|
'section' => [],
|
|
'cm' => [],
|
|
'count' => 0,
|
|
],
|
|
'remove' => [
|
|
'course' => [],
|
|
'section' => [],
|
|
'cm' => [],
|
|
'count' => 0,
|
|
],
|
|
];
|
|
foreach ($updatelist as $update) {
|
|
if (!isset($result[$update->action])) {
|
|
$result[$update->action] = [
|
|
'course' => [],
|
|
'section' => [],
|
|
'cm' => [],
|
|
'count' => 0,
|
|
];
|
|
}
|
|
$elementid = $update->fields->id ?? 0;
|
|
$result[$update->action][$update->name][$elementid] = $update->fields;
|
|
$result[$update->action]['count']++;
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Enrol, set and create the test user depending on the role name.
|
|
*
|
|
* @param stdClass $course the course data
|
|
* @param string $rolename the testing role name
|
|
*/
|
|
private function set_test_user_by_role(stdClass $course, string $rolename) {
|
|
if ($rolename == 'admin') {
|
|
$this->setAdminUser();
|
|
} else {
|
|
$user = $this->getDataGenerator()->create_user();
|
|
if ($rolename != 'unenroled') {
|
|
$this->getDataGenerator()->enrol_user($user->id, $course->id, $rolename);
|
|
}
|
|
$this->setUser($user);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test the behaviour course_state.
|
|
*
|
|
* @dataProvider get_state_provider
|
|
* @covers ::course_state
|
|
* @covers ::section_state
|
|
* @covers ::cm_state
|
|
*
|
|
* @param string $format The course will be created with this course format.
|
|
* @param string $role The role of the user that will execute the method.
|
|
* @param string $method the method to call
|
|
* @param array $params the ids, targetsection and targetcm to use as params
|
|
* @param array $expectedresults List of the course module names expected after calling the method.
|
|
* @param bool $expectedexception If this call will raise an exception.
|
|
|
|
*/
|
|
public function test_get_state(
|
|
string $format,
|
|
string $role,
|
|
string $method,
|
|
array $params,
|
|
array $expectedresults,
|
|
bool $expectedexception = false
|
|
): void {
|
|
|
|
$this->resetAfterTest();
|
|
|
|
// Create a course with 3 sections, 1 of them hidden.
|
|
$course = $this->create_course($format, 3, [2]);
|
|
|
|
$references = $this->course_references($course);
|
|
|
|
// Create and enrol user using given role.
|
|
$this->set_test_user_by_role($course, $role);
|
|
|
|
// Add some activities to the course. One visible and one hidden in both sections 1 and 2.
|
|
$references["cm0"] = $this->create_activity($course->id, 'assign', 1, true);
|
|
$references["cm1"] = $this->create_activity($course->id, 'book', 1, false);
|
|
$references["cm2"] = $this->create_activity($course->id, 'glossary', 2, true);
|
|
$references["cm3"] = $this->create_activity($course->id, 'page', 2, false);
|
|
|
|
if ($expectedexception) {
|
|
$this->expectException(moodle_exception::class);
|
|
}
|
|
|
|
// Initialise stateupdates.
|
|
$courseformat = course_get_format($course->id);
|
|
$updates = new stateupdates($courseformat);
|
|
|
|
// Execute given method.
|
|
$actions = new stateactions();
|
|
$actions->$method(
|
|
$updates,
|
|
$course,
|
|
$this->translate_references($references, $params['ids']),
|
|
$references[$params['targetsectionid']] ?? null,
|
|
$references[$params['targetcmid']] ?? null
|
|
);
|
|
|
|
// Format results in a way we can compare easily.
|
|
$results = $this->summarize_updates($updates);
|
|
|
|
// The state actions does not use create or remove actions because they are designed
|
|
// to refresh parts of the state.
|
|
$this->assertEquals(0, $results['create']['count']);
|
|
$this->assertEquals(0, $results['remove']['count']);
|
|
|
|
// Validate we have all the expected entries.
|
|
$expectedtotal = count($expectedresults['course']) + count($expectedresults['section']) + count($expectedresults['cm']);
|
|
$this->assertEquals($expectedtotal, $results['put']['count']);
|
|
|
|
// Validate course, section and cm.
|
|
foreach ($expectedresults as $name => $referencekeys) {
|
|
foreach ($referencekeys as $referencekey) {
|
|
$this->assertArrayHasKey($references[$referencekey], $results['put'][$name]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Data provider for data request creation tests.
|
|
*
|
|
* @return array the testing scenarios
|
|
*/
|
|
public function get_state_provider(): array {
|
|
return array_merge(
|
|
$this->course_state_provider('weeks'),
|
|
$this->course_state_provider('topics'),
|
|
$this->course_state_provider('social'),
|
|
$this->section_state_provider('weeks', 'admin'),
|
|
$this->section_state_provider('weeks', 'editingteacher'),
|
|
$this->section_state_provider('weeks', 'student'),
|
|
$this->section_state_provider('topics', 'admin'),
|
|
$this->section_state_provider('topics', 'editingteacher'),
|
|
$this->section_state_provider('topics', 'student'),
|
|
$this->section_state_provider('social', 'admin'),
|
|
$this->section_state_provider('social', 'editingteacher'),
|
|
$this->section_state_provider('social', 'student'),
|
|
$this->cm_state_provider('weeks', 'admin'),
|
|
$this->cm_state_provider('weeks', 'editingteacher'),
|
|
$this->cm_state_provider('weeks', 'student'),
|
|
$this->cm_state_provider('topics', 'admin'),
|
|
$this->cm_state_provider('topics', 'editingteacher'),
|
|
$this->cm_state_provider('topics', 'student'),
|
|
$this->cm_state_provider('social', 'admin'),
|
|
$this->cm_state_provider('social', 'editingteacher'),
|
|
$this->cm_state_provider('social', 'student'),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Course state data provider.
|
|
*
|
|
* @param string $format the course format
|
|
* @return array the testing scenarios
|
|
*/
|
|
public function course_state_provider(string $format): array {
|
|
$expectedexception = ($format === 'social');
|
|
return [
|
|
// Tests for course_state.
|
|
"admin $format course_state" => [
|
|
'format' => $format,
|
|
'role' => 'admin',
|
|
'method' => 'course_state',
|
|
'params' => [
|
|
'ids' => [], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => ['course'],
|
|
'section' => ['section0', 'section1', 'section2', 'section3'],
|
|
'cm' => ['cm0', 'cm1', 'cm2', 'cm3'],
|
|
],
|
|
'expectedexception' => $expectedexception,
|
|
],
|
|
"editingteacher $format course_state" => [
|
|
'format' => $format,
|
|
'role' => 'editingteacher',
|
|
'method' => 'course_state',
|
|
'params' => [
|
|
'ids' => [], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => ['course'],
|
|
'section' => ['section0', 'section1', 'section2', 'section3'],
|
|
'cm' => ['cm0', 'cm1', 'cm2', 'cm3'],
|
|
],
|
|
'expectedexception' => $expectedexception,
|
|
],
|
|
"student $format course_state" => [
|
|
'format' => $format,
|
|
'role' => 'student',
|
|
'method' => 'course_state',
|
|
'params' => [
|
|
'ids' => [], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => ['course'],
|
|
'section' => ['section0', 'section1', 'section3'],
|
|
'cm' => ['cm0'],
|
|
],
|
|
'expectedexception' => $expectedexception,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Section state data provider.
|
|
*
|
|
* @param string $format the course format
|
|
* @param string $role the user role
|
|
* @return array the testing scenarios
|
|
*/
|
|
public function section_state_provider(string $format, string $role): array {
|
|
|
|
// Social format will raise an exception and debug messages because it does not
|
|
// use sections and it does not provide a renderer.
|
|
$expectedexception = ($format === 'social');
|
|
|
|
// All sections and cms that the user can access to.
|
|
$usersections = ['section0', 'section1', 'section2', 'section3'];
|
|
$usercms = ['cm0', 'cm1', 'cm2', 'cm3'];
|
|
if ($role == 'student') {
|
|
$usersections = ['section0', 'section1', 'section3'];
|
|
$usercms = ['cm0'];
|
|
}
|
|
|
|
return [
|
|
"$role $format section_state no section" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'section_state',
|
|
'params' => [
|
|
'ids' => [], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [],
|
|
'expectedexception' => true,
|
|
],
|
|
"$role $format section_state section 0" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'section_state',
|
|
'params' => [
|
|
'ids' => ['section0'], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => [],
|
|
'section' => array_intersect(['section0'], $usersections),
|
|
'cm' => [],
|
|
],
|
|
'expectedexception' => $expectedexception,
|
|
],
|
|
"$role $format section_state visible section" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'section_state',
|
|
'params' => [
|
|
'ids' => ['section1'], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => [],
|
|
'section' => array_intersect(['section1'], $usersections),
|
|
'cm' => array_intersect(['cm0', 'cm1'], $usercms),
|
|
],
|
|
'expectedexception' => $expectedexception,
|
|
],
|
|
"$role $format section_state hidden section" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'section_state',
|
|
'params' => [
|
|
'ids' => ['section2'], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => [],
|
|
'section' => array_intersect(['section2'], $usersections),
|
|
'cm' => array_intersect(['cm2', 'cm3'], $usercms),
|
|
],
|
|
'expectedexception' => $expectedexception,
|
|
],
|
|
"$role $format section_state several sections" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'section_state',
|
|
'params' => [
|
|
'ids' => ['section1', 'section3'], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => [],
|
|
'section' => array_intersect(['section1', 'section3'], $usersections),
|
|
'cm' => array_intersect(['cm0', 'cm1'], $usercms),
|
|
],
|
|
'expectedexception' => $expectedexception,
|
|
],
|
|
"$role $format section_state invalid section" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'section_state',
|
|
'params' => [
|
|
'ids' => ['invalidsection'], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [],
|
|
'expectedexception' => true,
|
|
],
|
|
"$role $format section_state using target section" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'section_state',
|
|
'params' => [
|
|
'ids' => ['section1'], 'targetsectionid' => 'section3', 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => [],
|
|
'section' => array_intersect(['section1', 'section3'], $usersections),
|
|
'cm' => array_intersect(['cm0', 'cm1'], $usercms),
|
|
],
|
|
'expectedexception' => $expectedexception,
|
|
],
|
|
"$role $format section_state using target targetcmid" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'section_state',
|
|
'params' => [
|
|
'ids' => ['section3'], 'targetsectionid' => null, 'targetcmid' => 'cm1'
|
|
],
|
|
'expectedresults' => [
|
|
'course' => [],
|
|
'section' => array_intersect(['section3'], $usersections),
|
|
'cm' => array_intersect(['cm1'], $usercms),
|
|
],
|
|
'expectedexception' => $expectedexception,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Course module state data provider.
|
|
*
|
|
* @param string $format the course format
|
|
* @param string $role the user role
|
|
* @return array the testing scenarios
|
|
*/
|
|
public function cm_state_provider(string $format, string $role): array {
|
|
|
|
// All sections and cms that the user can access to.
|
|
$usersections = ['section0', 'section1', 'section2', 'section3'];
|
|
$usercms = ['cm0', 'cm1', 'cm2', 'cm3'];
|
|
if ($role == 'student') {
|
|
$usersections = ['section0', 'section1', 'section3'];
|
|
$usercms = ['cm0'];
|
|
}
|
|
|
|
return [
|
|
"$role $format cm_state no cms" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'cm_state',
|
|
'params' => [
|
|
'ids' => [], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [],
|
|
'expectedexception' => true,
|
|
],
|
|
"$role $format cm_state visible cm" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'cm_state',
|
|
'params' => [
|
|
'ids' => ['cm0'], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => [],
|
|
'section' => array_intersect(['section1'], $usersections),
|
|
'cm' => array_intersect(['cm0'], $usercms),
|
|
],
|
|
'expectedexception' => false,
|
|
],
|
|
"$role $format cm_state hidden cm" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'cm_state',
|
|
'params' => [
|
|
'ids' => ['cm1'], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => [],
|
|
'section' => array_intersect(['section1'], $usersections),
|
|
'cm' => array_intersect(['cm1'], $usercms),
|
|
],
|
|
'expectedexception' => false,
|
|
],
|
|
"$role $format cm_state several cm" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'cm_state',
|
|
'params' => [
|
|
'ids' => ['cm0', 'cm2'], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => [],
|
|
'section' => array_intersect(['section1', 'section2'], $usersections),
|
|
'cm' => array_intersect(['cm0', 'cm2'], $usercms),
|
|
],
|
|
'expectedexception' => false,
|
|
],
|
|
"$role $format cm_state using targetsection" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'cm_state',
|
|
'params' => [
|
|
'ids' => ['cm0'], 'targetsectionid' => 'section2', 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [
|
|
'course' => [],
|
|
'section' => array_intersect(['section1', 'section2'], $usersections),
|
|
'cm' => array_intersect(['cm0'], $usercms),
|
|
],
|
|
'expectedexception' => ($format === 'social'),
|
|
],
|
|
"$role $format cm_state using targetcm" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'cm_state',
|
|
'params' => [
|
|
'ids' => ['cm0'], 'targetsectionid' => null, 'targetcmid' => 'cm3'
|
|
],
|
|
'expectedresults' => [
|
|
'course' => [],
|
|
'section' => array_intersect(['section1', 'section2'], $usersections),
|
|
'cm' => array_intersect(['cm0', 'cm3'], $usercms),
|
|
],
|
|
'expectedexception' => false,
|
|
],
|
|
"$role $format cm_state using an invalid cm" => [
|
|
'format' => $format,
|
|
'role' => $role,
|
|
'method' => 'cm_state',
|
|
'params' => [
|
|
'ids' => ['invalidcm'], 'targetsectionid' => null, 'targetcmid' => null
|
|
],
|
|
'expectedresults' => [],
|
|
'expectedexception' => true,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Internal method for testing a specific state action.
|
|
*
|
|
* @param string $method the method to test
|
|
* @param string $role the user role
|
|
* @param string[] $idrefs the sections or cms id references to be used as method params
|
|
* @param bool $expectedexception whether the call should throw an exception
|
|
* @param int[] $expectedtotal the expected total number of state indexed by put, remove and create
|
|
* @param string|null $coursefield the course field to check
|
|
* @param int|string|null $coursevalue the section field value
|
|
* @param string|null $sectionfield the section field to check
|
|
* @param int|string|null $sectionvalue the section field value
|
|
* @param string|null $cmfield the cm field to check
|
|
* @param int|string|null $cmvalue the cm field value
|
|
* @param string|null $targetsection optional target section reference
|
|
* @param string|null $targetcm optional target cm reference
|
|
* @return array an array of elements to do extra validations (course, references, results)
|
|
*/
|
|
protected function basic_state_text(
|
|
string $method = 'section_hide',
|
|
string $role = 'editingteacher',
|
|
array $idrefs = [],
|
|
bool $expectedexception = false,
|
|
array $expectedtotals = [],
|
|
?string $coursefield = null,
|
|
$coursevalue = 0,
|
|
?string $sectionfield = null,
|
|
$sectionvalue = 0,
|
|
?string $cmfield = null,
|
|
$cmvalue = 0,
|
|
?string $targetsection = null,
|
|
?string $targetcm = null
|
|
): array {
|
|
$this->resetAfterTest();
|
|
|
|
// Create a course with 3 sections, 1 of them hidden.
|
|
$course = $this->create_course('topics', 3, [2]);
|
|
|
|
$references = $this->course_references($course);
|
|
|
|
$user = $this->getDataGenerator()->create_user();
|
|
$this->getDataGenerator()->enrol_user($user->id, $course->id, $role);
|
|
$this->setUser($user);
|
|
|
|
// Add some activities to the course. One visible and one hidden in both sections 1 and 2.
|
|
$references["cm0"] = $this->create_activity($course->id, 'assign', 1, true);
|
|
$references["cm1"] = $this->create_activity($course->id, 'book', 1, false);
|
|
$references["cm2"] = $this->create_activity($course->id, 'glossary', 2, true);
|
|
$references["cm3"] = $this->create_activity($course->id, 'page', 2, false);
|
|
$references["cm4"] = $this->create_activity($course->id, 'forum', 2, false);
|
|
$references["cm5"] = $this->create_activity($course->id, 'wiki', 2, false);
|
|
|
|
if ($expectedexception) {
|
|
$this->expectException(moodle_exception::class);
|
|
}
|
|
|
|
// Initialise stateupdates.
|
|
$courseformat = course_get_format($course->id);
|
|
$updates = new stateupdates($courseformat);
|
|
|
|
// Execute the method.
|
|
$actions = new stateactions();
|
|
$actions->$method(
|
|
$updates,
|
|
$course,
|
|
$this->translate_references($references, $idrefs),
|
|
($targetsection) ? $references[$targetsection] : null,
|
|
($targetcm) ? $references[$targetcm] : null,
|
|
);
|
|
|
|
// Format results in a way we can compare easily.
|
|
$results = $this->summarize_updates($updates);
|
|
|
|
// Validate we have all the expected entries.
|
|
$this->assertEquals($expectedtotals['create'] ?? 0, $results['create']['count']);
|
|
$this->assertEquals($expectedtotals['remove'] ?? 0, $results['remove']['count']);
|
|
$this->assertEquals($expectedtotals['put'] ?? 0, $results['put']['count']);
|
|
|
|
// Validate course, section and cm.
|
|
if (!empty($coursefield)) {
|
|
foreach ($results['put']['course'] as $courseid) {
|
|
$this->assertEquals($coursevalue, $results['put']['course'][$courseid][$coursefield]);
|
|
}
|
|
}
|
|
if (!empty($sectionfield)) {
|
|
foreach ($results['put']['section'] as $section) {
|
|
$this->assertEquals($sectionvalue, $section->$sectionfield);
|
|
}
|
|
}
|
|
if (!empty($cmfield)) {
|
|
foreach ($results['put']['cm'] as $cm) {
|
|
$this->assertEquals($cmvalue, $cm->$cmfield);
|
|
}
|
|
}
|
|
return [
|
|
'course' => $course,
|
|
'references' => $references,
|
|
'results' => $results,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Test for section_hide
|
|
*
|
|
* @covers ::section_hide
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_section_hide(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->basic_state_text(
|
|
'section_hide',
|
|
$role,
|
|
['section1', 'section2', 'section3'],
|
|
$expectedexception,
|
|
['put' => 9],
|
|
null,
|
|
null,
|
|
'visible',
|
|
0,
|
|
null,
|
|
null
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test for section_hide
|
|
*
|
|
* @covers ::section_show
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_section_show(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->basic_state_text(
|
|
'section_show',
|
|
$role,
|
|
['section1', 'section2', 'section3'],
|
|
$expectedexception,
|
|
['put' => 9],
|
|
null,
|
|
null,
|
|
'visible',
|
|
1,
|
|
null,
|
|
null
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test for cm_show
|
|
*
|
|
* @covers ::cm_show
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_cm_show(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->basic_state_text(
|
|
'cm_show',
|
|
$role,
|
|
['cm0', 'cm1', 'cm2', 'cm3'],
|
|
$expectedexception,
|
|
['put' => 4],
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'visible',
|
|
1
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test for cm_hide
|
|
*
|
|
* @covers ::cm_hide
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_cm_hide(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->basic_state_text(
|
|
'cm_hide',
|
|
$role,
|
|
['cm0', 'cm1', 'cm2', 'cm3'],
|
|
$expectedexception,
|
|
['put' => 4],
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'visible',
|
|
0
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test for cm_stealth
|
|
*
|
|
* @covers ::cm_stealth
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_cm_stealth(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
set_config('allowstealth', 1);
|
|
$this->basic_state_text(
|
|
'cm_stealth',
|
|
$role,
|
|
['cm0', 'cm1', 'cm2', 'cm3'],
|
|
$expectedexception,
|
|
['put' => 4],
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'stealth',
|
|
1
|
|
);
|
|
// Disable stealth.
|
|
set_config('allowstealth', 0);
|
|
// When stealth are disabled the validation is a but more complex because they depends
|
|
// also on the section visibility (legacy stealth).
|
|
$this->basic_state_text(
|
|
'cm_stealth',
|
|
$role,
|
|
['cm0', 'cm1'],
|
|
$expectedexception,
|
|
['put' => 2],
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'stealth',
|
|
0
|
|
);
|
|
$this->basic_state_text(
|
|
'cm_stealth',
|
|
$role,
|
|
['cm2', 'cm3'],
|
|
$expectedexception,
|
|
['put' => 2],
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'stealth',
|
|
1
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Data provider for basic role tests.
|
|
*
|
|
* @return array the testing scenarios
|
|
*/
|
|
public function basic_role_provider() {
|
|
return [
|
|
'editingteacher' => [
|
|
'role' => 'editingteacher',
|
|
'expectedexception' => false,
|
|
],
|
|
'teacher' => [
|
|
'role' => 'teacher',
|
|
'expectedexception' => true,
|
|
],
|
|
'student' => [
|
|
'role' => 'student',
|
|
'expectedexception' => true,
|
|
],
|
|
'guest' => [
|
|
'role' => 'guest',
|
|
'expectedexception' => true,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Duplicate course module method.
|
|
*
|
|
* @covers ::cm_duplicate
|
|
* @dataProvider cm_duplicate_provider
|
|
* @param string $targetsection the target section (empty for none)
|
|
* @param bool $validcms if uses valid cms
|
|
* @param string $role the current user role name
|
|
* @param bool $expectedexception if the test will raise an exception
|
|
*/
|
|
public function test_cm_duplicate(
|
|
string $targetsection = '',
|
|
bool $validcms = true,
|
|
string $role = 'admin',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->resetAfterTest();
|
|
|
|
// Create a course with 3 sections.
|
|
$course = $this->create_course('topics', 3, []);
|
|
|
|
$references = $this->course_references($course);
|
|
|
|
// Create and enrol user using given role.
|
|
$this->set_test_user_by_role($course, $role);
|
|
|
|
// Add some activities to the course. One visible and one hidden in both sections 1 and 2.
|
|
$references["cm0"] = $this->create_activity($course->id, 'assign', 1, true);
|
|
$references["cm1"] = $this->create_activity($course->id, 'page', 2, false);
|
|
|
|
if ($expectedexception) {
|
|
$this->expectException(moodle_exception::class);
|
|
}
|
|
|
|
// Initialise stateupdates.
|
|
$courseformat = course_get_format($course->id);
|
|
$updates = new stateupdates($courseformat);
|
|
|
|
// Execute method.
|
|
$targetsectionid = (!empty($targetsection)) ? $references[$targetsection] : null;
|
|
$cmrefs = ($validcms) ? ['cm0', 'cm1'] : ['invalidcm'];
|
|
$actions = new stateactions();
|
|
$actions->cm_duplicate(
|
|
$updates,
|
|
$course,
|
|
$this->translate_references($references, $cmrefs),
|
|
$targetsectionid,
|
|
);
|
|
|
|
// Check the new elements in the course structure.
|
|
$originalsections = [
|
|
'assign' => $references['section1'],
|
|
'page' => $references['section2'],
|
|
];
|
|
$modinfo = course_modinfo::instance($course);
|
|
$cms = $modinfo->get_cms();
|
|
$i = 0;
|
|
foreach ($cms as $cmid => $cminfo) {
|
|
if ($cmid == $references['cm0'] || $cmid == $references['cm1']) {
|
|
continue;
|
|
}
|
|
$references["newcm$i"] = $cmid;
|
|
if ($targetsectionid) {
|
|
$this->assertEquals($targetsectionid, $cminfo->section);
|
|
} else {
|
|
$this->assertEquals($originalsections[$cminfo->modname], $cminfo->section);
|
|
}
|
|
$i++;
|
|
}
|
|
|
|
// Check the resulting updates.
|
|
$results = $this->summarize_updates($updates);
|
|
|
|
if ($targetsectionid) {
|
|
$this->assertArrayHasKey($references[$targetsection], $results['put']['section']);
|
|
} else {
|
|
$this->assertArrayHasKey($references['section1'], $results['put']['section']);
|
|
$this->assertArrayHasKey($references['section2'], $results['put']['section']);
|
|
}
|
|
$countcms = ($targetsection == 'section3' || $targetsection === '') ? 2 : 3;
|
|
$this->assertCount($countcms, $results['put']['cm']);
|
|
$this->assertArrayHasKey($references['newcm0'], $results['put']['cm']);
|
|
$this->assertArrayHasKey($references['newcm1'], $results['put']['cm']);
|
|
}
|
|
|
|
/**
|
|
* Duplicate course module data provider.
|
|
*
|
|
* @return array the testing scenarios
|
|
*/
|
|
public function cm_duplicate_provider(): array {
|
|
return [
|
|
'valid cms without target section' => [
|
|
'targetsection' => '',
|
|
'validcms' => true,
|
|
'role' => 'admin',
|
|
'expectedexception' => false,
|
|
],
|
|
'valid cms targeting an empty section' => [
|
|
'targetsection' => 'section3',
|
|
'validcms' => true,
|
|
'role' => 'admin',
|
|
'expectedexception' => false,
|
|
],
|
|
'valid cms targeting a section with activities' => [
|
|
'targetsection' => 'section2',
|
|
'validcms' => true,
|
|
'role' => 'admin',
|
|
'expectedexception' => false,
|
|
],
|
|
'invalid cms without target section' => [
|
|
'targetsection' => '',
|
|
'validcms' => false,
|
|
'role' => 'admin',
|
|
'expectedexception' => true,
|
|
],
|
|
'invalid cms with target section' => [
|
|
'targetsection' => 'section3',
|
|
'validcms' => false,
|
|
'role' => 'admin',
|
|
'expectedexception' => true,
|
|
],
|
|
'student role with target section' => [
|
|
'targetsection' => 'section3',
|
|
'validcms' => true,
|
|
'role' => 'student',
|
|
'expectedexception' => true,
|
|
],
|
|
'student role without target section' => [
|
|
'targetsection' => '',
|
|
'validcms' => true,
|
|
'role' => 'student',
|
|
'expectedexception' => true,
|
|
],
|
|
'unrenolled user with target section' => [
|
|
'targetsection' => 'section3',
|
|
'validcms' => true,
|
|
'role' => 'unenroled',
|
|
'expectedexception' => true,
|
|
],
|
|
'unrenolled user without target section' => [
|
|
'targetsection' => '',
|
|
'validcms' => true,
|
|
'role' => 'unenroled',
|
|
'expectedexception' => true,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Test for cm_delete
|
|
*
|
|
* @covers ::cm_delete
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_cm_delete(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->resetAfterTest();
|
|
// We want modules to be deleted for good.
|
|
set_config('coursebinenable', 0, 'tool_recyclebin');
|
|
|
|
$info = $this->basic_state_text(
|
|
'cm_delete',
|
|
$role,
|
|
['cm2', 'cm3'],
|
|
$expectedexception,
|
|
['remove' => 2, 'put' => 1],
|
|
);
|
|
|
|
$course = $info['course'];
|
|
$references = $info['references'];
|
|
$results = $info['results'];
|
|
$courseformat = course_get_format($course->id);
|
|
|
|
$this->assertArrayNotHasKey($references['cm0'], $results['remove']['cm']);
|
|
$this->assertArrayNotHasKey($references['cm1'], $results['remove']['cm']);
|
|
$this->assertArrayHasKey($references['cm2'], $results['remove']['cm']);
|
|
$this->assertArrayHasKey($references['cm3'], $results['remove']['cm']);
|
|
$this->assertArrayNotHasKey($references['cm4'], $results['remove']['cm']);
|
|
$this->assertArrayNotHasKey($references['cm5'], $results['remove']['cm']);
|
|
|
|
// Check the new section cm list.
|
|
$newcmlist = $this->translate_references($references, ['cm4', 'cm5']);
|
|
$section = $results['put']['section'][$references['section2']];
|
|
$this->assertEquals($newcmlist, $section->cmlist);
|
|
|
|
// Check activities are deleted.
|
|
$modinfo = $courseformat->get_modinfo();
|
|
$cms = $modinfo->get_cms();
|
|
$this->assertArrayHasKey($references['cm0'], $cms);
|
|
$this->assertArrayHasKey($references['cm1'], $cms);
|
|
$this->assertArrayNotHasKey($references['cm2'], $cms);
|
|
$this->assertArrayNotHasKey($references['cm3'], $cms);
|
|
$this->assertArrayHasKey($references['cm4'], $cms);
|
|
$this->assertArrayHasKey($references['cm5'], $cms);
|
|
}
|
|
|
|
/**
|
|
* Test for cm_moveright
|
|
*
|
|
* @covers ::cm_moveright
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_cm_moveright(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->basic_state_text(
|
|
'cm_moveright',
|
|
$role,
|
|
['cm0', 'cm1', 'cm2', 'cm3'],
|
|
$expectedexception,
|
|
['put' => 4],
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'indent',
|
|
1
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test for cm_moveleft
|
|
*
|
|
* @covers ::cm_moveleft
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_cm_moveleft(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->basic_state_text(
|
|
'cm_moveleft',
|
|
$role,
|
|
['cm0', 'cm1', 'cm2', 'cm3'],
|
|
$expectedexception,
|
|
['put' => 4],
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'indent',
|
|
0
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test for cm_nogroups
|
|
*
|
|
* @covers ::cm_nogroups
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_cm_nogroups(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->basic_state_text(
|
|
'cm_nogroups',
|
|
$role,
|
|
['cm0', 'cm1', 'cm2', 'cm3'],
|
|
$expectedexception,
|
|
['put' => 4],
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'groupmode',
|
|
NOGROUPS
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test for cm_visiblegroups
|
|
*
|
|
* @covers ::cm_visiblegroups
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_cm_visiblegroups(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->basic_state_text(
|
|
'cm_visiblegroups',
|
|
$role,
|
|
['cm0', 'cm1', 'cm2', 'cm3'],
|
|
$expectedexception,
|
|
['put' => 4],
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'groupmode',
|
|
VISIBLEGROUPS
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test for cm_separategroups
|
|
*
|
|
* @covers ::cm_separategroups
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_cm_separategroups(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->basic_state_text(
|
|
'cm_separategroups',
|
|
$role,
|
|
['cm0', 'cm1', 'cm2', 'cm3'],
|
|
$expectedexception,
|
|
['put' => 4],
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
'groupmode',
|
|
SEPARATEGROUPS
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test for section_move_after
|
|
*
|
|
* @covers ::section_move_after
|
|
* @dataProvider section_move_after_provider
|
|
* @param string[] $sectiontomove the sections to move
|
|
* @param string $targetsection the target section reference
|
|
* @param string[] $finalorder the final sections order
|
|
* @param string[] $updatedcms the list of cms in the state updates
|
|
* @param int $totalputs the total amount of put updates
|
|
*/
|
|
public function test_section_move_after(
|
|
array $sectiontomove,
|
|
string $targetsection,
|
|
array $finalorder,
|
|
array $updatedcms,
|
|
int $totalputs
|
|
): void {
|
|
$this->resetAfterTest();
|
|
|
|
$course = $this->create_course('topics', 8, []);
|
|
|
|
$references = $this->course_references($course);
|
|
|
|
// Add some activities to the course. One visible and one hidden in both sections 1 and 2.
|
|
$references["cm0"] = $this->create_activity($course->id, 'assign', 1, true);
|
|
$references["cm1"] = $this->create_activity($course->id, 'book', 1, false);
|
|
$references["cm2"] = $this->create_activity($course->id, 'glossary', 2, true);
|
|
$references["cm3"] = $this->create_activity($course->id, 'page', 2, false);
|
|
$references["cm4"] = $this->create_activity($course->id, 'forum', 3, false);
|
|
$references["cm5"] = $this->create_activity($course->id, 'wiki', 3, false);
|
|
|
|
$user = $this->getDataGenerator()->create_user();
|
|
$this->getDataGenerator()->enrol_user($user->id, $course->id, 'editingteacher');
|
|
$this->setUser($user);
|
|
|
|
// Initialise stateupdates.
|
|
$courseformat = course_get_format($course->id);
|
|
$updates = new stateupdates($courseformat);
|
|
|
|
// Execute the method.
|
|
$actions = new stateactions();
|
|
$actions->section_move_after(
|
|
$updates,
|
|
$course,
|
|
$this->translate_references($references, $sectiontomove),
|
|
$references[$targetsection]
|
|
);
|
|
|
|
// Format results in a way we can compare easily.
|
|
$results = $this->summarize_updates($updates);
|
|
|
|
// Validate we have all the expected entries.
|
|
$this->assertEquals(0, $results['create']['count']);
|
|
$this->assertEquals(0, $results['remove']['count']);
|
|
// Moving a section puts:
|
|
// - The course state.
|
|
// - All sections state.
|
|
// - The cm states related to the moved and target sections.
|
|
$this->assertEquals($totalputs, $results['put']['count']);
|
|
|
|
// Course state should contain the sorted list of sections (section zero + 8 sections).
|
|
$finalsectionids = $this->translate_references($references, $finalorder);
|
|
$coursestate = reset($results['put']['course']);
|
|
$this->assertEquals($finalsectionids, $coursestate->sectionlist);
|
|
// All sections should be present in the update.
|
|
$this->assertCount(9, $results['put']['section']);
|
|
// Only cms from the affected sections should be updated.
|
|
$cmids = $this->translate_references($references, $updatedcms);
|
|
$cms = $results['put']['cm'];
|
|
foreach ($cmids as $cmid) {
|
|
$this->assertArrayHasKey($cmid, $cms);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Provider for test_section_move_after.
|
|
*
|
|
* @return array the testing scenarios
|
|
*/
|
|
public function section_move_after_provider(): array {
|
|
return [
|
|
'Move sections down' => [
|
|
'sectiontomove' => ['section2', 'section4'],
|
|
'targetsection' => 'section7',
|
|
'finalorder' => [
|
|
'section0',
|
|
'section1',
|
|
'section3',
|
|
'section5',
|
|
'section6',
|
|
'section7',
|
|
'section2',
|
|
'section4',
|
|
'section8',
|
|
],
|
|
'updatedcms' => ['cm2', 'cm3'],
|
|
'totalputs' => 12,
|
|
],
|
|
'Move sections up' => [
|
|
'sectiontomove' => ['section3', 'section5'],
|
|
'targetsection' => 'section1',
|
|
'finalorder' => [
|
|
'section0',
|
|
'section1',
|
|
'section3',
|
|
'section5',
|
|
'section2',
|
|
'section4',
|
|
'section6',
|
|
'section7',
|
|
'section8',
|
|
],
|
|
'updatedcms' => ['cm0', 'cm1', 'cm4', 'cm5'],
|
|
'totalputs' => 14,
|
|
],
|
|
'Move sections in the middle' => [
|
|
'sectiontomove' => ['section2', 'section5'],
|
|
'targetsection' => 'section3',
|
|
'finalorder' => [
|
|
'section0',
|
|
'section1',
|
|
'section3',
|
|
'section2',
|
|
'section5',
|
|
'section4',
|
|
'section6',
|
|
'section7',
|
|
'section8',
|
|
],
|
|
'updatedcms' => ['cm2', 'cm3', 'cm4', 'cm5'],
|
|
'totalputs' => 14,
|
|
],
|
|
'Move sections on top' => [
|
|
'sectiontomove' => ['section3', 'section5'],
|
|
'targetsection' => 'section0',
|
|
'finalorder' => [
|
|
'section0',
|
|
'section3',
|
|
'section5',
|
|
'section1',
|
|
'section2',
|
|
'section4',
|
|
'section6',
|
|
'section7',
|
|
'section8',
|
|
],
|
|
'updatedcms' => ['cm4', 'cm5'],
|
|
'totalputs' => 12,
|
|
],
|
|
'Move sections on bottom' => [
|
|
'sectiontomove' => ['section3', 'section5'],
|
|
'targetsection' => 'section8',
|
|
'finalorder' => [
|
|
'section0',
|
|
'section1',
|
|
'section2',
|
|
'section4',
|
|
'section6',
|
|
'section7',
|
|
'section8',
|
|
'section3',
|
|
'section5',
|
|
],
|
|
'updatedcms' => ['cm4', 'cm5'],
|
|
'totalputs' => 12,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Test for section_move_after capability checks.
|
|
*
|
|
* @covers ::section_move_after
|
|
* @dataProvider basic_role_provider
|
|
* @param string $role the user role
|
|
* @param bool $expectedexception if it will expect an exception.
|
|
*/
|
|
public function test_section_move_after_capabilities(
|
|
string $role = 'editingteacher',
|
|
bool $expectedexception = false
|
|
): void {
|
|
$this->resetAfterTest();
|
|
// We want modules to be deleted for good.
|
|
set_config('coursebinenable', 0, 'tool_recyclebin');
|
|
|
|
$info = $this->basic_state_text(
|
|
'section_move_after',
|
|
$role,
|
|
['section2'],
|
|
$expectedexception,
|
|
['put' => 9],
|
|
null,
|
|
0,
|
|
null,
|
|
0,
|
|
null,
|
|
0,
|
|
'section0'
|
|
);
|
|
}
|
|
}
|