first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+321
View File
@@ -0,0 +1,321 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_quiz\external;
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/../../../../webservice/tests/helpers.php');
use coding_exception;
use core_question_generator;
use externallib_advanced_testcase;
use mod_quiz\quiz_attempt;
use mod_quiz\quiz_settings;
use required_capability_exception;
use stdClass;
/**
* Test for the grade_items CRUD service.
*
* @package mod_quiz
* @category external
* @copyright 2023 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_quiz\external\create_grade_items
* @covers \mod_quiz\external\delete_grade_items
* @covers \mod_quiz\external\update_grade_items
* @covers \mod_quiz\structure
*/
final class grade_items_test extends externallib_advanced_testcase {
public function test_create_grade_items_service_works(): void {
$quizobj = $this->create_quiz_with_two_grade_items();
create_grade_items::execute($quizobj->get_quizid(), [
['name' => 'Speaking'],
['name' => 'Writing'],
]);
$structure = $quizobj->get_structure();
$items = array_values($structure->get_grade_items());
$this->assertEquals('Listening', $items[0]->name);
$this->assertEquals('Reading', $items[1]->name);
$this->assertEquals('Speaking', $items[2]->name);
$this->assertEquals('Writing', $items[3]->name);
}
public function test_create_grade_items_service_checks_permissions(): void {
$quizobj = $this->create_quiz_with_two_grade_items();
$unprivilegeduser = $this->getDataGenerator()->create_user();
$this->setUser($unprivilegeduser);
$this->expectException(required_capability_exception::class);
create_grade_items::execute($quizobj->get_quizid(), []);
}
public function test_update_grade_items_service_works(): void {
$quizobj = $this->create_quiz_with_two_grade_items();
$structure = $quizobj->get_structure();
$items = array_values($structure->get_grade_items());
update_grade_items::execute($quizobj->get_quizid(), [
['id' => $items[0]->id, 'name' => 'Speaking'],
['id' => $items[1]->id, 'name' => null],
]);
$structure = $quizobj->get_structure();
$updateditems = $structure->get_grade_items();
$this->assertEquals('Speaking', $updateditems[$items[0]->id]->name);
$this->assertEquals($items[1]->name, $updateditems[$items[1]->id]->name);
}
public function test_update_grade_items_service_checks_permissions(): void {
$quizobj = $this->create_quiz_with_two_grade_items();
$unprivilegeduser = $this->getDataGenerator()->create_user();
$this->setUser($unprivilegeduser);
$this->expectException(required_capability_exception::class);
update_grade_items::execute($quizobj->get_quizid(), []);
}
public function test_delete_grade_items_service_works(): void {
$quizobj = $this->create_quiz_with_two_grade_items();
$structure = $quizobj->get_structure();
$items = array_values($structure->get_grade_items());
$structure->update_slot_grade_item($structure->get_slot_by_number(1), null);
$structure->update_slot_grade_item($structure->get_slot_by_number(2), null);
delete_grade_items::execute($quizobj->get_quizid(), [['id' => $items[0]->id]]);
$structure = $quizobj->get_structure();
$updateditems = $structure->get_grade_items();
$this->assertCount(1, $updateditems);
$this->assertEquals('Reading', $updateditems[$items[1]->id]->name);
}
public function test_cant_delete_grade_item_that_is_used(): void {
$quizobj = $this->create_quiz_with_two_grade_items();
$structure = $quizobj->get_structure();
$items = array_values($structure->get_grade_items());
$this->expectException(coding_exception::class);
delete_grade_items::execute($quizobj->get_quizid(), [['id' => $items[0]->id]]);
}
public function test_delete_grade_items_service_checks_permissions(): void {
$quizobj = $this->create_quiz_with_two_grade_items();
$unprivilegeduser = $this->getDataGenerator()->create_user();
$this->setUser($unprivilegeduser);
$structure = $quizobj->get_structure();
$items = array_values($structure->get_grade_items());
$this->expectException(required_capability_exception::class);
delete_grade_items::execute($quizobj->get_quizid(), [['id' => $items[0]->id]]);
}
public function test_get_edit_grading_page_data_service_works(): void {
global $PAGE;
$PAGE->set_url('/');
$quizobj = $this->create_quiz_with_two_grade_items();
$jsondata = get_edit_grading_page_data::execute($quizobj->get_quizid());
$this->assertJson($jsondata);
$data = json_decode($jsondata);
$this->assertEquals($quizobj->get_quizid(), $data->quizid);
}
public function test_get_edit_grading_page_data_service_checks_permissions(): void {
$quizobj = $this->create_quiz_with_two_grade_items();
$unprivilegeduser = $this->getDataGenerator()->create_user();
$this->setUser($unprivilegeduser);
$this->expectException(required_capability_exception::class);
get_edit_grading_page_data::execute($quizobj->get_quizid());
}
/**
* Create a quiz of two shortanswer questions, each contributing to a different grade item.
*
* @return quiz_settings the newly created quiz.
*/
protected function create_quiz_with_two_grade_items(): quiz_settings {
global $SITE;
$this->resetAfterTest();
$this->setAdminUser();
// Make a quiz.
/** @var \mod_quiz_generator $quizgenerator */
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(['course' => $SITE->id]);
// Create two question.
/** @var core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $questiongenerator->create_question_category();
$saq1 = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
$saq2 = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
// Add them to the quiz.
quiz_add_quiz_question($saq1->id, $quiz, 0, 1);
quiz_add_quiz_question($saq2->id, $quiz, 0, 1);
// Create two quiz grade items.
$listeninggrade = $quizgenerator->create_grade_item(['quizid' => $quiz->id, 'name' => 'Listening']);
$readinggrade = $quizgenerator->create_grade_item(['quizid' => $quiz->id, 'name' => 'Reading']);
// Set the questions to use those grade items.
$quizobj = quiz_settings::create($quiz->id);
$structure = $quizobj->get_structure();
$structure->update_slot_grade_item($structure->get_slot_by_number(1), $listeninggrade->id);
$structure->update_slot_grade_item($structure->get_slot_by_number(2), $readinggrade->id);
$quizobj->get_grade_calculator()->recompute_quiz_sumgrades();
return $quizobj;
}
public function test_create_grade_item_per_section_works(): void {
global $SITE;
$this->resetAfterTest();
$this->setAdminUser();
// Create a quiz with no grade items yet, but two sections.
/** @var \mod_quiz_generator $quizgenerator */
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(['course' => $SITE->id]);
// Create three questions.
/** @var core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $questiongenerator->create_question_category();
$saq1 = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
$saq2 = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
$saq3 = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
// Add them to the quiz.
quiz_add_quiz_question($saq1->id, $quiz, 1, 1);
quiz_add_quiz_question($saq2->id, $quiz, 1, 1);
quiz_add_quiz_question($saq3->id, $quiz, 2, 1);
// Create two sections.
$quizobj = quiz_settings::create($quiz->id);
$structure = $quizobj->get_structure();
$defaultsection = array_values($structure->get_sections())[0];
$structure->set_section_heading($defaultsection->id, 'Listening');
$structure->add_section_heading(2, 'Reading');
// Call the method we are testing.
create_grade_item_per_section::execute($quizobj->get_quizid());
// Verify.
$structure = $quizobj->get_structure();
$gradeitems = array_values($structure->get_grade_items());
$this->assertCount(2, $gradeitems);
$this->assertEquals('Listening', $gradeitems[0]->name);
$this->assertEquals(1, $gradeitems[0]->sortorder);
$this->assertEquals('Reading', $gradeitems[1]->name);
$this->assertEquals(2, $gradeitems[1]->sortorder);
$this->assertEquals($gradeitems[0]->id, $structure->get_slot_by_number(1)->quizgradeitemid);
$this->assertEquals($gradeitems[0]->id, $structure->get_slot_by_number(2)->quizgradeitemid);
$this->assertEquals($gradeitems[1]->id, $structure->get_slot_by_number(3)->quizgradeitemid);
}
public function test_create_grade_item_per_section_with_descriptions(): void {
global $SITE;
$this->resetAfterTest();
$this->setAdminUser();
// Create a quiz with no grade items yet, but two sections.
/** @var \mod_quiz_generator $quizgenerator */
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(['course' => $SITE->id]);
// Create three questions.
/** @var core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $questiongenerator->create_question_category();
$desc1 = $questiongenerator->create_question('description', null, ['category' => $cat->id]);
$desc2 = $questiongenerator->create_question('description', null, ['category' => $cat->id]);
$saq1 = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
// Add them to the quiz.
quiz_add_quiz_question($desc1->id, $quiz, 1);
quiz_add_quiz_question($desc2->id, $quiz, 2);
quiz_add_quiz_question($saq1->id, $quiz, 2, 7);
// Create two sections.
$quizobj = quiz_settings::create($quiz->id);
$structure = $quizobj->get_structure();
$defaultsection = array_values($structure->get_sections())[0];
$structure->set_section_heading($defaultsection->id, 'Introduction');
$structure->add_section_heading(2, 'The question');
// Call the method we are testing.
create_grade_item_per_section::execute($quizobj->get_quizid());
// Verify.
$structure = $quizobj->get_structure();
$gradeitems = array_values($structure->get_grade_items());
$this->assertCount(1, $gradeitems);
$this->assertEquals('The question', $gradeitems[0]->name);
$this->assertEquals(1, $gradeitems[0]->sortorder);
$this->assertNull($structure->get_slot_by_number(1)->quizgradeitemid);
$this->assertNull($structure->get_slot_by_number(2)->quizgradeitemid);
$this->assertEquals($gradeitems[0]->id, $structure->get_slot_by_number(3)->quizgradeitemid);
}
public function test_create_grade_item_per_section_service_checks_permissions(): void {
global $SITE;
$this->resetAfterTest();
// Create a quiz.
/** @var \mod_quiz_generator $quizgenerator */
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(['course' => $SITE->id]);
$unprivilegeduser = $this->getDataGenerator()->create_user();
$this->setUser($unprivilegeduser);
$this->expectException(required_capability_exception::class);
create_grade_item_per_section::execute($quiz->id);
}
public function test_cant_create_grade_item_per_section_if_grade_items_already_exist(): void {
$quizobj = $this->create_quiz_with_two_grade_items();
$this->expectException(coding_exception::class);
create_grade_item_per_section::execute($quizobj->get_quizid());
}
}
+223
View File
@@ -0,0 +1,223 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_quiz\external;
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/../../../../webservice/tests/helpers.php');
/**
* Tests for override webservices
*
* @package mod_quiz
* @copyright 2024 Matthew Hilton <matthewhilton@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_quiz\external\get_overrides
* @covers \mod_quiz\external\save_overrides
* @covers \mod_quiz\external\delete_overrides
*/
final class override_test extends \externallib_advanced_testcase {
/**
* Creates a quiz for testing.
*
* @return object $quiz
*/
private function create_quiz(): object {
$course = $this->getDataGenerator()->create_course();
return $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
}
/**
* Provides values to test_get_overrides
*
* @return array
*/
public static function get_override_provider(): array {
return [
'quiz that exists' => [
'quizid' => ':quizid',
],
'quiz that does not exist' => [
'quizid' => -1,
'expectedexception' => \dml_missing_record_exception::class,
],
];
}
/**
* Tests get_overrides
*
* @param int|string $quizid
* @param string $expectedexception
* @dataProvider get_override_provider
*/
public function test_get_overrides(int|string $quizid, string $expectedexception = ''): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$quiz = $this->create_quiz();
// Create an override.
$DB->insert_record('quiz_overrides', ['quiz' => $quiz->id]);
// Replace placeholders.
if ($quizid == ":quizid") {
$quizid = $quiz->id;
}
if (!empty($expectedexception)) {
$this->expectException($expectedexception);
}
$result = get_overrides::execute($quizid);
$this->assertNotEmpty($result);
}
/**
* Provides values to test_save_overrides
*
* @return array
*/
public static function save_overrides_provider(): array {
return [
'good insert' => [
'data' => [
'timeopen' => 999,
],
],
'bad insert' => [
'data' => [
'id' => ':existingid',
'timeopen' => -1,
],
'expectedexception' => \invalid_parameter_exception::class,
],
'good update' => [
'data' => [
'timeopen' => 999,
],
],
'bad update' => [
'data' => [
'id' => ':existingid',
'timeopen' => -1,
],
'expectedexception' => \invalid_parameter_exception::class,
],
];
}
/**
* Tests save_overrides
*
* @dataProvider save_overrides_provider
* @param array $data
* @param string $expectedexception
*/
public function test_save_overrides(array $data, string $expectedexception = ''): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$quiz = $this->create_quiz();
$user = $this->getDataGenerator()->create_user();
if (!empty($data['id'])) {
$data['id'] = $DB->insert_record('quiz_overrides', ['quiz' => $quiz->id, 'userid' => $user->id]);
}
// Make a new user to insert a new override for.
$user = $this->getDataGenerator()->create_user();
$data = array_merge($data, ['userid' => $user->id]);
$payload = [
'quizid' => $quiz->id,
'overrides' => [
$data,
],
];
if (!empty($expectedexception)) {
$this->expectException($expectedexception);
}
$result = save_overrides::execute($payload);
// If has reached here, but not thrown exception and was expected to, fail the test.
if ($expectedexception) {
$this->fail("Expected exception " . $expectedexception . " was not thrown");
}
$this->assertNotEmpty($result['ids']);
$this->assertCount(1, $result['ids']);
}
/**
* Provides values to test_delete_overrides
*
* @return array
*/
public static function delete_overrides_provider(): array {
return [
'delete existing override' => [
'id' => ':existingid',
],
'delete override that does not exist' => [
'id' => -1,
'expectedexception' => \invalid_parameter_exception::class,
],
];
}
/**
* Tests delete_overrides
*
* @dataProvider delete_overrides_provider
* @param int|string $id
* @param string $expectedexception
*/
public function test_delete_overrides(int|string $id, string $expectedexception = ''): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$quiz = $this->create_quiz();
$user = $this->getDataGenerator()->create_user();
if ($id == ':existingid') {
$id = $DB->insert_record('quiz_overrides', ['quiz' => $quiz->id, 'userid' => $user->id]);
}
if (!empty($expectedexception)) {
$this->expectException($expectedexception);
}
$result = delete_overrides::execute(['quizid' => $quiz->id, 'ids' => [$id]]);
// If has reached here, but not thrown exception and was expected to, fail the test.
if ($expectedexception) {
$this->fail("Expected exception " . $expectedexception . " was not thrown");
}
$this->assertNotEmpty($result['ids']);
$this->assertContains($id, $result['ids']);
}
}
+181
View File
@@ -0,0 +1,181 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_quiz\external;
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/../../../../webservice/tests/helpers.php');
use coding_exception;
use core_question_generator;
use externallib_advanced_testcase;
use mod_quiz\quiz_attempt;
use mod_quiz\quiz_settings;
use required_capability_exception;
use stdClass;
/**
* Test for the reopen_attempt and get_reopen_attempt_confirmation services.
*
* @package mod_quiz
* @category external
* @copyright 2023 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_quiz\external\reopen_attempt
* @covers \mod_quiz\external\get_reopen_attempt_confirmation
*/
class reopen_attempt_test extends externallib_advanced_testcase {
/** @var stdClass|null if we make a quiz attempt, we store the student object here. */
protected $student;
public function test_reopen_attempt_service_works(): void {
[$attemptid] = $this->create_attempt_at_quiz_with_one_shortanswer_question();
reopen_attempt::execute($attemptid);
$attemptobj = quiz_attempt::create($attemptid);
$this->assertEquals(quiz_attempt::IN_PROGRESS, $attemptobj->get_state());
}
public function test_reopen_attempt_service_checks_permissions(): void {
[$attemptid] = $this->create_attempt_at_quiz_with_one_shortanswer_question();
$unprivilegeduser = $this->getDataGenerator()->create_user();
$this->setUser($unprivilegeduser);
$this->expectException(required_capability_exception::class);
reopen_attempt::execute($attemptid);
}
public function test_reopen_attempt_service_checks_attempt_state(): void {
[$attemptid] = $this->create_attempt_at_quiz_with_one_shortanswer_question(quiz_attempt::IN_PROGRESS);
$this->expectExceptionMessage("Attempt $attemptid is in the wrong state (In progress) to be reopened.");
reopen_attempt::execute($attemptid);
}
public function test_get_reopen_attempt_confirmation_staying_open(): void {
global $DB;
[$attemptid, $quizid] = $this->create_attempt_at_quiz_with_one_shortanswer_question();
$DB->set_field('quiz', 'timeclose', 0, ['id' => $quizid]);
$message = get_reopen_attempt_confirmation::execute($attemptid);
$this->assertEquals('<p>This will reopen attempt 1 by ' . fullname($this->student) .
'.</p><p>The attempt will remain open and can be continued.</p>',
$message);
}
public function test_get_reopen_attempt_confirmation_staying_open_until(): void {
global $DB;
[$attemptid, $quizid] = $this->create_attempt_at_quiz_with_one_shortanswer_question();
$timeclose = time() + HOURSECS;
$DB->set_field('quiz', 'timeclose', $timeclose, ['id' => $quizid]);
$message = get_reopen_attempt_confirmation::execute($attemptid);
$this->assertEquals('<p>This will reopen attempt 1 by ' . fullname($this->student) .
'.</p><p>The attempt will remain open and can be continued until the quiz closes on ' .
userdate($timeclose) . '.</p>',
$message);
}
public function test_get_reopen_attempt_confirmation_submitting(): void {
global $DB;
[$attemptid, $quizid] = $this->create_attempt_at_quiz_with_one_shortanswer_question();
$timeclose = time() - HOURSECS;
$DB->set_field('quiz', 'timeclose', $timeclose, ['id' => $quizid]);
$message = get_reopen_attempt_confirmation::execute($attemptid);
$this->assertEquals('<p>This will reopen attempt 1 by ' . fullname($this->student) .
'.</p><p>The attempt will be immediately submitted for grading.</p>',
$message);
}
public function test_get_reopen_attempt_confirmation_service_checks_permissions(): void {
[$attemptid] = $this->create_attempt_at_quiz_with_one_shortanswer_question();
$unprivilegeduser = $this->getDataGenerator()->create_user();
$this->setUser($unprivilegeduser);
$this->expectException(required_capability_exception::class);
get_reopen_attempt_confirmation::execute($attemptid);
}
public function test_get_reopen_attempt_confirmation_service_checks_attempt_state(): void {
[$attemptid] = $this->create_attempt_at_quiz_with_one_shortanswer_question(quiz_attempt::IN_PROGRESS);
$this->expectExceptionMessage("Attempt $attemptid is in the wrong state (In progress) to be reopened.");
get_reopen_attempt_confirmation::execute($attemptid);
}
/**
* Create a quiz of one shortanswer question and an attempt in a given state.
*
* @param string $attemptstate the desired attempt state. quiz_attempt::ABANDONED or ::IN_PROGRESS.
* @return array with two elements, the attempt id and the quiz id.
*/
protected function create_attempt_at_quiz_with_one_shortanswer_question(
string $attemptstate = quiz_attempt::ABANDONED
): array {
global $SITE;
$this->resetAfterTest();
// Make a quiz.
$timeclose = time() + HOURSECS;
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance([
'course' => $SITE->id,
'timeclose' => $timeclose,
'overduehandling' => 'autoabandon'
]);
// Create a question.
/** @var core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $questiongenerator->create_question_category();
$saq = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
// Add them to the quiz.
$quizobj = quiz_settings::create($quiz->id);
quiz_add_quiz_question($saq->id, $quiz, 0, 1);
$quizobj->get_grade_calculator()->recompute_quiz_sumgrades();
// Make a user to do the quiz.
$this->student = $this->getDataGenerator()->create_user();
$this->setUser($this->student);
$quizobj = quiz_settings::create($quiz->id, $this->student->id);
// Start the attempt.
$attempt = quiz_prepare_and_start_new_attempt($quizobj, 1, null);
$attemptobj = quiz_attempt::create($attempt->id);
if ($attemptstate === quiz_attempt::ABANDONED) {
// Attempt goes overdue (e.g. if cron ran).
$attemptobj->process_abandon($timeclose + 2 * get_config('quiz', 'graceperiodmin'), false);
} else if ($attemptstate !== quiz_attempt::IN_PROGRESS) {
throw new coding_exception('Status ' . $attemptstate . ' not currently supported.');
}
// Set current user to admin before we return.
$this->setAdminUser();
return [$attemptobj->get_attemptid(), $attemptobj->get_quizid()];
}
}
+112
View File
@@ -0,0 +1,112 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_quiz\external;
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/../../../../webservice/tests/helpers.php');
use core_question_generator;
use externallib_advanced_testcase;
use mod_quiz\quiz_settings;
use required_capability_exception;
/**
* Test for the update_slots service.
*
* @package mod_quiz
* @category external
* @copyright 2023 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_quiz\external\update_slots
*/
final class update_slots_test extends externallib_advanced_testcase {
public function test_update_slots_service_works(): void {
global $DB;
$quizobj = $this->create_quiz_with_two_shortanswer_questions();
$this->setAdminUser();
$structure = $quizobj->get_structure();
// No changes to slot 1.
$slot1data = [
'id' => $structure->get_slot_by_number(1)->id,
];
// Change everything in slot 2.
$slot2data = [
'id' => $structure->get_slot_by_number(2)->id,
'displaynumber' => '1b',
'requireprevious' => true,
'maxmark' => 7,
'quizgradeitemid' => 123,
];
update_slots::execute($quizobj->get_quizid(), [$slot1data, $slot2data]);
$slot = $DB->get_record('quiz_slots', ['id' => $slot2data['id']]);
$this->assertEquals('1b', $slot->displaynumber);
$this->assertTrue((bool) $slot->requireprevious);
$this->assertEquals(7, $slot->maxmark);
$this->assertEquals(123, $slot->quizgradeitemid);
}
public function test_update_slots_checks_permissions(): void {
$quizobj = $this->create_quiz_with_two_shortanswer_questions();
$unprivilegeduser = $this->getDataGenerator()->create_user();
$this->setUser($unprivilegeduser);
$this->expectException(required_capability_exception::class);
update_slots::execute($quizobj->get_quizid(), []);
}
/**
* Create a quiz of two shortanswer questions.
*
* @return quiz_settings the newly created quiz.
*/
protected function create_quiz_with_two_shortanswer_questions(): quiz_settings {
global $SITE;
$this->resetAfterTest();
// Make a quiz.
$timeclose = time() + HOURSECS;
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance([
'course' => $SITE->id,
'timeclose' => $timeclose,
'overduehandling' => 'autoabandon',
]);
// Create a question.
/** @var core_question_generator $questiongenerator */
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $questiongenerator->create_question_category();
$saq1 = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
$saq2 = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
// Add them to the quiz.
$quizobj = quiz_settings::create($quiz->id);
quiz_add_quiz_question($saq1->id, $quiz, 0, 1);
quiz_add_quiz_question($saq2->id, $quiz, 0, 1);
$quizobj->get_grade_calculator()->recompute_quiz_sumgrades();
return $quizobj;
}
}