From a737b613655c08dc341d3eb887d4dc20bd3f234d Mon Sep 17 00:00:00 2001 From: addshore Date: Sat, 9 Aug 2014 01:37:44 +0100 Subject: [PATCH] Add SpecialPageTestBase to simplify testing of special pages This is copied from Wikibase. A follow up change adds a test for Special:BlankPage to demonstrate how it works. Change-Id: I3c34fd17ceb0049b160ec4f821474de457533983 --- tests/TestsAutoLoader.php | 3 + .../includes/specials/SpecialPageTestBase.php | 165 ++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 tests/phpunit/includes/specials/SpecialPageTestBase.php diff --git a/tests/TestsAutoLoader.php b/tests/TestsAutoLoader.php index c3019c9fb0..8a81a64447 100644 --- a/tests/TestsAutoLoader.php +++ b/tests/TestsAutoLoader.php @@ -94,6 +94,9 @@ $wgAutoloadClasses += array( 'ResourceLoaderImageModuleTest' => "$testDir/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php", 'ResourceLoaderImageModuleTestable' => "$testDir/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php", + # tests/phpunit/includes/specials + 'SpecialPageTestBase' => "$testDir/phpunit/includes/specials/SpecialPageTestBase.php", + # tests/phpunit/languages 'LanguageClassesTestCase' => "$testDir/phpunit/languages/LanguageClassesTestCase.php", diff --git a/tests/phpunit/includes/specials/SpecialPageTestBase.php b/tests/phpunit/includes/specials/SpecialPageTestBase.php new file mode 100644 index 0000000000..9c7b0f0087 --- /dev/null +++ b/tests/phpunit/includes/specials/SpecialPageTestBase.php @@ -0,0 +1,165 @@ + + * @author Daniel Kinzler + * @author Adam Shorland + * @author Thiemo Mättig + */ +abstract class SpecialPageTestBase extends MediaWikiTestCase { + + private $obLevel; + + protected function setUp() { + parent::setUp(); + + $this->obLevel = ob_get_level(); + } + + protected function tearDown() { + $obLevel = ob_get_level(); + + while ( ob_get_level() > $this->obLevel ) { + ob_end_clean(); + } + + if ( $obLevel !== $this->obLevel ) { + $this->fail( + "Test changed output buffer level: was {$this->obLevel} before test, but $obLevel after test." + ); + } + + parent::tearDown(); + } + + /** + * Returns a new instance of the special page under test. + * + * @return SpecialPage + */ + abstract protected function newSpecialPage(); + + /** + * @param string $subPage The subpage parameter to call the page with + * @param WebRequest|null $request Web request that may contain URL parameters, etc + * @param Language|string|null $language The language which should be used in the context + * @param User|null $user The user which should be used in the context of this special page + * + * @throws Exception + * @return array( string, WebResponse ) A two-elements array containing the HTML output + * generated by the special page as well as the response object. + */ + protected function executeSpecialPage( + $subPage = '', + WebRequest $request = null, + $language = null, + User $user = null + ) { + $context = $this->newContext( $request, $language, $user ); + + $output = new OutputPage( $context ); + $context->setOutput( $output ); + + $page = $this->newSpecialPage(); + $page->setContext( $context ); + $output->setTitle( $page->getPageTitle() ); + + $html = $this->getHTMLFromSpecialPage( $page, $subPage ); + $response = $context->getRequest()->response(); + + if ( $response instanceof FauxResponse ) { + $code = $response->getStatusCode(); + + if ( $code > 0 ) { + $response->header( 'Status: ' . $code . ' ' . HttpStatus::getMessage( $code ) ); + } + } + + return array( $html, $response ); + } + + /** + * @param WebRequest|null $request + * @param Language|string|null $language + * @param User|null $user + * + * @return DerivativeContext + */ + private function newContext( + WebRequest $request = null, + $language = null, + User $user = null + ) { + $context = new DerivativeContext( RequestContext::getMain() ); + + $context->setRequest( $request ?: new FauxRequest() ); + + if ( $language !== null ) { + $context->setLanguage( $language ); + } + + if ( $user !== null ) { + $context->setUser( $user ); + } + + $this->setEditTokenFromUser( $context ); + + return $context; + } + + /** + * If we are trying to edit and no token is set, supply one. + * + * @param DerivativeContext $context + */ + private function setEditTokenFromUser( DerivativeContext $context ) { + $request = $context->getRequest(); + + // Edits via GET are a security issue and should not succeed. On the other hand, not all + // POST requests are edits, but should ignore unused parameters. + if ( !$request->getCheck( 'wpEditToken' ) && $request->wasPosted() ) { + $request->setVal( 'wpEditToken', $context->getUser()->getEditToken() ); + } + } + + /** + * @param SpecialPage $page + * @param string $subPage + * + * @throws Exception + * @return string HTML + */ + private function getHTMLFromSpecialPage( SpecialPage $page, $subPage ) { + ob_start(); + + try { + $page->execute( $subPage ); + + $output = $page->getOutput(); + + if ( $output->getRedirect() !== '' ) { + $output->output(); + $html = ob_get_contents(); + } elseif ( $output->isDisabled() ) { + $html = ob_get_contents(); + } else { + $html = $output->getHTML(); + } + } catch ( Exception $ex ) { + ob_end_clean(); + + // Re-throw exception after "finally" handling because PHP 5.3 doesn't have "finally". + throw $ex; + } + + ob_end_clean(); + + return $html; + } + +} -- 2.20.1