Completed
Push — master ( 3c4c47...76c067 )
by Kenji
03:45 queued 01:38
created

CIPHPUnitTestCase::isTestingEnv()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Part of ci-phpunit-test
4
 *
5
 * @author     Kenji Suzuki <https://github.com/kenjis>
6
 * @license    MIT License
7
 * @copyright  2015 Kenji Suzuki
8
 * @link       https://github.com/kenjis/ci-phpunit-test
9
 */
10
11
// Support PHPUnit 6.0
12
if (! class_exists('PHPUnit_Framework_TestCase'))
13
{
14
	class_alias('PHPUnit\Framework\TestCase', 'PHPUnit_Framework_TestCase');
15
}
16
17
/**
18
 * @property CIPHPUnitTestRequest    $request
19
 * @property CIPHPUnitTestDouble     $double
20
 * @property CIPHPUnitTestReflection $reflection
21
 */
22
class CIPHPUnitTestCase extends PHPUnit_Framework_TestCase
23
{
24
	protected $_error_reporting = -1;
25
26
	/**
27
	 * If you have a route with closure, PHPUnit can't serialize global variables.
28
	 * You would see `Exception: Serialization of 'Closure' is not allowed`.
29
	 *
30
	 * @var array
31
	 */
32
	protected $backupGlobalsBlacklist = ['RTR'];
33
34
	/**
35
	 * Detect warnings and notices in a request output
36
	 *
37
	 * @var bool
38
	 */
39
	protected $strictRequestErrorCheck = true;
40
41
	protected $restoreErrorHandler = false;
42
43
	/**
44
	 * @var CI_Controller CodeIgniter instance
45
	 */
46
	protected $CI;
47
48
	protected $class_map = [
49
		'request'    => 'CIPHPUnitTestRequest',
50
		'double'     => 'CIPHPUnitTestDouble',
51
		'reflection' => 'CIPHPUnitTestReflection',
52
	];
53
54
	public function setCI(CI_Controller $CI)
55
	{
56
		$this->CI = $CI;
57
	}
58
59
	public function getStrictRequestErrorCheck()
60
	{
61
		return $this->strictRequestErrorCheck;
62
	}
63
64
	public function __get($name)
65
	{
66
		if (isset($this->class_map[$name]))
67
		{
68
			$this->$name = new $this->class_map[$name]($this);
69
			return $this->$name;
70
		}
71
72
		throw new LogicException('No such property: ' . $name);
73
	}
74
75
	public static function setUpBeforeClass()
76
	{
77
		// Fix CLI args, because you may set invalid URI characters
78
		// For example, when you run tests on NetBeans
79
		$_SERVER['argv'] = [
80
			'index.php',
81
		];
82
		$_SERVER['argc'] = 1;
83
84
		// Reset current directroy
85
		chdir(FCPATH);
86
	}
87
88
	public static function tearDownAfterClass()
89
	{
90
		CIPHPUnitTestDbConnectionStore::destory();
91
	}
92
93
	/**
94
	 * Reset CodeIgniter instance and assign new CodeIgniter instance as $this->CI
95
	 *
96
	 *  @param bool $use_my_controller
97
	 */
98
	public function resetInstance($use_my_controller = false)
99
	{
100
		reset_instance();
101
		CIPHPUnitTest::createCodeIgniterInstance($use_my_controller);
102
		$this->CI =& get_instance();
103
	}
104
105
	protected function tearDown()
106
	{
107
		$this->disableStrictErrorCheck();
108
109
		if (class_exists('MonkeyPatch', false))
110
		{
111
			if (MonkeyPatchManager::isEnabled('FunctionPatcher'))
112
			{
113
				try {
114
					MonkeyPatch::verifyFunctionInvocations();
115
				} catch (Exception $e) {
116
					MonkeyPatch::resetFunctions();
117
					throw $e;
118
				}
119
120
				MonkeyPatch::resetFunctions();
121
			}
122
123
			if (MonkeyPatchManager::isEnabled('ConstantPatcher'))
124
			{
125
				MonkeyPatch::resetConstants();
126
			}
127
128
			if (MonkeyPatchManager::isEnabled('MethodPatcher'))
129
			{
130
				try {
131
					MonkeyPatch::verifyMethodInvocations();
132
				} catch (Exception $e) {
133
					MonkeyPatch::resetMethods();
134
					throw $e;
135
				}
136
137
				MonkeyPatch::resetMethods();
138
			}
139
		}
140
	}
141
142
	/**
143
	 * Request to Controller
144
	 *
145
	 * @param string       $http_method HTTP method
146
	 * @param array|string $argv        array of controller,method,arg|uri
147
	 * @param array        $params      POST parameters/Query string
148
	 */
149
	public function request($http_method, $argv, $params = [])
150
	{
151
		return $this->request->request($http_method, $argv, $params);
152
	}
153
154
	/**
155
	 * Disable strict error check
156
	 */
157
	public function disableStrictErrorCheck()
158
	{
159
		if ($this->restoreErrorHandler) {
160
			restore_error_handler();
161
			$this->restoreErrorHandler = false;
162
		}
163
	}
164
165
	/**
166
	 * Enable strict error check
167
	 */
168
	public function enableStrictErrorCheck()
169
	{
170
		if ($this->restoreErrorHandler) {
171
			throw new LogicException('Already strict error check mode');
172
		}
173
174
		set_error_handler(
175
			function ($errno, $errstr, $errfile, $errline) {
176
				throw new RuntimeException($errstr . ' on line ' . $errline . ' in file ' . $errfile);
177
			}
178
		);
179
180
		$this->restoreErrorHandler = true;
181
	}
182
183
	/**
184
	 * Request to Controller using ajax request
185
	 *
186
	 * @param string       $http_method HTTP method
187
	 * @param array|string $argv        array of controller,method,arg|uri
188
	 * @param array        $params      POST parameters/Query string
189
	 */
190
	public function ajaxRequest($http_method, $argv, $params = [])
191
	{
192
		$_SERVER['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest';
193
		return $this->request($http_method, $argv, $params);
194
	}
195
196
	/**
197
	 * Get Mock Object
198
	 *
199
	 * $email = $this->getMockBuilder('CI_Email')
200
	 *	->setMethods(['send'])
201
	 *	->getMock();
202
	 * $email->method('send')->willReturn(TRUE);
203
	 *
204
	 *  will be
205
	 *
206
	 * $email = $this->getDouble('CI_Email', ['send' => TRUE]);
207
	 *
208
	 * @param  string $classname
209
	 * @param  array  $params             [method_name => return_value]
210
	 * @param  bool   $enable_constructor enable constructor or not
211
	 * @return mixed  PHPUnit mock object
212
	 */
213
	public function getDouble($classname, $params, $enable_constructor = false)
214
	{
215
		return $this->double->getDouble($classname, $params, $enable_constructor);
216
	}
217
218
	/**
219
	 * Verifies that method was called exactly $times times
220
	 *
221
	 * $loader->expects($this->exactly(2))
222
	 * 	->method('view')
223
	 * 	->withConsecutive(
224
	 *		['shop_confirm', $this->anything(), TRUE],
225
	 * 		['shop_tmpl_checkout', $this->anything()]
226
	 * 	);
227
	 *
228
	 *  will be
229
	 *
230
	 * $this->verifyInvokedMultipleTimes(
231
	 * 	$loader,
232
	 * 	'view',
233
	 * 	2,
234
	 * 	[
235
	 * 		['shop_confirm', $this->anything(), TRUE],
236
	 * 		['shop_tmpl_checkout', $this->anything()]
237
	 * 	]
238
	 * );
239
	 *
240
	 * @param mixed  $mock   PHPUnit mock object
241
	 * @param string $method
242
	 * @param int    $times
243
	 * @param array  $params arguments
244
	 */
245
	public function verifyInvokedMultipleTimes($mock, $method, $times, $params = null)
246
	{
247
		$this->double->verifyInvokedMultipleTimes(
248
			$mock, $method, $times, $params
249
		);
250
	}
251
252
	/**
253
	 * Verifies a method was invoked at least once
254
	 *
255
	 * @param mixed  $mock   PHPUnit mock object
256
	 * @param string $method
257
	 * @param array  $params arguments
258
	 */
259
	public function verifyInvoked($mock, $method, $params = null)
260
	{
261
		$this->double->verifyInvoked($mock, $method, $params);
262
	}
263
264
	/**
265
	 * Verifies that method was invoked only once
266
	 *
267
	 * @param mixed  $mock   PHPUnit mock object
268
	 * @param string $method
269
	 * @param array  $params arguments
270
	 */
271
	public function verifyInvokedOnce($mock, $method, $params = null)
272
	{
273
		$this->double->verifyInvokedOnce($mock, $method, $params);
274
	}
275
276
	/**
277
	 * Verifies that method was not called
278
	 *
279
	 * @param mixed  $mock   PHPUnit mock object
280
	 * @param string $method
281
	 * @param array  $params arguments
282
	 */
283
	public function verifyNeverInvoked($mock, $method, $params = null)
284
	{
285
		$this->double->verifyNeverInvoked($mock, $method, $params);
286
	}
287
288
	public function warningOff()
289
	{
290
		$this->_error_reporting = error_reporting(
291
			E_ALL & ~E_WARNING & ~E_NOTICE
292
		);
293
	}
294
295
	public function warningOn()
296
	{
297
		error_reporting($this->_error_reporting);
298
	}
299
300
	/**
301
	 * Asserts HTTP response code
302
	 *
303
	 * @param int $code
304
	 */
305
	public function assertResponseCode($code)
306
	{
307
		$status = $this->request->getStatus();
308
		$actual = $status['code'];
309
310
		$this->assertSame(
311
			$code,
312
			$actual,
313
			'Status code is not ' . $code . ' but ' . $actual . '.'
314
		);
315
	}
316
317
	/**
318
	 * Asserts HTTP response header
319
	 *
320
	 * @param string $name  header name
321
	 * @param string $value header value
322
	 */
323
	public function assertResponseHeader($name, $value)
324
	{
325
		$CI =& get_instance();
326
		$actual = $CI->output->get_header($name);
327
328
		if ($actual === null)
329
		{
330
			$this->fail("The '$name' header is not set.\nNote that `assertResponseHeader()` can only assert headers set by `\$this->output->set_header()`");
331
		}
332
333
		$this->assertEquals(
334
			$value,
335
			$actual,
336
			"The '$name' header is not '$value' but '$actual'."
337
		);
338
	}
339
340
	/**
341
	 * Asserts HTTP response cookie
342
	 *
343
	 * @param string       $name            cookie name
344
	 * @param string|array $value           cookie value|array of cookie params
345
	 * @param bool         $allow_duplicate whether to allow duplicated cookies
346
	 */
347
	public function assertResponseCookie($name, $value, $allow_duplicate = false)
348
	{
349
		$CI =& get_instance();
350
		$cookies = isset($CI->output->_cookies[$name])
351
			? $CI->output->_cookies[$name] : null;
352
353
		if ($cookies === null)
354
		{
355
			$this->fail("The cookie '$name' is not set.\nNote that `assertResponseCookie()` can only assert cookies set by `\$this->input->set_cookie()`");
356
		}
357
358
		$count = count($cookies);
359
		if ($count > 1 && ! $allow_duplicate)
360
		{
361
			$values = [];
362
			foreach ($cookies as $key => $val)
363
			{
364
				$values[] = "'{$val['value']}'";
365
			}
366
			$values = implode(' and ', $values);
367
			$this->fail("You have more than one cookie '$name'. The values are $values.\nIf it is okay, please set `true` as the 3rd argument of `assertResponseCookie()`");
368
		}
369
370
		// Get the last cookie
371
		$cookie = $cookies[$count - 1];
372
		if (is_string($value))
373
		{
374
			$this->assertEquals(
375
				$value,
376
				$cookie['value'],
377
				"The cookie '$name' value is not '$value' but '{$cookie['value']}'."
378
			);
379
			return;
380
		}
381
382
		// In case of $this->anything()
383
		if (
384
			$value instanceof PHPUnit_Framework_Constraint_IsAnything
0 ignored issues
show
Bug introduced by
The class PHPUnit_Framework_Constraint_IsAnything does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
385
			|| $value instanceof PHPUnit\Framework\Constraint\IsAnything
0 ignored issues
show
Bug introduced by
The class PHPUnit\Framework\Constraint\IsAnything does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
386
		)
387
		{
388
			$this->assertTrue(true);
389
			return;
390
		}
391
392
		foreach ($value as $key => $val)
393
		{
394
			$this->assertEquals(
395
				$value[$key],
396
				$cookie[$key],
397
				"The cookie '$name' $key is not '{$value[$key]}' but '{$cookie[$key]}'."
398
			);
399
		}
400
	}
401
402
	/**
403
	 * Asserts Redirect
404
	 *
405
	 * @param string $uri  URI to redirect
406
	 * @param int    $code response code
407
	 */
408
	public function assertRedirect($uri, $code = null)
409
	{
410
		$status = $this->request->getStatus();
411
412
		if ($status['redirect'] === null)
413
		{
414
			$this->fail('redirect() is not called.');
415
		}
416
417
		if (! function_exists('site_url'))
418
		{
419
			$CI =& get_instance();
420
			$CI->load->helper('url');
421
		}
422
423
		if (! preg_match('#^(\w+:)?//#i', $uri))
424
		{
425
			$uri = site_url($uri);
426
		}
427
		$absolute_url = $uri;
428
		$expected = 'Redirect to ' . $absolute_url;
429
430
		$this->assertSame(
431
			$expected,
432
			$status['redirect'],
433
			'URL to redirect is not ' . $expected . ' but ' . $status['redirect'] . '.'
434
		);
435
436
		if ($code !== null)
437
		{
438
			$this->assertSame(
439
				$code,
440
				$status['code'],
441
				'Status code is not ' . $code . ' but ' . $status['code'] . '.'
442
			);
443
		}
444
	}
445
446
	/**
447
	 * Asserts the message is logged
448
	 *
449
	 * @param string $level
450
	 * @param string $message
451
	 */
452
	public function assertLogged($level, $message)
453
	{
454
		$result = CIPHPUnitTestLogger::didLog($level, $message);
455
		$this->assertTrue($result);
456
	}
457
458
	/**
459
	 * Testing Environment or not?
460
	 *
461
	 * @return bool
462
	 */
463
	public static function isTestingEnv()
464
	{
465
		return (ENVIRONMENT === 'testing');
466
	}
467
}
468