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 namespace mod_assign; 18 19 use context_module; 20 use assign; 21 22 /** 23 * Downloader tests class for mod_assign. 24 * 25 * @package mod_assign 26 * @category test 27 * @copyright 2022 Ferran Recio <ferran@moodle.com> 28 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 29 * @coversDefaultClass \mod_assign\downloader 30 */ 31 class downloader_test extends \advanced_testcase { 32 /** 33 * Setup to ensure that fixtures are loaded. 34 */ 35 public static function setupBeforeClass(): void { 36 global $CFG; 37 require_once($CFG->dirroot . '/mod/assign/locallib.php'); 38 } 39 40 /** 41 * Test for load_filelist method. 42 * 43 * @covers ::load_filelist 44 * @dataProvider load_filelist_provider 45 * 46 * @param bool $teamsubmission if the assign must have team submissions 47 * @param array $groupmembers the groups definition 48 * @param array|null $filterusers the filtered users (null for all users) 49 * @param bool $blindmarking if the assign has blind marking 50 * @param bool $downloadasfolder if the download as folder preference is set 51 * @param array $expected the expected file list 52 */ 53 public function test_load_filelist( 54 bool $teamsubmission, 55 array $groupmembers, 56 ?array $filterusers, 57 bool $blindmarking, 58 bool $downloadasfolder, 59 array $expected 60 ) { 61 global $CFG; 62 $this->resetAfterTest(); 63 $this->setAdminUser(); 64 65 if (!$downloadasfolder) { 66 set_user_preference('assign_downloadasfolders', 0); 67 } 68 69 // Create course and enrols. 70 $course = $this->getDataGenerator()->create_course(); 71 $users = [ 72 'student1' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 73 'student2' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 74 'student3' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 75 'student4' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 76 'student5' => $this->getDataGenerator()->create_and_enrol($course, 'student'), 77 ]; 78 79 // Generate groups. 80 $groups = []; 81 foreach ($groupmembers as $groupname => $groupusers) { 82 $group = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => $groupname]); 83 foreach ($groupusers as $user) { 84 groups_add_member($group, $users[$user]); 85 } 86 $groups[$groupname] = $group; 87 } 88 89 // Create activity. 90 $params = [ 91 'course' => $course, 92 'assignsubmission_file_enabled' => 1, 93 'assignsubmission_file_maxfiles' => 12, 94 'assignsubmission_file_maxsizebytes' => 1024 * 1024, 95 ]; 96 if ($teamsubmission) { 97 $params['teamsubmission'] = 1; 98 $params['preventsubmissionnotingroup'] = false; 99 } 100 if ($blindmarking) { 101 $params['blindmarking'] = 1; 102 } 103 $activity = $this->getDataGenerator()->create_module('assign', $params); 104 $cm = get_coursemodule_from_id('assign', $activity->cmid, 0, false, MUST_EXIST); 105 $context = context_module::instance($cm->id); 106 107 // Generate submissions. 108 $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 109 $files = [ 110 "mod/assign/tests/fixtures/submissionsample01.txt", 111 "mod/assign/tests/fixtures/submissionsample02.txt" 112 ]; 113 foreach ($users as $key => $user) { 114 if ($key == 'student5') { 115 continue; 116 } 117 $datagenerator->create_submission([ 118 'userid' => $user->id, 119 'assignid' => $cm->id, 120 'file' => implode(',', $files), 121 ]); 122 } 123 124 // Generate file list. 125 if ($filterusers) { 126 foreach ($filterusers as $key => $identifier) { 127 $filterusers[$key] = $users[$identifier]->id; 128 } 129 } 130 $manager = new assign($context, $cm, $course); 131 $downloader = new downloader($manager, $filterusers); 132 $hasfiles = $downloader->load_filelist(); 133 134 // Expose protected filelist attribute. 135 $rc = new \ReflectionClass(downloader::class); 136 $rcp = $rc->getProperty('filesforzipping'); 137 $rcp->setAccessible(true); 138 139 // Add some replacements. 140 $search = ['PARTICIPANT', 'DEFAULTTEAM']; 141 $replace = [get_string('participant', 'mod_assign'), get_string('defaultteam', 'mod_assign')]; 142 foreach ($users as $identifier => $user) { 143 $search[] = strtoupper($identifier . '.ID'); 144 $replace[] = $manager->get_uniqueid_for_user($user->id); 145 $search[] = strtoupper($identifier); 146 $replace[] = $this->prepare_filename_text(fullname($user)); 147 } 148 foreach ($groups as $identifier => $group) { 149 $search[] = strtoupper($identifier . '.ID'); 150 $replace[] = strtoupper($group->id); 151 $search[] = strtoupper($identifier); 152 $replace[] = $this->prepare_filename_text($group->name); 153 } 154 155 // Validate values. 156 $filelist = $rcp->getValue($downloader); 157 $result = array_keys($filelist); 158 159 $this->assertEquals($hasfiles, !empty($expected)); 160 $this->assertCount(count($expected), $result); 161 foreach ($expected as $path) { 162 $value = str_replace($search, $replace, $path); 163 $this->assertTrue(in_array($value, $result)); 164 } 165 } 166 167 /** 168 * Internal helper to clean a filename text. 169 * 170 * @param string $text the text to transform 171 * @return string the clean string 172 */ 173 private function prepare_filename_text(string $text): string { 174 return clean_filename(str_replace('_', ' ', $text)); 175 } 176 177 /** 178 * Data provider for test_load_filelist(). 179 * 180 * @return array of scenarios 181 */ 182 public function load_filelist_provider(): array { 183 $downloadasfoldertests = $this->load_filelist_downloadasfolder_scenarios(); 184 $downloadasfilestests = $this->load_filelist_downloadasfiles_scenarios(); 185 return array_merge( 186 $downloadasfoldertests, 187 $downloadasfilestests, 188 ); 189 } 190 191 /** 192 * Generate the standard test scenarios for load_filelist with download as file. 193 * 194 * The scenarios are the same as download as folder but replacing the "/" of the files 195 * by a "_" and setting the downloadasfolder to false. 196 * 197 * @return array of scenarios 198 */ 199 private function load_filelist_downloadasfiles_scenarios(): array { 200 $result = $this->load_filelist_downloadasfolder_scenarios("Download as files:"); 201 // Transform paths from files. 202 foreach ($result as $scenario => $info) { 203 $info['downloadasfolder'] = false; 204 foreach ($info['expected'] as $key => $path) { 205 $info['expected'][$key] = str_replace('/', '_', $path); 206 } 207 $result[$scenario] = $info; 208 } 209 return $result; 210 } 211 212 /** 213 * Generate the standard test scenarios for load_filelist with download as folder. 214 * 215 * @param string $prefix the scenarios prefix 216 * @return array of scenarios 217 */ 218 private function load_filelist_downloadasfolder_scenarios(string $prefix = "Download as folders:"): array { 219 return [ 220 // Test without team submissions. 221 $prefix . ' All users without groups' => [ 222 'teamsubmission' => false, 223 'groupmembers' => [], 224 'filterusers' => null, 225 'blindmarking' => false, 226 'downloadasfolder' => true, 227 'expected' => [ 228 'STUDENT1_STUDENT1.ID_assignsubmission_file/submissionsample01.txt', 229 'STUDENT1_STUDENT1.ID_assignsubmission_file/submissionsample02.txt', 230 'STUDENT2_STUDENT2.ID_assignsubmission_file/submissionsample01.txt', 231 'STUDENT2_STUDENT2.ID_assignsubmission_file/submissionsample02.txt', 232 'STUDENT3_STUDENT3.ID_assignsubmission_file/submissionsample01.txt', 233 'STUDENT3_STUDENT3.ID_assignsubmission_file/submissionsample02.txt', 234 'STUDENT4_STUDENT4.ID_assignsubmission_file/submissionsample01.txt', 235 'STUDENT4_STUDENT4.ID_assignsubmission_file/submissionsample02.txt', 236 ], 237 ], 238 $prefix . ' Filtered users' => [ 239 'teamsubmission' => false, 240 'groupmembers' => [], 241 'filterusers' => ['student1', 'student2'], 242 'blindmarking' => false, 243 'downloadasfolder' => true, 244 'expected' => [ 245 'STUDENT1_STUDENT1.ID_assignsubmission_file/submissionsample01.txt', 246 'STUDENT1_STUDENT1.ID_assignsubmission_file/submissionsample02.txt', 247 'STUDENT2_STUDENT2.ID_assignsubmission_file/submissionsample01.txt', 248 'STUDENT2_STUDENT2.ID_assignsubmission_file/submissionsample02.txt', 249 ], 250 ], 251 $prefix . ' Filtering users without submissions' => [ 252 'teamsubmission' => false, 253 'groupmembers' => [], 254 'filterusers' => ['student1', 'student5'], 255 'blindmarking' => false, 256 'downloadasfolder' => true, 257 'expected' => [ 258 'STUDENT1_STUDENT1.ID_assignsubmission_file/submissionsample01.txt', 259 'STUDENT1_STUDENT1.ID_assignsubmission_file/submissionsample02.txt', 260 ], 261 ], 262 $prefix . ' Asking only for users without submissions' => [ 263 'teamsubmission' => false, 264 'groupmembers' => [], 265 'filterusers' => ['student5'], 266 'blindmarking' => false, 267 'downloadasfolder' => true, 268 'expected' => [], 269 ], 270 // Test with team submissions and no default team. 271 $prefix . ' All users with all users in groups' => [ 272 'teamsubmission' => true, 273 'groupmembers' => [ 274 'group1' => ['student1'], 275 'group2' => ['student2', 'student3'], 276 'group3' => ['student4', 'student5'], 277 ], 278 'filterusers' => null, 279 'blindmarking' => false, 280 'downloadasfolder' => true, 281 'expected' => [ 282 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample01.txt', 283 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample02.txt', 284 'GROUP2_GROUP2.ID_assignsubmission_file/submissionsample01.txt', 285 'GROUP2_GROUP2.ID_assignsubmission_file/submissionsample02.txt', 286 'GROUP3_GROUP3.ID_assignsubmission_file/submissionsample01.txt', 287 'GROUP3_GROUP3.ID_assignsubmission_file/submissionsample02.txt', 288 ], 289 ], 290 $prefix . ' Filtering users with disjoined groups' => [ 291 'teamsubmission' => true, 292 'groupmembers' => [ 293 'group1' => ['student1'], 294 'group2' => ['student2', 'student3'], 295 'group3' => ['student4', 'student5'], 296 ], 297 'filterusers' => ['student1', 'student2'], 298 'blindmarking' => false, 299 'downloadasfolder' => true, 300 'expected' => [ 301 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample01.txt', 302 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample02.txt', 303 'GROUP2_GROUP2.ID_assignsubmission_file/submissionsample01.txt', 304 'GROUP2_GROUP2.ID_assignsubmission_file/submissionsample02.txt', 305 ], 306 ], 307 $prefix . ' Filtering users with default teams who does not do a submission' => [ 308 'teamsubmission' => true, 309 'groupmembers' => [ 310 'group1' => ['student1'], 311 'group2' => ['student2', 'student3'], 312 'group3' => ['student4', 'student5'], 313 ], 314 'filterusers' => ['student1', 'student5'], 315 'blindmarking' => false, 316 'downloadasfolder' => true, 317 'expected' => [ 318 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample01.txt', 319 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample02.txt', 320 'GROUP3_GROUP3.ID_assignsubmission_file/submissionsample01.txt', 321 'GROUP3_GROUP3.ID_assignsubmission_file/submissionsample02.txt', 322 ], 323 ], 324 $prefix . ' Filtering users without submission but member of a group' => [ 325 'teamsubmission' => true, 326 'groupmembers' => [ 327 'group1' => ['student1'], 328 'group2' => ['student2', 'student3'], 329 'group3' => ['student4', 'student5'], 330 ], 331 'filterusers' => [ 332 'student5' 333 ], 334 'blindmarking' => false, 335 'downloadasfolder' => true, 336 'expected' => [ 337 'GROUP3_GROUP3.ID_assignsubmission_file/submissionsample01.txt', 338 'GROUP3_GROUP3.ID_assignsubmission_file/submissionsample02.txt', 339 ], 340 ], 341 // Test with default team. 342 $prefix . ' All users with users in the default team' => [ 343 'teamsubmission' => true, 344 'groupmembers' => [ 345 'group1' => ['student1', 'student2'], 346 ], 347 'filterusers' => null, 348 'blindmarking' => false, 349 'downloadasfolder' => true, 350 'expected' => [ 351 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample01.txt', 352 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample02.txt', 353 'DEFAULTTEAM_assignsubmission_file/submissionsample01.txt', 354 'DEFAULTTEAM_assignsubmission_file/submissionsample02.txt', 355 ], 356 ], 357 $prefix . ' Filtered users in groups with users in the default team' => [ 358 'teamsubmission' => true, 359 'groupmembers' => [ 360 'group1' => ['student1', 'student2'], 361 ], 362 'filterusers' => ['student1', 'student2'], 363 'blindmarking' => false, 364 'downloadasfolder' => true, 365 'expected' => [ 366 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample01.txt', 367 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample02.txt', 368 ], 369 ], 370 $prefix . ' Filtered users without groups with users in the default team' => [ 371 'teamsubmission' => true, 372 'groupmembers' => [ 373 'group1' => ['student1', 'student2'], 374 ], 375 'filterusers' => ['student3', 'student4'], 376 'blindmarking' => false, 377 'downloadasfolder' => true, 378 'expected' => [ 379 'DEFAULTTEAM_assignsubmission_file/submissionsample01.txt', 380 'DEFAULTTEAM_assignsubmission_file/submissionsample02.txt', 381 ], 382 ], 383 $prefix . ' Filtered users with some users in the default team' => [ 384 'teamsubmission' => true, 385 'groupmembers' => [ 386 'group1' => ['student1', 'student2'], 387 ], 388 'filterusers' => ['student1', 'student3'], 389 'blindmarking' => false, 390 'downloadasfolder' => true, 391 'expected' => [ 392 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample01.txt', 393 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample02.txt', 394 'DEFAULTTEAM_assignsubmission_file/submissionsample01.txt', 395 'DEFAULTTEAM_assignsubmission_file/submissionsample02.txt', 396 ], 397 ], 398 $prefix . ' Filtering users with joined groups' => [ 399 'teamsubmission' => true, 400 'groupmembers' => [ 401 'group1' => ['student1', 'student2'], 402 'group2' => ['student2', 'student3'], 403 ], 404 'filterusers' => ['student1', 'student2'], 405 'blindmarking' => false, 406 'downloadasfolder' => true, 407 'expected' => [ 408 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample01.txt', 409 'GROUP1_GROUP1.ID_assignsubmission_file/submissionsample02.txt', 410 'DEFAULTTEAM_assignsubmission_file/submissionsample01.txt', 411 'DEFAULTTEAM_assignsubmission_file/submissionsample02.txt', 412 ], 413 ], 414 // Tests with blind marking. 415 $prefix . ' All users without groups and blindmarking' => [ 416 'teamsubmission' => false, 417 'groupmembers' => [], 418 'filterusers' => null, 419 'blindmarking' => true, 420 'downloadasfolder' => true, 421 'expected' => [ 422 'PARTICIPANT_STUDENT1.ID_assignsubmission_file/submissionsample01.txt', 423 'PARTICIPANT_STUDENT1.ID_assignsubmission_file/submissionsample02.txt', 424 'PARTICIPANT_STUDENT2.ID_assignsubmission_file/submissionsample01.txt', 425 'PARTICIPANT_STUDENT2.ID_assignsubmission_file/submissionsample02.txt', 426 'PARTICIPANT_STUDENT3.ID_assignsubmission_file/submissionsample01.txt', 427 'PARTICIPANT_STUDENT3.ID_assignsubmission_file/submissionsample02.txt', 428 'PARTICIPANT_STUDENT4.ID_assignsubmission_file/submissionsample01.txt', 429 'PARTICIPANT_STUDENT4.ID_assignsubmission_file/submissionsample02.txt', 430 ], 431 ], 432 $prefix . ' Filtered users without groups and blindmarking' => [ 433 'teamsubmission' => false, 434 'groupmembers' => [], 435 'filterusers' => ['student1', 'student2'], 436 'blindmarking' => true, 437 'downloadasfolder' => true, 438 'expected' => [ 439 'PARTICIPANT_STUDENT1.ID_assignsubmission_file/submissionsample01.txt', 440 'PARTICIPANT_STUDENT1.ID_assignsubmission_file/submissionsample02.txt', 441 'PARTICIPANT_STUDENT2.ID_assignsubmission_file/submissionsample01.txt', 442 'PARTICIPANT_STUDENT2.ID_assignsubmission_file/submissionsample02.txt', 443 ], 444 ], 445 ]; 446 } 447 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body