Merge branch 'MDL-74631-invalid-tag-311' of https://github.com/leonstr/moodle into...
[moodle.git] / completion / tests / cm_completion_details_test.php
blobbdbfcf683f96bc834f1e7f314e7c4344b5110fbd
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.
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/>.
17 /**
18 * Contains unit tests for core_completion/cm_completion_details.
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
25 declare(strict_types = 1);
27 namespace core_completion;
29 use advanced_testcase;
30 use cm_info;
31 use completion_info;
33 defined('MOODLE_INTERNAL') || die();
35 global $CFG;
36 require_once($CFG->libdir . '/completionlib.php');
38 /**
39 * Class for unit testing core_completion/cm_completion_details.
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
45 class cm_completion_details_test extends advanced_testcase {
47 /** @var completion_info A completion object. */
48 protected $completioninfo = null;
50 /**
51 * Fetches a mocked cm_completion_details instance.
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
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;
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();
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);
75 if (!empty($mockcompletiondata)) {
76 $this->completioninfo->expects($this->any())
77 ->method('get_data')
78 ->willReturn($mockcompletiondata);
81 // Build a mock cm_info instance.
82 $mockcminfo = $this->getMockBuilder(cm_info::class)
83 ->disableOriginalConstructor()
84 ->onlyMethods(['__get'])
85 ->getMock();
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 ]));
98 return new cm_completion_details($this->completioninfo, $mockcminfo, 2);
102 * Provides data for test_has_completion().
104 * @return array[]
106 public function has_completion_provider(): array {
107 return [
108 'Automatic' => [
109 COMPLETION_TRACKING_AUTOMATIC, true
111 'Manual' => [
112 COMPLETION_TRACKING_MANUAL, true
114 'None' => [
115 COMPLETION_TRACKING_NONE, false
121 * Test for has_completion().
123 * @dataProvider has_completion_provider
124 * @param int $completion The completion tracking mode.
125 * @param bool $expectedresult Expected result.
127 public function test_has_completion(int $completion, bool $expectedresult) {
128 $cmcompletion = $this->setup_data($completion);
130 $this->assertEquals($expectedresult, $cmcompletion->has_completion());
134 * Provides data for test_is_automatic().
136 * @return array[]
138 public function is_automatic_provider(): array {
139 return [
140 'Automatic' => [
141 COMPLETION_TRACKING_AUTOMATIC, true
143 'Manual' => [
144 COMPLETION_TRACKING_MANUAL, false
146 'None' => [
147 COMPLETION_TRACKING_NONE, false
153 * Test for is_available().
155 * @dataProvider is_automatic_provider
156 * @param int $completion The completion tracking mode.
157 * @param bool $expectedresult Expected result.
159 public function test_is_automatic(int $completion, bool $expectedresult) {
160 $cmcompletion = $this->setup_data($completion);
162 $this->assertEquals($expectedresult, $cmcompletion->is_automatic());
166 * Data provider for test_get_overall_completion().
167 * @return array[]
169 public function overall_completion_provider(): array {
170 return [
171 'Complete' => [COMPLETION_COMPLETE],
172 'Incomplete' => [COMPLETION_INCOMPLETE],
177 * Test for get_overall_completion().
179 * @dataProvider overall_completion_provider
180 * @param int $state
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());
189 * Data provider for test_get_details().
190 * @return array[]
192 public function get_details_provider() {
193 return [
194 'No completion tracking' => [
195 COMPLETION_TRACKING_NONE, null, null, []
197 'Manual completion tracking' => [
198 COMPLETION_TRACKING_MANUAL, null, null, []
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'),
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'),
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'),
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'),
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'),
238 'completionusegrade' => (object)[
239 'status' => COMPLETION_INCOMPLETE,
240 'description' => get_string('detail_desc:receivegrade', 'completion'),
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'),
250 'completionusegrade' => (object)[
251 'status' => COMPLETION_COMPLETE,
252 'description' => get_string('detail_desc:receivegrade', 'completion'),
260 * Test for \core_completion\cm_completion_details::get_details().
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().
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,
275 if (!is_null($completionview)) {
276 $options['completionview'] = true;
278 if (!is_null($completiongrade)) {
279 $options['completionusegrade'] = true;
282 $cmcompletion = $this->setup_data($completion, $options, $getdatareturn);
283 $this->assertEquals($expecteddetails, $cmcompletion->get_details());
287 * Data provider for test_get_details().
288 * @return array[]
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,
296 'completionsubmit' => true,
298 'assign',
299 ['completionview', 'completionsubmit', 'completionusegrade'],
301 'Custom and view/grade standard conditions, grade not last' => [
302 true,
303 true,
305 'completionminattempts' => 2,
306 'completionusegrade' => 50,
307 'completionpassorattemptsexhausted' => 1,
309 'quiz',
310 ['completionview', 'completionminattempts', 'completionusegrade', 'completionpassorattemptsexhausted'],
312 'Custom and grade standard conditions only, no view condition' => [
313 false,
314 true,
316 'completionsubmit' => true,
318 'assign',
319 ['completionsubmit', 'completionusegrade'],
321 'Custom and view standard conditions only, no grade condition' => [
322 true,
323 false,
325 'completionsubmit' => true
327 'assign',
328 ['completionview', 'completionsubmit'],
330 'View and grade conditions only, activity with no custom conditions' => [
331 true,
332 true,
334 'completionview' => true,
335 'completionusegrade' => true
337 'workshop',
338 ['completionview', 'completionusegrade'],
340 'View condition only, activity with no custom conditions' => [
341 true,
342 false,
344 'completionview' => true,
346 'workshop',
347 ['completionview'],
353 * Test custom sort order is functioning in \core_completion\cm_completion_details::get_details().
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.
362 public function test_get_details_custom_order(bool $completionview, bool $completiongrade, array $customcompletionrules,
363 string $modname, array $expectedorder) {
365 $options['customcompletion'] = [];
366 $customcompletiondata = [];
368 if ($completionview) {
369 $options['completionview'] = true;
372 if ($completiongrade) {
373 $options['completionusegrade'] = true;
376 // Set up the completion rules for the completion info.
377 foreach ($customcompletionrules as $customtype => $isenabled) {
378 $customcompletiondata[$customtype] = COMPLETION_COMPLETE;
381 $getdatareturn = (object)[
382 'viewed' => $completionview ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE,
383 'completiongrade' => $completiongrade ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE,
384 'customcompletion' => $customcompletiondata,
387 $cmcompletion = $this->setup_data(COMPLETION_TRACKING_AUTOMATIC, $options, $getdatareturn, $modname);
389 $this->completioninfo->expects($this->any())
390 ->method('get_data')
391 ->willReturn($getdatareturn);
393 $fetcheddetails = $cmcompletion->get_details();
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));