3 // Copyright (c) 2015 Blue Static
5 // This program is free software: you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or any later version.
9 // This program is distributed in the hope that it will be useful, but WITHOUT
10 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 // You should have received a copy of the GNU General Public License along with
15 // this program. If not, see <http://www.gnu.org/licenses/>.
17 namespace hoplite\test
;
18 use hoplite\http
as http
;
20 require_once HOPLITE_ROOT
. '/http/action.php';
21 require_once HOPLITE_ROOT
. '/http/front_controller.php';
22 require_once HOPLITE_ROOT
. '/http/interceptor.php';
23 require_once HOPLITE_ROOT
. '/http/output_filter.php';
24 require_once HOPLITE_ROOT
. '/http/url_map.php';
26 class ActionReporter
extends http\Action
28 public $did_invoke = FALSE;
30 public function Invoke(http\Request
$q, http\Response
$s)
32 $this->did_invoke
= TRUE;
36 class ClosureInterceptor
implements http\Interceptor
39 public $did_intercept = FALSE;
41 public function __construct($interceptor)
43 $this->interceptor
= $interceptor;
46 public function DoIntercept(http\FrontController
$controller,
47 http\Action
$action = NULL,
48 http\Request
$request,
49 http\Response
$response)
51 $this->did_intercept
= TRUE;
52 if ($this->interceptor
) {
53 $interceptor = $this->interceptor
;
54 $interceptor($controller, $action, $request, $response);
59 class FrontControllerTest
extends \PHPUnit_Framework_TestCase
62 Configures a mock FrontControler.
63 @param array|NULL Array of methods to mock
64 @param varargs Constructor parameters.
65 @return Mock FrontControler
67 public function ConfigureMock()
69 $args = func_get_args();
70 return $this->getMock('hoplite\http\FrontController', $args[0], array_slice($args, 1));
73 public function testProcessRequest()
75 $globals = array('_SERVER' => array(
76 'REQUEST_METHOD' => 'GET',
77 'PATH_INFO' => '/some/action/42'
79 $mock = $this->ConfigureMock(array('RouteRequest', 'SendResponse'), $globals);
81 $mock->request()->url
= 'some/action/42';
83 $mock->expects($this->once())
84 ->method('RouteRequest')
85 ->with($this->equalTo($mock->request()));
87 $mock->expects($this->once())
88 ->method('SendResponse');
90 $mock->ProcessRequest();
93 public function testRouteRequest()
96 $mock = $this->ConfigureMock(array('SendResponse', 'InvokeAction'), $globals);
98 $mock->request()->url
= 'some/action/42';
99 $map_value = 'ActionReporter';
100 $action = new ActionReporter($mock);
102 $url_map = $this->getMock('hoplite\http\UrlMap', array(), array($mock));
103 $url_map->expects($this->once())
105 ->with($this->equalTo($mock->request()))
106 ->will($this->returnValue($map_value));
107 $url_map->expects($this->once())
108 ->method('LookupAction')
109 ->with($this->equalTo($map_value))
110 ->will($this->returnValue($action));
112 $mock->set_url_map($url_map);
113 $mock->RouteRequest($mock->request());
115 $this->assertTrue($action->did_invoke
);
118 public function testRouteRequestInvalid()
121 $mock = $this->ConfigureMock(array('SendResponse'), $globals);
123 $mock->request()->url
= 'another/action';
125 $mock->expects($this->never())
126 ->method('SendResponse');
128 $url_map = $this->getMock('hoplite\http\UrlMap', array(), array($mock));
129 $url_map->expects($this->once())
131 ->with($this->equalTo($mock->request()));
133 $mock->set_url_map($url_map);
134 $mock->RouteRequest($mock->request());
135 // Nothing should happen for a non-routed request.
138 public function testSendResponse()
141 $mock = $this->ConfigureMock(array('_Exit'), $globals);
143 $mock->expects($this->once())
146 $output_filter = $this->getMock('hoplite\http\OutputFilter', array(), array($mock));
147 $output_filter->expects($this->once())
148 ->method('FilterOutput')
149 ->with($this->isInstanceOf('hoplite\http\Request'),
150 $this->isInstanceOf('hoplite\http\Response'));
152 $mock->set_output_filter($output_filter);
153 $mock->SendResponse();
156 public function testStopWithRedirect()
159 $mock = $this->ConfigureMock(array('_Exit'), $globals);
160 $mock->expects($this->once())
163 $output_filter = $this->getMock('hoplite\http\OutputFilter', array(), array($mock));
164 $output_filter->expects($this->once())
165 ->method('FilterOutput')
166 ->with($this->isInstanceOf('hoplite\http\Request'),
167 $this->isInstanceOf('hoplite\http\Response'));
169 $mock->set_output_filter($output_filter);
171 $mock->SendResponseRedirect('/foo/bar');
173 $this->assertEquals('/foo/bar', $mock->response()->headers
['Location']);
174 $this->assertEquals(http\ResponseCode
::FOUND
, $mock->response()->response_code
);
177 public function testAbsolutify()
181 'HTTP_HOST' => 'www.bluestatic.org',
182 'REQUEST_URI' => '/hoplite/webapp/test/path',
183 'PATH_INFO' => '/test/path',
187 $mock = new \hoplite\http\
FrontController($globals);
189 $this->assertEquals($mock->MakeURL('/'), '/hoplite/webapp/');
190 $this->assertEquals($mock->MakeURL('/', TRUE), 'http://www.bluestatic.org/hoplite/webapp/');
192 $this->assertEquals($mock->MakeURL('/path/2'), '/hoplite/webapp/path/2');
193 $this->assertEquals($mock->MakeURL('/path/3', TRUE), 'http://www.bluestatic.org/hoplite/webapp/path/3');
195 $globals['_SERVER']['HTTPS'] = 'on';
196 $globals['_SERVER']['SERVER_PORT'] = 443;
197 $mock = new \hoplite\http\
FrontController($globals);
198 $this->assertEquals($mock->MakeURL('/'), '/hoplite/webapp/');
199 $this->assertEquals($mock->MakeURL('/', TRUE), 'https://www.bluestatic.org/hoplite/webapp/');
201 $this->assertEquals($mock->MakeURL('/path/2'), '/hoplite/webapp/path/2');
202 $this->assertEquals($mock->MakeURL('/path/3', TRUE), 'https://www.bluestatic.org/hoplite/webapp/path/3');
204 $globals['_SERVER']['SERVER_PORT'] = 8080;
205 $mock = new \hoplite\http\
FrontController($globals);
206 $this->assertEquals($mock->MakeURL('/path/2'), '/hoplite/webapp/path/2');
207 $this->assertEquals($mock->MakeURL('/', TRUE), 'https://www.bluestatic.org:8080/hoplite/webapp/');
208 $this->assertEquals($mock->MakeURL('/path/3', TRUE), 'https://www.bluestatic.org:8080/hoplite/webapp/path/3');
211 public function testAbsolutifyFront()
215 'HTTP_HOST' => 'www.bluestatic.org',
216 'REQUEST_URI' => '/hoplite/webapp/',
221 $mock = new \hoplite\http\
FrontController($globals);
223 $this->assertEquals($mock->MakeURL('/'), '/hoplite/webapp/');
224 $this->assertEquals($mock->MakeURL('/', TRUE), 'http://www.bluestatic.org/hoplite/webapp/');
226 $globals['_SERVER']['HTTPS'] = 'on';
227 $globals['_SERVER']['SERVER_PORT'] = 443;
228 $mock = new \hoplite\http\
FrontController($globals);
229 $this->assertEquals($mock->MakeURL('/'), '/hoplite/webapp/');
230 $this->assertEquals($mock->MakeURL('/', TRUE), 'https://www.bluestatic.org/hoplite/webapp/');
232 $this->assertEquals($mock->MakeURL('/path/2'), '/hoplite/webapp/path/2');
233 $this->assertEquals($mock->MakeURL('/path/3', TRUE), 'https://www.bluestatic.org/hoplite/webapp/path/3');
235 $globals['_SERVER']['SERVER_PORT'] = 8080;
236 $mock = new \hoplite\http\
FrontController($globals);
237 $this->assertEquals($mock->MakeURL('/path/2'), '/hoplite/webapp/path/2');
238 $this->assertEquals($mock->MakeURL('/', TRUE), 'https://www.bluestatic.org:8080/hoplite/webapp/');
239 $this->assertEquals($mock->MakeURL('/path/3', TRUE), 'https://www.bluestatic.org:8080/hoplite/webapp/path/3');
242 public function testThreeInterceptors()
245 new ClosureInterceptor(NULL),
246 new ClosureInterceptor(NULL),
247 new ClosureInterceptor(NULL),
250 $mock = new \hoplite\http\
FrontController([]);
251 $mock->set_url_map(new http\
UrlMap($mock));
253 foreach ($interceptors as $interceptor) {
254 $mock->AddInterceptor($interceptor);
257 $mock->RouteRequest($mock->request());
259 foreach ($interceptors as $interceptor) {
260 $this->assertTrue($interceptor->did_intercept
);
264 public function testInterruptInterceptor()
266 $i1 = new ClosureInterceptor(NULL);
267 $i2 = new ClosureInterceptor(function($controller, $action, $request, $response) {
268 $controller->SendResponseCode(400);
271 $i3 = new ClosureInterceptor(function($controller, $action, $request, $response) use ($test) {
272 $test->assertEquals(400, $response->response_code
);
275 $mock = $this->ConfigureMock(['SendResponse'], []);
276 $mock->set_url_map(new http\
UrlMap($mock));
277 $mock->AddInterceptor($i1);
278 $mock->AddInterceptor($i2);
279 $mock->AddInterceptor($i3);
281 $mock->expects($this->once())
282 ->method('SendResponse');
284 $mock->RouteRequest($mock->request());
286 $this->assertEquals(400, $mock->response()->response_code
);
287 $this->assertTrue($i1->did_intercept
);
288 $this->assertTrue($i2->did_intercept
);
289 // i3 would not normally run but because _Exit is mocked, the script does