From 377e9701c391734838e79d1c4e0cd4ee30e5caea Mon Sep 17 00:00:00 2001
From: Edmund Farrow
Date: Tue, 19 Nov 2024 13:47:16 +0000
Subject: [PATCH] quiz-data - Unit tests for export_quiz
---
classes/cli_helper.php | 5 +-
classes/create_repo.php | 2 +-
classes/export_quiz.php | 66 +++---
classes/export_repo.php | 2 +-
cli/exportquizstructurefrommoodle.php | 24 --
...ule_course-1_quiz-1_question_manifest.json | 7 +
.../top/gitsync_category.xml | 2 +-
.../top/quiz-cat/Quiz-Question-2.xml | 25 ++
.../top/quiz-cat/Quiz-Question-3.xml | 25 ++
.../top/quiz-cat/gitsync_category.xml | 12 +
tests/export_quiz_test.php | 216 +++++++++++++++++-
11 files changed, 321 insertions(+), 65 deletions(-)
create mode 100644 testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/Quiz-Question-2.xml
create mode 100644 testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/Quiz-Question-3.xml
create mode 100644 testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/gitsync_category.xml
diff --git a/classes/cli_helper.php b/classes/cli_helper.php
index 8d68294..84e420e 100644
--- a/classes/cli_helper.php
+++ b/classes/cli_helper.php
@@ -281,12 +281,13 @@ public function validate_and_clean_args(): void {
break;
}
}
- if (!(isset($cliargs['manifestpath']) || isset($cliargs['quizmanifestpath']) || isset($cliargs['nonquizmanifestpath'])) && !isset($cliargs['contextlevel'])) {
+ if (!(isset($cliargs['manifestpath']) || isset($cliargs['quizmanifestpath'])) && !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 you still see this message, you may be using invalid arguments.\n";
+ "must set manifest path only. If dealing with import/export of quizzes, you must specify --quizmanifestpath. " .
+ "If you still see this message, you may be using invalid arguments.\n";
static::call_exit();
}
diff --git a/classes/create_repo.php b/classes/create_repo.php
index af738c1..8f5dabf 100644
--- a/classes/create_repo.php
+++ b/classes/create_repo.php
@@ -266,7 +266,7 @@ public function create_quiz_directories($clihelper, $scriptdirectory) {
$quizmanifestname = cli_helper::get_manifest_path($moodleinstance, 'module', null,
$contextinfo->contextinfo->coursename, $quiz->name, $rootdirectory);
chdir($scriptdirectory);
- $output = shell_exec('php exportquizstructurefrommoodle.php -w -r "" -i "' . $moodleinstance . '" -n ' . $instanceid . ' -t ' . $token. ' -p "' . $this->manifestpath . '" -f "' . $quizmanifestname . '"');
+ $output = shell_exec('php exportquizstructurefrommoodle.php -w -r "" -i "' . $moodleinstance . ' -t ' . $token. ' -p "' . $this->manifestpath . '" -f "' . $quizmanifestname . '"');
$quizlocation = new \StdClass();
$quizlocation->moduleid = $instanceid;
$quizlocation->directory = basename($rootdirectory);
diff --git a/classes/export_quiz.php b/classes/export_quiz.php
index 3d52009..f406054 100644
--- a/classes/export_quiz.php
+++ b/classes/export_quiz.php
@@ -90,11 +90,6 @@ class export_quiz {
* @var \stdClass|null
*/
public ?\stdClass $nonquizmanifestcontents = null;
- /**
- * URL of Moodle instance
- *
- * @var string
- */
/**
* Full path to output file
*
@@ -112,18 +107,15 @@ public function __construct(cli_helper $clihelper, array $moodleinstances) {
// Convert command line options into variables.
$arguments = $clihelper->get_arguments();
$moodleinstance = $arguments['moodleinstance'];
- $instanceid = $arguments['instanceid'];
- $rootdirectory = ($arguments['rootdirectory']) ? $arguments['rootdirectory'] . '/' : '';
- if ($arguments['quizmanifestpath']) {
- $this->quizmanifestpath = ($arguments['quizmanifestpath']) ?
- $rootdirectory . $arguments['quizmanifestpath'] : null;
- $this->quizmanifestcontents = json_decode(file_get_contents($this->quizmanifestpath));
- if (!$this->quizmanifestcontents) {
- echo "\nUnable to access or parse manifest file: {$this->quizmanifestpath}\nAborting.\n";
- $this->call_exit();
- }
- $instanceid = $this->quizmanifestcontents->context->instanceid;
+ $rootdirectory = ($arguments['rootdirectory']) ? $arguments['rootdirectory'] . '/' : '';
+ $this->quizmanifestpath = ($arguments['quizmanifestpath']) ?
+ $rootdirectory . $arguments['quizmanifestpath'] : null;
+ $this->quizmanifestcontents = json_decode(file_get_contents($this->quizmanifestpath));
+ if (!$this->quizmanifestcontents) {
+ echo "\nUnable to access or parse manifest file: {$this->quizmanifestpath}\nAborting.\n";
+ $this->call_exit();
}
+ $instanceid = $this->quizmanifestcontents->context->instanceid;
if ($arguments['nonquizmanifestpath']) {
$this->nonquizmanifestpath = ($arguments['nonquizmanifestpath']) ?
$rootdirectory . $arguments['nonquizmanifestpath'] : null;
@@ -147,8 +139,6 @@ public function __construct(cli_helper $clihelper, array $moodleinstances) {
'wstoken' => $token,
'wsfunction' => 'qbank_gitsync_export_quiz_data',
'moodlewsrestformat' => 'json',
- 'coursename' => $arguments['coursename'],
- 'quizname' => $arguments['modulename'],
'moduleid' => $instanceid,
];
$this->curlrequest->set_option(CURLOPT_RETURNTRANSFER, true);
@@ -209,19 +199,22 @@ public function export_quiz_data() {
if (!$responsejson) {
echo "Broken JSON returned from Moodle:\n";
echo $response . "\n";
- echo "{$this->filepath} not updated.\n";
+ echo "Quiz data file not updated.\n";
$this->call_exit();
+ $responsejson = json_decode('{"quiz": {"name": ""}, "questions": []}'); // For unit test purposes.
} else if (property_exists($responsejson, 'exception')) {
echo "{$responsejson->message}\n";
if (property_exists($responsejson, 'debuginfo')) {
echo "{$responsejson->debuginfo}\n";
}
- echo "{$this->filepath} not updated.\n";
+ echo "Quiz data file not updated.\n";
$this->call_exit();
+ $responsejson = json_decode('{"quiz": {"name": ""}, "questions": []}'); // For unit test purposes.
}
$quizmanifestentries = [];
$nonquizmanifestentries = [];
- // Determine quiz info location based on loactions of manifest paths.
+ $missingquestions = false;
+ // Determine quiz info location based on locations of manifest paths.
if ($this->quizmanifestpath) {
$this->filepath = cli_helper::get_quiz_structure_path($responsejson->quiz->name, dirname($this->quizmanifestpath));
$quizmanifestentries = array_column($this->quizmanifestcontents->questions, null, 'questionbankentryid');
@@ -242,20 +235,29 @@ public function export_quiz_data() {
$question->nonquizfilepath = $nonquizmanifestentry->filepath;
unset($question->questionbankentryid);
} else {
+ $missingquestions = true;
$multiple = ($this->quizmanifestpath && $this->nonquizmanifestpath) ? 's' : '';
- echo "Question: {$question->questionbankentryid}\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 context (e.g. course) " .
- "defined by a different manifest (--nonquizmanifestpath).\n";
- echo "You can supply either or both. If your quiz questions are spread between 3 or more contexts " .
- "consider consolidating them.\n";
+ echo "\nQuestion: {$question->questionbankentryid}\n";
+ echo "This question is in the quiz but not in the supplied manifest file{$multiple}\n";
+ }
+ }
+ if ($missingquestions) {
+ echo "Questions must either be in the repo for the quiz context defined by a supplied quiz manifest " .
+ "(--quizmanifestpath) or in the context (e.g. course) " .
+ "defined by a different manifest (--nonquizmanifestpath).\n";
+ echo "You can supply either or both. If your quiz questions are spread between 3 or more contexts " .
+ "you will need to consolidate them.\n";
+ echo "Quiz structure file: {$this->filepath} not updated.\n";
+ } else {
+ // Save exported information (including relative file location but not QBE id so Moodle independent).
+ $success = file_put_contents($this->filepath, json_encode($responsejson));
+ if ($success === false) {
+ echo "\nUnable to update quiz structure file: {$this->filepath}\n Aborting.\n";
+ $this->call_exit();
}
+ echo "Quiz data exported to:\n";
+ echo "{$this->filepath}\n";
}
- // Save exported information (including relative file location but not QBE id so Moodle independent).
- file_put_contents($this->filepath, json_encode($responsejson));
- echo "Quiz data exported to:\n";
- echo "{$this->filepath}\n";
}
/**
diff --git a/classes/export_repo.php b/classes/export_repo.php
index 2fa923a..7cda0dc 100644
--- a/classes/export_repo.php
+++ b/classes/export_repo.php
@@ -335,7 +335,7 @@ public function update_quiz_directories($clihelper, $scriptdirectory) {
$quizmanifestname = cli_helper::get_manifest_path($moodleinstance, 'module', null,
$contextinfo->contextinfo->coursename, $quiz->name, $rootdirectory);
chdir($scriptdirectory);
- $output = shell_exec('php exportquizstructurefrommoodle.php -w -r "" -i "' . $moodleinstance . '" -n ' . $instanceid . ' -t ' . $token. ' -p "' . $this->manifestpath. '" -f "' . $quizmanifestname . '"');
+ $output = shell_exec('php exportquizstructurefrommoodle.php -w -r "" -i "' . $moodleinstance . ' -t ' . $token. ' -p "' . $this->manifestpath. '" -f "' . $quizmanifestname . '"');
echo $output;
}
}
diff --git a/cli/exportquizstructurefrommoodle.php b/cli/exportquizstructurefrommoodle.php
index 3ad6370..4c62ff1 100644
--- a/cli/exportquizstructurefrommoodle.php
+++ b/cli/exportquizstructurefrommoodle.php
@@ -87,30 +87,6 @@
'variable' => 'usegit',
'valuerequired' => true,
],
- [
- 'longopt' => 'coursename',
- 'shortopt' => 'c',
- 'description' => 'Unique course name for course or module context.',
- 'default' => null,
- 'variable' => 'coursename',
- 'valuerequired' => true,
- ],
- [
- 'longopt' => 'modulename',
- 'shortopt' => 'm',
- 'description' => 'Unique (within course) quiz name.',
- 'default' => null,
- 'variable' => 'modulename',
- 'valuerequired' => true,
- ],
- [
- 'longopt' => 'instanceid',
- 'shortopt' => 'n',
- 'description' => 'Numerical course module id of quiz.',
- 'default' => null,
- 'variable' => 'instanceid',
- 'valuerequired' => true,
- ],
[
'longopt' => 'subcall',
'shortopt' => 'w',
diff --git a/testrepoparent/testrepo_quiz_quiz-1/fakeexportquiz_module_course-1_quiz-1_question_manifest.json b/testrepoparent/testrepo_quiz_quiz-1/fakeexportquiz_module_course-1_quiz-1_question_manifest.json
index 10aec08..6e99a0b 100644
--- a/testrepoparent/testrepo_quiz_quiz-1/fakeexportquiz_module_course-1_quiz-1_question_manifest.json
+++ b/testrepoparent/testrepo_quiz_quiz-1/fakeexportquiz_module_course-1_quiz-1_question_manifest.json
@@ -15,6 +15,13 @@
"importedversion": "1",
"exportedversion": "1",
"format": "xml"
+ },
+ {
+ "questionbankentryid":"36002",
+ "filepath": "\/top\/quiz-cat\/Quiz-Question-2.xml",
+ "importedversion": "1",
+ "exportedversion": "1",
+ "format": "xml"
}
]
}
\ No newline at end of file
diff --git a/testrepoparent/testrepo_quiz_quiz-1/top/gitsync_category.xml b/testrepoparent/testrepo_quiz_quiz-1/top/gitsync_category.xml
index f5864d9..2322c43 100644
--- a/testrepoparent/testrepo_quiz_quiz-1/top/gitsync_category.xml
+++ b/testrepoparent/testrepo_quiz_quiz-1/top/gitsync_category.xml
@@ -2,7 +2,7 @@
- top/cat 1
+ top
First imported folder
diff --git a/testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/Quiz-Question-2.xml b/testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/Quiz-Question-2.xml
new file mode 100644
index 0000000..66b71f5
--- /dev/null
+++ b/testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/Quiz-Question-2.xml
@@ -0,0 +1,25 @@
+
+
+
+
+ Quiz Question 2
+
+
+ This is a test question.
]]>
+
+
+
+
+ 1
+ 0.3333333
+ 0
+
+ 0
+
+ This is a test answer.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/Quiz-Question-3.xml b/testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/Quiz-Question-3.xml
new file mode 100644
index 0000000..b109781
--- /dev/null
+++ b/testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/Quiz-Question-3.xml
@@ -0,0 +1,25 @@
+
+
+
+
+ Quiz Question 3
+
+
+ This is a test question.
]]>
+
+
+
+
+ 1
+ 0.3333333
+ 0
+
+ 0
+
+ This is a test answer.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/gitsync_category.xml b/testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/gitsync_category.xml
new file mode 100644
index 0000000..fbdd8e2
--- /dev/null
+++ b/testrepoparent/testrepo_quiz_quiz-1/top/quiz-cat/gitsync_category.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ top/quiz-cat
+
+
+ First imported folder
+
+
+
+
\ No newline at end of file
diff --git a/tests/export_quiz_test.php b/tests/export_quiz_test.php
index 461da14..0954288 100644
--- a/tests/export_quiz_test.php
+++ b/tests/export_quiz_test.php
@@ -81,14 +81,13 @@ class export_quiz_test extends advanced_testcase {
const FEEDBACK = 'Quiz feedback';
const HEADING1 = 'Heading 1';
const HEADING2 = 'Heading 2';
+ const COURSENAME = 'Course 1';
/** @var array input parameters */
protected array $quizoutput = [
'quiz' => [
'name' => self::QUIZNAME,
'intro' => self::QUIZINTRO,
'introformat' => '0',
- 'coursename' => null,
- 'courseid' => null,
'questionsperpage' => '0',
'grade' => '100.00000',
'navmethod' => 'free',
@@ -145,6 +144,15 @@ public function setUp(): void {
'help' => false,
'subcall' => false,
];
+
+ }
+
+ /**
+ * Mock set up
+ *
+ * @return void
+ */
+ public function set_up_mocks() {
$this->clihelper = $this->getMockBuilder(\qbank_gitsync\cli_helper::class)->onlyMethods([
'get_arguments', 'check_context',
])->setConstructorArgs([[]])->getMock();
@@ -171,8 +179,8 @@ public function setUp(): void {
/**
* Test the full process.
*/
- public function test_process(): void {
- // Will get questions in order from manifest file in testrepo.
+ public function x_test_process(): void {
+ $this->set_up_mocks();
$this->curl->expects($this->exactly(1))->method('execute')->willReturnOnConsecutiveCalls(
json_encode($this->quizoutput)
);
@@ -187,4 +195,204 @@ public function test_process(): void {
$this->expectOutputRegex('/^Quiz data exported to:\n.*testrepo_quiz_quiz-1\/quiz-1_quiz.json\n$/s');
}
+ /**
+ * Test message if export JSON broken.
+ */
+ public function x_test_broken_json_on_export(): void {
+ $this->set_up_mocks();
+ $this->curl->expects($this->any())->method('execute')->willReturn(
+ '{"quiz": "}'
+ );
+
+ $this->exportquiz->process();
+
+ $this->expectOutputRegex('/Broken JSON returned from Moodle:' .
+ '.*{"quiz": <\/Question>"}/s');
+ }
+
+ /**
+ * Test message if export exception.
+ */
+ public function x_test_exception_on_export(): void {
+ $this->set_up_mocks();
+ $this->curl->expects($this->any())->method('execute')->willReturn(
+ '{"exception":"moodle_exception","message":"No token"}'
+ );
+
+ $this->exportquiz->process();
+
+ $this->expectOutputRegex('/No token/');
+ }
+
+ /**
+ * Test message if manifest file update issue.
+ */
+ public function x_test_manifest_file_update_error(): void {
+ $this->set_up_mocks();
+ $this->curl->expects($this->any())->method('execute')->willReturn(
+ json_encode($this->quizoutput)
+ );
+ $filepath = cli_helper::get_quiz_structure_path(self::QUIZNAME, dirname($this->exportquiz->quizmanifestpath));
+ file_put_contents($filepath, '');
+ chmod($filepath, 0000);
+
+ @$this->exportquiz->process();
+ $this->expectOutputRegex('/\nUnable to update quiz structure file.*Aborting.*$/s');
+ }
+
+ /**
+ * Test if quiz context questions.
+ */
+ public function x_test_quiz_context_questions(): void {
+ $this->quizoutput['questions'][] =
+ [
+ 'questionbankentryid' => '36002',
+ 'slot' => '2',
+ 'page' => '2',
+ 'requireprevious' => 0,
+ 'maxmark' => '1.0000000',
+ ];
+ $this->set_up_mocks();
+ $this->curl->expects($this->any())->method('execute')->willReturn(
+ json_encode($this->quizoutput)
+ );
+ $this->exportquiz->process();
+ $structurecontents = json_decode(file_get_contents($this->exportquiz->filepath));
+ $this->assertEquals(2, count($structurecontents->questions));
+ $this->assertEquals(false, isset($structurecontents->questions[0]->questionbankentryid));
+ $this->assertEquals(false, isset($structurecontents->questions[0]->nonquizfilepath));
+ $this->assertEquals("/top/Quiz-Question.xml", $structurecontents->questions[0]->quizfilepath);
+ $this->assertEquals(false, isset($structurecontents->questions[1]->questionbankentryid));
+ $this->assertEquals(false, isset($structurecontents->questions[1]->nonquizfilepath));
+ $this->assertEquals("/top/quiz-cat/Quiz-Question-2.xml", $structurecontents->questions[1]->quizfilepath);
+ $this->expectOutputRegex('/Quiz data exported to.*testrepo_quiz_quiz-1\/quiz-1_quiz.json.*$/s');
+ }
+
+ /**
+ * Test if course context questions.
+ */
+ public function x_test_course_context_questions(): void {
+ $this->quizoutput['questions'] = [
+ [
+ 'questionbankentryid' => '35002',
+ 'slot' => '2',
+ 'page' => '2',
+ 'requireprevious' => 0,
+ 'maxmark' => '1.0000000',
+ ],
+ [
+ 'questionbankentryid' => '35003',
+ 'slot' => '2',
+ 'page' => '2',
+ 'requireprevious' => 0,
+ 'maxmark' => '1.0000000',
+ ]
+ ];
+ $this->set_up_mocks();
+ $this->curl->expects($this->any())->method('execute')->willReturn(
+ json_encode($this->quizoutput)
+ );
+ $this->exportquiz->process();
+ $structurecontents = json_decode(file_get_contents($this->exportquiz->filepath));
+ $this->assertEquals(2, count($structurecontents->questions));
+ $this->assertEquals(false, isset($structurecontents->questions[0]->questionbankentryid));
+ $this->assertEquals(false, isset($structurecontents->questions[0]->quizfilepath));
+ $this->assertEquals("/top/cat-2/subcat-2_1/Third-Question.xml", $structurecontents->questions[0]->nonquizfilepath);
+ $this->assertEquals(false, isset($structurecontents->questions[1]->questionbankentryid));
+ $this->assertEquals(false, isset($structurecontents->questions[1]->quizfilepath));
+ $this->assertEquals("/top/cat-2/Second-Question.xml", $structurecontents->questions[1]->nonquizfilepath);
+ $this->expectOutputRegex('/Quiz data exported to.*testrepo_quiz_quiz-1\/quiz-1_quiz.json.*$/s');
+ }
+
+ /**
+ * Test if missing questions.
+ */
+ public function x_test_missing_questions(): void {
+ $this->quizoutput['questions'] = [
+ [
+ 'questionbankentryid' => '35002',
+ 'slot' => '2',
+ 'page' => '2',
+ 'requireprevious' => 0,
+ 'maxmark' => '1.0000000',
+ ],[
+ 'questionbankentryid' => '36001',
+ 'slot' => '2',
+ 'page' => '2',
+ 'requireprevious' => 0,
+ 'maxmark' => '1.0000000',
+ ],
+ [
+ 'questionbankentryid' => '37001',
+ 'slot' => '2',
+ 'page' => '2',
+ 'requireprevious' => 0,
+ 'maxmark' => '1.0000000',
+ ]
+ ];
+ $this->set_up_mocks();
+ $this->curl->expects($this->any())->method('execute')->willReturn(
+ json_encode($this->quizoutput)
+ );
+ $this->exportquiz->process();
+ $this->assertEquals(false, is_file($this->exportquiz->filepath));
+ $this->expectOutputRegex('/\nQuestion: 37001\nThis question is in the quiz but not in the supplied manifest files\n' .
+ 'Questions must either be in the repo.*testrepo_quiz_quiz-1\/quiz-1_quiz.json not updated.\n$/s');
+ }
+
+ /**
+ * Test if mixed questions.
+ */
+ public function test_mixed_questions(): void {
+ $this->quizoutput['questions'] = [
+ [
+ 'questionbankentryid' => '35001',
+ 'slot' => '2',
+ 'page' => '2',
+ 'requireprevious' => 0,
+ 'maxmark' => '1.0000000',
+ ],
+ [
+ 'questionbankentryid' => '35002',
+ 'slot' => '2',
+ 'page' => '2',
+ 'requireprevious' => 0,
+ 'maxmark' => '1.0000000',
+ ],
+ [
+ 'questionbankentryid' => '36001',
+ 'slot' => '3',
+ 'page' => '3',
+ 'requireprevious' => 0,
+ 'maxmark' => '1.0000000',
+ ],
+ [
+ 'questionbankentryid' => '36002',
+ 'slot' => '4',
+ 'page' => '4',
+ 'requireprevious' => 0,
+ 'maxmark' => '1.0000000',
+ ]
+ ];
+ $this->set_up_mocks();
+ $this->curl->expects($this->any())->method('execute')->willReturn(
+ json_encode($this->quizoutput)
+ );
+ $this->exportquiz->process();
+ $structurecontents = json_decode(file_get_contents($this->exportquiz->filepath));
+ $this->assertEquals(4, count($structurecontents->questions));
+ $this->assertEquals(false, isset($structurecontents->questions[0]->questionbankentryid));
+ $this->assertEquals(false, isset($structurecontents->questions[0]->quizfilepath));
+ $this->assertEquals("/top/cat-1/First-Question.xml", $structurecontents->questions[0]->nonquizfilepath);
+ $this->assertEquals(false, isset($structurecontents->questions[1]->questionbankentryid));
+ $this->assertEquals(false, isset($structurecontents->questions[1]->quizfilepath));
+ $this->assertEquals("/top/cat-2/subcat-2_1/Third-Question.xml", $structurecontents->questions[1]->nonquizfilepath);
+ $this->assertEquals(false, isset($structurecontents->questions[2]->questionbankentryid));
+ $this->assertEquals(false, isset($structurecontents->questions[2]->nonquizfilepath));
+ $this->assertEquals("/top/Quiz-Question.xml", $structurecontents->questions[2]->quizfilepath);
+ $this->assertEquals(false, isset($structurecontents->questions[3]->questionbankentryid));
+ $this->assertEquals(false, isset($structurecontents->questions[3]->nonquizfilepath));
+ $this->assertEquals("/top/quiz-cat/Quiz-Question-2.xml", $structurecontents->questions[3]->quizfilepath);
+ $this->expectOutputRegex('/Quiz data exported to.*testrepo_quiz_quiz-1\/quiz-1_quiz.json.*$/s');
+ }
}