Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [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 namespace mod_h5pactivity\local; 19 use context_module; 20 use stdClass; 21 22 /** 23 * Manager tests class for mod_h5pactivity. 24 * 25 * @package mod_h5pactivity 26 * @covers \mod_h5pactivity\local\manager 27 * @category test 28 * @copyright 2020 Ferran Recio <ferran@moodle.com> 29 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 30 */ 31 class manager_test extends \advanced_testcase { 32 33 /** 34 * Test for static create methods. 35 */ 36 public function test_create() { 37 38 $this->resetAfterTest(); 39 $this->setAdminUser(); 40 41 $course = $this->getDataGenerator()->create_course(); 42 $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]); 43 $cm = get_coursemodule_from_id('h5pactivity', $activity->cmid, 0, false, MUST_EXIST); 44 $context = context_module::instance($cm->id); 45 46 $manager = manager::create_from_instance($activity); 47 $manageractivity = $manager->get_instance(); 48 $this->assertEquals($activity->id, $manageractivity->id); 49 $managercm = $manager->get_coursemodule(); 50 $this->assertEquals($cm->id, $managercm->id); 51 $managercontext = $manager->get_context(); 52 $this->assertEquals($context->id, $managercontext->id); 53 54 $manager = manager::create_from_coursemodule($cm); 55 $manageractivity = $manager->get_instance(); 56 $this->assertEquals($activity->id, $manageractivity->id); 57 $managercm = $manager->get_coursemodule(); 58 $this->assertEquals($cm->id, $managercm->id); 59 $managercontext = $manager->get_context(); 60 $this->assertEquals($context->id, $managercontext->id); 61 } 62 63 /** 64 * Test for is_tracking_enabled. 65 * 66 * @dataProvider is_tracking_enabled_data 67 * @param bool $login if the user is logged in 68 * @param string $role user role in course 69 * @param int $enabletracking if tracking is enabled 70 * @param bool $expected expected result 71 */ 72 public function test_is_tracking_enabled(bool $login, string $role, int $enabletracking, bool $expected) { 73 74 $this->resetAfterTest(); 75 $this->setAdminUser(); 76 77 $course = $this->getDataGenerator()->create_course(); 78 $activity = $this->getDataGenerator()->create_module('h5pactivity', 79 ['course' => $course, 'enabletracking' => $enabletracking]); 80 81 $user = $this->getDataGenerator()->create_and_enrol($course, $role); 82 if ($login) { 83 $this->setUser($user); 84 $param = null; 85 } else { 86 $param = $user; 87 } 88 89 $manager = manager::create_from_instance($activity); 90 $this->assertEquals($expected, $manager->is_tracking_enabled($param)); 91 } 92 93 /** 94 * Data provider for is_tracking_enabled. 95 * 96 * @return array 97 */ 98 public function is_tracking_enabled_data(): array { 99 return [ 100 'Logged student, tracking enabled' => [ 101 true, 'student', 1, true 102 ], 103 'Logged student, tracking disabled' => [ 104 true, 'student', 0, false 105 ], 106 'Logged teacher, tracking enabled' => [ 107 true, 'editingteacher', 1, false 108 ], 109 'Logged teacher, tracking disabled' => [ 110 true, 'editingteacher', 0, false 111 ], 112 'No logged student, tracking enabled' => [ 113 true, 'student', 1, true 114 ], 115 'No logged student, tracking disabled' => [ 116 true, 'student', 0, false 117 ], 118 'No logged teacher, tracking enabled' => [ 119 true, 'editingteacher', 1, false 120 ], 121 'No logged teacher, tracking disabled' => [ 122 true, 'editingteacher', 0, false 123 ], 124 ]; 125 } 126 127 /** 128 * Test for get_users_scaled_score. 129 * 130 * @dataProvider get_users_scaled_score_data 131 * @param int $enabletracking if tracking is enabled 132 * @param int $gradingmethod new grading method 133 * @param array $result1 student 1 results (scaled, timemodified, attempt number) 134 * @param array $result2 student 2 results (scaled, timemodified, attempt number) 135 */ 136 public function test_get_users_scaled_score(int $enabletracking, int $gradingmethod, array $result1, array $result2) { 137 global $DB; 138 139 $this->resetAfterTest(); 140 $this->setAdminUser(); 141 142 $course = $this->getDataGenerator()->create_course(); 143 $activity = $this->getDataGenerator()->create_module('h5pactivity', 144 ['course' => $course, 'enabletracking' => $enabletracking, 'grademethod' => $gradingmethod]); 145 146 // Generate two users with 4 attempts each. 147 $user1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 148 $this->generate_fake_attempts($activity, $user1, 1); 149 $user2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 150 $this->generate_fake_attempts($activity, $user2, 2); 151 152 $manager = manager::create_from_instance($activity); 153 154 // Get all users scaled scores. 155 $scaleds = $manager->get_users_scaled_score(); 156 157 // No results will be returned if tracking is dsabled or manual grading method is defined. 158 if (empty($result1)) { 159 $this->assertNull($scaleds); 160 return; 161 } 162 163 $this->assertCount(2, $scaleds); 164 165 // Check expected user1 scaled score. 166 $scaled = $scaleds[$user1->id]; 167 $this->assertEquals($user1->id, $scaled->userid); 168 $this->assertEquals($result1[0], $scaled->scaled); 169 $this->assertEquals($result1[1], $scaled->timemodified); 170 if ($result1[2]) { 171 $attempt = $DB->get_record('h5pactivity_attempts', ['id' => $scaled->attemptid]); 172 $this->assertEquals($attempt->h5pactivityid, $activity->id); 173 $this->assertEquals($attempt->userid, $scaled->userid); 174 $this->assertEquals($attempt->scaled, round($scaled->scaled, 5)); 175 $this->assertEquals($attempt->timemodified, $scaled->timemodified); 176 $this->assertEquals($result1[2], $attempt->attempt); 177 } else { 178 $this->assertEquals(0, $scaled->attemptid); 179 } 180 181 // Check expected user2 scaled score. 182 $scaled = $scaleds[$user2->id]; 183 $this->assertEquals($user2->id, $scaled->userid); 184 $this->assertEquals($result2[0], round($scaled->scaled, 5)); 185 $this->assertEquals($result2[1], $scaled->timemodified); 186 if ($result2[2]) { 187 $attempt = $DB->get_record('h5pactivity_attempts', ['id' => $scaled->attemptid]); 188 $this->assertEquals($attempt->h5pactivityid, $activity->id); 189 $this->assertEquals($attempt->userid, $scaled->userid); 190 $this->assertEquals($attempt->scaled, $scaled->scaled); 191 $this->assertEquals($attempt->timemodified, $scaled->timemodified); 192 $this->assertEquals($result2[2], $attempt->attempt); 193 } else { 194 $this->assertEquals(0, $scaled->attemptid); 195 } 196 197 // Now check a single user record. 198 $scaleds = $manager->get_users_scaled_score($user2->id); 199 $this->assertCount(1, $scaleds); 200 $scaled2 = $scaleds[$user2->id]; 201 $this->assertEquals($scaled->userid, $scaled2->userid); 202 $this->assertEquals($scaled->scaled, $scaled2->scaled); 203 $this->assertEquals($scaled->attemptid, $scaled2->attemptid); 204 $this->assertEquals($scaled->timemodified, $scaled2->timemodified); 205 } 206 207 /** 208 * Data provider for get_users_scaled_score. 209 * 210 * @return array 211 */ 212 public function get_users_scaled_score_data(): array { 213 return [ 214 'Tracking with max attempt method' => [ 215 1, manager::GRADEHIGHESTATTEMPT, [1.00000, 31, 2], [0.66667, 32, 2] 216 ], 217 'Tracking with average attempt method' => [ 218 1, manager::GRADEAVERAGEATTEMPT, [0.61111, 51, 0], [0.52222, 52, 0] 219 ], 220 'Tracking with last attempt method' => [ 221 1, manager::GRADELASTATTEMPT, [0.33333, 51, 3], [0.40000, 52, 3] 222 ], 223 'Tracking with first attempt method' => [ 224 1, manager::GRADEFIRSTATTEMPT, [0.50000, 11, 1], [0.50000, 12, 1] 225 ], 226 'Tracking with manual attempt grading' => [ 227 1, manager::GRADEMANUAL, [], [] 228 ], 229 'No tracking with max attempt method' => [ 230 0, manager::GRADEHIGHESTATTEMPT, [], [] 231 ], 232 'No tracking with average attempt method' => [ 233 0, manager::GRADEAVERAGEATTEMPT, [], [] 234 ], 235 'No tracking with last attempt method' => [ 236 0, manager::GRADELASTATTEMPT, [], [] 237 ], 238 'No tracking with first attempt method' => [ 239 0, manager::GRADEFIRSTATTEMPT, [], [] 240 ], 241 'No tracking with manual attempt grading' => [ 242 0, manager::GRADEMANUAL, [], [] 243 ], 244 ]; 245 } 246 247 /** 248 * Test static get_grading_methods. 249 */ 250 public function test_get_grading_methods() { 251 $methods = manager::get_grading_methods(); 252 $this->assertCount(5, $methods); 253 $this->assertNotEmpty($methods[manager::GRADEHIGHESTATTEMPT]); 254 $this->assertNotEmpty($methods[manager::GRADEAVERAGEATTEMPT]); 255 $this->assertNotEmpty($methods[manager::GRADELASTATTEMPT]); 256 $this->assertNotEmpty($methods[manager::GRADEFIRSTATTEMPT]); 257 $this->assertNotEmpty($methods[manager::GRADEMANUAL]); 258 } 259 260 /** 261 * Test static get_selected_attempt. 262 * 263 * @dataProvider get_selected_attempt_data 264 * @param int $enabletracking if tracking is enabled 265 * @param int $gradingmethod new grading method 266 * @param int $result the expected result 267 */ 268 public function test_get_selected_attempt(int $enabletracking, int $gradingmethod, int $result) { 269 $this->resetAfterTest(); 270 $this->setAdminUser(); 271 272 $course = $this->getDataGenerator()->create_course(); 273 $activity = $this->getDataGenerator()->create_module('h5pactivity', 274 ['course' => $course, 'enabletracking' => $enabletracking, 'grademethod' => $gradingmethod]); 275 276 $manager = manager::create_from_instance($activity); 277 278 $selected = $manager->get_selected_attempt(); 279 280 $this->assertEquals($result, $selected[0]); 281 $this->assertNotEmpty($selected[1]); 282 } 283 284 /** 285 * Data provider for get_users_scaled_score. 286 * 287 * @return array 288 */ 289 public function get_selected_attempt_data(): array { 290 return [ 291 'Tracking with max attempt method' => [ 292 1, manager::GRADEHIGHESTATTEMPT, manager::GRADEHIGHESTATTEMPT 293 ], 294 'Tracking with average attempt method' => [ 295 1, manager::GRADEAVERAGEATTEMPT, manager::GRADEAVERAGEATTEMPT 296 ], 297 'Tracking with last attempt method' => [ 298 1, manager::GRADELASTATTEMPT, manager::GRADELASTATTEMPT 299 ], 300 'Tracking with first attempt method' => [ 301 1, manager::GRADEFIRSTATTEMPT, manager::GRADEFIRSTATTEMPT 302 ], 303 'Tracking with manual attempt grading' => [ 304 1, manager::GRADEMANUAL, manager::GRADEMANUAL 305 ], 306 'No tracking with max attempt method' => [ 307 0, manager::GRADEHIGHESTATTEMPT, manager::GRADEMANUAL 308 ], 309 'No tracking with average attempt method' => [ 310 0, manager::GRADEAVERAGEATTEMPT, manager::GRADEMANUAL 311 ], 312 'No tracking with last attempt method' => [ 313 0, manager::GRADELASTATTEMPT, manager::GRADEMANUAL 314 ], 315 'No tracking with first attempt method' => [ 316 0, manager::GRADEFIRSTATTEMPT, manager::GRADEMANUAL 317 ], 318 'No tracking with manual attempt grading' => [ 319 0, manager::GRADEMANUAL, manager::GRADEMANUAL 320 ], 321 ]; 322 } 323 324 /** 325 * Test static get_review_modes. 326 */ 327 public function test_get_review_modes() { 328 $methods = manager::get_review_modes(); 329 $this->assertCount(2, $methods); 330 $this->assertNotEmpty($methods[manager::REVIEWCOMPLETION]); 331 $this->assertNotEmpty($methods[manager::REVIEWNONE]); 332 } 333 334 /** 335 * Test get_grader method. 336 */ 337 public function test_get_grader() { 338 $this->resetAfterTest(); 339 $this->setAdminUser(); 340 341 $course = $this->getDataGenerator()->create_course(); 342 $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]); 343 $cm = get_coursemodule_from_id('h5pactivity', $activity->cmid, 0, false, MUST_EXIST); 344 $context = context_module::instance($cm->id); 345 346 $manager = manager::create_from_instance($activity); 347 $grader = $manager->get_grader(); 348 349 $this->assertInstanceOf('mod_h5pactivity\local\grader', $grader); 350 } 351 352 353 /** 354 * Test static can_view_all_attempts. 355 * 356 * @dataProvider can_view_all_attempts_data 357 * @param int $enabletracking if tracking is enabled 358 * @param bool $usestudent if test must be done with a user role 359 * @param bool $useloggedin if test must be done with the loggedin user 360 * @param bool $result the expected result 361 */ 362 public function test_can_view_all_attempts(int $enabletracking, bool $usestudent, bool $useloggedin, bool $result) { 363 global $USER; 364 365 $this->resetAfterTest(); 366 $this->setAdminUser(); 367 368 $course = $this->getDataGenerator()->create_course(); 369 $activity = $this->getDataGenerator()->create_module('h5pactivity', 370 ['course' => $course, 'enabletracking' => $enabletracking]); 371 372 $manager = manager::create_from_instance($activity); 373 374 $user = $this->getDataGenerator()->create_and_enrol($course, 'student'); 375 $loggedin = $USER; 376 377 // We want to test what when the method is called to check a different user than $USER. 378 if (!$usestudent) { 379 $loggedin = $user; 380 $user = $USER; 381 } 382 383 if ($useloggedin) { 384 $this->setUser($user); 385 $user = null; 386 } else { 387 $this->setUser($loggedin); 388 } 389 390 $this->assertEquals($result, $manager->can_view_all_attempts($user)); 391 } 392 393 /** 394 * Data provider for test_can_view_all_attempts. 395 * 396 * @return array 397 */ 398 public function can_view_all_attempts_data(): array { 399 return [ 400 // No tracking cases. 401 'No tracking with admin using $USER' => [ 402 0, false, false, false 403 ], 404 'No tracking with student using $USER' => [ 405 0, true, false, false 406 ], 407 'No tracking with admin loggedin' => [ 408 0, false, true, false 409 ], 410 'No tracking with student loggedin' => [ 411 0, true, true, false 412 ], 413 // Tracking enabled cases. 414 'Tracking with admin using $USER' => [ 415 1, false, false, true 416 ], 417 'Tracking with student using $USER' => [ 418 1, true, false, false 419 ], 420 'Tracking with admin loggedin' => [ 421 1, false, true, true 422 ], 423 'Tracking with student loggedin' => [ 424 1, true, true, false 425 ], 426 ]; 427 } 428 429 /** 430 * Test static can_view_own_attempts. 431 * 432 * @dataProvider can_view_own_attempts_data 433 * @param int $enabletracking if tracking is enabled 434 * @param int $reviewmode the attempt review mode 435 * @param bool $useloggedin if test must be done with the loggedin user 436 * @param bool $hasattempts if the student have attempts 437 * @param bool $result the expected result 438 */ 439 public function test_can_view_own_attempts(int $enabletracking, int $reviewmode, 440 bool $useloggedin, bool $hasattempts, bool $result) { 441 442 $this->resetAfterTest(); 443 $this->setAdminUser(); 444 445 $course = $this->getDataGenerator()->create_course(); 446 $activity = $this->getDataGenerator()->create_module('h5pactivity', 447 ['course' => $course, 'enabletracking' => $enabletracking, 'reviewmode' => $reviewmode]); 448 449 $manager = manager::create_from_instance($activity); 450 451 $user = $this->getDataGenerator()->create_and_enrol($course, 'student'); 452 453 if ($hasattempts) { 454 $this->generate_fake_attempts($activity, $user, 1); 455 } 456 457 if ($useloggedin) { 458 $this->setUser($user); 459 $user = null; 460 } 461 462 $this->assertEquals($result, $manager->can_view_own_attempts($user)); 463 } 464 465 /** 466 * Data provider for test_can_view_own_attempts. 467 * 468 * @return array 469 */ 470 public function can_view_own_attempts_data(): array { 471 return [ 472 // No tracking cases. 473 'No tracking, review none, using $USER, without attempts' => [ 474 0, manager::REVIEWNONE, false, false, false 475 ], 476 'No tracking, review enabled, using $USER, without attempts' => [ 477 0, manager::REVIEWCOMPLETION, false, false, false 478 ], 479 'No tracking, review none, loggedin, without attempts' => [ 480 0, manager::REVIEWNONE, true, false, false 481 ], 482 'No tracking, review enabled, loggedin, without attempts' => [ 483 0, manager::REVIEWCOMPLETION, true, false, false 484 ], 485 'No tracking, review none, using $USER, with attempts' => [ 486 0, manager::REVIEWNONE, false, true, false 487 ], 488 'No tracking, review enabled, using $USER, with attempts' => [ 489 0, manager::REVIEWCOMPLETION, false, true, false 490 ], 491 'No tracking, review none, loggedin, with attempts' => [ 492 0, manager::REVIEWNONE, true, true, false 493 ], 494 'No tracking, review enabled, loggedin, with attempts' => [ 495 0, manager::REVIEWCOMPLETION, true, true, false 496 ], 497 // Tracking enabled cases. 498 'Tracking enabled, review none, using $USER, without attempts' => [ 499 1, manager::REVIEWNONE, false, false, false 500 ], 501 'Tracking enabled, review enabled, using $USER, without attempts' => [ 502 1, manager::REVIEWCOMPLETION, false, false, true 503 ], 504 'Tracking enabled, review none, loggedin, without attempts' => [ 505 1, manager::REVIEWNONE, true, false, false 506 ], 507 'Tracking enabled, review enabled, loggedin, without attempts' => [ 508 1, manager::REVIEWCOMPLETION, true, false, true 509 ], 510 'Tracking enabled, review none, using $USER, with attempts' => [ 511 1, manager::REVIEWNONE, false, true, false 512 ], 513 'Tracking enabled, review enabled, using $USER, with attempts' => [ 514 1, manager::REVIEWCOMPLETION, false, true, true 515 ], 516 'Tracking enabled, review none, loggedin, with attempts' => [ 517 1, manager::REVIEWNONE, true, true, false 518 ], 519 'Tracking enabled, review enabled, loggedin, with attempts' => [ 520 1, manager::REVIEWCOMPLETION, true, true, true 521 ], 522 ]; 523 } 524 525 /** 526 * Test static count_attempts of one user. 527 */ 528 public function test_count_attempts() { 529 530 $this->resetAfterTest(); 531 $this->setAdminUser(); 532 533 $course = $this->getDataGenerator()->create_course(); 534 $activity = $this->getDataGenerator()->create_module('h5pactivity', 535 ['course' => $course]); 536 537 $manager = manager::create_from_instance($activity); 538 539 // User without attempts. 540 $user1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 541 542 // User with 1 attempt. 543 $user2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 544 $this->generate_fake_attempts($activity, $user2, 1); 545 546 // User with 2 attempts. 547 $user3 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 548 $this->generate_fake_attempts($activity, $user3, 1); 549 550 // Incomplete user2 and 3 has only 3 attempts completed. 551 $this->assertEquals(0, $manager->count_attempts($user1->id)); 552 $this->assertEquals(3, $manager->count_attempts($user2->id)); 553 $this->assertEquals(3, $manager->count_attempts($user3->id)); 554 } 555 556 /** 557 * Test static count_attempts of all active participants. 558 * 559 * @dataProvider count_attempts_all_data 560 * @param bool $canview if the student role has mod_h5pactivity/view capability 561 * @param bool $cansubmit if the student role has mod_h5pactivity/submit capability 562 * @param bool $extrarole if an extra role without submit capability is required 563 * @param int $result the expected result 564 */ 565 public function test_count_attempts_all(bool $canview, bool $cansubmit, bool $extrarole, int $result) { 566 global $DB; 567 568 $this->resetAfterTest(); 569 $this->setAdminUser(); 570 571 $course = $this->getDataGenerator()->create_course(); 572 $activity = $this->getDataGenerator()->create_module( 573 'h5pactivity', 574 ['course' => $course] 575 ); 576 577 $manager = manager::create_from_instance($activity); 578 579 $roleid = $DB->get_field('role', 'id', ['shortname' => 'student']); 580 581 $newcap = ($canview) ? CAP_ALLOW : CAP_PROHIBIT; 582 role_change_permission($roleid, $manager->get_context(), 'mod/h5pactivity:view', $newcap); 583 584 $newcap = ($cansubmit) ? CAP_ALLOW : CAP_PROHIBIT; 585 role_change_permission($roleid, $manager->get_context(), 'mod/h5pactivity:submit', $newcap); 586 587 // Teacher with review capability and attempts (should not be listed). 588 if ($extrarole) { 589 $user1 = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); 590 $this->generate_fake_attempts($activity, $user1, 1); 591 } 592 593 // Student with attempts. 594 $user2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 595 $this->generate_fake_attempts($activity, $user2, 1); 596 597 // Another student with attempts. 598 $user3 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 599 $this->generate_fake_attempts($activity, $user3, 1); 600 601 $this->assertEquals($result, $manager->count_attempts()); 602 } 603 604 /** 605 * Data provider for test_count_attempts_all. 606 * 607 * @return array 608 */ 609 public function count_attempts_all_data(): array { 610 return [ 611 'Students with both view and submit capability' => [true, true, false, 6], 612 'Students without view but with submit capability' => [false, true, false, 0], 613 'Students with view but without submit capability' => [true, false, false, 6], 614 'Students without both view and submit capability' => [false, false, false, 0], 615 'Students with both view and submit capability and extra role' => [true, true, true, 6], 616 'Students without view but with submit capability and extra role' => [false, true, true, 0], 617 'Students with view but without submit capability and extra role' => [true, false, true, 6], 618 'Students without both view and submit capability and extra role' => [false, false, true, 0], 619 ]; 620 } 621 622 /** 623 * Test static test_get_active_users_join of all active participants. 624 * 625 * Most method scenarios are tested in test_count_attempts_all so we only 626 * need to test the with $allpotentialusers true and false. 627 * 628 * @dataProvider get_active_users_join_data 629 * @param bool $allpotentialusers if the join should return all potential users or only the submitted ones. 630 * @param int $result the expected result 631 */ 632 public function test_get_active_users_join(bool $allpotentialusers, int $result) { 633 global $DB; 634 635 $this->resetAfterTest(); 636 $this->setAdminUser(); 637 638 $course = $this->getDataGenerator()->create_course(); 639 $activity = $this->getDataGenerator()->create_module( 640 'h5pactivity', 641 ['course' => $course] 642 ); 643 644 $manager = manager::create_from_instance($activity); 645 646 $user1 = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); 647 $this->generate_fake_attempts($activity, $user1, 1); 648 649 // Student with attempts. 650 $user2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 651 $this->generate_fake_attempts($activity, $user2, 1); 652 653 // 2 more students without attempts. 654 $this->getDataGenerator()->create_and_enrol($course, 'student'); 655 $this->getDataGenerator()->create_and_enrol($course, 'student'); 656 657 $usersjoin = $manager->get_active_users_join($allpotentialusers); 658 659 // Final SQL. 660 $num = $DB->count_records_sql( 661 "SELECT COUNT(DISTINCT u.id) 662 FROM {user} u $usersjoin->joins 663 WHERE $usersjoin->wheres", 664 array_merge($usersjoin->params) 665 ); 666 667 $this->assertEquals($result, $num); 668 } 669 670 /** 671 * Data provider for test_get_active_users_join. 672 * 673 * @return array 674 */ 675 public function get_active_users_join_data(): array { 676 return [ 677 'All potential users' => [ 678 'allpotentialusers' => true, 679 'result' => 3, 680 ], 681 'Users with attempts' => [ 682 'allpotentialusers' => false, 683 'result' => 1, 684 ], 685 ]; 686 } 687 688 /** 689 * Test active users joins returns appropriate results for groups 690 */ 691 public function test_get_active_users_join_groupmode(): void { 692 global $DB; 693 694 $this->resetAfterTest(); 695 $this->setAdminUser(); 696 697 $course = $this->getDataGenerator()->create_course(['groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1]); 698 699 // Teacher/user one in group one. 700 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); 701 $userone = $this->getDataGenerator()->create_and_enrol($course, 'student'); 702 703 $groupone = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 704 $this->getDataGenerator()->create_group_member(['groupid' => $groupone->id, 'userid' => $teacher->id]); 705 $this->getDataGenerator()->create_group_member(['groupid' => $groupone->id, 'userid' => $userone->id]); 706 707 // User two in group two. 708 $usertwo = $this->getDataGenerator()->create_and_enrol($course, 'student'); 709 710 $grouptwo = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 711 $this->getDataGenerator()->create_group_member(['groupid' => $grouptwo->id, 'userid' => $usertwo->id]); 712 713 $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]); 714 $manager = manager::create_from_instance($activity); 715 716 // Admin user can view all participants. 717 $usersjoin = $manager->get_active_users_join(true, 0); 718 $users = $DB->get_fieldset_sql("SELECT u.username FROM {user} u {$usersjoin->joins} WHERE {$usersjoin->wheres}", 719 $usersjoin->params); 720 721 $this->assertEqualsCanonicalizing([$teacher->username, $userone->username, $usertwo->username], $users); 722 723 // Switch to teacher, who cannot view all participants. 724 $this->setUser($teacher); 725 726 $usersjoin = $manager->get_active_users_join(true, 0); 727 $users = $DB->get_fieldset_sql("SELECT u.username FROM {user} u {$usersjoin->joins} WHERE {$usersjoin->wheres}", 728 $usersjoin->params); 729 730 $this->assertEmpty($users); 731 732 // Teacher can view participants inside group. 733 $usersjoin = $manager->get_active_users_join(true, $groupone->id); 734 $users = $DB->get_fieldset_sql("SELECT u.username FROM {user} u {$usersjoin->joins} WHERE {$usersjoin->wheres}", 735 $usersjoin->params); 736 737 $this->assertEqualsCanonicalizing([$teacher->username, $userone->username], $users); 738 } 739 740 /** 741 * Test static count_attempts. 742 */ 743 public function test_count_users_attempts() { 744 745 $this->resetAfterTest(); 746 $this->setAdminUser(); 747 748 $course = $this->getDataGenerator()->create_course(); 749 $activity = $this->getDataGenerator()->create_module('h5pactivity', 750 ['course' => $course]); 751 752 $manager = manager::create_from_instance($activity); 753 754 // User without attempts. 755 $user1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 756 757 // User with 1 attempt. 758 $user2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 759 $this->generate_fake_attempts($activity, $user2, 1); 760 761 // User with 2 attempts. 762 $user3 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 763 $this->generate_fake_attempts($activity, $user3, 1); 764 765 $attempts = $manager->count_users_attempts(); 766 $this->assertArrayNotHasKey($user1->id, $attempts); 767 $this->assertArrayHasKey($user2->id, $attempts); 768 $this->assertEquals(4, $attempts[$user2->id]); 769 $this->assertArrayHasKey($user3->id, $attempts); 770 $this->assertEquals(4, $attempts[$user3->id]); 771 } 772 773 /** 774 * Test static get_report. 775 * 776 * @dataProvider get_report_data 777 * @param int $enabletracking if tracking is enabled 778 * @param int $reviewmode the attempt review mode 779 * @param bool $createattempts if the student have attempts 780 * @param string $role the user role (student or editingteacher) 781 * @param array $results the expected classname (or null) 782 */ 783 public function test_get_report(int $enabletracking, int $reviewmode, bool $createattempts, 784 string $role, array $results) { 785 786 $this->resetAfterTest(); 787 $this->setAdminUser(); 788 789 $course = $this->getDataGenerator()->create_course(); 790 $activity = $this->getDataGenerator()->create_module('h5pactivity', 791 ['course' => $course, 'enabletracking' => $enabletracking, 'reviewmode' => $reviewmode]); 792 793 $manager = manager::create_from_instance($activity); 794 $cm = get_coursemodule_from_id('h5pactivity', $activity->cmid, 0, false, MUST_EXIST); 795 796 $users = [ 797 'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'), 798 'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 799 'otheruser' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 800 ]; 801 802 $attempts = []; 803 if ($createattempts) { 804 $this->generate_fake_attempts($activity, $users['student'], 1); 805 $this->generate_fake_attempts($activity, $users['otheruser'], 2); 806 $attempts['student'] = attempt::last_attempt($users['student'], $cm); 807 $attempts['otheruser'] = attempt::last_attempt($users['otheruser'], $cm); 808 } 809 810 $classnamebase = 'mod_h5pactivity\\local\\report\\'; 811 812 $attemptid = null; 813 if (isset($attempts['student'])) { 814 $attemptid = $attempts['student']->get_id() ?? null; 815 } 816 $userid = $users['student']->id; 817 818 // Check reports. 819 $this->setUser($users[$role]); 820 821 $report = $manager->get_report(null, null); 822 if ($results[0] === null) { 823 $this->assertNull($report); 824 } else { 825 $this->assertEquals($classnamebase.$results[0], get_class($report)); 826 } 827 828 $report = $manager->get_report($userid, null); 829 if ($results[1] === null) { 830 $this->assertNull($report); 831 } else { 832 $this->assertEquals($classnamebase.$results[1], get_class($report)); 833 } 834 835 $report = $manager->get_report($userid, $attemptid); 836 if ($results[2] === null) { 837 $this->assertNull($report); 838 } else { 839 $this->assertEquals($classnamebase.$results[2], get_class($report)); 840 } 841 842 // Check that student cannot access another student reports. 843 if ($role == 'student') { 844 $attemptid = null; 845 if (isset($attempts['otheruser'])) { 846 $attemptid = $attempts['otheruser']->get_id() ?? null; 847 } 848 $userid = $users['otheruser']->id; 849 850 $report = $manager->get_report($userid, null); 851 $this->assertNull($report); 852 853 $report = $manager->get_report($userid, $attemptid); 854 $this->assertNull($report); 855 } 856 } 857 858 /** 859 * Data provider for test_get_report. 860 * 861 * @return array 862 */ 863 public function get_report_data(): array { 864 return [ 865 // No tracking scenarios. 866 'No tracking, review none, no attempts, teacher' => [ 867 0, manager::REVIEWNONE, false, 'editingteacher', [null, null, null] 868 ], 869 'No tracking, review own, no attempts, teacher' => [ 870 0, manager::REVIEWCOMPLETION, false, 'editingteacher', [null, null, null] 871 ], 872 'No tracking, review none, no attempts, student' => [ 873 0, manager::REVIEWNONE, false, 'student', [null, null, null] 874 ], 875 'No tracking, review own, no attempts, student' => [ 876 0, manager::REVIEWCOMPLETION, false, 'student', [null, null, null] 877 ], 878 'No tracking, review none, with attempts, teacher' => [ 879 0, manager::REVIEWNONE, true, 'editingteacher', [null, null, null] 880 ], 881 'No tracking, review own, with attempts, teacher' => [ 882 0, manager::REVIEWCOMPLETION, true, 'editingteacher', [null, null, null] 883 ], 884 'No tracking, review none, with attempts, student' => [ 885 0, manager::REVIEWNONE, true, 'student', [null, null, null] 886 ], 887 'No tracking, review own, with attempts, student' => [ 888 0, manager::REVIEWCOMPLETION, true, 'student', [null, null, null] 889 ], 890 // Tracking enabled scenarios. 891 'Tracking enabled, review none, no attempts, teacher' => [ 892 1, manager::REVIEWNONE, false, 'editingteacher', ['participants', 'attempts', 'attempts'] 893 ], 894 'Tracking enabled, review own, no attempts, teacher' => [ 895 1, manager::REVIEWCOMPLETION, false, 'editingteacher', ['participants', 'attempts', 'attempts'] 896 ], 897 'Tracking enabled, review none, no attempts, student' => [ 898 1, manager::REVIEWNONE, false, 'student', [null, null, null] 899 ], 900 'Tracking enabled, review own, no attempts, student' => [ 901 1, manager::REVIEWCOMPLETION, false, 'student', ['attempts', 'attempts', 'attempts'] 902 ], 903 'Tracking enabled, review none, with attempts, teacher' => [ 904 1, manager::REVIEWNONE, true, 'editingteacher', ['participants', 'attempts', 'results'] 905 ], 906 'Tracking enabled, review own, with attempts, teacher' => [ 907 1, manager::REVIEWCOMPLETION, true, 'editingteacher', ['participants', 'attempts', 'results'] 908 ], 909 'Tracking enabled, review none, with attempts, student' => [ 910 1, manager::REVIEWNONE, true, 'student', [null, null, null] 911 ], 912 'Tracking enabled, review own, with attempts, student' => [ 913 1, manager::REVIEWCOMPLETION, true, 'student', ['attempts', 'attempts', 'results'] 914 ], 915 ]; 916 } 917 918 /** 919 * Test get_attempt method. 920 * 921 * @dataProvider get_attempt_data 922 * @param string $attemptname the attempt to use 923 * @param string|null $result the expected attempt ID or null for none 924 */ 925 public function test_get_attempt(string $attemptname, ?string $result): void { 926 927 $this->resetAfterTest(); 928 $this->setAdminUser(); 929 930 $course = $this->getDataGenerator()->create_course(); 931 932 $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]); 933 $cm = get_coursemodule_from_id('h5pactivity', $activity->cmid, 0, false, MUST_EXIST); 934 935 $otheractivity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]); 936 $othercm = get_coursemodule_from_id('h5pactivity', $otheractivity->cmid, 0, false, MUST_EXIST); 937 938 $manager = manager::create_from_instance($activity); 939 940 $user = $this->getDataGenerator()->create_and_enrol($course, 'student'); 941 942 $attempts = ['inexistent' => 0]; 943 944 $this->generate_fake_attempts($activity, $user, 1); 945 $attempt = attempt::last_attempt($user, $cm); 946 $attempts['current'] = $attempt->get_id(); 947 948 $this->generate_fake_attempts($otheractivity, $user, 1); 949 $attempt = attempt::last_attempt($user, $othercm); 950 $attempts['other'] = $attempt->get_id(); 951 952 $attempt = $manager->get_attempt($attempts[$attemptname]); 953 if ($result === null) { 954 $this->assertNull($attempt); 955 } else { 956 $this->assertEquals($attempts[$attemptname], $attempt->get_id()); 957 $this->assertEquals($activity->id, $attempt->get_h5pactivityid()); 958 $this->assertEquals($user->id, $attempt->get_userid()); 959 $this->assertEquals(4, $attempt->get_attempt()); 960 } 961 } 962 963 /** 964 * Data provider for test_get_attempt. 965 * 966 * @return array 967 */ 968 public function get_attempt_data(): array { 969 return [ 970 'Get the current activity attempt' => [ 971 'current', 'current' 972 ], 973 'Try to get another activity attempt' => [ 974 'other', null 975 ], 976 'Try to get an inexistent attempt' => [ 977 'inexistent', null 978 ], 979 ]; 980 } 981 982 /** 983 * Insert fake attempt data into h5pactiviyt_attempts. 984 * 985 * This function insert 4 attempts. 3 of them finished with different gradings 986 * and timestamps and 1 unfinished. 987 * 988 * @param stdClass $activity the activity record 989 * @param stdClass $user user record 990 * @param int $basescore a score to be used to generate all attempts 991 */ 992 private function generate_fake_attempts(stdClass $activity, stdClass $user, int $basescore) { 993 global $DB; 994 995 $attempt = (object)[ 996 'h5pactivityid' => $activity->id, 997 'userid' => $user->id, 998 'timecreated' => $basescore, 999 'timemodified' => ($basescore + 10), 1000 'attempt' => 1, 1001 'rawscore' => $basescore, 1002 'maxscore' => ($basescore + $basescore), 1003 'duration' => $basescore, 1004 'completion' => 1, 1005 'success' => 1, 1006 ]; 1007 $attempt->scaled = $attempt->rawscore / $attempt->maxscore; 1008 $DB->insert_record('h5pactivity_attempts', $attempt); 1009 1010 $attempt = (object)[ 1011 'h5pactivityid' => $activity->id, 1012 'userid' => $user->id, 1013 'timecreated' => ($basescore + 20), 1014 'timemodified' => ($basescore + 30), 1015 'attempt' => 2, 1016 'rawscore' => $basescore, 1017 'maxscore' => ($basescore + $basescore - 1), 1018 'duration' => $basescore, 1019 'completion' => 1, 1020 'success' => 1, 1021 ]; 1022 $attempt->scaled = $attempt->rawscore / $attempt->maxscore; 1023 $DB->insert_record('h5pactivity_attempts', $attempt); 1024 1025 $attempt = (object)[ 1026 'h5pactivityid' => $activity->id, 1027 'userid' => $user->id, 1028 'timecreated' => ($basescore + 40), 1029 'timemodified' => ($basescore + 50), 1030 'attempt' => 3, 1031 'rawscore' => $basescore, 1032 'maxscore' => ($basescore + $basescore + 1), 1033 'duration' => $basescore, 1034 'completion' => 1, 1035 'success' => 0, 1036 ]; 1037 $attempt->scaled = $attempt->rawscore / $attempt->maxscore; 1038 $DB->insert_record('h5pactivity_attempts', $attempt); 1039 1040 // Unfinished attempt. 1041 $attempt = (object)[ 1042 'h5pactivityid' => $activity->id, 1043 'userid' => $user->id, 1044 'timecreated' => ($basescore + 60), 1045 'timemodified' => ($basescore + 60), 1046 'attempt' => 4, 1047 'rawscore' => $basescore, 1048 'maxscore' => $basescore, 1049 'duration' => $basescore, 1050 ]; 1051 $DB->insert_record('h5pactivity_attempts', $attempt); 1052 } 1053 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body