Proyectos de Subversion Moodle

Rev

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