Commit 7f723723 authored by 0815-xyz's avatar 0815-xyz
Browse files

Initial commit: Transfer from MOODLE_404_KNIGHT

parents
{{!
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/>.
}}
{{!
@template mod_adaptivequiz/attempt_progress
Indicator of how many questions are answered out of the maximum number set for the attempt.
Variables required for this template:
* questionsanswerednumber - number of question already answered during the attempt
* maximumquestionsnumber - number of maximum questions set for the quiz in activity settings
* showprogressbar - whether a bar depicting the progress should be shown
* percentprogressbarfilled - percent of questions already answered out of maximum number during the attempt. Optional, but
should be present when 'showprogressbar' is present also
* helpiconcontent - already rendered help icon, optional.
Example context (json):
{
"questionsanswerednumber": "23",
"maximumquestionsnumber": "50",
"showprogressbar": true,
"percentprogressbarfilled": "46",
"helpiconcontent": "<a class='btn ..'><i class='icon fa fa-question-circle ..'></i></a>"
}
}}
<div class="attempt-progress">
<h3 class="no-out-of">
{{#str}} attemptquestionsprogress, adaptivequiz, {{questionsanswerednumber}} / {{maximumquestionsnumber}} {{/str}}
{{{helpiconcontent}}}
</h3>
{{#showprogressbar}}
<div class="progress-bar-wrapper">
<div class="bg-primary progress-bar-inner" style="width: {{percentprogressbarfilled}}%">&nbsp;</div>
</div>
{{/showprogressbar}}
</div>
{{!
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/>.
}}
{{!
@template mod_adaptivequiz/attempt_report_chart
This is a copy of core/chart.
The purpose of copying is to enable custom initialization of the chart, as not all the config options can be passed through
the chart renderable objects. Thus, the js section is implemented as a block to allow overriding in specific charts templates.
See core/chart for the required context.
}}
<div class="chart-area" id="chart-area-{{uniqid}}">
<div class="chart-image" role="presentation" aria-describedby="chart-table-data-{{uniqid}}"></div>
<div class="chart-table {{^withtable}}accesshide{{/withtable}}">
<p class="chart-table-expand">
<a href="#" aria-controls="chart-table-data-{{uniqid}}" role="button">
{{#str}}showchartdata, moodle{{/str}}
</a>
</p>
<div class="chart-table-data" id="chart-table-data-{{uniqid}}" {{#withtable}}role="complementary" aria-expanded="false"{{/withtable}}></div>
</div>
</div>
{{$initjs}}
{{#js}}
require([
'jquery',
'core/chart_builder',
'core/chart_output_chartjs',
'core/chart_output_htmltable',
], function(
$,
Builder,
Output,
OutputTable
) {
var data = {{{chartdata}}},
uniqid = "{{uniqid}}",
chartArea = $('#chart-area-' + uniqid),
chartImage = chartArea.find('.chart-image'),
chartTable = chartArea.find('.chart-table-data'),
chartLink = chartArea.find('.chart-table-expand a');
Builder.make(data).then(function(ChartInst) {
new Output(chartImage, ChartInst);
new OutputTable(chartTable, ChartInst);
});
chartLink.on('click', function(e) {
e.preventDefault();
if (chartTable.is(':visible')) {
chartTable.hide();
chartLink.text({{#quote}}{{#str}}showchartdata, moodle{{/str}}{{/quote}});
chartTable.attr('aria-expanded', false);
} else {
chartTable.show();
chartLink.text({{#quote}}{{#str}}hidechartdata, moodle{{/str}}{{/quote}});
chartTable.attr('aria-expanded', true);
}
});
});
{{/js}}
{{/initjs}}
{{!
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/>.
}}
{{!
@template mod_adaptivequiz/report/individual_user_attempt_actions
Set of actions for a user attempt in the report's column.
Classes required for JS:
* none
Context variables required for this template:
* actions - array of actions to be rendered as action links, each action contain the following elements:
- url: action URL
- icon: rendered icon to depict the action, serves as content of the action link
- title: title for the action link tag
Example context (json):
{
"actions": [
{
"url": "http://examplemoodle.org/mod/adaptivequiz/action.php?attempt=5",
"icon":
"title": "Some action"
}
]
}
}}
{{#actions}}
<a href="{{url}}" title="{{title}}">{{{icon}}}</a>
{{/actions}}
<?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_adaptivequiz;
use advanced_testcase;
use cm_info;
use context_module;
use mod_adaptivequiz\completion\custom_completion;
use mod_adaptivequiz\event\attempt_completed;
use mod_adaptivequiz\local\attempt\attempt_state;
use stdClass;
/**
* Tests observers of the attempt state change.
*
* @package mod_adaptivequiz
* @copyright 2022 Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* @covers \mod_adaptivequiz\attempt_state_change_observers::attempt_completed
*/
class attempt_state_change_observers_test extends advanced_testcase {
public function test_it_handles_completion_state(): void {
global $DB;
$this->resetAfterTest();
// Test it can set the activity as completed.
$course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
$questioncategory = $this->getDataGenerator()
->get_plugin_generator('core_question')
->create_question_category(['name' => 'My category']);
$adaptivequiz = $this->getDataGenerator()
->get_plugin_generator('mod_adaptivequiz')
->create_instance([
'course' => $course->id,
'completion' => 1,
'completionattemptcompleted' => 1,
'questionpool' => [$questioncategory->id],
]);
$user = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', ['shortname' => 'student']);
$this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
// We don't have any attempt generation yet. Set random data manually.
$attemptrecordsnapshot = new stdClass();
$attemptrecordsnapshot->id = 1;
$attemptrecordsnapshot->instance = $adaptivequiz->id;
$attemptrecordsnapshot->userid = $user->id;
$attemptrecordsnapshot->uniqueid = 1;
$attemptrecordsnapshot->attemptstate = attempt_state::IN_PROGRESS;
$attemptrecordsnapshot->attemptstopcriteria = 'Unable to fetch a questions for level 1';
$attemptrecordsnapshot->questionsattempted = 1;
$attemptrecordsnapshot->difficultysum = 0.0000000;
$attemptrecordsnapshot->standarderror = 1.51186;
$attemptrecordsnapshot->measure = 1.94591;
$attemptrecordsnapshot->timecreated = 1658524979;
$attemptrecordsnapshot->timemodified = 1658525029;
$cm = get_coursemodule_from_instance('adaptivequiz', $adaptivequiz->id, $adaptivequiz->course);
$context = context_module::instance($cm->id);
$attemptid = 1;
$event = attempt_completed::create([
'objectid' => $attemptid,
'context' => $context,
'userid' => $user->id,
]);
$event->add_record_snapshot('adaptivequiz_attempt', $attemptrecordsnapshot);
$event->add_record_snapshot('adaptivequiz', $adaptivequiz);
attempt_state_change_observers::attempt_completed($event);
$completion = new custom_completion(cm_info::create($cm), $user->id);
$this->assertEquals(COMPLETION_COMPLETE, $completion->get_overall_completion_state());
}
}
@mod @mod_adaptivequiz
Feature: Adaptive quiz content
In order to take a quiz with the CAT (Computer Adaptive Testing) algorithm
As a student
I need the quiz to adjust the questions sequence with accordance to CAT
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | John | The Teacher | johntheteacher@example.com |
| student1 | Peter | The Student | peterthestudent@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Adaptive Quiz Questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | answer |
| Adaptive Quiz Questions | truefalse | Q1 | Question 1 (difficulty 1). | True |
| Adaptive Quiz Questions | truefalse | Q2 | Question 2 (difficulty 1). | True |
| Adaptive Quiz Questions | truefalse | Q3 | Question 3 (difficulty 2). | True |
| Adaptive Quiz Questions | truefalse | Q4 | Question 4 (difficulty 2). | True |
| Adaptive Quiz Questions | truefalse | Q5 | Question 5 (difficulty 3). | True |
| Adaptive Quiz Questions | truefalse | Q6 | Question 6 (difficulty 3). | True |
| Adaptive Quiz Questions | truefalse | Q7 | Question 7 (difficulty 4). | True |
| Adaptive Quiz Questions | truefalse | Q8 | Question 8 (difficulty 4). | True |
| Adaptive Quiz Questions | truefalse | Q9 | Question 9 (difficulty 5). | True |
| Adaptive Quiz Questions | truefalse | Q10 | Question 10 (difficulty 5). | True |
And the following "core_question > Tags" exist:
| question | tag |
| Q1 | adpq_1 |
| Q2 | adpq_1 |
| Q3 | adpq_2 |
| Q4 | adpq_2 |
| Q5 | adpq_3 |
| Q6 | adpq_3 |
| Q7 | adpq_4 |
| Q8 | adpq_4 |
| Q9 | adpq_5 |
| Q10 | adpq_5 |
@javascript
Scenario: 20% standard error, user performs 1 level above the starting level
Given the following "activity" exists:
| activity | adaptivequiz |
| idnumber | adaptivequiz1 |
| course | C1 |
| name | Adaptive Quiz |
| startinglevel | 2 |
| lowestlevel | 1 |
| highestlevel | 5 |
| minimumquestions | 1 |
| maximumquestions | 10 |
| standarderror | 20 |
| questionpoolnamed | Adaptive Quiz Questions |
When I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
Then I should see " (difficulty 2)."
And I click on "True" "radio"
And I press "Submit answer"
And I should see " (difficulty 4)."
And I click on "False" "radio"
And I press "Submit answer"
And I should see " (difficulty 3)."
And I click on "True" "radio"
And I press "Submit answer"
And I should see " (difficulty 4)."
And I click on "False" "radio"
And I press "Submit answer"
And I should see " (difficulty 3)."
And I click on "False" "radio"
And I press "Submit answer"
And I should see " (difficulty 2)."
And I click on "True" "radio"
And I press "Submit answer"
And "Continue" "button" should be visible
@javascript
Scenario: 20% standard error, user performs on the lowest level
Given the following "activity" exists:
| activity | adaptivequiz |
| idnumber | adaptivequiz1 |
| course | C1 |
| name | Adaptive Quiz |
| startinglevel | 2 |
| lowestlevel | 1 |
| highestlevel | 5 |
| minimumquestions | 1 |
| maximumquestions | 10 |
| standarderror | 20 |
| questionpoolnamed | Adaptive Quiz Questions |
When I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
Then I should see " (difficulty 2)."
And I click on "False" "radio"
And I press "Submit answer"
And I should see " (difficulty 1)."
And I click on "False" "radio"
And I press "Submit answer"
And I should see " (difficulty 1)."
And I click on "False" "radio"
And I press "Submit answer"
And I should see " (difficulty 2)."
And I click on "False" "radio"
And I press "Submit answer"
And "Continue" "button" should be visible
@javascript
Scenario: 20% standard error, user performs on the highest level
Given the following "activity" exists:
| activity | adaptivequiz |
| idnumber | adaptivequiz1 |
| course | C1 |
| name | Adaptive Quiz |
| startinglevel | 2 |
| lowestlevel | 1 |
| highestlevel | 5 |
| minimumquestions | 1 |
| maximumquestions | 10 |
| standarderror | 20 |
| questionpoolnamed | Adaptive Quiz Questions |
When I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
Then I should see " (difficulty 2)."
And I click on "True" "radio"
And I press "Submit answer"
And I should see " (difficulty 4)."
And I click on "True" "radio"
And I press "Submit answer"
And I should see " (difficulty 5)."
And I click on "True" "radio"
And I press "Submit answer"
And I should see " (difficulty 5)."
And I click on "True" "radio"
And I press "Submit answer"
And I should see " (difficulty 4)."
And I click on "True" "radio"
And I press "Submit answer"
And "Continue" "button" should be visible
@mod @mod_adaptivequiz
Feature: Add an adaptive quiz
In order to evaluate students using an adaptive questions strategy
As a teacher
I need to add an adaptive quiz activity to a course
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | John | The Teacher | johntheteacher@example.com |
| student1 | Peter | The Student | peterthestudent@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Adaptive Quiz Questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Adaptive Quiz Questions | truefalse | TF1 | First question. |
| Adaptive Quiz Questions | truefalse | TF2 | Second question. |
| Adaptive Quiz Questions | truefalse | TF3 | Third question. |
| Adaptive Quiz Questions | truefalse | TF4 | Fourth question. |
@javascript
Scenario: Add an adaptive quiz to a course to be visible to a student
When the following "core_question > Tags" exist:
| question | tag |
| TF1 | adpq_1 |
And I log in as "teacher1"
And I add a "adaptivequiz" activity to course "Course 1" section "1" and I fill the form with:
| Name | Adaptive Quiz |
| Description | Adaptive quiz description. |
| Question pool | Adaptive Quiz Questions (4) |
| Starting level of difficulty | 1 |
| Lowest level of difficulty | 1 |
| Highest level of difficulty | 2 |
| Minimum number of questions | 1 |
| Maximum number of questions | 2 |
| Standard Error to stop | 25 |
| ID number | adaptivequiz1 |
And I log out
And I am on the "adaptivequiz1" "Activity" page logged in as "student1"
Then "Start attempt" "link" should exist
@javascript
Scenario: It is impossible to create an adaptive quiz without a properly tagged question for the starting level of difficulty
When the following "core_question > Tags" exist:
| question | tag |
| TF1 | adpq_001 |
| TF2 | adpq_2 |
| TF3 | truefalse_1 |
| TF3 | TF |
And I log in as "teacher1"
And I add a "adaptivequiz" activity to course "Course 1" section "1" and I fill the form with:
| Name | Adaptive Quiz |
| Description | Adaptive quiz description. |
| Question pool | Adaptive Quiz Questions (4) |
| Starting level of difficulty | 1 |
| Lowest level of difficulty | 1 |
| Highest level of difficulty | 2 |
| Minimum number of questions | 1 |
| Maximum number of questions | 2 |
| Standard Error to stop | 25 |
Then I should see "The selected questions categories do not contain questions which are properly tagged to match the selected starting level of difficulty."
@mod @mod_adaptivequiz
Feature: Attempt an adaptive quiz
In order to demonstrate what I know using the adaptive quiz strategy
As a student
I need to be able to attempt an adaptive quiz
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | John | The Teacher | johntheteacher@example.com |
| student1 | Peter | The Student | peterthestudent@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Adaptive Quiz Questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Adaptive Quiz Questions | truefalse | Q1 | First question |
| Adaptive Quiz Questions | truefalse | Q2 | Second question |
And the following "core_question > Tags" exist:
| question | tag |
| Q1 | adpq_1 |
| Q2 | adpq_2 |
And the following "activity" exists:
| activity | adaptivequiz |
| idnumber | adaptivequiz1 |
| course | C1 |
| name | Adaptive Quiz |
| startinglevel | 1 |
| lowestlevel | 1 |
| highestlevel | 2 |
| minimumquestions | 1 |
| maximumquestions | 2 |
| standarderror | 25 |
| questionpoolnamed | Adaptive Quiz Questions |
| attempts | 1 |
@javascript
Scenario: Attempt an adaptive quiz
When I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
Then I should see "First question"
@javascript
Scenario: A student cannot attempt an adaptive quiz if no more attempts are allowed
Given I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
When I am on the "adaptivequiz1" "Activity" page
Then "Start attempt" "link" should not be visible
And I should see "No more attempts allowed at this activity"
@javascript
Scenario: Return to a started attempt
Given the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Adaptive Quiz Questions | truefalse | Q3 | Third question |
| Adaptive Quiz Questions | truefalse | Q4 | Fourth question |
And the following "core_question > Tags" exist:
| question | tag |
| Q3 | adpq_2 |
| Q4 | adpq_3 |
And I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
And I click on "Settings" "link"
And I set the following fields to these values:
| Highest level of difficulty | 3 |
| Minimum number of questions | 1 |
| Maximum number of questions | 3 |
And I click on "Save and return to course" "button"
And I log out
When I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio"
And I press "Submit answer"
And I am on the "adaptivequiz1" "Activity" page
And I click on "Start attempt" "link"
And I click on "True" "radio"
And I press "Submit answer"
Then I should see "Fourth question"
@mod @mod_adaptivequiz
Feature: Delete an attempt on adaptive quiz
In order to keep the results of adaptive quiz relevant
As a teacher
I need to be able to delete students' attempts
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | John | The Teacher | johntheteacher@example.com |
| student1 | Peter | The Student | peterthestudent@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Adaptive Quiz Questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Adaptive Quiz Questions | truefalse | TF1 | First question |
| Adaptive Quiz Questions | truefalse | TF2 | Second question |
And the following "core_question > Tags" exist:
| question | tag |
| TF1 | adpq_2 |
| TF2 | adpq_3 |
And the following "activity" exists:
| activity | adaptivequiz |
| idnumber | adaptivequiz1 |
| course | C1 |
| name | Adaptive Quiz |
| startinglevel | 2 |
| lowestlevel | 1 |
| highestlevel | 10 |
| minimumquestions | 2 |
| maximumquestions | 20 |
| standarderror | 5 |
| questionpoolnamed | Adaptive Quiz Questions |
And I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
And I log out
@javascript
Scenario: Delete an individual attempt
When I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
And I click on "1" "link" in the "Peter The Student" "table_row"
And I click on "Delete attempt" "link" in the "Completed" "table_row"
And I press "Continue"
And I should see "Nothing to display"
@mod @mod_adaptivequiz
Feature: Attempt feedback
In order to get inspired and engaged
As a student
I want to get feedback on my attempts on adaptive quiz and ability estimation if I'm allowed to
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | John | The Teacher | johntheteacher@example.com |
| student1 | Peter | The Student | peterthestudent@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Adaptive Quiz Questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | answer |
| Adaptive Quiz Questions | truefalse | Q1 | First question | True |
| Adaptive Quiz Questions | truefalse | Q2 | Second question | True |
And the following "core_question > Tags" exist:
| question | tag |
| Q1 | adpq_1 |
| Q2 | adpq_2 |
And the following "activity" exists:
| activity | adaptivequiz |
| idnumber | adaptivequiz1 |
| course | C1 |
| name | Adaptive Quiz |
| startinglevel | 1 |
| lowestlevel | 1 |
| highestlevel | 2 |
| minimumquestions | 1 |
| maximumquestions | 2 |
| standarderror | 20 |
| questionpoolnamed | Adaptive Quiz Questions |
| showabilitymeasure | 1 |
@javascript
Scenario: Get default textual feedback after an attempt is finished
When I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
Then I should see "You've finished the attempt, thank you for taking the quiz!"
@javascript
Scenario: Get customized textual feedback after an attempt is finished
Given I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Attempt feedback | Thank you for taking the test! |
And I click on "Save and return to course" "button"
And I log out
When I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
Then I should see "Thank you for taking the test!"
@javascript
Scenario: Get estimated ability after an attempt is finished
When I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
Then I should see "Estimated ability: 1.7 / 1 - 2"
@javascript
Scenario: View attempt summary with estimated ability for the only allowed attempt
Given I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Attempts allowed | 1 |
And I click on "Save and return to course" "button"
And I log out
When I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
Then I should see "Attempt Summary"
And "attemptsummarytable" "table" should exist
And I should see "Completed" in the "#attemptstatecell" "css_element"
And I should see "1.7 / 1 - 2" in the "#abilitymeasurecell" "css_element"
@javascript
Scenario: View attempts summary with estimated ability for several attempts
Given I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
When I am on the "adaptivequiz1" "Activity" page
Then I should see "Your previous attempts"
And "userattemptstable" "table" should exist
And I should see "Estimated ability / 1 - 2" in the "th.abilitymeasurecol" "css_element"
And I should see "Completed" in the "#userattemptstable_r0 td.statecol" "css_element"
And I should see "Completed" in the "#userattemptstable_r1 td.statecol" "css_element"
And I should see "1.7" in the "#userattemptstable_r0 td.abilitymeasurecol" "css_element"
And I should see "1.7" in the "#userattemptstable_r1 td.abilitymeasurecol" "css_element"
@javascript
Scenario: Estimated ability after an attempt is finished is not visible when set accordingly
Given I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Show ability measure to students | No |
And I click on "Save and return to course" "button"
And I log out
When I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
Then I should not see "Estimated ability: 1.7 / 1 - 2"
@javascript
Scenario: Estimated ability for the only allowed attempt is not visible for a student when set accordingly
Given I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Attempts allowed | 1 |
| Show ability measure to students | No |
And I click on "Save and return to course" "button"
And I log out
And I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
When I am on the "adaptivequiz1" "Activity" page
Then "#abilitymeasurecell" "css_element" should not exist
@javascript
Scenario: Estimated ability is not visible for a student in attempts summary when set accordingly
Given I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Show ability measure to students | No |
And I click on "Save and return to course" "button"
And I log out
And I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
When I am on the "adaptivequiz1" "Activity" page
Then ".abilitymeasurecol" "css_element" should not exist
@mod @mod_adaptivequiz
Feature: Set activity as completed when at least one attempt is completed
In order to control whether the activity has been complete by students
As a teacher
I need the activity to be marked as completed for a student when they have made at least one attempt on the adaptive quiz
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | John | The Teacher | johntheteacher@example.com |
| student1 | Peter | The Student | peterthestudent@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 the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Adaptive Quiz Questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | answer |
| Adaptive Quiz Questions | truefalse | TF1 | First question | True |
| Adaptive Quiz Questions | truefalse | TF2 | Second question | True |
And the following "core_question > Tags" exist:
| question | tag |
| TF1 | adpq_2 |
| TF2 | adpq_3 |
And the following "activity" exists:
| activity | adaptivequiz |
| idnumber | adaptivequiz1 |
| course | C1 |
| name | Adaptive Quiz |
| startinglevel | 2 |
| lowestlevel | 1 |
| highestlevel | 10 |
| minimumquestions | 2 |
| maximumquestions | 20 |
| standarderror | 5 |
| questionpoolnamed | Adaptive Quiz Questions |
@javascript
Scenario: Teacher sets the completion rule and student completes an attempt
Given I am on the "Adaptive Quiz" "adaptivequiz activity editing" page logged in as teacher1
And I expand all fieldsets
And I set the following fields to these values:
| Add requirements | 1 |
| completionattemptcompleted | 1 |
And I click on "Save and return to course" "button"
And I log out
When I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
And I log out
And I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
Then "Adaptive Quiz" should have the "Complete an attempt" completion condition
And I am on "Course 1" course homepage
And I navigate to "Reports" in current page administration
And I click on "Activity completion" "link"
And "Completed" "icon" should exist in the "Peter The Student" "table_row"
@mod @mod_adaptivequiz
Feature: View analysis of questions usage in adaptive quizzes
In order to assess how items from the question bank are administered and answered in adaptive quizzes
As a teacher
I need a report with analysis of questions usage
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | John | The Teacher | johntheteacher@example.com |
| student1 | Peter | The Student | peterthestudent@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Adaptive Quiz Questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | answer |
| Adaptive Quiz Questions | truefalse | TF1 | First question | True |
| Adaptive Quiz Questions | truefalse | TF2 | Second question | True |
And the following "core_question > Tags" exist:
| question | tag |
| TF1 | adpq_2 |
| TF2 | adpq_3 |
And the following "activity" exists:
| activity | adaptivequiz |
| idnumber | adaptivequiz1 |
| course | C1 |
| name | Adaptive Quiz |
| startinglevel | 2 |
| lowestlevel | 1 |
| highestlevel | 10 |
| minimumquestions | 2 |
| maximumquestions | 20 |
| standarderror | 5 |
| questionpoolnamed | Adaptive Quiz Questions |
And I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
And I log out
@javascript
Scenario: Navigate to reviewing of an attempt listed in single question analysis
When I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
And I click on "Question Analysis" "link"
And I click on "TF1" "link"
And I click on "Review attempt" "link" in the "Peter The Student" "table_row"
Then I should see "Adaptive Quiz - reviewing attempt by Peter The Student"
@mod @mod_adaptivequiz
Feature: View students results in adaptive quiz
In order to control what results students have on attempting adaptive quizzes
As a teacher
I need an access to attempts reporting
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | John | The Teacher | johntheteacher@example.com |
| student1 | Peter | The Student | peterthestudent@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Adaptive Quiz Questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext | answer |
| Adaptive Quiz Questions | truefalse | TF1 | First question | True |
| Adaptive Quiz Questions | truefalse | TF2 | Second question | True |
And the following "core_question > Tags" exist:
| question | tag |
| TF1 | adpq_2 |
| TF2 | adpq_3 |
And the following "activity" exists:
| activity | adaptivequiz |
| idnumber | adaptivequiz1 |
| course | C1 |
| name | Adaptive Quiz |
| startinglevel | 2 |
| lowestlevel | 1 |
| highestlevel | 10 |
| minimumquestions | 2 |
| maximumquestions | 20 |
| standarderror | 5 |
| questionpoolnamed | Adaptive Quiz Questions |
And I am on the "adaptivequiz1" "Activity" page logged in as "student1"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
And I log out
@javascript
Scenario: Attempts report
When I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
Then I should see "Attempts report"
And "Peter The Student" "table_row" should exist
And "Peter The Student" row "Number of attempts" column of "usersattemptstable" table should contain "1"
@javascript
Scenario: Deleted user should not appear in the attempts report
Given the following "user" exists:
| username | student2 |
| firstname | Henry |
| lastname | The Student |
| email | henrythestudent@example.com |
And the following "course enrolment" exists:
| user | student2 |
| course | C1 |
| role | student |
And I am on the "adaptivequiz1" "Activity" page logged in as "student2"
And I click on "Start attempt" "link"
And I click on "True" "radio" in the "First question" "question"
And I press "Submit answer"
And I click on "True" "radio" in the "Second question" "question"
And I press "Submit answer"
And I press "Continue"
And I log out
And I log in as "admin"
And I navigate to "Users > Accounts > Bulk user actions" in site administration
And I set the field "Available" to "Henry The Student"
And I press "Add to selection"
And I set the field "id_action" to "Delete"
And I press "Go"
And I press "Yes"
And I log out
When I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
Then "Henry The Student" "table_row" should not exist
@javascript
Scenario: Individual user attempts report
When I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
And I click on "1" "link" in the "Peter The Student" "table_row"
Then I should see "Adaptive Quiz - individual user attempts report for Peter The Student"
And "Completed" "table_row" should exist
And "Completed" row "Reason for stopping attempt" column of "individualuserattemptstable" table should contain "Unable to fetch a question for level 5"
And "Completed" row "Sum of questions attempted" column of "individualuserattemptstable" table should contain "2"
@javascript
Scenario: View attempt summary
When I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
And I click on "1" "link" in the "Peter The Student" "table_row"
And I click on "Review attempt" "link" in the "Completed" "table_row"
Then I should see "Peter The Student (peterthestudent@example.com)" in the "User" "table_row"
@javascript
Scenario: View attempt questions details
When I am on the "adaptivequiz1" "Activity" page logged in as "teacher1"
And I click on "1" "link" in the "Peter The Student" "table_row"
And I click on "Review attempt" "link" in the "Completed" "table_row"
And I click on "Questions Details" "link"
# Info on the first question
Then I should see "Correct" in the "[id^=question-][id$=-1] .info .state" "css_element"
# Info on the second question
And I should see "Correct" in the "[id^=question-][id$=-2] .info .state" "css_element"
<?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/>.
/**
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_adaptivequiz\completion;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/adaptivequiz/locallib.php');
use advanced_testcase;
use cm_info;
use mod_adaptivequiz\completion\custom_completion;
/**
* @covers \mod_adaptivequiz\completion\custom_completion
*/
class custom_completion_test extends advanced_testcase {
public function test_it_defines_completion_state_based_on_attempt_completion():void {
global $DB;
$this->resetAfterTest();
$this->setup_test_data_xml();
$attemptuniqueid = 330;
$adaptivequizid = 330;
$cmid = 5;
$userid = 2;
$adaptivequiz = $DB->get_record('adaptivequiz', ['id' => $adaptivequizid]);
$context = \context_module::instance($cmid);
$cm = get_coursemodule_from_id('adaptivequiz', $cmid);
$cminfo = cm_info::create($cm);
$cminfo->override_customdata('customcompletionrules',
['completionattemptcompleted' => $adaptivequiz->completionattemptcompleted]);
$completion = new custom_completion($cminfo, $userid);
$this->assertEquals(COMPLETION_INCOMPLETE, $completion->get_state('completionattemptcompleted'));
adaptivequiz_complete_attempt($attemptuniqueid, $adaptivequiz, $context, $userid, '1', 'php unit test');
$this->assertEquals(COMPLETION_COMPLETE, $completion->get_state('completionattemptcompleted'));
}
private function setup_test_data_xml() {
$this->dataset_from_files(
[__DIR__.'/../fixtures/mod_adaptivequiz_adaptiveattempt.xml']
)->to_database();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- Tests no logs - Only query 3 should be processed -->
<dataset>
<table name="adaptivequiz_question">
<column>id</column>
<column>instance</column>
<column>questioncategory</column>
<row>
<value>1</value>
<value>12</value>
<value>2</value>
</row>
<row>
<value>2</value>
<value>12</value>
<value>4</value>
</row>
<row>
<value>3</value>
<value>12</value>
<value>6</value>
</row>
<row>
<value>4</value>
<value>12</value>
<value>8</value>
</row>
<row>
<value>5</value>
<value>12</value>
<value>10</value>
</row>
<row>
<value>6</value>
<value>12</value>
<value>12</value>
</row>
<row>
<value>7</value>
<value>13</value>
<value>1</value>
</row>
</table>
<table name="modules">
<column>id</column>
<column>name</column>
<row>
<value>50</value>
<value>adaptivequiz</value>
</row>
</table>
<table name="course">
<column>id</column>
<column>category</column>
<column>fullname</column>
<column>shortname</column>
<row>
<value>2</value>
<value>1</value>
<value>101</value>
<value>101</value>
</row>
</table>
<table name="course_sections">
<column>id</column>
<column>course</column>
<column>section</column>
<column>sequence</column>
<row>
<value>10</value>
<value>2</value>
<value>1</value>
<value>5,6</value>
</row>
</table>
<table name="course_modules">
<column>id</column>
<column>course</column>
<column>module</column>
<column>instance</column>
<column>section</column>
<row>
<value>5</value>
<value>2</value>
<value>50</value>
<value>13</value>
<value>10</value>
</row>
<row>
<value>6</value>
<value>2</value>
<value>50</value>
<value>1</value>
<value>10</value>
</row>
</table>
<table name="adaptivequiz">
<column>id</column>
<column>course</column>
<column>name</column>
<column>intro</column>
<column>attemptfeedback</column>
<column>highestlevel</column>
<column>lowestlevel</column>
<column>minimumquestions</column>
<column>maximumquestions</column>
<column>standarderror</column>
<column>startinglevel</column>
<row>
<value>1</value>
<value>2</value>
<value>Test re-using quba</value>
<value>intro asdf</value>
<value>attempt feedback</value>
<value>100</value>
<value>1</value>
<value>15</value>
<value>20</value>
<value>1.0</value>
<value>50</value>
</row>
<row>
<value>13</value>
<value>2</value>
<value>Test min_attempts_reached</value>
<value>intro asdf</value>
<value>attempt feedback</value>
<value>100</value>
<value>1</value>
<value>15</value>
<value>20</value>
<value>1.0</value>
<value>50</value>
</row>
<row>
<value>330</value>
<value>2</value>
<value>Test re-using quba</value>
<value>intro asdf</value>
<value>attempt feedback</value>
<value>100</value>
<value>1</value>
<value>15</value>
<value>20</value>
<value>1.0</value>
<value>50</value>
</row>
</table>
<table name="adaptivequiz_attempt">
<column>id</column>
<column>instance</column>
<column>userid</column>
<column>uniqueid</column>
<column>attemptstate</column>
<column>questionsattempted</column>
<column>standarderror</column>
<column>difficultysum</column>
<row>
<value>1</value>
<value>1</value>
<value>2</value>
<value>3</value>
<value>inprogress</value>
<value>0</value>
<value>1</value>
<value>1</value>
</row>
<row>
<value>2</value>
<value>13</value>
<value>3</value>
<value>3</value>
<value>complete</value>
<value>0</value>
<value>1</value>
<value>1</value>
</row>
<row>
<value>3</value>
<value>13</value>
<value>4</value>
<value>4</value>
<value>complete</value>
<value>16</value>
<value>1</value>
<value>1</value>
</row>
<row>
<value>5</value>
<value>330</value>
<value>2</value>
<value>330</value>
<value>inprogress</value>
<value>0</value>
<value>1</value>
<value>1</value>
</row>
</table>
<table name="question_usages">
<column>id</column>
<column>contextid</column>
<column>component</column>
<column>preferredbehaviour</column>
<row>
<value>330</value>
<value>330</value>
<value>mod_adaptivequiz</value>
<value>immediatefeedback</value>
</row>
</table>
<table name="context">
<column>id</column>
<column>contextlevel</column>
<column>instanceid</column>
<column>path</column>
<column>depth</column>
<row>
<value>16</value>
<value>50</value>
<value>2</value>
<value>/1/3/16</value>
<value>3</value>
</row>
<row>
<value>330</value>
<value>70</value>
<value>5</value>
<value>/1/3/16/330</value>
<value>4</value>
</row>
</table>
<table name="question_attempts">
<column>id</column>
<column>questionusageid</column>
<column>slot</column>
<column>questionid</column>
<column>maxmark</column>
<column>minfraction</column>
<column>rightanswer</column>
<column>timemodified</column>
<row>
<value>1</value>
<value>330</value>
<value>1</value>
<value>1</value>
<value>1.0</value>
<value>0.0</value>
<value>true</value>
<value>0</value>
</row>
<row>
<value>2</value>
<value>330</value>
<value>2</value>
<value>2</value>
<value>1.0</value>
<value>0.0</value>
<value>answer 1 (correct)</value>
<value>0</value>
</row>
</table>
<table name="question_attempt_steps">
<column>id</column>
<column>questionattemptid</column>
<column>sequencenumber</column>
<column>state</column>
<column>timecreated</column>
<column>userid</column>
<row>
<value>1</value>
<value>1</value>
<value>0</value>
<value>todo</value>
<value>0</value>
<value>2</value>
</row>
<row>
<value>2</value>
<value>1</value>
<value>1</value>
<value>gradedwrong</value>
<value>1</value>
<value>2</value>
</row>
<row>
<value>3</value>
<value>2</value>
<value>0</value>
<value>complete</value>
<value>1</value>
<value>2</value>
</row>
</table>
</dataset>
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<table name="context">
<column>id</column>
<column>contextlevel</column>
<column>instanceid</column>
<column>path</column>
<column>depth</column>
<row>
<value>16</value>
<value>50</value>
<value>200</value>
<value>/1/3/16</value>
<value>3</value>
</row>
<row>
<value>330</value>
<value>70</value>
<value>5</value>
<value>/1/3/16/330</value>
<value>4</value>
</row>
</table>
<table name="modules">
<column>id</column>
<column>name</column>
<row>
<value>50</value>
<value>adaptivequiz</value>
</row>
</table>
<table name="course">
<column>id</column>
<column>category</column>
<column>fullname</column>
<column>shortname</column>
<row>
<value>200</value>
<value>1</value>
<value>101</value>
<value>101</value>
</row>
</table>
<table name="course_sections">
<column>id</column>
<column>course</column>
<column>section</column>
<column>sequence</column>
<row>
<value>10</value>
<value>200</value>
<value>1</value>
<value>5</value>
</row>
</table>
<table name="course_modules">
<column>id</column>
<column>course</column>
<column>module</column>
<column>instance</column>
<column>section</column>
<column>completion</column>
<row>
<value>5</value>
<value>200</value>
<value>50</value>
<value>330</value>
<value>10</value>
<value>2</value>
</row>
</table>
<table name="question_categories">
<column>id</column>
<column>name</column>
<column>contextid</column>
<column>info</column>
<row>
<value>1</value>
<value>Default for 101</value>
<value>16</value>
<value>default question category</value>
</row>
<row>
<value>2</value>
<value>Default for Miscellaneous</value>
<value>3</value>
<value>default question category</value>
</row>
<row>
<value>3</value>
<value>Default for System</value>
<value>1</value>
<value>default question category</value>
</row>
</table>
<table name="question">
<column>id</column>
<column>category</column>
<column>parent</column>
<column>name</column>
<column>questiontext</column>
<column>generalfeedback</column>
<column>defaultmark</column>
<column>qtype</column>
<row>
<value>1</value>
<value>1</value>
<value>0</value>
<value>true or false 1</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>2</value>
<value>1</value>
<value>0</value>
<value>multiple choice 1</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>multichoice</value>
</row>
</table>
<table name="qtype_multichoice_options">
<column>id</column>
<column>questionid</column>
<column>layout</column>
<column>single</column>
<column>shuffleanswers</column>
<column>correctfeedback</column>
<column>correctfeedbackformat</column>
<column>partiallycorrectfeedback</column>
<column>partiallycorrectfeedbackformat</column>
<column>incorrectfeedback</column>
<column>incorrectfeedbackformat</column>
<column>answernumbering</column>
<column>shownumcorrect</column>
<column>showstandardinstruction</column>
<row>
<value>1</value>
<value>2</value>
<value>0</value>
<value>1</value>
<value>1</value>
<value>Your answer is correct.</value>
<value>1</value>
<value>Your answer is partially correct.</value>
<value>1</value>
<value>Your answer is incorrect.</value>
<value>1</value>
<value>abc</value>
<value>1</value>
<value>0</value>
</row>
</table>>
<table name="question_answers">
<column>id</column>
<column>question</column>
<column>answer</column>
<column>fraction</column>
<column>feedback</column>
<row>
<value>1</value>
<value>1</value>
<value>true</value>
<value>1.0</value>
<value>feedback for true</value>
</row>
<row>
<value>2</value>
<value>1</value>
<value>false</value>
<value>0.0</value>
<value>feedback for false</value>
</row>
<row>
<value>3</value>
<value>2</value>
<value>answer 1 (correct)</value>
<value>1.0</value>
<value>feedback for answer 1</value>
</row>
<row>
<value>4</value>
<value>2</value>
<value>answer 2 (incorrect)</value>
<value>0.0</value>
<value>feedback for answer 2</value>
</row>
<row>
<value>5</value>
<value>2</value>
<value>answer 3 (incorrect)</value>
<value>0.0</value>
<value>feedback for answer 3</value>
</row>
<row>
<value>6</value>
<value>2</value>
<value>answer 4 (incorrect)</value>
<value>0.0</value>
<value>feedback for answer 4</value>
</row>
<row>
<value>7</value>
<value>2</value>
<value>answer 5 (incorrect)</value>
<value>0.0</value>
<value>feedback for answer %</value>
</row>
</table>
<table name="question_attempts">
<column>id</column>
<column>questionusageid</column>
<column>slot</column>
<column>questionid</column>
<column>maxmark</column>
<column>minfraction</column>
<column>rightanswer</column>
<column>timemodified</column>
<row>
<value>1</value>
<value>330</value>
<value>1</value>
<value>1</value>
<value>1.0</value>
<value>0.0</value>
<value>true</value>
<value>0</value>
</row>
<row>
<value>2</value>
<value>330</value>
<value>2</value>
<value>2</value>
<value>1.0</value>
<value>0.0</value>
<value>answer 1 (correct)</value>
<value>0</value>
</row>
</table>
<table name="question_attempt_steps">
<column>id</column>
<column>questionattemptid</column>
<column>sequencenumber</column>
<column>state</column>
<column>timecreated</column>
<column>userid</column>
<row>
<value>1</value>
<value>1</value>
<value>0</value>
<value>todo</value>
<value>0</value>
<value>2</value>
</row>
<row>
<value>2</value>
<value>1</value>
<value>1</value>
<value>gradedwrong</value>
<value>1</value>
<value>2</value>
</row>
<row>
<value>3</value>
<value>2</value>
<value>0</value>
<value>complete</value>
<value>1</value>
<value>2</value>
</row>
</table>
<table name="question_truefalse">
<column>id</column>
<column>question</column>
<column>trueanswer</column>
<column>falseanswer</column>
<row>
<value>1</value>
<value>1</value>
<value>1</value>
<value>2</value>
</row>
</table>
<table name="tag">
<column>id</column>
<column>userid</column>
<column>tagcollid</column>
<column>name</column>
<column>rawname</column>
<column>tagtype</column>
<column>flag</column>
<row>
<value>1</value>
<value>2</value>
<value>1</value>
<value>adpq_5</value>
<value>adpq_5</value>
<value>default</value>
<value>0</value>
</row>
<row>
<value>2</value>
<value>2</value>
<value>1</value>
<value>phpunittag_5</value>
<value>phpunittag_5</value>
<value>default</value>
<value>0</value>
</row>
<row>
<value>3</value>
<value>2</value>
<value>1</value>
<value>phpunittag_888</value>
<value>phpunittag_888</value>
<value>default</value>
<value>0</value>
</row>
</table>
<table name="tag_instance">
<column>id</column>
<column>tagid</column>
<column>itemtype</column>
<column>itemid</column>
<column>tiuserid</column>
<row>
<value>1</value>
<value>1</value>
<value>question</value>
<value>1</value>
<value>0</value>
</row>
</table>
<table name="adaptivequiz">
<column>id</column>
<column>course</column>
<column>name</column>
<column>intro</column>
<column>attemptfeedback</column>
<column>highestlevel</column>
<column>lowestlevel</column>
<column>minimumquestions</column>
<column>maximumquestions</column>
<column>standarderror</column>
<column>startinglevel</column>
<column>completionattemptcompleted</column>
<row>
<value>330</value>
<value>200</value>
<value>Test re-using quba</value>
<value>intro asdf</value>
<value>attempt feedback</value>
<value>100</value>
<value>1</value>
<value>15</value>
<value>20</value>
<value>1.0</value>
<value>50</value>
<value>1</value>
</row>
</table>
<table name="adaptivequiz_attempt">
<column>id</column>
<column>instance</column>
<column>userid</column>
<column>uniqueid</column>
<column>attemptstate</column>
<column>questionsattempted</column>
<column>standarderror</column>
<row>
<value>1</value>
<value>220</value>
<value>2</value>
<value>1110</value>
<value>inprogress</value>
<value>0</value>
<value>1</value>
</row>
<row>
<value>2</value>
<value>221</value>
<value>2</value>
<value>1111</value>
<value>inprogress</value>
<value>10</value>
<value>1</value>
</row>
<row>
<value>3</value>
<value>222</value>
<value>2</value>
<value>1112</value>
<value>inprogress</value>
<value>20</value>
<value>1</value>
</row>
<row>
<value>4</value>
<value>223</value>
<value>2</value>
<value>1113</value>
<value>inprogress</value>
<value>40</value>
<value>1</value>
</row>
<row>
<value>5</value>
<value>330</value>
<value>2</value>
<value>330</value>
<value>inprogress</value>
<value>0</value>
<value>1</value>
</row>
</table>
<table name="question_usages">
<column>id</column>
<column>contextid</column>
<column>component</column>
<column>preferredbehaviour</column>
<row>
<value>330</value>
<value>330</value>
<value>mod_adaptivequiz</value>
<value>immediatefeedback</value>
</row>
</table>
</dataset>
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<table name="adaptivequiz_attempt">
<column>id</column>
<column>instance</column>
<column>userid</column>
<column>uniqueid</column>
<column>attemptstate</column>
<column>questionsattempted</column>
<column>standarderror</column>
<column>difficultysum</column>
<column>measure</column>
<row>
<value>1</value>
<value>220</value>
<value>2</value>
<value>1110</value>
<value>inprogress</value>
<value>0</value>
<value>1.2</value>
<value>99</value>
<value>2.222</value>
</row>
</table>
<table name="adaptivequiz">
<column>id</column>
<column>course</column>
<column>name</column>
<column>intro</column>
<column>attemptfeedback</column>
<column>highestlevel</column>
<column>lowestlevel</column>
<column>minimumquestions</column>
<column>maximumquestions</column>
<column>standarderror</column>
<column>startinglevel</column>
<row>
<value>220</value>
<value>1</value>
<value>Test for retrieve_standard_error()</value>
<value>intro asdf</value>
<value>attempt feedback</value>
<value>100</value>
<value>1</value>
<value>15</value>
<value>20</value>
<value>9.9</value>
<value>50</value>
</row>
</table>
</dataset>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<table name="context">
<column>id</column>
<column>contextlevel</column>
<column>instanceid</column>
<column>path</column>
<column>depth</column>
<row>
<value>16</value>
<value>50</value>
<value>2</value>
<value>/1/3/16</value>
<value>3</value>
</row>
</table>
<table name="course">
<column>id</column>
<column>category</column>
<column>fullname</column>
<column>shortname</column>
<row>
<value>2</value>
<value>1</value>
<value>101</value>
<value>101</value>
</row>
</table>
<table name="question_categories">
<column>id</column>
<column>name</column>
<column>contextid</column>
<column>info</column>
<column>stamp</column>
<row>
<value>1</value>
<value>Default for 101</value>
<value>16</value>
<value>default question category</value>
<value>example.loc+161208110835+ZNzubk</value>
</row>
<row>
<value>2</value>
<value>Default for Miscellaneous</value>
<value>3</value>
<value>default question category</value>
<value>example.loc+161208112421+aQXIHP</value>
</row>
<row>
<value>3</value>
<value>Default for System</value>
<value>1</value>
<value>default question category</value>
<value>example.loc+161208112421+HX4iPR</value>
</row>
<row>
<value>4</value>
<value>Test reattempt</value>
<value>16</value>
<value>Data test for fetch_question</value>
<value>example.loc+161208112853+RAFrV1</value>
</row>
<row>
<value>5</value>
<value>retrieve_tags_with_question_count</value>
<value>16</value>
<value>test_retrieve_tags_with_question_count</value>
<value>example.loc+161208112930+1oAcF9</value>
</row>
<row>
<value>6</value>
<value>find_questions_with_tags_with_multiple_quest_in_quest_category 1</value>
<value>16</value>
<value>find_questions_with_tags_with_multiple_quest_in_quest_category</value>
<value>example.loc+161208120113+5PvXXH</value>
</row>
<row>
<value>7</value>
<value>find_questions_with_tags_with_multiple_quest_in_quest_category 2</value>
<value>16</value>
<value>find_questions_with_tags_with_multiple_quest_in_quest_category</value>
<value>example.loc+170110181010+Ig7DE6</value>
</row>
<row>
<value>8</value>
<value>find_questions_with_tags_with_multiple_quest_in_quest_category 3</value>
<value>16</value>
<value>find_questions_with_tags_with_multiple_quest_in_quest_category</value>
<value>example.loc+170110181307+5LFZK2</value>
</row>
</table>
<table name="question">
<column>id</column>
<column>category</column>
<column>parent</column>
<column>name</column>
<column>questiontext</column>
<column>generalfeedback</column>
<column>defaultmark</column>
<column>qtype</column>
<row>
<value>1</value>
<value>1</value>
<value>0</value>
<value>true or false 1</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>2</value>
<value>4</value>
<value>0</value>
<value>true or false 2</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>3</value>
<value>4</value>
<value>0</value>
<value>true or false 3</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>4</value>
<value>4</value>
<value>0</value>
<value>true or false 4</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>5</value>
<value>4</value>
<value>0</value>
<value>true or false 5</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>6</value>
<value>4</value>
<value>0</value>
<value>true or false 6</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>7</value>
<value>5</value>
<value>0</value>
<value>TF test 1</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>8</value>
<value>5</value>
<value>0</value>
<value>TF test 2</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>9</value>
<value>5</value>
<value>0</value>
<value>TF test 3</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>10</value>
<value>5</value>
<value>0</value>
<value>TF test 4</value>
<value>question text</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>11</value>
<value>6</value>
<value>0</value>
<value>multiple_quest_in_quest_category 1</value>
<value>multiple_quest_in_quest_category 1</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>12</value>
<value>7</value>
<value>0</value>
<value>multiple_quest_in_quest_category 2</value>
<value>multiple_quest_in_quest_category 2</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
<row>
<value>13</value>
<value>8</value>
<value>0</value>
<value>multiple_quest_in_quest_category 3</value>
<value>multiple_quest_in_quest_category 3</value>
<value>general feedback</value>
<value>1.0</value>
<value>truefalse</value>
</row>
</table>
<table name="question_answers">
<column>id</column>
<column>question</column>
<column>answer</column>
<column>fraction</column>
<column>feedback</column>
<row>
<value>1</value>
<value>1</value>
<value>true</value>
<value>1.0</value>
<value>feedback for true</value>
</row>
<row>
<value>2</value>
<value>1</value>
<value>false</value>
<value>0.0</value>
<value>feedback for false</value>
</row>
</table>
<table name="question_truefalse">
<column>id</column>
<column>question</column>
<column>trueanswer</column>
<column>falseanswer</column>
<row>
<value>1</value>
<value>1</value>
<value>1</value>
<value>2</value>
</row>
</table>
<table name="course_modules">
<column>id</column>
<column>course</column>
<column>module</column>
<column>falseanswer</column>
</table>
<table name="tag">
<column>id</column>
<column>userid</column>
<column>tagcollid</column>
<column>name</column>
<column>rawname</column>
<column>flag</column>
<row>
<value>1</value>
<value>2</value>
<value>1</value>
<value>adpq_5</value>
<value>adpq_5</value>
<value>0</value>
</row>
<row>
<value>2</value>
<value>2</value>
<value>1</value>
<value>phpunittag_5</value>
<value>phpunittag_5</value>
<value>0</value>
</row>
<row>
<value>3</value>
<value>2</value>
<value>1</value>
<value>phpunittag_888</value>
<value>phpunittag_888</value>
<value>0</value>
</row>
<row>
<value>4</value>
<value>2</value>
<value>1</value>
<value>adpq_6</value>
<value>adpq_6</value>
<value>0</value>
</row>
<row>
<value>5</value>
<value>2</value>
<value>1</value>
<value>adpq_7</value>
<value>adpq_7</value>
<value>0</value>
</row>
<row>
<value>6</value>
<value>2</value>
<value>1</value>
<value>adpq_8</value>
<value>adpq_8</value>
<value>0</value>
</row>
<row>
<value>7</value>
<value>2</value>
<value>1</value>
<value>adpq_9</value>
<value>adpq_9</value>
<value>0</value>
</row>
<row>
<value>8</value>
<value>2</value>
<value>1</value>
<value>adpq_10</value>
<value>adpq_10</value>
<value>0</value>
</row>
<row>
<value>22</value>
<value>2</value>
<value>1</value>
<value>test1_22</value>
<value>test1_22</value>
<value>0</value>
</row>
<row>
<value>23</value>
<value>2</value>
<value>1</value>
<value>test1_23</value>
<value>test1_23</value>
<value>0</value>
</row>
<row>
<value>24</value>
<value>2</value>
<value>1</value>
<value>test1_24</value>
<value>test1_24</value>
<value>0</value>
</row>
<row>
<value>25</value>
<value>2</value>
<value>2</value>
<value>adpq_5</value>
<value>adpq_5</value>
<value>0</value>
</row>
</table>
<table name="tag_instance">
<column>id</column>
<column>tagid</column>
<column>component</column>
<column>itemtype</column>
<column>itemid</column>
<column>tiuserid</column>
<row>
<value>1</value>
<value>1</value>
<value>core_question</value>
<value>question</value>
<value>1</value>
<value>0</value>
</row>
<row>
<value>2</value>
<value>4</value>
<value>core_question</value>
<value>question</value>
<value>2</value>
<value>0</value>
</row>
<row>
<value>3</value>
<value>5</value>
<value>core_question</value>
<value>question</value>
<value>3</value>
<value>0</value>
</row>
<row>
<value>4</value>
<value>6</value>
<value>core_question</value>
<value>question</value>
<value>4</value>
<value>0</value>
</row>
<row>
<value>5</value>
<value>7</value>
<value>core_question</value>
<value>question</value>
<value>5</value>
<value>0</value>
</row>
<row>
<value>6</value>
<value>8</value>
<value>core_question</value>
<value>question</value>
<value>6</value>
<value>0</value>
</row>
<row>
<value>7</value>
<value>1</value>
<value>core_question</value>
<value>question</value>
<value>8</value>
<value>0</value>
</row>
<row>
<value>8</value>
<value>8</value>
<value>core_question</value>
<value>question</value>
<value>9</value>
<value>0</value>
</row>
<row>
<value>9</value>
<value>8</value>
<value>core_question</value>
<value>question</value>
<value>10</value>
<value>0</value>
</row>
<row>
<value>22</value>
<value>22</value>
<value>core_question</value>
<value>question</value>
<value>11</value>
<value>0</value>
</row>
<row>
<value>23</value>
<value>23</value>
<value>core_question</value>
<value>question</value>
<value>12</value>
<value>0</value>
</row>
<row>
<value>24</value>
<value>24</value>
<value>core_question</value>
<value>question</value>
<value>13</value>
<value>0</value>
</row>
<row>
<value>25</value>
<value>25</value>
<value>core</value>
<value>course</value>
<value>2</value>
<value>0</value>
</row>
<row>
<value>26</value>
<value>2</value>
<value>core_question</value>
<value>question</value>
<value>5</value>
<value>0</value>
</row>
</table>
<table name="adaptivequiz_question">
<column>id</column>
<column>instance</column>
<column>questioncategory</column>
<row>
<value>1</value>
<value>1</value>
<value>11</value>
</row>
<row>
<value>2</value>
<value>1</value>
<value>22</value>
</row>
</table>
</dataset>
\ No newline at end of file
<?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/>.
/**
* Generator for the module.
*
* @package mod_adaptivequiz
* @copyright 2013 onwards Remote-Learner {@link http://www.remote-learner.ca/}
* @copyright 2024 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_adaptivequiz_generator extends testing_module_generator {
/**
* Creates new module instance.
*
* For params description see the parent's method.
*
* @param array|stdClass|null $record
* @param array|null $options
* @return stdClass
* @throws coding_exception
*/
public function create_instance($record = null, array $options = null) {
global $CFG;
require_once($CFG->dirroot .'/mod/adaptivequiz/locallib.php');
$record = (object)(array)$record;
if (!isset($record->questionpool) && !isset($record->questionpoolnamed)) {
throw new coding_exception('either \'questionpool\' or \'questionpoolnamed\' property must be specified when '.
'generating an adaptive quiz instance');
}
// Named question pool takes precedence over the 'questionpool' setting.
if (isset($record->questionpoolnamed)) {
if (is_string($record->questionpoolnamed)) {
$record->questionpoolnamed = [$record->questionpoolnamed];
}
$record->questionpool = $this->get_question_category_id_list_by_names($record->questionpoolnamed);
unset($record->questionpoolnamed);
}
$defaultsettings = [
'introformat' => FORMAT_MOODLE,
'attempts' => 0,
'grademethod' => ADAPTIVEQUIZ_GRADEHIGHEST,
'password' => '',
'attemptfeedback' => '',
'attemptfeedbackformat' => FORMAT_MOODLE,
'attemptonlast' => 0,
'highestlevel' => 111,
'lowestlevel' => 1,
'minimumquestions' => 1,
'maximumquestions' => 111,
'standarderror' => 1.1,
'startinglevel' => 11,
'timecreated' => time(),
'timemodified' => time(),
];
foreach ($defaultsettings as $name => $value) {
if (!isset($record->{$name})) {
$record->{$name} = $value;
}
}
return parent::create_instance($record, $options);
}
/**
* Fetches a list of id for the given names of question categories.
*
* @param string[] $names
* @return int[]
*/
private function get_question_category_id_list_by_names(array $names): array {
global $DB;
[$namesql, $nameparams] = $DB->get_in_or_equal($names);
return $DB->get_fieldset_select('question_categories', 'id', "name $namesql", $nameparams);
}
}
<?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_adaptivequiz;
use advanced_testcase;
use context_course;
use context_module;
/**
* Adaptive PHPUnit data generator testcase.
*
* @package mod_adaptivequiz
* @copyright 2013 onwards Remote-Learner {@link http://www.remote-learner.ca/}
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* @covers \mod_adaptivequiz_generator
*/
class generator_test extends advanced_testcase {
public function test_generator() {
global $DB, $SITE;
$this->resetAfterTest();
$this->assertEquals(0, $DB->count_records('adaptivequiz'));
$generator = $this->getDataGenerator()->get_plugin_generator('mod_adaptivequiz');
$this->assertInstanceOf('mod_adaptivequiz_generator', $generator);
$this->assertEquals('adaptivequiz', $generator->get_modulename());
$questioncategory = $this->getDataGenerator()
->get_plugin_generator('core_question')
->create_question_category(['name' => 'My category']);
$generator->create_instance([
'course' => $SITE->id,
'questionpool' => [$questioncategory->id],
]);
$generator->create_instance([
'course' => $SITE->id,
'questionpool' => [$questioncategory->id],
]);
$adaptivequiz = $generator->create_instance([
'course' => $SITE->id,
'questionpool' => [$questioncategory->id],
]);
$this->assertEquals(3, $DB->count_records('adaptivequiz'));
$cm = get_coursemodule_from_instance('adaptivequiz', $adaptivequiz->id);
$this->assertEquals($adaptivequiz->id, $cm->instance);
$this->assertEquals('adaptivequiz', $cm->modname);
$this->assertEquals($SITE->id, $cm->course);
$context = context_module::instance($cm->id);
$this->assertEquals($adaptivequiz->cmid, $context->instanceid);
}
public function test_it_handles_question_category_names_when_creating_an_instance(): void {
global $DB;
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$coursecontext = context_course::instance($course->id);
$questioncategoryname1 = 'My category 1';
$questioncategoryname2 = 'My category 2';
$questioncategory1 = $this->getDataGenerator()
->get_plugin_generator('core_question')
->create_question_category([
'contextid' => $coursecontext->id,
'name' => $questioncategoryname1,
]);
$questioncategory2 = $this->getDataGenerator()
->get_plugin_generator('core_question')
->create_question_category([
'contextid' => $coursecontext->id,
'name' => $questioncategoryname2,
]);
$generator = $this->getDataGenerator()->get_plugin_generator('mod_adaptivequiz');
// Pool as a single string.
$adaptivequiz = $generator->create_instance([
'course' => $course->id,
'questionpoolnamed' => $questioncategoryname1,
]);
self::assertEquals(1, $DB->count_records('adaptivequiz_question', [
'instance' => $adaptivequiz->id,
'questioncategory' => $questioncategory1->id,
]));
// Pool as an array of strings.
$adaptivequiz = $generator->create_instance([
'course' => $course->id,
'questionpoolnamed' => [$questioncategoryname1, $questioncategoryname2],
]);
self::assertEquals(1, $DB->count_records('adaptivequiz_question', [
'instance' => $adaptivequiz->id,
'questioncategory' => $questioncategory1->id,
]));
self::assertEquals(1, $DB->count_records('adaptivequiz_question', [
'instance' => $adaptivequiz->id,
'questioncategory' => $questioncategory2->id,
]));
}
}
<?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/>.
/**
* Adaptive lib.php PHPUnit tests
*
* @copyright 2013 Remote-Learner {@link http://www.remote-learner.ca/}
* @copyright 2022 onwards Vitaly Potenko <potenkov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_adaptivequiz;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot.'/mod/adaptivequiz/lib.php');
use advanced_testcase;
use mod_adaptivequiz\local\attempt\attempt_state;
use stdClass;
/**
* @group mod_adaptivequiz
*/
class lib_test extends advanced_testcase {
/**
* This functions loads data via the tests/fixtures/mod_adaptivequiz.xml file
* @return void
*/
protected function setup_test_data_xml() {
$this->dataset_from_files(
[__DIR__.'/fixtures/mod_adaptivequiz.xml']
)->to_database();
}
/**
* Provide input data to the parameters of the test_questioncat_association_insert() method.
*/
public function questioncat_association_records() {
$data = array();
$adaptivequiz = new stdClass();
$adaptivequiz->questionpool = array(1, 2, 3, 4);
$data[] = array(1, $adaptivequiz);
$adaptivequiz = new stdClass();
$adaptivequiz->questionpool = array(1, 2);
$data[] = array(2, $adaptivequiz);
$adaptivequiz = new stdClass();
$adaptivequiz->questionpool = array(1, 2, 4);
$data[] = array(3, $adaptivequiz);
return $data;
}
/**
* Test insertion of question category association records.
*
* @dataProvider questioncat_association_records
* @param int $instance: activity instance id
* @param object $adaptivequiz: An object from the form in mod_form.php
* @group adaptivequiz_lib_test
* @covers ::adaptivequiz_add_questcat_association
*/
public function test_questioncat_association_insert($instance, stdClass $adaptivequiz) {
global $DB;
$this->resetAfterTest(true);
adaptivequiz_add_questcat_association($instance, $adaptivequiz);
if (1 == $instance) {
$this->assertEquals(4, $DB->count_records('adaptivequiz_question', array('instance' => $instance)));
}
if (2 == $instance) {
$this->assertEquals(2, $DB->count_records('adaptivequiz_question', array('instance' => $instance)));
}
if (3 == $instance) {
$this->assertEquals(3, $DB->count_records('adaptivequiz_question', array('instance' => $instance)));
}
}
/**
* Test update of question category associations records.
*
* @dataProvider questioncat_association_records
* @param int $instance: activity instance id
* @param object $adaptivequiz: An object from the form in mod_form.php
* @group adaptivequiz_lib_test
* @covers ::adaptivequiz_update_questcat_association
*/
public function test_questioncat_association_update($instance, stdClass $adaptivequiz) {
global $DB;
$this->resetAfterTest(true);
adaptivequiz_add_questcat_association($instance, $adaptivequiz);
if (1 == $instance) {
$adaptivequizupdate = new stdClass();
$adaptivequizupdate->questionpool = array(111, 222, 333, 444, 555, 122, 133, 144, 155, 166);
adaptivequiz_update_questcat_association($instance, $adaptivequizupdate);
$this->assertEquals(10, $DB->count_records('adaptivequiz_question', array('instance' => $instance)));
}
if (2 == $instance) {
$adaptivequizupdate = new stdClass();
$adaptivequizupdate->questionpool = array(4);
adaptivequiz_update_questcat_association($instance, $adaptivequizupdate);
$this->assertEquals(1, $DB->count_records('adaptivequiz_question', array('instance' => $instance)));
}
if (3 == $instance) {
$adaptivequizupdate = new stdClass();
$adaptivequizupdate->questionpool = array(4, 10, 20, 30, 40, 100, 333);
adaptivequiz_update_questcat_association($instance, $adaptivequizupdate);
$this->assertEquals(7, $DB->count_records('adaptivequiz_question', array('instance' => $instance)));
}
}
/**
* This function tests the removal of an activity instance and all related data.
*
* @covers ::adaptivequiz_delete_instance
*/
public function test_adaptivequiz_delete_instance() {
global $DB;
$this->resetAfterTest(true);
$this->setup_test_data_xml();
$instance = 330;
adaptivequiz_delete_instance($instance);
$this->assertEquals(0, $DB->count_records('adaptivequiz', array('id' => $instance)));
$this->assertEquals(0, $DB->count_records('adaptivequiz_question', array('instance' => $instance)));
$this->assertEquals(0, $DB->count_records('adaptivequiz_attempt', array('instance' => $instance)));
$this->assertEquals(0, $DB->count_records('question_usages', array('id' => $instance)));
}
/**
* This function tests the output from adaptivequiz_print_recent_mod_activity().
*
* @covers ::adaptivequiz_print_recent_mod_activity
*/
public function test_adaptivequiz_print_recent_mod_activity_details_true() {
$this->resetAfterTest(true);
$dummy = new stdClass();
$dummy->user = new stdClass();
$dummy->user->id = 2;
$dummy->user->fullname = 'user-phpunit';
$dummy->user->alternatename = 'user-phpunit';
$dummy->user->picture = '';
$dummy->user->firstname = 'user';
$dummy->user->middlename = '-';
$dummy->user->lastname = 'phpunit';
$dummy->user->imagealt = '';
$dummy->user->email = 'a@a.com';
$dummy->user->firstnamephonetic = 'user';
$dummy->user->lastnamephonetic = 'phpunit';
$dummy->content = new stdClass();
$dummy->content->attemptstate = attempt_state::IN_PROGRESS;
$dummy->content->questionsattempted = '12';
$dummy->timestamp = 1234;
$dummy->type = 'mod_adaptivequiz';
$dummy->name = 'my-phpunit-test';
$dummy->cmid = 99;
$output = adaptivequiz_print_recent_mod_activity($dummy, 1, true, array('mod_adaptivequiz' => 'adaptivequiz'), true, true);
$this->assertStringContainsString('<table', $output);
$this->assertStringContainsString('<tr>', $output);
$this->assertStringContainsString('<td', $output);
$this->assertStringContainsString('mod/adaptivequiz/view.php?id=99', $output);
$this->assertStringContainsString('/user/view.php?id=2', $output);
$this->assertStringContainsString('user phpunit', $output);
$this->assertStringContainsString('my-phpunit-test', $output);
}
/**
* This function tests the output from adaptivequiz_print_recent_mod_activity().
*
* @covers ::adaptivequiz_print_recent_mod_activity
*/
public function test_adaptivequiz_print_recent_mod_activity_details_false() {
$this->resetAfterTest(true);
$dummy = new stdClass();
$dummy->user = new stdClass();
$dummy->user->id = 2;
$dummy->user->fullname = 'user-phpunit';
$dummy->user->alternatename = 'user-phpunit';
$dummy->user->picture = '';
$dummy->user->firstname = 'user';
$dummy->user->middlename = '-';
$dummy->user->lastname = 'phpunit';
$dummy->user->imagealt = '';
$dummy->user->email = 'a@a.com';
$dummy->user->firstnamephonetic = 'user';
$dummy->user->lastnamephonetic = 'phpunit';
$dummy->content = new stdClass();
$dummy->content->attemptstate = attempt_state::IN_PROGRESS;
$dummy->content->questionsattempted = '12';
$dummy->timestamp = 1234;
$dummy->type = 'mod_adaptivequiz';
$dummy->name = 'my-phpunit-test';
$dummy->cmid = 99;
$output = adaptivequiz_print_recent_mod_activity($dummy, 1, false, array('mod_adaptivequiz' => 'adaptivequiz'), true, true);
$this->assertStringContainsString('<table', $output);
$this->assertStringContainsString('<tr>', $output);
$this->assertStringContainsString('<td', $output);
$this->assertStringContainsString('/user/view.php?id=2', $output);
$this->assertStringContainsString('user phpunit', $output);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment