<?php

use MediaWiki\Context\RequestContext;
use MediaWiki\Language\Language;
use MediaWiki\Permissions\Authority;
use MediaWiki\Request\WebRequest;
use MediaWiki\SpecialPage\SpecialPage;

/**
 * Base class for testing special pages. Re-used in extension test suites.
 *
 * @since 1.26
 *
 * @license GPL-2.0-or-later
 * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 * @author Daniel Kinzler
 * @author Addshore
 * @author Thiemo Kreuz
 */
abstract class SpecialPageTestBase extends MediaWikiIntegrationTestCase {

	/** @var int */
	private $obLevel;

	protected function setUp(): void {
		parent::setUp();

		$this->obLevel = ob_get_level();
	}

	protected function assertPostConditions(): void {
		$obLevel = ob_get_level();
		if ( $obLevel !== $this->obLevel ) {
			$this->fail(
				"Test changed output buffer level: was {$this->obLevel} before test, but $obLevel after test."
			);
		}
		parent::assertPostConditions();
	}

	protected function tearDown(): void {
		while ( ob_get_level() > $this->obLevel ) {
			ob_end_clean();
		}
		parent::tearDown();
	}

	/**
	 * Returns a new instance of the special page under test.
	 *
	 * @return SpecialPage
	 */
	abstract protected function newSpecialPage();

	/**
	 * @param string|null $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;
	 *  defaults to "qqx"
	 * @param Authority|null $performer The user which should be used in the context of this special page
	 * @param bool $fullHtml if true, the entirety of the generated HTML will be returned, this
	 * includes the opening <!DOCTYPE> declaration and closing </html> tag. If false, only value
	 * of OutputPage::getHTML() will be returned except if the page is redirect or where OutputPage
	 * is completely disabled.
	 * @param RequestContext|null $context Context to set on the special page. This allows setting the
	 * main request context, useful if any of the code being tested uses the main request context
	 * directly. If this is set, $request, $language and $performer are ignored, and instead should be
	 * set on the $context being passed in.
	 *
	 * @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,
		?Authority $performer = null,
		$fullHtml = false,
		?RequestContext $context = null
	) {
		return ( new SpecialPageExecutor() )->executeSpecialPage(
			$this->newSpecialPage(),
			$subPage,
			$request,
			$language ?: 'qqx',
			$performer,
			$fullHtml,
			$context
		);
	}

}
