<?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_h5pactivity;
use advanced_testcase;
use mod_h5pactivity\local\manager;
/**
* Unit tests for (some of) mod/h5pactivity/lib.php.
*
> * @package mod_h5pactivity
* @copyright 2021 Ilya Tregubov <ilya@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class lib_test extends advanced_testcase {
/**
* Load required test libraries
*/
public static function setUpBeforeClass(): void {
global $CFG;
require_once("{$CFG->dirroot}/mod/h5pactivity/lib.php");
}
/**
> * Test that h5pactivity_delete_instance removes data.
* Test that assign_print_recent_activity shows ungraded submitted assignments.
> *
*
> * @covers ::h5pactivity_delete_instance
* @covers ::h5pactivity_print_recent_activity
> */
*/
> public function test_h5pactivity_delete_instance() {
public function test_print_recent_activity() {
> global $DB;
$this->resetAfterTest();
> $this->resetAfterTest();
$this->setAdminUser();
> $this->setAdminUser();
>
$course = $this->getDataGenerator()->create_course();
> $course = $this->getDataGenerator()->create_course();
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
> $user = $this->getDataGenerator()->create_and_enrol($course, 'student');
$activity = $this->getDataGenerator()->create_module('h5pactivity',
> $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
['course' => $course, 'enabletracking' => 1, 'grademethod' => manager::GRADEHIGHESTATTEMPT]);
> $this->setUser($user);
>
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
> /** @var \mod_h5pactivity_generator $generator */
> $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
$manager = manager::create_from_instance($activity);
>
$cm = $manager->get_coursemodule();
> /** @var \core_h5p_generator $h5pgenerator */
> $h5pgenerator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
$user = $student;
>
$params = ['cmid' => $cm->id, 'userid' => $user->id];
> // Add an attempt to the H5P activity.
$generator->create_content($activity, $params);
> $attemptinfo = [
$this->setUser($student);
> 'userid' => $user->id,
$this->expectOutputRegex('/submitted:/');
> 'h5pactivityid' => $activity->id,
h5pactivity_print_recent_activity($course, true, time() - 3600);
> 'attempt' => 1,
}
> 'interactiontype' => 'compound',
> 'rawscore' => 2,
/**
> 'maxscore' => 2,
* Test that h5pactivity_print_recent_activity does not display any warnings when a custom fullname has been configured.
> 'duration' => 1,
*
> 'completion' => 1,
* @covers ::h5pactivity_print_recent_activity
> 'success' => 0,
*/
> ];
public function test_print_recent_activity_fullname() {
> $generator->create_attempt($attemptinfo);
$this->resetAfterTest();
>
$this->setAdminUser();
> // Add also a xAPI state to the H5P activity.
> $filerecord = [
$course = $this->getDataGenerator()->create_course();
> 'contextid' => \context_module::instance($activity->cmid)->id,
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
> 'component' => 'mod_h5pactivity',
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
> 'filearea' => 'package',
$activity = $this->getDataGenerator()->create_module('h5pactivity',
> 'itemid' => 0,
['course' => $course, 'enabletracking' => 1, 'grademethod' => manager::GRADEHIGHESTATTEMPT]);
> 'filepath' => '/',
> 'filepath' => '/',
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
> 'filename' => 'dummy.h5p',
> 'addxapistate' => true,
$manager = manager::create_from_instance($activity);
> ];
$cm = $manager->get_coursemodule();
> $h5pgenerator->generate_h5p_data(false, $filerecord);
>
$user = $student;
> // Check the H5P activity exists and the attempt has been created.
$params = ['cmid' => $cm->id, 'userid' => $user->id];
> $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id]));
$generator->create_content($activity, $params);
> $this->assertEquals(2, $DB->count_records('grade_items'));
> $this->assertEquals(2, $DB->count_records('grade_grades'));
$this->setUser($teacher);
> $this->assertEquals(1, $DB->count_records('xapi_states'));
>
$this->expectOutputRegex('/submitted:/');
> // Check nothing happens when given activity id doesn't exist.
set_config('fullnamedisplay', 'firstname, lastnamephonetic');
> h5pactivity_delete_instance($activity->id + 1);
h5pactivity_print_recent_activity($course, false, time() - 3600);
> $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id]));
}
> $this->assertEquals(2, $DB->count_records('grade_items'));
> $this->assertEquals(2, $DB->count_records('grade_grades'));
/**
> $this->assertEquals(1, $DB->count_records('xapi_states'));
* Test that h5pactivity_get_recent_mod_activity fetches the h5pactivity correctly.
>
*
> // Check the H5P instance and its associated data is removed.
* @covers ::h5pactivity_get_recent_mod_activity
> h5pactivity_delete_instance($activity->id);
*/
> $this->assertEmpty($DB->get_record('h5pactivity', ['id' => $activity->id]));
public function test_h5pactivity_get_recent_mod_activity() {
> $this->assertEquals(1, $DB->count_records('grade_items'));
$this->resetAfterTest();
> $this->assertEquals(1, $DB->count_records('grade_grades'));
$this->setAdminUser();
> $this->assertEquals(0, $DB->count_records('xapi_states'));
> }
$course = $this->getDataGenerator()->create_course();
>
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
> /**
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$activity = $this->getDataGenerator()->create_module('h5pactivity',
['course' => $course, 'enabletracking' => 1, 'grademethod' => manager::GRADEHIGHESTATTEMPT]);
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
$manager = manager::create_from_instance($activity);
$cm = $manager->get_coursemodule();
$user = $student;
$params = ['cmid' => $cm->id, 'userid' => $user->id];
$generator->create_content($activity, $params);
$index = 1;
$activities = [
$index => (object) [
'type' => 'h5pactivity',
'cmid' => $cm->id,
],
];
$this->setUser($teacher);
h5pactivity_get_recent_mod_activity($activities, $index, time() - HOURSECS, $course->id, $cm->id);
$activity = $activities[1];
$this->assertEquals("h5pactivity", $activity->type);
$this->assertEquals($student->id, $activity->user->id);
}
/**
* Test that h5pactivity_get_recent_mod_activity fetches activity correctly.
*
* @covers ::h5pactivity_fetch_recent_activity
*/
public function test_h5pactivity_fetch_recent_activity() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
// Create users and groups.
$students = array();
$groups = array();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
< for ($i = 1; $i < 4; $i++) {
> for ($i = 1; $i < 6; $i++) {
$students[$i] = $this->getDataGenerator()->create_and_enrol($course, 'student');
$groups[$i] = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
}
> $groups[$i] = $this->getDataGenerator()->create_group(array('courseid' => $course->id, 'participation' => 0));
// Update the course set the groupmode SEPARATEGROUPS and forced.
update_course((object)array('id' => $course->id, 'groupmode' => SEPARATEGROUPS, 'groupmodeforce' => true));
// Student 1 is in groups 1 and 3.
groups_add_member($groups[1], $students[1]);
groups_add_member($groups[3], $students[1]);
// Student 2 is in groups 1 and 2.
groups_add_member($groups[1], $students[2]);
groups_add_member($groups[2], $students[2]);
// Student 3 is only in group 3.
groups_add_member($groups[3], $students[3]);
> // Student 4 is only in group 5 (non-participation).
// Grader is only in group 3.
> groups_add_member($groups[6], $students[4]);
groups_add_member($groups[3], $teacher);
>
> // Student 5 is not in any groups.
$timestart = time() - 1;
>
// Create h5pactivity.
$activity = $this->getDataGenerator()->create_module('h5pactivity',
['course' => $course->id, 'enabletracking' => 1, 'grademethod' => manager::GRADEHIGHESTATTEMPT,
'groupmode' => SEPARATEGROUPS]);
$teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
$cmcontext = \context_module::instance($activity->cmid);
assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $teacherrole->id, $cmcontext, true);
$manager = manager::create_from_instance($activity);
$cm = $manager->get_coursemodule();
// Create attempts.
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
foreach ($students as $student) {
$params = ['cmid' => $cm->id, 'userid' => $student->id];
$generator->create_content($activity, $params);
}
// Get all attempts.
$dbparams = [$timestart, $course->id, 'h5pactivity'];
$userfieldsapi = \core_user\fields::for_userpic();
$namefields = $userfieldsapi->get_sql('u', false, '', 'userid', false)->selects;;
$sql = "SELECT h5pa.id, h5pa.timemodified, cm.id as cmid, $namefields
FROM {h5pactivity_attempts} h5pa
JOIN {h5pactivity} h5p ON h5p.id = h5pa.h5pactivityid
JOIN {course_modules} cm ON cm.instance = h5p.id
JOIN {modules} md ON md.id = cm.module
JOIN {user} u ON u.id = h5pa.userid
WHERE h5pa.timemodified > ?
AND h5p.course = ?
AND md.name = ?
ORDER BY h5pa.timemodified ASC";
$submissions = $DB->get_records_sql($sql, $dbparams);
$this->assertCount(count($students), $submissions);
// Fetch activity for student (only his own).
$this->setUser($students[1]);
$recentactivity = h5pactivity_fetch_recent_activity($submissions, $course->id);
$this->assertCount(1, $recentactivity);
$this->assertEquals($students[1]->id, $recentactivity[$students[1]->id]->userid);
// Fetch users group info for grader.
$this->setUser($teacher);
$recentactivity = h5pactivity_fetch_recent_activity($submissions, $course->id);
$this->assertCount(2, $recentactivity);
// Grader, Student 1 and 3 are in Group 3.
$this->assertEquals($students[1]->id, $recentactivity[$students[1]->id]->userid);
$this->assertEquals($students[3]->id, $recentactivity[$students[3]->id]->userid);
// Grader is in Group 2.
groups_remove_member($groups[3], $teacher);
groups_add_member($groups[2], $teacher);
get_fast_modinfo($course->id, 0, true);
$recentactivity = h5pactivity_fetch_recent_activity($submissions, $course->id);
$this->assertCount(1, $recentactivity);
// Grader, Student 2 are in Group 2.
$this->assertEquals($students[2]->id, $recentactivity[$students[2]->id]->userid);
// Grader is in Group 1.
groups_remove_member($groups[2], $teacher);
groups_add_member($groups[1], $teacher);
get_fast_modinfo($course->id, 0, true);
$recentactivity = h5pactivity_fetch_recent_activity($submissions, $course->id);
$this->assertCount(2, $recentactivity);
// Grader, Student 1 and 2 are in Group 1.
$this->assertEquals($students[1]->id, $recentactivity[$students[1]->id]->userid);
$this->assertEquals($students[2]->id, $recentactivity[$students[2]->id]->userid);
>
}
> // Grader is in no group.
}
> groups_remove_member($groups[1], $teacher);
> get_fast_modinfo($course->id, 0, true);
> $recentactivity = h5pactivity_fetch_recent_activity($submissions, $course->id);
> // Student 4 and Student 5 have submissions, but they are not in a participation group, so they do not show up in recent
> // activity for separate groups mode.
> $this->assertCount(0, $recentactivity);
> }
>
> /**
> * Test that h5pactivity_reset_userdata reset user data.
> *
> * @covers ::h5pactivity_reset_userdata
> */
> public function test_h5pactivity_reset_userdata() {
> global $DB;
> $this->resetAfterTest();
> $this->setAdminUser();
>
> $course = $this->getDataGenerator()->create_course();
> $user = $this->getDataGenerator()->create_and_enrol($course, 'student');
> $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
> $this->setUser($user);
>
> /** @var \mod_h5pactivity_generator $generator */
> $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
>
> /** @var \core_h5p_generator $h5pgenerator */
> $h5pgenerator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
>
> // Add an attempt to the H5P activity.
> $attemptinfo = [
> 'userid' => $user->id,
> 'h5pactivityid' => $activity->id,
> 'attempt' => 1,
> 'interactiontype' => 'compound',
> 'rawscore' => 2,
> 'maxscore' => 2,
> 'duration' => 1,
> 'completion' => 1,
> 'success' => 0,
> ];
> $generator->create_attempt($attemptinfo);
>
> // Add also a xAPI state to the H5P activity.
> $filerecord = [
> 'contextid' => \context_module::instance($activity->cmid)->id,
> 'component' => 'mod_h5pactivity',
> 'filearea' => 'package',
> 'itemid' => 0,
> 'filepath' => '/',
> 'filepath' => '/',
> 'filename' => 'dummy.h5p',
> 'addxapistate' => true,
> ];
> $h5pgenerator->generate_h5p_data(false, $filerecord);
>
> // Check the H5P activity exists and the attempt has been created with the expected data.
> $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id]));
> $this->assertEquals(2, $DB->count_records('grade_items'));
> $this->assertEquals(2, $DB->count_records('grade_grades'));
> $this->assertEquals(1, $DB->count_records('xapi_states'));
>
> // Check nothing happens when reset_h5pactivity is not set.
> $data = new \stdClass();
> h5pactivity_reset_userdata($data);
> $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id]));
> $this->assertEquals(2, $DB->count_records('grade_items'));
> $this->assertEquals(2, $DB->count_records('grade_grades'));
> $this->assertEquals(1, $DB->count_records('xapi_states'));
> $this->assertEquals(1, $DB->count_records('xapi_states'));
>
> // Check nothing happens when reset_h5pactivity is not set.
> $data = (object) [
> 'courseid' => $course->id,
> ];
> h5pactivity_reset_userdata($data);
> $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id]));
> $this->assertEquals(2, $DB->count_records('grade_items'));
> $this->assertEquals(2, $DB->count_records('grade_grades'));
> $this->assertEquals(1, $DB->count_records('xapi_states'));
> $this->assertEquals(1, $DB->count_records('xapi_states'));
>
> // Check nothing happens when the given course doesn't exist.
> $data = (object) [
> 'reset_h5pactivity' => true,
> 'courseid' => $course->id + 1,
> ];
> h5pactivity_reset_userdata($data);
> $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id]));
> $this->assertEquals(2, $DB->count_records('grade_items'));
> $this->assertEquals(2, $DB->count_records('grade_grades'));
> $this->assertEquals(1, $DB->count_records('xapi_states'));
> $this->assertEquals(1, $DB->count_records('xapi_states'));
>
> // Check the H5P instance and its associated data is reset.
> $data = (object) [
> 'reset_h5pactivity' => true,
> 'courseid' => $course->id,
> ];
> h5pactivity_reset_userdata($data);
> $this->assertNotEmpty($DB->get_record('h5pactivity', ['id' => $activity->id]));
> $this->assertEquals(2, $DB->count_records('grade_items'));
> $this->assertEquals(1, $DB->count_records('grade_grades'));
> $this->assertEquals(0, $DB->count_records('xapi_states'));