[TASK] Tests: Remove extbase BaseTestCase
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / BaseTestCase.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2005-2013 Robert Lemke (robert@typo3.org)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 /**
28 * The mother of all test cases.
29 *
30 * Don't sub class this test case but rather choose a more specialized base test case,
31 * such as UnitTestCase or FunctionalTestCase
32 *
33 */
34 abstract class BaseTestCase extends \PHPUnit_Framework_TestCase {
35
36 /**
37 * Whether global variables should be backed up
38 *
39 * @var boolean
40 */
41 protected $backupGlobals = TRUE;
42
43 /**
44 * Whether static attributes should be backed up
45 *
46 * @var boolean
47 */
48 protected $backupStaticAttributes = FALSE;
49
50 /**
51 * Creates a mock object which allows for calling protected methods and access of protected properties.
52 *
53 * @param string $originalClassName name of class to create the mock object of, must not be empty
54 * @param array<string> $methods name of the methods to mock
55 * @param array $arguments arguments to pass to constructor
56 * @param string $mockClassName the class name to use for the mock class
57 * @param boolean $callOriginalConstructor whether to call the constructor
58 * @param boolean $callOriginalClone whether to call the __clone method
59 * @param boolean $callAutoload whether to call any autoload function
60 *
61 * @return \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface
62 * a mock of $originalClassName with access methods added
63 *
64 * @throws \InvalidArgumentException
65 */
66 protected function getAccessibleMock(
67 $originalClassName, array $methods = array(), array $arguments = array(), $mockClassName = '',
68 $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE
69 ) {
70 if ($originalClassName === '') {
71 throw new \InvalidArgumentException('$originalClassName must not be empty.', 1334701880);
72 }
73
74 return $this->getMock(
75 $this->buildAccessibleProxy($originalClassName),
76 $methods,
77 $arguments,
78 $mockClassName,
79 $callOriginalConstructor,
80 $callOriginalClone,
81 $callAutoload
82 );
83 }
84
85 /**
86 * Returns a mock object which allows for calling protected methods and access
87 * of protected properties.
88 *
89 * @param string $originalClassName Full qualified name of the original class
90 * @param array $arguments
91 * @param string $mockClassName
92 * @param boolean $callOriginalConstructor
93 * @param boolean $callOriginalClone
94 * @param boolean $callAutoload
95 *
96 * @throws \InvalidArgumentException
97 *
98 * @return \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface
99 *
100 */
101 protected function getAccessibleMockForAbstractClass(
102 $originalClassName, array $arguments = array(), $mockClassName = '',
103 $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE
104 ) {
105 if ($originalClassName === '') {
106 throw new \InvalidArgumentException('$originalClassName must not be empty.', 1384268260);
107 }
108
109 return $this->getMockForAbstractClass(
110 $this->buildAccessibleProxy($originalClassName),
111 $arguments,
112 $mockClassName,
113 $callOriginalConstructor,
114 $callOriginalClone,
115 $callAutoload
116 );
117 }
118
119 /**
120 * Creates a proxy class of the specified class which allows
121 * for calling even protected methods and access of protected properties.
122 *
123 * @param string $className Name of class to make available, must not be empty
124 * @return string Fully qualified name of the built class, will not be empty
125 */
126 protected function buildAccessibleProxy($className) {
127 $accessibleClassName = uniqid('Tx_Phpunit_AccessibleProxy');
128 $class = new \ReflectionClass($className);
129 $abstractModifier = $class->isAbstract() ? 'abstract ' : '';
130
131 eval(
132 $abstractModifier . 'class ' . $accessibleClassName .
133 ' extends ' . $className . ' implements \TYPO3\CMS\Core\Tests\AccessibleObjectInterface {' .
134 'public function _call($methodName) {' .
135 'if ($methodName === \'\') {' .
136 'throw new \InvalidArgumentException(\'$methodName must not be empty.\', 1334663993);' .
137 '}' .
138 '$args = func_get_args();' .
139 'return call_user_func_array(array($this, $methodName), array_slice($args, 1));' .
140 '}' .
141 'public function _callRef(' .
142 '$methodName, &$arg1 = NULL, &$arg2 = NULL, &$arg3 = NULL, &$arg4 = NULL, &$arg5= NULL, &$arg6 = NULL, ' .
143 '&$arg7 = NULL, &$arg8 = NULL, &$arg9 = NULL' .
144 ') {' .
145 'if ($methodName === \'\') {' .
146 'throw new \InvalidArgumentException(\'$methodName must not be empty.\', 1334664210);' .
147 '}' .
148 'switch (func_num_args()) {' .
149 'case 0:' .
150 'throw new RuntimeException(\'The case of 0 arguments is not supposed to happen.\', 1334703124);' .
151 'break;' .
152 'case 1:' .
153 '$returnValue = $this->$methodName();' .
154 'break;' .
155 'case 2:' .
156 '$returnValue = $this->$methodName($arg1);' .
157 'break;' .
158 'case 3:' .
159 '$returnValue = $this->$methodName($arg1, $arg2);' .
160 'break;' .
161 'case 4:' .
162 '$returnValue = $this->$methodName($arg1, $arg2, $arg3);' .
163 'break;' .
164 'case 5:' .
165 '$returnValue = $this->$methodName($arg1, $arg2, $arg3, $arg4);' .
166 'break;' .
167 'case 6:' .
168 '$returnValue = $this->$methodName($arg1, $arg2, $arg3, $arg4, $arg5);' .
169 'break;' .
170 'case 7:' .
171 '$returnValue = $this->$methodName($arg1, $arg2, $arg3, $arg4, $arg5, $arg6);' .
172 'break;' .
173 'case 8:' .
174 '$returnValue = $this->$methodName($arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7);' .
175 'break;' .
176 'case 9:' .
177 '$returnValue = $this->$methodName($arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7, $arg8);' .
178 'break;' .
179 'case 10:' .
180 '$returnValue = $this->$methodName(' .
181 '$arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7, $arg8, $arg9' .
182 ');' .
183 'break;' .
184 'default:' .
185 'throw new \InvalidArgumentException(' .
186 '\'_callRef currently only allows calls to methods with no more than 9 parameters.\'' .
187 ');' .
188 '}' .
189 'return $returnValue;' .
190 '}' .
191 'public function _set($propertyName, $value) {' .
192 'if ($propertyName === \'\') {' .
193 'throw new \InvalidArgumentException(\'$propertyName must not be empty.\', 1334664355);' .
194 '}' .
195 '$this->$propertyName = $value;' .
196 '}' .
197 'public function _setRef($propertyName, &$value) {' .
198 'if ($propertyName === \'\') {' .
199 'throw new \InvalidArgumentException(\'$propertyName must not be empty.\', 1334664545);' .
200 '}' .
201 '$this->$propertyName = $value;' .
202 '}' .
203 'public function _setStatic($propertyName, $value) {' .
204 'if ($propertyName === \'\') {' .
205 'throw new \InvalidArgumentException(\'$propertyName must not be empty.\', 1344242602);' .
206 '}' .
207 'self::$$propertyName = $value;' .
208 '}' .
209 'public function _get($propertyName) {' .
210 'if ($propertyName === \'\') {' .
211 'throw new \InvalidArgumentException(\'$propertyName must not be empty.\', 1334664967);' .
212 '}' .
213 'return $this->$propertyName;' .
214 '}' .
215 'public function _getStatic($propertyName) {' .
216 'if ($propertyName === \'\') {' .
217 'throw new \InvalidArgumentException(\'$propertyName must not be empty.\', 1344242603);' .
218 '}' .
219 'return self::$$propertyName;' .
220 '}' .
221 '}'
222 );
223
224 return $accessibleClassName;
225 }
226
227 /**
228 * Helper function to call protected or private methods
229 *
230 * @param object $object The object to be invoked
231 * @param string $name the name of the method to call
232 * @return mixed
233 */
234 protected function callInaccessibleMethod($object, $name) {
235 // Remove first two arguments ($object and $name)
236 $arguments = func_get_args();
237 array_splice($arguments, 0, 2);
238
239 $reflectionObject = new \ReflectionObject($object);
240 $reflectionMethod = $reflectionObject->getMethod($name);
241 $reflectionMethod->setAccessible(TRUE);
242 return $reflectionMethod->invokeArgs($object, $arguments);
243 }
244
245 /**
246 * Injects $dependency into property $name of $target
247 *
248 * This is a convenience method for setting a protected or private property in
249 * a test subject for the purpose of injecting a dependency.
250 *
251 * @param object $target The instance which needs the dependency
252 * @param string $name Name of the property to be injected
253 * @param object $dependency The dependency to inject – usually an object but can also be any other type
254 * @return void
255 * @throws \RuntimeException
256 * @throws \InvalidArgumentException
257 */
258 protected function inject($target, $name, $dependency) {
259 if (!is_object($target)) {
260 throw new \InvalidArgumentException('Wrong type for argument $target, must be object.');
261 }
262
263 $objectReflection = new \ReflectionObject($target);
264 $methodNamePart = strtoupper($name[0]) . substr($name, 1);
265 if ($objectReflection->hasMethod('set' . $methodNamePart)) {
266 $methodName = 'set' . $methodNamePart;
267 $target->$methodName($dependency);
268 } elseif ($objectReflection->hasMethod('inject' . $methodNamePart)) {
269 $methodName = 'inject' . $methodNamePart;
270 $target->$methodName($dependency);
271 } elseif ($objectReflection->hasProperty($name)) {
272 $property = $objectReflection->getProperty($name);
273 $property->setAccessible(TRUE);
274 $property->setValue($target, $dependency);
275 } else {
276 throw new \RuntimeException('Could not inject ' . $name . ' into object of type ' . get_class($target));
277 }
278 }
279 }