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; } } /** * @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() { 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. * @param string $hookName Hook name * @param mixed $handler Value suitable for a hook handler * @since 1.34 */ protected function setTemporaryHook( $hookName, $handler ) { // This will be reset by tearDown() when it restores globals. We don't want to use // Hooks::register()/clear() because they won't replace other handlers for the same hook, // which doesn't match behavior of MediaWikiIntegrationTestCase. global $wgHooks; $wgHooks[$hookName] = [ $handler ]; } protected function getMockMessage( $text, ...$params ) { if ( isset( $params[0] ) && is_array( $params[0] ) ) { $params = $params[0]; } $msg = $this->getMockBuilder( Message::class ) ->disableOriginalConstructor() ->setMethods( [] ) ->getMock(); $msg->method( 'toString' )->willReturn( $text ); $msg->method( '__toString' )->willReturn( $text ); $msg->method( 'text' )->willReturn( $text ); $msg->method( 'parse' )->willReturn( $text ); $msg->method( 'plain' )->willReturn( $text ); $msg->method( 'parseAsBlock' )->willReturn( $text ); $msg->method( 'escaped' )->willReturn( $text ); $msg->method( 'title' )->willReturn( $msg ); $msg->method( 'inLanguage' )->willReturn( $msg ); $msg->method( 'inContentLanguage' )->willReturn( $msg ); $msg->method( 'useDatabase' )->willReturn( $msg ); $msg->method( 'setContext' )->willReturn( $msg ); $msg->method( 'exists' )->willReturn( true ); $msg->method( 'content' )->willReturn( new MessageContent( $msg ) ); return $msg; } }