Merge branch '1.3' into 1.3-misc

This commit is contained in:
mark_story 2009-11-09 20:10:56 -05:00
commit f5cfab7b4f
26 changed files with 436 additions and 96 deletions

View file

@ -230,6 +230,8 @@ class BakeShell extends Shell {
$this->out("\n\tbake model\n\t\tbakes a model. run 'bake model help' for more info");
$this->out("\n\tbake view\n\t\tbakes views. run 'bake view help' for more info");
$this->out("\n\tbake controller\n\t\tbakes a controller. run 'bake controller help' for more info");
$this->out("\n\tbake fixture\n\t\tbakes fixtures. run 'bake fixture help' for more info.");
$this->out("\n\tbake test\n\t\tbakes unit tests. run 'bake test help' for more info.");
$this->out();
}

View file

@ -258,6 +258,7 @@ class DbConfigTask extends Shell {
$oldConfigs = array();
if (file_exists($filename)) {
config('database');
$db = new $this->databaseClassName;
$temp = get_class_vars(get_class($db));

View file

@ -277,9 +277,11 @@ class FixtureTask extends Shell {
}
switch ($fieldInfo['type']) {
case 'integer':
case 'float':
$insert = $i + 1;
break;
case 'string';
case 'string':
case 'binary':
$isPrimaryUuid = (
isset($fieldInfo['key']) && strtolower($fieldInfo['key']) == 'primary' &&
isset($fieldInfo['length']) && $fieldInfo['length'] == 36

View file

@ -224,7 +224,8 @@ class ProjectTask extends Shell {
$File =& new File($path . 'webroot' . DS . 'index.php');
$contents = $File->read();
if (preg_match('/([\\t\\x20]*define\\(\\\'CAKE_CORE_INCLUDE_PATH\\\',[\\t\\x20\'A-z0-9]*\\);)/', $contents, $match)) {
$result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', '" . CAKE_CORE_INCLUDE_PATH . "');", $contents);
$root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " DS . '" : "'";
$result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', " . $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "');", $contents);
if (!$File->write($result)) {
return false;
}
@ -235,7 +236,7 @@ class ProjectTask extends Shell {
$File =& new File($path . 'webroot' . DS . 'test.php');
$contents = $File->read();
if (preg_match('/([\\t\\x20]*define\\(\\\'CAKE_CORE_INCLUDE_PATH\\\',[\\t\\x20\'A-z0-9]*\\);)/', $contents, $match)) {
$result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', '" . CAKE_CORE_INCLUDE_PATH . "');", $contents);
$result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', ". (strpos(CAKE_CORE_INCLUDE_PATH, '/')===0? " DS . '":"'") . str_replace('/', '\' . DS . \'', trim(CAKE_CORE_INCLUDE_PATH, '/')) . "');", $contents);
if (!$File->write($result)) {
return false;
}

View file

@ -614,15 +614,19 @@ class Dispatcher extends Object {
$this->_stop();
}
$isAsset = false;
$assets = array('js' => 'text/javascript', 'css' => 'text/css', 'gif' => 'image/gif', 'jpg' => 'image/jpeg', 'png' => 'image/png');
$assets = array(
'js' => 'text/javascript', 'css' => 'text/css',
'gif' => 'image/gif', 'jpg' => 'image/jpeg', 'png' => 'image/png'
);
$ext = array_pop(explode('.', $url));
foreach ($assets as $type => $contentType) {
if ($type === $ext) {
if ($type === 'css' || $type === 'js') {
$pos = strpos($url, $type . '/');
$parts = explode('/', $url);
if ($parts[0] === 'css' || $parts[0] === 'js' || $parts[0] === 'img') {
$pos = 0;
} else {
$pos = strpos($url, 'img/');
$pos = strlen($parts[0]);
}
$isAsset = true;
break;
@ -640,7 +644,7 @@ class Dispatcher extends Object {
$paths = array();
if ($pos > 0) {
$plugin = substr($url, 0, $pos - 1);
$plugin = substr($url, 0, $pos);
$url = preg_replace('/^' . preg_quote($plugin, '/') . '\//i', '', $url);
$paths[] = App::pluginPath($plugin) . 'vendors' . DS;
}

View file

@ -367,10 +367,6 @@ class Configure extends Object {
trigger_error(sprintf(__("Can't find application core file. Please create %score.php, and make sure it is readable by PHP.", true), CONFIGS), E_USER_ERROR);
}
if (!include(CONFIGS . 'bootstrap.php')) {
trigger_error(sprintf(__("Can't find application bootstrap file. Please create %sbootstrap.php, and make sure it is readable by PHP.", true), CONFIGS), E_USER_ERROR);
}
if (Configure::read('Cache.disable') !== true) {
$cache = Cache::config('default');
@ -407,6 +403,11 @@ class Configure extends Object {
}
Cache::config('default');
}
if (!include(CONFIGS . 'bootstrap.php')) {
trigger_error(sprintf(__("Can't find application bootstrap file. Please create %sbootstrap.php, and make sure it is readable by PHP.", true), CONFIGS), E_USER_ERROR);
}
if (App::path('controllers') == array()) {
App::build(array(
'models' => $modelPaths, 'views' => $viewPaths, 'controllers' => $controllerPaths,

View file

@ -576,7 +576,7 @@ class SecurityComponent extends Object {
}
$data = $controller->data;
if (!isset($data['_Token']) || !isset($data['_Token']['fields'])) {
if (!isset($data['_Token']) || !isset($data['_Token']['fields']) || !isset($data['_Token']['key'])) {
return false;
}
$token = $data['_Token']['key'];

View file

@ -1112,8 +1112,9 @@ class Controller extends Object {
$type = $defaults[0];
unset($defaults[0]);
}
extract($options = array_merge(array('page' => 1, 'limit' => 20), $defaults, $options));
$options = array_merge(array('page' => 1, 'limit' => 20), $defaults, $options);
$options['limit'] = (empty($options['limit']) || !is_numeric($options['limit'])) ? 1 : $options['limit'];
extract($options);
if (is_array($scope) && !empty($scope)) {
$conditions = array_merge($conditions, $scope);

View file

@ -107,10 +107,13 @@ class ErrorHandler extends Object {
if (!in_array(strtolower($method), array_map('strtolower', get_class_methods($this)))) {
$method = 'error';
}
if ($method !== 'error') {
if (Configure::read('debug') == 0) {
$parentMethods = get_class_methods(get_parent_class($this));
$parentClass = get_parent_class($this);
if (strtolower($parentClass) != 'errorhandler') {
$method = 'error404';
}
$parentMethods = get_class_methods($parentClass);
if (in_array($method, $parentMethods)) {
$method = 'error404';
}

View file

@ -155,7 +155,7 @@ class ContainableBehavior extends ModelBehavior {
if (!$reset && empty($instance->__backOriginalAssociation)) {
$instance->__backOriginalAssociation = $backupBindings;
} else if ($reset) {
$instance->__backAssociation[$type] = $instance->{$type};
$instance->__backAssociation[$type] = $backupBindings[$type];
}
$instance->{$type}[$assoc] = array_merge($instance->{$type}[$assoc], $model['keep'][$assoc]);
}

View file

@ -2453,7 +2453,7 @@ class Model extends Overloadable {
) ||
$this->beforeValidate($options) === false
) {
return $this->validationErrors;
return false;
}
if (!isset($this->validate) || empty($this->validate)) {
@ -2925,7 +2925,7 @@ class Model extends Overloadable {
}
/**
* Called during save operations, before validation. Please note that custom
* Called during validation operations, before validation. Please note that custom
* validation rules can be defined in $validate.
*
* @return boolean True if validate operation should continue, false to abort

View file

@ -68,24 +68,32 @@ class CacheHelper extends AppHelper {
$useCallbacks = false;
if (is_array($this->cacheAction)) {
$controller = Inflector::underscore($this->controllerName);
$controllerAlternate = Inflector::variable($this->controllerName);
$check = str_replace('/', '_', $this->here);
$replace = str_replace('/', '_', $this->base);
$basePath = str_replace('/', '_', $this->base);
$match = str_replace($this->base, '', $this->here);
$match = str_replace('//', '/', $match);
$match = str_replace('/' . $controller . '/', '', $match);
$match = str_replace('/' . $controllerAlternate . '/', '', $match);
$match = str_replace('/' . $this->controllerName . '/', '', $match);
$check = str_replace($replace, '', $check);
$check = str_replace($basePath, '', $check);
$check = str_replace('_' . $controller . '_', '', $check);
$check = str_replace('_' . $this->controllerName . '_', '', $check);
$check = str_replace('_' . $controllerAlternate . '_', '', $match);
$check = Inflector::slug($check);
$check = preg_replace('/^_+/', '', $check);
$check = trim($check, '_');
$keys = str_replace('/', '_', array_keys($this->cacheAction));
$found = array_keys($this->cacheAction);
$index = null;
$count = 0;
foreach ($keys as $key => $value) {
if (strpos($check, $value) === 0) {
if (strpos($check, rtrim($value, '_')) === 0) {
$index = $found[$count];
break;
}

View file

@ -355,7 +355,7 @@ class HtmlHelper extends AppHelper {
*
* #### Options
*
* - `inline` If set to false, the generated tag appears in the head tag of the layout.
* - `inline` If set to false, the generated tag appears in the head tag of the layout. Defaults to true
*
* @param mixed $path The name of a CSS style sheet or an array containing names of
* CSS stylesheets. If `$path` is prefixed with '/', the path will be relative to the webroot
@ -366,13 +366,13 @@ class HtmlHelper extends AppHelper {
* @access public
*/
function css($path, $rel = null, $options = array()) {
$inline = isset($options['inline']) ? $options['inline'] : true;
$options += array('inline' => true);
if (is_array($path)) {
$out = '';
foreach ($path as $i) {
$out .= "\n\t" . $this->css($i, $rel, $options, $inline);
$out .= "\n\t" . $this->css($i, $rel, $options);
}
if ($inline) {
if ($options['inline']) {
return $out . "\n";
}
return;
@ -401,7 +401,7 @@ class HtmlHelper extends AppHelper {
}
if ($rel == 'import') {
$out = sprintf($this->tags['style'], $this->_parseAttributes($options, null, '', ' '), '@import url(' . $url . ');');
$out = sprintf($this->tags['style'], $this->_parseAttributes($options, array('inline'), '', ' '), '@import url(' . $url . ');');
} else {
if ($rel == null) {
$rel = 'stylesheet';
@ -410,7 +410,7 @@ class HtmlHelper extends AppHelper {
}
$out = $this->output($out);
if ($inline) {
if ($options['inline']) {
return $out;
} else {
$view =& ClassRegistry::getObject('view');
@ -471,12 +471,10 @@ class HtmlHelper extends AppHelper {
$url = str_replace(JS_URL, 'cjs/', $url);
}
}
$inline = $options['inline'];
unset($options['inline'], $options['once']);
$attributes = $this->_parseAttributes($options, ' ', ' ');
$attributes = $this->_parseAttributes($options, array('inline', 'once'), ' ');
$out = $this->output(sprintf($this->tags['javascriptlink'], $url, $attributes));
if ($inline) {
if ($options['inline']) {
return $out;
} else {
$view =& ClassRegistry::getObject('view');
@ -496,8 +494,7 @@ class HtmlHelper extends AppHelper {
* @return mixed string or null depending on the value of `$options['inline']`
**/
function scriptBlock($script, $options = array()) {
$defaultOptions = array('safe' => true, 'inline' => true);
$options = array_merge($defaultOptions, $options);
$options += array('safe' => true, 'inline' => true);
if ($options['safe']) {
$script = "\n" . '//<![CDATA[' . "\n" . $script . "\n" . '//]]>' . "\n";
}
@ -526,8 +523,7 @@ class HtmlHelper extends AppHelper {
* @return void
**/
function scriptStart($options = array()) {
$defaultOptions = array('safe' => true, 'inline' => true);
$options = array_merge($defaultOptions, $options);
$options += array('safe' => true, 'inline' => true);
$this->_scriptBlockOptions = $options;
ob_start();
return null;

View file

@ -54,20 +54,20 @@ class PaginatorHelper extends AppHelper {
*
* The values that may be specified are:
*
* - <i>$options['format']</i> Format of the counter. Supported formats are 'range' and 'pages'
* - `$options['format']` Format of the counter. Supported formats are 'range' and 'pages'
* and custom (default). In the default mode the supplied string is parsed and constants are replaced
* by their actual values.
* Constants: %page%, %pages%, %current%, %count%, %start%, %end% .
* - <i>$options['separator']</i> The separator of the actual page and number of pages (default: ' of ').
* - <i>$options['url']</i> Url of the action. See Router::url()
* - <i>$options['url']['sort']</i> the key that the recordset is sorted.
* - <i>$options['url']['direction']</i> Direction of the sorting (default: 'asc').
* - <i>$options['url']['page']</i> Page # to display.
* - <i>$options['model']</i> The name of the model.
* - <i>$options['escape']</i> Defines if the title field for the link should be escaped (default: true).
* - <i>$options['update']</i> DOM id of the element updated with the results of the AJAX call.
* - `$options['separator']` The separator of the actual page and number of pages (default: ' of ').
* - `$options['url']` Url of the action. See Router::url()
* - `$options['url']['sort']` the key that the recordset is sorted.
* - `$options['url']['direction']` Direction of the sorting (default: 'asc').
* - `$options['url']['page']` Page # to display.
* - `$options['model']` The name of the model.
* - `$options['escape']` Defines if the title field for the link should be escaped (default: true).
* - `$options['update']` DOM id of the element updated with the results of the AJAX call.
* If this key isn't specified Paginator will use plain HTML links.
* - <i>$options['indicator']</i> DOM id of the element that will be shown when doing AJAX requests.
* - `$options['indicator']` DOM id of the element that will be shown when doing AJAX requests.
*
* @var array
*/
@ -235,6 +235,12 @@ class PaginatorHelper extends AppHelper {
/**
* Generates a "previous" link for a set of paged records
*
* Options:
*
* - `tag` The tag wrapping tag you want to use, defaults to 'span'
* - `escape` Whether you want the contents html entity encoded, defaults to true
* - `model` The model to use, defaults to PaginatorHelper::defaultModel()
*
* @param string $title Title for the link. Defaults to '<< Previous'.
* @param mixed $options Options for pagination link. See #options for list of keys.
* @param string $disabledTitle Title when the link is disabled.
@ -248,10 +254,16 @@ class PaginatorHelper extends AppHelper {
/**
* Generates a "next" link for a set of paged records
*
* Options:
*
* - `tag` The tag wrapping tag you want to use, defaults to 'span'
* - `escape` Whether you want the contents html entity encoded, defaults to true
* - `model` The model to use, defaults to PaginatorHelper::defaultModel()
*
* @param string $title Title for the link. Defaults to 'Next >>'.
* @param mixed $options Options for pagination link. See #options for list of keys.
* @param mixed $options Options for pagination link. See above for list of keys.
* @param string $disabledTitle Title when the link is disabled.
* @param mixed $disabledOptions Options for the disabled pagination link. See #options for list of keys.
* @param mixed $disabledOptions Options for the disabled pagination link. See above for list of keys.
* @return string A "next" link or or $disabledTitle text if the link is disabled.
*/
function next($title = 'Next >>', $options = array(), $disabledTitle = null, $disabledOptions = array()) {
@ -262,10 +274,15 @@ class PaginatorHelper extends AppHelper {
* Generates a sorting link. Sets named parameters for the sort and direction. Handles
* direction switching automatically.
*
* Options:
*
* - `escape` Whether you want the contents html entity encoded, defaults to true
* - `model` The model to use, defaults to PaginatorHelper::defaultModel()
*
* @param string $title Title for the link.
* @param string $key The name of the key that the recordset should be sorted. If $key is null
* $title will be used for the key, and a title will be generated by inflection.
* @param array $options Options for sorting link. See #options for list of keys.
* @param array $options Options for sorting link. See above for list of keys.
* @return string A link sorting default by 'asc'. If the resultset is sorted 'asc' by the specified
* key the returned link will sort by 'desc'.
*/
@ -306,6 +323,13 @@ class PaginatorHelper extends AppHelper {
/**
* Generates a plain or Ajax link with pagination parameters
*
* Options
*
* - `update` The Id of the DOM element you wish to update. Creates Ajax enabled links
* with the AjaxHelper.
* - `escape` Whether you want the contents html entity encoded, defaults to true
* - `model` The model to use, defaults to PaginatorHelper::defaultModel()
*
* @param string $title Title for the link.
* @param mixed $url Url for the action. See Router::url()
* @param array $options Options for the link. See #options for list of keys.
@ -335,7 +359,7 @@ class PaginatorHelper extends AppHelper {
* Merges passed URL options with current pagination state to generate a pagination URL.
*
* @param array $options Pagination/URL options array
* @param boolean $asArray
* @param boolean $asArray Return the url as an array, or a URI string
* @param string $model Which model to paginate on
* @return mixed By default, returns a full pagination URL string for use in non-standard contexts (i.e. JavaScript)
*/
@ -467,8 +491,16 @@ class PaginatorHelper extends AppHelper {
/**
* Returns a counter string for the paged result set
*
* Options
*
* - `model` The model to use, defaults to PaginatorHelper::defaultModel();
* - `format` The format string you want to use, defaults to 'pages' Which generates output like '1 of 5'
* set to 'range' to generate output like '1 - 3 of 13'. Can also be set to a custom string, containing
* the following placeholders `%page%`, `%pages%`, `%current%`, `%count%`, `%start%`, `%end%` and any
* custom content you would like.
* - `separator` The separator string to use, default to ' of '
*
* @param mixed $options Options for the counter string. See #options for list of keys.
* @todo See about deprecating the keys in $map for formatting
* @return string Counter string.
*/
function counter($options = array()) {
@ -480,7 +512,7 @@ class PaginatorHelper extends AppHelper {
array(
'model' => $this->defaultModel(),
'format' => 'pages',
'separator' => ' of '
'separator' => __(' of ', true)
),
$options);
@ -532,6 +564,19 @@ class PaginatorHelper extends AppHelper {
* Returns a set of numbers for the paged result set
* uses a modulus to decide how many numbers to show on each side of the current page (default: 8)
*
* Options
*
* - `before` Content to be inserted before the numbers
* - `after` Content to be inserted after the numbers
* - `model` Model to create numbers for, defaults to PaginatorHelper::defaultModel()
* - `modulus` how many numbers to include on either side of the current page, defaults to 8.
* - `separator` Separator content defaults to ' | '
* - `tag` The tag to wrap links in, defaults to 'span'
* - `first` Whether you want first links generated, set to an integer to define the number of 'first'
* links to generate
* - `last` Whether you want last links generated, set to an integer to define the number of 'last'
* links to generate
*
* @param mixed $options Options for the numbers, (before, after, model, modulus, separator)
* @return string numbers string.
*/
@ -639,6 +684,13 @@ class PaginatorHelper extends AppHelper {
/**
* Returns a first or set of numbers for the first pages
*
* Options:
*
* - `tag` The tag wrapping tag you want to use, defaults to 'span'
* - `before` Content to insert before the link/tag
* - `model` The model to use defaults to PaginatorHelper::defaultModel()
* - `separator` Content between the generated links, defaults to ' | '
*
* @param mixed $first if string use as label for the link, if numeric print page numbers
* @param mixed $options
* @return string numbers string.
@ -685,8 +737,15 @@ class PaginatorHelper extends AppHelper {
/**
* Returns a last or set of numbers for the last pages
*
* Options:
*
* - `tag` The tag wrapping tag you want to use, defaults to 'span'
* - `before` Content to insert before the link/tag
* - `model` The model to use defaults to PaginatorHelper::defaultModel()
* - `separator` Content between the generated links, defaults to ' | '
*
* @param mixed $last if string use as label for the link, if numeric print page numbers
* @param mixed $options
* @param mixed $options Array of options
* @return string numbers string.
*/
function last($last = 'last >>', $options = array()) {

View file

@ -61,7 +61,7 @@ class FixtureTaskTest extends CakeTestCase {
*
* @var array
**/
var $fixtures = array('core.article', 'core.comment');
var $fixtures = array('core.article', 'core.comment', 'core.datatype', 'core.binary_test');
/**
* startTest method
@ -259,6 +259,22 @@ class FixtureTaskTest extends CakeTestCase {
$this->assertNoPattern('/var \$records/', $result);
}
/**
* test record generation with float and binary types
*
* @return void
**/
function testRecordGenerationForBinaryAndFloat() {
$this->Task->connection = 'test_suite';
$this->Task->path = '/my/path/';
$result = $this->Task->bake('Article', 'datatypes');
$this->assertPattern("/'float_field' => 1/", $result);
$result = $this->Task->bake('Article', 'binary_tests');
$this->assertPattern("/'data' => 'Lorem ipsum dolor sit amet'/", $result);
}
/**
* Test that file generation includes headers and correct path for plugins.
*

View file

@ -130,6 +130,22 @@ class ProjectTaskTest extends CakeTestCase {
$this->assertNoPattern('/DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi/', $contents, 'Default Salt left behind. %s');
}
/**
* Test that index.php is generated correctly.
*
* @return void
**/
function testIndexPhpGeneration() {
$this->_setupTestProject();
$path = $this->Task->path . 'bake_test_app' . DS;
$this->Task->corePath($path);
$file =& new File($path . 'webroot' . DS . 'index.php');
$contents = $file->read();
$this->assertNoPattern('/define\(\'CAKE_CORE_INCLUDE_PATH\', \'ROOT/', $contents);
}
/**
* test getPrefix method, and that it returns Routing.prefix or writes to config file.
*

View file

@ -1785,7 +1785,7 @@ class DispatcherTest extends CakeTestCase {
Configure::write('debug', 0);
ob_start();
$Dispatcher->dispatch('/img/test.jpg');
$Dispatcher->dispatch('img/test.jpg');
$result = ob_get_clean();
$file = file_get_contents(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'vendors' . DS . 'img' . DS . 'test.jpg');
$this->assertEqual($file, $result);
@ -1830,6 +1830,15 @@ class DispatcherTest extends CakeTestCase {
$file = file_get_contents(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS . 'test_plugin' .DS . 'vendors' . DS . 'img' . DS . 'cake.icon.gif');
$this->assertEqual($file, $result);
Configure::write('debug', 2);
$Dispatcher->params = $Dispatcher->parseParams('plugin_js/js/plugin_js.js');
ob_start();
$Dispatcher->cached('plugin_js/js/plugin_js.js');
$result = ob_get_clean();
$expected = "alert('win sauce');";
$this->assertEqual($result, $expected);
header('Content-type: text/html');//reset the header content-type without page can render as plain text.
}

View file

@ -560,6 +560,31 @@ DIGEST;
$this->assertTrue($this->Controller->Security->validatePost($this->Controller));
}
/**
* test that validatePost fails if any of its required fields are missing.
*
* @return void
**/
function testValidatePostFormHacking() {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->params['_Token']['key'];
$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3An%3A1%3A%7Bv%3A0%3B';
$fields .= 'f%3A11%3A%22Zbqry.inyvq%22%3B%7D';
$this->Controller->data = array(
'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
'_Token' => compact('key')
);
$result = $this->Controller->Security->validatePost($this->Controller);
$this->assertFalse($result, 'validatePost passed when fields were missing. %s');
$this->Controller->data = array(
'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
'_Token' => compact('fields')
);
$result = $this->Controller->Security->validatePost($this->Controller);
$this->assertFalse($result, 'validatePost passed when key was missing. %s');
}
/**
* Tests validation of checkbox arrays
*

View file

@ -557,6 +557,22 @@ class ControllerTest extends CakeTestCase {
$Controller->paginate('ControllerPost');
$this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1, 'XSS exploit opened %s');
$this->assertIdentical($Controller->params['paging']['ControllerPost']['options']['page'], 1, 'XSS exploit opened %s');
$Controller->passedArgs = array();
$Controller->paginate = array('limit' => 0);
$Controller->paginate('ControllerPost');
$this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1);
$this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3);
$this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false);
$this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true);
$Controller->passedArgs = array();
$Controller->paginate = array('limit' => 'garbage!');
$Controller->paginate('ControllerPost');
$this->assertIdentical($Controller->params['paging']['ControllerPost']['page'], 1);
$this->assertIdentical($Controller->params['paging']['ControllerPost']['pageCount'], 3);
$this->assertIdentical($Controller->params['paging']['ControllerPost']['prevPage'], false);
$this->assertIdentical($Controller->params['paging']['ControllerPost']['nextPage'], true);
}
/**

View file

@ -3398,6 +3398,17 @@ class ContainableBehaviorTest extends CakeTestCase {
));
$this->assertEqual($expected, $this->Article->User->hasOne);
$this->Article->User->bindModel($userHasOne, false);
$expected = $this->Article->User->hasOne;
$this->Article->find('all', array(
'contain' => array(
'User' => array(
'Comment' => array('fields' => array('created'))
)
)
));
$this->assertEqual($expected, $this->Article->User->hasOne);
$this->Article->User->bindModel($userHasOne, false);
$expected = $this->Article->User->hasOne;
$this->Article->find('all', array(

View file

@ -568,7 +568,22 @@ class ModelDeleteTest extends BaseModelTest {
));
$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;
$result = $Model->delete(1);
$this->assertFalse($result);
$exists = $Model->findById(1);
$this->assertTrue(is_array($exists));
}
}
?>

View file

@ -616,6 +616,40 @@ class ModelWriteTest extends BaseModelTest {
$this->assertTrue($result);
}
/**
* test that beforeValidate returning false can abort saves.
*
* @return void
**/
function testBeforeValidateSaveAbortion() {
$Model =& new CallbackPostTestModel();
$Model->beforeValidateReturn = false;
$data = array(
'title' => 'new article',
'body' => 'this is some text.'
);
$Model->create();
$result = $Model->save($data);
$this->assertFalse($result);
}
/**
* test that beforeSave returning false can abort saves.
*
* @return void
**/
function testBeforeSaveSaveAbortion() {
$Model =& new CallbackPostTestModel();
$Model->beforeSaveReturn = false;
$data = array(
'title' => 'new article',
'body' => 'this is some text.'
);
$Model->create();
$result = $Model->save($data);
$this->assertFalse($result);
}
/**
* testValidates method
*

View file

@ -2025,7 +2025,58 @@ class AssociationTest2 extends CakeTestModel {
* @subpackage cake.tests.cases.libs.model
*/
class Callback extends CakeTestModel {
//
}
/**
* CallbackPostTestModel class
*
* @package cake
* @subpackage cake.tests.cases.libs.model
*/
class CallbackPostTestModel extends CakeTestModel {
var $useTable = 'posts';
/**
* variable to control return of beforeValidate
*
* @var string
*/
var $beforeValidateReturn = true;
/**
* variable to control return of beforeSave
*
* @var string
*/
var $beforeSaveReturn = true;
/**
* variable to control return of beforeDelete
*
* @var string
*/
var $beforeDeleteReturn = true;
/**
* beforeSave callback
*
* @return void
**/
function beforeSave($options) {
return $this->beforeSaveReturn;
}
/**
* beforeValidate callback
*
* @return void
**/
function beforeValidate($options) {
return $this->beforeValidateReturn;
}
/**
* beforeDelete callback
*
* @return void
**/
function beforeDelete($cascade = true) {
return $this->beforeDeleteReturn;
}
}
/**

View file

@ -25,15 +25,6 @@ if (!defined('CAKEPHP_UNIT_TEST_EXECUTION')) {
App::import('Core', array('Controller', 'Model', 'View'));
App::import('Helper', 'Cache');
/**
* TestCacheHelper class
*
* @package cake
* @subpackage cake.tests.cases.libs.view.helpers
*/
class TestCacheHelper extends CacheHelper {
}
/**
* CacheTestController class
*
@ -90,7 +81,8 @@ class CacheHelperTest extends CakeTestCase {
*/
function setUp() {
$this->Controller = new CacheTestController();
$this->Cache = new TestCacheHelper();
$this->Cache = new CacheHelper();
$this->_cacheSettings = Configure::read('Cache');
Configure::write('Cache.check', true);
Configure::write('Cache.disable', false);
}
@ -126,6 +118,7 @@ class CacheHelperTest extends CakeTestCase {
function tearDown() {
clearCache();
unset($this->Cache);
Configure::write('Cache', $this->_cacheSettings);
}
/**
@ -238,7 +231,7 @@ class CacheHelperTest extends CakeTestCase {
*/
function testComplexNoCache () {
$this->Controller->cache_parsing();
$this->Controller->cacheAction = array('cacheTest' => 21600);
$this->Controller->cacheAction = array('cache_complex' => 21600);
$this->Controller->here = '/cacheTest/cache_complex';
$this->Controller->action = 'cache_complex';
$this->Controller->layout = 'multi_cache';
@ -285,6 +278,81 @@ class CacheHelperTest extends CakeTestCase {
$this->assertPattern('/7\. layout after content and after element with no cache tags/', $contents);
}
/**
* test cacheAction set to a boolean
*
* @return void
**/
function testCacheActionArray() {
$this->Controller->cache_parsing();
$this->Controller->cacheAction = array(
'cache_parsing' => 21600
);
$this->Controller->here = '/cache_test/cache_parsing';
$this->Controller->action = 'cache_parsing';
$View = new View($this->Controller);
$result = $View->render('index');
$this->assertNoPattern('/cake:nocache/', $result);
$this->assertNoPattern('/php echo/', $result);
$filename = CACHE . 'views' . DS . 'cache_test_cache_parsing.php';
$this->assertTrue(file_exists($filename));
@unlink($filename);
$this->Controller->cache_parsing();
$this->Controller->cacheAction = array(
'cache_parsing/' => 21600
);
$this->Controller->here = '/cacheTest/cache_parsing';
$this->Controller->action = 'cache_parsing';
$View = new View($this->Controller);
$result = $View->render('index');
$this->assertNoPattern('/cake:nocache/', $result);
$this->assertNoPattern('/php echo/', $result);
$filename = CACHE . 'views' . DS . 'cachetest_cache_parsing.php';
$this->assertTrue(file_exists($filename));
@unlink($filename);
$this->Controller->cache_parsing();
$this->Controller->cacheAction = array(
'cache_parsing/33' => 21600
);
$this->Controller->here = '/cacheTest/cache_parsing/33';
$this->Controller->action = 'cache_parsing';
$View = new View($this->Controller);
$result = $View->render('index');
$this->assertNoPattern('/cake:nocache/', $result);
$this->assertNoPattern('/php echo/', $result);
$filename = CACHE . 'views' . DS . 'cachetest_cache_parsing_33.php';
$this->assertTrue(file_exists($filename));
@unlink($filename);
$this->Controller->cache_parsing();
$this->Controller->cacheAction = array(
'cache_parsing/33' => 21600
);
$this->Controller->here = '/cacheTest/cache_parsing';
$this->Controller->action = 'cache_parsing';
$View = new View($this->Controller);
$result = $View->render('index');
$this->assertNoPattern('/cake:nocache/', $result);
$this->assertNoPattern('/php echo/', $result);
$filename = CACHE . 'views' . DS . 'cachetest_cache_parsing.php';
$this->assertFalse(file_exists($filename));
}
/**
* testCacheEmptySections method
*

View file

@ -0,0 +1 @@
alert('win sauce');