e815cf9537901f4b1f7a99fef36e7a92c61377c0
[moodle.git] / favourites / tests / repository_test.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  * Testing the repository objects within core_favourites.
19  *
20  * @package    core_favourites
21  * @category   test
22  * @copyright  2018 Jake Dallimore <jrhdallimore@gmail.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 use \core_favourites\local\repository\favourites_repository;
30 /**
31  * Test class covering the favourites_repository.
32  *
33  * @copyright  2018 Jake Dallimore <jrhdallimore@gmail.com>
34  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35  */
36 class favourites_repository_testcase extends advanced_testcase {
38     public function setUp() {
39         $this->resetAfterTest();
40     }
42     // Basic setup stuff to be reused in most tests.
43     protected function setup_users_and_courses() {
44         $user1 = self::getDataGenerator()->create_user();
45         $user1context = \context_user::instance($user1->id);
46         $user2 = self::getDataGenerator()->create_user();
47         $user2context = \context_user::instance($user2->id);
48         $course1 = self::getDataGenerator()->create_course();
49         $course2 = self::getDataGenerator()->create_course();
50         $course1context = context_course::instance($course1->id);
51         $course2context = context_course::instance($course2->id);
52         return [$user1context, $user2context, $course1context, $course2context];
53     }
55     /**
56      * Verify the basic create operation can create records, and is validated.
57      */
58     public function test_add() {
59         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
61         // Create a favourites repository and favourite a course.
62         $favouritesrepo = new favourites_repository($user1context);
64         $favcourse = (object)[
65             'userid' => $user1context->instanceid,
66             'component' => 'core_course',
67             'itemtype' => 'course',
68             'itemid' => $course1context->instanceid,
69             'contextid' => $course1context->id,
70         ];
71         $timenow = time(); // Reference only, to check that the created item has a time equal to or greater than this.
72         $favourite = $favouritesrepo->add($favcourse);
74         // Verify we get the record back.
75         $this->assertInstanceOf(\stdClass::class, $favourite);
76         $this->assertEquals('core_course', $favourite->component);
77         $this->assertEquals('course', $favourite->itemtype);
79         // Verify the returned object has additional properties, created as part of the add.
80         $this->assertObjectHasAttribute('ordering', $favourite);
81         $this->assertObjectHasAttribute('timecreated', $favourite);
82         $this->assertGreaterThanOrEqual($timenow, $favourite->timecreated);
84         // Try to save the same record again and confirm the store throws an exception.
85         $this->expectException('dml_write_exception');
86         $favouritesrepo->add($favcourse);
87     }
89     /**
90      * Tests that malformed favourites cannot be saved.
91      */
92     public function test_add_malformed_favourite() {
93         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
95         // Create a favourites repository and favourite a course.
96         $favouritesrepo = new favourites_repository($user1context);
98         $favcourse = (object)[
99             'userid' => $user1context->instanceid,
100             'component' => 'core_course',
101             'itemtype' => 'course',
102             'itemid' => $course1context->instanceid,
103             'contextid' => $course1context->id,
104             'anotherfield' => 'cat'
105         ];
107         $this->expectException('moodle_exception');
108         $favouritesrepo->add($favcourse);
109     }
111     /**
112      * Tests that incomplete favourites cannot be saved.
113      */
114     public function test_add_incomplete_favourite() {
115         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
117         // Create a favourites repository and favourite a course.
118         $favouritesrepo = new favourites_repository($user1context);
120         $favcourse = (object)[
121             'component' => 'core_course',
122             'itemtype' => 'course',
123             'itemid' => $course1context->instanceid
124         ];
126         $this->expectException('moodle_exception');
127         $favouritesrepo->add($favcourse);
128     }
130     public function test_add_all_basic() {
131         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
133         // Create a favourites repository and favourite several courses.
134         $favouritesrepo = new favourites_repository($user1context);
135         $favcourses = [];
137         $favcourses[] = (object)[
138             'userid' => $user1context->instanceid,
139             'component' => 'core_course',
140             'itemtype' => 'course',
141             'itemid' => $course1context->instanceid,
142             'contextid' => $course1context->id,
143         ];
144         $favcourses[] = (object)[
145             'userid' => $user1context->instanceid,
146             'component' => 'core_course',
147             'itemtype' => 'course',
148             'itemid' => $course2context->instanceid,
149             'contextid' => $course2context->id,
150         ];
151         $timenow = time(); // Reference only, to check that the created item has a time equal to or greater than this.
152         $favourites = $favouritesrepo->add_all($favcourses);
154         $this->assertInternalType('array', $favourites);
155         $this->assertCount(2, $favourites);
156         foreach ($favourites as $favourite) {
157             // Verify we get the record back.
158             $this->assertEquals('core_course', $favourite->component);
159             $this->assertEquals('course', $favourite->itemtype);
161             // Verify the returned object has additional properties, created as part of the add.
162             $this->assertObjectHasAttribute('ordering', $favourite);
163             $this->assertObjectHasAttribute('timecreated', $favourite);
164             $this->assertGreaterThanOrEqual($timenow, $favourite->timecreated);
165         }
167         // Try to save the same record again and confirm the store throws an exception.
168         $this->expectException('dml_write_exception');
169         $favouritesrepo->add_all($favcourses);
170     }
172     /**
173      * Tests reading from the repository by instance id.
174      */
175     public function test_find() {
176         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
178         // Create a favourites repository and favourite a course.
179         $favouritesrepo = new favourites_repository($user1context);
180         $favourite = (object) [
181             'userid' => $user1context->instanceid,
182             'component' => 'core_course',
183             'itemtype' => 'course',
184             'itemid' => $course1context->instanceid,
185             'contextid' => $course1context->id
186         ];
187         $favourite = $favouritesrepo->add($favourite);
189         // Now, from the repo, get the single favourite we just created, by id.
190         $userfavourite = $favouritesrepo->find($favourite->id);
191         $this->assertInstanceOf(\stdClass::class, $userfavourite);
192         $this->assertObjectHasAttribute('timecreated', $userfavourite);
194         // Try to get a favourite we know doesn't exist.
195         // We expect an exception in this case.
196         $this->expectException(dml_exception::class);
197         $favouritesrepo->find(1);
198     }
200     /**
201      * Test verifying that find_all() returns all favourites, or an empty array.
202      */
203     public function test_find_all() {
204         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
206         $favouritesrepo = new favourites_repository($user1context);
208         // Verify that for an empty repository, find_all returns an empty array.
209         $this->assertEquals([], $favouritesrepo->find_all());
211         // Save a favourite for 2 courses, in different areas.
212         $favourite = (object) [
213             'userid' => $user1context->instanceid,
214             'component' => 'core_course',
215             'itemtype' => 'course',
216             'itemid' => $course1context->instanceid,
217             'contextid' => $course1context->id
218         ];
219         $favourite2 = (object) [
220             'userid' => $user1context->instanceid,
221             'component' => 'core_course',
222             'itemtype' => 'anothertype',
223             'itemid' => $course2context->instanceid,
224             'contextid' => $course2context->id
225         ];
226         $favouritesrepo->add($favourite);
227         $favouritesrepo->add($favourite2);
229         // Verify that find_all returns both of our favourites.
230         $favourites = $favouritesrepo->find_all();
231         $this->assertCount(2, $favourites);
232         foreach ($favourites as $fav) {
233             $this->assertObjectHasAttribute('id', $fav);
234             $this->assertObjectHasAttribute('timecreated', $fav);
235         }
236     }
238     /**
239      * Test retrieval of a user's favourites for a given criteria, in this case, area.
240      */
241     public function test_find_by() {
242         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
244         // Create a favourites repository and favourite a course.
245         $favouritesrepo = new favourites_repository($user1context);
246         $favourite = (object) [
247             'userid' => $user1context->instanceid,
248             'component' => 'core_course',
249             'itemtype' => 'course',
250             'itemid' => $course1context->instanceid,
251             'contextid' => $course1context->id
252         ];
253         $favouritesrepo->add($favourite);
255         // From the repo, get the list of favourites for the 'core_course/course' area.
256         $userfavourites = $favouritesrepo->find_by(['component' => 'core_course', 'itemtype' => 'course']);
257         $this->assertInternalType('array', $userfavourites);
258         $this->assertCount(1, $userfavourites);
260         // Try to get a list of favourites for a non-existent area.
261         $userfavourites = $favouritesrepo->find_by(['component' => 'core_cannibalism', 'itemtype' => 'course']);
262         $this->assertInternalType('array', $userfavourites);
263         $this->assertCount(0, $userfavourites);
264     }
266     /**
267      * Test the count_by() method.
268      */
269     public function test_count_by() {
270         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
272         // Create a favourites repository and add 2 favourites in different areas.
273         $favouritesrepo = new favourites_repository($user1context);
274         $favourite = (object) [
275             'userid' => $user1context->instanceid,
276             'component' => 'core_course',
277             'itemtype' => 'course',
278             'itemid' => $course1context->instanceid,
279             'contextid' => $course1context->id
280         ];
281         $favourite2 = (object) [
282             'userid' => $user1context->instanceid,
283             'component' => 'core_course',
284             'itemtype' => 'anothertype',
285             'itemid' => $course2context->instanceid,
286             'contextid' => $course2context->id
287         ];
288         $favouritesrepo->add($favourite);
289         $favouritesrepo->add($favourite2);
291         // Verify counts can be restricted by criteria.
292         $this->assertEquals(1, $favouritesrepo->count_by(['userid' => $user1context->instanceid, 'component' => 'core_course',
293                 'itemtype' => 'course']));
294         $this->assertEquals(1, $favouritesrepo->count_by(['userid' => $user1context->instanceid, 'component' => 'core_course',
295             'itemtype' => 'anothertype']));
296         $this->assertEquals(0, $favouritesrepo->count_by(['userid' => $user1context->instanceid, 'component' => 'core_course',
297             'itemtype' => 'nonexistenttype']));
298     }
300     public function test_exists() {
301         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
303         // Create a favourites repository and favourite a course.
304         $favouritesrepo = new favourites_repository($user1context);
305         $favourite = (object) [
306             'userid' => $user1context->instanceid,
307             'component' => 'core_course',
308             'itemtype' => 'course',
309             'itemid' => $course1context->instanceid,
310             'contextid' => $course1context->id
311         ];
312         $createdfavourite = $favouritesrepo->add($favourite);
314         // Verify the existence of the favourite in the repo.
315         $this->assertTrue($favouritesrepo->exists($createdfavourite->id));
317         // Verify exists returns false for non-existent favourite.
318         $this->assertFalse($favouritesrepo->exists(1));
319     }
321     public function test_exists_by_area() {
322         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
324         // Create a favourites repository and favourite two courses, in different areas.
325         $favouritesrepo = new favourites_repository($user1context);
326         $favourite = (object) [
327             'userid' => $user1context->instanceid,
328             'component' => 'core_course',
329             'itemtype' => 'course',
330             'itemid' => $course1context->instanceid,
331             'contextid' => $course1context->id
332         ];
333         $favourite2 = (object) [
334             'userid' => $user1context->instanceid,
335             'component' => 'core_course',
336             'itemtype' => 'anothertype',
337             'itemid' => $course2context->instanceid,
338             'contextid' => $course2context->id
339         ];
340         $favourite1 = $favouritesrepo->add($favourite);
341         $favourite2 = $favouritesrepo->add($favourite2);
343         // Verify the existence of the favourites.
344         $this->assertTrue($favouritesrepo->exists_by_area($user1context->instanceid, 'core_course', 'course', $favourite1->itemid,
345             $favourite1->contextid));
346         $this->assertTrue($favouritesrepo->exists_by_area($user1context->instanceid, 'core_course', 'anothertype',
347             $favourite2->itemid, $favourite2->contextid));
349         // Verify that we can't find a favourite from one area, in another.
350         $this->assertFalse($favouritesrepo->exists_by_area($user1context->instanceid, 'core_course', 'anothertype',
351             $favourite1->itemid, $favourite1->contextid));
352     }
354     /**
355      * Test the update() method, by simulating a user changing the ordering of a favourite.
356      */
357     public function test_update() {
358         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
360         // Create a favourites repository and favourite a course.
361         $favouritesrepo = new favourites_repository($user1context);
362         $favourite = (object) [
363             'userid' => $user1context->instanceid,
364             'component' => 'core_course',
365             'itemtype' => 'course',
366             'itemid' => $course1context->instanceid,
367             'contextid' => $course1context->id
368         ];
369         $favourite1 = $favouritesrepo->add($favourite);
371         // Verify we can update the ordering for 2 favourites.
372         $favourite1->ordering = 1;
373         $favourite1 = $favouritesrepo->update($favourite1);
374         $this->assertInstanceOf(stdClass::class, $favourite1);
375         $this->assertAttributeEquals('1', 'ordering', $favourite1);
376     }
378     public function test_delete() {
379         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
381         // Create a favourites repository and favourite a course.
382         $favouritesrepo = new favourites_repository($user1context);
383         $favourite = (object) [
384             'userid' => $user1context->instanceid,
385             'component' => 'core_course',
386             'itemtype' => 'course',
387             'itemid' => $course1context->instanceid,
388             'contextid' => $course1context->id
389         ];
390         $favourite = $favouritesrepo->add($favourite);
392         // Verify the existence of the favourite in the repo.
393         $this->assertTrue($favouritesrepo->exists($favourite->id));
395         // Now, delete the favourite and confirm it's not retrievable.
396         $favouritesrepo->delete($favourite->id);
397         $this->assertFalse($favouritesrepo->exists($favourite->id));
398     }
400     public function test_delete_by_area() {
401         list($user1context, $user2context, $course1context, $course2context) = $this->setup_users_and_courses();
403         // Create a favourites repository and favourite two courses, in different areas.
404         $favouritesrepo = new favourites_repository($user1context);
405         $favourite = (object) [
406             'userid' => $user1context->instanceid,
407             'component' => 'core_course',
408             'itemtype' => 'course',
409             'itemid' => $course1context->instanceid,
410             'contextid' => $course1context->id
411         ];
412         $favourite2 = (object) [
413             'userid' => $user1context->instanceid,
414             'component' => 'core_course',
415             'itemtype' => 'anothertype',
416             'itemid' => $course2context->instanceid,
417             'contextid' => $course2context->id
418         ];
419         $favourite1 = $favouritesrepo->add($favourite);
420         $favourite2 = $favouritesrepo->add($favourite2);
422         // Verify we have 2 items in the repo.
423         $this->assertEquals(2, $favouritesrepo->count());
425         // Try to delete by a non-existent area, and confirm it doesn't remove anything.
426         $favouritesrepo->delete_by_area($user1context->instanceid, 'core_course', 'donaldduck');
427         $this->assertEquals(2, $favouritesrepo->count());
429         // Try to delete by a non-existent area, and confirm it doesn't remove anything.
430         $favouritesrepo->delete_by_area($user1context->instanceid, 'core_course', 'cat');
431         $this->assertEquals(2, $favouritesrepo->count());
433         // Delete by area, and confirm we have one record left, from the 'core_course/anothertype' area.
434         $favouritesrepo->delete_by_area($user1context->instanceid, 'core_course', 'course');
435         $this->assertEquals(1, $favouritesrepo->count());
436         $this->assertFalse($favouritesrepo->exists($favourite1->id));
437         $this->assertTrue($favouritesrepo->exists($favourite2->id));
438     }