X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=tests%2Fphpunit%2FMediaWikiUnitTestCase.php;h=fda986ccc85dae53c8982d7543ba43374e15e998;hb=c2211946f7dd4e59faf6d759e9a78bf140699c3e;hp=edd8195991ff3277a519cde92671b643152d4d54;hpb=b5fc03a7bfe46f434e332613c477e0ce9fe50e09;p=lhc%2Fweb%2Fwiklou.git diff --git a/tests/phpunit/MediaWikiUnitTestCase.php b/tests/phpunit/MediaWikiUnitTestCase.php index edd8195991..fda986ccc8 100644 --- a/tests/phpunit/MediaWikiUnitTestCase.php +++ b/tests/phpunit/MediaWikiUnitTestCase.php @@ -20,6 +20,7 @@ */ use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Exception; /** * Base class for unit tests. @@ -34,30 +35,122 @@ abstract class MediaWikiUnitTestCase extends TestCase { use MediaWikiCoversValidator; use MediaWikiTestCaseTrait; - private $unitGlobals = []; + private static $originalGlobals; + private static $unitGlobals; - protected function setUp() { - parent::setUp(); - $reflection = new ReflectionClass( $this ); + /** + * Whitelist of globals to allow in MediaWikiUnitTestCase. + * + * Please, keep this list to the bare minimum. + * + * @return string[] + */ + private static function getGlobalsWhitelist() { + return [ + // The autoloader may change between bootstrap and the first test, + // so (lazily) capture these here instead. + 'wgAutoloadClasses', + 'wgAutoloadLocalClasses', + // Need for LoggerFactory. Default is NullSpi. + 'wgMWLoggerDefaultSpi', + 'wgAutoloadAttemptLowercase' + ]; + } + + public static function setUpBeforeClass() { + parent::setUpBeforeClass(); + + $reflection = new ReflectionClass( static::class ); $dirSeparator = DIRECTORY_SEPARATOR; - if ( strpos( $reflection->getFilename(), "${dirSeparator}unit${dirSeparator}" ) === false ) { - $this->fail( 'This unit test needs to be in "tests/phpunit/unit"!' ); + if ( stripos( $reflection->getFilename(), "${dirSeparator}unit${dirSeparator}" ) === false ) { + self::fail( 'This unit test needs to be in "tests/phpunit/unit"!' ); + } + + if ( defined( 'HHVM_VERSION' ) ) { + // There are a number of issues we encountered in trying to make this + // work on HHVM. Specifically, once an MediaWikiIntegrationTestCase executes + // before us, the original globals go missing. This might have to do with + // one of the non-unit tests passing GLOBALS somewhere and causing HHVM + // to get confused somehow. + return; + } + + self::$unitGlobals =& TestSetup::$bootstrapGlobals; + + foreach ( self::getGlobalsWhitelist() as $global ) { + self::$unitGlobals[ $global ] =& $GLOBALS[ $global ]; + } + + // Would be nice if we coud simply replace $GLOBALS as a whole, + // but unsetting or re-assigning that breaks the reference of this magic + // variable. Thus we have to modify it in place. + self::$originalGlobals = []; + foreach ( $GLOBALS as $key => $_ ) { + // Stash current values + self::$originalGlobals[$key] =& $GLOBALS[$key]; + + // Remove globals not part of the snapshot (see bootstrap.php, phpunit.php). + // Support: HHVM (avoid self-ref) + if ( $key !== 'GLOBALS' && !array_key_exists( $key, self::$unitGlobals ) ) { + unset( $GLOBALS[$key] ); + } + } + // Restore values from the early snapshot + // Not by ref because tests must not be able to modify the snapshot. + foreach ( self::$unitGlobals as $key => $value ) { + $GLOBALS[ $key ] = $value; } - $this->unitGlobals = $GLOBALS; - unset( $GLOBALS ); - $GLOBALS = []; - // Add back the minimal set of globals needed for unit tests to run for core + - // extensions/skins. - foreach ( $this->unitGlobals['wgPhpUnitBootstrapGlobals'] ?? [] as $key => $value ) { - $GLOBALS[ $key ] = $this->unitGlobals[ $key ]; + } + + /** + * @inheritDoc + */ + protected function runTest() { + try { + return parent::runTest(); + } catch ( ConfigException $exception ) { + throw new Exception( + 'Config variables must be mocked, they cannot be accessed directly in tests which extend ' + . self::class, + $exception->getCode(), + $exception + ); } } protected function tearDown() { - $GLOBALS = $this->unitGlobals; + if ( !defined( 'HHVM_VERSION' ) ) { + // Quick reset between tests + foreach ( $GLOBALS as $key => $_ ) { + if ( $key !== 'GLOBALS' && !array_key_exists( $key, self::$unitGlobals ) ) { + unset( $GLOBALS[$key] ); + } + } + foreach ( self::$unitGlobals as $key => $value ) { + $GLOBALS[ $key ] = $value; + } + } + parent::tearDown(); } + public static function tearDownAfterClass() { + if ( !defined( 'HHVM_VERSION' ) ) { + // Remove globals created by the test + foreach ( $GLOBALS as $key => $_ ) { + if ( $key !== 'GLOBALS' && !array_key_exists( $key, self::$originalGlobals ) ) { + unset( $GLOBALS[$key] ); + } + } + // Restore values (including reference!) + foreach ( self::$originalGlobals as $key => &$value ) { + $GLOBALS[ $key ] =& $value; + } + } + + parent::tearDownAfterClass(); + } + /** * Create a temporary hook handler which will be reset by tearDown. * This replaces other handlers for the same hook.