diff --git a/cake/console/libs/acl.php b/cake/console/libs/acl.php index c2b419f9d..99f117ad2 100644 --- a/cake/console/libs/acl.php +++ b/cake/console/libs/acl.php @@ -21,7 +21,8 @@ App::import('Component', 'Acl'); App::import('Model', 'DbAcl'); /** - * Shell for ACL management. + * Shell for ACL management. This console is known to have issues with zend.ze1_compatibility_mode + * being enabled. Be sure to turn it off when using this shell. * * @package cake * @subpackage cake.cake.console.libs diff --git a/cake/libs/cache/memcache.php b/cake/libs/cache/memcache.php index 0508df127..7314fca0b 100644 --- a/cake/libs/cache/memcache.php +++ b/cake/libs/cache/memcache.php @@ -80,12 +80,7 @@ class MemcacheEngine extends CacheEngine { $return = false; $this->__Memcache =& new Memcache(); foreach ($this->settings['servers'] as $server) { - $parts = explode(':', $server); - $host = $parts[0]; - $port = 11211; - if (isset($parts[1])) { - $port = $parts[1]; - } + list($host, $port) = $this->_parseServerString($server); if ($this->__Memcache->addServer($host, $port)) { $return = true; } @@ -95,6 +90,31 @@ class MemcacheEngine extends CacheEngine { return true; } +/** + * Parses the server address into the host/port. Handles both IPv6 and IPv4 + * addresses + * + * @param string $server The server address string. + * @return array Array containing host, port + */ + function _parseServerString($server) { + if (substr($server, 0, 1) == '[') { + $position = strpos($server, ']:'); + if ($position !== false) { + $position++; + } + } else { + $position = strpos($server, ':'); + } + $port = 11211; + $host = $server; + if ($position !== false) { + $host = substr($server, 0, $position); + $port = substr($server, $position + 1); + } + return array($host, $port); + } + /** * Write data for key into cache. When using memcache as your cache engine * remember that the Memcache pecl extension does not support cache expiry times greater diff --git a/cake/libs/controller/components/security.php b/cake/libs/controller/components/security.php index 7d1615fd4..c63b8ffda 100644 --- a/cake/libs/controller/components/security.php +++ b/cake/libs/controller/components/security.php @@ -389,7 +389,7 @@ class SecurityComponent extends Component { $keys = array(); $match = array(); $req = array('nonce' => 1, 'nc' => 1, 'cnonce' => 1, 'qop' => 1, 'username' => 1, 'uri' => 1, 'response' => 1); - preg_match_all('@(\w+)=([\'"]?)([a-zA-Z0-9=./\_-]+)\2@', $digest, $match, PREG_SET_ORDER); + preg_match_all('/(\w+)=([\'"]?)([a-zA-Z0-9@=.\/_-]+)\2/', $digest, $match, PREG_SET_ORDER); foreach ($match as $i) { $keys[$i[1]] = $i[3]; diff --git a/cake/libs/file.php b/cake/libs/file.php index 91a0cca5e..fbd305082 100644 --- a/cake/libs/file.php +++ b/cake/libs/file.php @@ -98,7 +98,7 @@ class File { $this->name = basename($path); } $this->pwd(); - !$this->exists() && $create && $this->safe($path) && $this->create(); + $create && !$this->exists() && $this->safe($path) && $this->create(); } /** diff --git a/cake/libs/model/cake_schema.php b/cake/libs/model/cake_schema.php index 1ac235536..961fc0eb5 100644 --- a/cake/libs/model/cake_schema.php +++ b/cake/libs/model/cake_schema.php @@ -232,13 +232,21 @@ class CakeSchema extends Object { if (is_array($models)) { foreach ($models as $model) { + $importModel = $model; if (isset($this->plugin)) { - $model = $this->plugin . '.' . $model; + $importModel = $this->plugin . '.' . $model; } - $Object = ClassRegistry::init(array('class' => $model, 'ds' => null)); + if (!App::import('Model', $importModel)) { + continue; + } + $vars = get_class_vars($model); + if (empty($vars['useDbConfig']) || $vars['useDbConfig'] != $connection) { + continue; + } + + $Object = ClassRegistry::init(array('class' => $model, 'ds' => $connection)); if (is_object($Object) && $Object->useTable !== false) { - $Object->setDataSource($connection); $table = $db->fullTableName($Object, false); if (in_array($table, $currentTables)) { $key = array_search($table, $currentTables); diff --git a/cake/libs/model/datasources/dbo_source.php b/cake/libs/model/datasources/dbo_source.php index dd515976b..24c48f603 100755 --- a/cake/libs/model/datasources/dbo_source.php +++ b/cake/libs/model/datasources/dbo_source.php @@ -151,7 +151,7 @@ class DboSource extends DataSource { * @param array $config An array defining the new configuration settings * @return boolean True on success, false on failure */ - public function reconnect($config = null) { + function reconnect($config = array()) { $this->disconnect(); $this->setConfig($config); $this->_sources = null; diff --git a/cake/libs/model/model.php b/cake/libs/model/model.php index 22c186219..823f8d2d6 100644 --- a/cake/libs/model/model.php +++ b/cake/libs/model/model.php @@ -1687,6 +1687,7 @@ class Model extends Object { } } } + if (!$this->__save($data, $options)) { $validationErrors[$this->alias] = $this->validationErrors; $validates = false; @@ -1757,7 +1758,6 @@ class Model extends Object { case ($options['validate'] === 'first'): $options['validate'] = true; $return = array(); - continue; break; default: if ($options['atomic']) { @@ -1770,6 +1770,10 @@ class Model extends Object { return $return; break; } + if ($options['atomic'] && !$validates) { + $db->rollback($this); + return false; + } } return $return; } @@ -1821,14 +1825,15 @@ class Model extends Object { } $id = $this->id; - if ($this->exists() && $this->beforeDelete($cascade)) { - $db = $this->getDataSource(); + if ($this->beforeDelete($cascade)) { $filters = $this->Behaviors->trigger($this, 'beforeDelete', array($cascade), array( 'break' => true, 'breakOn' => false )); - if (!$filters) { + if (!$filters || !$this->exists()) { return false; } + $db =& ConnectionManager::getDataSource($this->useDbConfig); + $this->_deleteDependent($id, $cascade); $this->_deleteLinks($id); $this->id = $id; diff --git a/cake/libs/set.php b/cake/libs/set.php index 6fa769bfa..cc7f53e6a 100644 --- a/cake/libs/set.php +++ b/cake/libs/set.php @@ -368,11 +368,11 @@ class Set { $options = array_merge(array('flatten' => true), $options); if (!isset($contexts[0])) { $current = current($data); - if ((is_array($current) && count($data) <= 1) || !is_array($current) || !Set::numeric(array_keys($data))) { + if ((is_array($current) && count($data) < 1) || !is_array($current) || !Set::numeric(array_keys($data))) { $contexts = array($data); } } - $tokens = array_slice(preg_split('/(? $this->plugin, 'controller' => $this->_View->viewPath, 'action' => $options['action'], - 0 => $id ); if (!empty($options['action']) && !isset($options['id'])) { $options['id'] = $this->domId($options['action'] . 'Form'); } $options['action'] = array_merge($actionDefaults, (array)$options['url']); + if (empty($options['action'][0])) { + $options['action'][0] = $id; + } } elseif (is_string($options['url'])) { $options['action'] = $options['url']; } @@ -582,7 +584,7 @@ class FormHelper extends AppHelper { * * In addition to fields control, inputs() allows you to use a few additional options. * - * - `fieldset` Set to false to disable the fieldset. If a string is supplied it will be used as + * - `fieldset` Set to false to disable the fieldset. If a string is supplied it will be used as * the classname for the fieldset element. * - `legend` Set to false to disable the legend for the generated input set. Or supply a string * to customize the legend text. @@ -1078,7 +1080,7 @@ class FormHelper extends AppHelper { array('name', 'type', 'id'), '', ' ' ); $tagName = Inflector::camelize( - $attributes['id'] . '_' . Inflector::underscore($optValue) + $attributes['id'] . '_' . Inflector::slug($optValue) ); if ($label) { @@ -1766,7 +1768,7 @@ class FormHelper extends AppHelper { * - `separator` The contents of the string between select elements. Defaults to '-' * - `empty` - If true, the empty select option is shown. If a string, * that string is displayed as the empty element. - * - `value` | `default` The default value to be used by the input. A value in `$this->data` + * - `value` | `default` The default value to be used by the input. A value in `$this->data` * matching the field name will override this value. If no default is provided `time()` will be used. * * @param string $fieldName Prefix name for the SELECT element @@ -1986,6 +1988,7 @@ class FormHelper extends AppHelper { )); if (!empty($name)) { + $name = $attributes['escape'] ? h($name) : $name; if ($attributes['style'] === 'checkbox') { $select[] = sprintf($this->Html->tags['fieldsetstart'], $name); } else { @@ -2019,7 +2022,7 @@ class FormHelper extends AppHelper { $htmlOptions['value'] = $name; $tagName = Inflector::camelize( - $this->model() . '_' . $this->field().'_'.Inflector::underscore($name) + $this->model() . '_' . $this->field().'_'.Inflector::slug($name) ); $htmlOptions['id'] = $tagName; $label = array('for' => $tagName); diff --git a/cake/libs/view/helpers/jquery_engine.php b/cake/libs/view/helpers/jquery_engine.php index e440f16c8..049091fa6 100644 --- a/cake/libs/view/helpers/jquery_engine.php +++ b/cake/libs/view/helpers/jquery_engine.php @@ -251,14 +251,13 @@ class JqueryEngineHelper extends JsBaseEngineHelper { $options['url'] = $url; if (isset($options['update'])) { $wrapCallbacks = isset($options['wrapCallbacks']) ? $options['wrapCallbacks'] : true; - if ($wrapCallbacks) { - $success = $this->jQueryObject . '("' . $options['update'] . '").html(data);'; - } else { - $success = sprintf( - 'function (data, textStatus) {%s("%s").html(data);}', - $this->jQueryObject, - $options['update'] - ); + $success = ''; + if(isset($options['success']) AND !empty($options['success'])) { + $success .= $options['success']; + } + $success .= $this->jQueryObject . '("' . $options['update'] . '").html(data);'; + if (!$wrapCallbacks) { + $success = 'function (data, textStatus) {' . $success . '}'; } $options['dataType'] = 'html'; $options['success'] = $success; diff --git a/cake/libs/view/view.php b/cake/libs/view/view.php index eae0222f0..013506e61 100644 --- a/cake/libs/view/view.php +++ b/cake/libs/view/view.php @@ -390,8 +390,8 @@ class View extends Object { if ($layout && $this->autoLayout) { $out = $this->renderLayout($out, $layout); $isCached = ( - isset($this->Helpers->Cache) && - (($this->cacheAction != false)) && (Configure::read('Cache.check') === true) + isset($this->Helpers->Cache) || + Configure::read('Cache.check') === true ); if ($isCached) { @@ -562,6 +562,7 @@ class View extends Object { if ( ($count == 1 && !empty($this->association)) || ($count == 1 && $this->model != $this->entityPath) || + ($count == 1 && empty($this->association) && !empty($this->field)) || ($count == 2 && !empty($this->fieldSuffix)) || is_numeric($path[0]) && !empty($assoc) ) { diff --git a/cake/tests/cases/libs/cache/memcache.test.php b/cake/tests/cases/libs/cache/memcache.test.php index f88291105..f0c77be85 100644 --- a/cake/tests/cases/libs/cache/memcache.test.php +++ b/cake/tests/cases/libs/cache/memcache.test.php @@ -20,6 +20,20 @@ if (!class_exists('Cache')) { require LIBS . 'cache.php'; } +App::import('Core', 'cache/Memcache'); + + +class TestMemcacheEngine extends MemcacheEngine { +/** + * public accessor to _parseServerString + * + * @param string $server + * @return array + */ + function parseServerString($server) { + return $this->_parseServerString($server); + } +} /** * MemcacheEngineTest class @@ -121,6 +135,38 @@ class MemcacheEngineTest extends CakeTestCase { $this->assertTrue($result); } +/** + * test connecting to an ipv6 server. + * + * @return void + */ + function testConnectIpv6() { + $Memcache =& new MemcacheEngine(); + $result = $Memcache->init(array( + 'prefix' => 'cake_', + 'duration' => 200, + 'engine' => 'Memcache', + 'servers' => array( + '[::1]:11211' + ) + )); + $this->assertTrue($result); + } + +/** + * test non latin domains. + * + * @return void + */ + function testParseServerStringNonLatin() { + $Memcache =& new TestMemcacheEngine(); + $result = $Memcache->parseServerString('schülervz.net:13211'); + $this->assertEqual($result, array('schülervz.net', '13211')); + + $result = $Memcache->parseServerString('sülül:1111'); + $this->assertEqual($result, array('sülül', '1111')); + } + /** * testReadAndWriteCache method * diff --git a/cake/tests/cases/libs/configure.test.php b/cake/tests/cases/libs/configure.test.php index 2d002d9d5..599e37b01 100644 --- a/cake/tests/cases/libs/configure.test.php +++ b/cake/tests/cases/libs/configure.test.php @@ -565,7 +565,15 @@ class AppImportTest extends CakeTestCase { $this->assertTrue($file); $this->assertTrue(class_exists('DboSource')); } + App::build(); + } +/** + * test import() with plugins + * + * @return void + */ + function testPluginImporting() { App::build(array( 'libs' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'libs' . DS), 'plugins' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS) @@ -587,10 +595,15 @@ class AppImportTest extends CakeTestCase { $result = App::import('Helper', 'TestPlugin.OtherHelper'); $this->assertTrue($result); $this->assertTrue(class_exists('OtherHelperHelper')); + + $result = App::import('Helper', 'TestPlugin.TestPluginApp'); + $this->assertTrue($result); + $this->assertTrue(class_exists('TestPluginAppHelper')); $result = App::import('Datasource', 'TestPlugin.TestSource'); $this->assertTrue($result); $this->assertTrue(class_exists('TestSource')); + App::build(); } diff --git a/cake/tests/cases/libs/controller/components/security.test.php b/cake/tests/cases/libs/controller/components/security.test.php index 6b725da77..e0506805c 100644 --- a/cake/tests/cases/libs/controller/components/security.test.php +++ b/cake/tests/cases/libs/controller/components/security.test.php @@ -1054,6 +1054,7 @@ DIGEST; DIGEST; $expected = array( 'username' => 'Mufasa', + 'realm' => 'testrealm@host.com', 'nonce' => 'dcd98b7102dd2f0e8b11d0f600bfb0c093', 'uri' => '/dir/index.html', 'qop' => 'auth', @@ -1088,6 +1089,7 @@ DIGEST; DIGEST; $expected = array( 'username' => 'Mufasa', + 'realm' => 'testrealm@host.com', 'nonce' => 'dcd98b7102dd2f0e8b11d0f600bfb0c093', 'uri' => '/dir/index.html', 'qop' => 'auth', @@ -1103,6 +1105,39 @@ DIGEST; $this->assertNull($result); } +/** + * test parsing digest information with email addresses + * + * @return void + */ + function testParseDigestAuthEmailAddress() { + $this->Controller->Security->startup($this->Controller); + $digest = << 'mark@example.com', + 'realm' => 'testrealm@host.com', + 'nonce' => 'dcd98b7102dd2f0e8b11d0f600bfb0c093', + 'uri' => '/dir/index.html', + 'qop' => 'auth', + 'nc' => '00000001', + 'cnonce' => '0a4f113b', + 'response' => '6629fae49393a05397450978507c4ef1', + 'opaque' => '5ccc069c403ebaf9f0171e9517f40e41' + ); + $result = $this->Controller->Security->parseDigestAuthData($digest); + $this->assertIdentical($result, $expected); + } + /** * testFormDisabledFields method * diff --git a/cake/tests/cases/libs/model/cake_schema.test.php b/cake/tests/cases/libs/model/cake_schema.test.php index 05396f265..0be67982d 100644 --- a/cake/tests/cases/libs/model/cake_schema.test.php +++ b/cake/tests/cases/libs/model/cake_schema.test.php @@ -680,17 +680,17 @@ class CakeSchemaTest extends CakeTestCase { 'name' => 'TestApp', 'models' => array('SchemaCrossDatabase', 'SchemaPost') )); - unset($read['tables']['missing']); $this->assertTrue(isset($read['tables']['posts'])); - $this->assertFalse(isset($read['tables']['cross_database'])); + $this->assertFalse(isset($read['tables']['cross_database']), 'Cross database should not appear'); + $this->assertFalse(isset($read['tables']['missing']['cross_database']), 'Cross database should not appear'); $read = $this->Schema->read(array( 'connection' => 'test2', 'name' => 'TestApp', 'models' => array('SchemaCrossDatabase', 'SchemaPost') )); - unset($read['tables']['missing']); - $this->assertFalse(isset($read['tables']['posts'])); + $this->assertFalse(isset($read['tables']['posts']), 'Posts should not appear'); + $this->assertFalse(isset($read['tables']['posts']), 'Posts should not appear'); $this->assertTrue(isset($read['tables']['cross_database'])); $fixture->drop($db2); diff --git a/cake/tests/cases/libs/model/model_delete.test.php b/cake/tests/cases/libs/model/model_delete.test.php index 7cc92aaf7..be790427f 100644 --- a/cake/tests/cases/libs/model/model_delete.test.php +++ b/cake/tests/cases/libs/model/model_delete.test.php @@ -267,446 +267,489 @@ class ModelDeleteTest extends BaseModelTest { } - /** - * test that delete() updates the correct records counterCache() records. - * - * @return void - */ - function testDeleteUpdatingCounterCacheCorrectly() { - $this->loadFixtures('CounterCacheUser', 'CounterCachePost'); - $User = new CounterCacheUser(); +/** + * test that delete() updates the correct records counterCache() records. + * + * @return void + */ + function testDeleteUpdatingCounterCacheCorrectly() { + $this->loadFixtures('CounterCacheUser', 'CounterCachePost'); + $User = new CounterCacheUser(); - $User->Post->delete(3); - $result = $User->read(null, 301); - $this->assertEqual($result['User']['post_count'], 0); + $User->Post->delete(3); + $result = $User->read(null, 301); + $this->assertEqual($result['User']['post_count'], 0); - $result = $User->read(null, 66); - $this->assertEqual($result['User']['post_count'], 2); - } + $result = $User->read(null, 66); + $this->assertEqual($result['User']['post_count'], 2); + } - /** - * testDeleteAll method - * - * @access public - * @return void - */ - function testDeleteAll() { - $this->loadFixtures('Article'); - $TestModel = new Article(); +/** + * testDeleteAll method + * + * @access public + * @return void + */ + function testDeleteAll() { + $this->loadFixtures('Article'); + $TestModel = new Article(); - $data = array('Article' => array( - 'user_id' => 2, + $data = array('Article' => array( + 'user_id' => 2, + 'id' => 4, + 'title' => 'Fourth Article', + 'published' => 'N' + )); + $result = $TestModel->set($data) && $TestModel->save(); + $this->assertTrue($result); + + $data = array('Article' => array( + 'user_id' => 2, + 'id' => 5, + 'title' => 'Fifth Article', + 'published' => 'Y' + )); + $result = $TestModel->set($data) && $TestModel->save(); + $this->assertTrue($result); + + $data = array('Article' => array( + 'user_id' => 1, + 'id' => 6, + 'title' => 'Sixth Article', + 'published' => 'N' + )); + $result = $TestModel->set($data) && $TestModel->save(); + $this->assertTrue($result); + + $TestModel->recursive = -1; + $result = $TestModel->find('all', array( + 'fields' => array('id', 'user_id', 'title', 'published') + )); + + $expected = array( + array('Article' => array( + 'id' => 1, + 'user_id' => 1, + 'title' => 'First Article', + 'published' => 'Y' + )), + array('Article' => array( + 'id' => 2, + 'user_id' => 3, + 'title' => 'Second Article', + 'published' => 'Y' + )), + array('Article' => array( + 'id' => 3, + 'user_id' => 1, + 'title' => 'Third Article', + 'published' => 'Y')), + array('Article' => array( 'id' => 4, + 'user_id' => 2, 'title' => 'Fourth Article', 'published' => 'N' - )); - $result = $TestModel->set($data) && $TestModel->save(); - $this->assertTrue($result); - - $data = array('Article' => array( - 'user_id' => 2, + )), + array('Article' => array( 'id' => 5, + 'user_id' => 2, 'title' => 'Fifth Article', 'published' => 'Y' - )); - $result = $TestModel->set($data) && $TestModel->save(); - $this->assertTrue($result); - - $data = array('Article' => array( - 'user_id' => 1, + )), + array('Article' => array( 'id' => 6, + 'user_id' => 1, 'title' => 'Sixth Article', 'published' => 'N' - )); - $result = $TestModel->set($data) && $TestModel->save(); - $this->assertTrue($result); + ))); - $TestModel->recursive = -1; - $result = $TestModel->find('all', array( - 'fields' => array('id', 'user_id', 'title', 'published') - )); + $this->assertEqual($result, $expected); - $expected = array( - array('Article' => array( - 'id' => 1, - 'user_id' => 1, - 'title' => 'First Article', - 'published' => 'Y' - )), - array('Article' => array( - 'id' => 2, - 'user_id' => 3, - 'title' => 'Second Article', - 'published' => 'Y' - )), - array('Article' => array( - 'id' => 3, - 'user_id' => 1, - 'title' => 'Third Article', - 'published' => 'Y')), - array('Article' => array( - 'id' => 4, - 'user_id' => 2, - 'title' => 'Fourth Article', - 'published' => 'N' - )), - array('Article' => array( - 'id' => 5, - 'user_id' => 2, - 'title' => 'Fifth Article', - 'published' => 'Y' - )), - array('Article' => array( - 'id' => 6, - 'user_id' => 1, - 'title' => 'Sixth Article', - 'published' => 'N' - ))); + $result = $TestModel->deleteAll(array('Article.published' => 'N')); + $this->assertTrue($result); - $this->assertEqual($result, $expected); + $TestModel->recursive = -1; + $result = $TestModel->find('all', array( + 'fields' => array('id', 'user_id', 'title', 'published') + )); + $expected = array( + array('Article' => array( + 'id' => 1, + 'user_id' => 1, + 'title' => 'First Article', + 'published' => 'Y' + )), + array('Article' => array( + 'id' => 2, + 'user_id' => 3, + 'title' => 'Second Article', + 'published' => 'Y' + )), + array('Article' => array( + 'id' => 3, + 'user_id' => 1, + 'title' => 'Third Article', + 'published' => 'Y' + )), + array('Article' => array( + 'id' => 5, + 'user_id' => 2, + 'title' => 'Fifth Article', + 'published' => 'Y' + ))); + $this->assertEqual($result, $expected); - $result = $TestModel->deleteAll(array('Article.published' => 'N')); - $this->assertTrue($result); + $data = array('Article.user_id' => array(2, 3)); + $result = $TestModel->deleteAll($data, true, true); + $this->assertTrue($result); - $TestModel->recursive = -1; - $result = $TestModel->find('all', array( - 'fields' => array('id', 'user_id', 'title', 'published') - )); - $expected = array( - array('Article' => array( - 'id' => 1, - 'user_id' => 1, - 'title' => 'First Article', - 'published' => 'Y' - )), - array('Article' => array( - 'id' => 2, - 'user_id' => 3, - 'title' => 'Second Article', - 'published' => 'Y' - )), - array('Article' => array( - 'id' => 3, - 'user_id' => 1, - 'title' => 'Third Article', - 'published' => 'Y' - )), - array('Article' => array( - 'id' => 5, - 'user_id' => 2, - 'title' => 'Fifth Article', - 'published' => 'Y' - ))); - $this->assertEqual($result, $expected); + $TestModel->recursive = -1; + $result = $TestModel->find('all', array( + 'fields' => array('id', 'user_id', 'title', 'published') + )); + $expected = array( + array('Article' => array( + 'id' => 1, + 'user_id' => 1, + 'title' => 'First Article', + 'published' => 'Y' + )), + array('Article' => array( + 'id' => 3, + 'user_id' => 1, + 'title' => 'Third Article', + 'published' => 'Y' + ))); + $this->assertEqual($result, $expected); - $data = array('Article.user_id' => array(2, 3)); - $result = $TestModel->deleteAll($data, true, true); - $this->assertTrue($result); + $result = $TestModel->deleteAll(array('Article.user_id' => 999)); + $this->assertTrue($result, 'deleteAll returned false when all no records matched conditions. %s'); - $TestModel->recursive = -1; - $result = $TestModel->find('all', array( - 'fields' => array('id', 'user_id', 'title', 'published') - )); - $expected = array( - array('Article' => array( - 'id' => 1, - 'user_id' => 1, - 'title' => 'First Article', - 'published' => 'Y' - )), - array('Article' => array( - 'id' => 3, - 'user_id' => 1, - 'title' => 'Third Article', - 'published' => 'Y' - ))); - $this->assertEqual($result, $expected); + $this->expectError(); + ob_start(); + $result = $TestModel->deleteAll(array('Article.non_existent_field' => 999)); + ob_get_clean(); + $this->assertFalse($result, 'deleteAll returned true when find query generated sql error. %s'); + } - $result = $TestModel->deleteAll(array('Article.user_id' => 999)); - $this->assertTrue($result, 'deleteAll returned false when all no records matched conditions. %s'); +/** + * testRecursiveDel method + * + * @access public + * @return void + */ + function testRecursiveDel() { + $this->loadFixtures('Article', 'Comment', 'Attachment'); + $TestModel = new Article(); - $this->expectError(); - ob_start(); - $result = $TestModel->deleteAll(array('Article.non_existent_field' => 999)); - ob_get_clean(); - $this->assertFalse($result, 'deleteAll returned true when find query generated sql error. %s'); - } + $result = $TestModel->delete(2); + $this->assertTrue($result); - /** - * testRecursiveDel method - * - * @access public - * @return void - */ - function testRecursiveDel() { - $this->loadFixtures('Article', 'Comment', 'Attachment'); - $TestModel = new Article(); + $TestModel->recursive = 2; + $result = $TestModel->read(null, 2); + $this->assertFalse($result); - $result = $TestModel->delete(2); - $this->assertTrue($result); + $result = $TestModel->Comment->read(null, 5); + $this->assertFalse($result); - $TestModel->recursive = 2; - $result = $TestModel->read(null, 2); - $this->assertFalse($result); + $result = $TestModel->Comment->read(null, 6); + $this->assertFalse($result); - $result = $TestModel->Comment->read(null, 5); - $this->assertFalse($result); + $result = $TestModel->Comment->Attachment->read(null, 1); + $this->assertFalse($result); - $result = $TestModel->Comment->read(null, 6); - $this->assertFalse($result); + $result = $TestModel->find('count'); + $this->assertEqual($result, 2); - $result = $TestModel->Comment->Attachment->read(null, 1); - $this->assertFalse($result); + $result = $TestModel->Comment->find('count'); + $this->assertEqual($result, 4); - $result = $TestModel->find('count'); - $this->assertEqual($result, 2); + $result = $TestModel->Comment->Attachment->find('count'); + $this->assertEqual($result, 0); + } - $result = $TestModel->Comment->find('count'); - $this->assertEqual($result, 4); +/** + * testDependentExclusiveDelete method + * + * @access public + * @return void + */ + function testDependentExclusiveDelete() { + $this->loadFixtures('Article', 'Comment'); + $TestModel = new Article10(); - $result = $TestModel->Comment->Attachment->find('count'); - $this->assertEqual($result, 0); - } + $result = $TestModel->find('all'); + $this->assertEqual(count($result[0]['Comment']), 4); + $this->assertEqual(count($result[1]['Comment']), 2); + $this->assertEqual($TestModel->Comment->find('count'), 6); - /** - * testDependentExclusiveDelete method - * - * @access public - * @return void - */ - function testDependentExclusiveDelete() { - $this->loadFixtures('Article', 'Comment'); - $TestModel = new Article10(); + $TestModel->delete(1); + $this->assertEqual($TestModel->Comment->find('count'), 2); + } - $result = $TestModel->find('all'); - $this->assertEqual(count($result[0]['Comment']), 4); - $this->assertEqual(count($result[1]['Comment']), 2); - $this->assertEqual($TestModel->Comment->find('count'), 6); +/** + * testDeleteLinks method + * + * @access public + * @return void + */ + function testDeleteLinks() { + $this->loadFixtures('Article', 'ArticlesTag', 'Tag'); + $TestModel = new Article(); - $TestModel->delete(1); - $this->assertEqual($TestModel->Comment->find('count'), 2); - } + $result = $TestModel->ArticlesTag->find('all'); + $expected = array( + array('ArticlesTag' => array( + 'article_id' => '1', + 'tag_id' => '1' + )), + array('ArticlesTag' => array( + 'article_id' => '1', + 'tag_id' => '2' + )), + array('ArticlesTag' => array( + 'article_id' => '2', + 'tag_id' => '1' + )), + array('ArticlesTag' => array( + 'article_id' => '2', + 'tag_id' => '3' + ))); + $this->assertEqual($result, $expected); - /** - * testDeleteLinks method - * - * @access public - * @return void - */ - function testDeleteLinks() { - $this->loadFixtures('Article', 'ArticlesTag', 'Tag'); - $TestModel = new Article(); + $TestModel->delete(1); + $result = $TestModel->ArticlesTag->find('all'); - $result = $TestModel->ArticlesTag->find('all'); - $expected = array( - array('ArticlesTag' => array( - 'article_id' => '1', - 'tag_id' => '1' - )), - array('ArticlesTag' => array( - 'article_id' => '1', - 'tag_id' => '2' - )), - array('ArticlesTag' => array( - 'article_id' => '2', - 'tag_id' => '1' - )), - array('ArticlesTag' => array( - 'article_id' => '2', - 'tag_id' => '3' - ))); - $this->assertEqual($result, $expected); + $expected = array( + array('ArticlesTag' => array( + 'article_id' => '2', + 'tag_id' => '1' + )), + array('ArticlesTag' => array( + 'article_id' => '2', + 'tag_id' => '3' + ))); + $this->assertEqual($result, $expected); - $TestModel->delete(1); - $result = $TestModel->ArticlesTag->find('all'); + $result = $TestModel->deleteAll(array('Article.user_id' => 999)); + $this->assertTrue($result, 'deleteAll returned false when all no records matched conditions. %s'); + } - $expected = array( - array('ArticlesTag' => array( - 'article_id' => '2', - 'tag_id' => '1' - )), - array('ArticlesTag' => array( - 'article_id' => '2', - 'tag_id' => '3' - ))); - $this->assertEqual($result, $expected); +/** + * test deleteLinks with Multiple habtm associations + * + * @return void + */ + function testDeleteLinksWithMultipleHabtmAssociations() { + $this->loadFixtures('JoinA', 'JoinB', 'JoinC', 'JoinAB', 'JoinAC'); + $JoinA = new JoinA(); - $result = $TestModel->deleteAll(array('Article.user_id' => 999)); - $this->assertTrue($result, 'deleteAll returned false when all no records matched conditions. %s'); - } + //create two new join records to expose the issue. + $JoinA->JoinAsJoinC->create(array( + 'join_a_id' => 1, + 'join_c_id' => 2, + )); + $JoinA->JoinAsJoinC->save(); + $JoinA->JoinAsJoinB->create(array( + 'join_a_id' => 1, + 'join_b_id' => 2, + )); + $JoinA->JoinAsJoinB->save(); - /** - * test deleteLinks with Multiple habtm associations - * - * @return void - */ - function testDeleteLinksWithMultipleHabtmAssociations() { - $this->loadFixtures('JoinA', 'JoinB', 'JoinC', 'JoinAB', 'JoinAC'); - $JoinA = new JoinA(); + $result = $JoinA->delete(1); + $this->assertTrue($result, 'Delete failed %s'); - //create two new join records to expose the issue. - $JoinA->JoinAsJoinC->create(array( - 'join_a_id' => 1, - 'join_c_id' => 2, - )); - $JoinA->JoinAsJoinC->save(); - $JoinA->JoinAsJoinB->create(array( - 'join_a_id' => 1, - 'join_b_id' => 2, - )); - $JoinA->JoinAsJoinB->save(); + $joinedBs = $JoinA->JoinAsJoinB->find('count', array( + 'conditions' => array('JoinAsJoinB.join_a_id' => 1) + )); + $this->assertEqual($joinedBs, 0, 'JoinA/JoinB link records left over. %s'); - $result = $JoinA->delete(1); - $this->assertTrue($result, 'Delete failed %s'); + $joinedBs = $JoinA->JoinAsJoinC->find('count', array( + 'conditions' => array('JoinAsJoinC.join_a_id' => 1) + )); + $this->assertEqual($joinedBs, 0, 'JoinA/JoinC link records left over. %s'); + } - $joinedBs = $JoinA->JoinAsJoinB->find('count', array( - 'conditions' => array('JoinAsJoinB.join_a_id' => 1) - )); - $this->assertEqual($joinedBs, 0, 'JoinA/JoinB link records left over. %s'); +/** + * testHabtmDeleteLinksWhenNoPrimaryKeyInJoinTable method + * + * @access public + * @return void + */ + function testHabtmDeleteLinksWhenNoPrimaryKeyInJoinTable() { - $joinedBs = $JoinA->JoinAsJoinC->find('count', array( - 'conditions' => array('JoinAsJoinC.join_a_id' => 1) - )); - $this->assertEqual($joinedBs, 0, 'JoinA/JoinC link records left over. %s'); - } + $this->loadFixtures('Apple', 'Device', 'ThePaperMonkies'); + $ThePaper = new ThePaper(); + $ThePaper->id = 1; + $ThePaper->save(array('Monkey' => array(2, 3))); - /** - * testHabtmDeleteLinksWhenNoPrimaryKeyInJoinTable method - * - * @access public - * @return void - */ - function testHabtmDeleteLinksWhenNoPrimaryKeyInJoinTable() { + $result = $ThePaper->findById(1); + $expected = array( + array( + 'id' => '2', + 'device_type_id' => '1', + 'name' => 'Device 2', + 'typ' => '1' + ), + array( + 'id' => '3', + 'device_type_id' => '1', + 'name' => 'Device 3', + 'typ' => '2' + )); + $this->assertEqual($result['Monkey'], $expected); - $this->loadFixtures('Apple', 'Device', 'ThePaperMonkies'); - $ThePaper = new ThePaper(); - $ThePaper->id = 1; - $ThePaper->save(array('Monkey' => array(2, 3))); + $ThePaper = new ThePaper(); + $ThePaper->id = 2; + $ThePaper->save(array('Monkey' => array(2, 3))); - $result = $ThePaper->findById(1); - $expected = array( - array( - 'id' => '2', - 'device_type_id' => '1', - 'name' => 'Device 2', - 'typ' => '1' - ), - array( - 'id' => '3', - 'device_type_id' => '1', - 'name' => 'Device 3', - 'typ' => '2' - )); - $this->assertEqual($result['Monkey'], $expected); + $result = $ThePaper->findById(2); + $expected = array( + array( + 'id' => '2', + 'device_type_id' => '1', + 'name' => 'Device 2', + 'typ' => '1' + ), + array( + 'id' => '3', + 'device_type_id' => '1', + 'name' => 'Device 3', + 'typ' => '2' + )); + $this->assertEqual($result['Monkey'], $expected); - $ThePaper = new ThePaper(); - $ThePaper->id = 2; - $ThePaper->save(array('Monkey' => array(2, 3))); + $ThePaper->delete(1); + $result = $ThePaper->findById(2); + $expected = array( + array( + 'id' => '2', + 'device_type_id' => '1', + 'name' => 'Device 2', + 'typ' => '1' + ), + array( + 'id' => '3', + 'device_type_id' => '1', + 'name' => 'Device 3', + 'typ' => '2' + )); + $this->assertEqual($result['Monkey'], $expected); + } - $result = $ThePaper->findById(2); - $expected = array( - array( - 'id' => '2', - 'device_type_id' => '1', - 'name' => 'Device 2', - 'typ' => '1' - ), - array( - 'id' => '3', - 'device_type_id' => '1', - 'name' => 'Device 3', - 'typ' => '2' - )); - $this->assertEqual($result['Monkey'], $expected); +/** + * test that beforeDelete returning false can abort deletion. + * + * @return void + */ + function testBeforeDeleteDeleteAbortion() { + $this->loadFixtures('Post'); + $Model = new CallbackPostTestModel(); + $Model->beforeDeleteReturn = false; - $ThePaper->delete(1); - $result = $ThePaper->findById(2); - $expected = array( - array( - 'id' => '2', - 'device_type_id' => '1', - 'name' => 'Device 2', - 'typ' => '1' - ), - array( - 'id' => '3', - 'device_type_id' => '1', - 'name' => 'Device 3', - 'typ' => '2' - )); - $this->assertEqual($result['Monkey'], $expected); - } + $result = $Model->delete(1); + $this->assertFalse($result); - /** - * test that beforeDelete returning false can abort deletion. - * - * @return void - */ - function testBeforeDeleteDeleteAbortion() { - $this->loadFixtures('Post'); - $Model = new CallbackPostTestModel(); - $Model->beforeDeleteReturn = false; + $exists = $Model->findById(1); + $this->assertTrue(is_array($exists)); + } - $result = $Model->delete(1); - $this->assertFalse($result); +/** + * test for a habtm deletion error that occurs in postgres but should not. + * And should not occur in any dbo. + * + * @return void + */ + function testDeleteHabtmPostgresFailure() { + $this->loadFixtures('Article', 'Tag', 'ArticlesTag'); - $exists = $Model->findById(1); - $this->assertTrue(is_array($exists)); - } + $Article = ClassRegistry::init('Article'); + $Article->hasAndBelongsToMany['Tag']['unique'] = true; - /** - * test for a habtm deletion error that occurs in postgres but should not. - * And should not occur in any dbo. - * - * @return void - */ - function testDeleteHabtmPostgresFailure() { - $this->loadFixtures('Article', 'Tag', 'ArticlesTag'); + $Tag = ClassRegistry::init('Tag'); + $Tag->bindModel(array('hasAndBelongsToMany' => array( + 'Article' => array( + 'className' => 'Article', + 'unique' => true + ) + )), true); - $Article = ClassRegistry::init('Article'); - $Article->hasAndBelongsToMany['Tag']['unique'] = true; + // Article 1 should have Tag.1 and Tag.2 + $before = $Article->find("all", array( + "conditions" => array("Article.id" => 1), + )); + $this->assertEqual(count($before[0]['Tag']), 2, 'Tag count for Article.id = 1 is incorrect, should be 2 %s'); - $Tag = ClassRegistry::init('Tag'); - $Tag->bindModel(array('hasAndBelongsToMany' => array( - 'Article' => array( - 'className' => 'Article', - 'unique' => true - ) - )), true); + // From now on, Tag #1 is only associated with Post #1 + $submitted_data = array( + "Tag" => array("id" => 1, 'tag' => 'tag1'), + "Article" => array( + "Article" => array(1) + ) + ); + $Tag->save($submitted_data); - // Article 1 should have Tag.1 and Tag.2 - $before = $Article->find("all", array( - "conditions" => array("Article.id" => 1), - )); - $this->assertEqual(count($before[0]['Tag']), 2, 'Tag count for Article.id = 1 is incorrect, should be 2 %s'); + // One more submission (The other way around) to make sure the reverse save looks good. + $submitted_data = array( + "Article" => array("id" => 2, 'title' => 'second article'), + "Tag" => array( + "Tag" => array(2, 3) + ) + ); + // ERROR: + // Postgresql: DELETE FROM "articles_tags" WHERE tag_id IN ('1', '3') + // MySQL: DELETE `ArticlesTag` FROM `articles_tags` AS `ArticlesTag` WHERE `ArticlesTag`.`article_id` = 2 AND `ArticlesTag`.`tag_id` IN (1, 3) + $Article->save($submitted_data); - // From now on, Tag #1 is only associated with Post #1 - $submitted_data = array( - "Tag" => array("id" => 1, 'tag' => 'tag1'), - "Article" => array( - "Article" => array(1) - ) - ); - $Tag->save($submitted_data); + // Want to make sure Article #1 has Tag #1 and Tag #2 still. + $after = $Article->find("all", array( + "conditions" => array("Article.id" => 1), + )); - // One more submission (The other way around) to make sure the reverse save looks good. - $submitted_data = array( - "Article" => array("id" => 2, 'title' => 'second article'), - "Tag" => array( - "Tag" => array(2, 3) - ) - ); - // ERROR: - // Postgresql: DELETE FROM "articles_tags" WHERE tag_id IN ('1', '3') - // MySQL: DELETE `ArticlesTag` FROM `articles_tags` AS `ArticlesTag` WHERE `ArticlesTag`.`article_id` = 2 AND `ArticlesTag`.`tag_id` IN (1, 3) - $Article->save($submitted_data); + // Removing Article #2 from Tag #1 is all that should have happened. + $this->assertEqual(count($before[0]["Tag"]), count($after[0]["Tag"])); + } - // Want to make sure Article #1 has Tag #1 and Tag #2 still. - $after = $Article->find("all", array( - "conditions" => array("Article.id" => 1), - )); +/** + * test that deleting records inside the beforeDelete doesn't truncate the table. + * + * @return void + */ + function testBeforeDeleteWipingTable() { + $this->loadFixtures('Comment'); - // Removing Article #2 from Tag #1 is all that should have happened. - $this->assertEqual(count($before[0]["Tag"]), count($after[0]["Tag"])); - } + $Comment =& new BeforeDeleteComment(); + // Delete 3 records. + $Comment->delete(4); + $result = $Comment->find('count'); + + $this->assertTrue($result > 1, 'Comments are all gone.'); + $Comment->create(array( + 'article_id' => 1, + 'user_id' => 2, + 'comment' => 'new record', + 'published' => 'Y' + )); + $Comment->save(); + + $Comment->delete(5); + $result = $Comment->find('count'); + + $this->assertTrue($result > 1, 'Comments are all gone.'); + } + +/** + * test that deleting the same record from the beforeDelete and the delete doesn't truncate the table. + * + * @return void + */ + function testBeforeDeleteWipingTableWithDuplicateDelete() { + $this->loadFixtures('Comment'); + + $Comment =& new BeforeDeleteComment(); + $Comment->delete(1); + + $result = $Comment->find('count'); + $this->assertTrue($result > 1, 'Comments are all gone.'); + } } diff --git a/cake/tests/cases/libs/model/model_write.test.php b/cake/tests/cases/libs/model/model_write.test.php index 32f70e8db..ec07b6e5a 100644 --- a/cake/tests/cases/libs/model/model_write.test.php +++ b/cake/tests/cases/libs/model/model_write.test.php @@ -2954,7 +2954,7 @@ class ModelWriteTest extends BaseModelTest { * * @return void */ - function testSaveAllTransactionNoRollback() { + function testSaveAllManyRowsTransactionNoRollback() { $this->loadFixtures('Post'); $this->getMock('DboSource', array(), array(), 'MockTransactionDboSource'); @@ -2984,6 +2984,44 @@ class ModelWriteTest extends BaseModelTest { $Post->saveAll($data, array('atomic' => true)); } +/** + * test saveAll with transactions and ensure there is no missing rollback. + * + * @return void + */ + function testSaveAllAssociatedTransactionNoRollback() { + $testDb = ConnectionManager::getDataSource('test_suite'); + + Mock::generate('DboSource', 'MockTransactionAssociatedDboSource'); + $db = ConnectionManager::create('mock_transaction_assoc', array( + 'datasource' => 'MockTransactionAssociatedDbo', + )); + $db->columns = $testDb->columns; + + $db->expectOnce('rollback'); + + $Post =& new Post(); + $Post->useDbConfig = 'mock_transaction_assoc'; + $Post->Author->useDbConfig = 'mock_transaction_assoc'; + + $Post->Author->validate = array( + 'user' => array('rule' => array('notEmpty')) + ); + + $data = array( + 'Post' => array( + 'title' => 'New post', + 'body' => 'Content', + 'published' => 'Y' + ), + 'Author' => array( + 'user' => '', + 'password' => "sekret" + ) + ); + $Post->saveAll($data); + } + /** * testSaveAllTransaction method * diff --git a/cake/tests/cases/libs/model/models.php b/cake/tests/cases/libs/model/models.php index 4e3c44b20..8770e2c01 100644 --- a/cake/tests/cases/libs/model/models.php +++ b/cake/tests/cases/libs/model/models.php @@ -284,6 +284,24 @@ class Article extends CakeTestModel { } } +/** + * Model stub for beforeDelete testing + * + * @see #250 + * @package cake.tests + */ +class BeforeDeleteComment extends CakeTestModel { + var $name = 'BeforeDeleteComment'; + + var $useTable = 'comments'; + + function beforeDelete($cascade = true) { + $db =& $this->getDataSource(); + $db->delete($this, array($this->alias . '.' . $this->primaryKey => array(1, 3))); + return true; + } +} + /** * NumericArticle class * diff --git a/cake/tests/cases/libs/set.test.php b/cake/tests/cases/libs/set.test.php index e2f92a4fd..29f250ca2 100644 --- a/cake/tests/cases/libs/set.test.php +++ b/cake/tests/cases/libs/set.test.php @@ -855,6 +855,39 @@ class SetTest extends CakeTestCase { $r = Set::extract('/file/.[type=application/zip]', $f); $this->assertEqual($r, $expected); + $f = array( + array( + 'file' => array( + 'name' => 'zipfile.zip', + 'type' => 'application/zip', + 'tmp_name' => '/tmp/php178.tmp', + 'error' => 0, + 'size' => '564647' + ) + ), + array( + 'file' => array( + 'name' => 'zipfile2.zip', + 'type' => 'application/x zip compressed', + 'tmp_name' => '/tmp/php179.tmp', + 'error' => 0, + 'size' => '354784' + ) + ), + array( + 'file' => array( + 'name' => 'picture.jpg', + 'type' => 'image/jpeg', + 'tmp_name' => '/tmp/php180.tmp', + 'error' => 0, + 'size' => '21324' + ) + ) + ); + $expected = array(array('name' => 'zipfile2.zip','type' => 'application/x zip compressed','tmp_name' => '/tmp/php179.tmp','error' => 0,'size' => '354784')); + $r = Set::extract('/file/.[type=application/x zip compressed]', $f); + $this->assertEqual($r, $expected); + $hasMany = array( 'Node' => array( 'id' => 1, @@ -1132,6 +1165,27 @@ class SetTest extends CakeTestCase { $expected = array(0 => array('Article' => array('id' => 1, 'approved' => 1))); $result = Set::extract('/Article[approved=1]', $startingAtOne); $this->assertEqual($result, $expected); + + $items = array( + 240 => array( + 'A' => array( + 'field1' => 'a240', + 'field2' => 'a240', + ), + 'B' => array( + 'field1' => 'b240', + 'field2' => 'b240' + ), + ) + ); + + $expected = array( + 0 => 'b240' + ); + + $result = Set::extract('/B/field1', $items); + $this->assertIdentical($result, $expected); + $this->assertIdentical($result, Set::extract('{n}.B.field1', $items)); } /** * testExtractWithArrays method diff --git a/cake/tests/cases/libs/view/helper.test.php b/cake/tests/cases/libs/view/helper.test.php index d5db21a7c..b30c2a767 100644 --- a/cake/tests/cases/libs/view/helper.test.php +++ b/cake/tests/cases/libs/view/helper.test.php @@ -595,6 +595,13 @@ class HelperTest extends CakeTestCase { $this->assertEqual($this->View->association, null); $this->assertEqual($this->View->fieldSuffix, null); + $this->Helper->setEntity('HelperTestTag'); + $this->assertEqual($this->View->model, 'HelperTestTag'); + $this->assertEqual($this->View->field, 'HelperTestTag'); + $this->assertEqual($this->View->modelId, null); + $this->assertEqual($this->View->association, null); + $this->assertEqual($this->View->fieldSuffix, null); + $this->assertEqual($this->View->entityPath, 'HelperTestTag'); } /** diff --git a/cake/tests/cases/libs/view/helpers/form.test.php b/cake/tests/cases/libs/view/helpers/form.test.php index b8649a665..6e8e2c06d 100644 --- a/cake/tests/cases/libs/view/helpers/form.test.php +++ b/cake/tests/cases/libs/view/helpers/form.test.php @@ -1871,7 +1871,7 @@ class FormHelperTest extends CakeTestCase { '/div' ); $this->assertTags($result, $expected); - + $result = $this->Form->input('User.active', array('label' => false, 'checked' => '1')); $expected = array( 'div' => array('class' => 'input checkbox'), @@ -2249,6 +2249,33 @@ class FormHelperTest extends CakeTestCase { $this->assertPattern('/input type="radio"/', $result); } +/** + * fields with the same name as the model should work. + * + * @return void + */ + function testInputWithMatchingFieldAndModelName() { + $this->Form->create('User'); + $this->Form->fieldset = array( + 'User' => array( + 'fields' => array( + 'User' => array('type' => 'text') + ), + 'validates' => array(), + 'key' => 'id' + ) + ); + $this->Form->data['User']['User'] = 'ABC, Inc.'; + $result = $this->Form->input('User', array('type' => 'text')); + $expected = array( + 'div' => array('class' => 'input text'), + 'label' => array('for' => 'UserUser'), 'User', '/label', + 'input' => array('name' => 'data[User][User]', 'type' => 'text', 'id' => 'UserUser', 'value' => 'ABC, Inc.'), + '/div' + ); + $this->assertTags($result, $expected); + } + /** * testFormInputs method * @@ -2475,6 +2502,18 @@ class FormHelperTest extends CakeTestCase { '/div', ); $this->assertTags($result, $expected); + + $result = $this->Form->select('Model.multi_field', array('1/2' => 'half'), null, array('multiple' => 'checkbox')); + $expected = array( + 'input' => array('type' => 'hidden', 'name' => 'data[Model][multi_field]', 'value' => '', 'id' => 'ModelMultiField'), + array('div' => array('class' => 'checkbox')), + array('input' => array('type' => 'checkbox', 'name' => 'data[Model][multi_field][]', 'value' => '1/2', 'id' => 'ModelMultiField12')), + array('label' => array('for' => 'ModelMultiField12')), + 'half', + '/label', + '/div', + ); + $this->assertTags($result, $expected); } /** @@ -2664,6 +2703,16 @@ class FormHelperTest extends CakeTestCase { ); $this->assertTags($result, $expected); + $result = $this->Form->radio('Model.field', array('1/2' => 'half')); + $expected = array( + 'input' => array('type' => 'hidden', 'name' => 'data[Model][field]', 'value' => '', 'id' => 'ModelField_'), + array('input' => array('type' => 'radio', 'name' => 'data[Model][field]', 'value' => '1/2', 'id' => 'ModelField12')), + 'label' => array('for' => 'ModelField12'), + 'half', + '/label' + ); + $this->assertTags($result, $expected); + $result = $this->Form->radio('Model.field', array('option A', 'option B')); $expected = array( 'fieldset' => array(), @@ -3066,6 +3115,47 @@ class FormHelperTest extends CakeTestCase { $this->assertTags($result, $expected); } +/** + * test that select() with optiongroups listens to the escape param. + * + * @return void + */ + function testSelectOptionGroupEscaping() { + $options = array( + '>< Key' => array( + 1 => 'One', + 2 => 'Two' + ) + ); + $result = $this->Form->select('Model.field', $options, null, array('empty' => false)); + $expected = array( + 'select' => array('name' => 'data[Model][field]', 'id' => 'ModelField'), + 'optgroup' => array('label' => '>< Key'), + array('option' => array('value' => '1')), 'One', '/option', + array('option' => array('value' => '2')), 'Two', '/option', + '/optgroup', + '/select' + ); + $this->assertTags($result, $expected); + + $options = array( + '>< Key' => array( + 1 => 'One', + 2 => 'Two' + ) + ); + $result = $this->Form->select('Model.field', $options, null, array('empty' => false, 'escape' => false)); + $expected = array( + 'select' => array('name' => 'data[Model][field]', 'id' => 'ModelField'), + 'optgroup' => array('label' => '>< Key'), + array('option' => array('value' => '1')), 'One', '/option', + array('option' => array('value' => '2')), 'Two', '/option', + '/optgroup', + '/select' + ); + $this->assertTags($result, $expected); + } + /** * Tests that FormHelper::select() allows null to be passed in the $attributes parameter * @@ -3448,7 +3538,7 @@ class FormHelperTest extends CakeTestCase { */ function testInputMultipleCheckboxes() { $result = $this->Form->input('Model.multi_field', array( - 'options' => array('first', 'second', 'third'), + 'options' => array('first', 'second', 'third'), 'multiple' => 'checkbox' )); $expected = array( @@ -3531,7 +3621,7 @@ class FormHelperTest extends CakeTestCase { $result = $this->Form->input('Model.multi_field', array( 'options' => array('2' => 'second'), 'multiple' => 'checkbox', - 'label' => false, + 'label' => false, 'div' => false )); $expected = array( @@ -5484,6 +5574,36 @@ class FormHelperTest extends CakeTestCase { $this->assertTags($result, $expected, true); } +/** + * test that create() doesn't add in extra passed params. + * + * @return void + */ + function testCreatePassedArgs() { + $encoding = strtolower(Configure::read('App.encoding')); + $this->Form->data['Contact']['id'] = 1; + $result = $this->Form->create('Contact', array( + 'type' => 'post', + 'escape' => false, + 'url' => array( + 'action' => 'edit', + 'myparam' + ) + )); + $expected = array( + 'form' => array( + 'id' => 'ContactAddForm', + 'method' => 'post', + 'action' => '/contacts/edit/myparam', + 'accept-charset' => $encoding + ), + 'div' => array('style' => 'display:none;'), + 'input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST'), + '/div' + ); + $this->assertTags($result, $expected, true); + } + /** * test creating a get form, and get form inputs. * diff --git a/cake/tests/cases/libs/view/helpers/jquery_engine.test.php b/cake/tests/cases/libs/view/helpers/jquery_engine.test.php index 17b8c6389..58131a9ad 100644 --- a/cake/tests/cases/libs/view/helpers/jquery_engine.test.php +++ b/cake/tests/cases/libs/view/helpers/jquery_engine.test.php @@ -189,7 +189,7 @@ class JqueryEngineHelperTest extends CakeTestCase { 'method' => 'post', 'wrapCallbacks' => false )); - $expected = '$.ajax({dataType:"html", success:function (data, textStatus) {$("#updated").html(data);}, type:"post", url:"\\/people\\/edit\\/1"});'; + $expected = '$.ajax({dataType:"html", success:function (data, textStatus) {doFoo$("#updated").html(data);}, type:"post", url:"\\/people\\/edit\\/1"});'; $this->assertEqual($result, $expected); $result = $this->Jquery->request('/people/edit/1', array( @@ -200,7 +200,7 @@ class JqueryEngineHelperTest extends CakeTestCase { 'data' => '$("#someId").serialize()', 'wrapCallbacks' => false )); - $expected = '$.ajax({data:$("#someId").serialize(), dataType:"html", success:function (data, textStatus) {$("#updated").html(data);}, type:"post", url:"\\/people\\/edit\\/1"});'; + $expected = '$.ajax({data:$("#someId").serialize(), dataType:"html", success:function (data, textStatus) {doFoo$("#updated").html(data);}, type:"post", url:"\\/people\\/edit\\/1"});'; $this->assertEqual($result, $expected); $result = $this->Jquery->request('/people/edit/1', array( @@ -230,7 +230,7 @@ class JqueryEngineHelperTest extends CakeTestCase { 'data' => '$j("#someId").serialize()', 'wrapCallbacks' => false )); - $expected = '$j.ajax({data:$j("#someId").serialize(), dataType:"html", success:function (data, textStatus) {$j("#updated").html(data);}, type:"post", url:"\\/people\\/edit\\/1"});'; + $expected = '$j.ajax({data:$j("#someId").serialize(), dataType:"html", success:function (data, textStatus) {doFoo$j("#updated").html(data);}, type:"post", url:"\\/people\\/edit\\/1"});'; $this->assertEqual($result, $expected); } diff --git a/cake/tests/cases/libs/view/view.test.php b/cake/tests/cases/libs/view/view.test.php index f63df2944..d6295f74f 100644 --- a/cake/tests/cases/libs/view/view.test.php +++ b/cake/tests/cases/libs/view/view.test.php @@ -799,6 +799,75 @@ class ViewTest extends CakeTestCase { @unlink($path); } +/** + * Test that render() will remove the cake:nocache tags when only the cachehelper is present. + * + * @return void + */ + function testRenderStrippingNoCacheTagsOnlyCacheHelper() { + Configure::write('Cache.check', false); + $View =& new View($this->PostsController); + $View->set(array('superman' => 'clark', 'variable' => 'var')); + $View->helpers = array('Html', 'Form', 'Cache'); + $View->layout = 'cache_layout'; + $result = $View->render('index'); + $this->assertNoPattern('/cake:nocache/', $result); + } + +/** + * Test that render() will remove the cake:nocache tags when only the Cache.check is true. + * + * @return void + */ + function testRenderStrippingNoCacheTagsOnlyCacheCheck() { + Configure::write('Cache.check', true); + $View =& new View($this->PostsController); + $View->set(array('superman' => 'clark', 'variable' => 'var')); + $View->helpers = array('Html', 'Form'); + $View->layout = 'cache_layout'; + $result = $View->render('index'); + $this->assertNoPattern('/cake:nocache/', $result); + } + +/** + * testRenderNocache method + * + * @access public + * @return void + */ + +/* This is a new test case for a pending enhancement + function testRenderNocache() { + $this->PostsController->helpers = array('Cache', 'Html'); + $this->PostsController->constructClasses(); + $this->PostsController->cacheAction = 21600; + $this->PostsController->here = '/posts/nocache_multiple_element'; + $this->PostsController->action = 'nocache_multiple_element'; + $this->PostsController->nocache_multiple_element(); + Configure::write('Cache.check', true); + Configure::write('Cache.disable', false); + + $filename = CACHE . 'views' . DS . 'posts_nocache_multiple_element.php'; + + $View = new TestView($this->PostsController); + $View->render(); + + ob_start(); + $View->renderCache($filename, getMicroTime()); + $result = ob_get_clean(); + @unlink($filename); + + $this->assertPattern('/php echo \$foo;/', $result); + $this->assertPattern('/php echo \$bar;/', $result); + $this->assertPattern('/php \$barfoo = \'in sub2\';/', $result); + $this->assertPattern('/php echo \$barfoo;/', $result); + $this->assertPattern('/printing: "in sub2"/', $result); + $this->assertPattern('/php \$foobar = \'in sub1\';/', $result); + $this->assertPattern('/php echo \$foobar;/', $result); + $this->assertPattern('/printing: "in sub1"/', $result); + } +*/ + /** * testSet method * @@ -854,6 +923,15 @@ class ViewTest extends CakeTestCase { $View->entityPath = '0.Node.title'; $expected = array(0, 'Node', 'title'); $this->assertEqual($View->entity(), $expected); + + $View->model = 'HelperTestTag'; + $View->field = 'HelperTestTag'; + $View->modelId = null; + $View->association = null; + $View->fieldSuffix = null; + $View->entityPath = 'HelperTestTag'; + $expected = array('HelperTestTag', 'HelperTestTag'); + $this->assertEqual($View->entity(), $expected); } /** diff --git a/cake/tests/cases/libs/xml.test.php b/cake/tests/cases/libs/xml.test.php index cc2d5d22e..0392a449a 100644 --- a/cake/tests/cases/libs/xml.test.php +++ b/cake/tests/cases/libs/xml.test.php @@ -25,7 +25,7 @@ App::import('Core', 'Xml'); * @package cake * @subpackage cake.tests.cases.libs */ -class Article extends CakeTestModel { +class XmlArticle extends CakeTestModel { /** * name property @@ -39,7 +39,12 @@ class Article extends CakeTestModel { * * @var array */ - public $belongsTo = array('User'); + public $belongsTo = array( + 'XmlUser' => array( + 'className' => 'XmlArticle', + 'foreignKey' => 'user_id' + ) + ); } /** @@ -48,7 +53,7 @@ class Article extends CakeTestModel { * @package cake * @subpackage cake.tests.cases.libs */ -class User extends CakeTestModel { +class XmlUser extends CakeTestModel { /** * name property @@ -822,7 +827,7 @@ class XmlTest extends CakeTestCase { public function testWithModel() { $this->loadFixtures('User', 'Article'); - $user = new User(); + $user = new XmlUser(); $data = $user->read(null, 1); $obj = Xml::build(compact('data')); diff --git a/cake/tests/test_app/plugins/test_plugin/views/helpers/test_plugin_app.php b/cake/tests/test_app/plugins/test_plugin/views/helpers/test_plugin_app.php new file mode 100644 index 000000000..a95374c3e --- /dev/null +++ b/cake/tests/test_app/plugins/test_plugin/views/helpers/test_plugin_app.php @@ -0,0 +1,5 @@ +