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 311 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 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   * @coversDefaultClass \core_completion\cm_completion_details
  45   */
  46  class cm_completion_details_test extends advanced_testcase {
  47  
  48      /** @var completion_info A completion object. */
  49      protected $completioninfo = null;
  50  
  51      /**
  52       * Fetches a mocked cm_completion_details instance.
  53       *
  54       * @param int|null $completion The completion tracking mode for the module.
  55       * @param array $completionoptions Completion options (e.g. completionview, completionusegrade, etc.)
  56       * @param object $mockcompletiondata Mock data to be returned by get_data.
  57       * @param string $modname The modname to set in the cm if a specific one is required.
  58       * @return cm_completion_details
  59       */
  60      protected function setup_data(?int $completion, array $completionoptions = [],
  61              object $mockcompletiondata = null, $modname = 'somenonexistentmod'): cm_completion_details {
  62          if (is_null($completion)) {
  63              $completion = COMPLETION_TRACKING_AUTOMATIC;
  64          }
  65  
  66          // Mock a completion_info instance so we can simply mock the returns of completion_info::get_data() later.
  67          $this->completioninfo = $this->getMockBuilder(completion_info::class)
  68              ->disableOriginalConstructor()
  69              ->getMock();
  70  
  71          // Mock return of completion_info's is_enabled() method to match the expected completion tracking for the module.
  72          $this->completioninfo->expects($this->any())
  73              ->method('is_enabled')
  74              ->willReturn($completion);
  75  
  76          if (!empty($mockcompletiondata)) {
  77              $this->completioninfo->expects($this->any())
  78                  ->method('get_data')
  79                  ->willReturn($mockcompletiondata);
  80          }
  81  
  82          // Build a mock cm_info instance.
  83          $mockcminfo = $this->getMockBuilder(cm_info::class)
  84              ->disableOriginalConstructor()
  85              ->onlyMethods(['__get'])
  86              ->getMock();
  87  
  88          // Mock the return of the magic getter method when fetching the cm_info object's customdata and instance values.
  89          $mockcminfo->expects($this->any())
  90              ->method('__get')
  91              ->will($this->returnValueMap([
  92                  ['completion', $completion],
  93                  ['instance', 1],
  94                  ['modname', $modname],
  95                  ['completionview', $completionoptions['completionview'] ?? COMPLETION_VIEW_NOT_REQUIRED],
  96                  ['completiongradeitemnumber', $completionoptions['completionusegrade'] ?? null],
  97                  ['completionpassgrade', $completionoptions['completionpassgrade'] ?? null],
  98              ]));
  99  
 100          return new cm_completion_details($this->completioninfo, $mockcminfo, 2);
 101      }
 102  
 103      /**
 104       * Provides data for test_has_completion().
 105       *
 106       * @return array[]
 107       */
 108      public function has_completion_provider(): array {
 109          return [
 110              'Automatic' => [
 111                  COMPLETION_TRACKING_AUTOMATIC, true
 112              ],
 113              'Manual' => [
 114                  COMPLETION_TRACKING_MANUAL, true
 115              ],
 116              'None' => [
 117                  COMPLETION_TRACKING_NONE, false
 118              ],
 119          ];
 120      }
 121  
 122      /**
 123       * Test for has_completion().
 124       *
 125       * @covers ::has_completion
 126       * @dataProvider has_completion_provider
 127       * @param int $completion The completion tracking mode.
 128       * @param bool $expectedresult Expected result.
 129       */
 130      public function test_has_completion(int $completion, bool $expectedresult) {
 131          $cmcompletion = $this->setup_data($completion);
 132  
 133          $this->assertEquals($expectedresult, $cmcompletion->has_completion());
 134      }
 135  
 136      /**
 137       * Provides data for test_is_automatic().
 138       *
 139       * @return array[]
 140       */
 141      public function is_automatic_provider(): array {
 142          return [
 143              'Automatic' => [
 144                  COMPLETION_TRACKING_AUTOMATIC, true
 145              ],
 146              'Manual' => [
 147                  COMPLETION_TRACKING_MANUAL, false
 148              ],
 149              'None' => [
 150                  COMPLETION_TRACKING_NONE, false
 151              ],
 152          ];
 153      }
 154  
 155      /**
 156       * Test for is_available().
 157       *
 158       * @covers ::is_automatic
 159       * @dataProvider is_automatic_provider
 160       * @param int $completion The completion tracking mode.
 161       * @param bool $expectedresult Expected result.
 162       */
 163      public function test_is_automatic(int $completion, bool $expectedresult) {
 164          $cmcompletion = $this->setup_data($completion);
 165  
 166          $this->assertEquals($expectedresult, $cmcompletion->is_automatic());
 167      }
 168  
 169      /**
 170       * Provides data for test_is_manual().
 171       *
 172       * @return array[]
 173       */
 174      public function is_manual_provider(): array {
 175          return [
 176              'Automatic' => [
 177                  COMPLETION_TRACKING_AUTOMATIC, false
 178              ],
 179              'Manual' => [
 180                  COMPLETION_TRACKING_MANUAL, true
 181              ],
 182              'None' => [
 183                  COMPLETION_TRACKING_NONE, false
 184              ],
 185          ];
 186      }
 187  
 188      /**
 189       * Test for is_manual().
 190       *
 191       * @covers ::is_manual
 192       * @dataProvider is_manual_provider
 193       * @param int $completion The completion tracking mode.
 194       * @param bool $expectedresult Expected result.
 195       */
 196      public function test_is_manual(int $completion, bool $expectedresult) {
 197          $cmcompletion = $this->setup_data($completion);
 198  
 199          $this->assertEquals($expectedresult, $cmcompletion->is_manual());
 200      }
 201  
 202      /**
 203       * Data provider for test_get_overall_completion().
 204       * @return array[]
 205       */
 206      public function overall_completion_provider(): array {
 207          return [
 208              'Complete' => [COMPLETION_COMPLETE],
 209              'Incomplete' => [COMPLETION_INCOMPLETE],
 210          ];
 211      }
 212  
 213      /**
 214       * Test for get_overall_completion().
 215       *
 216       * @covers ::get_overall_completion
 217       * @dataProvider overall_completion_provider
 218       * @param int $state
 219       */
 220      public function test_get_overall_completion(int $state) {
 221          $completiondata = (object)['completionstate' => $state];
 222          $cmcompletion = $this->setup_data(COMPLETION_TRACKING_AUTOMATIC, [], $completiondata);
 223          $this->assertEquals($state, $cmcompletion->get_overall_completion());
 224      }
 225  
 226      /**
 227       * Data provider for test_is_overall_complete().
 228       * @return array[]
 229       */
 230      public static function is_overall_complete_provider(): array {
 231          return [
 232              'Automatic, require view, not viewed' => [
 233                  'expected' => false,
 234                  'completion' => COMPLETION_TRACKING_AUTOMATIC,
 235                  'completionstate' => COMPLETION_INCOMPLETE,
 236                  'completionview' => COMPLETION_INCOMPLETE,
 237                  'completiongrade' => null,
 238                  'completionpassgrade' => null,
 239              ],
 240              'Automatic, require view, viewed' => [
 241                  'expected' => true,
 242                  'completion' => COMPLETION_TRACKING_AUTOMATIC,
 243                  'completionstate' => COMPLETION_COMPLETE,
 244                  'completionview' => COMPLETION_COMPLETE,
 245                  'completiongrade' => null,
 246                  'completionpassgrade' => null,
 247              ],
 248              'Automatic, require grade, not graded' => [
 249                  'expected' => false,
 250                  'completion' => COMPLETION_TRACKING_AUTOMATIC,
 251                  'completionstate' => COMPLETION_INCOMPLETE,
 252                  'completionview' => null,
 253                  'completiongrade' => COMPLETION_INCOMPLETE,
 254                  'completionpassgrade' => null,
 255              ],
 256              'Automatic, require grade, graded with fail' => [
 257                  'expected' => true,
 258                  'completion' => COMPLETION_TRACKING_AUTOMATIC,
 259                  'completionstate' => COMPLETION_COMPLETE_FAIL,
 260                  'completionview' => null,
 261                  'completiongrade' => COMPLETION_COMPLETE_FAIL,
 262                  'completionpassgrade' => null,
 263              ],
 264              'Automatic, require grade, graded with passing' => [
 265                  'expected' => true,
 266                  'completion' => COMPLETION_TRACKING_AUTOMATIC,
 267                  'completionstate' => COMPLETION_COMPLETE_PASS,
 268                  'completionview' => null,
 269                  'completiongrade' => COMPLETION_COMPLETE_PASS,
 270                  'completionpassgrade' => null,
 271              ],
 272              'Automatic, require passgrade, not graded' => [
 273                  'expected' => false,
 274                  'completion' => COMPLETION_TRACKING_AUTOMATIC,
 275                  'completionstate' => COMPLETION_INCOMPLETE,
 276                  'completionview' => null,
 277                  'completiongrade' => null,
 278                  'completionpassgrade' => COMPLETION_INCOMPLETE,
 279              ],
 280              'Automatic, require passgrade, graded with fail' => [
 281                  'expected' => false,
 282                  'completion' => COMPLETION_TRACKING_AUTOMATIC,
 283                  'completionstate' => COMPLETION_COMPLETE_FAIL,
 284                  'completionview' => null,
 285                  'completiongrade' => null,
 286                  'completionpassgrade' => COMPLETION_COMPLETE_FAIL,
 287              ],
 288              'Automatic, require passgrade, graded with passing' => [
 289                  'expected' => true,
 290                  'completion' => COMPLETION_TRACKING_AUTOMATIC,
 291                  'completionstate' => COMPLETION_COMPLETE_PASS,
 292                  'completionview' => null,
 293                  'completiongrade' => null,
 294                  'completionpassgrade' => COMPLETION_COMPLETE_PASS,
 295              ],
 296              'Manual, incomplete' => [
 297                  'expected' => false,
 298                  'completion' => COMPLETION_TRACKING_MANUAL,
 299                  'completionstate' => COMPLETION_INCOMPLETE,
 300              ],
 301              'Manual, complete' => [
 302                  'expected' => true,
 303                  'completion' => COMPLETION_TRACKING_MANUAL,
 304                  'completionstate' => COMPLETION_COMPLETE,
 305              ],
 306              'None, incomplete' => [
 307                  'expected' => false,
 308                  'completion' => COMPLETION_TRACKING_NONE,
 309                  'completionstate' => COMPLETION_INCOMPLETE,
 310              ],
 311              'None, complete' => [
 312                  'expected' => false,
 313                  'completion' => COMPLETION_TRACKING_NONE,
 314                  'completionstate' => COMPLETION_COMPLETE,
 315              ],
 316          ];
 317      }
 318  
 319      /**
 320       * Test for is_overall_complete().
 321       *
 322       * @covers ::is_overall_complete
 323       * @dataProvider is_overall_complete_provider
 324       * @param bool $expected Expected result returned by is_overall_complete().
 325       * @param int $completion The completion tracking mode.
 326       * @param int $completionstate The overall completion state.
 327       * @param int|null $completionview Completion status of the "view" completion condition.
 328       * @param int|null $completiongrade Completion status of the "must receive grade" completion condition.
 329       * @param int|null $completionpassgrade Completion status of the "must receive passing grade" completion condition.
 330       */
 331      public function test_is_overall_complete(
 332          bool $expected,
 333          int $completion,
 334          int $completionstate,
 335          ?int $completionview = null,
 336          ?int $completiongrade = null,
 337          ?int $completionpassgrade = null,
 338      ): void {
 339          $options = [];
 340          $getdatareturn = (object)[
 341              'completionstate' => $completionstate,
 342              'viewed' => $completionview,
 343              'completiongrade' => $completiongrade,
 344              'passgrade' => $completionpassgrade,
 345          ];
 346  
 347          if (!is_null($completionview)) {
 348              $options['completionview'] = true;
 349          }
 350          if (!is_null($completiongrade)) {
 351              $options['completionusegrade'] = true;
 352          }
 353          if (!is_null($completionpassgrade)) {
 354              $options['completionpassgrade'] = true;
 355          }
 356  
 357          $cmcompletion = $this->setup_data($completion, $options, $getdatareturn);
 358          $this->assertEquals($expected, $cmcompletion->is_overall_complete());
 359      }
 360  
 361      /**
 362       * Data provider for test_get_details().
 363       * @return array[]
 364       */
 365      public function get_details_provider() {
 366          return [
 367              'No completion tracking' => [
 368                  COMPLETION_TRACKING_NONE, null, null, null, []
 369              ],
 370              'Manual completion tracking' => [
 371                  COMPLETION_TRACKING_MANUAL, null, null, null, []
 372              ],
 373              'Automatic, require view, not viewed' => [
 374                  COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, null, null, [
 375                      'completionview' => (object)[
 376                          'status' => COMPLETION_INCOMPLETE,
 377                          'description' => get_string('detail_desc:view', 'completion'),
 378                      ]
 379                  ]
 380              ],
 381              'Automatic, require view, viewed' => [
 382                  COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, null, null, [
 383                      'completionview' => (object)[
 384                          'status' => COMPLETION_COMPLETE,
 385                          'description' => get_string('detail_desc:view', 'completion'),
 386                      ]
 387                  ]
 388              ],
 389              'Automatic, require grade, incomplete' => [
 390                  COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_INCOMPLETE, null, [
 391                      'completionusegrade' => (object)[
 392                          'status' => COMPLETION_INCOMPLETE,
 393                          'description' => get_string('detail_desc:receivegrade', 'completion'),
 394                      ]
 395                  ]
 396              ],
 397              'Automatic, require grade, complete' => [
 398                  COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, null, [
 399                      'completionusegrade' => (object)[
 400                          'status' => COMPLETION_COMPLETE,
 401                          'description' => get_string('detail_desc:receivegrade', 'completion'),
 402                      ]
 403                  ]
 404              ],
 405              'Automatic, require view (complete) and grade (incomplete)' => [
 406                  COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, null, [
 407                      'completionview' => (object)[
 408                          'status' => COMPLETION_COMPLETE,
 409                          'description' => get_string('detail_desc:view', 'completion'),
 410                      ],
 411                      'completionusegrade' => (object)[
 412                          'status' => COMPLETION_INCOMPLETE,
 413                          'description' => get_string('detail_desc:receivegrade', 'completion'),
 414                      ]
 415                  ]
 416              ],
 417              'Automatic, require view (incomplete) and grade (complete)' => [
 418                  COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, null, [
 419                      'completionview' => (object)[
 420                          'status' => COMPLETION_INCOMPLETE,
 421                          'description' => get_string('detail_desc:view', 'completion'),
 422                      ],
 423                      'completionusegrade' => (object)[
 424                          'status' => COMPLETION_COMPLETE,
 425                          'description' => get_string('detail_desc:receivegrade', 'completion'),
 426                      ]
 427                  ]
 428              ],
 429              'Automatic, require grade, require pass grade, complete' => [
 430                  COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [
 431                      'completionusegrade' => (object)[
 432                          'status' => COMPLETION_COMPLETE,
 433                          'description' => get_string('detail_desc:receivegrade', 'completion'),
 434                      ],
 435                      'completionpassgrade' => (object)[
 436                          'status' => COMPLETION_COMPLETE,
 437                          'description' => get_string('detail_desc:receivepassgrade', 'completion'),
 438                      ],
 439                  ]
 440              ],
 441              'Automatic, require grade, require pass grade, incomplete' => [
 442                  COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, [
 443                      'completionusegrade' => (object)[
 444                          'status' => COMPLETION_COMPLETE,
 445                          'description' => get_string('detail_desc:receivegrade', 'completion'),
 446                      ],
 447                      'completionpassgrade' => (object)[
 448                          'status' => COMPLETION_INCOMPLETE,
 449                          'description' => get_string('detail_desc:receivepassgrade', 'completion'),
 450                      ],
 451                  ]
 452              ],
 453              'Automatic, require view (complete), require grade(complete), require pass grade(complete)' => [
 454                  COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [
 455                      'completionview' => (object)[
 456                          'status' => COMPLETION_COMPLETE,
 457                          'description' => get_string('detail_desc:view', 'completion'),
 458                      ],
 459                      'completionusegrade' => (object)[
 460                          'status' => COMPLETION_COMPLETE,
 461                          'description' => get_string('detail_desc:receivegrade', 'completion'),
 462                      ],
 463                      'completionpassgrade' => (object)[
 464                          'status' => COMPLETION_COMPLETE,
 465                          'description' => get_string('detail_desc:receivepassgrade', 'completion'),
 466                      ],
 467                  ]
 468              ],
 469              'Automatic, require view (incomplete), require grade(complete), require pass grade(complete)' => [
 470                  COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [
 471                      'completionview' => (object)[
 472                          'status' => COMPLETION_INCOMPLETE,
 473                          'description' => get_string('detail_desc:view', 'completion'),
 474                      ],
 475                      'completionusegrade' => (object)[
 476                          'status' => COMPLETION_COMPLETE,
 477                          'description' => get_string('detail_desc:receivegrade', 'completion'),
 478                      ],
 479                      'completionpassgrade' => (object)[
 480                          'status' => COMPLETION_COMPLETE,
 481                          'description' => get_string('detail_desc:receivepassgrade', 'completion'),
 482                      ],
 483                  ]
 484              ],
 485          ];
 486      }
 487  
 488      /**
 489       * Test for \core_completion\cm_completion_details::get_details().
 490       *
 491       * @covers ::get_details
 492       * @dataProvider get_details_provider
 493       * @param int $completion The completion tracking mode.
 494       * @param int|null $completionview Completion status of the "view" completion condition.
 495       * @param int|null $completiongrade Completion status of the "must receive grade" completion condition.
 496       * @param int|null $completionpassgrade Completion status of the "must receive passing grade" completion condition.
 497       * @param array $expecteddetails Expected completion details returned by get_details().
 498       */
 499      public function test_get_details(int $completion, ?int $completionview,
 500               ?int $completiongrade, ?int $completionpassgrade, array $expecteddetails) {
 501          $options = [];
 502          $getdatareturn = (object)[
 503              'viewed' => $completionview,
 504              'completiongrade' => $completiongrade,
 505              'passgrade' => $completionpassgrade,
 506          ];
 507  
 508          if (!is_null($completionview)) {
 509              $options['completionview'] = true;
 510          }
 511          if (!is_null($completiongrade)) {
 512              $options['completionusegrade'] = true;
 513          }
 514          if (!is_null($completionpassgrade)) {
 515              $options['completionpassgrade'] = true;
 516          }
 517  
 518          $cmcompletion = $this->setup_data($completion, $options, $getdatareturn);
 519          $this->assertEquals($expecteddetails, $cmcompletion->get_details());
 520      }
 521  
 522      /**
 523       * Data provider for test_get_details_custom_order().
 524       * @return array[]
 525       */
 526      public function get_details_custom_order_provider() {
 527          return [
 528              'Custom and view/grade standard conditions, view first and grade last' => [
 529                  true,
 530                  true,
 531                  [
 532                      'completionsubmit' => true,
 533                  ],
 534                  'assign',
 535                  ['completionview', 'completionsubmit', 'completionusegrade'],
 536              ],
 537              'Custom and view/grade standard conditions, grade not last' => [
 538                  true,
 539                  true,
 540                  [
 541                      'completionminattempts' => 2,
 542                      'completionusegrade' => 50,
 543                      'completionpassorattemptsexhausted' => 1,
 544                  ],
 545                  'quiz',
 546                  ['completionview', 'completionminattempts', 'completionusegrade', 'completionpassorattemptsexhausted'],
 547              ],
 548              'Custom and grade standard conditions only, no view condition' => [
 549                  false,
 550                  true,
 551                  [
 552                      'completionsubmit' => true,
 553                  ],
 554                  'assign',
 555                  ['completionsubmit', 'completionusegrade'],
 556              ],
 557              'Custom and view standard conditions only, no grade condition' => [
 558                  true,
 559                  false,
 560                  [
 561                      'completionsubmit' => true
 562                  ],
 563                  'assign',
 564                  ['completionview', 'completionsubmit'],
 565              ],
 566              'View and grade conditions only, activity with no custom conditions' => [
 567                  true,
 568                  true,
 569                  [
 570                      'completionview' => true,
 571                      'completionusegrade' => true
 572                  ],
 573                  'workshop',
 574                  ['completionview', 'completionusegrade'],
 575              ],
 576              'View condition only, activity with no custom conditions' => [
 577                  true,
 578                  false,
 579                  [
 580                      'completionview' => true,
 581                  ],
 582                  'workshop',
 583                  ['completionview'],
 584              ],
 585          ];
 586      }
 587  
 588      /**
 589       * Test custom sort order is functioning in \core_completion\cm_completion_details::get_details().
 590       *
 591       * @covers ::get_details
 592       * @dataProvider get_details_custom_order_provider
 593       * @param bool $completionview Completion status of the "view" completion condition.
 594       * @param bool $completiongrade Completion status of the "must receive grade" completion condition.
 595       * @param array $customcompletionrules Custom completion requirements, along with their values.
 596       * @param string $modname The name of the module having data fetched.
 597       * @param array $expectedorder The expected order of completion conditions returned about the module.
 598       */
 599      public function test_get_details_custom_order(bool $completionview, bool $completiongrade, array $customcompletionrules,
 600              string $modname, array $expectedorder) {
 601  
 602          $options['customcompletion'] = [];
 603          $customcompletiondata = [];
 604  
 605          if ($completionview) {
 606              $options['completionview'] = true;
 607          }
 608  
 609          if ($completiongrade) {
 610              $options['completionusegrade'] = true;
 611          }
 612  
 613          // Set up the completion rules for the completion info.
 614          foreach ($customcompletionrules as $customtype => $isenabled) {
 615              $customcompletiondata[$customtype] = COMPLETION_COMPLETE;
 616          }
 617  
 618          $getdatareturn = (object)[
 619              'viewed' => $completionview ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE,
 620              'completiongrade' => $completiongrade ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE,
 621              'customcompletion' => $customcompletiondata,
 622          ];
 623  
 624          $cmcompletion = $this->setup_data(COMPLETION_TRACKING_AUTOMATIC, $options, $getdatareturn, $modname);
 625  
 626          $this->completioninfo->expects($this->any())
 627              ->method('get_data')
 628              ->willReturn($getdatareturn);
 629  
 630          $fetcheddetails = $cmcompletion->get_details();
 631  
 632          // Check the expected number of items are returned, and sorted in the correct order.
 633          $this->assertCount(count($expectedorder), $fetcheddetails);
 634          $this->assertTrue((array_keys($fetcheddetails) === $expectedorder));
 635      }
 636  }