From 1455c59e0ce56d132094630a2f39f0e2d4c373ad Mon Sep 17 00:00:00 2001 From: Majna Date: Fri, 4 Nov 2011 15:12:14 +0100 Subject: [PATCH 01/31] Fix notice when baking db config: Undefined variable 'driver'. --- lib/Cake/Console/Command/Task/DbConfigTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Console/Command/Task/DbConfigTask.php b/lib/Cake/Console/Command/Task/DbConfigTask.php index 20469bcd3..757f86a3b 100644 --- a/lib/Cake/Console/Command/Task/DbConfigTask.php +++ b/lib/Cake/Console/Command/Task/DbConfigTask.php @@ -314,7 +314,7 @@ class DbConfigTask extends Shell { extract($config); $out .= "\tpublic \${$name} = array(\n"; - $out .= "\t\t'datasource' => 'Database/{$driver}',\n"; + $out .= "\t\t'datasource' => 'Database/{$datasource}',\n"; $out .= "\t\t'persistent' => {$persistent},\n"; $out .= "\t\t'host' => '{$host}',\n"; From 1b9b90d2e7dc3f51aa5da8f4a14b7b304da76b2c Mon Sep 17 00:00:00 2001 From: Majna Date: Fri, 4 Nov 2011 23:07:31 +0100 Subject: [PATCH 02/31] Replacing 'driver' with 'datasource'. --- app/Config/database.php.default | 6 +++--- lib/Cake/Console/Command/Task/DbConfigTask.php | 8 ++++---- .../Console/Templates/skel/Config/database.php.default | 6 +++--- .../Test/Case/Console/Command/Task/DbConfigTaskTest.php | 2 +- lib/Cake/Test/Case/Utility/DebuggerTest.php | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/Config/database.php.default b/app/Config/database.php.default index 3ce441be3..11fca6fb5 100644 --- a/app/Config/database.php.default +++ b/app/Config/database.php.default @@ -27,14 +27,14 @@ * Database configuration class. * You can specify multiple configurations for production, development and testing. * - * driver => The name of a supported driver; valid options are as follows: + * datasource => The name of a supported datasource; valid options are as follows: * Database/Mysql - MySQL 4 & 5, * Database/Sqlite - SQLite (PHP5 only), * Database/Postgres - PostgreSQL 7 and higher, * Database/Sqlserver - Microsoft SQL Server 2005 and higher * - * You can add custom database drivers (or override existing drivers) by adding the - * appropriate file to app/Model/Datasource/Database. Drivers should be named 'MyDriver.php', + * You can add custom database datasources (or override existing datasources) by adding the + * appropriate file to app/Model/Datasource/Database. Datasources should be named 'MyDatasource.php', * * * persistent => true / false diff --git a/lib/Cake/Console/Command/Task/DbConfigTask.php b/lib/Cake/Console/Command/Task/DbConfigTask.php index 757f86a3b..3d61baaea 100644 --- a/lib/Cake/Console/Command/Task/DbConfigTask.php +++ b/lib/Cake/Console/Command/Task/DbConfigTask.php @@ -104,7 +104,7 @@ class DbConfigTask extends Shell { } } - $driver = $this->in(__d('cake_console', 'Driver:'), array('Mysql', 'Postgres', 'Sqlite', 'Sqlserver'), 'Mysql'); + $datasource = $this->in(__d('cake_console', 'Datasource:'), array('Mysql', 'Postgres', 'Sqlite', 'Sqlserver'), 'Mysql'); $persistent = $this->in(__d('cake_console', 'Persistent Connection?'), array('y', 'n'), 'n'); if (strtolower($persistent) == 'n') { @@ -167,7 +167,7 @@ class DbConfigTask extends Shell { } $schema = ''; - if ($driver == 'postgres') { + if ($datasource == 'postgres') { while ($schema == '') { $schema = $this->in(__d('cake_console', 'Table schema?'), null, 'n'); } @@ -176,7 +176,7 @@ class DbConfigTask extends Shell { $schema = null; } - $config = compact('name', 'driver', 'persistent', 'host', 'login', 'password', 'database', 'prefix', 'encoding', 'port', 'schema'); + $config = compact('name', 'datasource', 'persistent', 'host', 'login', 'password', 'database', 'prefix', 'encoding', 'port', 'schema'); while ($this->_verify($config) == false) { $this->_interactive(); @@ -209,7 +209,7 @@ class DbConfigTask extends Shell { $this->out(__d('cake_console', 'The following database configuration will be created:')); $this->hr(); $this->out(__d('cake_console', "Name: %s", $name)); - $this->out(__d('cake_console', "Driver: %s", $driver)); + $this->out(__d('cake_console', "Datasource: %s", $datasource)); $this->out(__d('cake_console', "Persistent: %s", $persistent)); $this->out(__d('cake_console', "Host: %s", $host)); diff --git a/lib/Cake/Console/Templates/skel/Config/database.php.default b/lib/Cake/Console/Templates/skel/Config/database.php.default index 3ce441be3..11fca6fb5 100644 --- a/lib/Cake/Console/Templates/skel/Config/database.php.default +++ b/lib/Cake/Console/Templates/skel/Config/database.php.default @@ -27,14 +27,14 @@ * Database configuration class. * You can specify multiple configurations for production, development and testing. * - * driver => The name of a supported driver; valid options are as follows: + * datasource => The name of a supported datasource; valid options are as follows: * Database/Mysql - MySQL 4 & 5, * Database/Sqlite - SQLite (PHP5 only), * Database/Postgres - PostgreSQL 7 and higher, * Database/Sqlserver - Microsoft SQL Server 2005 and higher * - * You can add custom database drivers (or override existing drivers) by adding the - * appropriate file to app/Model/Datasource/Database. Drivers should be named 'MyDriver.php', + * You can add custom database datasources (or override existing datasources) by adding the + * appropriate file to app/Model/Datasource/Database. Datasources should be named 'MyDatasource.php', * * * persistent => true / false diff --git a/lib/Cake/Test/Case/Console/Command/Task/DbConfigTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/DbConfigTaskTest.php index 56db22d1a..de3cb8779 100644 --- a/lib/Cake/Test/Case/Console/Command/Task/DbConfigTaskTest.php +++ b/lib/Cake/Test/Case/Console/Command/Task/DbConfigTaskTest.php @@ -115,7 +115,7 @@ class DbConfigTaskTest extends CakeTestCase { ->with(array( array( 'name' => 'default', - 'driver' => 'mysql', + 'datasource' => 'mysql', 'persistent' => 'false', 'host' => 'localhost', 'login' => 'root', diff --git a/lib/Cake/Test/Case/Utility/DebuggerTest.php b/lib/Cake/Test/Case/Utility/DebuggerTest.php index 9ddbe7692..dffd74b49 100644 --- a/lib/Cake/Test/Case/Utility/DebuggerTest.php +++ b/lib/Cake/Test/Case/Utility/DebuggerTest.php @@ -405,7 +405,7 @@ class DebuggerTest extends CakeTestCase { */ public function testNoDbCredentials() { $config = array( - 'driver' => 'mysql', + 'datasource' => 'mysql', 'persistent' => false, 'host' => 'void.cakephp.org', 'login' => 'cakephp-user', @@ -417,7 +417,7 @@ class DebuggerTest extends CakeTestCase { $output = Debugger::exportVar($config); $expectedArray = array( - 'driver' => 'mysql', + 'datasource' => 'mysql', 'persistent' => false, 'host' => '*****', 'login' => '*****', From d84b66e7444e052ca685ab01e6680bc22ad2c6be Mon Sep 17 00:00:00 2001 From: Majna Date: Sun, 6 Nov 2011 16:14:55 +0100 Subject: [PATCH 03/31] Fix View task generating only 'admin' methods views in non-interactive mode. --- lib/Cake/Console/Command/Task/ViewTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Console/Command/Task/ViewTask.php b/lib/Cake/Console/Command/Task/ViewTask.php index 0228c32ad..b30d45070 100644 --- a/lib/Cake/Console/Command/Task/ViewTask.php +++ b/lib/Cake/Console/Command/Task/ViewTask.php @@ -143,7 +143,7 @@ class ViewTask extends BakeTask { } $adminRoute = $this->Project->getPrefix(); foreach ($methods as $i => $method) { - if ($adminRoute && isset($this->params['admin'])) { + if ($adminRoute && !empty($this->params['admin'])) { if ($scaffoldActions) { $methods[$i] = $adminRoute . $method; continue; From aae8a8962326c5e9a76ac1df1ffc73a9f216fdf3 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 6 Nov 2011 11:50:00 -0500 Subject: [PATCH 04/31] Change var -> public in controllertask. Makes the confirmation message and generated code the same. Fixes #2216 --- lib/Cake/Console/Command/Task/ControllerTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Console/Command/Task/ControllerTask.php b/lib/Cake/Console/Command/Task/ControllerTask.php index 1946b0890..d7797024c 100644 --- a/lib/Cake/Console/Command/Task/ControllerTask.php +++ b/lib/Cake/Console/Command/Task/ControllerTask.php @@ -219,7 +219,7 @@ class ControllerTask extends BakeTask { $this->out(__d('cake_console', "Controller Name:\n\t%s", $controllerName)); if (strtolower($useDynamicScaffold) == 'y') { - $this->out("var \$scaffold;"); + $this->out("public \$scaffold;"); } $properties = array( From 60718c3b9f6c19d19ceb19e7111ac37d6c197529 Mon Sep 17 00:00:00 2001 From: Kyle Robinson Young Date: Sun, 6 Nov 2011 11:04:19 -0800 Subject: [PATCH 05/31] Remove 5.3 notice from Config/core timezone comment --- app/Config/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Config/core.php b/app/Config/core.php index 691b02606..97d26629d 100644 --- a/app/Config/core.php +++ b/app/Config/core.php @@ -225,8 +225,8 @@ Configure::write('Acl.database', 'default'); /** - * If you are on PHP 5.3 uncomment this line and correct your server timezone - * to fix the date & time related errors. + * Uncomment this line and correct your server timezone to fix + * any date & time related errors. */ //date_default_timezone_set('UTC'); From 01aa91b3cf26e7b653b1230aeb823f5b800a6995 Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 7 Nov 2011 02:04:57 +0530 Subject: [PATCH 06/31] Fixing bug where content length was not set for clients which don't accept compressed response. Closes #2225 --- lib/Cake/Network/CakeResponse.php | 3 +- .../Test/Case/Network/CakeResponseTest.php | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Network/CakeResponse.php b/lib/Cake/Network/CakeResponse.php index 6209b3b4e..efb41d537 100644 --- a/lib/Cake/Network/CakeResponse.php +++ b/lib/Cake/Network/CakeResponse.php @@ -669,7 +669,8 @@ class CakeResponse { * @return boolean */ public function outputCompressed() { - return ini_get("zlib.output_compression") === '1' || in_array('ob_gzhandler', ob_list_handlers()); + return strpos(env('HTTP_ACCEPT_ENCODING'), 'gzip') !== false + && (ini_get("zlib.output_compression") === '1' || in_array('ob_gzhandler', ob_list_handlers())); } /** diff --git a/lib/Cake/Test/Case/Network/CakeResponseTest.php b/lib/Cake/Test/Case/Network/CakeResponseTest.php index 95a9c373b..d5d2d3e41 100644 --- a/lib/Cake/Test/Case/Network/CakeResponseTest.php +++ b/lib/Cake/Test/Case/Network/CakeResponseTest.php @@ -389,6 +389,43 @@ class CakeResponseTest extends CakeTestCase { $this->assertEquals($expected, $result); } +/** +* Tests the outputCompressed method +* +*/ + public function testOutputCompressed() { + $response = new CakeResponse(); + + $_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip'; + $result = $response->outputCompressed(); + $this->assertFalse($result); + + $_SERVER['HTTP_ACCEPT_ENCODING'] = ''; + $result = $response->outputCompressed(); + $this->assertFalse($result); + + if (!extension_loaded("zlib")) { + $this->markTestSkipped('Skipping further tests for outputCompressed as zlib extension is not loaded'); + } + if (php_sapi_name() !== 'cli') { + $this->markTestSkipped('Testing outputCompressed method with compression enabled done only in cli'); + } + + if (ini_get("zlib.output_compression") !== '1') { + ob_start('ob_gzhandler'); + } + $_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip'; + $result = $response->outputCompressed(); + $this->assertTrue($result); + + $_SERVER['HTTP_ACCEPT_ENCODING'] = ''; + $result = $response->outputCompressed(); + $this->assertFalse($result); + if (ini_get("zlib.output_compression") !== '1') { + ob_get_clean(); + } + } + /** * Tests the send and setting of Content-Length * From b2414a777f7daad88791a85fdb5d2587975abc3c Mon Sep 17 00:00:00 2001 From: Kyle Robinson Young Date: Sun, 6 Nov 2011 13:17:07 -0800 Subject: [PATCH 07/31] Remove 5.3 notice from lib/Cake/Console/Templates/skel/Config/core timezone comment --- lib/Cake/Console/Templates/skel/Config/core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Console/Templates/skel/Config/core.php b/lib/Cake/Console/Templates/skel/Config/core.php index 691b02606..97d26629d 100644 --- a/lib/Cake/Console/Templates/skel/Config/core.php +++ b/lib/Cake/Console/Templates/skel/Config/core.php @@ -225,8 +225,8 @@ Configure::write('Acl.database', 'default'); /** - * If you are on PHP 5.3 uncomment this line and correct your server timezone - * to fix the date & time related errors. + * Uncomment this line and correct your server timezone to fix + * any date & time related errors. */ //date_default_timezone_set('UTC'); From d87f9f060bc2b3c981b81b7a706779626eca69a9 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 6 Nov 2011 16:32:51 -0500 Subject: [PATCH 08/31] Make parent method check explicit to Shell. This makes only methods on Shell inaccessible on the command line. Parent methods in AppShell or other parent classes can now be called directly. Fixes #2193 --- lib/Cake/Console/Shell.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Console/Shell.php b/lib/Cake/Console/Shell.php index b26628951..53e02c03f 100644 --- a/lib/Cake/Console/Shell.php +++ b/lib/Cake/Console/Shell.php @@ -273,15 +273,12 @@ class Shell extends Object { * @return boolean */ public function hasMethod($name) { - if (empty($this->_reflection)) { - $this->_reflection = new ReflectionClass($this); - } try { - $method = $this->_reflection->getMethod($name); + $method = new ReflectionMethod($this, $name); if (!$method->isPublic() || substr($name, 0, 1) === '_') { return false; } - if ($method->getDeclaringClass() != $this->_reflection) { + if ($method->getDeclaringClass()->name == 'Shell') { return false; } return true; From 1d52dc05e15cbd99495e1a970b18a14f31a13c16 Mon Sep 17 00:00:00 2001 From: jamiemill Date: Sun, 6 Nov 2011 19:01:47 +0000 Subject: [PATCH 09/31] Fix for UpgradeShell::helpers() not discovering core helpers. --- lib/Cake/Console/Command/UpgradeShell.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Cake/Console/Command/UpgradeShell.php b/lib/Cake/Console/Command/UpgradeShell.php index 3c619da2d..7643bad17 100644 --- a/lib/Cake/Console/Command/UpgradeShell.php +++ b/lib/Cake/Console/Command/UpgradeShell.php @@ -214,6 +214,9 @@ class UpgradeShell extends Shell { } $patterns = array(); + App::build(array( + 'View/Helper' => App::core('View/Helper'), + ), App::APPEND); $helpers = App::objects('helper'); $plugins = App::objects('plugin'); $pluginHelpers = array(); From 4368b62dfb8c4347ae412433a5dffc0d1e0336ae Mon Sep 17 00:00:00 2001 From: jamiemill Date: Sun, 6 Nov 2011 13:38:31 +0000 Subject: [PATCH 10/31] Added an 'exceptions' method to the UpgradeShell. This just replaces some of the basic cakeError() calls with equivalent exceptions. --- lib/Cake/Console/Command/UpgradeShell.php | 41 +++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/lib/Cake/Console/Command/UpgradeShell.php b/lib/Cake/Console/Command/UpgradeShell.php index 7643bad17..fc323d2ad 100644 --- a/lib/Cake/Console/Command/UpgradeShell.php +++ b/lib/Cake/Console/Command/UpgradeShell.php @@ -516,6 +516,43 @@ class UpgradeShell extends Shell { $this->_filesRegexpUpdate($patterns); } +/** + * Replace cakeError with built-in exceptions. + * NOTE: this ignores calls where you've passed your own secondary parameters to cakeError(). + * @return void + */ + public function exceptions() { + $controllers = array_diff(App::path('controllers'), App::core('controllers'), array(APP)); + $components = array_diff(App::path('components'), App::core('components')); + + $this->_paths = array_merge($controllers, $components); + + if (!empty($this->params['plugin'])) { + $pluginPath = App::pluginPath($this->params['plugin']); + $this->_paths = array( + $pluginPath . 'controllers' . DS, + $pluginPath . 'controllers' . DS . 'components' .DS, + ); + } + $patterns = array( + array( + '$this->cakeError("error400") -> throw new BadRequestException()', + '/(\$this->cakeError\(["\']error400["\']\));/', + 'throw new BadRequestException();' + ), + array( + '$this->cakeError("error404") -> throw new NotFoundException()', + '/(\$this->cakeError\(["\']error404["\']\));/', + 'throw new NotFoundException();' + ), + array( + '$this->cakeError("error500") -> throw new InternalErrorException()', + '/(\$this->cakeError\(["\']error404["\']\));/', + 'throw new InternalErrorException();' + ), + ); + $this->_filesRegexpUpdate($patterns); + } /** * Move application views files to where they now should be * @@ -776,6 +813,10 @@ class UpgradeShell extends Shell { ->addSubcommand('components', array( 'help' => __d('cake_console', 'Update components to extend Component class.'), 'parser' => $subcommandParser + )) + ->addSubcommand('exceptions', array( + 'help' => __d('cake_console', 'Replace use of cakeError with exceptions.'), + 'parser' => $subcommandParser )); } } From c966a35bebda6f79c1c79a835367ba17f5d1a0d5 Mon Sep 17 00:00:00 2001 From: jamiemill Date: Sun, 6 Nov 2011 12:27:45 +0000 Subject: [PATCH 11/31] Fixed bug in UpgradeShell::findFiles(). $this->_files was reset on each loop through paths, which means, for example, if you still had the old 'views' directory kicking around the results from 'View' would be overwritten. --- lib/Cake/Console/Command/UpgradeShell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Console/Command/UpgradeShell.php b/lib/Cake/Console/Command/UpgradeShell.php index fc323d2ad..63b1cc268 100644 --- a/lib/Cake/Console/Command/UpgradeShell.php +++ b/lib/Cake/Console/Command/UpgradeShell.php @@ -702,11 +702,11 @@ class UpgradeShell extends Shell { * @return void */ protected function _findFiles($extensions = '') { + $this->_files = array(); foreach ($this->_paths as $path) { if (!is_dir($path)) { continue; } - $this->_files = array(); $Iterator = new RegexIterator( new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)), '/^.+\.(' . $extensions . ')$/i', From e16890225cd652e01b7a43e91533311a81e063bc Mon Sep 17 00:00:00 2001 From: jamiemill Date: Sun, 6 Nov 2011 23:19:30 +0000 Subject: [PATCH 12/31] Fixed mistake in UpgradeShell::exceptions() My fault ;) --- lib/Cake/Console/Command/UpgradeShell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Console/Command/UpgradeShell.php b/lib/Cake/Console/Command/UpgradeShell.php index 63b1cc268..66d59be5b 100644 --- a/lib/Cake/Console/Command/UpgradeShell.php +++ b/lib/Cake/Console/Command/UpgradeShell.php @@ -547,7 +547,7 @@ class UpgradeShell extends Shell { ), array( '$this->cakeError("error500") -> throw new InternalErrorException()', - '/(\$this->cakeError\(["\']error404["\']\));/', + '/(\$this->cakeError\(["\']error500["\']\));/', 'throw new InternalErrorException();' ), ); From 57afa1873ef4e7bcc83e95f8328f4c094b93ba8b Mon Sep 17 00:00:00 2001 From: Majna Date: Mon, 7 Nov 2011 01:01:56 +0100 Subject: [PATCH 13/31] Make View task use prefixed template before falling back to generic one. It is possible now to create view templates for different prefixes. --- lib/Cake/Console/Command/Task/ViewTask.php | 4 ++++ .../Test/Case/Console/Command/Task/ViewTaskTest.php | 13 +++++++++++-- .../Console/Templates/test/views/admin_edit.ctp | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 lib/Cake/Test/test_app/Console/Templates/test/views/admin_edit.ctp diff --git a/lib/Cake/Console/Command/Task/ViewTask.php b/lib/Cake/Console/Command/Task/ViewTask.php index b30d45070..fff2572e8 100644 --- a/lib/Cake/Console/Command/Task/ViewTask.php +++ b/lib/Cake/Console/Command/Task/ViewTask.php @@ -393,6 +393,10 @@ class ViewTask extends BakeTask { if (!empty($this->template) && $action != $this->template) { return $this->template; } + $themePath = $this->Template->getThemePath(); + if (file_exists($themePath . 'views' . DS . $action . '.ctp')) { + return $action; + } $template = $action; $prefixes = Configure::read('Routing.prefixes'); foreach ((array)$prefixes as $prefix) { diff --git a/lib/Cake/Test/Case/Console/Command/Task/ViewTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ViewTaskTest.php index 1652b9267..57d254468 100644 --- a/lib/Cake/Test/Case/Console/Command/Task/ViewTaskTest.php +++ b/lib/Cake/Test/Case/Console/Command/Task/ViewTaskTest.php @@ -230,6 +230,7 @@ class ViewTaskTest extends CakeTestCase { $this->Task->path = TMP; $this->Task->Template->params['theme'] = 'default'; + $this->Task->Template->templatePaths = array('default' => CAKE . 'Console' . DS . 'Templates' . DS . 'default' .DS); } /** @@ -563,7 +564,7 @@ class ViewTaskTest extends CakeTestCase { } /** - * test `cake bake view $controller -admin` + * test `cake bake view $controller --admin` * Which only bakes admin methods, not non-admin methods. * * @return void @@ -701,7 +702,7 @@ class ViewTaskTest extends CakeTestCase { } /** - * test getting templates, make sure noTemplateActions works + * test getting templates, make sure noTemplateActions works and prefixed template is used before generic one. * * @return void */ @@ -716,6 +717,14 @@ class ViewTaskTest extends CakeTestCase { $result = $this->Task->getTemplate('admin_add'); $this->assertEqual($result, 'form'); + + $this->Task->Template->templatePaths = array( + 'test' => CAKE . 'Test' . DS . 'test_app' . DS . 'Console' . DS . 'Templates' . DS . 'test' .DS + ); + $this->Task->Template->params['theme'] = 'test'; + + $result = $this->Task->getTemplate('admin_edit'); + $this->assertEqual($result, 'admin_edit'); } } diff --git a/lib/Cake/Test/test_app/Console/Templates/test/views/admin_edit.ctp b/lib/Cake/Test/test_app/Console/Templates/test/views/admin_edit.ctp new file mode 100644 index 000000000..0d7ec6739 --- /dev/null +++ b/lib/Cake/Test/test_app/Console/Templates/test/views/admin_edit.ctp @@ -0,0 +1 @@ +admin_edit template \ No newline at end of file From 09300433f5bad7c194c818891942d51a887fe185 Mon Sep 17 00:00:00 2001 From: Kyle Robinson Young Date: Sun, 6 Nov 2011 22:26:58 -0800 Subject: [PATCH 14/31] Fix incorrect toQuarter docblock return tag --- lib/Cake/View/Helper/TimeHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/View/Helper/TimeHelper.php b/lib/Cake/View/Helper/TimeHelper.php index 7bd5b5e6f..ecad59b25 100644 --- a/lib/Cake/View/Helper/TimeHelper.php +++ b/lib/Cake/View/Helper/TimeHelper.php @@ -387,7 +387,7 @@ class TimeHelper extends AppHelper { * * @param string $dateString * @param boolean $range if true returns a range in Y-m-d format - * @return boolean True if datetime string is within current week + * @return mixed 1, 2, 3, or 4 quarter of year or array if $range true * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting */ public function toQuarter($dateString, $range = false) { From 72502e8fec86ad5bb2894e687e44115cbb4de3bc Mon Sep 17 00:00:00 2001 From: Kyle Robinson Young Date: Sun, 6 Nov 2011 22:54:52 -0800 Subject: [PATCH 15/31] Remove extra fromString in TimeHelper::gmt and update docblock --- lib/Cake/View/Helper/TimeHelper.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/Cake/View/Helper/TimeHelper.php b/lib/Cake/View/Helper/TimeHelper.php index 7bd5b5e6f..fe574207b 100644 --- a/lib/Cake/View/Helper/TimeHelper.php +++ b/lib/Cake/View/Helper/TimeHelper.php @@ -676,10 +676,10 @@ class TimeHelper extends AppHelper { } /** - * Returns gmt, given either a UNIX timestamp or a valid strtotime() date string. + * Returns gmt as a UNIX timestamp. * * @param string $string Datetime string - * @return string Formatted date string + * @return integer UNIX timestamp * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting */ public function gmt($string = null) { @@ -688,7 +688,6 @@ class TimeHelper extends AppHelper { } else { $string = time(); } - $string = $this->fromString($string); $hour = intval(date("G", $string)); $minute = intval(date("i", $string)); $second = intval(date("s", $string)); From 7224de962e8008332c6a28d8ff2736ee7ea072bc Mon Sep 17 00:00:00 2001 From: Ceeram Date: Mon, 7 Nov 2011 09:19:01 +0100 Subject: [PATCH 16/31] removing unused variable, fixes #2227 --- lib/Cake/Routing/Router.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Routing/Router.php b/lib/Cake/Routing/Router.php index e05b4add4..04679aded 100644 --- a/lib/Cake/Routing/Router.php +++ b/lib/Cake/Routing/Router.php @@ -820,7 +820,7 @@ class Router { * @see Router::url() */ protected static function _handleNoRoute($url) { - $named = $args = $query = array(); + $named = $args = array(); $skip = array_merge( array('bare', 'action', 'controller', 'plugin', 'prefix'), self::$_prefixes @@ -847,7 +847,7 @@ class Router { } } - if (empty($named) && empty($args) && empty($query) && (!isset($url['action']) || $url['action'] === 'index')) { + if (empty($named) && empty($args) && (!isset($url['action']) || $url['action'] === 'index')) { $url['action'] = null; } @@ -881,9 +881,6 @@ class Router { } } } - if (!empty($query)) { - $output .= Router::queryString($query); - } return $output; } From 2c91f119cb0bb5dc19d33100d7d256ef887cb697 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 7 Nov 2011 23:16:45 -0500 Subject: [PATCH 17/31] Remove redundant check. --- lib/Cake/Model/Datasource/Database/Sqlite.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Model/Datasource/Database/Sqlite.php b/lib/Cake/Model/Datasource/Database/Sqlite.php index 6b616f1b7..d69d288c9 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlite.php +++ b/lib/Cake/Model/Datasource/Database/Sqlite.php @@ -250,7 +250,7 @@ class Sqlite extends DboSource { if (in_array($col, array('text', 'integer', 'float', 'boolean', 'timestamp', 'date', 'datetime', 'time'))) { return $col; } - if (strpos($col, 'varchar') !== false || strpos($col, 'char') !== false) { + if (strpos($col, 'char') !== false) { return 'string'; } if (in_array($col, array('blob', 'clob'))) { From 1b95b012654aa18c83b0bfc66680a8929d10d3a2 Mon Sep 17 00:00:00 2001 From: Kyle Robinson Young Date: Mon, 7 Nov 2011 22:16:55 -0800 Subject: [PATCH 18/31] Fix docblock formatting with Time Helper Test --- lib/Cake/Test/Case/View/Helper/TimeHelperTest.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Test/Case/View/Helper/TimeHelperTest.php b/lib/Cake/Test/Case/View/Helper/TimeHelperTest.php index 672d63efc..724ed0adb 100644 --- a/lib/Cake/Test/Case/View/Helper/TimeHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/TimeHelperTest.php @@ -515,7 +515,8 @@ class TimeHelperTest extends CakeTestCase { $result = $this->Time->isThisYear(mktime(0, 0, 0, mt_rand(1, 12), mt_rand(1, 28), date('Y'))); $this->assertTrue($result); } - /** + +/** * testWasYesterday method * * @return void @@ -534,7 +535,8 @@ class TimeHelperTest extends CakeTestCase { $result = $this->Time->wasYesterday('-2 days'); $this->assertFalse($result); } - /** + +/** * testIsTomorrow method * * @return void @@ -594,7 +596,8 @@ class TimeHelperTest extends CakeTestCase { $this->assertTrue($this->Time->wasWithinLast('1 ', '-1 minute')); $this->assertTrue($this->Time->wasWithinLast('1 ', '-23 hours -59 minutes -59 seconds')); } - /** + +/** * testUserOffset method * * @return void From cfbc6d498920ccc41657257cb57107a673369ae4 Mon Sep 17 00:00:00 2001 From: Ceeram Date: Tue, 8 Nov 2011 20:29:33 +0100 Subject: [PATCH 19/31] adding extra test, disproves ticket [#2233 state:works-for-me] --- .../Test/Case/View/Helper/FormHelperTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index a3dc8c243..08b8cdf70 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -1924,6 +1924,24 @@ class FormHelperTest extends CakeTestCase { ); $this->assertTags($result, $expected); + $result = $this->Form->input('Contact.field', array( + 'type' => 'text', 'error' => array('attributes' => array('class' => 'error')) + )); + $expected = array( + 'div' => array('class' => 'input text error'), + 'label' => array('for' => 'ContactField'), + 'Field', + '/label', + 'input' => array( + 'type' => 'text', 'name' => 'data[Contact][field]', + 'id' => 'ContactField', 'class' => 'form-error' + ), + array('div' => array('class' => 'error')), + 'Badness!', + '/div' + ); + $this->assertTags($result, $expected); + $result = $this->Form->input('Contact.field', array( 'div' => array('tag' => 'span'), 'error' => array('attributes' => array('wrap' => false)) )); From 89ced25fad2d1d90580296f2728b078724d79007 Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 8 Nov 2011 19:23:36 -0500 Subject: [PATCH 20/31] Making HttpResponse more tolerant of line endings. --- lib/Cake/Network/Http/HttpResponse.php | 2 +- lib/Cake/Test/Case/Network/Http/HttpResponseTest.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Network/Http/HttpResponse.php b/lib/Cake/Network/Http/HttpResponse.php index f921aad1b..c0f757bea 100644 --- a/lib/Cake/Network/Http/HttpResponse.php +++ b/lib/Cake/Network/Http/HttpResponse.php @@ -204,7 +204,7 @@ class HttpResponse implements ArrayAccess { $chunkLength = null; while ($chunkLength !== 0) { - if (!preg_match("/^([0-9a-f]+) *(?:;(.+)=(.+))?\r\n/iU", $body, $match)) { + if (!preg_match('/^([0-9a-f]+) *(?:;(.+)=(.+))?(?:\r\n|\n)/iU', $body, $match)) { throw new SocketException(__d('cake_dev', 'HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.')); } diff --git a/lib/Cake/Test/Case/Network/Http/HttpResponseTest.php b/lib/Cake/Test/Case/Network/Http/HttpResponseTest.php index 23d51c77a..734519242 100644 --- a/lib/Cake/Test/Case/Network/Http/HttpResponseTest.php +++ b/lib/Cake/Test/Case/Network/Http/HttpResponseTest.php @@ -320,6 +320,15 @@ class HttpResponseTest extends CakeTestCase { $r = $this->HttpResponse->decodeBody($sample['encoded'], $encoding); $this->assertEquals($r, $sample['decoded']); + + $encoding = 'chunked'; + $sample = array( + 'encoded' => "19\nThis is a chunked message\r\n0\n", + 'decoded' => array('body' => "This is a chunked message", 'header' => false) + ); + + $r = $this->HttpResponse->decodeBody($sample['encoded'], $encoding); + $this->assertEquals($r, $sample['decoded'], 'Inconsistent line terminators should be tolerated.'); } /** From bdbc34bbed46e2ee329f300232a7b1d9f3d1ae04 Mon Sep 17 00:00:00 2001 From: teddyzeenny Date: Wed, 9 Nov 2011 16:38:36 +0200 Subject: [PATCH 21/31] Remove session.save_handler from php ini array --- lib/Cake/Model/Datasource/CakeSession.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Cake/Model/Datasource/CakeSession.php b/lib/Cake/Model/Datasource/CakeSession.php index b8641c335..f261bb861 100644 --- a/lib/Cake/Model/Datasource/CakeSession.php +++ b/lib/Cake/Model/Datasource/CakeSession.php @@ -539,8 +539,7 @@ class CakeSession { 'cookieTimeout' => 240, 'ini' => array( 'session.use_trans_sid' => 0, - 'session.cookie_path' => self::$path, - 'session.save_handler' => 'files' + 'session.cookie_path' => self::$path ) ), 'cake' => array( From 767d1afcd84ebcfab2c2c44023d7516ef8c51526 Mon Sep 17 00:00:00 2001 From: Ceeram Date: Wed, 9 Nov 2011 21:07:01 +0100 Subject: [PATCH 22/31] fixing helptext for AclShell --- lib/Cake/Console/Command/AclShell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Console/Command/AclShell.php b/lib/Cake/Console/Command/AclShell.php index 42fa202f1..b2dec95d3 100644 --- a/lib/Cake/Console/Command/AclShell.php +++ b/lib/Cake/Console/Command/AclShell.php @@ -485,7 +485,7 @@ class AclShell extends Shell { ) ) ))->addSubcommand('initdb', array( - 'help' => __d('cake_console', 'Initialize the DbAcl tables. Uses this command : cake schema run create DbAcl') + 'help' => __d('cake_console', 'Initialize the DbAcl tables. Uses this command : cake schema create DbAcl') ))->epilog( array( 'Node and parent arguments can be in one of the following formats:', From bc40a55f2028f47a69c05959b9a0a6e69aa5f337 Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 8 Nov 2011 20:57:32 -0500 Subject: [PATCH 23/31] Re-factor dispatcher asset test to use a data provider. --- lib/Cake/Test/Case/Routing/DispatcherTest.php | 206 +++++++++--------- 1 file changed, 105 insertions(+), 101 deletions(-) diff --git a/lib/Cake/Test/Case/Routing/DispatcherTest.php b/lib/Cake/Test/Case/Routing/DispatcherTest.php index f421e8e39..9a7aba6ea 100644 --- a/lib/Cake/Test/Case/Routing/DispatcherTest.php +++ b/lib/Cake/Test/Case/Routing/DispatcherTest.php @@ -1191,113 +1191,117 @@ class DispatcherTest extends CakeTestCase { } catch (MissingControllerException $e) { $this->assertEquals('Controller class ThemeController could not be found.', $e->getMessage()); } + } - ob_start(); - $Dispatcher->dispatch(new CakeRequest('theme/test_theme/flash/theme_test.swf'), $response); - $result = ob_get_clean(); +/** + * Data provider for asset() + * + * - theme assets. + * - plugin assets. + * - plugin assets in sub directories. + * - unknown plugin assets. + * + * @return array + */ + public static function assetProvider() { + return array( + array( + 'theme/test_theme/flash/theme_test.swf', + 'View/Themed/TestTheme/webroot/flash/theme_test.swf' + ), + array( + 'theme/test_theme/pdfs/theme_test.pdf', + 'View/Themed/TestTheme/webroot/pdfs/theme_test.pdf' + ), + array( + 'theme/test_theme/img/test.jpg', + 'View/Themed/TestTheme/webroot/img/test.jpg' + ), + array( + 'theme/test_theme/css/test_asset.css', + 'View/Themed/TestTheme/webroot/css/test_asset.css' + ), + array( + 'theme/test_theme/js/theme.js', + 'View/Themed/TestTheme/webroot/js/theme.js' + ), + array( + 'theme/test_theme/js/one/theme_one.js', + 'View/Themed/TestTheme/webroot/js/one/theme_one.js' + ), + array( + 'test_plugin/root.js', + 'Plugin/TestPlugin/webroot/root.js' + ), + array( + 'test_plugin/flash/plugin_test.swf', + 'Plugin/TestPlugin/webroot/flash/plugin_test.swf' + ), + array( + 'test_plugin/pdfs/plugin_test.pdf', + 'Plugin/TestPlugin/webroot/pdfs/plugin_test.pdf' + ), + array( + 'test_plugin/js/test_plugin/test.js', + 'Plugin/TestPlugin/webroot/js/test_plugin/test.js' + ), + array( + 'test_plugin/css/test_plugin_asset.css', + 'Plugin/TestPlugin/webroot/css/test_plugin_asset.css' + ), + array( + 'test_plugin/img/cake.icon.gif', + 'Plugin/TestPlugin/webroot/img/cake.icon.gif' + ), + array( + 'plugin_js/js/plugin_js.js', + 'Plugin/PluginJs/webroot/js/plugin_js.js' + ), + array( + 'plugin_js/js/one/plugin_one.js', + 'Plugin/PluginJs/webroot/js/one/plugin_one.js' + ), + array( + 'test_plugin/css/unknown.extension', + 'Plugin/TestPlugin/webroot/css/unknown.extension' + ), + array( + 'test_plugin/css/theme_one.htc', + 'Plugin/TestPlugin/webroot/css/theme_one.htc' + ), + ); + } - $file = file_get_contents(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS . 'Themed' . DS . 'TestTheme' . DS . 'webroot' . DS . 'flash' . DS . 'theme_test.swf'); - $this->assertEqual($file, $result); - $this->assertEqual('this is just a test to load swf file from the theme.', $result); +/** + * Test assets + * + * @dataProvider assetProvider + * @outputBuffering enabled + * @return void + */ + public function testAsset($url, $file) { + Router::reload(); - ob_start(); - $Dispatcher->dispatch(new CakeRequest('theme/test_theme/pdfs/theme_test.pdf'), $response); - $result = ob_get_clean(); - $file = file_get_contents(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS . 'Themed' . DS . 'TestTheme' . DS . 'webroot' . DS . 'pdfs' . DS . 'theme_test.pdf'); - $this->assertEqual($file, $result); - $this->assertEqual('this is just a test to load pdf file from the theme.', $result); - - ob_start(); - $Dispatcher->dispatch(new CakeRequest('theme/test_theme/img/test.jpg'), $response); - $result = ob_get_clean(); - $file = file_get_contents(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS . 'Themed' . DS . 'TestTheme' . DS . 'webroot' . DS . 'img' . DS . 'test.jpg'); - $this->assertEqual($file, $result); - - ob_start(); - $Dispatcher->asset('theme/test_theme/css/test_asset.css', $response); - $result = ob_get_clean(); - $this->assertEqual('this is the test asset css file', $result); - - ob_start(); - $Dispatcher->asset('theme/test_theme/js/theme.js', $response); - $result = ob_get_clean(); - $this->assertEqual('root theme js file', $result); - - ob_start(); - $Dispatcher->asset('theme/test_theme/js/one/theme_one.js', $response); - $result = ob_get_clean(); - $this->assertEqual('nested theme js file', $result); - - ob_start(); - $Dispatcher->asset('test_plugin/root.js', $response); - $result = ob_get_clean(); - $expected = file_get_contents(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS . 'TestPlugin' . DS . 'webroot' . DS . 'root.js'); - $this->assertEqual($expected, $result); - - ob_start(); - $Dispatcher->dispatch(new CakeRequest('test_plugin/flash/plugin_test.swf'), $response); - $result = ob_get_clean(); - $file = file_get_contents(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS . 'TestPlugin' . DS . 'webroot' . DS . 'flash' . DS . 'plugin_test.swf'); - $this->assertEqual($file, $result); - $this->assertEqual('this is just a test to load swf file from the plugin.', $result); - - ob_start(); - $Dispatcher->dispatch(new CakeRequest('test_plugin/pdfs/plugin_test.pdf'), $response); - $result = ob_get_clean(); - $file = file_get_contents(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS . 'TestPlugin' . DS . 'webroot' . DS . 'pdfs' . DS . 'plugin_test.pdf'); - $this->assertEqual($file, $result); - $this->assertEqual('this is just a test to load pdf file from the plugin.', $result); - - ob_start(); - $Dispatcher->asset('test_plugin/js/test_plugin/test.js', $response); - $result = ob_get_clean(); - $this->assertEqual('alert("Test App");', $result); - - ob_start(); - $Dispatcher->asset('test_plugin/js/test_plugin/test.js', $response); - $result = ob_get_clean(); - $this->assertEqual('alert("Test App");', $result); - - ob_start(); - $Dispatcher->asset('test_plugin/css/test_plugin_asset.css', $response); - $result = ob_get_clean(); - $this->assertEqual('this is the test plugin asset css file', $result); - - ob_start(); - $Dispatcher->asset('test_plugin/img/cake.icon.gif', $response); - $result = ob_get_clean(); - $file = file_get_contents(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS . 'TestPlugin' .DS . 'webroot' . DS . 'img' . DS . 'cake.icon.gif'); - $this->assertEqual($file, $result); - - ob_start(); - $Dispatcher->asset('plugin_js/js/plugin_js.js', $response); - $result = ob_get_clean(); - $expected = "alert('win sauce');"; - $this->assertEqual($expected, $result); - - ob_start(); - $Dispatcher->asset('plugin_js/js/one/plugin_one.js', $response); - $result = ob_get_clean(); - $expected = "alert('plugin one nested js file');"; - $this->assertEqual($expected, $result); - - ob_start(); - $Dispatcher->asset('test_plugin/css/unknown.extension', $response); - $result = ob_get_clean(); - $this->assertEqual('Testing a file with unknown extension to mime mapping.', $result); - - ob_start(); - $Dispatcher->asset('test_plugin/css/theme_one.htc', $response); - $result = ob_get_clean(); - $this->assertEqual('htc file', $result); + App::build(array( + 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS), + 'Vendor' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor'. DS), + 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View'. DS) + )); + CakePlugin::loadAll(); + $Dispatcher = new TestDispatcher(); $response = $this->getMock('CakeResponse', array('_sendHeader')); - ob_start(); - $Dispatcher->asset('test_plugin/css/unknown.extension', $response); - ob_end_clean(); - $expected = filesize(CakePlugin::path('TestPlugin') . 'webroot' . DS . 'css' . DS . 'unknown.extension'); + + $Dispatcher->dispatch(new CakeRequest($url), $response); + $result = ob_get_clean(); + + $path = CAKE. 'Test' . DS . 'test_app' . DS . str_replace('/', DS, $file); + $file = file_get_contents($path); + $this->assertEquals($file, $result); + + $expected = filesize($path); $headers = $response->header(); - $this->assertEqual($expected, $headers['Content-Length']); + $this->assertEquals($expected, $headers['Content-Length']); } /** From 1487357ba631bc34d19cabc08d93017294268401 Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 8 Nov 2011 21:18:24 -0500 Subject: [PATCH 24/31] Convert another long test to use a dataprovider. --- lib/Cake/Test/Case/Routing/DispatcherTest.php | 164 +++--------------- 1 file changed, 27 insertions(+), 137 deletions(-) diff --git a/lib/Cake/Test/Case/Routing/DispatcherTest.php b/lib/Cake/Test/Case/Routing/DispatcherTest.php index 9a7aba6ea..12dc144ea 100644 --- a/lib/Cake/Test/Case/Routing/DispatcherTest.php +++ b/lib/Cake/Test/Case/Routing/DispatcherTest.php @@ -1346,17 +1346,41 @@ class DispatcherTest extends CakeTestCase { $this->assertFalse($Dispatcher->asset('js/cjs/debug_kit.js', $response)); } + +/** + * Data provider for cached actions. + * + * - Test simple views + * - Test views with nocache tags + * - Test requests with named + passed params. + * - Test themed views. + * + * @return array + */ + public static function cacheActionProvider() { + return array( + array('/'), + array('test_cached_pages/index'), + array('TestCachedPages/index'), + array('test_cached_pages/test_nocache_tags'), + array('TestCachedPages/test_nocache_tags'), + array('test_cached_pages/view/param/param'), + array('test_cached_pages/view/foo:bar/value:goo'), + array('test_cached_pages/themed'), + ); + } + /** * testFullPageCachingDispatch method * + * @dataProvider cacheActionProvider * @return void */ - public function testFullPageCachingDispatch() { + public function testFullPageCachingDispatch($url) { Configure::write('Cache.disable', false); Configure::write('Cache.check', true); Configure::write('debug', 2); - Router::reload(); Router::connect('/', array('controller' => 'test_cached_pages', 'action' => 'index')); Router::connect('/:controller/:action/*'); @@ -1366,141 +1390,7 @@ class DispatcherTest extends CakeTestCase { ), true); $dispatcher = new TestDispatcher(); - $request = new CakeRequest('/'); - $response = new CakeResponse(); - - ob_start(); - $dispatcher->dispatch($request, $response); - $out = ob_get_clean(); - - ob_start(); - $dispatcher->cached($request->here); - $cached = ob_get_clean(); - - $result = str_replace(array("\t", "\r\n", "\n"), "", $out); - $cached = preg_replace('//', '', $cached); - $expected = str_replace(array("\t", "\r\n", "\n"), "", $cached); - - $this->assertEqual($expected, $result); - - $filename = $this->__cachePath($request->here); - unlink($filename); - - $request = new CakeRequest('test_cached_pages/index'); - $_POST = array( - 'slasher' => "Up in your's grill \ '" - ); - - ob_start(); - $dispatcher->dispatch($request, $response); - $out = ob_get_clean(); - - ob_start(); - $dispatcher->cached($request->here); - $cached = ob_get_clean(); - - $result = str_replace(array("\t", "\r\n", "\n"), "", $out); - $cached = preg_replace('//', '', $cached); - $expected = str_replace(array("\t", "\r\n", "\n"), "", $cached); - - $this->assertEqual($expected, $result); - $filename = $this->__cachePath($request->here); - unlink($filename); - - $request = new CakeRequest('TestCachedPages/index'); - - ob_start(); - $dispatcher->dispatch($request, $response); - $out = ob_get_clean(); - - ob_start(); - $dispatcher->cached($request->here); - $cached = ob_get_clean(); - - $result = str_replace(array("\t", "\r\n", "\n"), "", $out); - $cached = preg_replace('//', '', $cached); - $expected = str_replace(array("\t", "\r\n", "\n"), "", $cached); - - $this->assertEqual($expected, $result); - $filename = $this->__cachePath($request->here); - unlink($filename); - - $request = new CakeRequest('TestCachedPages/test_nocache_tags'); - - ob_start(); - $dispatcher->dispatch($request, $response); - $out = ob_get_clean(); - - ob_start(); - $dispatcher->cached($request->here); - $cached = ob_get_clean(); - - $result = str_replace(array("\t", "\r\n", "\n"), "", $out); - $cached = preg_replace('//', '', $cached); - $expected = str_replace(array("\t", "\r\n", "\n"), "", $cached); - - $this->assertEqual($expected, $result); - $filename = $this->__cachePath($request->here); - unlink($filename); - - $request = new CakeRequest('test_cached_pages/view/param/param'); - - ob_start(); - $dispatcher->dispatch($request, $response); - $out = ob_get_clean(); - - ob_start(); - $dispatcher->cached($request->here); - $cached = ob_get_clean(); - - $result = str_replace(array("\t", "\r\n", "\n"), "", $out); - $cached = preg_replace('//', '', $cached); - $expected = str_replace(array("\t", "\r\n", "\n"), "", $cached); - - $this->assertEqual($expected, $result); - $filename = $this->__cachePath($request->here); - unlink($filename); - - $request = new CakeRequest('test_cached_pages/view/foo:bar/value:goo'); - - ob_start(); - $dispatcher->dispatch($request, $response); - $out = ob_get_clean(); - - ob_start(); - $dispatcher->cached($request->here); - $cached = ob_get_clean(); - - $result = str_replace(array("\t", "\r\n", "\n"), "", $out); - $cached = preg_replace('//', '', $cached); - $expected = str_replace(array("\t", "\r\n", "\n"), "", $cached); - - $this->assertEqual($expected, $result); - $filename = $this->__cachePath($request->here); - $this->assertTrue(file_exists($filename)); - - unlink($filename); - } - -/** - * Test full page caching with themes. - * - * @return void - */ - public function testFullPageCachingWithThemes() { - Configure::write('Cache.disable', false); - Configure::write('Cache.check', true); - Configure::write('debug', 2); - - Router::reload(); - Router::connect('/:controller/:action/*'); - - App::build(array( - 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS), - ), true); - - $dispatcher = new TestDispatcher(); - $request = new CakeRequest('/test_cached_pages/themed'); + $request = new CakeRequest($url); $response = new CakeResponse(); ob_start(); From 0b0d180aada47e03e90985ef6d9156f0398c47ee Mon Sep 17 00:00:00 2001 From: mark_story Date: Wed, 9 Nov 2011 22:31:06 -0500 Subject: [PATCH 25/31] Changing how insertMulti handles boolean values. Binding values individually allows boolean to work correctly. --- lib/Cake/Model/Datasource/DboSource.php | 30 ++++++++++++++++--- .../Test/Fixture/CounterCachePostFixture.php | 2 +- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index 0c655bbc6..967f4bade 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -2734,9 +2734,11 @@ class DboSource extends DataSource { /** * Inserts multiple values into a table * - * @param string $table - * @param string $fields - * @param array $values + * @param string $table The table being inserted into. + * @param array $fields The array of field/column names being inserted. + * @param array $values The array of values to insert. The values should + * be an array of rows. Each row should have values keyed by the column name. + * Each row must have the values in the same order as $fields. * @return boolean */ public function insertMulti($table, $fields, $values) { @@ -2744,12 +2746,32 @@ class DboSource extends DataSource { $holder = implode(',', array_fill(0, count($fields), '?')); $fields = implode(', ', array_map(array(&$this, 'name'), $fields)); + $pdoMap = array( + 'integer' => PDO::PARAM_INT, + 'float' => PDO::PARAM_STR, + 'boolean' => PDO::PARAM_BOOL, + 'string' => PDO::PARAM_STR, + 'text' => PDO::PARAM_STR + ); + $columnMap = array(); + $count = count($values); $sql = "INSERT INTO {$table} ({$fields}) VALUES ({$holder})"; $statement = $this->_connection->prepare($sql); $this->begin(); + + foreach ($values[0] as $key => $val) { + $type = $this->introspectType($val); + $columnMap[$key] = $pdoMap[$type]; + } + for ($x = 0; $x < $count; $x++) { - $statement->execute($values[$x]); + $i = 1; + foreach ($values[$x] as $key => $val) { + $statement->bindValue($i, $val, $columnMap[$key]); + $i += 1; + } + $statement->execute(); $statement->closeCursor(); } return $this->commit(); diff --git a/lib/Cake/Test/Fixture/CounterCachePostFixture.php b/lib/Cake/Test/Fixture/CounterCachePostFixture.php index 9a5767dbb..dd7b92f1c 100644 --- a/lib/Cake/Test/Fixture/CounterCachePostFixture.php +++ b/lib/Cake/Test/Fixture/CounterCachePostFixture.php @@ -34,7 +34,7 @@ class CounterCachePostFixture extends CakeTestFixture { ); public $records = array( - array('id' => 1, 'title' => 'Rock and Roll', 'user_id' => 66, 'published' => 0), + array('id' => 1, 'title' => 'Rock and Roll', 'user_id' => 66, 'published' => false), array('id' => 2, 'title' => 'Music', 'user_id' => 66, 'published' => true), array('id' => 3, 'title' => 'Food', 'user_id' => 301, 'published' => true), ); From 7d756fda81423cdbc317755a46ce231ede448ab5 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 10 Nov 2011 22:22:11 -0500 Subject: [PATCH 26/31] Fix Helper::field() for Model.min This field would be treated as a field suffix even though it is not. Expand existing tests, and reformat some code. Fixes #2240 --- lib/Cake/Test/Case/View/HelperTest.php | 30 ++++++++++++++++++++------ lib/Cake/View/Helper.php | 10 +++++++-- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/Cake/Test/Case/View/HelperTest.php b/lib/Cake/Test/Case/View/HelperTest.php index 11335da17..b77198d35 100644 --- a/lib/Cake/Test/Case/View/HelperTest.php +++ b/lib/Cake/Test/Case/View/HelperTest.php @@ -220,32 +220,48 @@ class HelperTest extends CakeTestCase { return array( array( 'HelperTestPost.id', - array('HelperTestPost', 'id') + array('HelperTestPost', 'id'), + 'HelperTestPost', + 'id' ), array( 'HelperTestComment.body', - array('HelperTestComment', 'body') + array('HelperTestComment', 'body'), + 'HelperTestComment', + 'body' ), array( 'HelperTest.1.Comment.body', - array('HelperTest', '1', 'Comment', 'body') + array('HelperTest', '1', 'Comment', 'body'), + 'Comment', + 'body' ), array( 'HelperTestComment.BigField', - array('HelperTestComment', 'BigField') + array('HelperTestComment', 'BigField'), + 'HelperTestComment', + 'BigField' + ), + array( + 'HelperTestComment.min', + array('HelperTestComment', 'min'), + 'HelperTestComment', + 'min' ) ); } /** - * testFormFieldNameParsing method + * Test setting an entity and retriving the entity, model and field. * * @dataProvider entityProvider * @return void */ - public function testSetEntity($entity, $expected) { + public function testSetEntity($entity, $expected, $modelKey, $fieldKey) { $this->Helper->setEntity($entity); $this->assertEquals($expected, $this->Helper->entity()); + $this->assertEquals($modelKey, $this->Helper->model()); + $this->assertEquals($fieldKey, $this->Helper->field()); } /** @@ -255,7 +271,7 @@ class HelperTest extends CakeTestCase { */ public function testSetEntityScoped() { $this->Helper->setEntity('HelperTestPost', true); - $this->assertEquals(array('HelperTestPost'), $this->Helper->entity()); + $this->assertEquals(array('HelperTestPost'), $this->Helper->entity()); $this->Helper->setEntity('id'); $expected = array('HelperTestPost', 'id'); diff --git a/lib/Cake/View/Helper.php b/lib/Cake/View/Helper.php index 91fafae3b..523e59fee 100644 --- a/lib/Cake/View/Helper.php +++ b/lib/Cake/View/Helper.php @@ -446,7 +446,11 @@ class Helper extends Object { // 0.name, 0.created.month style inputs. Excludes inputs with the modelScope in them. if ( - $count >= 2 && is_numeric($parts[0]) && !is_numeric($parts[1]) && $this->_modelScope && strpos($entity, $this->_modelScope) === false + $count >= 2 && + is_numeric($parts[0]) && + !is_numeric($parts[1]) && + $this->_modelScope && + strpos($entity, $this->_modelScope) === false ) { $entity = $this->_modelScope . '.' . $entity; } @@ -500,6 +504,8 @@ class Helper extends Object { /** * Gets the currently-used model field of the rendering context. + * Strips off fieldsuffixes such as year, month, day, hour, min, meridian + * when the current entity is longer than 2 elements. * * @return string */ @@ -507,7 +513,7 @@ class Helper extends Object { $entity = $this->entity(); $count = count($entity); $last = $entity[$count - 1]; - if (in_array($last, $this->_fieldSuffixes)) { + if ($count > 2 && in_array($last, $this->_fieldSuffixes)) { $last = isset($entity[$count - 2]) ? $entity[$count - 2] : null; } return $last; From 7df3252d6b37e94c6718a5a18946a4ba7bf24d55 Mon Sep 17 00:00:00 2001 From: Kyle Robinson Young Date: Fri, 11 Nov 2011 10:51:14 -0800 Subject: [PATCH 27/31] Add missing @link to TimeHelper docblocks and correct @return --- lib/Cake/View/Helper/TimeHelper.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Cake/View/Helper/TimeHelper.php b/lib/Cake/View/Helper/TimeHelper.php index a7a8107f5..55fede407 100644 --- a/lib/Cake/View/Helper/TimeHelper.php +++ b/lib/Cake/View/Helper/TimeHelper.php @@ -61,6 +61,7 @@ class TimeHelper extends AppHelper { * Accepts the special specifier %S which mimics th modifier S for date() * @param string $time UNIX timestamp * @return string windows safe and date() function compatible format for strftime + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting */ public function convertSpecifiers($format, $time = null) { if (!$time) { @@ -172,7 +173,8 @@ class TimeHelper extends AppHelper { * * @param string $serverTime UNIX timestamp * @param integer $userOffset User's offset from GMT (in hours) - * @return string UNIX timestamp + * @return integer UNIX timestamp + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting */ public function convert($serverTime, $userOffset) { $serverOffset = $this->serverOffset(); @@ -185,6 +187,7 @@ class TimeHelper extends AppHelper { * Returns server's offset from GMT in seconds. * * @return integer Offset + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting */ public function serverOffset() { return date('Z', time()); @@ -311,6 +314,7 @@ class TimeHelper extends AppHelper { * @param string $dateString Datetime string or Unix timestamp * @param integer $userOffset User's offset from GMT (in hours) * @return boolean True if datetime string is today + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#testing-time */ public function isToday($dateString, $userOffset = null) { $date = $this->fromString($dateString, $userOffset); @@ -708,6 +712,7 @@ class TimeHelper extends AppHelper { * @param boolean $invalid flag to ignore results of fromString == false * @param integer $userOffset User's offset from GMT (in hours) * @return string Formatted date string + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting */ public function format($format, $date = null, $invalid = false, $userOffset = null) { $time = $this->fromString($date, $userOffset); @@ -732,6 +737,7 @@ class TimeHelper extends AppHelper { * @param boolean $invalid flag to ignore results of fromString == false * @param integer $userOffset User's offset from GMT (in hours) * @return string Formatted and translated date string + * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#formatting */ public function i18nFormat($date, $format = null, $invalid = false, $userOffset = null) { $date = $this->fromString($date, $userOffset); From 493ce3a442660e4079b4992d009e07ab0516d02b Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 11 Nov 2011 21:26:46 -0500 Subject: [PATCH 28/31] Fix issue where REST actions were not easily testable. Fixes #2198 --- .../Case/TestSuite/ControllerTestCaseTest.php | 15 ++++++++++ lib/Cake/TestSuite/ControllerTestCase.php | 30 +++++++++++++------ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/Cake/Test/Case/TestSuite/ControllerTestCaseTest.php b/lib/Cake/Test/Case/TestSuite/ControllerTestCaseTest.php index af9d932dd..f69ca32c9 100644 --- a/lib/Cake/Test/Case/TestSuite/ControllerTestCaseTest.php +++ b/lib/Cake/Test/Case/TestSuite/ControllerTestCaseTest.php @@ -425,6 +425,21 @@ class ControllerTestCaseTest extends CakeTestCase { $this->assertTrue(isset($query['blue'])); } +/** + * Test that REST actions with XML/JSON input work. + * + * @return void + */ + public function testTestActionJsonData() { + $result = $this->Case->testAction('/tests_apps_posts/input_data', array( + 'return' => 'vars', + 'method' => 'post', + 'data' => '{"key":"value","json":true}' + )); + $this->assertEquals('value', $result['data']['key']); + $this->assertTrue($result['data']['json']); + } + /** * Tests autoMock ability */ diff --git a/lib/Cake/TestSuite/ControllerTestCase.php b/lib/Cake/TestSuite/ControllerTestCase.php index 1557958fa..bda1cae45 100644 --- a/lib/Cake/TestSuite/ControllerTestCase.php +++ b/lib/Cake/TestSuite/ControllerTestCase.php @@ -187,11 +187,14 @@ abstract class ControllerTestCase extends CakeTestCase { } /** - * Tests a controller action. + * Lets you do functional tests of a controller action. * * ### Options: * - * - `data` POST or GET data to pass. Depends on the method. + * - `data` Will be used as the request data. If the `method` is GET, + * data will be used a GET params. If the `method` is POST, it will be used + * as POST data. By setting `$options['data']` to a string, you can simulate XML or JSON + * payloads to your controllers allowing you to test REST webservices. * - `method` POST or GET. Defaults to POST. * - `return` Specify the return type you want. Choose from: * - `vars` Get the set view variables. @@ -213,14 +216,23 @@ abstract class ControllerTestCase extends CakeTestCase { ), $options); $_SERVER['REQUEST_METHOD'] = strtoupper($options['method']); - if (strtoupper($options['method']) == 'GET') { - $_GET = $options['data']; - $_POST = array(); - } else { - $_POST = $options['data']; - $_GET = array(); + if (is_array($options['data'])) { + if (strtoupper($options['method']) == 'GET') { + $_GET = $options['data']; + $_POST = array(); + } else { + $_POST = $options['data']; + $_GET = array(); + } } - $request = new CakeRequest($url); + $request = $this->getMock('CakeRequest', array('_readInput'), array($url)); + + if (is_string($options['data'])) { + $request->expects($this->any()) + ->method('_readInput') + ->will($this->returnValue($options['data'])); + } + $Dispatch = new ControllerTestDispatcher(); foreach (Router::$routes as $route) { if ($route instanceof RedirectRoute) { From 99caa98df3beeec080654ef31eee7d363e9e7018 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 11 Nov 2011 21:28:24 -0500 Subject: [PATCH 29/31] Update message for PHPUnit3.6 --- lib/Cake/Console/Command/TestsuiteShell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Console/Command/TestsuiteShell.php b/lib/Cake/Console/Command/TestsuiteShell.php index 681b6036a..5c870b900 100644 --- a/lib/Cake/Console/Command/TestsuiteShell.php +++ b/lib/Cake/Console/Command/TestsuiteShell.php @@ -157,7 +157,7 @@ class TestsuiteShell extends Shell { ))->addOption('fixture', array( 'help' => __d('cake_console', 'Choose a custom fixture manager.'), ))->addOption('debug', array( - 'help' => __d('cake_console', 'More verbose output.'), + 'help' => __d('cake_console', 'Enable full output of testsuite. (supported in PHPUnit 3.6.0 and greater)'), )); return $parser; From ee6d1cfdf0b1b507ca1ec27dfa34c0cadfc42ea1 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 11 Nov 2011 21:39:30 -0500 Subject: [PATCH 30/31] Adding changes to test controller. Refs #2198 --- .../Test/test_app/Controller/TestsAppsPostsController.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Cake/Test/test_app/Controller/TestsAppsPostsController.php b/lib/Cake/Test/test_app/Controller/TestsAppsPostsController.php index 9062a5c20..96a9d5f63 100644 --- a/lib/Cake/Test/test_app/Controller/TestsAppsPostsController.php +++ b/lib/Cake/Test/test_app/Controller/TestsAppsPostsController.php @@ -53,6 +53,11 @@ class TestsAppsPostsController extends AppController { $this->render('index'); } + public function input_data() { + $this->set('data', $this->request->input('json_decode', true)); + $this->render('index'); + } + /** * Fixturized action for testAction() * From 5934a7a3244467f5264df28ece1e77da405994c1 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 11 Nov 2011 22:13:20 -0500 Subject: [PATCH 31/31] Fix html coverage reporting. HTML coverage reports now work with PHPUnit 3.6 Fixes #2235 --- .../Case/TestSuite/HtmlCoverageReportTest.php | 49 +++++++++++++++++++ .../TestSuite/Coverage/BaseCoverageReport.php | 11 +++-- .../TestSuite/Coverage/HtmlCoverageReport.php | 16 ++++-- .../TestSuite/Reporter/CakeHtmlReporter.php | 3 +- 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/lib/Cake/Test/Case/TestSuite/HtmlCoverageReportTest.php b/lib/Cake/Test/Case/TestSuite/HtmlCoverageReportTest.php index 8024272e9..b2f6495f4 100644 --- a/lib/Cake/Test/Case/TestSuite/HtmlCoverageReportTest.php +++ b/lib/Cake/Test/Case/TestSuite/HtmlCoverageReportTest.php @@ -127,6 +127,55 @@ class HtmlCoverageReportTest extends CakeTestCase { } } + +/** + * Test that coverage works with phpunit 3.6 as the data formats from coverage are totally different. + * + * @return void + */ + public function testPhpunit36Compatibility() { + $file = array( + 'line 1', + 'line 2', + 'line 3', + 'line 4', + 'line 5', + 'line 6', + 'line 7', + 'line 8', + 'line 9', + 'line 10', + ); + $coverage = array( + 1 => array('HtmlCoverageReportTest::testGenerateDiff'), + 2 => null, + 3 => array('HtmlCoverageReportTest::testGenerateDiff'), + 4 => array('HtmlCoverageReportTest::testGenerateDiff'), + 5 => array(), + 6 => array('HtmlCoverageReportTest::testGenerateDiff'), + 7 => array('HtmlCoverageReportTest::testGenerateDiff'), + 8 => array('HtmlCoverageReportTest::testGenerateDiff'), + 9 => array(), + 10 => array('HtmlCoverageReportTest::testSomething', 'HtmlCoverageReportTest::testGenerateDiff') + ); + + $result = $this->Coverage->generateDiff('myfile.php', $file, $coverage); + $this->assertRegExp('/myfile\.php Code coverage\: \d+\.?\d*\%/', $result); + $this->assertRegExp('/
assertRegExp('/
/', $result);
+		foreach ($file as $i => $line) {
+			$this->assertTrue(strpos($line, $result) !== 0, 'Content is missing ' . $i);
+			$class = 'covered';
+			if (in_array($i + 1, array(5, 9, 2))) {
+				$class = 'uncovered';
+			}
+			if ($i + 1 == 2) {
+				$class .= ' dead';
+			}
+			$this->assertTrue(strpos($class, $result) !== 0, 'Class name is wrong ' . $i);
+		}
+	}
+
 /**
  * test that covering methods show up as title attributes for lines.
  *
diff --git a/lib/Cake/TestSuite/Coverage/BaseCoverageReport.php b/lib/Cake/TestSuite/Coverage/BaseCoverageReport.php
index e12a06faa..788d67d12 100644
--- a/lib/Cake/TestSuite/Coverage/BaseCoverageReport.php
+++ b/lib/Cake/TestSuite/Coverage/BaseCoverageReport.php
@@ -120,7 +120,12 @@ abstract class BaseCoverageReport {
 	}
 
 /**
- * Calculates how many lines are covered and what the total number of executable lines is
+ * Calculates how many lines are covered and what the total number of executable lines is.
+ *
+ * Handles both PHPUnit3.5 and 3.6 formats.
+ *
+ * 3.5 uses -1 for uncovered, and -2 for dead.
+ * 3.6 uses array() for uncovered and null for dead.
  *
  * @param array $fileLines
  * @param array $coverageData
@@ -137,10 +142,10 @@ abstract class BaseCoverageReport {
 			if (!isset($coverageData[$lineno])) {
 				continue;
 			}
-			if (is_array($coverageData[$lineno])) {
+			if (is_array($coverageData[$lineno]) && !empty($coverageData[$lineno])) {
 				$covered++;
 				$total++;
-			} else if ($coverageData[$lineno] === -1) {
+			} else if ($coverageData[$lineno] === -1 || $coverageData[$lineno] === array()) {
 				$total++;
 			}
 		}
diff --git a/lib/Cake/TestSuite/Coverage/HtmlCoverageReport.php b/lib/Cake/TestSuite/Coverage/HtmlCoverageReport.php
index f85d13d1f..651bd1df4 100644
--- a/lib/Cake/TestSuite/Coverage/HtmlCoverageReport.php
+++ b/lib/Cake/TestSuite/Coverage/HtmlCoverageReport.php
@@ -47,6 +47,11 @@ HTML;
 /**
  * Generates an HTML diff for $file based on $coverageData.
  *
+ * Handles both PHPUnit3.5 and 3.6 formats.
+ *
+ * 3.5 uses -1 for uncovered, and -2 for dead.
+ * 3.6 uses array() for uncovered and null for dead.
+ *
  * @param string $filename Name of the file having coverage generated
  * @param array $fileLines File data as an array. See file() for how to get one of these.
  * @param array $coverageData Array of coverage data to use to generate HTML diffs with
@@ -65,17 +70,18 @@ HTML;
 		foreach ($fileLines as $lineno => $line) {
 			$class = 'ignored';
 			$coveringTests = array();
-			if (isset($coverageData[$lineno]) && is_array($coverageData[$lineno])) {
+			if (!empty($coverageData[$lineno]) && is_array($coverageData[$lineno])) {
 				$coveringTests = array();
 				foreach ($coverageData[$lineno] as $test) {
-					$testReflection = new ReflectionClass(current(explode('::', $test['id'])));
+					$class = (is_array($test) && isset($test['id'])) ? $test['id'] : $test;
+					$testReflection = new ReflectionClass(current(explode('::', $class)));
 					$this->_testNames[] = $this->_guessSubjectName($testReflection);
-					$coveringTests[] = $test['id'];
+					$coveringTests[] = $class;
 				}
 				$class = 'covered';
-			} elseif (isset($coverageData[$lineno]) && $coverageData[$lineno] === -1) {
+			} elseif (isset($coverageData[$lineno]) && ($coverageData[$lineno] === -1 || $coverageData[$lineno] === array())) {
 				$class = 'uncovered';
-			} elseif (isset($coverageData[$lineno]) && $coverageData[$lineno] === -2) {
+			} elseif (array_key_exists($lineno, $coverageData) && ($coverageData[$lineno] === -2 || $coverageData[$lineno] === null)) {
 				$class .= ' dead';
 			}
 			$diff[] = $this->_paintLine($line, $lineno, $class, $coveringTests);
diff --git a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php
index a24a22dce..16bb9d760 100644
--- a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php
+++ b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php
@@ -148,7 +148,7 @@ class CakeHtmlReporter extends CakeBaseReporter {
 			}
 			if (method_exists($coverage, 'getData')) {
 				$report = $coverage->getData();
-				echo '
' . __('Coverage generation is not supported with PHPUnit 3.6 at this time.') . '
'; + echo $this->paintCoverage($report); } } $this->paintDocumentEnd(); @@ -161,6 +161,7 @@ class CakeHtmlReporter extends CakeBaseReporter { */ public function paintCoverage(array $coverage) { App::uses('HtmlCoverageReport', 'TestSuite/Coverage'); + $reporter = new HtmlCoverageReport($coverage, $this); echo $reporter->report(); }