1 |
efrain |
1 |
<?php
|
|
|
2 |
// This file is part of Moodle - http://moodle.org/
|
|
|
3 |
//
|
|
|
4 |
// Moodle is free software: you can redistribute it and/or modify
|
|
|
5 |
// it under the terms of the GNU General Public License as published by
|
|
|
6 |
// the Free Software Foundation, either version 3 of the License, or
|
|
|
7 |
// (at your option) any later version.
|
|
|
8 |
//
|
|
|
9 |
// Moodle is distributed in the hope that it will be useful,
|
|
|
10 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
11 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
12 |
// GNU General Public License for more details.
|
|
|
13 |
//
|
|
|
14 |
// You should have received a copy of the GNU General Public License
|
|
|
15 |
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
16 |
namespace mod_h5pactivity\output\result;
|
|
|
17 |
|
|
|
18 |
use core_xapi\local\statement\item_result;
|
|
|
19 |
use mod_h5pactivity\local\manager;
|
|
|
20 |
|
|
|
21 |
/**
|
|
|
22 |
* Result test class for H5P activity.
|
|
|
23 |
*
|
|
|
24 |
* @package mod_h5pactivity
|
|
|
25 |
* @covers \mod_h5pactivity\output\result
|
|
|
26 |
* @category test
|
|
|
27 |
* @copyright 2023 Laurent David <laurent.david@moodle.com>
|
|
|
28 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
29 |
*/
|
|
|
30 |
class result_test extends \advanced_testcase {
|
|
|
31 |
/**
|
|
|
32 |
* Data provider for result export_options test
|
|
|
33 |
*
|
|
|
34 |
* @return array[]
|
|
|
35 |
*/
|
|
|
36 |
public static function result_data_provider(): array {
|
|
|
37 |
return [
|
|
|
38 |
'fill-in with case sensitive' => [
|
|
|
39 |
'result' => [
|
|
|
40 |
'interactiontype' => 'fill-in',
|
|
|
41 |
'description' => '<p>Fill in the missing words</p>
|
|
|
42 |
<p>Meow .... this is a __________</p>
|
|
|
43 |
<p>Bark... this is a __________</p>',
|
|
|
44 |
'correctpattern' => '["{case_matters=true}cat[,]dog"]',
|
|
|
45 |
'response' => 'Cat[,]dog',
|
|
|
46 |
'additionals' => '{"extensions":{"http:\\/\\/h5p.org\\/x-api\\/h5p-local-content-id":31,'
|
|
|
47 |
. '"https:\\/\\/h5p.org\\/x-api\\/case-sensitivity":true,'
|
|
|
48 |
. '"https:\\/\\/h5p.org\\/x-api\\/alternatives":[["cat"],["dog"]]},"contextExtensions":{}}',
|
|
|
49 |
],
|
|
|
50 |
'useranswers' => [
|
|
|
51 |
'Gap #1 - cat' => (object) ['answer' => 'Cat', 'incorrect' => true],
|
|
|
52 |
'Gap #2 - dog' => (object) ['answer' => 'dog', 'correct' => true],
|
|
|
53 |
],
|
|
|
54 |
],
|
|
|
55 |
'fill-in with case insensitive' => [
|
|
|
56 |
'result' => [
|
|
|
57 |
'interactiontype' => 'fill-in',
|
|
|
58 |
'description' => '<p>Fill in the missing words</p>
|
|
|
59 |
<p>Meow .... this is a __________</p>
|
|
|
60 |
<p>Bark... this is a __________</p>',
|
|
|
61 |
'correctpattern' => '["{case_matters=false}cat[,]dog"]',
|
|
|
62 |
'response' => 'Cat[,]dog',
|
|
|
63 |
'additionals' => '{"extensions":{"http:\\/\\/h5p.org\\/x-api\\/h5p-local-content-id":31,'
|
|
|
64 |
. '"https:\\/\\/h5p.org\\/x-api\\/case-sensitivity":false,'
|
|
|
65 |
. '"https:\\/\\/h5p.org\\/x-api\\/alternatives":[["cat"],["dog"]]},"contextExtensions":{}}',
|
|
|
66 |
],
|
|
|
67 |
'useranswers' => [
|
|
|
68 |
'Gap #1 - cat' => (object) ['answer' => 'Cat', 'correct' => true],
|
|
|
69 |
'Gap #2 - dog' => (object) ['answer' => 'dog', 'correct' => true],
|
|
|
70 |
],
|
|
|
71 |
],
|
|
|
72 |
'drag and drop' => [
|
|
|
73 |
'result' => [
|
|
|
74 |
'interactiontype' => 'matching',
|
|
|
75 |
'description' => 'Drag and Drop Test',
|
|
|
76 |
'correctpattern' => '["0[.]0[,]0[.]2[,]1[.]1[,]1[.]0"]',
|
|
|
77 |
'response' => '0[.]0[,]1[.]1[,]0[.]2[,]0[.]3',
|
|
|
78 |
'additionals' => '{"source":[{"id":"0","description":{"en-US":"Answer 1 (DZ1 and DZ2)\n"}},'
|
|
|
79 |
. '{"id":"1","description":{"en-US":"Anwser 2 (DZ2)\n"}},'
|
|
|
80 |
. '{"id":"2","description":{"en-US":"Anwser 3 (DZ1)\n"}},'
|
|
|
81 |
. '{"id":"3","description":{"en-US":"Anwser 4 (neither)\n"}}],'
|
|
|
82 |
. '"target":[{"id":"0","description":{"en-US":"Dropzone 1\n"}},'
|
|
|
83 |
. '{"id":"1","description":{"en-US":"Dropzone 2\n"}}],'
|
|
|
84 |
. '"extensions":{"http:\/\/h5p.org\/x-api\/h5p-local-content-id":41,'
|
|
|
85 |
. '"http:\/\/h5p.org\/x-api\/h5p-subContentId":"59590246-f16e-4855-8dd6-c80e892ef96b"},'
|
|
|
86 |
. '"contextExtensions":{}}',
|
|
|
87 |
],
|
|
|
88 |
'useranswers' => [
|
|
|
89 |
'Answer 1 (DZ1 and DZ2) - Dropzone 1, Dropzone 2' => (object) ['answer' => 'Dropzone 1', 'correct' => true],
|
|
|
90 |
'Anwser 2 (DZ2) - Dropzone 2' => (object) ['answer' => 'Dropzone 2', 'correct' => true],
|
|
|
91 |
'Anwser 3 (DZ1) - Dropzone 1' => (object) ['answer' => 'Dropzone 1', 'correct' => true],
|
|
|
92 |
'Anwser 4 (neither) - ' => (object) ['answer' => 'Dropzone 1', 'incorrect' => true],
|
|
|
93 |
],
|
|
|
94 |
],
|
|
|
95 |
'drag and drop with no answer' => [
|
|
|
96 |
'result' => [
|
|
|
97 |
'interactiontype' => 'matching',
|
|
|
98 |
'description' => 'Drag and Drop Test',
|
|
|
99 |
'correctpattern' => '["0[.]0[,]0[.]2[,]1[.]1[,]1[.]0"]',
|
|
|
100 |
'response' => '1[.]0[,]1[.]1',
|
|
|
101 |
'additionals' => '{"source":[{"id":"0","description":{"en-US":"Answer 1 (DZ1 and DZ2)\n"}},'
|
|
|
102 |
. '{"id":"1","description":{"en-US":"Anwser 2 (DZ2)\n"}},'
|
|
|
103 |
. '{"id":"2","description":{"en-US":"Anwser 3 (DZ1)\n"}},'
|
|
|
104 |
. '{"id":"3","description":{"en-US":"Anwser 4 (neither)\n"}}],'
|
|
|
105 |
. '"target":[{"id":"0","description":{"en-US":"Dropzone 1\n"}},'
|
|
|
106 |
. '{"id":"1","description":{"en-US":"Dropzone 2\n"}}],'
|
|
|
107 |
. '"extensions":{"http:\/\/h5p.org\/x-api\/h5p-local-content-id":41,'
|
|
|
108 |
. '"http:\/\/h5p.org\/x-api\/h5p-subContentId":"59590246-f16e-4855-8dd6-c80e892ef96b"},'
|
|
|
109 |
. '"contextExtensions":{}}',
|
|
|
110 |
],
|
|
|
111 |
'useranswers' => [
|
|
|
112 |
'Answer 1 (DZ1 and DZ2) - Dropzone 1, Dropzone 2' => (object) ['answer' => 'Dropzone 2', 'correct' => true],
|
|
|
113 |
'Anwser 2 (DZ2) - Dropzone 2' => (object) ['answer' => 'Dropzone 2', 'correct' => true],
|
|
|
114 |
'Anwser 3 (DZ1) - Dropzone 1' => (object) ['answer' => 'None', 'incorrect' => true],
|
|
|
115 |
'Anwser 4 (neither) - ' => (object) ['answer' => 'None', 'correct' => true],
|
|
|
116 |
],
|
|
|
117 |
],
|
|
|
118 |
'sort the paragraph text' => [
|
|
|
119 |
'result' => [
|
|
|
120 |
'interactiontype' => 'sequencing',
|
|
|
121 |
'description' => 'SortParagraphs',
|
|
|
122 |
'correctpattern' => '["0[,]1[,]2[,]3[,]4"]',
|
|
|
123 |
'response' => '0[,]1[,]3[,]2[,]4',
|
|
|
124 |
'additionals' => '{"choices":[{"id":0,"description":{"en":"First I wake up at 7.30 am\\n",'
|
|
|
125 |
. '"en-US":"First I wake up at 7.30 am\\n"}}'
|
|
|
126 |
. ',{"id":1,"description":{"en":"Next I get dressed\\n","en-US":"Next I get dressed\\n"}},'
|
|
|
127 |
. '{"id":2,"description":{"en":"Afterward I have breakfast\\n","en-US":"Afterward I have breakfast\\n"}},'
|
|
|
128 |
. '{"id":3,"description":{"en":"I brush my teeth\\n","en-US":"I brush my teeth\\n"}},'
|
|
|
129 |
. '{"id":4,"description":{"en":"Finally I go school\\n","en-US":"Finally I go school\\n"}}],'
|
|
|
130 |
.
|
|
|
131 |
'"extensions":{"http:\\/\\/h5p.org\\/x-api\\/h5p-local-content-id":39,'
|
|
|
132 |
. '"https:\\/\\/h5p.org\\/x-api\\/duplicates-interchangeable":1},"contextExtensions":{}}',
|
|
|
133 |
],
|
|
|
134 |
'useranswers' => [
|
|
|
135 |
'#1 - First I wake up at 7.30 am' => (object) ['answer' => 'Correct answer', 'pass' => true],
|
|
|
136 |
'#2 - Next I get dressed' => (object) ['answer' => 'Correct answer', 'pass' => true],
|
|
|
137 |
'#3 - Afterward I have breakfast' => (object) ['answer' => 'Incorrect answer', 'fail' => true],
|
|
|
138 |
'#4 - I brush my teeth' => (object) ['answer' => 'Incorrect answer', 'fail' => true],
|
|
|
139 |
'#5 - Finally I go school' => (object) ['answer' => 'Correct answer', 'pass' => true],
|
|
|
140 |
],
|
|
|
141 |
],
|
|
|
142 |
'sequencing images' => [
|
|
|
143 |
'result' => [
|
|
|
144 |
'interactiontype' => 'sequencing',
|
|
|
145 |
'description' => 'Order the planets from smallest to largest',
|
|
|
146 |
'correctpattern' => '["item_3[,]item_0[,]item_7[,]item_1[,]item_5[,]item_2[,]item_4[,]item_6"]',
|
|
|
147 |
'response' => 'item_0[,]item_1[,]item_3[,]item_2[,]item_5[,]item_4[,]item_6[,]item_7',
|
|
|
148 |
'additionals' => '{"choices":[{"id":"item_3","description":{"en-US":"Mercury"}},'
|
|
|
149 |
. '{"id":"item_0","description":{"en-US":"Mars"}},{"id":"item_7","description":{"en-US":"Earth"}},'
|
|
|
150 |
. '{"id":"item_1","description":{"en-US":"Venus"}},{"id":"item_5","description":{"en-US":"Uranus"}},'
|
|
|
151 |
. '{"id":"item_2","description":{"en-US":"Neptune"}},{"id":"item_4","description":{"en-US":"Saturn"}},'
|
|
|
152 |
. '{"id":"item_6","description":{"en-US":"Jupiter"}}],"extensions":'
|
|
|
153 |
. '{"http:\/\/h5p.org\/x-api\/h5p-local-content-id":43},"contextExtensions":{}}',
|
|
|
154 |
],
|
|
|
155 |
'useranswers' => [
|
|
|
156 |
'#1 - Mercury' => (object) ['answer' => 'Correct answer', 'pass' => true],
|
|
|
157 |
'#2 - Mars' => (object) ['answer' => 'Correct answer', 'pass' => true],
|
|
|
158 |
'#3 - Earth' => (object) ['answer' => 'Incorrect answer', 'fail' => true],
|
|
|
159 |
'#4 - Venus' => (object) ['answer' => 'Incorrect answer', 'fail' => true],
|
|
|
160 |
'#5 - Uranus' => (object) ['answer' => 'Incorrect answer', 'fail' => true],
|
|
|
161 |
'#6 - Neptune' => (object) ['answer' => 'Incorrect answer', 'fail' => true],
|
|
|
162 |
'#7 - Saturn' => (object) ['answer' => 'Correct answer', 'pass' => true],
|
|
|
163 |
'#8 - Jupiter' => (object) ['answer' => 'Correct answer', 'pass' => true],
|
|
|
164 |
],
|
|
|
165 |
],
|
|
|
166 |
];
|
|
|
167 |
}
|
|
|
168 |
|
|
|
169 |
/**
|
|
|
170 |
* Test result export_options
|
|
|
171 |
*
|
|
|
172 |
* @param array $providedresultdata
|
|
|
173 |
* @param array $expecteduseranswers
|
|
|
174 |
* @return void
|
|
|
175 |
* @dataProvider result_data_provider
|
|
|
176 |
* @covers \mod_h5pactivity\output\result::export_options
|
|
|
177 |
*/
|
|
|
178 |
public function test_result_options(array $providedresultdata, array $expecteduseranswers): void {
|
|
|
179 |
$this->resetAfterTest();
|
|
|
180 |
$this->setAdminUser();
|
|
|
181 |
|
|
|
182 |
$course = $this->getDataGenerator()->create_course();
|
|
|
183 |
$activity = $this->getDataGenerator()->create_module('h5pactivity',
|
|
|
184 |
['course' => $course]);
|
|
|
185 |
|
|
|
186 |
$manager = manager::create_from_instance($activity);
|
|
|
187 |
$cm = $manager->get_coursemodule();
|
|
|
188 |
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
|
|
189 |
|
|
|
190 |
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
|
|
|
191 |
|
|
|
192 |
$params = ['cmid' => $cm->id, 'userid' => $student->id];
|
|
|
193 |
$attempt = $generator->create_content($activity, $params);
|
|
|
194 |
$resultdata = [
|
|
|
195 |
'attemptid' => $attempt->id,
|
|
|
196 |
'subcontent' => '',
|
|
|
197 |
'timecreated' => time(),
|
|
|
198 |
'completion' => true,
|
|
|
199 |
'success' => true,
|
|
|
200 |
'score' => (object) ['min' => 0, 'max' => 2, 'raw' => 2, 'scaled' => 1],
|
|
|
201 |
'duration' => 'PT25S',
|
|
|
202 |
];
|
|
|
203 |
$resultdata = array_merge($resultdata, $providedresultdata);
|
|
|
204 |
$result = item_result::create_from_data((object) $resultdata);
|
|
|
205 |
$classname = "mod_h5pactivity\\output\\result\\{$providedresultdata['interactiontype']}";
|
|
|
206 |
$classname = str_replace('-', '', $classname);
|
|
|
207 |
|
|
|
208 |
$reflectionoutput = new \ReflectionClass($classname);
|
|
|
209 |
$constructor = $reflectionoutput->getConstructor();
|
|
|
210 |
$resultoutput = $reflectionoutput->newInstanceWithoutConstructor();
|
|
|
211 |
$constructor->invoke($resultoutput, $result->get_data());
|
|
|
212 |
|
|
|
213 |
$exportoptions = $reflectionoutput->getMethod('export_options');
|
|
|
214 |
|
|
|
215 |
$data = $exportoptions->invoke($resultoutput);
|
|
|
216 |
$useranswersdata = array_map(function($item) {
|
|
|
217 |
return $item->useranswer ?? null;
|
|
|
218 |
}, $data);
|
|
|
219 |
$keys = array_map(function($item) {
|
|
|
220 |
return $item->description . ' - ' . ($item->correctanswer->answer ?? '');
|
|
|
221 |
}, $data);
|
|
|
222 |
|
|
|
223 |
$useranswersdata = array_combine($keys, $useranswersdata);
|
|
|
224 |
$this->assertEquals($expecteduseranswers, $useranswersdata);
|
|
|
225 |
}
|
|
|
226 |
}
|