summaryrefslogtreecommitdiff
path: root/tests/phpunit/includes/specials/SpecialPageTestBase.php
blob: 9c7b0f0087ab455234f3f6abefcd7dba0dc2f501 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
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;
	}

}