Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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/>.
16
 
17
namespace tool_usertours;
18
 
19
/**
20
 * Tests for tour.
21
 *
22
 * @package    tool_usertours
23
 * @copyright  2016 Andrew Nicols <andrew@nicols.co.uk>
24
 * @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25
 * @covers    \tool_usertours\tour
26
 */
1441 ariadna 27
final class tour_test extends \advanced_testcase {
1 efrain 28
    /**
29
     * @var moodle_database
30
     */
31
    protected $db;
32
 
33
    public static function setUpBeforeClass(): void {
34
        global $CFG;
35
        require_once($CFG->libdir . '/formslib.php');
1441 ariadna 36
        parent::setUpBeforeClass();
1 efrain 37
    }
38
 
39
    /**
40
     * Setup to store the DB reference.
41
     */
42
    public function setUp(): void {
43
        global $DB;
1441 ariadna 44
        parent::setUp();
1 efrain 45
 
46
        $this->db = $DB;
47
    }
48
 
49
    /**
50
     * Tear down to restore the original DB reference.
51
     */
52
    public function tearDown(): void {
53
        global $DB;
54
 
55
        $DB = $this->db;
1441 ariadna 56
        parent::tearDown();
1 efrain 57
    }
58
 
59
    /**
60
     * Helper to mock the database.
61
     *
62
     * @return \PHPUnit\Framework\MockObject\MockObject
63
     */
64
    public function mock_database() {
65
        global $DB;
66
 
67
        $DB = $this->getMockBuilder(\moodle_database::class)
68
            ->getMock();
69
 
70
        return $DB;
71
    }
72
 
73
    /**
74
     * Data provider for the dirty value tester.
75
     *
76
     * @return array
77
     */
78
    public static function dirty_value_provider(): array {
79
        return [
80
            'name' => [
81
                'name',
82
                ['Lorem'],
83
            ],
84
            'description' => [
85
                'description',
86
                ['Lorem'],
87
            ],
88
            'pathmatch' => [
89
                'pathmatch',
90
                ['Lorem'],
91
            ],
92
            'enabled' => [
93
                'enabled',
94
                ['Lorem'],
95
            ],
96
            'sortorder' => [
97
                'sortorder',
98
                [1],
99
            ],
100
            'config' => [
101
                'config',
102
                ['key', 'value'],
103
            ],
104
            'showtourwhen' => [
105
                'showtourwhen',
106
                [0],
107
            ],
108
        ];
109
    }
110
 
111
    /**
112
     * Test that setters mark things as dirty.
113
     *
114
     * @dataProvider dirty_value_provider
115
     * @param   string  $name           The name of the key being tested
116
     * @param   mixed   $value          The value being set
117
     */
118
    public function test_dirty_values($name, $value): void {
119
        $tour = new \tool_usertours\tour();
120
        $method = 'set_' . $name;
121
        call_user_func_array([$tour, $method], $value);
122
 
123
        $rc = new \ReflectionClass(\tool_usertours\tour::class);
124
        $rcp = $rc->getProperty('dirty');
125
 
126
        $this->assertTrue($rcp->getValue($tour));
127
    }
128
 
129
    /**
130
     * Data provider for the get_ tests.
131
     *
132
     * @return array
133
     */
134
    public static function getter_provider(): array {
135
        return [
136
            'id' => [
137
                'id',
138
                rand(1, 100),
139
            ],
140
            'name' => [
141
                'name',
142
                'Lorem',
143
            ],
144
            'description' => [
145
                'description',
146
                'Lorem',
147
            ],
148
            'pathmatch' => [
149
                'pathmatch',
150
                'Lorem',
151
            ],
152
            'enabled' => [
153
                'enabled',
154
                'Lorem',
155
            ],
156
            'sortorder' => [
157
                'sortorder',
158
                rand(1, 100),
159
            ],
160
            'config' => [
161
                'config',
162
                ['key', 'value'],
163
            ],
164
        ];
165
    }
166
 
167
    /**
168
     * Test that getters return the configured value.
169
     *
170
     * @dataProvider getter_provider
171
     * @param   string  $key            The name of the key being tested
172
     * @param   mixed   $value          The value being set
173
     */
174
    public function test_getters($key, $value): void {
175
        $tour = new \tool_usertours\tour();
176
 
177
        $rc = new \ReflectionClass(tour::class);
178
 
179
        $rcp = $rc->getProperty($key);
180
        $rcp->setValue($tour, $value);
181
 
182
        $getter = 'get_' . $key;
183
 
184
        $this->assertEquals($value, $tour->$getter());
185
    }
186
 
187
    /**
188
     * Ensure that non-dirty tours are not persisted.
189
     */
190
    public function test_persist_non_dirty(): void {
191
        $tour = $this->getMockBuilder(tour::class)
192
            ->onlyMethods(['to_record'])
193
            ->getMock();
194
 
195
        $tour->expects($this->never())
196
            ->method('to_record');
197
 
198
        $this->assertSame($tour, $tour->persist());
199
    }
200
 
201
    /**
202
     * Ensure that new dirty tours are persisted.
203
     */
204
    public function test_persist_dirty_new(): void {
205
        // Mock the database.
206
        $DB = $this->mock_database();
207
 
208
        $DB->expects($this->never())
209
            ->method('update_record');
210
 
211
        $id = rand(1, 100);
212
        $DB->expects($this->once())
213
            ->method('insert_record')
214
            ->willReturn($id);
215
 
216
        // Mock the tour.
217
        $tour = $this->getMockBuilder(tour::class)
218
            ->onlyMethods([
219
                'to_record',
220
                'reload',
221
            ])
222
            ->getMock();
223
 
224
        $tour->expects($this->once())
225
            ->method('to_record');
226
 
227
        $tour->expects($this->once())
228
            ->method('reload');
229
 
230
        $rc = new \ReflectionClass(tour::class);
231
 
232
        $rcp = $rc->getProperty('dirty');
233
        $rcp->setValue($tour, true);
234
 
235
        $this->assertSame($tour, $tour->persist());
236
 
237
        $rcp = $rc->getProperty('id');
238
        $this->assertEquals($id, $rcp->getValue($tour));
239
    }
240
 
241
    /**
242
     * Ensure that non-dirty, forced tours are persisted.
243
     */
244
    public function test_persist_force_new(): void {
245
        global $DB;
246
 
247
        // Mock the database.
248
        $DB = $this->mock_database();
249
 
250
        $DB->expects($this->never())
251
            ->method('update_record');
252
 
253
        $id = rand(1, 100);
254
        $DB->expects($this->once())
255
            ->method('insert_record')
256
            ->willReturn($id);
257
 
258
        // Mock the tour.
259
        $tour = $this->getMockBuilder(tour::class)
260
            ->onlyMethods([
261
                'to_record',
262
                'reload',
263
            ])
264
            ->getMock();
265
 
266
        $tour->expects($this->once())
267
            ->method('to_record');
268
 
269
        $tour->expects($this->once())
270
            ->method('reload');
271
 
272
        $this->assertSame($tour, $tour->persist(true));
273
 
274
        $rc = new \ReflectionClass(tour::class);
275
        $rcp = $rc->getProperty('id');
276
        $this->assertEquals($id, $rcp->getValue($tour));
277
    }
278
 
279
    /**
280
     * Ensure that dirty tours are persisted.
281
     */
282
    public function test_persist_dirty_existing(): void {
283
        // Mock the database.
284
        $DB = $this->mock_database();
285
        $DB->expects($this->once())
286
            ->method('update_record')
287
            ->willReturn($this->returnSelf());
288
 
289
        $DB->expects($this->never())
290
            ->method('insert_record');
291
 
292
        // Mock the tour.
293
        $tour = $this->getMockBuilder(tour::class)
294
            ->onlyMethods([
295
                'to_record',
296
                'reload',
297
            ])
298
            ->getMock();
299
 
300
        $tour->expects($this->once())
301
            ->method('to_record');
302
 
303
        $tour->expects($this->once())
304
            ->method('reload');
305
 
306
        $rc = new \ReflectionClass(tour::class);
307
 
308
        $rcp = $rc->getProperty('id');
309
        $rcp->setValue($tour, 42);
310
 
311
        $rcp = $rc->getProperty('dirty');
312
        $rcp->setValue($tour, true);
313
 
314
        $this->assertSame($tour, $tour->persist());
315
    }
316
 
317
    /**
318
     * Ensure that non-dirty, forced tours are persisted.
319
     */
320
    public function test_persist_force(): void {
321
        global $DB;
322
 
323
        // Mock the database.
324
        $DB = $this->mock_database();
325
 
326
        $DB->expects($this->once())
327
            ->method('update_record')
328
            ->willReturn($this->returnSelf());
329
 
330
        $DB->expects($this->never())
331
            ->method('insert_record');
332
 
333
        // Mock the tour.
334
        $tour = $this->getMockBuilder(tour::class)
335
            ->onlyMethods([
336
                'to_record',
337
                'reload',
338
            ])
339
            ->getMock();
340
 
341
        $tour->expects($this->once())
342
            ->method('to_record');
343
 
344
        $tour->expects($this->once())
345
            ->method('reload');
346
 
347
        $rc = new \ReflectionClass(tour::class);
348
 
349
        $rcp = $rc->getProperty('id');
350
        $rcp->setValue($tour, 42);
351
 
352
        $rcp = $rc->getProperty('dirty');
353
        $rcp->setValue($tour, true);
354
 
355
        $this->assertSame($tour, $tour->persist(true));
356
    }
357
 
358
    /**
359
     * Test setting config.
360
     */
361
    public function test_set_config(): void {
362
        $tour = new \tool_usertours\tour();
363
 
364
        $tour->set_config('key', 'value');
365
        $tour->set_config('another', [
366
            'foo' => 'bar',
367
        ]);
368
 
369
        $rc = new \ReflectionClass(tour::class);
370
        $rcp = $rc->getProperty('config');
371
        $this->assertEquals((object) [
372
            'key' => 'value',
373
            'another' => [
374
                'foo' => 'bar',
375
            ],
376
        ], $rcp->getValue($tour));
377
    }
378
 
379
    /**
380
     * Test get_config with no keys provided.
381
     */
382
    public function test_get_config_no_keys(): void {
383
        $tour = new \tool_usertours\tour();
384
 
385
        $rc = new \ReflectionClass(tour::class);
386
        $rcp = $rc->getProperty('config');
387
 
388
        $allvalues = (object) [
389
            'some' => 'value',
390
            'another' => 42,
391
            'key' => [
392
                'somethingelse',
393
            ],
394
        ];
395
 
396
        $rcp->setValue($tour, $allvalues);
397
 
398
        $this->assertEquals($allvalues, $tour->get_config());
399
    }
400
 
401
    /**
402
     * Data provider for get_config.
403
     *
404
     * @return array
405
     */
406
    public static function get_config_provider(): array {
407
        $allvalues = (object) [
408
            'some' => 'value',
409
            'another' => 42,
410
            'key' => [
411
                'somethingelse',
412
            ],
413
        ];
414
 
415
        return [
416
            'No nitial config' => [
417
                null,
418
                null,
419
                null,
420
                (object) [],
421
            ],
422
            'All values' => [
423
                $allvalues,
424
                null,
425
                null,
426
                $allvalues,
427
            ],
428
            'Valid string value' => [
429
                $allvalues,
430
                'some',
431
                null,
432
                'value',
433
            ],
434
            'Valid array value' => [
435
                $allvalues,
436
                'key',
437
                null,
438
                ['somethingelse'],
439
            ],
440
            'Invalid value' => [
441
                $allvalues,
442
                'notavalue',
443
                null,
444
                null,
445
            ],
446
            'Configuration value' => [
447
                $allvalues,
448
                'placement',
449
                null,
450
                \tool_usertours\configuration::get_default_value('placement'),
451
            ],
452
            'Invalid value with default' => [
453
                $allvalues,
454
                'notavalue',
455
                'somedefault',
456
                'somedefault',
457
            ],
458
        ];
459
    }
460
 
461
    /**
462
     * Test get_config with valid keys provided.
463
     *
464
     * @dataProvider get_config_provider
465
     * @param   object  $values     The config values
466
     * @param   string  $key        The key
467
     * @param   mixed   $default    The default value
468
     * @param   mixed   $expected   The expected value
469
     */
470
    public function test_get_config_valid_keys($values, $key, $default, $expected): void {
471
        $tour = new \tool_usertours\tour();
472
 
473
        $rc = new \ReflectionClass(tour::class);
474
        $rcp = $rc->getProperty('config');
475
        $rcp->setValue($tour, $values);
476
 
477
        $this->assertEquals($expected, $tour->get_config($key, $default));
478
    }
479
 
480
    /**
481
     * Check that a tour which has never been persisted is removed correctly.
482
     */
483
    public function test_remove_non_persisted(): void {
484
        $tour = $this->getMockBuilder(tour::class)
485
            ->onlyMethods([
486
                'get_steps',
487
            ])
488
            ->getMock();
489
 
490
        $tour->expects($this->never())
491
            ->method('get_steps');
492
 
493
        // Mock the database.
494
        $DB = $this->mock_database();
495
        $DB->expects($this->never())
496
            ->method('delete_records');
497
 
498
        $this->assertNull($tour->remove());
499
    }
500
 
501
    /**
502
     * Check that a tour which has been persisted is removed correctly.
503
     */
504
    public function test_remove_persisted(): void {
505
        $id = rand(1, 100);
506
 
507
        $tour = $this->getMockBuilder(tour::class)
508
            ->onlyMethods([
509
                'get_steps',
510
            ])
511
            ->getMock();
512
 
513
        $rc = new \ReflectionClass(tour::class);
514
        $rcp = $rc->getProperty('id');
515
        $rcp->setValue($tour, $id);
516
 
517
        $step = $this->getMockBuilder(\tool_usertours\step::class)
518
            ->onlyMethods([
519
                'remove',
520
            ])
521
            ->getMock();
522
 
523
        $tour->expects($this->once())
524
            ->method('get_steps')
525
            ->willReturn([$step]);
526
 
527
        // Mock the database.
528
        $DB = $this->mock_database();
529
 
1441 ariadna 530
        $deleteinvocations = $this->exactly(3);
531
        $DB->expects($deleteinvocations)
1 efrain 532
            ->method('delete_records')
1441 ariadna 533
            ->willReturnCallback(function ($table, $conditions) use ($deleteinvocations, $id) {
534
                switch (self::getInvocationCount($deleteinvocations)) {
535
                    case 1:
536
                        $this->assertEquals('tool_usertours_tours', $table);
537
                        $this->assertEquals(['id' => $id], $conditions);
538
                        return null;
539
                        break;
540
                    case 2:
541
                        $this->assertEquals('user_preferences', $table);
542
                        $this->assertEquals(['name' => tour::TOUR_LAST_COMPLETED_BY_USER . $id], $conditions);
543
                        return null;
544
                        break;
545
                    case 3:
546
                        $this->assertEquals('user_preferences', $table);
547
                        $this->assertEquals(['name' => tour::TOUR_REQUESTED_BY_USER . $id], $conditions);
548
                        return null;
549
                        break;
550
                    default:
551
                        $this->fail('Unexpected call to delete_records');
552
                }
553
            });
1 efrain 554
 
555
        $DB->expects($this->once())
556
            ->method('get_records')
557
            ->with($this->equalTo('tool_usertours_tours'), $this->equalTo(null))
558
            ->willReturn([]);
559
 
560
        $this->assertNull($tour->remove());
561
    }
562
 
563
    /**
564
     * Teset that sortorder is reset according to sortorder with values from 0.
565
     */
566
    public function test_reset_step_sortorder(): void {
567
        $tour = new \tool_usertours\tour();
568
 
569
        $mockdata = [];
570
        for ($i = 4; $i >= 0; $i--) {
571
            $id = rand($i * 10, ($i * 10) + 9);
572
            $mockdata[] = (object) ['id' => $id];
1441 ariadna 573
            $expectations[] = [4 - $i, ['id' => $id]];
1 efrain 574
        }
575
 
576
        // Mock the database.
577
        $DB = $this->mock_database();
578
        $DB->expects($this->once())
579
            ->method('get_records')
580
            ->willReturn($mockdata);
581
 
1441 ariadna 582
        $setfieldinvocations = $this->exactly(5);
583
        $DB->expects($setfieldinvocations)
584
            ->method('set_field')
585
            ->willReturnCallback(function ($table, $field, $value, $conditions) use (
586
                $setfieldinvocations,
587
                $expectations,
588
            ): void {
589
                $expectation = $expectations[self::getInvocationCount($setfieldinvocations) - 1];
590
                $this->assertEquals('tool_usertours_steps', $table);
591
                $this->assertEquals('sortorder', $field);
592
                $this->assertEquals($expectation[0], $value);
593
                $this->assertEquals($expectation[1], $conditions);
594
            });
1 efrain 595
 
596
        $tour->reset_step_sortorder();
597
    }
598
 
599
    /**
600
     * Test that a disabled tour should never be shown to users.
601
     */
602
    public function test_should_show_for_user_disabled(): void {
603
        $tour = new \tool_usertours\tour();
604
        $tour->set_enabled(false);
605
 
606
        $this->assertFalse($tour->should_show_for_user());
607
    }
608
 
609
    /**
610
     * Provider for should_show_for_user.
611
     *
612
     * @return array
613
     */
614
    public static function should_show_for_user_provider(): array {
615
        $time = time();
616
        return [
617
            'Not seen by user at all' => [
618
                null,
619
                null,
620
                null,
621
                [],
622
                true,
623
            ],
624
            'Completed by user before majorupdatetime' => [
625
                $time - DAYSECS,
626
                null,
627
                $time,
628
                [],
629
                true,
630
            ],
631
            'Completed by user since majorupdatetime' => [
632
                $time,
633
                null,
634
                $time - DAYSECS,
635
                [],
636
                false,
637
            ],
638
            'Requested by user before current completion' => [
639
                $time,
640
                $time - DAYSECS,
641
                $time - MINSECS,
642
                [],
643
                false,
644
            ],
645
            'Requested by user since completion' => [
646
                $time - DAYSECS,
647
                $time,
648
                'null',
649
                [],
650
                true,
651
            ],
652
            'Tour will show on each load' => [
653
                $time,
654
                $time - DAYSECS,
655
                null,
656
                [
657
                    'showtourwhen' => tour::SHOW_TOUR_ON_EACH_PAGE_VISIT,
658
                ],
659
                true,
660
            ],
661
        ];
662
    }
663
 
664
    /**
665
     * Test that a disabled tour should never be shown to users.
666
     *
667
     * @dataProvider should_show_for_user_provider
668
     * @param   mixed   $completiondate The user's completion date for this tour
669
     * @param   mixed   $requesteddate  The user's last requested date for this tour
670
     * @param   mixed   $updateddate    The date this tour was last updated
671
     * @param   mixed   $config         The tour config to apply
672
     * @param   string  $expectation    The expected tour key
673
     */
674
    public function test_should_show_for_user(
675
        $completiondate,
676
        $requesteddate,
677
        $updateddate,
678
        $config,
679
        $expectation,
680
    ): void {
681
        // Uses user preferences so we must be in a user context.
682
        $this->resetAfterTest();
683
        $this->setAdminUser();
684
 
685
        $tour = $this->getMockBuilder(tour::class)
686
            ->onlyMethods([
687
                'get_id',
688
                'is_enabled',
689
            ])
690
            ->getMock();
691
 
692
        $tour->method('is_enabled')
693
            ->willReturn(true);
694
 
695
        foreach ($config as $key => $value) {
696
            $tour->set_config($key, $value);
697
        }
698
 
699
        $id = rand(1, 100);
700
        $tour->method('get_id')
701
            ->willReturn($id);
702
 
703
        if ($completiondate !== null) {
704
            set_user_preference(\tool_usertours\tour::TOUR_LAST_COMPLETED_BY_USER . $id, $completiondate);
705
        }
706
 
707
        if ($requesteddate !== null) {
708
            set_user_preference(\tool_usertours\tour::TOUR_REQUESTED_BY_USER . $id, $requesteddate);
709
        }
710
 
711
        if ($updateddate !== null) {
712
            $tour->set_config('majorupdatetime', $updateddate);
713
        }
714
 
715
        $this->assertEquals($expectation, $tour->should_show_for_user());
716
    }
717
 
718
    /**
719
     * Provider for get_tour_key.
720
     *
721
     * @return array
722
     */
723
    public static function get_tour_key_provider(): array {
724
        $id = rand(1, 100);
725
        $time = time();
726
 
727
        return [
728
            'No initial values' => [
729
                $id,
730
                [null, $time],
731
                static::logicalOr(
732
                    new \PHPUnit\Framework\Constraint\IsEqual($time),
733
                    new \PHPUnit\Framework\Constraint\GreaterThan($time),
734
                ),
735
                true,
736
                null,
737
                sprintf('tool_usertours_\d_%d_%s', $id, $time),
738
            ],
739
 
740
            'Initial tour time, no user pref' => [
741
                $id,
742
                [$time],
743
                null,
744
                false,
745
                null,
746
                sprintf('tool_usertours_\d_%d_%s', $id, $time),
747
            ],
748
            'Initial tour time, with user reset lower' => [
749
                $id,
750
                [$time],
751
                null,
752
                false,
753
                $time - DAYSECS,
754
                sprintf('tool_usertours_\d_%d_%s', $id, $time),
755
            ],
756
            'Initial tour time, with user reset higher' => [
757
                $id,
758
                [$time],
759
                null,
760
                false,
761
                $time + DAYSECS,
762
                sprintf('tool_usertours_\d_%d_%s', $id, $time + DAYSECS),
763
            ],
764
        ];
765
    }
766
 
767
    /**
768
     * Test that get_tour_key provides the anticipated unique keys.
769
     *
770
     * @dataProvider get_tour_key_provider
771
     * @param   int     $id             The tour ID
772
     * @param   array   $getconfig      The mocked values for get_config calls
773
     * @param   array   $setconfig      The mocked values for set_config calls
774
     * @param   bool    $willpersist    Whether a persist is expected
775
     * @param   mixed   $userpref       The value to set for the user preference
776
     * @param   string  $expectation    The expected tour key
777
     */
778
    public function test_get_tour_key($id, $getconfig, $setconfig, $willpersist, $userpref, $expectation): void {
779
        // Uses user preferences so we must be in a user context.
780
        $this->resetAfterTest();
781
        $this->setAdminUser();
782
 
783
        $tour = $this->getMockBuilder(tour::class)
784
            ->onlyMethods([
785
                'get_config',
786
                'set_config',
787
                'get_id',
788
                'persist',
789
            ])
790
            ->getMock();
791
 
792
        if ($getconfig) {
1441 ariadna 793
            $getinvocations = $this->exactly(count($getconfig));
794
            $tour->expects($getinvocations)
1 efrain 795
                ->method('get_config')
1441 ariadna 796
                ->willReturnCallback(function () use ($getinvocations, $getconfig) {
797
                    return $getconfig[self::getInvocationCount($getinvocations) - 1];
798
                });
1 efrain 799
        }
800
 
801
        if ($setconfig) {
802
            $tour->expects($this->once())
803
                ->method('set_config')
804
                ->with($this->equalTo('majorupdatetime'), $setconfig)
805
                ->will($this->returnSelf());
806
        } else {
807
            $tour->expects($this->never())
808
                ->method('set_config');
809
        }
810
 
811
        if ($willpersist) {
812
            $tour->expects($this->once())
813
                ->method('persist');
814
        } else {
815
            $tour->expects($this->never())
816
                ->method('persist');
817
        }
818
 
819
        $tour->expects($this->any())
820
            ->method('get_id')
821
            ->willReturn($id);
822
 
823
        if ($userpref !== null) {
824
            set_user_preference(\tool_usertours\tour::TOUR_REQUESTED_BY_USER . $id, $userpref);
825
        }
826
 
827
        $this->assertMatchesRegularExpression(
828
            '/' . $expectation . '/',
829
            $tour->get_tour_key()
830
        );
831
    }
832
 
833
    /**
834
     * Ensure that the request_user_reset function sets an appropriate value for the tour.
835
     */
836
    public function test_requested_user_reset(): void {
837
        $tour = $this->getMockBuilder(tour::class)
838
            ->onlyMethods([
839
                'get_id',
840
            ])
841
            ->getMock();
842
 
843
        $id = rand(1, 100);
844
        $time = time();
845
 
846
        $tour->expects($this->once())
847
            ->method('get_id')
848
            ->willReturn($id);
849
 
850
        $tour->request_user_reset();
851
 
852
        $this->assertGreaterThanOrEqual($time, get_user_preferences(\tool_usertours\tour::TOUR_REQUESTED_BY_USER . $id));
853
    }
854
 
855
    /**
856
     * Ensure that the request_user_reset function sets an appropriate value for the tour.
857
     */
858
    public function test_mark_user_completed(): void {
859
        $tour = $this->getMockBuilder(tour::class)
860
            ->onlyMethods([
861
                'get_id',
862
            ])
863
            ->getMock();
864
 
865
        $id = rand(1, 100);
866
        $time = time();
867
 
868
        $tour->expects($this->once())
869
            ->method('get_id')
870
            ->willReturn($id);
871
 
872
        $tour->mark_user_completed();
873
 
874
        $this->assertGreaterThanOrEqual($time, get_user_preferences(\tool_usertours\tour::TOUR_LAST_COMPLETED_BY_USER . $id));
875
    }
876
 
877
    /**
878
     * Provider for the is_first_tour and is_last_tour tests.
879
     *
880
     * @return array
881
     */
882
    public static function sortorder_first_last_provider(): array {
883
        $topcount = rand(10, 100);
884
        return [
885
            'Only tour => first + last' => [
886
                0,
887
                true,
888
                1,
889
                true,
890
            ],
891
            'First tour of many' => [
892
                0,
893
                true,
894
                $topcount,
895
                false,
896
            ],
897
            'Last tour of many' => [
898
                $topcount - 1,
899
                false,
900
                $topcount,
901
                true,
902
            ],
903
            'Middle tour of many' => [
904
                5,
905
                false,
906
                $topcount,
907
                false,
908
            ],
909
        ];
910
    }
911
 
912
    /**
913
     * Test the is_first_tour() function.
914
     *
915
     * @dataProvider sortorder_first_last_provider
916
     * @param   int     $sortorder      The new sort order
917
     * @param   bool    $isfirst        Whether this is the first tour
918
     * @param   int     $total          The number of tours
919
     * @param   bool    $islast         Whether this is the last tour
920
     */
921
    public function test_is_first_tour($sortorder, $isfirst, $total, $islast): void {
922
        $tour = new \tool_usertours\tour();
923
 
924
        $rc = new \ReflectionClass(tour::class);
925
        $rcp = $rc->getProperty('sortorder');
926
        $rcp->setValue($tour, $sortorder);
927
 
928
        $this->assertEquals($isfirst, $tour->is_first_tour());
929
    }
930
 
931
    /**
932
     * Test the is_last_tour() function.
933
     *
934
     * @dataProvider sortorder_first_last_provider
935
     * @param   int     $sortorder      The new sort order
936
     * @param   bool    $isfirst        Whether this is the first tour
937
     * @param   int     $total          The number of tours
938
     * @param   bool    $islast         Whether this is the last tour
939
     */
940
    public function test_is_last_tour_calculated($sortorder, $isfirst, $total, $islast): void {
941
        $tour = new \tool_usertours\tour();
942
 
943
        $rc = new \ReflectionClass(tour::class);
944
        $rcp = $rc->getProperty('sortorder');
945
        $rcp->setValue($tour, $sortorder);
946
 
947
        // The total will be calculated.
948
        $DB = $this->mock_database();
949
        $DB->expects($this->once())
950
            ->method('count_records')
951
            ->willReturn($total);
952
        $this->assertEquals($islast, $tour->is_last_tour());
953
    }
954
 
955
    /**
956
     * Test the is_last_tour() function.
957
     *
958
     * @dataProvider sortorder_first_last_provider
959
     * @param   int     $sortorder      The new sort order
960
     * @param   bool    $isfirst        Whether this is the first tour
961
     * @param   int     $total          The number of tours
962
     * @param   bool    $islast         Whether this is the last tour
963
     */
964
    public function test_is_last_tour_provided($sortorder, $isfirst, $total, $islast): void {
965
        $tour = new \tool_usertours\tour();
966
 
967
        $rc = new \ReflectionClass(tour::class);
968
        $rcp = $rc->getProperty('sortorder');
969
        $rcp->setValue($tour, $sortorder);
970
 
971
        // The total is provided.
972
        // No DB calls expected.
973
        $DB = $this->mock_database();
974
        $DB->expects($this->never())
975
            ->method('count_records')
976
            ->willReturn(0);
977
        $this->assertEquals($islast, $tour->is_last_tour($total));
978
    }
979
 
980
    /**
981
     * Data provider for the get_filter_values tests.
982
     *
983
     * @return array
984
     */
985
    public static function get_filter_values_provider(): array {
986
        $cheese = ['cheddar', 'boursin', 'mozzarella'];
987
        $horses = ['coolie', 'dakota', 'leo', 'twiggy'];
988
        return [
989
            'No config' => [
990
                [],
991
                'cheese',
992
                [],
993
            ],
994
            'Some config for another filter' => [
995
                [
996
                    'horses' => $horses,
997
                ],
998
                'cheese',
999
                [],
1000
            ],
1001
            'Some config for this filter' => [
1002
                [
1003
                    'horses' => $horses,
1004
                ],
1005
                'horses',
1006
                $horses,
1007
            ],
1008
            'Some config for several filters' => [
1009
                [
1010
                    'horses' => $horses,
1011
                    'cheese' => $cheese,
1012
                ],
1013
                'horses',
1014
                $horses,
1015
            ],
1016
        ];
1017
    }
1018
 
1019
    /**
1020
     * Tests for the get_filter_values function.
1021
     *
1022
     * @dataProvider get_filter_values_provider
1023
     * @param   array       $fullconfig     The config value being tested
1024
     * @param   string      $filtername     The name of the filter being tested
1025
     * @param   array       $expectedvalues The expected result
1026
     */
1027
    public function test_get_filter_values($fullconfig, $filtername, $expectedvalues): void {
1028
        $tour = $this->getMockBuilder(tour::class)
1029
            ->onlyMethods(['get_config'])
1030
            ->getMock();
1031
 
1032
        $tour->expects($this->once())
1033
            ->method('get_config')
1034
            ->will($this->returnValue($fullconfig));
1035
 
1036
        $this->assertEquals($expectedvalues, $tour->get_filter_values($filtername));
1037
    }
1038
 
1039
    /**
1040
     * Data provider for set_filter_values tests.
1041
     *
1042
     * @return  array
1043
     */
1044
    public static function set_filter_values_provider(): array {
1045
        $cheese = ['cheddar', 'boursin', 'mozzarella'];
1046
        $horses = ['coolie', 'dakota', 'leo', 'twiggy'];
1047
 
1048
        return [
1049
            'No initial value' => [
1050
                [],
1051
                'cheese',
1052
                $cheese,
1053
                ['cheese' => $cheese],
1054
            ],
1055
            'Existing filter merged' => [
1056
                ['horses' => $horses],
1057
                'cheese',
1058
                $cheese,
1059
                ['horses' => $horses, 'cheese' => $cheese],
1060
            ],
1061
            'Existing filter updated' => [
1062
                ['cheese' => $cheese],
1063
                'cheese',
1064
                ['cheddar'],
1065
                ['cheese' => ['cheddar']],
1066
            ],
1067
            'Existing filter updated with merge' => [
1068
                ['horses' => $horses, 'cheese' => $cheese],
1069
                'cheese',
1070
                ['cheddar'],
1071
                ['horses' => $horses, 'cheese' => ['cheddar']],
1072
            ],
1073
        ];
1074
    }
1075
 
1076
    /**
1077
     * Base tests for set_filter_values.
1078
     *
1079
     * @dataProvider set_filter_values_provider
1080
     * @param   array       $currentvalues  The current value
1081
     * @param   string      $filtername     The name of the filter to add to
1082
     * @param   array       $newvalues      The new values to store
1083
     * @param   array       $expectedvalues The combined values
1084
     */
1085
    public function test_set_filter_values_merge($currentvalues, $filtername, $newvalues, $expectedvalues): void {
1086
        $tour = $this->getMockBuilder(tour::class)
1087
            ->onlyMethods(['get_config', 'set_config'])
1088
            ->getMock();
1089
 
1090
        $tour->expects($this->once())
1091
            ->method('get_config')
1092
            ->will($this->returnValue($currentvalues));
1093
 
1094
        $tour->expects($this->once())
1095
            ->method('set_config')
1096
            ->with(
1097
                $this->equalTo('filtervalues'),
1098
                $this->equalTo($expectedvalues)
1099
            );
1100
 
1101
        $tour->set_filter_values($filtername, $newvalues);
1102
    }
1103
}