From c4273e28e2ac8bda8a2292ee18539000620cd05f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Gerg=C5=91=20Tisza?= Date: Mon, 25 Jan 2016 04:16:40 +0000 Subject: [PATCH] Handle static access in TestingAccessWrapper Change-Id: Ia8ec6ee0a364807e78fc182c4ce99d782b921eda --- .../data/helpers/WellProtectedClass.php | 11 +++ .../phpunit/includes/TestingAccessWrapper.php | 84 +++++++++++++++---- .../includes/TestingAccessWrapperTest.php | 67 +++++++++++++++ 3 files changed, 146 insertions(+), 16 deletions(-) diff --git a/tests/phpunit/data/helpers/WellProtectedClass.php b/tests/phpunit/data/helpers/WellProtectedClass.php index a45cfbbfc3..f2b5a14926 100644 --- a/tests/phpunit/data/helpers/WellProtectedClass.php +++ b/tests/phpunit/data/helpers/WellProtectedClass.php @@ -17,9 +17,20 @@ class WellProtectedParentClass { } class WellProtectedClass extends WellProtectedParentClass { + protected static $staticProperty = 'sp'; + private static $staticPrivateProperty = 'spp'; + protected $property; private $privateProperty; + protected static function staticMethod() { + return 'sm'; + } + + private static function staticPrivateMethod() { + return 'spm'; + } + public function __construct() { parent::__construct(); $this->property = 1; diff --git a/tests/phpunit/includes/TestingAccessWrapper.php b/tests/phpunit/includes/TestingAccessWrapper.php index 63d897198b..7332e15e8d 100644 --- a/tests/phpunit/includes/TestingAccessWrapper.php +++ b/tests/phpunit/includes/TestingAccessWrapper.php @@ -12,36 +12,98 @@ * $formatter = $title->getTitleFormatter(); * * TODO: - * - Provide access to static methods and properties. * - Organize other helper classes in tests/testHelpers.inc into a directory. */ class TestingAccessWrapper { + /** @var mixed The object, or the class name for static-only access */ public $object; /** * Return the same object, without access restrictions. */ public static function newFromObject( $object ) { + if ( !is_object( $object ) ) { + throw new InvalidArgumentException( __METHOD__ . ' must be called with an object' ); + } $wrapper = new TestingAccessWrapper(); $wrapper->object = $object; return $wrapper; } + /** + * Allow access to non-public static methods and properties of the class. + * Use non-static access, + */ + public static function newFromClass( $className ) { + if ( !is_string( $className ) ) { + throw new InvalidArgumentException( __METHOD__ . ' must be called with a class name' ); + } + $wrapper = new TestingAccessWrapper(); + $wrapper->object = $className; + return $wrapper; + } + public function __call( $method, $args ) { + $methodReflection = $this->getMethod( $method ); + + if ( $this->isStatic() && !$methodReflection->isStatic() ) { + throw new DomainException( __METHOD__ . ': Cannot call non-static when wrapping static class' ); + } + + return $methodReflection->invokeArgs( $methodReflection->isStatic() ? null : $this->object, + $args ); + } + + public function __set( $name, $value ) { + $propertyReflection = $this->getProperty( $name ); + + if ( $this->isStatic() && !$propertyReflection->isStatic() ) { + throw new DomainException( __METHOD__ . ': Cannot set property when wrapping static class' ); + } + + $propertyReflection->setValue( $this->object, $value ); + } + + public function __get( $name ) { + $propertyReflection = $this->getProperty( $name ); + + if ( $this->isStatic() && !$propertyReflection->isStatic() ) { + throw new DomainException( __METHOD__ . ': Cannot get property when wrapping static class' ); + } + + return $propertyReflection->getValue( $this->object ); + } + + private function isStatic() { + return is_string( $this->object ); + } + + /** + * Return a property and make it accessible. + * @param string $name + * @return ReflectionMethod + */ + private function getMethod( $name ) { $classReflection = new ReflectionClass( $this->object ); - $methodReflection = $classReflection->getMethod( $method ); + $methodReflection = $classReflection->getMethod( $name ); $methodReflection->setAccessible( true ); - return $methodReflection->invokeArgs( $this->object, $args ); + return $methodReflection; } /** + * Return a property and make it accessible. + * * ReflectionClass::getProperty() fails if the private property is defined * in a parent class. This works more like ReflectionClass::getMethod(). + * + * @param string $name + * @return ReflectionProperty + * @throws ReflectionException */ private function getProperty( $name ) { $classReflection = new ReflectionClass( $this->object ); try { - return $classReflection->getProperty( $name ); + $propertyReflection = $classReflection->getProperty( $name ); } catch ( ReflectionException $ex ) { while ( true ) { $classReflection = $classReflection->getParentClass(); @@ -54,23 +116,13 @@ class TestingAccessWrapper { continue; } if ( $propertyReflection->isPrivate() ) { - return $propertyReflection; + break; } else { throw $ex; } } } - } - - public function __set( $name, $value ) { - $propertyReflection = $this->getProperty( $name ); $propertyReflection->setAccessible( true ); - $propertyReflection->setValue( $this->object, $value ); - } - - public function __get( $name ) { - $propertyReflection = $this->getProperty( $name ); - $propertyReflection->setAccessible( true ); - return $propertyReflection->getValue( $this->object ); + return $propertyReflection; } } diff --git a/tests/phpunit/includes/TestingAccessWrapperTest.php b/tests/phpunit/includes/TestingAccessWrapperTest.php index fc54afae33..23eb023ab9 100644 --- a/tests/phpunit/includes/TestingAccessWrapperTest.php +++ b/tests/phpunit/includes/TestingAccessWrapperTest.php @@ -3,6 +3,7 @@ class TestingAccessWrapperTest extends MediaWikiTestCase { protected $raw; protected $wrapped; + protected $wrappedStatic; function setUp() { parent::setUp(); @@ -10,12 +11,38 @@ class TestingAccessWrapperTest extends MediaWikiTestCase { require_once __DIR__ . '/../data/helpers/WellProtectedClass.php'; $this->raw = new WellProtectedClass(); $this->wrapped = TestingAccessWrapper::newFromObject( $this->raw ); + $this->wrappedStatic = TestingAccessWrapper::newFromClass( 'WellProtectedClass' ); + } + + /** + * @expectedException InvalidArgumentException + */ + function testConstructorException() { + TestingAccessWrapper::newFromObject( 'WellProtectedClass' ); + } + + /** + * @expectedException InvalidArgumentException + */ + function testStaticConstructorException() { + TestingAccessWrapper::newFromClass( new WellProtectedClass() ); } function testGetProperty() { $this->assertSame( 1, $this->wrapped->property ); $this->assertSame( 42, $this->wrapped->privateProperty ); $this->assertSame( 9000, $this->wrapped->privateParentProperty ); + $this->assertSame( 'sp', $this->wrapped->staticProperty ); + $this->assertSame( 'spp', $this->wrapped->staticPrivateProperty ); + $this->assertSame( 'sp', $this->wrappedStatic->staticProperty ); + $this->assertSame( 'spp', $this->wrappedStatic->staticPrivateProperty ); + } + + /** + * @expectedException DomainException + */ + function testGetException() { + $this->wrappedStatic->property; } function testSetProperty() { @@ -30,6 +57,33 @@ class TestingAccessWrapperTest extends MediaWikiTestCase { $this->wrapped->privateParentProperty = 12; $this->assertSame( 12, $this->wrapped->privateParentProperty ); $this->assertSame( 12, $this->raw->getPrivateParentProperty() ); + + $this->wrapped->staticProperty = 'x'; + $this->assertSame( 'x', $this->wrapped->staticProperty ); + $this->assertSame( 'x', $this->wrappedStatic->staticProperty ); + + $this->wrapped->staticPrivateProperty = 'y'; + $this->assertSame( 'y', $this->wrapped->staticPrivateProperty ); + $this->assertSame( 'y', $this->wrappedStatic->staticPrivateProperty ); + + $this->wrappedStatic->staticProperty = 'X'; + $this->assertSame( 'X', $this->wrapped->staticProperty ); + $this->assertSame( 'X', $this->wrappedStatic->staticProperty ); + + $this->wrappedStatic->staticPrivateProperty = 'Y'; + $this->assertSame( 'Y', $this->wrapped->staticPrivateProperty ); + $this->assertSame( 'Y', $this->wrappedStatic->staticPrivateProperty ); + + // don't rely on PHPUnit to restore static properties + $this->wrapped->staticProperty = 'sp'; + $this->wrapped->staticPrivateProperty = 'spp'; + } + + /** + * @expectedException DomainException + */ + function testSetException() { + $this->wrappedStatic->property = 1; } function testCallMethod() { @@ -44,9 +98,22 @@ class TestingAccessWrapperTest extends MediaWikiTestCase { $this->wrapped->incrementPrivateParentPropertyValue(); $this->assertSame( 9001, $this->wrapped->privateParentProperty ); $this->assertSame( 9001, $this->raw->getPrivateParentProperty() ); + + $this->assertSame( 'sm', $this->wrapped->staticMethod() ); + $this->assertSame( 'spm', $this->wrapped->staticPrivateMethod() ); + $this->assertSame( 'sm', $this->wrappedStatic->staticMethod() ); + $this->assertSame( 'spm', $this->wrappedStatic->staticPrivateMethod() ); } function testCallMethodTwoArgs() { $this->assertSame( 'two', $this->wrapped->whatSecondArg( 'one', 'two' ) ); } + + /** + * @expectedException DomainException + */ + function testCallMethodException() { + $this->wrappedStatic->incrementPropertyValue(); + } + } -- 2.20.1