Proyectos de Subversion Moodle

Rev

Rev 11 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 11 Rev 1441
Línea 27... Línea 27...
27
 * @copyright  2008 Sam Marshall
27
 * @copyright  2008 Sam Marshall
28
 * @copyright  2013 Frédéric Massart
28
 * @copyright  2013 Frédéric Massart
29
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30
 * @coversDefaultClass \completion_info
30
 * @coversDefaultClass \completion_info
31
 */
31
 */
32
class completionlib_test extends advanced_testcase {
32
final class completionlib_test extends advanced_testcase {
33
    protected $course;
33
    protected $course;
34
    protected $user;
34
    protected $user;
35
    protected $module1;
35
    protected $module1;
36
    protected $module2;
36
    protected $module2;
Línea 74... Línea 74...
74
     * @param  float   $delta
74
     * @param  float   $delta
75
     * @param  integer $maxDepth
75
     * @param  integer $maxDepth
76
     * @param  boolean $canonicalize
76
     * @param  boolean $canonicalize
77
     * @param  boolean $ignoreCase
77
     * @param  boolean $ignoreCase
78
     */
78
     */
79
    public static function assertEquals($expected, $actual, string $message = '', float $delta = 0, int $maxDepth = 10,
79
    public static function assertCompletionEquals($expected, $actual, string $message = '', float $delta = 0, int $maxDepth = 10,
80
                                        bool $canonicalize = false, bool $ignoreCase = false): void {
80
                                        bool $canonicalize = false, bool $ignoreCase = false): void {
81
        // Nasty cheating hack: prevent random failures on timemodified field.
81
        // Nasty cheating hack: prevent random failures on timemodified field.
82
        if (is_array($actual) && (is_object($expected) || is_array($expected))) {
82
        if (is_array($actual) && (is_object($expected) || is_array($expected))) {
83
            $actual = (object) $actual;
83
            $actual = (object) $actual;
84
            $expected = (object) $expected;
84
            $expected = (object) $expected;
Línea 102... Línea 102...
102
        global $CFG;
102
        global $CFG;
103
        $this->mock_setup();
103
        $this->mock_setup();
Línea 104... Línea 104...
104
 
104
 
105
        // Config alone.
105
        // Config alone.
106
        $CFG->enablecompletion = COMPLETION_DISABLED;
106
        $CFG->enablecompletion = COMPLETION_DISABLED;
107
        $this->assertEquals(COMPLETION_DISABLED, completion_info::is_enabled_for_site());
107
        $this->assertCompletionEquals(COMPLETION_DISABLED, completion_info::is_enabled_for_site());
108
        $CFG->enablecompletion = COMPLETION_ENABLED;
108
        $CFG->enablecompletion = COMPLETION_ENABLED;
Línea 109... Línea 109...
109
        $this->assertEquals(COMPLETION_ENABLED, completion_info::is_enabled_for_site());
109
        $this->assertCompletionEquals(COMPLETION_ENABLED, completion_info::is_enabled_for_site());
110
 
110
 
111
        // Course.
111
        // Course.
112
        $course = (object)array('id' => 13);
112
        $course = (object)array('id' => 13);
113
        $c = new completion_info($course);
113
        $c = new completion_info($course);
114
        $course->enablecompletion = COMPLETION_DISABLED;
114
        $course->enablecompletion = COMPLETION_DISABLED;
115
        $this->assertEquals(COMPLETION_DISABLED, $c->is_enabled());
115
        $this->assertCompletionEquals(COMPLETION_DISABLED, $c->is_enabled());
116
        $course->enablecompletion = COMPLETION_ENABLED;
116
        $course->enablecompletion = COMPLETION_ENABLED;
117
        $this->assertEquals(COMPLETION_ENABLED, $c->is_enabled());
117
        $this->assertCompletionEquals(COMPLETION_ENABLED, $c->is_enabled());
Línea 118... Línea 118...
118
        $CFG->enablecompletion = COMPLETION_DISABLED;
118
        $CFG->enablecompletion = COMPLETION_DISABLED;
119
        $this->assertEquals(COMPLETION_DISABLED, $c->is_enabled());
119
        $this->assertCompletionEquals(COMPLETION_DISABLED, $c->is_enabled());
120
 
120
 
121
        // Course and CM.
121
        // Course and CM.
122
        $cm = new stdClass();
122
        $cm = new stdClass();
123
        $cm->completion = COMPLETION_TRACKING_MANUAL;
123
        $cm->completion = COMPLETION_TRACKING_MANUAL;
124
        $this->assertEquals(COMPLETION_DISABLED, $c->is_enabled($cm));
124
        $this->assertCompletionEquals(COMPLETION_DISABLED, $c->is_enabled($cm));
125
        $CFG->enablecompletion = COMPLETION_ENABLED;
125
        $CFG->enablecompletion = COMPLETION_ENABLED;
126
        $course->enablecompletion = COMPLETION_DISABLED;
126
        $course->enablecompletion = COMPLETION_DISABLED;
127
        $this->assertEquals(COMPLETION_DISABLED, $c->is_enabled($cm));
127
        $this->assertCompletionEquals(COMPLETION_DISABLED, $c->is_enabled($cm));
128
        $course->enablecompletion = COMPLETION_ENABLED;
128
        $course->enablecompletion = COMPLETION_ENABLED;
129
        $this->assertEquals(COMPLETION_TRACKING_MANUAL, $c->is_enabled($cm));
129
        $this->assertCompletionEquals(COMPLETION_TRACKING_MANUAL, $c->is_enabled($cm));
130
        $cm->completion = COMPLETION_TRACKING_NONE;
130
        $cm->completion = COMPLETION_TRACKING_NONE;
131
        $this->assertEquals(COMPLETION_TRACKING_NONE, $c->is_enabled($cm));
131
        $this->assertCompletionEquals(COMPLETION_TRACKING_NONE, $c->is_enabled($cm));
Línea 132... Línea 132...
132
        $cm->completion = COMPLETION_TRACKING_AUTOMATIC;
132
        $cm->completion = COMPLETION_TRACKING_AUTOMATIC;
133
        $this->assertEquals(COMPLETION_TRACKING_AUTOMATIC, $c->is_enabled($cm));
133
        $this->assertCompletionEquals(COMPLETION_TRACKING_AUTOMATIC, $c->is_enabled($cm));
134
    }
134
    }
Línea 245... Línea 245...
245
            ->with($cm)
245
            ->with($cm)
246
            ->will($this->returnValue(true));
246
            ->will($this->returnValue(true));
247
        $c->expects($this->exactly(1)) // Pretend the user has the required capability for overriding completion statuses.
247
        $c->expects($this->exactly(1)) // Pretend the user has the required capability for overriding completion statuses.
248
            ->method('user_can_override_completion')
248
            ->method('user_can_override_completion')
249
            ->will($this->returnValue(true));
249
            ->will($this->returnValue(true));
250
        $c->expects($this->exactly(2))
250
        $getinvocations = $this->exactly(2);
-
 
251
        $c->expects($getinvocations)
251
            ->method('get_data')
252
            ->method('get_data')
252
            ->with($cm, false, 100)
253
            ->with($cm, false, 100)
253
            ->willReturnOnConsecutiveCalls($current1, $current2);
254
            ->willReturnCallback(function () use ($getinvocations, $current1, $current2) {
-
 
255
                return match (self::getInvocationCount($getinvocations)) {
-
 
256
                    1 => $current1,
-
 
257
                    2 => $current2,
-
 
258
                    default => $this->fail('Unexpected invocation count'),
-
 
259
                };
-
 
260
            });
254
        $changed1 = clone($current1);
261
        $changed1 = clone($current1);
255
        $changed1->timemodified = time();
262
        $changed1->timemodified = time();
256
        $changed1->completionstate = COMPLETION_COMPLETE;
263
        $changed1->completionstate = COMPLETION_COMPLETE;
257
        $changed1->overrideby = 314159;
264
        $changed1->overrideby = 314159;
258
        $comparewith1 = new phpunit_constraint_object_is_equal_with_exceptions($changed1);
265
        $comparewith1 = new phpunit_constraint_object_is_equal_with_exceptions($changed1);
Línea 261... Línea 268...
261
        $changed2->timemodified = time();
268
        $changed2->timemodified = time();
262
        $changed2->overrideby = null;
269
        $changed2->overrideby = null;
263
        $changed2->completionstate = COMPLETION_INCOMPLETE;
270
        $changed2->completionstate = COMPLETION_INCOMPLETE;
264
        $comparewith2 = new phpunit_constraint_object_is_equal_with_exceptions($changed2);
271
        $comparewith2 = new phpunit_constraint_object_is_equal_with_exceptions($changed2);
265
        $comparewith2->add_exception('timemodified', 'assertGreaterThanOrEqual');
272
        $comparewith2->add_exception('timemodified', 'assertGreaterThanOrEqual');
266
        $c->expects($this->exactly(2))
273
        $setinvocations = $this->exactly(2);
-
 
274
        $c->expects($setinvocations)
267
            ->method('internal_set_data')
275
            ->method('internal_set_data')
-
 
276
            ->willReturnCallback(function ($comparecm, $comparewith) use (
268
            ->withConsecutive(
277
                $setinvocations,
-
 
278
                $cm,
269
                array($cm, $comparewith1),
279
                $comparewith1,
270
                array($cm, $comparewith2)
280
                $comparewith2
-
 
281
            ): void {
-
 
282
                switch (self::getInvocationCount($setinvocations)) {
-
 
283
                    case 1:
-
 
284
                        $this->assertCompletionEquals($cm, $comparecm);
-
 
285
                        $comparewith1->evaluate($comparewith);
-
 
286
                        break;
-
 
287
                    case 2:
-
 
288
                        $this->assertCompletionEquals($cm, $comparecm);
-
 
289
                        $comparewith2->evaluate($comparewith);
-
 
290
                        break;
-
 
291
                    default:
-
 
292
                        $this->fail('Unexpected invocation count');
-
 
293
                }
271
            );
294
            });
272
        $c->update_state($cm, COMPLETION_COMPLETE, 100, true);
295
        $c->update_state($cm, COMPLETION_COMPLETE, 100, true);
273
        // And confirm that the status can be changed back to incomplete without an override.
296
        // And confirm that the status can be changed back to incomplete without an override.
274
        $c->update_state($cm, COMPLETION_INCOMPLETE, 100);
297
        $c->update_state($cm, COMPLETION_INCOMPLETE, 100);
Línea 275... Línea 298...
275
 
298
 
Línea 329... Línea 352...
329
    /**
352
    /**
330
     * Data provider for test_internal_get_state().
353
     * Data provider for test_internal_get_state().
331
     *
354
     *
332
     * @return array[]
355
     * @return array[]
333
     */
356
     */
334
    public function internal_get_state_provider() {
357
    public static function internal_get_state_provider(): array {
335
        return [
358
        return [
336
            'View required, but not viewed yet' => [
359
            'View required, but not viewed yet' => [
337
                COMPLETION_VIEW_REQUIRED, 1, '', COMPLETION_INCOMPLETE
360
                COMPLETION_VIEW_REQUIRED, 1, '', COMPLETION_INCOMPLETE
338
            ],
361
            ],
339
            'View not required and not viewed yet' => [
362
            'View not required and not viewed yet' => [
Línea 382... Línea 405...
382
        }
405
        }
383
        // If view is required, but they haven't viewed it yet.
406
        // If view is required, but they haven't viewed it yet.
384
        $current = (object)['viewed' => COMPLETION_NOT_VIEWED];
407
        $current = (object)['viewed' => COMPLETION_NOT_VIEWED];
Línea 385... Línea 408...
385
 
408
 
386
        $completioninfo = new completion_info($this->course);
409
        $completioninfo = new completion_info($this->course);
387
        $this->assertEquals($expectedstate, $completioninfo->internal_get_state($cm, $userid, $current));
410
        $this->assertCompletionEquals($expectedstate, $completioninfo->internal_get_state($cm, $userid, $current));
Línea 388... Línea 411...
388
    }
411
    }
389
 
412
 
390
    /**
413
    /**
391
     * Provider for the test_internal_get_state_with_grade_criteria.
414
     * Provider for the test_internal_get_state_with_grade_criteria.
392
     *
415
     *
393
     * @return array
416
     * @return array
394
     */
417
     */
395
    public function internal_get_state_with_grade_criteria_provider() {
418
    public static function internal_get_state_with_grade_criteria_provider(): array {
396
        return [
419
        return [
397
            "Passing grade enabled and achieve. State should be COMPLETION_COMPLETE_PASS" => [
420
            "Passing grade enabled and achieve. State should be COMPLETION_COMPLETE_PASS" => [
398
                [
421
                [
Línea 478... Línea 501...
478
            $assign->save_grade($userid, $data);
501
            $assign->save_grade($userid, $data);
479
        }
502
        }
Línea 480... Línea 503...
480
 
503
 
481
        // The target user already received a grade, so internal_get_state should be already complete.
504
        // The target user already received a grade, so internal_get_state should be already complete.
482
        $completioninfo = new completion_info($this->course);
505
        $completioninfo = new completion_info($this->course);
483
        $this->assertEquals($expectedstate, $completioninfo->internal_get_state($cm, $userid, null));
506
        $this->assertCompletionEquals($expectedstate, $completioninfo->internal_get_state($cm, $userid, null));
Línea 484... Línea 507...
484
    }
507
    }
485
 
508
 
486
    /**
509
    /**
Línea 519... Línea 542...
519
        ];
542
        ];
520
        $assign->save_grade($userid, $data);
543
        $assign->save_grade($userid, $data);
Línea 521... Línea 544...
521
 
544
 
522
        // The target user already received a grade, so internal_get_state should be already complete.
545
        // The target user already received a grade, so internal_get_state should be already complete.
523
        $completioninfo = new completion_info($this->course);
546
        $completioninfo = new completion_info($this->course);
Línea 524... Línea 547...
524
        $this->assertEquals(COMPLETION_COMPLETE, $completioninfo->internal_get_state($cm, $userid, null));
547
        $this->assertCompletionEquals(COMPLETION_COMPLETE, $completioninfo->internal_get_state($cm, $userid, null));
525
 
548
 
526
        // As the teacher which does not have a grade in this cm, internal_get_state should return incomplete.
549
        // As the teacher which does not have a grade in this cm, internal_get_state should return incomplete.
Línea 527... Línea 550...
527
        $this->assertEquals(COMPLETION_INCOMPLETE, $completioninfo->internal_get_state($cm, $teacher->id, null));
550
        $this->assertCompletionEquals(COMPLETION_INCOMPLETE, $completioninfo->internal_get_state($cm, $teacher->id, null));
528
    }
551
    }
529
 
552
 
Línea 545... Línea 568...
545
 
568
 
Línea 546... Línea 569...
546
        $completioninfo = new completion_info($this->course);
569
        $completioninfo = new completion_info($this->course);
547
 
570
 
548
        // Fetch completion for the user who hasn't made a choice yet.
571
        // Fetch completion for the user who hasn't made a choice yet.
Línea 549... Línea 572...
549
        $completion = $completioninfo->internal_get_state($cminfo, $this->user->id, COMPLETION_INCOMPLETE);
572
        $completion = $completioninfo->internal_get_state($cminfo, $this->user->id, COMPLETION_INCOMPLETE);
550
        $this->assertEquals(COMPLETION_INCOMPLETE, $completion);
573
        $this->assertCompletionEquals(COMPLETION_INCOMPLETE, $completion);
551
 
574
 
552
        // Have the user make a choice.
575
        // Have the user make a choice.
553
        $choicewithoptions = choice_get_choice($choice->id);
576
        $choicewithoptions = choice_get_choice($choice->id);
554
        $optionids = array_keys($choicewithoptions->option);
577
        $optionids = array_keys($choicewithoptions->option);
555
        choice_user_submit_response($optionids[0], $choice, $this->user->id, $this->course, $cminfo);
578
        choice_user_submit_response($optionids[0], $choice, $this->user->id, $this->course, $cminfo);
Línea 556... Línea 579...
556
        $completion = $completioninfo->internal_get_state($cminfo, $this->user->id, COMPLETION_INCOMPLETE);
579
        $completion = $completioninfo->internal_get_state($cminfo, $this->user->id, COMPLETION_INCOMPLETE);
557
        $this->assertEquals(COMPLETION_COMPLETE, $completion);
580
        $this->assertCompletionEquals(COMPLETION_COMPLETE, $completion);
558
    }
581
    }
Línea 629... Línea 652...
629
        $DB->expects($this->once())
652
        $DB->expects($this->once())
630
            ->method('get_field_sql')
653
            ->method('get_field_sql')
631
            ->will($this->returnValue(666));
654
            ->will($this->returnValue(666));
Línea 632... Línea 655...
632
 
655
 
633
        $c = new completion_info($course);
656
        $c = new completion_info($course);
634
        $this->assertEquals(666, $c->count_user_data($cm));
657
        $this->assertCompletionEquals(666, $c->count_user_data($cm));
Línea 635... Línea 658...
635
    }
658
    }
636
 
659
 
637
    /**
660
    /**
Línea 683... Línea 706...
683
            ->method('get_tracked_users')
706
            ->method('get_tracked_users')
684
            ->will($this->returnValue(array(
707
            ->will($this->returnValue(array(
685
            (object)array('id' => 100, 'firstname' => 'Woot', 'lastname' => 'Plugh'),
708
            (object)array('id' => 100, 'firstname' => 'Woot', 'lastname' => 'Plugh'),
686
            (object)array('id' => 201, 'firstname' => 'Vroom', 'lastname' => 'Xyzzy'))));
709
            (object)array('id' => 201, 'firstname' => 'Vroom', 'lastname' => 'Xyzzy'))));
Línea 687... Línea 710...
687
 
710
 
-
 
711
        $updateinvocations = $this->exactly(3);
688
        $c->expects($this->exactly(3))
712
        $c->expects($updateinvocations)
-
 
713
            ->method('update_state')
-
 
714
            ->willReturnCallback(function ($comparecm, $state, $userid) use ($updateinvocations, $cm): void {
-
 
715
                $this->assertCompletionEquals($cm, $comparecm);
-
 
716
                $this->assertCompletionEquals(COMPLETION_UNKNOWN, $state);
689
            ->method('update_state')
717
                switch (self::getInvocationCount($updateinvocations)) {
690
            ->withConsecutive(
718
                    case 1:
-
 
719
                        $this->assertCompletionEquals(100, $userid);
-
 
720
                        break;
691
                array($cm, COMPLETION_UNKNOWN, 100),
721
                    case 2:
-
 
722
                        $this->assertCompletionEquals(101, $userid);
-
 
723
                        break;
692
                array($cm, COMPLETION_UNKNOWN, 101),
724
                    case 3:
-
 
725
                        $this->assertCompletionEquals(201, $userid);
-
 
726
                        break;
-
 
727
                    default:
-
 
728
                        $this->fail('Unexpected invocation count');
693
                array($cm, COMPLETION_UNKNOWN, 201)
729
                }
Línea 694... Línea 730...
694
            );
730
            });
695
 
731
 
Línea 696... Línea 732...
696
        $c->reset_all_state($cm);
732
        $c->reset_all_state($cm);
697
    }
733
    }
698
 
734
 
699
    /**
735
    /**
700
     * Data provider for test_get_data().
736
     * Data provider for test_get_data().
701
     *
737
     *
702
     * @return array[]
738
     * @return array[]
703
     */
739
     */
704
    public function get_data_provider() {
740
    public static function get_data_provider(): array {
705
        return [
741
        return [
706
            'No completion record' => [
742
            'No completion record' => [
Línea 782... Línea 818...
782
        $completioninfo = new completion_info($this->course);
818
        $completioninfo = new completion_info($this->course);
Línea 783... Línea 819...
783
 
819
 
Línea 784... Línea 820...
784
        $result = $completioninfo->get_data($cm, $wholecourse, $user->id);
820
        $result = $completioninfo->get_data($cm, $wholecourse, $user->id);
785
 
821
 
786
        // Course module ID of the returned completion data must match this activity's course module ID.
822
        // Course module ID of the returned completion data must match this activity's course module ID.
787
        $this->assertEquals($cm->id, $result->coursemoduleid);
823
        $this->assertCompletionEquals($cm->id, $result->coursemoduleid);
788
        // User ID of the returned completion data must match the user's ID.
824
        // User ID of the returned completion data must match the user's ID.
789
        $this->assertEquals($user->id, $result->userid);
825
        $this->assertCompletionEquals($user->id, $result->userid);
Línea 790... Línea 826...
790
        // The completion state of the returned completion data must match the expected completion state.
826
        // The completion state of the returned completion data must match the expected completion state.
791
        $this->assertEquals($completion, $result->completionstate);
827
        $this->assertCompletionEquals($completion, $result->completionstate);
792
 
828
 
793
        // If the user has no completion record, then the default record should be returned.
829
        // If the user has no completion record, then the default record should be returned.
Línea 794... Línea 830...
794
        if (!$hasrecord) {
830
        if (!$hasrecord) {
795
            $this->assertEquals(0, $result->id);
831
            $this->assertCompletionEquals(0, $result->id);
796
        }
832
        }
Línea 851... Línea 887...
851
            $this->assertTrue(property_exists($result, 'viewed'));
887
            $this->assertTrue(property_exists($result, 'viewed'));
852
            $this->assertTrue(property_exists($result, 'overrideby'));
888
            $this->assertTrue(property_exists($result, 'overrideby'));
853
            $this->assertTrue(property_exists($result, 'timemodified'));
889
            $this->assertTrue(property_exists($result, 'timemodified'));
854
            $this->assertFalse(property_exists($result, 'other_cm_completion_data_fetched'));
890
            $this->assertFalse(property_exists($result, 'other_cm_completion_data_fetched'));
Línea 855... Línea 891...
855
 
891
 
856
            $this->assertEquals($testcm->id, $result->coursemoduleid);
892
            $this->assertCompletionEquals($testcm->id, $result->coursemoduleid);
Línea 857... Línea 893...
857
            $this->assertEquals($this->user->id, $result->userid);
893
            $this->assertCompletionEquals($this->user->id, $result->userid);
858
 
894
 
Línea 859... Línea 895...
859
            $results[$testcm->id] = $result;
895
            $results[$testcm->id] = $result;
Línea 864... Línea 900...
864
 
900
 
865
        // The data should match when fetching modules individually.
901
        // The data should match when fetching modules individually.
866
        (cache::make('core', 'completion'))->purge();
902
        (cache::make('core', 'completion'))->purge();
867
        foreach ($modinfo->cms as $testcm) {
903
        foreach ($modinfo->cms as $testcm) {
868
            $result = $completioninfo->get_data($testcm, false);
904
            $result = $completioninfo->get_data($testcm, false);
869
            $this->assertEquals($result, $results[$testcm->id]);
905
            $this->assertCompletionEquals($result, $results[$testcm->id]);
870
        }
906
        }
Línea 871... Línea 907...
871
    }
907
    }
872
 
908
 
Línea 901... Línea 937...
901
        ];
937
        ];
Línea 902... Línea 938...
902
 
938
 
903
        $completiondatabeforeview = $completioninfo->get_completion_data($cm->id, $this->user->id, $defaultdata);
939
        $completiondatabeforeview = $completioninfo->get_completion_data($cm->id, $this->user->id, $defaultdata);
904
        $this->assertTrue(array_key_exists('viewed', $completiondatabeforeview));
940
        $this->assertTrue(array_key_exists('viewed', $completiondatabeforeview));
905
        $this->assertTrue(array_key_exists('coursemoduleid', $completiondatabeforeview));
941
        $this->assertTrue(array_key_exists('coursemoduleid', $completiondatabeforeview));
906
        $this->assertEquals(0, $completiondatabeforeview['viewed']);
942
        $this->assertCompletionEquals(0, $completiondatabeforeview['viewed']);
Línea 907... Línea 943...
907
        $this->assertEquals($cm->id, $completiondatabeforeview['coursemoduleid']);
943
        $this->assertCompletionEquals($cm->id, $completiondatabeforeview['coursemoduleid']);
908
 
944
 
909
        // Mark as completed before viewing it.
945
        // Mark as completed before viewing it.
910
        $completioninfo->update_state($cm, COMPLETION_COMPLETE, $this->user->id, true);
946
        $completioninfo->update_state($cm, COMPLETION_COMPLETE, $this->user->id, true);
Línea 911... Línea 947...
911
        $completiondatabeforeview = $completioninfo->get_completion_data($cm->id, $this->user->id, $defaultdata);
947
        $completiondatabeforeview = $completioninfo->get_completion_data($cm->id, $this->user->id, $defaultdata);
912
        $this->assertEquals(0, $completiondatabeforeview['viewed']);
948
        $this->assertCompletionEquals(0, $completiondatabeforeview['viewed']);
Línea 913... Línea 949...
913
 
949
 
914
        // Set viewed.
950
        // Set viewed.
915
        $completioninfo->set_module_viewed($cm, $this->user->id);
951
        $completioninfo->set_module_viewed($cm, $this->user->id);
916
 
952
 
917
        $completiondata = $completioninfo->get_completion_data($cm->id, $this->user->id, $defaultdata);
953
        $completiondata = $completioninfo->get_completion_data($cm->id, $this->user->id, $defaultdata);
Línea 918... Línea 954...
918
        $this->assertTrue(array_key_exists('viewed', $completiondata));
954
        $this->assertTrue(array_key_exists('viewed', $completiondata));
Línea 919... Línea 955...
919
        $this->assertTrue(array_key_exists('coursemoduleid', $completiondata));
955
        $this->assertTrue(array_key_exists('coursemoduleid', $completiondata));
920
        $this->assertEquals(1, $completiondata['viewed']);
956
        $this->assertCompletionEquals(1, $completiondata['viewed']);
921
        $this->assertEquals($cm->id, $completiondatabeforeview['coursemoduleid']);
957
        $this->assertCompletionEquals($cm->id, $completiondatabeforeview['coursemoduleid']);
922
 
958
 
923
        $completioninfo->reset_all_state($cm);
959
        $completioninfo->reset_all_state($cm);
924
 
960
 
Línea 925... Línea 961...
925
        $completiondataafterreset = $completioninfo->get_completion_data($cm->id, $this->user->id, $defaultdata);
961
        $completiondataafterreset = $completioninfo->get_completion_data($cm->id, $this->user->id, $defaultdata);
926
        $this->assertTrue(array_key_exists('viewed', $completiondataafterreset));
962
        $this->assertTrue(array_key_exists('viewed', $completiondataafterreset));
927
        $this->assertTrue(array_key_exists('coursemoduleid', $completiondataafterreset));
963
        $this->assertTrue(array_key_exists('coursemoduleid', $completiondataafterreset));
Línea 976... Línea 1012...
976
        // Check that fetching data for a module with custom completion provides its info.
1012
        // Check that fetching data for a module with custom completion provides its info.
977
        $choicecompletiondata = $method->invoke($completioninfo, $cmchoice, $user->id);
1013
        $choicecompletiondata = $method->invoke($completioninfo, $cmchoice, $user->id);
Línea 978... Línea 1014...
978
 
1014
 
979
        $this->assertArrayHasKey('customcompletion', $choicecompletiondata);
1015
        $this->assertArrayHasKey('customcompletion', $choicecompletiondata);
980
        $this->assertArrayHasKey('completionsubmit', $choicecompletiondata['customcompletion']);
1016
        $this->assertArrayHasKey('completionsubmit', $choicecompletiondata['customcompletion']);
Línea 981... Línea 1017...
981
        $this->assertEquals(COMPLETION_INCOMPLETE, $choicecompletiondata['customcompletion']['completionsubmit']);
1017
        $this->assertCompletionEquals(COMPLETION_INCOMPLETE, $choicecompletiondata['customcompletion']['completionsubmit']);
982
 
1018
 
983
        // Mock a choice answer so user has completed the requirement.
1019
        // Mock a choice answer so user has completed the requirement.
984
        $choicemockinfo = [
1020
        $choicemockinfo = [
985
            'choiceid' => $cmchoice->instance,
1021
            'choiceid' => $cmchoice->instance,
986
            'userid' => $this->user->id
1022
            'userid' => $this->user->id
Línea 987... Línea 1023...
987
        ];
1023
        ];
988
        $DB->insert_record('choice_answers', $choicemockinfo, false);
1024
        $DB->insert_record('choice_answers', $choicemockinfo, false);
989
 
1025
 
Línea 990... Línea 1026...
990
        // Confirm fetching again reflects the completion.
1026
        // Confirm fetching again reflects the completion.
991
        $choicecompletiondata = $method->invoke($completioninfo, $cmchoice, $user->id);
1027
        $choicecompletiondata = $method->invoke($completioninfo, $cmchoice, $user->id);
Línea 992... Línea 1028...
992
        $this->assertEquals(COMPLETION_COMPLETE, $choicecompletiondata['customcompletion']['completionsubmit']);
1028
        $this->assertCompletionEquals(COMPLETION_COMPLETE, $choicecompletiondata['customcompletion']['completionsubmit']);
993
 
1029
 
994
        // Check that fetching data for a module with no custom completion still provides its grade completion status.
1030
        // Check that fetching data for a module with no custom completion still provides its grade completion status.
995
        $workshopcompletiondata = $method->invoke($completioninfo, $cmworkshop, $user->id);
1031
        $workshopcompletiondata = $method->invoke($completioninfo, $cmworkshop, $user->id);
996
 
1032
 
Línea 997... Línea 1033...
997
        $this->assertArrayHasKey('completiongrade', $workshopcompletiondata);
1033
        $this->assertArrayHasKey('completiongrade', $workshopcompletiondata);
998
        $this->assertArrayHasKey('passgrade', $workshopcompletiondata);
1034
        $this->assertArrayHasKey('passgrade', $workshopcompletiondata);
999
        $this->assertArrayNotHasKey('customcompletion', $workshopcompletiondata);
1035
        $this->assertArrayNotHasKey('customcompletion', $workshopcompletiondata);
1000
        $this->assertEquals(COMPLETION_INCOMPLETE, $workshopcompletiondata['completiongrade']);
1036
        $this->assertCompletionEquals(COMPLETION_INCOMPLETE, $workshopcompletiondata['completiongrade']);
Línea 1028... Línea 1064...
1028
        $data->viewed = COMPLETION_NOT_VIEWED;
1064
        $data->viewed = COMPLETION_NOT_VIEWED;
1029
        $data->overrideby = null;
1065
        $data->overrideby = null;
Línea 1030... Línea 1066...
1030
 
1066
 
1031
        $c->internal_set_data($cm, $data);
1067
        $c->internal_set_data($cm, $data);
1032
        $d1 = $DB->get_field('course_modules_completion', 'id', array('coursemoduleid' => $cm->id));
1068
        $d1 = $DB->get_field('course_modules_completion', 'id', array('coursemoduleid' => $cm->id));
1033
        $this->assertEquals($d1, $data->id);
1069
        $this->assertCompletionEquals($d1, $data->id);
1034
        $cache = cache::make('core', 'completion');
1070
        $cache = cache::make('core', 'completion');
1035
        // Cache was not set for another user.
1071
        // Cache was not set for another user.
1036
        $cachevalue = $cache->get("{$data->userid}_{$cm->course}");
1072
        $cachevalue = $cache->get("{$data->userid}_{$cm->course}");
1037
        $this->assertEquals([
1073
        $this->assertCompletionEquals([
1038
            'cacherev' => $this->course->cacherev,
1074
            'cacherev' => $this->course->cacherev,
1039
            $cm->id => array_merge(
1075
            $cm->id => array_merge(
1040
                (array) $data,
1076
                (array) $data,
1041
                ['other_cm_completion_data_fetched' => true]
1077
                ['other_cm_completion_data_fetched' => true]
Línea 1057... Línea 1093...
1057
        $d2->viewed = COMPLETION_NOT_VIEWED;
1093
        $d2->viewed = COMPLETION_NOT_VIEWED;
1058
        $d2->overrideby = null;
1094
        $d2->overrideby = null;
1059
        $c->internal_set_data($cm2, $d2);
1095
        $c->internal_set_data($cm2, $d2);
1060
        // Cache for current user returns the data.
1096
        // Cache for current user returns the data.
1061
        $cachevalue = $cache->get($data->userid . '_' . $cm->course);
1097
        $cachevalue = $cache->get($data->userid . '_' . $cm->course);
1062
        $this->assertEquals(array_merge(
1098
        $this->assertCompletionEquals(array_merge(
1063
            (array) $data,
1099
            (array) $data,
1064
            ['other_cm_completion_data_fetched' => true]
1100
            ['other_cm_completion_data_fetched' => true]
1065
        ), $cachevalue[$cm->id]);
1101
        ), $cachevalue[$cm->id]);
Línea 1066... Línea 1102...
1066
 
1102
 
1067
        // Cache for another user is not filled.
1103
        // Cache for another user is not filled.
Línea 1068... Línea 1104...
1068
        $this->assertEquals(false, $cache->get($d2->userid . '_' . $cm2->course));
1104
        $this->assertCompletionEquals(false, $cache->get($d2->userid . '_' . $cm2->course));
1069
 
1105
 
1070
        // 3) Test where it THINKS the data is new (from cache) but actually in the database it has been set since.
1106
        // 3) Test where it THINKS the data is new (from cache) but actually in the database it has been set since.
1071
        $forum3 = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto);
1107
        $forum3 = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto);
Línea 1103... Línea 1139...
1103
        $this->assertEmpty($actual);
1139
        $this->assertEmpty($actual);
Línea 1104... Línea 1140...
1104
 
1140
 
1105
        $data->coursemoduleid = $cm->id;
1141
        $data->coursemoduleid = $cm->id;
1106
        $c->internal_set_data($cm, $data);
1142
        $c->internal_set_data($cm, $data);
1107
        $actual = $DB->get_records('course_completions');
1143
        $actual = $DB->get_records('course_completions');
1108
        $this->assertEquals(1, count($actual));
1144
        $this->assertCompletionEquals(1, count($actual));
Línea 1109... Línea 1145...
1109
        $this->assertEquals($this->user->id, reset($actual)->userid);
1145
        $this->assertCompletionEquals($this->user->id, reset($actual)->userid);
1110
 
1146
 
1111
        $data->userid = $newuser2->id;
1147
        $data->userid = $newuser2->id;
1112
        $c->internal_set_data($cm, $data, true);
1148
        $c->internal_set_data($cm, $data, true);
1113
        $actual = $DB->get_records('course_completions');
1149
        $actual = $DB->get_records('course_completions');
1114
        $this->assertEquals(1, count($actual));
1150
        $this->assertCompletionEquals(1, count($actual));
Línea 1115... Línea 1151...
1115
        $this->assertEquals($this->user->id, reset($actual)->userid);
1151
        $this->assertCompletionEquals($this->user->id, reset($actual)->userid);
1116
    }
1152
    }
1117
 
1153
 
Línea 1142... Línea 1178...
1142
        $progress2 = (object)array('userid' => 201, 'coursemoduleid' => 14);
1178
        $progress2 = (object)array('userid' => 201, 'coursemoduleid' => 14);
1143
        $DB->expects($this->once())
1179
        $DB->expects($this->once())
1144
            ->method('get_recordset_sql')
1180
            ->method('get_recordset_sql')
1145
            ->will($this->returnValue(new core_completionlib_fake_recordset(array($progress1, $progress2))));
1181
            ->will($this->returnValue(new core_completionlib_fake_recordset(array($progress1, $progress2))));
Línea 1146... Línea 1182...
1146
 
1182
 
1147
        $this->assertEquals(array(
1183
        $this->assertCompletionEquals(array(
1148
                100 => (object)array('id' => 100, 'firstname' => 'Woot', 'lastname' => 'Plugh',
1184
                100 => (object)array('id' => 100, 'firstname' => 'Woot', 'lastname' => 'Plugh',
1149
                    'progress' => array(13 => $progress1)),
1185
                    'progress' => array(13 => $progress1)),
1150
                201 => (object)array('id' => 201, 'firstname' => 'Vroom', 'lastname' => 'Xyzzy',
1186
                201 => (object)array('id' => 201, 'firstname' => 'Vroom', 'lastname' => 'Xyzzy',
1151
                    'progress' => array(14 => $progress2)),
1187
                    'progress' => array(14 => $progress2)),
Línea 1176... Línea 1212...
1176
        }
1212
        }
1177
        $c->expects($this->once())
1213
        $c->expects($this->once())
1178
            ->method('get_tracked_users')
1214
            ->method('get_tracked_users')
1179
            ->with(true,  3,  0,  '',  '',  '',  null)
1215
            ->with(true,  3,  0,  '',  '',  '',  null)
1180
            ->will($this->returnValue($tracked));
1216
            ->will($this->returnValue($tracked));
-
 
1217
        $inorequalsinvocations = $this->exactly(2);
1181
        $DB->expects($this->exactly(2))
1218
        $DB->expects($inorequalsinvocations)
1182
            ->method('get_in_or_equal')
1219
            ->method('get_in_or_equal')
-
 
1220
            ->willReturnCallback(function ($paramids) use ($inorequalsinvocations, $ids) {
-
 
1221
                switch (self::getInvocationCount($inorequalsinvocations)) {
1183
            ->withConsecutive(
1222
                    case 1:
1184
                array(array_slice($ids, 0, 1000)),
1223
                        $this->assertCompletionEquals(array_slice($ids, 0, 1000), $paramids);
1185
                array(array_slice($ids, 1000))
1224
                        return [' IN whatever', []];
1186
            )
1225
                    case 2:
-
 
1226
                        $this->assertCompletionEquals(array_slice($ids, 1000), $paramids);
1187
            ->willReturnOnConsecutiveCalls(
1227
                        return [' IN whatever2', []];
1188
                array(' IN whatever', array()),
1228
                    default:
-
 
1229
                        $this->fail('Unexpected invocation count');
-
 
1230
                }
-
 
1231
            });
1189
                array(' IN whatever2', array()));
1232
        $getinvocations = $this->exactly(2);
1190
        $DB->expects($this->exactly(2))
1233
        $DB->expects($getinvocations)
1191
            ->method('get_recordset_sql')
1234
            ->method('get_recordset_sql')
1192
            ->willReturnOnConsecutiveCalls(
1235
            ->willReturnCallback(function () use ($getinvocations, $progress) {
-
 
1236
                return match (self::getInvocationCount($getinvocations)) {
1193
                new core_completionlib_fake_recordset(array_slice($progress, 0, 1000)),
1237
                    1 => new core_completionlib_fake_recordset(array_slice($progress, 0, 1000)),
1194
                new core_completionlib_fake_recordset(array_slice($progress, 1000)));
1238
                    2 => new core_completionlib_fake_recordset(array_slice($progress, 1000)),
-
 
1239
                    default => $this->fail('Unexpected invocation count'),
-
 
1240
                };
-
 
1241
            });
Línea 1195... Línea 1242...
1195
 
1242
 
1196
        $result = $c->get_progress_all(true, 3);
1243
        $result = $c->get_progress_all(true, 3);
1197
        $resultok = true;
1244
        $resultok = true;
Línea 1294... Línea 1341...
1294
        $item->hidden = 0;
1341
        $item->hidden = 0;
1295
        $grade->rawgrade = 4.0;
1342
        $grade->rawgrade = 4.0;
1296
        $grade->finalgrade = null;
1343
        $grade->finalgrade = null;
Línea 1297... Línea 1344...
1297
 
1344
 
1298
        // Grade has pass mark and is not hidden,  user passes.
1345
        // Grade has pass mark and is not hidden,  user passes.
1299
        $this->assertEquals(
1346
        $this->assertCompletionEquals(
1300
            COMPLETION_COMPLETE_PASS,
1347
            COMPLETION_COMPLETE_PASS,
Línea 1301... Línea 1348...
1301
            completion_info::internal_get_grade_state($item, $grade));
1348
            completion_info::internal_get_grade_state($item, $grade));
1302
 
1349
 
1303
        // Same but user fails.
1350
        // Same but user fails.
1304
        $grade->rawgrade = 3.9;
1351
        $grade->rawgrade = 3.9;
1305
        $this->assertEquals(
1352
        $this->assertCompletionEquals(
Línea 1306... Línea 1353...
1306
            COMPLETION_COMPLETE_FAIL,
1353
            COMPLETION_COMPLETE_FAIL,
1307
            completion_info::internal_get_grade_state($item, $grade));
1354
            completion_info::internal_get_grade_state($item, $grade));
1308
 
1355
 
1309
        // User fails on raw grade but passes on final.
1356
        // User fails on raw grade but passes on final.
1310
        $grade->finalgrade = 4.0;
1357
        $grade->finalgrade = 4.0;
Línea 1311... Línea 1358...
1311
        $this->assertEquals(
1358
        $this->assertCompletionEquals(
1312
            COMPLETION_COMPLETE_PASS,
1359
            COMPLETION_COMPLETE_PASS,
1313
            completion_info::internal_get_grade_state($item, $grade));
1360
            completion_info::internal_get_grade_state($item, $grade));
1314
 
1361
 
1315
        // Item is hidden.
1362
        // Item is hidden.
Línea 1316... Línea 1363...
1316
        $item->hidden = 1;
1363
        $item->hidden = 1;
1317
        $this->assertEquals(
1364
        $this->assertCompletionEquals(
1318
            COMPLETION_COMPLETE,
1365
            COMPLETION_COMPLETE,
1319
            completion_info::internal_get_grade_state($item, $grade));
1366
            completion_info::internal_get_grade_state($item, $grade));
1320
 
1367
 
1321
        // Item isn't hidden but has no pass mark.
1368
        // Item isn't hidden but has no pass mark.
Línea 1322... Línea 1369...
1322
        $item->hidden = 0;
1369
        $item->hidden = 0;
1323
        $item->gradepass = 0;
1370
        $item->gradepass = 0;
1324
        $this->assertEquals(
1371
        $this->assertCompletionEquals(
1325
            COMPLETION_COMPLETE,
1372
            COMPLETION_COMPLETE,
1326
            completion_info::internal_get_grade_state($item, $grade));
1373
            completion_info::internal_get_grade_state($item, $grade));
1327
 
1374
 
1328
        // Item is hidden, but returnpassfail is true and the grade is passing.
1375
        // Item is hidden, but returnpassfail is true and the grade is passing.
Línea 1329... Línea 1376...
1329
        $item->hidden = 1;
1376
        $item->hidden = 1;
1330
        $item->gradepass = 4;
1377
        $item->gradepass = 4;
1331
        $grade->finalgrade = 5.0;
1378
        $grade->finalgrade = 5.0;
1332
        $this->assertEquals(
1379
        $this->assertCompletionEquals(
1333
            COMPLETION_COMPLETE_PASS,
1380
            COMPLETION_COMPLETE_PASS,
1334
            completion_info::internal_get_grade_state($item, $grade, true));
1381
            completion_info::internal_get_grade_state($item, $grade, true));
1335
 
1382
 
Línea 1336... Línea 1383...
1336
        // Item is hidden, but returnpassfail is true and the grade is failing.
1383
        // Item is hidden, but returnpassfail is true and the grade is failing.
1337
        $item->hidden = 1;
1384
        $item->hidden = 1;
1338
        $item->gradepass = 4;
1385
        $item->gradepass = 4;
1339
        $grade->finalgrade = 3.0;
1386
        $grade->finalgrade = 3.0;
1340
        $this->assertEquals(
1387
        $this->assertCompletionEquals(
1341
            COMPLETION_COMPLETE_FAIL_HIDDEN,
1388
            COMPLETION_COMPLETE_FAIL_HIDDEN,
1342
            completion_info::internal_get_grade_state($item, $grade, true));
1389
            completion_info::internal_get_grade_state($item, $grade, true));
1343
 
1390
 
Línea 1344... Línea 1391...
1344
        // Item is not hidden, but returnpassfail is true and the grade is failing.
1391
        // Item is not hidden, but returnpassfail is true and the grade is failing.
Línea 1473... Línea 1520...
1473
        $completionauto = array('completion' => COMPLETION_TRACKING_AUTOMATIC);
1520
        $completionauto = array('completion' => COMPLETION_TRACKING_AUTOMATIC);
1474
        $forum = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto);
1521
        $forum = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto);
Línea 1475... Línea 1522...
1475
 
1522
 
1476
        $c = new completion_info($this->course);
1523
        $c = new completion_info($this->course);
1477
        $activities = $c->get_activities();
1524
        $activities = $c->get_activities();
1478
        $this->assertEquals(1, count($activities));
1525
        $this->assertCompletionEquals(1, count($activities));
1479
        $this->assertTrue(isset($activities[$forum->cmid]));
1526
        $this->assertTrue(isset($activities[$forum->cmid]));
Línea 1480... Línea 1527...
1480
        $this->assertEquals($activities[$forum->cmid]->name, $forum->name);
1527
        $this->assertCompletionEquals($activities[$forum->cmid]->name, $forum->name);
1481
 
1528
 
1482
        $current = $c->get_data($activities[$forum->cmid], false, $this->user->id);
1529
        $current = $c->get_data($activities[$forum->cmid], false, $this->user->id);
1483
        $current->completionstate = COMPLETION_COMPLETE;
1530
        $current->completionstate = COMPLETION_COMPLETE;
1484
        $current->timemodified = time();
1531
        $current->timemodified = time();
1485
        $sink = $this->redirectEvents();
1532
        $sink = $this->redirectEvents();
1486
        $c->internal_set_data($activities[$forum->cmid], $current);
1533
        $c->internal_set_data($activities[$forum->cmid], $current);
1487
        $events = $sink->get_events();
1534
        $events = $sink->get_events();
1488
        $event = reset($events);
1535
        $event = reset($events);
1489
        $this->assertInstanceOf('\core\event\course_module_completion_updated', $event);
1536
        $this->assertInstanceOf('\core\event\course_module_completion_updated', $event);
1490
        $this->assertEquals($forum->cmid,
1537
        $this->assertCompletionEquals($forum->cmid,
1491
            $event->get_record_snapshot('course_modules_completion', $event->objectid)->coursemoduleid);
1538
            $event->get_record_snapshot('course_modules_completion', $event->objectid)->coursemoduleid);
1492
        $this->assertEquals($current, $event->get_record_snapshot('course_modules_completion', $event->objectid));
1539
        $this->assertCompletionEquals($current, $event->get_record_snapshot('course_modules_completion', $event->objectid));
1493
        $this->assertEquals(context_module::instance($forum->cmid), $event->get_context());
1540
        $this->assertCompletionEquals(context_module::instance($forum->cmid), $event->get_context());
1494
        $this->assertEquals($USER->id, $event->userid);
1541
        $this->assertCompletionEquals($USER->id, $event->userid);
1495
        $this->assertEquals($this->user->id, $event->relateduserid);
1542
        $this->assertCompletionEquals($this->user->id, $event->relateduserid);
Línea 1496... Línea 1543...
1496
        $this->assertInstanceOf('moodle_url', $event->get_url());
1543
        $this->assertInstanceOf('moodle_url', $event->get_url());
1497
    }
1544
    }
Línea 1515... Línea 1562...
1515
        $ccompletion->mark_complete();
1562
        $ccompletion->mark_complete();
1516
        $events = $sink->get_events();
1563
        $events = $sink->get_events();
1517
        $event = reset($events);
1564
        $event = reset($events);
Línea 1518... Línea 1565...
1518
 
1565
 
1519
        $this->assertInstanceOf('\core\event\course_completed', $event);
1566
        $this->assertInstanceOf('\core\event\course_completed', $event);
1520
        $this->assertEquals($this->course->id, $event->get_record_snapshot('course_completions', $event->objectid)->course);
1567
        $this->assertCompletionEquals($this->course->id, $event->get_record_snapshot('course_completions', $event->objectid)->course);
1521
        $this->assertEquals($this->course->id, $event->courseid);
1568
        $this->assertCompletionEquals($this->course->id, $event->courseid);
1522
        $this->assertEquals($USER->id, $event->userid);
1569
        $this->assertCompletionEquals($USER->id, $event->userid);
1523
        $this->assertEquals($this->user->id, $event->relateduserid);
1570
        $this->assertCompletionEquals($this->user->id, $event->relateduserid);
1524
        $this->assertEquals(context_course::instance($this->course->id), $event->get_context());
1571
        $this->assertCompletionEquals(context_course::instance($this->course->id), $event->get_context());
1525
        $this->assertInstanceOf('moodle_url', $event->get_url());
1572
        $this->assertInstanceOf('moodle_url', $event->get_url());
Línea 1526... Línea 1573...
1526
    }
1573
    }
1527
 
1574
 
Línea 1544... Línea 1591...
1544
        $sink->close();
1591
        $sink->close();
Línea 1545... Línea 1592...
1545
 
1592
 
1546
        $this->assertCount(1, $messages);
1593
        $this->assertCount(1, $messages);
Línea 1547... Línea 1594...
1547
        $message = array_pop($messages);
1594
        $message = array_pop($messages);
1548
 
1595
 
1549
        $this->assertEquals(core_user::get_noreply_user()->id, $message->useridfrom);
1596
        $this->assertCompletionEquals(core_user::get_noreply_user()->id, $message->useridfrom);
1550
        $this->assertEquals($this->user->id, $message->useridto);
1597
        $this->assertCompletionEquals($this->user->id, $message->useridto);
1551
        $this->assertEquals('coursecompleted', $message->eventtype);
1598
        $this->assertCompletionEquals('coursecompleted', $message->eventtype);
1552
        $this->assertEquals(get_string('coursecompleted', 'completion'), $message->subject);
1599
        $this->assertCompletionEquals(get_string('coursecompleted', 'completion'), $message->subject);
Línea 1553... Línea 1600...
1553
        $this->assertStringContainsString($this->course->fullname, $message->fullmessage);
1600
        $this->assertStringContainsString($this->course->fullname, $message->fullmessage);
1554
    }
1601
    }
Línea 1574... Línea 1621...
1574
        $events = $sink->get_events();
1621
        $events = $sink->get_events();
1575
        $event = array_pop($events);
1622
        $event = array_pop($events);
1576
        $sink->close();
1623
        $sink->close();
Línea 1577... Línea 1624...
1577
 
1624
 
1578
        $this->assertInstanceOf('\core\event\course_completion_updated', $event);
1625
        $this->assertInstanceOf('\core\event\course_completion_updated', $event);
1579
        $this->assertEquals($this->course->id, $event->courseid);
1626
        $this->assertCompletionEquals($this->course->id, $event->courseid);
1580
        $this->assertEquals($coursecontext, $event->get_context());
1627
        $this->assertCompletionEquals($coursecontext, $event->get_context());
1581
        $this->assertInstanceOf('moodle_url', $event->get_url());
1628
        $this->assertInstanceOf('moodle_url', $event->get_url());
Línea 1582... Línea 1629...
1582
    }
1629
    }
1583
 
1630
 
Línea 1598... Línea 1645...
1598
    /**
1645
    /**
1599
     * Data provider for test_get_grade_completion().
1646
     * Data provider for test_get_grade_completion().
1600
     *
1647
     *
1601
     * @return array[]
1648
     * @return array[]
1602
     */
1649
     */
1603
    public function get_grade_completion_provider() {
1650
    public static function get_grade_completion_provider(): array {
1604
        return [
1651
        return [
1605
            'Grade not required' => [false, false, null, null, null],
1652
            'Grade not required' => [false, false, null, null, null],
1606
            'Grade required, but has no grade yet' => [true, false, null, null, COMPLETION_INCOMPLETE],
1653
            'Grade required, but has no grade yet' => [true, false, null, null, COMPLETION_INCOMPLETE],
1607
            'Grade required, grade received' => [true, true, null, null, COMPLETION_COMPLETE],
1654
            'Grade required, grade received' => [true, true, null, null, COMPLETION_COMPLETE],
1608
            'Grade required, passing grade received' => [true, true, 70, null, COMPLETION_COMPLETE_PASS],
1655
            'Grade required, passing grade received' => [true, true, 70, null, COMPLETION_COMPLETE_PASS],
Línea 1645... Línea 1692...
1645
        $completioninfo = new completion_info($this->course);
1692
        $completioninfo = new completion_info($this->course);
1646
        if ($expectedexception) {
1693
        if ($expectedexception) {
1647
            $this->expectException($expectedexception);
1694
            $this->expectException($expectedexception);
1648
        }
1695
        }
1649
        $gradecompletion = $completioninfo->get_grade_completion($cm, $this->user->id);
1696
        $gradecompletion = $completioninfo->get_grade_completion($cm, $this->user->id);
1650
        $this->assertEquals($expectedresult, $gradecompletion);
1697
        $this->assertCompletionEquals($expectedresult, $gradecompletion);
1651
    }
1698
    }
Línea 1652... Línea 1699...
1652
 
1699
 
1653
    /**
1700
    /**
1654
     * Test the return value for cases when the activity module does not have associated grade_item.
1701
     * Test the return value for cases when the activity module does not have associated grade_item.
Línea 1676... Línea 1723...
1676
            'iteminstance' => $assign->id,
1723
            'iteminstance' => $assign->id,
1677
        ]);
1724
        ]);
Línea 1678... Línea 1725...
1678
 
1725
 
1679
        // Without the grade_item, the activity is considered incomplete.
1726
        // Without the grade_item, the activity is considered incomplete.
1680
        $completioninfo = new completion_info($this->course);
1727
        $completioninfo = new completion_info($this->course);
Línea 1681... Línea 1728...
1681
        $this->assertEquals(COMPLETION_INCOMPLETE, $completioninfo->get_grade_completion($cm, $this->user->id));
1728
        $this->assertCompletionEquals(COMPLETION_INCOMPLETE, $completioninfo->get_grade_completion($cm, $this->user->id));
1682
 
1729
 
1683
        // Once the activity is graded, the grade_item is automatically created.
1730
        // Once the activity is graded, the grade_item is automatically created.
1684
        $assigninstance = new assign($cm->context, $cm, $this->course);
1731
        $assigninstance = new assign($cm->context, $cm, $this->course);
1685
        $grade = $assigninstance->get_user_grade($this->user->id, true);
1732
        $grade = $assigninstance->get_user_grade($this->user->id, true);
Línea 1686... Línea 1733...
1686
        $grade->grade = 40;
1733
        $grade->grade = 40;
1687
        $assigninstance->update_grade($grade);
1734
        $assigninstance->update_grade($grade);
1688
 
1735
 
Línea 1689... Línea 1736...
1689
        // The implicitly created grade_item does not have grade to pass defined so it is not distinguished.
1736
        // The implicitly created grade_item does not have grade to pass defined so it is not distinguished.
1690
        $this->assertEquals(COMPLETION_COMPLETE, $completioninfo->get_grade_completion($cm, $this->user->id));
1737
        $this->assertCompletionEquals(COMPLETION_COMPLETE, $completioninfo->get_grade_completion($cm, $this->user->id));
1691
    }
1738
    }
Línea 1819... Línea 1866...
1819
 
1866
 
1820
        // We're testing a private method, so we need to setup reflector magic.
1867
        // We're testing a private method, so we need to setup reflector magic.
1821
        $method = new ReflectionMethod($ccompletion, '_save');
1868
        $method = new ReflectionMethod($ccompletion, '_save');
1822
        $completionid = $method->invoke($ccompletion);
1869
        $completionid = $method->invoke($ccompletion);
1823
        $completions = $DB->get_records('course_completions');
1870
        $completions = $DB->get_records('course_completions');
1824
        $this->assertEquals(count($completions), 1);
1871
        $this->assertCompletionEquals(count($completions), 1);
Línea 1825... Línea 1872...
1825
        $this->assertEquals(reset($completions)->id, $completionid);
1872
        $this->assertCompletionEquals(reset($completions)->id, $completionid);
1826
 
1873
 
1827
        $ccompletion->id = 0;
1874
        $ccompletion->id = 0;
1828
        $method = new ReflectionMethod($ccompletion, '_save');
1875
        $method = new ReflectionMethod($ccompletion, '_save');
Línea 1861... Línea 1908...
1861
        $completions = $DB->get_records('course_completions');
1908
        $completions = $DB->get_records('course_completions');
1862
        $this->assertEmpty($completions);
1909
        $this->assertEmpty($completions);
Línea 1863... Línea 1910...
1863
 
1910
 
1864
        $completionid = $ccompletion->mark_enrolled();
1911
        $completionid = $ccompletion->mark_enrolled();
1865
        $completions = $DB->get_records('course_completions');
1912
        $completions = $DB->get_records('course_completions');
1866
        $this->assertEquals(count($completions), 1);
1913
        $this->assertCompletionEquals(count($completions), 1);
Línea 1867... Línea 1914...
1867
        $this->assertEquals(reset($completions)->id, $completionid);
1914
        $this->assertCompletionEquals(reset($completions)->id, $completionid);
1868
 
1915
 
1869
        $ccompletion->id = 0;
1916
        $ccompletion->id = 0;
1870
        $completionid = $ccompletion->mark_enrolled();
1917
        $completionid = $ccompletion->mark_enrolled();
1871
        $this->assertDebuggingCalled('Can not update data object, no id!');
1918
        $this->assertDebuggingCalled('Can not update data object, no id!');
1872
        $this->assertNull($completionid);
1919
        $this->assertNull($completionid);
1873
        $completions = $DB->get_records('course_completions');
1920
        $completions = $DB->get_records('course_completions');
Línea 1874... Línea 1921...
1874
        $this->assertEquals(1, count($completions));
1921
        $this->assertCompletionEquals(1, count($completions));
1875
    }
1922
    }
1876
 
1923
 
Línea 1904... Línea 1951...
1904
        $completions = $DB->get_records('course_completions');
1951
        $completions = $DB->get_records('course_completions');
1905
        $this->assertEmpty($completions);
1952
        $this->assertEmpty($completions);
Línea 1906... Línea 1953...
1906
 
1953
 
1907
        $completionid = $ccompletion->mark_inprogress();
1954
        $completionid = $ccompletion->mark_inprogress();
1908
        $completions = $DB->get_records('course_completions');
1955
        $completions = $DB->get_records('course_completions');
1909
        $this->assertEquals(1, count($completions));
1956
        $this->assertCompletionEquals(1, count($completions));
Línea 1910... Línea 1957...
1910
        $this->assertEquals(reset($completions)->id, $completionid);
1957
        $this->assertCompletionEquals(reset($completions)->id, $completionid);
1911
 
1958
 
1912
        $ccompletion->id = 0;
1959
        $ccompletion->id = 0;
1913
        $completionid = $ccompletion->mark_inprogress();
1960
        $completionid = $ccompletion->mark_inprogress();
1914
        $this->assertDebuggingCalled('Can not update data object, no id!');
1961
        $this->assertDebuggingCalled('Can not update data object, no id!');
1915
        $this->assertNull($completionid);
1962
        $this->assertNull($completionid);
1916
        $completions = $DB->get_records('course_completions');
1963
        $completions = $DB->get_records('course_completions');
Línea 1917... Línea 1964...
1917
        $this->assertEquals(1, count($completions));
1964
        $this->assertCompletionEquals(1, count($completions));
1918
    }
1965
    }
1919
 
1966
 
Línea 1947... Línea 1994...
1947
        $completions = $DB->get_records('course_completions');
1994
        $completions = $DB->get_records('course_completions');
1948
        $this->assertEmpty($completions);
1995
        $this->assertEmpty($completions);
Línea 1949... Línea 1996...
1949
 
1996
 
1950
        $completionid = $ccompletion->mark_complete();
1997
        $completionid = $ccompletion->mark_complete();
1951
        $completions = $DB->get_records('course_completions');
1998
        $completions = $DB->get_records('course_completions');
1952
        $this->assertEquals(1, count($completions));
1999
        $this->assertCompletionEquals(1, count($completions));
Línea 1953... Línea 2000...
1953
        $this->assertEquals(reset($completions)->id, $completionid);
2000
        $this->assertCompletionEquals(reset($completions)->id, $completionid);
1954
 
2001
 
1955
        $ccompletion->id = 0;
2002
        $ccompletion->id = 0;
1956
        $completionid = $ccompletion->mark_complete();
2003
        $completionid = $ccompletion->mark_complete();
1957
        $this->assertNull($completionid);
2004
        $this->assertNull($completionid);
1958
        $completions = $DB->get_records('course_completions');
2005
        $completions = $DB->get_records('course_completions');
Línea 1959... Línea 2006...
1959
        $this->assertEquals(1, count($completions));
2006
        $this->assertCompletionEquals(1, count($completions));
1960
    }
2007
    }
1961
 
2008
 
Línea 1991... Línea 2038...
1991
        $completions = $DB->get_records('course_completions');
2038
        $completions = $DB->get_records('course_completions');
1992
        $this->assertEmpty($completions);
2039
        $this->assertEmpty($completions);
Línea 1993... Línea 2040...
1993
 
2040
 
1994
        $completionid = $completion->mark_complete($record['timecompleted']);
2041
        $completionid = $completion->mark_complete($record['timecompleted']);
1995
        $completions = $DB->get_records('course_completions');
2042
        $completions = $DB->get_records('course_completions');
1996
        $this->assertEquals(1, count($completions));
2043
        $this->assertCompletionEquals(1, count($completions));
1997
        $this->assertEquals(reset($completions)->id, $completionid);
2044
        $this->assertCompletionEquals(reset($completions)->id, $completionid);
Línea 1998... Línea 2045...
1998
    }
2045
    }
1999
 
2046
 
2000
    /**
2047
    /**
Línea 2037... Línea 2084...
2037
        $this->assertFalse($DB->record_exists_select('course_modules_viewed',
2084
        $this->assertFalse($DB->record_exists_select('course_modules_viewed',
2038
            'coursemoduleid IN (SELECT id FROM {course_modules} WHERE course=:course)',
2085
            'coursemoduleid IN (SELECT id FROM {course_modules} WHERE course=:course)',
2039
            ['course' => $this->course->id]
2086
            ['course' => $this->course->id]
2040
        ));
2087
        ));
2041
    }
2088
    }
-
 
2089
 
-
 
2090
    /**
-
 
2091
     * Data provider for test_count_modules_completed().
-
 
2092
     *
-
 
2093
     * @return array[]
-
 
2094
     */
-
 
2095
    public static function count_modules_completed_provider(): array {
-
 
2096
        return [
-
 
2097
            'Multiple users with two different modules but only one completed' => [
-
 
2098
                'existinguser' => true,
-
 
2099
                'totalusers' => 3,
-
 
2100
                'modules' => [
-
 
2101
                    [
-
 
2102
                        'name' => 'assign',
-
 
2103
                        'completionstate' => COMPLETION_COMPLETE,
-
 
2104
                    ],
-
 
2105
                    [
-
 
2106
                        'name' => 'choice',
-
 
2107
                        'completionstate' => COMPLETION_INCOMPLETE,
-
 
2108
                    ],
-
 
2109
                ],
-
 
2110
                'expectedcount' => 1,
-
 
2111
            ],
-
 
2112
            'Multiple users with three different modules but only two completed' => [
-
 
2113
                'existinguser' => true,
-
 
2114
                'totalusers' => 4,
-
 
2115
                'modules' => [
-
 
2116
                    [
-
 
2117
                        'name' => 'assign',
-
 
2118
                        'completionstate' => COMPLETION_COMPLETE,
-
 
2119
                    ],
-
 
2120
                    [
-
 
2121
                        'name' => 'choice',
-
 
2122
                        'completionstate' => COMPLETION_INCOMPLETE,
-
 
2123
                    ],
-
 
2124
                    [
-
 
2125
                        'name' => 'workshop',
-
 
2126
                        'completionstate' => COMPLETION_COMPLETE,
-
 
2127
                    ],
-
 
2128
                ],
-
 
2129
                'expectedcount' => 2,
-
 
2130
            ],
-
 
2131
            'Multiple users with one completion each' => [
-
 
2132
                'existinguser' => true,
-
 
2133
                'totalusers' => 5,
-
 
2134
                'modules' => [
-
 
2135
                    [
-
 
2136
                        'name' => 'assign',
-
 
2137
                        'completionstate' => COMPLETION_COMPLETE,
-
 
2138
                    ],
-
 
2139
                ],
-
 
2140
                'expectedcount' => 1,
-
 
2141
            ],
-
 
2142
            'One user with one completion' => [
-
 
2143
                'existinguser' => true,
-
 
2144
                'totalusers' => 1,
-
 
2145
                'modules' => [
-
 
2146
                    [
-
 
2147
                        'name' => 'assign',
-
 
2148
                        'completionstate' => COMPLETION_COMPLETE,
-
 
2149
                    ],
-
 
2150
                ],
-
 
2151
                'expectedcount' => 1,
-
 
2152
            ],
-
 
2153
            'Multiple users without completion' => [
-
 
2154
                'existinguser' => true,
-
 
2155
                'totalusers' => 3,
-
 
2156
                'modules' => [
-
 
2157
                    [
-
 
2158
                        'name' => 'assign',
-
 
2159
                        'completionstate' => COMPLETION_INCOMPLETE,
-
 
2160
                    ],
-
 
2161
                ],
-
 
2162
                'expectedcount' => 0,
-
 
2163
            ],
-
 
2164
            'Non-existing user' => [
-
 
2165
                'existinguser' => false,
-
 
2166
                'totalusers' => 1,
-
 
2167
                'modules' => [
-
 
2168
                    [
-
 
2169
                        'name' => 'assign',
-
 
2170
                        'completionstate' => COMPLETION_INCOMPLETE,
-
 
2171
                    ],
-
 
2172
                ],
-
 
2173
                'expectedcount' => 0,
-
 
2174
            ],
-
 
2175
        ];
-
 
2176
    }
-
 
2177
 
-
 
2178
    /**
-
 
2179
     * Test for count_modules_completed().
-
 
2180
     *
-
 
2181
     * @dataProvider count_modules_completed_provider
-
 
2182
     * @param bool $existinguser Whether the given user exists or not.
-
 
2183
     * @param int $totalusers The amount of users to check completion.
-
 
2184
     * @param array $modules The course modules with its completion state.
-
 
2185
     * @param int $expectedcount Expected total of modules completed.
-
 
2186
     * @covers ::count_modules_completed
-
 
2187
     */
-
 
2188
    public function test_count_modules_completed(bool $existinguser, int $totalusers, array $modules,
-
 
2189
        int $expectedcount): void {
-
 
2190
        global $DB;
-
 
2191
 
-
 
2192
        $this->setAdminUser();
-
 
2193
        $this->setup_data();
-
 
2194
 
-
 
2195
        // Loop through the provided modules array and set the id key based on the generated module.
-
 
2196
        $modules = array_map(function(array $module): array {
-
 
2197
            $generator = $this->getDataGenerator()->get_plugin_generator('mod_' . $module['name']);
-
 
2198
            $modinstance = $generator->create_instance([
-
 
2199
                'course' => $this->course->id,
-
 
2200
                'completion' => COMPLETION_TRACKING_AUTOMATIC,
-
 
2201
                'completionsubmit' => true,
-
 
2202
            ]);
-
 
2203
            $cminstance = get_coursemodule_from_instance($module['name'], $modinstance->id);
-
 
2204
 
-
 
2205
            $module['id'] = $cminstance->id;
-
 
2206
            return $module;
-
 
2207
        }, $modules);
-
 
2208
 
-
 
2209
        $completion = new completion_info($this->course);
-
 
2210
 
-
 
2211
        if ($existinguser) {
-
 
2212
            // Create users, assign them to a course and define the completion record.
-
 
2213
            for ($i = 0; $i < $totalusers; $i++) {
-
 
2214
                $user = $this->getDataGenerator()->create_user();
-
 
2215
                $this->getDataGenerator()->enrol_user($user->id, $this->course->id);
-
 
2216
                $users[] = $user;
-
 
2217
 
-
 
2218
                foreach ($modules as $module) {
-
 
2219
                    $cmcompletionrecords[] = (object)[
-
 
2220
                        'coursemoduleid' => $module['id'],
-
 
2221
                        'userid' => $user->id,
-
 
2222
                        'completionstate' => $module['completionstate'],
-
 
2223
                        'timemodified' => 0,
-
 
2224
                    ];
-
 
2225
                }
-
 
2226
            }
-
 
2227
 
-
 
2228
            $DB->insert_records('course_modules_completion', $cmcompletionrecords);
-
 
2229
 
-
 
2230
            foreach ($users as $user) {
-
 
2231
                $this->assertEquals($expectedcount, $completion->count_modules_completed($user->id));
-
 
2232
            }
-
 
2233
        } else {
-
 
2234
            $nonexistinguserid = 123;
-
 
2235
            $this->assertEquals($expectedcount, $completion->count_modules_completed($nonexistinguserid));
-
 
2236
        }
-
 
2237
    }
2042
}
2238
}
Línea 2043... Línea 2239...
2043
 
2239
 
2044
class core_completionlib_fake_recordset implements Iterator {
2240
class core_completionlib_fake_recordset implements Iterator {
2045
    protected $closed;
2241
    protected $closed;