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
@@ -0,0 +1,73 @@
<?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_survey\backup;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . "/phpunit/classes/restore_date_testcase.php");
/**
* Restore date tests.
*
* @package mod_survey
* @copyright 2017 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class restore_date_test extends \restore_date_testcase {
public function test_restore_dates(): void {
global $DB;
list($course, $survey) = $this->create_course_and_module('survey');
$context = \context_module::instance($survey->cmid);
// Build our questions and responses array.
$realquestions = array();
$questions = survey_get_questions($survey);
$i = 5;
foreach ($questions as $q) {
if ($q->type > 0) {
if ($q->multi) {
$subquestions = survey_get_subquestions($q);
foreach ($subquestions as $sq) {
$key = 'q' . $sq->id;
$realquestions[$key] = $i % 5 + 1;
$i++;
}
} else {
$key = 'q' . $q->id;
$realquestions[$key] = $i % 5 + 1;
$i++;
}
}
}
survey_save_answers($survey, $realquestions, $course, $context);
// We do not want second differences to fail our test because of execution delays.
$DB->set_field('survey_answers', 'time', $this->startdate);
// Do backup and restore.
$newcourseid = $this->backup_and_restore($course);
$newsurvey = $DB->get_record('survey', ['course' => $newcourseid]);
$this->assertFieldsNotRolledForward($survey, $newsurvey, ['timecreated', 'timemodified']);
$answers = $DB->get_records('survey_answers', ['survey' => $newsurvey->id]);
foreach ($answers as $answer) {
$this->assertEquals($this->startdate, $answer->time);
}
}
}
@@ -0,0 +1,65 @@
@mod @mod_survey @core_completion @javascript
Feature: A teacher can use activity completion to track a student progress
In order to use activity completion
As a teacher
I need to set survey activities and enable activity completion
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category | enablecompletion |
| Course 1 | C1 | 0 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And I enable "survey" "mod" plugin
And I log in as "teacher1"
Scenario: Require survey view
Given the following "activities" exist:
| activity | name | course | idnumber | template | completion | completionview | completionsubmit |
| survey | Test survey name | C1 | survey1 | 5 | 2 | 1 | 0 |
And I am on the "Test survey name" "survey activity" page
# Teacher view.
And "Test survey name" should have the "View" completion condition
# Student view.
When I am on the "Course 1" course page logged in as student1
And the "View" completion condition of "Test survey name" is displayed as "todo"
And I follow "Test survey name"
And I am on "Course 1" course homepage
Then the "View" completion condition of "Test survey name" is displayed as "done"
Scenario: Require survey submission
Given the following "activities" exist:
| activity | name | course | idnumber | template | completion | completionview | completionsubmit |
| survey | Test survey name | C1 | survey1 | 5 | 2 | 1 | 1 |
And I am on the "Test survey name" "survey activity" page
# Teacher view.
And "Test survey name" should have the "Submit answers" completion condition
# Student view.
When I am on the "Course 1" course page logged in as student1
And the "Submit answers" completion condition of "Test survey name" is displayed as "todo"
And I follow "Test survey name"
And the "Submit answers" completion condition of "Test survey name" is displayed as "todo"
And I press "Submit"
And I am on "Course 1" course homepage
And the "Submit answers" completion condition of "Test survey name" is displayed as "done"
And I follow "Test survey name"
And the "Submit answers" completion condition of "Test survey name" is displayed as "done"
Scenario: Use manual completion
Given the following "activities" exist:
| activity | name | course | idnumber | completion |
| survey | Test survey name | C1 | survey1 | 1 |
And I am on "Course 1" course homepage
# Teacher view.
And "Test survey name" should have the "Mark as done" completion condition
# Student view.
When I am on the "survey1" Activity page logged in as student1
Then the manual completion button of "Test survey name" is displayed as "Mark as done"
And I toggle the manual completion state of "Test survey name"
And the manual completion button of "Test survey name" is displayed as "Done"
@@ -0,0 +1,47 @@
@mod @mod_survey @javascript
Feature: A teacher navigates to response reports of students
If survey activity is configured for critical students
Only questions and particiats pages should be visible under response reports
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 1 | student2@example.com |
And the following "courses" exist:
| fullname | shortname | category | enablecompletion |
| Course 1 | C1 | 0 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And I enable "survey" "mod" plugin
And the following "activities" exist:
| activity | name | course | idnumber | template |
| survey | Test survey name | C1 | survey1 | 5 |
Scenario: Only questions and participants page should be available under response reports as teacher
Given I am on the "Test survey name" "survey activity" page logged in as student1
And I set the field "At what moment in class were you most engaged as a learner?" to "most engaged as student1"
And I set the field "At what moment in class were you most distanced as a learner?" to "most distanced as student1"
And I set the field "What action from anyone in the forums did you find most affirming or helpful?" to "most helpful student1"
And I set the field "What action from anyone in the forums did you find most puzzling or confusing?" to "most confusing student1"
And I set the field "What event surprised you most?" to "most surprised student1"
And I press "Submit"
And I press "Continue"
And I am on the "Test survey name" "survey activity" page logged in as student2
And I set the field "At what moment in class were you most engaged as a learner?" to "most engaged as student2"
And I set the field "At what moment in class were you most distanced as a learner?" to "most distanced as student2"
And I set the field "What action from anyone in the forums did you find most affirming or helpful?" to "most helpful student2"
And I set the field "What action from anyone in the forums did you find most puzzling or confusing?" to "most confusing student2"
And I set the field "What event surprised you most?" to "most surprised student1"
And I press "Submit"
And I press "Continue"
When I am on the "Test survey name" "survey activity" page logged in as teacher1
And I navigate to "Response reports" in current page administration
Then I should not see "Summary"
And I should not see "Scales"
And I should see "Questions"
And I should see "Participants"
@@ -0,0 +1,31 @@
@mod @mod_survey
Feature: The default introduction is displayed when the activity description is empty
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And I enable "survey" "mod" plugin
And the following "activities" exist:
| activity | name | course | idnumber | template |
| survey | Test survey name | C1 | survey1 | 1 |
Scenario: Display the default survey introduction when activity description is empty
Given I am on the "Test survey name" "survey activity" page logged in as "teacher1"
And I should see "Test survey 1"
When I am on the "Test survey name" "survey activity editing" page
And I set the following fields to these values:
| Description | |
And I press "Save and display"
Then I should see "The purpose of this survey is to help us understand"
And I am on the "Test survey name" "survey activity editing" page
And I set the following fields to these values:
| Survey type | ATTLS (20 item version) |
And I press "Save and display"
And I should see "The purpose of this questionnaire is to help us evaluate"
@@ -0,0 +1,86 @@
@mod @mod_survey
Feature: Viewing response reports by group
In order to view reponse reports on a large course
As a teacher
I need to filter the users on the response reports by group
Background:
And the following "courses" exist:
| fullname | shortname |
| Test Course 1 | C1 |
And the following "groups" exist:
| name | course | idnumber | participation |
| Group 1 | C1 | G1 | 1 |
| Group 2 | C1 | G2 | 1 |
| Group 3 | C1 | G3 | 0 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | TeacherG1 | 1 | teacher1@example.com |
| noneditor1 | NoneditorG1 | 1 | noneditor1@example.com |
| noneditor2 | NoneditorNone | 2 | noneditor2@example.com |
| user1 | User1G1 | 1 | user1@example.com |
| user2 | User2G2 | 2 | user2@example.com |
| user3 | User3None | 3 | user3@example.com |
| user4 | User4NPgroup | 4 | user4@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| noneditor1 | C1 | teacher |
| noneditor2 | C1 | teacher |
| user1 | C1 | student |
| user2 | C1 | student |
| user3 | C1 | student |
| user4 | C1 | student |
And the following "group members" exist:
| user | group |
| teacher1 | G1 |
| noneditor1 | G1 |
| user1 | G1 |
| user2 | G2 |
| user4 | G3 |
And I enable "survey" "mod" plugin
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode | template |
| survey | Separate survey | survey with separate groups | C1 | survey1 | 1 | 5 |
| survey | Visible survey | survey with visible groups | C1 | survey2 | 2 | 5 |
And I am on the "Separate survey" "survey activity" page logged in as user1
And I press "Submit"
And I am on the "Separate survey" "survey activity" page logged in as user2
And I press "Submit"
And I am on the "Separate survey" "survey activity" page logged in as user3
And I press "Submit"
And I am on the "Separate survey" "survey activity" page logged in as user4
And I press "Submit"
And I am on the "Visible survey" "survey activity" page logged in as user1
And I press "Submit"
And I am on the "Visible survey" "survey activity" page logged in as user2
And I press "Submit"
And I am on the "Visible survey" "survey activity" page logged in as user3
And I press "Submit"
And I am on the "Visible survey" "survey activity" page logged in as user4
And I press "Submit"
Scenario Outline: Editing teachers should see all groups on the Results page. Non-editing teachers should see just their own
groups in Separate groups mode, all groups in Visible groups mode.
Given I am on the "<survey>" "survey activity" page logged in as "<user>"
And I follow "Response reports"
Then I <all> see "All participants"
And I <G1> see "Group 1"
And I <G2> see "Group 2"
And I should not see "Group 3"
And I <user1> see "User1G1"
And I <user2> see "User2G2"
And I <user3> see "User3None"
And I <user4> see "User4NPgroup"
Examples:
| survey | user | all | G1 | G2 | user1 | user2 | user3 | user4 |
| survey1 | teacher1 | should | should | should | should | should | should | should |
| survey1 | noneditor1 | should not | should | should not | should | should not | should not | should not |
| survey2 | teacher1 | should | should | should | should | should | should | should |
| survey2 | noneditor1 | should | should | should | should | should not | should not | should not |
| survey2 | noneditor2 | should | should | should | should | should not | should not | should not |
Scenario: Non-editing teacher without access to any groups should not see survey results in separate groups mode
Given I am on the "survey1" "survey activity" page logged in as "noneditor2"
Then I should not see "Response reports"
@@ -0,0 +1,48 @@
@mod @mod_survey
Feature: A teacher can set three types of survey activity
In order to use verified survey instruments
As a teacher
I need to set survey activities and select which survey type suits my needs
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And I enable "survey" "mod" plugin
And I log in as "teacher1"
Scenario: Switching between the three survey types
Given the following "activities" exist:
| activity | name | course | idnumber |
| survey | Test survey name | C1 | survey1 |
And I am on the "Test survey name" "survey activity editing" page
And I set the following fields to these values:
| Survey type | ATTLS (20 item version) |
And I press "Save and display"
Then I should see "Attitudes Towards Thinking and Learning"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Survey type | Critical incidents |
And I press "Save and display"
And I should see "At what moment in class were you most engaged as a learner?"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Survey type | COLLES (Preferred and Actual) |
And I press "Save and display"
And I should see "In this online unit..."
And I should see "my learning focuses on issues that interest me."
Scenario: Survey activity is created via UI
Given I add a survey activity to course "Course 1" section "1"
And I set the following fields to these values:
| Name | Test survey name |
| Description | Test survey description |
| Survey type | ATTLS (20 item version) |
When I press "Save and return to course"
Then I should see "Test survey name"
@@ -0,0 +1,25 @@
@mod @mod_survey @javascript
Feature: When some answers are not selected, the survey should not be submitted
In order to submit valid responses
As a student
I need to fill values
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
And I enable "survey" "mod" plugin
Scenario: Require survey view
Given the following "activities" exist:
| activity | name | course |
| survey | Test survey name | C1 |
And I am on the "Test survey name" "survey activity" page logged in as "student1"
When I press "Submit"
Then I should see "Some of the multiple choice questions have not been answered." in the "Error" "dialogue"
+217
View File
@@ -0,0 +1,217 @@
<?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/>.
/**
* Contains unit tests for core_completion/activity_custom_completion.
*
* @package mod_survey
* @copyright Simey Lameze <simey@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
declare(strict_types=1);
namespace mod_survey;
use advanced_testcase;
use cm_info;
use coding_exception;
use mod_survey\completion\custom_completion;
use moodle_exception;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . '/completionlib.php');
/**
* Class for unit testing mod_survey/activity_custom_completion.
*
* @package mod_survey
* @copyright Simey Lameze <simey@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class custom_completion_test extends advanced_testcase {
/**
* Data provider for get_state().
*
* @return array[]
*/
public function get_state_provider(): array {
return [
'Undefined rule' => [
'somenonexistentrule', COMPLETION_DISABLED, false, null, coding_exception::class
],
'Rule not available' => [
'completionsubmit', COMPLETION_DISABLED, false, null, moodle_exception::class
],
'Rule available, user has not submitted' => [
'completionsubmit', COMPLETION_ENABLED, false, COMPLETION_INCOMPLETE, null
],
'Rule available, user has submitted' => [
'completionsubmit', COMPLETION_ENABLED, true, COMPLETION_COMPLETE, null
],
];
}
/**
* Test for get_state().
*
* @dataProvider get_state_provider
* @param string $rule The custom completion rule.
* @param int $available Whether this rule is available.
* @param bool $submitted
* @param int|null $status Expected status.
* @param string|null $exception Expected exception.
*/
public function test_get_state(string $rule, int $available, ?bool $submitted, ?int $status, ?string $exception): void {
global $DB;
if (!is_null($exception)) {
$this->expectException($exception);
}
// Custom completion rule data for cm_info::customdata.
$customdataval = [
'customcompletionrules' => [
$rule => $available
]
];
// Build a mock cm_info instance.
$mockcminfo = $this->getMockBuilder(cm_info::class)
->disableOriginalConstructor()
->onlyMethods(['__get'])
->getMock();
// Mock the return of the magic getter method when fetching the cm_info object's customdata and instance values.
$mockcminfo->expects($this->any())
->method('__get')
->will($this->returnValueMap([
['customdata', $customdataval],
['instance', 1],
]));
// Mock the DB calls.
$DB = $this->createMock(get_class($DB));
$DB->expects($this->atMost(1))
->method('record_exists')
->willReturn($submitted);
$customcompletion = new custom_completion($mockcminfo, 2);
$this->assertEquals($status, $customcompletion->get_state($rule));
}
/**
* Test for get_defined_custom_rules().
*/
public function test_get_defined_custom_rules(): void {
$rules = custom_completion::get_defined_custom_rules();
$this->assertCount(1, $rules);
$this->assertEquals('completionsubmit', reset($rules));
}
/**
* Test for get_defined_custom_rule_descriptions().
*/
public function test_get_custom_rule_descriptions(): void {
// Get defined custom rules.
$rules = custom_completion::get_defined_custom_rules();
// Build a mock cm_info instance.
$mockcminfo = $this->getMockBuilder(cm_info::class)
->disableOriginalConstructor()
->onlyMethods(['__get'])
->getMock();
// Instantiate a custom_completion object using the mocked cm_info.
$customcompletion = new custom_completion($mockcminfo, 1);
// Get custom rule descriptions.
$ruledescriptions = $customcompletion->get_custom_rule_descriptions();
// Confirm that defined rules and rule descriptions are consistent with each other.
$this->assertEquals(count($rules), count($ruledescriptions));
foreach ($rules as $rule) {
$this->assertArrayHasKey($rule, $ruledescriptions);
}
}
/**
* Test for is_defined().
*/
public function test_is_defined(): void {
// Build a mock cm_info instance.
$mockcminfo = $this->getMockBuilder(cm_info::class)
->disableOriginalConstructor()
->getMock();
$customcompletion = new custom_completion($mockcminfo, 1);
// Rule is defined.
$this->assertTrue($customcompletion->is_defined('completionsubmit'));
// Undefined rule.
$this->assertFalse($customcompletion->is_defined('somerandomrule'));
}
/**
* Data provider for test_get_available_custom_rules().
*
* @return array[]
*/
public function get_available_custom_rules_provider(): array {
return [
'Completion submit available' => [
COMPLETION_ENABLED, ['completionsubmit']
],
'Completion submit not available' => [
COMPLETION_DISABLED, []
],
];
}
/**
* Test for get_available_custom_rules().
*
* @dataProvider get_available_custom_rules_provider
* @param int $status
* @param array $expected
*/
public function test_get_available_custom_rules(int $status, array $expected): void {
$customdataval = [
'customcompletionrules' => [
'completionsubmit' => $status
]
];
// Build a mock cm_info instance.
$mockcminfo = $this->getMockBuilder(cm_info::class)
->disableOriginalConstructor()
->onlyMethods(['__get'])
->getMock();
// Mock the return of magic getter for the customdata attribute.
$mockcminfo->expects($this->any())
->method('__get')
->with('customdata')
->willReturn($customdataval);
$customcompletion = new custom_completion($mockcminfo, 1);
$this->assertEquals($expected, $customcompletion->get_available_custom_rules());
}
}
+138
View File
@@ -0,0 +1,138 @@
<?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/>.
/**
* Events tests.
*
* @package mod_survey
* @copyright 2014 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_survey\event;
/**
* Events tests class.
*
* @package mod_survey
* @copyright 2014 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class events_test extends \advanced_testcase {
/**
* Setup.
*/
public function setUp(): void {
$this->resetAfterTest();
// Survey module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('survey', 1);
}
/**
* Test report downloaded event.
*/
public function test_report_downloaded(): void {
// There is no proper API to call to generate chapters for a book, so what we are
// doing here is simply making sure that the events returns the right information.
$course = $this->getDataGenerator()->create_course();
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id));
$params = array(
'objectid' => $survey->id,
'context' => \context_module::instance($survey->cmid),
'courseid' => $course->id,
'other' => array('type' => 'xls')
);
$event = \mod_survey\event\report_downloaded::create($params);
// Triggering and capturing the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_survey\event\report_downloaded', $event);
$this->assertEquals(\context_module::instance($survey->cmid), $event->get_context());
$this->assertEquals($survey->id, $event->objectid);
$this->assertEventContextNotUsed($event);
}
/**
* Test report viewed event.
*/
public function test_report_viewed(): void {
// There is no proper API to call to generate chapters for a book, so what we are
// doing here is simply making sure that the events returns the right information.
$course = $this->getDataGenerator()->create_course();
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id));
$params = array(
'objectid' => $survey->id,
'context' => \context_module::instance($survey->cmid),
'courseid' => $course->id
);
$event = \mod_survey\event\report_viewed::create($params);
// Triggering and capturing the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_survey\event\report_viewed', $event);
$this->assertEquals(\context_module::instance($survey->cmid), $event->get_context());
$this->assertEquals($survey->id, $event->objectid);
}
/**
* Test response submitted event.
*/
public function test_response_submitted(): void {
// There is no proper API to call to generate chapters for a book, so what we are
// doing here is simply making sure that the events returns the right information.
$course = $this->getDataGenerator()->create_course();
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id));
$params = array(
'context' => \context_module::instance($survey->cmid),
'courseid' => $course->id,
'other' => array('surveyid' => $survey->id)
);
$event = \mod_survey\event\response_submitted::create($params);
// Triggering and capturing the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_survey\event\response_submitted', $event);
$this->assertEquals(\context_module::instance($survey->cmid), $event->get_context());
$this->assertEquals($survey->id, $event->other['surveyid']);
$this->assertEventContextNotUsed($event);
}
}
+413
View File
@@ -0,0 +1,413 @@
<?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_survey;
use core_external\external_api;
use externallib_advanced_testcase;
use mod_survey_external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
require_once($CFG->dirroot . '/mod/survey/lib.php');
/**
* Survey module external functions tests
*
* @package mod_survey
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
class externallib_test extends externallib_advanced_testcase {
/** @var \stdClass course record. */
protected $course;
/** @var \stdClass activity record. */
protected $survey;
/** @var \context_module context instance. */
protected $context;
/** @var \StdClass course module. */
protected $cm;
/** @var \StdClass student record. */
protected $student;
/** @var \StdClass teacher record. */
protected $teacher;
/** @var \StdClass student role. */
protected $studentrole;
/** @var \StdClass teacher role. */
protected $teacherrole;
/**
* Set up for every test
*/
public function setUp(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Survey module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('survey', 1);
// Setup test data.
$this->course = $this->getDataGenerator()->create_course();
$this->survey = $this->getDataGenerator()->create_module('survey', array('course' => $this->course->id));
$this->context = \context_module::instance($this->survey->cmid);
$this->cm = get_coursemodule_from_instance('survey', $this->survey->id);
// Create users.
$this->student = self::getDataGenerator()->create_user();
$this->teacher = self::getDataGenerator()->create_user();
// Users enrolments.
$this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
$this->getDataGenerator()->enrol_user($this->student->id, $this->course->id, $this->studentrole->id, 'manual');
$this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
}
/*
* Test get surveys by courses
*/
public function test_mod_survey_get_surveys_by_courses(): void {
global $DB;
// Create additional course.
$course2 = self::getDataGenerator()->create_course();
// Second survey.
$record = new \stdClass();
$record->course = $course2->id;
$survey2 = self::getDataGenerator()->create_module('survey', $record);
// Force empty intro.
$DB->set_field('survey', 'intro', '', array('id' => $survey2->id));
// Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
$enrol = enrol_get_plugin('manual');
$enrolinstances = enrol_get_instances($course2->id, true);
foreach ($enrolinstances as $courseenrolinstance) {
if ($courseenrolinstance->enrol == "manual") {
$instance2 = $courseenrolinstance;
break;
}
}
$enrol->enrol_user($instance2, $this->student->id, $this->studentrole->id);
self::setUser($this->student);
$returndescription = mod_survey_external::get_surveys_by_courses_returns();
// Create what we expect to be returned when querying the two courses.
// First for the student user.
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang',
'template', 'days', 'questions', 'surveydone');
// Add expected coursemodule and data.
$survey1 = $this->survey;
$survey1->coursemodule = $survey1->cmid;
$survey1->introformat = 1;
$survey1->surveydone = 0;
$survey1->section = 0;
$survey1->visible = true;
$survey1->groupmode = 0;
$survey1->groupingid = 0;
$survey1->introfiles = [];
$survey1->lang = '';
$survey2->coursemodule = $survey2->cmid;
$survey2->introformat = 1;
$survey2->surveydone = 0;
$survey2->section = 0;
$survey2->visible = true;
$survey2->groupmode = 0;
$survey2->groupingid = 0;
$tempo = $DB->get_field("survey", "intro", array("id" => $survey2->template));
$survey2->intro = nl2br(get_string($tempo, "survey"));
$survey2->introfiles = [];
$survey2->lang = '';
foreach ($expectedfields as $field) {
$expected1[$field] = $survey1->{$field};
$expected2[$field] = $survey2->{$field};
}
$expectedsurveys = array($expected2, $expected1);
// Call the external function passing course ids.
$result = mod_survey_external::get_surveys_by_courses(array($course2->id, $this->course->id));
$result = external_api::clean_returnvalue($returndescription, $result);
$this->assertEquals($expectedsurveys, $result['surveys']);
$this->assertCount(0, $result['warnings']);
// Call the external function without passing course id.
$result = mod_survey_external::get_surveys_by_courses();
$result = external_api::clean_returnvalue($returndescription, $result);
$this->assertEquals($expectedsurveys, $result['surveys']);
$this->assertCount(0, $result['warnings']);
// Unenrol user from second course and alter expected surveys.
$enrol->unenrol_user($instance2, $this->student->id);
array_shift($expectedsurveys);
// Call the external function without passing course id.
$result = mod_survey_external::get_surveys_by_courses();
$result = external_api::clean_returnvalue($returndescription, $result);
$this->assertEquals($expectedsurveys, $result['surveys']);
// Call for the second course we unenrolled the user from, expected warning.
$result = mod_survey_external::get_surveys_by_courses(array($course2->id));
$this->assertCount(1, $result['warnings']);
$this->assertEquals('1', $result['warnings'][0]['warningcode']);
$this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
// Now, try as a teacher for getting all the additional fields.
self::setUser($this->teacher);
$additionalfields = array('timecreated', 'timemodified', 'section', 'visible', 'groupmode', 'groupingid');
foreach ($additionalfields as $field) {
$expectedsurveys[0][$field] = $survey1->{$field};
}
$result = mod_survey_external::get_surveys_by_courses();
$result = external_api::clean_returnvalue($returndescription, $result);
$this->assertEquals($expectedsurveys, $result['surveys']);
// Admin also should get all the information.
self::setAdminUser();
$result = mod_survey_external::get_surveys_by_courses(array($this->course->id));
$result = external_api::clean_returnvalue($returndescription, $result);
$this->assertEquals($expectedsurveys, $result['surveys']);
// Now, prohibit capabilities.
$this->setUser($this->student);
$contextcourse1 = \context_course::instance($this->course->id);
// Prohibit capability = mod/survey:participate on Course1 for students.
assign_capability('mod/survey:participate', CAP_PROHIBIT, $this->studentrole->id, $contextcourse1->id);
accesslib_clear_all_caches_for_unit_testing();
$surveys = mod_survey_external::get_surveys_by_courses(array($this->course->id));
$surveys = external_api::clean_returnvalue(mod_survey_external::get_surveys_by_courses_returns(), $surveys);
$this->assertFalse(isset($surveys['surveys'][0]['intro']));
}
/**
* Test view_survey
*/
public function test_view_survey(): void {
global $DB;
// Test invalid instance id.
try {
mod_survey_external::view_survey(0);
$this->fail('Exception expected due to invalid mod_survey instance id.');
} catch (\moodle_exception $e) {
$this->assertEquals('invalidrecord', $e->errorcode);
}
// Test not-enrolled user.
$usernotenrolled = self::getDataGenerator()->create_user();
$this->setUser($usernotenrolled);
try {
mod_survey_external::view_survey($this->survey->id);
$this->fail('Exception expected due to not enrolled user.');
} catch (\moodle_exception $e) {
$this->assertEquals('requireloginerror', $e->errorcode);
}
// Test user with full capabilities.
$this->setUser($this->student);
// Trigger and capture the event.
$sink = $this->redirectEvents();
$result = mod_survey_external::view_survey($this->survey->id);
$result = external_api::clean_returnvalue(mod_survey_external::view_survey_returns(), $result);
$this->assertTrue($result['status']);
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = array_shift($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_survey\event\course_module_viewed', $event);
$this->assertEquals($this->context, $event->get_context());
$moodlesurvey = new \moodle_url('/mod/survey/view.php', array('id' => $this->cm->id));
$this->assertEquals($moodlesurvey, $event->get_url());
$this->assertEventContextNotUsed($event);
$this->assertNotEmpty($event->get_name());
// Test user with no capabilities.
// We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
assign_capability('mod/survey:participate', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
accesslib_clear_all_caches_for_unit_testing();
try {
mod_survey_external::view_survey($this->survey->id);
$this->fail('Exception expected due to missing capability.');
} catch (\moodle_exception $e) {
$this->assertEquals('nopermissions', $e->errorcode);
}
}
/**
* Test get_questions
*/
public function test_get_questions(): void {
global $DB;
// Test user with full capabilities.
$this->setUser($this->student);
// Build our expectation array.
$expectedquestions = array();
$questions = survey_get_questions($this->survey);
foreach ($questions as $q) {
if ($q->type >= 0) {
$expectedquestions[$q->id] = $q;
if ($q->multi) {
$subquestions = survey_get_subquestions($q);
foreach ($subquestions as $sq) {
$expectedquestions[$sq->id] = $sq;
}
}
}
}
$result = mod_survey_external::get_questions($this->survey->id);
$result = external_api::clean_returnvalue(mod_survey_external::get_questions_returns(), $result);
// Check we receive the same questions.
$this->assertCount(0, $result['warnings']);
foreach ($result['questions'] as $q) {
$this->assertEquals(get_string($expectedquestions[$q['id']]->text, 'survey'), $q['text']);
$this->assertEquals(get_string($expectedquestions[$q['id']]->shorttext, 'survey'), $q['shorttext']);
$this->assertEquals($expectedquestions[$q['id']]->multi, $q['multi']);
$this->assertEquals($expectedquestions[$q['id']]->type, $q['type']);
// Parent questions must have parent eq to 0.
if ($q['multi']) {
$this->assertEquals(0, $q['parent']);
$this->assertEquals(get_string($expectedquestions[$q['id']]->options, 'survey'), $q['options']);
}
}
// Test user with no capabilities.
// We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
assign_capability('mod/survey:participate', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
accesslib_clear_all_caches_for_unit_testing();
try {
mod_survey_external::get_questions($this->survey->id);
$this->fail('Exception expected due to missing capability.');
} catch (\moodle_exception $e) {
$this->assertEquals('nopermissions', $e->errorcode);
}
}
/**
* Test submit_answers
*/
public function test_submit_answers(): void {
global $DB;
// Test user with full capabilities.
$this->setUser($this->student);
// Build our questions and responses array.
$realquestions = array();
$questions = survey_get_questions($this->survey);
$i = 5;
foreach ($questions as $q) {
if ($q->type >= 0) {
if ($q->multi) {
$subquestions = survey_get_subquestions($q);
foreach ($subquestions as $sq) {
$realquestions[] = array(
'key' => 'q' . $sq->id,
'value' => $i % 5 + 1 // Values between 1 and 5.
);
$i++;
}
} else {
$realquestions[] = array(
'key' => 'q' . $q->id,
'value' => $i % 5 + 1
);
$i++;
}
}
}
$result = mod_survey_external::submit_answers($this->survey->id, $realquestions);
$result = external_api::clean_returnvalue(mod_survey_external::submit_answers_returns(), $result);
$this->assertTrue($result['status']);
$this->assertCount(0, $result['warnings']);
$dbanswers = $DB->get_records_menu('survey_answers', array('survey' => $this->survey->id), '', 'question, answer1');
foreach ($realquestions as $q) {
$id = str_replace('q', '', $q['key']);
$this->assertEquals($q['value'], $dbanswers[$id]);
}
// Submit again, we expect an error here.
try {
mod_survey_external::submit_answers($this->survey->id, $realquestions);
$this->fail('Exception expected due to answers already submitted.');
} catch (\moodle_exception $e) {
$this->assertEquals('alreadysubmitted', $e->errorcode);
}
// Test user with no capabilities.
// We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
assign_capability('mod/survey:participate', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
accesslib_clear_all_caches_for_unit_testing();
try {
mod_survey_external::submit_answers($this->survey->id, $realquestions);
$this->fail('Exception expected due to missing capability.');
} catch (\moodle_exception $e) {
$this->assertEquals('nopermissions', $e->errorcode);
}
// Test not-enrolled user.
$usernotenrolled = self::getDataGenerator()->create_user();
$this->setUser($usernotenrolled);
try {
mod_survey_external::submit_answers($this->survey->id, $realquestions);
$this->fail('Exception expected due to not enrolled user.');
} catch (\moodle_exception $e) {
$this->assertEquals('requireloginerror', $e->errorcode);
}
}
}
+75
View File
@@ -0,0 +1,75 @@
<?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/>.
/**
* mod_survey data generator.
*
* @package mod_survey
* @category test
* @copyright 2013 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* mod_survey data generator class.
*
* @package mod_survey
* @category test
* @copyright 2013 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_survey_generator extends testing_module_generator {
/**
* Cached list of available templates.
* @var array
*/
private $templates = null;
public function reset() {
$this->templates = null;
parent::reset();
}
public function create_instance($record = null, array $options = null) {
global $DB;
if ($this->templates === null) {
$this->templates = $DB->get_records_menu('survey', array('template' => 0), 'name', 'id, name');
}
if (empty($this->templates)) {
throw new moodle_exception('cannotfindsurveytmpt', 'survey');
}
$record = (array)$record;
if (isset($record['template']) && !is_number($record['template'])) {
// Substitute template name with template id.
$record['template'] = array_search($record['template'], $this->templates);
}
if (isset($record['template']) && !array_key_exists($record['template'], $this->templates)) {
throw new moodle_exception('cannotfindsurveytmpt', 'survey');
}
// Add default values for survey.
if (!isset($record['template'])) {
reset($this->templates);
$record['template'] = key($this->templates);
}
return parent::create_instance($record, (array)$options);
}
}
+97
View File
@@ -0,0 +1,97 @@
<?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_survey;
/**
* Genarator tests class for mod_survey.
*
* @package mod_survey
* @category test
* @copyright 2013 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class generator_test extends \advanced_testcase {
/**
* Setup testcase.
*/
public function setUp(): void {
// Survey module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('survey', 1);
}
public function test_create_instance(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$this->assertFalse($DB->record_exists('survey', array('course' => $course->id)));
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course));
$records = $DB->get_records('survey', array('course' => $course->id), 'id');
$this->assertEquals(1, count($records));
$this->assertTrue(array_key_exists($survey->id, $records));
$params = array('course' => $course->id, 'name' => 'Another survey');
$survey = $this->getDataGenerator()->create_module('survey', $params);
$records = $DB->get_records('survey', array('course' => $course->id), 'id');
$this->assertEquals(2, count($records));
$this->assertEquals('Another survey', $records[$survey->id]->name);
}
public function test_create_instance_with_template(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$templates = $DB->get_records_menu('survey', array('template' => 0), 'name', 'id, name');
$firsttemplateid = key($templates);
// By default survey is created with the first available template.
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course));
$record = $DB->get_record('survey', array('id' => $survey->id));
$this->assertEquals($firsttemplateid, $record->template);
// Survey can be created specifying the template id.
$tmplid = array_search('ciqname', $templates);
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course,
'template' => $tmplid));
$record = $DB->get_record('survey', array('id' => $survey->id));
$this->assertEquals($tmplid, $record->template);
// Survey can be created specifying the template name instead of id.
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course,
'template' => 'collesaname'));
$record = $DB->get_record('survey', array('id' => $survey->id));
$this->assertEquals(array_search('collesaname', $templates), $record->template);
// Survey can not be created specifying non-existing template id or name.
try {
$this->getDataGenerator()->create_module('survey', array('course' => $course,
'template' => 87654));
$this->fail('Exception about non-existing numeric template is expected');
} catch (\Exception $e) {}
try {
$this->getDataGenerator()->create_module('survey', array('course' => $course,
'template' => 'nonexistingcode'));
$this->fail('Exception about non-existing string template is expected');
} catch (\Exception $e) {}
}
}
+402
View File
@@ -0,0 +1,402 @@
<?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/>.
/**
* Unit tests for mod_survey lib
*
* @package mod_survey
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
namespace mod_survey;
defined('MOODLE_INTERNAL') || die();
/**
* Unit tests for mod_survey lib
*
* @package mod_survey
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
class lib_test extends \advanced_testcase {
/**
* Prepares things before this test case is initialised
* @return void
*/
public static function setUpBeforeClass(): void {
global $CFG;
require_once($CFG->dirroot . '/mod/survey/lib.php');
}
/**
* Setup testcase.
*/
public function setUp(): void {
// Survey module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('survey', 1);
}
/**
* Test survey_view
* @return void
*/
public function test_survey_view(): void {
global $CFG;
$CFG->enablecompletion = 1;
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id),
array('completion' => 2, 'completionview' => 1));
$context = \context_module::instance($survey->cmid);
$cm = get_coursemodule_from_instance('survey', $survey->id);
// Trigger and capture the event.
$sink = $this->redirectEvents();
survey_view($survey, $course, $cm, $context, 'form');
$events = $sink->get_events();
// 2 additional events thanks to completion.
$this->assertCount(3, $events);
$event = array_shift($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_survey\event\course_module_viewed', $event);
$this->assertEquals($context, $event->get_context());
$moodleurl = new \moodle_url('/mod/survey/view.php', array('id' => $cm->id));
$this->assertEquals($moodleurl, $event->get_url());
$this->assertEquals('form', $event->other['viewed']);
$this->assertEventContextNotUsed($event);
$this->assertNotEmpty($event->get_name());
// Check completion status.
$completion = new \completion_info($course);
$completiondata = $completion->get_data($cm);
$this->assertEquals(1, $completiondata->completionstate);
}
/**
* Test survey_order_questions
*/
public function test_survey_order_questions(): void {
global $DB;
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id));
$orderedquestionids = explode(',', $survey->questions);
$surveyquestions = $DB->get_records_list("survey_questions", "id", $orderedquestionids);
$questionsordered = survey_order_questions($surveyquestions, $orderedquestionids);
// Check one by one the correct order.
for ($i = 0; $i < count($orderedquestionids); $i++) {
$this->assertEquals($orderedquestionids[$i], $questionsordered[$i]->id);
}
}
/**
* Test survey_save_answers
*/
public function test_survey_save_answers(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$course = $this->getDataGenerator()->create_course();
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id));
$context = \context_module::instance($survey->cmid);
// Build our questions and responses array.
$realquestions = array();
$questions = survey_get_questions($survey);
$i = 5;
foreach ($questions as $q) {
if ($q->type > 0) {
if ($q->multi) {
$subquestions = survey_get_subquestions($q);
foreach ($subquestions as $sq) {
$key = 'q' . $sq->id;
$realquestions[$key] = $i % 5 + 1;
$i++;
}
} else {
$key = 'q' . $q->id;
$realquestions[$key] = $i % 5 + 1;
$i++;
}
}
}
$sink = $this->redirectEvents();
survey_save_answers($survey, $realquestions, $course, $context);
// Check the stored answers, they must match.
$dbanswers = $DB->get_records_menu('survey_answers', array('survey' => $survey->id), '', 'question, answer1');
foreach ($realquestions as $key => $value) {
$id = str_replace('q', '', $key);
$this->assertEquals($value, $dbanswers[$id]);
}
// Check events.
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = array_shift($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_survey\event\response_submitted', $event);
$this->assertEquals($context, $event->get_context());
$this->assertEquals($survey->id, $event->other['surveyid']);
}
public function test_survey_core_calendar_provide_event_action(): void {
$this->resetAfterTest();
$this->setAdminUser();
// Create the activity.
$course = $this->getDataGenerator()->create_course();
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id));
// Create a calendar event.
$event = $this->create_action_event($course->id, $survey->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_survey_core_calendar_provide_event_action($event, $factory);
// Confirm the event was decorated.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
$this->assertEquals(get_string('view'), $actionevent->get_name());
$this->assertInstanceOf('moodle_url', $actionevent->get_url());
$this->assertEquals(1, $actionevent->get_item_count());
$this->assertTrue($actionevent->is_actionable());
}
public function test_survey_core_calendar_provide_event_action_for_user(): void {
global $CFG;
$this->resetAfterTest();
$this->setAdminUser();
// Create the activity.
$course = $this->getDataGenerator()->create_course();
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id));
// Create a student and enrol into the course.
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Create a calendar event.
$event = $this->create_action_event($course->id, $survey->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Now log out.
$CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
$this->setUser();
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for the student.
$actionevent = mod_survey_core_calendar_provide_event_action($event, $factory, $student->id);
// Confirm the event was decorated.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
$this->assertEquals(get_string('view'), $actionevent->get_name());
$this->assertInstanceOf('moodle_url', $actionevent->get_url());
$this->assertEquals(1, $actionevent->get_item_count());
$this->assertTrue($actionevent->is_actionable());
}
public function test_survey_core_calendar_provide_event_action_as_non_user(): void {
global $CFG;
$this->resetAfterTest();
$this->setAdminUser();
// Create the activity.
$course = $this->getDataGenerator()->create_course();
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id));
// Create a calendar event.
$event = $this->create_action_event($course->id, $survey->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Log out the user and set force login to true.
\core\session\manager::init_empty_session();
$CFG->forcelogin = true;
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_survey_core_calendar_provide_event_action($event, $factory);
// Ensure result was null.
$this->assertNull($actionevent);
}
public function test_survey_core_calendar_provide_event_action_already_completed(): void {
global $CFG;
$this->resetAfterTest();
$this->setAdminUser();
$CFG->enablecompletion = 1;
// Create the activity.
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id),
array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
// Get some additional data.
$cm = get_coursemodule_from_instance('survey', $survey->id);
// Create a calendar event.
$event = $this->create_action_event($course->id, $survey->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Mark the activity as completed.
$completion = new \completion_info($course);
$completion->set_module_viewed($cm);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_survey_core_calendar_provide_event_action($event, $factory);
// Ensure result was null.
$this->assertNull($actionevent);
}
public function test_survey_core_calendar_provide_event_action_already_completed_for_user(): void {
global $CFG;
$this->resetAfterTest();
$this->setAdminUser();
$CFG->enablecompletion = 1;
// Create the activity.
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$survey = $this->getDataGenerator()->create_module('survey', array('course' => $course->id),
array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
// Create 2 students and enrol them into the course.
$student1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
$student2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Get some additional data.
$cm = get_coursemodule_from_instance('survey', $survey->id);
// Create a calendar event.
$event = $this->create_action_event($course->id, $survey->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Mark the activity as completed for the $student1.
$completion = new \completion_info($course);
$completion->set_module_viewed($cm, $student1->id);
// Now log in as $student2.
$this->setUser($student2);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event for $student1.
$actionevent = mod_survey_core_calendar_provide_event_action($event, $factory, $student1->id);
// Ensure result was null.
$this->assertNull($actionevent);
}
/**
* Creates an action event.
*
* @param int $courseid The course id.
* @param int $instanceid The instance id.
* @param string $eventtype The event type.
* @return bool|calendar_event
*/
private function create_action_event($courseid, $instanceid, $eventtype) {
$event = new \stdClass();
$event->name = 'Calendar event';
$event->modulename = 'survey';
$event->courseid = $courseid;
$event->instance = $instanceid;
$event->type = CALENDAR_EVENT_TYPE_ACTION;
$event->eventtype = $eventtype;
$event->timestart = time();
return \calendar_event::create($event);
}
/**
* Test the callback responsible for returning the completion rule descriptions.
* This function should work given either an instance of the module (cm_info), such as when checking the active rules,
* or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type.
*/
public function test_mod_survey_completion_get_active_rule_descriptions(): void {
$this->resetAfterTest();
$this->setAdminUser();
// Two activities, both with automatic completion. One has the 'completionsubmit' rule, one doesn't.
$course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]);
$survey1 = $this->getDataGenerator()->create_module('survey', [
'course' => $course->id,
'completion' => 2,
'completionsubmit' => 1,
]);
$survey2 = $this->getDataGenerator()->create_module('survey', [
'course' => $course->id,
'completion' => 2,
'completionsubmit' => 0,
]);
$cm1 = \cm_info::create(get_coursemodule_from_instance('survey', $survey1->id));
$cm2 = \cm_info::create(get_coursemodule_from_instance('survey', $survey2->id));
// Data for the stdClass input type.
// This type of input would occur when checking the default completion rules for an activity type, where we don't have
// any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info.
$moddefaults = new \stdClass();
$moddefaults->customdata = ['customcompletionrules' => ['completionsubmit' => 1]];
$moddefaults->completion = 2;
$activeruledescriptions = [get_string('completionsubmit', 'survey')];
$this->assertEquals(mod_survey_get_completion_active_rule_descriptions($cm1), $activeruledescriptions);
$this->assertEquals(mod_survey_get_completion_active_rule_descriptions($cm2), []);
$this->assertEquals(mod_survey_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions);
$this->assertEquals(mod_survey_get_completion_active_rule_descriptions(new \stdClass()), []);
}
}
+533
View File
@@ -0,0 +1,533 @@
<?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/>.
/**
* Data provider tests.
*
* @package mod_survey
* @category test
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_survey\privacy;
defined('MOODLE_INTERNAL') || die();
global $CFG;
use core_privacy\tests\provider_testcase;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
use mod_survey\privacy\provider;
require_once($CFG->dirroot . '/mod/survey/lib.php');
/**
* Data provider testcase class.
*
* @package mod_survey
* @category test
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends provider_testcase {
public function setUp(): void {
global $PAGE;
$this->resetAfterTest();
$PAGE->get_renderer('core');
// Survey module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('survey', 1);
}
public function test_get_contexts_for_userid(): void {
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$cm1a = $dg->create_module('survey', ['template' => 1, 'course' => $c1]);
$cm1b = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
$cm1c = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
$cm2a = $dg->create_module('survey', ['template' => 1, 'course' => $c2]);
$cm2b = $dg->create_module('survey', ['template' => 1, 'course' => $c2]);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$this->create_answer($cm1a->id, 1, $u1->id);
$this->create_answer($cm1a->id, 1, $u2->id);
$this->create_answer($cm1b->id, 1, $u2->id);
$this->create_answer($cm2a->id, 1, $u1->id);
$this->create_analysis($cm2b->id, $u1->id);
$this->create_analysis($cm1c->id, $u2->id);
$contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
$this->assertCount(3, $contextids);
$this->assertTrue(in_array(\context_module::instance($cm1a->cmid)->id, $contextids));
$this->assertTrue(in_array(\context_module::instance($cm2a->cmid)->id, $contextids));
$this->assertTrue(in_array(\context_module::instance($cm2b->cmid)->id, $contextids));
$contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
$this->assertCount(3, $contextids);
$this->assertTrue(in_array(\context_module::instance($cm1a->cmid)->id, $contextids));
$this->assertTrue(in_array(\context_module::instance($cm1b->cmid)->id, $contextids));
$this->assertTrue(in_array(\context_module::instance($cm1c->cmid)->id, $contextids));
}
/**
* Test for provider::test_get_users_in_context().
*/
public function test_get_users_in_context(): void {
$dg = $this->getDataGenerator();
$component = 'mod_survey';
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$cm1a = $dg->create_module('survey', ['template' => 1, 'course' => $c1]);
$cm1b = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
$cm2 = $dg->create_module('survey', ['template' => 1, 'course' => $c2]);
$cm1acontext = \context_module::instance($cm1a->cmid);
$cm1bcontext = \context_module::instance($cm1b->cmid);
$cm2context = \context_module::instance($cm2->cmid);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$bothusers = [$u1->id, $u2->id];
sort($bothusers);
$this->create_answer($cm1a->id, 1, $u1->id);
$this->create_answer($cm1b->id, 1, $u1->id);
$this->create_answer($cm1b->id, 1, $u2->id);
$this->create_answer($cm2->id, 1, $u2->id);
$this->create_analysis($cm2->id, $u1->id);
// Cm1a should only contain u1.
$userlist = new \core_privacy\local\request\userlist($cm1acontext, $component);
provider::get_users_in_context($userlist);
$this->assertCount(1, $userlist);
$this->assertEquals([$u1->id], $userlist->get_userids());
// Cm1b should contain u1 and u2 (both have answers).
$userlist = new \core_privacy\local\request\userlist($cm1bcontext, $component);
provider::get_users_in_context($userlist);
$this->assertCount(2, $userlist);
$actual = $userlist->get_userids();
sort($actual);
$this->assertEquals($bothusers, $actual);
// Cm2 should contain u1 (analysis) and u2 (answer).
$userlist = new \core_privacy\local\request\userlist($cm2context, $component);
provider::get_users_in_context($userlist);
$this->assertCount(2, $userlist);
$actual = $userlist->get_userids();
sort($actual);
$this->assertEquals($bothusers, $actual);
}
public function test_delete_data_for_all_users_in_context(): void {
global $DB;
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$cm1a = $dg->create_module('survey', ['template' => 1, 'course' => $c1]);
$cm1b = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
$cm1c = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$this->create_answer($cm1a->id, 1, $u1->id);
$this->create_answer($cm1a->id, 1, $u2->id);
$this->create_answer($cm1b->id, 1, $u2->id);
$this->create_answer($cm1c->id, 1, $u1->id);
$this->create_analysis($cm1a->id, $u1->id);
$this->create_analysis($cm1b->id, $u1->id);
$this->create_analysis($cm1a->id, $u2->id);
$this->create_analysis($cm1c->id, $u2->id);
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
// Deleting the course does nothing.
provider::delete_data_for_all_users_in_context(\context_course::instance($c1->id));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
provider::delete_data_for_all_users_in_context(\context_module::instance($cm1c->cmid));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
provider::delete_data_for_all_users_in_context(\context_module::instance($cm1a->cmid));
$this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
$this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
$this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
$this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
}
public function test_delete_data_for_user(): void {
global $DB;
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$cm1a = $dg->create_module('survey', ['template' => 1, 'course' => $c1]);
$cm1b = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
$cm1c = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$this->create_answer($cm1a->id, 1, $u1->id);
$this->create_answer($cm1a->id, 1, $u2->id);
$this->create_answer($cm1b->id, 1, $u2->id);
$this->create_answer($cm1c->id, 1, $u1->id);
$this->create_analysis($cm1a->id, $u1->id);
$this->create_analysis($cm1b->id, $u1->id);
$this->create_analysis($cm1a->id, $u2->id);
$this->create_analysis($cm1c->id, $u2->id);
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
provider::delete_data_for_user(new approved_contextlist($u1, 'mod_survey', [
\context_course::instance($c1->id)->id,
\context_module::instance($cm1a->cmid)->id,
\context_module::instance($cm1b->cmid)->id,
]));
$this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
$this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
}
/**
* Test for provider::delete_data_for_users().
*/
public function test_delete_data_for_users(): void {
global $DB;
$dg = $this->getDataGenerator();
$component = 'mod_survey';
$c1 = $dg->create_course();
$cm1a = $dg->create_module('survey', ['template' => 1, 'course' => $c1]);
$cm1b = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
$cm1c = $dg->create_module('survey', ['template' => 2, 'course' => $c1]);
$cm1acontext = \context_module::instance($cm1a->cmid);
$cm1bcontext = \context_module::instance($cm1b->cmid);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$this->create_answer($cm1a->id, 1, $u1->id);
$this->create_answer($cm1a->id, 1, $u2->id);
$this->create_analysis($cm1a->id, $u1->id);
$this->create_analysis($cm1a->id, $u2->id);
$this->create_answer($cm1b->id, 1, $u2->id);
$this->create_analysis($cm1b->id, $u1->id);
$this->create_answer($cm1c->id, 1, $u1->id);
$this->create_analysis($cm1c->id, $u2->id);
// Confirm data exists before deletion.
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
// Ensure only approved user data is deleted.
$approveduserids = [$u1->id];
$approvedlist = new approved_userlist($cm1acontext, $component, $approveduserids);
provider::delete_data_for_users($approvedlist);
$this->assertFalse($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertFalse($DB->record_exists('survey_analysis', ['userid' => $u1->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1a->id]));
$approveduserids = [$u1->id, $u2->id];
$approvedlist = new approved_userlist($cm1bcontext, $component, $approveduserids);
provider::delete_data_for_users($approvedlist);
$this->assertFalse($DB->record_exists('survey_answers', ['survey' => $cm1b->id]));
$this->assertFalse($DB->record_exists('survey_analysis', ['survey' => $cm1b->id]));
$this->assertTrue($DB->record_exists('survey_answers', ['userid' => $u1->id, 'survey' => $cm1c->id]));
$this->assertTrue($DB->record_exists('survey_analysis', ['userid' => $u2->id, 'survey' => $cm1c->id]));
}
public function test_export_data_for_user(): void {
global $DB;
$dg = $this->getDataGenerator();
$templates = $DB->get_records_menu('survey', array('template' => 0), 'name', 'name, id');
$c1 = $dg->create_course();
$s1a = $dg->create_module('survey', ['template' => $templates['attlsname'], 'course' => $c1]);
$s1b = $dg->create_module('survey', ['template' => $templates['ciqname'], 'course' => $c1]);
$s1c = $dg->create_module('survey', ['template' => $templates['collesapname'], 'course' => $c1]);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$s1actx = \context_module::instance($s1a->cmid);
$s1bctx = \context_module::instance($s1b->cmid);
$s1cctx = \context_module::instance($s1c->cmid);
$this->answer_survey($s1a, $u1, $c1, $s1actx);
$this->answer_survey($s1b, $u1, $c1, $s1bctx);
$this->create_analysis($s1a->id, $u1->id, 'Hello,');
$this->answer_survey($s1a, $u2, $c1, $s1actx);
$this->answer_survey($s1c, $u2, $c1, $s1cctx);
$this->create_analysis($s1b->id, $u2->id, 'World!');
provider::export_user_data(new approved_contextlist($u1, 'mod_survey', [$s1actx->id, $s1bctx->id, $s1cctx->id]));
$data = writer::with_context($s1actx)->get_data([]);
$this->assertNotEmpty($data);
$this->assert_exported_answers($data->answers, $u1, $s1a);
$data = writer::with_context($s1actx)->get_related_data([], 'survey_analysis');
$this->assertEquals('Hello,', $data->notes);
$data = writer::with_context($s1bctx)->get_data([]);
$this->assertNotEmpty($data);
$this->assert_exported_answers($data->answers, $u1, $s1b);
$data = writer::with_context($s1bctx)->get_related_data([], 'survey_analysis');
$this->assertEmpty($data);
$data = writer::with_context($s1cctx)->get_data([]);
$this->assertEmpty($data);
$data = writer::with_context($s1cctx)->get_related_data([], 'survey_analysis');
$this->assertEmpty($data);
writer::reset();
provider::export_user_data(new approved_contextlist($u2, 'mod_survey', [$s1actx->id, $s1bctx->id, $s1cctx->id]));
$data = writer::with_context($s1actx)->get_data([]);
$this->assertNotEmpty($data);
$this->assert_exported_answers($data->answers, $u2, $s1a);
$data = writer::with_context($s1actx)->get_related_data([], 'survey_analysis');
$this->assertEmpty($data);
$data = writer::with_context($s1bctx)->get_data([]);
$this->assertEmpty($data);
$data = writer::with_context($s1bctx)->get_related_data([], 'survey_analysis');
$this->assertEquals('World!', $data->notes);
$data = writer::with_context($s1cctx)->get_data([]);
$this->assertNotEmpty($data);
$this->assert_exported_answers($data->answers, $u2, $s1c);
$data = writer::with_context($s1cctx)->get_related_data([], 'survey_analysis');
$this->assertEmpty($data);
}
/**
* Answer a survey in a predictable manner.
*
* @param stdClass $survey The survey.
* @param stdClass $user The user.
* @param stdClass $course The course.
* @param context_module $context The module context.
* @return void
*/
protected function answer_survey($survey, $user, $course, \context_module $context) {
global $USER;
$userid = $user->id;
$questions = survey_get_questions($survey);
$answer = function(&$answers, $q) use ($userid) {
$key = 'q' . ($q->type == 2 ? 'P' : '') . $q->id;
if ($q->type < 1) {
$a = "A:{$q->id}:{$userid}";
$answers[$key] = $a;
} else if ($q->type < 3) {
$options = explode(',', get_string($q->options, 'mod_survey'));
$answers[$key] = ($q->id + $userid) % count($options) + 1;
} else {
$options = explode(',', get_string($q->options, 'mod_survey'));
$answers["q{$q->id}"] = ($q->id + $userid) % count($options) + 1;
$answers["qP{$q->id}"] = ($q->id + $userid + 1) % count($options) + 1;
}
};
foreach ($questions as $q) {
if ($q->type < 0) {
continue;
} else if ($q->type > 0 && $q->multi) {
$subquestions = survey_get_subquestions($q);
foreach ($subquestions as $sq) {
$answer($answers, $sq);
}
} else {
$answer($answers, $q);
}
}
$origuser = $USER;
$this->setUser($user);
survey_save_answers($survey, $answers, $course, $context);
$this->setUser($origuser);
}
/**
* Assert the answers provided to a survey.
*
* @param array $answers The answers.
* @param object $user The user.
* @param object $survey The survey.
* @return void
*/
protected function assert_exported_answers($answers, $user, $survey) {
global $DB;
$userid = $user->id;
$questionids = explode(',', $survey->questions);
$topquestions = $DB->get_records_list('survey_questions', 'id', $questionids, 'id');
$questions = [];
foreach ($topquestions as $q) {
if ($q->type < 0) {
continue;
} else if ($q->type > 0 && $q->multi) {
$questionids = explode(',', $q->multi);
$subqs = $DB->get_records_list('survey_questions', 'id', $questionids, 'id');
} else {
$subqs = [$q];
}
foreach ($subqs as $sq) {
$questions[] = $sq;
}
}
$this->assertCount(count($questions), $answers);
$answer = reset($answers);
foreach ($questions as $question) {
$qtype = $question->type;
$question = survey_translate_question($question);
$options = $qtype > 0 ? explode(',', $question->options) : '-';
$this->assertEquals($question->text, $answer['question']['text']);
$this->assertEquals($question->shorttext, $answer['question']['shorttext']);
$this->assertEquals($question->intro, $answer['question']['intro']);
$this->assertEquals($options, $answer['question']['options']);
if ($qtype < 1) {
$this->assertEquals("A:{$question->id}:{$userid}", $answer['answer']['actual']);
} else if ($qtype == 1 || $qtype == 2) {
$chosen = ($question->id + $userid) % count($options);
$key = $qtype == 1 ? 'actual' : 'preferred';
$this->assertEquals($options[$chosen], $answer['answer'][$key]);
} else {
$chosen = ($question->id + $userid) % count($options);
$this->assertEquals($options[$chosen], $answer['answer']['actual']);
$chosen = ($question->id + $userid + 1) % count($options);
$this->assertEquals($options[$chosen], $answer['answer']['preferred']);
}
// Grab next answer, if any.
$answer = next($answers);
}
}
/**
* Create analysis.
*
* @param int $surveyid The survey ID.
* @param int $userid The user ID.
* @param string $notes The nodes.
* @return stdClass
*/
protected function create_analysis($surveyid, $userid, $notes = '') {
global $DB;
$record = (object) [
'survey' => $surveyid,
'userid' => $userid,
'notes' => $notes
];
$record->id = $DB->insert_record('survey_analysis', $record);
return $record;
}
/**
* Create answer.
*
* @param int $surveyid The survey ID.
* @param int $questionid The question ID.
* @param int $userid The user ID.
* @param string $answer1 The first answer field.
* @param string $answer2 The second answer field.
* @return stdClass
*/
protected function create_answer($surveyid, $questionid, $userid, $answer1 = '', $answer2 = '') {
global $DB;
$record = (object) [
'survey' => $surveyid,
'question' => $questionid,
'userid' => $userid,
'answer1' => $answer1,
'answer2' => $answer2,
'time' => time()
];
$record->id = $DB->insert_record('survey_answers', $record);
return $record;
}
}
+84
View File
@@ -0,0 +1,84 @@
<?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/>.
/**
* Unit test for mod_survey searching.
*
* This is needed because the activity.php class overrides default behaviour.
*
* @package mod_survey
* @category test
* @copyright 2017 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_survey\search;
/**
* Unit test for mod_survey searching.
*
* This is needed because the activity.php class overrides default behaviour.
*
* @package mod_survey
* @category test
* @copyright 2017 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class search_test extends \advanced_testcase {
/**
* Setup testcase.
*/
public function setUp(): void {
// Survey module is disabled by default, enable it for testing.
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
$manager::enable_plugin('survey', 1);
}
/**
* Test survey_view
* @return void
*/
public function test_survey_indexing(): void {
global $CFG;
$this->resetAfterTest();
require_once($CFG->dirroot . '/search/tests/fixtures/testable_core_search.php');
\testable_core_search::instance();
$area = \core_search\manager::get_search_area('mod_survey-activity');
// Setup test data.
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$survey1 = $generator->create_module('survey', ['course' => $course->id]);
$survey2 = $generator->create_module('survey', ['course' => $course->id]);
// Get all surveys for indexing - note that there are special entries in the table with
// course zero which should not be returned.
$rs = $area->get_document_recordset();
$this->assertEquals(2, iterator_count($rs));
$rs->close();
// Test specific context and course context.
$rs = $area->get_document_recordset(0, \context_module::instance($survey1->cmid));
$this->assertEquals(1, iterator_count($rs));
$rs->close();
$rs = $area->get_document_recordset(0, \context_course::instance($course->id));
$this->assertEquals(2, iterator_count($rs));
$rs->close();
}
}