diff --git a/mod/quiz/report/attemptsreport.php b/mod/quiz/report/attemptsreport.php index fc259a226da..58163af3926 100644 --- a/mod/quiz/report/attemptsreport.php +++ b/mod/quiz/report/attemptsreport.php @@ -352,7 +352,7 @@ abstract class quiz_attempts_report extends quiz_default_report { WHERE {$allowedjoins->wheres} AND quiza.id = :attemptid"; } $params = $allowedjoins->params + array('attemptid' => $attemptid); - $attempt = $DB->get_record_sql($sql, $params); + $attempt = $DB->get_record_sql($sql, $params, IGNORE_MULTIPLE); if (!$attempt || $attempt->quiz != $quiz->id || $attempt->preview != 0) { // Ensure the attempt exists, belongs to this quiz and belongs to // a student included in the report. If not skip. diff --git a/mod/quiz/report/overview/tests/helpers.php b/mod/quiz/report/overview/tests/helpers.php new file mode 100644 index 00000000000..50a36507936 --- /dev/null +++ b/mod/quiz/report/overview/tests/helpers.php @@ -0,0 +1,59 @@ +. + +/** + * Makes some protected methods of quiz_attempts_report public to facilitate testing. + * + * @package quiz_overview + * @copyright 2020 Huong Nguyen + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot . '/mod/quiz/report/attemptsreport.php'); + +/** + * Makes some protected methods of quiz_attempts_report public to facilitate testing. + * + * @copyright 2020 Huong Nguyen + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class testable_quiz_attempts_report extends quiz_attempts_report { + + /** + * Override this function to displays the report. + * @param object $cm the course-module for this quiz. + * @param object $course the course we are in. + * @param object $quiz this quiz. + */ + public function display($cm, $course, $quiz) { + + } + + /** + * Testable delete_selected_attempts function. + * + * @param object $quiz + * @param object $cm + * @param array $attemptids + * @param \core\dml\sql_join $allowedjoins + */ + public function delete_selected_attempts($quiz, $cm, $attemptids, \core\dml\sql_join $allowedjoins) { + parent::delete_selected_attempts($quiz, $cm, $attemptids, $allowedjoins); + } +} diff --git a/mod/quiz/report/overview/tests/report_test.php b/mod/quiz/report/overview/tests/report_test.php index 41fd57dfed6..20a632a4cda 100644 --- a/mod/quiz/report/overview/tests/report_test.php +++ b/mod/quiz/report/overview/tests/report_test.php @@ -29,6 +29,7 @@ require_once($CFG->dirroot . '/mod/quiz/locallib.php'); require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php'); require_once($CFG->dirroot . '/mod/quiz/report/default.php'); require_once($CFG->dirroot . '/mod/quiz/report/overview/report.php'); +require_once($CFG->dirroot . '/mod/quiz/report/overview/tests/helpers.php'); /** @@ -263,4 +264,54 @@ class quiz_overview_report_testcase extends advanced_testcase { $this->assertEquals($expected, quiz_overview_report::get_bands_count_and_width($quiz)); } + /** + * Test delete_selected_attempts function. + */ + public function test_delete_selected_attempts() { + $this->resetAfterTest(true); + + $timestamp = 1234567890; + $timestart = $timestamp + 3600; + + // Create a course and a quiz. + $generator = $this->getDataGenerator(); + $course = $generator->create_course(); + $quizgenerator = $generator->get_plugin_generator('mod_quiz'); + $quiz = $quizgenerator->create_instance([ + 'course' => $course->id, + 'grademethod' => QUIZ_GRADEHIGHEST, + 'grade' => 100.0, + 'sumgrades' => 10.0, + 'attempts' => 10 + ]); + + // Add one question. + $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); + $cat = $questiongenerator->create_question_category(); + $q = $questiongenerator->create_question('essay', 'plain', ['category' => $cat->id]); + quiz_add_quiz_question($q->id, $quiz, 0 , 10); + + // Create student and enrol them in the course. + // Note: we create two enrolments, to test the problem reported in MDL-67942. + $student = $generator->create_user(); + $generator->enrol_user($student->id, $course->id); + $generator->enrol_user($student->id, $course->id, null, 'self'); + + $context = context_module::instance($quiz->cmid); + $cm = get_coursemodule_from_id('quiz', $quiz->cmid); + $allowedjoins = get_enrolled_with_capabilities_join($context, '', ['mod/quiz:attempt', 'mod/quiz:reviewmyattempts']); + $quizattemptsreport = new testable_quiz_attempts_report(); + + // Create the new attempt and initialize the question sessions. + $quizobj = quiz::create($quiz->id, $student->id); + $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); + $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); + $attempt = quiz_create_attempt($quizobj, 1, null, $timestart, false, $student->id); + $attempt = quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timestamp); + $attempt = quiz_attempt_save_started($quizobj, $quba, $attempt); + + // Delete the student's attempt. + $quizattemptsreport->delete_selected_attempts($quiz, $cm, [$attempt->id], $allowedjoins); + } + }