rdbms: Bump TransactionProfiler log entries to WARNING
[lhc/web/wiklou.git] / tests / phpunit / includes / parser / ParserOptionsTest.php
1 <?php
2
3 use Wikimedia\TestingAccessWrapper;
4 use Wikimedia\ScopedCallback;
5
6 /**
7 * @covers ParserOptions
8 */
9 class ParserOptionsTest extends MediaWikiTestCase {
10
11 private static function clearCache() {
12 $wrap = TestingAccessWrapper::newFromClass( ParserOptions::class );
13 $wrap->defaults = null;
14 $wrap->lazyOptions = [
15 'dateformat' => [ ParserOptions::class, 'initDateFormat' ],
16 ];
17 $wrap->inCacheKey = [
18 'dateformat' => true,
19 'numberheadings' => true,
20 'thumbsize' => true,
21 'stubthreshold' => true,
22 'printable' => true,
23 'userlang' => true,
24 'wrapclass' => true,
25 ];
26 }
27
28 protected function setUp() {
29 global $wgHooks;
30
31 parent::setUp();
32 self::clearCache();
33
34 $this->setMwGlobals( [
35 'wgRenderHashAppend' => '',
36 'wgHooks' => [
37 'PageRenderingHash' => [],
38 ] + $wgHooks,
39 ] );
40 }
41
42 protected function tearDown() {
43 self::clearCache();
44 parent::tearDown();
45 }
46
47 /**
48 * @dataProvider provideIsSafeToCache
49 * @param bool $expect Expected value
50 * @param array $options Options to set
51 */
52 public function testIsSafeToCache( $expect, $options ) {
53 $popt = ParserOptions::newCanonical();
54 foreach ( $options as $name => $value ) {
55 $popt->setOption( $name, $value );
56 }
57 $this->assertSame( $expect, $popt->isSafeToCache() );
58 }
59
60 public static function provideIsSafeToCache() {
61 return [
62 'No overrides' => [ true, [] ],
63 'In-key options are ok' => [ true, [
64 'thumbsize' => 1e100,
65 'wrapclass' => false,
66 ] ],
67 'Non-in-key options are not ok' => [ false, [
68 'removeComments' => false,
69 ] ],
70 'Canonical override, not default (1)' => [ true, [
71 'tidy' => true,
72 ] ],
73 'Canonical override, not default (2)' => [ false, [
74 'tidy' => false,
75 ] ],
76 ];
77 }
78
79 /**
80 * @dataProvider provideOptionsHash
81 * @param array $usedOptions Used options
82 * @param string $expect Expected value
83 * @param array $options Options to set
84 * @param array $globals Globals to set
85 */
86 public function testOptionsHash( $usedOptions, $expect, $options, $globals = [] ) {
87 global $wgHooks;
88
89 $globals += [
90 'wgHooks' => [],
91 ];
92 $globals['wgHooks'] += [
93 'PageRenderingHash' => [],
94 ] + $wgHooks;
95 $this->setMwGlobals( $globals );
96
97 $popt = ParserOptions::newCanonical();
98 foreach ( $options as $name => $value ) {
99 $popt->setOption( $name, $value );
100 }
101 $this->assertSame( $expect, $popt->optionsHash( $usedOptions ) );
102 }
103
104 public static function provideOptionsHash() {
105 $used = [ 'wrapclass', 'printable' ];
106
107 $classWrapper = TestingAccessWrapper::newFromClass( ParserOptions::class );
108 $classWrapper->getDefaults();
109 $allUsableOptions = array_diff(
110 array_keys( $classWrapper->inCacheKey ),
111 array_keys( $classWrapper->lazyOptions )
112 );
113
114 return [
115 'Canonical options, nothing used' => [ [], 'canonical', [] ],
116 'Canonical options, used some options' => [ $used, 'canonical', [] ],
117 'Used some options, non-default values' => [
118 $used,
119 'printable=1!wrapclass=foobar',
120 [
121 'wrapclass' => 'foobar',
122 'printable' => true,
123 ]
124 ],
125 'Canonical options, used all non-lazy options' => [ $allUsableOptions, 'canonical', [] ],
126 'Canonical options, nothing used, but with hooks and $wgRenderHashAppend' => [
127 [],
128 'canonical!wgRenderHashAppend!onPageRenderingHash',
129 [],
130 [
131 'wgRenderHashAppend' => '!wgRenderHashAppend',
132 'wgHooks' => [ 'PageRenderingHash' => [ [ __CLASS__ . '::onPageRenderingHash' ] ] ],
133 ]
134 ],
135 ];
136 }
137
138 public static function onPageRenderingHash( &$confstr ) {
139 $confstr .= '!onPageRenderingHash';
140 }
141
142 // Test weird historical behavior is still weird
143 public function testOptionsHashEditSection() {
144 $popt = ParserOptions::newCanonical();
145 $popt->registerWatcher( function ( $name ) {
146 $this->assertNotEquals( 'editsection', $name );
147 } );
148
149 $this->assertTrue( $popt->getEditSection() );
150 $this->assertSame( 'canonical', $popt->optionsHash( [] ) );
151 $this->assertSame( 'canonical', $popt->optionsHash( [ 'editsection' ] ) );
152
153 $popt->setEditSection( false );
154 $this->assertFalse( $popt->getEditSection() );
155 $this->assertSame( 'canonical', $popt->optionsHash( [] ) );
156 $this->assertSame( 'editsection=0', $popt->optionsHash( [ 'editsection' ] ) );
157 }
158
159 /**
160 * @expectedException InvalidArgumentException
161 * @expectedExceptionMessage Unknown parser option bogus
162 */
163 public function testGetInvalidOption() {
164 $popt = ParserOptions::newCanonical();
165 $popt->getOption( 'bogus' );
166 }
167
168 /**
169 * @expectedException InvalidArgumentException
170 * @expectedExceptionMessage Unknown parser option bogus
171 */
172 public function testSetInvalidOption() {
173 $popt = ParserOptions::newCanonical();
174 $popt->setOption( 'bogus', true );
175 }
176
177 public function testMatches() {
178 $classWrapper = TestingAccessWrapper::newFromClass( ParserOptions::class );
179 $oldDefaults = $classWrapper->defaults;
180 $oldLazy = $classWrapper->lazyOptions;
181 $reset = new ScopedCallback( function () use ( $classWrapper, $oldDefaults, $oldLazy ) {
182 $classWrapper->defaults = $oldDefaults;
183 $classWrapper->lazyOptions = $oldLazy;
184 } );
185
186 $popt1 = ParserOptions::newCanonical();
187 $popt2 = ParserOptions::newCanonical();
188 $this->assertTrue( $popt1->matches( $popt2 ) );
189
190 $popt1->enableLimitReport( true );
191 $popt2->enableLimitReport( false );
192 $this->assertTrue( $popt1->matches( $popt2 ) );
193
194 $popt2->setTidy( !$popt2->getTidy() );
195 $this->assertFalse( $popt1->matches( $popt2 ) );
196
197 $ctr = 0;
198 $classWrapper->defaults += [ __METHOD__ => null ];
199 $classWrapper->lazyOptions += [ __METHOD__ => function () use ( &$ctr ) {
200 return ++$ctr;
201 } ];
202 $popt1 = ParserOptions::newCanonical();
203 $popt2 = ParserOptions::newCanonical();
204 $this->assertFalse( $popt1->matches( $popt2 ) );
205
206 ScopedCallback::consume( $reset );
207 }
208
209 public function testAllCacheVaryingOptions() {
210 global $wgHooks;
211
212 // $wgHooks is already saved in self::setUp(), so we can modify it freely here
213 $wgHooks['ParserOptionsRegister'] = [];
214 $this->assertSame( [
215 'dateformat', 'numberheadings', 'printable', 'stubthreshold',
216 'thumbsize', 'userlang', 'wrapclass',
217 ], ParserOptions::allCacheVaryingOptions() );
218
219 self::clearCache();
220
221 $wgHooks['ParserOptionsRegister'][] = function ( &$defaults, &$inCacheKey ) {
222 $defaults += [
223 'foo' => 'foo',
224 'bar' => 'bar',
225 'baz' => 'baz',
226 ];
227 $inCacheKey += [
228 'foo' => true,
229 'bar' => false,
230 ];
231 };
232 $this->assertSame( [
233 'dateformat', 'foo', 'numberheadings', 'printable', 'stubthreshold',
234 'thumbsize', 'userlang', 'wrapclass',
235 ], ParserOptions::allCacheVaryingOptions() );
236 }
237
238 }