Merge "Logging related to WikiExport cleanup and changes in T203424"
[lhc/web/wiklou.git] / tests / phpunit / includes / debug / DeprecationHelperTest.php
1 <?php
2
3 use Wikimedia\TestingAccessWrapper;
4
5 /**
6 * @covers DeprecationHelper
7 */
8 class DeprecationHelperTest extends MediaWikiTestCase {
9
10 /** @var TestDeprecatedClass */
11 private $testClass;
12
13 /** @var TestDeprecatedSubclass */
14 private $testSubclass;
15
16 public function setUp() {
17 parent::setUp();
18 $this->testClass = new TestDeprecatedClass();
19 $this->testSubclass = new TestDeprecatedSubclass();
20 $this->setMwGlobals( 'wgDevelopmentWarnings', false );
21 }
22
23 /**
24 * @dataProvider provideGet
25 */
26 public function testGet( $propName, $expectedLevel, $expectedMessage ) {
27 if ( $expectedLevel ) {
28 $this->assertErrorTriggered( function () use ( $propName ) {
29 $this->assertSame( null, $this->testClass->$propName );
30 }, $expectedLevel, $expectedMessage );
31 } else {
32 $this->assertDeprecationWarningIssued( function () use ( $propName ) {
33 $this->assertSame( 1, $this->testClass->$propName );
34 } );
35 }
36 }
37
38 public function provideGet() {
39 return [
40 [ 'protectedDeprecated', null, null ],
41 [ 'protectedNonDeprecated', E_USER_ERROR,
42 'Cannot access non-public property TestDeprecatedClass::$protectedNonDeprecated' ],
43 [ 'privateDeprecated', null, null ],
44 [ 'privateNonDeprecated', E_USER_ERROR,
45 'Cannot access non-public property TestDeprecatedClass::$privateNonDeprecated' ],
46 [ 'nonExistent', E_USER_NOTICE, 'Undefined property: TestDeprecatedClass::$nonExistent' ],
47 ];
48 }
49
50 /**
51 * @dataProvider provideSet
52 */
53 public function testSet( $propName, $expectedLevel, $expectedMessage ) {
54 $this->assertPropertySame( 1, $this->testClass, $propName );
55 if ( $expectedLevel ) {
56 $this->assertErrorTriggered( function () use ( $propName ) {
57 $this->testClass->$propName = 0;
58 $this->assertPropertySame( 1, $this->testClass, $propName );
59 }, $expectedLevel, $expectedMessage );
60 } else {
61 if ( $propName === 'nonExistent' ) {
62 $this->testClass->$propName = 0;
63 } else {
64 $this->assertDeprecationWarningIssued( function () use ( $propName ) {
65 $this->testClass->$propName = 0;
66 } );
67 }
68 $this->assertPropertySame( 0, $this->testClass, $propName );
69 }
70 }
71
72 public function provideSet() {
73 return [
74 [ 'protectedDeprecated', null, null ],
75 [ 'protectedNonDeprecated', E_USER_ERROR,
76 'Cannot access non-public property TestDeprecatedClass::$protectedNonDeprecated' ],
77 [ 'privateDeprecated', null, null ],
78 [ 'privateNonDeprecated', E_USER_ERROR,
79 'Cannot access non-public property TestDeprecatedClass::$privateNonDeprecated' ],
80 [ 'nonExistent', null, null ],
81 ];
82 }
83
84 public function testInternalGet() {
85 $this->assertSame( [
86 'prod' => 1,
87 'prond' => 1,
88 'prid' => 1,
89 'prind' => 1,
90 ], $this->testClass->getThings() );
91 }
92
93 public function testInternalSet() {
94 $this->testClass->setThings( 2, 2, 2, 2 );
95 $wrapper = TestingAccessWrapper::newFromObject( $this->testClass );
96 $this->assertSame( 2, $wrapper->protectedDeprecated );
97 $this->assertSame( 2, $wrapper->protectedNonDeprecated );
98 $this->assertSame( 2, $wrapper->privateDeprecated );
99 $this->assertSame( 2, $wrapper->privateNonDeprecated );
100 }
101
102 public function testSubclassGetSet() {
103 $this->assertDeprecationWarningIssued( function () {
104 $this->assertSame( 1, $this->testSubclass->getDeprecatedPrivateParentProperty() );
105 } );
106 $this->assertDeprecationWarningIssued( function () {
107 $this->testSubclass->setDeprecatedPrivateParentProperty( 0 );
108 } );
109 $wrapper = TestingAccessWrapper::newFromObject( $this->testSubclass );
110 $this->assertSame( 0, $wrapper->privateDeprecated );
111
112 $fullName = 'TestDeprecatedClass::$privateNonDeprecated';
113 $this->assertErrorTriggered( function () {
114 $this->assertSame( null, $this->testSubclass->getNonDeprecatedPrivateParentProperty() );
115 }, E_USER_ERROR, "Cannot access non-public property $fullName" );
116 $this->assertErrorTriggered( function () {
117 $this->testSubclass->setNonDeprecatedPrivateParentProperty( 0 );
118 $wrapper = TestingAccessWrapper::newFromObject( $this->testSubclass );
119 $this->assertSame( 1, $wrapper->privateNonDeprecated );
120 }, E_USER_ERROR, "Cannot access non-public property $fullName" );
121 }
122
123 protected function assertErrorTriggered( callable $callback, $level, $message ) {
124 $actualLevel = $actualMessage = null;
125 set_error_handler( function ( $errorCode, $errorStr ) use ( &$actualLevel, &$actualMessage ) {
126 $actualLevel = $errorCode;
127 $actualMessage = $errorStr;
128 } );
129 $callback();
130 restore_error_handler();
131 $this->assertSame( $level, $actualLevel );
132 $this->assertSame( $message, $actualMessage );
133 }
134
135 protected function assertPropertySame( $expected, $object, $propName ) {
136 try {
137 $this->assertSame( $expected, TestingAccessWrapper::newFromObject( $object )->$propName );
138 } catch ( ReflectionException $e ) {
139 if ( !preg_match( "/Property (TestDeprecated(Class|Subclass)::)?$propName does not exist/",
140 $e->getMessage() )
141 ) {
142 throw $e;
143 }
144 // property_exists accepts monkey-patching, Reflection / TestingAccessWrapper doesn't
145 if ( property_exists( $object, $propName ) ) {
146 $this->assertSame( $expected, $object->$propName );
147 }
148 }
149 }
150
151 protected function assertDeprecationWarningIssued( callable $callback ) {
152 MWDebug::clearLog();
153 $callback();
154 $wrapper = TestingAccessWrapper::newFromClass( MWDebug::class );
155 $this->assertNotEmpty( $wrapper->deprecationWarnings );
156 }
157
158 }