Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Unit tests for badges 19 * 20 * @package core 21 * @subpackage 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> 25 */ 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 global $CFG; 30 require_once($CFG->libdir . '/badgeslib.php'); 31 require_once($CFG->dirroot . '/badges/lib.php'); 32 33 use core_badges\helper; 34 use core\task\manager; 35 36 class badgeslib_test extends advanced_testcase { 37 protected $badgeid; 38 protected $course; 39 protected $user; 40 protected $module; 41 protected $coursebadge; 42 protected $assertion; 43 44 /** @var $assertion2 to define json format for Open badge version 2 */ 45 protected $assertion2; 46 47 protected function setUp(): void { 48 global $DB, $CFG; 49 $this->resetAfterTest(true); 50 $CFG->enablecompletion = true; 51 $user = $this->getDataGenerator()->create_user(); 52 $fordb = new stdClass(); 53 $fordb->id = null; 54 $fordb->name = "Test badge with 'apostrophe' and other friends (<>&@#)"; 55 $fordb->description = "Testing badges"; 56 $fordb->timecreated = time(); 57 $fordb->timemodified = time(); 58 $fordb->usercreated = $user->id; 59 $fordb->usermodified = $user->id; 60 $fordb->issuername = "Test issuer"; 61 $fordb->issuerurl = "http://issuer-url.domain.co.nz"; 62 $fordb->issuercontact = "issuer@example.com"; 63 $fordb->expiredate = null; 64 $fordb->expireperiod = null; 65 $fordb->type = BADGE_TYPE_SITE; 66 $fordb->version = 1; 67 $fordb->language = 'en'; 68 $fordb->courseid = null; 69 $fordb->messagesubject = "Test message subject"; 70 $fordb->message = "Test message body"; 71 $fordb->attachment = 1; 72 $fordb->notification = 0; 73 $fordb->imageauthorname = "Image Author 1"; 74 $fordb->imageauthoremail = "author@example.com"; 75 $fordb->imageauthorurl = "http://author-url.example.com"; 76 $fordb->imagecaption = "Test caption image"; 77 $fordb->status = BADGE_STATUS_INACTIVE; 78 79 $this->badgeid = $DB->insert_record('badge', $fordb, true); 80 81 // Set the default Issuer (because OBv2 needs them). 82 set_config('badges_defaultissuername', $fordb->issuername); 83 set_config('badges_defaultissuercontact', $fordb->issuercontact); 84 85 // Create a course with activity and auto completion tracking. 86 $this->course = $this->getDataGenerator()->create_course(array('enablecompletion' => true)); 87 $this->user = $this->getDataGenerator()->create_user(); 88 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 89 $this->assertNotEmpty($studentrole); 90 91 // Get manual enrolment plugin and enrol user. 92 require_once($CFG->dirroot.'/enrol/manual/locallib.php'); 93 $manplugin = enrol_get_plugin('manual'); 94 $maninstance = $DB->get_record('enrol', array('courseid' => $this->course->id, 'enrol' => 'manual'), '*', MUST_EXIST); 95 $manplugin->enrol_user($maninstance, $this->user->id, $studentrole->id); 96 $this->assertEquals(1, $DB->count_records('user_enrolments')); 97 $completionauto = array('completion' => COMPLETION_TRACKING_AUTOMATIC); 98 $this->module = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto); 99 100 // Build badge and criteria. 101 $fordb->type = BADGE_TYPE_COURSE; 102 $fordb->courseid = $this->course->id; 103 $fordb->status = BADGE_STATUS_ACTIVE; 104 $this->coursebadge = $DB->insert_record('badge', $fordb, true); 105 106 // Insert Endorsement. 107 $endorsement = new stdClass(); 108 $endorsement->badgeid = $this->coursebadge; 109 $endorsement->issuername = "Issuer 123"; 110 $endorsement->issueremail = "issuer123@email.com"; 111 $endorsement->issuerurl = "https://example.org/issuer-123"; 112 $endorsement->dateissued = 1524567747; 113 $endorsement->claimid = "https://example.org/robotics-badge.json"; 114 $endorsement->claimcomment = "Test endorser comment"; 115 $DB->insert_record('badge_endorsement', $endorsement, true); 116 117 // Insert related badges. 118 $badge = new badge($this->coursebadge); 119 $clonedid = $badge->make_clone(); 120 $badgeclone = new badge($clonedid); 121 $badgeclone->status = BADGE_STATUS_ACTIVE; 122 $badgeclone->save(); 123 124 $relatebadge = new stdClass(); 125 $relatebadge->badgeid = $this->coursebadge; 126 $relatebadge->relatedbadgeid = $clonedid; 127 $relatebadge->relatedid = $DB->insert_record('badge_related', $relatebadge, true); 128 129 // Insert a aligment. 130 $alignment = new stdClass(); 131 $alignment->badgeid = $this->coursebadge; 132 $alignment->targetname = 'CCSS.ELA-Literacy.RST.11-12.3'; 133 $alignment->targeturl = 'http://www.corestandards.org/ELA-Literacy/RST/11-12/3'; 134 $alignment->targetdescription = 'Test target description'; 135 $alignment->targetframework = 'CCSS.RST.11-12.3'; 136 $alignment->targetcode = 'CCSS.RST.11-12.3'; 137 $DB->insert_record('badge_alignment', $alignment, true); 138 139 // Insert tags. 140 core_tag_tag::set_item_tags('core_badges', 'badge', $badge->id, $badge->get_context(), ['tag1', 'tag2']); 141 142 $this->assertion = new stdClass(); 143 $this->assertion->badge = '{"uid":"%s","recipient":{"identity":"%s","type":"email","hashed":true,"salt":"%s"},' . 144 '"badge":"%s","verify":{"type":"hosted","url":"%s"},"issuedOn":"%d","evidence":"%s","tags":%s}'; 145 $this->assertion->class = '{"name":"%s","description":"%s","image":"%s","criteria":"%s","issuer":"%s","tags":%s}'; 146 $this->assertion->issuer = '{"name":"%s","url":"%s","email":"%s"}'; 147 // Format JSON-LD for Openbadge specification version 2.0. 148 $this->assertion2 = new stdClass(); 149 $this->assertion2->badge = '{"recipient":{"identity":"%s","type":"email","hashed":true,"salt":"%s"},' . 150 '"badge":{"name":"%s","description":"%s","image":"%s",' . 151 '"criteria":{"id":"%s","narrative":"%s"},"issuer":{"name":"%s","url":"%s","email":"%s",' . 152 '"@context":"https:\/\/w3id.org\/openbadges\/v2","id":"%s","type":"Issuer"},' . 153 '"tags":%s,"@context":"https:\/\/w3id.org\/openbadges\/v2","id":"%s","type":"BadgeClass","version":"%s",' . 154 '"@language":"en","related":[{"id":"%s","version":"%s","@language":"%s"}],"endorsement":"%s",' . 155 '"alignments":[{"targetName":"%s","targetUrl":"%s","targetDescription":"%s","targetFramework":"%s",' . 156 '"targetCode":"%s"}]},"verify":{"type":"hosted","url":"%s"},"issuedOn":"%s","evidence":"%s","tags":%s,' . 157 '"@context":"https:\/\/w3id.org\/openbadges\/v2","type":"Assertion","id":"%s"}'; 158 159 $this->assertion2->class = '{"name":"%s","description":"%s","image":"%s",' . 160 '"criteria":{"id":"%s","narrative":"%s"},"issuer":{"name":"%s","url":"%s","email":"%s",' . 161 '"@context":"https:\/\/w3id.org\/openbadges\/v2","id":"%s","type":"Issuer"},' . 162 '"tags":%s,"@context":"https:\/\/w3id.org\/openbadges\/v2","id":"%s","type":"BadgeClass","version":"%s",' . 163 '"@language":"%s","related":[{"id":"%s","version":"%s","@language":"%s"}],"endorsement":"%s",' . 164 '"alignments":[{"targetName":"%s","targetUrl":"%s","targetDescription":"%s","targetFramework":"%s",' . 165 '"targetCode":"%s"}]}'; 166 $this->assertion2->issuer = '{"name":"%s","url":"%s","email":"%s",' . 167 '"@context":"https:\/\/w3id.org\/openbadges\/v2","id":"%s","type":"Issuer"}'; 168 } 169 170 public function test_create_badge() { 171 $badge = new badge($this->badgeid); 172 173 $this->assertInstanceOf('badge', $badge); 174 $this->assertEquals($this->badgeid, $badge->id); 175 } 176 177 public function test_clone_badge() { 178 $badge = new badge($this->badgeid); 179 $newid = $badge->make_clone(); 180 $clonedbadge = new badge($newid); 181 182 $this->assertEquals($badge->description, $clonedbadge->description); 183 $this->assertEquals($badge->issuercontact, $clonedbadge->issuercontact); 184 $this->assertEquals($badge->issuername, $clonedbadge->issuername); 185 $this->assertEquals($badge->issuercontact, $clonedbadge->issuercontact); 186 $this->assertEquals($badge->issuerurl, $clonedbadge->issuerurl); 187 $this->assertEquals($badge->expiredate, $clonedbadge->expiredate); 188 $this->assertEquals($badge->expireperiod, $clonedbadge->expireperiod); 189 $this->assertEquals($badge->type, $clonedbadge->type); 190 $this->assertEquals($badge->courseid, $clonedbadge->courseid); 191 $this->assertEquals($badge->message, $clonedbadge->message); 192 $this->assertEquals($badge->messagesubject, $clonedbadge->messagesubject); 193 $this->assertEquals($badge->attachment, $clonedbadge->attachment); 194 $this->assertEquals($badge->notification, $clonedbadge->notification); 195 $this->assertEquals($badge->version, $clonedbadge->version); 196 $this->assertEquals($badge->language, $clonedbadge->language); 197 $this->assertEquals($badge->imagecaption, $clonedbadge->imagecaption); 198 $this->assertEquals($badge->imageauthorname, $clonedbadge->imageauthorname); 199 $this->assertEquals($badge->imageauthoremail, $clonedbadge->imageauthoremail); 200 $this->assertEquals($badge->imageauthorurl, $clonedbadge->imageauthorurl); 201 } 202 203 public function test_badge_status() { 204 $badge = new badge($this->badgeid); 205 $old_status = $badge->status; 206 $badge->set_status(BADGE_STATUS_ACTIVE); 207 $this->assertNotEquals($old_status, $badge->status); 208 $this->assertEquals(BADGE_STATUS_ACTIVE, $badge->status); 209 } 210 211 public function test_delete_badge() { 212 $badge = new badge($this->badgeid); 213 $badge->delete(); 214 // We don't actually delete badges. We archive them. 215 $this->assertEquals(BADGE_STATUS_ARCHIVED, $badge->status); 216 } 217 218 /** 219 * Really delete the badge. 220 */ 221 public function test_delete_badge_for_real() { 222 global $DB; 223 224 $badge = new badge($this->badgeid); 225 // Insert tags for the badge. 226 core_tag_tag::set_item_tags('core_badges', 'badge', $badge->id, $badge->get_context(), ['tag1', 'tag2']); 227 228 $newid1 = $badge->make_clone(); 229 $newid2 = $badge->make_clone(); 230 $newid3 = $badge->make_clone(); 231 232 // Insert related badges to badge 1. 233 $badge->add_related_badges([$newid1, $newid2, $newid3]); 234 235 // Another badge. 236 $badge2 = new badge($newid2); 237 // Make badge 1 related for badge 2. 238 $badge2->add_related_badges([$this->badgeid]); 239 240 // Confirm that the records about this badge about its relations have been removed as well. 241 $relatedsql = 'badgeid = :badgeid OR relatedbadgeid = :relatedbadgeid'; 242 $relatedparams = array( 243 'badgeid' => $this->badgeid, 244 'relatedbadgeid' => $this->badgeid 245 ); 246 // Badge 1 has 4 related records. 3 where it's the badgeid, 1 where it's the relatedbadgeid. 247 $this->assertEquals(4, $DB->count_records_select('badge_related', $relatedsql, $relatedparams)); 248 249 // Badge has 2 tag instance records. 250 $this->assertEquals(2, $DB->count_records('tag_instance', ['itemid' => $this->badgeid])); 251 252 // Delete the badge for real. 253 $badge->delete(false); 254 255 // Confirm that the badge itself has been removed. 256 $this->assertFalse($DB->record_exists('badge', ['id' => $this->badgeid])); 257 258 // Confirm that the records about this badge about its relations have been removed as well. 259 $this->assertFalse($DB->record_exists_select('badge_related', $relatedsql, $relatedparams)); 260 261 // Confirm that the tag instance of the badge has been removed. 262 $this->assertFalse($DB->record_exists('tag_instance', ['itemid' => $this->badgeid])); 263 } 264 265 public function test_create_badge_criteria() { 266 $badge = new badge($this->badgeid); 267 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 268 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL)); 269 270 $this->assertCount(1, $badge->get_criteria()); 271 272 $criteria_profile = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $badge->id)); 273 $params = array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address'); 274 $criteria_profile->save($params); 275 276 $this->assertCount(2, $badge->get_criteria()); 277 } 278 279 public function test_add_badge_criteria_description() { 280 $criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $this->badgeid)); 281 $criteriaoverall->save(array( 282 'agg' => BADGE_CRITERIA_AGGREGATION_ALL, 283 'description' => 'Overall description', 284 'descriptionformat' => FORMAT_HTML 285 )); 286 287 $criteriaprofile = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $this->badgeid)); 288 $params = array( 289 'agg' => BADGE_CRITERIA_AGGREGATION_ALL, 290 'field_address' => 'address', 291 'description' => 'Description', 292 'descriptionformat' => FORMAT_HTML 293 ); 294 $criteriaprofile->save($params); 295 296 $badge = new badge($this->badgeid); 297 $this->assertEquals('Overall description', $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->description); 298 $this->assertEquals('Description', $badge->criteria[BADGE_CRITERIA_TYPE_PROFILE]->description); 299 } 300 301 public function test_delete_badge_criteria() { 302 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $this->badgeid)); 303 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL)); 304 $badge = new badge($this->badgeid); 305 306 $this->assertInstanceOf('award_criteria_overall', $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]); 307 308 $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->delete(); 309 $this->assertEmpty($badge->get_criteria()); 310 } 311 312 public function test_badge_awards() { 313 global $DB; 314 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 315 $badge = new badge($this->badgeid); 316 $user1 = $this->getDataGenerator()->create_user(); 317 318 $sink = $this->redirectMessages(); 319 320 $DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email'"); 321 set_user_preference('message_provider_moodle_badgerecipientnotice_enabled', 'email', $user1); 322 323 $badge->issue($user1->id, false); 324 $this->assertDebuggingCalled(); // Expect debugging while baking a badge via phpunit. 325 $this->assertTrue($badge->is_issued($user1->id)); 326 327 $messages = $sink->get_messages(); 328 $sink->close(); 329 $this->assertCount(1, $messages); 330 $message = array_pop($messages); 331 // Check we have the expected data. 332 $customdata = json_decode($message->customdata); 333 $this->assertObjectHasAttribute('notificationiconurl', $customdata); 334 $this->assertObjectHasAttribute('hash', $customdata); 335 336 $user2 = $this->getDataGenerator()->create_user(); 337 $badge->issue($user2->id, true); 338 $this->assertTrue($badge->is_issued($user2->id)); 339 340 $this->assertCount(2, $badge->get_awards()); 341 } 342 343 /** 344 * Test the {@link badges_get_user_badges()} function in lib/badgeslib.php 345 */ 346 public function test_badges_get_user_badges() { 347 global $DB; 348 349 // Messaging is not compatible with transactions. 350 $this->preventResetByRollback(); 351 352 $badges = array(); 353 $user1 = $this->getDataGenerator()->create_user(); 354 $user2 = $this->getDataGenerator()->create_user(); 355 356 // Record the current time, we need to be precise about a couple of things. 357 $now = time(); 358 // Create 11 badges with which to test. 359 for ($i = 1; $i <= 11; $i++) { 360 // Mock up a badge. 361 $badge = new stdClass(); 362 $badge->id = null; 363 $badge->name = "Test badge $i"; 364 $badge->description = "Testing badges $i"; 365 $badge->timecreated = $now - 12; 366 $badge->timemodified = $now - 12; 367 $badge->usercreated = $user1->id; 368 $badge->usermodified = $user1->id; 369 $badge->issuername = "Test issuer"; 370 $badge->issuerurl = "http://issuer-url.domain.co.nz"; 371 $badge->issuercontact = "issuer@example.com"; 372 $badge->expiredate = null; 373 $badge->expireperiod = null; 374 $badge->type = BADGE_TYPE_SITE; 375 $badge->courseid = null; 376 $badge->messagesubject = "Test message subject for badge $i"; 377 $badge->message = "Test message body for badge $i"; 378 $badge->attachment = 1; 379 $badge->notification = 0; 380 $badge->status = BADGE_STATUS_INACTIVE; 381 $badge->version = "Version $i"; 382 $badge->language = "en"; 383 $badge->imagecaption = "Image caption $i"; 384 $badge->imageauthorname = "Image author's name $i"; 385 $badge->imageauthoremail = "author$i@example.com"; 386 $badge->imageauthorname = "Image author's name $i"; 387 388 $badgeid = $DB->insert_record('badge', $badge, true); 389 $badges[$badgeid] = new badge($badgeid); 390 $badges[$badgeid]->issue($user2->id, true); 391 // Check it all actually worked. 392 $this->assertCount(1, $badges[$badgeid]->get_awards()); 393 394 // Hack the database to adjust the time each badge was issued. 395 // The alternative to this is sleep which is a no-no in unit tests. 396 $DB->set_field('badge_issued', 'dateissued', $now - 11 + $i, array('userid' => $user2->id, 'badgeid' => $badgeid)); 397 } 398 399 // Make sure the first user has no badges. 400 $result = badges_get_user_badges($user1->id); 401 $this->assertIsArray($result); 402 $this->assertCount(0, $result); 403 404 // Check that the second user has the expected 11 badges. 405 $result = badges_get_user_badges($user2->id); 406 $this->assertCount(11, $result); 407 408 // Test pagination. 409 // Ordering is by time issued desc, so things will come out with the last awarded badge first. 410 $result = badges_get_user_badges($user2->id, 0, 0, 4); 411 $this->assertCount(4, $result); 412 $lastbadgeissued = reset($result); 413 $this->assertSame('Test badge 11', $lastbadgeissued->name); 414 // Page 2. Expecting 4 results again. 415 $result = badges_get_user_badges($user2->id, 0, 1, 4); 416 $this->assertCount(4, $result); 417 $lastbadgeissued = reset($result); 418 $this->assertSame('Test badge 7', $lastbadgeissued->name); 419 // Page 3. Expecting just three results here. 420 $result = badges_get_user_badges($user2->id, 0, 2, 4); 421 $this->assertCount(3, $result); 422 $lastbadgeissued = reset($result); 423 $this->assertSame('Test badge 3', $lastbadgeissued->name); 424 // Page 4.... there is no page 4. 425 $result = badges_get_user_badges($user2->id, 0, 3, 4); 426 $this->assertCount(0, $result); 427 428 // Test search. 429 $result = badges_get_user_badges($user2->id, 0, 0, 0, 'badge 1'); 430 $this->assertCount(3, $result); 431 $lastbadgeissued = reset($result); 432 $this->assertSame('Test badge 11', $lastbadgeissued->name); 433 // The term Totara doesn't appear anywhere in the badges. 434 $result = badges_get_user_badges($user2->id, 0, 0, 0, 'Totara'); 435 $this->assertCount(0, $result); 436 437 // Issue a user with a course badge and verify its returned based on if 438 // coursebadges are enabled or disabled. 439 $sitebadgeid = key($badges); 440 $badges[$sitebadgeid]->issue($this->user->id, true); 441 442 $badge = new stdClass(); 443 $badge->id = null; 444 $badge->name = "Test course badge"; 445 $badge->description = "Testing course badge"; 446 $badge->timecreated = $now; 447 $badge->timemodified = $now; 448 $badge->usercreated = $user1->id; 449 $badge->usermodified = $user1->id; 450 $badge->issuername = "Test issuer"; 451 $badge->issuerurl = "http://issuer-url.domain.co.nz"; 452 $badge->issuercontact = "issuer@example.com"; 453 $badge->expiredate = null; 454 $badge->expireperiod = null; 455 $badge->type = BADGE_TYPE_COURSE; 456 $badge->courseid = $this->course->id; 457 $badge->messagesubject = "Test message subject for course badge"; 458 $badge->message = "Test message body for course badge"; 459 $badge->attachment = 1; 460 $badge->notification = 0; 461 $badge->status = BADGE_STATUS_ACTIVE; 462 $badge->version = "Version $i"; 463 $badge->language = "en"; 464 $badge->imagecaption = "Image caption"; 465 $badge->imageauthorname = "Image author's name"; 466 $badge->imageauthoremail = "author@example.com"; 467 $badge->imageauthorname = "Image author's name"; 468 469 $badgeid = $DB->insert_record('badge', $badge, true); 470 $badges[$badgeid] = new badge($badgeid); 471 $badges[$badgeid]->issue($this->user->id, true); 472 473 // With coursebadges off, we should only get the site badge. 474 set_config('badges_allowcoursebadges', false); 475 $result = badges_get_user_badges($this->user->id); 476 $this->assertCount(1, $result); 477 478 // With it on, we should get both. 479 set_config('badges_allowcoursebadges', true); 480 $result = badges_get_user_badges($this->user->id); 481 $this->assertCount(2, $result); 482 483 } 484 485 public function data_for_message_from_template() { 486 return array( 487 array( 488 'This is a message with no variables', 489 array(), // no params 490 'This is a message with no variables' 491 ), 492 array( 493 'This is a message with %amissing% variables', 494 array(), // no params 495 'This is a message with %amissing% variables' 496 ), 497 array( 498 'This is a message with %one% variable', 499 array('one' => 'a single'), 500 'This is a message with a single variable' 501 ), 502 array( 503 'This is a message with %one% %two% %three% variables', 504 array('one' => 'more', 'two' => 'than', 'three' => 'one'), 505 'This is a message with more than one variables' 506 ), 507 array( 508 'This is a message with %three% %two% %one%', 509 array('one' => 'variables', 'two' => 'ordered', 'three' => 'randomly'), 510 'This is a message with randomly ordered variables' 511 ), 512 array( 513 'This is a message with %repeated% %one% %repeated% of variables', 514 array('one' => 'and', 'repeated' => 'lots'), 515 'This is a message with lots and lots of variables' 516 ), 517 ); 518 } 519 520 /** 521 * @dataProvider data_for_message_from_template 522 */ 523 public function test_badge_message_from_template($message, $params, $result) { 524 $this->assertEquals(badge_message_from_template($message, $params), $result); 525 } 526 527 /** 528 * Test for working around the 61 tables join limit of mysql in award_criteria_activity in combination with the scheduled task. 529 * 530 * @covers \core_badges\badge::review_all_criteria 531 */ 532 public function test_badge_activity_criteria_with_a_huge_number_of_coursemodules() { 533 global $CFG; 534 require_once($CFG->dirroot.'/completion/criteria/completion_criteria_activity.php'); 535 536 if (!PHPUNIT_LONGTEST) { 537 $this->markTestSkipped('PHPUNIT_LONGTEST is not defined'); 538 } 539 540 // Messaging is not compatible with transactions. 541 $this->preventResetByRollback(); 542 543 // Create more than 61 modules to potentially trigger an mysql db error. 544 $assigncount = 75; 545 $assigns = []; 546 for ($i = 1; $i <= $assigncount; $i++) { 547 $assigns[] = $this->getDataGenerator()->create_module('assign', ['course' => $this->course->id], ['completion' => 1]); 548 } 549 $assigncmids = array_flip(array_map(fn ($assign) => $assign->cmid, $assigns)); 550 $criteriaactivityarray = array_fill_keys(array_keys($assigncmids), 1); 551 552 // Set completion criteria. 553 $criteriadata = (object) [ 554 'id' => $this->course->id, 555 'criteria_activity' => $criteriaactivityarray, 556 ]; 557 $criterion = new completion_criteria_activity(); 558 $criterion->update_config($criteriadata); 559 560 $badge = new badge($this->coursebadge); 561 562 $criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 563 $criteriaoverall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 564 $criteriaactivity = award_criteria::build(['criteriatype' => BADGE_CRITERIA_TYPE_ACTIVITY, 'badgeid' => $badge->id]); 565 566 $modulescrit = ['agg' => BADGE_CRITERIA_AGGREGATION_ALL]; 567 foreach ($assigns as $assign) { 568 $modulescrit['module_' . $assign->cmid] = $assign->cmid; 569 } 570 $criteriaactivity->save($modulescrit); 571 572 // Take one assign to complete it later. 573 $assigntemp = array_shift($assigns); 574 575 // Mark the user to complete the modules. 576 foreach ($assigns as $assign) { 577 $cmassign = get_coursemodule_from_id('assign', $assign->cmid); 578 $completion = new \completion_info($this->course); 579 $completion->update_state($cmassign, COMPLETION_COMPLETE, $this->user->id); 580 } 581 582 // Run the scheduled task to issue the badge. But the badge should not be issued. 583 ob_start(); 584 $task = manager::get_scheduled_task('core\task\badges_cron_task'); 585 $task->execute(); 586 ob_end_clean(); 587 588 $this->assertFalse($badge->is_issued($this->user->id)); 589 590 // Now complete the last uncompleted module. 591 $cmassign = get_coursemodule_from_id('assign', $assigntemp->cmid); 592 $completion = new \completion_info($this->course); 593 $completion->update_state($cmassign, COMPLETION_COMPLETE, $this->user->id); 594 595 // Run the scheduled task to issue the badge. Now the badge schould be issued. 596 ob_start(); 597 $task = manager::get_scheduled_task('core\task\badges_cron_task'); 598 $task->execute(); 599 ob_end_clean(); 600 601 $this->assertDebuggingCalled('Error baking badge image!'); 602 $this->assertTrue($badge->is_issued($this->user->id)); 603 } 604 605 /** 606 * Test badges observer when course module completion event id fired. 607 */ 608 public function test_badges_observer_course_module_criteria_review() { 609 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 610 $badge = new badge($this->coursebadge); 611 $this->assertFalse($badge->is_issued($this->user->id)); 612 613 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 614 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 615 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_ACTIVITY, 'badgeid' => $badge->id)); 616 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 'module_'.$this->module->cmid => $this->module->cmid)); 617 618 // Assert the badge will not be issued to the user as is. 619 $badge = new badge($this->coursebadge); 620 $badge->review_all_criteria(); 621 $this->assertFalse($badge->is_issued($this->user->id)); 622 623 // Set completion for forum activity. 624 $c = new completion_info($this->course); 625 $activities = $c->get_activities(); 626 $this->assertEquals(1, count($activities)); 627 $this->assertTrue(isset($activities[$this->module->cmid])); 628 $this->assertEquals($activities[$this->module->cmid]->name, $this->module->name); 629 630 $current = $c->get_data($activities[$this->module->cmid], false, $this->user->id); 631 $current->completionstate = COMPLETION_COMPLETE; 632 $current->timemodified = time(); 633 $sink = $this->redirectEmails(); 634 $c->internal_set_data($activities[$this->module->cmid], $current); 635 $this->assertCount(1, $sink->get_messages()); 636 $sink->close(); 637 638 // Check if badge is awarded. 639 $this->assertDebuggingCalled('Error baking badge image!'); 640 $this->assertTrue($badge->is_issued($this->user->id)); 641 } 642 643 /** 644 * Test badges observer when course_completed event is fired. 645 */ 646 public function test_badges_observer_course_criteria_review() { 647 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 648 $badge = new badge($this->coursebadge); 649 $this->assertFalse($badge->is_issued($this->user->id)); 650 651 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 652 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 653 $criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COURSE, 'badgeid' => $badge->id)); 654 $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 'course_'.$this->course->id => $this->course->id)); 655 656 $ccompletion = new completion_completion(array('course' => $this->course->id, 'userid' => $this->user->id)); 657 658 // Assert the badge will not be issued to the user as is. 659 $badge = new badge($this->coursebadge); 660 $badge->review_all_criteria(); 661 $this->assertFalse($badge->is_issued($this->user->id)); 662 663 // Mark course as complete. 664 $sink = $this->redirectMessages(); 665 $ccompletion->mark_complete(); 666 // Two messages are generated: One for the course completed and the other one for the badge awarded. 667 $messages = $sink->get_messages(); 668 $this->assertCount(2, $messages); 669 $this->assertEquals('badgerecipientnotice', $messages[0]->eventtype); 670 $this->assertEquals('coursecompleted', $messages[1]->eventtype); 671 $sink->close(); 672 673 // Check if badge is awarded. 674 $this->assertDebuggingCalled('Error baking badge image!'); 675 $this->assertTrue($badge->is_issued($this->user->id)); 676 } 677 678 /** 679 * Test badges observer when user_updated event is fired. 680 */ 681 public function test_badges_observer_profile_criteria_review() { 682 global $CFG, $DB; 683 require_once($CFG->dirroot.'/user/profile/lib.php'); 684 685 // Add a custom field of textarea type. 686 $customprofileid = $this->getDataGenerator()->create_custom_profile_field(array( 687 'shortname' => 'newfield', 'name' => 'Description of new field', 688 'datatype' => 'textarea'))->id; 689 690 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 691 $badge = new badge($this->coursebadge); 692 693 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 694 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 695 $criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $badge->id)); 696 $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address', 697 'field_department' => 'department', 'field_' . $customprofileid => $customprofileid)); 698 699 // Assert the badge will not be issued to the user as is. 700 $badge = new badge($this->coursebadge); 701 $badge->review_all_criteria(); 702 $this->assertFalse($badge->is_issued($this->user->id)); 703 704 // Set the required fields and make sure the badge got issued. 705 $this->user->address = 'Test address'; 706 $this->user->department = 'sillywalks'; 707 $sink = $this->redirectEmails(); 708 profile_save_data((object)array('id' => $this->user->id, 'profile_field_newfield' => 'X')); 709 user_update_user($this->user, false); 710 $this->assertCount(1, $sink->get_messages()); 711 $sink->close(); 712 // Check if badge is awarded. 713 $this->assertDebuggingCalled('Error baking badge image!'); 714 $this->assertTrue($badge->is_issued($this->user->id)); 715 } 716 717 /** 718 * Test badges observer when cohort_member_added event is fired and user required to belong to any cohort. 719 * 720 * @covers \award_criteria_cohort 721 */ 722 public function test_badges_observer_any_cohort_criteria_review() { 723 global $CFG; 724 725 require_once("$CFG->dirroot/cohort/lib.php"); 726 727 $cohort1 = $this->getDataGenerator()->create_cohort(); 728 $cohort2 = $this->getDataGenerator()->create_cohort(); 729 730 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 731 732 $badge = new badge($this->badgeid); 733 $this->assertFalse($badge->is_issued($this->user->id)); 734 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 735 736 // Set up the badge criteria. 737 $criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 738 $criteriaoverall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 739 $criteriaoverall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COHORT, 'badgeid' => $badge->id)); 740 $criteriaoverall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 741 'cohort_cohorts' => array('0' => $cohort1->id, '1' => $cohort2->id))); 742 $badge->set_status(BADGE_STATUS_ACTIVE); 743 744 // Reload it to contain criteria. 745 $badge = new badge($this->badgeid); 746 $this->assertFalse($badge->is_issued($this->user->id)); 747 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 748 749 // Add the user to the cohort. 750 cohort_add_member($cohort2->id, $this->user->id); 751 $this->assertDebuggingCalled(); 752 753 // Verify that the badge was awarded. 754 $this->assertTrue($badge->is_issued($this->user->id)); 755 // As the badge has been awarded to user because core_badges_observer been called when the member has been added to the 756 // cohort, there are no other users that can award this badge. 757 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 758 } 759 760 /** 761 * Test badges observer when cohort_member_added event is fired and user required to belong to multiple (all) cohorts. 762 * 763 * @covers \award_criteria_cohort 764 */ 765 public function test_badges_observer_all_cohort_criteria_review() { 766 global $CFG; 767 768 require_once("$CFG->dirroot/cohort/lib.php"); 769 770 $cohort1 = $this->getDataGenerator()->create_cohort(); 771 $cohort2 = $this->getDataGenerator()->create_cohort(); 772 $cohort3 = $this->getDataGenerator()->create_cohort(); 773 774 // Add user2 to cohort1 and cohort3. 775 $user2 = $this->getDataGenerator()->create_user(); 776 cohort_add_member($cohort3->id, $user2->id); 777 cohort_add_member($cohort1->id, $user2->id); 778 779 // Add user3 to cohort1, cohort2 and cohort3. 780 $user3 = $this->getDataGenerator()->create_user(); 781 cohort_add_member($cohort1->id, $user3->id); 782 cohort_add_member($cohort2->id, $user3->id); 783 cohort_add_member($cohort3->id, $user3->id); 784 785 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 786 787 // Cohort criteria are used in site badges. 788 $badge = new badge($this->badgeid); 789 790 $this->assertFalse($badge->is_issued($this->user->id)); 791 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 792 793 // Set up the badge criteria. 794 $criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 795 $criteriaoverall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 796 $criteriaoverall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COHORT, 'badgeid' => $badge->id)); 797 $criteriaoverall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 798 'cohort_cohorts' => array('0' => $cohort1->id, '1' => $cohort2->id, '2' => $cohort3->id))); 799 $badge->set_status(BADGE_STATUS_ACTIVE); 800 801 // Reload it to contain criteria. 802 $badge = new badge($this->badgeid); 803 804 // Verify that the badge was not awarded yet (ALL cohorts are needed and review_all_criteria has to be called). 805 $this->assertFalse($badge->is_issued($this->user->id)); 806 $this->assertFalse($badge->is_issued($user2->id)); 807 $this->assertFalse($badge->is_issued($user3->id)); 808 809 // Verify that after calling review_all_criteria, users with the criteria (user3) award the badge instantly. 810 $this->assertSame(1, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 811 $this->assertFalse($badge->is_issued($this->user->id)); 812 $this->assertFalse($badge->is_issued($user2->id)); 813 $this->assertTrue($badge->is_issued($user3->id)); 814 $this->assertDebuggingCalled(); 815 816 // Add the user to the cohort1. 817 cohort_add_member($cohort1->id, $this->user->id); 818 819 // Verify that the badge was not awarded yet (ALL cohorts are needed). 820 $this->assertFalse($badge->is_issued($this->user->id)); 821 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 822 823 // Add the user to the cohort3. 824 cohort_add_member($cohort3->id, $this->user->id); 825 826 // Verify that the badge was not awarded yet (ALL cohorts are needed). 827 $this->assertFalse($badge->is_issued($this->user->id)); 828 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 829 830 // Add user to cohort2. 831 cohort_add_member($cohort2->id, $this->user->id); 832 $this->assertDebuggingCalled(); 833 834 // Verify that the badge was awarded (ALL cohorts). 835 $this->assertTrue($badge->is_issued($this->user->id)); 836 // As the badge has been awarded to user because core_badges_observer been called when the member has been added to the 837 // cohort, there are no other users that can award this badge. 838 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 839 } 840 841 /** 842 * Test badges assertion generated when a badge is issued. 843 */ 844 public function test_badges_assertion() { 845 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 846 $badge = new badge($this->coursebadge); 847 $this->assertFalse($badge->is_issued($this->user->id)); 848 849 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 850 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 851 $criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $badge->id)); 852 $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address')); 853 854 $this->user->address = 'Test address'; 855 $sink = $this->redirectEmails(); 856 user_update_user($this->user, false); 857 $this->assertCount(1, $sink->get_messages()); 858 $sink->close(); 859 // Check if badge is awarded. 860 $this->assertDebuggingCalled('Error baking badge image!'); 861 $awards = $badge->get_awards(); 862 $this->assertCount(1, $awards); 863 864 // Get assertion. 865 $award = reset($awards); 866 $assertion = new core_badges_assertion($award->uniquehash, OPEN_BADGES_V1); 867 $testassertion = $this->assertion; 868 869 // Make sure JSON strings have the same structure. 870 $this->assertStringMatchesFormat($testassertion->badge, json_encode($assertion->get_badge_assertion())); 871 $this->assertStringMatchesFormat($testassertion->class, json_encode($assertion->get_badge_class())); 872 $this->assertStringMatchesFormat($testassertion->issuer, json_encode($assertion->get_issuer())); 873 874 // Test Openbadge specification version 2. 875 // Get assertion version 2. 876 $award = reset($awards); 877 $assertion2 = new core_badges_assertion($award->uniquehash, OPEN_BADGES_V2); 878 $testassertion2 = $this->assertion2; 879 880 // Make sure JSON strings have the same structure. 881 $this->assertStringMatchesFormat($testassertion2->badge, json_encode($assertion2->get_badge_assertion())); 882 $this->assertStringMatchesFormat($testassertion2->class, json_encode($assertion2->get_badge_class())); 883 $this->assertStringMatchesFormat($testassertion2->issuer, json_encode($assertion2->get_issuer())); 884 885 // Test Openbadge specification version 2.1. It has the same format as OBv2.0. 886 // Get assertion version 2.1. 887 $award = reset($awards); 888 $assertion2 = new core_badges_assertion($award->uniquehash, OPEN_BADGES_V2P1); 889 890 // Make sure JSON strings have the same structure. 891 $this->assertStringMatchesFormat($testassertion2->badge, json_encode($assertion2->get_badge_assertion())); 892 $this->assertStringMatchesFormat($testassertion2->class, json_encode($assertion2->get_badge_class())); 893 $this->assertStringMatchesFormat($testassertion2->issuer, json_encode($assertion2->get_issuer())); 894 } 895 896 /** 897 * Tests the core_badges_myprofile_navigation() function. 898 */ 899 public function test_core_badges_myprofile_navigation() { 900 // Set up the test. 901 $tree = new \core_user\output\myprofile\tree(); 902 $this->setAdminUser(); 903 $badge = new badge($this->badgeid); 904 $badge->issue($this->user->id, true); 905 $iscurrentuser = true; 906 $course = null; 907 908 // Enable badges. 909 set_config('enablebadges', true); 910 911 // Check the node tree is correct. 912 core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $course); 913 $reflector = new ReflectionObject($tree); 914 $nodes = $reflector->getProperty('nodes'); 915 $nodes->setAccessible(true); 916 $this->assertArrayHasKey('localbadges', $nodes->getValue($tree)); 917 } 918 919 /** 920 * Tests the core_badges_myprofile_navigation() function with badges disabled.. 921 */ 922 public function test_core_badges_myprofile_navigation_badges_disabled() { 923 // Set up the test. 924 $tree = new \core_user\output\myprofile\tree(); 925 $this->setAdminUser(); 926 $badge = new badge($this->badgeid); 927 $badge->issue($this->user->id, true); 928 $iscurrentuser = false; 929 $course = null; 930 931 // Disable badges. 932 set_config('enablebadges', false); 933 934 // Check the node tree is correct. 935 core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $course); 936 $reflector = new ReflectionObject($tree); 937 $nodes = $reflector->getProperty('nodes'); 938 $nodes->setAccessible(true); 939 $this->assertArrayNotHasKey('localbadges', $nodes->getValue($tree)); 940 } 941 942 /** 943 * Tests the core_badges_myprofile_navigation() function with a course badge. 944 */ 945 public function test_core_badges_myprofile_navigation_with_course_badge() { 946 // Set up the test. 947 $tree = new \core_user\output\myprofile\tree(); 948 $this->setAdminUser(); 949 $badge = new badge($this->coursebadge); 950 $badge->issue($this->user->id, true); 951 $iscurrentuser = false; 952 953 // Check the node tree is correct. 954 core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $this->course); 955 $reflector = new ReflectionObject($tree); 956 $nodes = $reflector->getProperty('nodes'); 957 $nodes->setAccessible(true); 958 $this->assertArrayHasKey('localbadges', $nodes->getValue($tree)); 959 } 960 961 /** 962 * Test insert and update endorsement with a site badge. 963 */ 964 public function test_badge_endorsement() { 965 $badge = new badge($this->badgeid); 966 967 // Insert Endorsement. 968 $endorsement = new stdClass(); 969 $endorsement->badgeid = $this->badgeid; 970 $endorsement->issuername = "Issuer 123"; 971 $endorsement->issueremail = "issuer123@email.com"; 972 $endorsement->issuerurl = "https://example.org/issuer-123"; 973 $endorsement->dateissued = 1524567747; 974 $endorsement->claimid = "https://example.org/robotics-badge.json"; 975 $endorsement->claimcomment = "Test endorser comment"; 976 977 $badge->save_endorsement($endorsement); 978 $endorsement1 = $badge->get_endorsement(); 979 $this->assertEquals($endorsement->badgeid, $endorsement1->badgeid); 980 $this->assertEquals($endorsement->issuername, $endorsement1->issuername); 981 $this->assertEquals($endorsement->issueremail, $endorsement1->issueremail); 982 $this->assertEquals($endorsement->issuerurl, $endorsement1->issuerurl); 983 $this->assertEquals($endorsement->dateissued, $endorsement1->dateissued); 984 $this->assertEquals($endorsement->claimid, $endorsement1->claimid); 985 $this->assertEquals($endorsement->claimcomment, $endorsement1->claimcomment); 986 987 // Update Endorsement. 988 $endorsement1->issuername = "Issuer update"; 989 $badge->save_endorsement($endorsement1); 990 $endorsement2 = $badge->get_endorsement(); 991 $this->assertEquals($endorsement1->id, $endorsement2->id); 992 $this->assertEquals($endorsement1->issuername, $endorsement2->issuername); 993 } 994 995 /** 996 * Test insert and delete related badge with a site badge. 997 */ 998 public function test_badge_related() { 999 $badge = new badge($this->badgeid); 1000 $newid1 = $badge->make_clone(); 1001 $newid2 = $badge->make_clone(); 1002 $newid3 = $badge->make_clone(); 1003 1004 // Insert an related badge. 1005 $badge->add_related_badges([$newid1, $newid2, $newid3]); 1006 $this->assertCount(3, $badge->get_related_badges()); 1007 1008 // Only get related is active. 1009 $clonedbage1 = new badge($newid1); 1010 $clonedbage1->status = BADGE_STATUS_ACTIVE; 1011 $clonedbage1->save(); 1012 $this->assertCount(1, $badge->get_related_badges(true)); 1013 1014 // Delete an related badge. 1015 $badge->delete_related_badge($newid2); 1016 $this->assertCount(2, $badge->get_related_badges()); 1017 } 1018 1019 /** 1020 * Test insert, update, delete alignment with a site badge. 1021 */ 1022 public function test_alignments() { 1023 $badge = new badge($this->badgeid); 1024 1025 // Insert a alignment. 1026 $alignment1 = new stdClass(); 1027 $alignment1->badgeid = $this->badgeid; 1028 $alignment1->targetname = 'CCSS.ELA-Literacy.RST.11-12.3'; 1029 $alignment1->targeturl = 'http://www.corestandards.org/ELA-Literacy/RST/11-12/3'; 1030 $alignment1->targetdescription = 'Test target description'; 1031 $alignment1->targetframework = 'CCSS.RST.11-12.3'; 1032 $alignment1->targetcode = 'CCSS.RST.11-12.3'; 1033 $alignment2 = clone $alignment1; 1034 $newid1 = $badge->save_alignment($alignment1); 1035 $newid2 = $badge->save_alignment($alignment2); 1036 $alignments1 = $badge->get_alignments(); 1037 $this->assertCount(2, $alignments1); 1038 1039 $this->assertEquals($alignment1->badgeid, $alignments1[$newid1]->badgeid); 1040 $this->assertEquals($alignment1->targetname, $alignments1[$newid1]->targetname); 1041 $this->assertEquals($alignment1->targeturl, $alignments1[$newid1]->targeturl); 1042 $this->assertEquals($alignment1->targetdescription, $alignments1[$newid1]->targetdescription); 1043 $this->assertEquals($alignment1->targetframework, $alignments1[$newid1]->targetframework); 1044 $this->assertEquals($alignment1->targetcode, $alignments1[$newid1]->targetcode); 1045 1046 // Update aligment. 1047 $alignments1[$newid1]->targetname = 'CCSS.ELA-Literacy.RST.11-12.3 update'; 1048 $badge->save_alignment($alignments1[$newid1], $alignments1[$newid1]->id); 1049 $alignments2 = $badge->get_alignments(); 1050 $this->assertEquals($alignments1[$newid1]->id, $alignments2[$newid1]->id); 1051 $this->assertEquals($alignments1[$newid1]->targetname, $alignments2[$newid1]->targetname); 1052 1053 // Delete alignment. 1054 $badge->delete_alignment($alignments1[$newid2]->id); 1055 $this->assertCount(1, $badge->get_alignments()); 1056 } 1057 1058 /** 1059 * Test badges_delete_site_backpack(). 1060 * 1061 */ 1062 public function test_badges_delete_site_backpack(): void { 1063 global $DB; 1064 1065 $this->setAdminUser(); 1066 1067 // Create one backpack. 1068 $total = $DB->count_records('badge_external_backpack'); 1069 $this->assertEquals(1, $total); 1070 1071 $data = new \stdClass(); 1072 $data->apiversion = OPEN_BADGES_V2P1; 1073 $data->backpackapiurl = 'https://dc.imsglobal.org/obchost/ims/ob/v2p1'; 1074 $data->backpackweburl = 'https://dc.imsglobal.org'; 1075 badges_create_site_backpack($data); 1076 $backpack = $DB->get_record('badge_external_backpack', ['backpackweburl' => $data->backpackweburl]); 1077 $user1 = $this->getDataGenerator()->create_user(); 1078 $user2 = $this->getDataGenerator()->create_user(); 1079 // User1 is connected to the backpack to be removed and has 2 collections. 1080 $backpackuser1 = helper::create_fake_backpack(['userid' => $user1->id, 'externalbackpackid' => $backpack->id]); 1081 helper::create_fake_backpack_collection(['backpackid' => $backpackuser1->id]); 1082 helper::create_fake_backpack_collection(['backpackid' => $backpackuser1->id]); 1083 // User2 is connected to a different backpack and has 1 collection. 1084 $backpackuser2 = helper::create_fake_backpack(['userid' => $user2->id]); 1085 helper::create_fake_backpack_collection(['backpackid' => $backpackuser2->id]); 1086 1087 $total = $DB->count_records('badge_external_backpack'); 1088 $this->assertEquals(2, $total); 1089 $total = $DB->count_records('badge_backpack'); 1090 $this->assertEquals(2, $total); 1091 $total = $DB->count_records('badge_external'); 1092 $this->assertEquals(3, $total); 1093 1094 // Remove the backpack created previously. 1095 $result = badges_delete_site_backpack($backpack->id); 1096 $this->assertTrue($result); 1097 1098 $total = $DB->count_records('badge_external_backpack'); 1099 $this->assertEquals(1, $total); 1100 1101 $total = $DB->count_records('badge_backpack'); 1102 $this->assertEquals(1, $total); 1103 1104 $total = $DB->count_records('badge_external'); 1105 $this->assertEquals(1, $total); 1106 1107 // Try to remove an non-existent backpack. 1108 $result = badges_delete_site_backpack($backpack->id); 1109 $this->assertFalse($result); 1110 } 1111 1112 /** 1113 * Test to validate badges_save_backpack_credentials. 1114 * 1115 * @dataProvider save_backpack_credentials_provider 1116 * @param bool $addbackpack True if backpack data has to be created; false otherwise (empty data will be used then). 1117 * @param string|null $mail Backpack mail address. 1118 * @param string|null $password Backpack password. 1119 */ 1120 public function test_save_backpack_credentials(bool $addbackpack = true, ?string $mail = null, ?string $password = null) { 1121 global $DB; 1122 1123 $this->resetAfterTest(); 1124 $this->setAdminUser(); 1125 1126 $data = []; 1127 if ($addbackpack) { 1128 $data = new \stdClass(); 1129 $data->apiversion = OPEN_BADGES_V2P1; 1130 $data->backpackapiurl = 'https://dc.imsglobal.org/obchost/ims/ob/v2p1'; 1131 $data->backpackweburl = 'https://dc.imsglobal.org'; 1132 badges_create_site_backpack($data); 1133 $backpack = $DB->get_record('badge_external_backpack', ['backpackweburl' => $data->backpackweburl]); 1134 $user = $this->getDataGenerator()->create_user(); 1135 1136 $data = [ 1137 'externalbackpackid' => $backpack->id, 1138 'userid' => $user->id, 1139 ]; 1140 1141 if (!empty($mail)) { 1142 $data['backpackemail'] = $mail; 1143 } 1144 if (!empty($password)) { 1145 $data['password'] = $password; 1146 } 1147 } 1148 1149 $return = badges_save_backpack_credentials((object) $data); 1150 if (array_key_exists('userid', $data)) { 1151 $record = $DB->get_record('badge_backpack', ['userid' => $user->id]); 1152 } else { 1153 $record = $DB->get_records('badge_backpack'); 1154 } 1155 1156 if (!empty($mail) && !empty($password)) { 1157 // The backpack credentials are created if the given information is right. 1158 $this->assertNotEmpty($record); 1159 $this->assertEquals($data['externalbackpackid'], $return); 1160 } else if ($addbackpack) { 1161 // If no email and password are given, no backpack is created/modified. 1162 $this->assertEmpty($record); 1163 $this->assertEquals($data['externalbackpackid'], $return); 1164 } else { 1165 // There weren't fields to add to the backpack so no DB change is expected. 1166 $this->assertEmpty($record); 1167 $this->assertEquals(0, $return); 1168 } 1169 1170 // Confirm the existing backpack credential can be updated (if it has been created). 1171 if (!empty($record)) { 1172 $data['backpackemail'] = 'modified_' . $mail; 1173 $data['id'] = $record->id; 1174 $return = badges_save_backpack_credentials((object) $data); 1175 $record = $DB->get_record('badge_backpack', ['userid' => $user->id]); 1176 1177 $this->assertNotEmpty($record); 1178 $this->assertEquals($data['backpackemail'], $record->email); 1179 $this->assertEquals($data['externalbackpackid'], $return); 1180 } 1181 } 1182 1183 /** 1184 * Data provider for test_create_backpack_credentials(). 1185 * 1186 * @return array 1187 */ 1188 public function save_backpack_credentials_provider(): array { 1189 return [ 1190 'Empty fields' => [ 1191 false, 1192 ], 1193 'No backpack mail or password are defined' => [ 1194 true, 1195 ], 1196 'Both backpack mail and password are defined' => [ 1197 true, 'test@test.com', '1234', 1198 ], 1199 'Only backpack mail is defined (no password is given)' => [ 1200 true, 'test@test.com', null, 1201 ], 1202 'Only backpack password is defined (no mail is given)' => [ 1203 true, null, '1234' 1204 ], 1205 ]; 1206 } 1207 1208 /** 1209 * Test badges_save_external_backpack. 1210 * 1211 * @dataProvider badges_save_external_backpack_provider 1212 * @param array $data Backpack data to save. 1213 * @param bool $adduser True if a real user has to be used for creating the backpack; false otherwise. 1214 * @param bool $duplicates True if duplicates has to be tested too; false otherwise. 1215 */ 1216 public function test_badges_save_external_backpack(array $data, bool $adduser, bool $duplicates) { 1217 global $DB; 1218 1219 $this->resetAfterTest(); 1220 1221 $userid = 0; 1222 if ($adduser) { 1223 $user = $this->getDataGenerator()->create_user(); 1224 $userid = $user->id; 1225 $data['userid'] = $user->id; 1226 } 1227 1228 $result = badges_save_external_backpack((object) $data); 1229 $this->assertNotEquals(0, $result); 1230 $record = $DB->get_record('badge_external_backpack', ['id' => $result]); 1231 $this->assertEquals($record->backpackweburl, $data['backpackweburl']); 1232 $this->assertEquals($record->backpackapiurl, $data['backpackapiurl']); 1233 1234 $record = $DB->get_record('badge_backpack', ['externalbackpackid' => $result]); 1235 if (!array_key_exists('backpackemail', $data) && !array_key_exists('password', $data)) { 1236 $this->assertEmpty($record); 1237 $total = $DB->count_records('badge_backpack'); 1238 $this->assertEquals(0, $total); 1239 } else { 1240 $this->assertNotEmpty($record); 1241 $this->assertEquals($record->userid, $userid); 1242 } 1243 1244 if ($duplicates) { 1245 // We shouldn't be able to insert multiple external_backpacks with the same values. 1246 $this->expectException('dml_write_exception'); 1247 $result = badges_save_external_backpack((object)$data); 1248 } 1249 } 1250 1251 /** 1252 * Provider for test_badges_save_external_backpack 1253 * 1254 * @return array 1255 */ 1256 public function badges_save_external_backpack_provider() { 1257 $data = [ 1258 'apiversion' => 2, 1259 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1260 'backpackweburl' => 'https://ca.badgr.io', 1261 ]; 1262 return [ 1263 'Test without user and auth details. Check duplicates too' => [ 1264 'data' => $data, 1265 'adduser' => false, 1266 'duplicates' => true, 1267 ], 1268 'Test without user and auth details. No duplicates' => [ 1269 'data' => $data, 1270 'adduser' => false, 1271 'duplicates' => false, 1272 ], 1273 'Test with user and without auth details' => [ 1274 'data' => $data, 1275 'adduser' => true, 1276 'duplicates' => false, 1277 ], 1278 'Test with user and without auth details. Check duplicates too' => [ 1279 'data' => $data, 1280 'adduser' => true, 1281 'duplicates' => true, 1282 ], 1283 'Test with empty backpackemail, password and id' => [ 1284 'data' => array_merge($data, [ 1285 'backpackemail' => '', 1286 'password' => '', 1287 'id' => 0, 1288 ]), 1289 'adduser' => false, 1290 'duplicates' => false, 1291 ], 1292 'Test with empty backpackemail, password and id but with user' => [ 1293 'data' => array_merge($data, [ 1294 'backpackemail' => '', 1295 'password' => '', 1296 'id' => 0, 1297 ]), 1298 'adduser' => true, 1299 'duplicates' => false, 1300 ], 1301 'Test with auth details but without user' => [ 1302 'data' => array_merge($data, [ 1303 'backpackemail' => 'test@test.com', 1304 'password' => 'test', 1305 ]), 1306 'adduser' => false, 1307 'duplicates' => false, 1308 ], 1309 'Test with auth details and user' => [ 1310 'data' => array_merge($data, [ 1311 'backpackemail' => 'test@test.com', 1312 'password' => 'test', 1313 ]), 1314 'adduser' => true, 1315 'duplicates' => false, 1316 ], 1317 ]; 1318 } 1319 1320 /** 1321 * Test backpack creation/update with auth details provided 1322 * 1323 * @param boolean $isadmin 1324 * @param boolean $updatetest 1325 * @dataProvider badges_create_site_backpack_provider 1326 */ 1327 public function test_badges_create_site_backpack($isadmin, $updatetest) { 1328 global $DB; 1329 $this->resetAfterTest(); 1330 1331 $data = [ 1332 'apiversion' => 2, 1333 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1334 'backpackweburl' => 'https://ca.badgr.io', 1335 ]; 1336 1337 $data['backpackemail'] = 'test@test.com'; 1338 $data['password'] = 'test'; 1339 if ($isadmin || $updatetest) { 1340 $this->setAdminUser(); 1341 $lastmax = $DB->get_field_sql('SELECT MAX(sortorder) FROM {badge_external_backpack}'); 1342 $backpack = badges_create_site_backpack((object) $data); 1343 } 1344 1345 if ($isadmin) { 1346 if ($updatetest) { 1347 $record = $DB->get_record('badge_backpack', ['userid' => 0]); 1348 $data['badgebackpack'] = $record->id; 1349 $data['backpackapiurl'] = 'https://api.ca.badgr.io/v3'; 1350 badges_update_site_backpack($backpack, (object)$data); 1351 } 1352 $record = $DB->get_record('badge_external_backpack', ['id' => $backpack]); 1353 $this->assertEquals($data['backpackweburl'], $record->backpackweburl); 1354 $this->assertEquals($data['backpackapiurl'], $record->backpackapiurl); 1355 $this->assertEquals($lastmax + 1, $record->sortorder); 1356 $record = $DB->get_record('badge_backpack', ['userid' => 0]); 1357 $this->assertNotEmpty($record); 1358 } else { 1359 $user = $this->getDataGenerator()->create_user(); 1360 $this->setUser($user); 1361 $this->expectException('required_capability_exception'); 1362 if ($updatetest) { 1363 $result = badges_update_site_backpack($backpack, (object) $data); 1364 } else { 1365 $result = badges_create_site_backpack((object)$data); 1366 } 1367 } 1368 } 1369 1370 /** 1371 * Provider for test_badges_(create/update)_site_backpack 1372 */ 1373 public function badges_create_site_backpack_provider() { 1374 return [ 1375 "Test as admin user - creation test" => [true, true], 1376 "Test as admin user - update test" => [true, false], 1377 "Test as normal user - creation test" => [false, true], 1378 "Test as normal user - update test" => [false, false], 1379 ]; 1380 } 1381 1382 /** 1383 * Test the badges_open_badges_backpack_api with different backpacks 1384 */ 1385 public function test_badges_open_badges_backpack_api() { 1386 $this->resetAfterTest(); 1387 1388 $data = [ 1389 'apiversion' => 2, 1390 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1391 'backpackweburl' => 'https://ca.badgr.io', 1392 'sortorder' => 2, 1393 ]; 1394 1395 // Given a complete set of unique data, a new backpack and auth records should exist in the tables. 1396 $data['backpackemail'] = 'test@test.com'; 1397 $data['password'] = 'test'; 1398 $backpack1 = badges_save_external_backpack((object) $data); 1399 $data['backpackweburl'] = 'https://eu.badgr.io'; 1400 $data['backpackapiurl'] = 'https://api.eu.badgr.io/v2'; 1401 $data['apiversion'] = '2.1'; 1402 $data['sortorder'] = 3; 1403 $backpack2 = badges_save_external_backpack((object) $data); 1404 1405 // Move backpack2 to the first position to set it as primary site backpack. 1406 $this->move_backpack_to_first_position($backpack2); 1407 1408 // The default response should check the default site backpack api version. 1409 $this->assertEquals(2.1, badges_open_badges_backpack_api()); 1410 // Check the api version for the other backpack created. 1411 $this->assertEquals(2, badges_open_badges_backpack_api($backpack1)); 1412 $this->assertEquals(2.1, badges_open_badges_backpack_api($backpack2)); 1413 } 1414 1415 /** 1416 * Test the badges_get_site_backpack function 1417 */ 1418 public function test_badges_get_site_backpack() { 1419 $this->resetAfterTest(); 1420 $user = $this->getDataGenerator()->create_user(); 1421 $data = [ 1422 'apiversion' => '2', 1423 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1424 'backpackweburl' => 'https://ca.badgr.io', 1425 ]; 1426 $backpack1 = badges_save_external_backpack((object) $data); 1427 $data2 = array_merge($data, [ 1428 'backpackapiurl' => 'https://api.eu.badgr.io/v2', 1429 'backpackweburl' => 'https://eu.badgr.io', 1430 'backpackemail' => 'test@test.com', 1431 'password' => 'test', 1432 ]); 1433 $backpack2 = badges_save_external_backpack((object) $data2); 1434 $data3 = array_merge($data2, [ 1435 'userid' => $user->id, 1436 'externalbackpackid' => $backpack2, 1437 'backpackemail' => 'test2@test.com' 1438 ]); 1439 // In the following case, the id returned below equals backpack2. So we aren't storing it. 1440 badges_save_backpack_credentials((object) $data3); 1441 unset($data3['userid']); 1442 1443 // Get a site back based on the id returned from creation and no user id provided. 1444 $this->assertEquals($data, array_intersect($data, (array) badges_get_site_backpack($backpack1))); 1445 $this->assertEquals($data2, array_intersect($data2, (array) badges_get_site_backpack($backpack2))); 1446 $this->assertEquals($data2, array_intersect($data2, (array) badges_get_site_backpack($backpack2, 0))); 1447 $this->assertEquals($data3, array_intersect($data3, (array) badges_get_site_backpack($backpack2, $user->id))); 1448 1449 // Non-existent user backpack should return only configuration details and not auth details. 1450 $userbackpack = badges_get_site_backpack($backpack1, $user->id); 1451 $this->assertNull($userbackpack->badgebackpack); 1452 $this->assertNull($userbackpack->password); 1453 $this->assertNull($userbackpack->backpackemail); 1454 } 1455 1456 /** 1457 * Test the badges_get_user_backpack function 1458 */ 1459 public function test_badges_get_user_backpack() { 1460 $this->resetAfterTest(); 1461 $user = $this->getDataGenerator()->create_user(); 1462 $data = [ 1463 'apiversion' => '2', 1464 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1465 'backpackweburl' => 'https://ca.badgr.io', 1466 ]; 1467 $backpack1 = badges_save_external_backpack((object) $data); 1468 $data2 = array_merge($data, [ 1469 'backpackapiurl' => 'https://api.eu.badgr.io/v2', 1470 'backpackweburl' => 'https://eu.badgr.io', 1471 'backpackemail' => 'test@test.com', 1472 'password' => 'test', 1473 ]); 1474 $backpack2 = badges_save_external_backpack((object) $data2); 1475 $data3 = array_merge($data2, [ 1476 'userid' => $user->id, 1477 'externalbackpackid' => $backpack2, 1478 'backpackemail' => 'test2@test.com' 1479 ]); 1480 // In the following case, the id returned below equals backpack2. So we aren't storing it. 1481 badges_save_backpack_credentials((object) $data3); 1482 unset($data3['userid']); 1483 1484 // Currently logged in as admin. 1485 $this->assertEquals($data2, array_intersect($data2, (array) badges_get_user_backpack())); 1486 $this->assertEquals($data2, array_intersect($data2, (array) badges_get_user_backpack(0))); 1487 $this->assertEquals($data3, array_intersect($data3, (array) badges_get_user_backpack($user->id))); 1488 1489 // Non-existent user backpack should return nothing. 1490 $this->assertFalse(badges_get_user_backpack($backpack1, $user->id)); 1491 1492 // Login as user. 1493 $this->setUser($user); 1494 $this->assertEquals($data3, array_intersect($data3, (array) badges_get_user_backpack())); 1495 } 1496 1497 /** 1498 * Test the badges_get_site_primary_backpack function 1499 * 1500 * @param boolean $withauth Testing with authentication or not. 1501 * @dataProvider badges_get_site_primary_backpack_provider 1502 */ 1503 public function test_badges_get_site_primary_backpack($withauth) { 1504 $data = [ 1505 'apiversion' => '2', 1506 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1507 'backpackweburl' => 'https://ca.badgr.io', 1508 'sortorder' => '2', 1509 ]; 1510 if ($withauth) { 1511 $data = array_merge($data, [ 1512 'backpackemail' => 'test@test.com', 1513 'password' => 'test', 1514 ]); 1515 } 1516 $backpack = badges_save_external_backpack((object) $data); 1517 1518 // Check the backpack created is not the primary one. 1519 $sitebackpack = badges_get_site_primary_backpack(); 1520 $this->assertNotEquals($backpack, $sitebackpack->id); 1521 1522 // Move backpack to the first position to set it as primary site backpack. 1523 $this->move_backpack_to_first_position($backpack); 1524 1525 $sitebackpack = badges_get_site_primary_backpack(); 1526 $this->assertEquals($backpack, $sitebackpack->id); 1527 1528 if ($withauth) { 1529 $this->assertEquals($data, array_intersect($data, (array) $sitebackpack)); 1530 $this->assertEquals($data['password'], $sitebackpack->password); 1531 $this->assertEquals($data['backpackemail'], $sitebackpack->backpackemail); 1532 } else { 1533 $this->assertNull($sitebackpack->badgebackpack); 1534 $this->assertNull($sitebackpack->password); 1535 $this->assertNull($sitebackpack->backpackemail); 1536 } 1537 } 1538 1539 /** 1540 * Test the test_badges_get_site_primary_backpack function. 1541 * 1542 * @return array 1543 */ 1544 public function badges_get_site_primary_backpack_provider() { 1545 return [ 1546 "Test with auth details" => [true], 1547 "Test without auth details" => [false], 1548 ]; 1549 } 1550 1551 /** 1552 * Test badges_change_sortorder_backpacks(). 1553 * 1554 * @dataProvider badges_change_sortorder_backpacks_provider 1555 * @covers ::badges_change_sortorder_backpacks 1556 * 1557 * @param int $backpacktomove Backpack index to move (from 0 to 5). 1558 * @param int $direction Direction to move the backpack. 1559 * @param int|null $expectedsortorder Expected sortorder or null if an exception is expected. 1560 */ 1561 public function test_badges_change_sortorder_backpacks(int $backpacktomove, int $direction, ?int $expectedsortorder): void { 1562 global $DB; 1563 1564 $this->resetAfterTest(); 1565 $this->setAdminUser(); 1566 1567 // Create 5 more backpacks. 1568 for ($i = 0; $i < 5; $i++) { 1569 $data = new \stdClass(); 1570 $data->apiversion = OPEN_BADGES_V2P1; 1571 $data->backpackapiurl = "https://myurl$i.cat/ob/v2p1"; 1572 $data->backpackweburl = "https://myurl$i.cat"; 1573 badges_create_site_backpack($data); 1574 } 1575 1576 // Check there are 6 backpacks (1 pre-existing + 5 news). 1577 $total = $DB->count_records('badge_external_backpack'); 1578 $this->assertEquals(6, $total); 1579 $backpacks = array_values(badges_get_site_backpacks()); 1580 1581 if (is_null($expectedsortorder)) { 1582 $this->expectException('moodle_exception'); 1583 } 1584 1585 // Move the backpack. 1586 badges_change_sortorder_backpacks($backpacks[$backpacktomove]->id, $direction); 1587 1588 if (!is_null($expectedsortorder)) { 1589 $backpack = badges_get_site_backpack($backpacks[$backpacktomove]->id); 1590 $this->assertEquals($expectedsortorder, $backpack->sortorder); 1591 } 1592 } 1593 1594 /** 1595 * Provider for test_badges_change_sortorder_backpacks. 1596 * 1597 * @return array 1598 */ 1599 public function badges_change_sortorder_backpacks_provider(): array { 1600 return [ 1601 "Test up" => [ 1602 'backpacktomove' => 1, 1603 'direction' => BACKPACK_MOVE_UP, 1604 'expectedsortorder' => 1, 1605 ], 1606 "Test down" => [ 1607 'backpacktomove' => 1, 1608 'direction' => BACKPACK_MOVE_DOWN, 1609 'expectedsortorder' => 3, 1610 ], 1611 "Test up the very first element" => [ 1612 'backpacktomove' => 0, 1613 'direction' => BACKPACK_MOVE_UP, 1614 'expectedsortorder' => 1, 1615 ], 1616 "Test down the very last element" => [ 1617 'backpacktomove' => 5, 1618 'direction' => BACKPACK_MOVE_DOWN, 1619 'expectedsortorder' => 6, 1620 ], 1621 "Test with an invalid direction value" => [ 1622 'backpacktomove' => 1, 1623 'direction' => 10, 1624 'expectedsortorder' => null, 1625 ], 1626 ]; 1627 } 1628 1629 /** 1630 * Test the Badgr URL generator function 1631 * 1632 * @param mixed $type Type corresponding to the badge entites 1633 * @param string $expected Expected string result 1634 * @dataProvider badgr_open_url_generator 1635 */ 1636 public function test_badges_generate_badgr_open_url($type, $expected) { 1637 $data = [ 1638 'apiversion' => '2', 1639 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1640 'backpackweburl' => 'https://ca.badgr.io', 1641 'backpackemail' => 'test@test.com', 1642 'password' => 'test', 1643 ]; 1644 $backpack2 = badges_save_external_backpack((object) $data); 1645 $backpack = badges_get_site_backpack($backpack2); 1646 $this->assertEquals($expected, badges_generate_badgr_open_url($backpack, $type, 123455)); 1647 } 1648 1649 /** 1650 * Data provider for test_badges_generate_badgr_open_url 1651 * @return array 1652 */ 1653 public function badgr_open_url_generator() { 1654 return [ 1655 'Badgr Assertion URL test' => [ 1656 OPEN_BADGES_V2_TYPE_ASSERTION, "https://api.ca.badgr.io/public/assertions/123455" 1657 ], 1658 'Badgr Issuer URL test' => [ 1659 OPEN_BADGES_V2_TYPE_ISSUER, "https://api.ca.badgr.io/public/issuers/123455" 1660 ], 1661 'Badgr Badge URL test' => [ 1662 OPEN_BADGES_V2_TYPE_BADGE, "https://api.ca.badgr.io/public/badges/123455" 1663 ] 1664 ]; 1665 } 1666 1667 /** 1668 * Test badges_external_get_mapping function 1669 * 1670 * @param int $internalid The internal id of the mapping 1671 * @param int $externalid The external / remote ref to the mapping 1672 * @param mixed $expected The expected result from the function 1673 * @param string|null $field The field we are passing to the function. Null if we don't want to pass anything.ss 1674 * 1675 * @dataProvider badges_external_get_mapping_provider 1676 */ 1677 public function test_badges_external_get_mapping($internalid, $externalid, $expected, $field = null) { 1678 $data = [ 1679 'apiversion' => '2', 1680 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1681 'backpackweburl' => 'https://ca.badgr.io', 1682 'backpackemail' => 'test@test.com', 1683 'password' => 'test', 1684 ]; 1685 $backpack2 = badges_save_external_backpack((object) $data); 1686 badges_external_create_mapping($backpack2, OPEN_BADGES_V2_TYPE_BADGE, $internalid, $externalid); 1687 $expected = $expected == "id" ? $backpack2 : $expected; 1688 if ($field) { 1689 $this->assertEquals($expected, badges_external_get_mapping($backpack2, OPEN_BADGES_V2_TYPE_BADGE, $internalid, $field)); 1690 } else { 1691 $this->assertEquals($expected, badges_external_get_mapping($backpack2, OPEN_BADGES_V2_TYPE_BADGE, $internalid)); 1692 } 1693 } 1694 1695 /** 1696 * Data provider for badges_external_get_mapping_provider 1697 * 1698 * @return array 1699 */ 1700 public function badges_external_get_mapping_provider() { 1701 return [ 1702 "Get the site backpack value" => [ 1703 1234, 4321, 'id', 'sitebackpackid' 1704 ], 1705 "Get the type of the mapping" => [ 1706 1234, 4321, OPEN_BADGES_V2_TYPE_BADGE, 'type' 1707 ], 1708 "Get the externalid of the mapping" => [ 1709 1234, 4321, 4321, 'externalid' 1710 ], 1711 "Get the externalid of the mapping without providing a param" => [ 1712 1234, 4321, 4321, null 1713 ], 1714 "Get the internalid of the mapping" => [ 1715 1234, 4321, 1234, 'internalid' 1716 ] 1717 ]; 1718 } 1719 1720 /** 1721 * Move the backpack to the first position, to set it as primary site backpack. 1722 * 1723 * @param int $backpackid The backpack identifier. 1724 */ 1725 private function move_backpack_to_first_position(int $backpackid): void { 1726 $backpack = badges_get_site_backpack($backpackid); 1727 while ($backpack->sortorder > 1) { 1728 badges_change_sortorder_backpacks($backpackid, BACKPACK_MOVE_UP); 1729 $backpack = badges_get_site_backpack($backpackid); 1730 } 1731 } 1732 1733 /** 1734 * Testing function test_badge_get_tagged_badges - search tagged badges 1735 * 1736 * @covers ::badge_get_tagged_badges 1737 */ 1738 public function test_badge_get_tagged_badges() { 1739 $this->resetAfterTest(); 1740 $this->setAdminUser(); 1741 1742 // Setup test data. 1743 $badge = new badge($this->coursebadge); 1744 \core_tag_tag::set_item_tags('core_badges', 'badge', $this->badgeid, $badge->get_context(), 1745 ['Cats', 'Dogs']); 1746 1747 $tag = \core_tag_tag::get_by_name(0, 'Cats'); 1748 1749 $res = badge_get_tagged_badges($tag, false, 0, 0, 1, 0); 1750 $this->assertStringContainsString("Test badge with 'apostrophe' and other friends (<>&@#)", $res->content); 1751 } 1752 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body