2 // This file is part of Moodle - http://moodle.org/
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.
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/>.
18 * Testing the repository objects within core_favourites.
20 * @package core_favourites
22 * @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
28 use \core_favourites\local\repository\favourites_repository;
31 * Test class covering the favourites_repository.
33 * @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 class favourites_repository_testcase extends advanced_testcase {
38 public function setUp() {
39 $this->resetAfterTest();
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];
56 * Verify the basic create operation can create records, and is validated.
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,
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);
90 * Tests that malformed favourites cannot be saved.
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'
107 $this->expectException('moodle_exception');
108 $favouritesrepo->add($favcourse);
112 * Tests that incomplete favourites cannot be saved.
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
126 $this->expectException('moodle_exception');
127 $favouritesrepo->add($favcourse);
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);
137 $favcourses[] = (object)[
138 'userid' => $user1context->instanceid,
139 'component' => 'core_course',
140 'itemtype' => 'course',
141 'itemid' => $course1context->instanceid,
142 'contextid' => $course1context->id,
144 $favcourses[] = (object)[
145 'userid' => $user1context->instanceid,
146 'component' => 'core_course',
147 'itemtype' => 'course',
148 'itemid' => $course2context->instanceid,
149 'contextid' => $course2context->id,
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);
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);
173 * Tests reading from the repository by instance id.
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
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);
201 * Test verifying that find_all() returns all favourites, or an empty array.
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
219 $favourite2 = (object) [
220 'userid' => $user1context->instanceid,
221 'component' => 'core_course',
222 'itemtype' => 'anothertype',
223 'itemid' => $course2context->instanceid,
224 'contextid' => $course2context->id
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);
239 * Test retrieval of a user's favourites for a given criteria, in this case, area.
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
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);
267 * Test the count_by() method.
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
281 $favourite2 = (object) [
282 'userid' => $user1context->instanceid,
283 'component' => 'core_course',
284 'itemtype' => 'anothertype',
285 'itemid' => $course2context->instanceid,
286 'contextid' => $course2context->id
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']));
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
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));
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
333 $favourite2 = (object) [
334 'userid' => $user1context->instanceid,
335 'component' => 'core_course',
336 'itemtype' => 'anothertype',
337 'itemid' => $course2context->instanceid,
338 'contextid' => $course2context->id
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));
355 * Test the update() method, by simulating a user changing the ordering of a favourite.
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
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);
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
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));
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
412 $favourite2 = (object) [
413 'userid' => $user1context->instanceid,
414 'component' => 'core_course',
415 'itemtype' => 'anothertype',
416 'itemid' => $course2context->instanceid,
417 'contextid' => $course2context->id
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));