Merge "Add 'mw-anonuserlink' class for anonymous users"
[lhc/web/wiklou.git] / tests / phpunit / structure / ResourcesTest.php
1 <?php
2 /**
3 * Sanity checks for making sure registered resources are sane.
4 *
5 * @file
6 * @author Antoine Musso
7 * @author Niklas Laxström
8 * @author Santhosh Thottingal
9 * @author Timo Tijhof
10 * @copyright © 2012, Antoine Musso
11 * @copyright © 2012, Niklas Laxström
12 * @copyright © 2012, Santhosh Thottingal
13 * @copyright © 2012, Timo Tijhof
14 *
15 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
16 */
17 class ResourcesTest extends MediaWikiTestCase {
18
19 /**
20 * @dataProvider provideResourceFiles
21 */
22 public function testFileExistence( $filename, $module, $resource ) {
23 $this->assertFileExists( $filename,
24 "File '$resource' referenced by '$module' must exist."
25 );
26 }
27
28 /**
29 * @dataProvider provideMediaStylesheets
30 */
31 public function testStyleMedia( $moduleName, $media, $filename, $css ) {
32 $cssText = CSSMin::minify( $css->cssText );
33
34 $this->assertTrue( strpos( $cssText, '@media' ) === false, 'Stylesheets should not both specify "media" and contain @media' );
35 }
36
37 public function testDependencies() {
38 $data = self::getAllModules();
39 $illegalDeps = array( 'jquery', 'mediawiki' );
40
41 foreach ( $data['modules'] as $moduleName => $module ) {
42 foreach ( $illegalDeps as $illegalDep ) {
43 $this->assertNotContains(
44 $illegalDep,
45 $module->getDependencies(),
46 "Module '$moduleName' must not depend on '$illegalDep'"
47 );
48 }
49 }
50 }
51
52 /**
53 * Get all registered modules from ResouceLoader.
54 */
55 protected static function getAllModules() {
56 global $wgEnableJavaScriptTest;
57
58 // Test existance of test suite files as well
59 // (can't use setUp or setMwGlobals because providers are static)
60 $org_wgEnableJavaScriptTest = $wgEnableJavaScriptTest;
61 $wgEnableJavaScriptTest = true;
62
63 // Initialize ResourceLoader
64 $rl = new ResourceLoader();
65
66 $modules = array();
67
68 foreach ( $rl->getModuleNames() as $moduleName ) {
69 $modules[$moduleName] = $rl->getModule( $moduleName );
70 }
71
72 // Restore settings
73 $wgEnableJavaScriptTest = $org_wgEnableJavaScriptTest;
74
75 return array(
76 'modules' => $modules,
77 'resourceloader' => $rl,
78 'context' => new ResourceLoaderContext( $rl, new FauxRequest() )
79 );
80 }
81
82 /**
83 * Get all stylesheet files from modules that are an instance of
84 * ResourceLoaderFileModule (or one of its subclasses).
85 */
86 public static function provideMediaStylesheets() {
87 $data = self::getAllModules();
88 $cases = array();
89
90 foreach ( $data['modules'] as $moduleName => $module ) {
91 if ( !$module instanceof ResourceLoaderFileModule ) {
92 continue;
93 }
94
95 $reflectedModule = new ReflectionObject( $module );
96
97 $getStyleFiles = $reflectedModule->getMethod( 'getStyleFiles' );
98 $getStyleFiles->setAccessible( true );
99
100 $readStyleFile = $reflectedModule->getMethod( 'readStyleFile' );
101 $readStyleFile->setAccessible( true );
102
103 $styleFiles = $getStyleFiles->invoke( $module, $data['context'] );
104
105 $flip = $module->getFlip( $data['context'] );
106
107 foreach ( $styleFiles as $media => $files ) {
108 if ( $media && $media !== 'all' ) {
109 foreach ( $files as $file ) {
110 $cases[] = array(
111 $moduleName,
112 $media,
113 $file,
114 // XXX: Wrapped in an object to keep it out of PHPUnit output
115 (object) array( 'cssText' => $readStyleFile->invoke( $module, $file, $flip ) ),
116 );
117 }
118 }
119 }
120 }
121
122 return $cases;
123 }
124
125 /**
126 * Get all resource files from modules that are an instance of
127 * ResourceLoaderFileModule (or one of its subclasses).
128 *
129 * Since the raw data is stored in protected properties, we have to
130 * overrride this through ReflectionObject methods.
131 */
132 public static function provideResourceFiles() {
133 $data = self::getAllModules();
134 $cases = array();
135
136 // See also ResourceLoaderFileModule::__construct
137 $filePathProps = array(
138 // Lists of file paths
139 'lists' => array(
140 'scripts',
141 'debugScripts',
142 'loaderScripts',
143 'styles',
144 ),
145
146 // Collated lists of file paths
147 'nested-lists' => array(
148 'languageScripts',
149 'skinScripts',
150 'skinStyles',
151 ),
152 );
153
154 foreach ( $data['modules'] as $moduleName => $module ) {
155 if ( !$module instanceof ResourceLoaderFileModule ) {
156 continue;
157 }
158
159 $reflectedModule = new ReflectionObject( $module );
160
161 $files = array();
162
163 foreach ( $filePathProps['lists'] as $propName ) {
164 $property = $reflectedModule->getProperty( $propName );
165 $property->setAccessible( true );
166 $list = $property->getValue( $module );
167 foreach ( $list as $key => $value ) {
168 // 'scripts' are numeral arrays.
169 // 'styles' can be numeral or associative.
170 // In case of associative the key is the file path
171 // and the value is the 'media' attribute.
172 if ( is_int( $key ) ) {
173 $files[] = $value;
174 } else {
175 $files[] = $key;
176 }
177 }
178 }
179
180 foreach ( $filePathProps['nested-lists'] as $propName ) {
181 $property = $reflectedModule->getProperty( $propName );
182 $property->setAccessible( true );
183 $lists = $property->getValue( $module );
184 foreach ( $lists as $list ) {
185 foreach ( $list as $key => $value ) {
186 // We need the same filter as for 'lists',
187 // due to 'skinStyles'.
188 if ( is_int( $key ) ) {
189 $files[] = $value;
190 } else {
191 $files[] = $key;
192 }
193 }
194 }
195 }
196
197 // Get method for resolving the paths to full paths
198 $method = $reflectedModule->getMethod( 'getLocalPath' );
199 $method->setAccessible( true );
200
201 // Populate cases
202 foreach ( $files as $file ) {
203 $cases[] = array(
204 $method->invoke( $module, $file ),
205 $moduleName,
206 $file,
207 );
208 }
209 }
210
211 return $cases;
212 }
213 }