Completed
Pull Request — master (#106)
by Kenji
04:30 queued 01:50
created

CIPHPUnitTestCase::warningOn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 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
/**
12
 * @property CIPHPUnitTestRequest    $request
13
 * @property CIPHPUnitTestDouble     $double
14
 * @property CIPHPUnitTestReflection $reflection
15
 */
16
class CIPHPUnitTestCase extends PHPUnit_Framework_TestCase
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
17
{
18
	protected $_error_reporting = -1;
19
	
20
	/**
21
	 * @var CI_Controller CodeIgniter instance
22
	 */
23
	protected $CI;
24
	
25
	protected $class_map = [
26
		'request'    => 'CIPHPUnitTestRequest',
27
		'double'     => 'CIPHPUnitTestDouble',
28
		'reflection' => 'CIPHPUnitTestReflection',
29
	];
30
31
	public function setCI(CI_Controller $CI)
32
	{
33
		$this->CI = $CI;
34
	}
35
36
	public function __get($name)
37
	{
38
		if (isset($this->class_map[$name]))
39
		{
40
			$this->$name = new $this->class_map[$name]($this);
41
			return $this->$name;
42
		}
43
44
		throw new LogicException('No such property: ' . $name);
45
	}
46
47
	public static function setUpBeforeClass()
0 ignored issues
show
Coding Style introduced by
setUpBeforeClass uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
48
	{
49
		// Fix CLI args, because you may set invalid URI characters
50
		// For example, when you run tests on NetBeans
51
		$_SERVER['argv'] = [
52
			'index.php',
53
		];
54
		$_SERVER['argc'] = 1;
55
	}
56
57
	/**
58
	 * Reset CodeIgniter instance and assign new CodeIgniter instance as $this->CI
59
	 */
60
	public function resetInstance()
61
	{
62
		reset_instance();
63
		CIPHPUnitTest::createCodeIgniterInstance();
64
		$this->CI =& get_instance();
65
	}
66
67
	protected function tearDown()
68
	{
69
		if (class_exists('MonkeyPatch', false))
70
		{
71
			if (MonkeyPatchManager::isEnabled('FunctionPatcher'))
72
			{
73
				try {
74
					MonkeyPatch::verifyFunctionInvocations();
75
				} catch (Exception $e) {
76
					MonkeyPatch::resetFunctions();
77
					throw $e;
78
				}
79
80
				MonkeyPatch::resetFunctions();
81
			}
82
83
			if (MonkeyPatchManager::isEnabled('ConstantPatcher'))
84
			{
85
				MonkeyPatch::resetConstants();
86
			}
87
88
			if (MonkeyPatchManager::isEnabled('MethodPatcher'))
89
			{
90
				try {
91
					MonkeyPatch::verifyMethodInvocations();
92
				} catch (Exception $e) {
93
					MonkeyPatch::resetMethods();
94
					throw $e;
95
				}
96
97
				MonkeyPatch::resetMethods();
98
			}
99
		}
100
	}
101
102
	/**
103
	 * Request to Controller
104
	 *
105
	 * @param string       $http_method HTTP method
106
	 * @param array|string $argv        array of controller,method,arg|uri
107
	 * @param array        $params      POST parameters/Query string
108
	 */
109
	public function request($http_method, $argv, $params = [])
110
	{
111
		return $this->request->request($http_method, $argv, $params);
112
	}
113
114
	/**
115
	 * Request to Controller using ajax request
116
	 *
117
	 * @param string       $http_method HTTP method
118
	 * @param array|string $argv        array of controller,method,arg|uri
119
	 * @param array        $params      POST parameters/Query string
120
	 */
121
	public function ajaxRequest($http_method, $argv, $params = [])
0 ignored issues
show
Coding Style introduced by
ajaxRequest uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
122
	{
123
		$_SERVER['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest';
124
		return $this->request($http_method, $argv, $params);
125
	}
126
127
	/**
128
	 * Get Mock Object
129
	 *
130
	 * $email = $this->getMockBuilder('CI_Email')
131
	 *	->setMethods(['send'])
132
	 *	->getMock();
133
	 * $email->method('send')->willReturn(TRUE);
134
	 *
135
	 *  will be
136
	 *
137
	 * $email = $this->getDouble('CI_Email', ['send' => TRUE]);
138
	 *
139
	 * @param  string $classname
140
	 * @param  array  $params             [method_name => return_value]
141
	 * @param  bool   $enable_constructor enable constructor or not
142
	 * @return object PHPUnit mock object
143
	 */
144
	public function getDouble($classname, $params, $enable_constructor = false)
145
	{
146
		return $this->double->getDouble($classname, $params, $enable_constructor);
147
	}
148
149
	/**
150
	 * Verifies that method was called exactly $times times
151
	 *
152
	 * $loader->expects($this->exactly(2))
153
	 * 	->method('view')
154
	 * 	->withConsecutive(
155
	 *		['shop_confirm', $this->anything(), TRUE],
156
	 * 		['shop_tmpl_checkout', $this->anything()]
157
	 * 	);
158
	 *
159
	 *  will be
160
	 *
161
	 * $this->verifyInvokedMultipleTimes(
162
	 * 	$loader,
163
	 * 	'view',
164
	 * 	2,
165
	 * 	[
166
	 * 		['shop_confirm', $this->anything(), TRUE],
167
	 * 		['shop_tmpl_checkout', $this->anything()]
168
	 * 	]
169
	 * );
170
	 *
171
	 * @param object $mock   PHPUnit mock object
172
	 * @param string $method
173
	 * @param int    $times
174
	 * @param array  $params arguments
175
	 */
176
	public function verifyInvokedMultipleTimes($mock, $method, $times, $params = null)
177
	{
178
		$this->double->verifyInvokedMultipleTimes(
179
			$mock, $method, $times, $params
180
		);
181
	}
182
183
	/**
184
	 * Verifies a method was invoked at least once
185
	 *
186
	 * @param object $mock   PHPUnit mock object
187
	 * @param string $method
188
	 * @param array  $params arguments
189
	 */
190
	public function verifyInvoked($mock, $method, $params = null)
191
	{
192
		$this->double->verifyInvoked($mock, $method, $params);
193
	}
194
195
	/**
196
	 * Verifies that method was invoked only once
197
	 *
198
	 * @param object $mock   PHPUnit mock object
199
	 * @param string $method
200
	 * @param array  $params arguments
201
	 */
202
	public function verifyInvokedOnce($mock, $method, $params = null)
203
	{
204
		$this->double->verifyInvokedOnce($mock, $method, $params);
205
	}
206
207
	/**
208
	 * Verifies that method was not called
209
	 *
210
	 * @param object $mock   PHPUnit mock object
211
	 * @param string $method
212
	 * @param array  $params arguments
213
	 */
214
	public function verifyNeverInvoked($mock, $method, $params = null)
215
	{
216
		$this->double->verifyNeverInvoked($mock, $method, $params);
217
	}
218
219
	public function warningOff()
220
	{
221
		$this->_error_reporting = error_reporting(
222
			E_ALL & ~E_WARNING & ~E_NOTICE
223
		);
224
	}
225
226
	public function warningOn()
227
	{
228
		error_reporting($this->_error_reporting);
229
	}
230
231
	/**
232
	 * Asserts HTTP response code
233
	 * 
234
	 * @param int $code
235
	 */
236
	public function assertResponseCode($code)
237
	{
238
		$status = $this->request->getStatus();
239
		$actual = $status['code'];
240
241
		$this->assertSame(
242
			$code,
243
			$actual,
244
			'Status code is not ' . $code . ' but ' . $actual . '.'
245
		);
246
	}
247
248
	/**
249
	 * Asserts HTTP response header
250
	 * 
251
	 * @param string $name  header name
252
	 * @param string $value header value
253
	 */
254
	public function assertResponseHeader($name, $value)
255
	{
256
		$CI =& get_instance();
257
		$actual = $CI->output->get_header($name);
258
259
		if ($actual === null)
260
		{
261
			$this->fail("The '$name' header is not set.\nNote that `assertResponseHeader()` can only assert headers set by `\$this->output->set_header()`");
262
		}
263
264
		$this->assertEquals(
265
			$value,
266
			$actual,
267
			"The '$name' header is not '$value' but '$actual'."
268
		);
269
	}
270
271
	/**
272
	 * Asserts HTTP response cookie
273
	 * 
274
	 * @param string       $name            cookie name
275
	 * @param string|array $value           cookie value|array of cookie params
276
	 * @param bool         $allow_duplicate whether to allow duplicated cookies
277
	 */
278
	public function assertResponseCookie($name, $value, $allow_duplicate = false)
279
	{
280
		$CI =& get_instance();
281
		$cookies = isset($CI->output->_cookies[$name])
282
			? $CI->output->_cookies[$name] : null;
283
284
		if ($cookies === null)
285
		{
286
			$this->fail("The cookie '$name' is not set.\nNote that `assertResponseCookie()` can only assert cookies set by `\$this->input->set_cookie()`");
287
		}
288
289
		$count = count($cookies);
290
		if ($count > 1 && ! $allow_duplicate)
291
		{
292
			$values = [];
293
			foreach ($cookies as $key => $val)
294
			{
295
				$values[] = "'{$val['value']}'";
296
			}
297
			$values = implode(' and ', $values);
298
			$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()`");
299
		}
300
301
		// Get the last cookie
302
		$cookie = $cookies[$count - 1];
303
		if (is_string($value))
304
		{
305
			$this->assertEquals(
306
				$value,
307
				$cookie['value'],
308
				"The cookie '$name' value is not '$value' but '{$cookie['value']}'."
309
			);
310
			return;
311
		}
312
313
		foreach ($value as $key => $val)
314
		{
315
			$this->assertEquals(
316
				$value[$key],
317
				$cookie[$key],
318
				"The cookie '$name' $key is not '{$value[$key]}' but '{$cookie[$key]}'."
319
			);
320
		}
321
	}
322
323
	/**
324
	 * Asserts Redirect
325
	 * 
326
	 * @param string $uri  URI to redirect
327
	 * @param int    $code response code
328
	 */
329
	public function assertRedirect($uri, $code = null)
330
	{
331
		$status = $this->request->getStatus();
332
333
		if ($status['redirect'] === null)
334
		{
335
			$this->fail('redirect() is not called.');
336
		}
337
338
		if (! function_exists('site_url'))
339
		{
340
			$CI =& get_instance();
341
			$CI->load->helper('url');
342
		}
343
344
		if (! preg_match('#^(\w+:)?//#i', $uri))
345
		{
346
			$uri = site_url($uri);
347
		}
348
		$absolute_url = $uri;
349
		$expected = 'Redirect to ' . $absolute_url;
350
351
		$this->assertSame(
352
			$expected,
353
			$status['redirect'],
354
			'URL to redirect is not ' . $expected . ' but ' . $status['redirect'] . '.'
355
		);
356
357
		if ($code !== null)
358
		{
359
			$this->assertSame(
360
				$code,
361
				$status['code'],
362
				'Status code is not ' . $code . ' but ' . $status['code'] . '.'
363
			);
364
		}
365
	}
366
}
367