Skip to content

Commit 5d3ad60

Browse files
authored
Merge pull request #160 from stronk7/load_components_from_file
Allow all components to be loaded from file instead of calculated
2 parents dce0fbe + 4ef55d5 commit 5d3ad60

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

moodle/Util/MoodleUtil.php

+41
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,47 @@ protected static function calculateAllComponents(string $moodleRoot): ?array {
9393

9494
// We haven't the components yet, let's calculate all them.
9595

96+
// First, try to get it from configuration/runtime option.
97+
// This accepts the full path to a file like the one generated
98+
// by moodle-local_ci/list_valid_components, which format is:
99+
// [plugin|subsystem],component_name,component_full_path.
100+
// Useful to load them when not all the code base is available
101+
// like it happens with CiBoT runs, for example.
102+
if ($componentsFile = Config::getConfigData('moodleComponentsListPath')) {
103+
if (!is_readable($componentsFile)) {
104+
throw new DeepExitException(
105+
"ERROR: Incorrect 'moodleComponentsListPath' config/runtime option. File not found: '$componentsFile'", 3);
106+
}
107+
// Go processing the file.
108+
$handle = fopen($componentsFile, "r");
109+
if ($handle) {
110+
while (($line = fgets($handle)) !== false) {
111+
$aline = explode(',', trim($line));
112+
// Exclude any line not starting by plugin|sybsystem.
113+
if ($aline[0] !== 'plugin' && $aline[0] !== 'subsystem') {
114+
continue;
115+
}
116+
// Exclude any component not being valid one.
117+
if (!preg_match('/^[a-z][a-z0-9]*(_[a-z][a-z0-9_]*)?[a-z0-9]+$/', $aline[1])) {
118+
continue;
119+
}
120+
// Exclude any path not being under Mooddle dirroot.
121+
if (strpos($aline[2], $moodleRoot) !== 0) {
122+
continue;
123+
}
124+
// Arrived here, it's a valid line, annotate the component.
125+
self::$moodleComponents[$aline[1]] = $aline[2];
126+
}
127+
fclose($handle);
128+
}
129+
// Let's sort the array in ascending order, so more specific matches first.
130+
arsort(self::$moodleComponents);
131+
132+
return self::$moodleComponents;
133+
}
134+
135+
// Let's try to get the components from core.
136+
96137
// Verify that core_component class is already available.
97138
// Make an exception for PHPUnit runs, to be able to test everything
98139
// because within tests it's always available and never invoked.

moodle/tests/moodleutil_test.php

+47
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
namespace local_codechecker;
1818

1919
use MoodleCodeSniffer\moodle\Util\MoodleUtil;
20+
use org\bovigo\vfs\vfsStream;
2021
use PHP_CodeSniffer\Config;
2122
use PHP_CodeSniffer\Exceptions\DeepExitException;
2223
use PHP_CodeSniffer\Files\File;
@@ -41,6 +42,52 @@
4142
*/
4243
class moodleutil_test extends local_codechecker_testcase {
4344

45+
/**
46+
* Unit test for calculateAllComponents.
47+
*
48+
* Not 100% orthodox because {@see calculateAllComponents()} is protected,
49+
* and it's already indirectly tested by {@see test_getMoodleComponent()}
50+
* but it has some feature that we need to test individually here.
51+
*/
52+
public function test_calculateAllComponents() {
53+
// Let's calculate moodleRoot.
54+
$moodleRoot = MoodleUtil::getMoodleRoot();
55+
56+
// Let's prepare a components file, with some correct and incorrect entries.
57+
$components =
58+
"nonono,mod_forum,{$moodleRoot}/mod_forum\n" . // Wrong type.
59+
"plugin,mod__nono,{$moodleRoot}/mod_forum\n" . // Wrong component.
60+
"plugin,mod_forum,/no/no/no/no//mod_forum\n" . // Wrong path.
61+
"plugin,local_codechecker,{$moodleRoot}/local/codechecker\n" .// All ok.
62+
"plugin,mod_forum,{$moodleRoot}/mod/forum\n"; // All ok.
63+
64+
// Let's use virtual filesystem instead of real one.
65+
$vfs = vfsStream::setup('root', null, ['components.txt' => $components]);
66+
67+
// Set codechecker config to point to it.
68+
Config::setConfigData('moodleComponentsListPath', $vfs->url() . '/components.txt', true);
69+
70+
// Let's run calculateAllComponents() and evaluate results.
71+
$method = new \ReflectionMethod(MoodleUtil::class, 'calculateAllComponents');
72+
$method->setAccessible(true);
73+
$method->invokeArgs(null, [$moodleRoot]);
74+
75+
// Let's inspect which components have been loaded.
76+
$property = new \ReflectionProperty(MoodleUtil::class, 'moodleComponents');
77+
$property->setAccessible(true);
78+
$loadedComponents = $property->getValue();
79+
80+
$this->assertCount(2, $loadedComponents);
81+
$this->assertSame(['mod_forum', 'local_codechecker'],
82+
array_keys($loadedComponents)); // Verify they are ordered in ascending order.
83+
$this->assertSame(["{$moodleRoot}/mod/forum", "{$moodleRoot}/local/codechecker"],
84+
array_values($loadedComponents)); // Verify component paths are also the expected ones.
85+
86+
// Ensure cached information doesn't affect other tests.
87+
$this->cleanMoodleUtilCaches();
88+
Config::setConfigData('moodleComponentsListPath', null, true);
89+
}
90+
4491
/**
4592
* Provider for test_getMoodleComponent.
4693
*/

0 commit comments

Comments
 (0)