d5f0b55bd247e49868bf86425af9656a4b5f055c
[moodle.git] / lib / tests / component_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * core_component related tests.
19  *
20  * @package    core
21  * @category   phpunit
22  * @copyright  2013 Petr Skoda {@link http://skodak.org}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
29 /**
30  * Class core_component_testcase.
31  */
32 class core_component_testcase extends advanced_testcase {
34     // To be changed if number of subsystems increases/decreases,
35     // this is defined here to annoy devs that try to add more without any thinking,
36     // always verify that it does not collide with any existing add-on modules and subplugins!!!
37     const SUBSYSTEMCOUNT = 63;
39     public function test_get_core_subsystems() {
40         global $CFG;
42         $subsystems = core_component::get_core_subsystems();
44         $this->assertCount(self::SUBSYSTEMCOUNT, $subsystems, 'Oh, somebody added or removed a core subsystem, think twice before doing that!');
46         // Make sure all paths are full/null, exist and are inside dirroot.
47         foreach ($subsystems as $subsystem => $fulldir) {
48             $this->assertFalse(strpos($subsystem, '_'), 'Core subsystems must be one work without underscores');
49             if ($fulldir === null) {
50                 if ($subsystem === 'filepicker' or $subsystem === 'help') {
51                     // Arrgghh, let's not introduce more subsystems for no real reason...
52                 } else {
53                     // Lang strings.
54                     $this->assertFileExists("$CFG->dirroot/lang/en/$subsystem.php", 'Core subsystems without fulldir are usually used for lang strings.');
55                 }
56                 continue;
57             }
58             $this->assertFileExists($fulldir);
59             // Check that base uses realpath() separators and "/" in the subdirs.
60             $this->assertStringStartsWith($CFG->dirroot.'/', $fulldir);
61             $reldir = substr($fulldir, strlen($CFG->dirroot)+1);
62             $this->assertFalse(strpos($reldir, '\\'));
63         }
65         // Make sure all core language files are also subsystems!
66         $items = new DirectoryIterator("$CFG->dirroot/lang/en");
67         foreach ($items as $item) {
68             if ($item->isDot() or $item->isDir()) {
69                 continue;
70             }
71             $file = $item->getFilename();
72             if ($file === 'moodle.php') {
73                 // Do not add new lang strings unless really necessary!!!
74                 continue;
75             }
77             if (substr($file, -4) !== '.php') {
78                 continue;
79             }
80             $file = substr($file, 0, strlen($file)-4);
81             $this->assertArrayHasKey($file, $subsystems, 'All core lang files should be subsystems, think twice before adding anything!');
82         }
83         unset($item);
84         unset($items);
86     }
88     public function test_deprecated_get_core_subsystems() {
89         global $CFG;
91         $subsystems = core_component::get_core_subsystems();
93         $this->assertSame($subsystems, get_core_subsystems(true));
95         $realsubsystems = get_core_subsystems();
96         $this->assertDebuggingCalled();
97         $this->assertSame($realsubsystems, get_core_subsystems(false));
98         $this->assertDebuggingCalled();
100         $this->assertEquals(count($subsystems), count($realsubsystems));
102         foreach ($subsystems as $subsystem => $fulldir) {
103             $this->assertArrayHasKey($subsystem, $realsubsystems);
104             if ($fulldir === null) {
105                 $this->assertNull($realsubsystems[$subsystem]);
106                 continue;
107             }
108             $this->assertSame($fulldir, $CFG->dirroot.'/'.$realsubsystems[$subsystem]);
109         }
110     }
112     public function test_get_plugin_types() {
113         global $CFG;
115         $this->assertTrue(empty($CFG->themedir), 'Non-empty $CFG->themedir is not covered by any tests yet, you need to disable it.');
117         $plugintypes = core_component::get_plugin_types();
119         foreach ($plugintypes as $plugintype => $fulldir) {
120             $this->assertStringStartsWith("$CFG->dirroot/", $fulldir);
121         }
122     }
124     public function test_deprecated_get_plugin_types() {
125         global $CFG;
127         $plugintypes = core_component::get_plugin_types();
129         $this->assertSame($plugintypes, get_plugin_types());
130         $this->assertSame($plugintypes, get_plugin_types(true));
132         $realplugintypes = get_plugin_types(false);
133         $this->assertDebuggingCalled();
135         foreach ($plugintypes as $plugintype => $fulldir) {
136             $this->assertSame($fulldir, $CFG->dirroot.'/'.$realplugintypes[$plugintype]);
137         }
138     }
140     public function test_get_plugin_list() {
141         global $CFG;
143         $plugintypes = core_component::get_plugin_types();
145         foreach ($plugintypes as $plugintype => $fulldir) {
146             $plugins = core_component::get_plugin_list($plugintype);
147             foreach ($plugins as $pluginname => $plugindir) {
148                 $this->assertStringStartsWith("$CFG->dirroot/", $plugindir);
149             }
150             if ($plugintype !== 'auth') {
151                 // Let's crosscheck it with independent implementation (auth/db is an exception).
152                 $reldir = substr($fulldir, strlen($CFG->dirroot)+1);
153                 $dirs = get_list_of_plugins($reldir);
154                 $dirs = array_values($dirs);
155                 $this->assertDebuggingCalled();
156                 $this->assertSame($dirs, array_keys($plugins));
157             }
158         }
159     }
161     public function test_deprecated_get_plugin_list() {
162         $plugintypes = core_component::get_plugin_types();
164         foreach ($plugintypes as $plugintype => $fulldir) {
165             $plugins = core_component::get_plugin_list($plugintype);
166             $this->assertSame($plugins, get_plugin_list($plugintype));
167         }
168     }
170     public function test_get_plugin_directory() {
171         $plugintypes = core_component::get_plugin_types();
173         foreach ($plugintypes as $plugintype => $fulldir) {
174             $plugins = core_component::get_plugin_list($plugintype);
175             foreach ($plugins as $pluginname => $plugindir) {
176                 $this->assertSame($plugindir, core_component::get_plugin_directory($plugintype, $pluginname));
177             }
178         }
179     }
181     public function test_deprecated_get_plugin_directory() {
182         $plugintypes = core_component::get_plugin_types();
184         foreach ($plugintypes as $plugintype => $fulldir) {
185             $plugins = core_component::get_plugin_list($plugintype);
186             foreach ($plugins as $pluginname => $plugindir) {
187                 $this->assertSame(core_component::get_plugin_directory($plugintype, $pluginname), get_plugin_directory($plugintype, $pluginname));
188             }
189         }
190     }
192     public function test_get_subsystem_directory() {
193         $subsystems = core_component::get_core_subsystems();
194         foreach ($subsystems as $subsystem => $fulldir) {
195             $this->assertSame($fulldir, core_component::get_subsystem_directory($subsystem));
196         }
197     }
199     public function test_is_valid_plugin_name() {
200         $this->assertTrue(core_component::is_valid_plugin_name('mod', 'example1'));
201         $this->assertTrue(core_component::is_valid_plugin_name('mod', 'feedback360'));
202         $this->assertFalse(core_component::is_valid_plugin_name('mod', 'feedback_360'));
203         $this->assertFalse(core_component::is_valid_plugin_name('mod', '2feedback'));
204         $this->assertFalse(core_component::is_valid_plugin_name('mod', '1example'));
205         $this->assertFalse(core_component::is_valid_plugin_name('mod', 'example.xx'));
206         $this->assertFalse(core_component::is_valid_plugin_name('mod', '.example'));
207         $this->assertFalse(core_component::is_valid_plugin_name('mod', '_example'));
208         $this->assertFalse(core_component::is_valid_plugin_name('mod', 'example_'));
209         $this->assertFalse(core_component::is_valid_plugin_name('mod', 'example_x1'));
210         $this->assertFalse(core_component::is_valid_plugin_name('mod', 'example-x1'));
211         $this->assertFalse(core_component::is_valid_plugin_name('mod', 'role'));
213         $this->assertTrue(core_component::is_valid_plugin_name('tool', 'example1'));
214         $this->assertTrue(core_component::is_valid_plugin_name('tool', 'example_x1'));
215         $this->assertTrue(core_component::is_valid_plugin_name('tool', 'example_x1_xxx'));
216         $this->assertTrue(core_component::is_valid_plugin_name('tool', 'feedback360'));
217         $this->assertTrue(core_component::is_valid_plugin_name('tool', 'feed_back360'));
218         $this->assertTrue(core_component::is_valid_plugin_name('tool', 'role'));
219         $this->assertFalse(core_component::is_valid_plugin_name('tool', '1example'));
220         $this->assertFalse(core_component::is_valid_plugin_name('tool', 'example.xx'));
221         $this->assertFalse(core_component::is_valid_plugin_name('tool', 'example-xx'));
222         $this->assertFalse(core_component::is_valid_plugin_name('tool', '.example'));
223         $this->assertFalse(core_component::is_valid_plugin_name('tool', '_example'));
224         $this->assertFalse(core_component::is_valid_plugin_name('tool', 'example_'));
225         $this->assertFalse(core_component::is_valid_plugin_name('tool', 'example__x1'));
226     }
228     public function test_normalize_componentname() {
229         // Moodle core.
230         $this->assertSame('core', core_component::normalize_componentname('core'));
231         $this->assertSame('core', core_component::normalize_componentname('moodle'));
232         $this->assertSame('core', core_component::normalize_componentname(''));
234         // Moodle core subsystems.
235         $this->assertSame('core_admin', core_component::normalize_componentname('admin'));
236         $this->assertSame('core_admin', core_component::normalize_componentname('core_admin'));
237         $this->assertSame('core_admin', core_component::normalize_componentname('moodle_admin'));
239         // Activity modules and their subplugins.
240         $this->assertSame('mod_workshop', core_component::normalize_componentname('workshop'));
241         $this->assertSame('mod_workshop', core_component::normalize_componentname('mod_workshop'));
242         $this->assertSame('workshopform_accumulative', core_component::normalize_componentname('workshopform_accumulative'));
243         $this->assertSame('mod_quiz', core_component::normalize_componentname('quiz'));
244         $this->assertSame('quiz_grading', core_component::normalize_componentname('quiz_grading'));
245         $this->assertSame('mod_data', core_component::normalize_componentname('data'));
246         $this->assertSame('datafield_checkbox', core_component::normalize_componentname('datafield_checkbox'));
248         // Other plugin types.
249         $this->assertSame('auth_mnet', core_component::normalize_componentname('auth_mnet'));
250         $this->assertSame('enrol_self', core_component::normalize_componentname('enrol_self'));
251         $this->assertSame('block_html', core_component::normalize_componentname('block_html'));
252         $this->assertSame('block_mnet_hosts', core_component::normalize_componentname('block_mnet_hosts'));
253         $this->assertSame('local_amos', core_component::normalize_componentname('local_amos'));
254         $this->assertSame('local_admin', core_component::normalize_componentname('local_admin'));
256         // Unknown words without underscore are supposed to be activity modules.
257         $this->assertSame('mod_whoonearthwouldcomewithsuchastupidnameofcomponent',
258             core_component::normalize_componentname('whoonearthwouldcomewithsuchastupidnameofcomponent'));
259         // Module names can not contain underscores, this must be a subplugin.
260         $this->assertSame('whoonearth_wouldcomewithsuchastupidnameofcomponent',
261             core_component::normalize_componentname('whoonearth_wouldcomewithsuchastupidnameofcomponent'));
262         $this->assertSame('whoonearth_would_come_withsuchastupidnameofcomponent',
263             core_component::normalize_componentname('whoonearth_would_come_withsuchastupidnameofcomponent'));
264     }
266     public function test_normalize_component() {
267         // Moodle core.
268         $this->assertSame(array('core', null), core_component::normalize_component('core'));
269         $this->assertSame(array('core', null), core_component::normalize_component('moodle'));
270         $this->assertSame(array('core', null), core_component::normalize_component(''));
272         // Moodle core subsystems.
273         $this->assertSame(array('core', 'admin'), core_component::normalize_component('admin'));
274         $this->assertSame(array('core', 'admin'), core_component::normalize_component('core_admin'));
275         $this->assertSame(array('core', 'admin'), core_component::normalize_component('moodle_admin'));
277         // Activity modules and their subplugins.
278         $this->assertSame(array('mod', 'workshop'), core_component::normalize_component('workshop'));
279         $this->assertSame(array('mod', 'workshop'), core_component::normalize_component('mod_workshop'));
280         $this->assertSame(array('workshopform', 'accumulative'), core_component::normalize_component('workshopform_accumulative'));
281         $this->assertSame(array('mod', 'quiz'), core_component::normalize_component('quiz'));
282         $this->assertSame(array('quiz', 'grading'), core_component::normalize_component('quiz_grading'));
283         $this->assertSame(array('mod', 'data'), core_component::normalize_component('data'));
284         $this->assertSame(array('datafield', 'checkbox'), core_component::normalize_component('datafield_checkbox'));
286         // Other plugin types.
287         $this->assertSame(array('auth', 'mnet'), core_component::normalize_component('auth_mnet'));
288         $this->assertSame(array('enrol', 'self'), core_component::normalize_component('enrol_self'));
289         $this->assertSame(array('block', 'html'), core_component::normalize_component('block_html'));
290         $this->assertSame(array('block', 'mnet_hosts'), core_component::normalize_component('block_mnet_hosts'));
291         $this->assertSame(array('local', 'amos'), core_component::normalize_component('local_amos'));
292         $this->assertSame(array('local', 'admin'), core_component::normalize_component('local_admin'));
294         // Unknown words without underscore are supposed to be activity modules.
295         $this->assertSame(array('mod', 'whoonearthwouldcomewithsuchastupidnameofcomponent'),
296             core_component::normalize_component('whoonearthwouldcomewithsuchastupidnameofcomponent'));
297         // Module names can not contain underscores, this must be a subplugin.
298         $this->assertSame(array('whoonearth', 'wouldcomewithsuchastupidnameofcomponent'),
299             core_component::normalize_component('whoonearth_wouldcomewithsuchastupidnameofcomponent'));
300         $this->assertSame(array('whoonearth', 'would_come_withsuchastupidnameofcomponent'),
301             core_component::normalize_component('whoonearth_would_come_withsuchastupidnameofcomponent'));
302     }
304     public function test_deprecated_normalize_component() {
305         // Moodle core.
306         $this->assertSame(array('core', null), normalize_component('core'));
307         $this->assertSame(array('core', null), normalize_component(''));
308         $this->assertSame(array('core', null), normalize_component('moodle'));
310         // Moodle core subsystems.
311         $this->assertSame(array('core', 'admin'), normalize_component('admin'));
312         $this->assertSame(array('core', 'admin'), normalize_component('core_admin'));
313         $this->assertSame(array('core', 'admin'), normalize_component('moodle_admin'));
315         // Activity modules and their subplugins.
316         $this->assertSame(array('mod', 'workshop'), normalize_component('workshop'));
317         $this->assertSame(array('mod', 'workshop'), normalize_component('mod_workshop'));
318         $this->assertSame(array('workshopform', 'accumulative'), normalize_component('workshopform_accumulative'));
319         $this->assertSame(array('mod', 'quiz'), normalize_component('quiz'));
320         $this->assertSame(array('quiz', 'grading'), normalize_component('quiz_grading'));
321         $this->assertSame(array('mod', 'data'), normalize_component('data'));
322         $this->assertSame(array('datafield', 'checkbox'), normalize_component('datafield_checkbox'));
324         // Other plugin types.
325         $this->assertSame(array('auth', 'mnet'), normalize_component('auth_mnet'));
326         $this->assertSame(array('enrol', 'self'), normalize_component('enrol_self'));
327         $this->assertSame(array('block', 'html'), normalize_component('block_html'));
328         $this->assertSame(array('block', 'mnet_hosts'), normalize_component('block_mnet_hosts'));
329         $this->assertSame(array('local', 'amos'), normalize_component('local_amos'));
330         $this->assertSame(array('local', 'admin'), normalize_component('local_admin'));
332         // Unknown words without underscore are supposed to be activity modules.
333         $this->assertSame(array('mod', 'whoonearthwouldcomewithsuchastupidnameofcomponent'),
334             normalize_component('whoonearthwouldcomewithsuchastupidnameofcomponent'));
335         // Module names can not contain underscores, this must be a subplugin.
336         $this->assertSame(array('whoonearth', 'wouldcomewithsuchastupidnameofcomponent'),
337             normalize_component('whoonearth_wouldcomewithsuchastupidnameofcomponent'));
338         $this->assertSame(array('whoonearth', 'would_come_withsuchastupidnameofcomponent'),
339             normalize_component('whoonearth_would_come_withsuchastupidnameofcomponent'));
340     }
342     public function test_get_component_directory() {
343         $plugintypes = core_component::get_plugin_types();
344         foreach ($plugintypes as $plugintype => $fulldir) {
345             $plugins = core_component::get_plugin_list($plugintype);
346             foreach ($plugins as $pluginname => $plugindir) {
347                 $this->assertSame($plugindir, core_component::get_component_directory(($plugintype.'_'.$pluginname)));
348             }
349         }
351         $subsystems = core_component::get_core_subsystems();
352         foreach ($subsystems as $subsystem => $fulldir) {
353             $this->assertSame($fulldir, core_component::get_component_directory(('core_'.$subsystem)));
354         }
355     }
357     public function test_deprecated_get_component_directory() {
358         $plugintypes = core_component::get_plugin_types();
359         foreach ($plugintypes as $plugintype => $fulldir) {
360             $plugins = core_component::get_plugin_list($plugintype);
361             foreach ($plugins as $pluginname => $plugindir) {
362                 $this->assertSame($plugindir, get_component_directory(($plugintype.'_'.$pluginname)));
363             }
364         }
366         $subsystems = core_component::get_core_subsystems();
367         foreach ($subsystems as $subsystem => $fulldir) {
368             $this->assertSame($fulldir, get_component_directory(('core_'.$subsystem)));
369         }
370     }
372     public function test_get_subtype_parent() {
373         global $CFG;
375         $this->assertNull(core_component::get_subtype_parent('mod'));
377         // Any plugin with more subtypes is ok here.
378         $this->assertFileExists("$CFG->dirroot/mod/assign/db/subplugins.php");
379         $this->assertSame('mod_assign', core_component::get_subtype_parent('assignsubmission'));
380         $this->assertSame('mod_assign', core_component::get_subtype_parent('assignfeedback'));
381         $this->assertNull(core_component::get_subtype_parent('assignxxxxx'));
382     }
384     public function test_get_subplugins() {
385         global $CFG;
387         // Any plugin with more subtypes is ok here.
388         $this->assertFileExists("$CFG->dirroot/mod/assign/db/subplugins.php");
390         $subplugins = core_component::get_subplugins('mod_assign');
391         $this->assertSame(array('assignsubmission', 'assignfeedback'), array_keys($subplugins));
393         $subs = core_component::get_plugin_list('assignsubmission');
394         $feeds = core_component::get_plugin_list('assignfeedback');
396         $this->assertSame(array_keys($subs), $subplugins['assignsubmission']);
397         $this->assertSame(array_keys($feeds), $subplugins['assignfeedback']);
399         // Any plugin without subtypes is ok here.
400         $this->assertFileExists("$CFG->dirroot/mod/choice");
401         $this->assertFileNotExists("$CFG->dirroot/mod/choice/db/subplugins.php");
403         $this->assertNull(core_component::get_subplugins('mod_choice'));
405         $this->assertNull(core_component::get_subplugins('xxxx_yyyy'));
406     }
408     public function test_get_plugin_types_with_subplugins() {
409         global $CFG;
411         $types = core_component::get_plugin_types_with_subplugins();
413         // Hardcode it here to detect if anybody hacks the code to include more subplugin types.
414         $expected = array(
415             'mod' => "$CFG->dirroot/mod",
416             'editor' => "$CFG->dirroot/lib/editor",
417             'tool' => "$CFG->dirroot/$CFG->admin/tool",
418             'local' => "$CFG->dirroot/local",
419         );
421         $this->assertSame($expected, $types);
423     }
425     public function test_get_plugin_list_with_file() {
426         $this->resetAfterTest(true);
428         // No extra reset here because core_component reset automatically.
430         $expected = array();
431         $reports = core_component::get_plugin_list('report');
432         foreach ($reports as $name => $fulldir) {
433             if (file_exists("$fulldir/lib.php")) {
434                 $expected[] = $name;
435             }
436         }
438         // Test cold.
439         $list = core_component::get_plugin_list_with_file('report', 'lib.php', false);
440         $this->assertEquals($expected, array_keys($list));
442         // Test hot.
443         $list = core_component::get_plugin_list_with_file('report', 'lib.php', false);
444         $this->assertEquals($expected, array_keys($list));
446         // Test with include.
447         $list = core_component::get_plugin_list_with_file('report', 'lib.php', true);
448         $this->assertEquals($expected, array_keys($list));
450         // Test missing.
451         $list = core_component::get_plugin_list_with_file('report', 'idontexist.php', true);
452         $this->assertEquals(array(), array_keys($list));
453     }