Browse Source

Fix Url helper and Behaviors.

dereuromark 9 years ago
parent
commit
5773b37239

+ 60 - 0
docs/Behavior/String.md

@@ -0,0 +1,60 @@
+# String Behavior
+
+A CakePHP behavior to apply basic string operations for your input.
+
+Note that most string modification should be done once, on save.
+Prevent using output modification if possible as it is done on every fetch.
+
+### Usage
+
+#### Input formatting
+Include behavior in your Table class as
+```php
+$this->addBehavior('Tools.String', [
+	'fields' => ['title'], 
+	'input' => ['ucfirst'],
+]);
+```
+This will `ucfirst()` the title prior to saving.
+
+Tip: If you have other behaviors that might modify the array data prior to saving, better use a lower (higher value) priority:
+```php
+$this->addBehavior('Tools.String', [
+	...
+	'priority' => 11,
+]);
+```
+
+The input filters are an array and therefore can also be stacked. They will be executed in the order given. 
+If string that function is expected to exist. You can also use callables and anonymous functions, of course. 
+
+#### Output formatting
+Instead of the preferred input formatting you can also modify the output (for each find):
+```php
+$this->addBehavior('Tools.String', [
+	...
+	'output' => ['ucfirst'],
+]);
+```
+
+
+### Examples
+
+Imagine the following config:
+```php
+	'fields' => ['title', 'comment'], 
+	'input' => ['strtolower', 'ucwords'],
+```
+
+And the input:
+```php
+$data = [
+	'title' => 'some nAme',
+	'comment' => 'myBlog',
+	'url' => 'www.dereuromark.de',
+];
+$comment = $this->Comments->newEntity($data);
+$result = $this->Comments->save($comment);
+```
+
+The title would be saved as `Some Name` and the comment as `MyBlog`.

+ 1 - 0
docs/README.md

@@ -18,6 +18,7 @@ This cake3 branch only works for **CakePHP3.x** - please use the master branch f
 * [Behavior/Slugged](Behavior/Slugged.md)
 * [Behavior/Bitmasked](Behavior/Bitmasked.md)
 * [Behavior/Reset](Behavior/Reset.md)
+* [Behavior/String](Behavior/String.md)
 * [View/Rss](View/Rss.md)
 * [Testing](TestSuite/Testing.md)
 

+ 21 - 20
src/Model/Behavior/JsonableBehavior.php

