Differences Between: [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 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 * Contains unit tests for core_completion/cm_completion_details. 19 * 20 * @package core_completion 21 * @copyright 2021 Jun Pataleta <jun@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 declare(strict_types = 1); 26 27 namespace core_completion; 28 29 use advanced_testcase; 30 use cm_info; 31 use completion_info; 32 33 defined('MOODLE_INTERNAL') || die(); 34 35 global $CFG; 36 require_once($CFG->libdir . '/completionlib.php'); 37 38 /** 39 * Class for unit testing core_completion/cm_completion_details. 40 * 41 * @package core_completion 42 * @copyright 2021 Jun Pataleta <jun@moodle.com> 43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 44 */ 45 class cm_completion_details_test extends advanced_testcase { 46 47 /** @var completion_info A completion object. */ 48 protected $completioninfo = null; 49 50 /** 51 * Fetches a mocked cm_completion_details instance. 52 * 53 * @param int|null $completion The completion tracking mode for the module. 54 * @param array $completionoptions Completion options (e.g. completionview, completionusegrade, etc.) 55 * @param object $mockcompletiondata Mock data to be returned by get_data. 56 * @param string $modname The modname to set in the cm if a specific one is required. 57 * @return cm_completion_details 58 */ 59 protected function setup_data(?int $completion, array $completionoptions = [], 60 object $mockcompletiondata = null, $modname = 'somenonexistentmod'): cm_completion_details { 61 if (is_null($completion)) { 62 $completion = COMPLETION_TRACKING_AUTOMATIC; 63 } 64 65 // Mock a completion_info instance so we can simply mock the returns of completion_info::get_data() later. 66 $this->completioninfo = $this->getMockBuilder(completion_info::class) 67 ->disableOriginalConstructor() 68 ->getMock(); 69 70 // Mock return of completion_info's is_enabled() method to match the expected completion tracking for the module. 71 $this->completioninfo->expects($this->any()) 72 ->method('is_enabled') 73 ->willReturn($completion); 74 75 if (!empty($mockcompletiondata)) { 76 $this->completioninfo->expects($this->any()) 77 ->method('get_data') 78 ->willReturn($mockcompletiondata); 79 } 80 81 // Build a mock cm_info instance. 82 $mockcminfo = $this->getMockBuilder(cm_info::class) 83 ->disableOriginalConstructor() 84 ->onlyMethods(['__get']) 85 ->getMock(); 86 87 // Mock the return of the magic getter method when fetching the cm_info object's customdata and instance values. 88 $mockcminfo->expects($this->any()) 89 ->method('__get') 90 ->will($this->returnValueMap([ 91 ['completion', $completion], 92 ['instance', 1], 93 ['modname', $modname], 94 ['completionview', $completionoptions['completionview'] ?? COMPLETION_VIEW_NOT_REQUIRED], 95 ['completiongradeitemnumber', $completionoptions['completionusegrade'] ?? null], 96 ])); 97 98 return new cm_completion_details($this->completioninfo, $mockcminfo, 2); 99 } 100 101 /** 102 * Provides data for test_has_completion(). 103 * 104 * @return array[] 105 */ 106 public function has_completion_provider(): array { 107 return [ 108 'Automatic' => [ 109 COMPLETION_TRACKING_AUTOMATIC, true 110 ], 111 'Manual' => [ 112 COMPLETION_TRACKING_MANUAL, true 113 ], 114 'None' => [ 115 COMPLETION_TRACKING_NONE, false 116 ], 117 ]; 118 } 119 120 /** 121 * Test for has_completion(). 122 * 123 * @dataProvider has_completion_provider 124 * @param int $completion The completion tracking mode. 125 * @param bool $expectedresult Expected result. 126 */ 127 public function test_has_completion(int $completion, bool $expectedresult) { 128 $cmcompletion = $this->setup_data($completion); 129 130 $this->assertEquals($expectedresult, $cmcompletion->has_completion()); 131 } 132 133 /** 134 * Provides data for test_is_automatic(). 135 * 136 * @return array[] 137 */ 138 public function is_automatic_provider(): array { 139 return [ 140 'Automatic' => [ 141 COMPLETION_TRACKING_AUTOMATIC, true 142 ], 143 'Manual' => [ 144 COMPLETION_TRACKING_MANUAL, false 145 ], 146 'None' => [ 147 COMPLETION_TRACKING_NONE, false 148 ], 149 ]; 150 } 151 152 /** 153 * Test for is_available(). 154 * 155 * @dataProvider is_automatic_provider 156 * @param int $completion The completion tracking mode. 157 * @param bool $expectedresult Expected result. 158 */ 159 public function test_is_automatic(int $completion, bool $expectedresult) { 160 $cmcompletion = $this->setup_data($completion); 161 162 $this->assertEquals($expectedresult, $cmcompletion->is_automatic()); 163 } 164 165 /** 166 * Data provider for test_get_overall_completion(). 167 * @return array[] 168 */ 169 public function overall_completion_provider(): array { 170 return [ 171 'Complete' => [COMPLETION_COMPLETE], 172 'Incomplete' => [COMPLETION_INCOMPLETE], 173 ]; 174 } 175 176 /** 177 * Test for get_overall_completion(). 178 * 179 * @dataProvider overall_completion_provider 180 * @param int $state 181 */ 182 public function test_get_overall_completion(int $state) { 183 $completiondata = (object)['completionstate' => $state]; 184 $cmcompletion = $this->setup_data(COMPLETION_TRACKING_AUTOMATIC, [], $completiondata); 185 $this->assertEquals($state, $cmcompletion->get_overall_completion()); 186 } 187 188 /** 189 * Data provider for test_get_details(). 190 * @return array[] 191 */ 192 public function get_details_provider() { 193 return [ 194 'No completion tracking' => [ 195 COMPLETION_TRACKING_NONE, null, null, [] 196 ], 197 'Manual completion tracking' => [ 198 COMPLETION_TRACKING_MANUAL, null, null, [] 199 ], 200 'Automatic, require view, not viewed' => [ 201 COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, null, [ 202 'completionview' => (object)[ 203 'status' => COMPLETION_INCOMPLETE, 204 'description' => get_string('detail_desc:view', 'completion'), 205 ] 206 ] 207 ], 208 'Automatic, require view, viewed' => [ 209 COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, null, [ 210 'completionview' => (object)[ 211 'status' => COMPLETION_COMPLETE, 212 'description' => get_string('detail_desc:view', 'completion'), 213 ] 214 ] 215 ], 216 'Automatic, require grade, incomplete' => [ 217 COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_INCOMPLETE, [ 218 'completionusegrade' => (object)[ 219 'status' => COMPLETION_INCOMPLETE, 220 'description' => get_string('detail_desc:receivegrade', 'completion'), 221 ] 222 ] 223 ], 224 'Automatic, require grade, complete' => [ 225 COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, [ 226 'completionusegrade' => (object)[ 227 'status' => COMPLETION_COMPLETE, 228 'description' => get_string('detail_desc:receivegrade', 'completion'), 229 ] 230 ] 231 ], 232 'Automatic, require view (complete) and grade (incomplete)' => [ 233 COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, [ 234 'completionview' => (object)[ 235 'status' => COMPLETION_COMPLETE, 236 'description' => get_string('detail_desc:view', 'completion'), 237 ], 238 'completionusegrade' => (object)[ 239 'status' => COMPLETION_INCOMPLETE, 240 'description' => get_string('detail_desc:receivegrade', 'completion'), 241 ] 242 ] 243 ], 244 'Automatic, require view (incomplete) and grade (complete)' => [ 245 COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, [ 246 'completionview' => (object)[ 247 'status' => COMPLETION_INCOMPLETE, 248 'description' => get_string('detail_desc:view', 'completion'), 249 ], 250 'completionusegrade' => (object)[ 251 'status' => COMPLETION_COMPLETE, 252 'description' => get_string('detail_desc:receivegrade', 'completion'), 253 ] 254 ] 255 ], 256 ]; 257 } 258 259 /** 260 * Test for \core_completion\cm_completion_details::get_details(). 261 * 262 * @dataProvider get_details_provider 263 * @param int $completion The completion tracking mode. 264 * @param int|null $completionview Completion status of the "view" completion condition. 265 * @param int|null $completiongrade Completion status of the "must receive grade" completion condition. 266 * @param array $expecteddetails Expected completion details returned by get_details(). 267 */ 268 public function test_get_details(int $completion, ?int $completionview, ?int $completiongrade, array $expecteddetails) { 269 $options = []; 270 $getdatareturn = (object)[ 271 'viewed' => $completionview, 272 'completiongrade' => $completiongrade, 273 ]; 274 275 if (!is_null($completionview)) { 276 $options['completionview'] = true; 277 } 278 if (!is_null($completiongrade)) { 279 $options['completionusegrade'] = true; 280 } 281 282 $cmcompletion = $this->setup_data($completion, $options, $getdatareturn); 283 $this->assertEquals($expecteddetails, $cmcompletion->get_details()); 284 } 285 286 /** 287 * Data provider for test_get_details(). 288 * @return array[] 289 */ 290 public function get_details_custom_order_provider() { 291 return [ 292 'Custom and view/grade standard conditions, view first and grade last' => [ 293 true, 294 true, 295 [ 296 'completionsubmit' => true, 297 ], 298 'assign', 299 ['completionview', 'completionsubmit', 'completionusegrade'], 300 ], 301 'Custom and view/grade standard conditions, grade not last' => [ 302 true, 303 true, 304 [ 305 'completionminattempts' => 2, 306 'completionusegrade' => 50, 307 'completionpassorattemptsexhausted' => 1, 308 ], 309 'quiz', 310 ['completionview', 'completionminattempts', 'completionusegrade', 'completionpassorattemptsexhausted'], 311 ], 312 'Custom and grade standard conditions only, no view condition' => [ 313 false, 314 true, 315 [ 316 'completionsubmit' => true, 317 ], 318 'assign', 319 ['completionsubmit', 'completionusegrade'], 320 ], 321 'Custom and view standard conditions only, no grade condition' => [ 322 true, 323 false, 324 [ 325 'completionsubmit' => true 326 ], 327 'assign', 328 ['completionview', 'completionsubmit'], 329 ], 330 'View and grade conditions only, activity with no custom conditions' => [ 331 true, 332 true, 333 [ 334 'completionview' => true, 335 'completionusegrade' => true 336 ], 337 'workshop', 338 ['completionview', 'completionusegrade'], 339 ], 340 'View condition only, activity with no custom conditions' => [ 341 true, 342 false, 343 [ 344 'completionview' => true, 345 ], 346 'workshop', 347 ['completionview'], 348 ], 349 ]; 350 } 351 352 /** 353 * Test custom sort order is functioning in \core_completion\cm_completion_details::get_details(). 354 * 355 * @dataProvider get_details_custom_order_provider 356 * @param bool $completionview Completion status of the "view" completion condition. 357 * @param bool $completiongrade Completion status of the "must receive grade" completion condition. 358 * @param array $customcompletionrules Custom completion requirements, along with their values. 359 * @param string $modname The name of the module having data fetched. 360 * @param array $expectedorder The expected order of completion conditions returned about the module. 361 */ 362 public function test_get_details_custom_order(bool $completionview, bool $completiongrade, array $customcompletionrules, 363 string $modname, array $expectedorder) { 364 365 $options['customcompletion'] = []; 366 $customcompletiondata = []; 367 368 if ($completionview) { 369 $options['completionview'] = true; 370 } 371 372 if ($completiongrade) { 373 $options['completionusegrade'] = true; 374 } 375 376 // Set up the completion rules for the completion info. 377 foreach ($customcompletionrules as $customtype => $isenabled) { 378 $customcompletiondata[$customtype] = COMPLETION_COMPLETE; 379 } 380 381 $getdatareturn = (object)[ 382 'viewed' => $completionview ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE, 383 'completiongrade' => $completiongrade ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE, 384 'customcompletion' => $customcompletiondata, 385 ]; 386 387 $cmcompletion = $this->setup_data(COMPLETION_TRACKING_AUTOMATIC, $options, $getdatareturn, $modname); 388 389 $this->completioninfo->expects($this->any()) 390 ->method('get_data') 391 ->willReturn($getdatareturn); 392 393 $fetcheddetails = $cmcompletion->get_details(); 394 395 // Check the expected number of items are returned, and sorted in the correct order. 396 $this->assertCount(count($expectedorder), $fetcheddetails); 397 $this->assertTrue((array_keys($fetcheddetails) === $expectedorder)); 398 } 399 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body