2 // This file is part of Moodle - http://moodle.org/
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.
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/>.
18 * Unit tests for badges
22 * @copyright 2013 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 * @author Yuliya Bozhko <yuliya.bozhko@totaralms.com>
27 defined('MOODLE_INTERNAL') ||
die();
30 require_once($CFG->libdir
. '/badgeslib.php');
32 class core_badgeslib_testcase
extends advanced_testcase
{
37 protected $coursebadge;
40 protected function setUp() {
42 $this->resetAfterTest(true);
44 $user = $this->getDataGenerator()->create_user();
46 $fordb = new stdClass();
48 $fordb->name
= "Test badge";
49 $fordb->description
= "Testing badges";
50 $fordb->timecreated
= time();
51 $fordb->timemodified
= time();
52 $fordb->usercreated
= $user->id
;
53 $fordb->usermodified
= $user->id
;
54 $fordb->issuername
= "Test issuer";
55 $fordb->issuerurl
= "http://issuer-url.domain.co.nz";
56 $fordb->issuercontact
= "issuer@example.com";
57 $fordb->expiredate
= null;
58 $fordb->expireperiod
= null;
59 $fordb->type
= BADGE_TYPE_SITE
;
60 $fordb->courseid
= null;
61 $fordb->messagesubject
= "Test message subject";
62 $fordb->message
= "Test message body";
63 $fordb->attachment
= 1;
64 $fordb->notification
= 0;
65 $fordb->status
= BADGE_STATUS_INACTIVE
;
67 $this->badgeid
= $DB->insert_record('badge', $fordb, true);
69 // Create a course with activity and auto completion tracking.
70 $this->course
= $this->getDataGenerator()->create_course();
71 $this->user
= $this->getDataGenerator()->create_user();
72 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
73 $this->assertNotEmpty($studentrole);
75 // Get manual enrolment plugin and enrol user.
76 require_once($CFG->dirroot
.'/enrol/manual/locallib.php');
77 $manplugin = enrol_get_plugin('manual');
78 $maninstance = $DB->get_record('enrol', array('courseid' => $this->course
->id
, 'enrol' => 'manual'), '*', MUST_EXIST
);
79 $manplugin->enrol_user($maninstance, $this->user
->id
, $studentrole->id
);
80 $this->assertEquals(1, $DB->count_records('user_enrolments'));
82 $completionauto = array('completion' => COMPLETION_TRACKING_AUTOMATIC
);
83 $this->module
= $this->getDataGenerator()->create_module('forum', array('course' => $this->course
->id
), $completionauto);
85 // Build badge and criteria.
86 $fordb->type
= BADGE_TYPE_COURSE
;
87 $fordb->courseid
= $this->course
->id
;
88 $fordb->status
= BADGE_STATUS_ACTIVE
;
90 $this->coursebadge
= $DB->insert_record('badge', $fordb, true);
91 $this->assertion
= new stdClass();
92 $this->assertion
->badge
= '{"uid":"%s","recipient":{"identity":"%s","type":"email","hashed":true,"salt":"%s"},"badge":"%s","verify":{"type":"hosted","url":"%s"},"issuedOn":"%d","evidence":"%s"}';
93 $this->assertion
->class = '{"name":"%s","description":"%s","image":"%s","criteria":"%s","issuer":"%s"}';
94 $this->assertion
->issuer
= '{"name":"%s","url":"%s","email":"%s"}';
97 public function test_create_badge() {
98 $badge = new badge($this->badgeid
);
100 $this->assertInstanceOf('badge', $badge);
101 $this->assertEquals($this->badgeid
, $badge->id
);
104 public function test_clone_badge() {
105 $badge = new badge($this->badgeid
);
106 $newid = $badge->make_clone();
107 $cloned_badge = new badge($newid);
109 $this->assertEquals($badge->description
, $cloned_badge->description
);
110 $this->assertEquals($badge->issuercontact
, $cloned_badge->issuercontact
);
111 $this->assertEquals($badge->issuername
, $cloned_badge->issuername
);
112 $this->assertEquals($badge->issuercontact
, $cloned_badge->issuercontact
);
113 $this->assertEquals($badge->issuerurl
, $cloned_badge->issuerurl
);
114 $this->assertEquals($badge->expiredate
, $cloned_badge->expiredate
);
115 $this->assertEquals($badge->expireperiod
, $cloned_badge->expireperiod
);
116 $this->assertEquals($badge->type
, $cloned_badge->type
);
117 $this->assertEquals($badge->courseid
, $cloned_badge->courseid
);
118 $this->assertEquals($badge->message
, $cloned_badge->message
);
119 $this->assertEquals($badge->messagesubject
, $cloned_badge->messagesubject
);
120 $this->assertEquals($badge->attachment
, $cloned_badge->attachment
);
121 $this->assertEquals($badge->notification
, $cloned_badge->notification
);
124 public function test_badge_status() {
125 $badge = new badge($this->badgeid
);
126 $old_status = $badge->status
;
127 $badge->set_status(BADGE_STATUS_ACTIVE
);
128 $this->assertAttributeNotEquals($old_status, 'status', $badge);
129 $this->assertAttributeEquals(BADGE_STATUS_ACTIVE
, 'status', $badge);
132 public function test_delete_badge() {
133 $badge = new badge($this->badgeid
);
135 // We don't actually delete badges. We archive them.
136 $this->assertAttributeEquals(BADGE_STATUS_ARCHIVED
, 'status', $badge);
139 public function test_create_badge_criteria() {
140 $badge = new badge($this->badgeid
);
141 $criteria_overall = award_criteria
::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL
, 'badgeid' => $badge->id
));
142 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL
));
144 $this->assertCount(1, $badge->get_criteria());
146 $criteria_profile = award_criteria
::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE
, 'badgeid' => $badge->id
));
147 $params = array('agg' => BADGE_CRITERIA_AGGREGATION_ALL
, 'field_address' => 'address');
148 $criteria_profile->save($params);
150 $this->assertCount(2, $badge->get_criteria());
153 public function test_delete_badge_criteria() {
154 $criteria_overall = award_criteria
::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL
, 'badgeid' => $this->badgeid
));
155 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL
));
156 $badge = new badge($this->badgeid
);
158 $this->assertInstanceOf('award_criteria_overall', $badge->criteria
[BADGE_CRITERIA_TYPE_OVERALL
]);
160 $badge->criteria
[BADGE_CRITERIA_TYPE_OVERALL
]->delete();
161 $this->assertEmpty($badge->get_criteria());
164 public function test_badge_awards() {
165 $badge = new badge($this->badgeid
);
166 $user1 = $this->getDataGenerator()->create_user();
168 $badge->issue($user1->id
, true);
169 $this->assertTrue($badge->is_issued($user1->id
));
171 $user2 = $this->getDataGenerator()->create_user();
172 $badge->issue($user2->id
, true);
173 $this->assertTrue($badge->is_issued($user2->id
));
175 $this->assertCount(2, $badge->get_awards());
178 public function data_for_message_from_template() {
181 'This is a message with no variables',
182 array(), // no params
183 'This is a message with no variables'
186 'This is a message with %amissing% variables',
187 array(), // no params
188 'This is a message with %amissing% variables'
191 'This is a message with %one% variable',
192 array('one' => 'a single'),
193 'This is a message with a single variable'
196 'This is a message with %one% %two% %three% variables',
197 array('one' => 'more', 'two' => 'than', 'three' => 'one'),
198 'This is a message with more than one variables'
201 'This is a message with %three% %two% %one%',
202 array('one' => 'variables', 'two' => 'ordered', 'three' => 'randomly'),
203 'This is a message with randomly ordered variables'
206 'This is a message with %repeated% %one% %repeated% of variables',
207 array('one' => 'and', 'repeated' => 'lots'),
208 'This is a message with lots and lots of variables'
214 * @dataProvider data_for_message_from_template
216 public function test_badge_message_from_template($message, $params, $result) {
217 $this->assertEquals(badge_message_from_template($message, $params), $result);
221 * Test badges observer when course module completion event id fired.
223 public function test_badges_observer_course_module_criteria_review() {
224 $badge = new badge($this->coursebadge
);
225 $this->assertFalse($badge->is_issued($this->user
->id
));
227 $criteria_overall = award_criteria
::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL
, 'badgeid' => $badge->id
));
228 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY
));
229 $criteria_overall = award_criteria
::build(array('criteriatype' => BADGE_CRITERIA_TYPE_ACTIVITY
, 'badgeid' => $badge->id
));
230 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY
, 'module_'.$this->module
->id
=> $this->module
->id
));
232 // Set completion for forum activity.
233 $c = new completion_info($this->course
);
234 $activities = $c->get_activities();
235 $this->assertEquals(1, count($activities));
236 $this->assertTrue(isset($activities[$this->module
->cmid
]));
237 $this->assertEquals($activities[$this->module
->cmid
]->name
, $this->module
->name
);
239 $current = $c->get_data($activities[$this->module
->cmid
], false, $this->user
->id
);
240 $current->completionstate
= COMPLETION_COMPLETE
;
241 $current->timemodified
= time();
242 $c->internal_set_data($activities[$this->module
->cmid
], $current);
244 // Check if badge is awarded.
245 $this->assertDebuggingCalled('Error baking badge image!');
246 $this->assertTrue($badge->is_issued($this->user
->id
));
250 * Test badges observer when course_completed event is fired.
252 public function test_badges_observer_course_criteria_review() {
253 $badge = new badge($this->coursebadge
);
254 $this->assertFalse($badge->is_issued($this->user
->id
));
256 $criteria_overall = award_criteria
::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL
, 'badgeid' => $badge->id
));
257 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY
));
258 $criteria_overall1 = award_criteria
::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COURSE
, 'badgeid' => $badge->id
));
259 $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY
, 'course_'.$this->course
->id
=> $this->course
->id
));
261 $ccompletion = new completion_completion(array('course' => $this->course
->id
, 'userid' => $this->user
->id
));
263 // Mark course as complete.
264 $ccompletion->mark_complete();
266 // Check if badge is awarded.
267 $this->assertDebuggingCalled('Error baking badge image!');
268 $this->assertTrue($badge->is_issued($this->user
->id
));
272 * Test badges observer when user_updated event is fired.
274 public function test_badges_observer_profile_criteria_review() {
275 $badge = new badge($this->coursebadge
);
276 $this->assertFalse($badge->is_issued($this->user
->id
));
278 $criteria_overall = award_criteria
::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL
, 'badgeid' => $badge->id
));
279 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY
));
280 $criteria_overall1 = award_criteria
::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE
, 'badgeid' => $badge->id
));
281 $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL
, 'field_address' => 'address'));
283 $this->user
->address
= 'Test address';
284 user_update_user($this->user
, false);
285 // Check if badge is awarded.
286 $this->assertDebuggingCalled('Error baking badge image!');
287 $this->assertTrue($badge->is_issued($this->user
->id
));
291 * Test badges assertion generated when a badge is issued.
293 public function test_badges_assertion() {
294 $badge = new badge($this->coursebadge
);
295 $this->assertFalse($badge->is_issued($this->user
->id
));
297 $criteria_overall = award_criteria
::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL
, 'badgeid' => $badge->id
));
298 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY
));
299 $criteria_overall1 = award_criteria
::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE
, 'badgeid' => $badge->id
));
300 $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL
, 'field_address' => 'address'));
302 $this->user
->address
= 'Test address';
303 user_update_user($this->user
, false);
304 // Check if badge is awarded.
305 $this->assertDebuggingCalled('Error baking badge image!');
306 $awards = $badge->get_awards();
307 $this->assertCount(1, $awards);
310 $award = reset($awards);
311 $assertion = new core_badges_assertion($award->uniquehash
);
312 $testassertion = $this->assertion
;
314 // Make sure JSON strings have the same structure.
315 $this->assertStringMatchesFormat($testassertion->badge
, json_encode($assertion->get_badge_assertion()));
316 $this->assertStringMatchesFormat($testassertion->class, json_encode($assertion->get_badge_class()));
317 $this->assertStringMatchesFormat($testassertion->issuer
, json_encode($assertion->get_issuer()));