From a443973e0873177e5e154c397deb7140cc05bac4 Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Sat, 18 Jun 2011 14:19:20 -0400 Subject: [PATCH] * Add a set of failing tests for UrlMap -- TDD! * Document how strict pattern matching works (versus prefix) --- README | 16 ++- http/request.php | 8 ++ http/url_map.php | 2 +- testing/tests/http/url_map_test.php | 152 ++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 testing/tests/http/url_map_test.php diff --git a/README b/README index 026dfc9..ba29b9e 100644 --- a/README +++ b/README @@ -137,7 +137,7 @@ Requests will be in the rewritten form of: https://example.comm/webapp/user/view/42 -The UrlMap would be any of the following: +The UrlMap could be any of the following: ID paramter extracted manually from the URL or through GET or POST variables 'user/view' @@ -147,8 +147,22 @@ The UrlMap would be any of the following: Using an ActionController (see previous section) 'user/{action}' + Or, 'user/{action}/{id}' +In the above forms, the matcher does prefix matching. Combined with the fact +that rules are evaluated linearly, this can lead to a potentially unexpected +result. When you have a more general rule before a specific one, the general +will always be the one matched. For example: + + 'document/edit' + 'document/edit/{id}' + +The second rule will never be matched, because the evaluator will find and +invoke the first rule and then stop. This isn't always the desired behavior and +can be altered by adding two slashes to the end of a rule. These two slashes +make the parser matching strict equality, rather than prefix. + The second type of matching is done by regular expressions. These patterns both start and end with a slash. They are evaluated every time a request is routed and any pattern groups are saved in the url_pattern key of the HttpRequest data. diff --git a/http/request.php b/http/request.php index 7f0590e..ff48b00 100644 --- a/http/request.php +++ b/http/request.php @@ -32,4 +32,12 @@ class Request extends \hoplite\base\StrictObject /*! @var array HTTP request data. */ public $data = array(); + + /*! + Constructor. Takes an optional URL. + */ + public function __construct($url = '') + { + $this->url = $url; + } } diff --git a/http/url_map.php b/http/url_map.php index b7d3fa4..d3590be 100644 --- a/http/url_map.php +++ b/http/url_map.php @@ -90,7 +90,7 @@ class UrlMap @return string|NULL A matched value in the ::map() or NULL if no match. */ - public function Evaluate($request_url) + public function Evaluate(Request $request) {} /*! @brief Takes a value from the map and returns an Action object. diff --git a/testing/tests/http/url_map_test.php b/testing/tests/http/url_map_test.php new file mode 100644 index 0000000..7f4280f --- /dev/null +++ b/testing/tests/http/url_map_test.php @@ -0,0 +1,152 @@ +. + +namespace hoplite\test; +use hoplite\http as http; + +require_once HOPLITE_ROOT . '/http/url_map.php'; + +class UrlMapTest extends \PHPUnit_Framework_TestCase +{ + public function setUp() + { + $globals = array(); + $this->fixture = new http\UrlMap(new http\RootController($globals)); + } + + public function testSimpleEvaluate() + { + $map = array( + 'action/two' => 'Invalid', + 'some/long/action' => 'Valid' + ); + $this->fixture->set_map($map); + + $request = new http\Request('some/long/action'); + $this->assertEquals('Valid', $this->fixture->Evaluate($request)); + + $request = new http\Request('another/action'); + $this->assertNull($this->fixture->Evaluate($request)); + } + + public function testSimpleExtendedEvaluate() + { + $map = array( + 'one/two/three' => 'Invald', + 'another/action' => 'Valid', + 'four/five/six' => 'Invalid2' + ); + $this->fixture->set_map($map); + + $request = new http\Request('another/action/thing'); + $this->assertEquals('Valid', $this->fixture->Evaluate($request)); + } + + public function testSimplePrecedenceEvaluate() + { + $map = array( + 'some/action/first' => 'First', + 'some/action' => 'Second', + 'some/action/second' => 'Third' + ); + $this->fixture->set_map($map); + + $request = new http\Request('some/action/first'); + $this->assertEquals('First', $this->fixture->Evaluate($request)); + + $request = new http\Request('some/action/second'); + $this->assertEquals('Second', $this->fixture->Evaluate($request)); + + $request = new http\Request('some/action/third'); + $this->assertNull($this->fixture->Evaluate($request)); + } + + public function testExtractSingle() + { + $map = array( + 'action/one' => 'First', + 'user/view/{id}' => 'Second', + 'user/add' => 'Third' + ); + $this->fixture->set_map($map); + + $request = new http\Request('user/view/42'); + $this->assertEquals('Second', $this->fixture->Evaluate($request)); + $this->assertEquals('42', $request->data['id']); + + $request = new http\Request('user/add'); + $this->assertEquals('Third', $this->fixture->Evaluate($request)); + } + + public function testExtractDouble() + { + $map = array( + 'action/unused' => 'Invalid', + 'document/{action}/{key}' => 'DocumentController' + ); + $this->fixture->set_map($map); + + $request = new http\Request('document/edit/42'); + $this->assertEquals('DocumentController', $this->fixture->Evaluate($request)); + $this->assertEquals('edit', $request->data['action']); + $this->assertEquals('42', $request->data['key']); + } + + public function testExactMatch() + { + $map = array( + 'action/one' => 'First', + 'action/two//' => 'Second', + 'action/two/alpha' => 'Third' + ); + $this->fixure->set_map($map); + + $request = new http\Request('action/one'); + $this->assertEquals('First', $this->fixture->Evaluate($request)); + + $request = new http\Request('action/two'); + $this->assertEquals('Second', $this->fixture->Evaluate($request)); + + $request = new http\Request('action/two/alpha'); + $this->assertEquals('Third', $this->fixture->Evaluate($request)); + } + + public function testRegEx() + { + $map = array( + 'user/test' => 'First', + '/user\/([a-z]+)(\/([0-9]+))?/' => 'Second', + 'user/test2' => 'Third' + ); + $this->fixture->set_map($map); + + $request = new http\Request('user/test'); + $this->assertEquals('First', $this->fixture->Evaluate($request)); + + $request = new http\Request('user/add'); + $this->assertEquals('Second', $this->fixture->Evaluate($request)); + $this->assertEquals('add', $request->data['url_pattern'][1]); + $this->assertNull($request->data['url_pattern'][2]); + + $request = new http\Request('user/view/14'); + $this->assertEquals('Second', $this->fixture->Evaluate($request)); + $this->assertEquals('view', $request->data['url_pattern'][1]); + $this->assertEquals('14', $request->data['url_pattern'][2]); + + $request = new http\Request('user/test2'); + $this->assertEquals('Third', $this->fixture->Evaluate($request)); + } +} -- 2.22.5