summaryrefslogtreecommitdiff
path: root/tests/phpunit/includes/exception
diff options
context:
space:
mode:
Diffstat (limited to 'tests/phpunit/includes/exception')
-rw-r--r--tests/phpunit/includes/exception/BadTitleErrorTest.php43
-rw-r--r--tests/phpunit/includes/exception/ErrorPageErrorTest.php67
-rw-r--r--tests/phpunit/includes/exception/MWExceptionHandlerTest.php74
-rw-r--r--tests/phpunit/includes/exception/MWExceptionTest.php241
-rw-r--r--tests/phpunit/includes/exception/ReadOnlyErrorTest.php16
-rw-r--r--tests/phpunit/includes/exception/ThrottledErrorTest.php44
-rw-r--r--tests/phpunit/includes/exception/UserNotLoggedInTest.php16
7 files changed, 501 insertions, 0 deletions
diff --git a/tests/phpunit/includes/exception/BadTitleErrorTest.php b/tests/phpunit/includes/exception/BadTitleErrorTest.php
new file mode 100644
index 00000000..003efd27
--- /dev/null
+++ b/tests/phpunit/includes/exception/BadTitleErrorTest.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @covers BadTitleError
+ * @author Adam Shorland
+ */
+class BadTitleErrorTest extends MediaWikiTestCase {
+
+ protected $wgOut;
+
+ protected function setUp() {
+ parent::setUp();
+ global $wgOut;
+ $this->wgOut = clone $wgOut;
+ }
+
+ protected function tearDown() {
+ parent::tearDown();
+ global $wgOut;
+ $wgOut = $this->wgOut;
+ }
+
+ public function testExceptionSetsStatusCode() {
+ global $wgOut;
+ $wgOut = $this->getMockWgOut();
+ try {
+ throw new BadTitleError();
+ } catch ( BadTitleError $e ) {
+ $e->report();
+ $this->assertTrue( true );
+ }
+ }
+
+ private function getMockWgOut() {
+ $mock = $this->getMockBuilder( 'OutputPage' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mock->expects( $this->once() )
+ ->method( 'setStatusCode' )
+ ->with( 400 );
+ return $mock;
+ }
+
+}
diff --git a/tests/phpunit/includes/exception/ErrorPageErrorTest.php b/tests/phpunit/includes/exception/ErrorPageErrorTest.php
new file mode 100644
index 00000000..13dcf33b
--- /dev/null
+++ b/tests/phpunit/includes/exception/ErrorPageErrorTest.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @covers ErrorPageError
+ * @author Adam Shorland
+ */
+class ErrorPageErrorTest extends MediaWikiTestCase {
+
+ private $wgOut;
+
+ protected function setUp() {
+ parent::setUp();
+ global $wgOut;
+ $this->wgOut = clone $wgOut;
+ }
+
+ protected function tearDown() {
+ global $wgOut;
+ $wgOut = $this->wgOut;
+ parent::tearDown();
+ }
+
+ private function getMockMessage() {
+ $mockMessage = $this->getMockBuilder( 'Message' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mockMessage->expects( $this->once() )
+ ->method( 'inLanguage' )
+ ->will( $this->returnValue( $mockMessage ) );
+ $mockMessage->expects( $this->once() )
+ ->method( 'useDatabase' )
+ ->will( $this->returnValue( $mockMessage ) );
+ return $mockMessage;
+ }
+
+ public function testConstruction() {
+ $mockMessage = $this->getMockMessage();
+ $title = 'Foo';
+ $params = array( 'Baz' );
+ $e = new ErrorPageError( $title, $mockMessage, $params );
+ $this->assertEquals( $title, $e->title );
+ $this->assertEquals( $mockMessage, $e->msg );
+ $this->assertEquals( $params, $e->params );
+ }
+
+ public function testReport() {
+ $mockMessage = $this->getMockMessage();
+ $title = 'Foo';
+ $params = array( 'Baz' );
+
+ global $wgOut;
+ $wgOut = $this->getMockBuilder( 'OutputPage' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $wgOut->expects( $this->once() )
+ ->method( 'showErrorPage' )
+ ->with( $title, $mockMessage, $params );
+ $wgOut->expects( $this->once() )
+ ->method( 'output' );
+
+ $e = new ErrorPageError( $title, $mockMessage, $params );
+ $e->report();
+ }
+
+
+
+}
diff --git a/tests/phpunit/includes/exception/MWExceptionHandlerTest.php b/tests/phpunit/includes/exception/MWExceptionHandlerTest.php
new file mode 100644
index 00000000..dc5dc6aa
--- /dev/null
+++ b/tests/phpunit/includes/exception/MWExceptionHandlerTest.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * @author Antoine Musso
+ * @copyright Copyright © 2013, Antoine Musso
+ * @copyright Copyright © 2013, Wikimedia Foundation Inc.
+ * @file
+ */
+
+class MWExceptionHandlerTest extends MediaWikiTestCase {
+
+ /**
+ * @covers MWExceptionHandler::getRedactedTrace
+ */
+ public function testGetRedactedTrace() {
+ $refvar = 'value';
+ try {
+ $array = array( 'a', 'b' );
+ $object = new StdClass();
+ self::helperThrowAnException( $array, $object, $refvar );
+ } catch ( Exception $e ) {
+ }
+
+ # Make sure our stack trace contains an array and an object passed to
+ # some function in the stacktrace. Else, we can not assert the trace
+ # redaction achieved its job.
+ $trace = $e->getTrace();
+ $hasObject = false;
+ $hasArray = false;
+ foreach ( $trace as $frame ) {
+ if ( !isset( $frame['args'] ) ) {
+ continue;
+ }
+ foreach ( $frame['args'] as $arg ) {
+ $hasObject = $hasObject || is_object( $arg );
+ $hasArray = $hasArray || is_array( $arg );
+ }
+
+ if ( $hasObject && $hasArray ) {
+ break;
+ }
+ }
+ $this->assertTrue( $hasObject,
+ "The stacktrace must have a function having an object has parameter" );
+ $this->assertTrue( $hasArray,
+ "The stacktrace must have a function having an array has parameter" );
+
+ # Now we redact the trace.. and make sure no function arguments are
+ # arrays or objects.
+ $redacted = MWExceptionHandler::getRedactedTrace( $e );
+
+ foreach ( $redacted as $frame ) {
+ if ( !isset( $frame['args'] ) ) {
+ continue;
+ }
+ foreach ( $frame['args'] as $arg ) {
+ $this->assertNotInternalType( 'array', $arg );
+ $this->assertNotInternalType( 'object', $arg );
+ }
+ }
+
+ $this->assertEquals( 'value', $refvar, 'Ensuring reference variable wasn\'t changed' );
+ }
+
+ /**
+ * Helper function for testExpandArgumentsInCall
+ *
+ * Pass it an object and an array, and something by reference :-)
+ *
+ * @throws Exception
+ */
+ protected static function helperThrowAnException( $a, $b, &$c ) {
+ throw new Exception();
+ }
+}
diff --git a/tests/phpunit/includes/exception/MWExceptionTest.php b/tests/phpunit/includes/exception/MWExceptionTest.php
new file mode 100644
index 00000000..ef0f2a9e
--- /dev/null
+++ b/tests/phpunit/includes/exception/MWExceptionTest.php
@@ -0,0 +1,241 @@
+<?php
+/**
+ * @author Antoine Musso
+ * @copyright Copyright © 2013, Antoine Musso
+ * @copyright Copyright © 2013, Wikimedia Foundation Inc.
+ * @file
+ */
+
+class MWExceptionTest extends MediaWikiTestCase {
+
+ /**
+ * @expectedException MWException
+ */
+ public function testMwexceptionThrowing() {
+ throw new MWException();
+ }
+
+ /**
+ * @dataProvider provideTextUseOutputPage
+ * @covers MWException::useOutputPage
+ */
+ public function testUseOutputPage( $expected, $wgLang, $wgFullyInitialised, $wgOut ) {
+ $this->setMwGlobals( array(
+ 'wgLang' => $wgLang,
+ 'wgFullyInitialised' => $wgFullyInitialised,
+ 'wgOut' => $wgOut,
+ ) );
+
+ $e = new MWException();
+ $this->assertEquals( $expected, $e->useOutputPage() );
+ }
+
+ public function provideTextUseOutputPage() {
+ return array(
+ // expected, wgLang, wgFullyInitialised, wgOut
+ array( false, null, null, null ),
+ array( false, $this->getMockLanguage(), null, null ),
+ array( false, $this->getMockLanguage(), true, null ),
+ array( false, null, true, null ),
+ array( false, null, null, true ),
+ array( true, $this->getMockLanguage(), true, true ),
+ );
+ }
+
+ private function getMockLanguage() {
+ return $this->getMockBuilder( 'Language' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ /**
+ * @dataProvider provideUseMessageCache
+ * @covers MWException::useMessageCache
+ */
+ public function testUseMessageCache( $expected, $wgLang ) {
+ $this->setMwGlobals( array(
+ 'wgLang' => $wgLang,
+ ) );
+ $e = new MWException();
+ $this->assertEquals( $expected, $e->useMessageCache() );
+ }
+
+ public function provideUseMessageCache() {
+ return array(
+ array( false, null ),
+ array( true, $this->getMockLanguage() ),
+ );
+ }
+
+ /**
+ * @covers MWException::isLoggable
+ */
+ public function testIsLogable() {
+ $e = new MWException();
+ $this->assertTrue( $e->isLoggable() );
+ }
+
+ /**
+ * @dataProvider provideRunHooks
+ * @covers MWException::runHooks
+ */
+ public function testRunHooks( $wgExceptionHooks, $name, $args, $expectedReturn ) {
+ $this->setMwGlobals( array(
+ 'wgExceptionHooks' => $wgExceptionHooks,
+ ) );
+ $e = new MWException();
+ $this->assertEquals( $expectedReturn, $e->runHooks( $name, $args ) );
+ }
+
+ public static function provideRunHooks() {
+ return array(
+ array( null, null, null, null ),
+ array( array(), 'name', array(), null ),
+ array( array( 'name' => false ), 'name', array(), null ),
+ array(
+ array( 'mockHook' => array( 'MWExceptionTest::mockHook' ) ),
+ 'mockHook', array(), 'YAY.[]'
+ ),
+ array(
+ array( 'mockHook' => array( 'MWExceptionTest::mockHook' ) ),
+ 'mockHook', array( 'a' ), 'YAY.{"1":"a"}'
+ ),
+ array(
+ array( 'mockHook' => array( 'MWExceptionTest::mockHook' ) ),
+ 'mockHook', array( null ), null
+ ),
+ );
+ }
+
+ /**
+ * Used in conjunction with provideRunHooks and testRunHooks as a mock callback for a hook
+ */
+ public static function mockHook() {
+ $args = func_get_args();
+ if ( !$args[0] instanceof MWException ) {
+ return '$caller not instance of MWException';
+ }
+ unset( $args[0] );
+ if ( array_key_exists( 1, $args ) && $args[1] === null ) {
+ return null;
+ }
+ return 'YAY.' . json_encode( $args );
+ }
+
+ /**
+ * @dataProvider provideIsCommandLine
+ * @covers MWException::isCommandLine
+ */
+ public function testisCommandLine( $expected, $wgCommandLineMode ) {
+ $this->setMwGlobals( array(
+ 'wgCommandLineMode' => $wgCommandLineMode,
+ ) );
+ $e = new MWException();
+ $this->assertEquals( $expected, $e->isCommandLine() );
+ }
+
+ public static function provideIsCommandLine() {
+ return array(
+ array( false, null ),
+ array( true, true ),
+ );
+ }
+
+ /**
+ * Verify the exception classes are JSON serializabe.
+ *
+ * @covers MWExceptionHandler::jsonSerializeException
+ * @dataProvider provideExceptionClasses
+ */
+ public function testJsonSerializeExceptions( $exception_class ) {
+ $json = MWExceptionHandler::jsonSerializeException(
+ new $exception_class()
+ );
+ $this->assertNotEquals( false, $json,
+ "The $exception_class exception should be JSON serializable, got false." );
+ }
+
+ public static function provideExceptionClasses() {
+ return array(
+ array( 'Exception' ),
+ array( 'MWException' ),
+ );
+ }
+
+ /**
+ * Lame JSON schema validation.
+ *
+ * @covers MWExceptionHandler::jsonSerializeException
+ *
+ * @param string $expectedKeyType Type expected as returned by gettype()
+ * @param string $exClass An exception class (ie: Exception, MWException)
+ * @param string $key Name of the key to validate in the serialized JSON
+ * @dataProvider provideJsonSerializedKeys
+ */
+ public function testJsonserializeexceptionKeys( $expectedKeyType, $exClass, $key ) {
+
+ # Make sure we log a backtrace:
+ $this->setMwGlobals( array( 'wgLogExceptionBacktrace' => true ) );
+
+ $json = json_decode(
+ MWExceptionHandler::jsonSerializeException( new $exClass())
+ );
+ $this->assertObjectHasAttribute( $key, $json,
+ "JSON serialized exception is missing key '$key'"
+ );
+ $this->assertInternalType( $expectedKeyType, $json->$key,
+ "JSON serialized key '$key' has type " . gettype( $json->$key )
+ . " (expected: $expectedKeyType)."
+ );
+ }
+
+ /**
+ * Returns test cases: exception class, key name, gettype()
+ */
+ public static function provideJsonSerializedKeys() {
+ $testCases = array();
+ foreach ( array( 'Exception', 'MWException' ) as $exClass ) {
+ $exTests = array(
+ array( 'string', $exClass, 'id' ),
+ array( 'string', $exClass, 'file' ),
+ array( 'integer', $exClass, 'line' ),
+ array( 'string', $exClass, 'message' ),
+ array( 'null', $exClass, 'url' ),
+ # Backtrace only enabled with wgLogExceptionBacktrace = true
+ array( 'array', $exClass, 'backtrace' ),
+ );
+ $testCases = array_merge( $testCases, $exTests );
+ }
+ return $testCases;
+ }
+
+ /**
+ * Given wgLogExceptionBacktrace is true
+ * then serialized exception SHOULD have a backtrace
+ *
+ * @covers MWExceptionHandler::jsonSerializeException
+ */
+ public function testJsonserializeexceptionBacktracingEnabled() {
+ $this->setMwGlobals( array( 'wgLogExceptionBacktrace' => true ) );
+ $json = json_decode(
+ MWExceptionHandler::jsonSerializeException( new Exception() )
+ );
+ $this->assertObjectHasAttribute( 'backtrace', $json );
+ }
+
+ /**
+ * Given wgLogExceptionBacktrace is false
+ * then serialized exception SHOULD NOT have a backtrace
+ *
+ * @covers MWExceptionHandler::jsonSerializeException
+ */
+ public function testJsonserializeexceptionBacktracingDisabled() {
+ $this->setMwGlobals( array( 'wgLogExceptionBacktrace' => false ) );
+ $json = json_decode(
+ MWExceptionHandler::jsonSerializeException( new Exception() )
+ );
+ $this->assertObjectNotHasAttribute( 'backtrace', $json );
+
+ }
+
+}
diff --git a/tests/phpunit/includes/exception/ReadOnlyErrorTest.php b/tests/phpunit/includes/exception/ReadOnlyErrorTest.php
new file mode 100644
index 00000000..6f6aba47
--- /dev/null
+++ b/tests/phpunit/includes/exception/ReadOnlyErrorTest.php
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @covers ReadOnlyError
+ * @author Adam Shorland
+ */
+class ReadOnlyErrorTest extends MediaWikiTestCase {
+
+ public function testConstruction() {
+ $e = new ReadOnlyError();
+ $this->assertEquals( 'readonly', $e->title );
+ $this->assertEquals( 'readonlytext', $e->msg );
+ $this->assertEquals( wfReadOnlyReason() ?: array(), $e->params );
+ }
+
+}
diff --git a/tests/phpunit/includes/exception/ThrottledErrorTest.php b/tests/phpunit/includes/exception/ThrottledErrorTest.php
new file mode 100644
index 00000000..bdb143fa
--- /dev/null
+++ b/tests/phpunit/includes/exception/ThrottledErrorTest.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @covers ThrottledError
+ * @author Adam Shorland
+ */
+class ThrottledErrorTest extends MediaWikiTestCase {
+
+ protected $wgOut;
+
+ protected function setUp() {
+ parent::setUp();
+ global $wgOut;
+ $this->wgOut = clone $wgOut;
+ }
+
+ protected function tearDown() {
+ parent::tearDown();
+ global $wgOut;
+ $wgOut = $this->wgOut;
+ }
+
+ public function testExceptionSetsStatusCode() {
+ global $wgOut;
+ $wgOut = $this->getMockWgOut();
+ try {
+ throw new ThrottledError();
+ } catch ( ThrottledError $e ) {
+ $e->report();
+ $this->assertTrue( true );
+ }
+ }
+
+ private function getMockWgOut() {
+ $mock = $this->getMockBuilder( 'OutputPage' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mock->expects( $this->once() )
+ ->method( 'setStatusCode' )
+ ->with( 429 );
+ return $mock;
+ }
+
+}
diff --git a/tests/phpunit/includes/exception/UserNotLoggedInTest.php b/tests/phpunit/includes/exception/UserNotLoggedInTest.php
new file mode 100644
index 00000000..591a0fa1
--- /dev/null
+++ b/tests/phpunit/includes/exception/UserNotLoggedInTest.php
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @covers UserNotLoggedIn
+ * @author Adam Shorland
+ */
+class UserNotLoggedInTest extends MediaWikiTestCase {
+
+ public function testConstruction() {
+ $e = new UserNotLoggedIn();
+ $this->assertEquals( 'exception-nologin', $e->title );
+ $this->assertEquals( 'exception-nologin-text', $e->msg );
+ $this->assertEquals( array(), $e->params );
+ }
+
+}