Merge branch 'wip-MDL-29487-master' of git://github.com/samhemelryk/moodle
[moodle.git] / rating / simpletest / testrating.php
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/>.
17 /**
18  * Unit tests for rating/lib.php
19  *
20  * @package    moodlecore
21  * @subpackage rating
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
24  */
26 defined('MOODLE_INTERNAL') || die();
28 // Include all the needed stuff
29 require_once($CFG->dirroot . '/rating/lib.php');
31 /**
32  * Unit test case for all the rating/lib.php requiring DB mockup & manipulation
33  */
34 class rating_db_test extends UnitTestCaseUsingDatabase {
36     public static $includecoverage = array(
37         'rating/lib.php'
38     );
40     protected $testtables = array(
41             'lib' => array(
42                 'rating', 'scale', 'context', 'capabilities', 'role_assignments', 'role_capabilities', 'course'));
44     protected $syscontext;
45     protected $neededcaps = array('view', 'viewall', 'viewany', 'rate');
46     protected $originaldefaultfrontpageroleid;
48     public function setUp() {
49         global $CFG;
50         parent::setUp();
52         // Make sure accesslib has cached a sensible system context object
53         // before we switch to the test DB.
54         $this->syscontext = get_context_instance(CONTEXT_SYSTEM);
56         foreach ($this->testtables as $dir => $tables) {
57             $this->create_test_tables($tables, $dir); // Create tables
58         }
60         $this->switch_to_test_db(); // Switch to test DB for all the execution
62         $this->fill_records();
64         // Ignore any frontpageroleid, that would require to crete more contexts
65         $this->originaldefaultfrontpageroleid = $CFG->defaultfrontpageroleid;
66         $CFG->defaultfrontpageroleid = null;
67     }
69     public function tearDown() {
70         global $CFG;
71         // Recover original frontpageroleid
72         $CFG->defaultfrontpageroleid = $this->originaldefaultfrontpageroleid;
73         parent::tearDown();
74     }
76     private function fill_records() {
77         global $DB;
79         // Set up systcontext in the test database.
80         $this->syscontext->id = $this->testdb->insert_record('context', $this->syscontext);
82         // Add the capabilities used by ratings
83         foreach ($this->neededcaps as $neededcap) {
84             $this->testdb->insert_record('capabilities', (object)array('name' => 'moodle/rating:' . $neededcap,
85                                                                  'contextlevel' => CONTEXT_COURSE));
86         }
87     }
89     /**
90      * Test the current get_ratings method main sql
91      */
92     function test_get_ratings_sql() {
94         // We load 3 items. Each is rated twice. For simplicity itemid == user id of the item owner
95         $ctxid = $this->syscontext->id;
96         $this->load_test_data('rating',
97                 array('contextid', 'component', 'ratingarea', 'itemid', 'scaleid', 'rating', 'userid', 'timecreated', 'timemodified'), array(
99                 //user 1's items. Average == 2
100                 array(    $ctxid , 'mod_forum',       'post',       1 ,       10 ,       1 ,       2 ,            1 ,              1),
101                 array(    $ctxid , 'mod_forum',       'post',       1 ,       10 ,       3 ,       3 ,            1 ,              1),
103                 //user 2's items. Average == 3
104                 array(    $ctxid , 'mod_forum',       'post',       2 ,       10 ,       1 ,       1 ,            1 ,              1),
105                 array(    $ctxid , 'mod_forum',       'post',       2 ,       10 ,       5 ,       3 ,            1 ,              1),
107                 //user 3's items. Average == 4
108                 array(    $ctxid , 'mod_forum',       'post',       3 ,       10 ,       3 ,       1 ,            1 ,              1),
109                 array(    $ctxid , 'mod_forum',       'post',       3 ,       10 ,       5 ,       2 ,            1 ,              1)
110                 ));
112         // a post (item) by user 1 (rated above by user 2 and 3 with average = 2)
113         $user1posts = array(
114                 (object)array('id' => 1, 'userid' => 1, 'message' => 'hello'));
115         // a post (item) by user 2 (rated above by user 1 and 3 with average = 3)
116         $user2posts = array(
117                 (object)array('id' => 2, 'userid' => 2, 'message' => 'world'));
118         // a post (item) by user 3 (rated above by user 1 and 2 with average = 4)
119         $user3posts = array(
120                 (object)array('id' => 3, 'userid' => 3, 'message' => 'moodle'));
122         // Prepare the default options
123         $defaultoptions = array (
124                 'context'    => $this->syscontext,
125                 'component'  => 'mod_forum',
126                 'ratingarea' => 'post',
127                 'scaleid'    => 10,
128                 'aggregate'  => RATING_AGGREGATE_AVERAGE);
130         $rm = new mockup_rating_manager();
132         // STEP 1: Retreive ratings using the current user
134         // Get results for user 1's item (expected average 1 + 3 / 2 = 2)
135         $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts));
136         $result = $rm->get_ratings($toptions);
137         $this->assertEqual(count($result), count($user1posts));
138         $this->assertEqual($result[0]->id, $user1posts[0]->id);
139         $this->assertEqual($result[0]->userid, $user1posts[0]->userid);
140         $this->assertEqual($result[0]->message, $user1posts[0]->message);
141         $this->assertEqual($result[0]->rating->count, 2);
142         $this->assertEqual($result[0]->rating->aggregate, 2);
143         // Note that $result[0]->rating->rating is somewhat random
144         // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests
146         // Get results for items of user 2 (expected average 1 + 5 / 2 = 3)
147         $toptions = (object)array_merge($defaultoptions, array('items' => $user2posts));
148         $result = $rm->get_ratings($toptions);
149         $this->assertEqual(count($result), count($user2posts));
150         $this->assertEqual($result[0]->id, $user2posts[0]->id);
151         $this->assertEqual($result[0]->userid, $user2posts[0]->userid);
152         $this->assertEqual($result[0]->message, $user2posts[0]->message);
153         $this->assertEqual($result[0]->rating->count, 2);
154         $this->assertEqual($result[0]->rating->aggregate, 3);
155         // Note that $result[0]->rating->rating is somewhat random
156         // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests
158         // Get results for items of user 3 (expected average 3 + 5 / 2 = 4)
159         $toptions = (object)array_merge($defaultoptions, array('items' => $user3posts));
160         $result = $rm->get_ratings($toptions);
161         $this->assertEqual(count($result), count($user3posts));
162         $this->assertEqual($result[0]->id, $user3posts[0]->id);
163         $this->assertEqual($result[0]->userid, $user3posts[0]->userid);
164         $this->assertEqual($result[0]->message, $user3posts[0]->message);
165         $this->assertEqual($result[0]->rating->count, 2);
166         $this->assertEqual($result[0]->rating->aggregate, 4);
167         // Note that $result[0]->rating->rating is somewhat random
168         // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests
170         // Get results for items of user 1 & 2 together (expected averages are 2 and 3, as tested above)
171         $posts = array_merge($user1posts, $user2posts);
172         $toptions = (object)array_merge($defaultoptions, array('items' => $posts));
173         $result = $rm->get_ratings($toptions);
174         $this->assertEqual(count($result), count($posts));
175         $this->assertEqual($result[0]->id, $posts[0]->id);
176         $this->assertEqual($result[0]->userid, $posts[0]->userid);
177         $this->assertEqual($result[0]->message, $posts[0]->message);
178         $this->assertEqual($result[0]->rating->count, 2);
179         $this->assertEqual($result[0]->rating->aggregate, 2);
180         // Note that $result[0]->rating->rating is somewhat random
181         // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests
183         $this->assertEqual($result[1]->id, $posts[1]->id);
184         $this->assertEqual($result[1]->userid, $posts[1]->userid);
185         $this->assertEqual($result[1]->message, $posts[1]->message);
186         $this->assertEqual($result[1]->rating->count, 2);
187         $this->assertEqual($result[1]->rating->aggregate, 3);
188         // Note that $result[0]->rating->rating is somewhat random
189         // We didn't supply a user ID so $USER was used which will vary depending on who runs the tests
191         // STEP 2: Retrieve ratings by a specified user
192         //         We still expect complete aggregations and counts
194         // Get results for items of user 1 rated by user 2 (avg 2, rating 1)
195         $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts, 'userid' => 2));
196         $result = $rm->get_ratings($toptions);
197         $this->assertEqual(count($result), count($user1posts));
198         $this->assertEqual($result[0]->id, $user1posts[0]->id);
199         $this->assertEqual($result[0]->userid, $user1posts[0]->userid);
200         $this->assertEqual($result[0]->message, $user1posts[0]->message);
201         $this->assertEqual($result[0]->rating->count, 2);
202         $this->assertEqual($result[0]->rating->aggregate, 2);
203         $this->assertEqual($result[0]->rating->rating, 1); //user 2 rated user 1 "1"
204         $this->assertEqual($result[0]->rating->userid, $toptions->userid); // Must be the passed userid
206         // Get results for items of user 1 rated by user 3
207         $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts, 'userid' => 3));
208         $result = $rm->get_ratings($toptions);
209         $this->assertEqual(count($result), count($user1posts));
210         $this->assertEqual($result[0]->id, $user1posts[0]->id);
211         $this->assertEqual($result[0]->userid, $user1posts[0]->userid);
212         $this->assertEqual($result[0]->message, $user1posts[0]->message);
213         $this->assertEqual($result[0]->rating->count, 2);
214         $this->assertEqual($result[0]->rating->aggregate, 2);
215         $this->assertEqual($result[0]->rating->rating, 3); //user 3 rated user 1 "3"
216         $this->assertEqual($result[0]->rating->userid, $toptions->userid); // Must be the passed userid
218         // Get results for items of user 1 & 2 together rated by user 3
219         $posts = array_merge($user1posts, $user2posts);
220         $toptions = (object)array_merge($defaultoptions, array('items' => $posts, 'userid' => 3));
221         $result = $rm->get_ratings($toptions);
222         $this->assertEqual(count($result), count($posts));
223         $this->assertEqual($result[0]->id, $posts[0]->id);
224         $this->assertEqual($result[0]->userid, $posts[0]->userid);
225         $this->assertEqual($result[0]->message, $posts[0]->message);
226         $this->assertEqual($result[0]->rating->count, 2);
227         $this->assertEqual($result[0]->rating->aggregate, 2);
228         $this->assertEqual($result[0]->rating->rating, 3); //user 3 rated user 1 "3"
229         $this->assertEqual($result[0]->rating->userid, $toptions->userid); // Must be the passed userid
231         $this->assertEqual($result[1]->id, $posts[1]->id);
232         $this->assertEqual($result[1]->userid, $posts[1]->userid);
233         $this->assertEqual($result[1]->message, $posts[1]->message);
234         $this->assertEqual($result[1]->rating->count, 2);
235         $this->assertEqual($result[1]->rating->aggregate, 3);
236         $this->assertEqual($result[0]->rating->rating, 3); //user 3 rated user 2 "5"
237         $this->assertEqual($result[1]->rating->userid, $toptions->userid); // Must be the passed userid
239         // STEP 3: Some special cases
241         // Get results for user 1's items (expected average 1 + 3 / 2 = 2)
242         // supplying a non-existent user id so no rating from that user should be found
243         $toptions = (object)array_merge($defaultoptions, array('items' => $user1posts));
244         $toptions->userid = 123456; //non-existent user
245         $result = $rm->get_ratings($toptions);
246         $this->assertNull($result[0]->rating->userid);
247         $this->assertNull($result[0]->rating->rating);
248         $this->assertEqual($result[0]->rating->aggregate, 2);//should still get the aggregate
250         // Get results for items of user 2 (expected average 1 + 5 / 2 = 3)
251         // Supplying the user id of the user who owns the items so no rating should be found
252         $toptions = (object)array_merge($defaultoptions, array('items' => $user2posts));
253         $toptions->userid = 2; //user 2 viewing the ratings of their own item
254         $result = $rm->get_ratings($toptions);
255         //these should be null as the user is viewing their own item and thus cannot rate
256         $this->assertNull($result[0]->rating->userid);
257         $this->assertNull($result[0]->rating->rating);
258         $this->assertEqual($result[0]->rating->aggregate, 3);//should still get the aggregate
259     }
262 /**
263  * rating_manager subclass for unit testing without requiring capabilities to be loaded
264  */
265 class mockup_rating_manager extends rating_manager {
267     /**
268      * Overwrite get_plugin_permissions_array() so it always return granted perms for unit testing
269      */
270     public function get_plugin_permissions_array($contextid, $component, $ratingarea) {
271         return array(
272             'rate' => true,
273             'view' => true,
274             'viewany' => true,
275             'viewall' => true);
276     }