Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 116 |
|
0.00% |
0 / 27 |
CRAP | |
0.00% |
0 / 1 |
SiteConfig | |
0.00% |
0 / 116 |
|
0.00% |
0 / 27 |
1640 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
reset | |
0.00% |
0 / 41 |
|
0.00% |
0 / 1 |
6 | |||
deleteNamespace | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
12 | |||
disableSubpagesForNS | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
enableSubpagesForNS | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
updateNamespace | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
setupInterwikiMap | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
interwikiMap | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
server | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
script | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
scriptpath | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
baseURI | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
allowedExternalImagePrefixes | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getMWConfigValue | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
30 | |||
setInterwikiMagic | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
interwikiMagic | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setMagicLinkEnabled | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
magicLinkEnabled | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
fakeTimestamp | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
timezoneOffset | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
widthOption | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
registerParserTestExtension | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
unregisterParserTestExtension | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
20 | |||
setExternalLinkTarget | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getExternalLinkTarget | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setNoFollowConfig | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
getNoFollowConfig | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | declare( strict_types = 1 ); |
3 | |
4 | namespace Wikimedia\Parsoid\ParserTests; |
5 | |
6 | use Monolog\Handler\FilterHandler; |
7 | use Monolog\Logger; |
8 | use Psr\Log\LoggerInterface; |
9 | use Wikimedia\Assert\Assert; |
10 | use Wikimedia\Parsoid\Config\Api\ApiHelper; |
11 | use Wikimedia\Parsoid\Config\Api\SiteConfig as ApiSiteConfig; |
12 | use Wikimedia\Parsoid\Ext\ExtensionModule; |
13 | use Wikimedia\Parsoid\Utils\ConfigUtils; |
14 | use Wikimedia\Parsoid\Utils\Utils; |
15 | |
16 | class SiteConfig extends ApiSiteConfig { |
17 | /** @var array overrides parent-class info */ |
18 | private $interwikiMap; |
19 | |
20 | /** @var bool overrides parent-class info */ |
21 | private $interwikiMagic; |
22 | |
23 | /** @var array<string,bool> overrides parent-class info */ |
24 | private $enabledMagicLinks = []; |
25 | |
26 | /** @var array overrides parent-class server info */ |
27 | private $serverData; |
28 | |
29 | /** @var array overrides parent-class info */ |
30 | public $allowedExternalImagePrefixes = [ '' ]; |
31 | |
32 | /** |
33 | * Init to default value for parserTests. Overrides parent-class info. |
34 | * @var array |
35 | */ |
36 | public $responsiveReferences; |
37 | |
38 | /** @var ?int */ |
39 | public $thumbsize; |
40 | |
41 | /** @var LoggerInterface */ |
42 | public $suppressLogger; |
43 | |
44 | /** If set, generate experimental Parsoid HTML v3 parser function output |
45 | * Individual parser tests could change this |
46 | */ |
47 | public bool $v3pf; |
48 | |
49 | /** @var string|false */ |
50 | private $externalLinkTarget = false; |
51 | |
52 | /** @var ?array */ |
53 | private $noFollowConfig; |
54 | |
55 | /** @inheritDoc */ |
56 | public function __construct( ApiHelper $api, array $opts ) { |
57 | $logger = self::createLogger(); |
58 | $opts['logger'] = $logger; |
59 | parent::__construct( $api, $opts ); |
60 | |
61 | // Needed for bidi-char-scrubbing html2wt tests. |
62 | $this->scrubBidiChars = true; |
63 | |
64 | // Logger to suppress all logs but fatals (critical errors) |
65 | $this->suppressLogger = new Logger( "ParserTests" ); |
66 | $errorLogHandler = $logger->getHandlers()[0]; |
67 | $filterHandler = new FilterHandler( $errorLogHandler, Logger::CRITICAL ); |
68 | $this->suppressLogger->pushHandler( $filterHandler ); |
69 | } |
70 | |
71 | public function reset() { |
72 | parent::reset(); |
73 | |
74 | // adjust config to match that used for PHP tests |
75 | // see core/tests/parser/parserTest.inc:setupGlobals() for |
76 | // full set of config normalizations done. |
77 | $this->serverData = [ |
78 | 'server' => 'http://example.org', |
79 | 'scriptpath' => '/', |
80 | 'script' => '/index.php', |
81 | 'articlepath' => '/wiki/$1', |
82 | 'baseURI' => 'http://example.org/wiki/' |
83 | ]; |
84 | |
85 | // Add 'MemoryAlpha' namespace (T53680) |
86 | $this->updateNamespace( [ |
87 | 'id' => 100, |
88 | 'case' => 'first-letter', |
89 | 'subpages' => false, |
90 | 'canonical' => 'MemoryAlpha', |
91 | 'name' => 'MemoryAlpha', |
92 | ] ); |
93 | |
94 | // Testing |
95 | if ( $this->iwp() === 'enwiki' ) { |
96 | $this->updateNamespace( [ |
97 | 'id' => 4, |
98 | 'case' => 'first-letter', |
99 | 'subpages' => true, |
100 | 'canonical' => 'Project', |
101 | 'name' => 'Base MW' |
102 | ] ); |
103 | $this->updateNamespace( [ |
104 | 'id' => 5, |
105 | 'case' => 'first-letter', |
106 | 'subpages' => true, |
107 | 'canonical' => 'Project talk', |
108 | 'name' => 'Base MW talk' |
109 | ] ); |
110 | } |
111 | |
112 | // Reset other values to defaults |
113 | $this->responsiveReferences = [ 'enabled' => true, 'threshold' => 10 ]; |
114 | $this->disableSubpagesForNS( 0 ); |
115 | $this->unregisterParserTestExtension( new StyleTag() ); |
116 | $this->unregisterParserTestExtension( new RawHTML() ); |
117 | $this->unregisterParserTestExtension( new ParserHook() ); |
118 | $this->unregisterParserTestExtension( new DummyAnnotation() ); |
119 | $this->unregisterParserTestExtension( new I18nTag() ); |
120 | $this->thumbsize = null; |
121 | $this->externalLinkTarget = false; |
122 | $this->noFollowConfig = null; |
123 | $this->v3pf = false; |
124 | } |
125 | |
126 | private function deleteNamespace( string $name ): void { |
127 | $normName = Utils::normalizeNamespaceName( $name ); |
128 | $id = $this->namespaceId( $normName ); |
129 | |
130 | if ( !$id ) { |
131 | $normName = $name; |
132 | $id = $this->namespaceId( $normName ); |
133 | } |
134 | |
135 | if ( $id ) { |
136 | unset( $this->nsCanon[$normName] ); |
137 | unset( $this->nsIds[$normName] ); |
138 | unset( $this->nsNames[$id] ); |
139 | unset( $this->nsCase[$id] ); |
140 | unset( $this->nsWithSubpages[$id] ); |
141 | } |
142 | } |
143 | |
144 | public function disableSubpagesForNS( int $ns ): void { |
145 | $this->nsWithSubpages[$ns] = false; |
146 | } |
147 | |
148 | public function enableSubpagesForNS( int $ns ): void { |
149 | $this->nsWithSubpages[$ns] = true; |
150 | } |
151 | |
152 | /** |
153 | * Update namespace info. |
154 | * |
155 | * Delete any existing namespace with the same id. |
156 | * Add new namespaces. |
157 | * |
158 | * @param array $ns |
159 | */ |
160 | private function updateNamespace( array $ns ): void { |
161 | $old = $this->namespaceName( (int)$ns['id'] ); |
162 | if ( $old ) { // Id may already be defined; if so, clear it. |
163 | if ( $old === Utils::normalizeNamespaceName( $ns['name'] ) ) { |
164 | // ParserTests does a lot redundantly. |
165 | return; |
166 | } |
167 | $this->deleteNamespace( $old ); |
168 | } |
169 | $this->addNamespace( $ns ); |
170 | Assert::invariant( $ns['case'] === 'first-letter', |
171 | 'ParserTests/SiteConfig only supports first-letter case currently' ); |
172 | } |
173 | |
174 | /** |
175 | * Compute the interwiki map based on mock raw data. |
176 | * This replaces the previously computed interwiki map |
177 | * based on data from MockApiHelper |
178 | * |
179 | * @param array $iwData |
180 | */ |
181 | public function setupInterwikiMap( array $iwData ): void { |
182 | $this->interwikiMap = ConfigUtils::computeInterwikiMap( $iwData ); |
183 | $this->interwikiMapNoNamespaces = null; |
184 | $this->iwMatcher = null; |
185 | } |
186 | |
187 | public function interwikiMap(): array { |
188 | return $this->interwikiMap; |
189 | } |
190 | |
191 | public function server(): string { |
192 | return $this->serverData['server']; |
193 | } |
194 | |
195 | public function script(): string { |
196 | return $this->serverData['script']; |
197 | } |
198 | |
199 | public function scriptpath(): string { |
200 | return $this->serverData['scriptpath']; |
201 | } |
202 | |
203 | public function baseURI(): string { |
204 | return $this->serverData['baseURI']; |
205 | } |
206 | |
207 | public function allowedExternalImagePrefixes(): array { |
208 | return $this->allowedExternalImagePrefixes; |
209 | } |
210 | |
211 | /** @inheritDoc */ |
212 | public function getMWConfigValue( string $key ) { |
213 | switch ( $key ) { |
214 | case 'CiteResponsiveReferences': |
215 | return $this->responsiveReferences['enabled']; |
216 | |
217 | case 'CiteResponsiveReferencesThreshold': |
218 | return $this->responsiveReferences['threshold']; |
219 | |
220 | case 'ParsoidExperimentalParserFunctionOutput': |
221 | return $this->v3pf; |
222 | |
223 | default: |
224 | return null; |
225 | } |
226 | } |
227 | |
228 | public function setInterwikiMagic( bool $val ): void { |
229 | $this->interwikiMagic = $val; |
230 | } |
231 | |
232 | public function interwikiMagic(): bool { |
233 | return $this->interwikiMagic; |
234 | } |
235 | |
236 | /** |
237 | * @param string $which One of "RFC", "PMID", or "ISBN". |
238 | * @param bool $val |
239 | */ |
240 | public function setMagicLinkEnabled( string $which, bool $val ): void { |
241 | $this->enabledMagicLinks[$which] = $val; |
242 | } |
243 | |
244 | public function magicLinkEnabled( string $which ): bool { |
245 | // defaults to enabled |
246 | return $this->enabledMagicLinks[$which] ?? true; |
247 | } |
248 | |
249 | public function fakeTimestamp(): ?int { |
250 | return 123; |
251 | } |
252 | |
253 | /** |
254 | * Hardcode value for parser tests |
255 | * |
256 | * @return int |
257 | */ |
258 | public function timezoneOffset(): int { |
259 | return 0; |
260 | } |
261 | |
262 | public function widthOption(): int { |
263 | return $this->thumbsize ?? 180; // wgThumbLimits setting in core ParserTestRunner |
264 | } |
265 | |
266 | /** |
267 | * Register an extension for use in parser tests |
268 | * @param ExtensionModule $ext |
269 | */ |
270 | public function registerParserTestExtension( ExtensionModule $ext ): void { |
271 | $this->getExtConfig(); // ensure $this->extConfig is initialized |
272 | $this->processExtensionModule( $ext ); |
273 | } |
274 | |
275 | /** |
276 | * Unregister a previously registered extension. |
277 | * @param ExtensionModule $ext |
278 | */ |
279 | private function unregisterParserTestExtension( ExtensionModule $ext ): void { |
280 | $extConfig = $ext->getConfig(); |
281 | $name = $extConfig['name']; |
282 | |
283 | $this->getExtConfig(); // ensure $this->extConfig is initialized |
284 | foreach ( ( $extConfig['tags'] ?? [] ) as $tagConfig ) { |
285 | $lowerTagName = mb_strtolower( $tagConfig['name'] ); |
286 | unset( $this->extConfig['allTags'][$lowerTagName] ); |
287 | unset( $this->extConfig['parsoidExtTags'][$lowerTagName] ); |
288 | } |
289 | |
290 | foreach ( ( $extConfig['annotations'] ?? [] ) as $annotationTag ) { |
291 | $lowerTagName = mb_strtolower( $annotationTag ); |
292 | unset( $this->extConfig['allTags'][$lowerTagName] ); |
293 | unset( $this->extConfig['annotationTags'][$lowerTagName] ); |
294 | } |
295 | |
296 | if ( isset( $extConfig['domProcessors'] ) ) { |
297 | unset( $this->extConfig['domProcessors'][$name] ); |
298 | } |
299 | |
300 | /* |
301 | * FIXME: Unsetting contentmodels is also tricky with the current |
302 | * state tracked during registration. We will have to reprocess all |
303 | * extensions or maintain a linked list of applicable extensions |
304 | * for every content model |
305 | */ |
306 | } |
307 | |
308 | /** |
309 | * @param string|false $value |
310 | */ |
311 | public function setExternalLinkTarget( $value ): void { |
312 | $this->externalLinkTarget = $value; |
313 | } |
314 | |
315 | /** |
316 | * @inheritDoc |
317 | */ |
318 | public function getExternalLinkTarget() { |
319 | return $this->externalLinkTarget; |
320 | } |
321 | |
322 | /** |
323 | * @param string $key |
324 | * @param mixed $value |
325 | */ |
326 | public function setNoFollowConfig( string $key, $value ): void { |
327 | $noFollowConfig = $this->getNoFollowConfig(); |
328 | $noFollowConfig[$key] = $value; |
329 | $this->noFollowConfig = $noFollowConfig; |
330 | } |
331 | |
332 | /** |
333 | * @inheritDoc |
334 | */ |
335 | public function getNoFollowConfig(): array { |
336 | if ( $this->noFollowConfig === null ) { |
337 | $this->noFollowConfig = parent::getNoFollowConfig(); |
338 | } |
339 | return $this->noFollowConfig; |
340 | } |
341 | } |