4 * This file is intended to test magic variables in the parser
5 * It was inspired by Raymond & Matěj Grabovský commenting about r66200
7 * As of february 2011, it only tests some revisions and date related
10 * @author Antoine Musso
11 * @copyright Copyright © 2011, Antoine Musso
15 namespace MediaWiki\Tests\Parser
;
17 use MediaWiki\MainConfigNames
;
18 use MediaWiki\Parser\Parser
;
19 use MediaWiki\Parser\ParserOptions
;
20 use MediaWiki\Title\Title
;
21 use MediaWiki\User\User
;
22 use MediaWikiIntegrationTestCase
;
23 use Wikimedia\TestingAccessWrapper
;
27 * @covers \MediaWiki\Parser\Parser::expandMagicVariable
29 class MagicVariableTest
extends MediaWikiIntegrationTestCase
{
33 private $testParser = null;
35 /** setup a basic parser object */
36 protected function setUp(): void
{
39 $services = $this->getServiceContainer();
40 $contLang = $services->getLanguageFactory()->getLanguage( 'en' );
41 $this->setService( 'ContentLanguage', $contLang );
42 $this->overrideConfigValues( [
43 MainConfigNames
::LanguageCode
=> $contLang->getCode(),
44 // NOTE: Europe/Stockholm DST applies Sun, Mar 26, 2023 2:00 - Sun, Oct 29, 2023 3:00AM
45 MainConfigNames
::Localtimezone
=> 'Europe/Stockholm',
46 MainConfigNames
::MiserMode
=> false,
47 MainConfigNames
::ParserCacheExpireTime
=> 86400 * 7,
50 $this->testParser
= $services->getParserFactory()->create();
51 $this->testParser
->setOptions( ParserOptions
::newFromUserAndLang( new User
, $contLang ) );
53 # initialize parser output
54 $this->testParser
->clearState();
56 # Needs a title to do magic word stuff
57 $title = Title
::makeTitle( NS_MAIN
, 'Tests' );
58 # Else it needs a db connection just to check if it's a redirect
59 # (when deciding the page language).
60 $title->mRedirect
= false;
62 $this->testParser
->setTitle( $title );
66 * @param int $num Upper limit for numbers
67 * @return array Array of strings naming numbers from 1 up to $num
69 private static function createProviderUpTo( $num ) {
71 for ( $i = 1; $i <= $num; $i++
) {
72 $ret[] = [ strval( $i ) ];
79 * @return array Array of months numbers (as an integer)
81 public static function provideMonths() {
82 return self
::createProviderUpTo( 12 );
86 * @return array Array of days numbers (as an integer)
88 public static function provideDays() {
89 return self
::createProviderUpTo( 31 );
92 # ############## TESTS #############################################
94 # - those got copy pasted, we can probably make them cleaner
95 # - tests are lacking useful messages
99 /** @dataProvider provideDays */
100 public function testCurrentdayIsUnPadded( $day ) {
101 $this->assertUnPadded( 'currentday', $day );
104 /** @dataProvider provideDays */
105 public function testCurrentdaytwoIsZeroPadded( $day ) {
106 $this->assertZeroPadded( 'currentday2', $day );
109 /** @dataProvider provideDays */
110 public function testLocaldayIsUnPadded( $day ) {
111 $this->assertUnPadded( 'localday', $day );
114 /** @dataProvider provideDays */
115 public function testLocaldaytwoIsZeroPadded( $day ) {
116 $this->assertZeroPadded( 'localday2', $day );
121 /** @dataProvider provideMonths */
122 public function testCurrentmonthIsZeroPadded( $month ) {
123 $this->assertZeroPadded( 'currentmonth', $month );
126 /** @dataProvider provideMonths */
127 public function testCurrentmonthoneIsUnPadded( $month ) {
128 $this->assertUnPadded( 'currentmonth1', $month );
131 /** @dataProvider provideMonths */
132 public function testLocalmonthIsZeroPadded( $month ) {
133 $this->assertZeroPadded( 'localmonth', $month );
136 /** @dataProvider provideMonths */
137 public function testLocalmonthoneIsUnPadded( $month ) {
138 $this->assertUnPadded( 'localmonth1', $month );
143 /** @dataProvider provideDays */
144 public function testRevisiondayIsUnPadded( $day ) {
145 $this->assertUnPadded( 'revisionday', $day );
148 /** @dataProvider provideDays */
149 public function testRevisiondaytwoIsZeroPadded( $day ) {
150 $this->assertZeroPadded( 'revisionday2', $day );
155 /** @dataProvider provideMonths */
156 public function testRevisionmonthIsZeroPadded( $month ) {
157 $this->assertZeroPadded( 'revisionmonth', $month );
160 /** @dataProvider provideMonths */
161 public function testRevisionmonthoneIsUnPadded( $month ) {
162 $this->assertUnPadded( 'revisionmonth1', $month );
165 public static function provideCurrentUnitTimestampWords() {
168 [ 'currentmonth', '20200208153011', '02', 604800 ],
169 [ 'currentmonth1', '20200208153011', '2', 604800 ],
170 [ 'currentmonthname', '20200208153011', 'February', 604800 ],
171 [ 'currentmonthnamegen', '20200208153011', 'February', 604800 ],
172 [ 'currentmonthabbrev', '20200208153011', 'Feb', 604800 ],
173 [ 'currentday', '20200208153011', '8', 30601 ],
174 [ 'currentday2', '20200208153011', '08', 30601 ],
175 [ 'currentdayname', '20200208153011', 'Saturday', 30601 ],
176 [ 'currentyear', '20200208153011', '2020', 604800 ],
177 [ 'currenthour', '20200208153011', '15', 1801 ],
178 [ 'currentweek', '20200208153011', '6', 30601 ],
179 [ 'currentdow', '20200208153011', '6', 30601 ],
180 [ 'currenttime', '20200208153011', '15:30', 3600 ],
182 [ 'currentmonth', '20200208223011', '02', 604800 ],
183 [ 'currentmonth1', '20200208223011', '2', 604800 ],
184 [ 'currentmonthname', '20200208223011', 'February', 604800 ],
185 [ 'currentmonthnamegen', '20200208223011', 'February', 604800 ],
186 [ 'currentmonthabbrev', '20200208223011', 'Feb', 604800 ],
187 [ 'currentday', '20200208223011', '8', 5401 ],
188 [ 'currentday2', '20200208223011', '08', 5401 ],
189 [ 'currentdayname', '20200208223011', 'Saturday', 5401 ],
190 [ 'currentyear', '20200208223011', '2020', 604800 ],
191 [ 'currenthour', '20200208223011', '22', 1801 ],
192 [ 'currentweek', '20200208223011', '6', 5401 ],
193 [ 'currentdow', '20200208223011', '6', 5401 ],
194 [ 'currenttime', '20200208223011', '22:30', 3600 ]
198 public static function provideLocalUnitTimestampWords() {
199 // NOTE: Europe/Stockholm DST applies Sun, Mar 26, 2023 2:00 - Sun, Oct 29, 2023 3:00AM
202 [ 'localmonth', '20200208153011', '02', 604800 ],
203 [ 'localmonth1', '20200208153011', '2', 604800 ],
204 [ 'localmonthname', '20200208153011', 'February', 604800 ],
205 [ 'localmonthnamegen', '20200208153011', 'February', 604800 ],
206 [ 'localmonthabbrev', '20200208153011', 'Feb', 604800 ],
207 [ 'localday', '20200208153011', '8', 27001 ],
208 [ 'localday2', '20200208153011', '08', 27001 ],
209 [ 'localdayname', '20200208153011', 'Saturday', 27001 ],
210 [ 'localyear', '20200208153011', '2020', 604800 ],
211 [ 'localhour', '20200208153011', '16', 1801 ],
212 [ 'localweek', '20200208153011', '6', 27001 ],
213 [ 'localdow', '20200208153011', '6', 27001 ],
214 [ 'localtime', '20200208153011', '16:30', 3600 ],
216 [ 'localmonth', '20200208223011', '02', 604800 ],
217 [ 'localmonth1', '20200208223011', '2', 604800 ],
218 [ 'localmonthname', '20200208223011', 'February', 604800 ],
219 [ 'localmonthnamegen', '20200208223011', 'February', 604800 ],
220 [ 'localmonthabbrev', '20200208223011', 'Feb', 604800 ],
221 [ 'localday', '20200208223011', '8', 1801 ],
222 [ 'localday2', '20200208223011', '08', 1801 ],
223 [ 'localdayname', '20200208223011', 'Saturday', 1801 ],
224 [ 'localyear', '20200208223011', '2020', 604800 ],
225 [ 'localhour', '20200208223011', '23', 1801 ],
226 [ 'localweek', '20200208223011', '6', 1801 ],
227 [ 'localdow', '20200208223011', '6', 1801 ],
228 [ 'localtime', '20200208223011', '23:30', 3600 ],
229 // Late night / early morning
230 [ 'localmonth', '20200208233011', '02', 604800 ],
231 [ 'localmonth1', '20200208233011', '2', 604800 ],
232 [ 'localmonthname', '20200208233011', 'February', 604800 ],
233 [ 'localmonthnamegen', '20200208233011', 'February', 604800 ],
234 [ 'localmonthabbrev', '20200208233011', 'Feb', 604800 ],
235 [ 'localday', '20200208233011', '9', 84601 ],
236 [ 'localday2', '20200208233011', '09', 84601 ],
237 [ 'localdayname', '20200208233011', 'Sunday', 84601 ],
238 [ 'localyear', '20200208233011', '2020', 604800 ],
239 [ 'localhour', '20200208233011', '00', 1801 ],
240 [ 'localweek', '20200208233011', '6', 84601 ],
241 [ 'localdow', '20200208233011', '0', 84601 ],
242 [ 'localtime', '20200208233011', '00:30', 3600 ]
247 * @param string $word
249 * @param string $expOutput
251 * @dataProvider provideCurrentUnitTimestampWords
252 * @dataProvider provideLocalUnitTimestampWords
254 public function testCurrentUnitTimestampExpiry( $word, $ts, $expOutput, $expTTL ) {
255 $this->setParserTimestamp( $ts );
257 $this->assertMagic( $expOutput, $word );
258 $this->assertSame( $expTTL, $this->testParser
->getOutput()->getCacheExpiry() );
261 # ############## HELPERS ############################################
264 * assertion helper expecting a magic output which is zero padded
265 * @param string $magic
266 * @param string $value
268 public function assertZeroPadded( $magic, $value ) {
269 $this->assertMagicPadding( $magic, $value, '%02d' );
273 * assertion helper expecting a magic output which is unpadded
274 * @param string $magic
275 * @param string $value
277 public function assertUnPadded( $magic, $value ) {
278 $this->assertMagicPadding( $magic, $value, '%d' );
282 * Main assertion helper for magic variables padding
283 * @param string $magic Magic variable name
284 * @param mixed $value Month or day
285 * @param string $format Sprintf format for $value
287 private function assertMagicPadding( $magic, $value, $format ) {
288 # Initialize parser timestamp as year 2010 at 12h34 56s.
289 # month and day are given by the caller ($value). Month < 12!
291 $month = $value %
12;
296 $this->setParserTimestamp(
297 sprintf( '2010%02d%02d123456', $month, $value )
300 # please keep the following commented line of code. It helps debugging.
301 // print "\nDEBUG (value $value):" . sprintf( '2010%02d%02d123456', $value, $value ) . "\n";
303 # format expectation and test it
304 $expected = sprintf( $format, $value );
305 $this->assertMagic( $expected, $magic );
309 * helper to set the parser timestamp and revision timestamp
312 private function setParserTimestamp( $ts ) {
313 $this->testParser
->getOptions()->setTimestamp( $ts );
314 TestingAccessWrapper
::newFromObject( $this->testParser
)->mRevisionTimestamp
= $ts;
318 * Assertion helper to test a magic variable output
319 * @param string|int $expected
320 * @param string $magic
322 private function assertMagic( $expected, $magic ) {
323 # Generate a message for the assertion
324 $msg = sprintf( "Magic %s should be <%s:%s>",
327 get_debug_type( $expected )
332 TestingAccessWrapper
::newFromObject( $this->testParser
)->expandMagicVariable( $magic ),