"
+
+ Examples:
+ | scalescores |
+ | Bad |
+ | OK |
+ | Pretty Good |
+ | Good |
diff --git a/grade/tests/component_gradeitems_test.php b/grade/tests/component_gradeitems_test.php
index a37c22d01c2ee..764be0608022d 100644
--- a/grade/tests/component_gradeitems_test.php
+++ b/grade/tests/component_gradeitems_test.php
@@ -76,7 +76,7 @@ public function test_get_itemname_mapping_for_valid_component_valid_mapping(): v
*
* @return array
*/
- public function is_valid_itemname_provider(): array {
+ public static function is_valid_itemname_provider(): array {
return [
'valid' => [
'someother',
@@ -173,7 +173,7 @@ public function test_get_advancedgrading_itemnames_for_component(): void {
*
* @return array
*/
- public function is_advancedgrading_itemname_provider(): array {
+ public static function is_advancedgrading_itemname_provider(): array {
return [
'valid' => [
'someother',
@@ -209,7 +209,7 @@ public function test_is_advancedgrading_itemname(string $itemname, bool $isadvan
*
* @return array
*/
- public function get_field_name_for_itemnumber_provider(): array {
+ public static function get_field_name_for_itemnumber_provider(): array {
return [
'Valid itemnumber 0 case 1' => [
0,
@@ -291,7 +291,7 @@ public function test_get_field_name_for_itemnumber_component_invalid_mapping_ite
*
* @return array
*/
- public function get_field_name_for_itemname_provider(): array {
+ public static function get_field_name_for_itemname_provider(): array {
return [
'Empty itemname empty case 1' => [
'',
@@ -393,7 +393,7 @@ public function test_get_field_name_for_itemname_invalid_mapping_with_name(): vo
*
* @return array
*/
- public function get_itemname_from_itemnumber_provider(): array {
+ public static function get_itemname_from_itemnumber_provider(): array {
return [
'Valid itemnumber 0' => [
0,
@@ -471,7 +471,7 @@ public function test_get_itemname_from_itemnumber_component_invalid_mapping_item
*
* @return array
*/
- public function get_itemnumber_from_itemname_provider(): array {
+ public static function get_itemnumber_from_itemname_provider(): array {
return [
'Empty itemname empty' => [
'',
diff --git a/grade/tests/export_test.php b/grade/tests/export_test.php
index f52c606ea8df9..ea58a8538ab1a 100644
--- a/grade/tests/export_test.php
+++ b/grade/tests/export_test.php
@@ -127,7 +127,7 @@ public function test_format_feedback_with_grade() {
*
* @return array
*/
- public function format_feedback_provider() : array {
+ public static function format_feedback_provider(): array {
return [
'Basic string (PLAIN)' => [
'This is an example string',
diff --git a/grade/tests/external/get_feedback_test.php b/grade/tests/external/get_feedback_test.php
index b0180301eb439..627dafba7bebd 100644
--- a/grade/tests/external/get_feedback_test.php
+++ b/grade/tests/external/get_feedback_test.php
@@ -77,7 +77,7 @@ public function test_get_feedback(?string $feedback, array $expected) {
*
* @return array
*/
- public function get_feedback_provider(): array {
+ public static function get_feedback_provider(): array {
return [
'Return when feedback is set.' => [
'Test feedback',
@@ -154,7 +154,7 @@ public function test_get_feedback_invalid_request(string $loggeduserrole, bool $
*
* @return array
*/
- public function get_feedback_invalid_request_provider(): array {
+ public static function get_feedback_invalid_request_provider(): array {
return [
'Logged user does not have permissions to view feedback.' => [
'user',
diff --git a/grade/tests/external/get_gradable_users_test.php b/grade/tests/external/get_gradable_users_test.php
index ae018bfdd3c00..7b76c5127a820 100644
--- a/grade/tests/external/get_gradable_users_test.php
+++ b/grade/tests/external/get_gradable_users_test.php
@@ -100,7 +100,7 @@ public function test_execute(bool $onlyactiveenrol, bool $grouprestricted, array
*
* @return array
*/
- public function execute_data(): array {
+ public static function execute_data(): array {
return [
'All users' => [
false,
diff --git a/grade/tests/grades/grader/gradingpanel/point/external/store_test.php b/grade/tests/grades/grader/gradingpanel/point/external/store_test.php
index 3467230cee9ae..ceea1d288a59d 100644
--- a/grade/tests/grades/grader/gradingpanel/point/external/store_test.php
+++ b/grade/tests/grades/grader/gradingpanel/point/external/store_test.php
@@ -293,7 +293,7 @@ public function test_execute_store_out_of__range(int $maxvalue, float $suppliedv
*
* @return array
*/
- public function execute_out_of_range_provider(): array {
+ public static function execute_out_of_range_provider(): array {
return [
'above' => [
'max' => 100,
diff --git a/grade/tests/grades/grader/gradingpanel/scale/external/store_test.php b/grade/tests/grades/grader/gradingpanel/scale/external/store_test.php
index ec9ddfe0dfa48..6a0d91fec7700 100644
--- a/grade/tests/grades/grader/gradingpanel/scale/external/store_test.php
+++ b/grade/tests/grades/grader/gradingpanel/scale/external/store_test.php
@@ -398,7 +398,7 @@ public function test_execute_store_out_of_range(int $suppliedvalue): void {
*
* @return array
*/
- public function execute_out_of_range_provider(): array {
+ public static function execute_out_of_range_provider(): array {
return [
'above' => [
'supplied' => 500,
diff --git a/grade/tests/lib_test.php b/grade/tests/lib_test.php
index 5f03f6dd50ef8..6e647c33f208e 100644
--- a/grade/tests/lib_test.php
+++ b/grade/tests/lib_test.php
@@ -527,7 +527,7 @@ public function test_ungraded_count_sumgrades_groups() {
/**
* Tests for calculate_average.
- * @dataProvider calculate_average_data()
+ * @dataProvider calculate_average_data
* @param int $meanselection Whether to inlcude all grades or non-empty grades in aggregation.
* @param array $expectedmeancount expected meancount value
* @param array $expectedaverage expceted average value
@@ -619,7 +619,7 @@ public function test_calculate_average(int $meanselection, array $expectedmeanco
*
* @return array of testing scenarios
*/
- public function calculate_average_data() : array {
+ public static function calculate_average_data(): array {
return [
'Non-empty grades' => [
'meanselection' => 1,
diff --git a/grade/tests/output/general_action_bar_test.php b/grade/tests/output/general_action_bar_test.php
index 49b09c061c8c2..bfdabc4fd5eec 100644
--- a/grade/tests/output/general_action_bar_test.php
+++ b/grade/tests/output/general_action_bar_test.php
@@ -155,7 +155,7 @@ public function test_export_for_template(string $userrole, bool $enableoutcomes,
*
* @return array
*/
- public function export_for_template_provider(): array {
+ public static function export_for_template_provider(): array {
$graderpluginname = get_string('pluginname', 'gradereport_grader');
$historypluginname = get_string('pluginname', 'gradereport_history');
$outcomespluginname = get_string('pluginname', 'gradereport_outcomes');
diff --git a/group/tests/reportbuilder/datasource/groups_test.php b/group/tests/reportbuilder/datasource/groups_test.php
index cf67b9c569813..5e07464c20874 100644
--- a/group/tests/reportbuilder/datasource/groups_test.php
+++ b/group/tests/reportbuilder/datasource/groups_test.php
@@ -232,7 +232,7 @@ public function test_datasource_non_default_columns(): void {
*
* @return array[]
*/
- public function datasource_filters_provider(): array {
+ public static function datasource_filters_provider(): array {
return [
// Course (just to test join).
'Filter course name' => ['course:fullname', [
diff --git a/h5p/tests/api_test.php b/h5p/tests/api_test.php
index b3fe6c3322d0f..5e67daf844b64 100644
--- a/h5p/tests/api_test.php
+++ b/h5p/tests/api_test.php
@@ -98,7 +98,7 @@ public function test_delete_library(string $libraryname, int $expectedh5p, int $
*
* @return array
*/
- public function delete_library_provider(): array {
+ public static function delete_library_provider(): array {
return [
'Delete MainLibrary' => [
'MainLibrary',
@@ -192,7 +192,7 @@ public function test_get_dependent_libraries(string $libraryname, int $expectedv
*
* @return array
*/
- public function get_dependent_libraries_provider(): array {
+ public static function get_dependent_libraries_provider(): array {
return [
'Main library of a content' => [
'MainLibrary',
@@ -256,7 +256,7 @@ public function test_get_library(string $libraryname, bool $emptyexpected): void
*
* @return array
*/
- public function get_library_provider(): array {
+ public static function get_library_provider(): array {
return [
'Main library of a content' => [
'MainLibrary',
@@ -529,7 +529,7 @@ public function test_can_edit_content(string $currentuser, string $fileauthor, s
*
* @return array
*/
- public function can_edit_content_provider(): array {
+ public static function can_edit_content_provider(): array {
return [
// Component = user.
'user: Admin user is author' => [
@@ -963,7 +963,7 @@ public function test_set_library_enabled(string $libraryname, string $action, in
*
* @return array
*/
- public function set_library_enabled_provider(): array {
+ public static function set_library_enabled_provider(): array {
return [
'Disable existing library' => [
'libraryname' => 'MainLibrary',
@@ -1068,7 +1068,7 @@ public function test_is_library_enabled(string $libraryname, bool $expected, boo
*
* @return array
*/
- public function is_library_enabled_provider(): array {
+ public static function is_library_enabled_provider(): array {
return [
'Library with 2 versions, one of them disabled' => [
'libraryname' => 'H5P.Lib1',
@@ -1194,7 +1194,7 @@ public function test_is_valid_package(string $filename, bool $expected, bool $is
*
* @return array
*/
- public function is_valid_package_provider(): array {
+ public static function is_valid_package_provider(): array {
return [
'Valid H5P file (as admin)' => [
'filename' => '/fixtures/greeting-card.h5p',
diff --git a/h5p/tests/editor_ajax_test.php b/h5p/tests/editor_ajax_test.php
index f09de5145a8c6..318f2478b424e 100644
--- a/h5p/tests/editor_ajax_test.php
+++ b/h5p/tests/editor_ajax_test.php
@@ -161,7 +161,7 @@ public function test_get_translations(array $datalibs, string $lang, bool $empty
*
* @return array
*/
- public function get_translations_provider(): array {
+ public static function get_translations_provider(): array {
return [
'No library' => [
[],
diff --git a/h5p/tests/editor_framework_test.php b/h5p/tests/editor_framework_test.php
index 1c93f87beb5ef..db142e1fc4cf3 100644
--- a/h5p/tests/editor_framework_test.php
+++ b/h5p/tests/editor_framework_test.php
@@ -125,7 +125,7 @@ public function test_get_language(array $datalib, string $lang, ?bool $emptyexpe
*
* @return array
*/
- public function get_language_provider(): array {
+ public static function get_language_provider(): array {
return [
'No library' => [
[],
@@ -289,7 +289,7 @@ public function test_get_available_languages(array $datalib, ?array $expectedlan
*
* @return array
*/
- public function get_available_languages_provider(): array {
+ public static function get_available_languages_provider(): array {
return [
'No library' => [
[],
diff --git a/h5p/tests/file_storage_test.php b/h5p/tests/file_storage_test.php
index cbf0ee5a13eb8..a8b97a788cfe6 100644
--- a/h5p/tests/file_storage_test.php
+++ b/h5p/tests/file_storage_test.php
@@ -598,7 +598,7 @@ public function test_get_icon_url(string $filename, bool $expected): void {
*
* @return array
*/
- public function get_icon_url_provider(): array {
+ public static function get_icon_url_provider(): array {
return [
'Icon included' => [
'filltheblanks.h5p',
diff --git a/h5p/tests/framework_test.php b/h5p/tests/framework_test.php
index 185a3624bcae6..1bb78772e9d8e 100644
--- a/h5p/tests/framework_test.php
+++ b/h5p/tests/framework_test.php
@@ -655,7 +655,7 @@ public function test_isPatchedLibrary(array $libraryrecords, array $testlibrary,
*
* @return array
*/
- public function isPatchedLibrary_provider(): array {
+ public static function isPatchedLibrary_provider(): array {
return [
'Unpatched library. No different versioning' => [
[
@@ -1557,7 +1557,7 @@ public function test_loadLibrarySemantics(array $libraryrecords, array $testlibr
*
* @return array
*/
- public function loadLibrarySemantics_provider(): array {
+ public static function loadLibrarySemantics_provider(): array {
$semantics = json_encode(
[
@@ -2348,7 +2348,7 @@ public function test_libraryHasUpgrade(array $libraryrecords, array $testlibrary
*
* @return array
*/
- public function libraryHasUpgrade_provider(): array {
+ public static function libraryHasUpgrade_provider(): array {
return [
'Lower major version; Identical lower version' => [
[
diff --git a/h5p/tests/generator_test.php b/h5p/tests/generator_test.php
index 623bf3cd220e5..1aac9a07dc09a 100644
--- a/h5p/tests/generator_test.php
+++ b/h5p/tests/generator_test.php
@@ -195,7 +195,7 @@ public function test_generate_h5p_data_files_creation(bool $createlibraryfiles,
*
* @return array
*/
- public function generate_h5p_data_files_creation_provider(): array {
+ public static function generate_h5p_data_files_creation_provider(): array {
return [
'Do not create library related files on the filesystem' => [
false,
@@ -304,7 +304,7 @@ public function test_generate_h5p_data_xapistates(?array $filerecord) {
*
* @return array
*/
- public function generate_h5p_data_xapistates_provider(): array {
+ public static function generate_h5p_data_xapistates_provider(): array {
return [
'Do not create the file nor xAPI states' => [
'filerecord' => null,
@@ -391,7 +391,7 @@ public function test_create_h5p_record(array $h5pdata, \stdClass $expected) {
*
* @return array
*/
- public function create_h5p_record_provider(): array {
+ public static function create_h5p_record_provider(): array {
$createdjsoncontent = json_encode(
array(
'text' => 'Created dummy text<\/p>\n',
@@ -512,7 +512,7 @@ public function test_create_contents_libraries_record(array $contentslibrariestd
*
* @return array
*/
- public function create_contents_libraries_record_provider(): array {
+ public static function create_contents_libraries_record_provider(): array {
return [
'Create h5p content library with set dependency type' => [
[
@@ -572,7 +572,7 @@ public function test_create_library_dependency_record(array $librarydependencyda
*
* @return array
*/
- public function create_library_dependency_record_provider(): array {
+ public static function create_library_dependency_record_provider(): array {
return [
'Create h5p library dependency with set dependency type' => [
[
@@ -638,7 +638,7 @@ public function test_create_content_file($filedata, $expecteddata): void {
*
* @return array
**/
- public function create_content_file_provider(): array {
+ public static function create_content_file_provider(): array {
return [
'Create file in content with id 4' => [
[
diff --git a/h5p/tests/helper_test.php b/h5p/tests/helper_test.php
index a257d04e246c9..c280f4a768a92 100644
--- a/h5p/tests/helper_test.php
+++ b/h5p/tests/helper_test.php
@@ -77,7 +77,7 @@ public function test_display_options(bool $frame, bool $export, bool $embed, boo
*
* @return array
*/
- public function display_options_provider(): array {
+ public static function display_options_provider(): array {
return [
'All display options disabled' => [
false,
@@ -468,7 +468,7 @@ public function test_parse_js_array(string $content, array $expected): void {
*
* @return array
*/
- public function parse_js_array_provider(): array {
+ public static function parse_js_array_provider(): array {
$lines = [
"{",
" missingTranslation: '[Missing translation :key]',",
diff --git a/h5p/tests/local/library/handler_test.php b/h5p/tests/local/library/handler_test.php
index 6e366d4ae2c6c..3298b1185d609 100644
--- a/h5p/tests/local/library/handler_test.php
+++ b/h5p/tests/local/library/handler_test.php
@@ -54,7 +54,7 @@ public function test_get_h5p_string(string $identifier, ?string $expectedresult,
*
* @return array
*/
- public function get_h5p_string_provider(): array {
+ public static function get_h5p_string_provider(): array {
return [
'Existing string in h5plib plugin' => [
'editor:add',
diff --git a/install/lang/be/admin.php b/install/lang/be/admin.php
new file mode 100644
index 0000000000000..9d4758981ce4c
--- /dev/null
+++ b/install/lang/be/admin.php
@@ -0,0 +1,41 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['clianswerno'] = 'n';
+$string['cliansweryes'] = 'y';
+$string['cliincorrectvalueerror'] = 'Памылка, хібнае значэньне "{$a->value}" для "{$a->option}"';
+$string['cliincorrectvalueretry'] = 'Хібнае значэньне, калі ласка, паўтарыце';
+$string['clitypevalue'] = 'значэньне тыпа';
+$string['clitypevaluedefault'] = 'значэньне тыпа, націсьніце Enter для выкарыстаньня стандартнага значэньня ({$a})';
+$string['cliunknowoption'] = 'Нераспазнаныя опцыі:
+ {$a}
+Калі ласка, выкарыстайце опцыю --help.';
+$string['cliyesnoprompt'] = 'надрукуйце y (yes) ці n (n=no)';
diff --git a/install/lang/ia/admin.php b/install/lang/ia/admin.php
index fa2318b58220f..074a6b99e462e 100644
--- a/install/lang/ia/admin.php
+++ b/install/lang/ia/admin.php
@@ -39,3 +39,5 @@
{$a}
Per favor usa le option --help.';
$string['cliyesnoprompt'] = 'typa s (significa si) o n (significa no)';
+$string['environmentrequireinstall'] = 'debe esser installate e habilitate';
+$string['environmentrequireversion'] = 'version {$a->needed} es requirite e tu es executante {$a->current}';
diff --git a/install/lang/ru/admin.php b/install/lang/ru/admin.php
index c609d706fbb3e..89dadfca6244e 100644
--- a/install/lang/ru/admin.php
+++ b/install/lang/ru/admin.php
@@ -29,8 +29,8 @@
defined('MOODLE_INTERNAL') || die();
-$string['clianswerno'] = 'нет';
-$string['cliansweryes'] = 'да';
+$string['clianswerno'] = 'n';
+$string['cliansweryes'] = 'y';
$string['cliincorrectvalueerror'] = 'Ошибка, некорректное значение «{$a->value}» для «{$a->option}»';
$string['cliincorrectvalueretry'] = 'Некорректное значение, пожалуйста, попробуйте заново';
$string['clitypevalue'] = 'введите значение';
diff --git a/install/lang/sgs/langconfig.php b/install/lang/sgs/langconfig.php
new file mode 100644
index 0000000000000..677968c275eee
--- /dev/null
+++ b/install/lang/sgs/langconfig.php
@@ -0,0 +1,32 @@
+.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'Žemaitėškā';
diff --git a/iplookup/tests/geoip_test.php b/iplookup/tests/geoip_test.php
index b547c186ff1e6..f623f26dc0c9d 100644
--- a/iplookup/tests/geoip_test.php
+++ b/iplookup/tests/geoip_test.php
@@ -16,14 +16,6 @@
namespace core;
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-
-require_once("{$CFG->libdir}/filelib.php");
-require_once("{$CFG->dirroot}/iplookup/lib.php");
-
-
/**
* GeoIp data file parsing test.
*
@@ -32,15 +24,21 @@
* @copyright 2012 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class geoip_test extends \advanced_testcase {
- public function setUp(): void {
- $this->resetAfterTest();
+final class geoip_test extends \advanced_testcase {
+ #[\Override]
+ public static function setUpBeforeClass(): void {
+ global $CFG;
+
+ parent::setUpBeforeClass();
+
+ require_once("{$CFG->libdir}/filelib.php");
+ require_once("{$CFG->dirroot}/iplookup/lib.php");
}
/**
* Setup the GeoIP2File system.
*/
- public function setup_geoip2file() {
+ public function setup_geoip2file(): void {
global $CFG;
$CFG->geoip2file = "$CFG->dirroot/iplookup/tests/fixtures/GeoIP2-City-Test.mmdb";
}
@@ -51,7 +49,9 @@ public function setup_geoip2file() {
* @dataProvider ip_provider
* @param string $ip The IP to test
*/
- public function test_ip($ip) {
+ public function test_ip($ip): void {
+ $this->resetAfterTest();
+
$this->setup_geoip2file();
// Note: The results we get from the iplookup tests are beyond our control.
@@ -76,7 +76,7 @@ public function test_ip($ip) {
*
* @return array
*/
- public function ip_provider() {
+ public static function ip_provider(): array {
return [
'IPv4: IPV4 test' => ['81.2.69.142'],
'IPv6: IPV6 test' => ['2001:252:1::1:1:1'],
diff --git a/lang/en/auth.php b/lang/en/auth.php
index c73816c063c1f..5da36a8a7eed1 100644
--- a/lang/en/auth.php
+++ b/lang/en/auth.php
@@ -38,7 +38,7 @@
$string['auth_changepasswordhelp_expl'] = 'Display lost password help to users who have lost their {$a} password. This will be displayed either as well as or instead of the Change Password URL or Internal Moodle password change.';
$string['auth_changepasswordurl'] = 'Change password URL';
$string['auth_changepasswordurl_expl'] = 'Specify the url to send users who have lost their {$a} password. Set Use standard Change Password page to No.';
-$string['auth_changingemailaddress'] = 'You have requested a change of email address, from {$a->oldemail} to {$a->newemail}. For security reasons, we are sending you an email message at the new address to confirm that it belongs to you. Your email address will be updated as soon as you open the URL sent to you in that message.';
+$string['auth_changingemailaddress'] = 'You have requested a change of email address, from {$a->oldemail} to {$a->newemail}. For security reasons, we are sending you an email message at the new address to confirm that it belongs to you. Your email address will be updated as soon as you open the URL sent to you in that message. The confirmation link will expire in 10 minutes';
$string['authinstructions'] = 'Leave this blank for the default login instructions to be displayed on the login page. If you want to provide custom login instructions, enter them here.';
$string['auth_invalidnewemailkey'] = 'Error: if you are trying to confirm a change of email address, you may have made a mistake in copying the URL we sent you by email. Please copy the address and try again.';
$string['auth_loginrecaptcha'] = 'Enable reCAPTCHA for login';
@@ -80,6 +80,7 @@
You have requested a change of your email address for your account on {$a->site}. To confirm this change, please go to the following web address:
{$a->url}
+The confirmation link will expire in 10 minutes.
{$a->supportemail}';
$string['emailupdatesuccess'] = 'Email address of user {$a->fullname} was successfully updated to {$a->email}.';
diff --git a/lib/behat/behat_field_manager.php b/lib/behat/behat_field_manager.php
index 07b87e5b3d85a..6136871759a13 100644
--- a/lib/behat/behat_field_manager.php
+++ b/lib/behat/behat_field_manager.php
@@ -337,6 +337,12 @@ protected static function normalise_fieldtype(string $fieldtype): string {
if ($fieldtype === 'tags') {
return 'autocomplete';
}
+ if ($fieldtype === 'date_time_selector') {
+ return 'date_time';
+ }
+ if ($fieldtype === 'date_selector') {
+ return 'date';
+ }
return $fieldtype;
}
diff --git a/lib/behat/classes/partial_named_selector.php b/lib/behat/classes/partial_named_selector.php
index 98ab02f6e82d4..edb2b0acadfaa 100644
--- a/lib/behat/classes/partial_named_selector.php
+++ b/lib/behat/classes/partial_named_selector.php
@@ -324,7 +324,13 @@ public function __construct() {
XPATH
,
'date_time' => << <<sessiontimeout;
+ $maxlifetime = (int) $CFG->sessiontimeout;
try {
// Kill all sessions of deleted and suspended users without any hesitation.
@@ -1060,7 +1060,7 @@ public static function gc() {
$rs->close();
// Delete expired sessions for guest user account, give them larger timeout, there is no security risk here.
- $params = array('purgebefore' => (time() - ($maxlifetime * 5)), 'guestid'=>$CFG->siteguest);
+ $params = array('purgebefore' => (time() - $maxlifetime), 'guestid' => $CFG->siteguest);
$rs = $DB->get_recordset_select('sessions', 'userid = :guestid AND timemodified < :purgebefore', $params, 'id DESC', 'id, sid');
foreach ($rs as $session) {
self::kill_session($session->sid);
diff --git a/lib/ddl/tests/ddl_test.php b/lib/ddl/tests/ddl_test.php
index 3dd3d07f22ac5..7e552f6edd2b4 100644
--- a/lib/ddl/tests/ddl_test.php
+++ b/lib/ddl/tests/ddl_test.php
@@ -2266,7 +2266,7 @@ public function test_object_name() {
*
* @return array The type-value pair fixture.
*/
- public function get_enc_quoted_provider() {
+ public static function get_enc_quoted_provider(): array {
return array(
// Reserved: some examples from SQL-92.
[true, 'from'],
@@ -2315,7 +2315,7 @@ public function test_get_enc_quoted($reserved, $columnname) {
*
* @return array The type-old-new tuple fixture.
*/
- public function sql_generator_get_rename_field_sql_provider() {
+ public static function sql_generator_get_rename_field_sql_provider(): array {
return array(
// Reserved: an example from SQL-92.
// Both names should be reserved.
diff --git a/lib/dml/tests/dml_read_slave_test.php b/lib/dml/tests/dml_read_slave_test.php
index 4ded903cb7d41..c561d61812f17 100644
--- a/lib/dml/tests/dml_read_slave_test.php
+++ b/lib/dml/tests/dml_read_slave_test.php
@@ -94,7 +94,7 @@ private function assert_readonly_handle($handle) : void {
* @return array
* @dataProvider table_names_provider
*/
- public function table_names_provider() : array {
+ public static function table_names_provider(): array {
return [
[
"SELECT *
diff --git a/lib/dml/tests/dml_table_test.php b/lib/dml/tests/dml_table_test.php
index 49da717dddf51..2fe8a45de2c0d 100644
--- a/lib/dml/tests/dml_table_test.php
+++ b/lib/dml/tests/dml_table_test.php
@@ -35,7 +35,7 @@ class dml_table_test extends \database_driver_testcase {
*
* @return array
*/
- public function get_field_select_provider() : array {
+ public static function get_field_select_provider(): array {
return [
'single field' => [
'tablename' => 'test_table_single',
@@ -102,7 +102,7 @@ public function test_get_field_select(
*
* @return array
*/
- public function extract_from_result_provider() : array {
+ public static function extract_from_result_provider(): array {
return [
'single table' => [
'fieldlist' => [
diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php
index 160c93c768084..a23ea275dac60 100644
--- a/lib/dml/tests/dml_test.php
+++ b/lib/dml/tests/dml_test.php
@@ -4451,7 +4451,7 @@ public function test_sql_concat() {
}
- public function sql_concat_join_provider() {
+ public static function sql_concat_join_provider(): array {
return array(
// All strings.
array(
@@ -6255,7 +6255,7 @@ public function test_get_server_info_mysql(
* @return array[]
* @see \mysqli_native_moodle_database::get_server_info
*/
- public function get_server_info_mysql_provider() {
+ public static function get_server_info_mysql_provider(): array {
return [
'MySQL 5.7.39 - MySQLi version' => [
'5.7.39-log',
diff --git a/lib/dml/tests/sqlsrv_native_moodle_database_test.php b/lib/dml/tests/sqlsrv_native_moodle_database_test.php
index 9e0f34b9f7ea5..79b93ab638904 100644
--- a/lib/dml/tests/sqlsrv_native_moodle_database_test.php
+++ b/lib/dml/tests/sqlsrv_native_moodle_database_test.php
@@ -40,8 +40,7 @@
* @copyright 2017 John Okely
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class sqlsrv_native_moodle_database_test extends \advanced_testcase {
-
+final class sqlsrv_native_moodle_database_test extends \advanced_testcase {
public function setUp(): void {
parent::setUp();
$this->resetAfterTest();
@@ -51,7 +50,7 @@ public function setUp(): void {
* Dataprovider for test_add_no_lock_to_temp_tables
* @return array Data for test_add_no_lock_to_temp_tables
*/
- public function add_no_lock_to_temp_tables_provider() {
+ public static function add_no_lock_to_temp_tables_provider(): array {
return [
"Basic temp table, nothing following" => [
'input' => 'SELECT * FROM {table_temp}',
@@ -144,7 +143,7 @@ public function test_add_no_lock_to_temp_tables($input, $expected) {
*
* @return array data for test_has_query_order_by
*/
- public function has_query_order_by_provider() {
+ public static function has_query_order_by_provider(): array {
// Fixtures taken from https://docs.moodle.org/en/ad-hoc_contributed_reports.
return [
diff --git a/lib/external/tests/external_api_test.php b/lib/external/tests/external_api_test.php
index cc359cae2294a..a45856dda3445 100644
--- a/lib/external/tests/external_api_test.php
+++ b/lib/external/tests/external_api_test.php
@@ -374,7 +374,7 @@ public function test_get_context_params3(): void {
*
* @return array
*/
- public function all_external_info_provider(): array {
+ public static function all_external_info_provider(): array {
global $DB;
// We are testing here that all the external function descriptions can be generated without
diff --git a/lib/external/tests/external_value_test.php b/lib/external/tests/external_value_test.php
index 9fe4fef6b4569..fff465956925d 100644
--- a/lib/external/tests/external_value_test.php
+++ b/lib/external/tests/external_value_test.php
@@ -34,7 +34,7 @@ class external_value_test extends advanced_testcase {
*
* @return array[]
*/
- public function required_param_provider(): array {
+ public static function required_param_provider(): array {
return [
[ VALUE_DEFAULT, false ],
[ VALUE_REQUIRED, false ],
diff --git a/lib/filestorage/tests/file_storage_test.php b/lib/filestorage/tests/file_storage_test.php
index 7a0fd34d15c9a..1ed4cd525d3a3 100644
--- a/lib/filestorage/tests/file_storage_test.php
+++ b/lib/filestorage/tests/file_storage_test.php
@@ -2132,7 +2132,7 @@ public function test_mimetype_not_found() {
*
* @return array[]
*/
- public function filepath_mimetype_provider(): array {
+ public static function filepath_mimetype_provider(): array {
return [
[__DIR__ . '/fixtures/testimage.jpg', 'image/jpeg'],
[__DIR__ . '/fixtures/testimage.svg', 'image/svg+xml'],
diff --git a/lib/filestorage/tests/file_system_filedir_test.php b/lib/filestorage/tests/file_system_filedir_test.php
index 2d7532f405d1d..04aab7e91dea7 100644
--- a/lib/filestorage/tests/file_system_filedir_test.php
+++ b/lib/filestorage/tests/file_system_filedir_test.php
@@ -1107,7 +1107,7 @@ public function test_empty_trash() {
*
* @return array
*/
- public function contenthash_dataprovider() {
+ public static function contenthash_dataprovider(): array {
return array(
array(
'contenthash' => 'eee4943847a35a4b6942c6f96daafde06bcfdfab',
diff --git a/lib/filestorage/tests/file_system_test.php b/lib/filestorage/tests/file_system_test.php
index 9a854308ed935..3cb3b2e4ed7b6 100644
--- a/lib/filestorage/tests/file_system_test.php
+++ b/lib/filestorage/tests/file_system_test.php
@@ -1238,7 +1238,7 @@ public function test_mimetype_from_storedfile_using_file_content_remote() {
*
* @return array
*/
- public function is_image_from_storedfile_provider() {
+ public static function is_image_from_storedfile_provider(): array {
return array(
'Standard image' => array('image/png', true),
'Made up document/image' => array('document/image', false),
@@ -1250,7 +1250,7 @@ public function is_image_from_storedfile_provider() {
*
* @return array
*/
- public function get_local_path_from_storedfile_provider() {
+ public static function get_local_path_from_storedfile_provider(): array {
return [
'default args (nofetch)' => [
'args' => [],
diff --git a/lib/filestorage/tests/mbz_packer_test.php b/lib/filestorage/tests/mbz_packer_test.php
index affed9f5f486d..9b50f1793c44c 100644
--- a/lib/filestorage/tests/mbz_packer_test.php
+++ b/lib/filestorage/tests/mbz_packer_test.php
@@ -89,7 +89,7 @@ public function test_archive_with_both_options() {
$this->assertEquals('frog', $out->get_content());
}
- public function usezipbackups_provider() {
+ public static function usezipbackups_provider(): array {
return [
'Use zips' => [true],
'Use tgz' => [false],
diff --git a/lib/form/tests/behat/dates.feature b/lib/form/tests/behat/dates.feature
new file mode 100644
index 0000000000000..ecb9bd7bb9e2f
--- /dev/null
+++ b/lib/form/tests/behat/dates.feature
@@ -0,0 +1,76 @@
+@core @core_form
+Feature: Setting and validating date fields
+ Behat steps to set and check the date fields
+
+ Background:
+ Given I log in as "admin"
+
+ Scenario: Setting moodleform date fields by field label
+ Given I am on fixture page "/lib/form/tests/behat/fixtures/dates_form.php"
+ And I set the following fields to these values:
+ | Simple only date | ## 2023-07-31 ## |
+ | simpleoptionaldateonly[enabled] | 1 |
+ | Simple optional only date | ## 2023-08-31 ## |
+ | Simple date and time | ## 2023-07-31 11:15 ## |
+ | simpleoptionaldatetime[enabled] | 1 |
+ | Simple optional date and time | ## 2023-08-31 14:45 ## |
+ | Group1 only date | ## 2023-07-31 ## |
+ | group1optionaldateonly[enabled] | 1 |
+ | Group1 optional only date | ## 2023-08-31 ## |
+ | Group1 date and time | ## 2023-07-31 11:15 ## |
+ | group1optionaldatetime[enabled] | 1 |
+ | Group1 optional date and time | ## 2023-08-31 14:45 ## |
+ | Group2 only date | ## 2023-07-31 ## |
+ | dategroup2[group2optionaldateonly][enabled] | 1 |
+ | Group2 optional only date | ## 2023-08-31 ## |
+ | Group2 date and time | ## 2023-07-31 11:15 ## |
+ | dategroup2[group2optionaldatetime][enabled] | 1 |
+ | Group2 optional date and time | ## 2023-08-31 14:45 ## |
+ When I press "Send form"
+ Then I should see "simpledateonly: 1690732800"
+ And I should see "simpleoptionaldateonly: 1693411200"
+ And I should see "simpledatetime: 1690773300"
+ And I should see "simpleoptionaldatetime: 1693464300"
+ And I should see "group1dateonly: 1690732800"
+ And I should see "group1optionaldateonly: 1693411200"
+ And I should see "group1datetime: 1690773300"
+ And I should see "group1optionaldatetime: 1693464300"
+ And I should see "dategroup2[group2dateonly]: 1690732800"
+ And I should see "dategroup2[group2optionaldateonly]: 1693411200"
+ And I should see "dategroup2[group2datetime]: 1690773300"
+ And I should see "dategroup2[group2optionaldatetime]: 1693464300"
+
+ Scenario: Setting moodleform date fields by field name
+ Given I am on fixture page "/lib/form/tests/behat/fixtures/dates_form.php"
+ And I set the following fields to these values:
+ | simpledateonly | ## 2023-07-31 ## |
+ | simpleoptionaldateonly[enabled] | 1 |
+ | simpleoptionaldateonly | ## 2023-08-31 ## |
+ | simpledatetime | ## 2023-07-31 11:15 ## |
+ | simpleoptionaldatetime[enabled] | 1 |
+ | simpleoptionaldatetime | ## 2023-08-31 14:45 ## |
+ | group1dateonly | ## 2023-07-31 ## |
+ | group1optionaldateonly[enabled] | 1 |
+ | group1optionaldateonly | ## 2023-08-31 ## |
+ | group1datetime | ## 2023-07-31 11:15 ## |
+ | group1optionaldatetime[enabled] | 1 |
+ | group1optionaldatetime | ## 2023-08-31 14:45 ## |
+ | dategroup2[group2dateonly] | ## 2023-07-31 ## |
+ | dategroup2[group2optionaldateonly][enabled] | 1 |
+ | dategroup2[group2optionaldateonly] | ## 2023-08-31 ## |
+ | dategroup2[group2datetime] | ## 2023-07-31 11:15 ## |
+ | dategroup2[group2optionaldatetime][enabled] | 1 |
+ | dategroup2[group2optionaldatetime] | ## 2023-08-31 14:45 ## |
+ When I press "Send form"
+ Then I should see "simpledateonly: 1690732800"
+ And I should see "simpleoptionaldateonly: 1693411200"
+ And I should see "simpledatetime: 1690773300"
+ And I should see "simpleoptionaldatetime: 1693464300"
+ And I should see "group1dateonly: 1690732800"
+ And I should see "group1optionaldateonly: 1693411200"
+ And I should see "group1datetime: 1690773300"
+ And I should see "group1optionaldatetime: 1693464300"
+ And I should see "dategroup2[group2dateonly]: 1690732800"
+ And I should see "dategroup2[group2optionaldateonly]: 1693411200"
+ And I should see "dategroup2[group2datetime]: 1690773300"
+ And I should see "dategroup2[group2optionaldatetime]: 1693464300"
diff --git a/lib/form/tests/behat/fixtures/dates_form.php b/lib/form/tests/behat/fixtures/dates_form.php
new file mode 100644
index 0000000000000..e20c03a0b4fc3
--- /dev/null
+++ b/lib/form/tests/behat/fixtures/dates_form.php
@@ -0,0 +1,99 @@
+.
+
+/**
+ * Test for setting date fields in behat
+ *
+ * @package core_form
+ * @copyright Marina Glancy
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../../../../config.php');
+
+defined('BEHAT_SITE_RUNNING') || die();
+
+global $CFG, $PAGE, $OUTPUT;
+require_once($CFG->libdir . '/formslib.php');
+$PAGE->set_url('/lib/form/tests/behat/fixtures/dates_form.php');
+$PAGE->add_body_class('limitedwidth');
+require_login();
+$PAGE->set_context(context_system::instance());
+
+/**
+ * Test form class adding all types of date elements
+ *
+ * @package core_form
+ */
+class test_dates_form extends moodleform {
+ /**
+ * Define the form.
+ */
+ public function definition() {
+ $mform = $this->_form;
+
+ $mform->addElement('date_selector', 'simpledateonly', 'Simple only date');
+ $mform->addElement('date_selector', 'simpleoptionaldateonly', 'Simple optional only date', ['optional' => true]);
+ $mform->addElement('date_time_selector', 'simpledatetime', 'Simple date and time');
+ $mform->addElement('date_time_selector', 'simpleoptionaldatetime', 'Simple optional date and time', ['optional' => true]);
+
+ $group = [];
+ $group[] = $mform->createElement('date_selector', 'group1dateonly', 'Group1 only date');
+ $group[] = $mform->createElement('date_selector', 'group1optionaldateonly', 'Group1 optional only date',
+ ['optional' => true]);
+ $group[] = $mform->createElement('date_time_selector', 'group1datetime', 'Group1 date and time');
+ $group[] = $mform->createElement('date_time_selector', 'group1optionaldatetime', 'Group1 optional date and time',
+ ['optional' => true]);
+ $mform->addGroup($group, 'dategroup1', 'Date group1', '', false);
+
+ $group = [];
+ $group[] = $mform->createElement('date_selector', 'group2dateonly', 'Group2 only date');
+ $group[] = $mform->createElement('date_selector', 'group2optionaldateonly', 'Group2 optional only date',
+ ['optional' => true]);
+ $group[] = $mform->createElement('date_time_selector', 'group2datetime', 'Group2 date and time');
+ $group[] = $mform->createElement('date_time_selector', 'group2optionaldatetime', 'Group2 optional date and time',
+ ['optional' => true]);
+ $mform->addGroup($group, 'dategroup2', 'Date group2', '', true);
+
+ $this->add_action_buttons(false, 'Send form');
+ }
+}
+
+echo $OUTPUT->header();
+
+echo "Quickform integration test
";
+
+$form = new test_dates_form();
+
+$data = $form->get_data();
+if ($data) {
+ echo "Submitted data
";
+ echo '';
+ $data = (array) $data;
+ foreach ($data as $field => $value) {
+ if (is_array($value)) {
+ foreach ($value as $key => $v) {
+ echo "- {$field}[$key]: $v
";
+ }
+ } else {
+ echo "- $field: $value
";
+ }
+ }
+ echo '
';
+}
+$form->display();
+
+echo $OUTPUT->footer();
diff --git a/lib/form/tests/duration_test.php b/lib/form/tests/duration_test.php
index a19ce851e20c5..34901d4bf676a 100644
--- a/lib/form/tests/duration_test.php
+++ b/lib/form/tests/duration_test.php
@@ -106,7 +106,7 @@ public function test_get_units(): void {
*
* @return array test cases.
*/
- public function seconds_to_unit_cases(): array {
+ public static function seconds_to_unit_cases(): array {
return [
[[0, MINSECS], 0], // Zero minutes, for a nice default unit.
[[1, 1], 1],
@@ -147,7 +147,7 @@ public function test_seconds_to_unit_different_default_unit() {
*
* @return array test cases.
*/
- public function export_value_cases(): array {
+ public static function export_value_cases(): array {
return [
[10, '10', 1],
[9, '9.3', 1],
diff --git a/lib/form/tests/filetypes_util_test.php b/lib/form/tests/filetypes_util_test.php
index 5bf2d73a45de9..73391aa9545f9 100644
--- a/lib/form/tests/filetypes_util_test.php
+++ b/lib/form/tests/filetypes_util_test.php
@@ -14,36 +14,21 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-/**
- * Provides the {@link core_form\filetypes_util_testcase} class.
- *
- * @package core_form
- * @category test
- * @copyright 2017 David Mudrák
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
namespace core_form;
-use advanced_testcase;
-
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-
/**
* Test cases for the {@link core_form\filetypes_util} class.
*
+ * @package core_form
* @copyright 2017 David Mudrak
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @covers \core_form\filetypes_util
*/
-class filetypes_util_test extends advanced_testcase {
-
+final class filetypes_util_test extends \advanced_testcase {
/**
* Test normalizing list of extensions.
*/
- public function test_normalize_file_types() {
-
+ public function test_normalize_file_types(): void {
$this->resetAfterTest(true);
$util = new filetypes_util();
@@ -74,8 +59,7 @@ public function test_normalize_file_types() {
/**
* Test MIME type formal recognition.
*/
- public function test_looks_like_mimetype() {
-
+ public function test_looks_like_mimetype(): void {
$this->resetAfterTest(true);
$util = new filetypes_util();
@@ -93,8 +77,7 @@ public function test_looks_like_mimetype() {
/**
* Test getting/checking group.
*/
- public function test_is_filetype_group() {
-
+ public function test_is_filetype_group(): void {
$this->resetAfterTest(true);
$util = new filetypes_util();
@@ -111,8 +94,7 @@ public function test_is_filetype_group() {
/**
* Test describing list of extensions.
*/
- public function test_describe_file_types() {
-
+ public function test_describe_file_types(): void {
$this->resetAfterTest(true);
$util = new filetypes_util();
@@ -169,8 +151,7 @@ public function test_describe_file_types() {
/**
* Test expanding mime types into extensions.
*/
- public function test_expand() {
-
+ public function test_expand(): void {
$this->resetAfterTest(true);
$util = new filetypes_util();
@@ -207,8 +188,7 @@ public function test_expand() {
/**
* Test checking that a type is among others.
*/
- public function test_is_listed() {
-
+ public function test_is_listed(): void {
$this->resetAfterTest(true);
$util = new filetypes_util();
@@ -250,8 +230,7 @@ public function test_is_listed() {
/**
* Test getting types not present in a list.
*/
- public function test_get_not_listed() {
-
+ public function test_get_not_listed(): void {
$this->resetAfterTest(true);
$util = new filetypes_util();
@@ -273,8 +252,7 @@ public function test_get_not_listed() {
/**
* Test populating the tree for the browser.
*/
- public function test_data_for_browser() {
-
+ public function test_data_for_browser(): void {
$this->resetAfterTest(true);
$util = new filetypes_util();
@@ -359,7 +337,7 @@ public function test_data_for_browser() {
*
* @return array
*/
- public function is_allowed_file_type_provider() {
+ public static function is_allowed_file_type_provider(): array {
return [
'Filetype not in extension list' => [
'filename' => 'test.xml',
@@ -421,7 +399,7 @@ public function test_is_allowed_file_type($filename, $list, $expected) {
*
* @return array
*/
- public function get_unknown_file_types_provider() {
+ public static function get_unknown_file_types_provider(): array {
return [
'Empty list' => [
'filetypes' => '',
diff --git a/lib/form/tests/privacy/provider_test.php b/lib/form/tests/privacy/provider_test.php
index dc42e39b204b9..d28d26cbe7456 100644
--- a/lib/form/tests/privacy/provider_test.php
+++ b/lib/form/tests/privacy/provider_test.php
@@ -27,16 +27,13 @@
use core_form\privacy\provider;
use core_privacy\local\request\writer;
-defined('MOODLE_INTERNAL') || die();
-
/**
* Unit tests for the privacy API implementation.
*
* @copyright 2018 David Mudrák
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class provider_test extends \core_privacy\tests\provider_testcase {
-
+final class provider_test extends \core_privacy\tests\provider_testcase {
/**
* When no preference exists, there should be no export.
*/
@@ -85,7 +82,7 @@ public function test_filemanager_recentviewmode(string $val, string $desc) {
*
* @return array
*/
- public function data_filemanager_recentviewmode() {
+ public static function data_filemanager_recentviewmode(): array {
return [
'icons' => [
'val' => '1',
diff --git a/lib/mlbackend/python/tests/processor_test.php b/lib/mlbackend/python/tests/processor_test.php
index d14dd088cccde..58ec84d1afcac 100644
--- a/lib/mlbackend/python/tests/processor_test.php
+++ b/lib/mlbackend/python/tests/processor_test.php
@@ -23,9 +23,9 @@
* @category test
* @copyright 2019 David Mudrák
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @covers \mlbackend_python\processor
*/
-class processor_test extends \advanced_testcase {
-
+final class processor_test extends \advanced_testcase {
/**
* Test implementation of the {@link \mlbackend_python\processor::check_pip_package_version()} method.
*
@@ -41,11 +41,12 @@ public function test_check_pip_package_version($actual, $required, $result) {
/**
* Check that the {@link \mlbackend_python\processor::check_pip_package_version()} can be called with single argument.
*/
- public function test_check_pip_package_version_default() {
-
+ public function test_check_pip_package_version_default(): void {
$this->assertSame(-1, \mlbackend_python\processor::check_pip_package_version('0.0.1'));
- $this->assertSame(0, \mlbackend_python\processor::check_pip_package_version(
- \mlbackend_python\processor::REQUIRED_PIP_PACKAGE_VERSION));
+ $this->assertSame(
+ 0,
+ \mlbackend_python\processor::check_pip_package_version(\mlbackend_python\processor::REQUIRED_PIP_PACKAGE_VERSION),
+ );
}
/**
@@ -53,7 +54,7 @@ public function test_check_pip_package_version_default() {
*
* @return array
*/
- public function check_pip_package_versions() {
+ public static function check_pip_package_versions(): array {
return [
// Exact match.
[
diff --git a/lib/phpunit/classes/advanced_testcase.php b/lib/phpunit/classes/advanced_testcase.php
index da4fa0a5714a4..329df1abf9f48 100644
--- a/lib/phpunit/classes/advanced_testcase.php
+++ b/lib/phpunit/classes/advanced_testcase.php
@@ -196,7 +196,7 @@ protected function loadDataSet() {
* @param array $files full paths to CSV or XML files to load.
* @return phpunit_dataset
*/
- protected function dataset_from_files(array $files) {
+ protected static function dataset_from_files(array $files) {
// We ignore $delimiter, $enclosure and $escape, use the default ones in your fixtures.
$dataset = new phpunit_dataset();
$dataset->from_files($files);
@@ -213,7 +213,7 @@ protected function dataset_from_files(array $files) {
* @param string $table name of the table which the file belongs to (only for CSV files).
* @return phpunit_dataset
*/
- protected function dataset_from_string(string $content, string $type, ?string $table = null) {
+ protected static function dataset_from_string(string $content, string $type, ?string $table = null) {
$dataset = new phpunit_dataset();
$dataset->from_string($content, $type, $table);
return $dataset;
@@ -227,7 +227,7 @@ protected function dataset_from_string(string $content, string $type, ?string $t
* @param array $data array of tables, see {@see phpunit_dataset::from_array()} for supported formats.
* @return phpunit_dataset
*/
- protected function dataset_from_array(array $data) {
+ protected static function dataset_from_array(array $data) {
$dataset = new phpunit_dataset();
$dataset->from_array($data);
return $dataset;
@@ -608,28 +608,31 @@ public static function getDataGenerator() {
* @param bool $https true if https required
* @return string url
*/
- public function getExternalTestFileUrl($path, $https = false) {
+ public static function getExternalTestFileUrl(
+ string $path,
+ bool $https = false,
+ ): string {
$path = ltrim($path, '/');
if ($path) {
- $path = '/'.$path;
+ $path = "/{$path}";
}
if ($https) {
if (defined('TEST_EXTERNAL_FILES_HTTPS_URL')) {
if (!TEST_EXTERNAL_FILES_HTTPS_URL) {
- $this->markTestSkipped('Tests using external https test files are disabled');
+ self::markTestSkipped('Tests using external https test files are disabled');
}
return TEST_EXTERNAL_FILES_HTTPS_URL.$path;
}
- return 'https://download.moodle.org/unittest'.$path;
+ return "https://download.moodle.org/unittest/{$path}";
}
if (defined('TEST_EXTERNAL_FILES_HTTP_URL')) {
if (!TEST_EXTERNAL_FILES_HTTP_URL) {
- $this->markTestSkipped('Tests using external http test files are disabled');
+ self::markTestSkipped('Tests using external http test files are disabled');
}
return TEST_EXTERNAL_FILES_HTTP_URL.$path;
}
- return 'http://download.moodle.org/unittest'.$path;
+ return "http://download.moodle.org/unittest/{$path}";
}
/**
@@ -744,25 +747,34 @@ protected function run_all_adhoc_tasks(): void {
}
/**
- * Convenience method to load a fixture from a component's fixture directory.
+ * Convenience method to get the path to a fixture.
*
* @param string $component
* @param string $path
* @throws coding_exception
*/
- protected static function load_fixture(
+ protected static function get_fixture_path(
string $component,
string $path,
- ): void {
- $fullpath = sprintf(
+ ): string {
+ return sprintf(
"%s/tests/fixtures/%s",
\core_component::get_component_directory($component),
$path,
);
- if (!file_exists($fullpath)) {
- throw new \coding_exception("Fixture file not found: $fullpath");
- }
+ }
+ /**
+ * Convenience method to load a fixture from a component's fixture directory.
+ *
+ * @param string $component
+ * @param string $path
+ * @throws coding_exception
+ */
+ protected static function load_fixture(
+ string $component,
+ string $path,
+ ): void {
global $ADMIN;
global $CFG;
global $DB;
@@ -774,6 +786,12 @@ protected static function load_fixture(
global $COURSE;
global $SITE;
+ $fullpath = static::get_fixture_path($component, $path);
+
+ if (!file_exists($fullpath)) {
+ throw new \coding_exception("Fixture file not found: $fullpath");
+ }
+
require_once($fullpath);
}
}
diff --git a/lib/phpunit/tests/phpunit_dataset_test.php b/lib/phpunit/tests/phpunit_dataset_test.php
index 4e0aa982f7439..4eb07e4acf13d 100644
--- a/lib/phpunit/tests/phpunit_dataset_test.php
+++ b/lib/phpunit/tests/phpunit_dataset_test.php
@@ -83,7 +83,7 @@ public function test_from_files() {
/**
* test_from_file() data provider.
*/
- public function from_file_provider() {
+ public static function from_file_provider(): array {
// Create an unreadable file with vfsStream.
$vfsfile = vfsStream::newFile('unreadable', 0222);
vfsStream::setup('root')->addChild($vfsfile);
@@ -183,7 +183,7 @@ public function test_from_file(string $fullpath, string $tablename, ?string $exc
/**
* test_from_string() data provider.
*/
- public function from_string_provider() {
+ public static function from_string_provider(): array {
return [
'wrong type' => [
@@ -276,7 +276,7 @@ public function test_from_string(string $content, string $type, string $tablenam
/**
* test_from_array() data provider.
*/
- public function from_array_provider() {
+ public static function from_array_provider(): array {
return [
'repeated array table many structures' => [
'structure' => [
@@ -425,7 +425,7 @@ public function test_from_array(array $structure, ?string $exception,
/**
* test_load_csv() data provider.
*/
- public function load_csv_provider() {
+ public static function load_csv_provider(): array {
return [
'repeated csv table many files' => [
@@ -516,7 +516,7 @@ public function test_load_csv(array $files, ?string $exception,
/**
* test_load_xml() data provider.
*/
- public function load_xml_provider() {
+ public static function load_xml_provider(): array {
return [
'repeated xml table multiple files' => [
@@ -687,7 +687,7 @@ public function test_load_xml(array $files, ?string $exception,
/**
* test_to_database() data provider.
*/
- public function to_database_provider() {
+ public static function to_database_provider(): array {
return [
'wrong table requested' => [
@@ -842,7 +842,7 @@ public function test_to_database(array $files, ?array $filter, ?string $exceptio
/**
* test_get_rows() data provider.
*/
- public function get_rows_provider() {
+ public static function get_rows_provider(): array {
return [
'wrong table requested' => [
diff --git a/lib/phpunit/tests/util_test.php b/lib/phpunit/tests/util_test.php
index 4676e4177a338..54c54462523f6 100644
--- a/lib/phpunit/tests/util_test.php
+++ b/lib/phpunit/tests/util_test.php
@@ -36,7 +36,7 @@ public function test_set_table_modified_by_sql($sql, $expectations) {
}
}
- public function set_table_modified_by_sql_provider() {
+ public static function set_table_modified_by_sql_provider(): array {
global $DB;
$prefix = $DB->get_prefix();
diff --git a/lib/table/tests/local/filter/filter_test.php b/lib/table/tests/local/filter/filter_test.php
index 1b37f312894bb..0f93aada46820 100644
--- a/lib/table/tests/local/filter/filter_test.php
+++ b/lib/table/tests/local/filter/filter_test.php
@@ -57,7 +57,7 @@ public function test_constructor(array $args, int $jointype, array $values): voi
*
* @return array
*/
- public function constructor_provider(): array {
+ public static function constructor_provider(): array {
return [
'Name without values' => [['keyword'], filter::JOINTYPE_DEFAULT, []],
'Name with valid join type ANY' => [[
@@ -147,7 +147,7 @@ public function test_constructor_invalid_joins($jointype): void {
*
* @return array
*/
- public function constructor_invalid_join_provider(): array {
+ public static function constructor_invalid_join_provider(): array {
return [
'Too low' => [-1],
'Too high' => [4],
@@ -255,7 +255,7 @@ public function test_get_name(): void {
*
* @return array
*/
- public function filter_value_provider(): array {
+ public static function filter_value_provider(): array {
return [
'Empty' => [[], 0],
'Single value' => [[10], 1],
diff --git a/lib/table/tests/local/filter/integer_filter_test.php b/lib/table/tests/local/filter/integer_filter_test.php
index caf0027155b5f..a42f873a72571 100644
--- a/lib/table/tests/local/filter/integer_filter_test.php
+++ b/lib/table/tests/local/filter/integer_filter_test.php
@@ -91,7 +91,7 @@ public function test_add_filter_value_type_invalid($value, string $type): void {
*
* @return array
*/
- public function add_filter_value_invalid_types_provider(): array {
+ public static function add_filter_value_invalid_types_provider(): array {
return [
'Null' => [null, 'NULL'],
'Empty string' => ['', 'string'],
diff --git a/lib/table/tests/local/filter/numeric_comparison_filter_test.php b/lib/table/tests/local/filter/numeric_comparison_filter_test.php
index af8ac564056fa..876bb5746eca9 100644
--- a/lib/table/tests/local/filter/numeric_comparison_filter_test.php
+++ b/lib/table/tests/local/filter/numeric_comparison_filter_test.php
@@ -117,7 +117,7 @@ public function test_add_filter_value_type_invalid($values, string $exceptiontyp
*
* @return array
*/
- public function add_filter_value_invalid_types_provider(): array {
+ public static function add_filter_value_invalid_types_provider(): array {
return [
'Null' => [
[null],
diff --git a/lib/table/tests/local/filter/string_filter_test.php b/lib/table/tests/local/filter/string_filter_test.php
index 7a092bb80e0f0..ecc3e58708491 100644
--- a/lib/table/tests/local/filter/string_filter_test.php
+++ b/lib/table/tests/local/filter/string_filter_test.php
@@ -91,7 +91,7 @@ public function test_add_filter_value_type_invalid($value, string $type): void {
*
* @return array
*/
- public function add_filter_value_invalid_types_provider(): array {
+ public static function add_filter_value_invalid_types_provider(): array {
return [
'Null' => [null, 'NULL'],
'1' => [1, 'integer'],
diff --git a/lib/tests/accesslib_has_capability_test.php b/lib/tests/accesslib_has_capability_test.php
index 8a274c6c6fd0b..22762599dd5d5 100644
--- a/lib/tests/accesslib_has_capability_test.php
+++ b/lib/tests/accesslib_has_capability_test.php
@@ -364,7 +364,7 @@ public function test_locked_contexts_for_admin_with_config($lockedcontexts, $blo
*
* @return array
*/
- public function locked_context_provider() {
+ public static function locked_context_provider(): array {
return [
'All unlocked' => [
'locked' => [
@@ -447,7 +447,7 @@ public function locked_context_provider() {
*
* @return array
*/
- public function login_as_provider(): array {
+ public static function login_as_provider(): array {
return [
[
'system',
diff --git a/lib/tests/accesslib_test.php b/lib/tests/accesslib_test.php
index b088124fbfb4c..ba63da58727a6 100644
--- a/lib/tests/accesslib_test.php
+++ b/lib/tests/accesslib_test.php
@@ -2060,7 +2060,7 @@ public function test_get_deprecated_capability_specific_cases(string $capability
*
* @return array
*/
- public function deprecated_capabilities_use_cases() {
+ public static function deprecated_capabilities_use_cases(): array {
return [
'capability missing' => [
'fake/access:missingcapability',
@@ -3034,7 +3034,7 @@ public function test_get_enrolled_sql_userswithhiddengroups() {
$this->assertEquals(1, count_enrolled_users($coursecontext, '', $groupids));
}
- public function get_enrolled_sql_provider() {
+ public static function get_enrolled_sql_provider(): array {
return array(
array(
// Two users who are enrolled.
@@ -4597,7 +4597,7 @@ public function test_get_with_capability_sql() {
*
* @return array
*/
- public function get_get_with_capability_join_override_cases() {
+ public static function get_get_with_capability_join_override_cases(): array {
return [
'no overrides' => [true, []],
'one override' => [true, ['moodle/course:viewscales']],
@@ -4799,7 +4799,7 @@ public function test_get_profile_roles() {
*
* @return array
*/
- public function is_parent_of_provider(): array {
+ public static function is_parent_of_provider(): array {
$provideboth = function(string $desc, string $contextpath, string $testpath, bool $expected): array {
return [
"includeself: true; {$desc}" => [
@@ -4902,7 +4902,7 @@ public function test_is_parent_of(string $contextpath, string $testpath, bool $t
*
* @return array
*/
- public function is_child_of_provider(): array {
+ public static function is_child_of_provider(): array {
$provideboth = function(string $desc, string $contextpath, string $testpath, bool $expected): array {
return [
"includeself: true; {$desc}" => [
diff --git a/lib/tests/adminlib_test.php b/lib/tests/adminlib_test.php
index 8be6e3e11fbdd..df1be0a4768ff 100644
--- a/lib/tests/adminlib_test.php
+++ b/lib/tests/adminlib_test.php
@@ -35,7 +35,7 @@ class adminlib_test extends \advanced_testcase {
*
* @return array
*/
- public function db_should_replace_dataprovider() {
+ public static function db_should_replace_dataprovider(): array {
return [
// Skipped tables.
['block_instances', '', false],
@@ -86,7 +86,7 @@ public function test_db_should_replace(string $table, string $column, bool $expe
* @covers ::db_should_replace
* @return array
*/
- public function db_should_replace_additional_skip_tables_dataprovider() {
+ public static function db_should_replace_additional_skip_tables_dataprovider(): array {
return [
// Skipped tables.
['block_instances', '', false],
diff --git a/lib/tests/behat/behat_navigation.php b/lib/tests/behat/behat_navigation.php
index f82d48e4468d0..915522b9d1f0b 100644
--- a/lib/tests/behat/behat_navigation.php
+++ b/lib/tests/behat/behat_navigation.php
@@ -937,10 +937,12 @@ protected function resolve_core_page_instance_url(string $type, string $identifi
]);
}
+ // This next section handles page types starting with an activity name. For example:
+ // "forum activity" or "quiz activity editing".
$parts = explode(' ', $type);
if (count($parts) > 1) {
+ $modname = $parts[0];
if ($parts[1] === 'activity') {
- $modname = $parts[0];
$cm = $this->get_cm_by_activity_name($modname, $identifier);
if (count($parts) == 2) {
@@ -962,6 +964,13 @@ protected function resolve_core_page_instance_url(string $type, string $identifi
// Permissions page.
return new moodle_url('/admin/roles/permissions.php', ['contextid' => $cm->context->id]);
}
+
+ } else if ($parts[1] === 'index' && count($parts) == 2) {
+ $courseid = $this->get_course_id($identifier);
+ if (!$courseid) {
+ throw $coursenotfoundexception;
+ }
+ return new moodle_url("/mod/$modname/index.php", ['id' => $courseid]);
}
}
diff --git a/lib/tests/behat/behat_transformations.php b/lib/tests/behat/behat_transformations.php
index bbd80ad44d308..106bdc2f7c65d 100644
--- a/lib/tests/behat/behat_transformations.php
+++ b/lib/tests/behat/behat_transformations.php
@@ -151,6 +151,18 @@ public function arg_insert_wwwroot(string $string): string {
return $this->replace_wwwroot($string);
}
+ /**
+ * Convert #dirroot# to the dirroot config value, so it is
+ * possible to reference files (e.g. fixtures) with an absolute path.
+ *
+ * @Transform /^((.*)#dirroot#(.*))$/
+ * @param string $string
+ * @return string
+ */
+ public function arg_insert_dirroot(string $string): string {
+ return $this->replace_dirroot($string);
+ }
+
/**
* Replaces $NASTYSTRING vars for a nasty string.
*
@@ -205,4 +217,15 @@ protected function replace_wwwroot(string $string): string {
global $CFG;
return str_replace('#wwwroot#', $CFG->wwwroot, $string);
}
+
+ /**
+ * Replace #dirroot# with the actual dirroot config value.
+ *
+ * @param string $string String to attempt the replacement in.
+ * @return string
+ */
+ protected function replace_dirroot(string $string): string {
+ global $CFG;
+ return str_replace('#dirroot#', $CFG->dirroot, $string);
+ }
}
diff --git a/lib/tests/behat_lib_test.php b/lib/tests/behat_lib_test.php
index fefaf4c362986..9b9f47375c702 100644
--- a/lib/tests/behat_lib_test.php
+++ b/lib/tests/behat_lib_test.php
@@ -77,7 +77,7 @@ public function test_behat_is_requested_url($url, $expectedvalue, $environment)
*
* @return array Array of values to test behat_is_requested_url() function.
*/
- public function url_provider() {
+ public static function url_provider(): array {
return [
// Tests for common ports.
['http://behat.moodle.org', true, ['behat.moodle.org', 80, '']],
diff --git a/lib/tests/client_test.php b/lib/tests/client_test.php
index 2f6a71838476a..e2249c03144e1 100644
--- a/lib/tests/client_test.php
+++ b/lib/tests/client_test.php
@@ -29,7 +29,7 @@ class client_test extends advanced_testcase {
*
* @return array
*/
- public function map_response_provider(): array {
+ public static function map_response_provider(): array {
return [
"Nested objects syntax a-b-c syntax " => [
[
diff --git a/lib/tests/completionlib_test.php b/lib/tests/completionlib_test.php
index af1405863c358..2cbcfe3c23a12 100644
--- a/lib/tests/completionlib_test.php
+++ b/lib/tests/completionlib_test.php
@@ -331,7 +331,7 @@ public function test_update_state() {
*
* @return array[]
*/
- public function internal_get_state_provider() {
+ public static function internal_get_state_provider(): array {
return [
'View required, but not viewed yet' => [
COMPLETION_VIEW_REQUIRED, 1, '', COMPLETION_INCOMPLETE
@@ -392,7 +392,7 @@ public function test_internal_get_state(int $completionview, int $completionuseg
*
* @return array
*/
- public function internal_get_state_with_grade_criteria_provider() {
+ public static function internal_get_state_with_grade_criteria_provider(): array {
return [
"Passing grade enabled and achieve. State should be COMPLETION_COMPLETE_PASS" => [
[
@@ -701,7 +701,7 @@ public function test_reset_all_state() {
*
* @return array[]
*/
- public function get_data_provider() {
+ public static function get_data_provider(): array {
return [
'No completion record' => [
false, true, false, COMPLETION_INCOMPLETE
@@ -1601,7 +1601,7 @@ public function test_completion_can_view_data() {
*
* @return array[]
*/
- public function get_grade_completion_provider() {
+ public static function get_grade_completion_provider(): array {
return [
'Grade not required' => [false, false, null, null, null],
'Grade required, but has no grade yet' => [true, false, null, null, COMPLETION_INCOMPLETE],
diff --git a/lib/tests/component_test.php b/lib/tests/component_test.php
index de219b35f4128..e224499b1362e 100644
--- a/lib/tests/component_test.php
+++ b/lib/tests/component_test.php
@@ -216,7 +216,7 @@ public function test_is_valid_plugin_name(array $arguments, bool $expected): voi
*
* @return array
*/
- public function is_valid_plugin_name_provider(): array {
+ public static function is_valid_plugin_name_provider(): array {
return [
[['mod', 'example1'], true],
[['mod', 'feedback360'], true],
@@ -684,7 +684,7 @@ public static function get_component_classes_in_namespace_provider(): array {
/**
* Data provider for classloader test
*/
- public function classloader_provider() {
+ public static function classloader_provider(): array {
global $CFG;
// As part of these tests, we Check that there are no unexpected problems with overlapping PSR namespaces.
@@ -784,7 +784,7 @@ public function test_classloader($psr0, $psr4, $classname, $includedfiles) {
/**
* Data provider for psr_classloader test
*/
- public function psr_classloader_provider() {
+ public static function psr_classloader_provider(): array {
global $CFG;
// As part of these tests, we Check that there are no unexpected problems with overlapping PSR namespaces.
@@ -981,7 +981,7 @@ public function test_psr_classloader($psr0, $psr4, $classname, $file) {
/**
* Data provider for get_class_file test
*/
- public function get_class_file_provider() {
+ public static function get_class_file_provider(): array {
global $CFG;
return [
diff --git a/lib/tests/configonlylib_test.php b/lib/tests/configonlylib_test.php
index 3532e7a3a2a88..30b6ec6bffc63 100644
--- a/lib/tests/configonlylib_test.php
+++ b/lib/tests/configonlylib_test.php
@@ -186,7 +186,7 @@ public function test_min_is_revision_valid_and_current(int $revision, bool $expe
*
* @return array
*/
- public function min_is_revision_valid_and_current_provider(): array {
+ public static function min_is_revision_valid_and_current_provider(): array {
return [
'Negative value' => [-1, false],
'Empty value' => [0, false],
diff --git a/lib/tests/core_renderer_template_exploit_test.php b/lib/tests/core_renderer_template_exploit_test.php
index 771ad6be66a94..e24d8fe5876ea 100644
--- a/lib/tests/core_renderer_template_exploit_test.php
+++ b/lib/tests/core_renderer_template_exploit_test.php
@@ -30,7 +30,7 @@ class core_renderer_template_exploit_test extends \advanced_testcase {
* text by the helper before being passed to other another helper. This prevents
* nested calls to helpers.
*/
- public function get_template_testcases() {
+ public static function get_template_testcases(): array {
// Different helper implementations to test various combinations of nested
// calls to render the templates.
$norender = function($text) {
@@ -387,7 +387,7 @@ public function get_template_testcases() {
/**
* Test that the mustache_helper_collection class correctly strips
- * @dataProvider get_template_testcases()
+ * @dataProvider get_template_testcases
* @param array $templates The template to add
* @param string $torender The name of the template to render
* @param array $context The template context
diff --git a/lib/tests/curl_security_helper_test.php b/lib/tests/curl_security_helper_test.php
index aa88abd7e995e..f76c9928953fe 100644
--- a/lib/tests/curl_security_helper_test.php
+++ b/lib/tests/curl_security_helper_test.php
@@ -62,7 +62,7 @@ function($host) use ($dns) {
*
* @return array
*/
- public function curl_security_url_data_provider() {
+ public static function curl_security_url_data_provider(): array {
$simpledns = ['localhost' => ['127.0.0.1']];
$multiplerecorddns = [
'sub.example.com' => ['1.2.3.4', '5.6.7.8']
@@ -180,7 +180,7 @@ public function test_curl_security_helper_is_enabled($blockedhosts, $allowedport
*
* @return array
*/
- public function curl_security_settings_data_provider() {
+ public static function curl_security_settings_data_provider(): array {
// Format: blocked hosts, allowed ports, expected result.
return [
["", "", false],
@@ -212,7 +212,7 @@ public function test_curl_security_helper_host_is_blocked($host, $blockedhosts,
*
* @return array
*/
- public function curl_security_host_data_provider() {
+ public static function curl_security_host_data_provider(): array {
return [
// IPv4 hosts.
["127.0.0.1", "127.0.0.1", true],
@@ -266,7 +266,7 @@ public function test_curl_security_helper_port_is_blocked($port, $allowedports,
*
* @return array
*/
- public function curl_security_port_data_provider() {
+ public static function curl_security_port_data_provider(): array {
return [
["", "80\n443", true],
[" ", "80\n443", true],
diff --git a/lib/tests/datalib_test.php b/lib/tests/datalib_test.php
index 134176da19c35..de2cc90c3eee2 100644
--- a/lib/tests/datalib_test.php
+++ b/lib/tests/datalib_test.php
@@ -906,7 +906,7 @@ public function test_get_users_listing(): void {
*
* @return array
*/
- public function get_safe_orderby_provider(): array {
+ public static function get_safe_orderby_provider(): array {
$orderbymap = [
'courseid' => 'c.id',
'somecustomvalue' => 'c.startdate, c.shortname',
@@ -994,7 +994,7 @@ public function test_get_safe_orderby(array $orderbymap, string $orderbykey, str
*
* @return array
*/
- public function get_safe_orderby_multiple_provider(): array {
+ public static function get_safe_orderby_multiple_provider(): array {
$orderbymap = [
'courseid' => 'c.id',
'firstname' => 'u.firstname',
diff --git a/lib/tests/date_test.php b/lib/tests/date_test.php
index ed825e84d4eb5..f8d8040a1154f 100644
--- a/lib/tests/date_test.php
+++ b/lib/tests/date_test.php
@@ -386,7 +386,7 @@ public function test_set_default_server_timezone() {
$this->assertSame('Etc/GMT-1', date_default_timezone_get());
}
- public function legacyUserTimezoneProvider() {
+ public static function legacyUserTimezoneProvider(): array {
return [
['', 'Australia/Perth'], // Fallback on default timezone.
['-13.0', 'Australia/Perth'], // Fallback on default timezone.
diff --git a/lib/tests/encryption_test.php b/lib/tests/encryption_test.php
index f106159bd30f5..70ed0c82fd424 100644
--- a/lib/tests/encryption_test.php
+++ b/lib/tests/encryption_test.php
@@ -56,7 +56,7 @@ protected function setUp(): void {
*
* @return array[] Array of method options for test
*/
- public function encryption_method_provider(): array {
+ public static function encryption_method_provider(): array {
return [
'Sodium' => [encryption::METHOD_SODIUM],
];
diff --git a/lib/tests/external/moodlenet_send_activity_test.php b/lib/tests/external/moodlenet_send_activity_test.php
index fdaebf8726d61..b3c72613ef6c4 100644
--- a/lib/tests/external/moodlenet_send_activity_test.php
+++ b/lib/tests/external/moodlenet_send_activity_test.php
@@ -140,7 +140,7 @@ public function test_moodlenet_send_activity_return_resource_url(bool $state, st
*
* @return array Test data.
*/
- public function return_resource_url_provider(): array {
+ public static function return_resource_url_provider(): array {
return [
'Success 1' => [
true,
diff --git a/lib/tests/external/moodlenet_send_course_test.php b/lib/tests/external/moodlenet_send_course_test.php
index 85d2c0483bb41..cd04cef332180 100644
--- a/lib/tests/external/moodlenet_send_course_test.php
+++ b/lib/tests/external/moodlenet_send_course_test.php
@@ -146,7 +146,7 @@ public function test_moodlenet_send_course_return_resource_url(bool $state, stri
*
* @return array Test data.
*/
- public function return_resource_url_provider(): array {
+ public static function return_resource_url_provider(): array {
return [
'Success 1' => [
true,
diff --git a/lib/tests/external/output/icon_system/load_fontawesome_map_test.php b/lib/tests/external/output/icon_system/load_fontawesome_map_test.php
index eb644c57c8ba7..a0916625f839d 100644
--- a/lib/tests/external/output/icon_system/load_fontawesome_map_test.php
+++ b/lib/tests/external/output/icon_system/load_fontawesome_map_test.php
@@ -77,7 +77,7 @@ public function test_execute_invalid_themename(): void {
*
* @return array
*/
- public function valid_fontawesome_theme_provider(): array {
+ public static function valid_fontawesome_theme_provider(): array {
return [
'Boost theme' => ['boost'],
'Classic theme (extends boost)' => ['classic'],
diff --git a/lib/tests/external/record_userfeedback_action_test.php b/lib/tests/external/record_userfeedback_action_test.php
index fa99bebe79d7b..758dbc7916fb1 100644
--- a/lib/tests/external/record_userfeedback_action_test.php
+++ b/lib/tests/external/record_userfeedback_action_test.php
@@ -48,7 +48,7 @@ class record_userfeedback_action_test extends externallib_advanced_testcase {
*
* @return array
*/
- public function record_userfeedback_action_provider() {
+ public static function record_userfeedback_action_provider(): array {
return [
'give action' => ['give'],
'remind action' => ['remind'],
diff --git a/lib/tests/filestorage_zip_archive_test.php b/lib/tests/filestorage_zip_archive_test.php
index 06eb9db2fed3d..681127ce36c3b 100644
--- a/lib/tests/filestorage_zip_archive_test.php
+++ b/lib/tests/filestorage_zip_archive_test.php
@@ -55,7 +55,7 @@ public function test_mangle_pathname($string, $expected) {
*
* @return array Array of tested pathnames and expected results.
*/
- public function pathname_provider() {
+ public static function pathname_provider(): array {
return [
// Test a string.
['my file.pdf', 'my file.pdf'],
diff --git a/lib/tests/gradelib_test.php b/lib/tests/gradelib_test.php
index b35cf5f94a663..f1964d7e9ff0f 100644
--- a/lib/tests/gradelib_test.php
+++ b/lib/tests/gradelib_test.php
@@ -188,7 +188,7 @@ public function test_grade_get_date_for_user_grade(\stdClass $grade, \stdClass $
*
* @return array
*/
- public function grade_get_date_for_user_grade_provider(): array {
+ public static function grade_get_date_for_user_grade_provider(): array {
$u1 = (object) [
'id' => 42,
];
diff --git a/lib/tests/graphlib_test.php b/lib/tests/graphlib_test.php
index f2afe31acb7ea..122bc29601219 100644
--- a/lib/tests/graphlib_test.php
+++ b/lib/tests/graphlib_test.php
@@ -36,7 +36,7 @@ class graphlib_test extends \basic_testcase {
*
* @return array
*/
- public function create_data(): array {
+ public static function create_data(): array {
return [
'data' =>
[
diff --git a/lib/tests/htmlpurifier_test.php b/lib/tests/htmlpurifier_test.php
index c047044f03124..6d5ddd6f03486 100644
--- a/lib/tests/htmlpurifier_test.php
+++ b/lib/tests/htmlpurifier_test.php
@@ -353,7 +353,7 @@ public function test_media_tags($mediatag, $expected) {
/**
* Test cases for the test_media_tags test.
*/
- public function media_tags_provider() {
+ public static function media_tags_provider(): array {
// Takes an array of attributes, then generates a test for each of them.
$generatetestcases = function($prefix, array $attrs, array $templates) {
return array_reduce($attrs, function($carry, $attr) use ($prefix, $templates) {
diff --git a/lib/tests/ip_utils_test.php b/lib/tests/ip_utils_test.php
index f189857607d4d..c177c22bc62e4 100644
--- a/lib/tests/ip_utils_test.php
+++ b/lib/tests/ip_utils_test.php
@@ -41,7 +41,7 @@ public function test_is_domain_name($domainname, $expected) {
*
* @return array
*/
- public function domain_name_data_provider() {
+ public static function domain_name_data_provider(): array {
return [
["com", true],
["i.net", true], // Single char, alpha tertiary domain.
@@ -91,7 +91,7 @@ public function test_is_domain_matching_pattern($str, $expected) {
*
* @return array
*/
- public function domain_matching_patterns_data_provider() {
+ public static function domain_matching_patterns_data_provider(): array {
return [
["*.com", true],
["*.example.com", true],
@@ -136,7 +136,7 @@ public function test_is_ip_address($address, $expected) {
*
* @return array
*/
- public function ip_address_data_provider() {
+ public static function ip_address_data_provider(): array {
return [
["127.0.0.1", true],
["10.1", false],
@@ -183,7 +183,7 @@ public function test_is_ipv4_address($address, $expected) {
*
* @return array
*/
- public function ipv4_address_data_provider() {
+ public static function ipv4_address_data_provider(): array {
return [
["127.0.0.1", true],
["0.0.0.0", true],
@@ -219,7 +219,7 @@ public function test_is_ipv4_range($addressrange, $expected) {
*
* @return array
*/
- public function ipv4_range_data_provider() {
+ public static function ipv4_range_data_provider(): array {
return [
["127.0.0.1/24", true],
["127.0.0.20-20", true],
@@ -260,7 +260,7 @@ public function test_is_ipv6_address($address, $expected) {
*
* @return array
*/
- public function ipv6_address_data_provider() {
+ public static function ipv6_address_data_provider(): array {
return [
["::", true],
["::0", true],
@@ -300,7 +300,7 @@ public function test_is_ipv6_range($addressrange, $expected) {
*
* @return array
*/
- public function ipv6_range_data_provider() {
+ public static function ipv6_range_data_provider(): array {
return [
["::/128", true],
["::1/128", true],
@@ -352,7 +352,7 @@ public function test_check_domain_against_allowed_domains($expected, $domain) {
*
* @return array
*/
- public function data_domain_addresses() {
+ public static function data_domain_addresses(): array {
return [
[true, 'example.com'],
[true, 'ExAmPle.com'],
@@ -378,7 +378,7 @@ public function data_domain_addresses() {
*
* @return array
*/
- public function data_is_ip_in_subnet_list() {
+ public static function data_is_ip_in_subnet_list(): array {
return [
[true, '1.1.1.1', '1.1.1.1', "\n"],
[false, '1.1.1.1', '2.2.2.2', "\n"],
diff --git a/lib/tests/ldaplib_test.php b/lib/tests/ldaplib_test.php
index c0e33b1bd3f45..5da201b74bb0a 100644
--- a/lib/tests/ldaplib_test.php
+++ b/lib/tests/ldaplib_test.php
@@ -184,7 +184,7 @@ public function test_ldap_normalise_objectclass($args, $expected) {
*
* @return array of testcases.
*/
- public function ldap_normalise_objectclass_provider() {
+ public static function ldap_normalise_objectclass_provider(): array {
return array(
'Empty value' => array(
array(null),
diff --git a/lib/tests/modinfolib_test.php b/lib/tests/modinfolib_test.php
index a7516a26634dd..24410eca1ec75 100644
--- a/lib/tests/modinfolib_test.php
+++ b/lib/tests/modinfolib_test.php
@@ -1082,7 +1082,7 @@ public function test_get_section_info_by_id(
*
* @return array
*/
- public function get_section_info_by_id_provider() {
+ public static function get_section_info_by_id_provider(): array {
return [
'Valid section id' => [
'sectionnum' => 1,
diff --git a/lib/tests/moodle_page_test.php b/lib/tests/moodle_page_test.php
index 94b4a88ae067e..87e007f47fca5 100644
--- a/lib/tests/moodle_page_test.php
+++ b/lib/tests/moodle_page_test.php
@@ -330,7 +330,7 @@ public function test_set_heading() {
*
* @return array
*/
- public function set_title_provider(): array {
+ public static function set_title_provider(): array {
return [
'Do not append the site name' => [
'shortname', false, '', false
@@ -780,7 +780,7 @@ public function test_cohort_get_user_theme($usertheme, $sitetheme, $cohortthemes
*
* @return array
*/
- public function get_user_theme_provider() {
+ public static function get_user_theme_provider(): array {
return [
'User not a member of any cohort' => [
'usertheme' => '',
diff --git a/lib/tests/moodle_url_test.php b/lib/tests/moodle_url_test.php
index b575dfd4d3563..ac9ee8c4ee2d6 100644
--- a/lib/tests/moodle_url_test.php
+++ b/lib/tests/moodle_url_test.php
@@ -341,7 +341,7 @@ public function test_make_pluginfile_url($slashargs, $args, $expected) {
*
* @return array[]
*/
- public function make_pluginfile_url_provider() {
+ public static function make_pluginfile_url_provider(): array {
$baseurl = "https://www.example.com/moodle/pluginfile.php";
$tokenbaseurl = "https://www.example.com/moodle/tokenpluginfile.php";
return [
diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php
index ccfa0d7ff2512..58c3c0df31839 100644
--- a/lib/tests/moodlelib_test.php
+++ b/lib/tests/moodlelib_test.php
@@ -1134,7 +1134,7 @@ public function test_shorten_text_multilang() {
*
* @return array of ($filename, $length, $expected, $includehash)
*/
- public function shorten_filename_provider() {
+ public static function shorten_filename_provider(): array {
$filename = 'sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium totam rem';
$shortfilename = 'sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque';
@@ -1237,7 +1237,7 @@ public function test_shorten_filename($filename, $length, $expected, $includehas
*
* @return array of ($filename, $length, $expected, $includehash)
*/
- public function shorten_filenames_provider() {
+ public static function shorten_filenames_provider(): array {
$shortfilename = 'sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque';
$longfilename = 'sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium totam rem';
$extfilename = $longfilename.'.zip';
@@ -3245,7 +3245,7 @@ public function test_require_logout() {
/**
* A data provider for testing email messageid
*/
- public function generate_email_messageid_provider() {
+ public static function generate_email_messageid_provider(): array {
return array(
'nopath' => array(
'wwwroot' => 'http://www.example.com',
@@ -3312,7 +3312,7 @@ public function test_send_email_with_custom_header() {
/**
* A data provider for testing email diversion
*/
- public function diverted_emails_provider() {
+ public static function diverted_emails_provider(): array {
return array(
'nodiverts' => array(
'divertallemailsto' => null,
@@ -3519,7 +3519,7 @@ public function test_email_to_user() {
*
* @return array
*/
- public function email_to_user_attachment_provider(): array {
+ public static function email_to_user_attachment_provider(): array {
global $CFG;
// Return all paths that can be used to send attachments from.
@@ -3892,7 +3892,7 @@ public function test_count_words(int $expectedcount, string $string, $format = n
*
* @return array of test cases.
*/
- public function count_words_testcases(): array {
+ public static function count_words_testcases(): array {
// Copy-pasting example from MDL-64240.
$copypasted = <<Snoot is booped
@@ -3967,7 +3967,7 @@ public function test_count_letters(int $expectedcount, string $string, $format =
*
* @return array of test cases.
*/
- public function count_letters_testcases(): array {
+ public static function count_letters_testcases(): array {
return [
[0, ''],
[1, 'x'],
@@ -4132,7 +4132,7 @@ public function test_complex_random_string() {
/**
* Data provider for private ips.
*/
- public function data_private_ips() {
+ public static function data_private_ips(): array {
return array(
array('10.0.0.0'),
array('172.16.0.0'),
@@ -4157,7 +4157,7 @@ public function test_ip_is_public_private_ips($ip) {
/**
* Data provider for public ips.
*/
- public function data_public_ips() {
+ public static function data_public_ips(): array {
return array(
array('2400:cb00:2048:1::8d65:71b3'),
array('2400:6180:0:d0::1b:2001'),
@@ -4210,7 +4210,7 @@ public function test_can_send_from_real_email_address($email, $display, $samecou
*
* @return array Returns an array of test data for the above function.
*/
- public function data_can_send_from_real_email_address() {
+ public static function data_can_send_from_real_email_address(): array {
return [
// Test from email is in allowed domain.
// Test that from display is set to show no one.
@@ -4356,7 +4356,7 @@ public function test_email_is_not_allowed_for_allowemailaddresses($email, $confi
*
* @return array Returns an array of test data for the above function.
*/
- public function data_email_is_not_allowed_for_allowemailaddresses() {
+ public static function data_email_is_not_allowed_for_allowemailaddresses(): array {
return [
// Test allowed domain empty list.
[
@@ -4435,7 +4435,7 @@ public function test_email_is_not_allowed_for_denyemailaddresses($email, $config
*
* @return array Returns an array of test data for the above function.
*/
- public function data_email_is_not_allowed_for_denyemailaddresses() {
+ public static function data_email_is_not_allowed_for_denyemailaddresses(): array {
return [
// Test denied domain empty list.
[
@@ -4613,7 +4613,7 @@ public function test_component_class_callback_found_accepts_multiple($params, $c
*
* @return array
*/
- public function component_class_callback_default_provider() {
+ public static function component_class_callback_default_provider(): array {
return [
'null' => [null],
'empty string' => [''],
@@ -4629,7 +4629,7 @@ public function component_class_callback_default_provider() {
*
* @return array
*/
- public function component_class_callback_data_provider() {
+ public static function component_class_callback_data_provider(): array {
return [
'empty string' => [''],
'string' => ['This is a string'],
@@ -4644,7 +4644,7 @@ public function component_class_callback_data_provider() {
*
* @return array
*/
- public function component_class_callback_multiple_params_provider() {
+ public static function component_class_callback_multiple_params_provider(): array {
return [
'empty array' => [
[],
@@ -4689,7 +4689,7 @@ public function test_get_callable_name($callable, $expectedname) {
*
* @return array of (string)case => [(mixed)callable, (string|bool)expected description]
*/
- public function callable_names_provider() {
+ public static function callable_names_provider(): array {
return [
'integer' => [
386,
@@ -4707,10 +4707,6 @@ public function callable_names_provider() {
['my_foobar_class', 'my_foobar_method'],
'my_foobar_class::my_foobar_method',
],
- 'static_method_of_object' => [
- [$this, 'my_foobar_method'],
- 'core\moodlelib_test::my_foobar_method',
- ],
'method_of_object' => [
[new lang_string('parentlanguage', 'core_langconfig'), 'my_foobar_method'],
'lang_string::my_foobar_method',
@@ -4726,12 +4722,19 @@ function($a) { return $a; },
];
}
+ /**
+ * Test that get_callable_name works with a static method on an instance.
+ */
+ public function test_get_callable_name_this(): void {
+ $this->assertSame('core\moodlelib_test::foo', get_callable_name([$this, 'foo']));
+ }
+
/**
* Data provider for \core_moodlelib_testcase::test_get_complete_user_data().
*
* @return array
*/
- public function user_data_provider() {
+ public static function user_data_provider(): array {
return [
'Fetch data using a valid username' => [
'username', 's1', true
@@ -4866,7 +4869,7 @@ public function test_get_time_interval_string(int $time1, int $time2, ?string $f
/**
* Data provider for the test_get_time_interval_string() method.
*/
- public function get_time_interval_string_provider() {
+ public static function get_time_interval_string_provider(): array {
return [
'Time is after the reference time by 1 minute, omitted format' => [
'time1' => 12345660,
@@ -5024,7 +5027,7 @@ public function test_rename_to_unused_name_failure() {
*
* @return array of ($size, $expected)
*/
- public function display_size_provider() {
+ public static function display_size_provider(): array {
return [
[0, '0 bytes'],
@@ -5066,7 +5069,7 @@ public function test_display_size($size, $expected) {
*
* @return array of ($size, $units, $expected)
*/
- public function display_size_fixed_provider(): array {
+ public static function display_size_fixed_provider(): array {
return [
[0, 'KB', '0.0 KB'],
[1, 'MB', '0.0 MB'],
@@ -5096,7 +5099,7 @@ public function test_display_size_fixed(int $size, string $units, string $expect
*
* @return array of ($size, $decimalplaces, $units, $expected)
*/
- public function display_size_dp_provider(): array {
+ public static function display_size_dp_provider(): array {
return [
[0, 1, 'KB', '0.0 KB'],
[1, 6, 'MB', '0.000001 MB'],
@@ -5142,7 +5145,7 @@ public function test_get_list_of_plugins(array $expectedlist, array $content, st
*
* @return array
*/
- public function get_list_of_plugins_provider(): array {
+ public static function get_list_of_plugins_provider(): array {
return [
'Standard excludes' => [
['amdd', 'class', 'local', 'test'],
@@ -5442,7 +5445,7 @@ public function test_html_is_blank() {
*
* @return array of test cases.
*/
- public function is_proxybypass_provider(): array {
+ public static function is_proxybypass_provider(): array {
return [
'Proxybypass contains the same IP as the beginning of the URL' => [
diff --git a/lib/tests/moodlenet/activity_sender_test.php b/lib/tests/moodlenet/activity_sender_test.php
index 3c106b9f569b8..a79f0b33a2035 100644
--- a/lib/tests/moodlenet/activity_sender_test.php
+++ b/lib/tests/moodlenet/activity_sender_test.php
@@ -257,7 +257,7 @@ public function test_share_resource(ResponseInterface $httpresponse, array $expe
*
* @return array Test data.
*/
- public function share_resource_provider(): array {
+ public static function share_resource_provider(): array {
return [
'Success' => [
'http_response' => new Response(
diff --git a/lib/tests/moodlenet/course_partial_sender_test.php b/lib/tests/moodlenet/course_partial_sender_test.php
index 0fc86fc84e6bc..5f6e0cfd89ee5 100644
--- a/lib/tests/moodlenet/course_partial_sender_test.php
+++ b/lib/tests/moodlenet/course_partial_sender_test.php
@@ -257,7 +257,7 @@ public function test_share_resource(ResponseInterface $httpresponse, array $expe
*
* @return array Test data.
*/
- public function share_resource_provider(): array {
+ public static function share_resource_provider(): array {
return [
'Success' => [
'http_response' => new Response(
diff --git a/lib/tests/moodlenet/course_sender_test.php b/lib/tests/moodlenet/course_sender_test.php
index 3827e5fdeaea6..41049d7ec6321 100644
--- a/lib/tests/moodlenet/course_sender_test.php
+++ b/lib/tests/moodlenet/course_sender_test.php
@@ -261,7 +261,7 @@ public function test_share_resource(ResponseInterface $httpresponse, array $expe
*
* @return array Test data.
*/
- public function share_resource_provider(): array {
+ public static function share_resource_provider(): array {
return [
'Success' => [
'http_response' => new Response(
diff --git a/lib/tests/myprofilelib_test.php b/lib/tests/myprofilelib_test.php
index 431e4dfa3badf..140e98462a88b 100644
--- a/lib/tests/myprofilelib_test.php
+++ b/lib/tests/myprofilelib_test.php
@@ -233,7 +233,7 @@ public function test_core_myprofile_navigation_contact_field_without_permission(
*
* @return array[]
*/
- public function core_myprofile_navigation_contact_timezone_provider(): array {
+ public static function core_myprofile_navigation_contact_timezone_provider(): array {
return [
'Hidden field' => ['timezone', '99', '99', null],
'Forced timezone' => ['', 'Europe/London', 'Pacific/Tahiti', 'Europe/London'],
diff --git a/lib/tests/navigation/output/primary_test.php b/lib/tests/navigation/output/primary_test.php
index 649ff0cefe92d..9d856ed52d0fe 100644
--- a/lib/tests/navigation/output/primary_test.php
+++ b/lib/tests/navigation/output/primary_test.php
@@ -113,7 +113,7 @@ public function test_primary_export(bool $withcustom, bool $withlang, string $us
*
* @return array
*/
- public function primary_export_provider(): array {
+ public static function primary_export_provider(): array {
return [
"Export the menu data when: custom menu exists; multiple langs installed; user is not logged in." => [
true, true, '', ['mobileprimarynav', 'moremenu', 'lang', 'user']
@@ -190,7 +190,7 @@ protected function get_custom_menu(string $config): array {
*
* @return array
*/
- public function custom_menu_provider(): array {
+ public static function custom_menu_provider(): array {
return [
'Simple custom menu' => [
"Course search|/course/search.php
diff --git a/lib/tests/navigation/views/primary_test.php b/lib/tests/navigation/views/primary_test.php
index 2551a9031b6cc..b28cee7a78fec 100644
--- a/lib/tests/navigation/views/primary_test.php
+++ b/lib/tests/navigation/views/primary_test.php
@@ -59,7 +59,7 @@ public function test_setting_initialise($usertype, $expected) {
/**
* Data provider for the test_setting_initialise function
*/
- public function setting_initialise_provider() {
+ public static function setting_initialise_provider(): array {
return [
'Testing as a guest user' => ['guest', ['home']],
'Testing as an admin' => ['admin', ['home', 'myhome', 'mycourses', 'siteadminnode']],
@@ -153,7 +153,7 @@ public function test_search_and_set_active_node(string $expectedkey, ?string $ke
*
* @return array
*/
- public function search_and_set_active_node_provider(): array {
+ public static function search_and_set_active_node_provider(): array {
return [
'Test by activating node which is part of the tree'
=> ['tenthchild', 'tenthchild'],
diff --git a/lib/tests/navigation/views/secondary_test.php b/lib/tests/navigation/views/secondary_test.php
index e25e995d2f2af..55f98d2d32ce5 100644
--- a/lib/tests/navigation/views/secondary_test.php
+++ b/lib/tests/navigation/views/secondary_test.php
@@ -74,7 +74,7 @@ public function test_get_leaf_nodes(float $siteorder, float $courseorder, float
* Data provider for test_get_leaf_nodes
* @return array
*/
- public function leaf_nodes_order_provider(): array {
+ public static function leaf_nodes_order_provider(): array {
return [
'Initialise the order with whole numbers' => [3, 2, 1],
'Initialise the order with a mix of whole and float numbers' => [2.1, 2, 1],
@@ -140,7 +140,7 @@ public function test_setting_initialise(string $context, string $expectedfirstno
* Data provider for the test_setting_initialise function
* @return array
*/
- public function setting_initialise_provider(): array {
+ public static function setting_initialise_provider(): array {
return [
'Testing in a course context' => ['course', 'coursehome', 'courseheader', 'Course'],
'Testing in a course context using a single activity course format' =>
@@ -233,7 +233,7 @@ public function test_active_node_scan(string $expectedkey, ?string $key = null,
*
* @return array
*/
- public function active_node_scan_provider(): array {
+ public static function active_node_scan_provider(): array {
return [
'Test by activating node adjacent to root node'
=> ['firstchild', 'firstchild'],
@@ -292,7 +292,7 @@ public function test_force_nodes_into_more_menu(array $secondarynavnodesdata, ar
*
* @return array
*/
- public function force_nodes_into_more_menu_provider(): array {
+ public static function force_nodes_into_more_menu_provider(): array {
return [
'The total number of navigation nodes exceeds the max display limit (5); ' .
'navnode2 and navnode4 are forced into "more" menu by default.' =>
@@ -476,7 +476,7 @@ public function test_nodes_match_current_url(string $selectedurl, string $expect
*
* @return \string[][]
*/
- public function nodes_match_current_url_provider(): array {
+ public static function nodes_match_current_url_provider(): array {
return [
"Match url to a node that is a deep nested" => [
'/view/course.php',
@@ -534,7 +534,7 @@ public function test_get_menu_array(string $selected, array $expected) {
*
* @return array[]
*/
- public function get_menu_array_provider(): array {
+ public static function get_menu_array_provider(): array {
return [
"Fetch information from a node with action and no children" => [
'child1',
@@ -640,7 +640,7 @@ public function test_get_node_with_first_action(string $selectedkey, ?string $ex
*
* @return array
*/
- public function get_node_with_first_action_provider(): array {
+ public static function get_node_with_first_action_provider(): array {
return [
"Search for action when parent has no action and multiple children with actions" => [
"child3",
@@ -700,7 +700,7 @@ public function test_add_external_nodes_to_secondary(array $structure, array $ex
*
* @return array
*/
- public function add_external_nodes_to_secondary_provider() {
+ public static function add_external_nodes_to_secondary_provider(): array {
return [
"Container node with internal action and external children" => [
[
@@ -870,7 +870,7 @@ public function test_get_overflow_menu_data(string $selectedurl, bool $expectedn
*
* @return string[]
*/
- public function get_overflow_menu_data_provider(): array {
+ public static function get_overflow_menu_data_provider(): array {
return [
"Active node is the course home node" => [
'/coursehome.php',
@@ -936,7 +936,7 @@ public function test_get_overflow_menu_data_course_admin(string $url, string $co
*
* @return array Provider information.
*/
- public function get_overflow_menu_data_course_admin_provider(): array {
+ public static function get_overflow_menu_data_course_admin_provider(): array {
return [
"Backup page returns overflow" => [
'/backup/backup.php',
diff --git a/lib/tests/navigationlib_test.php b/lib/tests/navigationlib_test.php
index ed875a7a8e1dd..e9b6e8dce31ce 100644
--- a/lib/tests/navigationlib_test.php
+++ b/lib/tests/navigationlib_test.php
@@ -588,7 +588,7 @@ public function test_set_force_into_more_menu(bool $haschildren, bool $forceinto
*
* @return array
*/
- public function set_force_into_more_menu_provider(): array {
+ public static function set_force_into_more_menu_provider(): array {
return [
'Navigation node without any children nodes; Force into "more" menu => true.' =>
[
@@ -625,7 +625,7 @@ public function test_is_action_link(navigation_node $node, bool $expected) {
*
* @return array
*/
- public function is_action_link_provider(): array {
+ public static function is_action_link_provider(): array {
return [
'The navigation node has an action link.' =>
[
@@ -678,7 +678,7 @@ public function test_action_link_actions(navigation_node $node) {
*
* @return array
*/
- public function action_link_actions_provider(): array {
+ public static function action_link_actions_provider(): array {
return [
'The navigation node has an action link with an action attached.' =>
[
diff --git a/lib/tests/oauth2/discovery/auth_server_config_reader_test.php b/lib/tests/oauth2/discovery/auth_server_config_reader_test.php
index fb5671b8870d5..580a91ce87386 100644
--- a/lib/tests/oauth2/discovery/auth_server_config_reader_test.php
+++ b/lib/tests/oauth2/discovery/auth_server_config_reader_test.php
@@ -83,7 +83,7 @@ public function test_read_configuration(string $issuerurl, ResponseInterface $ht
*
* @return array test data.
*/
- public function config_provider(): array {
+ public static function config_provider(): array {
return [
'Valid, good issuer URL, good config' => [
'issuer_url' => 'https://app.example.com',
diff --git a/lib/tests/oauth2_test.php b/lib/tests/oauth2_test.php
index b54766439ff67..873ceda852616 100644
--- a/lib/tests/oauth2_test.php
+++ b/lib/tests/oauth2_test.php
@@ -119,7 +119,7 @@ public function test_getters() {
*
* @return array
*/
- public function system_oauth_client_provider() {
+ public static function system_oauth_client_provider(): array {
return [
[
(object) [
@@ -306,7 +306,7 @@ public function test_create_endpoints_for_standard_issuer(string $type, ?string
*
* @return array
*/
- public function create_endpoints_for_standard_issuer_provider(): array {
+ public static function create_endpoints_for_standard_issuer_provider(): array {
return [
'Google' => [
'type' => 'google',
@@ -449,7 +449,7 @@ public function test_is_available_for_login() {
*
* @return array
*/
- public function create_custom_profile_fields(): array {
+ public static function create_custom_profile_fields(): array {
return [
'data' =>
[
diff --git a/lib/tests/output/activity_header_test.php b/lib/tests/output/activity_header_test.php
index aa9717c217645..588dca4c2e08a 100644
--- a/lib/tests/output/activity_header_test.php
+++ b/lib/tests/output/activity_header_test.php
@@ -60,7 +60,7 @@ public function test_set_title(string $value, string $expected): void {
* Provider for the test_set_title unit test.
* @return array
*/
- public function set_title_provider(): array {
+ public static function set_title_provider(): array {
return [
"Set the title with a plain text" => [
"Activity title", "Activity title"
@@ -129,7 +129,7 @@ public function test_set_attrs_invalid_variable(): void {
*
* @return array[]
*/
- public function get_heading_level_provider(): array {
+ public static function get_heading_level_provider(): array {
return [
'Title not allowed' => [false, '', 2],
'Title allowed, no title' => [true, '', 2],
diff --git a/lib/tests/output/icon_system_test.php b/lib/tests/output/icon_system_test.php
index 6d83c67e7252e..45056b9ba2d07 100644
--- a/lib/tests/output/icon_system_test.php
+++ b/lib/tests/output/icon_system_test.php
@@ -160,7 +160,7 @@ public function test_instance_singleton_reset(): void {
*
* @return array
*/
- public function icon_system_provider(): array {
+ public static function icon_system_provider(): array {
return [
'icon_system => icon_system_standard' => [
icon_system::class,
@@ -211,8 +211,8 @@ public function icon_system_provider(): array {
*
* @return array
*/
- public function is_valid_subsystem_provider(): array {
- return $this->icon_system_provider();
+ public static function is_valid_subsystem_provider(): array {
+ return self::icon_system_provider();
}
/**
@@ -220,9 +220,9 @@ public function is_valid_subsystem_provider(): array {
*
* @return array
*/
- public function invalid_instance_provider(): array {
+ public static function invalid_instance_provider(): array {
return array_filter(
- $this->icon_system_provider(),
+ self::icon_system_provider(),
function($data) {
return !$data[2];
},
@@ -235,9 +235,9 @@ function($data) {
*
* @return array
*/
- public function valid_instance_provider(): array {
+ public static function valid_instance_provider(): array {
return array_filter(
- $this->icon_system_provider(),
+ self::icon_system_provider(),
function($data) {
return $data[2];
},
diff --git a/lib/tests/output/language_menu_test.php b/lib/tests/output/language_menu_test.php
index 7587227f8f307..d8b3e10c5bfd3 100644
--- a/lib/tests/output/language_menu_test.php
+++ b/lib/tests/output/language_menu_test.php
@@ -101,7 +101,7 @@ public function test_get_lang_menu(bool $withadditionallangs, string $language,
*
* @return array
*/
- public function get_lang_menu_provider(): array {
+ public static function get_lang_menu_provider(): array {
return [
'Lang menu with only the current language' => [
false, 'en', []
diff --git a/lib/tests/output/mustache_helper_collection_test.php b/lib/tests/output/mustache_helper_collection_test.php
index 43b6b89fb4bfb..d89aac9a44279 100644
--- a/lib/tests/output/mustache_helper_collection_test.php
+++ b/lib/tests/output/mustache_helper_collection_test.php
@@ -31,7 +31,7 @@ class mustache_helper_collection_test extends \advanced_testcase {
* text by the helper before being passed to other another helper. This prevents
* nested calls to helpers.
*/
- public function get_strip_disallowed_helpers_testcases() {
+ public static function get_strip_disallowed_helpers_testcases(): array {
return [
'no disallowed' => [
'disallowed' => [],
@@ -123,7 +123,7 @@ public function get_strip_disallowed_helpers_testcases() {
/**
* Test that the mustache_helper_collection class correctly strips
- * @dataProvider get_strip_disallowed_helpers_testcases()
+ * @dataProvider get_strip_disallowed_helpers_testcases
* @param string[] $disallowed The list of helpers to strip
* @param string $input The input string for the helper
* @param string $expected The expected output of the string after disallowed strip
diff --git a/lib/tests/output/mustache_template_finder_test.php b/lib/tests/output/mustache_template_finder_test.php
index ce270719439f8..c9492a3c9b7ea 100644
--- a/lib/tests/output/mustache_template_finder_test.php
+++ b/lib/tests/output/mustache_template_finder_test.php
@@ -35,7 +35,7 @@ class mustache_template_finder_test extends \advanced_testcase {
*
* @return array
*/
- public function valid_template_directories_provider(): array {
+ public static function valid_template_directories_provider(): array {
return [
'plugin: mod_assign' => [
'component' => 'mod_assign',
@@ -111,7 +111,7 @@ public function test_invalid_component_get_template_directories_for_component()
*
* @return array
*/
- public function valid_template_filepath_provider(): array {
+ public static function valid_template_filepath_provider(): array {
return [
'Standard core template' => [
'template' => 'core/modal',
diff --git a/lib/tests/output/mustache_template_source_loader_test.php b/lib/tests/output/mustache_template_source_loader_test.php
index a3fabdd007de1..5e753b4f6cfeb 100644
--- a/lib/tests/output/mustache_template_source_loader_test.php
+++ b/lib/tests/output/mustache_template_source_loader_test.php
@@ -134,13 +134,13 @@ public function test_strip_template_comments() {
/**
* Data provider for the test_load function.
*/
- public function load_test_cases() {
+ public static function load_test_cases(): array {
$cache = [
'core' => [
'test' => '{{! a comment }}The rest of the template'
]
];
- $loader = $this->build_loader_from_static_cache($cache);
+ $loader = self::build_loader_from_static_cache($cache);
return [
'with comments' => [
@@ -177,7 +177,7 @@ public function test_load($loader, $component, $name, $includecomments, $expecte
/**
* Data provider for the load_with_dependencies function.
*/
- public function load_with_dependencies_test_cases() {
+ public static function load_with_dependencies_test_cases(): array {
// Create a bunch of templates that include one another in various ways. There is
// multiple instances of recursive inclusions to test that the code doensn't get
// stuck in an infinite loop.
@@ -205,7 +205,7 @@ public function load_with_dependencies_test_cases() {
'bim' => $bim
]
];
- $loader = $this->build_loader_from_static_cache($cache);
+ $loader = self::build_loader_from_static_cache($cache);
return [
'no template includes w comments' => [
@@ -344,7 +344,7 @@ public function test_load_with_dependencies($loader, $component, $name, $include
/**
* Data provider for the test_load function.
*/
- public function scan_template_source_for_dependencies_test_cases() {
+ public static function scan_template_source_for_dependencies_test_cases(): array {
$foo = '{{! a comment }}{{> core/bar }}{{< test/bop }}{{/ test/bop}}{{#str}} help, core {{/str}}';
$bar = '{{! a comment }}{{> core/baz }}';
$baz = '{{! a comment }}{{#str}} hide, core {{/str}}';
@@ -388,7 +388,7 @@ public function scan_template_source_for_dependencies_test_cases() {
'multiline5' => $multiline5,
]
];
- $loader = $this->build_loader_from_static_cache($cache);
+ $loader = self::build_loader_from_static_cache($cache);
return [
'single template include' => [
@@ -488,7 +488,7 @@ public function scan_template_source_for_dependencies_test_cases() {
/**
* Test the scan_template_source_for_dependencies function.
*
- * @dataProvider scan_template_source_for_dependencies_test_cases()
+ * @dataProvider scan_template_source_for_dependencies_test_cases
* @param mustache_template_source_loader $loader The loader
* @param string $source The template to test
* @param string $expected The expected output
@@ -510,7 +510,7 @@ public function test_scan_template_source_for_dependencies($loader, $source, $ex
* @param array $cache A cache of templates
* @return mustache_template_source_loader
*/
- private function build_loader_from_static_cache(array $cache) : mustache_template_source_loader {
+ private static function build_loader_from_static_cache(array $cache): mustache_template_source_loader {
return new mustache_template_source_loader(function($component, $name, $themename) use ($cache) {
return $cache[$component][$name];
});
diff --git a/lib/tests/output/participants_action_bar_test.php b/lib/tests/output/participants_action_bar_test.php
index 6a1468ec55623..fb3e1c5a09b21 100644
--- a/lib/tests/output/participants_action_bar_test.php
+++ b/lib/tests/output/participants_action_bar_test.php
@@ -69,7 +69,7 @@ public function test_get_content_for_select($type, $expectedcount, $expecteditem
* Provider for test_get_content_for_select
* @return array[]
*/
- public function get_content_for_select_provider() {
+ public static function get_content_for_select_provider(): array {
return [
'Get dropdown content when in a course context' => [
'course', 3, ['Enrolments', 'Groups', 'Permissions']
diff --git a/lib/tests/outputcomponents_test.php b/lib/tests/outputcomponents_test.php
index afd655bd8056c..16a7e3a058a02 100644
--- a/lib/tests/outputcomponents_test.php
+++ b/lib/tests/outputcomponents_test.php
@@ -755,7 +755,7 @@ public function test_url_select() {
*
* @return array
*/
- public function block_contents_is_fake_provider() {
+ public static function block_contents_is_fake_provider(): array {
return [
'Null' => [null, false],
'Not set' => [false, false],
diff --git a/lib/tests/outputrequirementslib_test.php b/lib/tests/outputrequirementslib_test.php
index e4bdccf17df46..6c770be8a8a2a 100644
--- a/lib/tests/outputrequirementslib_test.php
+++ b/lib/tests/outputrequirementslib_test.php
@@ -170,7 +170,7 @@ public function test_js_fix_url_moodle_url(\moodle_url $moodleurl, int $cfgslash
* @see \page_requirements_manager::js_fix_url()
* @see \moodle_url
*/
- public function js_fix_url_moodle_url_provider() {
+ public static function js_fix_url_moodle_url_provider(): array {
global $CFG;
$wwwroot = rtrim($CFG->wwwroot, '/');
$libdir = rtrim($CFG->libdir, '/');
@@ -253,7 +253,7 @@ public function test_js_fix_url_plain_string(string $url, int $cfgslashargs, str
* @return array
* @see \page_requirements_manager::js_fix_url()
*/
- public function js_fix_url_plain_string_provider() {
+ public static function js_fix_url_plain_string_provider(): array {
global $CFG;
$wwwroot = rtrim($CFG->wwwroot, '/');
$admin = "/{$CFG->admin}/"; // Deprecated, just for coverage purposes.
@@ -339,7 +339,7 @@ public function test_js_fix_url_coding_exception($url, string $exmessage) {
* @return array
* @see \page_requirements_manager::js_fix_url()
*/
- public function js_fix_url_coding_exception_provider() {
+ public static function js_fix_url_coding_exception_provider(): array {
global $CFG;
$wwwroot = rtrim($CFG->wwwroot, '/');
diff --git a/lib/tests/plugininfo/base_test.php b/lib/tests/plugininfo/base_test.php
index 6a04b96aec68f..dc316606cd792 100644
--- a/lib/tests/plugininfo/base_test.php
+++ b/lib/tests/plugininfo/base_test.php
@@ -83,7 +83,7 @@ public function test_load_disk_version_invalid_supported_version($supported, $in
*
* @return array
*/
- public function load_disk_version_invalid_supported_version_provider(): array {
+ public static function load_disk_version_invalid_supported_version_provider(): array {
return [
'Invalid supported range.' => [
'supported' => [31, 29],
@@ -149,7 +149,7 @@ public function test_load_disk_version_invalid_incompatible_version($incompatibl
*
* @return array
*/
- public function load_disk_version_invalid_incompatible_version_provider(): array {
+ public static function load_disk_version_invalid_incompatible_version_provider(): array {
return [
[[38]],
[['38']],
@@ -197,7 +197,7 @@ public function test_load_disk_version_branch_supports($supported, $incompatible
*
* @return array
*/
- public function load_disk_version_branch_supports_provider(): array {
+ public static function load_disk_version_branch_supports_provider(): array {
return [
'Range, branch in support, lowest' => [
'supported' => [29, 31],
@@ -311,7 +311,7 @@ public function test_get_sorted_plugins(
*
* @return string[]
*/
- public function plugins_not_supporting_ordering(): array {
+ public static function plugins_not_supporting_ordering(): array {
return [
['mod_assign'],
['block_login'],
diff --git a/lib/tests/plugininfo/block_test.php b/lib/tests/plugininfo/block_test.php
index 63ed074f0b7ad..65353f3dc8880 100644
--- a/lib/tests/plugininfo/block_test.php
+++ b/lib/tests/plugininfo/block_test.php
@@ -70,7 +70,7 @@ public function test_is_uninstall_allowed(
$this->assertEquals($expected, $plugininfo->is_uninstall_allowed());
}
- public function is_uninstall_allowed_provider(): array {
+ public static function is_uninstall_allowed_provider(): array {
$plugins = block::get_enabled_plugins();
return array_map(function ($plugin) {
$expected = true;
diff --git a/lib/tests/plugininfo/editor_test.php b/lib/tests/plugininfo/editor_test.php
index 685d0dea8b2dc..6b92a20cd3f0f 100644
--- a/lib/tests/plugininfo/editor_test.php
+++ b/lib/tests/plugininfo/editor_test.php
@@ -101,7 +101,7 @@ public function test_get_sorted_plugins(
*
* @return array
*/
- public function get_sorted_plugins_provider(): array {
+ public static function get_sorted_plugins_provider(): array {
$pluginmanager = \core_plugin_manager::instance();
$allplugins = array_keys($pluginmanager->get_plugins_of_type('editor'));
@@ -195,7 +195,7 @@ public function test_change_plugin_order(
*
* @return array
*/
- public function change_plugin_order_provider(): array {
+ public static function change_plugin_order_provider(): array {
$pluginmanager = \core_plugin_manager::instance();
$allplugins = array_keys($pluginmanager->get_plugins_of_type('editor'));
diff --git a/lib/tests/plugininfo/media_test.php b/lib/tests/plugininfo/media_test.php
index 05f1f9ba18c47..c46a42cf55063 100644
--- a/lib/tests/plugininfo/media_test.php
+++ b/lib/tests/plugininfo/media_test.php
@@ -69,7 +69,7 @@ public function test_is_uninstall_allowed(
*
* @return array
*/
- public function is_uninstall_allowed_provider(): array {
+ public static function is_uninstall_allowed_provider(): array {
$plugins = media::get_enabled_plugins();
return array_map(function ($plugin) {
return [
@@ -104,7 +104,7 @@ public function test_change_plugin_order(
);
}
- public function change_plugin_order_provider(): array {
+ public static function change_plugin_order_provider(): array {
$pluginmanager = \core_plugin_manager::instance();
$allplugins = $pluginmanager->get_plugins_of_type('media');
\core_collator::asort_objects_by_method($allplugins, 'get_rank', \core_collator::SORT_NUMERIC);
diff --git a/lib/tests/plugininfo/repository_test.php b/lib/tests/plugininfo/repository_test.php
index eb70cc6aa9734..fecd9d9c73cca 100644
--- a/lib/tests/plugininfo/repository_test.php
+++ b/lib/tests/plugininfo/repository_test.php
@@ -56,7 +56,7 @@ public function test_enable_plugin(string $pluginname, ?int $initialvisibility,
*
* @return array
*/
- public function enable_plugin_provider(): array {
+ public static function enable_plugin_provider(): array {
return [
'Disable an enable and visible repository' => [
'pluginname' => 'contentbank',
diff --git a/lib/tests/questionlib_test.php b/lib/tests/questionlib_test.php
index e3f412ce3d3b4..4765e21d17904 100644
--- a/lib/tests/questionlib_test.php
+++ b/lib/tests/questionlib_test.php
@@ -1540,7 +1540,7 @@ public function test_question_sort_tags_includes_filter_course_tags() {
*
* @return array
*/
- public function question_capability_on_question_provider() {
+ public static function question_capability_on_question_provider(): array {
return [
'Unrelated capability which is present' => [
'capabilities' => [
@@ -2170,7 +2170,7 @@ public function test_question_categorylist_parents_bad_data(): void {
*
* @return array test cases.
*/
- public function find_next_unused_idnumber_cases(): array {
+ public static function find_next_unused_idnumber_cases(): array {
return [
[null, null],
['id', null],
diff --git a/lib/tests/rtlcss_test.php b/lib/tests/rtlcss_test.php
index 80154dbd1b1b2..6e15f7aa7fa13 100644
--- a/lib/tests/rtlcss_test.php
+++ b/lib/tests/rtlcss_test.php
@@ -38,7 +38,7 @@ class rtlcss_test extends basic_testcase {
* Data provider.
* @return array
*/
- public function background_image_provider() {
+ public static function background_image_provider(): array {
return [
/* Not supported by MoodleHQ/RTLCSS yet.
[[
@@ -78,7 +78,7 @@ public function background_image_provider() {
* Data provider.
* @return array
*/
- public function background_position_provider() {
+ public static function background_position_provider(): array {
return [
[[
'should' => 'Should complement percentage horizontal position ',
@@ -182,7 +182,7 @@ public function background_position_provider() {
* Data provider.
* @return array
*/
- public function background_provider() {
+ public static function background_provider(): array {
return [
[[
'should' => 'Should treat 0 as 0%',
@@ -271,7 +271,7 @@ public function background_provider() {
* Data provider.
* @return array
*/
- public function directives_provider() {
+ public static function directives_provider(): array {
return [
[[
'should' => 'Should ignore flipping - rule level (default)',
@@ -356,7 +356,7 @@ public function directives_provider() {
* Data provider.
* @return array
*/
- public function properties_provider() {
+ public static function properties_provider(): array {
return [
[[
'should' => 'Should mirror property name: border-top-right-radius',
@@ -419,7 +419,7 @@ public function properties_provider() {
* Data provider.
* @return array
*/
- public function special_provider() {
+ public static function special_provider(): array {
return [
/* Not supported by MoodleHQ/RTLCSS yet.
[[
@@ -437,7 +437,7 @@ public function special_provider() {
* Data provider.
* @return array
*/
- public function transform_origin_provider() {
+ public static function transform_origin_provider(): array {
return [
[[
'should' => 'Should mirror (x-offset: 0 means 0%)',
@@ -612,7 +612,7 @@ public function transform_origin_provider() {
* Data provider.
* @return array
*/
- public function transforms_provider() {
+ public static function transforms_provider(): array {
return [
/* Not supported by MoodleHQ/RTLCSS yet.
[[
@@ -896,7 +896,7 @@ public function transforms_provider() {
* Data provider.
* @return array
*/
- public function values_nsyntax_provider() {
+ public static function values_nsyntax_provider(): array {
return [
[[
'should' => 'Should mirror property value: border-radius (4 values)',
@@ -1017,7 +1017,7 @@ public function values_nsyntax_provider() {
* Data provider.
* @return array
*/
- public function values_provider() {
+ public static function values_provider(): array {
return [
[[
'should' => 'Should mirror property value: clear',
diff --git a/lib/tests/scss_test.php b/lib/tests/scss_test.php
index ea53368e42324..cb550143877b7 100644
--- a/lib/tests/scss_test.php
+++ b/lib/tests/scss_test.php
@@ -32,7 +32,7 @@ class scss_test extends \advanced_testcase {
* Data provider for is_valid_file
* @return array
*/
- public function is_valid_file_provider() {
+ public static function is_valid_file_provider(): array {
$themedirectory = \core_component::get_component_directory('theme_boost');
$realroot = realpath($themedirectory);
return [
@@ -66,7 +66,7 @@ public function is_valid_file_provider() {
/**
* Test cases for SassC compilation.
*/
- public function scss_compilation_provider() {
+ public static function scss_compilation_provider(): array {
return [
'simple' => [
'scss' => '$font-stack: Helvetica, sans-serif;
diff --git a/lib/tests/session_manager_test.php b/lib/tests/session_manager_test.php
index 9cd4df4173ced..d7c29d4dfdf64 100644
--- a/lib/tests/session_manager_test.php
+++ b/lib/tests/session_manager_test.php
@@ -501,12 +501,14 @@ public function test_gc() {
$record->timemodified = time() - 60*20;
$r2 = $DB->insert_record('sessions', $record);
+ // Guest session still within the session timeout limit.
$record->sid = md5('hokus3');
$record->userid = $guestid;
$record->timecreated = time() - 60*60*60;
- $record->timemodified = time() - 60*20;
+ $record->timemodified = time() - 60*5;
$r3 = $DB->insert_record('sessions', $record);
+ // Guest session outside the session timeout limit.
$record->sid = md5('hokus4');
$record->userid = $guestid;
$record->timecreated = time() - 60*60*60;
@@ -792,7 +794,7 @@ public function sessionlock_history() {
*
* @return array
*/
- public function sessionlocks_info_provider() : array {
+ public static function sessionlocks_info_provider(): array {
return [
[
'url' => null,
@@ -849,7 +851,7 @@ public function test_cleanup_recent_session_locks() {
*
* @return array
*/
- public function array_session_diff_provider() {
+ public static function array_session_diff_provider(): array {
// Create an instance of this object so the comparison object's identities are the same.
// Used in one of the tests below.
$compareobjectb = (object) ['array' => 'b'];
diff --git a/lib/tests/sessionlib_test.php b/lib/tests/sessionlib_test.php
index f4e40ce08ae23..6babae44e8bfb 100644
--- a/lib/tests/sessionlib_test.php
+++ b/lib/tests/sessionlib_test.php
@@ -169,7 +169,7 @@ public function test_cron_setup_user() {
*
* @return array of config and secure result
*/
- public function moodle_cookie_secure_provider() {
+ public static function moodle_cookie_secure_provider(): array {
return array(
array(
// Non ssl, not set.
diff --git a/lib/tests/setuplib_test.php b/lib/tests/setuplib_test.php
index 0ef30f714a027..96b4f5921d83e 100644
--- a/lib/tests/setuplib_test.php
+++ b/lib/tests/setuplib_test.php
@@ -426,7 +426,7 @@ public function get_exception_info($ex) {
*
* @return array An array of arrays contain test data
*/
- public function data_for_test_get_real_size() {
+ public static function data_for_test_get_real_size(): array {
return array(
array('8KB', 8192),
array('8Kb', 8192),
diff --git a/lib/tests/statslib_test.php b/lib/tests/statslib_test.php
index 3981004eaf213..fb7d50a31725e 100644
--- a/lib/tests/statslib_test.php
+++ b/lib/tests/statslib_test.php
@@ -186,7 +186,7 @@ protected function load_xml_data_file($file) {
*
* @return array of fixture XML log file names.
*/
- public function daily_log_provider() {
+ public static function daily_log_provider(): array {
$logfiles = array();
$fileno = array('00', '01', '02', '03', '04', '05', '06', '07', '08');
@@ -202,7 +202,7 @@ public function daily_log_provider() {
*
* @return array Dates and timezones for which the first day of the week will be calculated
*/
- public function get_base_weekly_provider() {
+ public static function get_base_weekly_provider(): array {
return [
[
"startwday" => 0,
diff --git a/lib/tests/string_manager_standard_test.php b/lib/tests/string_manager_standard_test.php
index 2e296bb46ca02..2c1b9401385f0 100644
--- a/lib/tests/string_manager_standard_test.php
+++ b/lib/tests/string_manager_standard_test.php
@@ -97,14 +97,12 @@ public function test_deprecated_strings() {
*
* @return array
*/
- public function get_deprecated_strings_provider() {
+ public static function get_deprecated_strings_provider(): array {
global $CFG;
- $teststringman = testable_core_string_manager::instance($CFG->langotherroot, $CFG->langlocalroot, array());
+ $teststringman = testable_core_string_manager::instance($CFG->langotherroot, $CFG->langlocalroot, []);
$allstrings = $teststringman->get_all_deprecated_strings();
- return array_map(function($string) {
- return [$string];
- }, $allstrings);
+ return array_map(fn ($string): array => [$string], $allstrings);
}
/**
diff --git a/lib/tests/tablelib_test.php b/lib/tests/tablelib_test.php
index b7328a56a4395..ec5f9245a9977 100644
--- a/lib/tests/tablelib_test.php
+++ b/lib/tests/tablelib_test.php
@@ -363,7 +363,7 @@ public function test_50_cols() {
*
* @return array
*/
- public function fullname_column_provider() {
+ public static function fullname_column_provider(): array {
return [
['language'],
['alternatename lastname'],
@@ -782,7 +782,7 @@ public function test_initials_last_set(?string $getvalue, ?string $setvalue, ?st
*
* @return array
*/
- public function initials_provider(): array {
+ public static function initials_provider(): array {
return [
[null, null, null],
['A', null, 'A'],
diff --git a/lib/tests/task/database_logger_test.php b/lib/tests/task/database_logger_test.php
index 3ea897eb7fdbd..f4c93f6196e59 100644
--- a/lib/tests/task/database_logger_test.php
+++ b/lib/tests/task/database_logger_test.php
@@ -236,7 +236,7 @@ public function test_delete_task_logs($ids) {
*
* @return array
*/
- public function delete_task_logs_provider() : array {
+ public static function delete_task_logs_provider(): array {
return [
[
[0],
diff --git a/lib/tests/task/file_temp_cleanup_task_test.php b/lib/tests/task/file_temp_cleanup_task_test.php
index cc38ae1039720..f0a17cf49f5ee 100644
--- a/lib/tests/task/file_temp_cleanup_task_test.php
+++ b/lib/tests/task/file_temp_cleanup_task_test.php
@@ -16,6 +16,8 @@
namespace core\task;
+use stdClass;
+
/**
* Unit tests for the file_temp_cleanup task.
*
@@ -25,14 +27,13 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \core\task\file_temp_cleanup_task
*/
-class file_temp_cleanup_task_test extends \basic_testcase {
-
+final class file_temp_cleanup_task_test extends \basic_testcase {
/**
* Data provider for cron_delete_from_temp.
*
* @return array Provider data
*/
- public function cron_delete_from_temp_provider() {
+ public static function cron_delete_from_temp_provider(): array {
global $CFG;
$tmpdir = realpath($CFG->tempdir);
@@ -46,45 +47,45 @@ public function cron_delete_from_temp_provider() {
$nodes = array();
// Really old directory to remove.
- $nodes[] = $this->generate_test_path('/dir1/dir1_1/dir1_1_1/dir1_1_1_1/', true, $lastweekstime * 52, false);
+ $nodes[] = self::generate_test_path('/dir1/dir1_1/dir1_1_1/dir1_1_1_1/', true, $lastweekstime * 52, false);
// New Directory to keep.
- $nodes[] = $this->generate_test_path('/dir1/dir1_2/', true, $time, true);
+ $nodes[] = self::generate_test_path('/dir1/dir1_2/', true, $time, true);
// Directory a little less than 1 week old, keep.
- $nodes[] = $this->generate_test_path('/dir2/', true, $afterlastweekstime, true);
+ $nodes[] = self::generate_test_path('/dir2/', true, $afterlastweekstime, true);
// Directory older than 1 week old, remove.
- $nodes[] = $this->generate_test_path('/dir3/', true, $beforelastweekstime, false);
+ $nodes[] = self::generate_test_path('/dir3/', true, $beforelastweekstime, false);
// File older than 1 week old, remove.
- $nodes[] = $this->generate_test_path('/dir1/dir1_1/dir1_1_1/file1_1_1_1', false, $beforelastweekstime, false);
+ $nodes[] = self::generate_test_path('/dir1/dir1_1/dir1_1_1/file1_1_1_1', false, $beforelastweekstime, false);
// New File to keep.
- $nodes[] = $this->generate_test_path('/dir1/dir1_1/dir1_1_1/file1_1_1_2', false, $time, true);
+ $nodes[] = self::generate_test_path('/dir1/dir1_1/dir1_1_1/file1_1_1_2', false, $time, true);
// File older than 1 week old, remove.
- $nodes[] = $this->generate_test_path('/dir1/dir1_2/file1_1_2_1', false, $beforelastweekstime, false);
+ $nodes[] = self::generate_test_path('/dir1/dir1_2/file1_1_2_1', false, $beforelastweekstime, false);
// New file to keep.
- $nodes[] = $this->generate_test_path('/dir1/dir1_2/file1_1_2_2', false, $time, true);
+ $nodes[] = self::generate_test_path('/dir1/dir1_2/file1_1_2_2', false, $time, true);
// New file to keep.
- $nodes[] = $this->generate_test_path('/file1', false, $time, true);
+ $nodes[] = self::generate_test_path('/file1', false, $time, true);
// File older than 1 week, keep.
- $nodes[] = $this->generate_test_path('/file2', false, $beforelastweekstime, false);
+ $nodes[] = self::generate_test_path('/file2', false, $beforelastweekstime, false);
// Directory older than 1 week to keep.
// Note: Since this directory contains a directory that contains a file that is also older than a week
// the directory won't be deleted since it's mtime will be updated when the file is deleted.
- $nodes[] = $this->generate_test_path('/dir4/dir4_1', true, $beforelastweekstime, true);
+ $nodes[] = self::generate_test_path('/dir4/dir4_1', true, $beforelastweekstime, true);
- $nodes[] = $this->generate_test_path('/dir4/dir4_1/dir4_1_1/', true, $beforelastweekstime, true);
+ $nodes[] = self::generate_test_path('/dir4/dir4_1/dir4_1_1/', true, $beforelastweekstime, true);
// File older than 1 week to remove.
- $nodes[] = $this->generate_test_path('/dir4/dir4_1/dir4_1_1/file4_1_1_1', false, $beforelastweekstime, false);
+ $nodes[] = self::generate_test_path('/dir4/dir4_1/dir4_1_1/file4_1_1_1', false, $beforelastweekstime, false);
$expectednodes = array();
foreach ($nodes as $node) {
@@ -104,16 +105,10 @@ public function cron_delete_from_temp_provider() {
}
sort($expectednodes);
- $data = array(
- array(
- $nodes,
- $expectednodes
- ),
- array(
- array(),
- array()
- )
- );
+ $data = [
+ [$nodes, $expectednodes],
+ [[], []],
+ ];
return $data;
}
@@ -126,13 +121,13 @@ public function cron_delete_from_temp_provider() {
* @param int $time modified time of the node in epoch
* @param bool $keep Should the node exist after the delete function has run
*/
- private function generate_test_path($path, $isdir = false, $time = 0, $keep = false) {
- $node = new \stdClass();
- $node->path = $path;
- $node->isdir = $isdir;
- $node->time = $time;
- $node->keep = $keep;
- return $node;
+ private static function generate_test_path($path, $isdir = false, $time = 0, $keep = false): stdClass {
+ return (object) [
+ 'path' => $path,
+ 'isdir' => $isdir,
+ 'time' => $time,
+ 'keep' => $keep,
+ ];
}
/**
* Test removing files and directories from tempdir.
diff --git a/lib/tests/task/hide_ended_courses_task_test.php b/lib/tests/task/hide_ended_courses_task_test.php
index dc44c88d3c4d5..2a85b0ce6d030 100644
--- a/lib/tests/task/hide_ended_courses_task_test.php
+++ b/lib/tests/task/hide_ended_courses_task_test.php
@@ -31,7 +31,6 @@
* @coversDefaultClass \core\task\hide_ended_courses_task
*/
class hide_ended_courses_task_test extends \core\task\show_started_courses_task_test {
-
/**
* Test hide_ended_courses cron task.
*
diff --git a/lib/tests/task/scheduled_task_test.php b/lib/tests/task/scheduled_task_test.php
index 7f7bf513cd638..bb6bd4a082a95 100644
--- a/lib/tests/task/scheduled_task_test.php
+++ b/lib/tests/task/scheduled_task_test.php
@@ -949,7 +949,7 @@ public function test_reset_scheduled_tasks_for_component_keeps_original_lastrunt
*
* @return array[]
*/
- public function is_component_enabled_provider(): array {
+ public static function is_component_enabled_provider(): array {
return [
'Enabled component' => ['auth_cas', true],
'Disabled component' => ['auth_ldap', false],
diff --git a/lib/tests/task/show_started_courses_task_test.php b/lib/tests/task/show_started_courses_task_test.php
index 1d15c9ccb6c90..f47831cd2934a 100644
--- a/lib/tests/task/show_started_courses_task_test.php
+++ b/lib/tests/task/show_started_courses_task_test.php
@@ -116,7 +116,7 @@ public function test_show_started_courses(
*
* @return array
*/
- public function get_courses_provider(): array {
+ public static function get_courses_provider(): array {
return [
'No hidden courses' => [
'lastweek' => 0,
diff --git a/lib/tests/text_test.php b/lib/tests/text_test.php
index 148575e8c63b3..3d13c425b7fe4 100644
--- a/lib/tests/text_test.php
+++ b/lib/tests/text_test.php
@@ -607,7 +607,7 @@ public function test_strrchr() {
/**
* Tests the static checker is_charset_supported
*
- * @dataProvider is_charset_supported_provider()
+ * @dataProvider is_charset_supported_provider
* @param string $charset
* @param bool $expected
* @covers ::is_charset_supported()
@@ -621,7 +621,7 @@ public function test_is_charset_supported(string $charset, bool $expected) {
* Provider for the test_is_charset_supported()
* @return array[]
*/
- public function is_charset_supported_provider() {
+ public static function is_charset_supported_provider(): array {
return [
"Check unsupported windows charset" => [
"cp1250", false
diff --git a/lib/tests/upgrade_util_test.php b/lib/tests/upgrade_util_test.php
index 0176df678f60b..71fc45318d26d 100644
--- a/lib/tests/upgrade_util_test.php
+++ b/lib/tests/upgrade_util_test.php
@@ -38,7 +38,7 @@ class upgrade_util_test extends \advanced_testcase {
/**
* Test PHP/cURL validation.
*
- * @dataProvider validate_php_curl_tls_testcases()
+ * @dataProvider validate_php_curl_tls_testcases
* @param array $curlinfo server curl_version array
* @param int $zts 0 or 1 as defined by PHP_ZTS
* @param bool $expected expected result
@@ -50,7 +50,7 @@ public function test_validate_php_curl_tls($curlinfo, $zts, $expected) {
/**
* Test cases for validate_php_curl_tls test.
*/
- public function validate_php_curl_tls_testcases() {
+ public static function validate_php_curl_tls_testcases(): array {
$base = curl_version();
return [
@@ -125,7 +125,7 @@ public function test_can_use_tls12($sslversion, $uname, $expected) {
*
* @return array of testcases
*/
- public function can_use_tls12_testcases() {
+ public static function can_use_tls12_testcases(): array {
return [
// Bad versions.
['OpenSSL/0.9.8o', null, false],
diff --git a/lib/tests/upgradelib_test.php b/lib/tests/upgradelib_test.php
index 4b56c8507c187..7e2adf3afc50e 100644
--- a/lib/tests/upgradelib_test.php
+++ b/lib/tests/upgradelib_test.php
@@ -744,7 +744,7 @@ public function create_testthemes() {
*
* @return array
*/
- public function serialized_strings_dataprovider() {
+ public static function serialized_strings_dataprovider(): array {
return [
'A configuration that uses the old object' => [
'O:6:"object":3:{s:4:"text";s:32:"Nothing that anyone cares about.";s:5:"title";s:16:"Really old block";s:6:"format";s:1:"1";}',
@@ -1427,7 +1427,7 @@ public function test_check_oracle_usage_is_used(): void {
*
* @return array
*/
- public function usermenu_items_dataprovider(): array {
+ public static function usermenu_items_dataprovider(): array {
return [
'Add new item to empty usermenu' => [
'',
diff --git a/lib/tests/user_menu_test.php b/lib/tests/user_menu_test.php
index 7bd257977d6e3..3cea8b75b70b7 100644
--- a/lib/tests/user_menu_test.php
+++ b/lib/tests/user_menu_test.php
@@ -30,7 +30,7 @@ class user_menu_test extends \advanced_testcase {
*
* @return array containing testing data
*/
- public function custom_user_menu_data() {
+ public static function custom_user_menu_data(): array {
return array(
// These are fillers only.
array('###', 0, 1),
diff --git a/lib/tests/useragent_test.php b/lib/tests/useragent_test.php
index 308fafd29248b..4ae14b1ba55e1 100644
--- a/lib/tests/useragent_test.php
+++ b/lib/tests/useragent_test.php
@@ -36,7 +36,7 @@ public function tearDown(): void {
*
* @return array
*/
- public function user_agents_providers() {
+ public static function user_agents_providers(): array {
// Note: When adding new entries to this list, please ensure that any new browser versions are added to the corresponding list.
// This ensures that regression tests are applied to all known user agents.
return array(
diff --git a/lib/tests/weblib_format_text_test.php b/lib/tests/weblib_format_text_test.php
index e406e4ce5ab3d..fa51d3d8f647d 100644
--- a/lib/tests/weblib_format_text_test.php
+++ b/lib/tests/weblib_format_text_test.php
@@ -149,7 +149,7 @@ public function test_format_text_blanktarget($link, $expected) {
*
* @return array of testcases
*/
- public function format_text_blanktarget_testcases() {
+ public static function format_text_blanktarget_testcases(): array {
return [
'Simple link' => [
'Hey, that\'s pretty good!',
@@ -230,7 +230,7 @@ public function test_format_text_cleaning($input, $nocleaned, $cleaned) {
*
* @return array of testcases (string)testcasename => [(string)input, (string)nocleaned, (string)cleaned]
*/
- public function format_text_cleaning_testcases() {
+ public static function format_text_cleaning_testcases(): array {
return [
'JavaScript' => [
'Hello world',
diff --git a/lib/tests/weblib_test.php b/lib/tests/weblib_test.php
index 81f8351740296..3761022c17c10 100644
--- a/lib/tests/weblib_test.php
+++ b/lib/tests/weblib_test.php
@@ -451,7 +451,7 @@ public function test_trusttext_trusted() {
/**
* Data provider for trusttext_pre_edit() tests.
*/
- public function trusttext_pre_edit_provider(): array {
+ public static function trusttext_pre_edit_provider(): array {
return [
[true, 0, 'editingteacher', FORMAT_HTML, 1],
[true, 0, 'editingteacher', FORMAT_MOODLE, 1],
@@ -826,7 +826,7 @@ public function test_content_to_text($content, $format, $expected) {
/**
* Data provider for test_content_to_text.
*/
- public static function provider_content_to_text() {
+ public static function provider_content_to_text(): array {
return array(
array('asd', false, 'asd'),
// Trim '\r\n '.
@@ -852,7 +852,7 @@ public static function provider_content_to_text() {
*
* @return array Returns aray of test data for the test_validate_email function
*/
- public function data_validate_email() {
+ public static function data_validate_email(): array {
return [
// Test addresses that should pass.
[
@@ -1020,7 +1020,7 @@ public function test_validate_email($email, $result) {
/**
* Data provider for test_get_file_argument.
*/
- public static function provider_get_file_argument() {
+ public static function provider_get_file_argument(): array {
return array(
// Serving SCORM content w/o HTTP GET params.
array(array(
@@ -1268,7 +1268,7 @@ public function test_print_password_policy() {
*
* @return string[][]
*/
- public function get_html_lang_attribute_value_provider() {
+ public static function get_html_lang_attribute_value_provider(): array {
return [
'Empty lang code' => [' ', 'en'],
'English' => ['en', 'en'],
@@ -1314,7 +1314,7 @@ public function test_out_as_local_url_coding_exception(\moodle_url $url, string
* @see \moodle_url::out_as_local_url()
* @see parse_url()
*/
- public function out_as_local_url_coding_exception_provider() {
+ public static function out_as_local_url_coding_exception_provider(): array {
return [
'Google Maps CDN (HTTPS)' => [
new \moodle_url('https://maps.googleapis.com/maps/api/js', ['key' => 'googlemapkey3', 'sensor' => 'false']),
@@ -1349,7 +1349,7 @@ public function test_out_as_local_url(\moodle_url $url, string $expected) {
* @see \moodle_url::out_as_local_url()
* @see parse_url()
*/
- public function out_as_local_url_provider() {
+ public static function out_as_local_url_provider(): array {
global $CFG;
$wwwroot = rtrim($CFG->wwwroot, '/');
@@ -1388,7 +1388,7 @@ public function test_is_local_url(\moodle_url $url, bool $expected) {
* @return array
* @see \moodle_url::is_local_url()
*/
- public function is_local_url_provider() {
+ public static function is_local_url_provider(): array {
global $CFG;
$wwwroot = rtrim($CFG->wwwroot, '/');
@@ -1425,7 +1425,7 @@ public function is_local_url_provider() {
*
* @return array
*/
- public function strip_querystring_provider(): array {
+ public static function strip_querystring_provider(): array {
return [
'Null' => [null, ''],
'Empty string' => ['', ''],
diff --git a/lib/xapi/tests/external/delete_state_test.php b/lib/xapi/tests/external/delete_state_test.php
index 04411b7111d24..090598c71d54b 100644
--- a/lib/xapi/tests/external/delete_state_test.php
+++ b/lib/xapi/tests/external/delete_state_test.php
@@ -73,7 +73,7 @@ public function test_component_names(string $component, ?string $expected): void
*
* @return array
*/
- public function components_provider() : array {
+ public static function components_provider(): array {
return [
'Inexistent component' => [
'component' => 'inexistent_component',
@@ -150,7 +150,7 @@ public function test_delete_state(array $info, ?string $expected): void {
*
* @return array
*/
- public function states_provider() : array {
+ public static function states_provider(): array {
return [
'Existing and valid state' => [
'info' => [],
diff --git a/lib/xapi/tests/external/delete_states_test.php b/lib/xapi/tests/external/delete_states_test.php
index 3dad00aa3be18..8de52656638f4 100644
--- a/lib/xapi/tests/external/delete_states_test.php
+++ b/lib/xapi/tests/external/delete_states_test.php
@@ -135,7 +135,7 @@ protected static function validate_component(string $component): void {
*
* @return array
*/
- public function components_provider(): array {
+ public static function components_provider(): array {
return [
'Inexistent component' => [
'component' => 'inexistent_component',
@@ -263,7 +263,7 @@ public function test_delete_states(string $testedusername,
*
* @return array
*/
- public function states_provider(): array {
+ public static function states_provider(): array {
return [
'Activities with different users and components' => [
'username' => 'user1',
diff --git a/lib/xapi/tests/external/get_state_test.php b/lib/xapi/tests/external/get_state_test.php
index 56f9e23891c4e..7774c24c63c68 100644
--- a/lib/xapi/tests/external/get_state_test.php
+++ b/lib/xapi/tests/external/get_state_test.php
@@ -74,7 +74,7 @@ public function test_component_names(string $component, ?string $expected): void
*
* @return array
*/
- public function components_provider() : array {
+ public static function components_provider(): array {
return [
'Inexistent component' => [
'component' => 'inexistent_component',
@@ -150,7 +150,7 @@ public function test_get_state(array $info, string $expected): void {
*
* @return array
*/
- public function states_provider() : array {
+ public static function states_provider(): array {
return [
'Existing and valid state' => [
'info' => [],
diff --git a/lib/xapi/tests/external/get_states_test.php b/lib/xapi/tests/external/get_states_test.php
index a260dabf77484..4d902c8ef9027 100644
--- a/lib/xapi/tests/external/get_states_test.php
+++ b/lib/xapi/tests/external/get_states_test.php
@@ -145,7 +145,7 @@ public function test_component_names(string $component, ?bool $exception): void
*
* @return array
*/
- public function components_provider() : array {
+ public static function components_provider(): array {
return [
'Inexistent component' => [
'component' => 'inexistent_component',
@@ -189,7 +189,7 @@ public function test_since_formats(?string $since, ?array $expected, bool $excep
*
* @return array
*/
- public function since_formats_provider(): array {
+ public static function since_formats_provider(): array {
return [
'Null date' => [
'since' => null,
@@ -242,7 +242,7 @@ public function test_activity_iri(?string $activityiri, ?array $expected): void
*
* @return array
*/
- public function activity_iri_provider(): array {
+ public static function activity_iri_provider(): array {
return [
'Activity with several states' => [
'activityiri' => iri::generate('1', 'activity'),
@@ -294,7 +294,7 @@ public function test_agent_values(?string $agentreference, ?array $expected, boo
*
* @return array
*/
- public function agent_values_provider(): array {
+ public static function agent_values_provider(): array {
return [
'Current user' => [
'agentreference' => 'current',
@@ -332,7 +332,7 @@ public function test_registration_values(?string $registration, ?array $expected
*
* @return array
*/
- public function registration_values_provider(): array {
+ public static function registration_values_provider(): array {
return [
'Null registration' => [
'registration' => null,
diff --git a/lib/xapi/tests/external/post_state_test.php b/lib/xapi/tests/external/post_state_test.php
index f8878c16e5161..6255a1043aad0 100644
--- a/lib/xapi/tests/external/post_state_test.php
+++ b/lib/xapi/tests/external/post_state_test.php
@@ -72,7 +72,7 @@ public function test_component_names(string $component, ?string $expected): void
*
* @return array
*/
- public function components_provider() : array {
+ public static function components_provider(): array {
return [
'Inexistent component' => [
'component' => 'inexistent_component',
@@ -135,7 +135,7 @@ public function test_post_state(string $stateid, ?string $expected): void {
*
* @return array
*/
- public function states_provider() : array {
+ public static function states_provider(): array {
return [
'Empty stateid' => [
'stateid' => '',
diff --git a/lib/xapi/tests/external/post_statement_test.php b/lib/xapi/tests/external/post_statement_test.php
index 1502b6ee098d9..aac1a7655ebd6 100644
--- a/lib/xapi/tests/external/post_statement_test.php
+++ b/lib/xapi/tests/external/post_statement_test.php
@@ -187,7 +187,7 @@ public function test_component_names(string $component, array $expected) {
*
* @return array
*/
- public function components_provider() : array {
+ public static function components_provider(): array {
return [
'Inexistent component' => [
'inexistent_component', []
@@ -233,7 +233,7 @@ public function test_invalid_json(string $json) {
*
* @return array
*/
- public function invalid_json_provider() : array {
+ public static function invalid_json_provider(): array {
return [
'Wrong json' => [
'This is not { a json object /'
@@ -376,7 +376,7 @@ public function test_statements_group(bool $multiple, bool $validactor, bool $va
*
* @return array
*/
- public function statement_provider() : array {
+ public static function statement_provider(): array {
return [
// Single statement with group statements enabled.
'Single, Valid actor, valid verb' => [
@@ -449,7 +449,7 @@ public function test_group_disabled(bool $usegroup1, bool $usegroup2, array $exp
*
* @return array
*/
- public function group_statement_provider() : array {
+ public static function group_statement_provider(): array {
return [
// Single statement with group statements enabled.
'Group statement + group statement without group support' => [
diff --git a/lib/xapi/tests/iri_test.php b/lib/xapi/tests/iri_test.php
index c90a0d1ba9dc2..0e85b92f496c6 100644
--- a/lib/xapi/tests/iri_test.php
+++ b/lib/xapi/tests/iri_test.php
@@ -76,7 +76,7 @@ public function test_extract(string $expected, string $value, string $type = nul
*
* @return array
*/
- public function iri_samples_provider() : array {
+ public static function iri_samples_provider(): array {
global $CFG;
return [
@@ -120,7 +120,7 @@ public function test_check(string $value, bool $expected) {
*
* @return array
*/
- public function iri_check_provider() : array {
+ public static function iri_check_provider(): array {
return [
'Real IRI http' => [
'http://adlnet.gov/expapi/activities/example',
diff --git a/lib/xapi/tests/local/statement/item_activity_test.php b/lib/xapi/tests/local/statement/item_activity_test.php
index e1b7b7aed5ce6..60a8a815cc302 100644
--- a/lib/xapi/tests/local/statement/item_activity_test.php
+++ b/lib/xapi/tests/local/statement/item_activity_test.php
@@ -113,7 +113,7 @@ public function test_create_from_id(string $id, bool $usedefinition): void {
*
* @return array
*/
- public function create_from_id_provider() : array {
+ public static function create_from_id_provider(): array {
return [
'Fake IRI with no definition' => [
'paella', false,
@@ -155,7 +155,7 @@ public function test_invalid_data(string $type, string $id): void {
*
* @return array
*/
- public function invalid_data_provider() : array {
+ public static function invalid_data_provider(): array {
return [
'Invalid Avtivity objectType' => [
'Invalid Type!', iri::generate('paella', 'activity'),
diff --git a/lib/xapi/tests/local/statement/item_agent_test.php b/lib/xapi/tests/local/statement/item_agent_test.php
index 53aed33401552..7e17eeeab4e39 100644
--- a/lib/xapi/tests/local/statement/item_agent_test.php
+++ b/lib/xapi/tests/local/statement/item_agent_test.php
@@ -143,7 +143,7 @@ public function test_invalid_data(string $objecttype, bool $validhome, bool $val
*
* @return array
*/
- public function invalid_data_provider() : array {
+ public static function invalid_data_provider(): array {
return [
'Wrong objecttype' => [
'Invalid', true, true
@@ -203,7 +203,7 @@ public function test_unspupported_create(bool $usembox, bool $useaccount, bool $
*
* @return array
*/
- public function unspupported_create_provider() : array {
+ public static function unspupported_create_provider(): array {
return [
'Both mbox and account' => [
true, true, false, false
diff --git a/lib/xapi/tests/local/statement/item_attachment_test.php b/lib/xapi/tests/local/statement/item_attachment_test.php
index ee1c51f8cb9f9..11ea40d19f0d6 100644
--- a/lib/xapi/tests/local/statement/item_attachment_test.php
+++ b/lib/xapi/tests/local/statement/item_attachment_test.php
@@ -94,7 +94,7 @@ public function test_invalid_values(string $attr, $newvalue): void {
*
* @return array
*/
- public function invalid_values_data() : array {
+ public static function invalid_values_data(): array {
return [
'No usageType attachment' => [
'usageType', null
diff --git a/lib/xapi/tests/local/statement/item_definition_test.php b/lib/xapi/tests/local/statement/item_definition_test.php
index 92ea49b1df7f8..cbc2a52b9b21e 100644
--- a/lib/xapi/tests/local/statement/item_definition_test.php
+++ b/lib/xapi/tests/local/statement/item_definition_test.php
@@ -72,7 +72,7 @@ public function test_creation(string $interactiontype): void {
*
* @return array
*/
- public function creation_provider() : array {
+ public static function creation_provider(): array {
return [
'No interactionType' => [''],
'Choice' => ['choice'],
diff --git a/lib/xapi/tests/local/statement/item_group_test.php b/lib/xapi/tests/local/statement/item_group_test.php
index e55509009d059..b7bef6d34a5a6 100644
--- a/lib/xapi/tests/local/statement/item_group_test.php
+++ b/lib/xapi/tests/local/statement/item_group_test.php
@@ -143,7 +143,7 @@ public function test_invalid_data(string $objecttype, bool $validhome, bool $val
*
* @return array
*/
- public function invalid_data_provider() : array {
+ public static function invalid_data_provider(): array {
return [
'Wrong objecttype' => [
'Invalid', true, true
diff --git a/lib/xapi/tests/local/statement/item_object_test.php b/lib/xapi/tests/local/statement/item_object_test.php
index 2081c884b7870..a9de796cfe2ff 100644
--- a/lib/xapi/tests/local/statement/item_object_test.php
+++ b/lib/xapi/tests/local/statement/item_object_test.php
@@ -117,7 +117,7 @@ public function test_invalid_data(string $id): void {
*
* @return array
*/
- public function invalid_data_provider() : array {
+ public static function invalid_data_provider(): array {
return [
'Empty or null id' => [
'',
diff --git a/lib/xapi/tests/local/statement/item_result_test.php b/lib/xapi/tests/local/statement/item_result_test.php
index b6c25b8ae7fb9..7bd9561502752 100644
--- a/lib/xapi/tests/local/statement/item_result_test.php
+++ b/lib/xapi/tests/local/statement/item_result_test.php
@@ -98,7 +98,7 @@ public function test_duration_values(?string $duration, ?int $seconds, bool $exc
*
* @return array
*/
- public function duration_values_data() : array {
+ public static function duration_values_data(): array {
return [
'No duration' => [
null, null, false
diff --git a/lib/xapi/tests/local/statement/item_verb_test.php b/lib/xapi/tests/local/statement/item_verb_test.php
index deaecfecfe0fd..07892e95edba0 100644
--- a/lib/xapi/tests/local/statement/item_verb_test.php
+++ b/lib/xapi/tests/local/statement/item_verb_test.php
@@ -75,7 +75,7 @@ public function test_create_from_id(string $id): void {
*
* @return array
*/
- public function create_from_id_provider() : array {
+ public static function create_from_id_provider(): array {
return [
'Fake IRI' => [
'cook',
@@ -105,7 +105,7 @@ public function test_invalid_data(string $id): void {
*
* @return array
*/
- public function invalid_data_provider() : array {
+ public static function invalid_data_provider(): array {
return [
'Empty or null id' => [
'',
diff --git a/lib/xapi/tests/local/statement_test.php b/lib/xapi/tests/local/statement_test.php
index d1b5e47d226ab..c8c1d110b939f 100644
--- a/lib/xapi/tests/local/statement_test.php
+++ b/lib/xapi/tests/local/statement_test.php
@@ -184,7 +184,7 @@ public function test_create(bool $useagent, array $extras, array $extravalues) {
*
* @return array
*/
- public function create_provider() : array {
+ public static function create_provider(): array {
return [
'Agent statement with no extras' => [
true, [], []
@@ -413,7 +413,7 @@ public function test_invalid_gets(string $method, bool $exception) {
*
* @return array
*/
- public function invalid_gets_provider() : array {
+ public static function invalid_gets_provider(): array {
return [
'Method get_user on empty statement' => ['get_user', true],
'Method get_all_users on empty statement' => ['get_all_users', true],
@@ -532,7 +532,7 @@ public function test_invalid_data(bool $useuser, bool $userverb, bool $useobject
*
* @return array
*/
- public function invalid_data_provider() : array {
+ public static function invalid_data_provider(): array {
return [
'No actor, no verb, no object' => [false, false, false],
'No actor, verb, no object' => [false, true, false],
diff --git a/lib/xapi/tests/state_store_test.php b/lib/xapi/tests/state_store_test.php
index 817e5af7de528..353206a92e8c3 100644
--- a/lib/xapi/tests/state_store_test.php
+++ b/lib/xapi/tests/state_store_test.php
@@ -113,7 +113,7 @@ public function test_state_store_get(array $info, bool $expected): void {
*
* @return array
*/
- public function states_provider() : array {
+ public static function states_provider(): array {
return [
'Existing and valid state' => [
'info' => [],
@@ -193,7 +193,7 @@ public function test_state_store_put(array $info, string $expected): void {
*
* @return array
*/
- public function put_states_provider() : array {
+ public static function put_states_provider(): array {
return [
'Update existing state' => [
'info' => [],
@@ -334,7 +334,7 @@ public function test_state_store_wipe(array $info, int $expected): void {
*
* @return array
*/
- public function reset_wipe_states_provider() : array {
+ public static function reset_wipe_states_provider(): array {
return [
'With fake_component' => [
'info' => [],
@@ -501,7 +501,7 @@ public function test_get_state_ids(
*
* @return array
*/
- public function get_state_ids_provider(): array {
+ public static function get_state_ids_provider(): array {
return [
'empty_component' => [
'component' => 'empty_component',
@@ -583,7 +583,7 @@ public function test_invalid_activityid_format(string $operation, bool $usestate
*
* @return array
*/
- public function invalid_activityid_format_provider(): array {
+ public static function invalid_activityid_format_provider(): array {
return [
'delete' => [
'operation' => 'delete',
diff --git a/login/tests/login_lib_test.php b/login/tests/login_lib_test.php
index d86b611a118b6..041bd4dde38f4 100644
--- a/login/tests/login_lib_test.php
+++ b/login/tests/login_lib_test.php
@@ -233,7 +233,7 @@ public function test_core_login_process_password_reset_invalid_email_without_use
/**
* Data provider for \core_login_lib_testcase::test_core_login_validate_forgot_password_data().
*/
- public function forgot_password_data_provider() {
+ public static function forgot_password_data_provider(): array {
return [
'Both username and password supplied' => [
[
diff --git a/media/player/videojs/tests/player_test.php b/media/player/videojs/tests/player_test.php
index 893e63b3e4338..079f2cfe71ff0 100644
--- a/media/player/videojs/tests/player_test.php
+++ b/media/player/videojs/tests/player_test.php
@@ -289,7 +289,7 @@ public function test_youtube() {
*
* @return array
*/
- public function youtube_start_time_provider(): array {
+ public static function youtube_start_time_provider(): array {
return [
['https://www.youtube.com/watch?v=JNJMF1l3udM&t=1h11s', 3611],
['https://www.youtube.com/watch?v=dv2f_xfmbD8&index=4&list=PLxcO_MFWQBDcyn9xpbmx601YSDlDcTcr0&t=1m5s', 65],
diff --git a/message/tests/api_test.php b/message/tests/api_test.php
index fa0d56363549b..20f3c9f40bd1b 100644
--- a/message/tests/api_test.php
+++ b/message/tests/api_test.php
@@ -1823,7 +1823,7 @@ public function test_get_conversations_group_linked() {
* This provides sets of data to for testing.
* @return array
*/
- public function get_conversations_mixed_provider() {
+ public static function get_conversations_mixed_provider(): array {
return array(
'Test that conversations with messages contacts is correctly ordered.' => array(
'users' => array(
@@ -5589,7 +5589,7 @@ public function test_get_conversation_with_muted_conversation() {
/**
* Data provider for test_get_conversation_counts().
*/
- public function get_conversation_counts_test_cases() {
+ public static function get_conversation_counts_test_cases(): array {
$typeindividual = api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL;
$typegroup = api::MESSAGE_CONVERSATION_TYPE_GROUP;
$typeself = api::MESSAGE_CONVERSATION_TYPE_SELF;
diff --git a/message/tests/externallib_test.php b/message/tests/externallib_test.php
index 68801afa6d8fe..6971db4b79da7 100644
--- a/message/tests/externallib_test.php
+++ b/message/tests/externallib_test.php
@@ -5138,7 +5138,7 @@ public function test_get_conversation_with_messages() {
/**
* Data provider for test_get_conversation_counts().
*/
- public function get_conversation_counts_test_cases() {
+ public static function get_conversation_counts_test_cases(): array {
$typeindividual = \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL;
$typegroup = \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP;
$typeself = \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF;
@@ -5501,7 +5501,7 @@ public function get_conversation_counts_test_cases() {
/**
* Test the get_conversation_counts() function.
*
- * @dataProvider get_conversation_counts_test_cases()
+ * @dataProvider get_conversation_counts_test_cases
* @param array $conversationconfigs Conversations to create
* @param int $deletemessagesuser The user who is deleting the messages
* @param array $deletemessages The list of messages to delete (by index)
diff --git a/message/tests/helper_test.php b/message/tests/helper_test.php
index 6d08f834c88ba..af66d381c34e6 100644
--- a/message/tests/helper_test.php
+++ b/message/tests/helper_test.php
@@ -228,7 +228,7 @@ public function test_prevent_unclosed_html_tags(string $message, string $goodhtm
*
* @return array
*/
- public function prevent_unclosed_html_tags_data(): array {
+ public static function prevent_unclosed_html_tags_data(): array {
return [
'Prevent unclosed html elements' => [
'Title
Paragraph
Bold', 'Title
Paragraph
Bold', true
diff --git a/mod/assign/submission/onlinetext/tests/locallib_test.php b/mod/assign/submission/onlinetext/tests/locallib_test.php
index 0d6f33c122fa7..32c91b29394af 100644
--- a/mod/assign/submission/onlinetext/tests/locallib_test.php
+++ b/mod/assign/submission/onlinetext/tests/locallib_test.php
@@ -100,7 +100,7 @@ public function test_new_submission_empty($submissiontext, $expected) {
*
* @return array of testcases
*/
- public function submission_is_empty_testcases() {
+ public static function submission_is_empty_testcases(): array {
return [
'Empty submission string' => ['', true],
'Empty submission null' => [null, true],
diff --git a/mod/assign/tests/behat/assign_activity_completion.feature b/mod/assign/tests/behat/assign_activity_completion.feature
index ee011daadfe2c..50b056ab49409 100644
--- a/mod/assign/tests/behat/assign_activity_completion.feature
+++ b/mod/assign/tests/behat/assign_activity_completion.feature
@@ -70,7 +70,7 @@ Feature: View activity completion in the assignment activity
And the manual completion button for "Music history" should exist
@javascript
- Scenario: Use manual completion from the activity page
+ Scenario: A student can manually mark the assign activity as done but a teacher cannot
Given I am on the "Music history" "assign activity" page logged in as teacher1
# Teacher view.
And the manual completion button for "Music history" should be disabled
@@ -81,7 +81,7 @@ Feature: View activity completion in the assignment activity
And I toggle the manual completion state of "Music history"
And the manual completion button of "Music history" is displayed as "Done"
- Scenario: View automatic completion items as a teacher
+ Scenario: Verify that the assignment completion conditions are displayed to teachers
Given I am on the "Music history" "assign activity editing" page logged in as teacher1
And I expand all fieldsets
And I set the following fields to these values:
@@ -95,7 +95,7 @@ Feature: View activity completion in the assignment activity
And "Music history" should have the "Receive a grade" completion condition
@javascript
- Scenario: View automatic completion items as a student
+ Scenario: Verify that students can complete an assignment activity by achieving a passing grade
Given I am on the "Music history" "assign activity editing" page logged in as teacher1
And I expand all fieldsets
And I set the following fields to these values:
diff --git a/mod/assign/tests/custom_completion_test.php b/mod/assign/tests/custom_completion_test.php
index 91c7220eb8484..8136293171922 100644
--- a/mod/assign/tests/custom_completion_test.php
+++ b/mod/assign/tests/custom_completion_test.php
@@ -54,7 +54,7 @@ class custom_completion_test extends advanced_testcase {
*
* @return array[]
*/
- public function get_state_provider(): array {
+ public static function get_state_provider(): array {
return [
'Undefined rule' => [
'somenonexistentrule', COMPLETION_DISABLED, false, null, coding_exception::class
@@ -200,7 +200,7 @@ public function test_is_defined() {
*
* @return array[]
*/
- public function get_available_custom_rules_provider(): array {
+ public static function get_available_custom_rules_provider(): array {
return [
'Completion submit available' => [
COMPLETION_ENABLED, ['completionsubmit']
diff --git a/mod/assign/tests/dates_test.php b/mod/assign/tests/dates_test.php
index 57fbaa05cd36e..31b840c62b15c 100644
--- a/mod/assign/tests/dates_test.php
+++ b/mod/assign/tests/dates_test.php
@@ -43,7 +43,7 @@ class dates_test extends advanced_testcase {
* Data provider for get_dates_for_module().
* @return array[]
*/
- public function get_dates_for_module_provider(): array {
+ public static function get_dates_for_module_provider(): array {
$now = time();
$before = $now - DAYSECS;
$earlier = $before - DAYSECS;
diff --git a/mod/assign/tests/downloader_test.php b/mod/assign/tests/downloader_test.php
index da077a3a9ba2c..3b12671e309cf 100644
--- a/mod/assign/tests/downloader_test.php
+++ b/mod/assign/tests/downloader_test.php
@@ -179,9 +179,9 @@ private function prepare_filename_text(string $text): string {
*
* @return array of scenarios
*/
- public function load_filelist_provider(): array {
- $downloadasfoldertests = $this->load_filelist_downloadasfolder_scenarios();
- $downloadasfilestests = $this->load_filelist_downloadasfiles_scenarios();
+ public static function load_filelist_provider(): array {
+ $downloadasfoldertests = static::load_filelist_downloadasfolder_scenarios();
+ $downloadasfilestests = static::load_filelist_downloadasfiles_scenarios();
return array_merge(
$downloadasfoldertests,
$downloadasfilestests,
@@ -196,8 +196,8 @@ public function load_filelist_provider(): array {
*
* @return array of scenarios
*/
- private function load_filelist_downloadasfiles_scenarios(): array {
- $result = $this->load_filelist_downloadasfolder_scenarios("Download as files:");
+ private static function load_filelist_downloadasfiles_scenarios(): array {
+ $result = static::load_filelist_downloadasfolder_scenarios("Download as files:");
// Transform paths from files.
foreach ($result as $scenario => $info) {
$info['downloadasfolder'] = false;
@@ -215,7 +215,9 @@ private function load_filelist_downloadasfiles_scenarios(): array {
* @param string $prefix the scenarios prefix
* @return array of scenarios
*/
- private function load_filelist_downloadasfolder_scenarios(string $prefix = "Download as folders:"): array {
+ private static function load_filelist_downloadasfolder_scenarios(
+ string $prefix = "Download as folders:",
+ ): array {
return [
// Test without team submissions.
$prefix . ' All users without groups' => [
diff --git a/mod/assign/tests/externallib_test.php b/mod/assign/tests/externallib_test.php
index 70d6dc00f4b69..a4d8570f680d9 100644
--- a/mod/assign/tests/externallib_test.php
+++ b/mod/assign/tests/externallib_test.php
@@ -2762,7 +2762,7 @@ public function test_get_participant_relative_dates(array $courseconfig, array $
/**
* The test_get_participant_relative_dates data provider.
*/
- public function get_participant_relative_dates_provider() {
+ public static function get_participant_relative_dates_provider(): array {
$timenow = time();
return [
diff --git a/mod/assign/tests/locallib_test.php b/mod/assign/tests/locallib_test.php
index fc49843575883..48eeead0a1b03 100644
--- a/mod/assign/tests/locallib_test.php
+++ b/mod/assign/tests/locallib_test.php
@@ -150,7 +150,7 @@ public function test_is_blind_marking() {
*
* @return array Provider data
*/
- public function get_assign_perpage_provider() {
+ public static function get_assign_perpage_provider(): array {
return array(
array(
'maxperpage' => -1,
@@ -919,7 +919,7 @@ public function test_new_submission_empty($data, $expected) {
*
* @return array of testcases
*/
- public function new_submission_empty_testcases() {
+ public static function new_submission_empty_testcases(): array {
return [
'With file and onlinetext' => [
[
@@ -3067,7 +3067,7 @@ public function test_submission_comment_plugin_settings($globalenabled, $instanc
$this->assertEquals($isenabled, (bool) $plugin->is_enabled('enabled'));
}
- public function submission_plugin_settings_provider() {
+ public static function submission_plugin_settings_provider(): array {
return [
'CFG->usecomments true, empty config => Enabled by default' => [
true,
@@ -3202,7 +3202,7 @@ public function test_feedback_plugin_settings($instanceconfig, $isenabled) {
$this->assertEquals($isenabled, (bool) $plugin->is_enabled('enabled'));
}
- public function feedback_plugin_settings_provider() {
+ public static function feedback_plugin_settings_provider(): array {
return [
'No configuration => disabled' => [
[],
@@ -3957,7 +3957,7 @@ public function test_update_activity_completion_records_team_submission_new() {
* Data provider for test_fix_null_grades
* @return array[] Test data for test_fix_null_grades. Each element should contain grade, expectedcount and gradebookvalue
*/
- public function fix_null_grades_provider() {
+ public static function fix_null_grades_provider(): array {
return [
'Negative less than one is errant' => [
'grade' => -0.64,
@@ -4144,7 +4144,7 @@ public function test_assign_get_instance(array $courseconfig, array $assignconfi
/**
* The test_assign_get_instance data provider.
*/
- public function assign_get_instance_provider() {
+ public static function assign_get_instance_provider(): array {
$timenow = time();
// The get_default_instance() method shouldn't calculate any properties per-user. It should just return the record data.
@@ -4225,7 +4225,7 @@ public function test_assign_get_default_instance(array $courseconfig, array $ass
/**
* The test_assign_get_default_instance data provider.
*/
- public function assign_get_default_instance_provider() {
+ public static function assign_get_default_instance_provider(): array {
$timenow = time();
// The get_default_instance() method shouldn't calculate any properties per-user. It should just return the record data.
diff --git a/mod/bigbluebuttonbn/tests/backup_restore_test.php b/mod/bigbluebuttonbn/tests/backup_restore_test.php
index f173ea1802e7b..84bbf28ce285b 100644
--- a/mod/bigbluebuttonbn/tests/backup_restore_test.php
+++ b/mod/bigbluebuttonbn/tests/backup_restore_test.php
@@ -223,7 +223,7 @@ public function test_recycle_module_keep_meetingid(int $type) {
* Return an array of BigBlueButton types
* @return array[]
*/
- public function bbb_type_provider() {
+ public static function bbb_type_provider(): array {
return [
'All' => [instance::TYPE_ALL],
'Recording Only' => [instance::TYPE_RECORDING_ONLY],
diff --git a/mod/bigbluebuttonbn/tests/behat/bigbluebuttonbn_activity_availability.feature b/mod/bigbluebuttonbn/tests/behat/bigbluebuttonbn_activity_availability.feature
new file mode 100644
index 0000000000000..34ea0cdfe94c6
--- /dev/null
+++ b/mod/bigbluebuttonbn/tests/behat/bigbluebuttonbn_activity_availability.feature
@@ -0,0 +1,45 @@
+@mod @mod_bigbluebuttonbn
+Feature: Manage BigBlueButton session timings
+ As a teacher
+ I want to set and manage the open and close times for BigBlueButton sessions
+ So that I can control when students can join the sessions
+
+ Background:
+ Given a BigBlueButton mock server is configured
+ And I enable "bigbluebuttonbn" "mod" plugin
+ And the following "courses" exist:
+ | fullname | shortname |
+ | Course 1 | C1 |
+ And the following "users" exist:
+ | username | firstname | lastname | email |
+ | teacher1 | Teacher | One | teacher1@example.com |
+ | student1 | Student | One | student1@example.com |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teacher1 | C1 | editingteacher |
+ | student1 | C1 | student |
+ And the following "blocks" exist:
+ | blockname | contextlevel | reference | pagetypepattern | defaultregion |
+ | calendar_upcoming | System | 1 | my-index | side-post |
+
+ Scenario Outline: Setting and verifying BBB activity open and close times
+ Given the following "activities" exist:
+ | course | activity | name | openingtime | closingtime |
+ | C1 | bigbluebuttonbn | BBB 1 | | |
+ When I am on the "BBB 1" "bigbluebuttonbn activity" page logged in as student1
+ And "Join session" "link" exist
+ And I should see "Open:"
+ And I should see "%A, %d %B %Y##"
+ And I should see "Close:"
+ And I should see "%A, %d %B %Y##"
+ And I am viewing calendar in "month" view
+ And I see "BBB 1"
+ And I am on site homepage
+ And I follow "Dashboard"
+ And I see "BBB 1" in the "Upcoming events" "block"
+
+ Examples:
+ | openingtime | closingtime | calendarvisibility | buttonvisibility | upcomingeventvisibility |
+ | ##now +1 minute## | ##now +5 minutes## | should | should not | should |
+ | ##1 hour ago## | ##+2 hours## | should | should | should not |
+ | ##yesterday## | ##yesterday +3 hours## | should not | should not | should not |
diff --git a/mod/bigbluebuttonbn/tests/completion/completion_test.php b/mod/bigbluebuttonbn/tests/completion/completion_test.php
index 4870447881e28..c39061400efe0 100644
--- a/mod/bigbluebuttonbn/tests/completion/completion_test.php
+++ b/mod/bigbluebuttonbn/tests/completion/completion_test.php
@@ -281,7 +281,7 @@ public function test_get_completion_with_events(array $customcompletionrules, ar
*
* @return array[]
*/
- public function custom_completion_data_provider() {
+ public static function custom_completion_data_provider(): array {
return [
'simple' => [
'customcompletionrules' => [
diff --git a/mod/bigbluebuttonbn/tests/external/get_recordings_test.php b/mod/bigbluebuttonbn/tests/external/get_recordings_test.php
index 96b85bc481615..f5a208e7f60ac 100644
--- a/mod/bigbluebuttonbn/tests/external/get_recordings_test.php
+++ b/mod/bigbluebuttonbn/tests/external/get_recordings_test.php
@@ -420,7 +420,7 @@ public function test_get_recordings_groups($type, $groups, $users, $recordingsda
*
* @return array[]
*/
- public function recording_group_test_data() {
+ public static function recording_group_test_data(): array {
return [
'visiblegroups' => [
'type' => instance::TYPE_ALL,
diff --git a/mod/bigbluebuttonbn/tests/instance_test.php b/mod/bigbluebuttonbn/tests/instance_test.php
index 194b3c9aac36f..163d95a0e589f 100644
--- a/mod/bigbluebuttonbn/tests/instance_test.php
+++ b/mod/bigbluebuttonbn/tests/instance_test.php
@@ -65,7 +65,7 @@ public function test_get_from(string $function, string $field): void {
*
* @return string[][]
*/
- public function get_from_location_provider(): array {
+ public static function get_from_location_provider(): array {
return [
['get_from_instanceid', 'id'],
['get_from_cmid', 'cmid'],
@@ -204,7 +204,7 @@ public function test_get_from_meetingid_invalid(string $meetingid): void {
*
* @return \string[][]
*/
- public function invalid_meetingid_provider(): array {
+ public static function invalid_meetingid_provider(): array {
// Meeting IDs are in the formats:
// - --
// - --[]
@@ -314,7 +314,7 @@ public function test_get_meeting_id_without_groups(): void {
*
* @return array
*/
- public function is_currently_open_provider(): array {
+ public static function is_currently_open_provider(): array {
return [
'No opening or closing time set: Is open' => [null, null, true],
'Opening time set in the past, no closing: Is open' => [-DAYSECS, null, true],
@@ -393,7 +393,7 @@ public function test_user_must_wait_to_join(bool $isadmin, bool $ismoderator, bo
*
* @return array
*/
- public function user_must_wait_to_join_provider(): array {
+ public static function user_must_wait_to_join_provider(): array {
return [
'Admins must never wait to join (waiting disabled)' => [true, false, false, false],
'Admins must never wait to join (waiting enabled)' => [true, false, true, false],
@@ -437,7 +437,7 @@ public function test_does_current_user_count_towards_user_limit(
*
* @return array
*/
- public function does_current_user_count_towards_user_limit_provider(): array {
+ public static function does_current_user_count_towards_user_limit_provider(): array {
return [
'Admin does not count' => [true, false, false],
'Moderator does not count' => [false, true, false],
@@ -482,7 +482,7 @@ public function test_get_current_user_password(bool $isadmin, bool $ismoderator,
*
* @return array
*/
- public function get_current_user_password_provider(): array {
+ public static function get_current_user_password_provider(): array {
return [
'Admin is a moderator' => [true, false, true],
'Moderator is a moderator' => [false, true, true],
@@ -523,7 +523,7 @@ public function test_get_current_user_role(bool $isadmin, bool $ismoderator, boo
*
* @return array
*/
- public function get_current_user_role_provider(): array {
+ public static function get_current_user_role_provider(): array {
return [
'Admin is a moderator' => [true, false, true],
'Moderator is a moderator' => [false, true, true],
@@ -564,7 +564,7 @@ public function test_allow_recording_start_stop(
*
* @return array
*/
- public function allow_recording_start_stop_provider(): array {
+ public static function allow_recording_start_stop_provider(): array {
return [
'Meeting is not recorded: No start/stop' => [false, false, false],
'Meeting recorded, Buttons shown: Allow' => [true, true, true],
diff --git a/mod/bigbluebuttonbn/tests/local/bigbluebutton/recordings/recording_data_test.php b/mod/bigbluebuttonbn/tests/local/bigbluebutton/recordings/recording_data_test.php
index 4622c9d9e83ba..64a990f0cd934 100644
--- a/mod/bigbluebuttonbn/tests/local/bigbluebutton/recordings/recording_data_test.php
+++ b/mod/bigbluebuttonbn/tests/local/bigbluebutton/recordings/recording_data_test.php
@@ -44,7 +44,7 @@ public function test_get_recording_type_text(string $name, string $type) {
*
* @return \string[][]
*/
- public function type_text_provider(): array {
+ public static function type_text_provider(): array {
return [
['Presentation', 'presentation'],
['Video', 'video'],
diff --git a/mod/bigbluebuttonbn/tests/local/extension_test.php b/mod/bigbluebuttonbn/tests/local/extension_test.php
index be907af02a93f..5adcfd7476985 100644
--- a/mod/bigbluebuttonbn/tests/local/extension_test.php
+++ b/mod/bigbluebuttonbn/tests/local/extension_test.php
@@ -263,7 +263,7 @@ public function test_backup_restore(): void {
*
* @return array[]
*/
- public function classes_implementing_class(): array {
+ public static function classes_implementing_class(): array {
return [
'mod_instance_helper with plugin disabled' => [
'bbbenabled' => false,
diff --git a/mod/bigbluebuttonbn/tests/meeting_test.php b/mod/bigbluebuttonbn/tests/meeting_test.php
index d19dd8618d7fd..f6fa0283767ce 100644
--- a/mod/bigbluebuttonbn/tests/meeting_test.php
+++ b/mod/bigbluebuttonbn/tests/meeting_test.php
@@ -57,7 +57,7 @@ public function setUp(): void {
*
* @return array[]
*/
- public function get_instance_types_meeting_info(): array {
+ public static function get_instance_types_meeting_info(): array {
return [
'Instance Type ALL - No Group' => [
'type' => instance::TYPE_ALL,
@@ -417,7 +417,7 @@ protected function join_meeting(string $url) {
*
* @return array[]
*/
- public function get_data_can_join_with_dates(): array {
+ public static function get_data_can_join_with_dates(): array {
return [
'Instance Type ALL - No Group - Closed in past' => [
'type' => instance::TYPE_ALL,
diff --git a/mod/bigbluebuttonbn/tests/output/recording_row_playback_test.php b/mod/bigbluebuttonbn/tests/output/recording_row_playback_test.php
index 510a789c60472..1b0f62fa27aeb 100644
--- a/mod/bigbluebuttonbn/tests/output/recording_row_playback_test.php
+++ b/mod/bigbluebuttonbn/tests/output/recording_row_playback_test.php
@@ -130,7 +130,7 @@ public function test_should_be_included(string $role, array $canview, object $gl
*
* @return array
*/
- public function should_be_included_data_provider() {
+ public static function should_be_included_data_provider(): array {
return [
'editingteacher user should see all' => [
'role' => 'editingteacher',
diff --git a/mod/bigbluebuttonbn/tests/recording_test.php b/mod/bigbluebuttonbn/tests/recording_test.php
index fa4ff52fd64c2..8479a25cc1fe5 100644
--- a/mod/bigbluebuttonbn/tests/recording_test.php
+++ b/mod/bigbluebuttonbn/tests/recording_test.php
@@ -103,7 +103,7 @@ public function test_get_description(): void {
*
* @return array[]
*/
- public function get_status_provider(): array {
+ public static function get_status_provider(): array {
return [
[recording::RECORDING_STATUS_PROCESSED],
[recording::RECORDING_STATUS_DISMISSED],
@@ -137,7 +137,7 @@ public function test_get_allrecordings(int $type): void {
*
* @return array[]
*/
- public function get_allrecordings_types_provider(): array {
+ public static function get_allrecordings_types_provider(): array {
return [
'Instance Type ALL' => [
'type' => instance::TYPE_ALL
diff --git a/mod/book/tests/behat/book_activity_completion.feature b/mod/book/tests/behat/book_activity_completion.feature
index 5795c51a8634c..aef186845af4b 100644
--- a/mod/book/tests/behat/book_activity_completion.feature
+++ b/mod/book/tests/behat/book_activity_completion.feature
@@ -65,7 +65,7 @@ Feature: View activity completion information in the book activity
Then the "View" completion condition of "Art history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the book activity as done but a teacher cannot
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"
diff --git a/mod/chat/tests/behat/chat_activity_completion.feature b/mod/chat/tests/behat/chat_activity_completion.feature
index 1fcef4726b013..a4544d70c0267 100644
--- a/mod/chat/tests/behat/chat_activity_completion.feature
+++ b/mod/chat/tests/behat/chat_activity_completion.feature
@@ -36,7 +36,7 @@ Feature: View activity completion information in the chat activity
Then the "View" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the chat activity as done but a teacher cannot
Given I log in as "teacher1"
And the following "activity" exists:
| activity | chat |
diff --git a/mod/chat/tests/format_message_test.php b/mod/chat/tests/format_message_test.php
index d27691b4f36bf..3a27b0ec689f8 100644
--- a/mod/chat/tests/format_message_test.php
+++ b/mod/chat/tests/format_message_test.php
@@ -33,7 +33,7 @@ class format_message_test extends \advanced_testcase {
const USER_CURRENT = 1;
const USER_OTHER = 2;
- public function chat_format_message_manually_provider() {
+ public static function chat_format_message_manually_provider(): array {
$dateregexp = '\d{2}:\d{2}';
return [
'Beep everyone' => [
diff --git a/mod/choice/tests/custom_completion_test.php b/mod/choice/tests/custom_completion_test.php
index 0de6b5ebf025d..120d3e2f40076 100644
--- a/mod/choice/tests/custom_completion_test.php
+++ b/mod/choice/tests/custom_completion_test.php
@@ -43,7 +43,7 @@ class custom_completion_test extends advanced_testcase {
*
* @return array[]
*/
- public function get_state_provider(): array {
+ public static function get_state_provider(): array {
return [
'Undefined rule' => [
'somenonexistentrule', COMPLETION_DISABLED, false, null, coding_exception::class
@@ -166,7 +166,7 @@ public function test_is_defined() {
*
* @return array[]
*/
- public function get_available_custom_rules_provider(): array {
+ public static function get_available_custom_rules_provider(): array {
return [
'Completion submit available' => [
COMPLETION_ENABLED, ['completionsubmit']
diff --git a/mod/choice/tests/dates_test.php b/mod/choice/tests/dates_test.php
index b5c0d27f92eef..dd6eab7d69217 100644
--- a/mod/choice/tests/dates_test.php
+++ b/mod/choice/tests/dates_test.php
@@ -43,7 +43,7 @@ class dates_test extends advanced_testcase {
* Data provider for get_dates_for_module().
* @return array[]
*/
- public function get_dates_for_module_provider(): array {
+ public static function get_dates_for_module_provider(): array {
$now = time();
$before = $now - DAYSECS;
$earlier = $before - DAYSECS;
diff --git a/mod/data/locallib.php b/mod/data/locallib.php
index de36ed31360be..7ef3673ff4124 100644
--- a/mod/data/locallib.php
+++ b/mod/data/locallib.php
@@ -1082,11 +1082,7 @@ function data_search_entries($data, $cm, $context, $mode, $currentgroup, $search
// If a student is not part of a group and seperate groups is enabled, we don't
// want them seeing all records.
$groupmode = groups_get_activity_groupmode($cm);
- if ($currentgroup == 0 && $groupmode == 1 && !$canmanageentries) {
- $canviewallrecords = false;
- } else {
- $canviewallrecords = true;
- }
+ $canviewallrecords = $groupmode != SEPARATEGROUPS || has_capability('moodle/site:accessallgroups', $context);
$numentries = data_numentries($data);
$requiredentriesallowed = true;
diff --git a/mod/data/tests/behat/data_activity_completion.feature b/mod/data/tests/behat/data_activity_completion.feature
index bb07489ac79cf..fcba7afefc6a9 100644
--- a/mod/data/tests/behat/data_activity_completion.feature
+++ b/mod/data/tests/behat/data_activity_completion.feature
@@ -39,7 +39,7 @@ Feature: View activity completion in the database activity
| Field name | Instrument types |
And I log out
- Scenario: View automatic completion items as a teacher
+ Scenario: Database activity displays completion conditions to teachers
Given I am on the "Music history" "data activity" page logged in as teacher1
# We add an entry to let the user change to a different view.
When I add an entry to "Music history" database with:
@@ -53,7 +53,7 @@ Feature: View activity completion in the database activity
And "Music history" should have the "Make entries: 2" completion condition
And "Music history" should have the "Receive a grade" completion condition
- Scenario: View automatic completion items as a student
+ Scenario: A student can complete an database activity by achieving a passing grade
Given I am on the "Music history" "data activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 2" completion condition of "Music history" is displayed as "todo"
@@ -89,7 +89,7 @@ Feature: View activity completion in the database activity
And "Vinnie Student1" user has completed "Music history" activity
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the data activity as done but a teacher cannot
Given I am on the "Music history" "data 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"
diff --git a/mod/data/tests/behat/data_activity_completion_pass_grade.feature b/mod/data/tests/behat/data_activity_completion_pass_grade.feature
index c30b84c1e7ad3..3a646f07ef076 100644
--- a/mod/data/tests/behat/data_activity_completion_pass_grade.feature
+++ b/mod/data/tests/behat/data_activity_completion_pass_grade.feature
@@ -45,7 +45,7 @@ Feature: Completion pass grade
And I log out
@javascript
- Scenario: View automatic completion items as a teacher
+ Scenario: Database module completion conditions are displayed regardless of the view
Given I am on the "Music history" "data activity" page logged in as teacher1
# We add an entry to let the user change to a different view.
When I add an entry to "Music history" database with:
@@ -62,7 +62,7 @@ Feature: Completion pass grade
And "Music history" should have the "Receive a passing grade" completion condition
@javascript
- Scenario: View automatic completion items as a failing student
+ Scenario: Student cannot complete a database activity if one of the conditions are not met
Given I am on the "Music history" "data activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 2" completion condition of "Music history" is displayed as "todo"
@@ -101,7 +101,7 @@ Feature: Completion pass grade
And "Vinnie Student1" user has completed "Music history" activity
@javascript
- Scenario: View automatic completion items as a passing student
+ Scenario: Student can complete a database activity when all conditions are met
Given I am on the "Music history" "data activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 2" completion condition of "Music history" is displayed as "todo"
diff --git a/mod/data/tests/behat/group_mode.feature b/mod/data/tests/behat/group_mode.feature
index ac3676dbf2100..0da4d1426e128 100644
--- a/mod/data/tests/behat/group_mode.feature
+++ b/mod/data/tests/behat/group_mode.feature
@@ -16,6 +16,8 @@ Feature: Group data activity
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | TeacherG1 | 1 | teacher1@example.com |
+ | teacher2 | TeacherGNone | 2 | teacher2@example.com |
+ | teacher3 | TeacherGNone | 3 | teacher3@example.com |
| user1 | User1G1 | 1 | user1@example.com |
| user2 | User2G2 | 2 | user2@example.com |
| user3 | User3None | 3 | user3@example.com |
@@ -23,6 +25,8 @@ Feature: Group data activity
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
+ | teacher2 | C1 | editingteacher |
+ | teacher3 | C1 | teacher |
| user1 | C1 | student |
| user2 | C1 | student |
| user3 | C1 | student |
@@ -73,11 +77,15 @@ Feature: Group data activity
Examples:
| data | user | all | G1 | G2 | user1 | user2 |
| data1 | teacher1 | should see | should see | should see | should see | should see |
+ | data1 | teacher2 | should see | should see | should see | should see | should see |
+ | data1 | teacher3 | should see | should not see | should not see | should not see | should not see |
| data1 | user1 | should not see | should see | should not see | should see | should not see |
| data1 | user2 | should not see | should not see | should see | should not see | should see |
| data1 | user3 | should see | should not see | should not see | should not see | should not see |
| data1 | user4 | should see | should not see | should not see | should not see | should not see |
| data2 | teacher1 | should see | should see | should see | should see | should see |
+ | data2 | teacher2 | should see | should see | should see | should see | should see |
+ | data2 | teacher3 | should see | should see | should see | should see | should not see |
| data2 | user1 | should see | should see | should see | should see | should not see |
| data2 | user2 | should see | should see | should see | should not see | should see |
| data2 | user3 | should see | should see | should see | should see | should not see |
diff --git a/mod/data/tests/custom_completion_test.php b/mod/data/tests/custom_completion_test.php
index 8cd39265c54d7..2f41dad7a5b61 100644
--- a/mod/data/tests/custom_completion_test.php
+++ b/mod/data/tests/custom_completion_test.php
@@ -51,7 +51,7 @@ class custom_completion_test extends advanced_testcase {
*
* @return array[]
*/
- public function get_state_provider(): array {
+ public static function get_state_provider(): array {
return [
'Undefined rule' => [
'somenonexistentrule', COMPLETION_DISABLED, 0, null, coding_exception::class
@@ -173,7 +173,7 @@ public function test_is_defined() {
*
* @return array[]
*/
- public function get_available_custom_rules_provider(): array {
+ public static function get_available_custom_rules_provider(): array {
return [
'Completion entries available' => [
COMPLETION_ENABLED, ['completionentries']
diff --git a/mod/data/tests/dates_test.php b/mod/data/tests/dates_test.php
index 6fdd3494079ea..2a769e7f16918 100644
--- a/mod/data/tests/dates_test.php
+++ b/mod/data/tests/dates_test.php
@@ -43,7 +43,7 @@ class dates_test extends advanced_testcase {
* Data provider for get_dates_for_module().
* @return array[]
*/
- public function get_dates_for_module_provider(): array {
+ public static function get_dates_for_module_provider(): array {
$now = time();
$before = $now - DAYSECS;
$earlier = $before - DAYSECS;
diff --git a/mod/data/tests/entries_exporter_test.php b/mod/data/tests/entries_exporter_test.php
index 2e30875773e7f..7ae23c30f6cc5 100644
--- a/mod/data/tests/entries_exporter_test.php
+++ b/mod/data/tests/entries_exporter_test.php
@@ -56,7 +56,7 @@ public function test_get_records_count(array $rows, int $expectedcount): void {
*
* @return array data for testing
*/
- public function get_records_count_provider(): array {
+ public static function get_records_count_provider(): array {
return [
'onlyheader' => [
'rows' => [
@@ -109,7 +109,7 @@ public function test_add_file_from_string(array $files, bool $success): void {
*
* @return array data for testing
*/
- public function add_file_from_string_provider(): array {
+ public static function add_file_from_string_provider(): array {
return [
'one file' => [
'files' => [
@@ -187,7 +187,7 @@ public function test_create_unique_filename(string $inputfilename, string $resul
*
* @return array data for testing
*/
- public function create_unique_filename_provider(): array {
+ public static function create_unique_filename_provider(): array {
return [
'does not exist yet' => [
'inputfilename' => 'someuniquename.txt',
diff --git a/mod/data/tests/entries_import_test.php b/mod/data/tests/entries_import_test.php
index 8c2dd51d971a1..8ce9d59511186 100644
--- a/mod/data/tests/entries_import_test.php
+++ b/mod/data/tests/entries_import_test.php
@@ -463,7 +463,7 @@ public function test_get_added_record_messages(string $datafilecontent, int $exp
*
* @return array data for testing
*/
- public function get_added_record_messages_provider(): array {
+ public static function get_added_record_messages_provider(): array {
return [
'only header' => [
'datafilecontent' => 'ID,Param2,filefield,picturefield' . PHP_EOL,
diff --git a/mod/data/tests/entries_importer_test.php b/mod/data/tests/entries_importer_test.php
index 10f11f5fc861b..30b634467235d 100644
--- a/mod/data/tests/entries_importer_test.php
+++ b/mod/data/tests/entries_importer_test.php
@@ -133,7 +133,7 @@ public function test_get_file_content_from_zip(array $files, mixed $datafilecont
*
* @return array data for testing
*/
- public function get_file_content_from_zip_provider(): array {
+ public static function get_file_content_from_zip_provider(): array {
return [
'some files in the zip archive' => [
'files' => [
diff --git a/mod/data/tests/event/events_test.php b/mod/data/tests/event/events_test.php
index aa7b8207da5f1..8f53b5932fd56 100644
--- a/mod/data/tests/event/events_test.php
+++ b/mod/data/tests/event/events_test.php
@@ -341,7 +341,7 @@ public function test_template_updated() {
*
* @return array[]
*/
- public function preset_importer_provider(): array {
+ public static function preset_importer_provider(): array {
// Image gallery preset is: ['title' => 'text', 'description' => 'textarea', 'image' => 'picture'];
$titlefield = new \stdClass();
diff --git a/mod/data/tests/external/get_mapping_information_test.php b/mod/data/tests/external/get_mapping_information_test.php
index b521875004481..423e29f8669a9 100644
--- a/mod/data/tests/external/get_mapping_information_test.php
+++ b/mod/data/tests/external/get_mapping_information_test.php
@@ -40,7 +40,7 @@ class get_mapping_information_test extends \advanced_testcase {
*
* @return array[]
*/
- public function get_mapping_information_provider(): array {
+ public static function get_mapping_information_provider(): array {
// Image gallery preset is: ['title' => 'text', 'description' => 'textarea', 'image' => 'picture'];
$titlefield = new \stdClass();
diff --git a/mod/data/tests/generator_test.php b/mod/data/tests/generator_test.php
index eed49e5aec1dc..62b84bfdc81c7 100644
--- a/mod/data/tests/generator_test.php
+++ b/mod/data/tests/generator_test.php
@@ -300,7 +300,7 @@ public function test_create_preset(?stdClass $record) {
*
* @return array
*/
- public function create_preset_provider(): array {
+ public static function create_preset_provider(): array {
return [
'Create using the default configuration' => [
'record' => null,
diff --git a/mod/data/tests/lib_test.php b/mod/data/tests/lib_test.php
index be5b534e51d39..c1a87c6cdb6ab 100644
--- a/mod/data/tests/lib_test.php
+++ b/mod/data/tests/lib_test.php
@@ -746,7 +746,7 @@ public function test_data_refresh_events() {
*
* @return array
*/
- public function data_get_config_provider() {
+ public static function data_get_config_provider(): array {
$initialdata = (object) [
'template_foo' => true,
'template_bar' => false,
@@ -837,7 +837,7 @@ public function test_data_get_config($funcargs, $expectation) {
*
* @return array
*/
- public function data_set_config_provider() {
+ public static function data_set_config_provider(): array {
$basevalue = (object) ['id' => rand(1, 1000)];
$config = [
'template_foo' => true,
@@ -2141,7 +2141,7 @@ public function test_data_append_new_field_to_templates(bool $hasfield, bool $ha
*
* @return array of scenarios
*/
- public function data_append_new_field_to_templates_provider(): array {
+ public static function data_append_new_field_to_templates_provider(): array {
return [
'Plain template' => [
'hasfield' => false,
diff --git a/mod/data/tests/locallib_test.php b/mod/data/tests/locallib_test.php
index 2374a1ee152c0..f52e2c740fd3f 100644
--- a/mod/data/tests/locallib_test.php
+++ b/mod/data/tests/locallib_test.php
@@ -96,6 +96,101 @@ public function test_data_search_entries() {
$this->assert_record_entries_contains($records, $captionfield->field->id, 'caption');
}
+ /**
+ * Confirms that search is working with groups
+ * @covers ::data_search_entries
+ */
+ public function test_data_search_entries_with_groups(): void {
+ $this->resetAfterTest();
+ $this->setAdminUser();
+ $course = $this->getDataGenerator()->create_course(['groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1]);
+ $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+ $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
+ $student1 = $this->getDataGenerator()->create_and_enrol($course);
+ $student2 = $this->getDataGenerator()->create_and_enrol($course);
+ $student3 = $this->getDataGenerator()->create_and_enrol($course);
+ $teacher1 = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+ $teacher2 = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+ $teacher3 = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+ groups_add_member($group1->id, $student1->id);
+ groups_add_member($group1->id, $teacher1->id);
+ groups_add_member($group2->id, $student3->id);
+ groups_add_member($group2->id, $teacher3->id);
+
+ $record = new \stdClass();
+ $record->course = $course->id;
+ $record->name = "Mod data delete test";
+ $record->intro = "Some intro of some sort";
+ $module = $this->getDataGenerator()->create_module('data', $record);
+ $titlefield = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_field(
+ (object) [
+ 'name' => 'title',
+ 'type' => 'text',
+ 'required' => 1,
+ ],
+ $module);
+ $captionfield = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_field(
+ (object) [
+ 'name' => 'caption',
+ 'type' => 'text',
+ 'required' => 1,
+ ],
+ $module);
+ $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($module, [
+ $titlefield->field->id => 'Entry 1 - group 1',
+ $captionfield->field->id => 'caption',
+ ],
+ $group1->id,
+ [],
+ null,
+ $student1->id
+ );
+ $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($module, [
+ $titlefield->field->id => 'Entry 2 - group 1',
+ $captionfield->field->id => 'caption',
+ ],
+ $group1->id,
+ [],
+ null,
+ $student1->id
+ );
+ $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($module, [
+ $titlefield->field->id => 'Entry 3 - group 2',
+ $captionfield->field->id => '',
+ ],
+ $group2->id,
+ [],
+ null,
+ $student3->id
+ );
+ $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($module, [
+ $titlefield->field->id => 'Entry 3 - no group',
+ $captionfield->field->id => '',
+ ],
+ 0,
+ [],
+ null,
+ $student2->id
+ );
+ $cm = get_coursemodule_from_id('data', $module->cmid);
+ $this->setUser($teacher1);
+ // As a non editing teacher in group 1, I should see only the entries for group 1.
+ list($records, $maxcount, $totalcount, $page, $nowperpage, $sort, $mode) =
+ data_search_entries($module, $cm, \context_course::instance($course->id), 'list', $group1->id);
+ $this->assertCount(3, $records); // Record with group 1 and record with no group.
+ // As a non editing teacher not in a group, I should see the entry from users not in a group.
+ $this->setUser($teacher3);
+ list($records, $maxcount, $totalcount, $page, $nowperpage, $sort, $mode) =
+ data_search_entries($module, $cm, \context_course::instance($course->id), 'list', $group2->id);
+ $this->assertCount(2, $records); // Record with group 2 and record with no group.
+ // As a non editing teacher not in a group, I should see the entry from users not in a group.
+ $this->setUser($teacher2);
+ list($records, $maxcount, $totalcount, $page, $nowperpage, $sort, $mode) =
+ data_search_entries($module, $cm, \context_course::instance($course->id), 'list', 0);
+ $this->assertCount(1, $records); // Just the record with no group.
+ $this->assert_record_entries_contains($records, $titlefield->field->id, 'Entry 3 - no group');
+ }
+
/**
* Assert that all records contains a value for the matching field id.
*
diff --git a/mod/data/tests/manager_test.php b/mod/data/tests/manager_test.php
index 5dcc4a3849b6f..14d8067b961bb 100644
--- a/mod/data/tests/manager_test.php
+++ b/mod/data/tests/manager_test.php
@@ -482,7 +482,7 @@ public function test_can_view_preset(string $rolename, bool $ownpreset, ?bool $u
*
* @return array
*/
- public function can_view_preset_provider(): array {
+ public static function can_view_preset_provider(): array {
return [
// User presets.
'Teacher owned preset without user id param' => [
@@ -737,7 +737,7 @@ public function test_reset_template(string $templatetoreset, array $expected) {
*
* @return array
*/
- public function reset_template_provider(): array {
+ public static function reset_template_provider(): array {
return [
// User presets.
'listtemplate' => [
diff --git a/mod/data/tests/preset_importer_test.php b/mod/data/tests/preset_importer_test.php
index 34cefbb5084fc..d99d3f37de640 100644
--- a/mod/data/tests/preset_importer_test.php
+++ b/mod/data/tests/preset_importer_test.php
@@ -28,14 +28,13 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \mod_data\local\importer\preset_importer
*/
-class preset_importer_test extends \advanced_testcase {
-
+final class preset_importer_test extends \advanced_testcase {
/**
* Data provider for build providers for test_needs_mapping and test_set_affected_fields.
*
* @return array[]
*/
- public function preset_importer_provider(): array {
+ public static function preset_importer_provider(): array {
// Image gallery preset is: ['title' => 'text', 'description' => 'textarea', 'image' => 'picture'];
$titlefield = new \stdClass();
@@ -107,8 +106,8 @@ public function preset_importer_provider(): array {
*
* @return array[]
*/
- public function needs_mapping_provider(): array {
- $basedprovider = $this->preset_importer_provider();
+ public static function needs_mapping_provider(): array {
+ $basedprovider = static::preset_importer_provider();
$basedprovider['Empty database / Empty importer']['needsmapping'] = false;
$basedprovider['Empty database / Importer with fields']['needsmapping'] = false;
@@ -182,8 +181,8 @@ public function test_needs_mapping(
*
* @return array[]
*/
- public function set_affected_provider(): array {
- $basedprovider = $this->preset_importer_provider();
+ public static function set_affected_provider(): array {
+ $basedprovider = static::preset_importer_provider();
$basedprovider['Empty database / Empty importer']['fieldstocreate'] = 0;
$basedprovider['Empty database / Empty importer']['fieldstoremove'] = 0;
@@ -353,7 +352,7 @@ public function test_get_mapping_information(
*
* @return array[]
*/
- public function get_field_names_provider(): array {
+ public static function get_field_names_provider(): array {
return [
'Empty list' => [
'fields' => [],
diff --git a/mod/data/tests/preset_test.php b/mod/data/tests/preset_test.php
index 37f985667036f..018e6bdf3b6bb 100644
--- a/mod/data/tests/preset_test.php
+++ b/mod/data/tests/preset_test.php
@@ -495,7 +495,7 @@ public function test_is_directory_a_preset(string $directory, bool $expected): v
*
* @return array
*/
- public function is_directory_a_preset_provider(): array {
+ public static function is_directory_a_preset_provider(): array {
global $CFG;
return [
@@ -608,7 +608,7 @@ public function test_generate_preset_xml(array $params, ?string $description) {
*
* @return array
*/
- public function generate_preset_xml_provider(): array {
+ public static function generate_preset_xml_provider(): array {
return [
'Generate preset.xml with the default params and empty description' => [
'params' => [],
diff --git a/mod/data/tests/template_test.php b/mod/data/tests/template_test.php
index 31f2878f9cc0c..c0b86d72236ae 100644
--- a/mod/data/tests/template_test.php
+++ b/mod/data/tests/template_test.php
@@ -173,7 +173,7 @@ public function test_parse_entries(
*
* @return array of scenarios
*/
- public function parse_entries_provider(): array {
+ public static function parse_entries_provider(): array {
return [
// Teacher scenarios.
'Teacher id tag' => [
@@ -928,7 +928,7 @@ public function test_parse_add_entry(
*
* @return array of scenarios
*/
- public function parse_add_entry_provider(): array {
+ public static function parse_add_entry_provider(): array {
return [
// Editing an entry.
'Teacher editing entry tags tag' => [
diff --git a/mod/feedback/tests/behat/feedback_activity_completion.feature b/mod/feedback/tests/behat/feedback_activity_completion.feature
index cc3a3a3523a5b..9e66b57e17cf3 100644
--- a/mod/feedback/tests/behat/feedback_activity_completion.feature
+++ b/mod/feedback/tests/behat/feedback_activity_completion.feature
@@ -34,12 +34,12 @@ Feature: View activity completion in the feedback activity
| Multiple choice values | drums\guitar\hurdygurdy |
And I log out
- Scenario: View automatic completion items as a teacher
+ Scenario: Feedback module displays completion conditions to teachers
When I am on the "Music history" "feedback activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
And "Music history" should have the "Submit feedback" completion condition
- Scenario: View automatic completion items as a student
+ Scenario: Student can complete a feedback activity when all conditions are met
Given I am on the "Music history" "feedback activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "todo"
And the "Submit feedback" completion condition of "Music history" is displayed as "todo"
@@ -52,7 +52,7 @@ Feature: View activity completion in the feedback activity
And the "Submit feedback" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the feedback activity as done but a teacher cannot
Given I am on the "Music history" "feedback 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"
diff --git a/mod/feedback/tests/custom_completion_test.php b/mod/feedback/tests/custom_completion_test.php
index 3719b411588a0..630b063dc3aba 100644
--- a/mod/feedback/tests/custom_completion_test.php
+++ b/mod/feedback/tests/custom_completion_test.php
@@ -51,7 +51,7 @@ class custom_completion_test extends advanced_testcase {
*
* @return array[]
*/
- public function get_state_provider(): array {
+ public static function get_state_provider(): array {
return [
'Undefined rule' => [
'somenonexistentrule', COMPLETION_DISABLED, false, null, coding_exception::class
@@ -174,7 +174,7 @@ public function test_is_defined() {
*
* @return array[]
*/
- public function get_available_custom_rules_provider(): array {
+ public static function get_available_custom_rules_provider(): array {
return [
'Completion submit available' => [
COMPLETION_ENABLED, ['completionsubmit']
diff --git a/mod/feedback/tests/dates_test.php b/mod/feedback/tests/dates_test.php
index f37ba28a05f06..b9c6528238610 100644
--- a/mod/feedback/tests/dates_test.php
+++ b/mod/feedback/tests/dates_test.php
@@ -43,7 +43,7 @@ class dates_test extends advanced_testcase {
* Data provider for get_dates_for_module().
* @return array[]
*/
- public function get_dates_for_module_provider(): array {
+ public static function get_dates_for_module_provider(): array {
$now = time();
$before = $now - DAYSECS;
$earlier = $before - DAYSECS;
diff --git a/mod/feedback/tests/form/create_template_form_test.php b/mod/feedback/tests/form/create_template_form_test.php
index 268db0b281caa..ae56cce41f72a 100644
--- a/mod/feedback/tests/form/create_template_form_test.php
+++ b/mod/feedback/tests/form/create_template_form_test.php
@@ -102,7 +102,7 @@ public function test_createtemplate_form_with_modified_capabilities(array $unass
*
* @return array
*/
- public function createtemplate_form_with_modified_capabilities_provider(): array {
+ public static function createtemplate_form_with_modified_capabilities_provider(): array {
return [
"Manager without edititems permission cannot create any templates" => [
['mod/feedback:edititems'], false
@@ -180,7 +180,7 @@ public function test_createtemplate_form(string $loginas, bool $public,
*
* @return array
*/
- public function createtemplate_form_provider(): array {
+ public static function createtemplate_form_provider(): array {
return [
'Create a private template as an admin' => [
'admin', false
diff --git a/mod/feedback/tests/form/use_template_form_test.php b/mod/feedback/tests/form/use_template_form_test.php
index f57fe7d4aaec9..d5637b8d21ee4 100644
--- a/mod/feedback/tests/form/use_template_form_test.php
+++ b/mod/feedback/tests/form/use_template_form_test.php
@@ -100,7 +100,7 @@ public function test_usetemplate_form(string $loginas, bool $private, bool $expe
*
* @return array
*/
- public function usetemplate_form_provider() {
+ public static function usetemplate_form_provider(): array {
return [
'Test submission with a private template as an admin' => [
'admin', true, true
diff --git a/mod/folder/tests/behat/folder_activity_completion.feature b/mod/folder/tests/behat/folder_activity_completion.feature
index 04cf1332a1de8..69b0fc4ad8bcf 100644
--- a/mod/folder/tests/behat/folder_activity_completion.feature
+++ b/mod/folder/tests/behat/folder_activity_completion.feature
@@ -19,7 +19,7 @@ Feature: View activity completion information in the folder activity
| teacher1 | C1 | editingteacher |
| student1 | C2 | student |
- Scenario: View automatic completion items
+ Scenario: A folder is automatically completed when a student views it
Given the following "activity" exists:
| activity | folder |
| course | C1 |
@@ -37,7 +37,7 @@ Feature: View activity completion information in the folder activity
Then the "View" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the folder activity as done but a teacher cannot
Given the following "activity" exists:
| activity | folder |
| course | C1 |
diff --git a/mod/folder/tests/lib_test.php b/mod/folder/tests/lib_test.php
index 15825f7388dc9..b0b1c17adffb2 100644
--- a/mod/folder/tests/lib_test.php
+++ b/mod/folder/tests/lib_test.php
@@ -376,7 +376,7 @@ public function test_folder_get_recent_mod_activity(int $forcedownload, bool $ha
*
* @return array
*/
- public function folder_get_recent_mod_activity_provider(): array {
+ public static function folder_get_recent_mod_activity_provider(): array {
return [
'Teacher with force download' => [
'forcedownload' => 1,
diff --git a/mod/forum/tests/backup_forum_activity_task_test.php b/mod/forum/tests/backup_forum_activity_task_test.php
index d0990a31d462a..28c021717e5fe 100644
--- a/mod/forum/tests/backup_forum_activity_task_test.php
+++ b/mod/forum/tests/backup_forum_activity_task_test.php
@@ -49,7 +49,7 @@ public function test_encode_content_links($content, $expectation) {
$this->assertEquals($expectation, backup_forum_activity_task::encode_content_links($content));
}
- public function encode_content_links_provider() {
+ public static function encode_content_links_provider(): array {
global $CFG;
$altwwwroot = 'http://invalid.example.com/';
return [
diff --git a/mod/forum/tests/behat/add_forum.feature b/mod/forum/tests/behat/add_forum.feature
index e88dd30c7e3eb..36b1158e34015 100644
--- a/mod/forum/tests/behat/add_forum.feature
+++ b/mod/forum/tests/behat/add_forum.feature
@@ -43,6 +43,10 @@ Feature: Add forum activities and discussions
And I follow "Edit"
And the field "Attachment" matches value "empty.txt"
+ # Check the page that lists all the forums in a course.
+ And I am on the "C1" "forum index" page
+ And I should see "Test forum name"
+
@javascript
Scenario: Test forum settings validation
Given the following "courses" exist:
diff --git a/mod/forum/tests/behat/forum_activity_completion.feature b/mod/forum/tests/behat/forum_activity_completion.feature
index 1b566755ab148..78e102fa52cdf 100644
--- a/mod/forum/tests/behat/forum_activity_completion.feature
+++ b/mod/forum/tests/behat/forum_activity_completion.feature
@@ -39,7 +39,7 @@ Feature: View activity completion in the forum activity
And I press "Save and display"
@javascript
- Scenario: View automatic completion items as a teacher
+ Scenario: Forum module displays automatic completion conditions to teachers
When I am on the "Music history" "forum activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
And "Music history" should have the "Start discussions: 1" completion condition
@@ -48,7 +48,7 @@ Feature: View activity completion in the forum activity
And "Music history" should have the "Receive a grade" completion condition
@javascript
- Scenario: View automatic completion items as a student
+ Scenario: A student can complete a forum activity by meeting the completion conditions
Given I am on the "Music history" "forum activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Start discussions: 1" completion condition of "Music history" is displayed as "todo"
@@ -88,7 +88,7 @@ Feature: View activity completion in the forum activity
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the forum activity as done but a teacher cannot
Given I am on the "Music history" "forum 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"
diff --git a/mod/forum/tests/behat/forum_activity_completion_pass_grade.feature b/mod/forum/tests/behat/forum_activity_completion_pass_grade.feature
index 9e9f4e613d24c..d820c90adf3f4 100644
--- a/mod/forum/tests/behat/forum_activity_completion_pass_grade.feature
+++ b/mod/forum/tests/behat/forum_activity_completion_pass_grade.feature
@@ -39,7 +39,7 @@ Feature: Completion pass grade view activity completion in the forum activity
| completionreplies | 1 |
And I press "Save and display"
- Scenario: View automatic completion items as a teacher
+ Scenario: Forum module displays completion conditions to teachers
Given I am on the "Music history" "forum activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
And "Music history" should have the "Start discussions: 1" completion condition
@@ -49,7 +49,7 @@ Feature: Completion pass grade view activity completion in the forum activity
And "Music history" should have the "Receive a passing grade" completion condition
@javascript
- Scenario: View automatic completion items as a failing student
+ Scenario: Student cannot complete a forum activity if one of the conditions are not met
Given I am on the "Music history" "forum activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Start discussions: 1" completion condition of "Music history" is displayed as "todo"
@@ -93,7 +93,7 @@ Feature: Completion pass grade view activity completion in the forum activity
And the "Receive a passing grade" completion condition of "Music history" is displayed as "failed"
@javascript
- Scenario: View automatic completion items as a passing student
+ Scenario: Student can complete a forum activity when all conditions are met
Given I am on the "Music history" "forum activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Start discussions: 1" completion condition of "Music history" is displayed as "todo"
diff --git a/mod/forum/tests/custom_completion_test.php b/mod/forum/tests/custom_completion_test.php
index 0f7fd08085445..1d5df101112d2 100644
--- a/mod/forum/tests/custom_completion_test.php
+++ b/mod/forum/tests/custom_completion_test.php
@@ -55,7 +55,7 @@ class custom_completion_test extends advanced_testcase {
*
* @return array[]
*/
- public function get_state_provider(): array {
+ public static function get_state_provider(): array {
return [
'Undefined rule' => [
'somenonexistentrule', 0, COMPLETION_TRACKING_NONE, 0, 0, 0, null, coding_exception::class
@@ -214,7 +214,7 @@ public function test_is_defined() {
*
* @return array[]
*/
- public function get_available_custom_rules_provider(): array {
+ public static function get_available_custom_rules_provider(): array {
return [
'Completion discussions available' => [
COMPLETION_ENABLED, ['completiondiscussions']
diff --git a/mod/forum/tests/dates_test.php b/mod/forum/tests/dates_test.php
index 6a304e3e86777..79a9a04a30005 100644
--- a/mod/forum/tests/dates_test.php
+++ b/mod/forum/tests/dates_test.php
@@ -43,7 +43,7 @@ class dates_test extends advanced_testcase {
* Data provider for get_dates_for_module().
* @return array[]
*/
- public function get_dates_for_module_provider(): array {
+ public static function get_dates_for_module_provider(): array {
$now = time();
$before = $now - DAYSECS;
$after = $now + DAYSECS;
diff --git a/mod/forum/tests/entities_discussion_test.php b/mod/forum/tests/entities_discussion_test.php
index 4a0dccfaefc37..f4b448af8ce33 100644
--- a/mod/forum/tests/entities_discussion_test.php
+++ b/mod/forum/tests/entities_discussion_test.php
@@ -159,7 +159,7 @@ public function test_display_period_settings($testdescription, $startoffset, $en
*
* @return array start/end time offsets and the expected results.
*/
- public function diplay_period_options_provider() {
+ public static function diplay_period_options_provider(): array {
return array(
["No dates set", 0, 0, true, false, true],
["Only started date in the future", 100, 0, false, false, false],
diff --git a/mod/forum/tests/exporters_post_test.php b/mod/forum/tests/exporters_post_test.php
index ef2c33a51cdcc..8387b834b2723 100644
--- a/mod/forum/tests/exporters_post_test.php
+++ b/mod/forum/tests/exporters_post_test.php
@@ -201,7 +201,7 @@ public function test_export_post($istimed = false, $addtime = 0) {
*
* @return array
*/
- public function export_post_provider(): array {
+ public static function export_post_provider(): array {
return [
'Simple export' => [
],
diff --git a/mod/forum/tests/grade/forum_gradeitem_test.php b/mod/forum/tests/grade/forum_gradeitem_test.php
index 86d9c6ee1d888..3d62c316ea1c8 100644
--- a/mod/forum/tests/grade/forum_gradeitem_test.php
+++ b/mod/forum/tests/grade/forum_gradeitem_test.php
@@ -216,7 +216,7 @@ public function test_should_grade_only_active_users(bool $showonlyactiveenrolcon
*
* @return array
*/
- public function should_grade_only_active_users_provider(): array {
+ public static function should_grade_only_active_users_provider(): array {
return [
'Enabled showonlyactiveenrol setting; enabled showonlyactiveenrol preference; view suspended users capability' =>
[
diff --git a/mod/forum/tests/grade/gradeitems_test.php b/mod/forum/tests/grade/gradeitems_test.php
index 404791ac8a4f8..1bbe060d919c0 100644
--- a/mod/forum/tests/grade/gradeitems_test.php
+++ b/mod/forum/tests/grade/gradeitems_test.php
@@ -77,7 +77,7 @@ public function test_is_advancedgrading_itemname(string $itemname, bool $expecte
*
* @return array
*/
- public function is_advancedgrading_itemname_provider(): array {
+ public static function is_advancedgrading_itemname_provider(): array {
return [
'rating is not advanced' => [
'rating',
diff --git a/mod/forum/tests/h5p/canedit_test.php b/mod/forum/tests/h5p/canedit_test.php
index 1973bf8eeb64e..2602f615fd360 100644
--- a/mod/forum/tests/h5p/canedit_test.php
+++ b/mod/forum/tests/h5p/canedit_test.php
@@ -123,7 +123,7 @@ public function test_can_edit_content(string $currentuser, string $fileauthor, s
*
* @return array
*/
- public function can_edit_content_provider(): array {
+ public static function can_edit_content_provider(): array {
return [
// Component = mod_forum.
'mod_forum: Admin user is author' => [
diff --git a/mod/forum/tests/lib_test.php b/mod/forum/tests/lib_test.php
index 2624f053abe8d..979270ef8198d 100644
--- a/mod/forum/tests/lib_test.php
+++ b/mod/forum/tests/lib_test.php
@@ -3272,7 +3272,7 @@ public function test_forum_discussion_is_locked($forum, $discussion, $expect) {
*
* @return array
*/
- public function forum_discussion_is_locked_provider() {
+ public static function forum_discussion_is_locked_provider(): array {
return [
'Unlocked: lockdiscussionafter is false' => [
['lockdiscussionafter' => false],
@@ -3326,7 +3326,7 @@ public function test_forum_is_cutoff_date_reached($forum, $expect) {
*
* @return array
*/
- public function forum_is_cutoff_date_reached_provider() {
+ public static function forum_is_cutoff_date_reached_provider(): array {
$now = time();
return [
'cutoffdate is unset' => [
@@ -3374,7 +3374,7 @@ public function test_forum_is_due_date_reached($forum, $expect) {
*
* @return array
*/
- public function forum_is_due_date_reached_provider() {
+ public static function forum_is_due_date_reached_provider(): array {
$now = time();
return [
'duedate is unset' => [
@@ -4121,7 +4121,7 @@ public function test_forum_get_layout_modes() {
*
* @return array
*/
- public function forum_check_throttling_early_returns_provider() {
+ public static function forum_check_throttling_early_returns_provider(): array {
return [
'Empty blockafter' => [(object)['id' => 1, 'course' => SITEID, 'blockafter' => 0]],
'Empty blockperiod' => [(object)['id' => 1, 'course' => SITEID, 'blockafter' => DAYSECS, 'blockperiod' => 0]],
@@ -4144,7 +4144,7 @@ public function test_forum_check_throttling_early_returns(\stdClass $forum) {
*
* @return array
*/
- public function forum_check_throttling_early_exceptions_provider() {
+ public static function forum_check_throttling_early_exceptions_provider(): array {
return [
'Non-object forum' => ['a'],
'Forum ID not set' => [(object)['id' => false]],
diff --git a/mod/forum/tests/mail_test.php b/mod/forum/tests/mail_test.php
index d1bfe8af0c30b..f6d949604b36a 100644
--- a/mod/forum/tests/mail_test.php
+++ b/mod/forum/tests/mail_test.php
@@ -994,7 +994,7 @@ public function test_subjects() {
/**
* dataProvider for test_forum_post_email_templates().
*/
- public function forum_post_email_templates_provider() {
+ public static function forum_post_email_templates_provider(): array {
// Base information, we'll build variations based on it.
$base = array(
'user' => array('firstname' => 'Love', 'lastname' => 'Moodle', 'mailformat' => 0, 'maildigest' => 0),
diff --git a/mod/forum/tests/output_email_test.php b/mod/forum/tests/output_email_test.php
index 1169e2e032c76..1c997632677c7 100644
--- a/mod/forum/tests/output_email_test.php
+++ b/mod/forum/tests/output_email_test.php
@@ -29,7 +29,7 @@ class output_email_test extends \advanced_testcase {
/**
* Data provider for the postdate function tests.
*/
- public function postdate_provider() {
+ public static function postdate_provider(): array {
return array(
'Timed discussions disabled, timestart unset' => array(
'globalconfig' => array(
diff --git a/mod/forum/tests/subscriptions_test.php b/mod/forum/tests/subscriptions_test.php
index 6fcb5ee4eb0d4..bfa78fb6cfe1e 100644
--- a/mod/forum/tests/subscriptions_test.php
+++ b/mod/forum/tests/subscriptions_test.php
@@ -1353,7 +1353,7 @@ public function test_is_subscribed_cm() {
$this->assertGreaterThan($suppliedcmcount, $calculatedcmcount);
}
- public function is_subscribable_forums() {
+ public static function is_subscribable_forums(): array {
return [
[
'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE,
@@ -1370,9 +1370,9 @@ public function is_subscribable_forums() {
];
}
- public function is_subscribable_provider() {
+ public static function is_subscribable_provider(): array {
$data = [];
- foreach ($this->is_subscribable_forums() as $forum) {
+ foreach (self::is_subscribable_forums() as $forum) {
$data[] = [$forum];
}
@@ -1411,7 +1411,7 @@ public function test_is_subscribable_is_guest($options) {
$this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
}
- public function is_subscribable_loggedin_provider() {
+ public static function is_subscribable_loggedin_provider(): array {
return [
[
['forcesubscribe' => FORUM_DISALLOWSUBSCRIBE],
diff --git a/mod/glossary/tests/behat/glossary_activity_completion.feature b/mod/glossary/tests/behat/glossary_activity_completion.feature
index e7e8c966850c0..211b8615cdbae 100644
--- a/mod/glossary/tests/behat/glossary_activity_completion.feature
+++ b/mod/glossary/tests/behat/glossary_activity_completion.feature
@@ -36,13 +36,13 @@ Feature: View activity completion in the glossary activity
And I press "Save and display"
And I log out
- Scenario: View automatic completion items as a teacher
+ Scenario: View glossary automatic completion conditions as a teacher
Given I am on the "Music history" "glossary activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
And "Music history" should have the "Make entries: 1" completion condition
And "Music history" should have the "Receive a grade" completion condition
- Scenario: View automatic completion items as a student
+ Scenario: A student completes a glossary
Given I am on the "Music history" "glossary activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "todo"
@@ -67,7 +67,7 @@ Feature: View activity completion in the glossary activity
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the glossary activity as done but a teacher cannot
Given I am on the "Music history" "glossary 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"
diff --git a/mod/glossary/tests/behat/glossary_activity_completion_pass_grade.feature b/mod/glossary/tests/behat/glossary_activity_completion_pass_grade.feature
index bc7be369a25e4..a6a70e830a64e 100644
--- a/mod/glossary/tests/behat/glossary_activity_completion_pass_grade.feature
+++ b/mod/glossary/tests/behat/glossary_activity_completion_pass_grade.feature
@@ -38,7 +38,7 @@ Feature: Pass grade completion in the glossary activity
And I press "Save and display"
And I log out
- Scenario: View automatic completion items as a teacher
+ Scenario: A teacher can view a glossary activity completion conditions
Given I log in as "teacher1"
And I am on "Course 1" course homepage
When I follow "Music history"
@@ -47,7 +47,7 @@ Feature: Pass grade completion in the glossary activity
And "Music history" should have the "Receive a grade" completion condition
And "Music history" should have the "Receive a passing grade" completion condition
- Scenario: View automatic completion items as a failing student
+ Scenario: A student will not complete a glossary activity if the conditions are not met
Given I am on the "Music history" "glossary activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "todo"
@@ -75,7 +75,7 @@ Feature: Pass grade completion in the glossary activity
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
And the "Receive a passing grade" completion condition of "Music history" is displayed as "failed"
- Scenario: View automatic completion items as a passing student
+ Scenario: A student can complete a glossary activity by meeting the completion conditions
Given I am on the "Music history" "glossary activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "todo"
diff --git a/mod/glossary/tests/concept_cache_test.php b/mod/glossary/tests/concept_cache_test.php
index 010f066fee4b3..63745d5b48ecb 100644
--- a/mod/glossary/tests/concept_cache_test.php
+++ b/mod/glossary/tests/concept_cache_test.php
@@ -68,13 +68,13 @@ public function test_concept_fetching() {
$concepts1 = \mod_glossary\local\concept_cache::get_concepts($course1->id);
$this->assertCount(3, $concepts1[0]);
- $this->arrayHasKey($concepts1[0], $glossary1a->id);
- $this->arrayHasKey($concepts1[0], $glossary1b->id);
- $this->arrayHasKey($concepts1[0], $glossary3->id);
+ $this->assertArrayHasKey($glossary1a->id, $concepts1[0]);
+ $this->assertArrayHasKey($glossary1b->id, $concepts1[0]);
+ $this->assertArrayHasKey($glossary3->id, $concepts1[0]);
$this->assertCount(3, $concepts1[1]);
- $this->arrayHasKey($concepts1[1], $glossary1a->id);
- $this->arrayHasKey($concepts1[1], $glossary1b->id);
- $this->arrayHasKey($concepts1[0], $glossary3->id);
+ $this->assertArrayHasKey($glossary1a->id, $concepts1[1]);
+ $this->assertArrayHasKey($glossary1b->id, $concepts1[1]);
+ $this->assertArrayHasKey($glossary3->id, $concepts1[1]);
$this->assertCount(5, $concepts1[1][$glossary1a->id]);
foreach($concepts1[1][$glossary1a->id] as $concept) {
$this->assertSame(array('id', 'glossaryid', 'concept', 'casesensitive', 'category', 'fullmatch'), array_keys((array)$concept));
@@ -131,9 +131,9 @@ public function test_concept_fetching() {
$concepts3 = \mod_glossary\local\concept_cache::get_concepts($site->id);
$this->assertCount(1, $concepts3[0]);
- $this->arrayHasKey($concepts3[0], $glossary3->id);
+ $this->assertArrayHasKey($glossary3->id, $concepts3[0]);
$this->assertCount(1, $concepts3[1]);
- $this->arrayHasKey($concepts3[0], $glossary3->id);
+ $this->assertArrayHasKey($glossary3->id, $concepts3[1]);
foreach($concepts3[1][$glossary3->id] as $concept) {
$this->assertSame(array('id', 'glossaryid', 'concept', 'casesensitive', 'category', 'fullmatch'), array_keys((array)$concept));
if ($concept->concept === 'global') {
diff --git a/mod/glossary/tests/custom_completion_test.php b/mod/glossary/tests/custom_completion_test.php
index c9af3d71cd76e..87d7cd2ec70b6 100644
--- a/mod/glossary/tests/custom_completion_test.php
+++ b/mod/glossary/tests/custom_completion_test.php
@@ -51,7 +51,7 @@ class custom_completion_test extends advanced_testcase {
*
* @return array[]
*/
- public function get_state_provider(): array {
+ public static function get_state_provider(): array {
return [
'Undefined rule' => [
'somenonexistentrule', COMPLETION_DISABLED, 0, null, coding_exception::class
@@ -174,7 +174,7 @@ public function test_is_defined() {
*
* @return array[]
*/
- public function get_available_custom_rules_provider(): array {
+ public static function get_available_custom_rules_provider(): array {
return [
'Completion submit available' => [
COMPLETION_ENABLED, ['completionentries']
diff --git a/mod/h5pactivity/tests/behat/h5pactivity_completion.feature b/mod/h5pactivity/tests/behat/h5pactivity_completion.feature
index 43b4c622beb8b..a6a216937051e 100644
--- a/mod/h5pactivity/tests/behat/h5pactivity_completion.feature
+++ b/mod/h5pactivity/tests/behat/h5pactivity_completion.feature
@@ -25,22 +25,7 @@ Feature: View activity completion information in the h5p activity
| completionusegrade | 1 |
| packagefilepath | h5p/tests/fixtures/filltheblanks.h5p |
- Scenario: View automatic completion items
- Given I change window size to "large"
- And I am on the "Music history" "h5pactivity activity" page logged in as teacher1
- # Teacher view.
- And "Music history" should have the "View" completion condition
- And "Music history" should have the "Receive a grade" completion condition
- # Student view.
- When I am on the "Music history" "h5pactivity activity" page logged in as student1
- And I switch to "h5p-player" class iframe
- And I switch to "h5p-iframe" class iframe
- And I click on "Check" "button" in the ".h5p-question-buttons" "css_element"
- And I reload the page
- Then the "View" completion condition of "Music history" is displayed as "done"
- And the "Receive a grade" completion condition of "Music history" is displayed as "done"
-
- Scenario: Use manual completion
+ Scenario: A student can manually mark the h5p activity as done but a teacher cannot
Given I am on the "Music history" "h5pactivity 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"
diff --git a/mod/h5pactivity/tests/behat/h5pactivity_completion_pass_grade.feature b/mod/h5pactivity/tests/behat/h5pactivity_completion_pass_grade.feature
index 9c1ff08bfef2e..4f1d9a8809d5c 100644
--- a/mod/h5pactivity/tests/behat/h5pactivity_completion_pass_grade.feature
+++ b/mod/h5pactivity/tests/behat/h5pactivity_completion_pass_grade.feature
@@ -1,5 +1,8 @@
-@mod @mod_h5pactivity @core_h5p @_file_upload @_switch_iframe @javascript @core_completion
-Feature: Pass grade activity completion information in the h5p activity
+@mod @mod_h5pactivity @core_h5p @_switch_iframe @core_completion
+Feature: Completion of H5P activity by achieving a passing grade
+ In order to complete an H5P activity
+ As a student
+ I need to be able to complete the h5p activity to receive a grade
Background:
Given the following "users" exist:
@@ -28,23 +31,36 @@ Feature: Pass grade activity completion information in the h5p activity
| gradepass | 25 |
| packagefilepath | h5p/tests/fixtures/filltheblanks.h5p |
- Scenario: View automatic completion items
- # Teacher view.
+ Scenario: Verify that the h5p completion conditions are displayed to teachers
Given I change window size to "large"
And I am on the "Music history" "h5pactivity activity" page logged in as teacher1
- And "Music history" should have the "View" completion condition
+ Then "Music history" should have the "View" completion condition
And "Music history" should have the "Receive a grade" completion condition
And "Music history" should have the "Receive a passing grade" completion condition
- And I log out
- # Student view.
- When I am on the "Music history" "h5pactivity activity" page logged in as student1
+
+ @javascript
+ Scenario: Verify that students can complete an H5P activity by achieving a passing grade
+ # Student 1 attempt the H5P and fills the blanks with the wrong answers... needs more geography lessons!
+ Given I am on the "Music history" "h5pactivity activity" page logged in as student1
And I switch to "h5p-player" class iframe
And I switch to "h5p-iframe" class iframe
+ And I should see "Of which countries are Berlin, Washington, Beijing, Canberra and Brasilia the capitals?"
+ And I set the field with xpath "//input[contains(@aria-label,\"Blank input 1 of 4\")]" to "Rio de Janeiro"
+ And I set the field with xpath "//input[contains(@aria-label,\"Blank input 2 of 4\")]" to "New York"
+ And I set the field with xpath "//input[contains(@aria-label,\"Blank input 3 of 4\")]" to "Hamburg"
+ And I set the field with xpath "//input[contains(@aria-label,\"Blank input 4 of 4\")]" to "Sydney"
And I click on "Check" "button" in the ".h5p-question-buttons" "css_element"
+ And I switch to the main frame
And I reload the page
+ And the "View" completion condition of "Music history" is displayed as "done"
+ And the "Receive a grade" completion condition of "Music history" is displayed as "done"
+ And the "Receive a passing grade" completion condition of "Music history" is displayed as "failed"
+
+ # Student 2 attempts the H5P and fills the blanks with the correct answers.
And I am on the "Music history" "h5pactivity activity" page logged in as student2
And I switch to "h5p-player" class iframe
And I switch to "h5p-iframe" class iframe
+ And I should see "Of which countries are Berlin, Washington, Beijing, Canberra and Brasilia the capitals?"
And I set the field with xpath "//input[contains(@aria-label,\"Blank input 1 of 4\")]" to "Brasilia"
And I set the field with xpath "//input[contains(@aria-label,\"Blank input 2 of 4\")]" to "Washington"
And I set the field with xpath "//input[contains(@aria-label,\"Blank input 3 of 4\")]" to "Berlin"
@@ -52,15 +68,12 @@ Feature: Pass grade activity completion information in the h5p activity
And I click on "Check" "button" in the ".h5p-question-buttons" "css_element"
And I switch to the main frame
And I reload the page
- Then the "View" completion condition of "Music history" is displayed as "done"
- And the "Receive a grade" completion condition of "Music history" is displayed as "done"
- And the "Receive a passing grade" completion condition of "Music history" is displayed as "done"
- And I log out
- And I am on the "Music history" "h5pactivity activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
- And the "Receive a passing grade" completion condition of "Music history" is displayed as "failed"
- And I am on the "Course 1" "course" page logged in as "teacher1"
- And "Vinnie Student1" user has completed "Music history" activity
+ And the "Receive a passing grade" completion condition of "Music history" is displayed as "done"
+
+ # Teacher confirms which students have completed the H5P activity.
+ When I am on the "Course 1" "course" page logged in as "teacher1"
+ Then "Vinnie Student1" user has completed "Music history" activity
And "Vinnie Student2" user has completed "Music history" activity
And "Vinnie Student3" user has not completed "Music history" activity
diff --git a/mod/h5pactivity/tests/event/report_viewed_test.php b/mod/h5pactivity/tests/event/report_viewed_test.php
index afb5703b70a1f..a5de5faf978f2 100644
--- a/mod/h5pactivity/tests/event/report_viewed_test.php
+++ b/mod/h5pactivity/tests/event/report_viewed_test.php
@@ -114,7 +114,7 @@ public function test_report_viewed(bool $usea, bool $useattemptid, bool $useuser
*
* @return array
*/
- public function report_viewed_data(): array {
+ public static function report_viewed_data(): array {
return [
// Exception cases.
'Event withour other data (exception)' => [
diff --git a/mod/h5pactivity/tests/external/get_attempts_test.php b/mod/h5pactivity/tests/external/get_attempts_test.php
index 37529651fadd5..a519e3a59ce1a 100644
--- a/mod/h5pactivity/tests/external/get_attempts_test.php
+++ b/mod/h5pactivity/tests/external/get_attempts_test.php
@@ -154,7 +154,7 @@ public function test_execute(int $grademethod, string $loginuser, ?string $parti
*
* @return array
*/
- public function execute_data(): array {
+ public static function execute_data(): array {
return [
// Teacher checking a user with attempts.
'Manual grade, Teacher asking participant with attempts' => [
@@ -458,7 +458,7 @@ public function test_execute_multipleusers(string $loginuser, array $participant
*
* @return array
*/
- public function execute_multipleusers_data(): array {
+ public static function execute_multipleusers_data(): array {
return [
// Teacher checks.
'Teacher checking students with attempts' => [
diff --git a/mod/h5pactivity/tests/external/get_h5pactivity_access_information_test.php b/mod/h5pactivity/tests/external/get_h5pactivity_access_information_test.php
index 25760d2920003..4b80f485fc125 100644
--- a/mod/h5pactivity/tests/external/get_h5pactivity_access_information_test.php
+++ b/mod/h5pactivity/tests/external/get_h5pactivity_access_information_test.php
@@ -90,7 +90,7 @@ public function test_get_h5pactivity_access_information(string $role, int $enabl
*
* @return array
*/
- public function get_h5pactivity_access_information_data(): array {
+ public static function get_h5pactivity_access_information_data(): array {
return [
'Admin, tracking enabled' => [
'', 1, ['canview', 'canreviewattempts', 'canaddinstance']
diff --git a/mod/h5pactivity/tests/external/get_results_test.php b/mod/h5pactivity/tests/external/get_results_test.php
index fffa4f3a16df5..315240d7f4d55 100644
--- a/mod/h5pactivity/tests/external/get_results_test.php
+++ b/mod/h5pactivity/tests/external/get_results_test.php
@@ -146,7 +146,7 @@ public function test_execute(int $enabletracking, int $reviewmode, string $login
*
* @return array
*/
- public function execute_data(): array {
+ public static function execute_data(): array {
return [
'Teacher reviewing an attempt' => [
1, manager::REVIEWCOMPLETION, 'editingteacher', 'student', true, 1
@@ -277,7 +277,7 @@ public function test_execute_multipleattempts(string $loginuser,
*
* @return array
*/
- public function execute_multipleattempts_data(): array {
+ public static function execute_multipleattempts_data(): array {
return [
// Teacher cases.
'Teacher reviewing students attempts' => [
@@ -408,7 +408,7 @@ public function test_execute_mixactivities(string $activityname, string $attempt
*
* @return array
*/
- public function execute_mixactivities_data(): array {
+ public static function execute_mixactivities_data(): array {
return [
// Teacher cases.
'Correct activity id' => [
diff --git a/mod/h5pactivity/tests/external/get_user_attempts_test.php b/mod/h5pactivity/tests/external/get_user_attempts_test.php
index 2f0a344d7cb69..cfe51ba6dd171 100644
--- a/mod/h5pactivity/tests/external/get_user_attempts_test.php
+++ b/mod/h5pactivity/tests/external/get_user_attempts_test.php
@@ -145,7 +145,7 @@ public function test_execute_multipleusers(string $loginuser, array $participant
*
* @return array
*/
- public function execute_multipleusers_data(): array {
+ public static function execute_multipleusers_data(): array {
return [
// Teacher checks.
'Teacher checking students with attempts' => [
@@ -188,7 +188,7 @@ public function execute_multipleusers_data(): array {
*
* @return array[]
*/
- public function execute_with_sortorder(): array {
+ public static function execute_with_sortorder(): array {
return [
'Sort by id' => ['id', ['user01', 'user02']],
'Sort by id desc' => ['id desc', ['user02', 'user01']],
diff --git a/mod/h5pactivity/tests/local/attempt_test.php b/mod/h5pactivity/tests/local/attempt_test.php
index c1a2518c74e1d..33e284051e614 100644
--- a/mod/h5pactivity/tests/local/attempt_test.php
+++ b/mod/h5pactivity/tests/local/attempt_test.php
@@ -180,7 +180,7 @@ public function test_save_statement(string $subcontent, bool $hasdefinition, boo
*
* @return array
*/
- public function save_statement_data(): array {
+ public static function save_statement_data(): array {
return [
'Statement without definition and result' => [
'', false, false, [false, 0, 0, 0, 0, null, null]
@@ -312,7 +312,7 @@ public function test_delete_all_attempts(bool $hasstudent, array $results) {
*
* @return array
*/
- public function delete_all_attempts_data(): array {
+ public static function delete_all_attempts_data(): array {
return [
'Delete all attempts from activity' => [
false, [0, 0, 2, 2, 2, 4]
@@ -413,7 +413,7 @@ public function test_basic_setters(string $attribute, int $oldvalue, int $newval
*
* @return array
*/
- public function basic_setters_data(): array {
+ public static function basic_setters_data(): array {
return [
'Set attempt duration' => [
'duration', 25, 35
diff --git a/mod/h5pactivity/tests/local/grader_test.php b/mod/h5pactivity/tests/local/grader_test.php
index 36389c0c423b6..870a5119c977c 100644
--- a/mod/h5pactivity/tests/local/grader_test.php
+++ b/mod/h5pactivity/tests/local/grader_test.php
@@ -160,7 +160,7 @@ public function test_grade_item_update(int $newgrade, bool $reset, string $idnum
*
* @return array
*/
- public function grade_item_update_data(): array {
+ public static function grade_item_update_data(): array {
return [
'Change idnumber' => [
100, false, 'newidnumber'
@@ -258,7 +258,7 @@ public function test_update_grades(int $newgrade, bool $all, int $completion, ar
*
* @return array
*/
- public function update_grades_data(): array {
+ public static function update_grades_data(): array {
return [
// Quantitative grade, all attempts completed.
'Same grademax, all users, all completed' => [
diff --git a/mod/h5pactivity/tests/local/manager_test.php b/mod/h5pactivity/tests/local/manager_test.php
index 95f68146f806f..03f2a981477a2 100644
--- a/mod/h5pactivity/tests/local/manager_test.php
+++ b/mod/h5pactivity/tests/local/manager_test.php
@@ -100,7 +100,7 @@ public function test_is_tracking_enabled_and_can_submit(bool $login, string $rol
*
* @return array
*/
- public function is_tracking_enabled_data(): array {
+ public static function is_tracking_enabled_data(): array {
return [
'Logged student, tracking enabled' => [
true, 'student', 1, true, true,
@@ -214,7 +214,7 @@ public function test_get_users_scaled_score(int $enabletracking, int $gradingmet
*
* @return array
*/
- public function get_users_scaled_score_data(): array {
+ public static function get_users_scaled_score_data(): array {
return [
'Tracking with max attempt method' => [
1, manager::GRADEHIGHESTATTEMPT, [1.00000, 31, 2], [0.66667, 32, 2]
@@ -291,7 +291,7 @@ public function test_get_selected_attempt(int $enabletracking, int $gradingmetho
*
* @return array
*/
- public function get_selected_attempt_data(): array {
+ public static function get_selected_attempt_data(): array {
return [
'Tracking with max attempt method' => [
1, manager::GRADEHIGHESTATTEMPT, manager::GRADEHIGHESTATTEMPT
@@ -400,7 +400,7 @@ public function test_can_view_all_attempts(int $enabletracking, bool $usestudent
*
* @return array
*/
- public function can_view_all_attempts_data(): array {
+ public static function can_view_all_attempts_data(): array {
return [
// No tracking cases.
'No tracking with admin using $USER' => [
@@ -472,7 +472,7 @@ public function test_can_view_own_attempts(int $enabletracking, int $reviewmode,
*
* @return array
*/
- public function can_view_own_attempts_data(): array {
+ public static function can_view_own_attempts_data(): array {
return [
// No tracking cases.
'No tracking, review none, using $USER, without attempts' => [
@@ -611,7 +611,7 @@ public function test_count_attempts_all(bool $canview, bool $cansubmit, bool $ex
*
* @return array
*/
- public function count_attempts_all_data(): array {
+ public static function count_attempts_all_data(): array {
return [
'Students with both view and submit capability' => [true, true, false, 6],
'Students without view but with submit capability' => [false, true, false, 0],
@@ -677,7 +677,7 @@ public function test_get_active_users_join(bool $allpotentialusers, int $result)
*
* @return array
*/
- public function get_active_users_join_data(): array {
+ public static function get_active_users_join_data(): array {
return [
'All potential users' => [
'allpotentialusers' => true,
@@ -909,7 +909,7 @@ public function test_get_report(int $enabletracking, int $reviewmode, bool $crea
*
* @return array
*/
- public function get_report_data(): array {
+ public static function get_report_data(): array {
return [
// No tracking scenarios.
'No tracking, review none, no attempts, teacher' => [
@@ -1044,7 +1044,7 @@ public function test_get_report_groupmode(bool $activitygroupmode): void {
*
* @return array
*/
- public function get_report_data_groupmode(): array {
+ public static function get_report_data_groupmode(): array {
return [
// No tracking scenarios.
'course groupmode is SEPARATEGROUPS' => [false],
@@ -1102,7 +1102,7 @@ public function test_get_attempt(string $attemptname, ?string $result): void {
*
* @return array
*/
- public function get_attempt_data(): array {
+ public static function get_attempt_data(): array {
return [
'Get the current activity attempt' => [
'current', 'current'
diff --git a/mod/h5pactivity/tests/restore_test.php b/mod/h5pactivity/tests/restore_test.php
index 6b3d7778895a0..a060b1f08a5e4 100644
--- a/mod/h5pactivity/tests/restore_test.php
+++ b/mod/h5pactivity/tests/restore_test.php
@@ -155,7 +155,7 @@ public function test_backup_restore(bool $content, bool $userdata, array $result
*
* @return array
*/
- public function backup_restore_data(): array {
+ public static function backup_restore_data(): array {
return [
'Activity attempts and restore with userdata' => [
true, true, [1, 1, 3], [1, 1, 3]
diff --git a/mod/imscp/tests/behat/imscp_activity_completion.feature b/mod/imscp/tests/behat/imscp_activity_completion.feature
index 2d9d2bec48156..db271bb537a0a 100644
--- a/mod/imscp/tests/behat/imscp_activity_completion.feature
+++ b/mod/imscp/tests/behat/imscp_activity_completion.feature
@@ -17,7 +17,7 @@ Feature: View activity completion information in the IMS content package activit
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
- Scenario: View automatic completion items
+ Scenario: A student can complete a IMSCP activity by viewing it
Given the following "activities" exist:
| activity | course | name | completion | completionview | packagefilepath |
| imscp | C1 | Music history | 2 | 1 | mod/imscp/tests/pacakges/singescobbasic.zip |
@@ -26,7 +26,7 @@ Feature: View activity completion information in the IMS content package activit
Then the "View" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the IMSCP activity as done but a teacher cannot
Given the following "activities" exist:
| activity | course | name | completion | packagefilepath |
| imscp | C1 | Music history | 1 | mod/imscp/tests/packages/singescobasic.zip |
diff --git a/mod/label/tests/lib_test.php b/mod/label/tests/lib_test.php
index f6c5afd894689..daf75e96f3d8e 100644
--- a/mod/label/tests/lib_test.php
+++ b/mod/label/tests/lib_test.php
@@ -234,7 +234,7 @@ public function test_label_get_label_name(string $name, string $content, string
*
* @return array
*/
- public function label_get_name_data_provider(): array {
+ public static function label_get_name_data_provider(): array {
return [
'withlabelname' => [
'name' => 'Test label 1',
diff --git a/mod/lesson/tests/behat/lesson_activity_completion.feature b/mod/lesson/tests/behat/lesson_activity_completion.feature
index 254a666cfbc09..d91ef624da48a 100644
--- a/mod/lesson/tests/behat/lesson_activity_completion.feature
+++ b/mod/lesson/tests/behat/lesson_activity_completion.feature
@@ -37,14 +37,14 @@ Feature: View activity completion in the lesson activity
| Music history part 1 | The history of music part 1 | Next page | 0 |
| Music essay | | Next page | 1 |
- Scenario: View automatic completion items as a teacher
+ Scenario: A teacher can view a lesson activity automatic completion conditions
When I am on the "Music history" "lesson activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
And "Music history" should have the "Spend at least 3 secs on this activity" completion condition
And "Music history" should have the "Go through the activity to the end" completion condition
And "Music history" should have the "Receive a grade" completion condition
- Scenario: View automatic completion items as a student
+ Scenario: A student can complete a lesson activity by meeting the completion conditions
Given I am on the "Music history" "lesson activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Spend at least 3 secs on this activity" completion condition of "Music history" is displayed as "todo"
@@ -66,7 +66,7 @@ Feature: View activity completion in the lesson activity
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the lesson activity as done but a teacher cannot
Given I am on the "Music history" "lesson 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"
diff --git a/mod/lesson/tests/behat/lesson_completion_pass_grade.feature b/mod/lesson/tests/behat/lesson_completion_pass_grade.feature
index 00da02e453a27..c2cfd573c98e6 100644
--- a/mod/lesson/tests/behat/lesson_completion_pass_grade.feature
+++ b/mod/lesson/tests/behat/lesson_completion_pass_grade.feature
@@ -34,12 +34,12 @@ Feature: Pass grade activity completion in the lesson activity
| Numerical question | 3 | End of lesson | 1 |
| Numerical question | @#wronganswer#@ | Next page | 0 |
- Scenario: View automatic completion items as a teacher
+ Scenario: Lesson activity displays completion conditions to teachers
When I am on the "Music history" "lesson activity" page logged in as teacher1
And "Music history" should have the "Receive a grade" completion condition
And "Music history" should have the "Receive a passing grade" completion condition
- Scenario: View automatic completion items as a student
+ Scenario: A student can complete an lesson activity by achieving a passing grade
Given I am on the "Music history" "lesson activity" page logged in as student1
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
diff --git a/mod/lesson/tests/dates_test.php b/mod/lesson/tests/dates_test.php
index 4d4345cb665b8..0d2b676ff40de 100644
--- a/mod/lesson/tests/dates_test.php
+++ b/mod/lesson/tests/dates_test.php
@@ -43,7 +43,7 @@ class dates_test extends advanced_testcase {
* Data provider for get_dates_for_module().
* @return array[]
*/
- public function get_dates_for_module_provider(): array {
+ public static function get_dates_for_module_provider(): array {
$now = time();
$before = $now - DAYSECS;
$earlier = $before - DAYSECS;
diff --git a/mod/lesson/tests/locallib_test.php b/mod/lesson/tests/locallib_test.php
index 91e8ce64b4b65..7571ed7a1f4a8 100644
--- a/mod/lesson/tests/locallib_test.php
+++ b/mod/lesson/tests/locallib_test.php
@@ -260,7 +260,7 @@ public function test_is_participant() {
*
* @return array
*/
- public function get_last_attempt_dataprovider() {
+ public static function get_last_attempt_dataprovider(): array {
return [
[0, [(object)['id' => 1], (object)['id' => 2], (object)['id' => 3]], (object)['id' => 3]],
[1, [(object)['id' => 1], (object)['id' => 2], (object)['id' => 3]], (object)['id' => 1]],
diff --git a/mod/lesson/tests/numeric_helper_test.php b/mod/lesson/tests/numeric_helper_test.php
index a0ea02a24b93e..f72e32ded4653 100644
--- a/mod/lesson/tests/numeric_helper_test.php
+++ b/mod/lesson/tests/numeric_helper_test.php
@@ -62,7 +62,7 @@ public function test_lesson_format_numeric_value($decsep, $tests) {
*
* @return array
*/
- public function lesson_unformat_dataprovider() {
+ public static function lesson_unformat_dataprovider(): array {
return [
"Using a decimal as a separator" => [
"decsep" => ".",
@@ -100,7 +100,7 @@ public function lesson_unformat_dataprovider() {
*
* @return array
*/
- public function lesson_format_dataprovider() {
+ public static function lesson_format_dataprovider(): array {
return [
"Using a decimal as a separator" => [
"decsep" => ".",
diff --git a/mod/lti/tests/behat/lti_activity_completion.feature b/mod/lti/tests/behat/lti_activity_completion.feature
index 336c52447454e..48c4557d23aae 100644
--- a/mod/lti/tests/behat/lti_activity_completion.feature
+++ b/mod/lti/tests/behat/lti_activity_completion.feature
@@ -39,7 +39,7 @@ Feature: View activity completion information in the LTI activity
And the "View" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the LTI activity as done but a teacher cannot
Given I am on the "Music history" "lti 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"
diff --git a/mod/lti/tests/behat/lti_completion_pass_grade.feature b/mod/lti/tests/behat/lti_completion_pass_grade.feature
index 4c410e2016947..2a5e80b49e3a1 100644
--- a/mod/lti/tests/behat/lti_completion_pass_grade.feature
+++ b/mod/lti/tests/behat/lti_completion_pass_grade.feature
@@ -21,14 +21,14 @@ Feature: Pass grade activity completion information in the LTI activity
| activity | name | course | gradepass | completion | completionview | completionusegrade | completionpassgrade |
| lti | Music history | C1 | 50 | 2 | 1 | 1 | 1 |
- Scenario: View automatic completion items as a teacher
+ Scenario: Verify that the LTI completion conditions are displayed to teachers
Given I am on the "Music history" "lti activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
And "Music history" should have the "Receive a grade" completion condition
And "Music history" should have the "Receive a passing grade" completion condition
@javascript
- Scenario: View automatic completion items as a student
+ Scenario: Verify that students can complete an LTI activity by achieving a passing grade
Given I am on the "Music history" "lti activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
diff --git a/mod/lti/tests/local/ltiopenid/jwks_helper_test.php b/mod/lti/tests/local/ltiopenid/jwks_helper_test.php
index 0fe71e29fb939..8fcac76df8c0c 100644
--- a/mod/lti/tests/local/ltiopenid/jwks_helper_test.php
+++ b/mod/lti/tests/local/ltiopenid/jwks_helper_test.php
@@ -66,7 +66,7 @@ public function test_fix_jwks_alg(array $jwks, string $jwt, array $expected) {
* Provider for test_fix_jwks_alg.
* @return array test data.
*/
- public function jwks_alg_provider(): array {
+ public static function jwks_alg_provider(): array {
return [
// Algs already present, so no changes to input key array.
'All JWKS keys have algs set' => [
diff --git a/mod/lti/tests/locallib_test.php b/mod/lti/tests/locallib_test.php
index 48a9f58fa220e..cc491e8d9e5d2 100644
--- a/mod/lti/tests/locallib_test.php
+++ b/mod/lti/tests/locallib_test.php
@@ -517,7 +517,7 @@ public function test_lti_build_content_item_selection_request_invalid_presentati
*
* @return array of [urlToTest, expectedTool, allTools]
*/
- public function lti_get_best_tool_by_url_provider() {
+ public static function lti_get_best_tool_by_url_provider(): array {
$tools = [
(object) [
'name' => 'Here',
@@ -605,7 +605,7 @@ public function lti_get_best_tool_by_url_provider() {
// Construct the final array as required by the provider API. Each row
// of the array contains the URL to test, the expected tool, and
// the complete list of tools.
- return array_map(function($data) use ($tools) {
+ return array_map(function($data) use ($tools): array {
return [$data['url'], $data['expected'], $tools];
}, $data);
}
@@ -2020,7 +2020,7 @@ public function test_lti_get_ims_role(bool $islti2, string $rolename, ?string $s
*
* @return array[] the test case data.
*/
- public function lti_get_ims_role_provider() {
+ public static function lti_get_ims_role_provider(): array {
return [
'Student, LTI 1.1, no role switch' => [
'islti2' => false,
diff --git a/mod/lti/tests/servicelib_test.php b/mod/lti/tests/servicelib_test.php
index a20fbc8184e1a..1fd5c321a1a58 100644
--- a/mod/lti/tests/servicelib_test.php
+++ b/mod/lti/tests/servicelib_test.php
@@ -47,7 +47,7 @@ public function test_lti_parse_message_id($expected, $xml) {
*
* @return array
*/
- public function message_id_provider() {
+ public static function message_id_provider(): array {
$valid = <<
diff --git a/mod/page/tests/behat/page_activity_completion.feature b/mod/page/tests/behat/page_activity_completion.feature
index c9265abdcb92d..514a12dcfa8c7 100644
--- a/mod/page/tests/behat/page_activity_completion.feature
+++ b/mod/page/tests/behat/page_activity_completion.feature
@@ -18,7 +18,7 @@ Feature: View activity completion information in the Page resource
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
- Scenario: View automatic completion items as teacher
+ Scenario: A teacher can view a page resource automatic completion items
Given the following "activity" exists:
| activity | page |
| course | C1 |
@@ -30,7 +30,7 @@ Feature: View activity completion information in the Page resource
When I am on the "Music history" "page activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
- Scenario: View automatic completion items as student
+ Scenario: A student can complete a page resource by viewing it
Given the following "activity" exists:
| activity | page |
| course | C1 |
@@ -43,7 +43,7 @@ Feature: View activity completion information in the Page resource
Then the "View" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion as teacher
+ Scenario: A teacher cannot manually mark the page activity as done
Given the following "activity" exists:
| activity | page |
| course | C1 |
@@ -56,7 +56,7 @@ Feature: View activity completion information in the Page resource
Then the manual completion button for "Music history" should be disabled
@javascript
- Scenario: Use manual completion as student
+ Scenario: A student can manually mark the page activity as done
Given the following "activity" exists:
| activity | page |
| course | C1 |
diff --git a/mod/quiz/accessrule/seb/tests/access_manager_test.php b/mod/quiz/accessrule/seb/tests/access_manager_test.php
index 610c2c3f5e002..835869ef3a66d 100644
--- a/mod/quiz/accessrule/seb/tests/access_manager_test.php
+++ b/mod/quiz/accessrule/seb/tests/access_manager_test.php
@@ -343,7 +343,7 @@ public function test_get_seb_use_type() {
*
* @return array
*/
- public function should_validate_basic_header_data_provider() {
+ public static function should_validate_basic_header_data_provider(): array {
return [
[settings_provider::USE_SEB_NO, false],
[settings_provider::USE_SEB_CONFIG_MANUALLY, false],
@@ -377,7 +377,7 @@ public function test_should_validate_basic_header($type, $expected) {
*
* @return array
*/
- public function should_validate_config_key_data_provider() {
+ public static function should_validate_config_key_data_provider(): array {
return [
[settings_provider::USE_SEB_NO, false],
[settings_provider::USE_SEB_CONFIG_MANUALLY, true],
@@ -410,7 +410,7 @@ public function test_should_validate_config_key($type, $expected) {
*
* @return array
*/
- public function should_validate_browser_exam_key_data_provider() {
+ public static function should_validate_browser_exam_key_data_provider(): array {
return [
[settings_provider::USE_SEB_NO, false],
[settings_provider::USE_SEB_CONFIG_MANUALLY, false],
diff --git a/mod/quiz/accessrule/seb/tests/config_key_test.php b/mod/quiz/accessrule/seb/tests/config_key_test.php
index 57255c16c79cc..744cac2313ab5 100644
--- a/mod/quiz/accessrule/seb/tests/config_key_test.php
+++ b/mod/quiz/accessrule/seb/tests/config_key_test.php
@@ -74,7 +74,7 @@ public function test_presence_of_originator_version_does_not_effect_hash() {
*
* @return array
*/
- public function real_ck_hash_provider() : array {
+ public static function real_ck_hash_provider(): array {
return [
'unencrypted_mac2.1.4' => ['unencrypted_mac_001.seb',
'4fa9af8ec8759eb7c680752ef4ee5eaf1a860628608fccae2715d519849f9292', ''],
diff --git a/mod/quiz/accessrule/seb/tests/external/validate_quiz_access_test.php b/mod/quiz/accessrule/seb/tests/external/validate_quiz_access_test.php
index cf0982064dbd1..b1fd0f4d9a5b0 100644
--- a/mod/quiz/accessrule/seb/tests/external/validate_quiz_access_test.php
+++ b/mod/quiz/accessrule/seb/tests/external/validate_quiz_access_test.php
@@ -54,7 +54,7 @@ public function setUp(): void {
*
* @return array
*/
- public function bad_parameters_provider(): array {
+ public static function bad_parameters_provider(): array {
return [
'no params' => [
'cmid' => null,
diff --git a/mod/quiz/accessrule/seb/tests/property_list_test.php b/mod/quiz/accessrule/seb/tests/property_list_test.php
index 50eef4998694c..b6def63d989df 100644
--- a/mod/quiz/accessrule/seb/tests/property_list_test.php
+++ b/mod/quiz/accessrule/seb/tests/property_list_test.php
@@ -304,7 +304,7 @@ private function get_plist_xml_footer() : string {
*
* @return array Array with test data.
*/
- public function good_update_data_provider() : array {
+ public static function good_update_data_provider(): array {
return [
'Update string' => ['testKeytestValue', 'testKey', 'newValue'],
'Update bool' => ['testKey', 'testKey', false],
@@ -317,7 +317,7 @@ public function good_update_data_provider() : array {
*
* @return array Array with test data.
*/
- public function bad_update_data_provider() : array {
+ public static function bad_update_data_provider(): array {
return [
'Update string with bool' => ['testKeytestValue', 'testKey', true, 'testValue',
@@ -379,7 +379,7 @@ public function bad_update_data_provider() : array {
*
* @return array
*/
- public function json_data_provider() : array {
+ public static function json_data_provider(): array {
$data = "blahblah";
$base64data = base64_encode($data);
diff --git a/mod/quiz/accessrule/seb/tests/quiz_settings_test.php b/mod/quiz/accessrule/seb/tests/quiz_settings_test.php
index 22432ef5b549a..ae69a8a3edd1c 100644
--- a/mod/quiz/accessrule/seb/tests/quiz_settings_test.php
+++ b/mod/quiz/accessrule/seb/tests/quiz_settings_test.php
@@ -531,7 +531,7 @@ public function save_settings_with_optional_template($quizsettings, $savetype, $
*
* @return array
*/
- public function bad_browser_exam_key_provider() : array {
+ public static function bad_browser_exam_key_provider(): array {
return [
'Short string' => ['fdsf434r',
'A key should be a 64-character hex string.'],
@@ -547,7 +547,7 @@ public function bad_browser_exam_key_provider() : array {
*
* @return array Test data.
*/
- public function filter_rules_provider() : array {
+ public static function filter_rules_provider(): array {
return [
'enabled simple expessions' => [
(object) [
diff --git a/mod/quiz/accessrule/seb/tests/rule_test.php b/mod/quiz/accessrule/seb/tests/rule_test.php
index 7dbc66ad0c671..feaf4d70f0efd 100644
--- a/mod/quiz/accessrule/seb/tests/rule_test.php
+++ b/mod/quiz/accessrule/seb/tests/rule_test.php
@@ -87,7 +87,7 @@ private function get_seb_config_download_link() {
*
* @return array
*/
- public function valid_form_data_provider() : array {
+ public static function valid_form_data_provider(): array {
return [
'valid seb_requiresafeexambrowser' => ['seb_requiresafeexambrowser', '0'],
'valid seb_linkquitseb0' => ['seb_linkquitseb', 'http://safeexambrowser.org/macosx'],
@@ -103,7 +103,7 @@ public function valid_form_data_provider() : array {
*
* @return array
*/
- public function invalid_form_data_provider() : array {
+ public static function invalid_form_data_provider(): array {
return [
'invalid seb_requiresafeexambrowser' => ['seb_requiresafeexambrowser', 'Uh oh!'],
'invalid seb_linkquitseb0' => ['seb_linkquitseb', '\0'],
diff --git a/mod/quiz/accessrule/seb/tests/settings_provider_test.php b/mod/quiz/accessrule/seb/tests/settings_provider_test.php
index bf6c7f6b014d5..8d3713eb0e536 100644
--- a/mod/quiz/accessrule/seb/tests/settings_provider_test.php
+++ b/mod/quiz/accessrule/seb/tests/settings_provider_test.php
@@ -93,7 +93,7 @@ protected function set_up_user_and_role() {
*
* @return array
*/
- public function settings_capability_data_provider() {
+ public static function settings_capability_data_provider(): array {
$data = [];
// Build first level SEB config settings. Any of this setting let us use SEB manual config.
diff --git a/mod/quiz/accessrule/timelimit/tests/rule_test.php b/mod/quiz/accessrule/timelimit/tests/rule_test.php
index ab04271c2ced7..7ecb86073a031 100644
--- a/mod/quiz/accessrule/timelimit/tests/rule_test.php
+++ b/mod/quiz/accessrule/timelimit/tests/rule_test.php
@@ -63,7 +63,7 @@ public function test_time_limit_access_rule() {
*
* @return array of ($timetoclose, $timelimit, $displaylimit, $actuallimit)
*/
- public function time_limit_access_rule_with_time_close_provider() {
+ public static function time_limit_access_rule_with_time_close_provider(): array {
return [
'Close time is earlier than time limit' => [1800, 3600, 3600, 1800],
'Close time is on time limit' => [3600, 3600, 3600, 3600],
diff --git a/mod/quiz/report/overview/tests/report_test.php b/mod/quiz/report/overview/tests/report_test.php
index f7b13bb244e2d..74dd18c545a0a 100644
--- a/mod/quiz/report/overview/tests/report_test.php
+++ b/mod/quiz/report/overview/tests/report_test.php
@@ -52,7 +52,7 @@ class report_test extends \advanced_testcase {
*
* @return array the data for the test sub-cases.
*/
- public function report_sql_cases(): array {
+ public static function report_sql_cases(): array {
return [[null], ['csv']]; // Only need to test on or off, not all download types.
}
@@ -246,7 +246,7 @@ public function test_report_sql(?string $isdownloading): void {
* Bands provider.
* @return array
*/
- public function get_bands_count_and_width_provider(): array {
+ public static function get_bands_count_and_width_provider(): array {
return [
[10, [20, .5]],
[20, [20, 1]],
diff --git a/mod/quiz/report/responses/tests/responses_from_steps_walkthrough_test.php b/mod/quiz/report/responses/tests/responses_from_steps_walkthrough_test.php
index 07c06df8cc991..931e080c038a6 100644
--- a/mod/quiz/report/responses/tests/responses_from_steps_walkthrough_test.php
+++ b/mod/quiz/report/responses/tests/responses_from_steps_walkthrough_test.php
@@ -19,13 +19,6 @@
use mod_quiz\quiz_attempt;
use question_bank;
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-require_once($CFG->dirroot . '/mod/quiz/tests/attempt_walkthrough_from_csv_test.php');
-require_once($CFG->dirroot . '/mod/quiz/report/statistics/report.php');
-require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
-
/**
* Quiz attempt walk through using data from csv file.
*
@@ -35,16 +28,21 @@
* @author Jamie Pratt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class responses_from_steps_walkthrough_test extends \mod_quiz\attempt_walkthrough_from_csv_test {
- protected function get_full_path_of_csv_file(string $setname, string $test): string {
- // Overridden here so that __DIR__ points to the path of this file.
- return __DIR__."/fixtures/{$setname}{$test}.csv";
+final class responses_from_steps_walkthrough_test extends \mod_quiz\tests\attempt_walkthrough_testcase {
+ #[\Override]
+ public static function setUpBeforeClass(): void {
+ global $CFG;
+
+ parent::setUpBeforeClass();
+
+ require_once($CFG->dirroot . '/mod/quiz/report/statistics/report.php');
+ require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
}
- /**
- * @var string[] names of the files which contain the test data.
- */
- protected $files = ['questions', 'steps', 'responses'];
+ #[\Override]
+ protected static function get_test_files(): array {
+ return ['questions', 'steps', 'responses'];
+ }
/**
* Create a quiz add questions to it, walk through quiz attempts and then check results.
@@ -53,8 +51,7 @@ protected function get_full_path_of_csv_file(string $setname, string $test): str
* @param array $csvdata of data read from csv file "questionsXX.csv", "stepsXX.csv" and "responsesXX.csv".
* @dataProvider get_data_for_walkthrough
*/
- public function test_walkthrough_from_csv($quizsettings, $csvdata) {
-
+ public function test_walkthrough_from_csv($quizsettings, $csvdata): void {
$this->resetAfterTest(true);
question_bank::get_qtype('random')->clear_caches_before_testing();
@@ -72,7 +69,14 @@ public function test_walkthrough_from_csv($quizsettings, $csvdata) {
}
}
- protected function assert_response_test($quizattemptid, $responses) {
+ /**
+ * Helper to assert a response.
+ *
+ * @param mixed $quizattemptid
+ * @param mixed $responses
+ * @throws \coding_exception
+ */
+ protected function assert_response_test($quizattemptid, $responses): void {
$quizattempt = quiz_attempt::create($quizattemptid);
foreach ($responses['slot'] as $slot => $tests) {
diff --git a/mod/quiz/report/statistics/tests/stats_from_steps_walkthrough_test.php b/mod/quiz/report/statistics/tests/stats_from_steps_walkthrough_test.php
index 2f95f61674bb2..0a0bd7886c11c 100644
--- a/mod/quiz/report/statistics/tests/stats_from_steps_walkthrough_test.php
+++ b/mod/quiz/report/statistics/tests/stats_from_steps_walkthrough_test.php
@@ -21,13 +21,6 @@
use question_finder;
use quiz_statistics_report;
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-require_once($CFG->dirroot . '/mod/quiz/tests/attempt_walkthrough_from_csv_test.php');
-require_once($CFG->dirroot . '/mod/quiz/report/statistics/report.php');
-require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
-
/**
* Quiz attempt walk through using data from csv file.
*
@@ -45,22 +38,26 @@
* @author Jamie Pratt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class stats_from_steps_walkthrough_test extends \mod_quiz\attempt_walkthrough_from_csv_test {
-
+final class stats_from_steps_walkthrough_test extends \mod_quiz\tests\attempt_walkthrough_testcase {
/**
* @var quiz_statistics_report object to do stats calculations.
*/
protected $report;
- protected function get_full_path_of_csv_file(string $setname, string $test): string {
- // Overridden here so that __DIR__ points to the path of this file.
- return __DIR__."/fixtures/{$setname}{$test}.csv";
+ #[\Override]
+ public static function setUpBeforeClass(): void {
+ global $CFG;
+
+ parent::setUpBeforeClass();
+
+ require_once($CFG->dirroot . '/mod/quiz/report/statistics/report.php');
+ require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
}
- /**
- * @var string[] names of the files which contain the test data.
- */
- protected $files = ['questions', 'steps', 'results', 'qstats', 'responsecounts'];
+ #[\Override]
+ protected static function get_test_files(): array {
+ return ['questions', 'steps', 'results', 'qstats', 'responsecounts'];
+ }
/**
* Create a quiz add questions to it, walk through quiz attempts and then check results.
@@ -68,8 +65,7 @@ protected function get_full_path_of_csv_file(string $setname, string $test): str
* @param array $csvdata data read from csv file "questionsXX.csv", "stepsXX.csv" and "resultsXX.csv".
* @dataProvider get_data_for_walkthrough
*/
- public function test_walkthrough_from_csv($quizsettings, $csvdata) {
-
+ public function test_walkthrough_from_csv($quizsettings, $csvdata): void {
$this->create_quiz_simulate_attempts_and_check_results($quizsettings, $csvdata);
$whichattempts = QUIZ_GRADEAVERAGE; // All attempts.
diff --git a/mod/quiz/tests/attempt_walkthrough_from_csv_test.php b/mod/quiz/tests/attempt_walkthrough_from_csv_test.php
index 4cb2e15304b01..77b67c8bb79de 100644
--- a/mod/quiz/tests/attempt_walkthrough_from_csv_test.php
+++ b/mod/quiz/tests/attempt_walkthrough_from_csv_test.php
@@ -16,14 +16,7 @@
namespace mod_quiz;
-use question_engine;
-use mod_quiz\quiz_settings;
-
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-require_once($CFG->dirroot . '/mod/quiz/locallib.php');
-require_once($CFG->dirroot . '/mod/quiz/tests/quiz_question_helper_test_trait.php');
+// phpcs:disable moodle.PHPUnit.TestCaseNames.Missing
/**
* Quiz attempt walk through using data from csv file.
@@ -34,335 +27,9 @@
* @author Jamie Pratt
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class attempt_walkthrough_from_csv_test extends \advanced_testcase {
-
- use \quiz_question_helper_test_trait;
-
- /**
- * @var string[] names of the files which contain the test data.
- */
- protected $files = ['questions', 'steps', 'results'];
-
- /**
- * @var stdClass the quiz record we create.
- */
- protected $quiz;
-
- /**
- * @var array with slot no => question name => questionid. Question ids of questions created in the same category as random q.
- */
- protected $randqids;
-
- /**
- * The only test in this class. This is run multiple times depending on how many sets of files there are in fixtures/
- * directory.
- *
- * @param array $quizsettings of settings read from csv file quizzes.csv
- * @param array $csvdata of data read from csv file "questionsXX.csv", "stepsXX.csv" and "resultsXX.csv".
- * @dataProvider get_data_for_walkthrough
- */
- public function test_walkthrough_from_csv($quizsettings, $csvdata) {
-
- // CSV data files for these tests were generated using :
- // https://github.com/jamiepratt/moodle-quiz-tools/tree/master/responsegenerator
-
- $this->create_quiz_simulate_attempts_and_check_results($quizsettings, $csvdata);
- }
-
- public function create_quiz($quizsettings, $qs) {
- global $SITE, $DB;
- $this->setAdminUser();
-
- /** @var core_question_generator $questiongenerator */
- $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
- $slots = [];
- $qidsbycat = [];
- $sumofgrades = 0;
- foreach ($qs as $qsrow) {
- $q = $this->explode_dot_separated_keys_to_make_subindexs($qsrow);
-
- $catname = ['name' => $q['cat']];
- if (!$cat = $DB->get_record('question_categories', ['name' => $q['cat']])) {
- $cat = $questiongenerator->create_question_category($catname);
- }
- $q['catid'] = $cat->id;
- foreach (['which' => null, 'overrides' => []] as $key => $default) {
- if (empty($q[$key])) {
- $q[$key] = $default;
- }
- }
-
- if ($q['type'] !== 'random') {
- // Don't actually create random questions here.
- $overrides = ['category' => $cat->id, 'defaultmark' => $q['mark']] + $q['overrides'];
- if ($q['type'] === 'truefalse') {
- // True/false question can never have hints, but sometimes we need to put them
- // in the CSV file, to keep it rectangular.
- unset($overrides['hint']);
- }
- $question = $questiongenerator->create_question($q['type'], $q['which'], $overrides);
- $q['id'] = $question->id;
-
- if (!isset($qidsbycat[$q['cat']])) {
- $qidsbycat[$q['cat']] = [];
- }
- if (!empty($q['which'])) {
- $name = $q['type'].'_'.$q['which'];
- } else {
- $name = $q['type'];
- }
- $qidsbycat[$q['catid']][$name] = $q['id'];
- }
- if (!empty($q['slot'])) {
- $slots[$q['slot']] = $q;
- $sumofgrades += $q['mark'];
- }
- }
-
- ksort($slots);
-
- // Make a quiz.
- $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
-
- // Settings from param override defaults.
- $aggregratedsettings = $quizsettings + ['course' => $SITE->id,
- 'questionsperpage' => 0,
- 'grade' => 100.0,
- 'sumgrades' => $sumofgrades];
-
- $this->quiz = $quizgenerator->create_instance($aggregratedsettings);
-
- $this->randqids = [];
- foreach ($slots as $slotno => $slotquestion) {
- if ($slotquestion['type'] !== 'random') {
- quiz_add_quiz_question($slotquestion['id'], $this->quiz, 0, $slotquestion['mark']);
- } else {
- $this->add_random_questions($this->quiz->id, 0, $slotquestion['catid'], 1);
- $this->randqids[$slotno] = $qidsbycat[$slotquestion['catid']];
- }
- }
- }
-
- /**
- * Create quiz, simulate attempts and check results (if resultsXX.csv exists).
- *
- * @param array $quizsettings Quiz overrides for this quiz.
- * @param array $csvdata Data loaded from csv files for this test.
- */
- protected function create_quiz_simulate_attempts_and_check_results(array $quizsettings, array $csvdata) {
- $this->resetAfterTest();
-
- $this->create_quiz($quizsettings, $csvdata['questions']);
-
- $attemptids = $this->walkthrough_attempts($csvdata['steps']);
-
- if (isset($csvdata['results'])) {
- $this->check_attempts_results($csvdata['results'], $attemptids);
- }
- }
-
- /**
- * Get full path of CSV file.
- *
- * @param string $setname
- * @param string $test
- * @return string full path of file.
- */
- protected function get_full_path_of_csv_file(string $setname, string $test): string {
- return __DIR__."/fixtures/{$setname}{$test}.csv";
- }
-
- /**
- * Load dataset from CSV file "{$setname}{$test}.csv".
- *
- * @param string $setname
- * @param string $test
- * @return array
- */
- protected function load_csv_data_file(string $setname, string $test = ''): array {
- $files = [$setname => $this->get_full_path_of_csv_file($setname, $test)];
- return $this->dataset_from_files($files)->get_rows([$setname]);
- }
-
- /**
- * Break down row of csv data into sub arrays, according to column names.
- *
- * @param array $row from csv file with field names with parts separate by '.'.
- * @return array the row with each part of the field name following a '.' being a separate sub array's index.
- */
- protected function explode_dot_separated_keys_to_make_subindexs(array $row): array {
- $parts = [];
- foreach ($row as $columnkey => $value) {
- $newkeys = explode('.', trim($columnkey));
- $placetoputvalue =& $parts;
- foreach ($newkeys as $newkeydepth => $newkey) {
- if ($newkeydepth + 1 === count($newkeys)) {
- $placetoputvalue[$newkey] = $value;
- } else {
- // Going deeper down.
- if (!isset($placetoputvalue[$newkey])) {
- $placetoputvalue[$newkey] = [];
- }
- $placetoputvalue =& $placetoputvalue[$newkey];
- }
- }
- }
- return $parts;
- }
-
- /**
- * Data provider method for test_walkthrough_from_csv. Called by PHPUnit.
- *
- * @return array One array element for each run of the test. Each element contains an array with the params for
- * test_walkthrough_from_csv.
- */
- public function get_data_for_walkthrough(): array {
- $quizzes = $this->load_csv_data_file('quizzes')['quizzes'];
- $datasets = [];
- foreach ($quizzes as $quizsettings) {
- $dataset = [];
- foreach ($this->files as $file) {
- if (file_exists($this->get_full_path_of_csv_file($file, $quizsettings['testnumber']))) {
- $dataset[$file] = $this->load_csv_data_file($file, $quizsettings['testnumber'])[$file];
- }
- }
- $datasets[] = [$quizsettings, $dataset];
- }
- return $datasets;
- }
-
- /**
- * @param array $steps the step data from the csv file.
- * @return array attempt no as in csv file => the id of the quiz_attempt as stored in the db.
- */
- protected function walkthrough_attempts(array $steps): array {
- global $DB;
- $attemptids = [];
- foreach ($steps as $steprow) {
-
- $step = $this->explode_dot_separated_keys_to_make_subindexs($steprow);
- // Find existing user or make a new user to do the quiz.
- $username = ['firstname' => $step['firstname'],
- 'lastname' => $step['lastname']];
-
- if (!$user = $DB->get_record('user', $username)) {
- $user = $this->getDataGenerator()->create_user($username);
- }
-
- if (!isset($attemptids[$step['quizattempt']])) {
- // Start the attempt.
- $quizobj = quiz_settings::create($this->quiz->id, $user->id);
- $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
- $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
-
- $prevattempts = quiz_get_user_attempts($this->quiz->id, $user->id, 'all', true);
- $attemptnumber = count($prevattempts) + 1;
- $timenow = time();
- $attempt = quiz_create_attempt($quizobj, $attemptnumber, null, $timenow, false, $user->id);
- // Select variant and / or random sub question.
- if (!isset($step['variants'])) {
- $step['variants'] = [];
- }
- if (isset($step['randqs'])) {
- // Replace 'names' with ids.
- foreach ($step['randqs'] as $slotno => $randqname) {
- $step['randqs'][$slotno] = $this->randqids[$slotno][$randqname];
- }
- } else {
- $step['randqs'] = [];
- }
-
- quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow, $step['randqs'], $step['variants']);
- quiz_attempt_save_started($quizobj, $quba, $attempt);
- $attemptid = $attemptids[$step['quizattempt']] = $attempt->id;
- } else {
- $attemptid = $attemptids[$step['quizattempt']];
- }
-
- // Process some responses from the student.
- $attemptobj = quiz_attempt::create($attemptid);
- $attemptobj->process_submitted_actions($timenow, false, $step['responses']);
-
- // Finish the attempt.
- if (!isset($step['finished']) || ($step['finished'] == 1)) {
- $attemptobj = quiz_attempt::create($attemptid);
- $attemptobj->process_finish($timenow, false);
- }
- }
- return $attemptids;
- }
-
- /**
- * @param array $results the results data from the csv file.
- * @param array $attemptids attempt no as in csv file => the id of the quiz_attempt as stored in the db.
- */
- protected function check_attempts_results(array $results, array $attemptids) {
- foreach ($results as $resultrow) {
- $result = $this->explode_dot_separated_keys_to_make_subindexs($resultrow);
- // Re-load quiz attempt data.
- $attemptobj = quiz_attempt::create($attemptids[$result['quizattempt']]);
- $this->check_attempt_results($result, $attemptobj);
- }
- }
-
- /**
- * Check that attempt results are as specified in $result.
- *
- * @param array $result row of data read from csv file.
- * @param quiz_attempt $attemptobj the attempt object loaded from db.
- */
- protected function check_attempt_results(array $result, quiz_attempt $attemptobj) {
- foreach ($result as $fieldname => $value) {
- if ($value === '!NULL!') {
- $value = null;
- }
- switch ($fieldname) {
- case 'quizattempt' :
- break;
- case 'attemptnumber' :
- $this->assertEquals($value, $attemptobj->get_attempt_number());
- break;
- case 'slots' :
- foreach ($value as $slotno => $slottests) {
- foreach ($slottests as $slotfieldname => $slotvalue) {
- switch ($slotfieldname) {
- case 'mark' :
- $this->assertEquals(round($slotvalue, 2), $attemptobj->get_question_mark($slotno),
- "Mark for slot $slotno of attempt {$result['quizattempt']}.");
- break;
- default :
- throw new \coding_exception('Unknown slots sub field column in csv file '
- .s($slotfieldname));
- }
- }
- }
- break;
- case 'finished' :
- $this->assertEquals((bool)$value, $attemptobj->is_finished());
- break;
- case 'summarks' :
- $this->assertEquals((float)$value, $attemptobj->get_sum_marks(),
- "Sum of marks of attempt {$result['quizattempt']}.");
- break;
- case 'quizgrade' :
- // Check quiz grades.
- $grades = quiz_get_user_grades($attemptobj->get_quiz(), $attemptobj->get_userid());
- $grade = array_shift($grades);
- $this->assertEquals($value, $grade->rawgrade, "Quiz grade for attempt {$result['quizattempt']}.");
- break;
- case 'gradebookgrade' :
- // Check grade book.
- $gradebookgrades = grade_get_grades($attemptobj->get_courseid(),
- 'mod', 'quiz',
- $attemptobj->get_quizid(),
- $attemptobj->get_userid());
- $gradebookitem = array_shift($gradebookgrades->items);
- $gradebookgrade = array_shift($gradebookitem->grades);
- $this->assertEquals($value, $gradebookgrade->grade, "Gradebook grade for attempt {$result['quizattempt']}.");
- break;
- default :
- throw new \coding_exception('Unknown column in csv file '.s($fieldname));
- }
- }
+final class attempt_walkthrough_from_csv_test extends \mod_quiz\tests\attempt_walkthrough_testcase {
+ #[\Override]
+ protected static function get_test_files(): array {
+ return ['questions', 'steps', 'results'];
}
}
diff --git a/mod/quiz/tests/attempt_walkthrough_test.php b/mod/quiz/tests/attempt_walkthrough_test.php
index c9768d974c82d..a29d38a08183d 100644
--- a/mod/quiz/tests/attempt_walkthrough_test.php
+++ b/mod/quiz/tests/attempt_walkthrough_test.php
@@ -19,13 +19,7 @@
use moodle_url;
use question_bank;
use question_engine;
-use mod_quiz\question\bank\qbank_helper;
-
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-require_once($CFG->dirroot . '/mod/quiz/locallib.php');
-require_once($CFG->dirroot . '/mod/quiz/tests/quiz_question_helper_test_trait.php');
+use mod_quiz\tests\question_helper_test_trait;
/**
* Quiz attempt walk through.
@@ -37,9 +31,17 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_quiz\quiz_attempt
*/
-class attempt_walkthrough_test extends \advanced_testcase {
+final class attempt_walkthrough_test extends \advanced_testcase {
+ use question_helper_test_trait;
+
+ #[\Override]
+ public static function setUpBeforeClass(): void {
+ global $CFG;
- use \quiz_question_helper_test_trait;
+ parent::setUpBeforeClass();
+
+ require_once($CFG->dirroot . '/mod/quiz/locallib.php');
+ }
/**
* Create a quiz with questions and walk through a quiz attempt.
@@ -424,7 +426,7 @@ public function test_quiz_with_random_question_attempt_walkthrough() {
}
- public function get_correct_response_for_variants() {
+ public static function get_correct_response_for_variants(): array {
return [[1, 9.9], [2, 8.5], [5, 14.2], [10, 6.8, true]];
}
diff --git a/mod/quiz/tests/behat/completion_manual.feature b/mod/quiz/tests/behat/completion_manual.feature
index a34f3518313e6..2434ca73865cd 100644
--- a/mod/quiz/tests/behat/completion_manual.feature
+++ b/mod/quiz/tests/behat/completion_manual.feature
@@ -32,7 +32,7 @@ Feature: Manually complete a quiz
| First question | 1 |
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the quiz activity as done but a teacher cannot
Given I am on the "Test quiz name" "quiz activity" page logged in as teacher1
And the manual completion button for "Test quiz name" should be disabled
And I log out
diff --git a/mod/quiz/tests/behat/quiz_activity_completion.feature b/mod/quiz/tests/behat/quiz_activity_completion.feature
index 1fe3c90264e4c..c7e9d38e9ec41 100644
--- a/mod/quiz/tests/behat/quiz_activity_completion.feature
+++ b/mod/quiz/tests/behat/quiz_activity_completion.feature
@@ -43,7 +43,7 @@ Feature: View activity completion in the quiz activity
| question | page |
| First question | 1 |
- Scenario Outline: View automatic completion items as a student
+ Scenario Outline: A student can complete a quiz activity by achieving a passing grade
When I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Test quiz name"
diff --git a/mod/quiz/tests/classes/attempt_walkthrough_testcase.php b/mod/quiz/tests/classes/attempt_walkthrough_testcase.php
new file mode 100644
index 0000000000000..905d80125b6c3
--- /dev/null
+++ b/mod/quiz/tests/classes/attempt_walkthrough_testcase.php
@@ -0,0 +1,387 @@
+.
+
+namespace mod_quiz\tests;
+
+use question_engine;
+use mod_quiz\quiz_settings;
+use mod_quiz\quiz_attempt;
+use stdClass;
+
+/**
+ * Quiz attempt walk through using data from csv file.
+ *
+ * @package mod_quiz
+ * @category test
+ * @copyright 2013 The Open University
+ * @author Jamie Pratt
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class attempt_walkthrough_testcase extends \advanced_testcase {
+ use question_helper_test_trait;
+
+ /**
+ * @var stdClass the quiz record we create.
+ */
+ protected $quiz;
+
+ /**
+ * @var array with slot no => question name => questionid. Question ids of questions created in the same category as random q.
+ */
+ protected $randqids;
+
+ /**
+ * Get the list of files which contain test data.
+ *
+ * @return array
+ */
+ protected static function get_test_files(): array {
+ return [];
+ }
+
+ /**
+ * Get the component name.
+ *
+ * @return string
+ */
+ protected static function get_component(): string {
+ // If the late-static class name is namespaced, use the first part of the namespace.
+ if (str_contains(static::class, '\\')) {
+ return explode('\\', static::class)[0];
+ }
+
+ // Otherwise we have to assume that the test name is correctly frankenstyle named.
+ return implode('_',
+ array_slice(
+ explode('_', static::class, 3),
+ 0,
+ 2,
+ )
+ );
+ }
+
+ /**
+ * Get the full path of the csv file.
+ *
+ * @param string $setname
+ * @param string $test
+ * @return string
+ */
+ protected static function get_full_path_of_csv_file(string $setname, string $test): string {
+ return static::get_fixture_path(static::get_component(), "{$setname}{$test}.csv");
+ }
+
+ /**
+ * The only test in this class. This is run multiple times depending on how many sets of files there are in fixtures/
+ * directory.
+ *
+ * @param array $quizsettings of settings read from csv file quizzes.csv
+ * @param array $csvdata of data read from csv file "questionsXX.csv", "stepsXX.csv" and "resultsXX.csv".
+ * @dataProvider get_data_for_walkthrough
+ */
+ public function test_walkthrough_from_csv($quizsettings, $csvdata): void {
+ // CSV data files for these tests were generated using :
+ // https://github.com/jamiepratt/moodle-quiz-tools/tree/master/responsegenerator
+
+ $this->create_quiz_simulate_attempts_and_check_results($quizsettings, $csvdata);
+ }
+
+ public function create_quiz($quizsettings, $qs) {
+ global $SITE, $DB;
+ $this->setAdminUser();
+
+ /** @var core_question_generator $questiongenerator */
+ $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
+ $slots = [];
+ $qidsbycat = [];
+ $sumofgrades = 0;
+ foreach ($qs as $qsrow) {
+ $q = $this->explode_dot_separated_keys_to_make_subindexs($qsrow);
+
+ $catname = ['name' => $q['cat']];
+ if (!$cat = $DB->get_record('question_categories', ['name' => $q['cat']])) {
+ $cat = $questiongenerator->create_question_category($catname);
+ }
+ $q['catid'] = $cat->id;
+ foreach (['which' => null, 'overrides' => []] as $key => $default) {
+ if (empty($q[$key])) {
+ $q[$key] = $default;
+ }
+ }
+
+ if ($q['type'] !== 'random') {
+ // Don't actually create random questions here.
+ $overrides = ['category' => $cat->id, 'defaultmark' => $q['mark']] + $q['overrides'];
+ if ($q['type'] === 'truefalse') {
+ // True/false question can never have hints, but sometimes we need to put them
+ // in the CSV file, to keep it rectangular.
+ unset($overrides['hint']);
+ }
+ $question = $questiongenerator->create_question($q['type'], $q['which'], $overrides);
+ $q['id'] = $question->id;
+
+ if (!isset($qidsbycat[$q['cat']])) {
+ $qidsbycat[$q['cat']] = [];
+ }
+ if (!empty($q['which'])) {
+ $name = $q['type'].'_'.$q['which'];
+ } else {
+ $name = $q['type'];
+ }
+ $qidsbycat[$q['catid']][$name] = $q['id'];
+ }
+ if (!empty($q['slot'])) {
+ $slots[$q['slot']] = $q;
+ $sumofgrades += $q['mark'];
+ }
+ }
+
+ ksort($slots);
+
+ // Make a quiz.
+ $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
+
+ // Settings from param override defaults.
+ $aggregratedsettings = $quizsettings + ['course' => $SITE->id,
+ 'questionsperpage' => 0,
+ 'grade' => 100.0,
+ 'sumgrades' => $sumofgrades];
+
+ $this->quiz = $quizgenerator->create_instance($aggregratedsettings);
+
+ $this->randqids = [];
+ foreach ($slots as $slotno => $slotquestion) {
+ if ($slotquestion['type'] !== 'random') {
+ quiz_add_quiz_question($slotquestion['id'], $this->quiz, 0, $slotquestion['mark']);
+ } else {
+ $this->add_random_questions($this->quiz->id, 0, $slotquestion['catid'], 1);
+ $this->randqids[$slotno] = $qidsbycat[$slotquestion['catid']];
+ }
+ }
+ }
+
+ /**
+ * Create quiz, simulate attempts and check results (if resultsXX.csv exists).
+ *
+ * @param array $quizsettings Quiz overrides for this quiz.
+ * @param array $csvdata Data loaded from csv files for this test.
+ */
+ protected function create_quiz_simulate_attempts_and_check_results(array $quizsettings, array $csvdata) {
+ $this->resetAfterTest();
+
+ $this->create_quiz($quizsettings, $csvdata['questions']);
+
+ $attemptids = $this->walkthrough_attempts($csvdata['steps']);
+
+ if (isset($csvdata['results'])) {
+ $this->check_attempts_results($csvdata['results'], $attemptids);
+ }
+ }
+
+ /**
+ * Load dataset from CSV file "{$setname}{$test}.csv".
+ *
+ * @param string $setname
+ * @param string $test
+ * @return array
+ */
+ protected static function load_csv_data_file(string $setname, string $test = ''): array {
+ $files = [$setname => static::get_full_path_of_csv_file($setname, $test)];
+ return static::dataset_from_files($files)->get_rows([$setname]);
+ }
+
+ /**
+ * Break down row of csv data into sub arrays, according to column names.
+ *
+ * @param array $row from csv file with field names with parts separate by '.'.
+ * @return array the row with each part of the field name following a '.' being a separate sub array's index.
+ */
+ protected function explode_dot_separated_keys_to_make_subindexs(array $row): array {
+ $parts = [];
+ foreach ($row as $columnkey => $value) {
+ $newkeys = explode('.', trim($columnkey));
+ $placetoputvalue =& $parts;
+ foreach ($newkeys as $newkeydepth => $newkey) {
+ if ($newkeydepth + 1 === count($newkeys)) {
+ $placetoputvalue[$newkey] = $value;
+ } else {
+ // Going deeper down.
+ if (!isset($placetoputvalue[$newkey])) {
+ $placetoputvalue[$newkey] = [];
+ }
+ $placetoputvalue =& $placetoputvalue[$newkey];
+ }
+ }
+ }
+ return $parts;
+ }
+
+ /**
+ * Data provider method for test_walkthrough_from_csv. Called by PHPUnit.
+ *
+ * @return array One array element for each run of the test. Each element contains an array with the params for
+ * test_walkthrough_from_csv.
+ */
+ public static function get_data_for_walkthrough(): array {
+ $quizzes = self::load_csv_data_file('quizzes')['quizzes'];
+ $datasets = [];
+ foreach ($quizzes as $quizsettings) {
+ $dataset = [];
+ foreach (static::get_test_files() as $file) {
+ if (file_exists(static::get_full_path_of_csv_file($file, $quizsettings['testnumber']))) {
+ $dataset[$file] = self::load_csv_data_file($file, $quizsettings['testnumber'])[$file];
+ }
+ }
+ $datasets[] = [$quizsettings, $dataset];
+ }
+ return $datasets;
+ }
+
+ /**
+ * @param array $steps the step data from the csv file.
+ * @return array attempt no as in csv file => the id of the quiz_attempt as stored in the db.
+ */
+ protected function walkthrough_attempts(array $steps): array {
+ global $DB;
+ $attemptids = [];
+ foreach ($steps as $steprow) {
+
+ $step = $this->explode_dot_separated_keys_to_make_subindexs($steprow);
+ // Find existing user or make a new user to do the quiz.
+ $username = ['firstname' => $step['firstname'],
+ 'lastname' => $step['lastname']];
+
+ if (!$user = $DB->get_record('user', $username)) {
+ $user = $this->getDataGenerator()->create_user($username);
+ }
+
+ if (!isset($attemptids[$step['quizattempt']])) {
+ // Start the attempt.
+ $quizobj = quiz_settings::create($this->quiz->id, $user->id);
+ $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
+ $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
+
+ $prevattempts = quiz_get_user_attempts($this->quiz->id, $user->id, 'all', true);
+ $attemptnumber = count($prevattempts) + 1;
+ $timenow = time();
+ $attempt = quiz_create_attempt($quizobj, $attemptnumber, null, $timenow, false, $user->id);
+ // Select variant and / or random sub question.
+ if (!isset($step['variants'])) {
+ $step['variants'] = [];
+ }
+ if (isset($step['randqs'])) {
+ // Replace 'names' with ids.
+ foreach ($step['randqs'] as $slotno => $randqname) {
+ $step['randqs'][$slotno] = $this->randqids[$slotno][$randqname];
+ }
+ } else {
+ $step['randqs'] = [];
+ }
+
+ quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $timenow, $step['randqs'], $step['variants']);
+ quiz_attempt_save_started($quizobj, $quba, $attempt);
+ $attemptid = $attemptids[$step['quizattempt']] = $attempt->id;
+ } else {
+ $attemptid = $attemptids[$step['quizattempt']];
+ }
+
+ // Process some responses from the student.
+ $attemptobj = quiz_attempt::create($attemptid);
+ $attemptobj->process_submitted_actions($timenow, false, $step['responses']);
+
+ // Finish the attempt.
+ if (!isset($step['finished']) || ($step['finished'] == 1)) {
+ $attemptobj = quiz_attempt::create($attemptid);
+ $attemptobj->process_finish($timenow, false);
+ }
+ }
+ return $attemptids;
+ }
+
+ /**
+ * @param array $results the results data from the csv file.
+ * @param array $attemptids attempt no as in csv file => the id of the quiz_attempt as stored in the db.
+ */
+ protected function check_attempts_results(array $results, array $attemptids) {
+ foreach ($results as $resultrow) {
+ $result = $this->explode_dot_separated_keys_to_make_subindexs($resultrow);
+ // Re-load quiz attempt data.
+ $attemptobj = quiz_attempt::create($attemptids[$result['quizattempt']]);
+ $this->check_attempt_results($result, $attemptobj);
+ }
+ }
+
+ /**
+ * Check that attempt results are as specified in $result.
+ *
+ * @param array $result row of data read from csv file.
+ * @param quiz_attempt $attemptobj the attempt object loaded from db.
+ */
+ protected function check_attempt_results(array $result, quiz_attempt $attemptobj) {
+ foreach ($result as $fieldname => $value) {
+ if ($value === '!NULL!') {
+ $value = null;
+ }
+ switch ($fieldname) {
+ case 'quizattempt' :
+ break;
+ case 'attemptnumber' :
+ $this->assertEquals($value, $attemptobj->get_attempt_number());
+ break;
+ case 'slots' :
+ foreach ($value as $slotno => $slottests) {
+ foreach ($slottests as $slotfieldname => $slotvalue) {
+ switch ($slotfieldname) {
+ case 'mark' :
+ $this->assertEquals(round($slotvalue, 2), $attemptobj->get_question_mark($slotno),
+ "Mark for slot $slotno of attempt {$result['quizattempt']}.");
+ break;
+ default :
+ throw new \coding_exception('Unknown slots sub field column in csv file '
+ .s($slotfieldname));
+ }
+ }
+ }
+ break;
+ case 'finished' :
+ $this->assertEquals((bool)$value, $attemptobj->is_finished());
+ break;
+ case 'summarks' :
+ $this->assertEquals((float)$value, $attemptobj->get_sum_marks(),
+ "Sum of marks of attempt {$result['quizattempt']}.");
+ break;
+ case 'quizgrade' :
+ // Check quiz grades.
+ $grades = quiz_get_user_grades($attemptobj->get_quiz(), $attemptobj->get_userid());
+ $grade = array_shift($grades);
+ $this->assertEquals($value, $grade->rawgrade, "Quiz grade for attempt {$result['quizattempt']}.");
+ break;
+ case 'gradebookgrade' :
+ // Check grade book.
+ $gradebookgrades = grade_get_grades($attemptobj->get_courseid(),
+ 'mod', 'quiz',
+ $attemptobj->get_quizid(),
+ $attemptobj->get_userid());
+ $gradebookitem = array_shift($gradebookgrades->items);
+ $gradebookgrade = array_shift($gradebookitem->grades);
+ $this->assertEquals($value, $gradebookgrade->grade, "Gradebook grade for attempt {$result['quizattempt']}.");
+ break;
+ default :
+ throw new \coding_exception('Unknown column in csv file '.s($fieldname));
+ }
+ }
+ }
+}
diff --git a/mod/quiz/tests/classes/question_helper_test_trait.php b/mod/quiz/tests/classes/question_helper_test_trait.php
new file mode 100644
index 0000000000000..ea6356d7d2e68
--- /dev/null
+++ b/mod/quiz/tests/classes/question_helper_test_trait.php
@@ -0,0 +1,221 @@
+.
+
+namespace mod_quiz\tests;
+
+use backup;
+use backup_controller;
+use component_generator_base;
+use mod_quiz_generator;
+use mod_quiz\quiz_attempt;
+use mod_quiz\quiz_settings;
+use restore_controller;
+use stdClass;
+use question_engine;
+
+/**
+ * Helper trait for quiz question unit tests.
+ *
+ * This trait helps to execute different tests for quiz, for example if it needs to create a quiz, add question
+ * to the question, add random quetion to the quiz, do a backup or restore.
+ *
+ * @package mod_quiz
+ * @category test
+ * @copyright 2021 Catalyst IT Australia Pty Ltd
+ * @author Safat Shahin
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+trait question_helper_test_trait {
+ /** @var stdClass $course Test course to contain quiz. */
+ protected $course;
+
+ /** @var stdClass $quiz A test quiz. */
+ protected $quiz;
+
+ /** @var stdClass $user A test logged-in user. */
+ protected $user;
+
+ /**
+ * Create a test quiz for the specified course.
+ *
+ * @param stdClass $course
+ * @return stdClass
+ */
+ protected function create_test_quiz(stdClass $course): stdClass {
+ /** @var mod_quiz_generator $quizgenerator */
+ $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
+
+ return $quizgenerator->create_instance([
+ 'course' => $course->id,
+ 'questionsperpage' => 0,
+ 'grade' => 100.0,
+ 'sumgrades' => 2,
+ ]);
+ }
+
+ /**
+ * Helper method to add regular questions in quiz.
+ *
+ * @param component_generator_base $questiongenerator
+ * @param stdClass $quiz
+ * @param array $override
+ */
+ protected function add_two_regular_questions($questiongenerator, stdClass $quiz, $override = null): void {
+ // Create a couple of questions.
+ $cat = $questiongenerator->create_question_category($override);
+
+ $saq = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
+ // Create another version.
+ $questiongenerator->update_question($saq);
+ quiz_add_quiz_question($saq->id, $quiz);
+ $numq = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]);
+ // Create two version.
+ $questiongenerator->update_question($numq);
+ $questiongenerator->update_question($numq);
+ quiz_add_quiz_question($numq->id, $quiz);
+ }
+
+ /**
+ * Helper method to add random question to quiz.
+ *
+ * @param component_generator_base $questiongenerator
+ * @param stdClass $quiz
+ * @param array $override
+ */
+ protected function add_one_random_question($questiongenerator, stdClass $quiz, $override = []): void {
+ // Create a random question.
+ $cat = $questiongenerator->create_question_category($override);
+ $questiongenerator->create_question('truefalse', null, ['category' => $cat->id]);
+ $questiongenerator->create_question('essay', null, ['category' => $cat->id]);
+ $this->add_random_questions($quiz->id, 0, $cat->id, 1);
+ }
+
+ /**
+ * Attempt questions for a quiz and user.
+ *
+ * @param stdClass $quiz Quiz to attempt.
+ * @param stdClass $user A user to attempt the quiz.
+ * @param int $attemptnumber
+ * @return array
+ */
+ protected function attempt_quiz(stdClass $quiz, stdClass $user, $attemptnumber = 1): array {
+ $this->setUser($user);
+
+ $starttime = time();
+ $quizobj = quiz_settings::create($quiz->id, $user->id);
+
+ $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
+ $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
+
+ // Start the attempt.
+ $attempt = quiz_create_attempt($quizobj, $attemptnumber, null, $starttime, false, $user->id);
+ quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $starttime);
+ quiz_attempt_save_started($quizobj, $quba, $attempt);
+
+ // Finish the attempt.
+ $attemptobj = quiz_attempt::create($attempt->id);
+ $attemptobj->process_finish($starttime, false);
+
+ $this->setUser();
+ return [$quizobj, $quba, $attemptobj];
+ }
+
+ /**
+ * A helper method to backup test quiz.
+ *
+ * @param stdClass $quiz Quiz to attempt.
+ * @param stdClass $user A user to attempt the quiz.
+ * @return string A backup ID ready to be restored.
+ */
+ protected function backup_quiz(stdClass $quiz, stdClass $user): string {
+ global $CFG;
+
+ // Get the necessary files to perform backup and restore.
+ require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
+ require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
+
+ $backupid = 'test-question-backup-restore';
+
+ $bc = new backup_controller(
+ backup::TYPE_1ACTIVITY,
+ $quiz->cmid,
+ backup::FORMAT_MOODLE,
+ backup::INTERACTIVE_NO,
+ backup::MODE_GENERAL,
+ $user->id,
+ );
+ $bc->execute_plan();
+
+ $results = $bc->get_results();
+ $file = $results['backup_destination'];
+ $fp = get_file_packer('application/vnd.moodle.backup');
+ $filepath = $CFG->dataroot . '/temp/backup/' . $backupid;
+ $file->extract_to_pathname($fp, $filepath);
+ $bc->destroy();
+
+ return $backupid;
+ }
+
+ /**
+ * A helper method to restore provided backup.
+ *
+ * @param string $backupid Backup ID to restore.
+ * @param stdClass $course
+ * @param stdClass $user
+ */
+ protected function restore_quiz(string $backupid, stdClass $course, stdClass $user): void {
+ $rc = new restore_controller($backupid, $course->id,
+ backup::INTERACTIVE_NO, backup::MODE_GENERAL, $user->id, backup::TARGET_CURRENT_ADDING);
+ $this->assertTrue($rc->execute_precheck());
+ $rc->execute_plan();
+ $rc->destroy();
+ }
+
+ /**
+ * A helper method to emulate duplication of the quiz.
+ *
+ * @param stdClass $course
+ * @param stdClass $quiz
+ * @return \cm_info|null
+ */
+ protected function duplicate_quiz($course, $quiz): ?\cm_info {
+ return duplicate_module($course, get_fast_modinfo($course)->get_cm($quiz->cmid));
+ }
+
+ /**
+ * Add random questions to a quiz, with a filter condition based on a category ID.
+ *
+ * @param int $quizid The quiz to add the questions to.
+ * @param int $page The page number to add the questions to.
+ * @param int $categoryid The category ID to use for the filter condition.
+ * @param int $number The number of questions to add.
+ * @return void
+ */
+ protected function add_random_questions(int $quizid, int $page, int $categoryid, int $number): void {
+ $quizobj = quiz_settings::create($quizid);
+ $structure = $quizobj->get_structure();
+ $filtercondition = [
+ 'filter' => [
+ 'category' => [
+ 'jointype' => \core_question\local\bank\condition::JOINTYPE_DEFAULT,
+ 'values' => [$categoryid],
+ 'filteroptions' => ['includesubcategories' => false],
+ ],
+ ],
+ ];
+ $structure->add_random_questions($page, $number, $filtercondition);
+ }
+}
diff --git a/mod/quiz/tests/dates_test.php b/mod/quiz/tests/dates_test.php
index b550f1690edad..5b0c135612c59 100644
--- a/mod/quiz/tests/dates_test.php
+++ b/mod/quiz/tests/dates_test.php
@@ -43,7 +43,7 @@ class dates_test extends advanced_testcase {
* Data provider for get_dates_for_module().
* @return array[]
*/
- public function get_dates_for_module_provider(): array {
+ public static function get_dates_for_module_provider(): array {
$now = time();
$before = $now - DAYSECS;
$earlier = $before - DAYSECS;
diff --git a/mod/quiz/tests/lib_test.php b/mod/quiz/tests/lib_test.php
index 4b0536b4a487e..540f34d74d026 100644
--- a/mod/quiz/tests/lib_test.php
+++ b/mod/quiz/tests/lib_test.php
@@ -914,7 +914,7 @@ public function test_creation_with_no_calendar_capabilities() {
*
* @return array List of data sets (test cases)
*/
- public function mod_quiz_inplace_editable_provider(): array {
+ public static function mod_quiz_inplace_editable_provider(): array {
return [
'set to A1' => [1, 'A1'],
'set with HTML characters' => [2, 'A & & <-:'],
diff --git a/mod/quiz/tests/locallib_test.php b/mod/quiz/tests/locallib_test.php
index 9a79fab38d9eb..8e11b8cdd9656 100644
--- a/mod/quiz/tests/locallib_test.php
+++ b/mod/quiz/tests/locallib_test.php
@@ -60,7 +60,7 @@ public function test_quiz_rescale_grade() {
format_float(0.247, 3));
}
- public function quiz_attempt_state_data_provider() {
+ public static function quiz_attempt_state_data_provider(): array {
return [
[quiz_attempt::IN_PROGRESS, null, null, display_options::DURING],
[quiz_attempt::FINISHED, -90, null, display_options::IMMEDIATELY_AFTER],
diff --git a/mod/quiz/tests/quiz_question_helper_test_trait.php b/mod/quiz/tests/quiz_question_helper_test_trait.php
index c5b2220c489bc..754a05802438e 100644
--- a/mod/quiz/tests/quiz_question_helper_test_trait.php
+++ b/mod/quiz/tests/quiz_question_helper_test_trait.php
@@ -12,196 +12,16 @@
// 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 .
-use mod_quiz\quiz_attempt;
-use mod_quiz\quiz_settings;
+// along with Moodle. If not, see .
/**
- * Helper trait for quiz question unit tests.
+ * Trait helper.
*
- * This trait helps to execute different tests for quiz, for example if it needs to create a quiz, add question
- * to the question, add random quetion to the quiz, do a backup or restore.
- *
- * @package mod_quiz
- * @category test
- * @copyright 2021 Catalyst IT Australia Pty Ltd
- * @author Safat Shahin
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package mod_quiz
+ * @category test
+ * @copyright 2013 The Open University
+ * @author Jamie Pratt
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-trait quiz_question_helper_test_trait {
-
- /** @var \stdClass $course Test course to contain quiz. */
- protected $course;
-
- /** @var \stdClass $quiz A test quiz. */
- protected $quiz;
-
- /** @var \stdClass $user A test logged-in user. */
- protected $user;
-
- /**
- * Create a test quiz for the specified course.
- *
- * @param \stdClass $course
- * @return \stdClass
- */
- protected function create_test_quiz(\stdClass $course): \stdClass {
-
- /** @var mod_quiz_generator $quizgenerator */
- $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
-
- return $quizgenerator->create_instance([
- 'course' => $course->id,
- 'questionsperpage' => 0,
- 'grade' => 100.0,
- 'sumgrades' => 2,
- ]);
- }
-
- /**
- * Helper method to add regular questions in quiz.
- *
- * @param component_generator_base $questiongenerator
- * @param \stdClass $quiz
- * @param array $override
- */
- protected function add_two_regular_questions($questiongenerator, \stdClass $quiz, $override = null): void {
- // Create a couple of questions.
- $cat = $questiongenerator->create_question_category($override);
-
- $saq = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
- // Create another version.
- $questiongenerator->update_question($saq);
- quiz_add_quiz_question($saq->id, $quiz);
- $numq = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]);
- // Create two version.
- $questiongenerator->update_question($numq);
- $questiongenerator->update_question($numq);
- quiz_add_quiz_question($numq->id, $quiz);
- }
-
- /**
- * Helper method to add random question to quiz.
- *
- * @param component_generator_base $questiongenerator
- * @param \stdClass $quiz
- * @param array $override
- */
- protected function add_one_random_question($questiongenerator, \stdClass $quiz, $override = []): void {
- // Create a random question.
- $cat = $questiongenerator->create_question_category($override);
- $questiongenerator->create_question('truefalse', null, ['category' => $cat->id]);
- $questiongenerator->create_question('essay', null, ['category' => $cat->id]);
- $this->add_random_questions($quiz->id, 0, $cat->id, 1);
- }
-
- /**
- * Attempt questions for a quiz and user.
- *
- * @param \stdClass $quiz Quiz to attempt.
- * @param \stdClass $user A user to attempt the quiz.
- * @param int $attemptnumber
- * @return array
- */
- protected function attempt_quiz(\stdClass $quiz, \stdClass $user, $attemptnumber = 1): array {
- $this->setUser($user);
-
- $starttime = time();
- $quizobj = quiz_settings::create($quiz->id, $user->id);
-
- $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
- $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
-
- // Start the attempt.
- $attempt = quiz_create_attempt($quizobj, $attemptnumber, null, $starttime, false, $user->id);
- quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $starttime);
- quiz_attempt_save_started($quizobj, $quba, $attempt);
-
- // Finish the attempt.
- $attemptobj = quiz_attempt::create($attempt->id);
- $attemptobj->process_finish($starttime, false);
-
- $this->setUser();
- return [$quizobj, $quba, $attemptobj];
- }
-
- /**
- * A helper method to backup test quiz.
- *
- * @param \stdClass $quiz Quiz to attempt.
- * @param \stdClass $user A user to attempt the quiz.
- * @return string A backup ID ready to be restored.
- */
- protected function backup_quiz(\stdClass $quiz, \stdClass $user): string {
- global $CFG;
-
- // Get the necessary files to perform backup and restore.
- require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
- require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
-
- $backupid = 'test-question-backup-restore';
-
- $bc = new backup_controller(backup::TYPE_1ACTIVITY, $quiz->cmid, backup::FORMAT_MOODLE,
- backup::INTERACTIVE_NO, backup::MODE_GENERAL, $user->id);
- $bc->execute_plan();
-
- $results = $bc->get_results();
- $file = $results['backup_destination'];
- $fp = get_file_packer('application/vnd.moodle.backup');
- $filepath = $CFG->dataroot . '/temp/backup/' . $backupid;
- $file->extract_to_pathname($fp, $filepath);
- $bc->destroy();
-
- return $backupid;
- }
-
- /**
- * A helper method to restore provided backup.
- *
- * @param string $backupid Backup ID to restore.
- * @param stdClass $course
- * @param stdClass $user
- */
- protected function restore_quiz(string $backupid, stdClass $course, stdClass $user): void {
- $rc = new restore_controller($backupid, $course->id,
- backup::INTERACTIVE_NO, backup::MODE_GENERAL, $user->id, backup::TARGET_CURRENT_ADDING);
- $this->assertTrue($rc->execute_precheck());
- $rc->execute_plan();
- $rc->destroy();
- }
-
- /**
- * A helper method to emulate duplication of the quiz.
- *
- * @param stdClass $course
- * @param stdClass $quiz
- * @return \cm_info|null
- */
- protected function duplicate_quiz($course, $quiz): ?\cm_info {
- return duplicate_module($course, get_fast_modinfo($course)->get_cm($quiz->cmid));
- }
- /**
- * Add random questions to a quiz, with a filter condition based on a category ID.
- *
- * @param int $quizid The quiz to add the questions to.
- * @param int $page The page number to add the questions to.
- * @param int $categoryid The category ID to use for the filter condition.
- * @param int $number The number of questions to add.
- * @return void
- */
- protected function add_random_questions(int $quizid, int $page, int $categoryid, int $number): void {
- $quizobj = quiz_settings::create($quizid);
- $structure = $quizobj->get_structure();
- $filtercondition = [
- 'filter' => [
- 'category' => [
- 'jointype' => \qbank_managecategories\category_condition::JOINTYPE_DEFAULT,
- 'values' => [$categoryid],
- 'filteroptions' => ['includesubcategories' => false],
- ],
- ],
- ];
- $structure->add_random_questions($page, $number, $filtercondition);
- }
-}
+class_alias(\mod_quiz\tests\question_helper_test_trait::class, \quiz_question_helper_test_trait::class);
diff --git a/mod/quiz/upgrade.txt b/mod/quiz/upgrade.txt
index dcef03bf008b1..e95c9103be3bd 100644
--- a/mod/quiz/upgrade.txt
+++ b/mod/quiz/upgrade.txt
@@ -1,5 +1,11 @@
This file describes API changes in the quiz code.
+=== 4.3.9 ===
+* A new test-case, `\mod_quiz\tests\attempt_walkthrough_testcase`, has been extracted from the
+ `\mod_quiz\attempt_walkthrough_from_csv_test` unit test and should be used instead.
+ To support this testcase the existing `$files` instance property should be replaced with a new static method,
+ `::get_test_files`. Both the existing instance property and the new static method can co-exist.
+
=== 4.3.4 ===
* There is a new function qbank_helper::get_version_information_for_questions_in_attempt to efficiently
check whether each question in an attempt is using the latest versions. This is used by re-grading,
diff --git a/mod/resource/tests/behat/resource_activity_completion.feature b/mod/resource/tests/behat/resource_activity_completion.feature
index 9f2b93d55469e..9169ff32daef7 100644
--- a/mod/resource/tests/behat/resource_activity_completion.feature
+++ b/mod/resource/tests/behat/resource_activity_completion.feature
@@ -68,7 +68,7 @@ Feature: View activity completion information for file resources
And the manual completion button of "Myfile" is displayed as "Done"
@javascript
- Scenario: View automatic completion items
+ Scenario: A student can complete a resource activity by viewing it
Given the following "activities" exist:
| activity | course | name | display | defaultfilename | uploaded |
| resource | C1 | Myfile | 1 | mod/resource/tests/fixtures/samplefile.txt | 1 |
diff --git a/mod/scorm/tests/behat/scorm_activity_completion.feature b/mod/scorm/tests/behat/scorm_activity_completion.feature
index a27e28c5fcb82..08777a3883e82 100644
--- a/mod/scorm/tests/behat/scorm_activity_completion.feature
+++ b/mod/scorm/tests/behat/scorm_activity_completion.feature
@@ -33,7 +33,7 @@ Feature: View activity completion in the SCORM activity
| completionusegrade | 1 |
@javascript
- Scenario: View automatic completion items as a teacher
+ Scenario: A teacher can view a SCORM activity automatic completion conditions
Given I am on the "Music history" "scorm activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
And "Music history" should have the "Receive a score of 3 or more" completion condition
@@ -51,7 +51,7 @@ Feature: View activity completion in the SCORM activity
And I should not see "Passing grade"
@javascript
- Scenario: View automatic completion items as a student
+ Scenario: A student can complete a SCORM activity by achieving a passing grade
Given I am on the "Music history" "scorm activity" page logged in as student1
# We need a little taller window because Firefox is, apparently, unable to auto-scroll within
# an iframe, so we need to ensure that the "Save changes" button is visible in the viewport.
@@ -117,7 +117,7 @@ Feature: View activity completion in the SCORM activity
And the "Complete or pass the activity" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the scorm activity as done but a teacher cannot
Given I am on the "Music history" "scorm activity" page logged in as teacher1
And I navigate to "Settings" in current page administration
And I expand all fieldsets
diff --git a/mod/scorm/tests/custom_completion_test.php b/mod/scorm/tests/custom_completion_test.php
index cf267af1c7685..fdb083d4282c4 100644
--- a/mod/scorm/tests/custom_completion_test.php
+++ b/mod/scorm/tests/custom_completion_test.php
@@ -44,7 +44,7 @@ class custom_completion_test extends advanced_testcase {
*
* @return array[]
*/
- public function get_state_provider(): array {
+ public static function get_state_provider(): array {
// Prepare various reusable user scorm track data used to mock various completion states/requirements.
$completionincomplete = (object) [
@@ -301,7 +301,7 @@ public function test_is_defined() {
*
* @return array[]
*/
- public function get_available_custom_rules_provider(): array {
+ public static function get_available_custom_rules_provider(): array {
return [
'Completion status enabled only' => [
[
diff --git a/mod/scorm/tests/dates_test.php b/mod/scorm/tests/dates_test.php
index 363e5444af981..f9cf79c1dcc1c 100644
--- a/mod/scorm/tests/dates_test.php
+++ b/mod/scorm/tests/dates_test.php
@@ -43,7 +43,7 @@ class dates_test extends advanced_testcase {
* Data provider for get_dates_for_module().
* @return array[]
*/
- public function get_dates_for_module_provider(): array {
+ public static function get_dates_for_module_provider(): array {
$now = time();
$before = $now - DAYSECS;
$earlier = $before - DAYSECS;
diff --git a/mod/scorm/tests/event/events_test.php b/mod/scorm/tests/event/events_test.php
index deafc58c07c95..2828ad3797a12 100644
--- a/mod/scorm/tests/event/events_test.php
+++ b/mod/scorm/tests/event/events_test.php
@@ -195,7 +195,7 @@ public function test_user_report_viewed_event_validations() {
/**
* dataProvider for test_scoreraw_submitted_event().
*/
- public function get_scoreraw_submitted_event_provider() {
+ public static function get_scoreraw_submitted_event_provider() {
return array(
// SCORM 1.2.
// - cmi.core.score.raw.
@@ -219,7 +219,7 @@ public function get_scoreraw_submitted_event_provider() {
/**
* dataProvider for test_scoreraw_submitted_event_validations().
*/
- public function get_scoreraw_submitted_event_validations() {
+ public static function get_scoreraw_submitted_event_validations(): array {
return array(
'scoreraw_submitted => missing cmielement' => array(
null, '50',
@@ -280,7 +280,7 @@ public function test_scoreraw_submitted_event_validations($cmielement, $cmivalue
/**
* dataProvider for test_status_submitted_event().
*/
- public function get_status_submitted_event_provider() {
+ public static function get_status_submitted_event_provider() {
return array(
// SCORM 1.2.
// 1. Status: cmi.core.lesson_status.
@@ -306,7 +306,7 @@ public function get_status_submitted_event_provider() {
/**
* dataProvider for test_status_submitted_event_validations().
*/
- public function get_status_submitted_event_validations() {
+ public static function get_status_submitted_event_validations(): array {
return array(
'status_submitted => missing cmielement' => array(
null, 'passed',
diff --git a/mod/survey/tests/behat/survey_completion.feature b/mod/survey/tests/behat/survey_completion.feature
index 2c2c681094137..707f0014221f6 100644
--- a/mod/survey/tests/behat/survey_completion.feature
+++ b/mod/survey/tests/behat/survey_completion.feature
@@ -50,7 +50,7 @@ Feature: A teacher can use activity completion to track a student progress
And I follow "Test survey name"
And the "Submit answers" completion condition of "Test survey name" is displayed as "done"
- Scenario: Use manual completion
+ Scenario: A student can manually mark the survey activity as done but a teacher cannot
Given the following "activities" exist:
| activity | name | course | idnumber | completion |
| survey | Test survey name | C1 | survey1 | 1 |
diff --git a/mod/survey/tests/custom_completion_test.php b/mod/survey/tests/custom_completion_test.php
index 08b12b7cb0497..98373d8e05b98 100644
--- a/mod/survey/tests/custom_completion_test.php
+++ b/mod/survey/tests/custom_completion_test.php
@@ -51,7 +51,7 @@ class custom_completion_test extends advanced_testcase {
*
* @return array[]
*/
- public function get_state_provider(): array {
+ public static function get_state_provider(): array {
return [
'Undefined rule' => [
'somenonexistentrule', COMPLETION_DISABLED, false, null, coding_exception::class
@@ -174,7 +174,7 @@ public function test_is_defined() {
*
* @return array[]
*/
- public function get_available_custom_rules_provider(): array {
+ public static function get_available_custom_rules_provider(): array {
return [
'Completion submit available' => [
COMPLETION_ENABLED, ['completionsubmit']
diff --git a/mod/url/tests/behat/url_activity_completion.feature b/mod/url/tests/behat/url_activity_completion.feature
index 052c03a7e928f..b86e2a130cceb 100644
--- a/mod/url/tests/behat/url_activity_completion.feature
+++ b/mod/url/tests/behat/url_activity_completion.feature
@@ -19,7 +19,7 @@ Feature: View activity completion information in the URL resource
And the following config values are set as admin:
| displayoptions | 0,1,2,3,4,5,6 | url |
- Scenario: View automatic completion items in automatic display mode as teacher
+ Scenario: URL resource module displays completion conditions to teachers
Given the following "activity" exists:
| activity | url |
| course | C1 |
@@ -35,7 +35,7 @@ Feature: View activity completion information in the URL resource
And I should see "Click on Music history to open the resource."
And "Music history" should have the "View" completion condition
- Scenario: View automatic completion items in automatic display mode as student
+ Scenario: A student can complete a URL activity by viewing it
Given the following "activity" exists:
| activity | url |
| course | C1 |
@@ -49,7 +49,7 @@ Feature: View activity completion information in the URL resource
When I am on the "Music history" "url activity" page logged in as student1
Then the "View" completion condition of "Music history" is displayed as "done"
- Scenario: View automatic completion items in embed display mode as teacher
+ Scenario: A teacher can view a URL activity completion conditions in embed display mode
Given the following "activity" exists:
| activity | url |
| course | C1 |
@@ -63,7 +63,7 @@ Feature: View activity completion information in the URL resource
When I am on the "Music history" "url activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
- Scenario: View automatic completion items in embed display mode as student
+ Scenario: A student can complete a url resource by viewing it in embed display mode
Given the following "activity" exists:
| activity | url |
| course | C1 |
@@ -78,7 +78,7 @@ Feature: View activity completion information in the URL resource
Then the "View" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: View automatic completion items in open display mode as teacher
+ Scenario: A teacher can view url resource automatic completion items in open display mode as teacher
Given the following "activity" exists:
| activity | url |
| course | C1 |
@@ -94,7 +94,7 @@ Feature: View activity completion information in the URL resource
Then "Music history" should have the "View" completion condition
@javascript
- Scenario: View automatic completion items in open display mode as student
+ Scenario: A student can view url resource automatic completion items in open display mode
Given the following "activity" exists:
| activity | url |
| course | C1 |
@@ -109,7 +109,7 @@ Feature: View activity completion information in the URL resource
And I am on the "Course 1" course page
Then the "View" completion condition of "Music history" is displayed as "done"
- Scenario: View automatic completion items in pop-up display mode as teacher
+ Scenario: An URL resource shows automatic completion conditions in pop-up display mode as teacher
Given the following "activity" exists:
| activity | url |
| course | C1 |
@@ -125,7 +125,7 @@ Feature: View activity completion information in the URL resource
When I am on the "Music history" "url activity" page logged in as student1
Then "Music history" should have the "View" completion condition
- Scenario: View automatic completion items in pop-up display mode as student
+ Scenario: View url resource automatic completion conditions in pop-up display mode as student
Given the following "activity" exists:
| activity | url |
| course | C1 |
@@ -142,7 +142,7 @@ Feature: View activity completion information in the URL resource
Then the "View" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion with automatic URL as teacher
+ Scenario: A teacher cannot manually mark the url activity as done
Given the following "activity" exists:
| activity | url |
| course | C1 |
@@ -157,7 +157,7 @@ Feature: View activity completion information in the URL resource
Then the manual completion button for "Music history" should be disabled
@javascript
- Scenario: Use manual completion with automatic URL as student
+ Scenario: A student can manually mark the url activity as done
Given the following "activity" exists:
| activity | url |
| course | C1 |
diff --git a/mod/wiki/tests/behat/wiki_activity_completion.feature b/mod/wiki/tests/behat/wiki_activity_completion.feature
index 8946d25623364..2aa2f263de9a7 100644
--- a/mod/wiki/tests/behat/wiki_activity_completion.feature
+++ b/mod/wiki/tests/behat/wiki_activity_completion.feature
@@ -26,7 +26,7 @@ Feature: View activity completion information in the Wiki activity
And I am on the "Music history" "wiki activity" page logged in as teacher1
And I click on "Create page" "button"
- Scenario: View automatic completion items as a teacher and confirm all tabs display conditions
+ Scenario: View automatic wiki completion conditions as a teacher and confirm all tabs display conditions
When I am on the "Music history" "wiki activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
And I select "Edit" from the "jump" singleselect
@@ -40,12 +40,12 @@ Feature: View activity completion information in the Wiki activity
And I select "Administration" from the "jump" singleselect
And "Music history" should have the "View" completion condition
- Scenario: View automatic completion items as a student
+ Scenario: A students can complete a wiki activity by viewing it
When I am on the "Music history" "wiki activity" page logged in as student1
Then the "View" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the wiki activity as done but a teacher cannot
Given I am on the "Music history" "wiki activity" page logged in as teacher1
And I am on the "Music history" "wiki activity editing" page
And I expand all fieldsets
diff --git a/mod/wiki/tests/wikiparser_test.php b/mod/wiki/tests/wikiparser_test.php
index d267cb5b51764..d878a9e4338a8 100644
--- a/mod/wiki/tests/wikiparser_test.php
+++ b/mod/wiki/tests/wikiparser_test.php
@@ -64,7 +64,7 @@ public function test_urls_inside_link_text(string $markup, string $input, string
*
* @return array
*/
- public function urls_inside_link_text_provider() {
+ public static function urls_inside_link_text_provider(): array {
return [
'creole implicit link' => [
'markup' => 'creole',
diff --git a/mod/workshop/tests/behat/workshop_activity_completion.feature b/mod/workshop/tests/behat/workshop_activity_completion.feature
index 6e504236446b1..99a37d2fe3b65 100644
--- a/mod/workshop/tests/behat/workshop_activity_completion.feature
+++ b/mod/workshop/tests/behat/workshop_activity_completion.feature
@@ -30,12 +30,12 @@ Feature: View activity completion information in the Workshop activity
| id_description__idx_0_editor | Aspect1 |
And I change phase in workshop "Music history" to "Submission phase"
- Scenario: View automatic completion items as a teacher
+ Scenario: The workshop module displays automatic completion conditions to teachers
Given I am on the "Music history" "workshop activity" page
Then "Music history" should have the "Receive a grade" completion condition
And "Music history" should have the "View" completion condition
- Scenario: View automatic completion items as a student
+ Scenario: Students can complete a workshop activity by achieving a passing grade
Given I am on the "Music history" "workshop activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
@@ -66,7 +66,7 @@ Feature: View activity completion information in the Workshop activity
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
@javascript
- Scenario: Use manual completion
+ Scenario: A student can manually mark the workshop activity as done but a teacher cannot
Given I am on the "Music history" "workshop activity" page
And I am on the "Music history" "workshop activity editing" page
And I expand all fieldsets
diff --git a/mod/workshop/tests/behat/workshop_submission_view.feature b/mod/workshop/tests/behat/workshop_submission_view.feature
new file mode 100644
index 0000000000000..6ba2003111a38
--- /dev/null
+++ b/mod/workshop/tests/behat/workshop_submission_view.feature
@@ -0,0 +1,75 @@
+@mod @mod_workshop
+Feature: Student can view their submission assessments
+ In order to view submission assessments when workshop is closed
+ As a teacher
+ I should be able to set the workshop to closed phase
+
+ Background:
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | teacher1 | Teacher | One | teacher1@example.com |
+ | student1 | One | Student | student1@example.com |
+ | student2 | Two | Student | student2@example.com |
+ And the following "courses" exist:
+ | fullname | shortname |
+ | Course 1 | C1 |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teacher1 | C1 | editingteacher |
+ | student1 | C1 | student |
+ | student2 | C1 | student |
+ And the following "activities" exist:
+ | activity | name | course | submissiontypetext |
+ | workshop | Workshop 1 | C1 | 2 |
+ And I am on the "Workshop 1" "workshop activity" page logged in as teacher1
+ And I edit assessment form in workshop "Workshop 1" as:
+ | id_description__idx_0_editor | Aspect1 |
+ And I change phase in workshop "Workshop 1" to "Submission phase"
+ # Create workshop submissions.
+ And I am on the "Workshop 1" "workshop activity" page logged in as student1
+ And I add a submission in workshop "Workshop 1" as:
+ | Title | Submission 1 |
+ | Submission content | Submission 1 content |
+ And I am on the "Workshop 1" "workshop activity" page logged in as student2
+ And I add a submission in workshop "Workshop 1" as:
+ | Title | Submission 2 |
+ | Submission content | Submission 2 content |
+ And I am on the "Workshop 1" "workshop activity" page logged in as teacher1
+ And I change phase in workshop "Workshop 1" to "Assessment phase"
+ # Allocate and assess submissions.
+ And I allocate submissions in workshop "Workshop 1" as:
+ | Participant | Reviewer |
+ | One Student | Two Student |
+ | Two Student | One Student |
+ And I am on the "Workshop 1" "workshop activity" page logged in as student1
+ And I assess submission "Two" in workshop "Workshop 1" as:
+ | grade__idx_0 | 5 / 10 |
+ | peercomment__idx_0 | You can do better |
+ And I am on the "Workshop 1" "workshop activity" page logged in as student2
+ And I assess submission "One" in workshop "Workshop 1" as:
+ | grade__idx_0 | 8 / 10 |
+ | peercomment__idx_0 | Great job! |
+
+ Scenario: Student can view their submission assessment after workshop is closed
+ # Re-calculate grades to generate workshop grades from assessment.
+ Given I am on the "Course 1" course page logged in as teacher1
+ And I change phase in workshop "Workshop 1" to "Grading evaluation phase"
+ And I am on the "Workshop 1" "workshop activity" page
+ And I click on "Re-calculate grades" "button"
+ # Close workshop activity.
+ And I change phase in workshop "Workshop 1" to "Closed"
+ When I am on the "Course 1" "grades > Grader report > View" page
+ # Confirm that grades are reflected on the gradebook.
+ Then the following should exist in the "user-grades" table:
+ | -1- | -2- | -3- |
+ | One Student | student1@example.com | 64.00 |
+ | Two Student | student2@example.com | 40.00 |
+ # Confirm that student can view submission assessment grades and comments after workshop is closed.
+ And I am on the "Workshop 1" "workshop activity" page logged in as student1
+ And I click on "Submission 1" "link"
+ And I should see "8 / 10"
+ And I should see "Great job!"
+ And I am on the "Workshop 1" "workshop activity" page logged in as student2
+ And I click on "Submission 2" "link"
+ And I should see "5 / 10"
+ And I should see "You can do better"
diff --git a/mod/workshop/tests/dates_test.php b/mod/workshop/tests/dates_test.php
index 0484a5d146f05..3c49437bf816b 100644
--- a/mod/workshop/tests/dates_test.php
+++ b/mod/workshop/tests/dates_test.php
@@ -43,7 +43,7 @@ class dates_test extends advanced_testcase {
* Data provider for get_dates_for_module().
* @return array[]
*/
- public function get_dates_for_module_provider(): array {
+ public static function get_dates_for_module_provider(): array {
$now = time();
$before = $now - DAYSECS;
$earlier = $before - DAYSECS;
diff --git a/mod/workshop/tests/lib_test.php b/mod/workshop/tests/lib_test.php
index ef6c2005f74fa..eddb14b9c53a9 100644
--- a/mod/workshop/tests/lib_test.php
+++ b/mod/workshop/tests/lib_test.php
@@ -537,7 +537,7 @@ public function test_mod_workshop_core_calendar_get_valid_event_timestart_range_
*
* @return array of (submissionstart, submissionend, assessmentstart, assessmentend, eventtype, expectedmin, expectedmax)
*/
- public function mod_workshop_core_calendar_get_valid_event_timestart_range_due_no_limit_provider() {
+ public static function mod_workshop_core_calendar_get_valid_event_timestart_range_due_no_limit_provider(): array {
$submissionstart = time() + DAYSECS;
$submissionend = $submissionstart + DAYSECS;
$assessmentstart = $submissionend + DAYSECS;
@@ -692,7 +692,7 @@ public function test_mod_workshop_core_calendar_event_timestart_updated_unknown_
*
* @return array of (submissionstart, submissionend, assessmentstart, assessmentend, eventtype, fieldtoupdate, newtime)
*/
- public function mod_workshop_core_calendar_event_timestart_updated_provider() {
+ public static function mod_workshop_core_calendar_event_timestart_updated_provider(): array {
$submissionstart = time() + DAYSECS;
$submissionend = $submissionstart + DAYSECS;
$assessmentstart = $submissionend + DAYSECS;
diff --git a/notes/tests/reportbuilder/datasource/notes_test.php b/notes/tests/reportbuilder/datasource/notes_test.php
index 9ddf227fd901f..ee4b504f6ef2e 100644
--- a/notes/tests/reportbuilder/datasource/notes_test.php
+++ b/notes/tests/reportbuilder/datasource/notes_test.php
@@ -136,7 +136,7 @@ public function test_datasource_non_default_columns(): void {
*
* @return array[]
*/
- public function datasource_filters_provider(): array {
+ public static function datasource_filters_provider(): array {
return [
'Filter content' => ['content', 'Cool', 'note:content', [
'note:content_operator' => text::IS_EQUAL_TO,
diff --git a/payment/tests/helper_test.php b/payment/tests/helper_test.php
index 13fe85b627d85..eb9e9b5a025ff 100644
--- a/payment/tests/helper_test.php
+++ b/payment/tests/helper_test.php
@@ -137,7 +137,7 @@ public function test_archive_restore_account() {
*
* @return array
*/
- public function get_rounded_cost_provider(): array {
+ public static function get_rounded_cost_provider(): array {
return [
'IRR 0 surcharge' => [5.345, 'IRR', 0, 5],
'IRR 12% surcharge' => [5.345, 'IRR', 12, 6],
@@ -151,7 +151,7 @@ public function get_rounded_cost_provider(): array {
*
* @return array[]
*/
- public function get_cost_as_string_provider(): array {
+ public static function get_cost_as_string_provider(): array {
return [
'IRR 0 surcharge' => [5.345, 'IRR', 0, 'IRR'."\xc2\xa0".'5'],
'IRR 12% surcharge' => [5.345, 'IRR', 12, 'IRR'."\xc2\xa0".'6'],
diff --git a/privacy/tests/collection_test.php b/privacy/tests/collection_test.php
index 1a1c81025a2fc..9a7c482c70665 100644
--- a/privacy/tests/collection_test.php
+++ b/privacy/tests/collection_test.php
@@ -199,7 +199,7 @@ public function test_link_plugintype() {
*
* @return array
*/
- public function component_list_provider() {
+ public static function component_list_provider(): array {
return [
['core_privacy'],
['mod_forum'],
diff --git a/privacy/tests/contextlist_base_test.php b/privacy/tests/contextlist_base_test.php
index 851710e55333a..bdef2e312c457 100644
--- a/privacy/tests/contextlist_base_test.php
+++ b/privacy/tests/contextlist_base_test.php
@@ -64,7 +64,7 @@ public function test_get_contextids($input, $expected, $count) {
*
* @return array
*/
- public function get_contextids_provider() {
+ public static function get_contextids_provider(): array {
return [
'basic' => [
[1, 2, 3, 4, 5],
diff --git a/privacy/tests/contextlist_test.php b/privacy/tests/contextlist_test.php
index b81cdd631d37b..a7038d0066c6b 100644
--- a/privacy/tests/contextlist_test.php
+++ b/privacy/tests/contextlist_test.php
@@ -138,7 +138,7 @@ public function test_guess_id_field_from_sql($sql, $expected) {
*
* @return array
*/
- public function data_guess_id_field_from_sql() {
+ public static function data_guess_id_field_from_sql(): array {
return [
'easy' => [
'SELECT contextid FROM {foo}',
diff --git a/privacy/tests/manager_test.php b/privacy/tests/manager_test.php
index f749609a31948..c91002e8ab8e0 100644
--- a/privacy/tests/manager_test.php
+++ b/privacy/tests/manager_test.php
@@ -138,7 +138,7 @@ public function test_component_is_compliant() {
*
* @return array
*/
- public function component_is_compliant_provider() {
+ public static function component_is_compliant_provider(): array {
return [
'An empty subsystem' => [
'core_countries',
@@ -294,7 +294,7 @@ public function test_is_empty_subsystem($component, $expected) {
*
* @return array
*/
- public function is_empty_subsystem_provider() {
+ public static function is_empty_subsystem_provider(): array {
return [
'A subsystem which has no directory' => [
'core_langconfig',
diff --git a/privacy/tests/moodle_content_writer_test.php b/privacy/tests/moodle_content_writer_test.php
index e2d8de216fe65..939ef1dd546f3 100644
--- a/privacy/tests/moodle_content_writer_test.php
+++ b/privacy/tests/moodle_content_writer_test.php
@@ -173,7 +173,7 @@ public function test_export_data_multiple_writes_same_context() {
/**
* Data provider for exporting user data.
*/
- public function export_data_provider() {
+ public static function export_data_provider(): array {
return [
'basic' => [
(object) [
@@ -308,7 +308,7 @@ public function test_export_metadata_to_multiple_contexts() {
*
* return array
*/
- public function export_metadata_provider() {
+ public static function export_metadata_provider(): array {
return [
'basic' => [
'key',
@@ -472,7 +472,7 @@ public function test_export_file($filearea, $itemid, $filepath, $filename, $cont
*
* @return array
*/
- public function export_file_provider() {
+ public static function export_file_provider(): array {
return [
'basic' => [
'intro',
@@ -858,7 +858,7 @@ public function test_export_user_preference_replace() {
*
* @return array
*/
- public function export_user_preference_provider() {
+ public static function export_user_preference_provider(): array {
return [
'basic' => [
'core_privacy',
@@ -1024,7 +1024,7 @@ public function test_export_user_preference_unescaped_unicode($text) {
*
* @return array
*/
- public function unescaped_unicode_export_provider() {
+ public static function unescaped_unicode_export_provider(): array {
return [
'Unicode' => ['ةكءيٓپچژکگیٹڈڑہھےâîûğŞAaÇÖáǽ你好!'],
];
@@ -1193,7 +1193,7 @@ public function test_export_user_preference_long_filename($longtext, $expected,
*
* @return array
*/
- public function long_filename_provider() {
+ public static function long_filename_provider(): array {
return [
'More than 100 characters' => [
'Etiam sit amet dui vel leo blandit viverra. Proin viverra suscipit velit. Aenean efficitur suscipit nibh nec suscipit',
@@ -1290,7 +1290,7 @@ public function test_rewrite_pluginfile_urls($filearea, $itemid, $input, $expect
*
* @return array
*/
- public function rewrite_pluginfile_urls_provider() {
+ public static function rewrite_pluginfile_urls_provider(): array {
return [
'nullcontent' => [
'intro',
diff --git a/privacy/tests/privacy/provider_test.php b/privacy/tests/privacy/provider_test.php
index d49735378b2b7..87125bba89c67 100644
--- a/privacy/tests/privacy/provider_test.php
+++ b/privacy/tests/privacy/provider_test.php
@@ -46,7 +46,7 @@ class provider_test extends \advanced_testcase {
*
* @return array the array of frankenstyle component names with the relevant class name.
*/
- public function get_component_list() {
+ public static function get_component_list(): array {
$components = ['core' => [
'component' => 'core',
'classname' => manager::get_provider_classname_for_component('core')
@@ -97,12 +97,12 @@ public function test_null_provider($component, $classname) {
*
* @return array
*/
- public function null_provider_provider() {
- return array_filter($this->get_component_list(), function($component) {
- return static::component_implements(
- $component['classname'],
- \core_privacy\local\metadata\null_provider::class
- );
+ public static function null_provider_provider(): array {
+ return array_filter(self::get_component_list(), function($component): bool {
+ return static::component_implements(
+ $component['classname'],
+ \core_privacy\local\metadata\null_provider::class
+ );
});
}
@@ -218,12 +218,12 @@ public function test_userdata_provider_implements_userlist($component) {
*
* @return array
*/
- public function metadata_provider_provider() {
- return array_filter($this->get_component_list(), function($component) {
- return static::component_implements(
- $component['classname'],
- \core_privacy\local\metadata\provider::class
- );
+ public static function metadata_provider_provider(): array {
+ return array_filter(self::get_component_list(), function($component): bool {
+ return static::component_implements(
+ $component['classname'],
+ \core_privacy\local\metadata\provider::class
+ );
});
}
@@ -232,12 +232,12 @@ public function metadata_provider_provider() {
*
* @return array
*/
- public function is_user_data_provider() {
- return array_filter($this->get_component_list(), function($component) {
- return static::component_implements(
- $component['classname'],
- \core_privacy\local\request\core_user_data_provider::class
- );
+ public static function is_user_data_provider(): array {
+ return array_filter(self::get_component_list(), function($component): bool {
+ return static::component_implements(
+ $component['classname'],
+ \core_privacy\local\request\core_user_data_provider::class
+ );
});
}
@@ -310,7 +310,7 @@ public function test_table_coverage() {
}
}
- $componentlist = $this->metadata_provider_provider();
+ $componentlist = self::metadata_provider_provider();
foreach ($componentlist as $componentarray) {
$component = $componentarray['component'];
$classname = $componentarray['classname'];
diff --git a/privacy/tests/request_transform_test.php b/privacy/tests/request_transform_test.php
index 4182273158b65..da5505a7768a1 100644
--- a/privacy/tests/request_transform_test.php
+++ b/privacy/tests/request_transform_test.php
@@ -110,7 +110,7 @@ public function test_yesno($input, $expected) {
*
* @return array
*/
- public function yesno_provider() {
+ public static function yesno_provider(): array {
return [
'Bool False' => [
false,
diff --git a/privacy/tests/types_database_table_test.php b/privacy/tests/types_database_table_test.php
index 9d46af57f6144..714a6b5faf9a9 100644
--- a/privacy/tests/types_database_table_test.php
+++ b/privacy/tests/types_database_table_test.php
@@ -84,7 +84,7 @@ public function test_valid_configs($name, $fields, $summary) {
*
* @return array
*/
- public function invalid_string_provider() {
+ public static function invalid_string_provider(): array {
return [
'Space in summary' => [
'example',
@@ -128,7 +128,7 @@ public function invalid_string_provider() {
*
* @return array
*/
- public function valid_string_provider() {
+ public static function valid_string_provider(): array {
return [
'Valid combination' => [
'example',
diff --git a/privacy/tests/types_external_location_test.php b/privacy/tests/types_external_location_test.php
index 87a39072777f0..34bfa71e52dfb 100644
--- a/privacy/tests/types_external_location_test.php
+++ b/privacy/tests/types_external_location_test.php
@@ -84,7 +84,7 @@ public function test_valid_configs($name, $fields, $summary) {
*
* @return array
*/
- public function invalid_string_provider() {
+ public static function invalid_string_provider(): array {
return [
'Space in summary' => [
'example',
@@ -128,7 +128,7 @@ public function invalid_string_provider() {
*
* @return array
*/
- public function valid_string_provider() {
+ public static function valid_string_provider(): array {
return [
'Valid combination' => [
'example',
diff --git a/privacy/tests/types_plugintype_link_test.php b/privacy/tests/types_plugintype_link_test.php
index 187c5f3b49aaf..e268941a19b47 100644
--- a/privacy/tests/types_plugintype_link_test.php
+++ b/privacy/tests/types_plugintype_link_test.php
@@ -77,7 +77,7 @@ public function test_valid_configs($name, $privacyfields, $summary) {
*
* @return array
*/
- public function invalid_string_provider() {
+ public static function invalid_string_provider(): array {
return [
'Space in summary' => [
'example',
@@ -97,7 +97,7 @@ public function invalid_string_provider() {
*
* @return array
*/
- public function valid_string_provider() {
+ public static function valid_string_provider(): array {
return [
'Valid combination' => [
'example',
diff --git a/privacy/tests/types_subsystem_link_test.php b/privacy/tests/types_subsystem_link_test.php
index 53cc24586e324..aaace71ae4158 100644
--- a/privacy/tests/types_subsystem_link_test.php
+++ b/privacy/tests/types_subsystem_link_test.php
@@ -77,7 +77,7 @@ public function test_valid_configs($name, $privacyfields, $summary) {
*
* @return array
*/
- public function invalid_string_provider() {
+ public static function invalid_string_provider(): array {
return [
'Space in summary' => [
'example',
@@ -97,7 +97,7 @@ public function invalid_string_provider() {
*
* @return array
*/
- public function valid_string_provider() {
+ public static function valid_string_provider(): array {
return [
'Valid combination' => [
'example',
diff --git a/privacy/tests/types_user_preference_test.php b/privacy/tests/types_user_preference_test.php
index 3e2dd30e45248..c0c12b4a64bd2 100644
--- a/privacy/tests/types_user_preference_test.php
+++ b/privacy/tests/types_user_preference_test.php
@@ -77,7 +77,7 @@ public function test_valid_configs($name, $summary) {
*
* @return array
*/
- public function invalid_string_provider() {
+ public static function invalid_string_provider(): array {
return [
'Space in summary' => [
'example',
@@ -95,7 +95,7 @@ public function invalid_string_provider() {
*
* @return array
*/
- public function valid_string_provider() {
+ public static function valid_string_provider(): array {
return [
'Valid combination' => [
'example',
diff --git a/privacy/tests/userlist_base_test.php b/privacy/tests/userlist_base_test.php
index 0a5e7bfe8ba19..9e8ffaf39d19a 100644
--- a/privacy/tests/userlist_base_test.php
+++ b/privacy/tests/userlist_base_test.php
@@ -64,7 +64,7 @@ public function test_get_userids($input, $expected, $count) {
*
* @return array
*/
- public function get_userids_provider() {
+ public static function get_userids_provider(): array {
return [
'basic' => [
[1, 2, 3, 4, 5],
diff --git a/question/bank/bulkmove/tests/behat/bulk_move.feature b/question/bank/bulkmove/tests/behat/bulk_move.feature
index 9acf88e339240..fe9cf4983893a 100644
--- a/question/bank/bulkmove/tests/behat/bulk_move.feature
+++ b/question/bank/bulkmove/tests/behat/bulk_move.feature
@@ -3,15 +3,22 @@ Feature: Use the qbank plugin manager page for bulkmove
In order to check the plugin behaviour with enable and disable
Background:
- Given the following "courses" exist:
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | teacher1 | Teacher | 1 | teacher1@example.com |
+ And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
And the following "question categories" exist:
- | contextlevel | reference | name |
- | Course | C1 | Test questions |
+ | contextlevel | reference | name |
+ | Course | C1 | Test questions |
+ | Course | C1 | Moved questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
@@ -32,3 +39,26 @@ Feature: Use the qbank plugin manager page for bulkmove
And I click on "First question" "checkbox"
And I click on "With selected" "button"
And I should see question bulk action "move"
+
+ @javascript
+ Scenario: Questions can be bulk moved from the question bank
+ Given the following "questions" exist:
+ | questioncategory | qtype | name | questiontext |
+ | Test questions | truefalse | Question 1 | Answer the first question |
+ | Test questions | missingtype | Question 2 | Write something |
+ | Test questions | essay | Question 3 | frog |
+ # Navigate to question bank.
+ And I am on the "Course 1" "core_question > course question bank" page logged in as teacher1
+ # Select questions to be moved.
+ And I click on "Question 1" "checkbox"
+ And I click on "Question 2" "checkbox"
+ And I click on "With selected" "button"
+ When I press "Move to"
+ # Select a different category to move the questions into.
+ And I select "Moved questions" from the "category" singleselect
+ And I press "Move to"
+ # Confirm that selected questions are moved to selected category while unselected questions are not moved.
+ Then I should see "Moved questions"
+ And I should see "Question 1"
+ And I should see "Question 2"
+ And I should not see "Question 3"
diff --git a/question/bank/deletequestion/tests/behat/delete_question_column.feature b/question/bank/deletequestion/tests/behat/delete_question_column.feature
index 2e09b09a4649c..4e6344c5f21a7 100644
--- a/question/bank/deletequestion/tests/behat/delete_question_column.feature
+++ b/question/bank/deletequestion/tests/behat/delete_question_column.feature
@@ -3,9 +3,15 @@ Feature: Use the qbank plugin manager page for deletequestion
In order to check the plugin behaviour with enable and disable
Background:
- Given the following "courses" exist:
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | teacher1 | Teacher | 1 | teacher1@example.com |
+ And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| quiz | Test quiz | C1 | quiz1 |
@@ -69,3 +75,29 @@ Feature: Use the qbank plugin manager page for deletequestion
When I click on "Delete" "button" in the "Delete question?" "dialogue"
Then I should not see "Third question"
And "foo" "autocomplete_selection" should exist
+
+ @javascript
+ Scenario: Questions can be bulk deleted from the question bank
+ Given the following "questions" exist:
+ | questioncategory | qtype | name | questiontext |
+ | Test questions | truefalse | Question 1 | Answer the first question |
+ | Test questions | missingtype | Question 2 | Write something |
+ | Test questions | essay | Question 3 | frog |
+ # Navigate to question bank.
+ And I am on the "Course 1" "core_question > course question bank" page logged in as teacher1
+ # Select questions to be deleted.
+ And I click on "Question 1" "checkbox"
+ And I click on "Question 2" "checkbox"
+ And I click on "With selected" "button"
+ When I press "Delete"
+ # Confirm that delete confirmation message is displayed.
+ Then I should see "This will delete the following questions and all their versions:"
+ # Confirm that selected questions are listed on the confirmation dialog.
+ And I should see "Question 1 v1"
+ And I should see "Question 2 v1"
+ # Delete selected questions.
+ And I press "Delete"
+ # Confirm that selected questions are deleted while unselected questions still exist.
+ And I should not see "Question 1"
+ And I should not see "Question 2"
+ And I should see "Question 3"
diff --git a/question/bank/statistics/tests/helper_test.php b/question/bank/statistics/tests/helper_test.php
index 92e3c2d44b5da..8f9e72befaedb 100644
--- a/question/bank/statistics/tests/helper_test.php
+++ b/question/bank/statistics/tests/helper_test.php
@@ -201,7 +201,7 @@ private function submit_quiz(object $quiz, array $answers): void {
*
* @return array
*/
- private function generate_attempt_answers(array $correctanswerflags): array {
+ private static function generate_attempt_answers(array $correctanswerflags): array {
$attempt = [];
for ($i = 1; $i <= 4; $i++) {
if (isset($correctanswerflags) && $correctanswerflags[$i - 1] == 1) {
@@ -273,31 +273,31 @@ private function load_quiz_statistics_for_place(\context $context): ?all_calcula
*
* @return \Generator
*/
- public function load_question_facility_provider(): \Generator {
+ public static function load_question_facility_provider(): \Generator {
yield 'Facility case 1' => [
'Quiz 1 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
],
'Expected quiz 1 facilities' => ['100.00%', '0.00%', '0.00%', '0.00%'],
'Quiz 2 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
- $this->generate_attempt_answers([1, 1, 0, 0]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 1, 0, 0]),
],
'Expected quiz 2 facilities' => ['100.00%', '50.00%', '0.00%', '0.00%'],
'Expected average facilities' => ['100.00%', '25.00%', '0.00%', '0.00%'],
];
yield 'Facility case 2' => [
'Quiz 1 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
- $this->generate_attempt_answers([1, 1, 0, 0]),
- $this->generate_attempt_answers([1, 1, 1, 0]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 1, 0, 0]),
+ self::generate_attempt_answers([1, 1, 1, 0]),
],
'Expected quiz 1 facilities' => ['100.00%', '66.67%', '33.33%', '0.00%'],
'Quiz 2 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
- $this->generate_attempt_answers([1, 1, 0, 0]),
- $this->generate_attempt_answers([1, 1, 1, 0]),
- $this->generate_attempt_answers([1, 1, 1, 1]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 1, 0, 0]),
+ self::generate_attempt_answers([1, 1, 1, 0]),
+ self::generate_attempt_answers([1, 1, 1, 1]),
],
'Expected quiz 2 facilities' => ['100.00%', '75.00%', '50.00%', '25.00%'],
'Expected average facilities' => ['100.00%', '70.83%', '41.67%', '12.50%'],
@@ -381,20 +381,20 @@ public function test_load_question_facility(
* Data provider for {@see test_load_question_discriminative_efficiency()}.
* @return \Generator
*/
- public function load_question_discriminative_efficiency_provider(): \Generator {
+ public static function load_question_discriminative_efficiency_provider(): \Generator {
yield 'Discriminative efficiency' => [
'Quiz 1 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
- $this->generate_attempt_answers([1, 1, 0, 0]),
- $this->generate_attempt_answers([1, 0, 1, 0]),
- $this->generate_attempt_answers([1, 1, 1, 1]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 1, 0, 0]),
+ self::generate_attempt_answers([1, 0, 1, 0]),
+ self::generate_attempt_answers([1, 1, 1, 1]),
],
'Expected quiz 1 discriminative efficiency' => ['N/A', '33.33%', '33.33%', '100.00%'],
'Quiz 2 attempts' => [
- $this->generate_attempt_answers([1, 1, 1, 1]),
- $this->generate_attempt_answers([0, 0, 0, 0]),
- $this->generate_attempt_answers([1, 0, 0, 1]),
- $this->generate_attempt_answers([0, 1, 1, 0]),
+ self::generate_attempt_answers([1, 1, 1, 1]),
+ self::generate_attempt_answers([0, 0, 0, 0]),
+ self::generate_attempt_answers([1, 0, 0, 1]),
+ self::generate_attempt_answers([0, 1, 1, 0]),
],
'Expected quiz 2 discriminative efficiency' => ['50.00%', '50.00%', '50.00%', '50.00%'],
'Expected average discriminative efficiency' => ['50.00%', '41.67%', '41.67%', '75.00%'],
@@ -502,20 +502,20 @@ public function test_load_question_discriminative_efficiency(
* Data provider for {@see test_load_question_discrimination_index()}.
* @return \Generator
*/
- public function load_question_discrimination_index_provider(): \Generator {
+ public static function load_question_discrimination_index_provider(): \Generator {
yield 'Discrimination Index' => [
'Quiz 1 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
- $this->generate_attempt_answers([1, 1, 0, 0]),
- $this->generate_attempt_answers([1, 0, 1, 0]),
- $this->generate_attempt_answers([1, 1, 1, 1]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 1, 0, 0]),
+ self::generate_attempt_answers([1, 0, 1, 0]),
+ self::generate_attempt_answers([1, 1, 1, 1]),
],
'Expected quiz 1 Discrimination Index' => ['N/A', '30.15%', '30.15%', '81.65%'],
'Quiz 2 attempts' => [
- $this->generate_attempt_answers([1, 1, 1, 1]),
- $this->generate_attempt_answers([0, 0, 0, 0]),
- $this->generate_attempt_answers([1, 0, 0, 1]),
- $this->generate_attempt_answers([0, 1, 1, 0]),
+ self::generate_attempt_answers([1, 1, 1, 1]),
+ self::generate_attempt_answers([0, 0, 0, 0]),
+ self::generate_attempt_answers([1, 0, 0, 1]),
+ self::generate_attempt_answers([0, 1, 1, 0]),
],
'Expected quiz 2 discrimination Index' => ['44.72%', '44.72%', '44.72%', '44.72%'],
'Expected average discrimination Index' => ['44.72%', '37.44%', '37.44%', '63.19%'],
diff --git a/question/bank/tagquestion/tests/external/submit_tags_test.php b/question/bank/tagquestion/tests/external/submit_tags_test.php
index 0d31bc2e0f77e..dbe24e698133f 100644
--- a/question/bank/tagquestion/tests/external/submit_tags_test.php
+++ b/question/bank/tagquestion/tests/external/submit_tags_test.php
@@ -201,7 +201,7 @@ public function test_submit_tags_form_tagmine_permission_non_owner_question() {
*
* @return array Test cases
*/
- public function get_submit_tags_form_testcases() {
+ public static function get_submit_tags_form_testcases(): array {
return [
'course - course' => [
'editingcontext' => 'course',
@@ -283,7 +283,7 @@ public function get_submit_tags_form_testcases() {
* Course tags can only be set on a course category or system context question that
* is being editing in a course context.
*
- * @dataProvider get_submit_tags_form_testcases()
+ * @dataProvider get_submit_tags_form_testcases
* @param string $editingcontext The type of the context the question is being edited in
* @param string $questioncontext The type of the context the question belongs to
* @param string[] $questiontags The tag names to set as question tags
diff --git a/question/editlib.php b/question/editlib.php
index 78559c9ac53fa..f275496de416a 100644
--- a/question/editlib.php
+++ b/question/editlib.php
@@ -275,7 +275,23 @@ function question_build_edit_resources($edittab, $baseurl, $params,
if (!is_array($params['filter'])) {
$params['filter'] = json_decode($params['filter'], true);
}
- $cleanparams['filter'] = $params['filter'];
+ $cleanparams['filter'] = [];
+ foreach ($params['filter'] as $filterkey => $filtervalue) {
+ if ($filterkey == 'jointype') {
+ $cleanparams['filter']['jointype'] = clean_param($filtervalue, PARAM_INT);
+ } else {
+ if (!array_key_exists('name', $filtervalue)) {
+ $filtervalue['name'] = $filterkey;
+ }
+ $cleanfilter = [
+ 'name' => clean_param($filtervalue['name'], PARAM_ALPHANUM),
+ 'jointype' => clean_param($filtervalue['jointype'], PARAM_INT),
+ 'values' => $filtervalue['values'],
+ 'filteroptions' => $filtervalue['filteroptions'] ?? [],
+ ];
+ $cleanparams['filter'][$filterkey] = $cleanfilter;
+ }
+ }
}
if (isset($params['sortdata'])) {
diff --git a/question/engine/tests/datalib_test.php b/question/engine/tests/datalib_test.php
index 373f5cbbaf001..490d29f412011 100644
--- a/question/engine/tests/datalib_test.php
+++ b/question/engine/tests/datalib_test.php
@@ -285,7 +285,7 @@ public function test_cannot_save_a_step_with_a_missing_state(): void {
*
* @return array test cases
*/
- public function get_file_area_name_cases(): array {
+ public static function get_file_area_name_cases(): array {
return [
'simple variable' => ['response_attachments', 'response_attachments'],
'behaviour variable' => ['response_5:answer', 'response_5answer'],
diff --git a/question/engine/tests/question_display_options_test.php b/question/engine/tests/question_display_options_test.php
index 1923c7bc27dc9..ece6c30f22ac7 100644
--- a/question/engine/tests/question_display_options_test.php
+++ b/question/engine/tests/question_display_options_test.php
@@ -32,7 +32,7 @@ class question_display_options_test extends \advanced_testcase {
*
* @return array[]
*/
- public function has_question_identifier_provider(): array {
+ public static function has_question_identifier_provider(): array {
return [
'Empty string' => ['', false],
'Empty space' => [' ', false],
@@ -61,7 +61,7 @@ public function test_has_question_identifier(?string $identifier, bool $expected
*
* @return array[]
*/
- public function add_question_identifier_to_label_provider(): array {
+ public static function add_question_identifier_to_label_provider(): array {
return [
'Empty string identifier' => ['Hello', '', false, false, "Hello"],
'Null identifier' => ['Hello', null, false, false, "Hello"],
diff --git a/question/engine/tests/question_engine_test.php b/question/engine/tests/question_engine_test.php
index edb2aa9fcf8bc..6bc38bd6b5518 100644
--- a/question/engine/tests/question_engine_test.php
+++ b/question/engine/tests/question_engine_test.php
@@ -88,7 +88,7 @@ public function test_get_behaviour_unused_display_options(string $behaviour, arr
*
* @return array
*/
- public function get_behaviour_unused_display_options_provider(): array {
+ public static function get_behaviour_unused_display_options_provider(): array {
return [
'interactive' => [
'interactive',
@@ -126,7 +126,7 @@ public function test_can_questions_finish_during_the_attempt(string $behaviour,
*
* @return array
*/
- public function can_questions_finish_during_the_attempt_provider(): array {
+ public static function can_questions_finish_during_the_attempt_provider(): array {
return [
['deferredfeedback', false],
['interactive', true],
@@ -150,7 +150,7 @@ public function test_sort_behaviours(array $input, array $expected): void {
*
* @return array
*/
- public function sort_behaviours_provider(): array {
+ public static function sort_behaviours_provider(): array {
$in = [
'b1' => 'Behave 1',
'b2' => 'Behave 2',
@@ -221,7 +221,7 @@ public function test_is_manual_grade_in_range(array $post, array $params, bool $
*
* @return array
*/
- public function is_manual_grade_in_range_provider(): array {
+ public static function is_manual_grade_in_range_provider(): array {
return [
'In range' => [
'post' => [
@@ -309,7 +309,7 @@ public function test_render_question_number($value, string $expected): void {
*
* @return array
*/
- public function render_question_number_provider(): array {
+ public static function render_question_number_provider(): array {
return [
'Test with number is i character' => [
'i',
diff --git a/question/engine/tests/questionattempt_with_steps_test.php b/question/engine/tests/questionattempt_with_steps_test.php
index 8ddfb7a518155..e0cc0c7f20cc4 100644
--- a/question/engine/tests/questionattempt_with_steps_test.php
+++ b/question/engine/tests/questionattempt_with_steps_test.php
@@ -169,7 +169,7 @@ public function test_cannot_get_max_fraction_before_start() {
*
* @return array test cases
*/
- public function validate_manual_mark_cases(): array {
+ public static function validate_manual_mark_cases(): array {
// Recall, the DB schema stores question grade information to 7 decimal places.
return [
[0, 1, 2, null, ''],
diff --git a/question/format/gift/tests/giftformat_test.php b/question/format/gift/tests/giftformat_test.php
index ef0321b2ee7f9..52924ae6730bf 100644
--- a/question/format/gift/tests/giftformat_test.php
+++ b/question/format/gift/tests/giftformat_test.php
@@ -366,7 +366,7 @@ public function test_import_multichoice($numberingstyle) {
*
* @return array Array of 1-element arrays of qtype_multichoice numbering styles
*/
- public function numberingstyle_provider() {
+ public static function numberingstyle_provider(): array {
return [
['abc'],
['ABCD'],
@@ -1330,7 +1330,7 @@ public function test_import_question_with_tags() {
*
* @return array the test cases.
*/
- public function extract_idnumber_and_tags_from_comment_testcases() {
+ public static function extract_idnumber_and_tags_from_comment_testcases(): array {
return [
'blank comment' => ['', [], ''],
'nothing in comment' => ['', [], '// A basic comment.'],
diff --git a/question/tests/calculated_question_summary_test.php b/question/tests/calculated_question_summary_test.php
index b90dcf8236628..2d536e7b7096d 100644
--- a/question/tests/calculated_question_summary_test.php
+++ b/question/tests/calculated_question_summary_test.php
@@ -33,7 +33,7 @@ class calculated_question_summary_test extends \advanced_testcase {
*
* @return array
*/
- public function get_min_max_provider() {
+ public static function get_min_max_provider(): array {
return [
'negative number and null' => [
[
@@ -105,7 +105,7 @@ public function test_get_min_max_of($subqstats, $expected) {
*
* @return array
*/
- public function get_sd_min_max_provider() {
+ public static function get_sd_min_max_provider(): array {
return [
'null and number' => [
[
diff --git a/question/tests/externallib_test.php b/question/tests/externallib_test.php
index 7776f84d0bc23..0a27d9f668a56 100644
--- a/question/tests/externallib_test.php
+++ b/question/tests/externallib_test.php
@@ -112,7 +112,7 @@ public function test_core_question_update_flag() {
/**
* Data provider for the get_random_question_summaries test.
*/
- public function get_random_question_summaries_test_cases() {
+ public static function get_random_question_summaries_test_cases(): array {
return [
'empty category' => [
'categoryindex' => 'emptycat',
@@ -184,7 +184,7 @@ public function get_random_question_summaries_test_cases() {
* Parent: cat1
* Category: emptycat
*
- * @dataProvider get_random_question_summaries_test_cases()
+ * @dataProvider get_random_question_summaries_test_cases
* @param string $categoryindex The named index for the category to use
* @param bool $includesubcategories If the search should include subcategories
* @param string[] $usetagnames The tag names to include in the search
diff --git a/question/tests/local/statistics/statistics_bulk_loader_test.php b/question/tests/local/statistics/statistics_bulk_loader_test.php
index 8fd078bc44304..c512568e2ccf4 100644
--- a/question/tests/local/statistics/statistics_bulk_loader_test.php
+++ b/question/tests/local/statistics/statistics_bulk_loader_test.php
@@ -16,8 +16,6 @@
namespace core_question\local\statistics;
-defined('MOODLE_INTERNAL') || die();
-
use advanced_testcase;
use context;
use context_module;
@@ -30,9 +28,6 @@
use question_engine;
use ReflectionMethod;
-global $CFG;
-require_once($CFG->dirroot . '/mod/quiz/tests/quiz_question_helper_test_trait.php');
-
/**
* Tests for question statistics.
*
@@ -41,9 +36,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \core_question\local\statistics\statistics_bulk_loader
*/
-class statistics_bulk_loader_test extends advanced_testcase {
-
- use \quiz_question_helper_test_trait;
+final class statistics_bulk_loader_test extends advanced_testcase {
+ use \mod_quiz\tests\question_helper_test_trait;
/** @var float Delta used when comparing statistics values out-of 1. */
protected const DELTA = 0.00005;
@@ -223,7 +217,7 @@ private function submit_quiz(object $quiz, array $answers): void {
*
* @return array
*/
- private function generate_attempt_answers(array $correctanswerflags): array {
+ private static function generate_attempt_answers(array $correctanswerflags): array {
$attempt = [];
for ($i = 1; $i <= 4; $i++) {
if (isset($correctanswerflags) && $correctanswerflags[$i - 1] == 1) {
@@ -294,31 +288,31 @@ private function load_quiz_statistics_for_place(context $context): ?all_calculat
*
* @return Generator
*/
- public function load_question_facility_provider(): Generator {
+ public static function load_question_facility_provider(): Generator {
yield 'Facility case 1' => [
'Quiz 1 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
],
'Expected quiz 1 facilities' => [1.0, 0.0, 0.0, 0.0],
'Quiz 2 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
- $this->generate_attempt_answers([1, 1, 0, 0]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 1, 0, 0]),
],
'Expected quiz 2 facilities' => [1.0, 0.5, 0.0, 0.0],
'Expected average facilities' => [1.0, 0.25, 0.0, 0.0],
];
yield 'Facility case 2' => [
'Quiz 1 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
- $this->generate_attempt_answers([1, 1, 0, 0]),
- $this->generate_attempt_answers([1, 1, 1, 0]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 1, 0, 0]),
+ self::generate_attempt_answers([1, 1, 1, 0]),
],
'Expected quiz 1 facilities' => [1.0, 0.6667, 0.3333, 0.0],
'Quiz 2 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
- $this->generate_attempt_answers([1, 1, 0, 0]),
- $this->generate_attempt_answers([1, 1, 1, 0]),
- $this->generate_attempt_answers([1, 1, 1, 1]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 1, 0, 0]),
+ self::generate_attempt_answers([1, 1, 1, 0]),
+ self::generate_attempt_answers([1, 1, 1, 1]),
],
'Expected quiz 2 facilities' => [1.0, 0.75, 0.5, 0.25],
'Expected average facilities' => [1.0, 0.7083, 0.4167, 0.1250],
@@ -391,20 +385,20 @@ public function test_load_question_facility(
* Data provider for {@see test_load_question_discriminative_efficiency()}.
* @return Generator
*/
- public function load_question_discriminative_efficiency_provider(): Generator {
+ public static function load_question_discriminative_efficiency_provider(): Generator {
yield 'Discriminative efficiency' => [
'Quiz 1 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
- $this->generate_attempt_answers([1, 1, 0, 0]),
- $this->generate_attempt_answers([1, 0, 1, 0]),
- $this->generate_attempt_answers([1, 1, 1, 1]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 1, 0, 0]),
+ self::generate_attempt_answers([1, 0, 1, 0]),
+ self::generate_attempt_answers([1, 1, 1, 1]),
],
'Expected quiz 1 discriminative efficiency' => [null, 33.33, 33.33, 100.00],
'Quiz 2 attempts' => [
- $this->generate_attempt_answers([1, 1, 1, 1]),
- $this->generate_attempt_answers([0, 0, 0, 0]),
- $this->generate_attempt_answers([1, 0, 0, 1]),
- $this->generate_attempt_answers([0, 1, 1, 0]),
+ self::generate_attempt_answers([1, 1, 1, 1]),
+ self::generate_attempt_answers([0, 0, 0, 0]),
+ self::generate_attempt_answers([1, 0, 0, 1]),
+ self::generate_attempt_answers([0, 1, 1, 0]),
],
'Expected quiz 2 discriminative efficiency' => [50.00, 50.00, 50.00, 50.00],
'Expected average discriminative efficiency' => [50.00, 41.67, 41.67, 75.00],
@@ -485,20 +479,20 @@ public function test_load_question_discriminative_efficiency(
* Data provider for {@see test_load_question_discrimination_index()}.
* @return Generator
*/
- public function load_question_discrimination_index_provider(): Generator {
+ public static function load_question_discrimination_index_provider(): Generator {
yield 'Discrimination Index' => [
'Quiz 1 attempts' => [
- $this->generate_attempt_answers([1, 0, 0, 0]),
- $this->generate_attempt_answers([1, 1, 0, 0]),
- $this->generate_attempt_answers([1, 0, 1, 0]),
- $this->generate_attempt_answers([1, 1, 1, 1]),
+ self::generate_attempt_answers([1, 0, 0, 0]),
+ self::generate_attempt_answers([1, 1, 0, 0]),
+ self::generate_attempt_answers([1, 0, 1, 0]),
+ self::generate_attempt_answers([1, 1, 1, 1]),
],
'Expected quiz 1 Discrimination Index' => [null, 30.15, 30.15, 81.65],
'Quiz 2 attempts' => [
- $this->generate_attempt_answers([1, 1, 1, 1]),
- $this->generate_attempt_answers([0, 0, 0, 0]),
- $this->generate_attempt_answers([1, 0, 0, 1]),
- $this->generate_attempt_answers([0, 1, 1, 0]),
+ self::generate_attempt_answers([1, 1, 1, 1]),
+ self::generate_attempt_answers([0, 0, 0, 0]),
+ self::generate_attempt_answers([1, 0, 0, 1]),
+ self::generate_attempt_answers([0, 1, 1, 0]),
],
'Expected quiz 2 discrimination Index' => [44.72, 44.72, 44.72, 44.72],
'Expected average discrimination Index' => [44.72, 37.44, 37.44, 63.19],
@@ -582,8 +576,8 @@ public function test_statistics_disabled(): void {
$this->resetAfterTest();
// Prepare some quizzes and attempts. Exactly what is not important to this test.
- $quiz1attempts = [$this->generate_attempt_answers([1, 0, 0, 0])];
- $quiz2attempts = [$this->generate_attempt_answers([1, 1, 1, 1])];
+ $quiz1attempts = [self::generate_attempt_answers([1, 0, 0, 0])];
+ $quiz2attempts = [self::generate_attempt_answers([1, 1, 1, 1])];
[, , $questions] = $this->prepare_and_submit_quizzes($quiz1attempts, $quiz2attempts);
// Prepare some useful arrays.
diff --git a/question/tests/random_question_loader_test.php b/question/tests/random_question_loader_test.php
index 33b05269690ce..c4775f7f2dffd 100644
--- a/question/tests/random_question_loader_test.php
+++ b/question/tests/random_question_loader_test.php
@@ -379,7 +379,7 @@ public static function get_questions_test_cases(): array {
* Parent: cat1
* Category: emptycat
*
- * @dataProvider get_questions_test_cases()
+ * @dataProvider get_questions_test_cases
* @param string $categoryindex The named index for the category to use
* @param bool $includesubcategories If the search should include subcategories
* @param string[] $usetagnames The tag names to include in the search
@@ -589,7 +589,7 @@ public static function count_questions_test_cases(): array {
* Parent: cat1
* Category: emptycat
*
- * @dataProvider count_questions_test_cases()
+ * @dataProvider count_questions_test_cases
* @param string $categoryindex The named index for the category to use
* @param bool $includesubcategories If the search should include subcategories
* @param string[] $usetagnames The tag names to include in the search
diff --git a/question/type/ddimageortext/tests/privacy/provider_test.php b/question/type/ddimageortext/tests/privacy/provider_test.php
index e19bdfaeb5e1e..353f014d8902e 100644
--- a/question/type/ddimageortext/tests/privacy/provider_test.php
+++ b/question/type/ddimageortext/tests/privacy/provider_test.php
@@ -91,7 +91,7 @@ public function test_export_user_preferences($name, $value, $expected) {
*
* @return array Array of valid user preferences.
*/
- public function user_preference_provider() {
+ public static function user_preference_provider(): array {
return [
'default mark 1' => ['defaultmark', 1, 1],
'penalty 33.33333%' => ['penalty', 0.3333333, '33.33333%'],
diff --git a/question/type/ddmarker/tests/privacy/provider_test.php b/question/type/ddmarker/tests/privacy/provider_test.php
index fcf69c7d15e84..94cb4654891f5 100644
--- a/question/type/ddmarker/tests/privacy/provider_test.php
+++ b/question/type/ddmarker/tests/privacy/provider_test.php
@@ -91,7 +91,7 @@ public function test_export_user_preferences($name, $value, $expected) {
*
* @return array Array of valid user preferences.
*/
- public function user_preference_provider() {
+ public static function user_preference_provider(): array {
return [
'default mark 1.5' => ['defaultmark', 1.5, 1.5],
'penalty 33.33333%' => ['penalty', 0.3333333, '33.33333%'],
diff --git a/question/type/ddwtos/tests/privacy/provider_test.php b/question/type/ddwtos/tests/privacy/provider_test.php
index 711b7c1744c69..1dda6d7f42abe 100644
--- a/question/type/ddwtos/tests/privacy/provider_test.php
+++ b/question/type/ddwtos/tests/privacy/provider_test.php
@@ -91,7 +91,7 @@ public function test_export_user_preferences($name, $value, $expected) {
*
* @return array Array of valid user preferences.
*/
- public function user_preference_provider() {
+ public static function user_preference_provider(): array {
return [
'default mark 2' => ['defaultmark', 2, 2],
'penalty 33.33333%' => ['penalty', 0.3333333, '33.33333%'],
diff --git a/question/type/essay/tests/form/edit_form_test.php b/question/type/essay/tests/form/edit_form_test.php
index f2f6c7bed8191..f55765a44e5eb 100644
--- a/question/type/essay/tests/form/edit_form_test.php
+++ b/question/type/essay/tests/form/edit_form_test.php
@@ -102,7 +102,7 @@ public function test_attachments_validation(int $allowed, int $required, array $
*
* @return array, an array of all possible options.
*/
- public function user_preference_provider(): array {
+ public static function user_preference_provider(): array {
$valid = [];
$invalid = ['attachmentsrequired' => get_string('mustrequirefewer', 'qtype_essay')];
return [
diff --git a/question/type/essay/tests/privacy/provider_test.php b/question/type/essay/tests/privacy/provider_test.php
index ef88678dc3b2e..b5016af5371b8 100644
--- a/question/type/essay/tests/privacy/provider_test.php
+++ b/question/type/essay/tests/privacy/provider_test.php
@@ -91,7 +91,7 @@ public function test_export_user_preferences($name, $value, $expected) {
*
* @return array Array of valid user preferences.
*/
- public function user_preference_provider() {
+ public static function user_preference_provider(): array {
return [
'default mark 2' => ['defaultmark', 2, 2],
'responseformat editror ' => ['responseformat', 'editor', get_string('formateditor', 'qtype_essay')],
diff --git a/question/type/essay/tests/question_test.php b/question/type/essay/tests/question_test.php
index 1e79abf54f57c..6102b1ea40ecf 100644
--- a/question/type/essay/tests/question_test.php
+++ b/question/type/essay/tests/question_test.php
@@ -80,7 +80,7 @@ public function test_summarise_response(int $responserequired, int $attachmentsr
*
* @return array List of data sets (test cases)
*/
- public function summarise_response_provider(): array {
+ public static function summarise_response_provider(): array {
return [
'text input required, not attachments required' =>
[1, 0, 'This is the text input for this essay.', 0, 'This is the text input for this essay.'],
@@ -331,7 +331,7 @@ public function test_get_question_definition_for_external_rendering() {
*
* (The tests are done with a fixed 14-word response.)
*
- * @dataProvider get_min_max_wordlimit_test_cases()
+ * @dataProvider get_min_max_wordlimit_test_cases
* @param int $responserequired whether response required (yes = 1, no = 0)
* @param int $minwordlimit minimum word limit
* @param int $maxwordlimit maximum word limit
@@ -353,7 +353,7 @@ public function test_get_validation_error(int $responserequired,
*
* @return array the test cases.
*/
- public function get_min_max_wordlimit_test_cases(): array {
+ public static function get_min_max_wordlimit_test_cases(): array {
return [
'text input required, min/max word limit not set' => [1, 0, 0, ''],
'text input required, min/max word limit valid (within the boundaries)' => [1, 10, 25, ''],
@@ -370,7 +370,7 @@ public function get_min_max_wordlimit_test_cases(): array {
*
* (The tests are done with a fixed 14-word response.)
*
- * @dataProvider get_word_count_message_for_review_test_cases()
+ * @dataProvider get_word_count_message_for_review_test_cases
* @param int|null $minwordlimit minimum word limit
* @param int|null $maxwordlimit maximum word limit
* @param string $expected error message | null
@@ -389,7 +389,7 @@ public function test_get_word_count_message_for_review(?int $minwordlimit, ?int
*
* @return array the test cases.
*/
- public function get_word_count_message_for_review_test_cases() {
+ public static function get_word_count_message_for_review_test_cases(): array {
return [
'No limit' =>
[null, null, ''],
diff --git a/question/type/gapselect/tests/privacy/provider_test.php b/question/type/gapselect/tests/privacy/provider_test.php
index 85734954527b3..0fa9f6a402d6c 100644
--- a/question/type/gapselect/tests/privacy/provider_test.php
+++ b/question/type/gapselect/tests/privacy/provider_test.php
@@ -91,7 +91,7 @@ public function test_export_user_preferences($name, $value, $expected) {
*
* @return array Array of valid user preferences.
*/
- public function user_preference_provider() {
+ public static function user_preference_provider(): array {
return [
'default mark 1.5' => ['defaultmark', 1.5, 1.5],
'penalty 25%' => ['penalty', 0.2500000, '25%'],
diff --git a/question/type/match/tests/privacy/provider_test.php b/question/type/match/tests/privacy/provider_test.php
index 41b0fc5147d5f..7bffe8e9f9058 100644
--- a/question/type/match/tests/privacy/provider_test.php
+++ b/question/type/match/tests/privacy/provider_test.php
@@ -91,7 +91,7 @@ public function test_export_user_preferences($name, $value, $expected) {
*
* @return array Array of valid user preferences.
*/
- public function user_preference_provider() {
+ public static function user_preference_provider(): array {
return [
'default mark 1' => ['defaultmark', 1, 1],
'penalty 33.33333%' => ['penalty', 0.3333333, '33.33333%'],
diff --git a/question/type/multichoice/tests/privacy/provider_test.php b/question/type/multichoice/tests/privacy/provider_test.php
index 0f2dcb0791813..d8fc1877ff592 100644
--- a/question/type/multichoice/tests/privacy/provider_test.php
+++ b/question/type/multichoice/tests/privacy/provider_test.php
@@ -91,7 +91,7 @@ public function test_export_user_preferences($name, $value, $expected) {
*
* @return array Array of valid user preferences.
*/
- public function user_preference_provider() {
+ public static function user_preference_provider(): array {
return [
'default mark 2' => ['defaultmark', 2, 2],
'penalty 33.33333%' => ['penalty', 0.3333333, '33.33333%'],
diff --git a/question/type/multichoice/tests/question_type_test.php b/question/type/multichoice/tests/question_type_test.php
index 2caba525bb032..0a053e7e11744 100644
--- a/question/type/multichoice/tests/question_type_test.php
+++ b/question/type/multichoice/tests/question_type_test.php
@@ -107,7 +107,7 @@ public function test_get_possible_responses_multi() {
), $this->qtype->get_possible_responses($q));
}
- public function get_question_saving_which() {
+ public static function get_question_saving_which(): array {
return array(array('two_of_four'), array('one_of_four'));
}
diff --git a/question/type/numerical/tests/answerprocessor_test.php b/question/type/numerical/tests/answerprocessor_test.php
index dd764665b5daa..d62bc52ca8f52 100644
--- a/question/type/numerical/tests/answerprocessor_test.php
+++ b/question/type/numerical/tests/answerprocessor_test.php
@@ -72,7 +72,7 @@ public function test_parse_response(array $expected, $args): void {
*
* @return array
*/
- public function parse_response_provider(): array {
+ public static function parse_response_provider(): array {
return [
[['3', '142', '', ''], '3.142'],
[['', '2', '', ''], '.2'],
@@ -191,7 +191,7 @@ public function test_apply_units(
*
* @return array
*/
- public function apply_units_provider(): array {
+ public static function apply_units_provider(): array {
return [
[3e8, 'm/s', 1, '3x10^8 m/s'],
[3e8, '', null, '3x10^8'],
@@ -250,7 +250,7 @@ public function test_apply_units_with_unit(
*
* @return array
*/
- public function apply_units_provider_with_units(): array {
+ public static function apply_units_provider_with_units(): array {
return [
[3e8, 'm/s', 1, '3x10^8', 'm/s'],
[3e8, '', null, '3x10^8', ''],
@@ -280,7 +280,7 @@ public function test_euro_style(array $expected, string $params): void {
*
* return array
*/
- public function euro_provider(): array {
+ public static function euro_provider(): array {
return [
[[-1000, '', null], '-1 000'],
[[3.14159, '', null], '3,14159'],
@@ -305,7 +305,7 @@ public function test_percent(array $expected, string $params): void {
*
* @return array
*/
- public function percent_provider(): array {
+ public static function percent_provider(): array {
return [
[['3', '%', 0.01], '3%'],
[['1e-6', '%', 0.01], '1e-6 %'],
@@ -334,7 +334,7 @@ public function test_currency(array $expected, string $params): void {
*
* @return array
*/
- public function currency_provider(): array {
+ public static function currency_provider(): array {
return [
[['1234.56', '£', 1], '£1,234.56'],
[['100', '$', 1], '$100'],
diff --git a/question/type/shortanswer/tests/privacy/provider_test.php b/question/type/shortanswer/tests/privacy/provider_test.php
index 4c1aed9fdaabb..beb293198ddf0 100644
--- a/question/type/shortanswer/tests/privacy/provider_test.php
+++ b/question/type/shortanswer/tests/privacy/provider_test.php
@@ -91,7 +91,7 @@ public function test_export_user_preferences($name, $value, $expected) {
*
* @return array Array of valid user preferences.
*/
- public function user_preference_provider() {
+ public static function user_preference_provider(): array {
return [
'default mark 2' => ['defaultmark', 2, 2],
'penalty 33.33333%' => ['penalty', 0.3333333, '33.33333%'],
diff --git a/rating/tests/rating_test.php b/rating/tests/rating_test.php
index b2fa6a55d15d6..f9f034a41d3c4 100644
--- a/rating/tests/rating_test.php
+++ b/rating/tests/rating_test.php
@@ -279,7 +279,7 @@ public function test_get_ratings_sql() {
*
* @return array
*/
- public function get_aggregate_string_provider() {
+ public static function get_aggregate_string_provider(): array {
return [
'Non-numeric aggregate produces empty string' => [
RATING_AGGREGATE_NONE,
diff --git a/reportbuilder/tests/external/system_report_exporter_test.php b/reportbuilder/tests/external/system_report_exporter_test.php
index 3a2c90e0641c7..dd36c9631fc3f 100644
--- a/reportbuilder/tests/external/system_report_exporter_test.php
+++ b/reportbuilder/tests/external/system_report_exporter_test.php
@@ -48,7 +48,7 @@ public static function setUpBeforeClass(): void {
*
* @return array[]
*/
- public function export_provider(): array {
+ public static function export_provider(): array {
return [
['With filters' => true],
['Without filters' => false],
diff --git a/reportbuilder/tests/local/entities/user_test.php b/reportbuilder/tests/local/entities/user_test.php
index fb71ab648a845..ee0535d55a09b 100644
--- a/reportbuilder/tests/local/entities/user_test.php
+++ b/reportbuilder/tests/local/entities/user_test.php
@@ -71,7 +71,7 @@ public function test_get_identity_filter(): void {
*
* @return array
*/
- public function get_name_fields_select_provider(): array {
+ public static function get_name_fields_select_provider(): array {
return [
['firstname', ['firstname']],
['firstname lastname', ['firstname', 'lastname']],
diff --git a/reportbuilder/tests/local/filters/autocomplete_test.php b/reportbuilder/tests/local/filters/autocomplete_test.php
index e42768eb18f6a..5216cccc7c479 100644
--- a/reportbuilder/tests/local/filters/autocomplete_test.php
+++ b/reportbuilder/tests/local/filters/autocomplete_test.php
@@ -37,7 +37,7 @@ class autocomplete_test extends advanced_testcase {
*
* @return array
*/
- public function get_sql_filter_provider(): array {
+ public static function get_sql_filter_provider(): array {
return [
[[], ["Course 1 full name", "Course 2 full name", "Course 3 full name", "PHPUnit test site"]],
[["course1", "course3"], ["Course 1 full name", "Course 3 full name"]],
diff --git a/reportbuilder/tests/local/filters/boolean_select_test.php b/reportbuilder/tests/local/filters/boolean_select_test.php
index ee28dfedc860d..f808e66c32613 100644
--- a/reportbuilder/tests/local/filters/boolean_select_test.php
+++ b/reportbuilder/tests/local/filters/boolean_select_test.php
@@ -38,7 +38,7 @@ class boolean_select_test extends advanced_testcase {
*
* @return array
*/
- public function get_sql_filter_simple_provider(): array {
+ public static function get_sql_filter_simple_provider(): array {
return [
[boolean_select::ANY_VALUE, true],
[boolean_select::CHECKED, true],
diff --git a/reportbuilder/tests/local/filters/category_test.php b/reportbuilder/tests/local/filters/category_test.php
index 5b57b5edfa15e..2a898317940c3 100644
--- a/reportbuilder/tests/local/filters/category_test.php
+++ b/reportbuilder/tests/local/filters/category_test.php
@@ -38,7 +38,7 @@ class category_test extends advanced_testcase {
*
* @return array
*/
- public function get_sql_filter_provider(): array {
+ public static function get_sql_filter_provider(): array {
return [
// Equal to.
['One', category::EQUAL_TO, false, ['One']],
diff --git a/reportbuilder/tests/local/filters/select_test.php b/reportbuilder/tests/local/filters/select_test.php
index 2038a7bbc9f30..475ae6b585165 100644
--- a/reportbuilder/tests/local/filters/select_test.php
+++ b/reportbuilder/tests/local/filters/select_test.php
@@ -38,7 +38,7 @@ class select_test extends advanced_testcase {
*
* @return array
*/
- public function get_sql_filter_simple_provider(): array {
+ public static function get_sql_filter_simple_provider(): array {
return [
[select::ANY_VALUE, null, true],
[select::EQUAL_TO, 'starwars', true],
diff --git a/reportbuilder/tests/local/filters/text_test.php b/reportbuilder/tests/local/filters/text_test.php
index 9a9a5f0d017f4..0125ebdc7d118 100644
--- a/reportbuilder/tests/local/filters/text_test.php
+++ b/reportbuilder/tests/local/filters/text_test.php
@@ -38,7 +38,7 @@ class text_test extends advanced_testcase {
*
* @return array
*/
- public function get_sql_filter_simple_provider(): array {
+ public static function get_sql_filter_simple_provider(): array {
return [
[text::ANY_VALUE, null, true],
[text::CONTAINS, 'looking', true],
@@ -101,7 +101,7 @@ public function test_get_sql_filter_simple(int $operator, ?string $value, bool $
*
* @return array
*/
- public function get_sql_filter_empty_provider(): array {
+ public static function get_sql_filter_empty_provider(): array {
return [
[text::IS_EMPTY, null, true],
[text::IS_EMPTY, '', true],
diff --git a/reportbuilder/tests/local/filters/user_test.php b/reportbuilder/tests/local/filters/user_test.php
index a9cc75590bf68..ea041c402e9b9 100644
--- a/reportbuilder/tests/local/filters/user_test.php
+++ b/reportbuilder/tests/local/filters/user_test.php
@@ -38,7 +38,7 @@ class user_test extends advanced_testcase {
*
* @return array
*/
- public function get_sql_filter_simple(): array {
+ public static function get_sql_filter_simple(): array {
return [
[user::USER_ANY, ['admin', 'guest', 'user01', 'user02']],
[user::USER_CURRENT, ['user01']],
diff --git a/reportbuilder/tests/local/helpers/schedule_test.php b/reportbuilder/tests/local/helpers/schedule_test.php
index e25dffaf5ac75..98d6363f2f476 100644
--- a/reportbuilder/tests/local/helpers/schedule_test.php
+++ b/reportbuilder/tests/local/helpers/schedule_test.php
@@ -257,7 +257,7 @@ public function test_get_schedule_report_count(): void {
*
* @return string[]
*/
- public function get_schedule_report_file_format(): array {
+ public static function get_schedule_report_file_format(): array {
return [
['csv'],
['excel'],
diff --git a/reportbuilder/tests/local/helpers/user_filter_manager_test.php b/reportbuilder/tests/local/helpers/user_filter_manager_test.php
index c3049ba757d48..909c3667877a3 100644
--- a/reportbuilder/tests/local/helpers/user_filter_manager_test.php
+++ b/reportbuilder/tests/local/helpers/user_filter_manager_test.php
@@ -46,7 +46,7 @@ private function get_filter_preferences(): array {
*
* @return array
*/
- public function get_provider(): array {
+ public static function get_provider(): array {
return [
'Small value' => ['foo'],
'Large value' => [str_repeat('A', 4000)],
@@ -113,7 +113,7 @@ public function test_get_empty(): void {
*
* @return array
*/
- public function reset_all_provider(): array {
+ public static function reset_all_provider(): array {
return [
'Small value' => ['foo'],
'Large value' => [str_repeat('A', 4000)],
diff --git a/reportbuilder/tests/local/report/action_test.php b/reportbuilder/tests/local/report/action_test.php
index 316a3f114e748..1e3735c96ea12 100644
--- a/reportbuilder/tests/local/report/action_test.php
+++ b/reportbuilder/tests/local/report/action_test.php
@@ -63,7 +63,7 @@ public function test_add_callback_false(): void {
*
* @return array[]
*/
- public function action_title_provider(): array {
+ public static function action_title_provider(): array {
$title = new lang_string('yes');
return [
'Specified via constructor' => ['', [], $title],
diff --git a/reportbuilder/tests/manager_test.php b/reportbuilder/tests/manager_test.php
index 68d01b9eb4cf9..983661927aa3f 100644
--- a/reportbuilder/tests/manager_test.php
+++ b/reportbuilder/tests/manager_test.php
@@ -180,7 +180,7 @@ public function test_create_report_persistent(): void {
*
* @return array
*/
- public function report_limit_reached_provider(): array {
+ public static function report_limit_reached_provider(): array {
return [
[0, 1, false],
[1, 1, true],
diff --git a/reportbuilder/tests/task/send_schedule_test.php b/reportbuilder/tests/task/send_schedule_test.php
index 57958a1ce0984..9e63827a7d3c7 100644
--- a/reportbuilder/tests/task/send_schedule_test.php
+++ b/reportbuilder/tests/task/send_schedule_test.php
@@ -44,7 +44,7 @@ class send_schedule_test extends advanced_testcase {
*
* @return array[]
*/
- public function execute_report_viewas_user_provider(): array {
+ public static function execute_report_viewas_user_provider(): array {
return [
'View report as schedule creator' => [schedule::REPORT_VIEWAS_CREATOR, null, 'admin', 'admin'],
'View report as schedule recipient' => [schedule::REPORT_VIEWAS_RECIPIENT, null, 'userone', 'usertwo'],
diff --git a/repository/contentbank/tests/search/search_test.php b/repository/contentbank/tests/search/search_test.php
index 8cba994618ed4..76a62d7443cf1 100644
--- a/repository/contentbank/tests/search/search_test.php
+++ b/repository/contentbank/tests/search/search_test.php
@@ -75,7 +75,7 @@ public function test_get_search_contents(array $contentnames, string $search, ar
*
* @return array
*/
- public function get_search_contents_provider(): array {
+ public static function get_search_contents_provider(): array {
return [
'Search for existing pattern found within the name of content items' => [
[
diff --git a/repository/dropbox/tests/api_test.php b/repository/dropbox/tests/api_test.php
index cec67079f1aa3..4b128c160c7a4 100644
--- a/repository/dropbox/tests/api_test.php
+++ b/repository/dropbox/tests/api_test.php
@@ -29,7 +29,7 @@ class api_test extends \advanced_testcase {
*
* @return array
*/
- public function has_additional_results_provider() {
+ public static function has_additional_results_provider(): array {
return [
'No more results' => [
(object) [
@@ -88,7 +88,7 @@ public function test_has_additional_results($result, $expected) {
*
* @return array
*/
- public function check_and_handle_api_errors_provider() {
+ public static function check_and_handle_api_errors_provider(): array {
return [
'200 http_code' => [
['http_code' => 200],
@@ -180,7 +180,7 @@ public function test_check_and_handle_api_errors($info, $data, $exception, $exce
*
* @return array
*/
- public function supports_thumbnail_provider() {
+ public static function supports_thumbnail_provider(): array {
$tests = [
'Only files support thumbnails' => [
(object) ['.tag' => 'folder'],
diff --git a/repository/googledocs/tests/googledocs_search_content_test.php b/repository/googledocs/tests/googledocs_search_content_test.php
index 5dbedae124c41..4bdf067cbeae7 100644
--- a/repository/googledocs/tests/googledocs_search_content_test.php
+++ b/repository/googledocs/tests/googledocs_search_content_test.php
@@ -105,7 +105,7 @@ public function test_get_content_nodes(string $query, bool $sortcontent, array $
*
* @return array
*/
- public function get_content_nodes_provider(): array {
+ public static function get_content_nodes_provider(): array {
$rootid = \repository_googledocs::REPOSITORY_ROOT_ID;
$searchnodeid = \repository_googledocs::SEARCH_ROOT_ID;
@@ -118,26 +118,26 @@ public function get_content_nodes_provider(): array {
true,
[],
[
- $this->create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
+ self::create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
],
[
- $this->create_google_drive_file_object('d85b21c0f86cb0', 'Test file 3.pdf',
+ self::create_google_drive_file_object('d85b21c0f86cb0', 'Test file 3.pdf',
'application/pdf', 'pdf', '1000', '',
'https://drive.google.com/uc?id=d85b21c0f86cb0&export=download'),
- $this->create_google_drive_folder_object('0c4ad262c65333', 'Test folder 1'),
- $this->create_google_drive_file_object('bed5a0f08d412a', 'Test file 1.pdf',
+ self::create_google_drive_folder_object('0c4ad262c65333', 'Test folder 1'),
+ self::create_google_drive_file_object('bed5a0f08d412a', 'Test file 1.pdf',
'application/pdf', 'pdf'),
- $this->create_google_drive_folder_object('9c4ad262c65333', 'Test folder 2'),
+ self::create_google_drive_folder_object('9c4ad262c65333', 'Test folder 2'),
],
[
- $this->create_folder_content_node_array('0c4ad262c65333', 'Test folder 1',
+ self::create_folder_content_node_array('0c4ad262c65333', 'Test folder 1',
"{$rootid}|Google+Drive/{$searchnodeid}|" . urlencode("{$searchforstring} 'test'")),
- $this->create_folder_content_node_array('9c4ad262c65333', 'Test folder 2',
+ self::create_folder_content_node_array('9c4ad262c65333', 'Test folder 2',
"{$rootid}|Google+Drive/{$searchnodeid}|" . urlencode("{$searchforstring} 'test'")),
- $this->create_file_content_node_array('bed5a0f08d412a', 'Test file 1.pdf',
+ self::create_file_content_node_array('bed5a0f08d412a', 'Test file 1.pdf',
'Test file 1.pdf', null, '', 'https://googleusercontent.com/type/application/pdf',
'', 'download'),
- $this->create_file_content_node_array('d85b21c0f86cb0', 'Test file 3.pdf',
+ self::create_file_content_node_array('d85b21c0f86cb0', 'Test file 3.pdf',
'Test file 3.pdf', '1000', '', 'https://googleusercontent.com/type/application/pdf',
'https://drive.google.com/uc?id=d85b21c0f86cb0&export=download', 'download'),
],
@@ -149,16 +149,16 @@ public function get_content_nodes_provider(): array {
[],
[],
[
- $this->create_google_drive_folder_object('0c4ad262c65333', 'Testing folder 3'),
- $this->create_google_drive_folder_object('d85b21c0f86cb0', 'Testing folder 1'),
- $this->create_google_drive_folder_object('bed5a0f08d412a', 'Testing folder 2'),
+ self::create_google_drive_folder_object('0c4ad262c65333', 'Testing folder 3'),
+ self::create_google_drive_folder_object('d85b21c0f86cb0', 'Testing folder 1'),
+ self::create_google_drive_folder_object('bed5a0f08d412a', 'Testing folder 2'),
],
[
- $this->create_folder_content_node_array('0c4ad262c65333', 'Testing folder 3',
+ self::create_folder_content_node_array('0c4ad262c65333', 'Testing folder 3',
"{$rootid}|Google+Drive/{$searchnodeid}|" . urlencode("{$searchforstring} 'testing'")),
- $this->create_folder_content_node_array('d85b21c0f86cb0', 'Testing folder 1',
+ self::create_folder_content_node_array('d85b21c0f86cb0', 'Testing folder 1',
"{$rootid}|Google+Drive/{$searchnodeid}|" . urlencode("{$searchforstring} 'testing'")),
- $this->create_folder_content_node_array('bed5a0f08d412a', 'Testing folder 2',
+ self::create_folder_content_node_array('bed5a0f08d412a', 'Testing folder 2',
"{$rootid}|Google+Drive/{$searchnodeid}|" . urlencode("{$searchforstring} 'testing'")),
],
],
@@ -168,18 +168,18 @@ public function get_content_nodes_provider(): array {
false,
['doc', 'txt'],
[
- $this->create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
+ self::create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
],
[
- $this->create_google_drive_file_object('d85b21c0f86cb0', 'Testing file 3.pdf',
+ self::create_google_drive_file_object('d85b21c0f86cb0', 'Testing file 3.pdf',
'application/pdf', 'pdf', '1000'),
- $this->create_google_drive_file_object('a85b21c0f86cb0', 'Testing file 1.txt',
+ self::create_google_drive_file_object('a85b21c0f86cb0', 'Testing file 1.txt',
'text/plain', 'txt', '3000'),
- $this->create_google_drive_file_object('f85b21c0f86cb0', 'Testing file 2.doc',
+ self::create_google_drive_file_object('f85b21c0f86cb0', 'Testing file 2.doc',
'application/msword', 'doc', '2000'),
],
[
- $this->create_file_content_node_array('d85b21c0f86cb0', 'Testing file 3.pdf',
+ self::create_file_content_node_array('d85b21c0f86cb0', 'Testing file 3.pdf',
'Testing file 3.pdf', '1000', '',
'https://googleusercontent.com/type/application/pdf', '', 'download'),
],
diff --git a/repository/googledocs/tests/helper_test.php b/repository/googledocs/tests/helper_test.php
index 64c32d8ce06c9..dd761c446afc8 100644
--- a/repository/googledocs/tests/helper_test.php
+++ b/repository/googledocs/tests/helper_test.php
@@ -50,7 +50,7 @@ public function test_build_node_path(string $id, string $name, string $rootpath,
*
* @return array
*/
- public function build_node_path_provider(): array {
+ public static function build_node_path_provider(): array {
$rootid = \repository_googledocs::REPOSITORY_ROOT_ID;
$mydriveid = \repository_googledocs::MY_DRIVE_ROOT_ID;
@@ -105,7 +105,7 @@ public function test_explode_node_path(string $node, array $expected) {
*
* @return array
*/
- public function explode_node_path_provider(): array {
+ public static function explode_node_path_provider(): array {
$rootid = \repository_googledocs::REPOSITORY_ROOT_ID;
@@ -155,7 +155,7 @@ public function test_get_browser(string $nodepath, string $expected) {
*
* @return array
*/
- public function get_browser_provider(): array {
+ public static function get_browser_provider(): array {
$rootid = \repository_googledocs::REPOSITORY_ROOT_ID;
$mydriveid = \repository_googledocs::MY_DRIVE_ROOT_ID;
@@ -208,17 +208,16 @@ public function test_get_node(\stdClass $gdcontent, string $expected) {
*
* @return array
*/
- public function get_node_provider(): array {
-
+ public static function get_node_provider(): array {
return [
'The content object represents a Google Drive folder.' =>
[
- $this->create_google_drive_folder_object('e3b0c44298fc1c149', 'Folder', ''),
+ self::create_google_drive_folder_object('e3b0c44298fc1c149', 'Folder', ''),
\repository_googledocs\local\node\folder_node::class,
],
'The content object represents a Google Drive file.' =>
[
- $this->create_google_drive_file_object('de04d58dc5ccc', 'File.pdf',
+ self::create_google_drive_file_object('de04d58dc5ccc', 'File.pdf',
'application/pdf'),
\repository_googledocs\local\node\file_node::class,
],
@@ -253,7 +252,7 @@ public function test_request_exception(\Exception $exception, \Exception $expect
*
* @return array
*/
- public function request_exception_provider(): array {
+ public static function request_exception_provider(): array {
return [
'The API call throws exception (status: 403; message: Access Not Configured).' =>
diff --git a/repository/googledocs/tests/local/browser/googledocs_drive_content_test.php b/repository/googledocs/tests/local/browser/googledocs_drive_content_test.php
index ad5e43e331f79..f7b2d36ffc29a 100644
--- a/repository/googledocs/tests/local/browser/googledocs_drive_content_test.php
+++ b/repository/googledocs/tests/local/browser/googledocs_drive_content_test.php
@@ -100,8 +100,7 @@ public function test_get_content_nodes(string $query, string $path, bool $sortco
*
* @return array
*/
- public function get_content_nodes_provider(): array {
-
+ public static function get_content_nodes_provider(): array {
$rootid = \repository_googledocs::REPOSITORY_ROOT_ID;
$mydriveid = \repository_googledocs::MY_DRIVE_ROOT_ID;
@@ -113,25 +112,25 @@ public function get_content_nodes_provider(): array {
true,
[],
[
- $this->create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
+ self::create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
],
[
- $this->create_google_drive_folder_object('1c4ad262c65333', 'Folder 2'),
- $this->create_google_drive_file_object('d85b21c0f86cb0', 'File 3.pdf',
+ self::create_google_drive_folder_object('1c4ad262c65333', 'Folder 2'),
+ self::create_google_drive_file_object('d85b21c0f86cb0', 'File 3.pdf',
'application/pdf', 'pdf', '1000'),
- $this->create_google_drive_folder_object('0c4ad262c65333', 'Folder 1'),
- $this->create_google_drive_file_object('bed5a0f08d412a', 'File 1.pdf',
+ self::create_google_drive_folder_object('0c4ad262c65333', 'Folder 1'),
+ self::create_google_drive_file_object('bed5a0f08d412a', 'File 1.pdf',
'application/pdf', 'pdf'),
],
[
- $this->create_folder_content_node_array('0c4ad262c65333', 'Folder 1',
+ self::create_folder_content_node_array('0c4ad262c65333', 'Folder 1',
"{$rootid}|Google+Drive/{$mydriveid}|My+Drive"),
- $this->create_folder_content_node_array('1c4ad262c65333', 'Folder 2',
+ self::create_folder_content_node_array('1c4ad262c65333', 'Folder 2',
"{$rootid}|Google+Drive/{$mydriveid}|My+Drive"),
- $this->create_file_content_node_array('bed5a0f08d412a', 'File 1.pdf', 'File 1.pdf',
+ self::create_file_content_node_array('bed5a0f08d412a', 'File 1.pdf', 'File 1.pdf',
null, '', 'https://googleusercontent.com/type/application/pdf', '',
'download'),
- $this->create_file_content_node_array('d85b21c0f86cb0', 'File 3.pdf', 'File 3.pdf',
+ self::create_file_content_node_array('d85b21c0f86cb0', 'File 3.pdf', 'File 3.pdf',
'1000', '', 'https://googleusercontent.com/type/application/pdf', '',
'download'),
],
@@ -144,16 +143,16 @@ public function get_content_nodes_provider(): array {
[],
[],
[
- $this->create_google_drive_folder_object('0c4ad262c65333', 'Folder 3'),
- $this->create_google_drive_folder_object('d85b21c0f86cb0', 'Folder 1'),
- $this->create_google_drive_folder_object('bed5a0f08d412a', 'Folder 2'),
+ self::create_google_drive_folder_object('0c4ad262c65333', 'Folder 3'),
+ self::create_google_drive_folder_object('d85b21c0f86cb0', 'Folder 1'),
+ self::create_google_drive_folder_object('bed5a0f08d412a', 'Folder 2'),
],
[
- $this->create_folder_content_node_array('0c4ad262c65333', 'Folder 3',
+ self::create_folder_content_node_array('0c4ad262c65333', 'Folder 3',
"{$rootid}|Google+Drive/{$mydriveid}|My+Drive"),
- $this->create_folder_content_node_array('d85b21c0f86cb0', 'Folder 1',
+ self::create_folder_content_node_array('d85b21c0f86cb0', 'Folder 1',
"{$rootid}|Google+Drive/{$mydriveid}|My+Drive"),
- $this->create_folder_content_node_array('bed5a0f08d412a', 'Folder 2',
+ self::create_folder_content_node_array('bed5a0f08d412a', 'Folder 2',
"{$rootid}|Google+Drive/{$mydriveid}|My+Drive"),
],
],
@@ -165,18 +164,18 @@ public function get_content_nodes_provider(): array {
['txt'],
[],
[
- $this->create_google_drive_file_object('d85b21c0f86cb0', 'File 3.pdf',
+ self::create_google_drive_file_object('d85b21c0f86cb0', 'File 3.pdf',
'application/pdf', 'pdf', '1000'),
- $this->create_google_drive_file_object('a85b21c0f86cb0', 'File 1.txt',
+ self::create_google_drive_file_object('a85b21c0f86cb0', 'File 1.txt',
'text/plain', 'txt', '3000'),
- $this->create_google_drive_file_object('f85b21c0f86cb0', 'File 2.doc',
+ self::create_google_drive_file_object('f85b21c0f86cb0', 'File 2.doc',
'application/msword', 'doc', '2000'),
],
[
- $this->create_file_content_node_array('d85b21c0f86cb0', 'File 3.pdf', 'File 3.pdf',
+ self::create_file_content_node_array('d85b21c0f86cb0', 'File 3.pdf', 'File 3.pdf',
'1000', '', 'https://googleusercontent.com/type/application/pdf', '',
'download'),
- $this->create_file_content_node_array('f85b21c0f86cb0', 'File 2.doc', 'File 2.doc',
+ self::create_file_content_node_array('f85b21c0f86cb0', 'File 2.doc', 'File 2.doc',
'2000', '', 'https://googleusercontent.com/type/application/msword', '',
'download'),
],
@@ -217,7 +216,7 @@ public function test_get_navigation(string $nodepath, array $expected) {
*
* @return array
*/
- public function get_navigation_provider(): array {
+ public static function get_navigation_provider(): array {
$rootid = \repository_googledocs::REPOSITORY_ROOT_ID;
$mydriveid = \repository_googledocs::MY_DRIVE_ROOT_ID;
diff --git a/repository/googledocs/tests/local/browser/googledocs_root_content_test.php b/repository/googledocs/tests/local/browser/googledocs_root_content_test.php
index 0ec0b70dff8d4..fb46d44a5b311 100644
--- a/repository/googledocs/tests/local/browser/googledocs_root_content_test.php
+++ b/repository/googledocs/tests/local/browser/googledocs_root_content_test.php
@@ -29,8 +29,7 @@
* @copyright 2021 Mihail Geshoski
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class googledocs_root_content_test extends \googledocs_content_testcase {
-
+final class googledocs_root_content_test extends \googledocs_content_testcase {
/**
* Test get_content_nodes().
*
@@ -66,37 +65,34 @@ public function test_get_content_nodes(array $shareddrives, array $expected) {
*
* @return array
*/
- public function get_content_nodes_provider(): array {
-
+ public static function get_content_nodes_provider(): array {
$rootid = \repository_googledocs::REPOSITORY_ROOT_ID;
$mydriveid = \repository_googledocs::MY_DRIVE_ROOT_ID;
$shareddrivesid = \repository_googledocs::SHARED_DRIVES_ROOT_ID;
return [
- 'Shared drives exist.' =>
+ 'Shared drives exist.' => [
+ [
+ self::create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
+ self::create_google_drive_shared_drive_object('d85b21c0f86cb0', 'Shared Drive 3'),
+ ],
[
- [
- $this->create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
- $this->create_google_drive_shared_drive_object('d85b21c0f86cb0', 'Shared Drive 3'),
- ],
- [
- $this->create_folder_content_node_array($mydriveid,
- get_string('mydrive', 'repository_googledocs'),
- "{$rootid}|Google+Drive"),
- $this->create_folder_content_node_array($shareddrivesid,
- get_string('shareddrives', 'repository_googledocs'),
- "{$rootid}|Google+Drive"),
- ],
+ self::create_folder_content_node_array($mydriveid,
+ get_string('mydrive', 'repository_googledocs'),
+ "{$rootid}|Google+Drive"),
+ self::create_folder_content_node_array($shareddrivesid,
+ get_string('shareddrives', 'repository_googledocs'),
+ "{$rootid}|Google+Drive"),
],
- 'Shared drives do not exist.' =>
+ ],
+ 'Shared drives do not exist.' => [
+ [],
[
- [],
- [
- $this->create_folder_content_node_array($mydriveid,
- get_string('mydrive', 'repository_googledocs'),
- "{$rootid}|Google+Drive"),
- ],
+ self::create_folder_content_node_array($mydriveid,
+ get_string('mydrive', 'repository_googledocs'),
+ "{$rootid}|Google+Drive"),
],
+ ],
];
}
}
diff --git a/repository/googledocs/tests/local/browser/googledocs_shared_drives_content_test.php b/repository/googledocs/tests/local/browser/googledocs_shared_drives_content_test.php
index 93e1fc4288b71..4d07e39c20638 100644
--- a/repository/googledocs/tests/local/browser/googledocs_shared_drives_content_test.php
+++ b/repository/googledocs/tests/local/browser/googledocs_shared_drives_content_test.php
@@ -29,8 +29,7 @@
* @copyright 2021 Mihail Geshoski
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class googledocs_shared_drives_content_test extends \googledocs_content_testcase {
-
+final class googledocs_shared_drives_content_test extends \googledocs_content_testcase {
/**
* Test get_content_nodes().
*
@@ -68,8 +67,7 @@ public function test_get_content_nodes(array $shareddrives, bool $sortcontent, a
*
* @return array
*/
- public function get_content_nodes_provider(): array {
-
+ public static function get_content_nodes_provider(): array {
$rootid = \repository_googledocs::REPOSITORY_ROOT_ID;
$shareddrivesid = \repository_googledocs::SHARED_DRIVES_ROOT_ID;
$shareddrivesstring = get_string('shareddrives', 'repository_googledocs');
@@ -78,34 +76,34 @@ public function get_content_nodes_provider(): array {
'Shared drives exist; ordering applied.' =>
[
[
- $this->create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
- $this->create_google_drive_shared_drive_object('d85b21c0f86cb0', 'Shared Drive 3'),
- $this->create_google_drive_shared_drive_object('bed5a0f08d412a', 'Shared Drive 2'),
+ self::create_google_drive_shared_drive_object('d85b21c0f86cb5', 'Shared Drive 1'),
+ self::create_google_drive_shared_drive_object('d85b21c0f86cb0', 'Shared Drive 3'),
+ self::create_google_drive_shared_drive_object('bed5a0f08d412a', 'Shared Drive 2'),
],
true,
[
- $this->create_folder_content_node_array('d85b21c0f86cb5', 'Shared Drive 1',
+ self::create_folder_content_node_array('d85b21c0f86cb5', 'Shared Drive 1',
"{$rootid}|Google+Drive/{$shareddrivesid}|" . urlencode($shareddrivesstring)),
- $this->create_folder_content_node_array('bed5a0f08d412a', 'Shared Drive 2',
+ self::create_folder_content_node_array('bed5a0f08d412a', 'Shared Drive 2',
"{$rootid}|Google+Drive/{$shareddrivesid}|" . urlencode($shareddrivesstring)),
- $this->create_folder_content_node_array('d85b21c0f86cb0', 'Shared Drive 3',
+ self::create_folder_content_node_array('d85b21c0f86cb0', 'Shared Drive 3',
"{$rootid}|Google+Drive/{$shareddrivesid}|" . urlencode($shareddrivesstring)),
],
],
'Shared drives exist; ordering not applied.' =>
[
[
- $this->create_google_drive_shared_drive_object('0c4ad262c65333', 'Shared Drive 3'),
- $this->create_google_drive_shared_drive_object('d85b21c0f86cb0', 'Shared Drive 1'),
- $this->create_google_drive_shared_drive_object('bed5a0f08d412a', 'Shared Drive 2'),
+ self::create_google_drive_shared_drive_object('0c4ad262c65333', 'Shared Drive 3'),
+ self::create_google_drive_shared_drive_object('d85b21c0f86cb0', 'Shared Drive 1'),
+ self::create_google_drive_shared_drive_object('bed5a0f08d412a', 'Shared Drive 2'),
],
false,
[
- $this->create_folder_content_node_array('0c4ad262c65333', 'Shared Drive 3',
+ self::create_folder_content_node_array('0c4ad262c65333', 'Shared Drive 3',
"{$rootid}|Google+Drive/{$shareddrivesid}|" . urlencode($shareddrivesstring)),
- $this->create_folder_content_node_array('d85b21c0f86cb0', 'Shared Drive 1',
+ self::create_folder_content_node_array('d85b21c0f86cb0', 'Shared Drive 1',
"{$rootid}|Google+Drive/{$shareddrivesid}|" . urlencode($shareddrivesstring)),
- $this->create_folder_content_node_array('bed5a0f08d412a', 'Shared Drive 2',
+ self::create_folder_content_node_array('bed5a0f08d412a', 'Shared Drive 2',
"{$rootid}|Google+Drive/{$shareddrivesid}|" . urlencode($shareddrivesstring)),
],
],
diff --git a/repository/googledocs/tests/local/node/file_node_test.php b/repository/googledocs/tests/local/node/file_node_test.php
index 188341c15d98b..623f5a6f789f3 100644
--- a/repository/googledocs/tests/local/node/file_node_test.php
+++ b/repository/googledocs/tests/local/node/file_node_test.php
@@ -28,8 +28,7 @@
* @copyright 2021 Mihail Geshoski
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class file_node_test extends \repository_googledocs_testcase {
-
+final class file_node_test extends \repository_googledocs_testcase {
/**
* Test create_node_array().
*
@@ -56,55 +55,54 @@ public function test_create_node_array(\stdClass $gdfile, array $configsettings,
*
* @return array
*/
- public function create_node_array_provider(): array {
-
+ public static function create_node_array_provider(): array {
return [
'Google Drive file with an extension.' =>
[
- $this->create_google_drive_file_object('d85b21c0f86cb0', 'File.pdf',
+ self::create_google_drive_file_object('d85b21c0f86cb0', 'File.pdf',
'application/pdf', 'pdf', '1000', '01/01/21 0:30'),
[],
- $this->create_file_content_node_array('d85b21c0f86cb0', 'File.pdf', 'File.pdf', '1000',
+ self::create_file_content_node_array('d85b21c0f86cb0', 'File.pdf', 'File.pdf', '1000',
'1609432200', 'https://googleusercontent.com/type/application/pdf', '',
'download'),
],
'Google Drive file that has webContentLink and webViewLink.' =>
[
- $this->create_google_drive_file_object('d85b21c0f86cb0', 'File.pdf',
+ self::create_google_drive_file_object('d85b21c0f86cb0', 'File.pdf',
'application/pdf', 'pdf', null, '',
'https://drive.google.com/uc?id=d85b21c0f86cb0&export=download',
'https://drive.google.com/file/d/d85b21c0f86cb0/view?usp=drivesdk'),
[
'documentformat' => 'rtf',
],
- $this->create_file_content_node_array('d85b21c0f86cb0', 'File.pdf', 'File.pdf', null,
+ self::create_file_content_node_array('d85b21c0f86cb0', 'File.pdf', 'File.pdf', null,
'', 'https://googleusercontent.com/type/application/pdf',
'https://drive.google.com/file/d/d85b21c0f86cb0/view?usp=drivesdk', 'download'),
],
'Google Drive file that has webContentLink and no webViewLink.' =>
[
- $this->create_google_drive_file_object('d85b21c0f86cb0', 'File.pdf',
+ self::create_google_drive_file_object('d85b21c0f86cb0', 'File.pdf',
'application/pdf', 'pdf', null, '',
'https://drive.google.com/uc?id=d85b21c0f86cb0&export=download', ''),
[],
- $this->create_file_content_node_array('d85b21c0f86cb0', 'File.pdf', 'File.pdf', null,
+ self::create_file_content_node_array('d85b21c0f86cb0', 'File.pdf', 'File.pdf', null,
'', 'https://googleusercontent.com/type/application/pdf',
'https://drive.google.com/uc?id=d85b21c0f86cb0&export=download', 'download'),
],
'Google Drive file without an extension (Google document file; documentformat config set to rtf).' =>
[
- $this->create_google_drive_file_object('d85b21c0f86cb0', 'File',
+ self::create_google_drive_file_object('d85b21c0f86cb0', 'File',
'application/vnd.google-apps.document', null),
[
'documentformat' => 'rtf',
],
- $this->create_file_content_node_array('d85b21c0f86cb0', 'File', 'File.gdoc', '', '',
+ self::create_file_content_node_array('d85b21c0f86cb0', 'File', 'File.gdoc', '', '',
'https://googleusercontent.com/type/application/vnd.google-apps.document', '',
'application/rtf', 'document'),
],
'Google Drive file without an extension (Google presentation file; presentationformat config not set).' =>
[
- $this->create_google_drive_file_object('d85b21c0f86cb0', 'File',
+ self::create_google_drive_file_object('d85b21c0f86cb0', 'File',
'application/vnd.google-apps.presentation', null),
[
'documentformat' => 'rtf',
@@ -113,7 +111,7 @@ public function create_node_array_provider(): array {
],
'Google Drive file without an extension (File type not supported).' =>
[
- $this->create_google_drive_file_object('d85b21c0f86cb0', 'File',
+ self::create_google_drive_file_object('d85b21c0f86cb0', 'File',
'application/vnd.google-apps.unknownmimetype', null),
[],
null,
diff --git a/repository/googledocs/tests/local/node/folder_node_test.php b/repository/googledocs/tests/local/node/folder_node_test.php
index 51a2ad7a33e4f..fce98c80d267d 100644
--- a/repository/googledocs/tests/local/node/folder_node_test.php
+++ b/repository/googledocs/tests/local/node/folder_node_test.php
@@ -50,23 +50,26 @@ public function test_create_node_array(\stdClass $gdfolder, string $path, array
*
* @return array
*/
- public function create_node_array_provider(): array {
-
+ public static function create_node_array_provider(): array {
$rootid = \repository_googledocs::REPOSITORY_ROOT_ID;
return [
'Google Drive folder with modified date.' =>
[
- $this->create_google_drive_folder_object('d85b21c0f86cb0', 'Folder', '01/01/21 0:30'),
+ self::create_google_drive_folder_object('d85b21c0f86cb0', 'Folder', '01/01/21 0:30'),
"{$rootid}|Google+Drive",
- $this->create_folder_content_node_array('d85b21c0f86cb0', 'Folder',
- "{$rootid}|Google+Drive", '1609432200'),
+ self::create_folder_content_node_array(
+ 'd85b21c0f86cb0',
+ 'Folder',
+ "{$rootid}|Google+Drive",
+ '1609432200',
+ ),
],
'Google Drive folder without modified date.' =>
[
- $this->create_google_drive_folder_object('d85b21c0f86cb0', 'Folder', ''),
+ self::create_google_drive_folder_object('d85b21c0f86cb0', 'Folder', ''),
'',
- $this->create_folder_content_node_array('d85b21c0f86cb0', 'Folder', '', ''),
+ self::create_folder_content_node_array('d85b21c0f86cb0', 'Folder', '', ''),
],
];
}
diff --git a/repository/googledocs/tests/repository_googledocs_testcase.php b/repository/googledocs/tests/repository_googledocs_testcase.php
index 8b9c0707b1d93..1de7ca58910b9 100644
--- a/repository/googledocs/tests/repository_googledocs_testcase.php
+++ b/repository/googledocs/tests/repository_googledocs_testcase.php
@@ -32,9 +32,12 @@ abstract class repository_googledocs_testcase extends \advanced_testcase {
* @param string $modified The date of the last modification
* @return array The repository folder node array
*/
- protected function create_folder_content_node_array(string $id, string $name, string $path,
- string $modified = ''): array {
-
+ protected static function create_folder_content_node_array(
+ string $id,
+ string $name,
+ string $path,
+ string $modified = '',
+ ): array {
global $CFG, $OUTPUT;
return [
@@ -63,10 +66,17 @@ protected function create_folder_content_node_array(string $id, string $name, st
* @param string|null $googledoctype The type of the Google Doc file (if applicable)
* @return array The repository file node array
*/
- protected function create_file_content_node_array(string $id, string $name, string $title, ?string $size = null,
- string $modified = '', string $thumbnail = '' , string $link = '', string $exportformat = '',
- ?string $googledoctype = null): array {
-
+ protected static function create_file_content_node_array(
+ string $id,
+ string $name,
+ string $title,
+ ?string $size = null,
+ string $modified = '',
+ string $thumbnail = '',
+ string $link = '',
+ string $exportformat = '',
+ ?string $googledoctype = null,
+ ): array {
return [
'id' => $id,
'title' => $title,
@@ -75,7 +85,7 @@ protected function create_file_content_node_array(string $id, string $name, stri
'name' => $name,
'link' => $link,
'exportformat' => $exportformat,
- 'googledoctype' => $googledoctype
+ 'googledoctype' => $googledoctype,
]),
'date' => $modified,
'size' => $size,
@@ -92,8 +102,8 @@ protected function create_file_content_node_array(string $id, string $name, stri
* @param string $name The name of the shared drive
* @return \stdClass The shared drive object
*/
- protected function create_google_drive_shared_drive_object(string $id, string $name): \stdClass {
- return (object)[
+ protected static function create_google_drive_shared_drive_object(string $id, string $name): \stdClass {
+ return (object) [
'kind' => 'drive#drive',
'id' => $id,
'name' => $name,
@@ -108,7 +118,7 @@ protected function create_google_drive_shared_drive_object(string $id, string $n
* @param string|null $modified The date of the last modification
* @return \stdClass The folder object
*/
- protected function create_google_drive_folder_object(string $id, string $name, ?string $modified = null): \stdClass {
+ protected static function create_google_drive_folder_object(string $id, string $name, ?string $modified = null): \stdClass {
return (object)[
'id' => $id,
'name' => $name,
@@ -132,10 +142,16 @@ protected function create_google_drive_folder_object(string $id, string $name, ?
* @param string|null $webviewlink The link for opening the file in a browser
* @return \stdClass The file object
*/
- protected function create_google_drive_file_object(string $id, string $name, string $mimetype,
- ?string $extension = null, ?string $size = null, ?string $modified = null, ?string $webcontentlink = null,
- ?string $webviewlink = null): \stdClass {
-
+ protected static function create_google_drive_file_object(
+ string $id,
+ string $name,
+ string $mimetype,
+ ?string $extension = null,
+ ?string $size = null,
+ ?string $modified = null,
+ ?string $webcontentlink = null,
+ ?string $webviewlink = null,
+ ): \stdClass {
$googledrivefile = [
'id' => $id,
'name' => $name,
diff --git a/repository/nextcloud/tests/lib_test.php b/repository/nextcloud/tests/lib_test.php
index c8f66937a90e3..fb942cf5b58e9 100644
--- a/repository/nextcloud/tests/lib_test.php
+++ b/repository/nextcloud/tests/lib_test.php
@@ -853,7 +853,7 @@ public function test_send_file_errors() {
*
* @return array[]
*/
- public function sync_reference_provider():array {
+ public static function sync_reference_provider(): array {
return [
'referecncelastsync done recently' => [
[
diff --git a/search/engine/solr/tests/engine_test.php b/search/engine/solr/tests/engine_test.php
index 7b52d2c97c7cf..d79c206212261 100644
--- a/search/engine/solr/tests/engine_test.php
+++ b/search/engine/solr/tests/engine_test.php
@@ -46,8 +46,7 @@
*
* @runTestsInSeparateProcesses
*/
-class engine_test extends \advanced_testcase {
-
+final class engine_test extends \advanced_testcase {
/**
* @var \core_search\manager
*/
@@ -143,7 +142,7 @@ public function tearDown(): void {
/**
* Simple data provider to allow tests to be run with file indexing on and off.
*/
- public function file_indexing_provider() {
+ public static function file_indexing_provider(): array {
return array(
'file-indexing-on' => array(1),
'file-indexing-off' => array(0)
diff --git a/search/tests/document_test.php b/search/tests/document_test.php
index d7b83d1d0303b..6ae7dee5fb356 100644
--- a/search/tests/document_test.php
+++ b/search/tests/document_test.php
@@ -211,7 +211,7 @@ public function test_document_author_visibility(
*
* @return array
*/
- public function document_author_visibility_provider(): array {
+ public static function document_author_visibility_provider(): array {
return [
'Teacher' => [
'rolename' => 'editingteacher',
diff --git a/search/tests/manager_test.php b/search/tests/manager_test.php
index c1363e687bca3..1d4e34c9f7581 100644
--- a/search/tests/manager_test.php
+++ b/search/tests/manager_test.php
@@ -106,7 +106,7 @@ public function test_course_search_url(?bool $gsenabled, ?bool $allcourses, ?boo
*
* @return array[]
*/
- public function data_course_search_url(): array {
+ public static function data_course_search_url(): array {
return [
'defaults' => [null, null, null, '/course/search.php'],
'enabled' => [true, true, true, '/search/index.php'],
@@ -155,7 +155,7 @@ public function test_can_replace_course_search(?bool $gsenabled, ?bool $allcours
*
* @return array[]
*/
- public function data_can_replace_course_search(): array {
+ public static function data_can_replace_course_search(): array {
return [
'defaults' => [null, null, null, false],
'enabled' => [true, true, true, true],
@@ -1503,7 +1503,7 @@ public function test_build_limitcourseids() {
*
* @return array
*/
- public function parse_search_area_id_data_provider() {
+ public static function parse_search_area_id_data_provider(): array {
return [
['mod_book-chapter', ['mod_book', 'search_chapter']],
['mod_customcert-activity', ['mod_customcert', 'search_activity']],
diff --git a/tag/tests/behat/tagindex.feature b/tag/tests/behat/tagindex.feature
index ffe4db35d2b8f..1816ec2501130 100644
--- a/tag/tests/behat/tagindex.feature
+++ b/tag/tests/behat/tagindex.feature
@@ -6,10 +6,13 @@ Feature: Browsing tagged items
Background:
Given the following "users" exist:
- | username | firstname | lastname | email | interests |
- | user1 | User | 1 | user1@example.com | Cat |
- | user2 | User | 2 | user1@example.com | Cat, Dog |
- | user3 | User | 3 | user1@example.com | Dog |
+ | username | firstname | lastname | email | interests |
+ | user1 | User | 1 | user1@example.com | Cat, Zebra |
+ | user2 | User | 2 | user2@example.com | Cat, Dog, Zebra |
+ | user3 | User | 3 | user3@example.com | Zebra |
+ | user4 | User | 4 | user4@example.com | Zebra |
+ | user5 | User | 5 | user5@example.com | Zebra |
+ | user6 | User | 6 | user6@example.com | Zebra |
And the following "courses" exist:
| fullname | shortname | tags |
| Course 1 | c1 | Cat, Dog |
@@ -19,12 +22,15 @@ Feature: Browsing tagged items
| Course 5 | c5 | Cat |
| Course 6 | c6 | Cat |
| Course 7 | c7 | Cat |
+ And the following config values are set as admin:
+ | unaddableblocks | | theme_boost|
+ And the following "permission overrides" exist:
+ | capability | permission | role | contextlevel | reference |
+ | moodle/user:viewdetails | Allow | user | System | |
Scenario: Browse tag index with javascript disabled
When I log in as "user1"
And I turn editing mode on
- And the following config values are set as admin:
- | unaddableblocks | | theme_boost|
# TODO MDL-57120 "Tags" link not accessible without navigation block.
And I add the "Navigation" block if not present
And I click on "Tags" "link" in the "Navigation" "block"
@@ -72,8 +78,6 @@ Feature: Browsing tagged items
Scenario: Browse tag index with javascript enabled
When I log in as "user1"
And I turn editing mode on
- And the following config values are set as admin:
- | unaddableblocks | | theme_boost|
# TODO MDL-57120 "Tags" link not accessible without navigation block.
And I add the "Navigation" block if not present
And I click on "Site pages" "list_item" in the "Navigation" "block"
@@ -114,3 +118,25 @@ Feature: Browsing tagged items
And I should not see "Course2"
And I should not see "Course1"
And I log out
+
+ Scenario Outline: Browse tag index and view other profiles
+ Given I log in as "user1"
+ And I turn editing mode on
+ And the following "permission overrides" exist:
+ | capability | permission | role | contextlevel | reference |
+ | moodle/user:viewdetails | | user | System | |
+ # TODO MDL-57120 "Tags" link not accessible without navigation block.
+ And I add the "Navigation" block if not present
+ When I click on "Tags" "link" in the "Navigation" "block"
+ And I follow "Zebra"
+ Then I should "User 2"
+ And I should "User 3"
+ And I should "User 4"
+ And I should "User 5"
+ # Pagination test.
+ And I should "More" in the "#tagarea-core-user" "css_element"
+
+ Examples:
+ | permission | action1 | action2 |
+ | Prevent | not see | not see |
+ | Allow | see | see |
diff --git a/tag/tests/reportbuilder/datasource/tags_test.php b/tag/tests/reportbuilder/datasource/tags_test.php
index feceadccbea3b..61d9a1d15b44c 100644
--- a/tag/tests/reportbuilder/datasource/tags_test.php
+++ b/tag/tests/reportbuilder/datasource/tags_test.php
@@ -143,7 +143,7 @@ public function test_datasource_non_default_columns(): void {
*
* @return array[]
*/
- public function datasource_filters_provider(): array {
+ public static function datasource_filters_provider(): array {
return [
// Collection.
'Filter collection name' => ['collection:name', [
diff --git a/theme/boost/amd/build/drawers.min.js b/theme/boost/amd/build/drawers.min.js
index 7ecb3c0d35de4..3d0e58ede2c31 100644
--- a/theme/boost/amd/build/drawers.min.js
+++ b/theme/boost/amd/build/drawers.min.js
@@ -1,3 +1,3 @@
-define("theme_boost/drawers",["exports","core/modal_backdrop","core/templates","core/aria","core/event_dispatcher","core/utils","core/pagehelpers","core/pending","core_user/repository","jquery"],(function(_exports,_modal_backdrop,_templates,Aria,_event_dispatcher,_utils,_pagehelpers,_pending,_repository,_jquery){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_modal_backdrop=_interopRequireDefault(_modal_backdrop),_templates=_interopRequireDefault(_templates),Aria=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Aria),_pending=_interopRequireDefault(_pending),_jquery=_interopRequireDefault(_jquery);let backdropPromise=null;const drawerMap=new Map,SELECTORS_BUTTONS='[data-toggler="drawers"]',SELECTORS_CLOSEBTN='[data-toggler="drawers"][data-action="closedrawer"]',SELECTORS_OPENBTN='[data-toggler="drawers"][data-action="opendrawer"]',SELECTORS_TOGGLEBTN='[data-toggler="drawers"][data-action="toggle"]',SELECTORS_DRAWERS='[data-region="fixed-drawer"]',SELECTORS_DRAWERCONTENT=".drawercontent",SELECTORS_PAGECONTENT="#page-content",SELECTORS_HEADERCONTENT=".drawerheadercontent",CLASSES_SCROLLED="scrolled",CLASSES_SHOW="show",CLASSES_NOTINITIALISED="not-initialized",getDrawerZIndex=()=>{const drawer=document.querySelector(SELECTORS_DRAWERS);return drawer?parseInt(window.getComputedStyle(drawer).zIndex,10):null},getBackdrop=()=>(backdropPromise||(backdropPromise=_templates.default.render("core/modal_backdrop",{}).then((html=>new _modal_backdrop.default(html))).then((modalBackdrop=>(getDrawerZIndex()&&modalBackdrop.setZIndex(getDrawerZIndex()-1),modalBackdrop.getAttachmentPoint().get(0).addEventListener("click",(e=>{e.preventDefault(),Drawers.closeAllDrawers()})),modalBackdrop))).catch()),backdropPromise),getDrawerOpenButton=drawerId=>{let openButton=document.querySelector("".concat(SELECTORS_OPENBTN,'[data-target="').concat(drawerId,'"]'));return openButton||(openButton=document.querySelector("".concat(SELECTORS_TOGGLEBTN,'[data-target="').concat(drawerId,'"]'))),openButton},disableDrawerTooltips=drawerNode=>{[drawerNode.querySelector(SELECTORS_CLOSEBTN),getDrawerOpenButton(drawerNode.id)].forEach((button=>{button&&disableButtonTooltip(button)}))},disableButtonTooltip=(button,enableOnBlur)=>{button.hasAttribute("data-original-title")?((0,_jquery.default)(button).tooltip("disable"),button.setAttribute("title",button.dataset.originalTitle)):(button.dataset.disabledToggle=button.dataset.toggle,button.removeAttribute("data-toggle")),enableOnBlur&&(button.dataset.restoreTooltipOnBlur=!0)},enableButtonTooltip=button=>{button.hasAttribute("data-original-title")?((0,_jquery.default)(button).tooltip("enable"),button.removeAttribute("title")):button.dataset.disabledToggle&&(button.dataset.toggle=button.dataset.disabledToggle,(0,_jquery.default)(button).tooltip()),delete button.dataset.restoreTooltipOnBlur};class Drawers{constructor(drawerNode){_defineProperty(this,"drawerNode",null),_defineProperty(this,"boundingRect",null),void 0===drawerNode.dataset.behatFakeDrawer&&(this.drawerNode=drawerNode,(0,_pagehelpers.isSmall)()&&this.closeDrawer({focusOnOpenButton:!1,updatePreferences:!1}),this.drawerNode.classList.contains(CLASSES_SHOW)?this.openDrawer({focusOnCloseButton:!1}):1==this.drawerNode.dataset.forceopen?(0,_pagehelpers.isSmall)()||this.openDrawer({focusOnCloseButton:!1}):Aria.hide(this.drawerNode),(0,_pagehelpers.isSmall)()&&disableDrawerTooltips(this.drawerNode),(drawerNode=>{const content=drawerNode.querySelector(SELECTORS_DRAWERCONTENT);content&&content.addEventListener("scroll",(()=>{drawerNode.classList.toggle(CLASSES_SCROLLED,0!=content.scrollTop)}))})(this.drawerNode),drawerMap.set(drawerNode,this),drawerNode.classList.remove(CLASSES_NOTINITIALISED))}get isOpen(){return this.drawerNode.classList.contains(CLASSES_SHOW)}get closeOnResize(){return!!parseInt(this.drawerNode.dataset.closeOnResize)}static getDrawerInstanceForNode(drawerNode){return drawerMap.has(drawerNode)||new Drawers(drawerNode),drawerMap.get(drawerNode)}dispatchEvent(eventname){let cancelable=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return(0,_event_dispatcher.dispatchEvent)(eventname,{drawerInstance:this},this.drawerNode,{cancelable:cancelable})}openDrawer(){var _this$drawerNode$quer,_this$drawerNode$quer2;let{focusOnCloseButton:focusOnCloseButton=!0}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const pendingPromise=new _pending.default("theme_boost/drawers:open");if(this.dispatchEvent(Drawers.eventTypes.drawerShow,!0).defaultPrevented)return;null===(_this$drawerNode$quer=this.drawerNode.querySelector(SELECTORS_CLOSEBTN))||void 0===_this$drawerNode$quer||_this$drawerNode$quer.classList.toggle("hidden",!0),null===(_this$drawerNode$quer2=this.drawerNode.querySelector(SELECTORS_HEADERCONTENT))||void 0===_this$drawerNode$quer2||_this$drawerNode$quer2.classList.toggle("hidden",!0);let openButton=getDrawerOpenButton(this.drawerNode.id);var _jQuery;openButton&&openButton.hasAttribute("data-original-title")&&(null===(_jQuery=(0,_jquery.default)(openButton))||void 0===_jQuery||_jQuery.tooltip("hide"));Aria.unhide(this.drawerNode),this.drawerNode.classList.add(CLASSES_SHOW);const preference=this.drawerNode.dataset.preference;preference&&!(0,_pagehelpers.isSmall)()&&1!=this.drawerNode.dataset.forceopen&&(0,_repository.setUserPreference)(preference,!0);const state=this.drawerNode.dataset.state;if(state){document.getElementById("page").classList.add(state)}this.boundingRect=this.drawerNode.getBoundingClientRect(),(0,_pagehelpers.isSmall)()&&getBackdrop().then((backdrop=>{backdrop.show();return document.getElementById("page").style.overflow="hidden",backdrop})).catch();const closeButton=this.drawerNode.querySelector(SELECTORS_CLOSEBTN),headerContent=this.drawerNode.querySelector(SELECTORS_HEADERCONTENT);focusOnCloseButton&&closeButton&&disableButtonTooltip(closeButton,!0),setTimeout((()=>{closeButton.classList.toggle("hidden",!1),headerContent.classList.toggle("hidden",!1),focusOnCloseButton&&closeButton.focus(),pendingPromise.resolve()}),300),this.dispatchEvent(Drawers.eventTypes.drawerShown)}closeDrawer(){let{focusOnOpenButton:focusOnOpenButton=!0,updatePreferences:updatePreferences=!0}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const pendingPromise=new _pending.default("theme_boost/drawers:close");if(this.dispatchEvent(Drawers.eventTypes.drawerHide,!0).defaultPrevented)return;const closeButton=this.drawerNode.querySelector(SELECTORS_CLOSEBTN);null==closeButton||closeButton.classList.toggle("hidden",!0);const headerContent=this.drawerNode.querySelector(SELECTORS_HEADERCONTENT);var _jQuery2;(null==headerContent||headerContent.classList.toggle("hidden",!0),closeButton.hasAttribute("data-original-title"))&&(null===(_jQuery2=(0,_jquery.default)(closeButton))||void 0===_jQuery2||_jQuery2.tooltip("hide"));const preference=this.drawerNode.dataset.preference;preference&&updatePreferences&&!(0,_pagehelpers.isSmall)()&&(0,_repository.setUserPreference)(preference,!1);const state=this.drawerNode.dataset.state;if(state){document.getElementById("page").classList.remove(state)}Aria.hide(this.drawerNode),this.drawerNode.classList.remove(CLASSES_SHOW),getBackdrop().then((backdrop=>{if(backdrop.hide(),(0,_pagehelpers.isSmall)()){document.getElementById("page").style.overflow="visible"}return backdrop})).catch();let openButton=getDrawerOpenButton(this.drawerNode.id);openButton&&disableButtonTooltip(openButton,!0),setTimeout((()=>{openButton&&focusOnOpenButton&&openButton.focus(),pendingPromise.resolve()}),300),this.dispatchEvent(Drawers.eventTypes.drawerHidden)}toggleVisibility(){this.drawerNode.classList.contains(CLASSES_SHOW)?this.closeDrawer():this.openDrawer()}displace(scrollPosition){var _this$drawerNode$data;let displace=scrollPosition,openButton=getDrawerOpenButton(this.drawerNode.id);if(0===scrollPosition)return this.drawerNode.style.transform="",void(openButton&&(openButton.style.transform=""));const state=null===(_this$drawerNode$data=this.drawerNode.dataset)||void 0===_this$drawerNode$data?void 0:_this$drawerNode$data.state,drawrWidth=this.drawerNode.offsetWidth;let scrollThreshold=drawrWidth,direction=-1;"show-drawer-right"===state&&(direction=1,scrollThreshold=20),Math.abs(scrollPosition)>scrollThreshold&&(displace=Math.sign(scrollPosition)*(drawrWidth+20)),displace*=direction;const transform="translateX(".concat(displace,"px)");openButton&&(openButton.style.transform=transform),this.drawerNode.style.transform=transform}preventOverlap(currentFocus){var _this$drawerNode$data2;if(!this.isOpen||"show-drawer-left"===(null===(_this$drawerNode$data2=this.drawerNode.dataset)||void 0===_this$drawerNode$data2?void 0:_this$drawerNode$data2.state))return;const drawrWidth=this.drawerNode.offsetWidth,element=currentFocus.getBoundingClientRect();let overlapping=element.right+20>this.boundingRect.left&&element.left-20currentBoundingRect.top&&element.top{drawerInstance.closeDrawer()}))}static closeOtherDrawers(comparisonInstance){drawerMap.forEach((drawerInstance=>{drawerInstance!==comparisonInstance&&drawerInstance.closeDrawer()}))}static preventCoveringFocusedElement(){const currentFocus=document.activeElement,pagecontent=document.querySelector(SELECTORS_PAGECONTENT);currentFocus&&null!=pagecontent&&pagecontent.contains(currentFocus)?drawerMap.forEach((drawerInstance=>{drawerInstance.preventOverlap(currentFocus)})):Drawers.displaceDrawers(window.scrollX)}static displaceDrawers(displace){drawerMap.forEach((drawerInstance=>{drawerInstance.displace(displace)}))}}_exports.default=Drawers,_defineProperty(Drawers,"eventTypes",{drawerShow:"theme_boost/drawers:show",drawerShown:"theme_boost/drawers:shown",drawerHide:"theme_boost/drawers:hide",drawerHidden:"theme_boost/drawers:hidden"});const setLastUsedToggle=toggleButton=>{toggleButton.dataset.target&&(document.querySelectorAll("".concat(SELECTORS_BUTTONS,'[data-target="').concat(toggleButton.dataset.target,'"]')).forEach((btn=>{btn.dataset.lastused=!1})),toggleButton.dataset.lastused=!0)};(()=>{document.addEventListener("click",(e=>{const toggleButton=e.target.closest(SELECTORS_TOGGLEBTN);if(toggleButton&&toggleButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(toggleButton.dataset.target),drawerInstance=Drawers.getDrawerInstanceForNode(targetDrawer);setLastUsedToggle(toggleButton),drawerInstance.toggleVisibility()}const openDrawerButton=e.target.closest(SELECTORS_OPENBTN);if(openDrawerButton&&openDrawerButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(openDrawerButton.dataset.target),drawerInstance=Drawers.getDrawerInstanceForNode(targetDrawer);setLastUsedToggle(toggleButton),drawerInstance.openDrawer()}const closeDrawerButton=e.target.closest(SELECTORS_CLOSEBTN);if(closeDrawerButton&&closeDrawerButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(closeDrawerButton.dataset.target);Drawers.getDrawerInstanceForNode(targetDrawer).closeDrawer(),(target=>{const lastUsedButton=document.querySelector("".concat(SELECTORS_BUTTONS,'[data-target="').concat(target,'"][data-lastused="true"'));lastUsedButton&&lastUsedButton.focus()})(closeDrawerButton.dataset.target)}})),document.addEventListener(Drawers.eventTypes.drawerShow,(e=>{(0,_pagehelpers.isLarge)()||Drawers.closeOtherDrawers(e.detail.drawerInstance)}));const btnSelector="".concat(SELECTORS_TOGGLEBTN,", ").concat(SELECTORS_OPENBTN,", ").concat(SELECTORS_CLOSEBTN);document.addEventListener("focusout",(e=>{const button=e.target.closest(btnSelector);void 0!==(null==button?void 0:button.dataset.restoreTooltipOnBlur)&&enableButtonTooltip(button)}));document.addEventListener("scroll",(()=>{const body=document.querySelector("body");window.scrollY>=window.innerHeight?body.classList.add(CLASSES_SCROLLED):body.classList.remove(CLASSES_SCROLLED),Drawers.displaceDrawers(window.scrollX)}));const preventOverlap=(0,_utils.debounce)(Drawers.preventCoveringFocusedElement,100);document.addEventListener("focusin",preventOverlap),document.addEventListener("focusout",preventOverlap),window.addEventListener("resize",(0,_utils.debounce)((()=>{if((0,_pagehelpers.isSmall)()){let anyOpen=!1;drawerMap.forEach((drawerInstance=>{disableDrawerTooltips(drawerInstance.drawerNode),drawerInstance.isOpen&&(drawerInstance.closeOnResize?drawerInstance.closeDrawer():anyOpen=!0)})),anyOpen&&getBackdrop().then((backdrop=>backdrop.show())).catch()}else drawerMap.forEach((drawerInstance=>{var drawerNode;[(drawerNode=drawerInstance.drawerNode).querySelector(SELECTORS_CLOSEBTN),getDrawerOpenButton(drawerNode.id)].forEach((button=>{button&&enableButtonTooltip(button)}))})),getBackdrop().then((backdrop=>backdrop.hide())).catch()}),400))})();return document.querySelectorAll(SELECTORS_DRAWERS).forEach((drawerNode=>Drawers.getDrawerInstanceForNode(drawerNode))),_exports.default}));
+define("theme_boost/drawers",["exports","core/modal_backdrop","core/templates","core/aria","core/event_dispatcher","core/utils","core/pagehelpers","core/pending","core_user/repository","jquery"],(function(_exports,_modal_backdrop,_templates,Aria,_event_dispatcher,_utils,_pagehelpers,_pending,_repository,_jquery){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_modal_backdrop=_interopRequireDefault(_modal_backdrop),_templates=_interopRequireDefault(_templates),Aria=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Aria),_pending=_interopRequireDefault(_pending),_jquery=_interopRequireDefault(_jquery);let backdropPromise=null;const drawerMap=new Map,SELECTORS_BUTTONS='[data-toggler="drawers"]',SELECTORS_CLOSEBTN='[data-toggler="drawers"][data-action="closedrawer"]',SELECTORS_OPENBTN='[data-toggler="drawers"][data-action="opendrawer"]',SELECTORS_TOGGLEBTN='[data-toggler="drawers"][data-action="toggle"]',SELECTORS_DRAWERS='[data-region="fixed-drawer"]',SELECTORS_DRAWERCONTENT=".drawercontent",SELECTORS_PAGECONTENT="#page-content",SELECTORS_HEADERCONTENT=".drawerheadercontent",CLASSES_SCROLLED="scrolled",CLASSES_SHOW="show",CLASSES_NOTINITIALISED="not-initialized",getDrawerZIndex=()=>{const drawer=document.querySelector(SELECTORS_DRAWERS);return drawer?parseInt(window.getComputedStyle(drawer).zIndex,10):null},getBackdrop=()=>(backdropPromise||(backdropPromise=_templates.default.render("core/modal_backdrop",{}).then((html=>new _modal_backdrop.default(html))).then((modalBackdrop=>(getDrawerZIndex()&&modalBackdrop.setZIndex(getDrawerZIndex()-1),modalBackdrop.getAttachmentPoint().get(0).addEventListener("click",(e=>{e.preventDefault(),Drawers.closeAllDrawers()})),modalBackdrop))).catch()),backdropPromise),getDrawerOpenButton=drawerId=>{let openButton=document.querySelector("".concat(SELECTORS_OPENBTN,'[data-target="').concat(drawerId,'"]'));return openButton||(openButton=document.querySelector("".concat(SELECTORS_TOGGLEBTN,'[data-target="').concat(drawerId,'"]'))),openButton},disableDrawerTooltips=drawerNode=>{[drawerNode.querySelector(SELECTORS_CLOSEBTN),getDrawerOpenButton(drawerNode.id)].forEach((button=>{button&&disableButtonTooltip(button)}))},disableButtonTooltip=(button,enableOnBlur)=>{button.hasAttribute("data-original-title")?((0,_jquery.default)(button).tooltip("disable"),button.setAttribute("title",button.dataset.originalTitle)):(button.dataset.disabledToggle=button.dataset.toggle,button.removeAttribute("data-toggle")),enableOnBlur&&(button.dataset.restoreTooltipOnBlur=!0)},enableButtonTooltip=button=>{button.hasAttribute("data-original-title")?((0,_jquery.default)(button).tooltip("enable"),button.removeAttribute("title")):button.dataset.disabledToggle&&(button.dataset.toggle=button.dataset.disabledToggle,(0,_jquery.default)(button).tooltip()),delete button.dataset.restoreTooltipOnBlur};class Drawers{constructor(drawerNode){_defineProperty(this,"drawerNode",null),_defineProperty(this,"boundingRect",null),void 0===drawerNode.dataset.behatFakeDrawer&&(this.drawerNode=drawerNode,(0,_pagehelpers.isSmall)()&&this.closeDrawer({focusOnOpenButton:!1,updatePreferences:!1}),this.drawerNode.classList.contains(CLASSES_SHOW)?this.openDrawer({focusOnCloseButton:!1}):1==this.drawerNode.dataset.forceopen?(0,_pagehelpers.isSmall)()||this.openDrawer({focusOnCloseButton:!1}):Aria.hide(this.drawerNode),(0,_pagehelpers.isSmall)()&&disableDrawerTooltips(this.drawerNode),(drawerNode=>{const content=drawerNode.querySelector(SELECTORS_DRAWERCONTENT);content&&content.addEventListener("scroll",(()=>{drawerNode.classList.toggle(CLASSES_SCROLLED,0!=content.scrollTop)}))})(this.drawerNode),drawerMap.set(drawerNode,this),drawerNode.classList.remove(CLASSES_NOTINITIALISED))}get isOpen(){return this.drawerNode.classList.contains(CLASSES_SHOW)}get closeOnResize(){return!!parseInt(this.drawerNode.dataset.closeOnResize)}static getDrawerInstanceForNode(drawerNode){return drawerMap.has(drawerNode)||new Drawers(drawerNode),drawerMap.get(drawerNode)}dispatchEvent(eventname){let cancelable=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return(0,_event_dispatcher.dispatchEvent)(eventname,{drawerInstance:this},this.drawerNode,{cancelable:cancelable})}openDrawer(){var _this$drawerNode$quer,_this$drawerNode$quer2;let{focusOnCloseButton:focusOnCloseButton=!0}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const pendingPromise=new _pending.default("theme_boost/drawers:open");if(this.dispatchEvent(Drawers.eventTypes.drawerShow,!0).defaultPrevented)return;null===(_this$drawerNode$quer=this.drawerNode.querySelector(SELECTORS_CLOSEBTN))||void 0===_this$drawerNode$quer||_this$drawerNode$quer.classList.toggle("hidden",!0),null===(_this$drawerNode$quer2=this.drawerNode.querySelector(SELECTORS_HEADERCONTENT))||void 0===_this$drawerNode$quer2||_this$drawerNode$quer2.classList.toggle("hidden",!0);let openButton=getDrawerOpenButton(this.drawerNode.id);var _jQuery;openButton&&openButton.hasAttribute("data-original-title")&&(null===(_jQuery=(0,_jquery.default)(openButton))||void 0===_jQuery||_jQuery.tooltip("hide"));Aria.unhide(this.drawerNode),this.drawerNode.classList.add(CLASSES_SHOW);const preference=this.drawerNode.dataset.preference;preference&&!(0,_pagehelpers.isSmall)()&&1!=this.drawerNode.dataset.forceopen&&(0,_repository.setUserPreference)(preference,!0);const state=this.drawerNode.dataset.state;if(state){document.getElementById("page").classList.add(state)}this.boundingRect=this.drawerNode.getBoundingClientRect(),(0,_pagehelpers.isSmall)()&&getBackdrop().then((backdrop=>{backdrop.show();return document.getElementById("page").style.overflow="hidden",backdrop})).catch();const closeButton=this.drawerNode.querySelector(SELECTORS_CLOSEBTN),headerContent=this.drawerNode.querySelector(SELECTORS_HEADERCONTENT);focusOnCloseButton&&closeButton&&disableButtonTooltip(closeButton,!0),setTimeout((()=>{closeButton.classList.toggle("hidden",!1),headerContent.classList.toggle("hidden",!1),focusOnCloseButton&&closeButton.focus(),pendingPromise.resolve()}),300),this.dispatchEvent(Drawers.eventTypes.drawerShown)}closeDrawer(){let{focusOnOpenButton:focusOnOpenButton=!0,updatePreferences:updatePreferences=!0}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const pendingPromise=new _pending.default("theme_boost/drawers:close");if(this.dispatchEvent(Drawers.eventTypes.drawerHide,!0).defaultPrevented)return;const closeButton=this.drawerNode.querySelector(SELECTORS_CLOSEBTN);null==closeButton||closeButton.classList.toggle("hidden",!0);const headerContent=this.drawerNode.querySelector(SELECTORS_HEADERCONTENT);var _jQuery2;(null==headerContent||headerContent.classList.toggle("hidden",!0),closeButton.hasAttribute("data-original-title"))&&(null===(_jQuery2=(0,_jquery.default)(closeButton))||void 0===_jQuery2||_jQuery2.tooltip("hide"));const preference=this.drawerNode.dataset.preference;preference&&updatePreferences&&!(0,_pagehelpers.isSmall)()&&(0,_repository.setUserPreference)(preference,!1);const state=this.drawerNode.dataset.state;if(state){document.getElementById("page").classList.remove(state)}Aria.hide(this.drawerNode),this.drawerNode.classList.remove(CLASSES_SHOW),getBackdrop().then((backdrop=>{if(backdrop.hide(),(0,_pagehelpers.isSmall)()){document.getElementById("page").style.overflow="visible"}return backdrop})).catch();let openButton=getDrawerOpenButton(this.drawerNode.id);openButton&&disableButtonTooltip(openButton,!0),setTimeout((()=>{openButton&&focusOnOpenButton&&openButton.focus(),pendingPromise.resolve()}),300),this.dispatchEvent(Drawers.eventTypes.drawerHidden)}toggleVisibility(){this.drawerNode.classList.contains(CLASSES_SHOW)?this.closeDrawer():this.openDrawer()}displace(scrollPosition){var _this$drawerNode$data;let displace=scrollPosition,openButton=getDrawerOpenButton(this.drawerNode.id);if(0===scrollPosition)return this.drawerNode.style.transform="",void(openButton&&(openButton.style.transform=""));const state=null===(_this$drawerNode$data=this.drawerNode.dataset)||void 0===_this$drawerNode$data?void 0:_this$drawerNode$data.state,drawrWidth=this.drawerNode.offsetWidth;let scrollThreshold=drawrWidth,direction=-1;"show-drawer-right"===state&&(direction=1,scrollThreshold=20),Math.abs(scrollPosition)>scrollThreshold&&(displace=Math.sign(scrollPosition)*(drawrWidth+20)),displace*=direction;const transform="translateX(".concat(displace,"px)");openButton&&(openButton.style.transform=transform),this.drawerNode.style.transform=transform}preventOverlap(currentFocus){var _this$drawerNode$data2;if(!this.isOpen||"show-drawer-left"===(null===(_this$drawerNode$data2=this.drawerNode.dataset)||void 0===_this$drawerNode$data2?void 0:_this$drawerNode$data2.state))return;const drawrWidth=this.drawerNode.offsetWidth,element=currentFocus.getBoundingClientRect();let overlapping=element.right+20>this.boundingRect.left&&element.left-20currentBoundingRect.top&&element.top{drawerInstance.closeDrawer()}))}static closeOtherDrawers(comparisonInstance){drawerMap.forEach((drawerInstance=>{drawerInstance!==comparisonInstance&&drawerInstance.closeDrawer()}))}static preventCoveringFocusedElement(){const currentFocus=document.activeElement,pagecontent=document.querySelector(SELECTORS_PAGECONTENT);currentFocus&&null!=pagecontent&&pagecontent.contains(currentFocus)?drawerMap.forEach((drawerInstance=>{drawerInstance.preventOverlap(currentFocus)})):Drawers.displaceDrawers(window.scrollX)}static displaceDrawers(displace){drawerMap.forEach((drawerInstance=>{drawerInstance.displace(displace)}))}}_exports.default=Drawers,_defineProperty(Drawers,"eventTypes",{drawerShow:"theme_boost/drawers:show",drawerShown:"theme_boost/drawers:shown",drawerHide:"theme_boost/drawers:hide",drawerHidden:"theme_boost/drawers:hidden"});const setLastUsedToggle=toggleButton=>{toggleButton.dataset.target&&(document.querySelectorAll("".concat(SELECTORS_BUTTONS,'[data-target="').concat(toggleButton.dataset.target,'"]')).forEach((btn=>{btn.dataset.lastused=!1})),toggleButton.dataset.lastused=!0)};(()=>{document.addEventListener("click",(e=>{const toggleButton=e.target.closest(SELECTORS_TOGGLEBTN);if(toggleButton&&toggleButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(toggleButton.dataset.target),drawerInstance=Drawers.getDrawerInstanceForNode(targetDrawer);setLastUsedToggle(toggleButton),drawerInstance.toggleVisibility()}const openDrawerButton=e.target.closest(SELECTORS_OPENBTN);if(openDrawerButton&&openDrawerButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(openDrawerButton.dataset.target),drawerInstance=Drawers.getDrawerInstanceForNode(targetDrawer);setLastUsedToggle(toggleButton),drawerInstance.openDrawer()}const closeDrawerButton=e.target.closest(SELECTORS_CLOSEBTN);if(closeDrawerButton&&closeDrawerButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(closeDrawerButton.dataset.target);Drawers.getDrawerInstanceForNode(targetDrawer).closeDrawer(),(target=>{const lastUsedButton=document.querySelector("".concat(SELECTORS_BUTTONS,'[data-target="').concat(target,'"][data-lastused="true"'));lastUsedButton&&lastUsedButton.focus()})(closeDrawerButton.dataset.target)}})),document.addEventListener(Drawers.eventTypes.drawerShow,(e=>{(0,_pagehelpers.isLarge)()||Drawers.closeOtherDrawers(e.detail.drawerInstance)}));const btnSelector="".concat(SELECTORS_TOGGLEBTN,", ").concat(SELECTORS_OPENBTN,", ").concat(SELECTORS_CLOSEBTN);document.addEventListener("focusout",(e=>{const button=e.target.closest(btnSelector);void 0!==(null==button?void 0:button.dataset.restoreTooltipOnBlur)&&enableButtonTooltip(button)}));document.addEventListener("scroll",(()=>{const body=document.querySelector("body");window.scrollY>=window.innerHeight?body.classList.add(CLASSES_SCROLLED):body.classList.remove(CLASSES_SCROLLED),Drawers.displaceDrawers(window.scrollX)}));const preventOverlap=(0,_utils.debounce)(Drawers.preventCoveringFocusedElement,100);document.addEventListener("focusin",preventOverlap),document.addEventListener("focusout",preventOverlap),window.addEventListener("resize",(0,_utils.debounce)((()=>{if((0,_pagehelpers.isSmall)()){let anyOpen=!1;drawerMap.forEach((drawerInstance=>{disableDrawerTooltips(drawerInstance.drawerNode),drawerInstance.isOpen&&(drawerInstance.closeOnResize?drawerInstance.closeDrawer():anyOpen=!0)})),anyOpen&&getBackdrop().then((backdrop=>backdrop.show())).catch()}else drawerMap.forEach((drawerInstance=>{var drawerNode;[(drawerNode=drawerInstance.drawerNode).querySelector(SELECTORS_CLOSEBTN),getDrawerOpenButton(drawerNode.id)].forEach((button=>{button&&enableButtonTooltip(button)}))})),getBackdrop().then((backdrop=>backdrop.hide())).catch()}),400,{pending:!0}))})();return document.querySelectorAll(SELECTORS_DRAWERS).forEach((drawerNode=>Drawers.getDrawerInstanceForNode(drawerNode))),_exports.default}));
//# sourceMappingURL=drawers.min.js.map
\ No newline at end of file
diff --git a/theme/boost/amd/build/drawers.min.js.map b/theme/boost/amd/build/drawers.min.js.map
index d141fdb3324d8..fa025c9ad0675 100644
--- a/theme/boost/amd/build/drawers.min.js.map
+++ b/theme/boost/amd/build/drawers.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"drawers.min.js","sources":["../src/drawers.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Toggling the visibility of the secondary navigation on mobile.\n *\n * @module theme_boost/drawers\n * @copyright 2021 Bas Brands\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport ModalBackdrop from 'core/modal_backdrop';\nimport Templates from 'core/templates';\nimport * as Aria from 'core/aria';\nimport {dispatchEvent} from 'core/event_dispatcher';\nimport {debounce} from 'core/utils';\nimport {isSmall, isLarge} from 'core/pagehelpers';\nimport Pending from 'core/pending';\nimport {setUserPreference} from 'core_user/repository';\n// The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-71979 is integrated.\nimport jQuery from 'jquery';\n\nlet backdropPromise = null;\n\nconst drawerMap = new Map();\n\nconst SELECTORS = {\n BUTTONS: '[data-toggler=\"drawers\"]',\n CLOSEBTN: '[data-toggler=\"drawers\"][data-action=\"closedrawer\"]',\n OPENBTN: '[data-toggler=\"drawers\"][data-action=\"opendrawer\"]',\n TOGGLEBTN: '[data-toggler=\"drawers\"][data-action=\"toggle\"]',\n DRAWERS: '[data-region=\"fixed-drawer\"]',\n DRAWERCONTENT: '.drawercontent',\n PAGECONTENT: '#page-content',\n HEADERCONTENT: '.drawerheadercontent',\n};\n\nconst CLASSES = {\n SCROLLED: 'scrolled',\n SHOW: 'show',\n NOTINITIALISED: 'not-initialized',\n};\n\n/**\n * Pixel thresshold to auto-hide drawers.\n *\n * @type {Number}\n */\nconst THRESHOLD = 20;\n\n/**\n * Try to get the drawer z-index from the page content.\n *\n * @returns {Number|null} the z-index of the drawer.\n * @private\n */\nconst getDrawerZIndex = () => {\n const drawer = document.querySelector(SELECTORS.DRAWERS);\n if (!drawer) {\n return null;\n }\n return parseInt(window.getComputedStyle(drawer).zIndex, 10);\n};\n\n/**\n * Add a backdrop to the page.\n *\n * @returns {Promise} rendering of modal backdrop.\n * @private\n */\nconst getBackdrop = () => {\n if (!backdropPromise) {\n backdropPromise = Templates.render('core/modal_backdrop', {})\n .then(html => new ModalBackdrop(html))\n .then(modalBackdrop => {\n const drawerZindex = getDrawerZIndex();\n if (drawerZindex) {\n modalBackdrop.setZIndex(getDrawerZIndex() - 1);\n }\n modalBackdrop.getAttachmentPoint().get(0).addEventListener('click', e => {\n e.preventDefault();\n Drawers.closeAllDrawers();\n });\n return modalBackdrop;\n })\n .catch();\n }\n return backdropPromise;\n};\n\n/**\n * Get the button element to open a specific drawer.\n *\n * @param {String} drawerId the drawer element Id\n * @return {HTMLElement|undefined} the open button element\n * @private\n */\nconst getDrawerOpenButton = (drawerId) => {\n let openButton = document.querySelector(`${SELECTORS.OPENBTN}[data-target=\"${drawerId}\"]`);\n if (!openButton) {\n openButton = document.querySelector(`${SELECTORS.TOGGLEBTN}[data-target=\"${drawerId}\"]`);\n }\n return openButton;\n};\n\n/**\n * Disable drawer tooltips.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst disableDrawerTooltips = (drawerNode) => {\n const buttons = [\n drawerNode.querySelector(SELECTORS.CLOSEBTN),\n getDrawerOpenButton(drawerNode.id),\n ];\n buttons.forEach(button => {\n if (!button) {\n return;\n }\n disableButtonTooltip(button);\n });\n};\n\n/**\n * Disable the button tooltips.\n *\n * @param {HTMLElement} button the button element\n * @param {boolean} enableOnBlur if the tooltip must be re-enabled on blur.\n * @private\n */\nconst disableButtonTooltip = (button, enableOnBlur) => {\n if (button.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(button).tooltip('disable');\n button.setAttribute('title', button.dataset.originalTitle);\n } else {\n button.dataset.disabledToggle = button.dataset.toggle;\n button.removeAttribute('data-toggle');\n }\n if (enableOnBlur) {\n button.dataset.restoreTooltipOnBlur = true;\n }\n};\n\n/**\n * Enable drawer tooltips.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst enableDrawerTooltips = (drawerNode) => {\n const buttons = [\n drawerNode.querySelector(SELECTORS.CLOSEBTN),\n getDrawerOpenButton(drawerNode.id),\n ];\n buttons.forEach(button => {\n if (!button) {\n return;\n }\n enableButtonTooltip(button);\n });\n};\n\n/**\n * Enable the button tooltips.\n *\n * @param {HTMLElement} button the button element\n * @private\n */\nconst enableButtonTooltip = (button) => {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n if (button.hasAttribute('data-original-title')) {\n jQuery(button).tooltip('enable');\n button.removeAttribute('title');\n } else if (button.dataset.disabledToggle) {\n button.dataset.toggle = button.dataset.disabledToggle;\n jQuery(button).tooltip();\n }\n delete button.dataset.restoreTooltipOnBlur;\n};\n\n/**\n * Add scroll listeners to a drawer element.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst addInnerScrollListener = (drawerNode) => {\n const content = drawerNode.querySelector(SELECTORS.DRAWERCONTENT);\n if (!content) {\n return;\n }\n content.addEventListener(\"scroll\", () => {\n drawerNode.classList.toggle(\n CLASSES.SCROLLED,\n content.scrollTop != 0\n );\n });\n};\n\n/**\n * The Drawers class is used to control on-screen drawer elements.\n *\n * It handles opening, and closing of drawer elements, as well as more detailed behaviours such as closing a drawer when\n * another drawer is opened, and supports closing a drawer when the screen is resized.\n *\n * Drawers are instantiated on page load, and can also be toggled lazily when toggling any drawer toggle, open button,\n * or close button.\n *\n * A range of show and hide events are also dispatched as detailed in the class\n * {@link module:theme_boost/drawers#eventTypes eventTypes} object.\n *\n * @example Standard usage\n *\n * // The module just needs to be included to add drawer support.\n * import 'theme_boost/drawers';\n *\n * @example Manually open or close any drawer\n *\n * import Drawers from 'theme_boost/drawers';\n *\n * const myDrawer = Drawers.getDrawerInstanceForNode(document.querySelector('.myDrawerNode');\n * myDrawer.closeDrawer();\n *\n * @example Listen to the before show event and cancel it\n *\n * import Drawers from 'theme_boost/drawers';\n *\n * document.addEventListener(Drawers.eventTypes.drawerShow, e => {\n * // The drawer which will be shown.\n * window.console.log(e.target);\n *\n * // The instance of the Drawers class for this drawer.\n * window.console.log(e.detail.drawerInstance);\n *\n * // Prevent this drawer from being shown.\n * e.preventDefault();\n * });\n *\n * @example Listen to the shown event\n *\n * document.addEventListener(Drawers.eventTypes.drawerShown, e => {\n * // The drawer which was shown.\n * window.console.log(e.target);\n *\n * // The instance of the Drawers class for this drawer.\n * window.console.log(e.detail.drawerInstance);\n * });\n */\nexport default class Drawers {\n /**\n * The underlying HTMLElement which is controlled.\n */\n drawerNode = null;\n\n /**\n * The drawer page bounding box dimensions.\n * @var {DOMRect} boundingRect\n */\n boundingRect = null;\n\n constructor(drawerNode) {\n // Some behat tests may use fake drawer divs to test components in drawers.\n if (drawerNode.dataset.behatFakeDrawer !== undefined) {\n return;\n }\n\n this.drawerNode = drawerNode;\n\n if (isSmall()) {\n this.closeDrawer({focusOnOpenButton: false, updatePreferences: false});\n }\n\n if (this.drawerNode.classList.contains(CLASSES.SHOW)) {\n this.openDrawer({focusOnCloseButton: false});\n } else if (this.drawerNode.dataset.forceopen == 1) {\n if (!isSmall()) {\n this.openDrawer({focusOnCloseButton: false});\n }\n } else {\n Aria.hide(this.drawerNode);\n }\n\n // Disable tooltips in small screens.\n if (isSmall()) {\n disableDrawerTooltips(this.drawerNode);\n }\n\n addInnerScrollListener(this.drawerNode);\n\n drawerMap.set(drawerNode, this);\n\n drawerNode.classList.remove(CLASSES.NOTINITIALISED);\n }\n\n /**\n * Whether the drawer is open.\n *\n * @returns {boolean}\n */\n get isOpen() {\n return this.drawerNode.classList.contains(CLASSES.SHOW);\n }\n\n /**\n * Whether the drawer should close when the window is resized\n *\n * @returns {boolean}\n */\n get closeOnResize() {\n return !!parseInt(this.drawerNode.dataset.closeOnResize);\n }\n\n /**\n * The list of event types.\n *\n * @static\n * @property {String} drawerShow See {@link event:theme_boost/drawers:show}\n * @property {String} drawerShown See {@link event:theme_boost/drawers:shown}\n * @property {String} drawerHide See {@link event:theme_boost/drawers:hide}\n * @property {String} drawerHidden See {@link event:theme_boost/drawers:hidden}\n */\n static eventTypes = {\n /**\n * An event triggered before a drawer is shown.\n *\n * @event theme_boost/drawers:show\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that will be opened.\n */\n drawerShow: 'theme_boost/drawers:show',\n\n /**\n * An event triggered after a drawer is shown.\n *\n * @event theme_boost/drawers:shown\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that was be opened.\n */\n drawerShown: 'theme_boost/drawers:shown',\n\n /**\n * An event triggered before a drawer is hidden.\n *\n * @event theme_boost/drawers:hide\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that will be hidden.\n */\n drawerHide: 'theme_boost/drawers:hide',\n\n /**\n * An event triggered after a drawer is hidden.\n *\n * @event theme_boost/drawers:hidden\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that was be hidden.\n */\n drawerHidden: 'theme_boost/drawers:hidden',\n };\n\n\n /**\n * Get the drawer instance for the specified node\n *\n * @param {HTMLElement} drawerNode\n * @returns {module:theme_boost/drawers}\n */\n static getDrawerInstanceForNode(drawerNode) {\n if (!drawerMap.has(drawerNode)) {\n new Drawers(drawerNode);\n }\n\n return drawerMap.get(drawerNode);\n }\n\n /**\n * Dispatch a drawer event.\n *\n * @param {string} eventname the event name\n * @param {boolean} cancelable if the event is cancelable\n * @returns {CustomEvent} the resulting custom event\n */\n dispatchEvent(eventname, cancelable = false) {\n return dispatchEvent(\n eventname,\n {\n drawerInstance: this,\n },\n this.drawerNode,\n {\n cancelable,\n }\n );\n }\n\n /**\n * Open the drawer.\n *\n * By default, openDrawer sets the page focus to the close drawer button. However, when a drawer is open at page\n * load, this represents an accessibility problem as the initial focus changes without any user interaction. The\n * focusOnCloseButton parameter can be set to false to prevent this behaviour.\n *\n * @param {object} args\n * @param {boolean} [args.focusOnCloseButton=true] Whether to alter page focus when opening the drawer\n */\n openDrawer({focusOnCloseButton = true} = {}) {\n\n const pendingPromise = new Pending('theme_boost/drawers:open');\n const showEvent = this.dispatchEvent(Drawers.eventTypes.drawerShow, true);\n if (showEvent.defaultPrevented) {\n return;\n }\n\n // Hide close button and header content while the drawer is showing to prevent glitchy effects.\n this.drawerNode.querySelector(SELECTORS.CLOSEBTN)?.classList.toggle('hidden', true);\n this.drawerNode.querySelector(SELECTORS.HEADERCONTENT)?.classList.toggle('hidden', true);\n\n\n // Remove open tooltip if still visible.\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (openButton && openButton.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(openButton)?.tooltip('hide');\n }\n\n Aria.unhide(this.drawerNode);\n this.drawerNode.classList.add(CLASSES.SHOW);\n\n const preference = this.drawerNode.dataset.preference;\n if (preference && !isSmall() && (this.drawerNode.dataset.forceopen != 1)) {\n setUserPreference(preference, true);\n }\n\n const state = this.drawerNode.dataset.state;\n if (state) {\n const page = document.getElementById('page');\n page.classList.add(state);\n }\n\n this.boundingRect = this.drawerNode.getBoundingClientRect();\n\n if (isSmall()) {\n getBackdrop().then(backdrop => {\n backdrop.show();\n\n const pageWrapper = document.getElementById('page');\n pageWrapper.style.overflow = 'hidden';\n return backdrop;\n })\n .catch();\n }\n\n // Show close button and header content once the drawer is fully opened.\n const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);\n const headerContent = this.drawerNode.querySelector(SELECTORS.HEADERCONTENT);\n if (focusOnCloseButton && closeButton) {\n disableButtonTooltip(closeButton, true);\n }\n setTimeout(() => {\n closeButton.classList.toggle('hidden', false);\n headerContent.classList.toggle('hidden', false);\n if (focusOnCloseButton) {\n closeButton.focus();\n }\n pendingPromise.resolve();\n }, 300);\n\n this.dispatchEvent(Drawers.eventTypes.drawerShown);\n }\n\n /**\n * Close the drawer.\n *\n * @param {object} args\n * @param {boolean} [args.focusOnOpenButton=true] Whether to alter page focus when opening the drawer\n * @param {boolean} [args.updatePreferences=true] Whether to update the user prewference\n */\n closeDrawer({focusOnOpenButton = true, updatePreferences = true} = {}) {\n\n const pendingPromise = new Pending('theme_boost/drawers:close');\n\n const hideEvent = this.dispatchEvent(Drawers.eventTypes.drawerHide, true);\n if (hideEvent.defaultPrevented) {\n return;\n }\n\n // Hide close button and header content while the drawer is hiding to prevent glitchy effects.\n const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);\n closeButton?.classList.toggle('hidden', true);\n const headerContent = this.drawerNode.querySelector(SELECTORS.HEADERCONTENT);\n headerContent?.classList.toggle('hidden', true);\n // Remove the close button tooltip if visible.\n if (closeButton.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(closeButton)?.tooltip('hide');\n }\n\n const preference = this.drawerNode.dataset.preference;\n if (preference && updatePreferences && !isSmall()) {\n setUserPreference(preference, false);\n }\n\n const state = this.drawerNode.dataset.state;\n if (state) {\n const page = document.getElementById('page');\n page.classList.remove(state);\n }\n\n Aria.hide(this.drawerNode);\n this.drawerNode.classList.remove(CLASSES.SHOW);\n\n getBackdrop().then(backdrop => {\n backdrop.hide();\n\n if (isSmall()) {\n const pageWrapper = document.getElementById('page');\n pageWrapper.style.overflow = 'visible';\n }\n return backdrop;\n })\n .catch();\n\n // Move focus to the open drawer (or toggler) button once the drawer is hidden.\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (openButton) {\n disableButtonTooltip(openButton, true);\n }\n setTimeout(() => {\n if (openButton && focusOnOpenButton) {\n openButton.focus();\n }\n pendingPromise.resolve();\n }, 300);\n\n this.dispatchEvent(Drawers.eventTypes.drawerHidden);\n }\n\n /**\n * Toggle visibility of the drawer.\n */\n toggleVisibility() {\n if (this.drawerNode.classList.contains(CLASSES.SHOW)) {\n this.closeDrawer();\n } else {\n this.openDrawer();\n }\n }\n\n /**\n * Displaces the drawer outsite the page.\n *\n * @param {Number} scrollPosition the page current scroll position\n */\n displace(scrollPosition) {\n let displace = scrollPosition;\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (scrollPosition === 0) {\n this.drawerNode.style.transform = '';\n if (openButton) {\n openButton.style.transform = '';\n }\n return;\n }\n const state = this.drawerNode.dataset?.state;\n const drawrWidth = this.drawerNode.offsetWidth;\n let scrollThreshold = drawrWidth;\n let direction = -1;\n if (state === 'show-drawer-right') {\n direction = 1;\n scrollThreshold = THRESHOLD;\n }\n // LTR scroll is positive while RTL scroll is negative.\n if (Math.abs(scrollPosition) > scrollThreshold) {\n displace = Math.sign(scrollPosition) * (drawrWidth + THRESHOLD);\n }\n displace *= direction;\n const transform = `translateX(${displace}px)`;\n if (openButton) {\n openButton.style.transform = transform;\n }\n this.drawerNode.style.transform = transform;\n }\n\n /**\n * Prevent drawer from overlapping an element.\n *\n * @param {HTMLElement} currentFocus\n */\n preventOverlap(currentFocus) {\n // Start position drawer (aka. left drawer) will never overlap with the page content.\n if (!this.isOpen || this.drawerNode.dataset?.state === 'show-drawer-left') {\n return;\n }\n const drawrWidth = this.drawerNode.offsetWidth;\n const element = currentFocus.getBoundingClientRect();\n\n // The this.boundingRect is calculated only once and it is reliable\n // for horizontal overlapping (which is the most common). However,\n // it is not reliable for vertical overlapping because the drawer\n // height can be changed by other elements like sticky footer.\n // To prevent recalculating the boundingRect on every\n // focusin event, we use horizontal overlapping as first fast check.\n let overlapping = (\n (element.right + THRESHOLD) > this.boundingRect.left &&\n (element.left - THRESHOLD) < this.boundingRect.right\n );\n if (overlapping) {\n const currentBoundingRect = this.drawerNode.getBoundingClientRect();\n overlapping = (\n (element.bottom) > currentBoundingRect.top &&\n (element.top) < currentBoundingRect.bottom\n );\n }\n\n if (overlapping) {\n // Force drawer to displace out of the page.\n let displaceOut = drawrWidth + 1;\n if (window.right_to_left()) {\n displaceOut *= -1;\n }\n this.displace(displaceOut);\n } else {\n // Reset drawer displacement.\n this.displace(window.scrollX);\n }\n }\n\n /**\n * Close all drawers.\n */\n static closeAllDrawers() {\n drawerMap.forEach(drawerInstance => {\n drawerInstance.closeDrawer();\n });\n }\n\n /**\n * Close all drawers except for the specified drawer.\n *\n * @param {module:theme_boost/drawers} comparisonInstance\n */\n static closeOtherDrawers(comparisonInstance) {\n drawerMap.forEach(drawerInstance => {\n if (drawerInstance === comparisonInstance) {\n return;\n }\n\n drawerInstance.closeDrawer();\n });\n }\n\n /**\n * Prevent drawers from covering the focused element.\n */\n static preventCoveringFocusedElement() {\n const currentFocus = document.activeElement;\n // Focus on page layout elements should be ignored.\n const pagecontent = document.querySelector(SELECTORS.PAGECONTENT);\n if (!currentFocus || !pagecontent?.contains(currentFocus)) {\n Drawers.displaceDrawers(window.scrollX);\n return;\n }\n drawerMap.forEach(drawerInstance => {\n drawerInstance.preventOverlap(currentFocus);\n });\n }\n\n /**\n * Prevent drawer from covering the content when the page content covers the full page.\n *\n * @param {Number} displace\n */\n static displaceDrawers(displace) {\n drawerMap.forEach(drawerInstance => {\n drawerInstance.displace(displace);\n });\n }\n}\n\n/**\n * Set the last used attribute for the last used toggle button for a drawer.\n *\n * @param {object} toggleButton The clicked button.\n */\nconst setLastUsedToggle = (toggleButton) => {\n if (toggleButton.dataset.target) {\n document.querySelectorAll(`${SELECTORS.BUTTONS}[data-target=\"${toggleButton.dataset.target}\"]`)\n .forEach(btn => {\n btn.dataset.lastused = false;\n });\n toggleButton.dataset.lastused = true;\n }\n};\n\n/**\n * Set the focus to the last used button to open this drawer.\n * @param {string} target The drawer target.\n */\nconst focusLastUsedToggle = (target) => {\n const lastUsedButton = document.querySelector(`${SELECTORS.BUTTONS}[data-target=\"${target}\"][data-lastused=\"true\"`);\n if (lastUsedButton) {\n lastUsedButton.focus();\n }\n};\n\n/**\n * Register the event listeners for the drawer.\n *\n * @private\n */\nconst registerListeners = () => {\n // Listen for show/hide events.\n document.addEventListener('click', e => {\n const toggleButton = e.target.closest(SELECTORS.TOGGLEBTN);\n if (toggleButton && toggleButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(toggleButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n setLastUsedToggle(toggleButton);\n\n drawerInstance.toggleVisibility();\n }\n\n const openDrawerButton = e.target.closest(SELECTORS.OPENBTN);\n if (openDrawerButton && openDrawerButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(openDrawerButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n setLastUsedToggle(toggleButton);\n\n drawerInstance.openDrawer();\n }\n\n const closeDrawerButton = e.target.closest(SELECTORS.CLOSEBTN);\n if (closeDrawerButton && closeDrawerButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(closeDrawerButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n\n drawerInstance.closeDrawer();\n focusLastUsedToggle(closeDrawerButton.dataset.target);\n }\n });\n\n // Close drawer when another drawer opens.\n document.addEventListener(Drawers.eventTypes.drawerShow, e => {\n if (isLarge()) {\n return;\n }\n Drawers.closeOtherDrawers(e.detail.drawerInstance);\n });\n\n // Tooglers and openers blur listeners.\n const btnSelector = `${SELECTORS.TOGGLEBTN}, ${SELECTORS.OPENBTN}, ${SELECTORS.CLOSEBTN}`;\n document.addEventListener('focusout', (e) => {\n const button = e.target.closest(btnSelector);\n if (button?.dataset.restoreTooltipOnBlur !== undefined) {\n enableButtonTooltip(button);\n }\n });\n\n const closeOnResizeListener = () => {\n if (isSmall()) {\n let anyOpen = false;\n drawerMap.forEach(drawerInstance => {\n disableDrawerTooltips(drawerInstance.drawerNode);\n if (drawerInstance.isOpen) {\n if (drawerInstance.closeOnResize) {\n drawerInstance.closeDrawer();\n } else {\n anyOpen = true;\n }\n }\n });\n\n if (anyOpen) {\n getBackdrop().then(backdrop => backdrop.show()).catch();\n }\n } else {\n drawerMap.forEach(drawerInstance => {\n enableDrawerTooltips(drawerInstance.drawerNode);\n });\n getBackdrop().then(backdrop => backdrop.hide()).catch();\n }\n };\n\n document.addEventListener('scroll', () => {\n const body = document.querySelector('body');\n if (window.scrollY >= window.innerHeight) {\n body.classList.add(CLASSES.SCROLLED);\n } else {\n body.classList.remove(CLASSES.SCROLLED);\n }\n // Horizontal scroll listener to displace the drawers to prevent covering\n // any possible sticky content.\n Drawers.displaceDrawers(window.scrollX);\n });\n\n const preventOverlap = debounce(Drawers.preventCoveringFocusedElement, 100);\n document.addEventListener('focusin', preventOverlap);\n document.addEventListener('focusout', preventOverlap);\n\n window.addEventListener('resize', debounce(closeOnResizeListener, 400));\n};\n\nregisterListeners();\n\nconst drawers = document.querySelectorAll(SELECTORS.DRAWERS);\ndrawers.forEach(drawerNode => Drawers.getDrawerInstanceForNode(drawerNode));\n"],"names":["backdropPromise","drawerMap","Map","SELECTORS","CLASSES","getDrawerZIndex","drawer","document","querySelector","parseInt","window","getComputedStyle","zIndex","getBackdrop","Templates","render","then","html","ModalBackdrop","modalBackdrop","setZIndex","getAttachmentPoint","get","addEventListener","e","preventDefault","Drawers","closeAllDrawers","catch","getDrawerOpenButton","drawerId","openButton","disableDrawerTooltips","drawerNode","id","forEach","button","disableButtonTooltip","enableOnBlur","hasAttribute","tooltip","setAttribute","dataset","originalTitle","disabledToggle","toggle","removeAttribute","restoreTooltipOnBlur","enableButtonTooltip","constructor","undefined","behatFakeDrawer","closeDrawer","focusOnOpenButton","updatePreferences","this","classList","contains","openDrawer","focusOnCloseButton","forceopen","Aria","hide","content","scrollTop","addInnerScrollListener","set","remove","isOpen","closeOnResize","has","dispatchEvent","eventname","cancelable","drawerInstance","pendingPromise","Pending","eventTypes","drawerShow","defaultPrevented","unhide","add","preference","state","getElementById","boundingRect","getBoundingClientRect","backdrop","show","style","overflow","closeButton","headerContent","setTimeout","focus","resolve","drawerShown","drawerHide","drawerHidden","toggleVisibility","displace","scrollPosition","transform","_this$drawerNode$data","drawrWidth","offsetWidth","scrollThreshold","direction","Math","abs","sign","preventOverlap","currentFocus","element","overlapping","right","left","currentBoundingRect","bottom","top","displaceOut","right_to_left","scrollX","comparisonInstance","activeElement","pagecontent","displaceDrawers","setLastUsedToggle","toggleButton","target","querySelectorAll","btn","lastused","closest","targetDrawer","getDrawerInstanceForNode","openDrawerButton","closeDrawerButton","lastUsedButton","focusLastUsedToggle","closeOtherDrawers","detail","btnSelector","body","scrollY","innerHeight","preventCoveringFocusedElement","anyOpen","registerListeners"],"mappings":"uuDAiCIA,gBAAkB,WAEhBC,UAAY,IAAIC,IAEhBC,kBACO,2BADPA,mBAEQ,sDAFRA,kBAGO,qDAHPA,oBAIS,iDAJTA,kBAKO,+BALPA,wBAMa,iBANbA,sBAOW,gBAPXA,wBAQa,uBAGbC,iBACQ,WADRA,aAEI,OAFJA,uBAGc,kBAgBdC,gBAAkB,WACdC,OAASC,SAASC,cAAcL,0BACjCG,OAGEG,SAASC,OAAOC,iBAAiBL,QAAQM,OAAQ,IAF7C,MAWTC,YAAc,KACXb,kBACDA,gBAAkBc,mBAAUC,OAAO,sBAAuB,IACzDC,MAAKC,MAAQ,IAAIC,wBAAcD,QAC/BD,MAAKG,gBACmBd,mBAEjBc,cAAcC,UAAUf,kBAAoB,GAEhDc,cAAcE,qBAAqBC,IAAI,GAAGC,iBAAiB,SAASC,IAChEA,EAAEC,iBACFC,QAAQC,qBAELR,iBAEVS,SAEE5B,iBAUL6B,oBAAuBC,eACrBC,WAAaxB,SAASC,wBAAiBL,2CAAkC2B,uBACxEC,aACDA,WAAaxB,SAASC,wBAAiBL,6CAAoC2B,iBAExEC,YASLC,sBAAyBC,aACX,CACZA,WAAWzB,cAAcL,oBACzB0B,oBAAoBI,WAAWC,KAE3BC,SAAQC,SACPA,QAGLC,qBAAqBD,YAWvBC,qBAAuB,CAACD,OAAQE,gBAC9BF,OAAOG,aAAa,4CAEbH,QAAQI,QAAQ,WACvBJ,OAAOK,aAAa,QAASL,OAAOM,QAAQC,iBAE5CP,OAAOM,QAAQE,eAAiBR,OAAOM,QAAQG,OAC/CT,OAAOU,gBAAgB,gBAEvBR,eACAF,OAAOM,QAAQK,sBAAuB,IA6BxCC,oBAAuBZ,SAErBA,OAAOG,aAAa,4CACbH,QAAQI,QAAQ,UACvBJ,OAAOU,gBAAgB,UAChBV,OAAOM,QAAQE,iBACtBR,OAAOM,QAAQG,OAAST,OAAOM,QAAQE,mCAChCR,QAAQI,kBAEZJ,OAAOM,QAAQK,4BAuELrB,QAYjBuB,YAAYhB,8CARC,0CAME,WAIgCiB,IAAvCjB,WAAWS,QAAQS,uBAIlBlB,WAAaA,YAEd,gCACKmB,YAAY,CAACC,mBAAmB,EAAOC,mBAAmB,IAG/DC,KAAKtB,WAAWuB,UAAUC,SAASrD,mBAC9BsD,WAAW,CAACC,oBAAoB,IACO,GAArCJ,KAAKtB,WAAWS,QAAQkB,WAC1B,gCACIF,WAAW,CAACC,oBAAoB,IAGzCE,KAAKC,KAAKP,KAAKtB,aAIf,2BACAD,sBAAsBuB,KAAKtB,YAlGPA,CAAAA,mBACtB8B,QAAU9B,WAAWzB,cAAcL,yBACpC4D,SAGLA,QAAQxC,iBAAiB,UAAU,KAC/BU,WAAWuB,UAAUX,OACjBzC,iBACqB,GAArB2D,QAAQC,eA6FZC,CAAuBV,KAAKtB,YAE5BhC,UAAUiE,IAAIjC,WAAYsB,MAE1BtB,WAAWuB,UAAUW,OAAO/D,yBAQ5BgE,oBACOb,KAAKtB,WAAWuB,UAAUC,SAASrD,cAQ1CiE,4BACS5D,SAAS8C,KAAKtB,WAAWS,QAAQ2B,+CAyDdpC,mBACvBhC,UAAUqE,IAAIrC,iBACXP,QAAQO,YAGThC,UAAUqB,IAAIW,YAUzBsC,cAAcC,eAAWC,0EACd,mCACHD,UACA,CACIE,eAAgBnB,MAEpBA,KAAKtB,WACL,CACIwC,WAAAA,aAeZf,kEAAWC,mBAACA,oBAAqB,0DAAQ,SAE/BgB,eAAiB,IAAIC,iBAAQ,+BACjBrB,KAAKgB,cAAc7C,QAAQmD,WAAWC,YAAY,GACtDC,2DAKT9C,WAAWzB,cAAcL,4EAAqBqD,UAAUX,OAAO,UAAU,uCACzEZ,WAAWzB,cAAcL,mFAA0BqD,UAAUX,OAAO,UAAU,OAI/Ed,WAAaF,oBAAoB0B,KAAKtB,WAAWC,gBACjDH,YAAcA,WAAWQ,aAAa,6DAE/BR,wCAAaS,QAAQ,SAGhCqB,KAAKmB,OAAOzB,KAAKtB,iBACZA,WAAWuB,UAAUyB,IAAI7E,oBAExB8E,WAAa3B,KAAKtB,WAAWS,QAAQwC,WACvCA,cAAe,2BAAmD,GAArC3B,KAAKtB,WAAWS,QAAQkB,6CACnCsB,YAAY,SAG5BC,MAAQ5B,KAAKtB,WAAWS,QAAQyC,SAClCA,MAAO,CACM5E,SAAS6E,eAAe,QAChC5B,UAAUyB,IAAIE,YAGlBE,aAAe9B,KAAKtB,WAAWqD,yBAEhC,2BACAzE,cAAcG,MAAKuE,WACfA,SAASC,cAEWjF,SAAS6E,eAAe,QAChCK,MAAMC,SAAW,SACtBH,YAEV3D,cAIC+D,YAAcpC,KAAKtB,WAAWzB,cAAcL,oBAC5CyF,cAAgBrC,KAAKtB,WAAWzB,cAAcL,yBAChDwD,oBAAsBgC,aACtBtD,qBAAqBsD,aAAa,GAEtCE,YAAW,KACPF,YAAYnC,UAAUX,OAAO,UAAU,GACvC+C,cAAcpC,UAAUX,OAAO,UAAU,GACrCc,oBACAgC,YAAYG,QAEhBnB,eAAeoB,YAChB,UAEExB,cAAc7C,QAAQmD,WAAWmB,aAU1C5C,kBAAYC,kBAACA,mBAAoB,EAArBC,kBAA2BA,mBAAoB,0DAAQ,SAEzDqB,eAAiB,IAAIC,iBAAQ,gCAEjBrB,KAAKgB,cAAc7C,QAAQmD,WAAWoB,YAAY,GACtDlB,8BAKRY,YAAcpC,KAAKtB,WAAWzB,cAAcL,oBAClDwF,MAAAA,aAAAA,YAAanC,UAAUX,OAAO,UAAU,SAClC+C,cAAgBrC,KAAKtB,WAAWzB,cAAcL,uCACpDyF,MAAAA,eAAAA,cAAepC,UAAUX,OAAO,UAAU,GAEtC8C,YAAYpD,aAAa,+DAElBoD,2CAAcnD,QAAQ,eAG3B0C,WAAa3B,KAAKtB,WAAWS,QAAQwC,WACvCA,YAAc5B,qBAAsB,6DAClB4B,YAAY,SAG5BC,MAAQ5B,KAAKtB,WAAWS,QAAQyC,SAClCA,MAAO,CACM5E,SAAS6E,eAAe,QAChC5B,UAAUW,OAAOgB,OAG1BtB,KAAKC,KAAKP,KAAKtB,iBACVA,WAAWuB,UAAUW,OAAO/D,cAEjCS,cAAcG,MAAKuE,cACfA,SAASzB,QAEL,0BAAW,CACSvD,SAAS6E,eAAe,QAChCK,MAAMC,SAAW,iBAE1BH,YAEV3D,YAGGG,WAAaF,oBAAoB0B,KAAKtB,WAAWC,IACjDH,YACAM,qBAAqBN,YAAY,GAErC8D,YAAW,KACH9D,YAAcsB,mBACdtB,WAAW+D,QAEfnB,eAAeoB,YAChB,UAEExB,cAAc7C,QAAQmD,WAAWqB,cAM1CC,mBACQ5C,KAAKtB,WAAWuB,UAAUC,SAASrD,mBAC9BgD,mBAEAM,aASb0C,SAASC,8CACDD,SAAWC,eACXtE,WAAaF,oBAAoB0B,KAAKtB,WAAWC,OAC9B,IAAnBmE,2BACKpE,WAAWwD,MAAMa,UAAY,QAC9BvE,aACAA,WAAW0D,MAAMa,UAAY,WAI/BnB,oCAAQ5B,KAAKtB,WAAWS,gDAAhB6D,sBAAyBpB,MACjCqB,WAAajD,KAAKtB,WAAWwE,gBAC/BC,gBAAkBF,WAClBG,WAAa,EACH,sBAAVxB,QACAwB,UAAY,EACZD,gBA1gBM,IA6gBNE,KAAKC,IAAIR,gBAAkBK,kBAC3BN,SAAWQ,KAAKE,KAAKT,iBAAmBG,WA9gBlC,KAghBVJ,UAAYO,gBACNL,+BAA0BF,gBAC5BrE,aACAA,WAAW0D,MAAMa,UAAYA,gBAE5BrE,WAAWwD,MAAMa,UAAYA,UAQtCS,eAAeC,6CAENzD,KAAKa,QAA6C,0DAA9BnC,WAAWS,wEAASyC,oBAGvCqB,WAAajD,KAAKtB,WAAWwE,YAC7BQ,QAAUD,aAAa1B,4BAQzB4B,YACCD,QAAQE,MA5iBH,GA4iBwB5D,KAAK8B,aAAa+B,MAC/CH,QAAQG,KA7iBH,GA6iBuB7D,KAAK8B,aAAa8B,SAE/CD,YAAa,OACPG,oBAAsB9D,KAAKtB,WAAWqD,wBAC5C4B,YACKD,QAAQK,OAAUD,oBAAoBE,KACtCN,QAAQM,IAAOF,oBAAoBC,UAIxCJ,YAAa,KAETM,YAAchB,WAAa,EAC3B9F,OAAO+G,kBACPD,cAAgB,QAEfpB,SAASoB,uBAGTpB,SAAS1F,OAAOgH,kCAQzBzH,UAAUkC,SAAQuC,iBACdA,eAAetB,0CASEuE,oBACrB1H,UAAUkC,SAAQuC,iBACVA,iBAAmBiD,oBAIvBjD,eAAetB,8DAQb4D,aAAezG,SAASqH,cAExBC,YAActH,SAASC,cAAcL,uBACtC6G,cAAiBa,MAAAA,aAAAA,YAAapE,SAASuD,cAI5C/G,UAAUkC,SAAQuC,iBACdA,eAAeqC,eAAeC,iBAJ9BtF,QAAQoG,gBAAgBpH,OAAOgH,gCAahBtB,UACnBnG,UAAUkC,SAAQuC,iBACdA,eAAe0B,SAASA,uDAzaf1E,qBAyEG,CAQhBoD,WAAY,2BASZkB,YAAa,4BASbC,WAAY,2BASZC,aAAc,qCAuUhB6B,kBAAqBC,eACnBA,aAAatF,QAAQuF,SACrB1H,SAAS2H,2BAAoB/H,2CAAkC6H,aAAatF,QAAQuF,cACnF9F,SAAQgG,MACLA,IAAIzF,QAAQ0F,UAAW,KAE3BJ,aAAatF,QAAQ0F,UAAW,IAoBd,MAEtB7H,SAASgB,iBAAiB,SAASC,UACzBwG,aAAexG,EAAEyG,OAAOI,QAAQlI,wBAClC6H,cAAgBA,aAAatF,QAAQuF,OAAQ,CAC7CzG,EAAEC,uBACI6G,aAAe/H,SAAS6E,eAAe4C,aAAatF,QAAQuF,QAC5DvD,eAAiBhD,QAAQ6G,yBAAyBD,cACxDP,kBAAkBC,cAElBtD,eAAeyB,yBAGbqC,iBAAmBhH,EAAEyG,OAAOI,QAAQlI,sBACtCqI,kBAAoBA,iBAAiB9F,QAAQuF,OAAQ,CACrDzG,EAAEC,uBACI6G,aAAe/H,SAAS6E,eAAeoD,iBAAiB9F,QAAQuF,QAChEvD,eAAiBhD,QAAQ6G,yBAAyBD,cACxDP,kBAAkBC,cAElBtD,eAAehB,mBAGb+E,kBAAoBjH,EAAEyG,OAAOI,QAAQlI,uBACvCsI,mBAAqBA,kBAAkB/F,QAAQuF,OAAQ,CACvDzG,EAAEC,uBACI6G,aAAe/H,SAAS6E,eAAeqD,kBAAkB/F,QAAQuF,QAChDvG,QAAQ6G,yBAAyBD,cAEzClF,cAzCE6E,CAAAA,eACnBS,eAAiBnI,SAASC,wBAAiBL,2CAAkC8H,mCAC/ES,gBACAA,eAAe5C,SAuCX6C,CAAoBF,kBAAkB/F,QAAQuF,YAKtD1H,SAASgB,iBAAiBG,QAAQmD,WAAWC,YAAYtD,KACjD,2BAGJE,QAAQkH,kBAAkBpH,EAAEqH,OAAOnE,yBAIjCoE,sBAAiB3I,iCAAwBA,+BAAsBA,oBACrEI,SAASgB,iBAAiB,YAAaC,UAC7BY,OAASZ,EAAEyG,OAAOI,QAAQS,kBACa5F,KAAzCd,MAAAA,cAAAA,OAAQM,QAAQK,uBAChBC,oBAAoBZ,WA6B5B7B,SAASgB,iBAAiB,UAAU,WAC1BwH,KAAOxI,SAASC,cAAc,QAChCE,OAAOsI,SAAWtI,OAAOuI,YACzBF,KAAKvF,UAAUyB,IAAI7E,kBAEnB2I,KAAKvF,UAAUW,OAAO/D,kBAI1BsB,QAAQoG,gBAAgBpH,OAAOgH,kBAG7BX,gBAAiB,mBAASrF,QAAQwH,8BAA+B,KACvE3I,SAASgB,iBAAiB,UAAWwF,gBACrCxG,SAASgB,iBAAiB,WAAYwF,gBAEtCrG,OAAOa,iBAAiB,UAAU,oBAzCJ,SACtB,0BAAW,KACP4H,SAAU,EACdlJ,UAAUkC,SAAQuC,iBACd1C,sBAAsB0C,eAAezC,YACjCyC,eAAeN,SACXM,eAAeL,cACfK,eAAetB,cAEf+F,SAAU,MAKlBA,SACAtI,cAAcG,MAAKuE,UAAYA,SAASC,SAAQ5D,aAGpD3B,UAAUkC,SAAQuC,iBArnBAzC,IAAAA,WACV,EADUA,WAsnBOyC,eAAezC,YApnBjCzB,cAAcL,oBACzB0B,oBAAoBI,WAAWC,KAE3BC,SAAQC,SACPA,QAGLY,oBAAoBZ,cA+mBhBvB,cAAcG,MAAKuE,UAAYA,SAASzB,SAAQlC,UAoBU,OAGtEwH,UAEgB7I,SAAS2H,iBAAiB/H,mBAClCgC,SAAQF,YAAcP,QAAQ6G,yBAAyBtG"}
\ No newline at end of file
+{"version":3,"file":"drawers.min.js","sources":["../src/drawers.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Toggling the visibility of the secondary navigation on mobile.\n *\n * @module theme_boost/drawers\n * @copyright 2021 Bas Brands\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport ModalBackdrop from 'core/modal_backdrop';\nimport Templates from 'core/templates';\nimport * as Aria from 'core/aria';\nimport {dispatchEvent} from 'core/event_dispatcher';\nimport {debounce} from 'core/utils';\nimport {isSmall, isLarge} from 'core/pagehelpers';\nimport Pending from 'core/pending';\nimport {setUserPreference} from 'core_user/repository';\n// The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-71979 is integrated.\nimport jQuery from 'jquery';\n\nlet backdropPromise = null;\n\nconst drawerMap = new Map();\n\nconst SELECTORS = {\n BUTTONS: '[data-toggler=\"drawers\"]',\n CLOSEBTN: '[data-toggler=\"drawers\"][data-action=\"closedrawer\"]',\n OPENBTN: '[data-toggler=\"drawers\"][data-action=\"opendrawer\"]',\n TOGGLEBTN: '[data-toggler=\"drawers\"][data-action=\"toggle\"]',\n DRAWERS: '[data-region=\"fixed-drawer\"]',\n DRAWERCONTENT: '.drawercontent',\n PAGECONTENT: '#page-content',\n HEADERCONTENT: '.drawerheadercontent',\n};\n\nconst CLASSES = {\n SCROLLED: 'scrolled',\n SHOW: 'show',\n NOTINITIALISED: 'not-initialized',\n};\n\n/**\n * Pixel thresshold to auto-hide drawers.\n *\n * @type {Number}\n */\nconst THRESHOLD = 20;\n\n/**\n * Try to get the drawer z-index from the page content.\n *\n * @returns {Number|null} the z-index of the drawer.\n * @private\n */\nconst getDrawerZIndex = () => {\n const drawer = document.querySelector(SELECTORS.DRAWERS);\n if (!drawer) {\n return null;\n }\n return parseInt(window.getComputedStyle(drawer).zIndex, 10);\n};\n\n/**\n * Add a backdrop to the page.\n *\n * @returns {Promise} rendering of modal backdrop.\n * @private\n */\nconst getBackdrop = () => {\n if (!backdropPromise) {\n backdropPromise = Templates.render('core/modal_backdrop', {})\n .then(html => new ModalBackdrop(html))\n .then(modalBackdrop => {\n const drawerZindex = getDrawerZIndex();\n if (drawerZindex) {\n modalBackdrop.setZIndex(getDrawerZIndex() - 1);\n }\n modalBackdrop.getAttachmentPoint().get(0).addEventListener('click', e => {\n e.preventDefault();\n Drawers.closeAllDrawers();\n });\n return modalBackdrop;\n })\n .catch();\n }\n return backdropPromise;\n};\n\n/**\n * Get the button element to open a specific drawer.\n *\n * @param {String} drawerId the drawer element Id\n * @return {HTMLElement|undefined} the open button element\n * @private\n */\nconst getDrawerOpenButton = (drawerId) => {\n let openButton = document.querySelector(`${SELECTORS.OPENBTN}[data-target=\"${drawerId}\"]`);\n if (!openButton) {\n openButton = document.querySelector(`${SELECTORS.TOGGLEBTN}[data-target=\"${drawerId}\"]`);\n }\n return openButton;\n};\n\n/**\n * Disable drawer tooltips.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst disableDrawerTooltips = (drawerNode) => {\n const buttons = [\n drawerNode.querySelector(SELECTORS.CLOSEBTN),\n getDrawerOpenButton(drawerNode.id),\n ];\n buttons.forEach(button => {\n if (!button) {\n return;\n }\n disableButtonTooltip(button);\n });\n};\n\n/**\n * Disable the button tooltips.\n *\n * @param {HTMLElement} button the button element\n * @param {boolean} enableOnBlur if the tooltip must be re-enabled on blur.\n * @private\n */\nconst disableButtonTooltip = (button, enableOnBlur) => {\n if (button.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(button).tooltip('disable');\n button.setAttribute('title', button.dataset.originalTitle);\n } else {\n button.dataset.disabledToggle = button.dataset.toggle;\n button.removeAttribute('data-toggle');\n }\n if (enableOnBlur) {\n button.dataset.restoreTooltipOnBlur = true;\n }\n};\n\n/**\n * Enable drawer tooltips.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst enableDrawerTooltips = (drawerNode) => {\n const buttons = [\n drawerNode.querySelector(SELECTORS.CLOSEBTN),\n getDrawerOpenButton(drawerNode.id),\n ];\n buttons.forEach(button => {\n if (!button) {\n return;\n }\n enableButtonTooltip(button);\n });\n};\n\n/**\n * Enable the button tooltips.\n *\n * @param {HTMLElement} button the button element\n * @private\n */\nconst enableButtonTooltip = (button) => {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n if (button.hasAttribute('data-original-title')) {\n jQuery(button).tooltip('enable');\n button.removeAttribute('title');\n } else if (button.dataset.disabledToggle) {\n button.dataset.toggle = button.dataset.disabledToggle;\n jQuery(button).tooltip();\n }\n delete button.dataset.restoreTooltipOnBlur;\n};\n\n/**\n * Add scroll listeners to a drawer element.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst addInnerScrollListener = (drawerNode) => {\n const content = drawerNode.querySelector(SELECTORS.DRAWERCONTENT);\n if (!content) {\n return;\n }\n content.addEventListener(\"scroll\", () => {\n drawerNode.classList.toggle(\n CLASSES.SCROLLED,\n content.scrollTop != 0\n );\n });\n};\n\n/**\n * The Drawers class is used to control on-screen drawer elements.\n *\n * It handles opening, and closing of drawer elements, as well as more detailed behaviours such as closing a drawer when\n * another drawer is opened, and supports closing a drawer when the screen is resized.\n *\n * Drawers are instantiated on page load, and can also be toggled lazily when toggling any drawer toggle, open button,\n * or close button.\n *\n * A range of show and hide events are also dispatched as detailed in the class\n * {@link module:theme_boost/drawers#eventTypes eventTypes} object.\n *\n * @example Standard usage\n *\n * // The module just needs to be included to add drawer support.\n * import 'theme_boost/drawers';\n *\n * @example Manually open or close any drawer\n *\n * import Drawers from 'theme_boost/drawers';\n *\n * const myDrawer = Drawers.getDrawerInstanceForNode(document.querySelector('.myDrawerNode');\n * myDrawer.closeDrawer();\n *\n * @example Listen to the before show event and cancel it\n *\n * import Drawers from 'theme_boost/drawers';\n *\n * document.addEventListener(Drawers.eventTypes.drawerShow, e => {\n * // The drawer which will be shown.\n * window.console.log(e.target);\n *\n * // The instance of the Drawers class for this drawer.\n * window.console.log(e.detail.drawerInstance);\n *\n * // Prevent this drawer from being shown.\n * e.preventDefault();\n * });\n *\n * @example Listen to the shown event\n *\n * document.addEventListener(Drawers.eventTypes.drawerShown, e => {\n * // The drawer which was shown.\n * window.console.log(e.target);\n *\n * // The instance of the Drawers class for this drawer.\n * window.console.log(e.detail.drawerInstance);\n * });\n */\nexport default class Drawers {\n /**\n * The underlying HTMLElement which is controlled.\n */\n drawerNode = null;\n\n /**\n * The drawer page bounding box dimensions.\n * @var {DOMRect} boundingRect\n */\n boundingRect = null;\n\n constructor(drawerNode) {\n // Some behat tests may use fake drawer divs to test components in drawers.\n if (drawerNode.dataset.behatFakeDrawer !== undefined) {\n return;\n }\n\n this.drawerNode = drawerNode;\n\n if (isSmall()) {\n this.closeDrawer({focusOnOpenButton: false, updatePreferences: false});\n }\n\n if (this.drawerNode.classList.contains(CLASSES.SHOW)) {\n this.openDrawer({focusOnCloseButton: false});\n } else if (this.drawerNode.dataset.forceopen == 1) {\n if (!isSmall()) {\n this.openDrawer({focusOnCloseButton: false});\n }\n } else {\n Aria.hide(this.drawerNode);\n }\n\n // Disable tooltips in small screens.\n if (isSmall()) {\n disableDrawerTooltips(this.drawerNode);\n }\n\n addInnerScrollListener(this.drawerNode);\n\n drawerMap.set(drawerNode, this);\n\n drawerNode.classList.remove(CLASSES.NOTINITIALISED);\n }\n\n /**\n * Whether the drawer is open.\n *\n * @returns {boolean}\n */\n get isOpen() {\n return this.drawerNode.classList.contains(CLASSES.SHOW);\n }\n\n /**\n * Whether the drawer should close when the window is resized\n *\n * @returns {boolean}\n */\n get closeOnResize() {\n return !!parseInt(this.drawerNode.dataset.closeOnResize);\n }\n\n /**\n * The list of event types.\n *\n * @static\n * @property {String} drawerShow See {@link event:theme_boost/drawers:show}\n * @property {String} drawerShown See {@link event:theme_boost/drawers:shown}\n * @property {String} drawerHide See {@link event:theme_boost/drawers:hide}\n * @property {String} drawerHidden See {@link event:theme_boost/drawers:hidden}\n */\n static eventTypes = {\n /**\n * An event triggered before a drawer is shown.\n *\n * @event theme_boost/drawers:show\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that will be opened.\n */\n drawerShow: 'theme_boost/drawers:show',\n\n /**\n * An event triggered after a drawer is shown.\n *\n * @event theme_boost/drawers:shown\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that was be opened.\n */\n drawerShown: 'theme_boost/drawers:shown',\n\n /**\n * An event triggered before a drawer is hidden.\n *\n * @event theme_boost/drawers:hide\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that will be hidden.\n */\n drawerHide: 'theme_boost/drawers:hide',\n\n /**\n * An event triggered after a drawer is hidden.\n *\n * @event theme_boost/drawers:hidden\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that was be hidden.\n */\n drawerHidden: 'theme_boost/drawers:hidden',\n };\n\n\n /**\n * Get the drawer instance for the specified node\n *\n * @param {HTMLElement} drawerNode\n * @returns {module:theme_boost/drawers}\n */\n static getDrawerInstanceForNode(drawerNode) {\n if (!drawerMap.has(drawerNode)) {\n new Drawers(drawerNode);\n }\n\n return drawerMap.get(drawerNode);\n }\n\n /**\n * Dispatch a drawer event.\n *\n * @param {string} eventname the event name\n * @param {boolean} cancelable if the event is cancelable\n * @returns {CustomEvent} the resulting custom event\n */\n dispatchEvent(eventname, cancelable = false) {\n return dispatchEvent(\n eventname,\n {\n drawerInstance: this,\n },\n this.drawerNode,\n {\n cancelable,\n }\n );\n }\n\n /**\n * Open the drawer.\n *\n * By default, openDrawer sets the page focus to the close drawer button. However, when a drawer is open at page\n * load, this represents an accessibility problem as the initial focus changes without any user interaction. The\n * focusOnCloseButton parameter can be set to false to prevent this behaviour.\n *\n * @param {object} args\n * @param {boolean} [args.focusOnCloseButton=true] Whether to alter page focus when opening the drawer\n */\n openDrawer({focusOnCloseButton = true} = {}) {\n\n const pendingPromise = new Pending('theme_boost/drawers:open');\n const showEvent = this.dispatchEvent(Drawers.eventTypes.drawerShow, true);\n if (showEvent.defaultPrevented) {\n return;\n }\n\n // Hide close button and header content while the drawer is showing to prevent glitchy effects.\n this.drawerNode.querySelector(SELECTORS.CLOSEBTN)?.classList.toggle('hidden', true);\n this.drawerNode.querySelector(SELECTORS.HEADERCONTENT)?.classList.toggle('hidden', true);\n\n\n // Remove open tooltip if still visible.\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (openButton && openButton.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(openButton)?.tooltip('hide');\n }\n\n Aria.unhide(this.drawerNode);\n this.drawerNode.classList.add(CLASSES.SHOW);\n\n const preference = this.drawerNode.dataset.preference;\n if (preference && !isSmall() && (this.drawerNode.dataset.forceopen != 1)) {\n setUserPreference(preference, true);\n }\n\n const state = this.drawerNode.dataset.state;\n if (state) {\n const page = document.getElementById('page');\n page.classList.add(state);\n }\n\n this.boundingRect = this.drawerNode.getBoundingClientRect();\n\n if (isSmall()) {\n getBackdrop().then(backdrop => {\n backdrop.show();\n\n const pageWrapper = document.getElementById('page');\n pageWrapper.style.overflow = 'hidden';\n return backdrop;\n })\n .catch();\n }\n\n // Show close button and header content once the drawer is fully opened.\n const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);\n const headerContent = this.drawerNode.querySelector(SELECTORS.HEADERCONTENT);\n if (focusOnCloseButton && closeButton) {\n disableButtonTooltip(closeButton, true);\n }\n setTimeout(() => {\n closeButton.classList.toggle('hidden', false);\n headerContent.classList.toggle('hidden', false);\n if (focusOnCloseButton) {\n closeButton.focus();\n }\n pendingPromise.resolve();\n }, 300);\n\n this.dispatchEvent(Drawers.eventTypes.drawerShown);\n }\n\n /**\n * Close the drawer.\n *\n * @param {object} args\n * @param {boolean} [args.focusOnOpenButton=true] Whether to alter page focus when opening the drawer\n * @param {boolean} [args.updatePreferences=true] Whether to update the user prewference\n */\n closeDrawer({focusOnOpenButton = true, updatePreferences = true} = {}) {\n\n const pendingPromise = new Pending('theme_boost/drawers:close');\n\n const hideEvent = this.dispatchEvent(Drawers.eventTypes.drawerHide, true);\n if (hideEvent.defaultPrevented) {\n return;\n }\n\n // Hide close button and header content while the drawer is hiding to prevent glitchy effects.\n const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);\n closeButton?.classList.toggle('hidden', true);\n const headerContent = this.drawerNode.querySelector(SELECTORS.HEADERCONTENT);\n headerContent?.classList.toggle('hidden', true);\n // Remove the close button tooltip if visible.\n if (closeButton.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(closeButton)?.tooltip('hide');\n }\n\n const preference = this.drawerNode.dataset.preference;\n if (preference && updatePreferences && !isSmall()) {\n setUserPreference(preference, false);\n }\n\n const state = this.drawerNode.dataset.state;\n if (state) {\n const page = document.getElementById('page');\n page.classList.remove(state);\n }\n\n Aria.hide(this.drawerNode);\n this.drawerNode.classList.remove(CLASSES.SHOW);\n\n getBackdrop().then(backdrop => {\n backdrop.hide();\n\n if (isSmall()) {\n const pageWrapper = document.getElementById('page');\n pageWrapper.style.overflow = 'visible';\n }\n return backdrop;\n })\n .catch();\n\n // Move focus to the open drawer (or toggler) button once the drawer is hidden.\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (openButton) {\n disableButtonTooltip(openButton, true);\n }\n setTimeout(() => {\n if (openButton && focusOnOpenButton) {\n openButton.focus();\n }\n pendingPromise.resolve();\n }, 300);\n\n this.dispatchEvent(Drawers.eventTypes.drawerHidden);\n }\n\n /**\n * Toggle visibility of the drawer.\n */\n toggleVisibility() {\n if (this.drawerNode.classList.contains(CLASSES.SHOW)) {\n this.closeDrawer();\n } else {\n this.openDrawer();\n }\n }\n\n /**\n * Displaces the drawer outsite the page.\n *\n * @param {Number} scrollPosition the page current scroll position\n */\n displace(scrollPosition) {\n let displace = scrollPosition;\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (scrollPosition === 0) {\n this.drawerNode.style.transform = '';\n if (openButton) {\n openButton.style.transform = '';\n }\n return;\n }\n const state = this.drawerNode.dataset?.state;\n const drawrWidth = this.drawerNode.offsetWidth;\n let scrollThreshold = drawrWidth;\n let direction = -1;\n if (state === 'show-drawer-right') {\n direction = 1;\n scrollThreshold = THRESHOLD;\n }\n // LTR scroll is positive while RTL scroll is negative.\n if (Math.abs(scrollPosition) > scrollThreshold) {\n displace = Math.sign(scrollPosition) * (drawrWidth + THRESHOLD);\n }\n displace *= direction;\n const transform = `translateX(${displace}px)`;\n if (openButton) {\n openButton.style.transform = transform;\n }\n this.drawerNode.style.transform = transform;\n }\n\n /**\n * Prevent drawer from overlapping an element.\n *\n * @param {HTMLElement} currentFocus\n */\n preventOverlap(currentFocus) {\n // Start position drawer (aka. left drawer) will never overlap with the page content.\n if (!this.isOpen || this.drawerNode.dataset?.state === 'show-drawer-left') {\n return;\n }\n const drawrWidth = this.drawerNode.offsetWidth;\n const element = currentFocus.getBoundingClientRect();\n\n // The this.boundingRect is calculated only once and it is reliable\n // for horizontal overlapping (which is the most common). However,\n // it is not reliable for vertical overlapping because the drawer\n // height can be changed by other elements like sticky footer.\n // To prevent recalculating the boundingRect on every\n // focusin event, we use horizontal overlapping as first fast check.\n let overlapping = (\n (element.right + THRESHOLD) > this.boundingRect.left &&\n (element.left - THRESHOLD) < this.boundingRect.right\n );\n if (overlapping) {\n const currentBoundingRect = this.drawerNode.getBoundingClientRect();\n overlapping = (\n (element.bottom) > currentBoundingRect.top &&\n (element.top) < currentBoundingRect.bottom\n );\n }\n\n if (overlapping) {\n // Force drawer to displace out of the page.\n let displaceOut = drawrWidth + 1;\n if (window.right_to_left()) {\n displaceOut *= -1;\n }\n this.displace(displaceOut);\n } else {\n // Reset drawer displacement.\n this.displace(window.scrollX);\n }\n }\n\n /**\n * Close all drawers.\n */\n static closeAllDrawers() {\n drawerMap.forEach(drawerInstance => {\n drawerInstance.closeDrawer();\n });\n }\n\n /**\n * Close all drawers except for the specified drawer.\n *\n * @param {module:theme_boost/drawers} comparisonInstance\n */\n static closeOtherDrawers(comparisonInstance) {\n drawerMap.forEach(drawerInstance => {\n if (drawerInstance === comparisonInstance) {\n return;\n }\n\n drawerInstance.closeDrawer();\n });\n }\n\n /**\n * Prevent drawers from covering the focused element.\n */\n static preventCoveringFocusedElement() {\n const currentFocus = document.activeElement;\n // Focus on page layout elements should be ignored.\n const pagecontent = document.querySelector(SELECTORS.PAGECONTENT);\n if (!currentFocus || !pagecontent?.contains(currentFocus)) {\n Drawers.displaceDrawers(window.scrollX);\n return;\n }\n drawerMap.forEach(drawerInstance => {\n drawerInstance.preventOverlap(currentFocus);\n });\n }\n\n /**\n * Prevent drawer from covering the content when the page content covers the full page.\n *\n * @param {Number} displace\n */\n static displaceDrawers(displace) {\n drawerMap.forEach(drawerInstance => {\n drawerInstance.displace(displace);\n });\n }\n}\n\n/**\n * Set the last used attribute for the last used toggle button for a drawer.\n *\n * @param {object} toggleButton The clicked button.\n */\nconst setLastUsedToggle = (toggleButton) => {\n if (toggleButton.dataset.target) {\n document.querySelectorAll(`${SELECTORS.BUTTONS}[data-target=\"${toggleButton.dataset.target}\"]`)\n .forEach(btn => {\n btn.dataset.lastused = false;\n });\n toggleButton.dataset.lastused = true;\n }\n};\n\n/**\n * Set the focus to the last used button to open this drawer.\n * @param {string} target The drawer target.\n */\nconst focusLastUsedToggle = (target) => {\n const lastUsedButton = document.querySelector(`${SELECTORS.BUTTONS}[data-target=\"${target}\"][data-lastused=\"true\"`);\n if (lastUsedButton) {\n lastUsedButton.focus();\n }\n};\n\n/**\n * Register the event listeners for the drawer.\n *\n * @private\n */\nconst registerListeners = () => {\n // Listen for show/hide events.\n document.addEventListener('click', e => {\n const toggleButton = e.target.closest(SELECTORS.TOGGLEBTN);\n if (toggleButton && toggleButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(toggleButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n setLastUsedToggle(toggleButton);\n\n drawerInstance.toggleVisibility();\n }\n\n const openDrawerButton = e.target.closest(SELECTORS.OPENBTN);\n if (openDrawerButton && openDrawerButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(openDrawerButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n setLastUsedToggle(toggleButton);\n\n drawerInstance.openDrawer();\n }\n\n const closeDrawerButton = e.target.closest(SELECTORS.CLOSEBTN);\n if (closeDrawerButton && closeDrawerButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(closeDrawerButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n\n drawerInstance.closeDrawer();\n focusLastUsedToggle(closeDrawerButton.dataset.target);\n }\n });\n\n // Close drawer when another drawer opens.\n document.addEventListener(Drawers.eventTypes.drawerShow, e => {\n if (isLarge()) {\n return;\n }\n Drawers.closeOtherDrawers(e.detail.drawerInstance);\n });\n\n // Tooglers and openers blur listeners.\n const btnSelector = `${SELECTORS.TOGGLEBTN}, ${SELECTORS.OPENBTN}, ${SELECTORS.CLOSEBTN}`;\n document.addEventListener('focusout', (e) => {\n const button = e.target.closest(btnSelector);\n if (button?.dataset.restoreTooltipOnBlur !== undefined) {\n enableButtonTooltip(button);\n }\n });\n\n const closeOnResizeListener = () => {\n if (isSmall()) {\n let anyOpen = false;\n drawerMap.forEach(drawerInstance => {\n disableDrawerTooltips(drawerInstance.drawerNode);\n if (drawerInstance.isOpen) {\n if (drawerInstance.closeOnResize) {\n drawerInstance.closeDrawer();\n } else {\n anyOpen = true;\n }\n }\n });\n\n if (anyOpen) {\n getBackdrop().then(backdrop => backdrop.show()).catch();\n }\n } else {\n drawerMap.forEach(drawerInstance => {\n enableDrawerTooltips(drawerInstance.drawerNode);\n });\n getBackdrop().then(backdrop => backdrop.hide()).catch();\n }\n };\n\n document.addEventListener('scroll', () => {\n const body = document.querySelector('body');\n if (window.scrollY >= window.innerHeight) {\n body.classList.add(CLASSES.SCROLLED);\n } else {\n body.classList.remove(CLASSES.SCROLLED);\n }\n // Horizontal scroll listener to displace the drawers to prevent covering\n // any possible sticky content.\n Drawers.displaceDrawers(window.scrollX);\n });\n\n const preventOverlap = debounce(Drawers.preventCoveringFocusedElement, 100);\n document.addEventListener('focusin', preventOverlap);\n document.addEventListener('focusout', preventOverlap);\n\n window.addEventListener('resize', debounce(closeOnResizeListener, 400, {pending: true}));\n};\n\nregisterListeners();\n\nconst drawers = document.querySelectorAll(SELECTORS.DRAWERS);\ndrawers.forEach(drawerNode => Drawers.getDrawerInstanceForNode(drawerNode));\n"],"names":["backdropPromise","drawerMap","Map","SELECTORS","CLASSES","getDrawerZIndex","drawer","document","querySelector","parseInt","window","getComputedStyle","zIndex","getBackdrop","Templates","render","then","html","ModalBackdrop","modalBackdrop","setZIndex","getAttachmentPoint","get","addEventListener","e","preventDefault","Drawers","closeAllDrawers","catch","getDrawerOpenButton","drawerId","openButton","disableDrawerTooltips","drawerNode","id","forEach","button","disableButtonTooltip","enableOnBlur","hasAttribute","tooltip","setAttribute","dataset","originalTitle","disabledToggle","toggle","removeAttribute","restoreTooltipOnBlur","enableButtonTooltip","constructor","undefined","behatFakeDrawer","closeDrawer","focusOnOpenButton","updatePreferences","this","classList","contains","openDrawer","focusOnCloseButton","forceopen","Aria","hide","content","scrollTop","addInnerScrollListener","set","remove","isOpen","closeOnResize","has","dispatchEvent","eventname","cancelable","drawerInstance","pendingPromise","Pending","eventTypes","drawerShow","defaultPrevented","unhide","add","preference","state","getElementById","boundingRect","getBoundingClientRect","backdrop","show","style","overflow","closeButton","headerContent","setTimeout","focus","resolve","drawerShown","drawerHide","drawerHidden","toggleVisibility","displace","scrollPosition","transform","_this$drawerNode$data","drawrWidth","offsetWidth","scrollThreshold","direction","Math","abs","sign","preventOverlap","currentFocus","element","overlapping","right","left","currentBoundingRect","bottom","top","displaceOut","right_to_left","scrollX","comparisonInstance","activeElement","pagecontent","displaceDrawers","setLastUsedToggle","toggleButton","target","querySelectorAll","btn","lastused","closest","targetDrawer","getDrawerInstanceForNode","openDrawerButton","closeDrawerButton","lastUsedButton","focusLastUsedToggle","closeOtherDrawers","detail","btnSelector","body","scrollY","innerHeight","preventCoveringFocusedElement","anyOpen","pending","registerListeners"],"mappings":"uuDAiCIA,gBAAkB,WAEhBC,UAAY,IAAIC,IAEhBC,kBACO,2BADPA,mBAEQ,sDAFRA,kBAGO,qDAHPA,oBAIS,iDAJTA,kBAKO,+BALPA,wBAMa,iBANbA,sBAOW,gBAPXA,wBAQa,uBAGbC,iBACQ,WADRA,aAEI,OAFJA,uBAGc,kBAgBdC,gBAAkB,WACdC,OAASC,SAASC,cAAcL,0BACjCG,OAGEG,SAASC,OAAOC,iBAAiBL,QAAQM,OAAQ,IAF7C,MAWTC,YAAc,KACXb,kBACDA,gBAAkBc,mBAAUC,OAAO,sBAAuB,IACzDC,MAAKC,MAAQ,IAAIC,wBAAcD,QAC/BD,MAAKG,gBACmBd,mBAEjBc,cAAcC,UAAUf,kBAAoB,GAEhDc,cAAcE,qBAAqBC,IAAI,GAAGC,iBAAiB,SAASC,IAChEA,EAAEC,iBACFC,QAAQC,qBAELR,iBAEVS,SAEE5B,iBAUL6B,oBAAuBC,eACrBC,WAAaxB,SAASC,wBAAiBL,2CAAkC2B,uBACxEC,aACDA,WAAaxB,SAASC,wBAAiBL,6CAAoC2B,iBAExEC,YASLC,sBAAyBC,aACX,CACZA,WAAWzB,cAAcL,oBACzB0B,oBAAoBI,WAAWC,KAE3BC,SAAQC,SACPA,QAGLC,qBAAqBD,YAWvBC,qBAAuB,CAACD,OAAQE,gBAC9BF,OAAOG,aAAa,4CAEbH,QAAQI,QAAQ,WACvBJ,OAAOK,aAAa,QAASL,OAAOM,QAAQC,iBAE5CP,OAAOM,QAAQE,eAAiBR,OAAOM,QAAQG,OAC/CT,OAAOU,gBAAgB,gBAEvBR,eACAF,OAAOM,QAAQK,sBAAuB,IA6BxCC,oBAAuBZ,SAErBA,OAAOG,aAAa,4CACbH,QAAQI,QAAQ,UACvBJ,OAAOU,gBAAgB,UAChBV,OAAOM,QAAQE,iBACtBR,OAAOM,QAAQG,OAAST,OAAOM,QAAQE,mCAChCR,QAAQI,kBAEZJ,OAAOM,QAAQK,4BAuELrB,QAYjBuB,YAAYhB,8CARC,0CAME,WAIgCiB,IAAvCjB,WAAWS,QAAQS,uBAIlBlB,WAAaA,YAEd,gCACKmB,YAAY,CAACC,mBAAmB,EAAOC,mBAAmB,IAG/DC,KAAKtB,WAAWuB,UAAUC,SAASrD,mBAC9BsD,WAAW,CAACC,oBAAoB,IACO,GAArCJ,KAAKtB,WAAWS,QAAQkB,WAC1B,gCACIF,WAAW,CAACC,oBAAoB,IAGzCE,KAAKC,KAAKP,KAAKtB,aAIf,2BACAD,sBAAsBuB,KAAKtB,YAlGPA,CAAAA,mBACtB8B,QAAU9B,WAAWzB,cAAcL,yBACpC4D,SAGLA,QAAQxC,iBAAiB,UAAU,KAC/BU,WAAWuB,UAAUX,OACjBzC,iBACqB,GAArB2D,QAAQC,eA6FZC,CAAuBV,KAAKtB,YAE5BhC,UAAUiE,IAAIjC,WAAYsB,MAE1BtB,WAAWuB,UAAUW,OAAO/D,yBAQ5BgE,oBACOb,KAAKtB,WAAWuB,UAAUC,SAASrD,cAQ1CiE,4BACS5D,SAAS8C,KAAKtB,WAAWS,QAAQ2B,+CAyDdpC,mBACvBhC,UAAUqE,IAAIrC,iBACXP,QAAQO,YAGThC,UAAUqB,IAAIW,YAUzBsC,cAAcC,eAAWC,0EACd,mCACHD,UACA,CACIE,eAAgBnB,MAEpBA,KAAKtB,WACL,CACIwC,WAAAA,aAeZf,kEAAWC,mBAACA,oBAAqB,0DAAQ,SAE/BgB,eAAiB,IAAIC,iBAAQ,+BACjBrB,KAAKgB,cAAc7C,QAAQmD,WAAWC,YAAY,GACtDC,2DAKT9C,WAAWzB,cAAcL,4EAAqBqD,UAAUX,OAAO,UAAU,uCACzEZ,WAAWzB,cAAcL,mFAA0BqD,UAAUX,OAAO,UAAU,OAI/Ed,WAAaF,oBAAoB0B,KAAKtB,WAAWC,gBACjDH,YAAcA,WAAWQ,aAAa,6DAE/BR,wCAAaS,QAAQ,SAGhCqB,KAAKmB,OAAOzB,KAAKtB,iBACZA,WAAWuB,UAAUyB,IAAI7E,oBAExB8E,WAAa3B,KAAKtB,WAAWS,QAAQwC,WACvCA,cAAe,2BAAmD,GAArC3B,KAAKtB,WAAWS,QAAQkB,6CACnCsB,YAAY,SAG5BC,MAAQ5B,KAAKtB,WAAWS,QAAQyC,SAClCA,MAAO,CACM5E,SAAS6E,eAAe,QAChC5B,UAAUyB,IAAIE,YAGlBE,aAAe9B,KAAKtB,WAAWqD,yBAEhC,2BACAzE,cAAcG,MAAKuE,WACfA,SAASC,cAEWjF,SAAS6E,eAAe,QAChCK,MAAMC,SAAW,SACtBH,YAEV3D,cAIC+D,YAAcpC,KAAKtB,WAAWzB,cAAcL,oBAC5CyF,cAAgBrC,KAAKtB,WAAWzB,cAAcL,yBAChDwD,oBAAsBgC,aACtBtD,qBAAqBsD,aAAa,GAEtCE,YAAW,KACPF,YAAYnC,UAAUX,OAAO,UAAU,GACvC+C,cAAcpC,UAAUX,OAAO,UAAU,GACrCc,oBACAgC,YAAYG,QAEhBnB,eAAeoB,YAChB,UAEExB,cAAc7C,QAAQmD,WAAWmB,aAU1C5C,kBAAYC,kBAACA,mBAAoB,EAArBC,kBAA2BA,mBAAoB,0DAAQ,SAEzDqB,eAAiB,IAAIC,iBAAQ,gCAEjBrB,KAAKgB,cAAc7C,QAAQmD,WAAWoB,YAAY,GACtDlB,8BAKRY,YAAcpC,KAAKtB,WAAWzB,cAAcL,oBAClDwF,MAAAA,aAAAA,YAAanC,UAAUX,OAAO,UAAU,SAClC+C,cAAgBrC,KAAKtB,WAAWzB,cAAcL,uCACpDyF,MAAAA,eAAAA,cAAepC,UAAUX,OAAO,UAAU,GAEtC8C,YAAYpD,aAAa,+DAElBoD,2CAAcnD,QAAQ,eAG3B0C,WAAa3B,KAAKtB,WAAWS,QAAQwC,WACvCA,YAAc5B,qBAAsB,6DAClB4B,YAAY,SAG5BC,MAAQ5B,KAAKtB,WAAWS,QAAQyC,SAClCA,MAAO,CACM5E,SAAS6E,eAAe,QAChC5B,UAAUW,OAAOgB,OAG1BtB,KAAKC,KAAKP,KAAKtB,iBACVA,WAAWuB,UAAUW,OAAO/D,cAEjCS,cAAcG,MAAKuE,cACfA,SAASzB,QAEL,0BAAW,CACSvD,SAAS6E,eAAe,QAChCK,MAAMC,SAAW,iBAE1BH,YAEV3D,YAGGG,WAAaF,oBAAoB0B,KAAKtB,WAAWC,IACjDH,YACAM,qBAAqBN,YAAY,GAErC8D,YAAW,KACH9D,YAAcsB,mBACdtB,WAAW+D,QAEfnB,eAAeoB,YAChB,UAEExB,cAAc7C,QAAQmD,WAAWqB,cAM1CC,mBACQ5C,KAAKtB,WAAWuB,UAAUC,SAASrD,mBAC9BgD,mBAEAM,aASb0C,SAASC,8CACDD,SAAWC,eACXtE,WAAaF,oBAAoB0B,KAAKtB,WAAWC,OAC9B,IAAnBmE,2BACKpE,WAAWwD,MAAMa,UAAY,QAC9BvE,aACAA,WAAW0D,MAAMa,UAAY,WAI/BnB,oCAAQ5B,KAAKtB,WAAWS,gDAAhB6D,sBAAyBpB,MACjCqB,WAAajD,KAAKtB,WAAWwE,gBAC/BC,gBAAkBF,WAClBG,WAAa,EACH,sBAAVxB,QACAwB,UAAY,EACZD,gBA1gBM,IA6gBNE,KAAKC,IAAIR,gBAAkBK,kBAC3BN,SAAWQ,KAAKE,KAAKT,iBAAmBG,WA9gBlC,KAghBVJ,UAAYO,gBACNL,+BAA0BF,gBAC5BrE,aACAA,WAAW0D,MAAMa,UAAYA,gBAE5BrE,WAAWwD,MAAMa,UAAYA,UAQtCS,eAAeC,6CAENzD,KAAKa,QAA6C,0DAA9BnC,WAAWS,wEAASyC,oBAGvCqB,WAAajD,KAAKtB,WAAWwE,YAC7BQ,QAAUD,aAAa1B,4BAQzB4B,YACCD,QAAQE,MA5iBH,GA4iBwB5D,KAAK8B,aAAa+B,MAC/CH,QAAQG,KA7iBH,GA6iBuB7D,KAAK8B,aAAa8B,SAE/CD,YAAa,OACPG,oBAAsB9D,KAAKtB,WAAWqD,wBAC5C4B,YACKD,QAAQK,OAAUD,oBAAoBE,KACtCN,QAAQM,IAAOF,oBAAoBC,UAIxCJ,YAAa,KAETM,YAAchB,WAAa,EAC3B9F,OAAO+G,kBACPD,cAAgB,QAEfpB,SAASoB,uBAGTpB,SAAS1F,OAAOgH,kCAQzBzH,UAAUkC,SAAQuC,iBACdA,eAAetB,0CASEuE,oBACrB1H,UAAUkC,SAAQuC,iBACVA,iBAAmBiD,oBAIvBjD,eAAetB,8DAQb4D,aAAezG,SAASqH,cAExBC,YAActH,SAASC,cAAcL,uBACtC6G,cAAiBa,MAAAA,aAAAA,YAAapE,SAASuD,cAI5C/G,UAAUkC,SAAQuC,iBACdA,eAAeqC,eAAeC,iBAJ9BtF,QAAQoG,gBAAgBpH,OAAOgH,gCAahBtB,UACnBnG,UAAUkC,SAAQuC,iBACdA,eAAe0B,SAASA,uDAzaf1E,qBAyEG,CAQhBoD,WAAY,2BASZkB,YAAa,4BASbC,WAAY,2BASZC,aAAc,qCAuUhB6B,kBAAqBC,eACnBA,aAAatF,QAAQuF,SACrB1H,SAAS2H,2BAAoB/H,2CAAkC6H,aAAatF,QAAQuF,cACnF9F,SAAQgG,MACLA,IAAIzF,QAAQ0F,UAAW,KAE3BJ,aAAatF,QAAQ0F,UAAW,IAoBd,MAEtB7H,SAASgB,iBAAiB,SAASC,UACzBwG,aAAexG,EAAEyG,OAAOI,QAAQlI,wBAClC6H,cAAgBA,aAAatF,QAAQuF,OAAQ,CAC7CzG,EAAEC,uBACI6G,aAAe/H,SAAS6E,eAAe4C,aAAatF,QAAQuF,QAC5DvD,eAAiBhD,QAAQ6G,yBAAyBD,cACxDP,kBAAkBC,cAElBtD,eAAeyB,yBAGbqC,iBAAmBhH,EAAEyG,OAAOI,QAAQlI,sBACtCqI,kBAAoBA,iBAAiB9F,QAAQuF,OAAQ,CACrDzG,EAAEC,uBACI6G,aAAe/H,SAAS6E,eAAeoD,iBAAiB9F,QAAQuF,QAChEvD,eAAiBhD,QAAQ6G,yBAAyBD,cACxDP,kBAAkBC,cAElBtD,eAAehB,mBAGb+E,kBAAoBjH,EAAEyG,OAAOI,QAAQlI,uBACvCsI,mBAAqBA,kBAAkB/F,QAAQuF,OAAQ,CACvDzG,EAAEC,uBACI6G,aAAe/H,SAAS6E,eAAeqD,kBAAkB/F,QAAQuF,QAChDvG,QAAQ6G,yBAAyBD,cAEzClF,cAzCE6E,CAAAA,eACnBS,eAAiBnI,SAASC,wBAAiBL,2CAAkC8H,mCAC/ES,gBACAA,eAAe5C,SAuCX6C,CAAoBF,kBAAkB/F,QAAQuF,YAKtD1H,SAASgB,iBAAiBG,QAAQmD,WAAWC,YAAYtD,KACjD,2BAGJE,QAAQkH,kBAAkBpH,EAAEqH,OAAOnE,yBAIjCoE,sBAAiB3I,iCAAwBA,+BAAsBA,oBACrEI,SAASgB,iBAAiB,YAAaC,UAC7BY,OAASZ,EAAEyG,OAAOI,QAAQS,kBACa5F,KAAzCd,MAAAA,cAAAA,OAAQM,QAAQK,uBAChBC,oBAAoBZ,WA6B5B7B,SAASgB,iBAAiB,UAAU,WAC1BwH,KAAOxI,SAASC,cAAc,QAChCE,OAAOsI,SAAWtI,OAAOuI,YACzBF,KAAKvF,UAAUyB,IAAI7E,kBAEnB2I,KAAKvF,UAAUW,OAAO/D,kBAI1BsB,QAAQoG,gBAAgBpH,OAAOgH,kBAG7BX,gBAAiB,mBAASrF,QAAQwH,8BAA+B,KACvE3I,SAASgB,iBAAiB,UAAWwF,gBACrCxG,SAASgB,iBAAiB,WAAYwF,gBAEtCrG,OAAOa,iBAAiB,UAAU,oBAzCJ,SACtB,0BAAW,KACP4H,SAAU,EACdlJ,UAAUkC,SAAQuC,iBACd1C,sBAAsB0C,eAAezC,YACjCyC,eAAeN,SACXM,eAAeL,cACfK,eAAetB,cAEf+F,SAAU,MAKlBA,SACAtI,cAAcG,MAAKuE,UAAYA,SAASC,SAAQ5D,aAGpD3B,UAAUkC,SAAQuC,iBArnBAzC,IAAAA,WACV,EADUA,WAsnBOyC,eAAezC,YApnBjCzB,cAAcL,oBACzB0B,oBAAoBI,WAAWC,KAE3BC,SAAQC,SACPA,QAGLY,oBAAoBZ,cA+mBhBvB,cAAcG,MAAKuE,UAAYA,SAASzB,SAAQlC,UAoBU,IAAK,CAACwH,SAAS,MAGrFC,UAEgB9I,SAAS2H,iBAAiB/H,mBAClCgC,SAAQF,YAAcP,QAAQ6G,yBAAyBtG"}
\ No newline at end of file
diff --git a/theme/boost/amd/src/drawers.js b/theme/boost/amd/src/drawers.js
index df318d45c96ed..135dd2df9feca 100644
--- a/theme/boost/amd/src/drawers.js
+++ b/theme/boost/amd/src/drawers.js
@@ -812,7 +812,7 @@ const registerListeners = () => {
document.addEventListener('focusin', preventOverlap);
document.addEventListener('focusout', preventOverlap);
- window.addEventListener('resize', debounce(closeOnResizeListener, 400));
+ window.addEventListener('resize', debounce(closeOnResizeListener, 400, {pending: true}));
};
registerListeners();
diff --git a/theme/boost/templates/drawer.mustache b/theme/boost/templates/drawer.mustache
index b2e31e5fed5d1..9e8cc0008f0d2 100644
--- a/theme/boost/templates/drawer.mustache
+++ b/theme/boost/templates/drawer.mustache
@@ -57,5 +57,8 @@
{{#js}}
-require(['theme_boost/drawers']);
+M.util.js_pending('theme_boost/drawers:load');
+require(['theme_boost/drawers'], function() {
+ M.util.js_complete('theme_boost/drawers:load');
+});
{{/js}}
diff --git a/theme/boost/tests/boostnavbar_test.php b/theme/boost/tests/boostnavbar_test.php
index 86e756b54dbf0..1109d35dd7a87 100644
--- a/theme/boost/tests/boostnavbar_test.php
+++ b/theme/boost/tests/boostnavbar_test.php
@@ -31,7 +31,7 @@ class boostnavbar_test extends \advanced_testcase {
*
* @return array
*/
- public function remove_no_link_items_provider(): array {
+ public static function remove_no_link_items_provider(): array {
return [
'All nodes have links links including leaf node. Set to remove section nodes.' => [
[
@@ -231,7 +231,7 @@ public function test_remove_no_link_items(array $setup, bool $removesectionnodes
*
* @return array
*/
- public function remove_duplicate_items_provider(): array {
+ public static function remove_duplicate_items_provider(): array {
global $CFG;
return [
@@ -411,7 +411,7 @@ public function test_remove_duplicate_items(array $navbarnodes, array $expected)
*
* @return array
*/
- public function remove_items_that_exist_in_navigation_provider(): array {
+ public static function remove_items_that_exist_in_navigation_provider(): array {
global $CFG;
return [
diff --git a/theme/boost/tests/privacy/provider_test.php b/theme/boost/tests/privacy/provider_test.php
index 4655f3b5f5a66..7da1d3e7a4f55 100644
--- a/theme/boost/tests/privacy/provider_test.php
+++ b/theme/boost/tests/privacy/provider_test.php
@@ -35,7 +35,7 @@ class provider_test extends \core_privacy\tests\provider_testcase {
*
* @return array[]
*/
- public function export_user_preference_provider(): array {
+ public static function export_user_preference_provider(): array {
return [
'Index drawer open' => [provider::DRAWER_OPEN_INDEX, true, 'privacy:drawerindexopen'],
'Index drawer closed' => [provider::DRAWER_OPEN_INDEX, false, 'privacy:drawerindexclosed'],
diff --git a/user/edit.php b/user/edit.php
index 0524632a7c975..45c86df821487 100644
--- a/user/edit.php
+++ b/user/edit.php
@@ -199,9 +199,11 @@
// Other users require a confirmation email.
if (isset($usernew->email) and $user->email != $usernew->email && !has_capability('moodle/user:update', $systemcontext)) {
$a = new stdClass();
- $emailchangedkey = random_string(20);
+ // Set the key to expire in 10 minutes.
+ $validuntil = time() + 600;
+ $emailchangedkey = create_user_key('core_user/email_change', $user->id, null, null, $validuntil);
+
set_user_preference('newemail', $usernew->email, $user->id);
- set_user_preference('newemailkey', $emailchangedkey, $user->id);
set_user_preference('newemailattemptsleft', 3, $user->id);
$a->newemail = $emailchanged = $usernew->email;
diff --git a/user/editlib.php b/user/editlib.php
index e02ad6617cfeb..3b968d595660a 100644
--- a/user/editlib.php
+++ b/user/editlib.php
@@ -31,8 +31,8 @@
*/
function cancel_email_update($userid) {
unset_user_preference('newemail', $userid);
- unset_user_preference('newemailkey', $userid);
unset_user_preference('newemailattemptsleft', $userid);
+ delete_user_key('core_user/email_change', $userid);
}
/**
diff --git a/user/emailupdate.php b/user/emailupdate.php
index 6de500eff433d..9e3da79563036 100644
--- a/user/emailupdate.php
+++ b/user/emailupdate.php
@@ -44,6 +44,14 @@
$PAGE->set_title($stremailupdate);
$PAGE->set_heading(format_string($SITE->fullname) . ": $stremailupdate");
+// Validate the key.
+$errormessage = get_string('auth_invalidnewemailkey', 'auth');
+try {
+ $userkey = validate_user_key($key, 'core_user/email_change', null);
+} catch (moodle_exception $e) {
+ $userkey = null;
+ $errormessage = $e->getMessage();
+}
if (empty($preferences['newemailattemptsleft'])) {
redirect("$CFG->wwwroot/user/view.php?id=$user->id");
@@ -54,7 +62,8 @@
echo $OUTPUT->header();
echo $OUTPUT->box(get_string('auth_outofnewemailupdateattempts', 'auth'), 'center');
echo $OUTPUT->footer();
-} else if ($key == $preferences['newemailkey']) {
+} else if ($userkey && $userkey->userid == $user->id) {
+ // Key validated, continue with email update.
$olduser = clone($user);
cancel_email_update($user->id);
$user->email = $preferences['newemail'];
@@ -90,6 +99,6 @@
$preferences['newemailattemptsleft']--;
set_user_preference('newemailattemptsleft', $preferences['newemailattemptsleft'], $user->id);
echo $OUTPUT->header();
- echo $OUTPUT->box(get_string('auth_invalidnewemailkey', 'auth'), 'center');
+ echo $OUTPUT->box($errormessage, 'center');
echo $OUTPUT->footer();
}
diff --git a/user/lib.php b/user/lib.php
index 0c050d0c9bc2d..0e86499cb2af1 100644
--- a/user/lib.php
+++ b/user/lib.php
@@ -1287,15 +1287,24 @@ function user_get_tagged_users($tag, $exclusivemode = false, $fromctx = 0, $ctx
}
$perpage = $exclusivemode ? 24 : 5;
$content = '';
- $totalpages = ceil($usercount / $perpage);
+ $excludedusers = 0;
if ($usercount) {
$userlist = $tag->get_tagged_items('core', 'user', $page * $perpage, $perpage,
'it.deleted=:notdeleted', array('notdeleted' => 0));
+ foreach ($userlist as $user) {
+ if (!user_can_view_profile($user)) {
+ unset($userlist[$user->id]);
+ $excludedusers++;
+ }
+ }
$renderer = $PAGE->get_renderer('core', 'user');
$content .= $renderer->user_list($userlist, $exclusivemode);
}
+ // Calculate the total number of pages.
+ $totalpages = ceil(($usercount - $excludedusers) / $perpage);
+
return new core_tag\output\tagindex($tag, 'core', 'user', $content,
$exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages);
}
diff --git a/user/profile/field/text/tests/field_class_test.php b/user/profile/field/text/tests/field_class_test.php
index e0936f845acfa..23a987f798da2 100644
--- a/user/profile/field/text/tests/field_class_test.php
+++ b/user/profile/field/text/tests/field_class_test.php
@@ -60,7 +60,7 @@ public function test_filter_display_data(string $input, string $expected): void
*
* @return string[]
*/
- public function filter_profile_field_text_provider(): array {
+ public static function filter_profile_field_text_provider(): array {
return [
'simple_string' => ['Simple string', 'Simple string'],
'format_string' => ['HTML & is escaped', 'HTML & is escaped'],
diff --git a/user/tests/externallib_test.php b/user/tests/externallib_test.php
index a7615f965f3e3..84bdf39438c2c 100644
--- a/user/tests/externallib_test.php
+++ b/user/tests/externallib_test.php
@@ -611,7 +611,7 @@ public function test_create_users_empty_password() {
/**
* Data provider for \core_user_externallib_testcase::test_create_users_with_same_emails().
*/
- public function create_users_provider_with_same_emails() {
+ public static function create_users_provider_with_same_emails(): array {
return [
'Same emails allowed, same case' => [
1, false
@@ -697,7 +697,7 @@ public function test_create_users_invalid_parameter(array $data, $expectmessage)
*
* @return array
*/
- public function data_create_users_invalid_parameter() {
+ public static function data_create_users_invalid_parameter(): array {
return [
'blank_username' => [
'data' => [
@@ -956,7 +956,7 @@ public function test_update_users() {
*
* @return array
*/
- public function users_with_same_emails() {
+ public static function users_with_same_emails(): array {
return [
'Same emails not allowed: Update name using exactly the same email' => [
0, 'John', 's1@example.com', 'Johnny', 's1@example.com', false, true
diff --git a/user/tests/fields_test.php b/user/tests/fields_test.php
index 1d7977be335b2..5a5fd0fa15203 100644
--- a/user/tests/fields_test.php
+++ b/user/tests/fields_test.php
@@ -549,7 +549,7 @@ public function test_get_sql_selects_format() {
*
* @return array
*/
- public function get_sql_fullname_provider(): array {
+ public static function get_sql_fullname_provider(): array {
return [
['firstname lastname', 'FN LN'],
['lastname, firstname', 'LN, FN'],
diff --git a/user/tests/profilelib_test.php b/user/tests/profilelib_test.php
index e8609d710561f..458739341ccf9 100644
--- a/user/tests/profilelib_test.php
+++ b/user/tests/profilelib_test.php
@@ -281,7 +281,7 @@ public function test_profile_get_custom_field_data_by_shortname_missing() {
*
* @return array[]
*/
- public function profile_get_custom_field_data_by_shortname_case_sensitivity_provider(): array {
+ public static function profile_get_custom_field_data_by_shortname_case_sensitivity_provider(): array {
return [
'Matching case, case-sensitive search' => ['hello', 'hello', true, true],
'Matching case, case-insensitive search' => ['hello', 'hello', false, true],
diff --git a/user/tests/table/participants_search_test.php b/user/tests/table/participants_search_test.php
index d3470db902d9d..81063bf59ace7 100644
--- a/user/tests/table/participants_search_test.php
+++ b/user/tests/table/participants_search_test.php
@@ -796,7 +796,7 @@ public function test_country_filter(array $usersdata, array $countries, int $joi
*
* @return array
*/
- public function country_provider(): array {
+ public static function country_provider(): array {
$tests = [
'users' => [
'user1' => 'DE',
@@ -991,7 +991,7 @@ public function test_keywords_filter(array $usersdata, array $keywords, int $joi
*
* @return array
*/
- public function keywords_provider(): array {
+ public static function keywords_provider(): array {
$tests = [
// Users where the keyword matches basic user fields such as names and email.
'Users with basic names' => (object) [
@@ -1537,7 +1537,7 @@ public function test_status_filter(array $usersdata, array $statuses, int $joint
*
* @return array
*/
- public function status_provider(): array {
+ public static function status_provider(): array {
$tests = [
// Users with different statuses and enrolment methods (so multiple statuses are possible for the same user).
'Users with different enrolment statuses' => (object) [
@@ -1792,7 +1792,7 @@ public function test_enrolments_filter(array $usersdata, array $enrolmethods, in
*
* @return array
*/
- public function enrolments_provider(): array {
+ public static function enrolments_provider(): array {
$tests = [
// Users with different enrolment methods.
'Users with different enrolment methods' => (object) [
@@ -2016,7 +2016,7 @@ public function test_groups_filter(array $usersdata, array $groupsavailable, arr
*
* @return array
*/
- public function groups_provider(): array {
+ public static function groups_provider(): array {
$tests = [
'Users in different groups' => (object) [
'groupsavailable' => [
@@ -2355,7 +2355,7 @@ public function test_groups_filter_separate_groups(array $usersdata, array $grou
*
* @return array
*/
- public function groups_separate_provider(): array {
+ public static function groups_separate_provider(): array {
$tests = [
'Users in different groups with separate groups mode enabled' => (object) [
'groupsavailable' => [
@@ -2715,7 +2715,7 @@ public function test_accesssince_filter(array $usersdata, array $accesssince, in
*
* @return array
*/
- public function accesssince_provider(): array {
+ public static function accesssince_provider(): array {
$tests = [
// Users with different last access times.
'Users in different groups' => (object) [
@@ -3120,7 +3120,7 @@ public function test_filterset_joins(array $usersdata, array $filterdata, array
*
* @return array
*/
- public function filterset_joins_provider(): array {
+ public static function filterset_joins_provider(): array {
$tests = [
// Users with different configurations.
'Users with different configurations' => (object) [
diff --git a/user/tests/userlib_test.php b/user/tests/userlib_test.php
index 070eb276e04c1..cfde634a6c07e 100644
--- a/user/tests/userlib_test.php
+++ b/user/tests/userlib_test.php
@@ -387,7 +387,7 @@ public function test_create_user_invalid_username($username, $expectmessage) {
*
* @return array
*/
- public function data_create_user_invalid_username() {
+ public static function data_create_user_invalid_username(): array {
return [
'empty_string' => [
'',
diff --git a/version.php b/version.php
index bbe0f41cfad72..e73ca81d5f981 100644
--- a/version.php
+++ b/version.php
@@ -29,9 +29,9 @@
defined('MOODLE_INTERNAL') || die();
-$version = 2023100908.00; // 20231009 = branching date YYYYMMDD - do not modify!
+$version = 2023100909.00; // 20231009 = branching date YYYYMMDD - do not modify!
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
-$release = '4.3.8 (Build: 20241007)'; // Human-friendly version name
+$release = '4.3.9 (Build: 20241209)'; // Human-friendly version name
$branch = '403'; // This version's branch.
$maturity = MATURITY_STABLE; // This version's maturity level.
diff --git a/webservice/rest/tests/server_test.php b/webservice/rest/tests/server_test.php
index e1b781b1faa57..71e53b562e1c1 100644
--- a/webservice/rest/tests/server_test.php
+++ b/webservice/rest/tests/server_test.php
@@ -32,13 +32,12 @@
* @copyright 2016 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class server_test extends \advanced_testcase {
-
+final class server_test extends \advanced_testcase {
/**
* Data provider for test_xmlize.
* @return array
*/
- public function xmlize_provider() {
+ public static function xmlize_provider(): array {
$data = [];
$data[] = [null, null, ''];
$data[] = [new external_value(PARAM_BOOL), false, "0\n"];
@@ -210,5 +209,4 @@ public function test_xmlize($description, $value, $expected) {
$method->setAccessible(true);
$this->assertEquals($expected, $method->invoke(null, $value, $description));
}
-
}
diff --git a/webservice/tests/lib_test.php b/webservice/tests/lib_test.php
index 059eb5723df65..53ddcd8f64620 100644
--- a/webservice/tests/lib_test.php
+++ b/webservice/tests/lib_test.php
@@ -269,7 +269,7 @@ public function test_get_missing_capabilities_by_users() {
*
* @return array
*/
- public function get_active_tokens_provider(): array {
+ public static function get_active_tokens_provider(): array {
return [
'No expiration' => [0, true],
'Active' => [time() + DAYSECS, true],