Merge "docs: Fix typo"
[mediawiki.git] / tests / phpunit / includes / ResourceLoader / ContextTest.php
blobc570f7addfa4439988cec502907f1af8d27663fb
1 <?php
3 namespace MediaWiki\Tests\ResourceLoader;
5 use Generator;
6 use MediaWiki\Config\HashConfig;
7 use MediaWiki\MainConfigNames;
8 use MediaWiki\Message\Message;
9 use MediaWiki\Request\FauxRequest;
10 use MediaWiki\Request\WebRequest;
11 use MediaWiki\ResourceLoader\Context;
12 use MediaWiki\ResourceLoader\ResourceLoader;
13 use MediaWiki\User\User;
14 use MediaWikiCoversValidator;
15 use MediaWikiTestCaseTrait;
16 use PHPUnit\Framework\TestCase;
17 use Psr\Log\LoggerInterface;
19 /**
20 * See also:
21 * - ImageModuleTest::testContext
23 * @group ResourceLoader
24 * @covers \MediaWiki\ResourceLoader\Context
26 class ContextTest extends TestCase {
28 use MediaWikiCoversValidator;
29 use MediaWikiTestCaseTrait;
31 protected static function getResourceLoader() {
32 return new EmptyResourceLoader( new HashConfig( [
33 MainConfigNames::ResourceLoaderDebug => false,
34 MainConfigNames::LoadScript => '/w/load.php',
35 ] ) );
38 public function testEmpty() {
39 $ctx = new Context( self::getResourceLoader(), new FauxRequest( [] ) );
41 // Request parameters
42 $this->assertEquals( [], $ctx->getModules() );
43 $this->assertEquals( 'qqx', $ctx->getLanguage() );
44 $this->assertSame( 0, $ctx->getDebug() );
45 $this->assertNull( $ctx->getOnly() );
46 $this->assertEquals( 'fallback', $ctx->getSkin() );
47 $this->assertNull( $ctx->getUser() );
48 $this->assertNull( $ctx->getContentOverrideCallback() );
50 // Misc
51 $this->assertEquals( 'ltr', $ctx->getDirection() );
52 $this->assertEquals( 'qqx|fallback|0|||||||', $ctx->getHash() );
53 $this->assertSame( [], $ctx->getReqBase() );
54 $this->assertInstanceOf( User::class, $ctx->getUserObj() );
55 $this->assertNull( $ctx->getUserIdentity() );
58 public function testDummy() {
59 $this->assertInstanceOf(
60 Context::class,
61 Context::newDummyContext()
65 public function testAccessors() {
66 $ctx = new Context( self::getResourceLoader(), new FauxRequest( [] ) );
67 $this->assertInstanceOf( ResourceLoader::class, $ctx->getResourceLoader() );
68 $this->assertInstanceOf( WebRequest::class, $ctx->getRequest() );
69 $this->assertInstanceOf( LoggerInterface::class, $ctx->getLogger() );
72 public function testTypicalRequest() {
73 $ctx = new Context( self::getResourceLoader(), new FauxRequest( [
74 'debug' => 'false',
75 'lang' => 'zh',
76 'modules' => 'foo|foo.quux,baz,bar|baz.quux',
77 'only' => 'styles',
78 'skin' => 'fallback',
79 ] ) );
81 // Request parameters
82 $this->assertEquals(
83 [ 'foo', 'foo.quux', 'foo.baz', 'foo.bar', 'baz.quux' ],
84 $ctx->getModules()
86 $this->assertSame( 0, $ctx->getDebug() );
87 $this->assertEquals( 'zh', $ctx->getLanguage() );
88 $this->assertEquals( 'styles', $ctx->getOnly() );
89 $this->assertEquals( 'fallback', $ctx->getSkin() );
90 $this->assertNull( $ctx->getUser() );
92 // Misc
93 $this->assertEquals( 'ltr', $ctx->getDirection() );
94 $this->assertEquals( 'zh|fallback|0||styles|||||', $ctx->getHash() );
95 $this->assertSame( [ 'lang' => 'zh' ], $ctx->getReqBase() );
98 public static function provideDirection() {
99 yield 'LTR language' => [
100 [ 'lang' => 'en' ],
101 'ltr',
103 yield 'RTL language' => [
104 [ 'lang' => 'he' ],
105 'rtl',
107 yield 'explicit LTR' => [
108 [ 'lang' => 'he', 'dir' => 'ltr' ],
109 'ltr',
111 yield 'explicit RTL' => [
112 [ 'lang' => 'en', 'dir' => 'rtl' ],
113 'rtl',
115 // Not supported, but tested to cover the case and detect change
116 yield 'invalid dir' => [
117 [ 'lang' => 'he', 'dir' => 'xyz' ],
118 'rtl',
123 * @dataProvider provideDirection
125 public function testDirection( array $params, $expected ) {
126 $ctx = new Context( self::getResourceLoader(), new FauxRequest( $params ) );
127 $this->assertEquals( $expected, $ctx->getDirection() );
130 public function testShouldInclude() {
131 $ctx = new Context( self::getResourceLoader(), new FauxRequest( [] ) );
132 $this->assertTrue( $ctx->shouldIncludeScripts(), 'Scripts in combined' );
133 $this->assertTrue( $ctx->shouldIncludeStyles(), 'Styles in combined' );
134 $this->assertTrue( $ctx->shouldIncludeMessages(), 'Messages in combined' );
136 $ctx = new Context( self::getResourceLoader(), new FauxRequest( [
137 'only' => 'styles'
138 ] ) );
139 $this->assertFalse( $ctx->shouldIncludeScripts(), 'Scripts not in styles-only' );
140 $this->assertTrue( $ctx->shouldIncludeStyles(), 'Styles in styles-only' );
141 $this->assertFalse( $ctx->shouldIncludeMessages(), 'Messages not in styles-only' );
143 $ctx = new Context( self::getResourceLoader(), new FauxRequest( [
144 'only' => 'scripts'
145 ] ) );
146 $this->assertTrue( $ctx->shouldIncludeScripts(), 'Scripts in scripts-only' );
147 $this->assertFalse( $ctx->shouldIncludeStyles(), 'Styles not in scripts-only' );
148 $this->assertFalse( $ctx->shouldIncludeMessages(), 'Messages not in scripts-only' );
151 public function testGetUser() {
152 $ctx = new Context( self::getResourceLoader(), new FauxRequest( [] ) );
153 $this->assertSame( null, $ctx->getUser() );
154 $this->assertFalse( $ctx->getUserObj()->isRegistered() );
155 $this->assertNull( $ctx->getUserIdentity() );
157 $ctx = new Context( self::getResourceLoader(), new FauxRequest( [
158 'user' => 'Example'
159 ] ) );
160 $this->assertSame( 'Example', $ctx->getUser() );
161 $this->assertEquals( 'Example', $ctx->getUserObj()->getName() );
162 $this->assertEquals( 'Example', $ctx->getUserIdentity()->getName() );
165 public function testMsg() {
166 $ctx = new Context( self::getResourceLoader(), new FauxRequest( [
167 'lang' => 'en'
168 ] ) );
169 $msg = $ctx->msg( 'mainpage' );
170 $this->assertInstanceOf( Message::class, $msg );
171 $this->assertSame( 'Main Page', $msg->useDatabase( false )->plain() );
174 public function testEncodeJson() {
175 $ctx = new Context( self::getResourceLoader(), new FauxRequest( [] ) );
177 $json = $ctx->encodeJson( [ 'x' => 'A' ] );
178 $this->assertSame( '{"x":"A"}', $json );
180 // Regression: https://phabricator.wikimedia.org/T329330
181 $json = @$ctx->encodeJson( [
182 'x' => 'A',
183 'y' => "Foo\x80\xf0Bar",
184 'z' => 'C',
185 ] );
186 $this->assertSame( '{"x":"A","y":null,"z":"C"}', $json, 'Ignore invalid UTF-8' );
189 public function testEncodeJsonWarning() {
190 $ctx = new Context( self::getResourceLoader(), new FauxRequest( [] ) );
192 $this->expectPHPError(
193 E_USER_WARNING,
194 static function () use ( $ctx ) {
195 $ctx->encodeJson( [
196 'x' => 'A',
197 'y' => "Foo\x80\xf0Bar",
198 'z' => 'C',
199 ] );
201 'encodeJson partially failed: Malformed UTF-8'
205 public static function skinsProvider(): Generator {
206 // expected skin, supplied skin, installed skins
207 yield 'keep validated' => [
208 'example',
209 [ 'skin' => 'example' ],
210 [ 'example', 'foo', 'bar' ]
213 yield 'fallback invalid' => [
214 'fallback',
215 [ 'skin' => 'not-example' ],
216 [ 'example', 'foo', 'bar' ]
219 yield 'keep anything without validation' => [
220 'not-example',
221 [ 'skin' => 'not-example' ],
222 null
227 * @dataProvider skinsProvider
229 public function testContextWithSkinsValidation(
230 string $expectedSkin, array $suppliedSkin, ?array $installedSkins
232 $context = new Context(
233 self::getResourceLoader(), new FauxRequest( $suppliedSkin ), $installedSkins
236 $this->assertSame( $expectedSkin, $context->getSkin() );