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 PHPUnit\Framework\Attributes\WithoutErrorHandler;
1 efrain 20
use phpunit_util;
21
 
22
/**
23
 * Test basic_testcase extra features and PHPUnit Moodle integration.
24
 *
25
 * @package    core
26
 * @category   test
27
 * @copyright  2012 Petr Skoda {@link http://skodak.org}
28
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29
 */
1441 ariadna 30
final class basic_test extends \basic_testcase {
1 efrain 31
    protected $testassertexecuted = false;
32
 
33
    protected function setUp(): void {
34
        parent::setUp();
35
        if ($this->getName() === 'test_setup_assert') {
36
            $this->assertTrue(true);
37
            $this->testassertexecuted = true;
38
            return;
39
        }
40
    }
41
 
42
    /**
43
     * Tests that bootstrapping has occurred correctly
44
     * @return void
45
     */
11 efrain 46
    public function test_bootstrap(): void {
1 efrain 47
        global $CFG;
48
 
49
        // The httpswwwroot has been deprecated, we keep it as an alias for backwards compatibility with plugins only.
50
        $this->assertTrue(isset($CFG->httpswwwroot));
51
        $this->assertEquals($CFG->httpswwwroot, $CFG->wwwroot);
52
        $this->assertEquals($CFG->prefix, $CFG->phpunit_prefix);
53
    }
54
 
55
    /**
56
     * This is just a verification if I understand the PHPUnit assert docs right --skodak
57
     * @return void
58
     */
11 efrain 59
    public function test_assert_behaviour(): void {
1 efrain 60
        // Arrays.
61
        $a = array('a', 'b', 'c');
62
        $b = array('a', 'c', 'b');
63
        $c = array('a', 'b', 'c');
64
        $d = array('a', 'b', 'C');
65
        $this->assertNotEquals($a, $b);
66
        $this->assertNotEquals($a, $d);
67
        $this->assertEquals($a, $c);
68
        $this->assertEqualsCanonicalizing($a, $b);
69
 
70
        // Objects.
71
        $a = new \stdClass();
72
        $a->x = 'x';
73
        $a->y = 'y';
74
        $b = new \stdClass(); // Switched order.
75
        $b->y = 'y';
76
        $b->x = 'x';
77
        $c = $a;
78
        $d = new \stdClass();
79
        $d->x = 'x';
80
        $d->y = 'y';
81
        $d->z = 'z';
82
        $this->assertEquals($a, $b);
83
        $this->assertNotSame($a, $b);
84
        $this->assertEquals($a, $c);
85
        $this->assertSame($a, $c);
86
        $this->assertNotEquals($a, $d);
87
 
88
        // String comparison.
89
        $this->assertEquals(1, '1');
90
        $this->assertEquals(null, '');
91
 
92
        $this->assertNotEquals(0, '');
93
        $this->assertNotEquals(null, '0');
94
        $this->assertNotEquals(array(), '');
95
 
96
        // Other comparison.
97
        $this->assertEquals(null, null);
98
        $this->assertEquals(false, null);
99
        $this->assertEquals(0, null);
100
 
101
        // Emptiness.
102
        $this->assertEmpty(0);
103
        $this->assertEmpty(0.0);
104
        $this->assertEmpty('');
105
        $this->assertEmpty('0');
106
        $this->assertEmpty(false);
107
        $this->assertEmpty(null);
108
        $this->assertEmpty(array());
109
 
110
        $this->assertNotEmpty(1);
111
        $this->assertNotEmpty(0.1);
112
        $this->assertNotEmpty(-1);
113
        $this->assertNotEmpty(' ');
114
        $this->assertNotEmpty('0 ');
115
        $this->assertNotEmpty(true);
116
        $this->assertNotEmpty(array(null));
117
        $this->assertNotEmpty(new \stdClass());
118
    }
119
 
120
    /**
121
     * Make sure there are no sloppy Windows line endings
122
     * that would break our tests.
123
     */
11 efrain 124
    public function test_lineendings(): void {
1 efrain 125
        $string = <<<STRING
126
a
127
b
128
STRING;
129
        $this->assertSame("a\nb", $string, 'Make sure all project files are checked out with unix line endings.');
130
 
131
    }
132
 
133
    /**
134
     * Make sure asserts in setUp() do not create problems.
135
     */
11 efrain 136
    public function test_setup_assert(): void {
1 efrain 137
        $this->assertTrue($this->testassertexecuted);
138
        $this->testassertexecuted = false;
139
    }
140
 
141
    /**
142
     * Test assert Tag
143
     */
11 efrain 144
    public function test_assert_tag(): void {
1 efrain 145
        // This should succeed.
146
        self::assertTag(['id' => 'testid'], "<div><span id='testid'></span></div>");
147
        $this->expectException(\PHPUnit\Framework\ExpectationFailedException::class);
148
        self::assertTag(['id' => 'testid'], "<div><div>");
149
    }
150
 
151
    /**
152
     * Tests for assertEqualsIgnoringWhitespace.
153
     *
154
     * @param string $expected
155
     * @param string $actual
156
     * @param bool $expectationvalid
157
     * @dataProvider equals_ignoring_whitespace_provider
158
     */
159
    public function test_assertEqualsIgnoringWhitespace( // phpcs:ignore
160
        string $expected,
161
        string $actual,
162
        bool $expectationvalid,
163
    ): void {
164
        if (!$expectationvalid) {
165
            $this->expectException(\PHPUnit\Framework\ExpectationFailedException::class);
166
        }
167
        self::assertEqualsIgnoringWhitespace($expected, $actual);
168
    }
169
 
170
    /**
171
     * Data provider for assertEqualsIgnoringWhitespace tests
172
     *
173
     * @return array
174
     */
175
    public static function equals_ignoring_whitespace_provider(): array {
176
        return [
177
            'equal' => ['a b c', 'a b c', true],
178
            'equal with whitespace' => ["a b c", "a\nb c", true],
179
            'equal with extra whitespace' => ["a b c", "a\nb  c", true],
180
            'whitespace missing' => ["ab c", "a\nb  c", false],
181
            'not equal' => ['a b c', 'a b d', false],
182
            'various space types' => [
183
                implode(' ', [
184
                    '20', // Regular space.
185
                    "a0", // No-Break Space (NBSP).
186
                    "80", // Ogham Space Mark.
187
                    "0", // En Quad.
188
                    "1", // Em Quad.
189
                    "2", // En Space.
190
                    "3", // Em Space.
191
                    "4", // Three-Per-Em Space.
192
                    "5", // Four-Per-Em Space.
193
                    "6", // Six-Per-Em Space.
194
                    "7", // Figure Space.
195
                    "8", // Punctuation Space.
196
                    "9", // Thin Space.
197
                    "0a", // Hair Space.
198
                    "2f", // Narrow No-Break Space (NNBSP).
199
                    "5f", // Medium Mathematical Space.
200
                    "3000", // Ideographic Space.
201
                    ".",
202
                ]),
203
                implode('', [
204
                    // All space chars taken from https://www.compart.com/en/unicode/category/Zs.
205
                    "20\u{0020}", // Regular space.
206
                    "a0\u{00a0}", // No-Break Space (NBSP).
207
                    "80\u{1680}", // Ogham Space Mark.
208
                    "0\u{2000}", // En Quad.
209
                    "1\u{2001}", // Em Quad.
210
                    "2\u{2002}", // En Space.
211
                    "3\u{2003}", // Em Space.
212
                    "4\u{2004}", // Three-Per-Em Space.
213
                    "5\u{2005}", // Four-Per-Em Space.
214
                    "6\u{2006}", // Six-Per-Em Space.
215
                    "7\u{2007}", // Figure Space.
216
                    "8\u{2008}", // Punctuation Space.
217
                    "9\u{2009}", // Thin Space.
218
                    "0a\u{200a}", // Hair Space.
219
                    "2f\u{202f}", // Narrow No-Break Space (NNBSP).
220
                    "5f\u{205f}", // Medium Mathematical Space.
221
                    "3000\u{3000}", // Ideographic Space.
222
                    ".",
223
                ]),
224
                true,
225
            ],
226
        ];
227
    }
228
 
229
    /**
230
     * Test that a database modification is detected.
231
     *
232
     * @runInSeparateProcess
233
     * @covers \phpunit_util
234
     */
235
    public function test_db_modification(): void {
236
        global $DB;
237
        $DB->set_field('user', 'confirmed', 1, ['id' => -1]);
238
 
1441 ariadna 239
        $this->expectException(\core_phpunit\exception\test_exception::class);
1 efrain 240
        $this->expectExceptionMessage('Warning: unexpected database modification');
241
        phpunit_util::reset_all_data(true);
242
    }
243
 
244
    /**
245
     * Test that a $CFG modification is detected.
246
     *
247
     * @runInSeparateProcess
248
     * @covers \phpunit_util
249
     */
250
    public function test_cfg_modification(): void {
251
        global $CFG;
252
        $CFG->xx = 'yy';
253
        unset($CFG->admin);
254
        $CFG->rolesactive = 0;
255
 
256
        $this->expectException(\Exception::class);
257
        $this->expectExceptionMessageMatches('/rolesactive.*xx value.*removal.*admin/ms'); // 3 messages matched.
258
        phpunit_util::reset_all_data(true);
259
    }
260
 
261
    /**
262
     * Test that a $USER modification is detected.
263
     *
264
     * @runInSeparateProcess
265
     * @covers \phpunit_util
266
     */
267
    public function test_user_modification(): void {
268
        global $USER;
269
        $USER->id = 10;
270
 
271
        $this->expectException(\Exception::class);
272
        $this->expectExceptionMessage('Warning: unexpected change of $USER');
273
        phpunit_util::reset_all_data(true);
274
    }
275
 
276
    /**
277
     * Test that a $COURSE modification is detected.
278
     *
279
     * @runInSeparateProcess
280
     * @covers \phpunit_util
281
     */
282
    public function test_course_modification(): void {
283
        global $COURSE;
284
        $COURSE->id = 10;
285
 
286
        $this->expectException(\Exception::class);
287
        $this->expectExceptionMessage('Warning: unexpected change of $COURSE');
288
        phpunit_util::reset_all_data(true);
289
    }
290
 
291
    /**
292
     * Test that all modifications are detected together.
293
     *
294
     * @runInSeparateProcess
295
     * @covers \phpunit_util
296
     */
297
    public function test_all_modifications(): void {
298
        global $DB, $CFG, $USER, $COURSE;
299
        $DB->set_field('user', 'confirmed', 1, ['id' => -1]);
300
        $CFG->xx = 'yy';
301
        unset($CFG->admin);
302
        $CFG->rolesactive = 0;
303
        $USER->id = 10;
304
        $COURSE->id = 10;
305
 
306
        $this->expectException(\Exception::class);
307
        $this->expectExceptionMessageMatches('/resetting.*rolesactive.*new.*removal.*USER.*COURSE/ms'); // 6 messages matched.
308
        phpunit_util::reset_all_data(true);
309
    }
310
 
311
    /**
312
     * Test that an open transaction are managed ok by the reset code (silently rolled back).
313
     *
314
     * @runInSeparateProcess
315
     * @covers \phpunit_util
316
     */
317
    public function test_transaction_problem(): void {
318
        global $DB, $COURSE;
319
        $originalname = $DB->get_field('course', 'fullname', ['id' => $COURSE->id]); // Normally "PHPUnit test site".
320
        $changedname = 'Ongoing transaction test site';
321
 
322
        // Start a transaction and make some database changes.
323
        $DB->start_delegated_transaction();
324
        $DB->set_field('course', 'fullname', $changedname, ['id' => $COURSE->id]);
325
 
326
        // Assert that the transaction is open and the changes were made.
327
        $this->assertTrue($DB->is_transaction_started());
328
        $this->assertEquals($changedname, $DB->get_field('course', 'fullname', ['id' => $COURSE->id]));
329
 
330
        phpunit_util::reset_all_data(false); // We don't want to detect/warn on database changes for this test.
331
 
332
        // Assert that the transaction is now closed and the changes were rolled back.
333
        $this->assertFalse($DB->is_transaction_started());
334
        $this->assertEquals($originalname, $DB->get_field('course', 'fullname', ['id' => $COURSE->id]));
335
    }
1441 ariadna 336
 
337
    /**
338
     * Test that the navigation node URL is overridden correctly.
339
     */
340
    public function test_set_navigation_url(): void {
341
        \navigation_node::override_active_url(new \core\url('/foo/bar/baz'));
342
        $this->assertNotNull(
343
            (new \ReflectionClass(\navigation_node::class))->getStaticPropertyValue('fullmeurl', null),
344
        );
345
    }
346
 
347
    /**
348
     * Test that the after-test teardown correctly resets the navigation node URL.
349
     *
350
     * @depends test_set_navigation_url
351
     */
352
    public function test_navigation_url_reset(): void {
353
        $this->assertNull(
354
            (new \ReflectionClass(\navigation_node::class))->getStaticPropertyValue('fullmeurl', null),
355
        );
356
    }
1 efrain 357
}