Proyectos de Subversion Moodle

Rev

Rev 11 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 11 Rev 1441
Línea 12... Línea 12...
12
// GNU General Public License for more details.
12
// GNU General Public License for more details.
13
//
13
//
14
// You should have received a copy of the GNU General Public License
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/>.
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
Línea -... Línea 16...
-
 
16
 
-
 
17
namespace core;
-
 
18
 
16
 
19
use core\exception\coding_exception;
-
 
20
use core\tests\fake_plugins_test_trait;
-
 
21
use DirectoryIterator;
-
 
22
use ReflectionClass;
Línea 17... Línea 23...
17
// phpcs:disable moodle.PHPUnit.TestCaseNames.MissingNS
23
use ReflectionProperty;
18
 
24
 
19
/**
25
/**
20
 * core_component related tests.
26
 * component related tests.
21
 *
27
 *
22
 * @package    core
28
 * @package    core
23
 * @category   test
29
 * @category   test
24
 * @copyright  2013 Petr Skoda {@link http://skodak.org}
30
 * @copyright  2013 Petr Skoda {@link http://skodak.org}
25
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26
 *
32
 *
27
 * @covers \core_component
33
 * @covers \core\component
28
 */
-
 
29
final class component_test extends advanced_testcase {
-
 
30
    /**
-
 
31
     * To be changed if number of subsystems increases/decreases,
-
 
32
     * this is defined here to annoy devs that try to add more without any thinking,
-
 
33
     * always verify that it does not collide with any existing add-on modules and subplugins!!!
34
 */
Línea 34... Línea 35...
34
     */
35
final class component_test extends \advanced_testcase {
35
    const SUBSYSTEMCOUNT = 77;
36
    use fake_plugins_test_trait;
36
 
37
 
Línea 37... Línea 38...
37
    #[\Override]
38
    #[\Override]
38
    public function tearDown(): void {
39
    public function tearDown(): void {
Línea -... Línea 40...
-
 
40
        parent::tearDown();
-
 
41
 
-
 
42
        ini_set('error_log', null);
-
 
43
    }
-
 
44
 
-
 
45
    /**
-
 
46
     * To be changed if number of subsystems increases/decreases,
39
        parent::tearDown();
47
     * this is defined here to annoy devs that try to add more without any thinking,
40
 
48
     * always verify that it does not collide with any existing add-on modules and subplugins!!!
Línea 41... Línea 49...
41
        \core_component::reset();
49
     */
Línea 42... Línea 50...
42
    }
50
    const SUBSYSTEMCOUNT = 80;
43
 
51
 
44
    public function test_get_core_subsystems(): void {
52
    public function test_get_core_subsystems(): void {
45
        global $CFG;
53
        global $CFG;
Línea 101... Línea 109...
101
    }
109
    }
Línea 102... Línea 110...
102
 
110
 
103
    public function test_deprecated_get_core_subsystems(): void {
111
    public function test_deprecated_get_core_subsystems(): void {
Línea 104... Línea 112...
104
        global $CFG;
112
        global $CFG;
Línea 105... Línea 113...
105
 
113
 
-
 
114
        $subsystems = component::get_core_subsystems();
-
 
115
 
Línea 106... Línea 116...
106
        $subsystems = core_component::get_core_subsystems();
116
        $this->assertSame($subsystems, get_core_subsystems(true));
107
 
117
        $this->assertDebuggingCalled();
-
 
118
        $this->resetDebugging();
-
 
119
 
108
        $this->assertSame($subsystems, get_core_subsystems(true));
120
        $realsubsystems = get_core_subsystems();
109
 
121
        $this->assertdebuggingcalledcount(2);
-
 
122
        $this->resetDebugging();
Línea 110... Línea 123...
110
        $realsubsystems = get_core_subsystems();
123
 
Línea 111... Línea 124...
111
        $this->assertDebuggingCalled();
124
        $this->assertSame($realsubsystems, get_core_subsystems(false));
112
        $this->assertSame($realsubsystems, get_core_subsystems(false));
125
        $this->assertdebuggingcalledcount(2);
Línea 130... Línea 143...
130
        $this->assertTrue(
143
        $this->assertTrue(
131
            empty($CFG->themedir),
144
            empty($CFG->themedir),
132
            'Non-empty $CFG->themedir is not covered by any tests yet, you need to disable it.',
145
            'Non-empty $CFG->themedir is not covered by any tests yet, you need to disable it.',
133
        );
146
        );
Línea 134... Línea 147...
134
 
147
 
Línea 135... Línea 148...
135
        $plugintypes = core_component::get_plugin_types();
148
        $plugintypes = component::get_plugin_types();
136
 
149
 
137
        foreach ($plugintypes as $plugintype => $fulldir) {
150
        foreach ($plugintypes as $plugintype => $fulldir) {
138
            $this->assertStringStartsWith("$CFG->dirroot/", $fulldir);
151
            $this->assertStringStartsWith("$CFG->dirroot/", $fulldir);
Línea 139... Línea 152...
139
        }
152
        }
140
    }
153
    }
Línea 141... Línea 154...
141
 
154
 
Línea 142... Línea 155...
142
    public function test_deprecated_get_plugin_types(): void {
155
    public function test_deprecated_get_plugin_types(): void {
-
 
156
        global $CFG;
-
 
157
 
-
 
158
        $plugintypes = component::get_plugin_types();
143
        global $CFG;
159
 
-
 
160
        $this->assertSame($plugintypes, get_plugin_types());
-
 
161
        $this->assertDebuggingCalled();
Línea 144... Línea 162...
144
 
162
        $this->resetDebugging();
145
        $plugintypes = core_component::get_plugin_types();
163
 
-
 
164
        $this->assertSame($plugintypes, get_plugin_types(true));
Línea 146... Línea 165...
146
 
165
        $this->assertDebuggingCalled();
147
        $this->assertSame($plugintypes, get_plugin_types());
166
        $this->resetDebugging();
148
        $this->assertSame($plugintypes, get_plugin_types(true));
167
 
149
 
168
        $realplugintypes = get_plugin_types(false);
Línea 150... Línea 169...
150
        $realplugintypes = get_plugin_types(false);
169
        $this->assertdebuggingcalledcount(2);
151
        $this->assertDebuggingCalled();
170
        $this->resetDebugging();
Línea 152... Línea 171...
152
 
171
 
Línea 153... Línea 172...
153
        foreach ($plugintypes as $plugintype => $fulldir) {
172
        foreach ($plugintypes as $plugintype => $fulldir) {
154
            $this->assertSame($fulldir, $CFG->dirroot . '/' . $realplugintypes[$plugintype]);
173
            $this->assertSame($fulldir, $CFG->dirroot . '/' . $realplugintypes[$plugintype]);
155
        }
174
        }
156
    }
175
    }
157
 
176
 
158
    public function test_get_plugin_list(): void {
177
    public function test_get_plugin_list(): void {
159
        global $CFG;
178
        global $CFG;
Línea 175... Línea 194...
175
            }
194
            }
176
        }
195
        }
177
    }
196
    }
Línea 178... Línea 197...
178
 
197
 
179
    public function test_deprecated_get_plugin_list(): void {
198
    public function test_deprecated_get_plugin_list(): void {
Línea 180... Línea 199...
180
        $plugintypes = core_component::get_plugin_types();
199
        $plugintypes = component::get_plugin_types();
181
 
200
 
182
        foreach ($plugintypes as $plugintype => $fulldir) {
201
        foreach ($plugintypes as $plugintype => $fulldir) {
-
 
202
            $plugins = component::get_plugin_list($plugintype);
-
 
203
            $this->assertSame($plugins, get_plugin_list($plugintype));
183
            $plugins = core_component::get_plugin_list($plugintype);
204
            $this->assertDebuggingCalled();
184
            $this->assertSame($plugins, get_plugin_list($plugintype));
205
            $this->resetDebugging();
Línea 185... Línea 206...
185
        }
206
        }
186
    }
207
    }
Línea 187... Línea 208...
187
 
208
 
188
    public function test_get_plugin_directory(): void {
209
    public function test_get_plugin_directory(): void {
189
        $plugintypes = core_component::get_plugin_types();
210
        $plugintypes = component::get_plugin_types();
190
 
211
 
191
        foreach ($plugintypes as $plugintype => $fulldir) {
212
        foreach ($plugintypes as $plugintype => $fulldir) {
192
            $plugins = core_component::get_plugin_list($plugintype);
213
            $plugins = component::get_plugin_list($plugintype);
193
            foreach ($plugins as $pluginname => $plugindir) {
214
            foreach ($plugins as $pluginname => $plugindir) {
Línea 194... Línea 215...
194
                $this->assertSame($plugindir, core_component::get_plugin_directory($plugintype, $pluginname));
215
                $this->assertSame($plugindir, component::get_plugin_directory($plugintype, $pluginname));
195
            }
216
            }
Línea 196... Línea 217...
196
        }
217
        }
197
    }
218
    }
198
 
219
 
199
    public function test_deprecated_get_plugin_directory(): void {
220
    public function test_deprecated_get_plugin_directory(): void {
200
        $plugintypes = core_component::get_plugin_types();
221
        $plugintypes = component::get_plugin_types();
201
 
222
 
202
        foreach ($plugintypes as $plugintype => $fulldir) {
223
        foreach ($plugintypes as $plugintype => $fulldir) {
-
 
224
            $plugins = component::get_plugin_list($plugintype);
-
 
225
            foreach ($plugins as $pluginname => $plugindir) {
203
            $plugins = core_component::get_plugin_list($plugintype);
226
                $this->assertSame(
204
            foreach ($plugins as $pluginname => $plugindir) {
227
                    component::get_plugin_directory($plugintype, $pluginname),
205
                $this->assertSame(
228
                    get_plugin_directory($plugintype, $pluginname),
Línea 206... Línea 229...
206
                    core_component::get_plugin_directory($plugintype, $pluginname),
229
                );
207
                    get_plugin_directory($plugintype, $pluginname),
230
                $this->assertDebuggingCalled();
208
                );
231
                $this->resetDebugging();
209
            }
232
            }
210
        }
233
        }
211
    }
234
    }
Línea 212... Línea 235...
212
 
235
 
213
    public function test_get_subsystem_directory(): void {
236
    public function test_get_subsystem_directory(): void {
214
        $subsystems = core_component::get_core_subsystems();
237
        $subsystems = component::get_core_subsystems();
215
        foreach ($subsystems as $subsystem => $fulldir) {
238
        foreach ($subsystems as $subsystem => $fulldir) {
216
            $this->assertSame($fulldir, core_component::get_subsystem_directory($subsystem));
239
            $this->assertSame($fulldir, component::get_subsystem_directory($subsystem));
217
        }
240
        }
218
    }
241
    }
219
 
242
 
