From 50ca1aec1a9a38bf64e3867929261ce33ec66f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannis=20Mo=C3=9Fhammer?= Date: Wed, 31 Jul 2013 10:59:34 +0200 Subject: [PATCH] Refactor URL class and test The constructor of the class is now private, instantiation happens with Url::fromRequest and Url::fromPath. Also updated all occurences of Url and fixed the Qlink helper to not overwrite the baseUrl with null values refs #4381 --- application/views/helpers/QUrl.php | 2 +- application/views/helpers/Qlink.php | 7 +- library/Icinga/File/Pdf.php | 2 +- library/Icinga/Web/Url.php | 312 +++++++++++---- library/Icinga/Web/View/helpers/url.php | 4 +- library/Icinga/Web/Widget/Dashboard.php | 6 +- .../Icinga/Web/Widget/Dashboard/Component.php | 4 +- library/Icinga/Web/Widget/Tabs.php | 14 +- .../controllers/SoapController.php | 2 +- test/php/library/Icinga/Web/UrlTest.php | 364 ++++++++++++++++++ 10 files changed, 617 insertions(+), 100 deletions(-) create mode 100644 test/php/library/Icinga/Web/UrlTest.php diff --git a/application/views/helpers/QUrl.php b/application/views/helpers/QUrl.php index 56f1d704e..fbd66b5e3 100644 --- a/application/views/helpers/QUrl.php +++ b/application/views/helpers/QUrl.php @@ -38,7 +38,7 @@ class Zend_View_Helper_QUrl extends Zend_View_Helper_Abstract } else { $params = array(); } - return Url::create($url, $params); + return Url::fromPath($url, $params); $params = array_map('rawurlencode', $params); return $this->view->baseUrl(vsprintf($url, $params)); } diff --git a/application/views/helpers/Qlink.php b/application/views/helpers/Qlink.php index 6747db786..7b456f625 100755 --- a/application/views/helpers/Qlink.php +++ b/application/views/helpers/Qlink.php @@ -79,9 +79,12 @@ class Zend_View_Helper_Qlink extends Zend_View_Helper_Abstract $url = $urlFormat; $uriParams = $url->getParams() + $uriParams; } else { - $url = Url::create($urlFormat); + $url = Url::fromPath($urlFormat); + } + $url->setParams($uriParams); + if ($baseUrl) { + $url->setBaseUrl($baseUrl); } - $url->setParams($uriParams)->setBaseUrl($baseUrl); return sprintf( '%s', // $this->getFormattedUrl($urlFormat, $uriParams, $baseUrl), diff --git a/library/Icinga/File/Pdf.php b/library/Icinga/File/Pdf.php index 0c8aebed1..289dfb692 100644 --- a/library/Icinga/File/Pdf.php +++ b/library/Icinga/File/Pdf.php @@ -12,7 +12,7 @@ define('K_TCPDF_EXTERNAL_CONFIG', true); //define('K_PATH_URL', 'http://net-test-icinga-vm1.adm.netways.de/develop/'); // ??? // define('K_PATH_URL', '/var/www/net-test-icinga-vm1.adm.netways.de/develop/public'); // ??? -define('K_PATH_URL', (string) Url::create('/') === '/' ? '' : (string) Url::create('/')); // ???'/')); +define('K_PATH_URL', (string) Url::fromPath('/') === '/' ? '' : (string) Url::fromPath('/')); // ???'/')); define('K_PATH_MAIN', dirname(ICINGA_LIBDIR) . '/public'); define('K_PATH_FONTS', ICINGA_LIBDIR . '/vendor/tcpdf/fonts/'); define('K_PATH_CACHE', ICINGA_LIBDIR . '/vendor/tcpdf/cache/'); diff --git a/library/Icinga/Web/Url.php b/library/Icinga/Web/Url.php index 1637c6b7b..b6c085c72 100644 --- a/library/Icinga/Web/Url.php +++ b/library/Icinga/Web/Url.php @@ -3,108 +3,221 @@ namespace Icinga\Web; use Icinga\Application\Icinga; -use Icinga\Exception\ProgrammingError; +/** + * Url class that provides convenient access to parameters, allows to modify query parameters and + * returns Urls reflecting all changes made to the url and to the parameters. + * + * Direct instantiation is prohibited and should be done either with @see Url::fromRequest() or + * @see Url::fromUrlString() + * + * Currently, protocol, host and port are ignored and will be implemented when required + * + */ class Url { - protected $params = array(); - protected $path; - protected $baseUrl; - protected $request; + /** + * An array of all parameters stored in this Url + * + * @var array + */ + private $params = array(); - public function __construct($url, $params = null, $request = null) + /** + * The relative path of this Url, without query parameters + * + * @var string + */ + private $path = ''; + + /** + * The baseUrl that will be appended to @see Url::$path in order to + * create an absolute Url + * + * @var string + */ + private $baseUrl = '/'; + + + + private function __construct() + { + } + + /** + * Create a new Url class representing the current request + * + * If $params are given, those will be added to the request's parameters + * and overwrite any existing parameters + * + * @param string $url The string representation of the Url to parse + * @param array $params Parameters that should additionally be considered for the Url + * @param Zend_Request $request A request to use instead of the default one + * + * @return Url + */ + public static function fromRequest(array $params = array(), $request = null) { if ($request === null) { - $this->request = Icinga::app()->getFrontController()->getRequest(); - } else { - // Tests only - $this->request = $request; - } - if ($url === null) { - $this->path = $this->request->getPathInfo(); - $this->params = $this->request->getQuery(); - } else { - if (($split = strpos($url, '?')) === false) { - $this->path = $url; - } else { - $this->path = substr($url, 0, $split); - // TODO: Use something better than parse_str - parse_str(substr($url, $split + 1), $urlParams); - $this->params = $urlParams; - } - } - if (! empty($params)) { - $this->setParams($params); + $request = Icinga::app()->getFrontController()->getRequest(); } + + $urlObject = new Url(); + $urlObject->setPath($request->getPathInfo()); + $urlObject->setParams(array_merge($request->getQuery(), $params)); + $urlObject->setBaseUrl($request->getBaseUrl()); + return $urlObject; } - public static function create($url, $params = null, $request = null) + /** + * Create a new Url class representing the given url + * + * If $params are given, those will be added to the urls parameters + * and overwrite any existing parameters + * + * @param string $url The string representation of the Url to parse + * @param array $params An array of parameters that should additionally be considered for the Url + * @param Zend_Request $request A request to use instead of the default one + * + * @return Url + */ + public static function fromPath($url, array $params = array(), $request = null) { - $u = new Url($url, $params, $request); - return $u; + $urlObject = new Url(); + if ($request === null) { + $request = Icinga::app()->getFrontController()->getRequest(); + } + $urlObject->setBaseUrl($request->getBaseUrl()); + + $urlParts = parse_url($url); + if (isset($urlParts["path"])) { + $urlObject->setPath($urlParts["path"]); + } + if (isset($urlParts["query"])) { + parse_str($urlParts["query"], $urlParams); + $params = array_merge($urlParams, $params); + } + + $urlObject->setParams($params); + return $urlObject; } - // For tests + + /** + * Overwrite the baseUrl. + * + * If an empty Url is given '/' is used as the base + * + * @param string $baseUrl The url path to use as the Url Base + * @return $this + */ public function setBaseUrl($baseUrl) { + if (trim($baseUrl) == '') { + $baseUrl = '/'; + } $this->baseUrl = $baseUrl; return $this; } - public static function current($request = null) + /** + * Set the relative path of this url, without query parameters + * + * @param string $path The path to set + */ + public function setPath($path) { - $url = new Url(null, null, $request); - return $url; + $this->path = $path; } + /** + * Return the relative path of this Url, without query parameters + * + * If you want the relative path with query parameters use getRelativeUrl + * + * @return string + */ public function getPath() { return $this->path; } - public function getRelative() + /** + * Return the relative url with query parameters as a string + * + * @return string + */ + public function getRelativeUrl() { - $params = $args = array(); - foreach ($this->params as $name => $value) { - if (is_int($name)) { - $params[] = rawurlencode($value); - } else { - $args[] = rawurlencode($name) . '=' . rawurlencode($value); - } - } - $url = vsprintf($this->path, $params); - if (! empty($args)) { - $url .= '?' . implode('&', $args); - } - return $url; + if (empty($this->params)) + return ltrim($this->path,'/'); + return ltrim($this->path,'/').'?'.http_build_query($this->params); } - public function addParams($params) + /** + * Return the absolute url with query parameters as a string + * + * @return string + */ + public function getAbsoluteUrl() + { + $url = $this->getRelativeUrl(); + $baseUrl = '/'.ltrim($this->baseUrl, '/'); + return $baseUrl.'/'.$url; + } + + /** + * Add a set of parameters to the query part + * + * @param array $params The parameters to add + * @return $this + */ + public function addParams(array $params) { $this->params += $params; return $this; } - public function setParams($params) + /** + * Overwrite the parameters used in the query part + * + * @param array $params The new parameters to use for the query part + * @return $this + */ + public function setParams(array $params) { - if ($params === null) { - $this->params = array(); - } else { - $this->params = $params; - } + $this->params = $params; return $this; } + /** + * Return all parameters that will be used in the query part + * + * @return array An associative key => value array containing all parameters + */ public function getParams() { return $this->params; } + /** + * Return true if the Urls' query parameter with $key exists, otherwise false + * + * @param $key A key to check for existing + * @return bool + */ public function hasParam($key) { return array_key_exists($key, $this->params); } + /** + * Return the Url's query parameter with the name $key if exists, otherwise $default + * + * @param $key A query parameter name to return if existing + * @param mixed $default A value to return when the parameter doesn't exist + * @return mixed + */ public function getParam($key, $default = null) { if ($this->hasParam($key)) { @@ -113,48 +226,85 @@ class Url return $default; } + /** + * Set a single parameter $key, overwriting existing ones with the same key + * + * @param string $key A string representing the key of the parameter + * @param array|string $value An array or string to set as the parameter value + * @return $this + */ public function setParam($key, $value) { $this->params[$key] = $value; return $this; } - public function remove() + /** + * Remove provided key (if string) or keys (if array of string) from the query parameter array + * + * @param string|array $keyOrArrayOfKeys An array of strings or a string representing the key(s) + * of the parameters to be removed + * @return $this + */ + public function remove($keyOrArrayOfKeys) { - $args = func_get_args(); - foreach ($args as $keys) { - if (! is_array($keys)) { - $keys = array($keys); - } - foreach ($keys as $key) { - if (array_key_exists($key, $this->params)) { - unset($this->params[$key]); - } - } + if (is_array($keyOrArrayOfKeys)) { + $this->removeKeys($keyOrArrayOfKeys); + } else { + $this->removeKey($keyOrArrayOfKeys); } return $this; } - public function without() + /** + * Remove all parameters with the parameter names in the $keys array + * + * @param array $keys An array of strings containing parameter names to remove + * @return $this + */ + public function removeKeys(array $keys) { - $url = clone($this); - $args = func_get_args(); - return call_user_func_array(array($url, 'remove'), $args); + foreach ($keys as $key) { + $this->removeKey($key); + } + return $this; } - public function __toString() + /** + * Remove a single parameter with the provided parameter name $key + * + * @param string $key The key to remove from the Url + * @return $this + */ + public function removeKey($key) { - $url = $this->getRelative(); - $base = null === $this->baseUrl - ? $this->request->getBaseUrl() - : $this->baseUrl; - if ($base === '' && $url[0]!== '/') { - // Otherwise all URLs would be relative to wherever you are - $base = '/'; + if (isset($this->params[$key])) { + unset($this->params[$key]); } - if (strlen($base) > 0 && strlen($url) > 0 && $url[0] !== '?') { - $base = rtrim($base, '/') . '/'; - } - return $base . $url; + return $this; + } + + /** + * Return a copy of this url without the parameter given + * + * The argument can either a single query parameter name or an array of parameter names to + * remove from the query list + * + * @param string|array $keyOrArrayOfKeys A single string or an array containing parameter names + * @return Url + */ + public function getUrlWithout($keyOrArrayOfKeys) + { + $url = clone($this); + $url->remove($keyOrArrayOfKeys); + return $url; + } + + /** + * Alias for @see Url::getAbsoluteUrl() + * @return mixed + */ + public function __toString() { + return $this->getAbsoluteUrl(); } } diff --git a/library/Icinga/Web/View/helpers/url.php b/library/Icinga/Web/View/helpers/url.php index 41a8608c7..eb07ebf9f 100644 --- a/library/Icinga/Web/View/helpers/url.php +++ b/library/Icinga/Web/View/helpers/url.php @@ -7,12 +7,12 @@ use Icinga\Web\Url; function url($path = null, $params = null) { if ($path === null) { - $url = Url::current(); + $url = Url::fromRequest(); if ($params !== null) { $url->setParams($params); } } else { - $url = Url::create($path, $params); + $url = Url::fromPath($path, $params); } return $url; } diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index 964a71e35..fb8770f25 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -24,7 +24,7 @@ class Dashboard extends AbstractWidget protected function init() { if ($this->url === null) { - $this->url = Url::current()->without($this->tabParam); + $this->url = Url::fromRequest()->without($this->tabParam); } } @@ -141,7 +141,7 @@ class Dashboard extends AbstractWidget { $active = $this->tabs()->getActiveName(); if (! $active) { - if ($active = Url::current()->getParam($this->tabParam)) { + if ($active = Url::fromRequest()->getParam($this->tabParam)) { $this->activate($active); } else { reset($this->panes); @@ -186,7 +186,7 @@ class Dashboard extends AbstractWidget unset($item['base_url']); $this->getPane($dashboard)->addComponent( $title, - Url::create($base_url, $item) + Url::fromPath($base_url, $item) ); } } diff --git a/library/Icinga/Web/Widget/Dashboard/Component.php b/library/Icinga/Web/Widget/Dashboard/Component.php index 81fe64d62..48ddd78e0 100644 --- a/library/Icinga/Web/Widget/Dashboard/Component.php +++ b/library/Icinga/Web/Widget/Dashboard/Component.php @@ -22,7 +22,7 @@ class Component if ($url instanceof Url) { $this->url = $url; } else { - $this->url = Url::create($url); + $this->url = Url::fromPath($url); } } @@ -57,7 +57,7 @@ class Component if ($url instanceof Url) { $this->url = $url; } else { - $this->url = Url::create($url); + $this->url = Url::fromPath($url); } return $this; } diff --git a/library/Icinga/Web/Widget/Tabs.php b/library/Icinga/Web/Widget/Tabs.php index db568a277..8e9c3483d 100644 --- a/library/Icinga/Web/Widget/Tabs.php +++ b/library/Icinga/Web/Widget/Tabs.php @@ -204,34 +204,34 @@ class Tabs extends AbstractWidget implements Countable $special = array(); $special[] = $this->view()->qlink( $this->view()->img('img/classic/application-pdf.png') . ' PDF', - Url::current(), + Url::fromRequest(), array('filetype' => 'pdf'), array('target' => '_blank', 'quote' => false) ); $special[] = $this->view()->qlink( $this->view()->img('img/classic/application-csv.png') . ' CSV', - Url::current(), + Url::fromRequest(), array('format' => 'csv'), array('target' => '_blank', 'quote' => false) ); $special[] = $this->view()->qlink( $this->view()->img('img/classic/application-json.png') . ' JSON', - Url::current(), + Url::fromRequest(), array('format' => 'json', 'quote' => false), array('target' => '_blank', 'quote' => false) ); $special[] = $this->view()->qlink( $this->view()->img('img/classic/basket.png') . ' URL Basket', - Url::create('basket/add'), - array('url' => Url::current()->getRelative()), + Url::fromPath('basket/add'), + array('url' => Url::fromRequest()->getRelativeUrl()), array('quote' => false) ); $special[] = $this->view()->qlink( $this->view()->img('img/classic/dashboard.png') . ' Dashboard', - Url::create('dashboard/addurl'), - array('url' => Url::current()->getRelative()), + Url::fromPath('dashboard/addurl'), + array('url' => Url::fromRequest()->getRelativeUrl()), array('quote' => false) ); // $auth = Auth::getInstance(); diff --git a/modules/monitoring/application/controllers/SoapController.php b/modules/monitoring/application/controllers/SoapController.php index d6a7a1d80..f849200ec 100644 --- a/modules/monitoring/application/controllers/SoapController.php +++ b/modules/monitoring/application/controllers/SoapController.php @@ -39,7 +39,7 @@ class Monitoring_SoapController extends ModuleActionController $wsdl->handle(); } else { $wsdl->dump('/tmp/test.wsdl'); - $uri = 'http://itenos-devel.tom.local/' . Url::create('monitoring/soap'); + $uri = 'http://itenos-devel.tom.local/' . Url::fromPath('monitoring/soap'); $server = new Zend_Soap_Server('/tmp/test.wsdl'); $server->setClass('Api'); $server->handle(); diff --git a/test/php/library/Icinga/Web/UrlTest.php b/test/php/library/Icinga/Web/UrlTest.php new file mode 100644 index 000000000..06a9038ef --- /dev/null +++ b/test/php/library/Icinga/Web/UrlTest.php @@ -0,0 +1,364 @@ +path; + } + + /** + * Returns the baseUrl set for the request + * + * @return string + */ + public function getBaseUrl() + { + return $this->baseUrl; + } + + /** + * Returns the query set for the request + * + * @return array + */ + public function getQuery() + { + return $this->query; + } +} + + +/** + * Tests for the Icinga\Web\Url class that provides convenient access to Url manipulation method + * + * + */ +class UrlTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Tests whether a simple Url without query parameters and baseUrl is correctly parsed and returns correct Urls + * + */ + function testFromStringWithoutQuery() + { + $url = Url::fromPath('http://myHost/my/test/url.html', array(), new RequestMock()); + $this->assertEquals('/my/test/url.html', $url->getPath(), 'Assert the parsed url path to be equal to the input path'); + $this->assertEquals($url->getPath(), '/'.$url->getRelativeUrl(), 'Assert the path of an url without query to be equal the relative path'); + } + + /** + * Tests whether a simple Url without query parameters and with baseUrl is correctly parsed and returns correct Urls + * + */ + function testFromUrlWithBasePath() + { + $url = Url::fromPath('my/test/url.html', array(), new RequestMock()); + $url->setBaseUrl('the/path/to'); + $this->assertEquals('/the/path/to/my/test/url.html', $url->getAbsoluteUrl(), 'Assert the url path to be the base path with the relative path'); + } + + /** + * Tests whether query parameters in Urls are correctly recognized and decoded + * + */ + function testFromUrlWithKeyValueQuery() + { + $url = Url::fromPath('/my/test/url.html?param1=%25arg1¶m2=arg2', array(), new RequestMock()); + $this->assertEquals('/my/test/url.html', $url->getPath(), 'Assert the parsed url path to be equal to the input path'); + $this->assertEquals( + array( + 'param1' => '%arg1', + 'param2' => 'arg2' + ), + $url->getParams(), + 'Assert single key=value Url parameters to be correctly parsed and recognized' + ); + } + + /** + * Tests whether unnamed query parameters in Urls are correctly recognized and decoded + * + */ + function testFromUrlWithArrayInQuery() + { + $url = Url::fromPath('/my/test/url.html?param[]=%25val1¶m[]=%40val2', array(), new RequestMock()); + $this->assertEquals( + array( + 'param' => array('%val1', '@val2') + ), + $url->getParams(), + 'Assert arrays in param[] = value syntax to be correctly recognized and parsed as arrays' + ); + } + + /** + * Tests whether named query parameters in Urls are correctly recognized and decoded + * + */ + function testFromUrlWithAssociativeArrayInQuery() + { + $url = Url::fromPath('/my/test/url.html?param[value]=%25val1¶m[value2]=%40val2', array(), new RequestMock()); + $this->assertEquals( + array( + 'param' => array( + 'value' => '%val1', + 'value2' => '@val2' + ) + ), + $url->getParams(), + 'Assert arrays in param[] = value syntax to be correctly recognized and parsed as arrays' + ); + } + + /** + * Tests whether simple query parameters can be correctly added on an existing query and ends up in correct Urls + * + */ + function testAddQueryParameterToUrlWithoutQuery() + { + $url = Url::fromPath( + '/my/test/url.html', + array( + 'param1' => 'val1', + 'param2' => 'val2' + ), + new RequestMock() + ); + $url->setBaseUrl('path/to'); + $this->assertEquals( + '/path/to/my/test/url.html?param1=val1¶m2=val2', + $url->getAbsoluteUrl(), + 'Assert additional parameters to be correctly added to the Url' + ); + } + + /** + * Test whether parameters are correctly added to existing query parameters and existing ones are correctly overwritten + * if they have the same key + * + */ + function testOverwritePartialQuery() + { + $url = Url::fromPath( + '/my/test/url.html?param1=oldval1', + array( + 'param1' => 'val1', + 'param2' => 'val2' + ), + new RequestMock() + ); + $url->setBaseUrl('path/to'); + $this->assertEquals( + '/path/to/my/test/url.html?param1=val1¶m2=val2', + $url->getAbsoluteUrl(), + 'Assert additional parameters to be correctly added to the Url and overwriting existing parameters' + ); + } + + /** + * Test whether array parameters are correctly added to an existing Url and end up in correct Urls + * + */ + function testSetQueryWithArrayParameter() + { + $url = Url::fromPath( + '/my/test/url.html', + array( + 'flatarray' => array('val1', 'val2'), + 'param' => array('value1'=>'val1', 'value2' => 'val2') + ), + new RequestMock() + ); + $url->setBaseUrl('path/to'); + $this->assertEquals( + '/path/to/my/test/url.html?flatarray'.urlencode('[0]').'=val1&'. + 'flatarray'.urlencode('[1]').'=val2&'. + 'param'.urlencode('[value1]').'=val1&'. + 'param'.urlencode('[value2]').'=val2', + $url->getAbsoluteUrl(), + 'Assert array parameters to be correctly encoded and added to the Url' + ); + } + + /** + * Test whether Urls from the request are correctly parsed when no query is given + * + */ + function testUrlFromRequestWithoutQuery() + { + $request = new RequestMock(); + $request->baseUrl = 'path/to'; + $request->path = 'my/test/url.html'; + $request->query = array(); + $url = Url::fromRequest(array(), $request); + $this->assertEquals( + '/path/to/my/test/url.html', + $url->getAbsoluteUrl(), + 'Asserting absolute path resembling the requests path appended by the baseUrl' + ); + } + + /** + * Test whether Urls from the request are correctly parsed when a query is given + * + */ + function testUrlFromRequestWithQuery() + { + $request = new RequestMock(); + $request->baseUrl = 'path/to'; + $request->path = 'my/test/url.html'; + $request->query = array( + 'param1' => 'value1', + 'param2' => array('key1' => 'value1', 'key2' => 'value2') + ); + $url = Url::fromRequest(array(), $request); + $this->assertEquals( + '/path/to/my/test/url.html?param1=value1&'. + 'param2'.urlencode('[key1]').'=value1&'. + 'param2'.urlencode('[key2]').'=value2', + $url->getAbsoluteUrl(), + 'Asserting absolute path resembling the requests path appended by the baseUrl' + ); + } + + /** + * Test the @see Url::getParam($name, $default) function + * + */ + function testGetParameterByName() + { + $url = Url::fromPath('/my/test/url.html?param=val¶m2=val2', array(), new RequestMock()); + $this->assertEquals( + "val", + $url->getParam("param", "wrongval"), + "Asserting a parameter can be fetched via getParam()" + ); + $this->assertEquals( + "val2", + $url->getParam("param2", "wrongval2"), + "Asserting a parameter can be fetched via getParam()" + ); + $this->assertEquals( + "nonexisting", + $url->getParam("param3", "nonexisting"), + "Asserting a non existing parameter returning the default value when fetched via getParam()" + ); + } + + /** + * Test the Url::remove function with a single key passed + * + */ + function testRemoveSingleParameter() + { + $url = Url::fromPath('/my/test/url.html?param=val¶m2=val2', array(), new RequestMock()); + $url->remove("param"); + $this->assertEquals( + "val2", + $url->getParam("param2", "wrongval2"), + "Asserting other parameters (param2) not being affected by remove" + ); + $this->assertEquals( + "rightval", + $url->getParam("param", "rightval"), + "Asserting a parameter (param) can be removed via remove" + ); + } + + /** + * Test the Url::remove function with an array of keys passed + * + */ + function testRemoveMultipleParameters() + { + $url = Url::fromPath('/my/test/url.html?param=val¶m2=val2¶m3=val3', array(), new RequestMock()); + $url->remove(array("param", "param2")); + $this->assertEquals( + "val3", + $url->getParam("param3", "wrongval"), + "Asserting other parameters (param3) not being affected by remove" + ); + $this->assertEquals( + "rightval", + $url->getParam("param", "rightval"), + "Asserting a parameter (param) can be removed via remove in a batch" + ); + $this->assertEquals( + "rightval", + $url->getParam("param2", "rightval"), + "Asserting a parameter (param2) can be removed via remove in a batch" + ); + } + + /** + * Test the Url::without call and whether it returns a copy instead of working on the called object + * + */ + function testWithoutCall() + { + $url = Url::fromPath('/my/test/url.html?param=val¶m2=val2¶m3=val3', array(), new RequestMock()); + $url2 = $url->getUrlWithout(array("param")); + $this->assertNotEquals( + $url, + $url2, + "Asserting without creating a copy of the url" + ); + $this->assertTrue( + $url->hasParam("param"), + "Asserting the original Url not being affected when calling 'without'" + ); + $this->assertFalse( + $url2->hasParam("param"), + "Asserting the returned Url being without the passed parameter when calling 'without'" + ); + } + + /** + * Test whether toString is the same as getAbsoluteUrl + * + */ + function testToString() + { + $url = Url::fromPath('/my/test/url.html?param=val¶m2=val2¶m3=val3', array(), new RequestMock()); + $this->assertEquals($url->getAbsoluteUrl(), (string) $url, "Asserting whether toString returns the absolute Url"); + } +} \ No newline at end of file