Merge "Include change tags in revision import structure"
[lhc/web/wiklou.git] / tests / phpunit / MediaWikiUnitTestCase.php
1 <?php
2 /**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 * @ingroup Testing
20 */
21
22 use PHPUnit\Framework\TestCase;
23
24 /**
25 * Base class for unit tests.
26 *
27 * Extend this class if you are testing classes which use dependency injection and do not access
28 * global functions, variables, services or a storage backend.
29 *
30 * @since 1.34
31 */
32 abstract class MediaWikiUnitTestCase extends TestCase {
33 use PHPUnit4And6Compat;
34 use MediaWikiCoversValidator;
35 use MediaWikiTestCaseTrait;
36
37 private static $originalGlobals;
38 private static $unitGlobals;
39
40 public static function setUpBeforeClass() {
41 parent::setUpBeforeClass();
42
43 $reflection = new ReflectionClass( static::class );
44 $dirSeparator = DIRECTORY_SEPARATOR;
45 if ( stripos( $reflection->getFilename(), "${dirSeparator}unit${dirSeparator}" ) === false ) {
46 self::fail( 'This unit test needs to be in "tests/phpunit/unit"!' );
47 }
48
49 if ( defined( 'HHVM_VERSION' ) ) {
50 // There are a number of issues we encountered in trying to make this
51 // work on HHVM. Specifically, once an MediaWikiIntegrationTestCase executes
52 // before us, the original globals go missing. This might have to do with
53 // one of the non-unit tests passing GLOBALS somewhere and causing HHVM
54 // to get confused somehow.
55 return;
56 }
57
58 self::$unitGlobals =& TestSetup::$bootstrapGlobals;
59 // The autoloader may change between bootstrap and the first test,
60 // so (lazily) capture these here instead.
61 self::$unitGlobals['wgAutoloadClasses'] =& $GLOBALS['wgAutoloadClasses'];
62 self::$unitGlobals['wgAutoloadLocalClasses'] =& $GLOBALS['wgAutoloadLocalClasses'];
63 // This value should always be true.
64 self::$unitGlobals['wgAutoloadAttemptLowercase'] = true;
65
66 // Would be nice if we coud simply replace $GLOBALS as a whole,
67 // but unsetting or re-assigning that breaks the reference of this magic
68 // variable. Thus we have to modify it in place.
69 self::$originalGlobals = [];
70 foreach ( $GLOBALS as $key => $_ ) {
71 // Stash current values
72 self::$originalGlobals[$key] =& $GLOBALS[$key];
73
74 // Remove globals not part of the snapshot (see bootstrap.php, phpunit.php).
75 // Support: HHVM (avoid self-ref)
76 if ( $key !== 'GLOBALS' && !array_key_exists( $key, self::$unitGlobals ) ) {
77 unset( $GLOBALS[$key] );
78 }
79 }
80 // Restore values from the early snapshot
81 // Not by ref because tests must not be able to modify the snapshot.
82 foreach ( self::$unitGlobals as $key => $value ) {
83 $GLOBALS[ $key ] = $value;
84 }
85 }
86
87 protected function tearDown() {
88 if ( !defined( 'HHVM_VERSION' ) ) {
89 // Quick reset between tests
90 foreach ( $GLOBALS as $key => $_ ) {
91 if ( $key !== 'GLOBALS' && !array_key_exists( $key, self::$unitGlobals ) ) {
92 unset( $GLOBALS[$key] );
93 }
94 }
95 foreach ( self::$unitGlobals as $key => $value ) {
96 $GLOBALS[ $key ] = $value;
97 }
98 }
99
100 parent::tearDown();
101 }
102
103 public static function tearDownAfterClass() {
104 if ( !defined( 'HHVM_VERSION' ) ) {
105 // Remove globals created by the test
106 foreach ( $GLOBALS as $key => $_ ) {
107 if ( $key !== 'GLOBALS' && !array_key_exists( $key, self::$originalGlobals ) ) {
108 unset( $GLOBALS[$key] );
109 }
110 }
111 // Restore values (including reference!)
112 foreach ( self::$originalGlobals as $key => &$value ) {
113 $GLOBALS[ $key ] =& $value;
114 }
115 }
116
117 parent::tearDownAfterClass();
118 }
119
120 /**
121 * Create a temporary hook handler which will be reset by tearDown.
122 * This replaces other handlers for the same hook.
123 * @param string $hookName Hook name
124 * @param mixed $handler Value suitable for a hook handler
125 * @since 1.34
126 */
127 protected function setTemporaryHook( $hookName, $handler ) {
128 // This will be reset by tearDown() when it restores globals. We don't want to use
129 // Hooks::register()/clear() because they won't replace other handlers for the same hook,
130 // which doesn't match behavior of MediaWikiIntegrationTestCase.
131 global $wgHooks;
132 $wgHooks[$hookName] = [ $handler ];
133 }
134
135 protected function getMockMessage( $text, ...$params ) {
136 if ( isset( $params[0] ) && is_array( $params[0] ) ) {
137 $params = $params[0];
138 }
139
140 $msg = $this->getMockBuilder( Message::class )
141 ->disableOriginalConstructor()
142 ->setMethods( [] )
143 ->getMock();
144
145 $msg->method( 'toString' )->willReturn( $text );
146 $msg->method( '__toString' )->willReturn( $text );
147 $msg->method( 'text' )->willReturn( $text );
148 $msg->method( 'parse' )->willReturn( $text );
149 $msg->method( 'plain' )->willReturn( $text );
150 $msg->method( 'parseAsBlock' )->willReturn( $text );
151 $msg->method( 'escaped' )->willReturn( $text );
152
153 $msg->method( 'title' )->willReturn( $msg );
154 $msg->method( 'inLanguage' )->willReturn( $msg );
155 $msg->method( 'inContentLanguage' )->willReturn( $msg );
156 $msg->method( 'useDatabase' )->willReturn( $msg );
157 $msg->method( 'setContext' )->willReturn( $msg );
158
159 $msg->method( 'exists' )->willReturn( true );
160 $msg->method( 'content' )->willReturn( new MessageContent( $msg ) );
161
162 return $msg;
163 }
164 }