220
    /**
243
    /**
221
     * Test that the get_plugin_list_with_file() function returns the correct list of plugins.
244
     * Test that the get_plugin_list_with_file() function returns the correct list of plugins.
222
     *
245
     *
Línea 223... Línea 246...
223
     * @covers \core_component::is_valid_plugin_name
246
     * @covers \core\component::is_valid_plugin_name
224
     * @dataProvider is_valid_plugin_name_provider
247
     * @dataProvider is_valid_plugin_name_provider
225
     * @param array $arguments
248
     * @param array $arguments
Línea 271... Línea 294...
271
        ];
294
        ];
272
    }
295
    }
Línea 273... Línea 296...
273
 
296
 
274
    public function test_normalize_componentname(): void {
297
    public function test_normalize_componentname(): void {
275
        // Moodle core.
298
        // Moodle core.
276
        $this->assertSame('core', core_component::normalize_componentname('core'));
299
        $this->assertSame('core', component::normalize_componentname('core'));
277
        $this->assertSame('core', core_component::normalize_componentname('moodle'));
300
        $this->assertSame('core', component::normalize_componentname('moodle'));
Línea 278... Línea 301...
278
        $this->assertSame('core', core_component::normalize_componentname(''));
301
        $this->assertSame('core', component::normalize_componentname(''));
279
 
302
 
280
        // Moodle core subsystems.
303
        // Moodle core subsystems.
281
        $this->assertSame('core_admin', core_component::normalize_componentname('admin'));
304
        $this->assertSame('core_admin', component::normalize_componentname('admin'));
Línea 282... Línea 305...
282
        $this->assertSame('core_admin', core_component::normalize_componentname('core_admin'));
305
        $this->assertSame('core_admin', component::normalize_componentname('core_admin'));
283
        $this->assertSame('core_admin', core_component::normalize_componentname('moodle_admin'));
306
        $this->assertSame('core_admin', component::normalize_componentname('moodle_admin'));
284
 
307
 
285
        // Activity modules and their subplugins.
308
        // Activity modules and their subplugins.
286
        $this->assertSame('mod_workshop', core_component::normalize_componentname('workshop'));
309
        $this->assertSame('mod_workshop', component::normalize_componentname('workshop'));
287
        $this->assertSame('mod_workshop', core_component::normalize_componentname('mod_workshop'));
310
        $this->assertSame('mod_workshop', component::normalize_componentname('mod_workshop'));
288
        $this->assertSame('workshopform_accumulative', core_component::normalize_componentname('workshopform_accumulative'));
311
        $this->assertSame('workshopform_accumulative', component::normalize_componentname('workshopform_accumulative'));
289
        $this->assertSame('mod_quiz', core_component::normalize_componentname('quiz'));
312
        $this->assertSame('mod_quiz', component::normalize_componentname('quiz'));
Línea 290... Línea 313...
290
        $this->assertSame('quiz_grading', core_component::normalize_componentname('quiz_grading'));
313
        $this->assertSame('quiz_grading', component::normalize_componentname('quiz_grading'));
291
        $this->assertSame('mod_data', core_component::normalize_componentname('data'));
314
        $this->assertSame('mod_data', component::normalize_componentname('data'));
292
        $this->assertSame('datafield_checkbox', core_component::normalize_componentname('datafield_checkbox'));
315
        $this->assertSame('datafield_checkbox', component::normalize_componentname('datafield_checkbox'));
293
 
316
 
294
        // Other plugin types.
317
        // Other plugin types.
295
        $this->assertSame('auth_mnet', core_component::normalize_componentname('auth_mnet'));
318
        $this->assertSame('auth_ldap', component::normalize_componentname('auth_ldap'));
296
        $this->assertSame('enrol_self', core_component::normalize_componentname('enrol_self'));
319
        $this->assertSame('enrol_self', component::normalize_componentname('enrol_self'));
Línea 297... Línea 320...
297
        $this->assertSame('block_html', core_component::normalize_componentname('block_html'));
320
        $this->assertSame('block_html', component::normalize_componentname('block_html'));
298
        $this->assertSame('block_mnet_hosts', core_component::normalize_componentname('block_mnet_hosts'));
321
        $this->assertSame('auth_oauth2', component::normalize_componentname('auth_oauth2'));
299
        $this->assertSame('local_amos', core_component::normalize_componentname('local_amos'));
322
        $this->assertSame('local_amos', component::normalize_componentname('local_amos'));
300
        $this->assertSame('local_admin', core_component::normalize_componentname('local_admin'));
323
        $this->assertSame('local_admin', component::normalize_componentname('local_admin'));
301
 
324
 
302
        // Unknown words without underscore are supposed to be activity modules.
325
        // Unknown words without underscore are supposed to be activity modules.
303
        $this->assertSame(
326
        $this->assertSame(
304
            'mod_whoonearthwouldcomewithsuchastupidnameofcomponent',
327
            'mod_whoonearthwouldcomewithsuchastupidnameofcomponent',
305
            core_component::normalize_componentname('whoonearthwouldcomewithsuchastupidnameofcomponent')
328
            component::normalize_componentname('whoonearthwouldcomewithsuchastupidnameofcomponent')
306
        );
329
        );
307
        // Module names can not contain underscores, this must be a subplugin.
330
        // Module names can not contain underscores, this must be a subplugin.
308
        $this->assertSame(
331
        $this->assertSame(
309
            'whoonearth_wouldcomewithsuchastupidnameofcomponent',
332
            'whoonearth_wouldcomewithsuchastupidnameofcomponent',
310
            core_component::normalize_componentname('whoonearth_wouldcomewithsuchastupidnameofcomponent')
333
            component::normalize_componentname('whoonearth_wouldcomewithsuchastupidnameofcomponent')
311
        );
334
        );
Línea 312... Línea -...
312
        $this->assertSame(
-
 
313
            'whoonearth_would_come_withsuchastupidnameofcomponent',
335
        $this->assertSame(
314
            core_component::normalize_componentname('whoonearth_would_come_withsuchastupidnameofcomponent')
336
            'whoonearth_would_come_withsuchastupidnameofcomponent',
315
        );
-
 
316
    }
-
 
317
 
-
 
318
    public function test_normalize_component(): void {
-
 
319
        // Moodle core.
-
 
320
        $this->assertSame(['core', null], core_component::normalize_component('core'));
-
 
321
        $this->assertSame(['core', null], core_component::normalize_component('moodle'));
-
 
322
        $this->assertSame(['core', null], core_component::normalize_component(''));
337
            component::normalize_componentname('whoonearth_would_come_withsuchastupidnameofcomponent')
323
 
338
        );
324
        // Moodle core subsystems.
-
 
325
        $this->assertSame(['core', 'admin'], core_component::normalize_component('admin'));
-
 
326
        $this->assertSame(['core', 'admin'], core_component::normalize_component('core_admin'));
-
 
327
        $this->assertSame(['core', 'admin'], core_component::normalize_component('moodle_admin'));
-
 
328
 
-
 
329
        // Activity modules and their subplugins.
-
 
330
        $this->assertSame(['mod', 'workshop'], core_component::normalize_component('workshop'));
-
 
331
        $this->assertSame(['mod', 'workshop'], core_component::normalize_component('mod_workshop'));
-
 
332
        $this->assertSame(['workshopform', 'accumulative'], core_component::normalize_component('workshopform_accumulative'));
339
    }
333
        $this->assertSame(['mod', 'quiz'], core_component::normalize_component('quiz'));
-
 
334
        $this->assertSame(['quiz', 'grading'], core_component::normalize_component('quiz_grading'));
-
 
335
        $this->assertSame(['mod', 'data'], core_component::normalize_component('data'));
-
 
336
        $this->assertSame(['datafield', 'checkbox'], core_component::normalize_component('datafield_checkbox'));
-
 
337
 
-
 
338
        // Other plugin types.
-
 
339
        $this->assertSame(['auth', 'mnet'], core_component::normalize_component('auth_mnet'));
-
 
340
        $this->assertSame(['enrol', 'self'], core_component::normalize_component('enrol_self'));
-
 
341
        $this->assertSame(['block', 'html'], core_component::normalize_component('block_html'));
340
 
342
        $this->assertSame(['block', 'mnet_hosts'], core_component::normalize_component('block_mnet_hosts'));
-
 
343
        $this->assertSame(['local', 'amos'], core_component::normalize_component('local_amos'));
-
 
344
        $this->assertSame(['local', 'admin'], core_component::normalize_component('local_admin'));
341
    /**
345
 
-
 
346
        // Unknown words without underscore are supposed to be activity modules.
-
 
347
        $this->assertSame(
-
 
348
            ['mod', 'whoonearthwouldcomewithsuchastupidnameofcomponent'],
342
     * Test \core_component::normalize_component function.
349
            core_component::normalize_component('whoonearthwouldcomewithsuchastupidnameofcomponent')
-
 
350
        );
343
     *
351
        // Module names can not contain underscores, this must be a subplugin.
344
     * @dataProvider normalise_component_provider
352
        $this->assertSame(
345
     * @param array $expected
353
            ['whoonearth', 'wouldcomewithsuchastupidnameofcomponent'],
346
     * @param string $args
354
            core_component::normalize_component('whoonearth_wouldcomewithsuchastupidnameofcomponent')
347
     */
Línea -... Línea 348...
-
 
348
    public function test_normalize_component(array $expected, string $args): void {
355
        );
349
        $this->assertSame(
356
        $this->assertSame(
350
            $expected,
357
            ['whoonearth', 'would_come_withsuchastupidnameofcomponent'],
351
            component::normalize_component($args),
358
            core_component::normalize_component('whoonearth_would_come_withsuchastupidnameofcomponent')
352
        );
359
        );
353
    }
360
    }
354
 
361
 
355
    /**
362
    public function test_deprecated_normalize_component(): void {
356
     * Test the deprecated normalize_component function.
363
        // Moodle core.
357
     *
364
        $this->assertSame(['core', null], normalize_component('core'));
358
     * @dataProvider normalise_component_provider
-
 
359
     * @param array $expected
Línea 365... Línea -...
365
        $this->assertSame(['core', null], normalize_component(''));
-
 
366
        $this->assertSame(['core', null], normalize_component('moodle'));
-
 
367
 
-
 
368
        // Moodle core subsystems.
-
 
369
        $this->assertSame(['core', 'admin'], normalize_component('admin'));
360
     * @param string $args
370
        $this->assertSame(['core', 'admin'], normalize_component('core_admin'));
-
 
371
        $this->assertSame(['core', 'admin'], normalize_component('moodle_admin'));
-
 
372
 
-
 
-
 
361
     */
Línea -... Línea 362...
-
 
362
    public function test_deprecated_normalize_component(array $expected, string $args): void {
-
 
363
        $this->assertSame(
-
 
364
            $expected,
-
 
365
            normalize_component($args),
-
 
366
        );
-
 
367
 
-
 
368
        $this->assertDebuggingCalled();
-
 
369
    }
-
 
370
 
-
 
371
    /**
-
 
372
     * Data provider for the normalize_component function.
-
 
373
     */
-
 
374
    public static function normalise_component_provider(): array {
-
 
375
        return [
-
 
376
            // Moodle core.
-
 
377
            [['core', null], 'core'],
-
 
378
            [['core', null], ''],
-
 
379
            [['core', null], 'moodle'],
-
 
380
 
-
 
381
            // Moodle core subsystems.
-
 
382
            [['core', 'admin'], 'admin'],
-
 
383
            [['core', 'admin'], 'core_admin'],
-
 
384
            [['core', 'admin'], 'moodle_admin'],
-
 
385
 
373
        // Activity modules and their subplugins.
386
            // Activity modules and their subplugins.
374
        $this->assertSame(['mod', 'workshop'], normalize_component('workshop'));
387
            [['mod', 'workshop'], 'workshop'],
375
        $this->assertSame(['mod', 'workshop'], normalize_component('mod_workshop'));
388
            [['mod', 'workshop'], 'mod_workshop'],
376
        $this->assertSame(['workshopform', 'accumulative'], normalize_component('workshopform_accumulative'));
389
            [['workshopform', 'accumulative'], 'workshopform_accumulative'],
377
        $this->assertSame(['mod', 'quiz'], normalize_component('quiz'));
390
            [['mod', 'quiz'], 'quiz'],
378
        $this->assertSame(['quiz', 'grading'], normalize_component('quiz_grading'));
391
            [['quiz', 'grading'], 'quiz_grading'],
379
        $this->assertSame(['mod', 'data'], normalize_component('data'));
392
            [['mod', 'data'], 'data'],
Línea 380... Línea 393...
380
        $this->assertSame(['datafield', 'checkbox'], normalize_component('datafield_checkbox'));
393
            [['datafield', 'checkbox'], 'datafield_checkbox'],
381
 
394
 
382
        // Other plugin types.
395
            // Other plugin types.
383
        $this->assertSame(['auth', 'mnet'], normalize_component('auth_mnet'));
396
            [['auth', 'ldap'], 'auth_ldap'],
384
        $this->assertSame(['enrol', 'self'], normalize_component('enrol_self'));
397
            [['enrol', 'self'], 'enrol_self'],
385
        $this->assertSame(['block', 'html'], normalize_component('block_html'));
398
            [['block', 'html'], 'block_html'],
386
        $this->assertSame(['block', 'mnet_hosts'], normalize_component('block_mnet_hosts'));
399
            [['auth', 'oauth2'], 'auth_oauth2'],
387
        $this->assertSame(['local', 'amos'], normalize_component('local_amos'));
400
            [['local', 'amos'], 'local_amos'],
388
        $this->assertSame(['local', 'admin'], normalize_component('local_admin'));
401
            [['local', 'admin'], 'local_admin'],
389
 
402
 
390
        // Unknown words without underscore are supposed to be activity modules.
403
            // Unknown words without underscore are supposed to be activity modules.
391
        $this->assertSame(
404
            [
392
            ['mod', 'whoonearthwouldcomewithsuchastupidnameofcomponent'],
405
                ['mod', 'whoonearthwouldcomewithsuchastupidnameofcomponent'],
-
 
406
                'whoonearthwouldcomewithsuchastupidnameofcomponent',
393
            normalize_component('whoonearthwouldcomewithsuchastupidnameofcomponent')
407
            ],
394
        );
408
            // Module names can not contain underscores, this must be a subplugin.
Línea 395... Línea 409...
395
        // Module names can not contain underscores, this must be a subplugin.
409
            [
396
        $this->assertSame(
410
                ['whoonearth', 'wouldcomewithsuchastupidnameofcomponent'],
397
            ['whoonearth', 'wouldcomewithsuchastupidnameofcomponent'],
411
                'whoonearth_wouldcomewithsuchastupidnameofcomponent',
398
            normalize_component('whoonearth_wouldcomewithsuchastupidnameofcomponent')
412
            ],
399
        );
413
            [
400
        $this->assertSame(
414
                ['whoonearth', 'would_come_withsuchastupidnameofcomponent'],
401
            ['whoonearth', 'would_come_withsuchastupidnameofcomponent'],
415
                'whoonearth_would_come_withsuchastupidnameofcomponent',
402
            normalize_component('whoonearth_would_come_withsuchastupidnameofcomponent')
416
            ],
Línea 403... Línea 417...
403
        );
417
        ];
404
    }
