Differences Between: [Versions 310 and 311] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
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 17 /** 18 * mod_h5pactivity generator tests 19 * 20 * @package mod_h5pactivity 21 * @category test 22 * @copyright 2020 Ferran Recio <ferran@moodle.com> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 namespace mod_h5pactivity\xapi; 27 28 use \core_xapi\local\statement; 29 use \core_xapi\local\statement\item; 30 use \core_xapi\local\statement\item_agent; 31 use \core_xapi\local\statement\item_activity; 32 use \core_xapi\local\statement\item_definition; 33 use \core_xapi\local\statement\item_verb; 34 use \core_xapi\local\statement\item_result; 35 use context_module; 36 use stdClass; 37 38 /** 39 * Attempt tests class for mod_h5pactivity. 40 * 41 * @package mod_h5pactivity 42 * @category test 43 * @copyright 2020 Ferran Recio <ferran@moodle.com> 44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 45 */ 46 class handler_test extends \advanced_testcase { 47 48 /** 49 * Generate a valid scenario for each tests. 50 * 51 * @return stdClass an object with all scenario data in it 52 */ 53 private function generate_testing_scenario(): stdClass { 54 55 $this->resetAfterTest(); 56 $this->setAdminUser(); 57 58 $data = new stdClass(); 59 60 $data->course = $this->getDataGenerator()->create_course(); 61 62 // Generate 2 users, one enroled into course and one not. 63 $data->student = $this->getDataGenerator()->create_and_enrol($data->course, 'student'); 64 $data->otheruser = $this->getDataGenerator()->create_user(); 65 66 // H5P activity. 67 $data->activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $data->course]); 68 $data->context = context_module::instance($data->activity->cmid); 69 70 $data->xapihandler = handler::create('mod_h5pactivity'); 71 $this->assertNotEmpty($data->xapihandler); 72 $this->assertInstanceOf('\mod_h5pactivity\xapi\handler', $data->xapihandler); 73 74 $this->setUser($data->student); 75 76 return $data; 77 } 78 79 /** 80 * Test for xapi_handler with valid statements. 81 */ 82 public function test_xapi_handler() { 83 global $DB; 84 85 $data = $this->generate_testing_scenario(); 86 $xapihandler = $data->xapihandler; 87 $context = $data->context; 88 $student = $data->student; 89 $otheruser = $data->otheruser; 90 91 // Check we have 0 entries in the attempts tables. 92 $count = $DB->count_records('h5pactivity_attempts'); 93 $this->assertEquals(0, $count); 94 $count = $DB->count_records('h5pactivity_attempts_results'); 95 $this->assertEquals(0, $count); 96 97 $statements = $this->generate_statements($context, $student); 98 99 // Insert first statement. 100 $event = $xapihandler->statement_to_event($statements[0]); 101 $this->assertNotNull($event); 102 $count = $DB->count_records('h5pactivity_attempts'); 103 $this->assertEquals(1, $count); 104 $count = $DB->count_records('h5pactivity_attempts_results'); 105 $this->assertEquals(1, $count); 106 107 // Insert second statement. 108 $event = $xapihandler->statement_to_event($statements[1]); 109 $this->assertNotNull($event); 110 $count = $DB->count_records('h5pactivity_attempts'); 111 $this->assertEquals(1, $count); 112 $count = $DB->count_records('h5pactivity_attempts_results'); 113 $this->assertEquals(2, $count); 114 115 // Insert again first statement. 116 $event = $xapihandler->statement_to_event($statements[0]); 117 $this->assertNotNull($event); 118 $count = $DB->count_records('h5pactivity_attempts'); 119 $this->assertEquals(2, $count); 120 $count = $DB->count_records('h5pactivity_attempts_results'); 121 $this->assertEquals(3, $count); 122 123 // Insert again second statement. 124 $event = $xapihandler->statement_to_event($statements[1]); 125 $this->assertNotNull($event); 126 $count = $DB->count_records('h5pactivity_attempts'); 127 $this->assertEquals(2, $count); 128 $count = $DB->count_records('h5pactivity_attempts_results'); 129 $this->assertEquals(4, $count); 130 } 131 132 /** 133 * Testing wrong statements scenarios. 134 * 135 * @dataProvider xapi_handler_errors_data 136 * @param bool $hasverb valid verb 137 * @param bool $hasdefinition generate definition 138 * @param bool $hasresult generate result 139 * @param bool $hascontext valid context 140 * @param bool $hasuser valid user 141 * @param bool $generateattempt if generates an empty attempt 142 */ 143 public function test_xapi_handler_errors(bool $hasverb, bool $hasdefinition, bool $hasresult, 144 bool $hascontext, bool $hasuser, bool $generateattempt) { 145 global $DB, $CFG; 146 147 $data = $this->generate_testing_scenario(); 148 $xapihandler = $data->xapihandler; 149 $context = $data->context; 150 $student = $data->student; 151 $otheruser = $data->otheruser; 152 153 // Check we have 0 entries in the attempts tables. 154 $count = $DB->count_records('h5pactivity_attempts'); 155 $this->assertEquals(0, $count); 156 $count = $DB->count_records('h5pactivity_attempts_results'); 157 $this->assertEquals(0, $count); 158 159 $statement = new statement(); 160 if ($hasverb) { 161 $statement->set_verb(item_verb::create_from_id('http://adlnet.gov/expapi/verbs/completed')); 162 } else { 163 $statement->set_verb(item_verb::create_from_id('cook')); 164 } 165 $definition = null; 166 if ($hasdefinition) { 167 $definition = item_definition::create_from_data((object)[ 168 'interactionType' => 'compound', 169 'correctResponsesPattern' => '1', 170 ]); 171 } 172 if ($hascontext) { 173 $statement->set_object(item_activity::create_from_id($context->id, $definition)); 174 } else { 175 $statement->set_object(item_activity::create_from_id('paella', $definition)); 176 } 177 if ($hasresult) { 178 $statement->set_result(item_result::create_from_data((object)[ 179 'completion' => true, 180 'success' => true, 181 'score' => (object) ['min' => 0, 'max' => 2, 'raw' => 2, 'scaled' => 1], 182 ])); 183 } 184 if ($hasuser) { 185 $statement->set_actor(item_agent::create_from_user($student)); 186 } else { 187 $statement->set_actor(item_agent::create_from_user($otheruser)); 188 } 189 190 $event = $xapihandler->statement_to_event($statement); 191 $this->assertNull($event); 192 // No enties should be generated. 193 $count = $DB->count_records('h5pactivity_attempts'); 194 $attempts = ($generateattempt) ? 1 : 0; 195 $this->assertEquals($attempts, $count); 196 $count = $DB->count_records('h5pactivity_attempts_results'); 197 $this->assertEquals(0, $count); 198 } 199 200 /** 201 * Data provider for data request creation tests. 202 * 203 * @return array 204 */ 205 public function xapi_handler_errors_data(): array { 206 return [ 207 // Invalid Definitions and results possibilities. 208 'Invalid definition and result' => [ 209 true, false, false, true, true, false 210 ], 211 'Invalid result' => [ 212 true, true, false, true, true, false 213 ], 214 'Invalid definition (generate empty attempt)' => [ 215 true, false, true, true, true, true 216 ], 217 // Invalid verb possibilities. 218 'Invalid verb, definition and result' => [ 219 false, false, false, true, true, false 220 ], 221 'Invalid verb and result' => [ 222 false, true, false, true, true, false 223 ], 224 'Invalid verb and result' => [ 225 false, false, true, true, true, false 226 ], 227 // Invalid context possibilities. 228 'Invalid definition, result and context' => [ 229 true, false, false, false, true, false 230 ], 231 'Invalid result' => [ 232 true, true, false, false, true, false 233 ], 234 'Invalid result and context' => [ 235 true, false, true, false, true, false 236 ], 237 'Invalid verb, definition result and context' => [ 238 false, false, false, false, true, false 239 ], 240 'Invalid verb, result and context' => [ 241 false, true, false, false, true, false 242 ], 243 'Invalid verb, result and context' => [ 244 false, false, true, false, true, false 245 ], 246 // Invalid user possibilities. 247 'Invalid definition, result and user' => [ 248 true, false, false, true, false, false 249 ], 250 'Invalid result and user' => [ 251 true, true, false, true, false, false 252 ], 253 'Invalid definition and user' => [ 254 true, false, true, true, false, false 255 ], 256 'Invalid verb, definition, result and user' => [ 257 false, false, false, true, false, false 258 ], 259 'Invalid verb, result and user' => [ 260 false, true, false, true, false, false 261 ], 262 'Invalid verb, result and user' => [ 263 false, false, true, true, false, false 264 ], 265 'Invalid definition, result, context and user' => [ 266 true, false, false, false, false, false 267 ], 268 'Invalid result, context and user' => [ 269 true, true, false, false, false, false 270 ], 271 'Invalid definition, context and user' => [ 272 true, false, true, false, false, false 273 ], 274 'Invalid verb, definition, result, context and user' => [ 275 false, false, false, false, false, false 276 ], 277 'Invalid verb, result, context and user' => [ 278 false, true, false, false, false, false 279 ], 280 'Invalid verb, result, context and user' => [ 281 false, false, true, false, false, false 282 ], 283 ]; 284 } 285 286 /** 287 * Test xapi_handler stored statements. 288 */ 289 public function test_stored_statements() { 290 global $DB; 291 292 $data = $this->generate_testing_scenario(); 293 $xapihandler = $data->xapihandler; 294 $context = $data->context; 295 $student = $data->student; 296 $otheruser = $data->otheruser; 297 $activity = $data->activity; 298 299 // Check we have 0 entries in the attempts tables. 300 $count = $DB->count_records('h5pactivity_attempts'); 301 $this->assertEquals(0, $count); 302 $count = $DB->count_records('h5pactivity_attempts_results'); 303 $this->assertEquals(0, $count); 304 305 $statements = $this->generate_statements($context, $student); 306 307 // Insert statements. 308 $stored = $xapihandler->process_statements($statements); 309 $this->assertCount(2, $stored); 310 $this->assertEquals(true, $stored[0]); 311 $this->assertEquals(true, $stored[1]); 312 $count = $DB->count_records('h5pactivity_attempts'); 313 $this->assertEquals(1, $count); 314 $count = $DB->count_records('h5pactivity_attempts_results'); 315 $this->assertEquals(2, $count); 316 317 // Validate stored data. 318 $attempts = $DB->get_records('h5pactivity_attempts'); 319 $attempt = array_shift($attempts); 320 $statement = $statements[0]; 321 $data = $statement->get_result()->get_data(); 322 $this->assertEquals(1, $attempt->attempt); 323 $this->assertEquals($student->id, $attempt->userid); 324 $this->assertEquals($activity->id, $attempt->h5pactivityid); 325 $this->assertEquals($data->score->raw, $attempt->rawscore); 326 $this->assertEquals($data->score->max, $attempt->maxscore); 327 $this->assertEquals($statement->get_result()->get_duration(), $attempt->duration); 328 $this->assertEquals($data->completion, $attempt->completion); 329 $this->assertEquals($data->success, $attempt->success); 330 331 $results = $DB->get_records('h5pactivity_attempts_results'); 332 foreach ($results as $result) { 333 $statement = (empty($result->subcontent)) ? $statements[0] : $statements[1]; 334 $xapiresult = $statement->get_result()->get_data(); 335 $xapiobject = $statement->get_object()->get_data(); 336 $this->assertEquals($attempt->id, $result->attemptid); 337 $this->assertEquals($xapiobject->definition->interactionType, $result->interactiontype); 338 $this->assertEquals($xapiresult->score->raw, $result->rawscore); 339 $this->assertEquals($xapiresult->score->max, $result->maxscore); 340 $this->assertEquals($statement->get_result()->get_duration(), $result->duration); 341 $this->assertEquals($xapiresult->completion, $result->completion); 342 $this->assertEquals($xapiresult->success, $result->success); 343 } 344 } 345 346 /** 347 * Returns a basic xAPI statements simulating a H5P content. 348 * 349 * @param context_module $context activity context 350 * @param stdClass $user user record 351 * @return statement[] array of xAPI statements 352 */ 353 private function generate_statements(context_module $context, stdClass $user): array { 354 $statements = []; 355 356 $statement = new statement(); 357 $statement->set_actor(item_agent::create_from_user($user)); 358 $statement->set_verb(item_verb::create_from_id('http://adlnet.gov/expapi/verbs/completed')); 359 $definition = item_definition::create_from_data((object)[ 360 'interactionType' => 'compound', 361 'correctResponsesPattern' => '1', 362 ]); 363 $statement->set_object(item_activity::create_from_id($context->id, $definition)); 364 $statement->set_result(item_result::create_from_data((object)[ 365 'completion' => true, 366 'success' => true, 367 'score' => (object) ['min' => 0, 'max' => 2, 'raw' => 2, 'scaled' => 1], 368 'duration' => 'PT25S', 369 ])); 370 $statements[] = $statement; 371 372 $statement = new statement(); 373 $statement->set_actor(item_agent::create_from_user($user)); 374 $statement->set_verb(item_verb::create_from_id('http://adlnet.gov/expapi/verbs/completed')); 375 $definition = item_definition::create_from_data((object)[ 376 'interactionType' => 'matching', 377 'correctResponsesPattern' => '1', 378 ]); 379 $statement->set_object(item_activity::create_from_id($context->id.'?subContentId=111-222-333', $definition)); 380 $statement->set_result(item_result::create_from_data((object)[ 381 'completion' => true, 382 'success' => true, 383 'score' => (object) ['min' => 0, 'max' => 1, 'raw' => 0, 'scaled' => 0], 384 'duration' => 'PT20S', 385 ])); 386 $statements[] = $statement; 387 388 return $statements; 389 } 390 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body