Skip to content

Commit

Permalink
quiz-data - Import quiz unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
EJMFarrow committed Nov 20, 2024
1 parent 377e970 commit ec21d9d
Show file tree
Hide file tree
Showing 8 changed files with 753 additions and 55 deletions.
5 changes: 3 additions & 2 deletions classes/cli_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,13 @@ public function validate_and_clean_args(): void {
break;
}
}
if (!(isset($cliargs['manifestpath']) || isset($cliargs['quizmanifestpath'])) && !isset($cliargs['contextlevel'])) {
if (!(isset($cliargs['manifestpath']) || isset($cliargs['quizmanifestpath'])
|| (isset($cliargs['nonquizmanifestpath']) && isset($cliargs['instanceid']))) && !isset($cliargs['contextlevel'])) {
echo "\nYou have not specified context. " .
"You must specify context level (--contextlevel) unless " .
"using a function where this information can be read from a manifest file, in which case " .
"you could set a manifest path (--manifestpath) instead. If using exportrepofrommoodle, you " .
"must set manifest path only. If dealing with import/export of quizzes, you must specify --quizmanifestpath. " .
"must set manifest path only. If dealing with export of quizzes, you must specify --quizmanifestpath. " .
"If you still see this message, you may be using invalid arguments.\n";
static::call_exit();
}
Expand Down
103 changes: 60 additions & 43 deletions classes/import_quiz.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class import_quiz {
*
* @var string|null
*/
public ?string $quizmanifestpath;
public ?string $quizmanifestpath = null;
/**
* Parsed content of JSON manifest file
*
Expand All @@ -83,7 +83,7 @@ class import_quiz {
*
* @var string|null
*/
public ?string $nonquizmanifestpath;
public ?string $nonquizmanifestpath = null;
/**
* Parsed content of JSON manifest file
*
Expand All @@ -99,9 +99,9 @@ class import_quiz {
/**
* Full path to data file
*
* @var string
* @var string|null
*/
public string $quizdatapath;
public ?string $quizdatapath = null;
/**
* Parsed content of JSON data file
*
Expand All @@ -128,6 +128,17 @@ public function __construct(cli_helper $clihelper, array $moodleinstances) {
if (!$this->quizmanifestcontents) {
echo "\nUnable to access or parse manifest file: {$this->quizmanifestpath}\nAborting.\n";
$this->call_exit();

} else {
$this->quizdatapath = cli_helper::get_quiz_structure_path($this->quizmanifestcontents->context->modulename, dirname($this->quizmanifestpath));
}
} else {
if ($arguments['quizdatapath']) {
$this->quizdatapath = $arguments['rootdirectory'] . '/' . $arguments['quizdatapath'];
} else {
echo "\nPlease supply a quiz manifest filepath or a quiz data filepath.\nAborting.\n";
$this->call_exit();
return; // Required for unit tests.
}
}
if ($arguments['nonquizmanifestpath']) {
Expand All @@ -138,9 +149,16 @@ public function __construct(cli_helper $clihelper, array $moodleinstances) {
echo "\nUnable to access or parse manifest file: {$this->nonquizmanifestpath}\nAborting.\n";
$this->call_exit();
}
$instanceid = $this->quizmanifestcontents->context->instanceid;
if ($this->nonquizmanifestcontents->context->contextlevel === cli_helper::get_context_level('course')) {
$instanceid = $this->nonquizmanifestcontents->context->instanceid;
}
}
if (!$instanceid && !$arguments['coursename']) {
echo "\nYou must identify the course you wish to add the quiz to. Use a course manifest path (--nonquizmanifestpath)" .
"or specify the course id (--instanceid) or course name (--coursename).\nAborting.\n";
$this->call_exit();
return; // Required for unit tests.
}
$this->quizdatapath = $arguments['rootdirectory'] . '/' . $arguments['quizdatapath'];
$this->quizdatacontents = json_decode(file_get_contents($this->quizdatapath));
if (!$this->quizdatacontents) {
echo "\nUnable to access or parse data file: {$this->quizdatapath}\nAborting.\n";
Expand Down Expand Up @@ -182,6 +200,18 @@ public function __construct(cli_helper $clihelper, array $moodleinstances) {
];
$this->curlrequest->set_option(CURLOPT_RETURNTRANSFER, true);
$this->curlrequest->set_option(CURLOPT_POST, 1);
$instanceinfo = $this->clihelper->check_context($this, false, true);
if ($arguments['subcall']) {
echo "\nCreating quiz: {$this->quizdatacontents->quiz->name}\n";
} else {
echo "\nPreparing to create a new quiz in Moodle.\n";
echo "Moodle URL: {$this->moodleurl}\n";
echo "Course: {$instanceinfo->contextinfo->coursename}\n";
echo "Quiz: {$this->quizdatacontents->quiz->name}\n";
$this->handle_abort();
}
$this->postsettings['quiz[coursename]'] = $instanceinfo->contextinfo->coursename;
$this->postsettings['quiz[courseid]'] = $instanceinfo->contextinfo->instanceid;
}

/**
Expand Down Expand Up @@ -211,17 +241,6 @@ public function get_curl_request($wsurl):curl_request {
* @return void
*/
public function import_quiz_data() {
$instanceinfo = $this->clihelper->check_context($this, false, true);
$arguments = $this->clihelper->get_arguments();
if ($arguments['subcall']) {
echo "Creating quiz: {$this->quizdatacontents->quiz->name}\n";
} else {
echo "Preparing to create a new quiz in Moodle.\n";
echo "Moodle URL: {$this->moodleurl}\n";
echo "Course: {$instanceinfo->contextinfo->coursename}\n";
echo "Quiz: {$this->quizdatacontents->quiz->name}\n";
$this->handle_abort();
}
$quizmanifestentries = [];
$nonquizmanifestentries = [];
if ($this->quizmanifestpath) {
Expand All @@ -234,8 +253,6 @@ public function import_quiz_data() {
foreach ($this->quizdatacontents->quiz as $key => $quizparam) {
$this->postsettings["quiz[{$key}]"] = $quizparam;
}
$this->postsettings['quiz[coursename]'] = $instanceinfo->contextinfo->coursename;
$this->postsettings['quiz[courseid]'] = $instanceinfo->contextinfo->instanceid;

foreach ($this->quizdatacontents->sections as $sectionkey => $section) {
foreach ($section as $key => $sectionparam) {
Expand All @@ -246,31 +263,31 @@ public function import_quiz_data() {
foreach ($this->quizdatacontents->questions as $questionkey => $question) {
foreach ($question as $key => $questionparam) {
$this->postsettings["questions[{$questionkey}][{$key}]"] = $questionparam;
$manifestentry = false;
$qidentifier = '';
if (isset($question->quizfilepath)) {
$manifestentry = $quizmanifestentries["{$question->quizfilepath}"] ?? false;
$qidentifier = "Quiz repo: {$question->quizfilepath}";
unset($this->postsettings["questions[{$questionkey}][quizfilepath]"]);
} else if (isset($question->nonquizfilepath)) {
$manifestentry = $nonquizmanifestentries["{$question->nonquizfilepath}"] ?? false;
$qidentifier = "Non-quiz repo: {$question->nonquizfilepath}";
unset($this->postsettings["questions[{$questionkey}][nonquizfilepath]"]);
}
}
$manifestentry = false;
$qidentifier = '';
if (isset($question->quizfilepath)) {
$manifestentry = $quizmanifestentries["{$question->quizfilepath}"] ?? false;
$qidentifier = "Quiz repo: {$question->quizfilepath}";
unset($this->postsettings["questions[{$questionkey}][quizfilepath]"]);
} else if (isset($question->nonquizfilepath)) {
$manifestentry = $nonquizmanifestentries["{$question->nonquizfilepath}"] ?? false;
$qidentifier = "Non-quiz repo: {$question->nonquizfilepath}";
unset($this->postsettings["questions[{$questionkey}][nonquizfilepath]"]);
}

if ($manifestentry) {
$this->postsettings["questions[{$questionkey}][questionbankentryid]"] = $manifestentry->questionbankentryid;
} else {
$multiple = ($this->quizmanifestpath && $this->nonquizmanifestpath) ? 's' : '';
echo "Question: {$qidentifier}\n";
echo "This question is in the quiz but not in the supplied manifest file" . $multiple . ".\n";
echo "Questions must either be in the repo for the quiz context defined by a supplied quiz manifest " .
"(--quizmanifestpath) or in the course context " .
"defined by a different manifest (--nonquizmanifestpath).\n";
echo "You can supply either or both.\n";
echo "Aborting.\n";
$this->call_exit();;
}
if ($manifestentry) {
$this->postsettings["questions[{$questionkey}][questionbankentryid]"] = $manifestentry->questionbankentryid;
} else {
$multiple = ($this->quizmanifestpath && $this->nonquizmanifestpath) ? 's' : '';
echo "Question: {$qidentifier}\n";
echo "This question is in the quiz but not in the supplied manifest file" . $multiple . ".\n";
echo "Questions must either be in the repo for the quiz context defined by a supplied quiz manifest " .
"(--quizmanifestpath) or in the course context " .
"defined by a different manifest (--nonquizmanifestpath).\n";
echo "You can supply either or both.\n";
echo "Aborting.\n";
$this->call_exit();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"context": {
"contextlevel": 10,
"contextlevel": 50,
"coursename": "",
"modulename": "",
"coursecategory": "",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"context": {
"contextlevel": 50,
"coursename": "",
"modulename": "",
"coursecategory": "",
"instanceid": "5",
"defaultsubdirectory": "top\/cat-2",
"defaultsubcategoryid": 5
},
"questions": [
{
"questionbankentryid": "35001",
"filepath": "\/top\/cat-1\/First-Question.xml",
"importedversion": "1",
"exportedversion": "1",
"format": "xml"
},
{
"questionbankentryid": "35002",
"filepath": "\/top\/cat-2\/subcat-2_1\/Third-Question.xml",
"importedversion": "6",
"exportedversion": "7",
"format": "xml"
},
{
"questionbankentryid": "35004",
"filepath": "\/top\/cat-2\/subcat-2_1\/Fourth-Question.xml",
"importedversion": "1",
"exportedversion": "1",
"currentcommit": "35004test",
"format": "xml"
},
{
"questionbankentryid": "35003",
"filepath": "\/top\/cat-2\/Second-Question.xml",
"importedversion": "1",
"exportedversion": "1",
"format": "xml"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"context": {
"contextlevel": 70,
"coursename": "",
"modulename": "Import quiz",
"coursecategory": "",
"instanceid": "",
"defaultsubdirectory": "top",
"defaultsubcategoryid": 5
},
"questions": [
{
"questionbankentryid": "36001",
"filepath": "\/top\/Quiz-Question.xml",
"importedversion": "1",
"exportedversion": "1",
"format": "xml"
},
{
"questionbankentryid": "36002",
"filepath": "\/top\/quiz-cat\/Quiz-Question-2.xml",
"importedversion": "1",
"exportedversion": "1",
"format": "xml"
}
]
}
39 changes: 39 additions & 0 deletions testrepoparent/testrepo_quiz_quiz-1/import-quiz_quiz.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"quiz": {
"name": "Quiz 1",
"intro": "Quiz intro",
"introformat": "0",
"questionsperpage": "0",
"grade": "100.00000",
"navmethod": "free"
},
"sections": [
{
"firstslot": "1",
"heading": "Heading 1",
"shufflequestions": 0
},
{
"firstslot": "2",
"heading": "Heading 2",
"shufflequestions": 0
}
],
"questions": [
{
"quizfilepath": "\/top\/Quiz-Question.xml",
"slot": "1",
"page": "1",
"requireprevious": 0,
"maxmark": "1.0000000"
}
],
"feedback": [
{
"feedbacktext": "Quiz feedback",
"feedbacktextformat": "0",
"mingrade": "0.0000000",
"maxgrade": "50.000000"
}
]
}
18 changes: 9 additions & 9 deletions tests/export_quiz_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// along with Stack. If not, see <http://www.gnu.org/licenses/>.

/**
* Unit tests for export repo command line script for gitsync
* Unit tests for export quiz command line script for gitsync
*
* @package qbank_gitsync
* @copyright 2023 The Open University
Expand Down Expand Up @@ -75,7 +75,7 @@ class export_quiz_test extends advanced_testcase {
/** @var string root of virtual file system */
public string $rootpath;
/** @var string used to store output of multiple calls to a function */
const MOODLE = 'fakeexportquiz'; /** Name of question to be generated and exported. */
const MOODLE = 'fakeexportquiz';
const QUIZNAME = 'Quiz 1';
const QUIZINTRO = 'Quiz intro';
const FEEDBACK = 'Quiz feedback';
Expand Down Expand Up @@ -179,7 +179,7 @@ public function set_up_mocks() {
/**
* Test the full process.
*/
public function x_test_process(): void {
public function test_process(): void {
$this->set_up_mocks();
$this->curl->expects($this->exactly(1))->method('execute')->willReturnOnConsecutiveCalls(
json_encode($this->quizoutput)
Expand All @@ -198,7 +198,7 @@ public function x_test_process(): void {
/**
* Test message if export JSON broken.
*/
public function x_test_broken_json_on_export(): void {
public function test_broken_json_on_export(): void {
$this->set_up_mocks();
$this->curl->expects($this->any())->method('execute')->willReturn(
'{"quiz": </Question>"}'
Expand All @@ -213,7 +213,7 @@ public function x_test_broken_json_on_export(): void {
/**
* Test message if export exception.
*/
public function x_test_exception_on_export(): void {
public function test_exception_on_export(): void {
$this->set_up_mocks();
$this->curl->expects($this->any())->method('execute')->willReturn(
'{"exception":"moodle_exception","message":"No token"}'
Expand All @@ -227,7 +227,7 @@ public function x_test_exception_on_export(): void {
/**
* Test message if manifest file update issue.
*/
public function x_test_manifest_file_update_error(): void {
public function test_manifest_file_update_error(): void {
$this->set_up_mocks();
$this->curl->expects($this->any())->method('execute')->willReturn(
json_encode($this->quizoutput)
Expand All @@ -243,7 +243,7 @@ public function x_test_manifest_file_update_error(): void {
/**
* Test if quiz context questions.
*/
public function x_test_quiz_context_questions(): void {
public function test_quiz_context_questions(): void {
$this->quizoutput['questions'][] =
[
'questionbankentryid' => '36002',
Expand Down Expand Up @@ -271,7 +271,7 @@ public function x_test_quiz_context_questions(): void {
/**
* Test if course context questions.
*/
public function x_test_course_context_questions(): void {
public function test_course_context_questions(): void {
$this->quizoutput['questions'] = [
[
'questionbankentryid' => '35002',
Expand Down Expand Up @@ -307,7 +307,7 @@ public function x_test_course_context_questions(): void {
/**
* Test if missing questions.
*/
public function x_test_missing_questions(): void {
public function test_missing_questions(): void {
$this->quizoutput['questions'] = [
[
'questionbankentryid' => '35002',
Expand Down
Loading

0 comments on commit ec21d9d

Please sign in to comment.