Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403]

   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   * Unit tests for workshop api class defined in mod/workshop/locallib.php
  19   *
  20   * @package    mod_workshop
  21   * @category   phpunit
  22   * @copyright  2009 David Mudrak <david.mudrak@gmail.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  namespace mod_workshop;
  26  
  27  use testable_workshop;
  28  use workshop;
  29  use workshop_example_assessment;
  30  use workshop_example_reference_assessment;
  31  
  32  defined('MOODLE_INTERNAL') || die();
  33  
  34  global $CFG;
  35  require_once($CFG->dirroot . '/mod/workshop/locallib.php'); // Include the code to test
  36  require_once (__DIR__ . '/fixtures/testable.php');
  37  
  38  
  39  /**
  40   * Test cases for the internal workshop api
  41   */
  42  class locallib_test extends \advanced_testcase {
  43  
  44      /** @var object */
  45      protected $course;
  46  
  47      /** @var workshop */
  48      protected $workshop;
  49  
  50      /** setup testing environment */
  51      protected function setUp(): void {
  52          parent::setUp();
  53          $this->setAdminUser();
  54          $this->course = $this->getDataGenerator()->create_course();
  55          $workshop = $this->getDataGenerator()->create_module('workshop', array('course' => $this->course));
  56          $cm = get_coursemodule_from_instance('workshop', $workshop->id, $this->course->id, false, MUST_EXIST);
  57          $this->workshop = new testable_workshop($workshop, $cm, $this->course);
  58      }
  59  
  60      protected function tearDown(): void {
  61          $this->workshop = null;
  62          parent::tearDown();
  63      }
  64  
  65      public function test_aggregate_submission_grades_process_notgraded() {
  66          $this->resetAfterTest(true);
  67  
  68          // fixture set-up
  69          $batch = array();   // batch of a submission's assessments
  70          $batch[] = (object)array('submissionid' => 12, 'submissiongrade' => null, 'weight' => 1, 'grade' => null);
  71          //$DB->expectNever('update_record');
  72          // exercise SUT
  73          $this->workshop->aggregate_submission_grades_process($batch);
  74      }
  75  
  76      public function test_aggregate_submission_grades_process_single() {
  77          $this->resetAfterTest(true);
  78  
  79          // fixture set-up
  80          $batch = array();   // batch of a submission's assessments
  81          $batch[] = (object)array('submissionid' => 12, 'submissiongrade' => null, 'weight' => 1, 'grade' => 10.12345);
  82          $expected = 10.12345;
  83          //$DB->expectOnce('update_record');
  84          // exercise SUT
  85          $this->workshop->aggregate_submission_grades_process($batch);
  86      }
  87  
  88      public function test_aggregate_submission_grades_process_null_doesnt_influence() {
  89          $this->resetAfterTest(true);
  90  
  91          // fixture set-up
  92          $batch = array();   // batch of a submission's assessments
  93          $batch[] = (object)array('submissionid' => 12, 'submissiongrade' => null, 'weight' => 1, 'grade' => 45.54321);
  94          $batch[] = (object)array('submissionid' => 12, 'submissiongrade' => null, 'weight' => 1, 'grade' => null);
  95          $expected = 45.54321;
  96          //$DB->expectOnce('update_record');
  97          // exercise SUT
  98          $this->workshop->aggregate_submission_grades_process($batch);
  99      }
 100  
 101      public function test_aggregate_submission_grades_process_weighted_single() {
 102          $this->resetAfterTest(true);
 103  
 104          // fixture set-up
 105          $batch = array();   // batch of a submission's assessments
 106          $batch[] = (object)array('submissionid' => 12, 'submissiongrade' => null, 'weight' => 4, 'grade' => 14.00012);
 107          $expected = 14.00012;
 108          //$DB->expectOnce('update_record');
 109          // exercise SUT
 110          $this->workshop->aggregate_submission_grades_process($batch);
 111      }
 112  
 113      public function test_aggregate_submission_grades_process_mean() {
 114          $this->resetAfterTest(true);
 115  
 116          // fixture set-up
 117          $batch = array();   // batch of a submission's assessments
 118          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => null, 'weight' => 1, 'grade' => 56.12000);
 119          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => null, 'weight' => 1, 'grade' => 12.59000);
 120          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => null, 'weight' => 1, 'grade' => 10.00000);
 121          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => null, 'weight' => 1, 'grade' => 0.00000);
 122          $expected = 19.67750;
 123          //$DB->expectOnce('update_record');
 124          // exercise SUT
 125          $this->workshop->aggregate_submission_grades_process($batch);
 126      }
 127  
 128      public function test_aggregate_submission_grades_process_mean_changed() {
 129          $this->resetAfterTest(true);
 130  
 131          // fixture set-up
 132          $batch = array();   // batch of a submission's assessments
 133          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => 12.57750, 'weight' => 1, 'grade' => 56.12000);
 134          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => 12.57750, 'weight' => 1, 'grade' => 12.59000);
 135          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => 12.57750, 'weight' => 1, 'grade' => 10.00000);
 136          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => 12.57750, 'weight' => 1, 'grade' => 0.00000);
 137          $expected = 19.67750;
 138          //$DB->expectOnce('update_record');
 139          // exercise SUT
 140          $this->workshop->aggregate_submission_grades_process($batch);
 141      }
 142  
 143      public function test_aggregate_submission_grades_process_mean_nochange() {
 144          $this->resetAfterTest(true);
 145  
 146          // fixture set-up
 147          $batch = array();   // batch of a submission's assessments
 148          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => 19.67750, 'weight' => 1, 'grade' => 56.12000);
 149          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => 19.67750, 'weight' => 1, 'grade' => 12.59000);
 150          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => 19.67750, 'weight' => 1, 'grade' => 10.00000);
 151          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => 19.67750, 'weight' => 1, 'grade' => 0.00000);
 152          //$DB->expectNever('update_record');
 153          // exercise SUT
 154          $this->workshop->aggregate_submission_grades_process($batch);
 155      }
 156  
 157      public function test_aggregate_submission_grades_process_rounding() {
 158          $this->resetAfterTest(true);
 159  
 160          // fixture set-up
 161          $batch = array();   // batch of a submission's assessments
 162          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => null, 'weight' => 1, 'grade' => 4.00000);
 163          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => null, 'weight' => 1, 'grade' => 2.00000);
 164          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => null, 'weight' => 1, 'grade' => 1.00000);
 165          $expected = 2.33333;
 166          //$DB->expectOnce('update_record');
 167          // exercise SUT
 168          $this->workshop->aggregate_submission_grades_process($batch);
 169      }
 170  
 171      public function test_aggregate_submission_grades_process_weighted_mean() {
 172          $this->resetAfterTest(true);
 173  
 174          // fixture set-up
 175          $batch = array();   // batch of a submission's assessments
 176          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => null, 'weight' => 3, 'grade' => 12.00000);
 177          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => null, 'weight' => 2, 'grade' => 30.00000);
 178          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => null, 'weight' => 1, 'grade' => 10.00000);
 179          $batch[] = (object)array('submissionid' => 45, 'submissiongrade' => null, 'weight' => 0, 'grade' => 1000.00000);
 180          $expected = 17.66667;
 181          //$DB->expectOnce('update_record');
 182          // exercise SUT
 183          $this->workshop->aggregate_submission_grades_process($batch);
 184      }
 185  
 186      public function test_aggregate_grading_grades_process_nograding() {
 187          $this->resetAfterTest(true);
 188          // fixture set-up
 189          $batch = array();
 190          $batch[] = (object)array('reviewerid'=>2, 'gradinggrade'=>null, 'gradinggradeover'=>null, 'aggregationid'=>null, 'aggregatedgrade'=>null);
 191          // expectation
 192          //$DB->expectNever('update_record');
 193          // excersise SUT
 194          $this->workshop->aggregate_grading_grades_process($batch);
 195      }
 196  
 197      public function test_aggregate_grading_grades_process_single_grade_new() {
 198          $this->resetAfterTest(true);
 199          // fixture set-up
 200          $batch = array();
 201          $batch[] = (object)array('reviewerid'=>3, 'gradinggrade'=>82.87670, 'gradinggradeover'=>null, 'aggregationid'=>null, 'aggregatedgrade'=>null);
 202          // expectation
 203          $now = time();
 204          $expected = new \stdClass();
 205          $expected->workshopid = $this->workshop->id;
 206          $expected->userid = 3;
 207          $expected->gradinggrade = 82.87670;
 208          $expected->timegraded = $now;
 209          //$DB->expectOnce('insert_record', array('workshop_aggregations', $expected));
 210          // excersise SUT
 211          $this->workshop->aggregate_grading_grades_process($batch, $now);
 212      }
 213  
 214      public function test_aggregate_grading_grades_process_single_grade_update() {
 215          $this->resetAfterTest(true);
 216          // fixture set-up
 217          $batch = array();
 218          $batch[] = (object)array('reviewerid'=>3, 'gradinggrade'=>90.00000, 'gradinggradeover'=>null, 'aggregationid'=>1, 'aggregatedgrade'=>82.87670);
 219          // expectation
 220          //$DB->expectOnce('update_record');
 221          // excersise SUT
 222          $this->workshop->aggregate_grading_grades_process($batch);
 223      }
 224  
 225      public function test_aggregate_grading_grades_process_single_grade_uptodate() {
 226          $this->resetAfterTest(true);
 227          // fixture set-up
 228          $batch = array();
 229          $batch[] = (object)array('reviewerid'=>3, 'gradinggrade'=>90.00000, 'gradinggradeover'=>null, 'aggregationid'=>1, 'aggregatedgrade'=>90.00000);
 230          // expectation
 231          //$DB->expectNever('update_record');
 232          // excersise SUT
 233          $this->workshop->aggregate_grading_grades_process($batch);
 234      }
 235  
 236      public function test_aggregate_grading_grades_process_single_grade_overridden() {
 237          $this->resetAfterTest(true);
 238          // fixture set-up
 239          $batch = array();
 240          $batch[] = (object)array('reviewerid'=>4, 'gradinggrade'=>91.56700, 'gradinggradeover'=>82.32105, 'aggregationid'=>2, 'aggregatedgrade'=>91.56700);
 241          // expectation
 242          //$DB->expectOnce('update_record');
 243          // excersise SUT
 244          $this->workshop->aggregate_grading_grades_process($batch);
 245      }
 246  
 247      public function test_aggregate_grading_grades_process_multiple_grades_new() {
 248          $this->resetAfterTest(true);
 249          // fixture set-up
 250          $batch = array();
 251          $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>99.45670, 'gradinggradeover'=>null, 'aggregationid'=>null, 'aggregatedgrade'=>null);
 252          $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>87.34311, 'gradinggradeover'=>null, 'aggregationid'=>null, 'aggregatedgrade'=>null);
 253          $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>51.12000, 'gradinggradeover'=>null, 'aggregationid'=>null, 'aggregatedgrade'=>null);
 254          // expectation
 255          $now = time();
 256          $expected = new \stdClass();
 257          $expected->workshopid = $this->workshop->id;
 258          $expected->userid = 5;
 259          $expected->gradinggrade = 79.3066;
 260          $expected->timegraded = $now;
 261          //$DB->expectOnce('insert_record', array('workshop_aggregations', $expected));
 262          // excersise SUT
 263          $this->workshop->aggregate_grading_grades_process($batch, $now);
 264      }
 265  
 266      public function test_aggregate_grading_grades_process_multiple_grades_update() {
 267          $this->resetAfterTest(true);
 268          // fixture set-up
 269          $batch = array();
 270          $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>56.23400, 'gradinggradeover'=>null, 'aggregationid'=>2, 'aggregatedgrade'=>79.30660);
 271          $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>87.34311, 'gradinggradeover'=>null, 'aggregationid'=>2, 'aggregatedgrade'=>79.30660);
 272          $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>51.12000, 'gradinggradeover'=>null, 'aggregationid'=>2, 'aggregatedgrade'=>79.30660);
 273          // expectation
 274          //$DB->expectOnce('update_record');
 275          // excersise SUT
 276          $this->workshop->aggregate_grading_grades_process($batch);
 277      }
 278  
 279      public function test_aggregate_grading_grades_process_multiple_grades_overriden() {
 280          $this->resetAfterTest(true);
 281          // fixture set-up
 282          $batch = array();
 283          $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>56.23400, 'gradinggradeover'=>99.45670, 'aggregationid'=>2, 'aggregatedgrade'=>64.89904);
 284          $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>87.34311, 'gradinggradeover'=>null, 'aggregationid'=>2, 'aggregatedgrade'=>64.89904);
 285          $batch[] = (object)array('reviewerid'=>5, 'gradinggrade'=>51.12000, 'gradinggradeover'=>null, 'aggregationid'=>2, 'aggregatedgrade'=>64.89904);
 286          // expectation
 287          //$DB->expectOnce('update_record');
 288          // excersise SUT
 289          $this->workshop->aggregate_grading_grades_process($batch);
 290      }
 291  
 292      public function test_aggregate_grading_grades_process_multiple_grades_one_missing() {
 293          $this->resetAfterTest(true);
 294          // fixture set-up
 295          $batch = array();
 296          $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>50.00000, 'gradinggradeover'=>null, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
 297          $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>null, 'gradinggradeover'=>null, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
 298          $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>52.20000, 'gradinggradeover'=>null, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
 299          // expectation
 300          //$DB->expectOnce('update_record');
 301          // excersise SUT
 302          $this->workshop->aggregate_grading_grades_process($batch);
 303      }
 304  
 305      public function test_aggregate_grading_grades_process_multiple_grades_missing_overridden() {
 306          $this->resetAfterTest(true);
 307          // fixture set-up
 308          $batch = array();
 309          $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>50.00000, 'gradinggradeover'=>null, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
 310          $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>null, 'gradinggradeover'=>69.00000, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
 311          $batch[] = (object)array('reviewerid'=>6, 'gradinggrade'=>52.20000, 'gradinggradeover'=>null, 'aggregationid'=>3, 'aggregatedgrade'=>100.00000);
 312          // expectation
 313          //$DB->expectOnce('update_record');
 314          // excersise SUT
 315          $this->workshop->aggregate_grading_grades_process($batch);
 316      }
 317  
 318      public function test_percent_to_value() {
 319          $this->resetAfterTest(true);
 320          // fixture setup
 321          $total = 185;
 322          $percent = 56.6543;
 323          // exercise SUT
 324          $part = workshop::percent_to_value($percent, $total);
 325          // verify
 326          $this->assertEquals($part, $total * $percent / 100);
 327      }
 328  
 329      public function test_percent_to_value_negative() {
 330          $this->resetAfterTest(true);
 331          // fixture setup
 332          $total = 185;
 333          $percent = -7.098;
 334  
 335          // exercise SUT
 336          $this->expectException(\coding_exception::class);
 337          $part = workshop::percent_to_value($percent, $total);
 338      }
 339  
 340      public function test_percent_to_value_over_hundred() {
 341          $this->resetAfterTest(true);
 342          // fixture setup
 343          $total = 185;
 344          $percent = 121.08;
 345  
 346          // exercise SUT
 347          $this->expectException(\coding_exception::class);
 348          $part = workshop::percent_to_value($percent, $total);
 349      }
 350  
 351      public function test_lcm() {
 352          $this->resetAfterTest(true);
 353          // fixture setup + exercise SUT + verify in one step
 354          $this->assertEquals(workshop::lcm(1,4), 4);
 355          $this->assertEquals(workshop::lcm(2,4), 4);
 356          $this->assertEquals(workshop::lcm(4,2), 4);
 357          $this->assertEquals(workshop::lcm(2,3), 6);
 358          $this->assertEquals(workshop::lcm(6,4), 12);
 359      }
 360  
 361      public function test_lcm_array() {
 362          $this->resetAfterTest(true);
 363          // fixture setup
 364          $numbers = array(5,3,15);
 365          // excersise SUT
 366          $lcm = array_reduce($numbers, 'workshop::lcm', 1);
 367          // verify
 368          $this->assertEquals($lcm, 15);
 369      }
 370  
 371      public function test_prepare_example_assessment() {
 372          $this->resetAfterTest(true);
 373          // fixture setup
 374          $fakerawrecord = (object)array(
 375              'id'                => 42,
 376              'submissionid'      => 56,
 377              'weight'            => 0,
 378              'timecreated'       => time() - 10,
 379              'timemodified'      => time() - 5,
 380              'grade'             => null,
 381              'gradinggrade'      => null,
 382              'gradinggradeover'  => null,
 383              'feedbackauthor'    => null,
 384              'feedbackauthorformat' => 0,
 385              'feedbackauthorattachment' => 0,
 386          );
 387          // excersise SUT
 388          $a = $this->workshop->prepare_example_assessment($fakerawrecord);
 389          // verify
 390          $this->assertTrue($a instanceof workshop_example_assessment);
 391          $this->assertTrue($a->url instanceof \moodle_url);
 392  
 393          // modify setup
 394          $fakerawrecord->weight = 1;
 395          $this->expectException('coding_exception');
 396          // excersise SUT
 397          $a = $this->workshop->prepare_example_assessment($fakerawrecord);
 398      }
 399  
 400      public function test_prepare_example_reference_assessment() {
 401          global $USER;
 402          $this->resetAfterTest(true);
 403          // fixture setup
 404          $fakerawrecord = (object)array(
 405              'id'                => 38,
 406              'submissionid'      => 56,
 407              'weight'            => 1,
 408              'timecreated'       => time() - 100,
 409              'timemodified'      => time() - 50,
 410              'grade'             => 0.75000,
 411              'gradinggrade'      => 1.00000,
 412              'gradinggradeover'  => null,
 413              'feedbackauthor'    => null,
 414              'feedbackauthorformat' => 0,
 415              'feedbackauthorattachment' => 0,
 416          );
 417          // excersise SUT
 418          $a = $this->workshop->prepare_example_reference_assessment($fakerawrecord);
 419          // verify
 420          $this->assertTrue($a instanceof workshop_example_reference_assessment);
 421  
 422          // modify setup
 423          $fakerawrecord->weight = 0;
 424          $this->expectException('coding_exception');
 425          // excersise SUT
 426          $a = $this->workshop->prepare_example_reference_assessment($fakerawrecord);
 427      }
 428  
 429      /**
 430       * Tests user restrictions, as they affect lists of users returned by
 431       * core API functions.
 432       *
 433       * This includes the groupingid option (when group mode is in use), and
 434       * standard activity restrictions using the availability API.
 435       */
 436      public function test_user_restrictions() {
 437          global $DB, $CFG;
 438  
 439          $this->resetAfterTest();
 440  
 441          // Use existing sample course from setUp.
 442          $courseid = $this->workshop->course->id;
 443  
 444          // Make a test grouping and two groups.
 445          $generator = $this->getDataGenerator();
 446          $grouping = $generator->create_grouping(array('courseid' => $courseid));
 447          $group1 = $generator->create_group(array('courseid' => $courseid));
 448          groups_assign_grouping($grouping->id, $group1->id);
 449          $group2 = $generator->create_group(array('courseid' => $courseid));
 450          groups_assign_grouping($grouping->id, $group2->id);
 451  
 452          // Group 3 is not in the grouping.
 453          $group3 = $generator->create_group(array('courseid' => $courseid));
 454  
 455          // Enrol some students.
 456          $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
 457          $student1 = $generator->create_user();
 458          $student2 = $generator->create_user();
 459          $student3 = $generator->create_user();
 460          $generator->enrol_user($student1->id, $courseid, $roleids['student']);
 461          $generator->enrol_user($student2->id, $courseid, $roleids['student']);
 462          $generator->enrol_user($student3->id, $courseid, $roleids['student']);
 463  
 464          // Place students in groups (except student 3).
 465          groups_add_member($group1, $student1);
 466          groups_add_member($group2, $student2);
 467          groups_add_member($group3, $student3);
 468  
 469          // The existing workshop doesn't have any restrictions, so user lists
 470          // should include all three users.
 471          $allusers = get_enrolled_users(\context_course::instance($courseid));
 472          $result = $this->workshop->get_grouped($allusers);
 473          $this->assertCount(4, $result);
 474          $users = array_keys($result[0]);
 475          sort($users);
 476          $this->assertEquals(array($student1->id, $student2->id, $student3->id), $users);
 477          $this->assertEquals(array($student1->id), array_keys($result[$group1->id]));
 478          $this->assertEquals(array($student2->id), array_keys($result[$group2->id]));
 479          $this->assertEquals(array($student3->id), array_keys($result[$group3->id]));
 480  
 481          // Test get_users_with_capability_sql (via get_potential_authors).
 482          $users = $this->workshop->get_potential_authors(false);
 483          $this->assertCount(3, $users);
 484          $users = $this->workshop->get_potential_authors(false, $group2->id);
 485          $this->assertEquals(array($student2->id), array_keys($users));
 486  
 487          // Create another test workshop with grouping set.
 488          $workshopitem = $this->getDataGenerator()->create_module('workshop',
 489                  array('course' => $courseid, 'groupmode' => SEPARATEGROUPS,
 490                  'groupingid' => $grouping->id));
 491          $cm = get_coursemodule_from_instance('workshop', $workshopitem->id,
 492                  $courseid, false, MUST_EXIST);
 493          $workshopgrouping = new testable_workshop($workshopitem, $cm, $this->workshop->course);
 494  
 495          // This time the result should only include users and groups in the
 496          // selected grouping.
 497          $result = $workshopgrouping->get_grouped($allusers);
 498          $this->assertCount(3, $result);
 499          $users = array_keys($result[0]);
 500          sort($users);
 501          $this->assertEquals(array($student1->id, $student2->id), $users);
 502          $this->assertEquals(array($student1->id), array_keys($result[$group1->id]));
 503          $this->assertEquals(array($student2->id), array_keys($result[$group2->id]));
 504  
 505          // Test get_users_with_capability_sql (via get_potential_authors).
 506          $users = $workshopgrouping->get_potential_authors(false);
 507          $userids = array_keys($users);
 508          sort($userids);
 509          $this->assertEquals(array($student1->id, $student2->id), $userids);
 510          $users = $workshopgrouping->get_potential_authors(false, $group2->id);
 511          $this->assertEquals(array($student2->id), array_keys($users));
 512  
 513          // Enable the availability system and create another test workshop with
 514          // availability restriction on grouping.
 515          $CFG->enableavailability = true;
 516          $workshopitem = $this->getDataGenerator()->create_module('workshop',
 517                  array('course' => $courseid, 'availability' => json_encode(
 518                      \core_availability\tree::get_root_json(array(
 519                      \availability_grouping\condition::get_json($grouping->id)),
 520                      \core_availability\tree::OP_AND, false))));
 521          $cm = get_coursemodule_from_instance('workshop', $workshopitem->id,
 522                  $courseid, false, MUST_EXIST);
 523          $workshoprestricted = new testable_workshop($workshopitem, $cm, $this->workshop->course);
 524  
 525          // The get_grouped function isn't intended to apply this restriction,
 526          // so it should be the same as the base workshop. (Note: in reality,
 527          // get_grouped is always run with the parameter being the result of
 528          // one of the get_potential_xxx functions, so it works.)
 529          $result = $workshoprestricted->get_grouped($allusers);
 530          $this->assertCount(4, $result);
 531          $this->assertCount(3, $result[0]);
 532  
 533          // The get_users_with_capability_sql-based functions should apply it.
 534          $users = $workshoprestricted->get_potential_authors(false);
 535          $userids = array_keys($users);
 536          sort($userids);
 537          $this->assertEquals(array($student1->id, $student2->id), $userids);
 538          $users = $workshoprestricted->get_potential_authors(false, $group2->id);
 539          $this->assertEquals(array($student2->id), array_keys($users));
 540      }
 541  
 542      /**
 543       * Test the workshop reset feature.
 544       */
 545      public function test_reset_phase() {
 546          $this->resetAfterTest(true);
 547  
 548          $this->workshop->switch_phase(workshop::PHASE_CLOSED);
 549          $this->assertEquals(workshop::PHASE_CLOSED, $this->workshop->phase);
 550  
 551          $settings = (object)array(
 552              'reset_workshop_phase' => 0,
 553          );
 554          $status = $this->workshop->reset_userdata($settings);
 555          $this->assertEquals(workshop::PHASE_CLOSED, $this->workshop->phase);
 556  
 557          $settings = (object)array(
 558              'reset_workshop_phase' => 1,
 559          );
 560          $status = $this->workshop->reset_userdata($settings);
 561          $this->assertEquals(workshop::PHASE_SETUP, $this->workshop->phase);
 562          foreach ($status as $result) {
 563              $this->assertFalse($result['error']);
 564          }
 565      }
 566  
 567      /**
 568       * Test deleting assessments related data on workshop reset.
 569       */
 570      public function test_reset_userdata_assessments() {
 571          global $DB;
 572          $this->resetAfterTest(true);
 573  
 574          $student1 = $this->getDataGenerator()->create_user();
 575          $student2 = $this->getDataGenerator()->create_user();
 576  
 577          $this->getDataGenerator()->enrol_user($student1->id, $this->workshop->course->id);
 578          $this->getDataGenerator()->enrol_user($student2->id, $this->workshop->course->id);
 579  
 580          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
 581  
 582          $subid1 = $workshopgenerator->create_submission($this->workshop->id, $student1->id);
 583          $subid2 = $workshopgenerator->create_submission($this->workshop->id, $student2->id);
 584  
 585          $asid1 = $workshopgenerator->create_assessment($subid1, $student2->id);
 586          $asid2 = $workshopgenerator->create_assessment($subid2, $student1->id);
 587  
 588          $settings = (object)array(
 589              'reset_workshop_assessments' => 1,
 590          );
 591          $status = $this->workshop->reset_userdata($settings);
 592  
 593          foreach ($status as $result) {
 594              $this->assertFalse($result['error']);
 595          }
 596  
 597          $this->assertEquals(2, $DB->count_records('workshop_submissions', array('workshopid' => $this->workshop->id)));
 598          $this->assertEquals(0, $DB->count_records('workshop_assessments'));
 599      }
 600  
 601      /**
 602       * Test deleting submissions related data on workshop reset.
 603       */
 604      public function test_reset_userdata_submissions() {
 605          global $DB;
 606          $this->resetAfterTest(true);
 607  
 608          $student1 = $this->getDataGenerator()->create_user();
 609          $student2 = $this->getDataGenerator()->create_user();
 610  
 611          $this->getDataGenerator()->enrol_user($student1->id, $this->workshop->course->id);
 612          $this->getDataGenerator()->enrol_user($student2->id, $this->workshop->course->id);
 613  
 614          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
 615  
 616          $subid1 = $workshopgenerator->create_submission($this->workshop->id, $student1->id);
 617          $subid2 = $workshopgenerator->create_submission($this->workshop->id, $student2->id);
 618  
 619          $asid1 = $workshopgenerator->create_assessment($subid1, $student2->id);
 620          $asid2 = $workshopgenerator->create_assessment($subid2, $student1->id);
 621  
 622          $settings = (object)array(
 623              'reset_workshop_submissions' => 1,
 624          );
 625          $status = $this->workshop->reset_userdata($settings);
 626  
 627          foreach ($status as $result) {
 628              $this->assertFalse($result['error']);
 629          }
 630  
 631          $this->assertEquals(0, $DB->count_records('workshop_submissions', array('workshopid' => $this->workshop->id)));
 632          $this->assertEquals(0, $DB->count_records('workshop_assessments'));
 633      }
 634  
 635      /**
 636       * Test normalizing list of extensions.
 637       */
 638      public function test_normalize_file_extensions() {
 639          $this->resetAfterTest(true);
 640  
 641          workshop::normalize_file_extensions('');
 642          $this->assertDebuggingCalled();
 643      }
 644  
 645      /**
 646       * Test cleaning list of extensions.
 647       */
 648      public function test_clean_file_extensions() {
 649          $this->resetAfterTest(true);
 650  
 651          workshop::clean_file_extensions('');
 652          $this->assertDebuggingCalledCount(2);
 653      }
 654  
 655      /**
 656       * Test validation of the list of file extensions.
 657       */
 658      public function test_invalid_file_extensions() {
 659          $this->resetAfterTest(true);
 660  
 661          workshop::invalid_file_extensions('', '');
 662          $this->assertDebuggingCalledCount(3);
 663      }
 664  
 665      /**
 666       * Test checking file name against the list of allowed extensions.
 667       */
 668      public function test_is_allowed_file_type() {
 669          $this->resetAfterTest(true);
 670  
 671          workshop::is_allowed_file_type('', '');
 672          $this->assertDebuggingCalledCount(2);
 673      }
 674  
 675      /**
 676       * Test workshop::check_group_membership() functionality.
 677       */
 678      public function test_check_group_membership() {
 679          global $DB, $CFG;
 680  
 681          $this->resetAfterTest();
 682  
 683          $courseid = $this->course->id;
 684          $generator = $this->getDataGenerator();
 685  
 686          // Make test groups.
 687          $group1 = $generator->create_group(array('courseid' => $courseid));
 688          $group2 = $generator->create_group(array('courseid' => $courseid));
 689          $group3 = $generator->create_group(array('courseid' => $courseid));
 690  
 691          // Revoke the accessallgroups from non-editing teachers (tutors).
 692          $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
 693          unassign_capability('moodle/site:accessallgroups', $roleids['teacher']);
 694  
 695          // Create test use accounts.
 696          $teacher1 = $generator->create_user();
 697          $tutor1 = $generator->create_user();
 698          $tutor2 = $generator->create_user();
 699          $student1 = $generator->create_user();
 700          $student2 = $generator->create_user();
 701          $student3 = $generator->create_user();
 702  
 703          // Enrol the teacher (has the access all groups permission).
 704          $generator->enrol_user($teacher1->id, $courseid, $roleids['editingteacher']);
 705  
 706          // Enrol tutors (can not access all groups).
 707          $generator->enrol_user($tutor1->id, $courseid, $roleids['teacher']);
 708          $generator->enrol_user($tutor2->id, $courseid, $roleids['teacher']);
 709  
 710          // Enrol students.
 711          $generator->enrol_user($student1->id, $courseid, $roleids['student']);
 712          $generator->enrol_user($student2->id, $courseid, $roleids['student']);
 713          $generator->enrol_user($student3->id, $courseid, $roleids['student']);
 714  
 715          // Add users in groups.
 716          groups_add_member($group1, $tutor1);
 717          groups_add_member($group2, $tutor2);
 718          groups_add_member($group1, $student1);
 719          groups_add_member($group2, $student2);
 720          groups_add_member($group3, $student3);
 721  
 722          // Workshop with no groups.
 723          $workshopitem1 = $this->getDataGenerator()->create_module('workshop', [
 724              'course' => $courseid,
 725              'groupmode' => NOGROUPS,
 726          ]);
 727          $cm = get_coursemodule_from_instance('workshop', $workshopitem1->id, $courseid, false, MUST_EXIST);
 728          $workshop1 = new testable_workshop($workshopitem1, $cm, $this->course);
 729  
 730          $this->setUser($teacher1);
 731          $this->assertTrue($workshop1->check_group_membership($student1->id));
 732          $this->assertTrue($workshop1->check_group_membership($student2->id));
 733          $this->assertTrue($workshop1->check_group_membership($student3->id));
 734  
 735          $this->setUser($tutor1);
 736          $this->assertTrue($workshop1->check_group_membership($student1->id));
 737          $this->assertTrue($workshop1->check_group_membership($student2->id));
 738          $this->assertTrue($workshop1->check_group_membership($student3->id));
 739  
 740          // Workshop in visible groups mode.
 741          $workshopitem2 = $this->getDataGenerator()->create_module('workshop', [
 742              'course' => $courseid,
 743              'groupmode' => VISIBLEGROUPS,
 744          ]);
 745          $cm = get_coursemodule_from_instance('workshop', $workshopitem2->id, $courseid, false, MUST_EXIST);
 746          $workshop2 = new testable_workshop($workshopitem2, $cm, $this->course);
 747  
 748          $this->setUser($teacher1);
 749          $this->assertTrue($workshop2->check_group_membership($student1->id));
 750          $this->assertTrue($workshop2->check_group_membership($student2->id));
 751          $this->assertTrue($workshop2->check_group_membership($student3->id));
 752  
 753          $this->setUser($tutor1);
 754          $this->assertTrue($workshop2->check_group_membership($student1->id));
 755          $this->assertTrue($workshop2->check_group_membership($student2->id));
 756          $this->assertTrue($workshop2->check_group_membership($student3->id));
 757  
 758          // Workshop in separate groups mode.
 759          $workshopitem3 = $this->getDataGenerator()->create_module('workshop', [
 760              'course' => $courseid,
 761              'groupmode' => SEPARATEGROUPS,
 762          ]);
 763          $cm = get_coursemodule_from_instance('workshop', $workshopitem3->id, $courseid, false, MUST_EXIST);
 764          $workshop3 = new testable_workshop($workshopitem3, $cm, $this->course);
 765  
 766          $this->setUser($teacher1);
 767          $this->assertTrue($workshop3->check_group_membership($student1->id));
 768          $this->assertTrue($workshop3->check_group_membership($student2->id));
 769          $this->assertTrue($workshop3->check_group_membership($student3->id));
 770  
 771          $this->setUser($tutor1);
 772          $this->assertTrue($workshop3->check_group_membership($student1->id));
 773          $this->assertFalse($workshop3->check_group_membership($student2->id));
 774          $this->assertFalse($workshop3->check_group_membership($student3->id));
 775  
 776          $this->setUser($tutor2);
 777          $this->assertFalse($workshop3->check_group_membership($student1->id));
 778          $this->assertTrue($workshop3->check_group_membership($student2->id));
 779          $this->assertFalse($workshop3->check_group_membership($student3->id));
 780      }
 781  
 782      /**
 783       * Test init_initial_bar function.
 784       *
 785       * @covers \workshop::init_initial_bar
 786       */
 787      public function test_init_initial_bar(): void {
 788          global $SESSION;
 789          $this->resetAfterTest();
 790  
 791          $_GET['ifirst'] = 'A';
 792          $_GET['ilast'] = 'B';
 793          $contextid = $this->workshop->context->id;
 794  
 795          $this->workshop->init_initial_bar();
 796          $initialbarprefs = $this->get_initial_bar_prefs_property();
 797  
 798          $this->assertEquals('A', $initialbarprefs['i_first']);
 799          $this->assertEquals('B', $initialbarprefs['i_last']);
 800          $this->assertEquals('A', $SESSION->mod_workshop->initialbarprefs['id-' . $contextid]['i_first']);
 801          $this->assertEquals('B', $SESSION->mod_workshop->initialbarprefs['id-' . $contextid]['i_last']);
 802  
 803          $_GET['ifirst'] = null;
 804          $_GET['ilast'] = null;
 805          $SESSION->mod_workshop->initialbarprefs['id-' . $contextid]['i_first'] = 'D';
 806          $SESSION->mod_workshop->initialbarprefs['id-' . $contextid]['i_last'] = 'E';
 807  
 808          $this->workshop->init_initial_bar();
 809          $initialbarprefs = $this->get_initial_bar_prefs_property();
 810  
 811          $this->assertEquals('D', $initialbarprefs['i_first']);
 812          $this->assertEquals('E', $initialbarprefs['i_last']);
 813      }
 814  
 815      /**
 816       * Test empty init_initial_bar
 817       *
 818       * @covers \workshop::init_initial_bar
 819       */
 820      public function test_init_initial_bar_empty(): void {
 821          $this->resetAfterTest();
 822  
 823          $this->workshop->init_initial_bar();
 824          $initialbarprefs = $this->get_initial_bar_prefs_property();
 825  
 826          $this->assertEmpty($initialbarprefs);
 827      }
 828  
 829      /**
 830       * Test get_initial_first function
 831       *
 832       * @covers \workshop::get_initial_first
 833       */
 834      public function test_get_initial_first(): void {
 835          $this->resetAfterTest();
 836          $this->workshop->init_initial_bar();
 837          $this->assertEquals(null, $this->workshop->get_initial_first());
 838  
 839          $_GET['ifirst'] = 'D';
 840          $this->workshop->init_initial_bar();
 841          $this->assertEquals('D', $this->workshop->get_initial_first());
 842      }
 843  
 844      /**
 845       * Test get_initial_last function
 846       *
 847       * @covers \workshop::get_initial_last
 848       */
 849      public function test_get_initial_last(): void {
 850          $this->resetAfterTest();
 851          $this->workshop->init_initial_bar();
 852          $this->assertEquals(null, $this->workshop->get_initial_last());
 853  
 854          $_GET['ilast'] = 'D';
 855          $this->workshop->init_initial_bar();
 856          $this->assertEquals('D', $this->workshop->get_initial_last());
 857      }
 858  
 859      /**
 860       * Get the protected propertyinitialbarprefs from workshop class.
 861       *
 862       * @coversNothing
 863       * @return array initialbarspref property. eg ['i_first' => 'A', 'i_last' => 'B']
 864       */
 865      private function get_initial_bar_prefs_property(): array {
 866  
 867          $reflector = new \ReflectionObject($this->workshop);
 868          $initialbarprefsprop = $reflector->getProperty('initialbarprefs');
 869          $initialbarprefsprop->setAccessible(true);
 870          $initialbarprefs = $initialbarprefsprop->getValue($this->workshop);
 871  
 872          return $initialbarprefs;
 873      }
 874  }