Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Contains unit tests for core_completion/cm_completion_details.
 *
 * @package   core_completion
 * @copyright 2021 Jun Pataleta <jun@moodle.com>
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

declare(strict_types = 1);

namespace core_completion;

use advanced_testcase;
use cm_info;
use completion_info;

defined('MOODLE_INTERNAL') || die();

global $CFG;
require_once($CFG->libdir . '/completionlib.php');

/**
 * Class for unit testing core_completion/cm_completion_details.
 *
 * @package   core_completion
 * @copyright 2021 Jun Pataleta <jun@moodle.com>
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
> * @coversDefaultClass \core_completion\cm_completion_details
*/ class cm_completion_details_test extends advanced_testcase { /** @var completion_info A completion object. */ protected $completioninfo = null; /** * Fetches a mocked cm_completion_details instance. * * @param int|null $completion The completion tracking mode for the module. * @param array $completionoptions Completion options (e.g. completionview, completionusegrade, etc.) * @param object $mockcompletiondata Mock data to be returned by get_data. * @param string $modname The modname to set in the cm if a specific one is required. * @return cm_completion_details */ protected function setup_data(?int $completion, array $completionoptions = [], object $mockcompletiondata = null, $modname = 'somenonexistentmod'): cm_completion_details { if (is_null($completion)) { $completion = COMPLETION_TRACKING_AUTOMATIC; } // Mock a completion_info instance so we can simply mock the returns of completion_info::get_data() later. $this->completioninfo = $this->getMockBuilder(completion_info::class) ->disableOriginalConstructor() ->getMock(); // Mock return of completion_info's is_enabled() method to match the expected completion tracking for the module. $this->completioninfo->expects($this->any()) ->method('is_enabled') ->willReturn($completion); if (!empty($mockcompletiondata)) { $this->completioninfo->expects($this->any()) ->method('get_data') ->willReturn($mockcompletiondata); } // Build a mock cm_info instance. $mockcminfo = $this->getMockBuilder(cm_info::class) ->disableOriginalConstructor() ->onlyMethods(['__get']) ->getMock(); // Mock the return of the magic getter method when fetching the cm_info object's customdata and instance values. $mockcminfo->expects($this->any()) ->method('__get') ->will($this->returnValueMap([ ['completion', $completion], ['instance', 1], ['modname', $modname], ['completionview', $completionoptions['completionview'] ?? COMPLETION_VIEW_NOT_REQUIRED], ['completiongradeitemnumber', $completionoptions['completionusegrade'] ?? null],
> ['completionpassgrade', $completionoptions['completionpassgrade'] ?? null],
])); return new cm_completion_details($this->completioninfo, $mockcminfo, 2); } /** * Provides data for test_has_completion(). * * @return array[] */ public function has_completion_provider(): array { return [ 'Automatic' => [ COMPLETION_TRACKING_AUTOMATIC, true ], 'Manual' => [ COMPLETION_TRACKING_MANUAL, true ], 'None' => [ COMPLETION_TRACKING_NONE, false ], ]; } /** * Test for has_completion(). *
> * @covers ::has_completion
* @dataProvider has_completion_provider * @param int $completion The completion tracking mode. * @param bool $expectedresult Expected result. */ public function test_has_completion(int $completion, bool $expectedresult) { $cmcompletion = $this->setup_data($completion); $this->assertEquals($expectedresult, $cmcompletion->has_completion()); } /** * Provides data for test_is_automatic(). * * @return array[] */ public function is_automatic_provider(): array { return [ 'Automatic' => [ COMPLETION_TRACKING_AUTOMATIC, true ], 'Manual' => [ COMPLETION_TRACKING_MANUAL, false ], 'None' => [ COMPLETION_TRACKING_NONE, false ], ]; } /** * Test for is_available(). *
> * @covers ::is_automatic
* @dataProvider is_automatic_provider * @param int $completion The completion tracking mode. * @param bool $expectedresult Expected result. */ public function test_is_automatic(int $completion, bool $expectedresult) { $cmcompletion = $this->setup_data($completion); $this->assertEquals($expectedresult, $cmcompletion->is_automatic()); } /**
> * Provides data for test_is_manual(). * Data provider for test_get_overall_completion(). > * * @return array[] > * @return array[] */ > */ public function overall_completion_provider(): array { > public function is_manual_provider(): array { return [ > return [ 'Complete' => [COMPLETION_COMPLETE], > 'Automatic' => [ 'Incomplete' => [COMPLETION_INCOMPLETE], > COMPLETION_TRACKING_AUTOMATIC, false ]; > ], } > 'Manual' => [ > COMPLETION_TRACKING_MANUAL, true /** > ], * Test for get_overall_completion(). > 'None' => [ * > COMPLETION_TRACKING_NONE, false * @dataProvider overall_completion_provider > ], * @param int $state > ]; */ > } public function test_get_overall_completion(int $state) { > $completiondata = (object)['completionstate' => $state]; > /** $cmcompletion = $this->setup_data(COMPLETION_TRACKING_AUTOMATIC, [], $completiondata); > * Test for is_manual(). $this->assertEquals($state, $cmcompletion->get_overall_completion()); > * } > * @covers ::is_manual > * @dataProvider is_manual_provider /** > * @param int $completion The completion tracking mode. * Data provider for test_get_details(). > * @param bool $expectedresult Expected result. * @return array[] > */ */ > public function test_is_manual(int $completion, bool $expectedresult) { public function get_details_provider() { > $cmcompletion = $this->setup_data($completion); return [ > 'No completion tracking' => [ > $this->assertEquals($expectedresult, $cmcompletion->is_manual()); COMPLETION_TRACKING_NONE, null, null, [] > } ], > 'Manual completion tracking' => [ > /**
COMPLETION_TRACKING_MANUAL, null, null, []
> * @covers ::get_overall_completion
],
> * Data provider for test_is_overall_complete(). 'Automatic, require view, not viewed' => [ > * @return array[] COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, null, [ > */ 'completionview' => (object)[ > public static function is_overall_complete_provider(): array { 'status' => COMPLETION_INCOMPLETE, > return [ 'description' => get_string('detail_desc:view', 'completion'), > 'Automatic, require view, not viewed' => [ ] > 'expected' => false, ] > 'completion' => COMPLETION_TRACKING_AUTOMATIC, ], > 'completionstate' => COMPLETION_INCOMPLETE, 'Automatic, require view, viewed' => [ > 'completionview' => COMPLETION_INCOMPLETE, COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, null, [ > 'completiongrade' => null, 'completionview' => (object)[ > 'completionpassgrade' => null, 'status' => COMPLETION_COMPLETE, > ], 'description' => get_string('detail_desc:view', 'completion'), > 'Automatic, require view, viewed' => [ ] > 'expected' => true, ] > 'completion' => COMPLETION_TRACKING_AUTOMATIC, ], > 'completionstate' => COMPLETION_COMPLETE, 'Automatic, require grade, incomplete' => [ > 'completionview' => COMPLETION_COMPLETE, COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_INCOMPLETE, [ > 'completiongrade' => null, 'completionusegrade' => (object)[ > 'completionpassgrade' => null, 'status' => COMPLETION_INCOMPLETE, > ], 'description' => get_string('detail_desc:receivegrade', 'completion'), > 'Automatic, require grade, not graded' => [ ] > 'expected' => false, ] > 'completion' => COMPLETION_TRACKING_AUTOMATIC, ], > 'completionstate' => COMPLETION_INCOMPLETE, 'Automatic, require grade, complete' => [ > 'completionview' => null, COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, [ > 'completiongrade' => COMPLETION_INCOMPLETE, 'completionusegrade' => (object)[ > 'completionpassgrade' => null, 'status' => COMPLETION_COMPLETE, > ], 'description' => get_string('detail_desc:receivegrade', 'completion'), > 'Automatic, require grade, graded with fail' => [ ] > 'expected' => true, ] > 'completion' => COMPLETION_TRACKING_AUTOMATIC, ], > 'completionstate' => COMPLETION_COMPLETE_FAIL, 'Automatic, require view (complete) and grade (incomplete)' => [ > 'completionview' => null, COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, [ > 'completiongrade' => COMPLETION_COMPLETE_FAIL, 'completionview' => (object)[ > 'completionpassgrade' => null, 'status' => COMPLETION_COMPLETE, > ], 'description' => get_string('detail_desc:view', 'completion'), > 'Automatic, require grade, graded with passing' => [ ], > 'expected' => true, 'completionusegrade' => (object)[ > 'completion' => COMPLETION_TRACKING_AUTOMATIC, 'status' => COMPLETION_INCOMPLETE, > 'completionstate' => COMPLETION_COMPLETE_PASS, 'description' => get_string('detail_desc:receivegrade', 'completion'), > 'completionview' => null, ] > 'completiongrade' => COMPLETION_COMPLETE_PASS, ] > 'completionpassgrade' => null, ], > ], 'Automatic, require view (incomplete) and grade (complete)' => [ > 'Automatic, require passgrade, not graded' => [ COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, [ > 'expected' => false, 'completionview' => (object)[ > 'completion' => COMPLETION_TRACKING_AUTOMATIC, 'status' => COMPLETION_INCOMPLETE, > 'completionstate' => COMPLETION_INCOMPLETE, 'description' => get_string('detail_desc:view', 'completion'), > 'completionview' => null, ], > 'completiongrade' => null, 'completionusegrade' => (object)[ > 'completionpassgrade' => COMPLETION_INCOMPLETE, 'status' => COMPLETION_COMPLETE, > ], 'description' => get_string('detail_desc:receivegrade', 'completion'), > 'Automatic, require passgrade, graded with fail' => [ ] > 'expected' => false, ] > 'completion' => COMPLETION_TRACKING_AUTOMATIC, ], > 'completionstate' => COMPLETION_COMPLETE_FAIL, ]; > 'completionview' => null, } > 'completiongrade' => null, > 'completionpassgrade' => COMPLETION_COMPLETE_FAIL, /** > ], * Test for \core_completion\cm_completion_details::get_details(). > 'Automatic, require passgrade, graded with passing' => [ * > 'expected' => true, * @dataProvider get_details_provider > 'completion' => COMPLETION_TRACKING_AUTOMATIC, * @param int $completion The completion tracking mode. > 'completionstate' => COMPLETION_COMPLETE_PASS, * @param int|null $completionview Completion status of the "view" completion condition. > 'completionview' => null, * @param int|null $completiongrade Completion status of the "must receive grade" completion condition. > 'completiongrade' => null, * @param array $expecteddetails Expected completion details returned by get_details(). > 'completionpassgrade' => COMPLETION_COMPLETE_PASS, */ > ], public function test_get_details(int $completion, ?int $completionview, ?int $completiongrade, array $expecteddetails) { > 'Manual, incomplete' => [ $options = []; > 'expected' => false, $getdatareturn = (object)[ > 'completion' => COMPLETION_TRACKING_MANUAL, 'viewed' => $completionview, > 'completionstate' => COMPLETION_INCOMPLETE, 'completiongrade' => $completiongrade, > ], ]; > 'Manual, complete' => [ > 'expected' => true, if (!is_null($completionview)) { > 'completion' => COMPLETION_TRACKING_MANUAL, $options['completionview'] = true; > 'completionstate' => COMPLETION_COMPLETE, } > ], if (!is_null($completiongrade)) { > 'None, incomplete' => [ $options['completionusegrade'] = true; > 'expected' => false, } > 'completion' => COMPLETION_TRACKING_NONE, > 'completionstate' => COMPLETION_INCOMPLETE, $cmcompletion = $this->setup_data($completion, $options, $getdatareturn); > ], $this->assertEquals($expecteddetails, $cmcompletion->get_details()); > 'None, complete' => [ } > 'expected' => false, > 'completion' => COMPLETION_TRACKING_NONE, /** > 'completionstate' => COMPLETION_COMPLETE, * Data provider for test_get_details(). > ], * @return array[] > ]; */ > } public function get_details_custom_order_provider() { > return [ > /** 'Custom and view/grade standard conditions, view first and grade last' => [ > * Test for is_overall_complete(). true, > * true, > * @covers ::is_overall_complete [ > * @dataProvider is_overall_complete_provider 'completionsubmit' => true, > * @param bool $expected Expected result returned by is_overall_complete(). ], > * @param int $completion The completion tracking mode. 'assign', > * @param int $completionstate The overall completion state. ['completionview', 'completionsubmit', 'completionusegrade'], > * @param int|null $completionview Completion status of the "view" completion condition. ], > * @param int|null $completiongrade Completion status of the "must receive grade" completion condition. 'Custom and view/grade standard conditions, grade not last' => [ > * @param int|null $completionpassgrade Completion status of the "must receive passing grade" completion condition. true, > */ true, > public function test_is_overall_complete( [ > bool $expected, 'completionminattempts' => 2, > int $completion, 'completionusegrade' => 50, > int $completionstate, 'completionpassorattemptsexhausted' => 1, > ?int $completionview = null, ], > ?int $completiongrade = null, 'quiz', > ?int $completionpassgrade = null, ['completionview', 'completionminattempts', 'completionusegrade', 'completionpassorattemptsexhausted'], > ): void { ], > $options = []; 'Custom and grade standard conditions only, no view condition' => [ > $getdatareturn = (object)[ false, > 'completionstate' => $completionstate, true, > 'viewed' => $completionview, [ > 'completiongrade' => $completiongrade, 'completionsubmit' => true, > 'passgrade' => $completionpassgrade, ], > ]; 'assign', > ['completionsubmit', 'completionusegrade'], > if (!is_null($completionview)) { ], > $options['completionview'] = true; 'Custom and view standard conditions only, no grade condition' => [ > } true, > if (!is_null($completiongrade)) { false, > $options['completionusegrade'] = true; [ > } 'completionsubmit' => true > if (!is_null($completionpassgrade)) { ], > $options['completionpassgrade'] = true; 'assign', > } ['completionview', 'completionsubmit'], > ], > $cmcompletion = $this->setup_data($completion, $options, $getdatareturn); 'View and grade conditions only, activity with no custom conditions' => [ > $this->assertEquals($expected, $cmcompletion->is_overall_complete()); true, > } true, > [ > /**
< COMPLETION_TRACKING_NONE, null, null, []
> COMPLETION_TRACKING_NONE, null, null, null, []
< COMPLETION_TRACKING_MANUAL, null, null, []
> COMPLETION_TRACKING_MANUAL, null, null, null, []
< COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, null, [
> COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, null, null, [
< COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, null, [
> COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, null, null, [
< COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_INCOMPLETE, [
> COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_INCOMPLETE, null, [
< COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, [
> COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, null, [
< COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, [
> COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, null, [
< COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, [
> COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, null, [
false,
> 'Automatic, require grade, require pass grade, complete' => [ [ > COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [ 'completionview' => true, > 'completionusegrade' => (object)[ ], > 'status' => COMPLETION_COMPLETE, 'workshop', > 'description' => get_string('detail_desc:receivegrade', 'completion'), ['completionview'], > ], ], > 'completionpassgrade' => (object)[ ]; > 'status' => COMPLETION_COMPLETE, } > 'description' => get_string('detail_desc:receivepassgrade', 'completion'), > ], /** > ] * Test custom sort order is functioning in \core_completion\cm_completion_details::get_details(). > ], * > 'Automatic, require grade, require pass grade, incomplete' => [ * @dataProvider get_details_custom_order_provider > COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, [ * @param bool $completionview Completion status of the "view" completion condition. > 'completionusegrade' => (object)[ * @param bool $completiongrade Completion status of the "must receive grade" completion condition. > 'status' => COMPLETION_COMPLETE, * @param array $customcompletionrules Custom completion requirements, along with their values. > 'description' => get_string('detail_desc:receivegrade', 'completion'), * @param string $modname The name of the module having data fetched. > ], * @param array $expectedorder The expected order of completion conditions returned about the module. > 'completionpassgrade' => (object)[ */ > 'status' => COMPLETION_INCOMPLETE, public function test_get_details_custom_order(bool $completionview, bool $completiongrade, array $customcompletionrules, > 'description' => get_string('detail_desc:receivepassgrade', 'completion'), string $modname, array $expectedorder) { > ], > ] $options['customcompletion'] = []; > ], $customcompletiondata = []; > 'Automatic, require view (complete), require grade(complete), require pass grade(complete)' => [ > COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [ if ($completionview) { > 'completionview' => (object)[ $options['completionview'] = true; > 'status' => COMPLETION_COMPLETE, } > 'description' => get_string('detail_desc:view', 'completion'), > ], if ($completiongrade) { > 'completionusegrade' => (object)[ $options['completionusegrade'] = true; > 'status' => COMPLETION_COMPLETE, } > 'description' => get_string('detail_desc:receivegrade', 'completion'), > ], // Set up the completion rules for the completion info. > 'completionpassgrade' => (object)[ foreach ($customcompletionrules as $customtype => $isenabled) { > 'status' => COMPLETION_COMPLETE, $customcompletiondata[$customtype] = COMPLETION_COMPLETE; > 'description' => get_string('detail_desc:receivepassgrade', 'completion'), } > ], > ] $getdatareturn = (object)[ > ], 'viewed' => $completionview ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE, > 'Automatic, require view (incomplete), require grade(complete), require pass grade(complete)' => [ 'completiongrade' => $completiongrade ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE, > COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [ 'customcompletion' => $customcompletiondata, > 'completionview' => (object)[ ]; > 'status' => COMPLETION_INCOMPLETE, > 'description' => get_string('detail_desc:view', 'completion'), $cmcompletion = $this->setup_data(COMPLETION_TRACKING_AUTOMATIC, $options, $getdatareturn, $modname); > ], > 'completionusegrade' => (object)[ $this->completioninfo->expects($this->any()) > 'status' => COMPLETION_COMPLETE, ->method('get_data') > 'description' => get_string('detail_desc:receivegrade', 'completion'), ->willReturn($getdatareturn); > ], > 'completionpassgrade' => (object)[ $fetcheddetails = $cmcompletion->get_details(); > 'status' => COMPLETION_COMPLETE, > 'description' => get_string('detail_desc:receivepassgrade', 'completion'), // Check the expected number of items are returned, and sorted in the correct order. > ], $this->assertCount(count($expectedorder), $fetcheddetails); > ] $this->assertTrue((array_keys($fetcheddetails) === $expectedorder)); > ],
}
> * @covers ::get_details
}
> * @param int|null $completionpassgrade Completion status of the "must receive passing grade" completion condition.
< public function test_get_details(int $completion, ?int $completionview, ?int $completiongrade, array $expecteddetails) {
> public function test_get_details(int $completion, ?int $completionview, > ?int $completiongrade, ?int $completionpassgrade, array $expecteddetails) {
> 'passgrade' => $completionpassgrade,
> if (!is_null($completionpassgrade)) { > $options['completionpassgrade'] = true; > }
< * Data provider for test_get_details().
> * Data provider for test_get_details_custom_order().
> * @covers ::get_details