418
    }
405
 
419
 
406
    public function test_get_component_directory(): void {
420
    public function test_get_component_directory(): void {
407
        $plugintypes = core_component::get_plugin_types();
421
        $plugintypes = component::get_plugin_types();
Línea 408... Línea 422...
408
        foreach ($plugintypes as $plugintype => $fulldir) {
422
        foreach ($plugintypes as $plugintype => $fulldir) {
409
            $plugins = core_component::get_plugin_list($plugintype);
423
            $plugins = component::get_plugin_list($plugintype);
410
            foreach ($plugins as $pluginname => $plugindir) {
424
            foreach ($plugins as $pluginname => $plugindir) {
411
                $this->assertSame($plugindir, core_component::get_component_directory(($plugintype . '_' . $pluginname)));
425
                $this->assertSame($plugindir, component::get_component_directory(($plugintype . '_' . $pluginname)));
412
            }
426
            }
413
        }
427
        }
414
 
428
 
415
        $subsystems = core_component::get_core_subsystems();
429
        $subsystems = component::get_core_subsystems();
416
        foreach ($subsystems as $subsystem => $fulldir) {
430
        foreach ($subsystems as $subsystem => $fulldir) {
417
            $this->assertSame($fulldir, core_component::get_component_directory(('core_' . $subsystem)));
431
            $this->assertSame($fulldir, component::get_component_directory(('core_' . $subsystem)));
418
        }
432
        }
419
    }
433
    }
420
 
434
 
421
    /**
435
    /**
422
     * Unit tests for get_component_from_classname.
436
     * Unit tests for get_component_from_classname.
423
     *
437
     *
424
     * @dataProvider get_component_from_classname_provider
438
     * @dataProvider get_component_from_classname_provider
Línea 425... Línea 439...
425
     * @param string $classname The class name to test
439
     * @param string $classname The class name to test
426
     * @param string|null $expected The expected component
440
     * @param string|null $expected The expected component
Línea 484... Línea 498...
484
            ),
498
            ),
485
        );
499
        );
486
    }
500
    }
Línea 487... Línea 501...
487
 
501
 
488
    public function test_deprecated_get_component_directory(): void {
502
    public function test_deprecated_get_component_directory(): void {
489
        $plugintypes = core_component::get_plugin_types();
503
        $plugintypes = component::get_plugin_types();
490
        foreach ($plugintypes as $plugintype => $fulldir) {
504
        foreach ($plugintypes as $plugintype => $fulldir) {
491
            $plugins = core_component::get_plugin_list($plugintype);
505
            $plugins = component::get_plugin_list($plugintype);
492
            foreach ($plugins as $pluginname => $plugindir) {
506
            foreach ($plugins as $pluginname => $plugindir) {
-
 
507
                $this->assertSame($plugindir, get_component_directory(($plugintype . '_' . $pluginname)));
-
 
508
                $this->assertDebuggingCalled();
493
                $this->assertSame($plugindir, get_component_directory(($plugintype . '_' . $pluginname)));
509
                $this->resetDebugging();
494
            }
510
            }
Línea 495... Línea 511...
495
        }
511
        }
496
 
512
 
497
        $subsystems = core_component::get_core_subsystems();
513
        $subsystems = component::get_core_subsystems();
-
 
514
        foreach ($subsystems as $subsystem => $fulldir) {
-
 
515
            $this->assertSame($fulldir, get_component_directory(('core_' . $subsystem)));
498
        foreach ($subsystems as $subsystem => $fulldir) {
516
            $this->assertDebuggingCalled();
499
            $this->assertSame($fulldir, get_component_directory(('core_' . $subsystem)));
517
            $this->resetDebugging();
Línea 500... Línea 518...
500
        }
518
        }
501
    }
519
    }
Línea 502... Línea 520...
502
 
520
 
Línea 503... Línea 521...
503
    public function test_get_subtype_parent(): void {
521
    public function test_get_subtype_parent(): void {
504
        global $CFG;
522
        global $CFG;
505
 
523
 
506
        $this->assertNull(core_component::get_subtype_parent('mod'));
524
        $this->assertNull(component::get_subtype_parent('mod'));
507
 
525
 
508
        // Any plugin with more subtypes is ok here.
526
        // Any plugin with more subtypes is ok here.
Línea 509... Línea 527...
509
        $this->assertFileExists("$CFG->dirroot/mod/assign/db/subplugins.json");
527
        $this->assertFileExists("$CFG->dirroot/mod/assign/db/subplugins.json");
510
        $this->assertSame('mod_assign', core_component::get_subtype_parent('assignsubmission'));
528
        $this->assertSame('mod_assign', component::get_subtype_parent('assignsubmission'));
Línea 511... Línea 529...
511
        $this->assertSame('mod_assign', core_component::get_subtype_parent('assignfeedback'));
529
        $this->assertSame('mod_assign', component::get_subtype_parent('assignfeedback'));
512
        $this->assertNull(core_component::get_subtype_parent('assignxxxxx'));
530
        $this->assertNull(component::get_subtype_parent('assignxxxxx'));
Línea 513... Línea 531...
513
    }
531
    }
514
 
532
 
Línea 515... Línea 533...
515
    public function test_get_subplugins(): void {
533
    public function test_get_subplugins(): void {
516
        global $CFG;
534
        global $CFG;
Línea 517... Línea 535...
517
 
535
 
518
        // Any plugin with more subtypes is ok here.
536
        // Any plugin with more subtypes is ok here.
Línea 519... Línea 537...
519
        $this->assertFileExists("$CFG->dirroot/mod/assign/db/subplugins.json");
537
        $this->assertFileExists("$CFG->dirroot/mod/assign/db/subplugins.json");
520
 
538
 
521
        $subplugins = core_component::get_subplugins('mod_assign');
539
        $subplugins = component::get_subplugins('mod_assign');
Línea 522... Línea 540...
522
        $this->assertSame(['assignsubmission', 'assignfeedback'], array_keys($subplugins));
540
        $this->assertSame(['assignsubmission', 'assignfeedback'], array_keys($subplugins));
Línea 523... Línea 541...
523
 
541
 
524
        $subs = core_component::get_plugin_list('assignsubmission');
542
        $subs = component::get_plugin_list('assignsubmission');
Línea 525... Línea 543...
525
        $feeds = core_component::get_plugin_list('assignfeedback');
543
        $feeds = component::get_plugin_list('assignfeedback');
526
 
544
 
Línea 527... Línea 545...
527
        $this->assertSame(array_keys($subs), $subplugins['assignsubmission']);
545
        $this->assertSame(array_keys($subs), $subplugins['assignsubmission']);
Línea 528... Línea 546...
528
        $this->assertSame(array_keys($feeds), $subplugins['assignfeedback']);
546
        $this->assertSame(array_keys($feeds), $subplugins['assignfeedback']);
529
 
547
 
530
        // Any plugin without subtypes is ok here.
548
        // Any plugin without subtypes is ok here.
531
        $this->assertFileExists("$CFG->dirroot/mod/choice");
549
        $this->assertFileExists("$CFG->dirroot/mod/choice");
Línea 553... Línea 571...
553
    }
571
    }
Línea 554... Línea 572...
554
 
572
 
555
    public function test_get_plugin_list_with_file(): void {
573
    public function test_get_plugin_list_with_file(): void {
Línea 556... Línea 574...
556
        $this->resetAfterTest(true);
574
        $this->resetAfterTest(true);
Línea 557... Línea 575...
557
 
575
 
558
        // No extra reset here because core_component reset automatically.
576
        // No extra reset here because component reset automatically.
559
 
577
 
560
        $expected = [];
578
        $expected = [];
561
        $reports = core_component::get_plugin_list('report');
579
        $reports = component::get_plugin_list('report');
562
        foreach ($reports as $name => $fulldir) {
580
        foreach ($reports as $name => $fulldir) {
563
            if (file_exists("$fulldir/lib.php")) {
581
            if (file_exists("$fulldir/lib.php")) {
Línea 564... Línea 582...
564
                $expected[] = $name;
582
                $expected[] = $name;
565
            }
583
            }
566
        }
584
        }
Línea 567... Línea 585...
567
 
585
 
568
        // Test cold.
586
        // Test cold.
569
        $list = core_component::get_plugin_list_with_file('report', 'lib.php', false);
587
        $list = component::get_plugin_list_with_file('report', 'lib.php', false);
Línea 570... Línea 588...
570
        $this->assertEquals($expected, array_keys($list));
588
        $this->assertEquals($expected, array_keys($list));
571
 
589
 
572
        // Test hot.
590
        // Test hot.
Línea 573... Línea 591...
573
        $list = core_component::get_plugin_list_with_file('report', 'lib.php', false);
591
        $list = component::get_plugin_list_with_file('report', 'lib.php', false);
574
        $this->assertEquals($expected, array_keys($list));
592
        $this->assertEquals($expected, array_keys($list));
575
 
593
 
576
        // Test with include.
594
        // Test with include.
Línea 577... Línea 595...
577
        $list = core_component::get_plugin_list_with_file('report', 'lib.php', true);
595
        $list = component::get_plugin_list_with_file('report', 'lib.php', true);
578
        $this->assertEquals($expected, array_keys($list));
596
        $this->assertEquals($expected, array_keys($list));
579
 
597
 
580
        // Test missing.
598
        // Test missing.
581
        $list = core_component::get_plugin_list_with_file('report', 'idontexist.php', true);
599
        $list = component::get_plugin_list_with_file('report', 'idontexist.php', true);
582
        $this->assertEquals([], array_keys($list));
600
        $this->assertEquals([], array_keys($list));
583
    }
601
    }
Línea 584... Línea 602...
584
 
602
 
585
    /**
603
    /**
586
     * Tests for get_component_classes_in_namespace.
604
     * Tests for get_component_classes_in_namespace.
587
     */
605
     */
