diff options
Diffstat (limited to 'tests/phpunit/includes/specials')
4 files changed, 297 insertions, 2 deletions
diff --git a/tests/phpunit/includes/specials/SpecialBlankPageTest.php b/tests/phpunit/includes/specials/SpecialBlankPageTest.php new file mode 100644 index 00000000..1d4f5e51 --- /dev/null +++ b/tests/phpunit/includes/specials/SpecialBlankPageTest.php @@ -0,0 +1,25 @@ +<?php + +/** + * @licence GNU GPL v2+ + * @author Adam Shorland + * + * @covers SpecialBlankpage + */ +class SpecialBlankPageTest extends SpecialPageTestBase { + + /** + * Returns a new instance of the special page under test. + * + * @return SpecialPage + */ + protected function newSpecialPage() { + return new SpecialBlankpage(); + } + + public function testHasWikiMsg() { + list( $html, ) = $this->executeSpecialPage(); + $this->assertContains( wfMessage( 'intentionallyblankpage' )->text(), $html ); + } + +} diff --git a/tests/phpunit/includes/specials/SpecialPageTestBase.php b/tests/phpunit/includes/specials/SpecialPageTestBase.php new file mode 100644 index 00000000..9c7b0f00 --- /dev/null +++ b/tests/phpunit/includes/specials/SpecialPageTestBase.php @@ -0,0 +1,165 @@ +<?php + +/** + * Base class for testing special pages. + * + * @since 1.26 + * + * @licence GNU GPL v2+ + * @author Jeroen De Dauw < jeroendedauw@gmail.com > + * @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; + } + +} diff --git a/tests/phpunit/includes/specials/SpecialPreferencesTest.php b/tests/phpunit/includes/specials/SpecialPreferencesTest.php index 4f6c4116..1545d7ec 100644 --- a/tests/phpunit/includes/specials/SpecialPreferencesTest.php +++ b/tests/phpunit/includes/specials/SpecialPreferencesTest.php @@ -4,10 +4,11 @@ * * Copyright © 2013, Antoine Musso * Copyright © 2013, Wikimedia Foundation Inc. - * */ /** + * @group Database + * * @covers SpecialPreferences */ class SpecialPreferencesTest extends MediaWikiTestCase { diff --git a/tests/phpunit/includes/specials/SpecialSearchTest.php b/tests/phpunit/includes/specials/SpecialSearchTest.php index 83489c65..13c28381 100644 --- a/tests/phpunit/includes/specials/SpecialSearchTest.php +++ b/tests/phpunit/includes/specials/SpecialSearchTest.php @@ -136,9 +136,113 @@ class SpecialSearchTest extends MediaWikiTestCase { # Compare :-] $this->assertRegExp( - '/' . preg_quote( $term ) . '/', + '/' . preg_quote( $term, '/' ) . '/', $pageTitle, "Search term '{$term}' should not be expanded in Special:Search <title>" ); } + + public function provideRewriteQueryWithSuggestion() { + return array( + array( + 'With suggestion and no rewritten query shows did you mean', + '/Did you mean: <a[^>]+>first suggestion/', + new SpecialSearchTestMockResultSet( 'first suggestion', null, array( + SearchResult::newFromTitle( Title::newMainPage() ), + ) ), + ), + + array( + 'With rewritten query informs user of change', + '/Showing results for <a[^>]+>first suggestion/', + new SpecialSearchTestMockResultSet( 'asdf', 'first suggestion', array( + SearchResult::newFromTitle( Title::newMainPage() ), + ) ), + ), + + array( + 'When both queries have no results user gets no results', + '/There were no results matching the query/', + new SpecialSearchTestMockResultSet( 'first suggestion', 'first suggestion', array() ), + ), + ); + } + + /** + * @dataProvider provideRewriteQueryWithSuggestion + */ + public function testRewriteQueryWithSuggestion( $message, $expectRegex, $results ) { + $mockSearchEngine = $this->mockSearchEngine( $results ); + $search = $this->getMockBuilder( 'SpecialSearch' ) + ->setMethods( array( 'getSearchEngine' ) ) + ->getMock(); + $search->expects( $this->any() ) + ->method( 'getSearchEngine' ) + ->will( $this->returnValue( $mockSearchEngine ) ); + + $search->getContext()->setTitle( Title::makeTitle( NS_SPECIAL, 'Search' ) ); + $search->load(); + $search->showResults( 'this is a fake search' ); + + $html = $search->getContext()->getOutput()->getHTML(); + foreach ( (array)$expectRegex as $regex ) { + $this->assertRegExp( $regex, $html, $message ); + } + } + + protected function mockSearchEngine( $results ) { + $mock = $this->getMockBuilder( 'SearchEngine' ) + ->setMethods( array( 'searchText', 'searchTitle' ) ) + ->getMock(); + + $mock->expects( $this->any() ) + ->method( 'searchText' ) + ->will( $this->returnValue( $results ) ); + + return $mock; + } +} + +class SpecialSearchTestMockResultSet extends SearchResultSet { + protected $results; + protected $suggestion; + + public function __construct( $suggestion = null, $rewrittenQuery = null, array $results = array(), $containedSyntax = false) { + $this->suggestion = $suggestion; + $this->rewrittenQuery = $rewrittenQuery; + $this->results = $results; + $this->containedSyntax = $containedSyntax; + } + + public function numRows() { + return count( $this->results ); + } + + public function getTotalHits() { + return $this->numRows(); + } + + public function hasSuggestion() { + return $this->suggestion !== null; + } + + public function getSuggestionQuery() { + return $this->suggestion; + } + + public function getSuggestionSnippet() { + return $this->suggestion; + } + + public function hasRewrittenQuery() { + return $this->rewrittenQuery !== null; + } + + public function getQueryAfterRewrite() { + return $this->rewrittenQuery; + } + + public function getQueryAfterRewriteSnippet() { + return htmlspecialchars( $this->rewrittenQuery ); + } } |