Merge branch 'MDL-81073' of https://github.com/paulholden/moodle
[moodle.git] / rating / tests / rating_test.php
blobb2fa6a55d15d6b306f498efdffb3433796590a8e
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 namespace core_rating;
19 use rating_manager;
21 defined('MOODLE_INTERNAL') || die();
23 // Include all the needed stuff.
24 global $CFG;
25 require_once($CFG->dirroot . '/rating/lib.php');
28 /**
29 * Unit test case for all the rating/lib.php requiring DB mockup & manipulation
31 * @package core_rating
32 * @category test
33 * @copyright 2011 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 * @covers \rating
37 class rating_test extends \advanced_testcase {
39 protected $syscontext;
40 protected $neededcaps = array('view', 'viewall', 'viewany', 'rate');
41 protected $originaldefaultfrontpageroleid;
43 public function setUp(): void {
44 global $CFG;
45 parent::setUp();
47 $this->resetAfterTest(true);
49 $CFG->defaultfrontpageroleid = null;
52 /**
53 * Test the current get_ratings method main sql
55 public function test_get_ratings_sql() {
56 global $DB;
58 // We load 3 items. Each is rated twice. For simplicity itemid == user id of the item owner.
59 $ctxid = \context_system::instance()->id;
60 $ratings = array(
61 // User 1's items. Average == 2.
62 array('contextid' => $ctxid,
63 'component' => 'mod_forum',
64 'ratingarea' => 'post',
65 'itemid' => 1,
66 'scaleid' => 10,
67 'rating' => 1,
68 'userid' => 2,
69 'timecreated' => 1,
70 'timemodified' => 1),
72 array('contextid' => $ctxid,
73 'component' => 'mod_forum',
74 'ratingarea' => 'post',
75 'itemid' => 1,
76 'scaleid' => 10,
77 'rating' => 3,
78 'userid' => 3,
79 'timecreated' => 1,
80 'timemodified' => 1),
82 // User 2's items. Average == 3.
83 array('contextid' => $ctxid,
84 'component' => 'mod_forum',
85 'ratingarea' => 'post',
86 'itemid' => 2,
87 'scaleid' => 10,
88 'rating' => 1,
89 'userid' => 1,
90 'timecreated' => 1,
91 'timemodified' => 1),
93 array('contextid' => $ctxid,
94 'component' => 'mod_forum',
95 'ratingarea' => 'post',
96 'itemid' => 2,
97 'scaleid' => 10,
98 'rating' => 4,
99 'userid' => 3,
100 'timecreated' => 1,
101 'timemodified' => 1),
103 // User 3's items. Average == 4.
104 array('contextid' => $ctxid,
105 'component' => 'mod_forum',
106 'ratingarea' => 'post',
107 'itemid' => 3,
108 'scaleid' => 10,
109 'rating' => 3,
110 'userid' => 1,
111 'timecreated' => 1,
112 'timemodified' => 1),
114 array('contextid' => $ctxid,
115 'component' => 'mod_forum',
116 'ratingarea' => 'post',
117 'itemid' => 3,
118 'scaleid' => 10,
119 'rating' => 5,
120 'userid' => 2,
121 'timecreated' => 1,
122 'timemodified' => 1)
124 foreach ($ratings as $rating) {
125 $DB->insert_record('rating', $rating);
128 // A post (item) by user 1 (rated above by user 2 and 3 with average = 2).
129 $user1posts = array(
130 (object)array('id' => 1, 'userid' => 1, 'message' => 'hello'));
131 // A post (item) by user 2 (rated above by user 1 and 3 with average = 3).
132 $user2posts = array(
133 (object)array('id' => 2, 'userid' => 2, 'message' => 'world'));
134 // A post (item) by user 3 (rated above by user 1 and 2 with average = 4).
135 $user3posts = array(
136 (object)array('id' => 3, 'userid' => 3, 'message' => 'moodle'));
138 // Prepare the default options.
139 $defaultoptions = array (
140 'context' => \context_system::instance(),
141 'component' => 'mod_forum',
142 'ratingarea' => 'post',
143 'scaleid' => 10,
144 'aggregate' => RATING_AGGREGATE_AVERAGE);
146 $rm = new mockup_rating_manager();
148 // STEP 1: Retreive ratings using the current user.
150 // Get results for user 1's item (expected average 1 + 3 / 2 = 2).
151 $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts));
152 $result = $rm->get_ratings($toptions);
153 $this->assertEquals(count($result), count($user1posts));
154 $this->assertEquals($result[0]->id, $user1posts[0]->id);
155 $this->assertEquals($result[0]->userid, $user1posts[0]->userid);
156 $this->assertEquals($result[0]->message, $user1posts[0]->message);
157 $this->assertEquals($result[0]->rating->count, 2);
158 $this->assertEquals($result[0]->rating->aggregate, 2);
159 // Note that $result[0]->rating->rating is somewhat random.
160 // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests.
162 // Get results for items of user 2 (expected average 1 + 4 / 2 = 2.5).
163 $toptions = (object)array_merge($defaultoptions, array('items' => $user2posts));
164 $result = $rm->get_ratings($toptions);
165 $this->assertEquals(count($result), count($user2posts));
166 $this->assertEquals($result[0]->id, $user2posts[0]->id);
167 $this->assertEquals($result[0]->userid, $user2posts[0]->userid);
168 $this->assertEquals($result[0]->message, $user2posts[0]->message);
169 $this->assertEquals($result[0]->rating->count, 2);
170 $this->assertEquals($result[0]->rating->aggregate, 2.5);
171 // Note that $result[0]->rating->rating is somewhat random.
172 // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests.
174 // Get results for items of user 3 (expected average 3 + 5 / 2 = 4).
175 $toptions = (object)array_merge($defaultoptions, array('items' => $user3posts));
176 $result = $rm->get_ratings($toptions);
177 $this->assertEquals(count($result), count($user3posts));
178 $this->assertEquals($result[0]->id, $user3posts[0]->id);
179 $this->assertEquals($result[0]->userid, $user3posts[0]->userid);
180 $this->assertEquals($result[0]->message, $user3posts[0]->message);
181 $this->assertEquals($result[0]->rating->count, 2);
182 $this->assertEquals($result[0]->rating->aggregate, 4);
183 // Note that $result[0]->rating->rating is somewhat random.
184 // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests.
186 // Get results for items of user 1 & 2 together (expected averages are 2 and 2.5, as tested above).
187 $posts = array_merge($user1posts, $user2posts);
188 $toptions = (object)array_merge($defaultoptions, array('items' => $posts));
189 $result = $rm->get_ratings($toptions);
190 $this->assertEquals(count($result), count($posts));
191 $this->assertEquals($result[0]->id, $posts[0]->id);
192 $this->assertEquals($result[0]->userid, $posts[0]->userid);
193 $this->assertEquals($result[0]->message, $posts[0]->message);
194 $this->assertEquals($result[0]->rating->count, 2);
195 $this->assertEquals($result[0]->rating->aggregate, 2);
196 // Note that $result[0]->rating->rating is somewhat random.
197 // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests.
199 $this->assertEquals($result[1]->id, $posts[1]->id);
200 $this->assertEquals($result[1]->userid, $posts[1]->userid);
201 $this->assertEquals($result[1]->message, $posts[1]->message);
202 $this->assertEquals($result[1]->rating->count, 2);
203 $this->assertEquals($result[1]->rating->aggregate, 2.5);
204 // Note that $result[0]->rating->rating is somewhat random.
205 // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests.
207 // STEP 2: Retrieve ratings by a specified user.
208 // We still expect complete aggregations and counts.
210 // Get results for items of user 1 rated by user 2 (avg 2, rating 1).
211 $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts, 'userid' => 2));
212 $result = $rm->get_ratings($toptions);
213 $this->assertEquals(count($result), count($user1posts));
214 $this->assertEquals($result[0]->id, $user1posts[0]->id);
215 $this->assertEquals($result[0]->userid, $user1posts[0]->userid);
216 $this->assertEquals($result[0]->message, $user1posts[0]->message);
217 $this->assertEquals($result[0]->rating->count, 2);
218 $this->assertEquals($result[0]->rating->aggregate, 2);
219 $this->assertEquals($result[0]->rating->rating, 1); // User 2 rated user 1 "1".
220 $this->assertEquals($result[0]->rating->userid, $toptions->userid); // Must be the passed userid.
222 // Get results for items of user 1 rated by user 3.
223 $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts, 'userid' => 3));
224 $result = $rm->get_ratings($toptions);
225 $this->assertEquals(count($result), count($user1posts));
226 $this->assertEquals($result[0]->id, $user1posts[0]->id);
227 $this->assertEquals($result[0]->userid, $user1posts[0]->userid);
228 $this->assertEquals($result[0]->message, $user1posts[0]->message);
229 $this->assertEquals($result[0]->rating->count, 2);
230 $this->assertEquals($result[0]->rating->aggregate, 2);
231 $this->assertEquals($result[0]->rating->rating, 3); // User 3 rated user 1 "3".
232 $this->assertEquals($result[0]->rating->userid, $toptions->userid); // Must be the passed userid.
234 // Get results for items of user 1 & 2 together rated by user 3.
235 $posts = array_merge($user1posts, $user2posts);
236 $toptions = (object)array_merge($defaultoptions, array('items' => $posts, 'userid' => 3));
237 $result = $rm->get_ratings($toptions);
238 $this->assertEquals(count($result), count($posts));
239 $this->assertEquals($result[0]->id, $posts[0]->id);
240 $this->assertEquals($result[0]->userid, $posts[0]->userid);
241 $this->assertEquals($result[0]->message, $posts[0]->message);
242 $this->assertEquals($result[0]->rating->count, 2);
243 $this->assertEquals($result[0]->rating->aggregate, 2);
244 $this->assertEquals($result[0]->rating->rating, 3); // User 3 rated user 1 "3".
245 $this->assertEquals($result[0]->rating->userid, $toptions->userid); // Must be the passed userid.
247 $this->assertEquals($result[1]->id, $posts[1]->id);
248 $this->assertEquals($result[1]->userid, $posts[1]->userid);
249 $this->assertEquals($result[1]->message, $posts[1]->message);
250 $this->assertEquals($result[1]->rating->count, 2);
251 $this->assertEquals($result[1]->rating->aggregate, 2.5);
252 $this->assertEquals($result[0]->rating->rating, 3); // User 3 rated user 2 "5".
253 $this->assertEquals($result[1]->rating->userid, $toptions->userid); // Must be the passed userid.
255 // STEP 3: Some special cases.
257 // Get results for user 1's items (expected average 1 + 3 / 2 = 2).
258 // Supplying a non-existent user id so no rating from that user should be found.
259 $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts));
260 $toptions->userid = 123456; // Non-existent user.
261 $result = $rm->get_ratings($toptions);
262 $this->assertNull($result[0]->rating->userid);
263 $this->assertNull($result[0]->rating->rating);
264 $this->assertEquals($result[0]->rating->aggregate, 2); // Should still get the aggregate.
266 // Get results for items of user 2 (expected average 1 + 4 / 2 = 2.5).
267 // Supplying the user id of the user who owns the items so no rating should be found.
268 $toptions = (object)array_merge($defaultoptions, array('items' => $user2posts));
269 $toptions->userid = 2; // User 2 viewing the ratings of their own item.
270 $result = $rm->get_ratings($toptions);
271 // These should be null as the user is viewing their own item and thus cannot rate.
272 $this->assertNull($result[0]->rating->userid);
273 $this->assertNull($result[0]->rating->rating);
274 $this->assertEquals($result[0]->rating->aggregate, 2.5); // Should still get the aggregate.
278 * Data provider for get_aggregate_string tests.
280 * @return array
282 public function get_aggregate_string_provider() {
283 return [
284 'Non-numeric aggregate produces empty string' => [
285 RATING_AGGREGATE_NONE,
286 'string',
287 null,
288 ['Foo', 'Bar'],
291 'Aggregate count produces empty string' => [
292 RATING_AGGREGATE_COUNT,
294 null,
295 ['Foo', 'Bar'],
298 'Numeric SUM with non-numeric scale produces returns original value' => [
299 RATING_AGGREGATE_SUM,
301 false,
302 ['Foo', 'Bar'],
303 '10',
305 'Numeric SUM with non-numeric scale produces returns rounded value' => [
306 RATING_AGGREGATE_SUM,
307 10.45,
308 false,
309 ['Foo', 'Bar'],
310 '10.5',
312 'Numeric SUM with numeric scale produces returns rounded value' => [
313 RATING_AGGREGATE_SUM,
314 10.45,
315 true,
316 ['Foo', 'Bar'],
317 '10.5',
319 'Numeric AVERAGE with numeric scale produces returns rounded value' => [
320 RATING_AGGREGATE_AVERAGE,
321 10.45,
322 true,
323 ['Foo', 'Bar'],
324 '10.5',
326 'Numeric AVERAGE with non-numeric scale produces returns indexed value (0)' => [
327 RATING_AGGREGATE_AVERAGE,
329 false,
330 ['Foo', 'Bar'],
331 'Foo',
333 'Numeric AVERAGE with non-numeric scale produces returns indexed value (1)' => [
334 RATING_AGGREGATE_AVERAGE,
336 false,
337 ['Foo', 'Bar'],
338 'Bar',
344 * Test the value returned by get_aggregate_string().
346 * @dataProvider get_aggregate_string_provider
348 public function test_get_aggregate_string($method, $aggregate, $isnumeric, $scaleitems, $expectation) {
349 $options = new \stdClass();
350 $options->aggregate = $aggregate;
351 $options->context = null;
352 $options->component = null;
353 $options->ratingarea = null;
354 $options->itemid = null;
355 $options->scaleid = null;
356 $options->userid = null;
358 $options->settings = new \stdClass();
359 $options->settings->aggregationmethod = $method;
360 $options->settings->scale = new \stdClass();
361 $options->settings->scale->isnumeric = $isnumeric;
362 $options->settings->scale->scaleitems = $scaleitems;
364 $rating = new \rating($options);
365 $this->assertEquals($expectation, $rating->get_aggregate_string());
370 * rating_manager subclass for unit testing without requiring capabilities to be loaded
372 class mockup_rating_manager extends rating_manager {
375 * Overwrite get_plugin_permissions_array() so it always return granted perms for unit testing
377 public function get_plugin_permissions_array($contextid, $component, $ratingarea) {
378 return array(
379 'rate' => true,
380 'view' => true,
381 'viewany' => true,
382 'viewall' => true);