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