@@ -37,6 +37,8 @@ use Tools\Utility\Text;
  */
 class JsonableBehavior extends Behavior {
 
+	const OPTIONS_DEFAULT = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_ERROR_INF_OR_NAN | JSON_PARTIAL_OUTPUT_ON_ERROR;
+
 	/**
 	 * @var string|false|null
 	 */
@@ -60,7 +62,7 @@ class JsonableBehavior extends Behavior {
 		'unique' => true, // only for list (autoclean values on insert),
 		'map' => [], // map on a different DB field
 		'encodeParams' => [ // params for json_encode
-			'options' => 0,
+			'options' => null,
 			'depth' => 512,
 		],
 		'decodeParams' => [ // params for json_decode
@@ -71,8 +73,6 @@ class JsonableBehavior extends Behavior {
 	];
 
 	/**
-	 * JsonableBehavior::initialize()
-	 *
 	 * @param array $config
 	 * @return void
 	 */
@@ -93,6 +93,9 @@ class JsonableBehavior extends Behavior {
 		foreach ($this->_config['fields'] as $field) {
 			$this->_table->schema()->columnType($field, 'array');
 		}
+		if ($this->_config['encodeParams']['options'] === null) {
+			$this->_config['encodeParams']['options'] = static::OPTIONS_DEFAULT;
+		}
 	}
 
 	/**
@@ -153,8 +156,6 @@ class JsonableBehavior extends Behavior {
 	}
 
 	/**
-	 * JsonableBehavior::_getMappedFields()
-	 *
 	 * @return array
 	 */
 	protected function _getMappedFields() {
@@ -177,10 +178,8 @@ class JsonableBehavior extends Behavior {
 	}
 
 	/**
-	 * JsonableBehavior::_encode()
-	 *
-	 * @param mixed $val
-	 * @return string
+	 * @param array|string $val
+	 * @return string|null
 	 */
 	public function _encode($val) {
 		if (!empty($this->_config['fields'])) {
@@ -197,23 +196,18 @@ class JsonableBehavior extends Behavior {
 			}
 		}
 
-		if (is_array($val)) {
-			// Depth param added in PHP 5.5
-			if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
-				$val = json_encode($val, $this->_config['encodeParams']['options'], $this->_config['encodeParams']['depth']);
-			} else {
-				$val = json_encode($val, $this->_config['encodeParams']['options']);
-			}
+		if (!is_array($val)) {
+			return null;
 		}
 
-		return $val;
+		return json_encode($val, $this->_config['encodeParams']['options'], $this->_config['encodeParams']['depth']);
 	}
 
 	/**
 	 * Fields are absolutely necessary to function properly!
 	 *
-	 * @param mixed $val
-	 * @return mixed
+	 * @param array|null $val
+	 * @return array|null|false
 	 */
 	public function _decode($val) {
 		if (!is_string($val)) {
@@ -250,6 +244,11 @@ class JsonableBehavior extends Behavior {
 		return implode($this->_config['separator'], $res);
 	}
 
+	/**
+	 * @param string $val
+	 *
+	 * @return array
+	 */
 	public function _fromParam($val) {
 		$leftBound = $this->_config['leftBound'];
 		$rightBound = $this->_config['rightBound'];
@@ -283,7 +282,9 @@ class JsonableBehavior extends Behavior {
 	 * @return array
 	 */
 	public function _fromList($val) {
-		extract($this->_config);
+		$separator = $this->_config['separator'];
+		$leftBound = $this->_config['leftBound'];
+		$rightBound = $this->_config['rightBound'];
 
 		return Text::tokenize($val, $separator, $leftBound, $rightBound);
 	}

+ 8 - 10
src/Model/Behavior/NeighborBehavior.php

@@ -12,25 +12,25 @@ use InvalidArgumentException;
 class NeighborBehavior extends Behavior {
 
 	/**
-	 * Default config for a model that has this behavior attached.
-	 *
-	 * Setting force_modified to true will have the same effect as overriding the save method as
-	 * described in the code example for "Using created and modified" in the Cookbook.
-	 *
 	 * @var array
-	 * @link http://book.cakephp.org/2.0/en/models/saving-your-data.html#using-created-and-modified
 	 */
 	protected $_defaultConfig = [
 	];
 
+	/**
+	 * @param int $id
+	 * @param array $options
+	 *
+	 * @return array
+	 */
 	public function neighbors($id, array $options = []) {
-		if (empty($id)) {
+		if (!$id) {
 			throw new InvalidArgumentException("The 'id' key is required for find('neighbors')");
 		}
+
 		$sortField = $this->_table->hasField('created') ? 'created' : $this->_table->primaryKey();
 		$defaults = [
 			'sortField' => $this->_table->alias() . '.' . $sortField,
-			//'displayField' => $this->_table->alias() . '.' . $this->_table->displayField()
 		];
 		$options += $defaults;
 
@@ -59,13 +59,11 @@ class NeighborBehavior extends Behavior {
 		$prevOptions = $findOptions;
 		$prevOptions['conditions'] = Hash::merge($prevOptions['conditions'], [$options['sortField'] . ' ' . $sortDirSymb[1] => $options['value']]);
 		$prevOptions['order'] = [$options['sortField'] => $sortDirWord[1]];
-		//debug($prevOptions);
 		$return['prev'] = $this->_table->find('all', $prevOptions)->first();
 
 		$nextOptions = $findOptions;
 		$nextOptions['conditions'] = Hash::merge($nextOptions['conditions'], [$options['sortField'] . ' ' . $sortDirSymb[0] => $options['value']]);
 		$nextOptions['order'] = [$options['sortField'] => $sortDirWord[0]];
-		//debug($nextOptions);
 		$return['next'] = $this->_table->find('all', $nextOptions)->first();
 
 		return $return;

+ 1 - 4
src/Model/Behavior/StringBehavior.php

@@ -38,8 +38,6 @@ class StringBehavior extends Behavior {
 	];
 
 	/**
-	 * JsonableBehavior::initialize()
-	 *
 	 * @param array $config
 	 * @return void
 	 */
@@ -56,8 +54,7 @@ class StringBehavior extends Behavior {
 	public function beforeFind(Event $event, Query $query) {
 		$query->formatResults(function (ResultSetInterface $results) {
 			return $results->map(function ($row) {
-				//TODO?
-				//$this->processItems($row, 'output');
+				$this->processItems($row, 'output');
 				return $row;
 			});
 		});

+ 10 - 0
src/Model/Table/Table.php

@@ -8,6 +8,16 @@ use Shim\Model\Table\Table as ShimTable;
 use Tools\Utility\Time;
 use Tools\Utility\Utility;
 
+/**
+ * @mixin \Tools\Model\Behavior\PasswordableBehavior
+ * @mixin \Tools\Model\Behavior\JsonableBehavior
+ * @mixin \Tools\Model\Behavior\BitmaskedBehavior
+ * @mixin \Tools\Model\Behavior\SluggedBehavior
+ * @mixin \Tools\Model\Behavior\NeighborBehavior
+ * @mixin \Tools\Model\Behavior\StringBehavior
+ * @mixin \Tools\Model\Behavior\ConfirmableBehavior
+ * @mixin \Tools\Model\Behavior\ResetBehavior
+ */
 class Table extends ShimTable {
 
 	/**

+ 5 - 0
src/Utility/Language.php

@@ -7,6 +7,11 @@ namespace Tools\Utility;
  */
 class Language {
 
+	/**
+	 * @param string|null $languageList
+	 *
+	 * @return array
+	 */
 	public static function parseLanguageList($languageList = null) {
 		if ($languageList === null) {
 			if (empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {

+ 32 - 16
src/View/Helper/UrlHelper.php

@@ -23,49 +23,65 @@ use Cake\View\Helper\UrlHelper as CoreUrlHelper;
 class UrlHelper extends CoreUrlHelper {
 
 	/**
-	 * @deprecated
-	 * @param string|array|null $url URL.
-	 * @param bool $full
-	 * @return string
-	 */
-	public function defaultBuild($url = null, $full = false) {
-		return $this->reset($url, $full);
-	}
-
-	/**
 	 * Creates a reset URL.
 	 * The prefix and plugin params are resetting to default false.
 	 *
+	 * Can only add defaults for array URLs.
+	 *
 	 * @param string|array|null $url URL.
 	 * @param bool $full If true, the full base URL will be prepended to the result
 	 * @return string Full translated URL with base path.
 	 */
 	public function reset($url = null, $full = false) {
 		if (is_array($url)) {
-			$url += ['prefix' => false, 'plugin' => false];
+			$url += $this->defaults();
 		}
+
 		return parent::build($url, $full);
 	}
 
 	/**
+	 * @return array
+     */
+	public function defaults() {
+		return [
+			'prefix' => false,
+			'plugin' => false
+		];
+	}
+
+	/**
 	 * Returns a URL based on provided parameters.
 	 *
+	 * Can only add query strings for array URLs.
+	 *
 	 * @param string|array|null $url URL.
 	 * @param bool $full If true, the full base URL will be prepended to the result
 	 * @return string Full translated URL with base path.
 	 */
 	public function complete($url = null, $full = false) {
 		if (is_array($url)) {
-			// Add query strings
-			if (!isset($url['?'])) {
-				$url['?'] = [];
-			}
-			$url['?'] += $this->request->query;
+			$url = $this->addQueryStrings($url);
 		}
+
 		return parent::build($url, $full);
 	}
 
 	/**
+	 * @param array $url
+	 *
+	 * @return array
+     */
+	protected function addQueryStrings(array $url) {
+		if (!isset($url['?'])) {
+			$url['?'] = [];
+		}
+		$url['?'] += $this->request->query;
+
+		return $url;
+	}
+
+	/**
 	 * Event listeners.
 	 *
 	 * @return array

+ 2 - 5
tests/TestApp/Controller/CommonComponentTestController.php

@@ -5,15 +5,12 @@ use Tools\Controller\Controller;
 
 /**
  * Use Controller instead of AppController to avoid conflicts
+ *
+ * @property \Tools\Controller\Component\CommonComponent $Common
  */
 class CommonComponentTestController extends Controller {
 
 	/**
-	 * @var string
-	 */
-	public $name = 'MyController';
-
-	/**
 	 * @var array
 	 */
 	public $components = ['Tools.Common'];

+ 3 - 0
tests/TestApp/Controller/MobileComponentTestController.php

@@ -3,6 +3,9 @@ namespace TestApp\Controller;
 
 use Tools\Controller\Controller;
 
+/**
+ * @property \Tools\Controller\Component\MobileComponent $Mobile
+ */
 class MobileComponentTestController extends Controller {
 
 	/**

+ 5 - 0
tests/TestCase/Controller/Component/CommonComponentTest.php

@@ -19,6 +19,11 @@ class CommonComponentTest extends TestCase {
 	public $Controller;
 
 	/**
+	 * @var \Cake\Network\Request
+	 */
+	public $request;
+
+	/**
 	 * @return void
 	 */
 	public function setUp() {

+ 75 - 20
tests/TestCase/Model/Behavior/JsonableBehaviorTest.php

@@ -72,8 +72,6 @@ class JsonableBehaviorTest extends TestCase {
 	}
 
 	/**
-	 * JsonableBehaviorTest::testFieldsWithList()
-	 *
 	 * @return void
 	 */
 	public function testFieldsWithList() {
@@ -111,8 +109,6 @@ class JsonableBehaviorTest extends TestCase {
 	}
 
 	/**
-	 * JsonableBehaviorTest::testFieldsWithParam()
-	 *
 	 * @return void
 	 */
 	public function testFieldsWithParam() {
@@ -133,13 +129,9 @@ class JsonableBehaviorTest extends TestCase {
 	}
 
 	/**
-	 * JsonableBehaviorTest::testFieldsOnFind()
-	 *
 	 * @return void
 	 */
 	public function testFieldsOnFind() {
-		//echo $this->_header(__FUNCTION__);
-
 		// array
 		$this->Comments->removeBehavior('Jsonable');
 		$this->Comments->addBehavior('Tools.Jsonable', ['fields' => ['details']]);
@@ -206,14 +198,9 @@ class JsonableBehaviorTest extends TestCase {
 	}
 
 	/**
-	 * JsonableBehaviorTest::testEncodeParams()
-	 *
 	 * @return void
 	 */
 	public function testEncodeParams() {
-		// $depth param added in 5.5.0
-		$this->skipIf(!version_compare(PHP_VERSION, '5.5.0', '>='));
-
 		// Test encode depth = 1
 		$this->Comments->removeBehavior('Jsonable');
 		$this->Comments->addBehavior('Tools.Jsonable', ['fields' => ['details'], 'encodeParams' => ['depth' => 1]]);
@@ -228,7 +215,7 @@ class JsonableBehaviorTest extends TestCase {
 		$this->Comments->save($entity);
 
 		$res = $this->Comments->find('all', ['conditions' => ['title' => 'param']])->first();
-		$expected = [];
+		$expected = ['x' => ['y' => 'z']];
 		$this->assertEquals($expected, $res['details']);
 
 		$this->Comments->truncate();
@@ -254,10 +241,10 @@ class JsonableBehaviorTest extends TestCase {
 		$this->assertEquals($expected, $res['details']);
 	}
 
+	/**
+	 * @return void
+	 */
 	public function testEncodeParamsAssocFalse() {
-		// $depth param added in 5.5.0
-		$this->skipIf(!version_compare(PHP_VERSION, '5.5.0', '>='));
-
 		// Test encode depth = 1
 		$this->Comments->removeBehavior('Jsonable');
 		$this->Comments->addBehavior('Tools.Jsonable', ['fields' => ['details'], 'encodeParams' => ['depth' => 1], 'decodeParams' => ['assoc' => false]]);
@@ -292,13 +279,13 @@ class JsonableBehaviorTest extends TestCase {
 		$this->Comments->save($entity);
 
 		$res = $this->Comments->find('all', ['conditions' => ['title' => 'param']])->first();
-		$expected = null;
+		$expected = new stdClass();
+		$expected->y = new stdClass();
+		$expected->y->yy = 'yyy';
 		$this->assertEquals($expected, $res['details']);
 	}
 
 	/**
-	 * JsonableBehaviorTest::testDecodeParams()
-	 *
 	 * @return void
 	 */
 	public function testDecodeParams() {
@@ -347,4 +334,72 @@ class JsonableBehaviorTest extends TestCase {
 		$this->assertEquals($expected, $res['details']);
 	}
 
+	/**
+	 * @return void
+	 */
+	public function testEncodeWithComplexContent()
+	{
+		$this->Comments->removeBehavior('Jsonable');
+		$this->Comments->addBehavior('Tools.Jsonable', [
+			'output' => 'array',
+			'fields' => ['details'],
+		]);
+
+		$data = [
+			'comment' => 'blabla',
+			'url' => 'www.dereuromark.de',
+			'title' => 'param',
+			'details' => [
+				'foo' => 'bar',
+				'nan' => NAN,
+				'inf' => INF,
+			],
+		];
+		$entity = $this->Comments->newEntity($data);
+		$result = $this->Comments->save($entity);
+		$this->assertTrue((bool)$result);
+
+		$res = $this->Comments->get($entity->id);
+		$expected = [
+			'foo' => 'bar',
+			'nan' => 0,
+			'inf' => 0,
+		];
+		$this->assertSame($expected, $res->details);
+	}
+
+	/**
+	 * @return void
+	 */
+	public function testEncodeWithNoParamsComplexContent()
+	{
+		$this->Comments->removeBehavior('Jsonable');
+		$this->Comments->addBehavior('Tools.Jsonable', [
+			'output' => 'array',
+			'fields' => ['details'],
+			'encodeParams' => [
+				'options' => 0
+			]
+		]);
+
+		$data = [
+			'comment' => 'blabla',
+			'url' => 'www.dereuromark.de',
+			'title' => 'param',
+			'details' => [
+				'foo' => 'bar',
+				'nan' => NAN,
+				'inf' => INF,
+			],
+		];
+		$entity = $this->Comments->newEntity($data);
+		$result = $this->Comments->save($entity);
+		$this->assertTrue((bool)$result);
+
+		$res = $this->Comments->get($entity->id);
+		$expected = [
+		];
+		$this->assertSame($expected, $res->details);
+	}
+
 }

+ 6 - 16
tests/TestCase/Model/Behavior/NeighborBehaviorTest.php

@@ -18,15 +18,19 @@ class NeighborBehaviorTest extends TestCase {
 	 */
 	public $fixtures = ['plugin.tools.stories'];
 
+	/**
+	 * @return void
+	 */
 	public function setUp() {
 		parent::setUp();
 
-		//Configure::write('App.namespace', 'TestApp');
-
 		$this->Table = TableRegistry::get('Stories');
 		$this->Table->addBehavior('Tools.Neighbor');
 	}
 
+	/**
+	 * @return void
+	 */
 	public function tearDown() {
 		TableRegistry::clear();
 
@@ -34,8 +38,6 @@ class NeighborBehaviorTest extends TestCase {
 	}
 
 	/**
-	 * NeighborBehaviorTest::testNeighborRecords()
-	 *
 	 * @return void
 	 */
 	public function testNeighbors() {
@@ -48,8 +50,6 @@ class NeighborBehaviorTest extends TestCase {
 	}
 
 	/**
-	 * NeighborBehaviorTest::testNeighborRecords()
-	 *
 	 * @return void
 	 */
 	public function testNeighborsReverse() {
@@ -62,8 +62,6 @@ class NeighborBehaviorTest extends TestCase {
 	}
 
 	/**
-	 * NeighborBehaviorTest::testNeighborRecords()
-	 *
 	 * @return void
 	 */
 	public function testNeighborsCustomSortField() {
@@ -76,22 +74,17 @@ class NeighborBehaviorTest extends TestCase {
 	}
 
 	/**
-	 * NeighborBehaviorTest::testNeighborRecords()
-	 *
 	 * @return void
 	 */
 	public function testNeighborsCustomFields() {
 		$id = 2;
 
 		$result = $this->Table->neighbors($id, ['sortField' => 'sort', 'fields' => ['title']]);
-		//debug($result);
 		$this->assertEquals(['title' => 'Second'], $result['prev']->toArray());
 		$this->assertEquals(['title' => 'First'], $result['next']->toArray());
 	}
 
 	/**
-	 * NeighborBehaviorTest::testNeighborRecords()
-	 *
 	 * @return void
 	 */
 	public function testNeighborsStart() {
@@ -104,15 +97,12 @@ class NeighborBehaviorTest extends TestCase {
 	}
 
 	/**
-	 * NeighborBehaviorTest::testNeighborRecords()
-	 *
 	 * @return void
 	 */
 	public function testNeighborsEnd() {
 		$id = 4;
 
 		$result = $this->Table->neighbors($id);
-		//debug($result);
 		$this->assertEquals('Third', $result['prev']['title']);
 		$this->assertNull($result['next']);
 	}

+ 23 - 6
tests/TestCase/Model/Behavior/StringBehaviorTest.php

@@ -27,15 +27,13 @@ class StringBehaviorTest extends TestCase {
 	}
 
 	/**
-	 * StringBehaviorTest::testBasic()
-	 *
 	 * @return void
 	 */
 	public function testBasic() {
 		$data = [
+			'title' => 'some Name',
 			'comment' => 'blabla',
 			'url' => 'www.dereuromark.de',
-			'title' => 'some Name',
 		];
 		$entity = $this->Comments->newEntity($data);
 		$res = $this->Comments->save($entity);
@@ -45,17 +43,15 @@ class StringBehaviorTest extends TestCase {
 	}
 
 	/**
-	 * StringBehaviorTest::testMultipleFieldsAndMultipleFilters()
-	 *
 	 * @return void
 	 */
 	public function testMultipleFieldsAndMultipleFilters() {
 		$this->Comments->behaviors()->String->config(['fields' => ['title', 'comment'], 'input' => ['strtolower', 'ucwords']]);
 
 		$data = [
+			'title' => 'some nAme',
 			'comment' => 'blaBla',
 			'url' => 'www.dereuromark.de',
-			'title' => 'some nAme',
 		];
 		$entity = $this->Comments->newEntity($data);
 		$res = $this->Comments->save($entity);
@@ -65,4 +61,25 @@ class StringBehaviorTest extends TestCase {
 		$this->assertSame('Blabla', $res['comment']);
 	}
 
+	/**
+	 * @return void
+	 */
+	public function testBasicOutput() {
+		$this->Comments->removeBehavior('String');
+
+		$data = [
+			'title' => 'some Name',
+			'comment' => 'blabla',
+			'url' => ''
+		];
+		$entity = $this->Comments->newEntity($data);
+		$res = $this->Comments->save($entity);
+		$this->assertTrue((bool)$res);
+
+		$this->Comments->addBehavior('Tools.String', ['fields' => ['title'], 'output' => ['ucfirst']]);
+
+		$res = $this->Comments->get($entity->id);
+		$this->assertSame('Some Name', $res['title']);
+	}
+
 }

+ 49 - 11
tests/TestCase/View/Helper/UrlHelperTest.php

@@ -2,6 +2,7 @@
 
 namespace Tools\Test\TestCase\View\Helper;
 
+use Cake\Core\Plugin;
 use Cake\Network\Request;
 use Cake\Routing\Router;
 use Cake\View\View;
@@ -13,6 +14,9 @@ use Tools\View\Helper\UrlHelper;
  */
 class UrlHelperTest extends TestCase {
 
+	/**
+	 * @return void
+	 */
 	public function setUp() {
 		parent::setUp();
 
@@ -31,29 +35,65 @@ class UrlHelperTest extends TestCase {
 
 		$result = $this->Url->reset(['controller' => 'foobar', 'action' => 'test']);
 		$expected = '/foobar/test';
-		$this->assertEquals($expected, $result);
+		$this->assertSame($expected, $result);
 
 		$this->Url->request->here = '/admin/foobar/test';
-		$this->Url->request->params['admin'] = true;
 		$this->Url->request->params['prefix'] = 'admin';
 		Router::reload();
 		Router::connect('/:controller/:action/*');
 		Router::prefix('admin', function ($routes) {
-			$routes->connect('/:controller/:action/*');
+			$routes->fallbacks();
 		});
+		Router::pushRequest($this->Url->request);
 
 		$result = $this->Url->build(['prefix' => 'admin', 'controller' => 'foobar', 'action' => 'test']);
 		$expected = '/admin/foobar/test';
-		$this->assertEquals($expected, $result);
+		$this->assertSame($expected, $result);
 
 		$result = $this->Url->build(['controller' => 'foobar', 'action' => 'test']);
 		$expected = '/admin/foobar/test';
-		//debug($result);
-		//$this->assertEquals($expected, $result);
+		$this->assertSame($expected, $result);
+
+		$result = $this->Url->reset(['controller' => 'foobar', 'action' => 'test']);
+		$expected = '/foobar/test';
+		$this->assertSame($expected, $result);
+	}
+
+	/**
+	 * Tests
+	 *
+	 * @return void
+	 */
+	public function testResetWithPlugin() {
+		Router::connect('/:controller/:action/*');
 
 		$result = $this->Url->reset(['controller' => 'foobar', 'action' => 'test']);
 		$expected = '/foobar/test';
-		$this->assertEquals($expected, $result);
+		$this->assertSame($expected, $result);
+
+		$this->Url->request->here = '/admin/foo/bar/baz/test';
+		$this->Url->request->params['prefix'] = 'admin';
+		$this->Url->request->params['plugin'] = 'Foo';
+		Router::reload();
+		Router::connect('/:controller/:action/*');
+		Router::plugin('Foo', function ($routes) {
+			$routes->fallbacks();
+		});
+		Router::prefix('admin', function ($routes) {
+			$routes->plugin('Foo', function ($routes) {
+				$routes->fallbacks();
+			});
+		});
+		Plugin::routes();
+		Router::pushRequest($this->Url->request);
+
+		$result = $this->Url->build(['controller' => 'bar', 'action' => 'baz', 'x']);
+		$expected = '/admin/foo/bar/baz/x';
+		$this->assertSame($expected, $result);
+
+		$result = $this->Url->reset(['controller' => 'bar', 'action' => 'baz', 'x']);
+		$expected = '/bar/baz/x';
+		$this->assertSame($expected, $result);
 	}
 
 	/**
@@ -66,16 +106,14 @@ class UrlHelperTest extends TestCase {
 
 		$result = $this->Url->complete(['action' => 'test']);
 		$expected = '/test?x=y';
-		$this->assertEquals($expected, $result);
+		$this->assertSame($expected, $result);
 
 		$result = $this->Url->complete(['action' => 'test', '?' => ['a' => 'b']]);
 		$expected = '/test?a=b&x=y';
-		$this->assertEquals($expected, $result);
+		$this->assertSame($expected, $result);
 	}
 
 	/**
-	 * TearDown method
-	 *
 	 * @return void
 	 */
 	public function tearDown() {