MDL-61905 mod_workshop: Adjust privacy SQL queries
[moodle.git] / rating / tests / rating_test.php
blobc066978da5726f68c061013508a18351f04ff144
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 rating/lib.php
20 * @package core_ratings
21 * @category phpunit
22 * @copyright 2011 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
28 // Include all the needed stuff.
29 global $CFG;
30 require_once($CFG->dirroot . '/rating/lib.php');
33 /**
34 * Unit test case for all the rating/lib.php requiring DB mockup & manipulation
36 class core_rating_testcase extends advanced_testcase {
38 protected $syscontext;
39 protected $neededcaps = array('view', 'viewall', 'viewany', 'rate');
40 protected $originaldefaultfrontpageroleid;
42 public function setUp() {
43 global $CFG;
44 parent::setUp();
46 $this->resetAfterTest(true);
48 $CFG->defaultfrontpageroleid = null;
51 /**
52 * Test the current get_ratings method main sql
54 public function test_get_ratings_sql() {
55 global $DB;
57 // We load 3 items. Each is rated twice. For simplicity itemid == user id of the item owner.
58 $ctxid = context_system::instance()->id;
59 $ratings = array(
60 // User 1's items. Average == 2.
61 array('contextid' => $ctxid,
62 'component' => 'mod_forum',
63 'ratingarea' => 'post',
64 'itemid' => 1,
65 'scaleid' => 10,
66 'rating' => 1,
67 'userid' => 2,
68 'timecreated' => 1,
69 'timemodified' => 1),
71 array('contextid' => $ctxid,
72 'component' => 'mod_forum',
73 'ratingarea' => 'post',
74 'itemid' => 1,
75 'scaleid' => 10,
76 'rating' => 3,
77 'userid' => 3,
78 'timecreated' => 1,
79 'timemodified' => 1),
81 // User 2's items. Average == 3.
82 array('contextid' => $ctxid,
83 'component' => 'mod_forum',
84 'ratingarea' => 'post',
85 'itemid' => 2,
86 'scaleid' => 10,
87 'rating' => 1,
88 'userid' => 1,
89 'timecreated' => 1,
90 'timemodified' => 1),
92 array('contextid' => $ctxid,
93 'component' => 'mod_forum',
94 'ratingarea' => 'post',
95 'itemid' => 2,
96 'scaleid' => 10,
97 'rating' => 5,
98 'userid' => 3,
99 'timecreated' => 1,
100 'timemodified' => 1),
102 // User 3's items. Average == 4.
103 array('contextid' => $ctxid,
104 'component' => 'mod_forum',
105 'ratingarea' => 'post',
106 'itemid' => 3,
107 'scaleid' => 10,
108 'rating' => 3,
109 'userid' => 1,
110 'timecreated' => 1,
111 'timemodified' => 1),
113 array('contextid' => $ctxid,
114 'component' => 'mod_forum',
115 'ratingarea' => 'post',
116 'itemid' => 3,
117 'scaleid' => 10,
118 'rating' => 5,
119 'userid' => 2,
120 'timecreated' => 1,
121 'timemodified' => 1)
123 foreach ($ratings as $rating) {
124 $DB->insert_record('rating', $rating);
127 // A post (item) by user 1 (rated above by user 2 and 3 with average = 2).
128 $user1posts = array(
129 (object)array('id' => 1, 'userid' => 1, 'message' => 'hello'));
130 // A post (item) by user 2 (rated above by user 1 and 3 with average = 3).
131 $user2posts = array(
132 (object)array('id' => 2, 'userid' => 2, 'message' => 'world'));
133 // A post (item) by user 3 (rated above by user 1 and 2 with average = 4).
134 $user3posts = array(
135 (object)array('id' => 3, 'userid' => 3, 'message' => 'moodle'));
137 // Prepare the default options.
138 $defaultoptions = array (
139 'context' => context_system::instance(),
140 'component' => 'mod_forum',
141 'ratingarea' => 'post',
142 'scaleid' => 10,
143 'aggregate' => RATING_AGGREGATE_AVERAGE);
145 $rm = new mockup_rating_manager();
147 // STEP 1: Retreive ratings using the current user.
149 // Get results for user 1's item (expected average 1 + 3 / 2 = 2).
150 $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts));
151 $result = $rm->get_ratings($toptions);
152 $this->assertEquals(count($result), count($user1posts));
153 $this->assertEquals($result[0]->id, $user1posts[0]->id);
154 $this->assertEquals($result[0]->userid, $user1posts[0]->userid);
155 $this->assertEquals($result[0]->message, $user1posts[0]->message);
156 $this->assertEquals($result[0]->rating->count, 2);
157 $this->assertEquals($result[0]->rating->aggregate, 2);
158 // Note that $result[0]->rating->rating is somewhat random.
159 // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests.
161 // Get results for items of user 2 (expected average 1 + 5 / 2 = 3).
162 $toptions = (object)array_merge($defaultoptions, array('items' => $user2posts));
163 $result = $rm->get_ratings($toptions);
164 $this->assertEquals(count($result), count($user2posts));
165 $this->assertEquals($result[0]->id, $user2posts[0]->id);
166 $this->assertEquals($result[0]->userid, $user2posts[0]->userid);
167 $this->assertEquals($result[0]->message, $user2posts[0]->message);
168 $this->assertEquals($result[0]->rating->count, 2);
169 $this->assertEquals($result[0]->rating->aggregate, 3);
170 // Note that $result[0]->rating->rating is somewhat random.
171 // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests.
173 // Get results for items of user 3 (expected average 3 + 5 / 2 = 4).
174 $toptions = (object)array_merge($defaultoptions, array('items' => $user3posts));
175 $result = $rm->get_ratings($toptions);
176 $this->assertEquals(count($result), count($user3posts));
177 $this->assertEquals($result[0]->id, $user3posts[0]->id);
178 $this->assertEquals($result[0]->userid, $user3posts[0]->userid);
179 $this->assertEquals($result[0]->message, $user3posts[0]->message);
180 $this->assertEquals($result[0]->rating->count, 2);
181 $this->assertEquals($result[0]->rating->aggregate, 4);
182 // Note that $result[0]->rating->rating is somewhat random.
183 // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests.
185 // Get results for items of user 1 & 2 together (expected averages are 2 and 3, as tested above).
186 $posts = array_merge($user1posts, $user2posts);
187 $toptions = (object)array_merge($defaultoptions, array('items' => $posts));
188 $result = $rm->get_ratings($toptions);
189 $this->assertEquals(count($result), count($posts));
190 $this->assertEquals($result[0]->id, $posts[0]->id);
191 $this->assertEquals($result[0]->userid, $posts[0]->userid);
192 $this->assertEquals($result[0]->message, $posts[0]->message);
193 $this->assertEquals($result[0]->rating->count, 2);
194 $this->assertEquals($result[0]->rating->aggregate, 2);
195 // Note that $result[0]->rating->rating is somewhat random.
196 // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests.
198 $this->assertEquals($result[1]->id, $posts[1]->id);
199 $this->assertEquals($result[1]->userid, $posts[1]->userid);
200 $this->assertEquals($result[1]->message, $posts[1]->message);
201 $this->assertEquals($result[1]->rating->count, 2);
202 $this->assertEquals($result[1]->rating->aggregate, 3);
203 // Note that $result[0]->rating->rating is somewhat random.
204 // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests.
206 // STEP 2: Retrieve ratings by a specified user.
207 // We still expect complete aggregations and counts.
209 // Get results for items of user 1 rated by user 2 (avg 2, rating 1).
210 $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts, 'userid' => 2));
211 $result = $rm->get_ratings($toptions);
212 $this->assertEquals(count($result), count($user1posts));
213 $this->assertEquals($result[0]->id, $user1posts[0]->id);
214 $this->assertEquals($result[0]->userid, $user1posts[0]->userid);
215 $this->assertEquals($result[0]->message, $user1posts[0]->message);
216 $this->assertEquals($result[0]->rating->count, 2);
217 $this->assertEquals($result[0]->rating->aggregate, 2);
218 $this->assertEquals($result[0]->rating->rating, 1); // User 2 rated user 1 "1".
219 $this->assertEquals($result[0]->rating->userid, $toptions->userid); // Must be the passed userid.
221 // Get results for items of user 1 rated by user 3.
222 $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts, 'userid' => 3));
223 $result = $rm->get_ratings($toptions);
224 $this->assertEquals(count($result), count($user1posts));
225 $this->assertEquals($result[0]->id, $user1posts[0]->id);
226 $this->assertEquals($result[0]->userid, $user1posts[0]->userid);
227 $this->assertEquals($result[0]->message, $user1posts[0]->message);
228 $this->assertEquals($result[0]->rating->count, 2);
229 $this->assertEquals($result[0]->rating->aggregate, 2);
230 $this->assertEquals($result[0]->rating->rating, 3); // User 3 rated user 1 "3".
231 $this->assertEquals($result[0]->rating->userid, $toptions->userid); // Must be the passed userid.
233 // Get results for items of user 1 & 2 together rated by user 3.
234 $posts = array_merge($user1posts, $user2posts);
235 $toptions = (object)array_merge($defaultoptions, array('items' => $posts, 'userid' => 3));
236 $result = $rm->get_ratings($toptions);
237 $this->assertEquals(count($result), count($posts));
238 $this->assertEquals($result[0]->id, $posts[0]->id);
239 $this->assertEquals($result[0]->userid, $posts[0]->userid);
240 $this->assertEquals($result[0]->message, $posts[0]->message);
241 $this->assertEquals($result[0]->rating->count, 2);
242 $this->assertEquals($result[0]->rating->aggregate, 2);
243 $this->assertEquals($result[0]->rating->rating, 3); // User 3 rated user 1 "3".
244 $this->assertEquals($result[0]->rating->userid, $toptions->userid); // Must be the passed userid.
246 $this->assertEquals($result[1]->id, $posts[1]->id);
247 $this->assertEquals($result[1]->userid, $posts[1]->userid);
248 $this->assertEquals($result[1]->message, $posts[1]->message);
249 $this->assertEquals($result[1]->rating->count, 2);
250 $this->assertEquals($result[1]->rating->aggregate, 3);
251 $this->assertEquals($result[0]->rating->rating, 3); // User 3 rated user 2 "5".
252 $this->assertEquals($result[1]->rating->userid, $toptions->userid); // Must be the passed userid.
254 // STEP 3: Some special cases.
256 // Get results for user 1's items (expected average 1 + 3 / 2 = 2).
257 // Supplying a non-existent user id so no rating from that user should be found.
258 $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts));
259 $toptions->userid = 123456; // Non-existent user.
260 $result = $rm->get_ratings($toptions);
261 $this->assertNull($result[0]->rating->userid);
262 $this->assertNull($result[0]->rating->rating);
263 $this->assertEquals($result[0]->rating->aggregate, 2); // Should still get the aggregate.
265 // Get results for items of user 2 (expected average 1 + 5 / 2 = 3).
266 // Supplying the user id of the user who owns the items so no rating should be found.
267 $toptions = (object)array_merge($defaultoptions, array('items' => $user2posts));
268 $toptions->userid = 2; // User 2 viewing the ratings of their own item.
269 $result = $rm->get_ratings($toptions);
270 // These should be null as the user is viewing their own item and thus cannot rate.
271 $this->assertNull($result[0]->rating->userid);
272 $this->assertNull($result[0]->rating->rating);
273 $this->assertEquals($result[0]->rating->aggregate, 3); // Should still get the aggregate.
277 * Data provider for get_aggregate_string tests.
279 * @return array
281 public function get_aggregate_string_provider() {
282 return [
283 'Non-numeric aggregate produces empty string' => [
284 RATING_AGGREGATE_NONE,
285 'string',
286 null,
287 ['Foo', 'Bar'],
290 'Aggregate count produces empty string' => [
291 RATING_AGGREGATE_COUNT,
293 null,
294 ['Foo', 'Bar'],
297 'Numeric SUM with non-numeric scale produces returns original value' => [
298 RATING_AGGREGATE_SUM,
300 false,
301 ['Foo', 'Bar'],
302 '10',
304 'Numeric SUM with non-numeric scale produces returns rounded value' => [
305 RATING_AGGREGATE_SUM,
306 10.45,
307 false,
308 ['Foo', 'Bar'],
309 '10.5',
311 'Numeric SUM with numeric scale produces returns rounded value' => [
312 RATING_AGGREGATE_SUM,
313 10.45,
314 true,
315 ['Foo', 'Bar'],
316 '10.5',
318 'Numeric AVERAGE with numeric scale produces returns rounded value' => [
319 RATING_AGGREGATE_AVERAGE,
320 10.45,
321 true,
322 ['Foo', 'Bar'],
323 '10.5',
325 'Numeric AVERAGE with non-numeric scale produces returns indexed value (0)' => [
326 RATING_AGGREGATE_AVERAGE,
328 false,
329 ['Foo', 'Bar'],
330 'Foo',
332 'Numeric AVERAGE with non-numeric scale produces returns indexed value (1)' => [
333 RATING_AGGREGATE_AVERAGE,
335 false,
336 ['Foo', 'Bar'],
337 'Bar',
343 * Test the value returned by get_aggregate_string().
345 * @dataProvider get_aggregate_string_provider
347 public function test_get_aggregate_string($method, $aggregate, $isnumeric, $scaleitems, $expectation) {
348 $options = new stdClass();
349 $options->aggregate = $aggregate;
350 $options->context = null;
351 $options->component = null;
352 $options->ratingarea = null;
353 $options->itemid = null;
354 $options->scaleid = null;
355 $options->userid = null;
357 $options->settings = new stdClass();
358 $options->settings->aggregationmethod = $method;
359 $options->settings->scale = new stdClass();
360 $options->settings->scale->isnumeric = $isnumeric;
361 $options->settings->scale->scaleitems = $scaleitems;
363 $rating = new rating($options);
364 $this->assertEquals($expectation, $rating->get_aggregate_string());
369 * rating_manager subclass for unit testing without requiring capabilities to be loaded
371 class mockup_rating_manager extends rating_manager {
374 * Overwrite get_plugin_permissions_array() so it always return granted perms for unit testing
376 public function get_plugin_permissions_array($contextid, $component, $ratingarea) {
377 return array(
378 'rate' => true,
379 'view' => true,
380 'viewany' => true,
381 'viewall' => true);