Merge "Make a hidden form field to keep the language code"
[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(
35 strpos( $cssText, '@media' ) === false,
36 'Stylesheets should not both specify "media" and contain @media'
37 );
38 }
39
40 public function testDependencies() {
41 $data = self::getAllModules();
42 $illegalDeps = array( 'jquery', 'mediawiki' );
43
44 foreach ( $data['modules'] as $moduleName => $module ) {
45 foreach ( $illegalDeps as $illegalDep ) {
46 $this->assertNotContains(
47 $illegalDep,
48 $module->getDependencies(),
49 "Module '$moduleName' must not depend on '$illegalDep'"
50 );
51 }
52 }
53 }
54
55 /**
56 * Get all registered modules from ResouceLoader.
57 */
58 protected static function getAllModules() {
59 global $wgEnableJavaScriptTest;
60
61 // Test existance of test suite files as well
62 // (can't use setUp or setMwGlobals because providers are static)
63 $org_wgEnableJavaScriptTest = $wgEnableJavaScriptTest;
64 $wgEnableJavaScriptTest = true;
65
66 // Initialize ResourceLoader
67 $rl = new ResourceLoader();
68
69 $modules = array();
70
71 foreach ( $rl->getModuleNames() as $moduleName ) {
72 $modules[$moduleName] = $rl->getModule( $moduleName );
73 }
74
75 // Restore settings
76 $wgEnableJavaScriptTest = $org_wgEnableJavaScriptTest;
77
78 return array(
79 'modules' => $modules,
80 'resourceloader' => $rl,
81 'context' => new ResourceLoaderContext( $rl, new FauxRequest() )
82 );
83 }
84
85 /**
86 * Get all stylesheet files from modules that are an instance of
87 * ResourceLoaderFileModule (or one of its subclasses).
88 */
89 public static function provideMediaStylesheets() {
90 $data = self::getAllModules();
91 $cases = array();
92
93 foreach ( $data['modules'] as $moduleName => $module ) {
94 if ( !$module instanceof ResourceLoaderFileModule ) {
95 continue;
96 }
97
98 $reflectedModule = new ReflectionObject( $module );
99
100 $getStyleFiles = $reflectedModule->getMethod( 'getStyleFiles' );
101 $getStyleFiles->setAccessible( true );
102
103 $readStyleFile = $reflectedModule->getMethod( 'readStyleFile' );
104 $readStyleFile->setAccessible( true );
105
106 $styleFiles = $getStyleFiles->invoke( $module, $data['context'] );
107
108 $flip = $module->getFlip( $data['context'] );
109
110 foreach ( $styleFiles as $media => $files ) {
111 if ( $media && $media !== 'all' ) {
112 foreach ( $files as $file ) {
113 $cases[] = array(
114 $moduleName,
115 $media,
116 $file,
117 // XXX: Wrapped in an object to keep it out of PHPUnit output
118 (object)array( 'cssText' => $readStyleFile->invoke( $module, $file, $flip ) ),
119 );
120 }
121 }
122 }
123 }
124
125 return $cases;
126 }
127
128 /**
129 * Get all resource files from modules that are an instance of
130 * ResourceLoaderFileModule (or one of its subclasses).
131 *
132 * Since the raw data is stored in protected properties, we have to
133 * overrride this through ReflectionObject methods.
134 */
135 public static function provideResourceFiles() {
136 $data = self::getAllModules();
137 $cases = array();
138
139 // See also ResourceLoaderFileModule::__construct
140 $filePathProps = array(
141 // Lists of file paths
142 'lists' => array(
143 'scripts',
144 'debugScripts',
145 'loaderScripts',
146 'styles',
147 ),
148
149 // Collated lists of file paths
150 'nested-lists' => array(
151 'languageScripts',
152 'skinScripts',
153 'skinStyles',
154 ),
155 );
156
157 foreach ( $data['modules'] as $moduleName => $module ) {
158 if ( !$module instanceof ResourceLoaderFileModule ) {
159 continue;
160 }
161
162 $reflectedModule = new ReflectionObject( $module );
163
164 $files = array();
165
166 foreach ( $filePathProps['lists'] as $propName ) {
167 $property = $reflectedModule->getProperty( $propName );
168 $property->setAccessible( true );
169 $list = $property->getValue( $module );
170 foreach ( $list as $key => $value ) {
171 // 'scripts' are numeral arrays.
172 // 'styles' can be numeral or associative.
173 // In case of associative the key is the file path
174 // and the value is the 'media' attribute.
175 if ( is_int( $key ) ) {
176 $files[] = $value;
177 } else {
178 $files[] = $key;
179 }
180 }
181 }
182
183 foreach ( $filePathProps['nested-lists'] as $propName ) {
184 $property = $reflectedModule->getProperty( $propName );
185 $property->setAccessible( true );
186 $lists = $property->getValue( $module );
187 foreach ( $lists as $list ) {
188 foreach ( $list as $key => $value ) {
189 // We need the same filter as for 'lists',
190 // due to 'skinStyles'.
191 if ( is_int( $key ) ) {
192 $files[] = $value;
193 } else {
194 $files[] = $key;
195 }
196 }
197 }
198 }
199
200 // Get method for resolving the paths to full paths
201 $method = $reflectedModule->getMethod( 'getLocalPath' );
202 $method->setAccessible( true );
203
204 // Populate cases
205 foreach ( $files as $file ) {
206 $cases[] = array(
207 $method->invoke( $module, $file ),
208 $moduleName,
209 $file,
210 );
211 }
212 }
213
214 return $cases;
215 }
216 }