Proyectos de Subversion Moodle

Rev

Rev 11 | | 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 core;
18
 
1441 ariadna 19
use core_phpunit\exception\test_exception;
20
 
1 efrain 21
/**
22
 * Test advanced_testcase extra features.
23
 *
24
 * @package    core
25
 * @category   test
26
 * @copyright  2012 Petr Skoda {@link http://skodak.org}
27
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28
 * @coversDefaultClass \advanced_testcase
29
 */
1441 ariadna 30
final class advanced_test extends \advanced_testcase {
1 efrain 31
    public static function setUpBeforeClass(): void {
32
        global $CFG;
33
        require_once(__DIR__ . '/fixtures/adhoc_test_task.php');
1441 ariadna 34
        parent::setUpBeforeClass();
1 efrain 35
    }
36
 
11 efrain 37
    public function test_debugging(): void {
1 efrain 38
        global $CFG;
39
        $this->resetAfterTest();
40
 
41
        debugging('hokus');
42
        $this->assertDebuggingCalled();
43
        debugging('pokus');
44
        $this->assertDebuggingCalled('pokus');
45
        debugging('pokus', DEBUG_MINIMAL);
46
        $this->assertDebuggingCalled('pokus', DEBUG_MINIMAL);
47
        $this->assertDebuggingNotCalled();
48
 
49
        debugging('a');
50
        debugging('b', DEBUG_MINIMAL);
51
        debugging('c', DEBUG_DEVELOPER);
52
        $debuggings = $this->getDebuggingMessages();
53
        $this->assertCount(3, $debuggings);
54
        $this->assertSame('a', $debuggings[0]->message);
55
        $this->assertSame(DEBUG_NORMAL, $debuggings[0]->level);
56
        $this->assertSame('b', $debuggings[1]->message);
57
        $this->assertSame(DEBUG_MINIMAL, $debuggings[1]->level);
58
        $this->assertSame('c', $debuggings[2]->message);
59
        $this->assertSame(DEBUG_DEVELOPER, $debuggings[2]->level);
60
 
61
        $this->resetDebugging();
62
        $this->assertDebuggingNotCalled();
63
        $debuggings = $this->getDebuggingMessages();
64
        $this->assertCount(0, $debuggings);
65
 
66
        set_debugging(DEBUG_NONE);
67
        debugging('hokus');
68
        $this->assertDebuggingNotCalled();
69
        set_debugging(DEBUG_DEVELOPER);
70
    }
71
 
72
    /**
73
     * @test
74
     *
75
     * Annotations are a valid PHPUnit method for running tests.  Debugging needs to support them.
76
     */
77
    public function debugging_called_with_annotation() {
78
        debugging('pokus', DEBUG_MINIMAL);
79
        $this->assertDebuggingCalled('pokus', DEBUG_MINIMAL);
80
    }
81
 
11 efrain 82
    public function test_set_user(): void {
1 efrain 83
        global $USER, $DB, $SESSION;
84
 
85
        $this->resetAfterTest();
86
 
87
        $this->assertEquals(0, $USER->id);
88
        $this->assertSame($_SESSION['USER'], $USER);
89
        $this->assertSame($GLOBALS['USER'], $USER);
90
 
91
        $user = $DB->get_record('user', array('id'=>2));
92
        $this->assertNotEmpty($user);
93
        $this->setUser($user);
94
        $this->assertEquals(2, $USER->id);
95
        $this->assertEquals(2, $_SESSION['USER']->id);
96
        $this->assertSame($_SESSION['USER'], $USER);
97
        $this->assertSame($GLOBALS['USER'], $USER);
98
 
99
        $USER->id = 3;
100
        $this->assertEquals(3, $USER->id);
101
        $this->assertEquals(3, $_SESSION['USER']->id);
102
        $this->assertSame($_SESSION['USER'], $USER);
103
        $this->assertSame($GLOBALS['USER'], $USER);
104
 
105
        \core\session\manager::set_user($user);
106
        $this->assertEquals(2, $USER->id);
107
        $this->assertEquals(2, $_SESSION['USER']->id);
108
        $this->assertSame($_SESSION['USER'], $USER);
109
        $this->assertSame($GLOBALS['USER'], $USER);
110
 
111
        $USER = $DB->get_record('user', array('id'=>1));
112
        $this->assertNotEmpty($USER);
113
        $this->assertEquals(1, $USER->id);
114
        $this->assertEquals(1, $_SESSION['USER']->id);
115
        $this->assertSame($_SESSION['USER'], $USER);
116
        $this->assertSame($GLOBALS['USER'], $USER);
117
 
118
        $this->setUser(null);
119
        $this->assertEquals(0, $USER->id);
120
        $this->assertSame($_SESSION['USER'], $USER);
121
        $this->assertSame($GLOBALS['USER'], $USER);
122
 
123
        // Ensure session is reset after setUser, as it may contain extra info.
124
        $SESSION->sometestvalue = true;
125
        $this->setUser($user);
126
        $this->assertObjectNotHasProperty('sometestvalue', $SESSION);
127
    }
128
 
11 efrain 129
    public function test_set_admin_user(): void {
1 efrain 130
        global $USER;
131
 
132
        $this->resetAfterTest();
133
 
134
        $this->setAdminUser();
135
        $this->assertEquals($USER->id, 2);
136
        $this->assertTrue(is_siteadmin());
137
    }
138
 
11 efrain 139
    public function test_set_guest_user(): void {
1 efrain 140
        global $USER;
141
 
142
        $this->resetAfterTest();
143
 
144
        $this->setGuestUser();
145
        $this->assertEquals($USER->id, 1);
146
        $this->assertTrue(isguestuser());
147
    }
148
 
11 efrain 149
    public function test_database_reset(): void {
1 efrain 150
        global $DB;
151
 
152
        $this->resetAfterTest();
153
 
154
        $this->preventResetByRollback();
155
 
156
        $this->assertEquals(1, $DB->count_records('course')); // Only frontpage in new site.
157
 
158
        // This is weird table - id is NOT a sequence here.
159
        $this->assertEquals(0, $DB->count_records('context_temp'));
160
        $DB->import_record('context_temp', array('id'=>5, 'path'=>'/1/2', 'depth'=>2));
161
        $record = $DB->get_record('context_temp', array());
162
        $this->assertEquals(5, $record->id);
163
 
164
        $this->assertEquals(0, $DB->count_records('user_preferences'));
165
        $originaldisplayid = $DB->insert_record('user_preferences', array('userid'=>2, 'name'=> 'phpunittest', 'value'=>'x'));
166
        $this->assertEquals(1, $DB->count_records('user_preferences'));
167
 
168
        $numcourses = $DB->count_records('course');
169
        $course = $this->getDataGenerator()->create_course();
170
        $this->assertEquals($numcourses + 1, $DB->count_records('course'));
171
 
172
        $this->assertEquals(2, $DB->count_records('user'));
173
        $DB->delete_records('user', array('id'=>1));
174
        $this->assertEquals(1, $DB->count_records('user'));
175
 
176
        $this->resetAllData();
177
 
178
        $this->assertEquals(1, $DB->count_records('course')); // Only frontpage in new site.
179
        $this->assertEquals(0, $DB->count_records('context_temp')); // Only frontpage in new site.
180
 
181
        $numcourses = $DB->count_records('course');
182
        $course = $this->getDataGenerator()->create_course();
183
        $this->assertEquals($numcourses + 1, $DB->count_records('course'));
184
 
185
        $displayid = $DB->insert_record('user_preferences', array('userid'=>2, 'name'=> 'phpunittest', 'value'=>'x'));
186
        $this->assertEquals($originaldisplayid, $displayid);
187
 
188
        $this->assertEquals(2, $DB->count_records('user'));
189
        $DB->delete_records('user', array('id'=>2));
190
        $user = $this->getDataGenerator()->create_user();
191
        $this->assertEquals(2, $DB->count_records('user'));
192
        $this->assertGreaterThan(2, $user->id);
193
 
194
        $this->resetAllData();
195
 
196
        $numcourses = $DB->count_records('course');
197
        $course = $this->getDataGenerator()->create_course();
198
        $this->assertEquals($numcourses + 1, $DB->count_records('course'));
199
 
200
        $this->assertEquals(2, $DB->count_records('user'));
201
        $DB->delete_records('user', array('id'=>2));
202
 
203
        $this->resetAllData();
204
 
205
        $numcourses = $DB->count_records('course');
206
        $course = $this->getDataGenerator()->create_course();
207
        $this->assertEquals($numcourses + 1, $DB->count_records('course'));
208
 
209
        $this->assertEquals(2, $DB->count_records('user'));
210
    }
211
 
11 efrain 212
    public function test_change_detection(): void {
1 efrain 213
        global $DB, $CFG, $COURSE, $SITE, $USER;
214
 
215
        $this->preventResetByRollback();
216
        self::resetAllData(true);
217
 
218
        // Database change.
219
        $this->assertEquals(1, $DB->get_field('user', 'confirmed', array('id'=>2)));
220
        $DB->set_field('user', 'confirmed', 0, array('id'=>2));
1441 ariadna 221
 
1 efrain 222
        try {
223
            self::resetAllData(true);
1441 ariadna 224
        } catch (test_exception $e) {
225
            $this->assertStringContainsString('unexpected database modification', $e->getMessage());
1 efrain 226
        }
1441 ariadna 227
 
1 efrain 228
        $this->assertEquals(1, $DB->get_field('user', 'confirmed', array('id'=>2)));
229
        // Config change.
230
        $CFG->xx = 'yy';
231
        unset($CFG->admin);
232
        $CFG->rolesactive = 0;
1441 ariadna 233
 
1 efrain 234
        try {
235
            self::resetAllData(true);
1441 ariadna 236
        } catch (test_exception $e) {
1 efrain 237
            $this->assertStringContainsString('xx', $e->getMessage());
238
            $this->assertStringContainsString('admin', $e->getMessage());
239
            $this->assertStringContainsString('rolesactive', $e->getMessage());
1441 ariadna 240
            $this->assertFalse(isset($CFG->xx));
241
            $this->assertTrue(isset($CFG->admin));
242
            $this->assertEquals(1, $CFG->rolesactive);
1 efrain 243
        }
244
 
245
        // _GET change.
246
        $_GET['__somethingthatwillnotnormallybepresent__'] = 'yy';
247
        self::resetAllData(true);
248
 
249
        $this->assertEquals(array(), $_GET);
250
 
251
        // _POST change.
252
        $_POST['__somethingthatwillnotnormallybepresent2__'] = 'yy';
253
        self::resetAllData(true);
254
        $this->assertEquals(array(), $_POST);
255
 
256
        // _FILES change.
257
        $_FILES['__somethingthatwillnotnormallybepresent3__'] = 'yy';
258
        self::resetAllData(true);
259
        $this->assertEquals(array(), $_FILES);
260
 
261
        // _REQUEST change.
262
        $_REQUEST['__somethingthatwillnotnormallybepresent4__'] = 'yy';
263
        self::resetAllData(true);
264
        $this->assertEquals(array(), $_REQUEST);
265
 
266
        // Silent changes.
267
        $_SERVER['xx'] = 'yy';
268
        self::resetAllData(true);
269
        $this->assertFalse(isset($_SERVER['xx']));
270
 
271
        // COURSE change.
272
        $SITE->id = 10;
273
        $COURSE = new \stdClass();
274
        $COURSE->id = 7;
1441 ariadna 275
 
1 efrain 276
        try {
277
            self::resetAllData(true);
1441 ariadna 278
        } catch (test_exception $e) {
279
            $this->assertStringContainsString('unexpected change of $COURSE', $e->getMessage());
1 efrain 280
        }
281
 
1441 ariadna 282
        $this->assertEquals(1, $SITE->id);
283
        $this->assertSame($SITE, $COURSE);
284
        $this->assertSame($SITE, $COURSE);
285
 
1 efrain 286
        // USER change.
287
        $this->setUser(2);
1441 ariadna 288
 
1 efrain 289
        try {
290
            self::resetAllData(true);
1441 ariadna 291
        } catch (test_exception $e) {
292
            $this->assertStringContainsString('unexpected change of $USER', $e->getMessage());
1 efrain 293
        }
1441 ariadna 294
 
295
        $this->assertEquals(0, $USER->id);
296
 
1 efrain 297
    }
298
 
11 efrain 299
    public function test_getDataGenerator(): void {
1 efrain 300
        $generator = $this->getDataGenerator();
301
        $this->assertInstanceOf('testing_data_generator', $generator);
302
    }
303
 
1441 ariadna 304
    /**
305
     * Some basic tests for the getExternalTestFileUrl() method.
306
     */
307
    public function test_external_file_url(): void {
308
        $url = self::getExternalTestFileUrl('testfile.txt');
309
        // There should only be a // after the protocol.
310
        $this->assertCount(2, explode('//', $url));
311
 
312
        if (defined('TEST_EXTERNAL_FILES_HTTP_URL')) {
313
            $this->assertStringContainsString(TEST_EXTERNAL_FILES_HTTP_URL, $url);
314
        } else {
315
            $this->assertStringContainsString('http://download.moodle.org/unittest', $url);
316
        }
317
 
318
        $url = self::getExternalTestFileUrl('testfile.txt', true);
319
        $this->assertCount(2, explode('//', $url));
320
 
321
        if (defined('TEST_EXTERNAL_FILES_HTTPS_URL')) {
322
            $this->assertStringContainsString(TEST_EXTERNAL_FILES_HTTPS_URL, $url);
323
        } else {
324
            $this->assertStringContainsString('https://download.moodle.org/unittest', $url);
325
        }
326
    }
327
 
11 efrain 328
    public function test_database_mock1(): void {
1 efrain 329
        global $DB;
330
 
331
        try {
332
            $DB->get_record('pokus', array());
333
            $this->fail('Exception expected when accessing non existent table');
334
        } catch (\moodle_exception $e) {
335
            $this->assertInstanceOf('dml_exception', $e);
336
        }
337
        $DB = $this->createMock(get_class($DB));
338
        $this->assertNull($DB->get_record('pokus', array()));
339
        // Rest continues after reset.
340
    }
341
 
11 efrain 342
    public function test_database_mock2(): void {
1 efrain 343
        global $DB;
344
 
345
        // Now the database should be back to normal.
346
        $this->assertFalse($DB->get_record('user', array('id'=>9999)));
347
    }
348
 
11 efrain 349
    public function test_assert_time_current(): void {
1 efrain 350
        $this->assertTimeCurrent(time());
351
 
352
        $this->setCurrentTimeStart();
353
        $this->assertTimeCurrent(time());
354
        $this->waitForSecond();
355
        $this->assertTimeCurrent(time());
356
        $this->assertTimeCurrent(time()-1);
357
 
358
        try {
359
            $this->setCurrentTimeStart();
360
            $this->assertTimeCurrent(time()+10);
361
            $this->fail('Failed assert expected');
362
        } catch (\Exception $e) {
363
            $this->assertInstanceOf('PHPUnit\Framework\ExpectationFailedException', $e);
364
        }
365
 
366
        try {
367
            $this->setCurrentTimeStart();
368
            $this->assertTimeCurrent(time()-10);
369
            $this->fail('Failed assert expected');
370
        } catch (\Exception $e) {
371
            $this->assertInstanceOf('PHPUnit\Framework\ExpectationFailedException', $e);
372
        }
373
    }
374
 
375
    /**
376
     * Test the assertEventContextNotUsed() assertion.
377
     *
378
     * Verify that events using the event context in some of their
379
     * methods are detected properly (will throw a warning if they are).
380
     *
381
     * To do so, we'll be using some fixture events (context_used_in_event_xxxx),
382
     * that, on purpose, use the event context (incorrectly) in their methods.
383
     *
384
     * Note that because we are using imported fixture classes, and because we
385
     * are testing for warnings, better we run the tests in a separate process.
386
     *
387
     * @param string $fixture The fixture class to use.
388
     * @param bool $phpwarn Whether a PHP warning is expected.
389
     *
390
     * @runInSeparateProcess
391
     * @dataProvider assert_event_context_not_used_provider
392
     * @covers ::assertEventContextNotUsed
393
     */
394
    public function test_assert_event_context_not_used($fixture, $phpwarn): void {
395
        require(__DIR__ . '/fixtures/event_fixtures.php');
396
        // Create an event that uses the event context in its get_url() and get_description() methods.
397
        $event = $fixture::create([
398
            'other' => [
399
                'sample' => 1,
400
                'xx' => 10,
401
            ],
402
        ]);
403
 
404
        if ($phpwarn) {
405
            // Let's convert the warnings into an assert-able exception.
406
            set_error_handler(
407
                static function ($errno, $errstr) {
408
                    restore_error_handler();
409
                    throw new \Exception($errstr, $errno);
410
                },
411
                E_WARNING // Or any other specific E_ that we want to assert.
412
            );
413
            $this->expectException(\Exception::class);
414
        }
415
        $this->assertEventContextNotUsed($event);
416
    }
417
 
418
    /**
419
     * Data provider for test_assert_event_context_not_used().
420
     *
421
     * @return array
422
     */
423
    public static function assert_event_context_not_used_provider(): array {
424
        return [
425
            'correct' => ['\core\event\context_used_in_event_correct', false],
426
            'wrong_get_url' => ['\core\event\context_used_in_event_get_url', true],
427
            'wrong_get_description' => ['\core\event\context_used_in_event_get_description', true],
428
        ];
429
    }
430
 
11 efrain 431
    public function test_message_processors_reset(): void {
1 efrain 432
        global $DB;
433
 
434
        $this->resetAfterTest(true);
435
 
436
        // Get all processors first.
437
        $processors1 = get_message_processors();
438
 
439
        // Add a new message processor and get all processors again.
440
        $processor = new \stdClass();
441
        $processor->name = 'test_processor';
442
        $processor->enabled = 1;
443
        $DB->insert_record('message_processors', $processor);
444
 
445
        $processors2 = get_message_processors();
446
 
447
        // Assert that new processor still haven't been added to the list.
448
        $this->assertSame($processors1, $processors2);
449
 
450
        // Reset message processors data.
451
        $processors3 = get_message_processors(false, true);
452
        // Now, list of processors should not be the same any more,
453
        // And we should have one more message processor in the list.
454
        $this->assertNotSame($processors1, $processors3);
455
        $this->assertEquals(count($processors1) + 1, count($processors3));
456
    }
457
 
11 efrain 458
    public function test_message_redirection(): \phpunit_message_sink {
1 efrain 459
        $this->preventResetByRollback(); // Messaging is not compatible with transactions...
460
        $this->resetAfterTest(false);
461
 
462
        $user1 = $this->getDataGenerator()->create_user();
463
        $user2 = $this->getDataGenerator()->create_user();
464
 
465
        // Any core message will do here.
466
        $message1 = new \core\message\message();
467
        $message1->courseid          = 1;
468
        $message1->component         = 'moodle';
469
        $message1->name              = 'instantmessage';
470
        $message1->userfrom          = $user1;
471
        $message1->userto            = $user2;
472
        $message1->subject           = 'message subject 1';
473
        $message1->fullmessage       = 'message body';
474
        $message1->fullmessageformat = FORMAT_MARKDOWN;
475
        $message1->fullmessagehtml   = '<p>message body</p>';
476
        $message1->smallmessage      = 'small message';
477
        $message1->notification      = 0;
478
 
479
        $message2 = new \core\message\message();
480
        $message2->courseid          = 1;
481
        $message2->component         = 'moodle';
482
        $message2->name              = 'instantmessage';
483
        $message2->userfrom          = $user2;
484
        $message2->userto            = $user1;
485
        $message2->subject           = 'message subject 2';
486
        $message2->fullmessage       = 'message body';
487
        $message2->fullmessageformat = FORMAT_MARKDOWN;
488
        $message2->fullmessagehtml   = '<p>message body</p>';
489
        $message2->smallmessage      = 'small message';
490
        $message2->notification      = 0;
491
 
492
        // There should be debugging message without redirection.
493
        $mailsink = $this->redirectEmails();
494
        $mailsink->close();
495
        message_send($message1);
496
        $this->assertDebuggingCalled(null, null, 'message_send() must print debug message that messaging is disabled in phpunit tests.');
497
 
498
        // Sink should catch messages.
499
        $sink = $this->redirectMessages();
500
        $mid1 = message_send($message1);
501
        $mid2 = message_send($message2);
502
 
503
        $this->assertDebuggingNotCalled('message redirection must prevent debug messages from the message_send()');
504
        $this->assertEquals(2, $sink->count());
505
        $this->assertGreaterThanOrEqual(1, $mid1);
506
        $this->assertGreaterThanOrEqual($mid1, $mid2);
507
 
508
        $messages = $sink->get_messages();
509
        $this->assertIsArray($messages);
510
        $this->assertCount(2, $messages);
511
        $this->assertEquals($mid1, $messages[0]->id);
512
        $this->assertEquals($message1->userto->id, $messages[0]->useridto);
513
        $this->assertEquals($message1->userfrom->id, $messages[0]->useridfrom);
514
        $this->assertEquals($message1->smallmessage, $messages[0]->smallmessage);
515
        $this->assertEquals($mid2, $messages[1]->id);
516
        $this->assertEquals($message2->userto->id, $messages[1]->useridto);
517
        $this->assertEquals($message2->userfrom->id, $messages[1]->useridfrom);
518
        $this->assertEquals($message2->smallmessage, $messages[1]->smallmessage);
519
 
520
        // Test resetting.
521
        $sink->clear();
522
        $messages = $sink->get_messages();
523
        $this->assertIsArray($messages);
524
        $this->assertCount(0, $messages);
525
 
526
        message_send($message1);
527
        $messages = $sink->get_messages();
528
        $this->assertIsArray($messages);
529
        $this->assertCount(1, $messages);
530
 
531
        // Test closing.
532
        $sink->close();
533
        $messages = $sink->get_messages();
534
        $this->assertIsArray($messages);
535
        $this->assertCount(1, $messages, 'Messages in sink are supposed to stay there after close');
536
 
537
        // Test debugging is enabled again.
538
        message_send($message1);
539
        $this->assertDebuggingCalled(null, null, 'message_send() must print debug message that messaging is disabled in phpunit tests.');
540
 
541
        // Test invalid names and components.
542
 
543
        $sink = $this->redirectMessages();
544
 
545
        $message3 = new \core\message\message();
546
        $message3->courseid          = 1;
547
        $message3->component         = 'xxxx_yyyyy';
548
        $message3->name              = 'instantmessage';
549
        $message3->userfrom          = $user2;
550
        $message3->userto            = $user1;
551
        $message3->subject           = 'message subject 2';
552
        $message3->fullmessage       = 'message body';
553
        $message3->fullmessageformat = FORMAT_MARKDOWN;
554
        $message3->fullmessagehtml   = '<p>message body</p>';
555
        $message3->smallmessage      = 'small message';
556
        $message3->notification      = 0;
557
 
558
        $this->assertFalse(message_send($message3));
559
        $this->assertDebuggingCalled('Attempt to send msg from a provider xxxx_yyyyy/instantmessage '.
560
            'that is inactive or not allowed for the user id='.$user1->id);
561
 
562
        $message3->component = 'moodle';
563
        $message3->name      = 'yyyyyy';
564
 
565
        $this->assertFalse(message_send($message3));
566
        $this->assertDebuggingCalled('Attempt to send msg from a provider moodle/yyyyyy '.
567
            'that is inactive or not allowed for the user id='.$user1->id);
568
 
569
        message_send($message1);
570
        $this->assertEquals(1, $sink->count());
571
 
572
        // Test if sink can be carried over to next test.
573
        $this->assertTrue(\phpunit_util::is_redirecting_messages());
574
        return $sink;
575
    }
576
 
577
    /**
578
     * @depends test_message_redirection
579
     */
11 efrain 580
    public function test_message_redirection_noreset(\phpunit_message_sink $sink): void {
1 efrain 581
        if ($this->isInIsolation()) {
582
            $this->markTestSkipped('State cannot be carried over between tests in isolated tests');
583
        }
584
 
585
        $this->preventResetByRollback(); // Messaging is not compatible with transactions...
586
        $this->resetAfterTest();
587
 
588
        $this->assertTrue(\phpunit_util::is_redirecting_messages());
589
        $this->assertEquals(1, $sink->count());
590
 
591
        $message = new \core\message\message();
592
        $message->courseid          = 1;
593
        $message->component         = 'moodle';
594
        $message->name              = 'instantmessage';
595
        $message->userfrom          = get_admin();
596
        $message->userto            = get_admin();
597
        $message->subject           = 'message subject 1';
598
        $message->fullmessage       = 'message body';
599
        $message->fullmessageformat = FORMAT_MARKDOWN;
600
        $message->fullmessagehtml   = '<p>message body</p>';
601
        $message->smallmessage      = 'small message';
602
        $message->notification      = 0;
603
 
604
        message_send($message);
605
        $this->assertEquals(2, $sink->count());
606
    }
607
 
608
    /**
609
     * @depends test_message_redirection_noreset
610
     */
11 efrain 611
    public function test_message_redirection_reset(): void {
1 efrain 612
        $this->assertFalse(\phpunit_util::is_redirecting_messages(), 'Test reset must stop message redirection.');
613
    }
614
 
11 efrain 615
    public function test_set_timezone(): void {
1 efrain 616
        global $CFG;
617
        $this->resetAfterTest();
618
 
619
        $this->assertSame('Australia/Perth', $CFG->timezone);
620
        $this->assertSame('Australia/Perth', date_default_timezone_get());
621
 
622
        $this->setTimezone('Pacific/Auckland', 'Europe/Prague');
623
        $this->assertSame('Pacific/Auckland', $CFG->timezone);
624
        $this->assertSame('Pacific/Auckland', date_default_timezone_get());
625
 
626
        $this->setTimezone('99', 'Europe/Prague');
627
        $this->assertSame('99', $CFG->timezone);
628
        $this->assertSame('Europe/Prague', date_default_timezone_get());
629
 
1441 ariadna 630
        // Catch warning for invalid 'xxx' timezone.
631
        set_error_handler(function ($errno, $errstr): void {
632
            $this->assertStringContainsString('Unknown or bad timezone', $errstr);
633
        }, E_WARNING);
1 efrain 634
        $this->setTimezone('xxx', 'Europe/Prague');
1441 ariadna 635
        restore_error_handler();
1 efrain 636
        $this->assertSame('xxx', $CFG->timezone);
637
        $this->assertSame('Europe/Prague', date_default_timezone_get());
638
 
639
        $this->setTimezone();
640
        $this->assertSame('Australia/Perth', $CFG->timezone);
641
        $this->assertSame('Australia/Perth', date_default_timezone_get());
642
 
1441 ariadna 643
        // Catch warnings for other invalid cases.
644
        $invalidtimezones = ['', 'xxxx', null];
645
        foreach ($invalidtimezones as $invalidtz) {
646
            set_error_handler(function ($errno, $errstr): void {
647
                $this->assertStringContainsString('Unknown or bad timezone', $errstr);
648
            }, E_WARNING);
649
            try {
650
                $this->setTimezone('Pacific/Auckland', $invalidtz);
651
            } catch (\Throwable $e) {
652
                $this->assertInstanceOf('PHPUnit\Framework\Error\Warning', $e);
653
            }
654
            restore_error_handler();
1 efrain 655
        }
656
 
657
    }
658
 
11 efrain 659
    public function test_locale_reset(): void {
1 efrain 660
        global $CFG;
661
 
662
        $this->resetAfterTest();
663
 
664
        // If this fails self::resetAllData(); must be updated.
665
        $this->assertSame('en_AU.UTF-8', get_string('locale', 'langconfig'));
666
        $this->assertSame('English_Australia.1252', get_string('localewin', 'langconfig'));
667
 
668
        if ($CFG->ostype === 'WINDOWS') {
669
            $this->assertSame('English_Australia.1252', setlocale(LC_TIME, 0));
670
            setlocale(LC_TIME, 'English_USA.1252');
671
        } else {
672
            $this->assertSame('en_AU.UTF-8', setlocale(LC_TIME, 0));
673
            setlocale(LC_TIME, 'en_US.UTF-8');
674
        }
675
 
676
        try {
677
            self::resetAllData(true);
1441 ariadna 678
        } catch (test_exception $e) {
679
            $this->assertStringContainsString('unexpected change of locale', $e->getMessage());
1 efrain 680
        }
681
 
682
        if ($CFG->ostype === 'WINDOWS') {
683
            $this->assertSame('English_Australia.1252', setlocale(LC_TIME, 0));
684
        } else {
685
            $this->assertSame('en_AU.UTF-8', setlocale(LC_TIME, 0));
686
        }
687
 
688
        if ($CFG->ostype === 'WINDOWS') {
689
            $this->assertSame('English_Australia.1252', setlocale(LC_TIME, 0));
690
            setlocale(LC_TIME, 'English_USA.1252');
691
        } else {
692
            $this->assertSame('en_AU.UTF-8', setlocale(LC_TIME, 0));
693
            setlocale(LC_TIME, 'en_US.UTF-8');
694
        }
695
 
696
        self::resetAllData(false);
697
 
698
        if ($CFG->ostype === 'WINDOWS') {
699
            $this->assertSame('English_Australia.1252', setlocale(LC_TIME, 0));
700
        } else {
701
            $this->assertSame('en_AU.UTF-8', setlocale(LC_TIME, 0));
702
        }
703
    }
704
 
705
    /**
706
     * This test sets a user agent and makes sure that it is cleared when the test is reset.
707
     */
11 efrain 708
    public function test_it_resets_useragent_after_test(): void {
1 efrain 709
        $this->resetAfterTest();
710
        $fakeagent = 'New user agent set.';
711
 
712
        // Sanity check: it should not be set when test begins.
713
        self::assertFalse(\core_useragent::get_user_agent_string(), 'It should not be set at first.');
714
 
715
        // Set a fake useragent and check it was set properly.
716
        \core_useragent::instance(true, $fakeagent);
717
        self::assertSame($fakeagent, \core_useragent::get_user_agent_string(), 'It should be the forced agent.');
718
 
719
        // Reset test data and ansure the useragent was cleaned.
720
        self::resetAllData(false);
721
        self::assertFalse(\core_useragent::get_user_agent_string(), 'It should not be set again, data was reset.');
722
    }
723
 
724
    /**
725
     * @covers ::runAdhocTasks
726
     */
727
    public function test_runadhoctasks_no_tasks_queued(): void {
728
        $this->runAdhocTasks();
729
        $this->expectOutputRegex('/^$/');
730
    }
731
 
732
    /**
733
     * @covers ::runAdhocTasks
734
     */
735
    public function test_runadhoctasks_tasks_queued(): void {
736
        $this->resetAfterTest(true);
737
        $admin = get_admin();
738
        \core\task\manager::queue_adhoc_task(new \core_phpunit\adhoc_test_task());
739
        $this->runAdhocTasks();
740
        $this->expectOutputRegex("/Task was run as {$admin->id}/");
741
    }
742
 
743
    /**
744
     * @covers ::runAdhocTasks
745
     */
746
    public function test_runadhoctasks_with_existing_user_change(): void {
747
        $this->resetAfterTest(true);
748
        $admin = get_admin();
749
 
750
        $this->setGuestUser();
751
        \core\task\manager::queue_adhoc_task(new \core_phpunit\adhoc_test_task());
752
        $this->runAdhocTasks();
753
        $this->expectOutputRegex("/Task was run as {$admin->id}/");
754
    }
755
 
756
    /**
757
     * @covers ::runAdhocTasks
758
     */
759
    public function test_runadhoctasks_with_existing_user_change_and_specified(): void {
760
        global $USER;
761
 
762
        $this->resetAfterTest(true);
763
        $user = $this->getDataGenerator()->create_user();
764
 
765
        $this->setGuestUser();
766
        $task = new \core_phpunit\adhoc_test_task();
767
        $task->set_userid($user->id);
768
        \core\task\manager::queue_adhoc_task($task);
769
        $this->runAdhocTasks();
770
        $this->expectOutputRegex("/Task was run as {$user->id}/");
771
    }
772
 
773
    /**
774
     * Test the incrementing mock clock.
775
     *
776
     * @covers ::mock_clock_with_incrementing
777
     * @covers \incrementing_clock
778
     */
779
    public function test_mock_clock_with_incrementing(): void {
780
        $standard = \core\di::get(\core\clock::class);
781
        $this->assertInstanceOf(\Psr\Clock\ClockInterface::class, $standard);
782
        $this->assertInstanceOf(\core\clock::class, $standard);
783
 
784
        $newclock = $this->mock_clock_with_incrementing(0);
785
        $mockedclock = \core\di::get(\core\clock::class);
786
        $this->assertInstanceOf(\incrementing_clock::class, $newclock);
787
        $this->assertSame($newclock, $mockedclock);
788
 
789
        // Test the functionality.
790
        $this->assertEquals(0, $mockedclock->now()->getTimestamp());
791
        $this->assertEquals(1, $newclock->now()->getTimestamp());
792
        $this->assertEquals(2, $mockedclock->now()->getTimestamp());
1441 ariadna 793
        $this->assertEquals('Australia/Perth', $newclock->now()->getTimezone()->getName());
1 efrain 794
 
795
        // Specify a specific start time.
796
        $newclock = $this->mock_clock_with_incrementing(12345);
797
        $mockedclock = \core\di::get(\core\clock::class);
798
        $this->assertSame($newclock, $mockedclock);
799
 
800
        $this->assertEquals(12345, $mockedclock->now()->getTimestamp());
801
        $this->assertEquals(12346, $newclock->now()->getTimestamp());
802
        $this->assertEquals(12347, $mockedclock->now()->getTimestamp());
803
 
804
        $this->assertEquals($newclock->time, $mockedclock->now()->getTimestamp());
1441 ariadna 805
        $this->assertEquals('Australia/Perth', $newclock->now()->getTimezone()->getName());
1 efrain 806
    }
807
 
808
    /**
809
     * Test the incrementing mock clock.
810
     *
811
     * @covers ::mock_clock_with_frozen
812
     * @covers \frozen_clock
813
     */
814
    public function test_mock_clock_with_frozen(): void {
815
        $standard = \core\di::get(\core\clock::class);
816
        $this->assertInstanceOf(\Psr\Clock\ClockInterface::class, $standard);
817
        $this->assertInstanceOf(\core\clock::class, $standard);
818
 
819
        $newclock = $this->mock_clock_with_frozen(0);
820
        $mockedclock = \core\di::get(\core\clock::class);
821
        $this->assertInstanceOf(\frozen_clock::class, $newclock);
822
        $this->assertSame($newclock, $mockedclock);
823
 
824
        // Test the functionality.
825
        $initialtime = $mockedclock->now()->getTimestamp();
826
        $this->assertEquals($initialtime, $newclock->now()->getTimestamp());
827
        $this->assertEquals($initialtime, $mockedclock->now()->getTimestamp());
1441 ariadna 828
        $this->assertEquals('Australia/Perth', $newclock->now()->getTimezone()->getName());
1 efrain 829
 
830
        // Specify a specific start time.
831
        $newclock = $this->mock_clock_with_frozen(12345);
832
        $mockedclock = \core\di::get(\core\clock::class);
833
        $this->assertSame($newclock, $mockedclock);
834
 
835
        $initialtime = $mockedclock->now();
836
        $this->assertEquals($initialtime, $mockedclock->now());
837
        $this->assertEquals($initialtime, $newclock->now());
838
        $this->assertEquals($initialtime, $mockedclock->now());
1441 ariadna 839
        $this->assertEquals('Australia/Perth', $newclock->now()->getTimezone()->getName());
1 efrain 840
    }
841
}