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 core_external;
18
 
19
/**
20
 * Unit tests for core_external\util.
21
 *
22
 * @package     core_external
23
 * @category    test
24
 * @copyright   2022 Andrew Lyons <andrew@nicols.co.uk>
25
 * @license     http://www.gnu.org/copyleft/gpl.html GNU Public License
26
 * @covers      \core_external\util
27
 */
1441 ariadna 28
final class util_test extends \advanced_testcase {
1 efrain 29
    /** @var \moodle_database The database connection */
30
    protected $db;
31
 
32
    /**
33
     * Store the global DB for restore between tests.
34
     */
35
    public function setUp(): void {
36
        global $DB;
1441 ariadna 37
        parent::setUp();
1 efrain 38
 
39
        $this->db = $DB;
40
        external_settings::reset();
41
    }
42
 
43
    /**
44
     * A helper to include the legacy external functions.
45
     */
46
    protected function include_legacy_functions(): void {
47
        global $CFG;
48
 
49
        $this->assertTrue(
50
            $this->isInIsolation(),
51
            'Inclusion of the legacy test functions requires the test to be run in isolation.',
52
        );
53
 
54
        // Note: This is retained for testing of the old functions.
55
        require_once("{$CFG->libdir}/externallib.php");
56
    }
57
 
58
    /**
59
     * Reset the global DB between tests.
60
     */
61
    public function tearDown(): void {
62
        global $DB;
63
        if ($this->db !== null) {
64
            $DB = $this->db;
65
        }
66
        external_settings::reset();
1441 ariadna 67
        parent::tearDown();
1 efrain 68
    }
69
 
70
    /**
71
     * Validate courses, but still return courses even if they fail validation.
72
     *
73
     * @covers \core_external\util::validate_courses
74
     */
75
    public function test_validate_courses_keepfails(): void {
76
        $this->resetAfterTest(true);
77
 
78
        $c1 = $this->getDataGenerator()->create_course();
79
        $c2 = $this->getDataGenerator()->create_course();
80
        $c3 = $this->getDataGenerator()->create_course();
81
        $u1 = $this->getDataGenerator()->create_user();
82
        $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
83
        $courseids = [$c1->id, $c2->id, $c3->id];
84
 
85
        $this->setUser($u1);
86
        [$courses, $warnings] = util::validate_courses($courseids, [], false, true);
87
        $this->assertCount(2, $warnings);
88
        $this->assertEquals($c2->id, $warnings[0]['itemid']);
89
        $this->assertEquals($c3->id, $warnings[1]['itemid']);
90
        $this->assertCount(3, $courses);
91
        $this->assertTrue($courses[$c1->id]->contextvalidated);
92
        $this->assertFalse($courses[$c2->id]->contextvalidated);
93
        $this->assertFalse($courses[$c3->id]->contextvalidated);
94
    }
95
 
96
    /**
97
     * Validate courses can re-use an array of prefetched courses.
98
     *
99
     * @covers \core_external\util::validate_courses
100
     */
101
    public function test_validate_courses_prefetch(): void {
102
        $this->resetAfterTest(true);
103
 
104
        $c1 = $this->getDataGenerator()->create_course();
105
        $c2 = $this->getDataGenerator()->create_course();
106
        $c3 = $this->getDataGenerator()->create_course();
107
        $c4 = $this->getDataGenerator()->create_course();
108
        $u1 = $this->getDataGenerator()->create_user();
109
        $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
110
        $this->getDataGenerator()->enrol_user($u1->id, $c2->id);
111
 
112
        $courseids = [$c1->id, $c2->id, $c3->id];
113
        $courses = [$c2->id => $c2, $c3->id => $c3, $c4->id => $c4];
114
 
115
        $this->setUser($u1);
116
        [$courses, $warnings] = util::validate_courses($courseids, $courses);
117
        $this->assertCount(2, $courses);
118
        $this->assertCount(1, $warnings);
119
        $this->assertArrayHasKey($c1->id, $courses);
120
        $this->assertSame($c2, $courses[$c2->id]);
121
        $this->assertArrayNotHasKey($c3->id, $courses);
122
        // The extra course passed is not returned.
123
        $this->assertArrayNotHasKey($c4->id, $courses);
124
    }
125
 
126
    /**
127
     * Test the Validate courses standard functionality.
128
     *
129
     * @covers \core_external\util::validate_courses
130
     */
131
    public function test_validate_courses(): void {
132
        $this->resetAfterTest(true);
133
 
134
        $c1 = $this->getDataGenerator()->create_course();
135
        $c2 = $this->getDataGenerator()->create_course();
136
        $c3 = $this->getDataGenerator()->create_course();
137
        $u1 = $this->getDataGenerator()->create_user();
138
        $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
139
        $courseids = [$c1->id, $c2->id, $c3->id];
140
 
141
        $this->setAdminUser();
142
        [$courses, $warnings] = util::validate_courses($courseids);
143
        $this->assertEmpty($warnings);
144
        $this->assertCount(3, $courses);
145
        $this->assertArrayHasKey($c1->id, $courses);
146
        $this->assertArrayHasKey($c2->id, $courses);
147
        $this->assertArrayHasKey($c3->id, $courses);
148
        $this->assertEquals($c1->id, $courses[$c1->id]->id);
149
        $this->assertEquals($c2->id, $courses[$c2->id]->id);
150
        $this->assertEquals($c3->id, $courses[$c3->id]->id);
151
 
152
        $this->setUser($u1);
153
        [$courses, $warnings] = util::validate_courses($courseids);
154
        $this->assertCount(2, $warnings);
155
        $this->assertEquals($c2->id, $warnings[0]['itemid']);
156
        $this->assertEquals($c3->id, $warnings[1]['itemid']);
157
        $this->assertCount(1, $courses);
158
        $this->assertArrayHasKey($c1->id, $courses);
159
        $this->assertArrayNotHasKey($c2->id, $courses);
160
        $this->assertArrayNotHasKey($c3->id, $courses);
161
        $this->assertEquals($c1->id, $courses[$c1->id]->id);
162
    }
163
 
164
    /**
165
     * Text util::get_area_files
166
     *
167
     * @covers \core_external\util::get_area_files
168
     */
169
    public function test_get_area_files(): void {
170
        global $CFG, $DB;
171
 
172
        $this->db = $DB;
173
        $DB = $this->getMockBuilder('moodle_database')->getMock();
174
 
175
        $content = base64_encode("Let us create a nice simple file.");
176
        $timemodified = 102030405;
177
        $itemid = 42;
178
        $filesize = strlen($content);
179
 
180
        $DB->method('get_records_sql')->willReturn([
181
            (object) [
182
                'filename'      => 'example.txt',
183
                'filepath'      => '/',
184
                'mimetype'      => 'text/plain',
185
                'filesize'      => $filesize,
186
                'timemodified'  => $timemodified,
187
                'itemid'        => $itemid,
188
                'pathnamehash'  => sha1('/example.txt'),
189
            ],
190
        ]);
191
 
192
        $component = 'mod_foo';
193
        $filearea = 'area';
194
        $context = 12345;
195
 
196
        $expectedfiles = [[
197
            'filename' => 'example.txt',
198
            'filepath' => '/',
199
            'fileurl' => "{$CFG->wwwroot}/webservice/pluginfile.php/{$context}/{$component}/{$filearea}/{$itemid}/example.txt",
200
            'timemodified' => $timemodified,
201
            'filesize' => $filesize,
202
            'mimetype' => 'text/plain',
203
            'isexternalfile' => false,
204
            'icon' => 'f/text',
205
        ],
206
        ];
207
        // Get all the files for the area.
208
        $files = util::get_area_files($context, $component, $filearea, false);
209
        $this->assertEquals($expectedfiles, $files);
210
 
211
        $DB->method('get_in_or_equal')->willReturn([
212
            '= :mock1',
213
            ['mock1' => $itemid],
214
        ]);
215
 
216
        // Get just the file indicated by $itemid.
217
        $files = util::get_area_files($context, $component, $filearea, $itemid);
218
        $this->assertEquals($expectedfiles, $files);
219
    }
220
 
221
    /**
222
     * Test default time for user created tokens.
223
     *
224
     * @covers \core_external\util::generate_token_for_current_user
225
     */
226
    public function test_user_created_tokens_duration(): void {
227
        global $CFG, $DB;
228
        $this->resetAfterTest(true);
229
 
230
        $CFG->enablewebservices = 1;
231
        $CFG->enablemobilewebservice = 1;
232
        $user1 = $this->getDataGenerator()->create_user();
233
        $user2 = $this->getDataGenerator()->create_user();
234
        $service = $DB->get_record('external_services', ['shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE, 'enabled' => 1]);
235
 
236
        $this->setUser($user1);
237
        $timenow = time();
238
        $token = util::generate_token_for_current_user($service);
239
        $this->assertGreaterThanOrEqual($timenow + $CFG->tokenduration, $token->validuntil);
240
 
241
        // Change token default time.
242
        $this->setUser($user2);
243
        set_config('tokenduration', DAYSECS);
244
        $token = util::generate_token_for_current_user($service);
245
        $timenow = time();
246
        $this->assertLessThanOrEqual($timenow + DAYSECS, $token->validuntil);
247
    }
248
 
249
 
250
    /**
251
     * Test the format_text function.
252
     *
253
     * @covers \core_external\util::format_text
254
     * @runInSeparateProcess
255
     */
256
    public function test_format_text(): void {
257
        $this->include_legacy_functions();
258
        $settings = external_settings::get_instance();
259
 
260
        $settings->set_raw(true);
261
        $settings->set_filter(false);
262
        $context = \context_system::instance();
263
 
264
        $test = '$$ \pi $$';
265
        $testformat = FORMAT_MARKDOWN;
266
        $correct = [$test, $testformat];
267
        $this->assertSame($correct, util::format_text($test, $testformat, $context, 'core', '', 0));
268
 
269
        // Function external_format_text should work with context id or context instance.
270
        $this->assertSame(external_format_text($test, $testformat, $context->id, 'core', '', 0), $correct);
271
        $this->assertSame(external_format_text($test, $testformat, $context, 'core', '', 0), $correct);
272
 
273
        $settings->set_raw(false);
274
        $settings->set_filter(true);
275
 
276
        $test = '$$ \pi $$';
277
        $testformat = FORMAT_MARKDOWN;
278
        $correct = ['<span class="filter_mathjaxloader_equation"><p><span class="nolink">$$ \pi $$</span></p>
279
</span>', FORMAT_HTML,
280
        ];
281
        $this->assertSame(util::format_text($test, $testformat, $context, 'core', '', 0), $correct);
282
 
283
        // Function external_format_text should work with context id or context instance.
284
        $this->assertSame(external_format_text($test, $testformat, $context->id, 'core', '', 0), $correct);
285
        $this->assertSame(external_format_text($test, $testformat, $context, 'core', '', 0), $correct);
286
 
287
        // Filters can be opted out from by the developer.
288
        $test = '$$ \pi $$';
289
        $testformat = FORMAT_MARKDOWN;
290
        $correct = ['<p>$$ \pi $$</p>
291
', FORMAT_HTML,
292
        ];
293
        $this->assertSame(util::format_text($test, $testformat, $context, 'core', '', 0, ['filter' => false]), $correct);
294
 
295
        // Function external_format_text should work with context id or context instance.
296
        $this->assertSame(external_format_text($test, $testformat, $context->id, 'core', '', 0, ['filter' => false]), $correct);
297
        $this->assertSame(external_format_text($test, $testformat, $context, 'core', '', 0, ['filter' => false]), $correct);
298
 
299
        $test = '<p><a id="test"></a><a href="#test">Text</a></p>';
300
        $testformat = FORMAT_HTML;
301
        $correct = [$test, FORMAT_HTML];
302
        $options = ['allowid' => true];
303
        $this->assertSame(util::format_text($test, $testformat, $context, 'core', '', 0, $options), $correct);
304
        // Function external_format_text should work with context id or context instance.
305
        $this->assertSame(external_format_text($test, $testformat, $context->id, 'core', '', 0, $options), $correct);
306
        $this->assertSame(external_format_text($test, $testformat, $context, 'core', '', 0, $options), $correct);
307
 
308
        $test = '<p><a id="test"></a><a href="#test">Text</a></p>';
309
        $testformat = FORMAT_HTML;
310
        $correct = ['<p><a></a><a href="#test">Text</a></p>', FORMAT_HTML];
311
        $options = new \stdClass();
312
        $options->allowid = false;
313
        $this->assertSame(util::format_text($test, $testformat, $context, 'core', '', 0, $options), $correct);
314
 
315
        // Function external_format_text should work with context id or context instance.
316
        $this->assertSame(external_format_text($test, $testformat, $context->id, 'core', '', 0, $options), $correct);
317
        $this->assertSame(external_format_text($test, $testformat, $context, 'core', '', 0, $options), $correct);
318
 
319
        $test = '<p><a id="test"></a><a href="#test">Text</a></p>' . "\n" . 'Newline';
320
        $testformat = FORMAT_MOODLE;
321
        $correct = ['<p><a id="test"></a><a href="#test">Text</a></p> Newline', FORMAT_HTML];
322
        $options = new \stdClass();
323
        $options->newlines = false;
324
        $this->assertSame(util::format_text($test, $testformat, $context, 'core', '', 0, $options), $correct);
325
 
326
        // Function external_format_text should work with context id or context instance.
327
        $this->assertSame(external_format_text($test, $testformat, $context->id, 'core', '', 0, $options), $correct);
328
        $this->assertSame(external_format_text($test, $testformat, $context, 'core', '', 0, $options), $correct);
329
 
330
        $test = '<p><a id="test"></a><a href="#test">Text</a></p>';
331
        $testformat = FORMAT_MOODLE;
332
        $correct = ['<div class="text_to_html">' . $test . '</div>', FORMAT_HTML];
333
        $options = new \stdClass();
334
        $options->para = true;
335
        $this->assertSame(util::format_text($test, $testformat, $context, 'core', '', 0, $options), $correct);
336
 
337
        // Function external_format_text should work with context id or context instance.
338
        $this->assertSame(external_format_text($test, $testformat, $context->id, 'core', '', 0, $options), $correct);
339
        $this->assertSame(external_format_text($test, $testformat, $context, 'core', '', 0, $options), $correct);
340
 
341
        $test = '<p><a id="test"></a><a href="#test">Text</a></p>';
342
        $testformat = FORMAT_MOODLE;
343
        $correct = [$test, FORMAT_HTML];
344
        $options = new \stdClass();
345
        $options->context = $context;
346
        $this->assertSame(util::format_text($test, $testformat, $context, 'core', '', 0, $options), $correct);
347
 
348
        // Function external_format_text should work with context id or context instance.
349
        $this->assertSame(external_format_text($test, $testformat, $context->id, 'core', '', 0, $options), $correct);
350
        $this->assertSame(external_format_text($test, $testformat, $context, 'core', '', 0, $options), $correct);
351
    }
352
    /**
353
     * Teset the format_string function.
354
     *
355
     * @covers \core_external\util::format_string
356
     * @runInSeparateProcess
357
     */
358
    public function test_external_format_string(): void {
359
        $this->resetAfterTest();
360
        $this->include_legacy_functions();
361
        $settings = external_settings::get_instance();
362
 
363
        // Enable multilang filter to on content and heading.
364
        filter_set_global_state('multilang', TEXTFILTER_ON);
365
        filter_set_applies_to_strings('multilang', 1);
366
        $filtermanager = \filter_manager::instance();
367
        $filtermanager->reset_caches();
368
 
369
        $settings->set_raw(true);
370
        $settings->set_filter(true);
371
        $context = \context_system::instance();
372
 
373
        $test = '<span lang="en" class="multilang">EN</span><span lang="fr" class="multilang">FR</span> ';
374
        $test .= '<script>hi</script> <h3>there</h3>!';
375
        $correct = $test;
376
        $this->assertSame($correct, util::format_string($test, $context));
377
 
378
        // Function external_format_string should work with context id or context instance.
379
        $this->assertSame($correct, external_format_string($test, $context));
380
        $this->assertSame($correct, external_format_string($test, $context->id));
381
 
382
        $settings->set_raw(false);
383
        $settings->set_filter(false);
384
 
385
        $test = '<span lang="en" class="multilang">EN</span><span lang="fr" class="multilang">FR</span> ';
386
        $test .= '<script>hi</script> <h3>there</h3>?';
387
        $correct = 'ENFR hi there?';
388
        $this->assertSame($correct, util::format_string($test, $context));
389
 
390
        // Function external_format_string should work with context id or context instance.
391
        $this->assertSame($correct, external_format_string($test, $context));
392
        $this->assertSame($correct, external_format_string($test, $context->id));
393
 
394
        $settings->set_filter(true);
395
 
396
        $test = '<span lang="en" class="multilang">EN</span><span lang="fr" class="multilang">FR</span> ';
397
        $test .= '<script>hi</script> <h3>there</h3>@';
398
        $correct = 'EN hi there@';
399
        $this->assertSame($correct, util::format_string($test, $context));
400
 
401
        // Function external_format_string should work with context id or context instance.
402
        $this->assertSame($correct, external_format_string($test, $context));
403
        $this->assertSame($correct, external_format_string($test, $context->id));
404
 
405
        // Filters can be opted out.
406
        $test = '<span lang="en" class="multilang">EN</span><span lang="fr" class="multilang">FR</span> ';
407
        $test .= '<script>hi</script> <h3>there</h3>%';
408
        $correct = 'ENFR hi there%';
409
        $this->assertSame($correct, util::format_string($test, $context, false, ['filter' => false]));
410
 
411
        // Function external_format_string should work with context id or context instance.
412
        $this->assertSame($correct, external_format_string($test, $context->id, false, ['filter' => false]));
413
        $this->assertSame($correct, external_format_string($test, $context, false, ['filter' => false]));
414
 
415
        $this->assertSame("& < > \" '", format_string("& < > \" '", true, ['escape' => false]));
416
    }
417
}