588
    public function test_get_component_classes_in_namespace(): void {
606
    public function test_get_component_classes_in_namespace(): void {
Línea 589... Línea 607...
589
        // Unexisting.
607
        // Unexisting.
590
        $this->assertCount(0, core_component::get_component_classes_in_namespace('core_unexistingcomponent', 'something'));
608
        $this->assertCount(0, component::get_component_classes_in_namespace('core_unexistingcomponent', 'something'));
591
        $this->assertCount(0, core_component::get_component_classes_in_namespace('auth_cas', 'something'));
609
        $this->assertCount(0, component::get_component_classes_in_namespace('auth_db', 'something'));
592
 
610
 
593
        // Matches the last namespace level name not partials.
611
        // Matches the last namespace level name not partials.
Línea 594... Línea 612...
594
        $this->assertCount(0, core_component::get_component_classes_in_namespace('auth_cas', 'tas'));
612
        $this->assertCount(0, component::get_component_classes_in_namespace('auth_db', 'tas'));
595
        $this->assertCount(0, core_component::get_component_classes_in_namespace('core_user', 'course'));
613
        $this->assertCount(0, component::get_component_classes_in_namespace('core_user', 'course'));
596
        $this->assertCount(0, core_component::get_component_classes_in_namespace('mod_forum', 'output\\emaildigest'));
614
        $this->assertCount(0, component::get_component_classes_in_namespace('mod_forum', 'output\\emaildigest'));
Línea 611... Línea 629...
611
     */
629
     */
612
    public function test_get_component_classes_in_namespace_provider(
630
    public function test_get_component_classes_in_namespace_provider(
613
        array $methodargs,
631
        array $methodargs,
614
        string $expectedclassnameformat,
632
        string $expectedclassnameformat,
615
    ): void {
633
    ): void {
616
        $classlist = core_component::get_component_classes_in_namespace(...$methodargs);
634
        $classlist = component::get_component_classes_in_namespace(...$methodargs);
617
        $this->assertGreaterThan(0, count($classlist));
635
        $this->assertGreaterThan(0, count($classlist));
Línea 618... Línea 636...
618
 
636
 
619
        foreach (array_keys($classlist) as $classname) {
637
        foreach (array_keys($classlist) as $classname) {
620
            $this->assertStringMatchesFormat($expectedclassnameformat, $classname);
638
            $this->assertStringMatchesFormat($expectedclassnameformat, $classname);
Línea 645... Línea 663...
645
                ['mod_forum', '\\output\\email\\'],
663
                ['mod_forum', '\\output\\email\\'],
646
                'mod_forum\output\email\%s',
664
                'mod_forum\output\email\%s',
647
            ],
665
            ],
648
            // Prefix with backslash if it doesn\'t come prefixed.
666
            // Prefix with backslash if it doesn\'t come prefixed.
649
            [
667
            [
650
                ['auth_cas', 'task'],
668
                ['auth_db', 'task'],
651
                'auth_cas\task\%s',
669
                'auth_db\task\%s',
652
            ],
670
            ],
653
            [
671
            [
654
                ['auth_cas', '\\task'],
672
                ['auth_db', '\\task'],
655
                'auth_cas\task\%s',
673
                'auth_db\task\%s',
656
            ],
674
            ],
Línea 657... Línea 675...
657
 
675
 
658
            // Core as a component works, the function can normalise the component name.
676
            // Core as a component works, the function can normalise the component name.
659
            [
677
            [
Línea 797... Línea 815...
797
     * @param string $classname The name of the class to attempt to load.
815
     * @param string $classname The name of the class to attempt to load.
798
     * @param string $includedfiles The file expected to be loaded.
816
     * @param string $includedfiles The file expected to be loaded.
799
     * @runInSeparateProcess
817
     * @runInSeparateProcess
800
     */
818
     */
801
    public function test_classloader($psr0, $psr4, $classname, $includedfiles): void {
819
    public function test_classloader($psr0, $psr4, $classname, $includedfiles): void {
802
        $psr0namespaces = new ReflectionProperty('core_component', 'psr0namespaces');
820
        $psr0namespaces = new ReflectionProperty(component::class, 'psr0namespaces');
803
        $psr0namespaces->setValue(null, $psr0);
821
        $psr0namespaces->setValue(null, $psr0);
Línea 804... Línea 822...
804
 
822
 
805
        $psr4namespaces = new ReflectionProperty('core_component', 'psr4namespaces');
823
        $psr4namespaces = new ReflectionProperty(component::class, 'psr4namespaces');
Línea 806... Línea 824...
806
        $psr4namespaces->setValue(null, $psr4);
824
        $psr4namespaces->setValue(null, $psr4);
807
 
825
 
808
        core_component::classloader($classname);
826
        component::classloader($classname);
809
        if (DIRECTORY_SEPARATOR != '/') {
827
        if (DIRECTORY_SEPARATOR != '/') {
810
            // Denormalise the expected path so that we can quickly compare with get_included_files.
828
            // Denormalise the expected path so that we can quickly compare with get_included_files.
811
            $includedfiles = str_replace('/', DIRECTORY_SEPARATOR, $includedfiles);
829
            $includedfiles = str_replace('/', DIRECTORY_SEPARATOR, $includedfiles);
Línea 903... Línea 921...
903
                        'lib/psr/http-message/src',
921
                        'lib/psr/http-message/src',
904
                        'lib/psr/http-factory/src',
922
                        'lib/psr/http-factory/src',
905
                    ],
923
                    ],
906
                ],
924
                ],
907
                'classname' => 'Psr\Http\Message\ServerRequestInterface',
925
                'classname' => 'Psr\Http\Message\ServerRequestInterface',
908
                'includedfiles' => "{$dirroot}/lib/psr/http-message/src/ServerRequestInterface.php",
926
                'file' => "{$dirroot}/lib/psr/http-message/src/ServerRequestInterface.php",
909
            ],
927
            ],
910
            'PSR-4 namespaces can come from multiple sources - second source' => [
928
            'PSR-4 namespaces can come from multiple sources - second source' => [
911
                'psr0' => [],
929
                'psr0' => [],
912
                'psr4' => [
930
                'psr4' => [
913
                    'Psr\\Http\\Message' => [
931
                    'Psr\\Http\\Message' => [
914
                        'lib/psr/http-message/src',
932
                        'lib/psr/http-message/src',
915
                        'lib/psr/http-factory/src',
933
                        'lib/psr/http-factory/src',
916
                    ],
934
                    ],
917
                ],
935
                ],
918
                'classname' => 'Psr\Http\Message\ServerRequestFactoryInterface',
936
                'classname' => 'Psr\Http\Message\ServerRequestFactoryInterface',
919
                'includedfiles' => "{$dirroot}/lib/psr/http-factory/src/ServerRequestFactoryInterface.php",
937
                'file' => "{$dirroot}/lib/psr/http-factory/src/ServerRequestFactoryInterface.php",
920
            ],
938
            ],
921
        ];
939
        ];
922
    }
940
    }
Línea 923... Línea 941...
923
 
941
 
Línea 956... Línea 974...
956
 
974
 
957
        // Note: This is pretty hacky, but it's the only way to test the classloader.
975
        // Note: This is pretty hacky, but it's the only way to test the classloader.
958
        // We have to override the dirroot and libdir, and then reset the plugintypes property.
976
        // We have to override the dirroot and libdir, and then reset the plugintypes property.
959
        $CFG->dirroot = $vfileroot->url();
977
        $CFG->dirroot = $vfileroot->url();
960
        $CFG->libdir = $vfileroot->url() . '/lib';
978
        $CFG->libdir = $vfileroot->url() . '/lib';
Línea 961... Línea 979...
961
        \core_component::reset();
979
        component::reset();
962
 
980
 
963
        // Existing classes do not break.
981
        // Existing classes do not break.
