From 1e21a4bcab1826cd95ca020cd14d52bac30f3c27 Mon Sep 17 00:00:00 2001 From: Brad Jorsch Date: Wed, 9 Sep 2015 11:32:37 -0400 Subject: [PATCH] Fix TestingAccessWrapper private property access and parent classes PHP's reflection mechanism is weird: reflecting on a private method will find it even if it's defined in a parent class, while reflecting on a private property just fails. It would likely be more useful if TestingAccessWrapper could find private properties defined in parent classes, so let's make that happen. Change-Id: I9cfdde2694136d0e4559cc419a528762ea14ae4b --- .../data/helpers/WellProtectedClass.php | 29 +++++++++++++++- .../phpunit/includes/TestingAccessWrapper.php | 34 ++++++++++++++++--- .../includes/TestingAccessWrapperTest.php | 18 ++++++++++ 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/tests/phpunit/data/helpers/WellProtectedClass.php b/tests/phpunit/data/helpers/WellProtectedClass.php index 99c7f642f2..a45cfbbfc3 100644 --- a/tests/phpunit/data/helpers/WellProtectedClass.php +++ b/tests/phpunit/data/helpers/WellProtectedClass.php @@ -1,20 +1,47 @@ privateParentProperty = 9000; + } + + private function incrementPrivateParentPropertyValue() { + $this->privateParentProperty++; + } + + public function getPrivateParentProperty() { + return $this->privateParentProperty; + } +} + +class WellProtectedClass extends WellProtectedParentClass { protected $property; + private $privateProperty; public function __construct() { + parent::__construct(); $this->property = 1; + $this->privateProperty = 42; } protected function incrementPropertyValue() { $this->property++; } + private function incrementPrivatePropertyValue() { + $this->privateProperty++; + } + public function getProperty() { return $this->property; } + public function getPrivateProperty() { + return $this->privateProperty; + } + protected function whatSecondArg( $a, $b = false ) { return $b; } diff --git a/tests/phpunit/includes/TestingAccessWrapper.php b/tests/phpunit/includes/TestingAccessWrapper.php index 84c0f9b5be..63d897198b 100644 --- a/tests/phpunit/includes/TestingAccessWrapper.php +++ b/tests/phpunit/includes/TestingAccessWrapper.php @@ -34,16 +34,42 @@ class TestingAccessWrapper { return $methodReflection->invokeArgs( $this->object, $args ); } - public function __set( $name, $value ) { + /** + * ReflectionClass::getProperty() fails if the private property is defined + * in a parent class. This works more like ReflectionClass::getMethod(). + */ + private function getProperty( $name ) { $classReflection = new ReflectionClass( $this->object ); - $propertyReflection = $classReflection->getProperty( $name ); + try { + return $classReflection->getProperty( $name ); + } catch ( ReflectionException $ex ) { + while ( true ) { + $classReflection = $classReflection->getParentClass(); + if ( !$classReflection ) { + throw $ex; + } + try { + $propertyReflection = $classReflection->getProperty( $name ); + } catch ( ReflectionException $ex2 ) { + continue; + } + if ( $propertyReflection->isPrivate() ) { + return $propertyReflection; + } else { + throw $ex; + } + } + } + } + + public function __set( $name, $value ) { + $propertyReflection = $this->getProperty( $name ); $propertyReflection->setAccessible( true ); $propertyReflection->setValue( $this->object, $value ); } public function __get( $name ) { - $classReflection = new ReflectionClass( $this->object ); - $propertyReflection = $classReflection->getProperty( $name ); + $propertyReflection = $this->getProperty( $name ); $propertyReflection->setAccessible( true ); return $propertyReflection->getValue( $this->object ); } diff --git a/tests/phpunit/includes/TestingAccessWrapperTest.php b/tests/phpunit/includes/TestingAccessWrapperTest.php index 7e5b91a119..fc54afae33 100644 --- a/tests/phpunit/includes/TestingAccessWrapperTest.php +++ b/tests/phpunit/includes/TestingAccessWrapperTest.php @@ -14,18 +14,36 @@ class TestingAccessWrapperTest extends MediaWikiTestCase { function testGetProperty() { $this->assertSame( 1, $this->wrapped->property ); + $this->assertSame( 42, $this->wrapped->privateProperty ); + $this->assertSame( 9000, $this->wrapped->privateParentProperty ); } function testSetProperty() { $this->wrapped->property = 10; $this->assertSame( 10, $this->wrapped->property ); $this->assertSame( 10, $this->raw->getProperty() ); + + $this->wrapped->privateProperty = 11; + $this->assertSame( 11, $this->wrapped->privateProperty ); + $this->assertSame( 11, $this->raw->getPrivateProperty() ); + + $this->wrapped->privateParentProperty = 12; + $this->assertSame( 12, $this->wrapped->privateParentProperty ); + $this->assertSame( 12, $this->raw->getPrivateParentProperty() ); } function testCallMethod() { $this->wrapped->incrementPropertyValue(); $this->assertSame( 2, $this->wrapped->property ); $this->assertSame( 2, $this->raw->getProperty() ); + + $this->wrapped->incrementPrivatePropertyValue(); + $this->assertSame( 43, $this->wrapped->privateProperty ); + $this->assertSame( 43, $this->raw->getPrivateProperty() ); + + $this->wrapped->incrementPrivateParentPropertyValue(); + $this->assertSame( 9001, $this->wrapped->privateParentProperty ); + $this->assertSame( 9001, $this->raw->getPrivateParentProperty() ); } function testCallMethodTwoArgs() { -- 2.20.1