assertSame( $expectedFoo, $foo, $msg ); $this->assertSame( $expectedBar, $bar, $msg ); } /** * @dataProvider provideHooks * @covers Hooks::register * @covers Hooks::run */ public function testNewStyleHooks( $msg, $hook, $expectedFoo, $expectedBar ) { $foo = $bar = 'original'; Hooks::register( 'MediaWikiHooksTest001', $hook ); Hooks::run( 'MediaWikiHooksTest001', [ &$foo, &$bar ] ); $this->assertSame( $expectedFoo, $foo, $msg ); $this->assertSame( $expectedBar, $bar, $msg ); } /** * @covers Hooks::isRegistered * @covers Hooks::register * @covers Hooks::getHandlers * @covers Hooks::run */ public function testNewStyleHookInteraction() { global $wgHooks; $a = new NothingClass(); $b = new NothingClass(); $wgHooks['MediaWikiHooksTest001'][] = $a; $this->assertTrue( Hooks::isRegistered( 'MediaWikiHooksTest001' ), 'Hook registered via $wgHooks should be noticed by Hooks::isRegistered' ); Hooks::register( 'MediaWikiHooksTest001', $b ); $this->assertEquals( 2, count( Hooks::getHandlers( 'MediaWikiHooksTest001' ) ), 'Hooks::getHandlers() should return hooks registered via wgHooks as well as Hooks::register' ); $foo = 'quux'; $bar = 'qaax'; Hooks::run( 'MediaWikiHooksTest001', [ &$foo, &$bar ] ); $this->assertEquals( 1, $a->calls, 'Hooks::run() should run hooks registered via wgHooks as well as Hooks::register' ); $this->assertEquals( 1, $b->calls, 'Hooks::run() should run hooks registered via wgHooks as well as Hooks::register' ); } /** * @expectedException MWException * @covers Hooks::run */ public function testUncallableFunction() { Hooks::register( 'MediaWikiHooksTest001', 'ThisFunctionDoesntExist' ); Hooks::run( 'MediaWikiHooksTest001', [] ); } /** * @covers Hooks::run */ public function testFalseReturn() { Hooks::register( 'MediaWikiHooksTest001', function ( &$foo ) { return false; } ); Hooks::register( 'MediaWikiHooksTest001', function ( &$foo ) { $foo = 'test'; return true; } ); $foo = 'original'; Hooks::run( 'MediaWikiHooksTest001', [ &$foo ] ); $this->assertSame( 'original', $foo, 'Hooks abort after a false return.' ); } /** * @covers Hooks::runWithoutAbort */ public function testRunWithoutAbort() { $list = []; Hooks::register( 'MediaWikiHooksTest001', function ( &$list ) { $list[] = 1; return true; // Explicit true } ); Hooks::register( 'MediaWikiHooksTest001', function ( &$list ) { $list[] = 2; return; // Implicit null } ); Hooks::register( 'MediaWikiHooksTest001', function ( &$list ) { $list[] = 3; // No return } ); Hooks::runWithoutAbort( 'MediaWikiHooksTest001', [ &$list ] ); $this->assertSame( [ 1, 2, 3 ], $list, 'All hooks ran.' ); } /** * @covers Hooks::runWithoutAbort */ public function testRunWithoutAbortWarning() { Hooks::register( 'MediaWikiHooksTest001', function ( &$foo ) { return false; } ); Hooks::register( 'MediaWikiHooksTest001', function ( &$foo ) { $foo = 'test'; return true; } ); $foo = 'original'; $this->setExpectedException( UnexpectedValueException::class, 'Invalid return from hook-MediaWikiHooksTest001-closure for ' . 'unabortable MediaWikiHooksTest001' ); Hooks::runWithoutAbort( 'MediaWikiHooksTest001', [ &$foo ] ); } /** * @expectedException FatalError * @covers Hooks::run */ public function testFatalError() { Hooks::register( 'MediaWikiHooksTest001', function () { return 'test'; } ); Hooks::run( 'MediaWikiHooksTest001', [] ); } } function NothingFunction( &$foo, &$bar ) { $foo = 'changed-func'; return true; } function NothingFunctionData( $data, &$foo, &$bar ) { $foo = $data; return true; } class NothingClass { public $calls = 0; public static function someStatic( &$foo, &$bar ) { $foo = 'changed-static'; return true; } public function someNonStatic( &$foo, &$bar ) { $this->calls++; $foo = 'changed-nonstatic'; $bar = 'changed-nonstatic'; return true; } public function onMediaWikiHooksTest001( &$foo, &$bar ) { $this->calls++; $foo = 'changed-onevent'; return true; } public function someNonStaticWithData( $data, &$foo, &$bar ) { $this->calls++; $foo = $data; return true; } }