964
        $this->assertTrue(
982
        $this->assertTrue(
Línea 988... Línea 1006...
988
     * @param string $classname The name of the class to attempt to load.
1006
     * @param string $classname The name of the class to attempt to load.
989
     * @param string|bool $file The expected file corresponding to the class or false for nonexistant.
1007
     * @param string|bool $file The expected file corresponding to the class or false for nonexistant.
990
     * @runInSeparateProcess
1008
     * @runInSeparateProcess
991
     */
1009
     */
992
    public function test_psr_classloader($psr0, $psr4, $classname, $file): void {
1010
    public function test_psr_classloader($psr0, $psr4, $classname, $file): void {
-
 
1011
        return;
993
        $psr0namespaces = new ReflectionProperty('core_component', 'psr0namespaces');
1012
        $psr0namespaces = new ReflectionProperty(component::class, 'psr0namespaces');
994
        $psr0namespaces->setValue(null, $psr0);
1013
        $psr0namespaces->setValue(null, $psr0);
Línea 995... Línea 1014...
995
 
1014
 
996
        $psr4namespaces = new ReflectionProperty('core_component', 'psr4namespaces');
1015
        $psr4namespaces = new ReflectionProperty(component::class, 'psr4namespaces');
Línea 997... Línea 1016...
997
        $psr4namespaces->setValue(null, $psr4);
1016
        $psr4namespaces->setValue(null, $psr4);
998
 
1017
 
Línea 999... Línea 1018...
999
        $component = new ReflectionClass('core_component');
1018
        $component = new ReflectionClass(component::class);
1000
        $psrclassloader = $component->getMethod('psr_classloader');
1019
        $psrclassloader = $component->getMethod('psr_classloader');
1001
 
1020
 
Línea 1054... Línea 1073...
1054
     * @param string $path The relative path to the base directory of the source files.
1073
     * @param string $path The relative path to the base directory of the source files.
1055
     * @param string[] $separators The characters that should be used for separating.
1074
     * @param string[] $separators The characters that should be used for separating.
1056
     * @param string|bool $result The expected result to be returned from get_class_file.
1075
     * @param string|bool $result The expected result to be returned from get_class_file.
1057
     */
1076
     */
1058
    public function test_get_class_file($classname, $prefix, $path, $separators, $result): void {
1077
    public function test_get_class_file($classname, $prefix, $path, $separators, $result): void {
1059
        $component = new ReflectionClass('core_component');
1078
        $component = new ReflectionClass(component::class);
1060
        $psrclassloader = $component->getMethod('get_class_file');
1079
        $psrclassloader = $component->getMethod('get_class_file');
Línea 1061... Línea 1080...
1061
 
1080
 
1062
        $file = $psrclassloader->invokeArgs(null, [$classname, $prefix, $path, $separators]);
1081
        $file = $psrclassloader->invokeArgs(null, [$classname, $prefix, $path, $separators]);
1063
        $this->assertEquals($result, $file);
1082
        $this->assertEquals($result, $file);
Línea 1066... Línea 1085...
1066
    /**
1085
    /**
1067
     * Confirm the get_component_list method contains an entry for every component.
1086
     * Confirm the get_component_list method contains an entry for every component.
1068
     */
1087
     */
1069
    public function test_get_component_list_contains_all_components(): void {
1088
    public function test_get_component_list_contains_all_components(): void {
1070
        global $CFG;
1089
        global $CFG;
1071
        $componentslist = \core_component::get_component_list();
1090
        $componentslist = component::get_component_list();
Línea 1072... Línea 1091...
1072
 
1091
 
1073
        // We should have an entry for each plugin type, and one additional for 'core'.
1092
        // We should have an entry for each plugin type, and one additional for 'core'.
1074
        $plugintypes = \core_component::get_plugin_types();
1093
        $plugintypes = component::get_plugin_types();
1075
        $numelementsexpected = count($plugintypes) + 1;
1094
        $numelementsexpected = count($plugintypes) + 1;
Línea 1076... Línea 1095...
1076
        $this->assertEquals($numelementsexpected, count($componentslist));
1095
        $this->assertEquals($numelementsexpected, count($componentslist));
1077
 
1096
 
Línea 1099... Línea 1118...
1099
    public function test_get_component_names(
1118
    public function test_get_component_names(
1100
        bool $includecore,
1119
        bool $includecore,
1101
        bool $coreexpected,
1120
        bool $coreexpected,
1102
    ): void {
1121
    ): void {
1103
        global $CFG;
1122
        global $CFG;
1104
        $componentnames = \core_component::get_component_names($includecore);
1123
        $componentnames = component::get_component_names($includecore);
Línea 1105... Línea 1124...
1105
 
1124
 
1106
        // We should have an entry for each plugin type.
1125
        // We should have an entry for each plugin type.
1107
        $plugintypes = \core_component::get_plugin_types();
1126
        $plugintypes = component::get_plugin_types();
1108
        $numplugintypes = 0;
1127
        $numplugintypes = 0;
1109
        foreach (array_keys($plugintypes) as $type) {
1128
        foreach (array_keys($plugintypes) as $type) {
1110
            $numplugintypes += count(\core_component::get_plugin_list($type));
1129
            $numplugintypes += count(component::get_plugin_list($type));
1111
        }
1130
        }
1112
        // And an entry for each core subsystem.
1131
        // And an entry for each core subsystem.
Línea 1113... Línea 1132...
1113
        $numcomponents = $numplugintypes + count(\core_component::get_core_subsystems());
1132
        $numcomponents = $numplugintypes + count(component::get_core_subsystems());
1114
 
1133
 
1115
        if ($coreexpected) {
1134
        if ($coreexpected) {
1116
            // Add one for core.
1135
            // Add one for core.
Línea 1141... Línea 1160...
1141
            [true, true],
1160
            [true, true],
1142
        ];
1161
        ];
1143
    }
1162
    }
Línea 1144... Línea 1163...
1144
 
1163
 
1145
    /**
1164
    /**
1146
     * Basic tests for APIs related functions in the core_component class.
1165
     * Basic tests for APIs related functions in the component class.
1147
     */
1166
     */
1148
    public function test_apis_methods(): void {
1167
    public function test_apis_methods(): void {
1149
        $apis = core_component::get_core_apis();
1168
        $apis = component::get_core_apis();
Línea 1150... Línea 1169...
1150
        $this->assertIsArray($apis);
1169
        $this->assertIsArray($apis);
1151
 
1170
 
Línea 1152... Línea 1171...
1152
        $apinames = core_component::get_core_api_names();
1171
        $apinames = component::get_core_api_names();
1153
        $this->assertIsArray($apis);
1172
        $this->assertIsArray($apis);
Línea 1154... Línea 1173...
1154
 
1173
 
1155
        // Both should return the very same APIs.
1174
        // Both should return the very same APIs.
1156
        $this->assertEquals($apinames, array_keys($apis));
1175
        $this->assertEquals($apinames, array_keys($apis));
Línea 1157... Línea 1176...
1157
 
1176
 
1158
        $this->assertFalse(core_component::is_core_api('lalala'));
1177
        $this->assertFalse(component::is_core_api('lalala'));
1159
        $this->assertTrue(core_component::is_core_api('privacy'));
1178
        $this->assertTrue(component::is_core_api('privacy'));
1160
    }
1179
    }
1161
 
1180
 
1162
    /**
1181
    /**
1163
     * Test that the apis.json structure matches expectations
1182
     * Test that the apis.json structure matches expectations
1164
     *
1183
     *
1165
     * While we include an apis.schema.json file in core, there isn't any PHP built-in allowing us
1184
     * While we include an apis.schema.json file in core, there isn't any PHP built-in allowing us
1166
     * to validate it (3rd part libraries needed). Plus the schema doesn't allow to validate things
1185
     * to validate it (3rd part libraries needed). Plus the schema doesn't allow to validate things
Línea 1167... Línea 1186...
1167
     * like uniqueness or sorting. We are going to do all that here.
1186
     * like uniqueness or sorting. We are going to do all that here.
1168
     */
1187
     */
Línea 1169... Línea 1188...
1169
    public function test_apis_json_validation(): void {
1188
    public function test_apis_json_validation(): void {
1170
        $apis = $sortedapis = core_component::get_core_apis();
1189
        $apis = $sortedapis = component::get_core_apis();
1171
        ksort($sortedapis); // We'll need this later.
1190
        ksort($sortedapis); // We'll need this later.
Línea 1213... Línea 1232...
1213
    /**
1232
    /**
1214
     * Test for monologo icons check in plugins.
1233
     * Test for monologo icons check in plugins.
1215
     */
1234
     */
1216
    public function test_has_monologo_icon(): void {
1235
    public function test_has_monologo_icon(): void {
1217
        // The Forum activity plugin has monologo icons.
1236
        // The Forum activity plugin has monologo icons.
1218
        $this->assertTrue(core_component::has_monologo_icon('mod', 'forum'));
1237
        $this->assertTrue(component::has_monologo_icon('mod', 'forum'));
1219
        // The core H5P subsystem doesn't have monologo icons.
1238
        // The core H5P subsystem doesn't have monologo icons.
1220
        $this->assertFalse(core_component::has_monologo_icon('core', 'h5p'));
1239
        $this->assertFalse(component::has_monologo_icon('core', 'h5p'));
1221
        // The function will return false for a non-existent component.
1240
        // The function will return false for a non-existent component.
1222
        $this->assertFalse(core_component::has_monologo_icon('randomcomponent', 'h5p'));
1241
        $this->assertFalse(component::has_monologo_icon('randomcomponent', 'h5p'));
1223
    }
1242
    }
Línea 1224... Línea 1243...
1224
 
1243
 
1225
    /*
1244
    /*
1226
     * Tests the getter for the db directory summary hash.
1245
     * Tests the getter for the db directory summary hash.
1227
     *
1246
     *
1228
     * @covers \core_component::get_all_directory_hashes
1247
     * @covers \core\component::get_all_directory_hashes
1229
     */
1248
     */
1230
    public function test_get_db_directories_hash(): void {
1249
    public function test_get_db_directories_hash(): void {
Línea 1231... Línea 1250...
1231
        $initial = \core_component::get_all_component_hash();
1250
        $initial = component::get_all_component_hash();
1232
 
1251
 
1233
        $dir = make_request_directory();
1252
        $dir = make_request_directory();
Línea 1234... Línea 1253...
1234
        $hashes = \core_component::get_all_directory_hashes([$dir]);
1253
        $hashes = component::get_all_directory_hashes([$dir]);
1235
        $emptydirhash = \core_component::get_all_component_hash([$hashes]);
1254
        $emptydirhash = component::get_all_component_hash([$hashes]);
Línea 1236... Línea 1255...
1236
 
1255
 
1237
        // Confirm that a single empty directory is a different hash to the core hash.
1256
        // Confirm that a single empty directory is a different hash to the core hash.
1238
        $this->assertNotEquals($initial, $emptydirhash);
1257
        $this->assertNotEquals($initial, $emptydirhash);
1239
 
1258
 
Línea 1240... Línea 1259...
1240
        // Now lets add something to the dir, and check the hash is different.
1259
        // Now lets add something to the dir, and check the hash is different.
1241
        $file = fopen($dir . '/test.php', 'w');
1260
        $file = fopen($dir . '/test.php', 'w');
1242
        fwrite($file, 'sometestdata');
1261
        fwrite($file, 'sometestdata');
Línea 1243... Línea 1262...
1243
        fclose($file);
1262
        fclose($file);
1244
 
1263
 
1245
        $hashes = \core_component::get_all_directory_hashes([$dir]);
1264
        $hashes = component::get_all_directory_hashes([$dir]);
1246
        $onefiledirhash = \core_component::get_all_component_hash([$hashes]);
1265
        $onefiledirhash = component::get_all_component_hash([$hashes]);
1247
        $this->assertNotEquals($emptydirhash, $onefiledirhash);
1266
        $this->assertNotEquals($emptydirhash, $onefiledirhash);
1248
 
1267
 
-
 
1268
        // Now add a subdirectory inside the request dir. This should not affect the hash.
-
 
1269
        mkdir($dir . '/subdir');
-
 
1270
        $hashes = component::get_all_directory_hashes([$dir]);
-
 
1271
        $finalhash = component::get_all_component_hash([$hashes]);
-
 
1272
        $this->assertEquals($onefiledirhash, $finalhash);
-
 
1273
    }
-
 
1274
 
-
 
1275
    /**
-
 
1276
     * Data provider fetching all third-party lib directories.
-
 
1277
     *
-
 
1278
     * @return array
-
 
1279
     */
-
 
1280
    public static function core_thirdparty_libs_provider(): array {
-
 
1281
        global $CFG;
-
 
1282
 
-
 
1283
        $libs = [];
-
 
1284
 
-
 
1285
        $xmlpath = $CFG->libdir . '/thirdpartylibs.xml';
-
 
1286
        $xml = simplexml_load_file($xmlpath);
-
 
1287
        foreach ($xml as $lib) {
-
 
1288
            $base = realpath(dirname($xmlpath));
-
 
1289
            $fullpath = "{$base}/{$lib->location}";
-
 
1290
            $relativepath = substr($fullpath, strlen($CFG->dirroot));
-
 
1291
 
-
 
1292
            $libs[$relativepath] = [
-
 
1293
                'name' => (string) $lib->name,
-
 
1294
                'fullpath' => $fullpath,
-
 
1295
                'relativepath' => $relativepath,
-
 
1296
            ];
-
 
1297
        }
-
 
1298
 
-
 
1299
        return $libs;
-
 
1300
    }
-
 
1301
 
-
 
1302
    /**
-
 
1303
     * Data provider fetching all third-party lib directories with a composer.json file.
-
 
1304
     *
-
 
1305
     * @return array
-
 
1306
     */
-
 
1307
    public static function core_thirdparty_libs_with_composer_provider(): array {
-
 
1308
        return array_filter(self::core_thirdparty_libs_provider(), function ($lib) {
-
 
1309
            return file_exists("{$lib['fullpath']}/composer.json");
-
 
1310
        });
-
 
1311
    }
-
 
1312
 
-
 
1313
    /**
-
 
1314
     * Summary of test_composer_files
-
 
1315
     *
-
 
1316
     * @dataProvider core_thirdparty_libs_with_composer_provider
-
 
1317
     * @param string $name
-
 
1318
     * @param string $fullpath
-
 
1319
     * @param string $relativepath
-
 
1320
     */
-
 
1321
    public function test_composer_files(
-
 
1322
        string $name,
-
 
1323
        string $fullpath,
-
 
1324
        string $relativepath,
-
 
1325
    ): void {
-
 
1326
        $this->assertFileExists("{$fullpath}/composer.json");
-
 
1327
 
-
 
1328
        $composer = json_decode(file_get_contents("{$fullpath}/composer.json"), true);
-
 
1329
 
-
 
1330
        $rc = new ReflectionClass(\core\component::class);
-
 
1331
 
-
 
1332
        if (array_key_exists('autoload', $composer)) {
-
 
1333
            // Check that the PSR-4 namespaces are present and correct.
-
 
1334
            if (array_key_exists('psr-4', $composer['autoload'])) {
-
 
1335
                $autoloadnamespaces = $rc->getProperty('psr4namespaces')->getValue(null);
-
 
1336
                foreach ($composer['autoload']['psr-4'] as $namespace => $path) {
-
 
1337
                    // Composer PSR-4 namespace autoloads may optionally have a trailing slash. Standardise the value.
-
 
1338
                    $namespace = rtrim($namespace, '\\');
-
 
1339
 
-
 
1340
                    // If it exists in the composer.json the namespace must exist in our autoloader.
-
 
1341
                    $this->assertArrayHasKey($namespace, $autoloadnamespaces);
-
 
1342
 
-
 
1343
                    // Ours should be standardised to not have a trailing slash.
-
 
1344
                    $this->assertEquals(
-
 
1345
                        rtrim($relativepath, '/'),
-
 
1346
                        $relativepath,
-
 
1347
                        "Moodle PSR-4 namespaces must have no trailing /",
-
 
1348
                    );
-
 
1349
 
-
 
1350
                    // The composer.json can specify an array of possible values.
-
 
1351
                    // Standardise the format to the array format.
-
 
1352
                    $paths = is_array($path) ? $path : [$path];
-
 
1353
 
-
 
1354
                    foreach ($paths as $path) {
-
 
1355
                        // The composer.json can specify any arbitrary directory within the folder.
-
 
1356
                        // It always contains a leading slash (/) or backslash (\) on Windows.
-
 
1357
                        // It may also have an optional trailing slash (/).
-
 
1358
                        // Concatenate the parts and removes the slashes.
-
 
1359
                        $relativenamespacepath = trim("{$relativepath}/{$path}", '/\\');
-
 
1360
 
-
 
1361
                        // The Moodle PSR-4 autoloader data has two formats:
-
 
1362
                        // - a string, for a single source; or
-
 
1363
                        // - an array, for multiple sources.
-
 
1364
                        // Standardise the format to the latter format.
-
 
1365
                        if (!is_array($autoloadnamespaces[$namespace])) {
-
 
1366
                            $autoloadnamespaces[$namespace] = [$autoloadnamespaces[$namespace]];
-
 
1367
                        }
-
 
1368
 
-
 
1369
                        // Ensure that the autoloader contains the normalised path.
-
 
1370
                        $this->assertContains(
-
 
1371
                            $relativenamespacepath,
-
 
1372
                            $autoloadnamespaces[$namespace],
-
 
1373
                            "Moodle PSR-4 namespace missing entry for library {$name}: {$namespace} => {$relativenamespacepath}",
-
 
1374
                        );
-
 
1375
                    }
-
 
1376
                }
-
 
1377
            }
-
 
1378
 
-
 
1379
            // Check that the composer autoload files are present.
-
 
1380
            if (array_key_exists('files', $composer['autoload'])) {
-
 
1381
                // The Moodle composer file autoloads are a simple string[].
-
 
1382
                $autoloadnamefiles = $rc->getProperty('composerautoloadfiles')->getValue(null);
-
 
1383
                foreach ($composer['autoload']['files'] as $file) {
-
 
1384
                    $this->assertContains(trim($relativepath, '/\\') . "/{$file}", $autoloadnamefiles);
-
 
1385
                }
-
 
1386
            }
-
 
1387
        }
-
 
1388
    }
-
 
1389
 
-
 
1390
    /**
-
 
1391
     * Test that fetching of subtype data throws an exception when a subplugins.php is present without a json equivalent.
-
 
1392
     */
-
 
1393
    public function test_fetch_subtypes_php_only(): void {
-
 
1394
        $vfileroot = \org\bovigo\vfs\vfsStream::setup('root', null, [
-
 
1395
            'plugintype' => [
-
 
1396
                'exampleplugin' => [
-
 
1397
                    'db' => [
-
 
1398
                        'subplugins.php' => '',
-
 
1399
                    ],
-
 
1400
                ],
-
 
1401
            ],
-
 
1402
        ]);
-
 
1403
 
-
 
1404
        $this->expectException(coding_exception::class);
-
 
1405
        $this->expectExceptionMessageMatches('/Use of subplugins.php has been deprecated and is no longer supported/');
-
 
1406
 
-
 
1407
        $pluginroot = $vfileroot->getChild('plugintype/exampleplugin');
-
 
1408
 
-
 
1409
        $rcm = new \ReflectionMethod(\core\component::class, 'fetch_subtypes');
-
 
1410
        $rcm->invoke(null, $pluginroot->url());
-
 
1411
    }
-
 
1412
 
-
 
1413
    /**
-
 
1414
     * Test that fetching of subtype data does not throw an exception when a subplugins.php is present
-
 
1415
     * with a json file equivalent.
-
 
1416
     *
-
 
1417
     * Note: The content of the php file is irrelevant and we no longer use it anyway.
-
 
1418
     */
-
 
1419
    public function test_fetch_subtypes_php_and_json(): void {
-
 
1420
        global $CFG;
-
 
1421
 
-
 
1422
        $this->resetAfterTest();
-
 
1423
        $vfileroot = \org\bovigo\vfs\vfsStream::setup('root', null, [
-
 
1424
            'plugintype' => [
-
 
1425
                'exampleplugin' => [
-
 
1426
                    'db' => [
-
 
1427
                        'subplugins.json' => json_encode([
-
 
1428
                            'subplugintypes' => [
-
 
1429
                                'exampleplugina' => 'apples',
-
 
1430
                            ],
-
 
1431
                        ]),
-
 
1432
                        'subplugins.php' => '',
-
 
1433
                    ],
-
 
1434
                    'apples' => [],
-
 
1435
                ],
-
 
1436
            ],
-
 
1437
        ]);
-
 
1438
 
-
 
1439
        $CFG->dirroot = $vfileroot->url();
-
 
1440
        $pluginroot = $vfileroot->getChild('plugintype/exampleplugin');
-
 
1441
 
-
 
1442
        $rcm = new \ReflectionMethod(\core\component::class, 'fetch_subtypes');
-
 
1443
        $subplugins = $rcm->invoke(null, $pluginroot->url());
-
 
1444
 
-
 
1445
        $this->assertEquals([
-
 
1446
            'plugintypes' => [
-
 
1447
                'exampleplugina' => $pluginroot->getChild('apples')->url(),
-
 
1448
            ],
-
 
1449
        ], $subplugins);
-
 
1450
    }
-
 
1451
 
-
 
1452
    /**
-
 
1453
     * Test that fetching of subtype data in a file which is missing the new subplugintypes key warns.
-
 
1454
     */
-
 
1455
    public function test_fetch_subtypes_plugintypes_only(): void {
-
 
1456
        global $CFG;
-
 
1457
 
-
 
1458
        $this->resetAfterTest();
-
 
1459
        $vfileroot = \org\bovigo\vfs\vfsStream::setup('root', null, [
-
 
1460
            'plugintype' => [
-
 
1461
                'exampleplugin' => [
-
 
1462
                    'db' => [
-
 
1463
                        'subplugins.json' => json_encode([
-
 
1464
                            'plugintypes' => [
-
 
1465
                                'exampleplugina' => 'plugintype/exampleplugin/apples',
-
 
1466
                            ],
-
 
1467
                        ]),
-
 
1468
                        'subplugins.php' => '',
-
 
1469
                    ],
-
 
1470
                    'apples' => [],
-
 
1471
                ],
-
 
1472
            ],
-
 
1473
        ]);
-
 
1474
 
-
 
1475
        $CFG->dirroot = $vfileroot->url();
-
 
1476
        $pluginroot = $vfileroot->getChild('plugintype/exampleplugin');
-
 
1477
 
-
 
1478
        $logdir = make_request_directory();
-
 
1479
        $logfile = "{$logdir}/error.log";
-
 
1480
        ini_set('error_log', $logfile);
-
 
1481
 
-
 
1482
        $rcm = new \ReflectionMethod(\core\component::class, 'fetch_subtypes');
-
 
1483
        $subplugins = $rcm->invoke(null, $pluginroot->url());
-
 
1484
 
-
 
1485
        $this->assertEquals([
-
 
1486
            'plugintypes' => [
-
 
1487
                'exampleplugina' => $pluginroot->getChild('apples')->url(),
-
 
1488
            ],
-
 
1489
        ], $subplugins);
-
 
1490
 
-
 
1491
        $warnings = file_get_contents($logfile);
-
 
1492
        $this->assertMatchesRegularExpression('/No subplugintypes defined in .*subplugins.json/', $warnings);
-
 
1493
    }
-
 
1494
 
-
 
1495
    /**
-
 
1496
     * Ensure that invalid JSON in the subplugins.json file warns appropriately.
-
 
1497
     *
-
 
1498
     * @dataProvider invalid_subplugins_json_provider
-
 
1499
     * @param string[] $expectedwarnings Errors to expect in the exception message
-
 
1500
     * @param array[] $json The contents of the subplugins.json file
-
 
1501
     */
-
 
1502
    public function test_fetch_subtypes_json_invalid_values(
-
 
1503
        array $expectedwarnings,
-
 
1504
        array $json,
-
 
1505
    ): void {
-
 
1506
        global $CFG;
-
 
1507
 
-
 
1508
        $this->resetAfterTest();
-
 
1509
        $vfileroot = \org\bovigo\vfs\vfsStream::setup('root', null, [
-
 
1510
            'plugintype' => [
-
 
1511
                'exampleplugin' => [
-
 
1512
                    'db' => [
-
 
1513
                        'subplugins.json' => json_encode($json),
-
 
1514
                        'subplugins.php' => '',
-
 
1515
                    ],
-
 
1516
                    'apples' => [],
-
 
1517
                    'pears' => [],
-
 
1518
                ],
-
 
1519
            ],
-
 
1520
        ]);
-
 
1521
 
-
 
1522
        $CFG->dirroot = $vfileroot->url();
-
 
1523
        $pluginroot = $vfileroot->getChild('plugintype/exampleplugin');
-
 
1524
 
-
 
1525
        $logdir = make_request_directory();
-
 
1526
        $logfile = "{$logdir}/error.log";
-
 
1527
        ini_set('error_log', $logfile);
-
 
1528
 
-
 
1529
        $rcm = new \ReflectionMethod(\core\component::class, 'fetch_subtypes');
-
 
1530
        $rcm->invoke(null, $pluginroot->url());
-
 
1531
 
-
 
1532
        $warnings = file_get_contents($logfile);
-
 
1533
        foreach ($expectedwarnings as $expectedwarning) {
-
 
1534
            $this->assertMatchesRegularExpression($expectedwarning, $warnings);
-
 
1535
        }
-
 
1536
    }
-
 
1537
 
-
 
1538
    /**
-
 
1539
     * Data provider for invalid subplugins.json files.
-
 
1540
     *
-
 
1541
     * @return array
-
 
1542
     */
-
 
1543
    public static function invalid_subplugins_json_provider(): array {
-
 
1544
        return [
-
 
1545
            'Invalid characters in subtype name' => [
-
 
1546
                'expectedwarnings' => [
-
 
1547
                    "/Invalid subtype .*APPLES.*detected.*invalid characters present/",
-
 
1548
                ],
-
 
1549
                'json' => [
-
 
1550
                    'subplugintypes' => [
-
 
1551
                        'APPLES' => 'plugintype/exampleplugin/apples',
-
 
1552
                    ],
-
 
1553
                ],
-
 
1554
            ],
-
 
1555
 
-
 
1556
            'Subplugin which duplicates a core subsystem' => [
-
 
1557
                'expectedwarnings' => [
-
 
1558
                    "/Invalid subtype .*editor.*detected.*duplicates core subsystem/",
-
 
1559
                ],
-
 
1560
                'json' => [
-
 
1561
                    'subplugintypes' => [
-
 
1562
                        'editor' => 'apples',
-
 
1563
                    ],
-
 
1564
                ],
-
 
1565
            ],
-
 
1566
 
-
 
1567
            'Subplugin directory does not exist' => [
-
 
1568
                'expectedwarnings' => [
-
 
1569
                    "/Invalid subtype directory/",
-
 
1570
                ],
-
 
1571
                'json' => [
-
 
1572
                    'subplugintypes' => [
-
 
1573
                        'exampleapples' => 'berries',
-
 
1574
                    ],
-
 
1575
                ],
-
 
1576
            ],
-
 
1577
 
-
 
1578
            'More subplugintypes than plugintypes' => [
-
 
1579
                'expectedwarnings' => [
-
 
1580
                    "/Subplugintypes and plugintypes are not in sync/",
-
 
1581
                ],
-
 
1582
                'json' => [
-
 
1583
                    'subplugintypes' => [
-
 
1584
                        'apples' => 'pears',
-
 
1585
                    ],
-
 
1586
                    'plugintypes' => [],
-
 
1587
                ],
-
 
1588
            ],
-
 
1589
 
-
 
1590
            'More plugintypes than subplugintypes' => [
-
 
1591
                'expectedwarnings' => [
-
 
1592
                    "/Subplugintypes and plugintypes are not in sync /",
-
 
1593
                ],
-
 
1594
                'json' => [
-
 
1595
                    'subplugintypes' => [
-
 
1596
                        'apples' => 'apples',
-
 
1597
                    ],
-
 
1598
                    'plugintypes' => [
-
 
1599
                        'apples' => 'plugintype/exampleplugin/apples',
-
 
1600
                        'pears' => 'plugintype/exampleplugin/pears',
-
 
1601
                    ],
-
 
1602
                ],
-
 
1603
            ],
-
 
1604
 
-
 
1605
            'subplugintype not defined in plugintype' => [
-
 
1606
                'expectedwarnings' => [
-
 
1607
                    "/Subplugintypes and plugintypes are not in sync for 'apples'/",
-
 
1608
                ],
-
 
1609
                'json' => [
-
 
1610
                    'subplugintypes' => [
-
 
1611
                        'apples' => 'apples',
-
 
1612
                    ],
-
 
1613
                    'plugintypes' => [
-
 
1614
                        'pears' => 'plugintype/exampleplugin/pears',
-
 
1615
                    ],
-
 
1616
                ],
-
 
1617
            ],
-
 
1618
            'subplugintype does not match plugintype' => [
-
 
1619
                'expectedwarnings' => [
-
 
1620
                    "/Subplugintypes and plugintypes are not in sync for 'apples'/",
-
 
1621
                ],
-
 
1622
                'json' => [
-
 
1623
                    'subplugintypes' => [
-
 
1624
                        'apples' => 'apples',
-
 
1625
                    ],
-
 
1626
                    'plugintypes' => [
-
 
1627
                        'apples' => 'plugintype/exampleplugin/pears',
-
 
1628
                    ],
-
 
1629
                ],
-
 
1630
            ],
-
 
1631
        ];
-
 
1632
    }
-
 
1633
 
-
 
1634
    /**
-
 
1635
     * Test various methods when a deprecated plugin type is introduced.
-
 
1636
     *
-
 
1637
     * @runInSeparateProcess
-
 
1638
     * @return void
-
 
1639
     */
-
 
1640
    public function test_core_component_deprecated_plugintype(): void {
-
 
1641
        $this->resetAfterTest();
-
 
1642
 
-
 
1643
        // Inject the 'fake' plugin type.
-
 
1644
        $this->add_full_mocked_plugintype(
-
 
1645
            plugintype: 'fake',
-
 
1646
            path: 'lib/tests/fixtures/fakeplugins/fake'
-
 
1647
        );
-
 
1648
 
-
 
1649
        $componenthashbefore = component::get_all_component_hash();
-
 
1650
        $versionhashbefore = component::get_all_versions_hash();
-
 
1651
 
-
 
1652
        // Deprecation-specific APIs - pre-deprecation.
-
 
1653
        $this->assertArrayHasKey('fake', component::get_plugin_types());
-
 
1654
        $this->assertArrayHasKey('fullfeatured', component::get_plugin_list('fake'));
-
 
1655
        $this->assertFalse(component::is_deprecated_plugin_type('fake'));
-
 
1656
        $this->assertFalse(component::is_deleted_plugin_type('fake'));
-
 
1657
        $this->assertFalse(component::is_plugintype_in_deprecation('fake'));
-
 
1658
        $this->assertArrayNotHasKey('fake', component::get_deprecated_plugin_types());
-
 
1659
        $this->assertArrayNotHasKey('fullfeatured', component::get_deprecated_plugin_list('fake'));
-
 
1660
        $this->assertArrayNotHasKey('fake', component::get_deleted_plugin_types());
-
 
1661
        $this->assertArrayNotHasKey('fullfeatured', component::get_deleted_plugin_list('fake'));
-
 
1662
        $this->assertArrayHasKey('fake', component::get_all_plugin_types());
-
 
1663
        $this->assertArrayHasKey('fullfeatured', component::get_all_plugins_list('fake'));
-
 
1664
 
-
 
1665
        // Deprecate the fake plugintype via mocking component sources.
-
 
1666
        $this->deprecate_full_mocked_plugintype('fake');
-
 
1667
 
-
 
1668
        // Verify before/after hashes have changed, since the plugintype is no longer part of the hash calcs.
-
 
1669
        $this->assertNotEquals(component::get_all_component_hash(), $componenthashbefore);
-
 
1670
        $this->assertNotEquals(component::get_all_versions_hash(), $versionhashbefore);
-
 
1671
 
-
 
1672
        // Deprecation-specific APIs - post-deprecation.
-
 
1673
        $this->assertTrue(component::is_deprecated_plugin_type('fake'));
-
 
1674
        $this->assertFalse(component::is_deleted_plugin_type('fake'));
-
 
1675
        $this->assertTrue(component::is_plugintype_in_deprecation('fake'));
-
 
1676
        $this->assertArrayHasKey('fake', component::get_deprecated_plugin_types());
-
 
1677
        $this->assertArrayHasKey('fullfeatured', component::get_deprecated_plugin_list('fake'));
-
 
1678
        $this->assertArrayNotHasKey('fake', component::get_deleted_plugin_types());
-
 
1679
        $this->assertArrayNotHasKey('fullfeatured', component::get_deleted_plugin_list('fake'));
-
 
1680
        $this->assertArrayHasKey('fake', component::get_all_plugin_types());
-
 
1681
        $this->assertArrayHasKey('fullfeatured', component::get_all_plugins_list('fake'));
-
 
1682
 
-
 
1683
        // Deprecated plugins excluded from the following for B/C.
-
 
1684
        $this->assertArrayNotHasKey('fake', component::get_plugin_types());
-
 
1685
        $this->assertArrayNotHasKey('fullfeatured', component::get_plugin_list('fake'));
-
 
1686
        $this->assertArrayNotHasKey('fake', component::get_component_list());
-
 
1687
        $this->assertEmpty(component::get_plugin_list_with_file('fake', 'classes/dummy.php'));
-
 
1688
        $this->assertEmpty(component::get_plugin_list_with_class('fake', 'dummy'));
-
 
1689
 
-
 
1690
        // Deprecated plugins excluded by default for B/C, but can be included by request.
-
 
1691
        $this->assertNotContains('fake_fullfeatured', component::get_component_names());
-
 
1692
        $this->assertContains('fake_fullfeatured', component::get_component_names(false, true));
-
 
1693
 
-
 
1694
        // Deprecated plugins included in the following.
-
 
1695
        $this->assertIsString(component::get_plugin_directory('fake', 'fullfeatured')); // Used by string manager.
-
 
1696
        $this->assertIsString(component::get_component_directory('fake_fullfeatured')); // Uses get_plugin_directory().
-
 
1697
        $this->assertTrue(component::has_monologo_icon('fake', 'fullfeatured'));  // Uses get_plugin_directory().
-
 
1698
        $this->assertEquals('fake_fullfeatured', component::get_component_from_classname(\fake_fullfeatured\example::class));
-
 
1699
 
-
 
1700
        // Class autoloading of deprecated plugins is permitted, to facilitate plugin migration code.
-
 
1701
        $this->assertArrayHasKey('fake_fullfeatured\dummy',
-
 
1702
            component::get_component_classes_in_namespace('fake_fullfeatured'));
-
 
1703
        $this->assertTrue(class_exists(\fake_fullfeatured\dummy::class));
-
 
1704
    }
-
 
1705
 
-
 
1706
    /**
-
 
1707
     * Test various core_component APIs when dealing with deleted plugin types.
-
 
1708
     *
-
 
1709
     * @runInSeparateProcess
-
 
1710
     * @return void
-
 
1711
     */
-
 
1712
    public function test_core_component_deleted_plugintype(): void {
-
 
1713
        $this->resetAfterTest();
-
 
1714
 
-
 
1715
        // Inject the 'fake' plugin type.
-
 
1716
        $this->add_full_mocked_plugintype(
-
 
1717
            plugintype: 'fake',
-
 
1718
            path: 'lib/tests/fixtures/fakeplugins/fake',
-
 
1719
        );
-
 
1720
 
-
 
1721
        // Delete the fake plugintype via mocking component sources.
-
 
1722
        $this->delete_full_mocked_plugintype('fake');
-
 
1723
 
-
 
1724
        // Deprecation-specific methods.
-
 
1725
        $this->assertFalse(component::is_deprecated_plugin_type('fake'));
-
 
1726
        $this->assertTrue(component::is_deleted_plugin_type('fake'));
-
 
1727
        $this->assertTrue(component::is_plugintype_in_deprecation('fake'));
-
 
1728
        $this->assertArrayNotHasKey('fake', component::get_deprecated_plugin_types());
-
 
1729
        $this->assertArrayNotHasKey('fullfeatured', component::get_deprecated_plugin_list('fake'));
-
 
1730
        $this->assertArrayHasKey('fake', component::get_deleted_plugin_types());
-
 
1731
        $this->assertArrayHasKey('fullfeatured', component::get_deleted_plugin_list('fake'));
-
 
1732
        $this->assertArrayHasKey('fake', component::get_all_plugin_types());
-
 
1733
        $this->assertArrayHasKey('fullfeatured', component::get_all_plugins_list('fake'));
-
 
1734
 
-
 
1735
        // Deleted plugintypes/plugins are not included in other methods.
-
 
1736
        $this->assertArrayNotHasKey('fake', component::get_plugin_types());
-
 
1737
        $this->assertArrayNotHasKey('fullfeatured', component::get_plugin_list('fake'));
-
 
1738
        $this->assertNotContains('fake_fullfeatured', component::get_component_names());
-
 
1739
        $this->assertNotContains('fake_fullfeatured', component::get_component_names(false, true));
-
 
1740
        $this->assertArrayNotHasKey('fake', component::get_component_list());
-
 
1741
        $this->assertEmpty(component::get_plugin_list_with_file('fake', 'classes/dummy.php'));
-
 
1742
        $this->assertEmpty(component::get_plugin_list_with_class('fake', 'dummy'));
-
 
1743
        $this->assertFalse(component::has_monologo_icon('fake', 'fullfeatured'));
-
 
1744
        $this->assertNull(component::get_plugin_directory('fake', 'fullfeatured'));
-
 
1745
        $this->assertNull(component::get_component_directory('fake_fullfeatured'));
-
 
1746
        $this->assertNull(component::get_component_from_classname(\fake_fullfeatured\example::class));
-
 
1747
 
-
 
1748
        // Class autoloading of deleted plugins is not supported.
-
 
1749
        $this->assertArrayNotHasKey('fake_fullfeatured\dummy',
-
 
1750
            component::get_component_classes_in_namespace('fake_fullfeatured'));
-
 
1751
        $this->assertFalse(class_exists(fake_fullfeatured\dummy::class));
-
 
1752
    }
-
 
1753
 
-
 
1754
    /**
-
 
1755
     * Test various core_component APIs when dealing with deprecated subplugins.
-
 
1756
     *
-
 
1757
     * @runInSeparateProcess
-
 
1758
     * @return void
-
 
1759
     */
-
 
1760
    public function test_core_component_deprecated_subplugintype(): void {
-
 
1761
        $this->resetAfterTest();
-
 
1762
 
-
 
1763
        // Inject the 'fake' plugin type. This includes three mock subplugins:
-
 
1764
        // 1. fullsubtype_example: a regular plugin type, not deprecated, nor deleted.
-
 
1765
        // 2. fulldeprecatedsubtype_test: a deprecated subplugin type.
-
 
1766
        // 3. fulldeletedsubtype_demo: a deleted subplugin type.
-
 
1767
        $this->add_full_mocked_plugintype(
-
 
1768
            plugintype: 'fake',
-
 
1769
            path: 'lib/tests/fixtures/fakeplugins/fake',
-
 
1770
            subpluginsupport: true
-
 
1771
        );
-
 
1772
        $this->assert_deprecation_apis_subplugins();
-
 
1773
    }
-
 
1774
 
-
 
1775
    /**
-
 
1776
     * Verify that a plugin which supports subplugins cannot be deprecated.
-
 
1777
     *
-
 
1778
     * @runInSeparateProcess
-
 
1779
     * @return void
-
 
1780
     */
-
 
1781
    public function test_core_component_deprecated_subplugintype_supporting_subplugins(): void {
-
 
1782
        $this->resetAfterTest();
-
 
1783
 
-
 
1784
        // Inject the 'fake' plugin type. This includes three mock subplugins:
-
 
1785
        // 1. fullsubtype_example: a regular plugin type, not deprecated, nor deleted.
-
 
1786
        // 2. fulldeprecatedsubtype_test: a deprecated subplugin type.
-
 
1787
        // 3. fulldeletedsubtype_demo: a deleted subplugin type.
-
 
1788
        $this->add_full_mocked_plugintype(
-
 
1789
            plugintype: 'fake',
-
 
1790
            path: 'lib/tests/fixtures/fakeplugins/fake',
-
 
1791
            subpluginsupport: true
-
 
1792
        );
-
 
1793
 
-
 
1794
        // Try to deprecate the fake plugintype via mocking component sources.
-
 
1795
        $this->deprecate_full_mocked_plugintype('fake');
-
 
1796
 
-
 
1797
        // Deprecation unsupported, so verify core_component treats all plugins the same as before the deprecation attempt.
-
 
1798
        // Debugging is expected to be emitted during core_component::init().
-
 
1799
        $this->assert_deprecation_apis_subplugins();
-
 
1800
        $this->assertDebuggingCalled('Deprecation of a plugin type which supports subplugins is not supported. ' .
-
 
1801
            'These plugin types will continue to be treated as active.', DEBUG_DEVELOPER);
-
 
1802
    }
-
 
1803
 
-
 
1804
    /**
-
 
1805
     * Verify that a plugin which supports subplugins cannot be deleted.
-
 
1806
     *
-
 
1807
     * @runInSeparateProcess
-
 
1808
     * @return void
-
 
1809
     */
-
 
1810
    public function test_core_component_deleted_subplugintype_supporting_subplugins(): void {
-
 
1811
        $this->resetAfterTest();
-
 
1812
 
-
 
1813
        // Inject the 'fake' plugin type. This includes three mock subplugins:
-
 
1814
        // 1. fullsubtype_example: a regular plugin type, not deprecated, nor deleted.
-
 
1815
        // 2. fulldeprecatedsubtype_test: a deprecated subplugin type.
-
 
1816
        // 3. fulldeletedsubtype_demo: a deleted subplugin type.
-
 
1817
        $this->add_full_mocked_plugintype(
-
 
1818
            plugintype: 'fake',
-
 
1819
            path: 'lib/tests/fixtures/fakeplugins/fake',
-
 
1820
            subpluginsupport: true
-
 
1821
        );
-
 
1822
 
-
 
1823
        // Try to delete the fake plugintype via mocking component sources.
-
 
1824
        $this->delete_full_mocked_plugintype('fake');
-
 
1825
 
-
 
1826
        // Deletion unsupported, so verify core_component treats all plugins the same as before the deletion attempt.
-
 
1827
        // Debugging is expected to be emitted during core_component::init().
-
 
1828
        $this->assert_deprecation_apis_subplugins();
-
 
1829
        $this->assertDebuggingCalled('Deprecation of a plugin type which supports subplugins is not supported. ' .
-
 
1830
            'These plugin types will continue to be treated as active.', DEBUG_DEVELOPER);
-
 
1831
    }
-
 
1832
 
-
 
1833
    /**
-
 
1834
     * Helper asserting the returns for various core_component APIs when dealing with deprecated and deleted subplugins.
-
 
1835
     *
-
 
1836
     * @return void
-
 
1837
     */
-
 
1838
    protected function assert_deprecation_apis_subplugins(): void {
-
 
1839
        // Deprecation-specific methods.
-
 
1840
        $this->assertFalse(component::is_deprecated_plugin_type('fake'));
-
 
1841
        $this->assertFalse(component::is_deprecated_plugin_type('fullsubtype'));
-
 
1842
        $this->assertTrue(component::is_deprecated_plugin_type('fulldeprecatedsubtype'));
-
 
1843
        $this->assertFalse(component::is_deprecated_plugin_type('fulldeletedsubtype'));
-
 
1844
 
-
 
1845
        $this->assertFalse(component::is_deleted_plugin_type('fake'));
-
 
1846
        $this->assertFalse(component::is_deleted_plugin_type('fullsubtype'));
-
 
1847
        $this->assertFalse(component::is_deleted_plugin_type('fulldeprecatedsubtype'));
-
 
1848
        $this->assertTrue(component::is_deleted_plugin_type('fulldeletedsubtype'));
-
 
1849
 
-
 
1850
        $this->assertFalse(component::is_plugintype_in_deprecation('fake'));
-
 
1851
        $this->assertFalse(component::is_plugintype_in_deprecation('fullsubtype'));
-
 
1852
        $this->assertTrue(component::is_plugintype_in_deprecation('fulldeprecatedsubtype'));
-
 
1853
        $this->assertTrue(component::is_plugintype_in_deprecation('fulldeletedsubtype'));
-
 
1854
 
-
 
1855
        $this->assertArrayNotHasKey('fake', component::get_deprecated_plugin_types());
-
 
1856
        $this->assertArrayNotHasKey('fullsubtype', component::get_deprecated_plugin_types());
-
 
1857
        $this->assertArrayHasKey('fulldeprecatedsubtype', component::get_deprecated_plugin_types());
-
 
1858
        $this->assertArrayNotHasKey('fulldeletedsubtype', component::get_deprecated_plugin_types());
-
 
1859
 
-
 
1860
        $this->assertArrayNotHasKey('fullfeatured', component::get_deprecated_plugin_list('fake'));
-
 
1861
        $this->assertArrayNotHasKey('example', component::get_deprecated_plugin_list('fullsubtype'));
-
 
1862
        $this->assertArrayHasKey('test', component::get_deprecated_plugin_list('fulldeprecatedsubtype'));
-
 
1863
        $this->assertArrayNotHasKey('demo', component::get_deprecated_plugin_list('fulldeletedsubtype'));
-
 
1864
 
-
 
1865
        $this->assertArrayNotHasKey('fake', component::get_deleted_plugin_types());
-
 
1866
        $this->assertArrayNotHasKey('fullsubtype', component::get_deleted_plugin_types());
-
 
1867
        $this->assertArrayNotHasKey('fulldeprecatedsubtype', component::get_deleted_plugin_types());
-
 
1868
        $this->assertArrayHasKey('fulldeletedsubtype', component::get_deleted_plugin_types());
-
 
1869
 
-
 
1870
        $this->assertArrayNotHasKey('fullfeatured', component::get_deleted_plugin_list('fake'));
-
 
1871
        $this->assertArrayNotHasKey('example', component::get_deleted_plugin_list('fullsubtype'));
-
 
1872
        $this->assertArrayNotHasKey('test', component::get_deleted_plugin_list('fulldeprecatedsubtype'));
-
 
1873
        $this->assertArrayHasKey('demo', component::get_deleted_plugin_list('fulldeletedsubtype'));
-
 
1874
 
-
 
1875
        $this->assertArrayHasKey('fake', component::get_all_plugin_types());
-
 
1876
        $this->assertArrayHasKey('fullsubtype', component::get_all_plugin_types());
-
 
1877
        $this->assertArrayHasKey('fulldeprecatedsubtype', component::get_all_plugin_types());
-
 
1878
        $this->assertArrayHasKey('fulldeletedsubtype', component::get_all_plugin_types());
-
 
1879
 
-
 
1880
        $this->assertArrayHasKey('fullfeatured', component::get_all_plugins_list('fake'));
-
 
1881
        $this->assertArrayHasKey('example', component::get_all_plugins_list('fullsubtype'));
-
 
1882
        $this->assertArrayHasKey('test', component::get_all_plugins_list('fulldeprecatedsubtype'));
-
 
1883
        $this->assertArrayHasKey('demo', component::get_all_plugins_list('fulldeletedsubtype'));
-
 
1884
 
-
 
1885
        // Deprecated and deleted plugins excluded from the following for B/C.
-
 
1886
        $this->assertArrayHasKey('fake', component::get_plugin_types());
-
 
1887
        $this->assertArrayHasKey('fullsubtype', component::get_plugin_types());
-
 
1888
        $this->assertArrayNotHasKey('fulldeprecatedsubtype', component::get_plugin_types());
-
 
1889
        $this->assertArrayNotHasKey('fulldeletedsubtype', component::get_plugin_types());
-
 
1890
 
-
 
1891
        $this->assertNotEmpty(component::get_plugin_list('fake'));
-
 
1892
        $this->assertNotEmpty(component::get_plugin_list('fullsubtype'));
-
 
1893
        $this->assertEmpty(component::get_plugin_list('fulldeprecatedsubtype'));
-
 
1894
        $this->assertEmpty(component::get_plugin_list('fulldeletedsubtype'));
-
 
1895
 
-
 
1896
        $this->assertArrayHasKey('fake', component::get_component_list());
-
 
1897
        $this->assertArrayHasKey('fullsubtype', component::get_component_list());
-
 
1898
        $this->assertArrayNotHasKey('fulldeprecatedsubtype', component::get_component_list());
-
 
1899
        $this->assertArrayNotHasKey('fulldeletedsubtype', component::get_component_list());
-
 
1900
 
-
 
1901
        $this->assertArrayHasKey('fullfeatured', component::get_plugin_list_with_file('fake', 'classes/dummy.php'));
-
 
1902
        $this->assertArrayHasKey('example', component::get_plugin_list_with_file('fullsubtype', 'classes/dummy.php'));
-
 
1903
        $this->assertEmpty(component::get_plugin_list_with_file('fulldeprecatedsubtype', 'classes/dummy.php'));
-
 
1904
        $this->assertEmpty(component::get_plugin_list_with_file('fulldeletedsubtype', 'classes/dummy.php'));
-
 
1905
 
-
 
1906
        $this->assertArrayHasKey('fake_fullfeatured', component::get_plugin_list_with_class('fake', 'dummy'));
-
 
1907
        $this->assertArrayHasKey('fullsubtype_example', component::get_plugin_list_with_class('fullsubtype', 'dummy'));
-
 
1908
        $this->assertEmpty(component::get_plugin_list_with_class('fulldeprecatedsubtype', 'dummy'));
-
 
1909
        $this->assertEmpty(component::get_plugin_list_with_class('fulldeletedsubtype', 'dummy'));
-
 
1910
 
-
 
1911
        $this->assertArrayHasKey('fullsubtype', component::get_subplugins('fake_fullfeatured'));
-
 
1912
        $this->assertContains('example', component::get_subplugins('fake_fullfeatured')['fullsubtype']);
-
 
1913
        $this->assertArrayNotHasKey('fulldeprecatedsubtype', component::get_subplugins('fake_fullfeatured'));
-
 
1914
        $this->assertArrayNotHasKey('fulldeletedsubtype', component::get_subplugins('fake_fullfeatured'));
-
 
1915
 
-
 
1916
        $this->assertArrayHasKey('fullsubtype', component::get_all_subplugins('fake_fullfeatured'));
-
 
1917
        $this->assertContains('example', component::get_all_subplugins('fake_fullfeatured')['fullsubtype']);
-
 
1918
        $this->assertContains('test', component::get_all_subplugins('fake_fullfeatured')['fulldeprecatedsubtype']);
-
 
1919
        $this->assertContains('demo', component::get_all_subplugins('fake_fullfeatured')['fulldeletedsubtype']);
-
 
1920
 
-
 
1921
        // Deprecated plugins excluded by default for B/C, but can be included by request.
-
 
1922
        // Deleted plugins are always excluded.
-
 
1923
        $this->assertContains('fake_fullfeatured', component::get_component_names());
-
 
1924
        $this->assertContains('fullsubtype_example', component::get_component_names());
-
 
1925
        $this->assertNotContains('fulldeprecatedsubtype_test', component::get_component_names());
-
 
1926
        $this->assertNotContains('fulldeletedsubtype_demo', component::get_component_names());
-
 
1927
        $this->assertContains('fulldeprecatedsubtype_test', component::get_component_names(false, true));
-
 
1928
        $this->assertNotContains('fulldeletedsubtype_demo', component::get_component_names(false, true));
-
 
1929
 
-
 
1930
        // Deprecated plugins included in the following, but deleted plugins are excluded.
-
 
1931
        $this->assertIsString(component::get_plugin_directory('fake', 'fullfeatured')); // Used by string manager.
-
 
1932
        $this->assertIsString(component::get_plugin_directory('fullsubtype', 'example'));
-
 
1933
        $this->assertIsString(component::get_plugin_directory('fulldeprecatedsubtype', 'test'));
-
 
1934
        $this->assertNull(component::get_plugin_directory('fulldeletedsubtype', 'demo'));
-
 
1935
 
-
 
1936
        $this->assertIsString(component::get_component_directory('fake_fullfeatured')); // Uses get_plugin_directory().
-
 
1937
        $this->assertIsString(component::get_component_directory('fullsubtype_example'));
-
 
1938
        $this->assertIsString(component::get_component_directory('fulldeprecatedsubtype_test'));
-
 
1939
        $this->assertNull(component::get_component_directory('fulldeletedsubtype_demo'));
-
 
1940
 
-
 
1941
        $this->assertTrue(component::has_monologo_icon('fullsubtype', 'example')); // Uses get_plugin_directory().
-
 
1942
        $this->assertTrue(component::has_monologo_icon('fulldeprecatedsubtype', 'test'));
-
 
1943
        $this->assertFalse(component::has_monologo_icon('fulldeletedsubtype', 'demo'));
-
 
1944
 
-
 
1945
        $this->assertEquals('fake_fullfeatured', component::get_component_from_classname(\fake_fullfeatured\example::class));
-
 
1946
        $this->assertEquals('fullsubtype_example',
-
 
1947
            component::get_component_from_classname(\fullsubtype_example\example::class));
-
 
1948
        $this->assertEquals('fulldeprecatedsubtype_test',
-
 
1949
            component::get_component_from_classname(\fulldeprecatedsubtype_test\example::class));
-
 
1950
        $this->assertNull(component::get_component_from_classname(\fulldeletedsubtype_demo\example::class));
-
 
1951
 
-
 
1952
        // Deprecated and deleted plugins included in the following.
-
 
1953
        $this->assertEquals('fake_fullfeatured', component::get_subtype_parent('fullsubtype'));
-
 
1954
        $this->assertEquals('fake_fullfeatured', component::get_subtype_parent('fulldeprecatedsubtype'));
-
 
1955
        $this->assertEquals('fake_fullfeatured', component::get_subtype_parent('fulldeletedsubtype'));
-
 
1956
 
-
 
1957
        // Class autoloading of deprecated plugins is permitted, to facilitate plugin migration code, but not for deleted plugins.
-
 
1958
        $this->assertArrayHasKey('fake_fullfeatured\dummy',
-
 
1959
            component::get_component_classes_in_namespace('fake_fullfeatured'));
-
 
1960
        $this->assertArrayHasKey('fullsubtype_example\dummy',
-
 
1961
            component::get_component_classes_in_namespace('fullsubtype_example'));
-
 
1962
        $this->assertArrayHasKey('fulldeprecatedsubtype_test\dummy',
-
 
1963
            component::get_component_classes_in_namespace('fulldeprecatedsubtype_test'));
-
 
1964
        $this->assertEquals([], component::get_component_classes_in_namespace('fulldeletedsubtype_demo'));
1249
        // Now add a subdirectory inside the request dir. This should not affect the hash.
1965