wiki.techinc.nl/tests/phpunit/includes/debug/MWDebugTest.php
Daimona Eaytoy 89f583625a tests: Add replacement for assertions deprecated in PHPUnit 9.6
expectWarning() and friends have been deprecated in PHPUnit 9.6, and
removed in PHPUnit 10. Unfortunately, there is no simple replacement
because PHPUnit no longer converts them to exceptions in the first
place. In fact, Sebastian Bergmann explicitly stated that he does not
consider the use case of

> a library developer to verify a code block warns its consumer when
> certain action is performed

worth supporting.

So, add an ad-hoc replacement for all the deprecated methods. This is
quite ugly, but it's simple enough given the low number of usages.

On the bright side, this new method does not halt the test when the
warning is triggered. This seems to align with the developers'
expectation, seen in a few existing tests, that any code following the
notice will be executed.

Bug: T342110
Change-Id: I214abfed4280834840c115777ed78eb0a5570da9
2024-02-23 22:09:45 +01:00

209 lines
5.5 KiB
PHP

<?php
use MediaWiki\Context\RequestContext;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MainConfigNames;
use MediaWiki\Request\FauxRequest;
use MediaWiki\Title\TitleValue;
use Psr\Log\LoggerInterface;
/**
* @covers \MWDebug
*/
class MWDebugTest extends MediaWikiIntegrationTestCase {
protected function setUp(): void {
$this->setMwGlobals( 'wgDevelopmentWarnings', false );
parent::setUp();
/** Clear log before each test */
MWDebug::clearLog();
}
public static function setUpBeforeClass(): void {
parent::setUpBeforeClass();
MWDebug::init();
}
public static function tearDownAfterClass(): void {
MWDebug::deinit();
parent::tearDownAfterClass();
}
public function testLog() {
@MWDebug::log( 'logging a string' );
$this->assertEquals(
[ [
'msg' => 'logging a string',
'type' => 'log',
'caller' => 'MWDebugTest->testLog',
] ],
MWDebug::getLog()
);
}
public function testWarningProduction() {
$logger = $this->createMock( LoggerInterface::class );
$logger->expects( $this->once() )->method( 'info' );
$this->setLogger( 'warning', $logger );
@MWDebug::warning( 'Ohnosecond!' );
}
public function testWarningDevelopment() {
$this->setMwGlobals( 'wgDevelopmentWarnings', true );
$this->expectPHPError(
E_USER_NOTICE,
static function () {
MWDebug::warning( 'Ohnosecond!' );
},
'Ohnosecond!'
);
}
/**
* Message from the error channel are copied to the debug toolbar "Console" log.
*
* This normally happens via wfDeprecated -> MWDebug::deprecated -> trigger_error
* -> MWExceptionHandler -> LoggerFactory -> LegacyLogger -> MWDebug::debugMsg.
*
* The above test asserts up until trigger_error.
* This test asserts from LegacyLogger down.
*/
public function testMessagesFromErrorChannel() {
// Turn off to keep mw-error.log file empty in CI (and thus avoid build failure)
$this->setMwGlobals( 'wgDebugLogGroups', [] );
MWExceptionHandler::handleError( E_USER_DEPRECATED, 'Warning message' );
$this->assertEquals(
[ [
'msg' => 'PHP Deprecated: Warning message',
'type' => 'warn',
'caller' => 'MWDebugTest::testMessagesFromErrorChannel',
] ],
MWDebug::getLog()
);
}
public function testDetectDeprecatedOverride() {
$baseclassInstance = new TitleValue( NS_MAIN, 'Test' );
$this->assertFalse(
MWDebug::detectDeprecatedOverride(
$baseclassInstance,
TitleValue::class,
'getNamespace',
MW_VERSION
)
);
// create a dummy subclass that overrides a method
$subclassInstance = new class ( NS_MAIN, 'Test' ) extends TitleValue {
public function getNamespace(): int {
// never called
return -100;
}
};
$this->expectPHPError(
E_USER_DEPRECATED,
static function () use ( $subclassInstance ) {
MWDebug::detectDeprecatedOverride(
$subclassInstance,
TitleValue::class,
'getNamespace',
MW_VERSION
);
},
'@anonymous'
);
}
public function testDeprecated() {
$this->expectPHPError(
E_USER_DEPRECATED,
static function () {
MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' );
},
'wfOldFunction'
);
}
/**
* @doesNotPerformAssertions
*/
public function testDeprecatedIgnoreDuplicate() {
@MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' );
MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' );
// If we reach here, than the second one did not throw any deprecation warning.
// The first one was silenced to seed the ignore logic.
}
/**
* @doesNotPerformAssertions
*/
public function testDeprecatedIgnoreNonConsecutivesDuplicate() {
@MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' );
@MWDebug::warning( 'some warning' );
@MWDebug::log( 'we could have logged something too' );
// Another deprecation (not silenced)
MWDebug::deprecated( 'wfOldFunction', '1.0', 'component' );
}
public function testDebugMsg() {
$this->overrideConfigValue( MainConfigNames::ShowDebug, true );
// Generate a log to be sure there is at least one
$logger = LoggerFactory::getInstance( 'test-debug-channel' );
$logger->debug( 'My message', [] );
$debugLog = (string)MWDebug::getHTMLDebugLog();
$this->assertNotSame( '', $debugLog, 'MWDebug::getHTMLDebugLog() should not be an empty string' );
$this->assertStringNotContainsString( "<ul id=\"mw-debug-html\">\n</ul>", $debugLog,
'MWDebug::getHTMLDebugLog() should contain a non-empty debug log'
);
}
public function testAppendDebugInfoToApiResultXmlFormat() {
$request = $this->newApiRequest(
[ 'action' => 'help', 'format' => 'xml' ],
'/api.php?action=help&format=xml'
);
$context = new RequestContext();
$context->setRequest( $request );
$result = new ApiResult( false );
MWDebug::appendDebugInfoToApiResult( $context, $result );
$this->assertInstanceOf( ApiResult::class, $result );
$data = $result->getResultData();
$expectedKeys = [ 'mwVersion', 'phpEngine', 'phpVersion', 'gitRevision', 'gitBranch',
'gitViewUrl', 'time', 'log', 'debugLog', 'queries', 'request', 'memory',
'memoryPeak', 'includes', '_element' ];
foreach ( $expectedKeys as $expectedKey ) {
$this->assertArrayHasKey( $expectedKey, $data['debuginfo'], "debuginfo has $expectedKey" );
}
$xml = ApiFormatXml::recXmlPrint( 'help', $data, null );
// exception not thrown
$this->assertIsString( $xml );
}
/**
* @param string[] $params
* @param string $requestUrl
* @return FauxRequest
*/
private function newApiRequest( array $params, $requestUrl ) {
$req = new FauxRequest( $params );
$req->setRequestURL( $requestUrl );
return $req;
}
}