See Release Notes
Long Term Support Release
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 the core_rating implementation of the Privacy API. 19 * 20 * @package core_rating 21 * @category test 22 * @copyright 2018 Andrew Nicols <andrew@nicols.co.uk> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 global $CFG; 29 require_once($CFG->dirroot . '/rating/lib.php'); 30 31 use \core_rating\privacy\provider; 32 use \core_privacy\local\request\writer; 33 34 /** 35 * Unit tests for the core_rating implementation of the Privacy API. 36 * 37 * @copyright 2018 Andrew Nicols <andrew@nicols.co.uk> 38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 */ 40 class core_rating_privacy_testcase extends \core_privacy\tests\provider_testcase { 41 42 /** 43 * Rate something as a user. 44 * 45 * @param int $userid 46 * @param string $component 47 * @param string $ratingarea 48 * @param int $itemid 49 * @param \context $context 50 * @param string $score 51 */ 52 protected function rate_as_user($userid, $component, $ratingarea, $itemid, $context, $score) { 53 // Rate the courses. 54 $rm = new rating_manager(); 55 $ratingoptions = (object) [ 56 'component' => $component, 57 'ratingarea' => $ratingarea, 58 'scaleid' => 100, 59 ]; 60 61 // Rate all courses as u1, and the course category too.. 62 $ratingoptions->itemid = $itemid; 63 $ratingoptions->userid = $userid; 64 $ratingoptions->context = $context; 65 $rating = new \rating($ratingoptions); 66 $rating->update_rating($score); 67 } 68 69 /** 70 * Ensure that the get_sql_join function returns valid SQL which returns the correct list of rated itemids. 71 */ 72 public function test_get_sql_join() { 73 global $DB; 74 $this->resetAfterTest(); 75 76 $course1 = $this->getDataGenerator()->create_course(); 77 $course2 = $this->getDataGenerator()->create_course(); 78 $course3 = $this->getDataGenerator()->create_course(); 79 80 $u1 = $this->getDataGenerator()->create_user(); 81 $u2 = $this->getDataGenerator()->create_user(); 82 $u3 = $this->getDataGenerator()->create_user(); 83 84 // Rate the courses. 85 $rm = new rating_manager(); 86 $ratingoptions = (object) [ 87 'component' => 'core_course', 88 'ratingarea' => 'course', 89 'scaleid' => 100, 90 ]; 91 92 // Rate all courses as u1, and something else in the same context. 93 $this->rate_as_user($u1->id, 'core_course', 'course', $course1->id, \context_course::instance($course1->id), 25); 94 $this->rate_as_user($u1->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 50); 95 $this->rate_as_user($u1->id, 'core_course', 'course', $course3->id, \context_course::instance($course3->id), 75); 96 $this->rate_as_user($u1->id, 'core_course', 'files', $course3->id, \context_course::instance($course3->id), 99); 97 98 // Rate course2 as u2, and something else in a different context/component.. 99 $this->rate_as_user($u2->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 90); 100 $this->rate_as_user($u2->id, 'user', 'user', $u3->id, \context_user::instance($u3->id), 10); 101 102 // Return any course which the u1 has rated. 103 // u1 rated all three courses. 104 $ratingquery = provider::get_sql_join('r', 'core_course', 'course', 'c.id', $u1->id); 105 $sql = "SELECT c.id FROM {course} c {$ratingquery->join} WHERE {$ratingquery->userwhere}"; 106 $courses = $DB->get_records_sql($sql, $ratingquery->params); 107 108 $this->assertCount(3, $courses); 109 $this->assertTrue(isset($courses[$course1->id])); 110 $this->assertTrue(isset($courses[$course2->id])); 111 $this->assertTrue(isset($courses[$course3->id])); 112 113 // User u1 rated files in course 3 only. 114 $ratingquery = provider::get_sql_join('r', 'core_course', 'files', 'c.id', $u1->id); 115 $sql = "SELECT c.id FROM {course} c {$ratingquery->join} WHERE {$ratingquery->userwhere}"; 116 $courses = $DB->get_records_sql($sql, $ratingquery->params); 117 118 $this->assertCount(1, $courses); 119 $this->assertFalse(isset($courses[$course1->id])); 120 $this->assertFalse(isset($courses[$course2->id])); 121 $this->assertTrue(isset($courses[$course3->id])); 122 123 // Return any course which the u2 has rated. 124 // User u2 rated only course 2. 125 $ratingquery = provider::get_sql_join('r', 'core_course', 'course', 'c.id', $u2->id); 126 $sql = "SELECT c.id FROM {course} c {$ratingquery->join} WHERE {$ratingquery->userwhere}"; 127 $courses = $DB->get_records_sql($sql, $ratingquery->params); 128 129 $this->assertCount(1, $courses); 130 $this->assertFalse(isset($courses[$course1->id])); 131 $this->assertTrue(isset($courses[$course2->id])); 132 $this->assertFalse(isset($courses[$course3->id])); 133 134 // User u2 rated u3. 135 $ratingquery = provider::get_sql_join('r', 'user', 'user', 'u.id', $u2->id); 136 $sql = "SELECT u.id FROM {user} u {$ratingquery->join} WHERE {$ratingquery->userwhere}"; 137 $users = $DB->get_records_sql($sql, $ratingquery->params); 138 139 $this->assertCount(1, $users); 140 $this->assertFalse(isset($users[$u1->id])); 141 $this->assertFalse(isset($users[$u2->id])); 142 $this->assertTrue(isset($users[$u3->id])); 143 144 // Return any course which the u3 has rated. 145 // User u3 did not rate anything. 146 $ratingquery = provider::get_sql_join('r', 'core_course', 'course', 'c.id', $u3->id); 147 $sql = "SELECT c.id FROM {course} c {$ratingquery->join} WHERE {$ratingquery->userwhere}"; 148 $courses = $DB->get_records_sql($sql, $ratingquery->params); 149 150 $this->assertCount(0, $courses); 151 $this->assertFalse(isset($courses[$course1->id])); 152 $this->assertFalse(isset($courses[$course2->id])); 153 $this->assertFalse(isset($courses[$course3->id])); 154 } 155 156 /** 157 * Ensure that the get_sql_join function returns valid SQL which returns the correct list of rated itemids. 158 * This makes use of the optional inner join argument. 159 */ 160 public function test_get_sql_join_inner() { 161 global $DB; 162 $this->resetAfterTest(); 163 164 $course1 = $this->getDataGenerator()->create_course(); 165 $course2 = $this->getDataGenerator()->create_course(); 166 $course3 = $this->getDataGenerator()->create_course(); 167 168 $u1 = $this->getDataGenerator()->create_user(); 169 $u2 = $this->getDataGenerator()->create_user(); 170 $u3 = $this->getDataGenerator()->create_user(); 171 172 // Rate the courses. 173 $rm = new rating_manager(); 174 $ratingoptions = (object) [ 175 'component' => 'core_course', 176 'ratingarea' => 'course', 177 'scaleid' => 100, 178 ]; 179 180 // Rate all courses as u1, and something else in the same context. 181 $this->rate_as_user($u1->id, 'core_course', 'course', $course1->id, \context_course::instance($course1->id), 25); 182 $this->rate_as_user($u1->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 50); 183 $this->rate_as_user($u1->id, 'core_course', 'course', $course3->id, \context_course::instance($course3->id), 75); 184 $this->rate_as_user($u1->id, 'core_course', 'files', $course3->id, \context_course::instance($course3->id), 99); 185 186 // Rate course2 as u2, and something else in a different context/component.. 187 $this->rate_as_user($u2->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 90); 188 $this->rate_as_user($u2->id, 'user', 'user', $u3->id, \context_user::instance($u3->id), 10); 189 190 // Return any course which the u1 has rated. 191 // u1 rated all three courses. 192 $ratingquery = provider::get_sql_join('r', 'core_course', 'course', 'c.id', $u1->id, true); 193 $sql = "SELECT c.id FROM {course} c {$ratingquery->join} WHERE {$ratingquery->userwhere}"; 194 $courses = $DB->get_records_sql($sql, $ratingquery->params); 195 196 $this->assertCount(3, $courses); 197 $this->assertTrue(isset($courses[$course1->id])); 198 $this->assertTrue(isset($courses[$course2->id])); 199 $this->assertTrue(isset($courses[$course3->id])); 200 201 // User u1 rated files in course 3 only. 202 $ratingquery = provider::get_sql_join('r', 'core_course', 'files', 'c.id', $u1->id, true); 203 $sql = "SELECT c.id FROM {course} c {$ratingquery->join} WHERE {$ratingquery->userwhere}"; 204 $courses = $DB->get_records_sql($sql, $ratingquery->params); 205 206 $this->assertCount(1, $courses); 207 $this->assertFalse(isset($courses[$course1->id])); 208 $this->assertFalse(isset($courses[$course2->id])); 209 $this->assertTrue(isset($courses[$course3->id])); 210 211 // Return any course which the u2 has rated. 212 // User u2 rated only course 2. 213 $ratingquery = provider::get_sql_join('r', 'core_course', 'course', 'c.id', $u2->id, true); 214 $sql = "SELECT c.id FROM {course} c {$ratingquery->join} WHERE {$ratingquery->userwhere}"; 215 $courses = $DB->get_records_sql($sql, $ratingquery->params); 216 217 $this->assertCount(1, $courses); 218 $this->assertFalse(isset($courses[$course1->id])); 219 $this->assertTrue(isset($courses[$course2->id])); 220 $this->assertFalse(isset($courses[$course3->id])); 221 222 // User u2 rated u3. 223 $ratingquery = provider::get_sql_join('r', 'user', 'user', 'u.id', $u2->id, true); 224 $sql = "SELECT u.id FROM {user} u {$ratingquery->join} WHERE {$ratingquery->userwhere}"; 225 $users = $DB->get_records_sql($sql, $ratingquery->params); 226 227 $this->assertCount(1, $users); 228 $this->assertFalse(isset($users[$u1->id])); 229 $this->assertFalse(isset($users[$u2->id])); 230 $this->assertTrue(isset($users[$u3->id])); 231 232 // Return any course which the u3 has rated. 233 // User u3 did not rate anything. 234 $ratingquery = provider::get_sql_join('r', 'core_course', 'course', 'c.id', $u3->id, true); 235 $sql = "SELECT c.id FROM {course} c {$ratingquery->join} WHERE {$ratingquery->userwhere}"; 236 $courses = $DB->get_records_sql($sql, $ratingquery->params); 237 238 $this->assertCount(0, $courses); 239 $this->assertFalse(isset($courses[$course1->id])); 240 $this->assertFalse(isset($courses[$course2->id])); 241 $this->assertFalse(isset($courses[$course3->id])); 242 } 243 244 /** 245 * Ensure that export_area_ratings exports all ratings that a user has made, and all ratings for a users own content. 246 */ 247 public function test_export_area_ratings() { 248 global $DB; 249 $this->resetAfterTest(); 250 251 $course1 = $this->getDataGenerator()->create_course(); 252 $course2 = $this->getDataGenerator()->create_course(); 253 $course3 = $this->getDataGenerator()->create_course(); 254 255 $u1 = $this->getDataGenerator()->create_user(); 256 $u2 = $this->getDataGenerator()->create_user(); 257 $u3 = $this->getDataGenerator()->create_user(); 258 259 // Rate the courses. 260 $rm = new rating_manager(); 261 $ratingoptions = (object) [ 262 'component' => 'core_course', 263 'ratingarea' => 'course', 264 'scaleid' => 100, 265 ]; 266 267 // Rate all courses as u1, and something else in the same context. 268 $this->rate_as_user($u1->id, 'core_course', 'course', $course1->id, \context_course::instance($course1->id), 25); 269 $this->rate_as_user($u1->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 50); 270 $this->rate_as_user($u1->id, 'core_course', 'course', $course3->id, \context_course::instance($course3->id), 75); 271 $this->rate_as_user($u1->id, 'core_course', 'files', $course3->id, \context_course::instance($course3->id), 99); 272 $this->rate_as_user($u1->id, 'user', 'user', $u3->id, \context_user::instance($u3->id), 10); 273 274 // Rate course2 as u2, and something else in a different context/component.. 275 $this->rate_as_user($u2->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 90); 276 $this->rate_as_user($u2->id, 'user', 'user', $u3->id, \context_user::instance($u3->id), 20); 277 278 // Test exports. 279 // User 1 rated all three courses, and the core_course, and user 3. 280 // User 1::course1 is stored in [] subcontext. 281 $context = \context_course::instance($course1->id); 282 $subcontext = []; 283 provider::export_area_ratings($u1->id, $context, $subcontext, 'core_course', 'course', $course1->id, true); 284 285 $writer = writer::with_context($context); 286 $this->assertTrue($writer->has_any_data()); 287 $rating = $writer->get_related_data($subcontext, 'rating'); 288 $this->assert_has_rating($u1, 25, $rating); 289 290 // User 1::course2 is stored in ['foo'] subcontext. 291 $context = \context_course::instance($course2->id); 292 $subcontext = ['foo']; 293 provider::export_area_ratings($u1->id, $context, $subcontext, 'core_course', 'course', $course2->id, true); 294 295 $writer = writer::with_context($context); 296 $this->assertTrue($writer->has_any_data()); 297 $result = $writer->get_related_data($subcontext, 'rating'); 298 $this->assertCount(1, $result); 299 $this->assert_has_rating($u1, 50, $result); 300 301 // User 1::course3 is stored in ['foo'] subcontext. 302 $context = \context_course::instance($course3->id); 303 $subcontext = ['foo']; 304 provider::export_area_ratings($u1->id, $context, $subcontext, 'core_course', 'course', $course3->id, true); 305 306 $writer = writer::with_context($context); 307 $this->assertTrue($writer->has_any_data()); 308 $result = $writer->get_related_data($subcontext, 'rating'); 309 $this->assertCount(1, $result); 310 $this->assert_has_rating($u1, 75, $result); 311 312 // User 1::course3::files is stored in ['foo', 'files'] subcontext. 313 $context = \context_course::instance($course3->id); 314 $subcontext = ['foo', 'files']; 315 provider::export_area_ratings($u1->id, $context, $subcontext, 'core_course', 'files', $course3->id, true); 316 317 $writer = writer::with_context($context); 318 $this->assertTrue($writer->has_any_data()); 319 $result = $writer->get_related_data($subcontext, 'rating'); 320 $this->assertCount(1, $result); 321 $this->assert_has_rating($u1, 99, $result); 322 323 // Both users 1 and 2 rated user 3. 324 // Exporting the data for user 3 should include both of those ratings. 325 $context = \context_user::instance($u3->id); 326 $subcontext = ['user']; 327 provider::export_area_ratings($u3->id, $context, $subcontext, 'user', 'user', $u3->id, false); 328 329 $writer = writer::with_context($context); 330 $this->assertTrue($writer->has_any_data()); 331 $result = $writer->get_related_data($subcontext, 'rating'); 332 $this->assertCount(2, $result); 333 $this->assert_has_rating($u1, 10, $result); 334 $this->assert_has_rating($u2, 20, $result); 335 } 336 337 /** 338 * Test delete_ratings() method. 339 */ 340 public function test_delete_ratings() { 341 global $DB; 342 $this->resetAfterTest(); 343 344 $course1 = $this->getDataGenerator()->create_course(); 345 $course2 = $this->getDataGenerator()->create_course(); 346 $course3 = $this->getDataGenerator()->create_course(); 347 348 $u1 = $this->getDataGenerator()->create_user(); 349 $u2 = $this->getDataGenerator()->create_user(); 350 $u3 = $this->getDataGenerator()->create_user(); 351 352 // Rate all courses as u1, and something else in the same context. 353 $this->rate_as_user($u1->id, 'core_course', 'course', $course1->id, \context_course::instance($course1->id), 25); 354 $this->rate_as_user($u1->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 50); 355 $this->rate_as_user($u1->id, 'core_course', 'course', $course3->id, \context_course::instance($course3->id), 75); 356 $this->rate_as_user($u1->id, 'core_course', 'files', $course3->id, \context_course::instance($course3->id), 99); 357 $this->rate_as_user($u1->id, 'core_user', 'user', $u3->id, \context_user::instance($u3->id), 10); 358 359 // Rate course2 as u2, and something else in a different context/component.. 360 $this->rate_as_user($u2->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 90); 361 $this->rate_as_user($u2->id, 'core_user', 'user', $u3->id, \context_user::instance($u3->id), 20); 362 363 // Delete all ratings in course1. 364 $expectedratingscount = $DB->count_records('rating'); 365 core_rating\privacy\provider::delete_ratings(\context_course::instance($course1->id)); 366 $expectedratingscount -= 1; 367 $this->assertEquals($expectedratingscount, $DB->count_records('rating')); 368 369 // Delete ratings in course2 specifying wrong component. 370 core_rating\privacy\provider::delete_ratings(\context_course::instance($course2->id), 'other_component'); 371 $this->assertEquals($expectedratingscount, $DB->count_records('rating')); 372 373 // Delete ratings in course2 specifying correct component. 374 core_rating\privacy\provider::delete_ratings(\context_course::instance($course2->id), 'core_course'); 375 $expectedratingscount -= 2; 376 $this->assertEquals($expectedratingscount, $DB->count_records('rating')); 377 378 // Delete user ratings specifyng all attributes. 379 core_rating\privacy\provider::delete_ratings(\context_user::instance($u3->id), 'core_user', 'user', $u3->id); 380 $expectedratingscount -= 2; 381 $this->assertEquals($expectedratingscount, $DB->count_records('rating')); 382 } 383 384 /** 385 * Test delete_ratings_select() method. 386 */ 387 public function test_delete_ratings_select() { 388 global $DB; 389 $this->resetAfterTest(); 390 391 $course1 = $this->getDataGenerator()->create_course(); 392 $course2 = $this->getDataGenerator()->create_course(); 393 $course3 = $this->getDataGenerator()->create_course(); 394 395 $u1 = $this->getDataGenerator()->create_user(); 396 $u2 = $this->getDataGenerator()->create_user(); 397 $u3 = $this->getDataGenerator()->create_user(); 398 399 // Rate all courses as u1, and something else in the same context. 400 $this->rate_as_user($u1->id, 'core_course', 'course', $course1->id, \context_course::instance($course1->id), 25); 401 $this->rate_as_user($u1->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 50); 402 $this->rate_as_user($u1->id, 'core_course', 'course', $course3->id, \context_course::instance($course3->id), 75); 403 $this->rate_as_user($u1->id, 'core_course', 'files', $course3->id, \context_course::instance($course3->id), 99); 404 $this->rate_as_user($u1->id, 'core_user', 'user', $u3->id, \context_user::instance($u3->id), 10); 405 406 // Rate course2 as u2, and something else in a different context/component.. 407 $this->rate_as_user($u2->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 90); 408 $this->rate_as_user($u2->id, 'core_user', 'user', $u3->id, \context_user::instance($u3->id), 20); 409 410 // Delete ratings in course1. 411 list($sql, $params) = $DB->get_in_or_equal([$course1->id, $course2->id], SQL_PARAMS_NAMED); 412 $expectedratingscount = $DB->count_records('rating'); 413 core_rating\privacy\provider::delete_ratings_select(\context_course::instance($course1->id), 414 'core_course', 'course', $sql, $params); 415 $expectedratingscount -= 1; 416 $this->assertEquals($expectedratingscount, $DB->count_records('rating')); 417 } 418 419 /** 420 * Assert that a user has the correct rating. 421 * 422 * @param \stdClass $author The user with the rating 423 * @param int $score The rating that was given 424 * @param \stdClass[] The ratings which were found 425 */ 426 protected function assert_has_rating($author, $score, $actual) { 427 $found = false; 428 foreach ($actual as $rating) { 429 if ($author->id == $rating->author) { 430 $found = true; 431 $this->assertEquals($score, $rating->rating); 432 } 433 } 434 $this->assertTrue($found); 435 } 436 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body