Merge branch 'MDL-63214-master' of git://github.com/sarjona/moodle
[moodle.git] / rating / tests / privacy_provider_test.php
blob7f0fb1793316d4db54a8048b12199cf7c81ad1f1
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Unit tests for the core_rating implementation of the Privacy API.
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
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->dirroot . '/rating/lib.php');
31 use \core_rating\privacy\provider;
32 use \core_privacy\local\request\writer;
34 /**
35 * Unit tests for the core_rating implementation of the Privacy API.
37 * @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 class core_rating_privacy_testcase extends \core_privacy\tests\provider_testcase {
42 /**
43 * Rate something as a user.
45 * @param int $userid
46 * @param string $component
47 * @param string $ratingarea
48 * @param int $itemid
49 * @param \context $context
50 * @param string $score
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,
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);
69 /**
70 * Ensure that the get_sql_join function returns valid SQL which returns the correct list of rated itemids.
72 public function test_get_sql_join() {
73 global $DB;
74 $this->resetAfterTest();
76 $course1 = $this->getDataGenerator()->create_course();
77 $course2 = $this->getDataGenerator()->create_course();
78 $course3 = $this->getDataGenerator()->create_course();
80 $u1 = $this->getDataGenerator()->create_user();
81 $u2 = $this->getDataGenerator()->create_user();
82 $u3 = $this->getDataGenerator()->create_user();
84 // Rate the courses.
85 $rm = new rating_manager();
86 $ratingoptions = (object) [
87 'component' => 'core_course',
88 'ratingarea' => 'course',
89 'scaleid' => 100,
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);
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);
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);
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]));
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);
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]));
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);
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]));
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);
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]));
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);
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]));
157 * Ensure that export_area_ratings exports all ratings that a user has made, and all ratings for a users own content.
159 public function test_export_area_ratings() {
160 global $DB;
161 $this->resetAfterTest();
163 $course1 = $this->getDataGenerator()->create_course();
164 $course2 = $this->getDataGenerator()->create_course();
165 $course3 = $this->getDataGenerator()->create_course();
167 $u1 = $this->getDataGenerator()->create_user();
168 $u2 = $this->getDataGenerator()->create_user();
169 $u3 = $this->getDataGenerator()->create_user();
171 // Rate the courses.
172 $rm = new rating_manager();
173 $ratingoptions = (object) [
174 'component' => 'core_course',
175 'ratingarea' => 'course',
176 'scaleid' => 100,
179 // Rate all courses as u1, and something else in the same context.
180 $this->rate_as_user($u1->id, 'core_course', 'course', $course1->id, \context_course::instance($course1->id), 25);
181 $this->rate_as_user($u1->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 50);
182 $this->rate_as_user($u1->id, 'core_course', 'course', $course3->id, \context_course::instance($course3->id), 75);
183 $this->rate_as_user($u1->id, 'core_course', 'files', $course3->id, \context_course::instance($course3->id), 99);
184 $this->rate_as_user($u1->id, 'user', 'user', $u3->id, \context_user::instance($u3->id), 10);
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), 20);
190 // Test exports.
191 // User 1 rated all three courses, and the core_course, and user 3.
192 // User 1::course1 is stored in [] subcontext.
193 $context = \context_course::instance($course1->id);
194 $subcontext = [];
195 provider::export_area_ratings($u1->id, $context, $subcontext, 'core_course', 'course', $course1->id, true);
197 $writer = writer::with_context($context);
198 $this->assertTrue($writer->has_any_data());
199 $rating = $writer->get_related_data($subcontext, 'rating');
200 $this->assert_has_rating($u1, 25, $rating);
202 // User 1::course2 is stored in ['foo'] subcontext.
203 $context = \context_course::instance($course2->id);
204 $subcontext = ['foo'];
205 provider::export_area_ratings($u1->id, $context, $subcontext, 'core_course', 'course', $course2->id, true);
207 $writer = writer::with_context($context);
208 $this->assertTrue($writer->has_any_data());
209 $result = $writer->get_related_data($subcontext, 'rating');
210 $this->assertCount(1, $result);
211 $this->assert_has_rating($u1, 50, $result);
213 // User 1::course3 is stored in ['foo'] subcontext.
214 $context = \context_course::instance($course3->id);
215 $subcontext = ['foo'];
216 provider::export_area_ratings($u1->id, $context, $subcontext, 'core_course', 'course', $course3->id, true);
218 $writer = writer::with_context($context);
219 $this->assertTrue($writer->has_any_data());
220 $result = $writer->get_related_data($subcontext, 'rating');
221 $this->assertCount(1, $result);
222 $this->assert_has_rating($u1, 75, $result);
224 // User 1::course3::files is stored in ['foo', 'files'] subcontext.
225 $context = \context_course::instance($course3->id);
226 $subcontext = ['foo', 'files'];
227 provider::export_area_ratings($u1->id, $context, $subcontext, 'core_course', 'files', $course3->id, true);
229 $writer = writer::with_context($context);
230 $this->assertTrue($writer->has_any_data());
231 $result = $writer->get_related_data($subcontext, 'rating');
232 $this->assertCount(1, $result);
233 $this->assert_has_rating($u1, 99, $result);
235 // Both users 1 and 2 rated user 3.
236 // Exporting the data for user 3 should include both of those ratings.
237 $context = \context_user::instance($u3->id);
238 $subcontext = ['user'];
239 provider::export_area_ratings($u3->id, $context, $subcontext, 'user', 'user', $u3->id, false);
241 $writer = writer::with_context($context);
242 $this->assertTrue($writer->has_any_data());
243 $result = $writer->get_related_data($subcontext, 'rating');
244 $this->assertCount(2, $result);
245 $this->assert_has_rating($u1, 10, $result);
246 $this->assert_has_rating($u2, 20, $result);
250 * Test delete_ratings() method.
252 public function test_delete_ratings() {
253 global $DB;
254 $this->resetAfterTest();
256 $course1 = $this->getDataGenerator()->create_course();
257 $course2 = $this->getDataGenerator()->create_course();
258 $course3 = $this->getDataGenerator()->create_course();
260 $u1 = $this->getDataGenerator()->create_user();
261 $u2 = $this->getDataGenerator()->create_user();
262 $u3 = $this->getDataGenerator()->create_user();
264 // Rate all courses as u1, and something else in the same context.
265 $this->rate_as_user($u1->id, 'core_course', 'course', $course1->id, \context_course::instance($course1->id), 25);
266 $this->rate_as_user($u1->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 50);
267 $this->rate_as_user($u1->id, 'core_course', 'course', $course3->id, \context_course::instance($course3->id), 75);
268 $this->rate_as_user($u1->id, 'core_course', 'files', $course3->id, \context_course::instance($course3->id), 99);
269 $this->rate_as_user($u1->id, 'core_user', 'user', $u3->id, \context_user::instance($u3->id), 10);
271 // Rate course2 as u2, and something else in a different context/component..
272 $this->rate_as_user($u2->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 90);
273 $this->rate_as_user($u2->id, 'core_user', 'user', $u3->id, \context_user::instance($u3->id), 20);
275 // Delete all ratings in course1.
276 $expectedratingscount = $DB->count_records('rating');
277 core_rating\privacy\provider::delete_ratings(\context_course::instance($course1->id));
278 $expectedratingscount -= 1;
279 $this->assertEquals($expectedratingscount, $DB->count_records('rating'));
281 // Delete ratings in course2 specifying wrong component.
282 core_rating\privacy\provider::delete_ratings(\context_course::instance($course2->id), 'other_component');
283 $this->assertEquals($expectedratingscount, $DB->count_records('rating'));
285 // Delete ratings in course2 specifying correct component.
286 core_rating\privacy\provider::delete_ratings(\context_course::instance($course2->id), 'core_course');
287 $expectedratingscount -= 2;
288 $this->assertEquals($expectedratingscount, $DB->count_records('rating'));
290 // Delete user ratings specifyng all attributes.
291 core_rating\privacy\provider::delete_ratings(\context_user::instance($u3->id), 'core_user', 'user', $u3->id);
292 $expectedratingscount -= 2;
293 $this->assertEquals($expectedratingscount, $DB->count_records('rating'));
297 * Test delete_ratings_select() method.
299 public function test_delete_ratings_select() {
300 global $DB;
301 $this->resetAfterTest();
303 $course1 = $this->getDataGenerator()->create_course();
304 $course2 = $this->getDataGenerator()->create_course();
305 $course3 = $this->getDataGenerator()->create_course();
307 $u1 = $this->getDataGenerator()->create_user();
308 $u2 = $this->getDataGenerator()->create_user();
309 $u3 = $this->getDataGenerator()->create_user();
311 // Rate all courses as u1, and something else in the same context.
312 $this->rate_as_user($u1->id, 'core_course', 'course', $course1->id, \context_course::instance($course1->id), 25);
313 $this->rate_as_user($u1->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 50);
314 $this->rate_as_user($u1->id, 'core_course', 'course', $course3->id, \context_course::instance($course3->id), 75);
315 $this->rate_as_user($u1->id, 'core_course', 'files', $course3->id, \context_course::instance($course3->id), 99);
316 $this->rate_as_user($u1->id, 'core_user', 'user', $u3->id, \context_user::instance($u3->id), 10);
318 // Rate course2 as u2, and something else in a different context/component..
319 $this->rate_as_user($u2->id, 'core_course', 'course', $course2->id, \context_course::instance($course2->id), 90);
320 $this->rate_as_user($u2->id, 'core_user', 'user', $u3->id, \context_user::instance($u3->id), 20);
322 // Delete ratings in course1.
323 list($sql, $params) = $DB->get_in_or_equal([$course1->id, $course2->id], SQL_PARAMS_NAMED);
324 $expectedratingscount = $DB->count_records('rating');
325 core_rating\privacy\provider::delete_ratings_select(\context_course::instance($course1->id),
326 'core_course', 'course', $sql, $params);
327 $expectedratingscount -= 1;
328 $this->assertEquals($expectedratingscount, $DB->count_records('rating'));
332 * Assert that a user has the correct rating.
334 * @param \stdClass $author The user with the rating
335 * @param int $score The rating that was given
336 * @param \stdClass[] The ratings which were found
338 protected function assert_has_rating($author, $score, $actual) {
339 $found = false;
340 foreach ($actual as $rating) {
341 if ($author->id == $rating->author) {
342 $found = true;
343 $this->assertEquals($score, $rating->rating);
346 $this->assertTrue($found);