ResourcesTest.php 5.5 KB

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