Merge branch '2.x' into 2.next

This commit is contained in:
mark_story 2016-08-09 22:12:26 -04:00
commit 61b3fbd605
28 changed files with 335 additions and 79 deletions

2
.stickler.yml Normal file
View file

@ -0,0 +1,2 @@
branches:
ignore: ['2.x', '2.next']

View file

@ -30,6 +30,7 @@ before_script:
- sh -c "composer global require 'phpunit/phpunit=3.7.33'" - sh -c "composer global require 'phpunit/phpunit=3.7.33'"
- sh -c "ln -s ~/.composer/vendor/phpunit/phpunit/PHPUnit ./vendors/PHPUnit" - sh -c "ln -s ~/.composer/vendor/phpunit/phpunit/PHPUnit ./vendors/PHPUnit"
- sudo locale-gen de_DE - sudo locale-gen de_DE
- sudo locale-gen es_ES
- sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test;'; fi" - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test;'; fi"
- sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test2;'; fi" - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test2;'; fi"
- sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test3;'; fi" - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test3;'; fi"

View file

@ -1,3 +1,9 @@
# Uncomment the following to prevent the httpoxy vulnerability
# See: https://httpoxy.org/
#<IfModule mod_headers.c>
# RequestHeader unset Proxy
#</IfModule>
<IfModule mod_rewrite.c> <IfModule mod_rewrite.c>
RewriteEngine On RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d

View file

@ -71,6 +71,9 @@ class TestShell extends Shell {
))->addOption('coverage-clover', array( ))->addOption('coverage-clover', array(
'help' => __d('cake_console', '<file> Write code coverage data in Clover XML format.'), 'help' => __d('cake_console', '<file> Write code coverage data in Clover XML format.'),
'default' => false 'default' => false
))->addOption('coverage-text', array(
'help' => __d('cake_console', 'Output code coverage report in Text format.'),
'boolean' => true
))->addOption('testdox-html', array( ))->addOption('testdox-html', array(
'help' => __d('cake_console', '<file> Write agile documentation in HTML format to file.'), 'help' => __d('cake_console', '<file> Write agile documentation in HTML format to file.'),
'default' => false 'default' => false
@ -152,6 +155,7 @@ class TestShell extends Shell {
'default' => false 'default' => false
))->addOption('directive', array( ))->addOption('directive', array(
'help' => __d('cake_console', 'key[=value] Sets a php.ini value.'), 'help' => __d('cake_console', 'key[=value] Sets a php.ini value.'),
'short' => 'd',
'default' => false 'default' => false
))->addOption('fixture', array( ))->addOption('fixture', array(
'help' => __d('cake_console', 'Choose a custom fixture manager.') 'help' => __d('cake_console', 'Choose a custom fixture manager.')
@ -234,7 +238,11 @@ class TestShell extends Shell {
if ($value === false) { if ($value === false) {
continue; continue;
} }
$options[] = '--' . $param; if ($param === 'directive') {
$options[] = '-d';
} else {
$options[] = '--' . $param;
}
if (is_string($value)) { if (is_string($value)) {
$options[] = $value; $options[] = $value;
} }

View file

@ -359,7 +359,7 @@ class AuthComponent extends Component {
return true; return true;
} }
if (!$controller->request->is('ajax')) { if (!$controller->request->is('ajax') && !$controller->request->is('json')) {
$this->flash($this->authError); $this->flash($this->authError);
$this->Session->write('Auth.redirect', $controller->request->here(false)); $this->Session->write('Auth.redirect', $controller->request->here(false));
$controller->redirect($this->loginAction); $controller->redirect($this->loginAction);
@ -611,8 +611,12 @@ class AuthComponent extends Component {
$user = $this->identify($this->request, $this->response); $user = $this->identify($this->request, $this->response);
} }
if ($user) { if ($user) {
$this->Session->renew(); if (static::$sessionKey) {
$this->Session->write(static::$sessionKey, $user); $this->Session->renew();
$this->Session->write(static::$sessionKey, $user);
} else {
static::$_user = $user;
}
$event = new CakeEvent('Auth.afterIdentify', $this, array('user' => $user)); $event = new CakeEvent('Auth.afterIdentify', $this, array('user' => $user));
$this->_Collection->getController()->getEventManager()->dispatch($event); $this->_Collection->getController()->getEventManager()->dispatch($event);
} }

View file

@ -20,9 +20,12 @@
*/ */
App::uses('Sanitize', 'Utility'); App::uses('Sanitize', 'Utility');
App::uses('Dispatcher', 'Routing');
App::uses('Router', 'Routing'); App::uses('Router', 'Routing');
App::uses('CakeResponse', 'Network');
App::uses('Controller', 'Controller'); App::uses('Controller', 'Controller');
App::uses('CakeRequest', 'Network');
App::uses('CakeResponse', 'Network');
App::uses('CakeEvent', 'Event');
/** /**
* Exception Renderer. * Exception Renderer.
@ -287,7 +290,7 @@ class ExceptionRenderer {
protected function _outputMessage($template) { protected function _outputMessage($template) {
try { try {
$this->controller->render($template); $this->controller->render($template);
$this->controller->afterFilter(); $this->_shutdown();
$this->controller->response->send(); $this->controller->response->send();
} catch (MissingViewException $e) { } catch (MissingViewException $e) {
$attributes = $e->getAttributes(); $attributes = $e->getAttributes();
@ -327,4 +330,23 @@ class ExceptionRenderer {
$this->controller->response->send(); $this->controller->response->send();
} }
/**
* Run the shutdown events.
*
* Triggers the afterFilter and afterDispatch events.
*
* @return void
*/
protected function _shutdown() {
$afterFilterEvent = new CakeEvent('Controller.shutdown', $this->controller);
$this->controller->getEventManager()->dispatch($afterFilterEvent);
$Dispatcher = new Dispatcher();
$afterDispatchEvent = new CakeEvent('Dispatcher.afterDispatch', $Dispatcher, array(
'request' => $this->controller->request,
'response' => $this->controller->response
));
$Dispatcher->getEventManager()->dispatch($afterDispatchEvent);
}
} }

View file

@ -272,6 +272,7 @@ class L10n {
'hy' => array('language' => 'Armenian - Armenia', 'locale' => 'hye', 'localeFallback' => 'hye', 'charset' => 'utf-8', 'direction' => 'ltr'), 'hy' => array('language' => 'Armenian - Armenia', 'locale' => 'hye', 'localeFallback' => 'hye', 'charset' => 'utf-8', 'direction' => 'ltr'),
'id' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'), 'id' => array('language' => 'Indonesian', 'locale' => 'ind', 'localeFallback' => 'ind', 'charset' => 'utf-8', 'direction' => 'ltr'),
'is' => array('language' => 'Icelandic', 'locale' => 'isl', 'localeFallback' => 'isl', 'charset' => 'utf-8', 'direction' => 'ltr'), 'is' => array('language' => 'Icelandic', 'locale' => 'isl', 'localeFallback' => 'isl', 'charset' => 'utf-8', 'direction' => 'ltr'),
'is-is' => array('language' => 'Icelandic (Iceland)', 'locale' => 'is_is', 'localeFallback' => 'isl', 'charset' => 'utf-8', 'direction' => 'ltr'),
'it' => array('language' => 'Italian', 'locale' => 'ita', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'), 'it' => array('language' => 'Italian', 'locale' => 'ita', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'),
'it-ch' => array('language' => 'Italian (Swiss) ', 'locale' => 'it_ch', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'), 'it-ch' => array('language' => 'Italian (Swiss) ', 'locale' => 'it_ch', 'localeFallback' => 'ita', 'charset' => 'utf-8', 'direction' => 'ltr'),
'ja' => array('language' => 'Japanese', 'locale' => 'jpn', 'localeFallback' => 'jpn', 'charset' => 'utf-8', 'direction' => 'ltr'), 'ja' => array('language' => 'Japanese', 'locale' => 'jpn', 'localeFallback' => 'jpn', 'charset' => 'utf-8', 'direction' => 'ltr'),

View file

@ -487,6 +487,9 @@ class CakeSchema extends CakeObject {
foreach ($fields as $field => $value) { foreach ($fields as $field => $value) {
if (!empty($old[$table][$field])) { if (!empty($old[$table][$field])) {
$diff = $this->_arrayDiffAssoc($value, $old[$table][$field]); $diff = $this->_arrayDiffAssoc($value, $old[$table][$field]);
if (empty($diff)) {
$diff = $this->_arrayDiffAssoc($old[$table][$field], $value);
}
if (!empty($diff) && $field !== 'indexes' && $field !== 'tableParameters') { if (!empty($diff) && $field !== 'indexes' && $field !== 'tableParameters') {
$tables[$table]['change'][$field] = $value; $tables[$table]['change'][$field] = $value;
} }

View file

@ -437,13 +437,7 @@ class Mysql extends DboSource {
if (empty($conditions)) { if (empty($conditions)) {
$alias = $joins = false; $alias = $joins = false;
} }
$complexConditions = false; $complexConditions = $this->_deleteNeedsComplexConditions($model, $conditions);
foreach ((array)$conditions as $key => $value) {
if (strpos($key, $model->alias) === false) {
$complexConditions = true;
break;
}
}
if (!$complexConditions) { if (!$complexConditions) {
$joins = false; $joins = false;
} }
@ -459,6 +453,27 @@ class Mysql extends DboSource {
return true; return true;
} }
/**
* Checks whether complex conditions are needed for a delete with the given conditions.
*
* @param Model $model The model to delete from.
* @param mixed $conditions The conditions to use.
* @return bool Whether or not complex conditions are needed
*/
protected function _deleteNeedsComplexConditions(Model $model, $conditions) {
$fields = array_keys($this->describe($model));
foreach ((array)$conditions as $key => $value) {
if (in_array(strtolower(trim($key)), $this->_sqlBoolOps, true)) {
if ($this->_deleteNeedsComplexConditions($model, $value)) {
return true;
}
} elseif (strpos($key, $model->alias) === false && !in_array($key, $fields, true)) {
return true;
}
}
return false;
}
/** /**
* Sets the database encoding * Sets the database encoding
* *

View file

@ -183,6 +183,13 @@ class DboSource extends DataSource {
*/ */
protected $_sqlOps = array('like', 'ilike', 'rlike', 'or', 'not', 'in', 'between', 'regexp', 'similar to'); protected $_sqlOps = array('like', 'ilike', 'rlike', 'or', 'not', 'in', 'between', 'regexp', 'similar to');
/**
* The set of valid SQL boolean operations usable in a WHERE statement
*
* @var array
*/
protected $_sqlBoolOps = array('and', 'or', 'not', 'and not', 'or not', 'xor', '||', '&&');
/** /**
* Indicates the level of nested transactions * Indicates the level of nested transactions
* *
@ -2678,7 +2685,6 @@ class DboSource extends DataSource {
public function conditionKeysToString($conditions, $quoteValues = true, Model $Model = null) { public function conditionKeysToString($conditions, $quoteValues = true, Model $Model = null) {
$out = array(); $out = array();
$data = $columnType = null; $data = $columnType = null;
$bool = array('and', 'or', 'not', 'and not', 'or not', 'xor', '||', '&&');
foreach ($conditions as $key => $value) { foreach ($conditions as $key => $value) {
$join = ' AND '; $join = ' AND ';
@ -2695,8 +2701,8 @@ class DboSource extends DataSource {
continue; continue;
} elseif (is_numeric($key) && is_string($value)) { } elseif (is_numeric($key) && is_string($value)) {
$out[] = $this->_quoteFields($value); $out[] = $this->_quoteFields($value);
} elseif ((is_numeric($key) && is_array($value)) || in_array(strtolower(trim($key)), $bool)) { } elseif ((is_numeric($key) && is_array($value)) || in_array(strtolower(trim($key)), $this->_sqlBoolOps)) {
if (in_array(strtolower(trim($key)), $bool)) { if (in_array(strtolower(trim($key)), $this->_sqlBoolOps)) {
$join = ' ' . strtoupper($key) . ' '; $join = ' ' . strtoupper($key) . ' ';
} else { } else {
$key = $join; $key = $join;

View file

@ -1035,13 +1035,13 @@ class Model extends CakeObject implements CakeEventListener {
unset($association[$assoc]); unset($association[$assoc]);
$assoc = $value; $assoc = $value;
$value = array(); $value = array();
$association[$assoc] = $value;
}
if (strpos($assoc, '.') !== false) { if (!isset($value['className']) && strpos($assoc, '.') !== false) {
list($plugin, $assoc) = pluginSplit($assoc, true); unset($association[$assoc]);
$association[$assoc] = array('className' => $plugin . $assoc); list($plugin, $assoc) = pluginSplit($assoc, true);
} else { $association[$assoc] = array('className' => $plugin . $assoc) + $value;
$association[$assoc] = $value;
}
} }
$this->_generateAssociation($type, $assoc); $this->_generateAssociation($type, $assoc);

View file

@ -748,7 +748,13 @@ class CakeRequest implements ArrayAccess {
* @return mixed Either false on no header being set or the value of the header. * @return mixed Either false on no header being set or the value of the header.
*/ */
public static function header($name) { public static function header($name) {
$name = 'HTTP_' . strtoupper(str_replace('-', '_', $name)); $name = strtoupper(str_replace('-', '_', $name));
$httpName = 'HTTP_' . $name;
if (isset($_SERVER[$httpName])) {
return $_SERVER[$httpName];
}
// Work around Apache issues where 'Authorization' is not
// passed to PHP.
if (isset($_SERVER[$name])) { if (isset($_SERVER[$name])) {
return $_SERVER[$name]; return $_SERVER[$name];
} }

View file

@ -587,7 +587,7 @@ class CakeResponse {
if (is_numeric($header)) { if (is_numeric($header)) {
list($header, $value) = array($value, null); list($header, $value) = array($value, null);
} }
if ($value === null) { if ($value === null && strpos($header, ':') !== false) {
list($header, $value) = explode(':', $header, 2); list($header, $value) = explode(':', $header, 2);
} }
$this->_headers[$header] = is_array($value) ? array_map('trim', $value) : trim($value); $this->_headers[$header] = is_array($value) ? array_map('trim', $value) : trim($value);

View file

@ -32,13 +32,6 @@ class SmtpTransport extends AbstractTransport {
*/ */
protected $_socket; protected $_socket;
/**
* CakeEmail
*
* @var CakeEmail
*/
protected $_cakeEmail;
/** /**
* Content of email to return * Content of email to return
* *
@ -90,12 +83,10 @@ class SmtpTransport extends AbstractTransport {
* @throws SocketException * @throws SocketException
*/ */
public function send(CakeEmail $email) { public function send(CakeEmail $email) {
$this->_cakeEmail = $email;
$this->_connect(); $this->_connect();
$this->_auth(); $this->_auth();
$this->_sendRcpt(); $this->_sendRcpt($email);
$this->_sendData(); $this->_sendData($email);
$this->_disconnect(); $this->_disconnect();
return $this->_content; return $this->_content;
@ -235,12 +226,13 @@ class SmtpTransport extends AbstractTransport {
/** /**
* Prepares the `from` email address. * Prepares the `from` email address.
* *
* @param CakeEmail $email CakeEmail
* @return array * @return array
*/ */
protected function _prepareFromAddress() { protected function _prepareFromAddress(CakeEmail $email) {
$from = $this->_cakeEmail->returnPath(); $from = $email->returnPath();
if (empty($from)) { if (empty($from)) {
$from = $this->_cakeEmail->from(); $from = $email->from();
} }
return $from; return $from;
} }
@ -248,31 +240,34 @@ class SmtpTransport extends AbstractTransport {
/** /**
* Prepares the recipient email addresses. * Prepares the recipient email addresses.
* *
* @param CakeEmail $email CakeEmail
* @return array * @return array
*/ */
protected function _prepareRecipientAddresses() { protected function _prepareRecipientAddresses(CakeEmail $email) {
$to = $this->_cakeEmail->to(); $to = $email->to();
$cc = $this->_cakeEmail->cc(); $cc = $email->cc();
$bcc = $this->_cakeEmail->bcc(); $bcc = $email->bcc();
return array_merge(array_keys($to), array_keys($cc), array_keys($bcc)); return array_merge(array_keys($to), array_keys($cc), array_keys($bcc));
} }
/** /**
* Prepares the message headers. * Prepares the message headers.
* *
* @param CakeEmail $email CakeEmail
* @return array * @return array
*/ */
protected function _prepareMessageHeaders() { protected function _prepareMessageHeaders(CakeEmail $email) {
return $this->_cakeEmail->getHeaders(array('from', 'sender', 'replyTo', 'readReceipt', 'to', 'cc', 'subject')); return $email->getHeaders(array('from', 'sender', 'replyTo', 'readReceipt', 'to', 'cc', 'subject'));
} }
/** /**
* Prepares the message body. * Prepares the message body.
* *
* @param CakeEmail $email CakeEmail
* @return string * @return string
*/ */
protected function _prepareMessage() { protected function _prepareMessage(CakeEmail $email) {
$lines = $this->_cakeEmail->message(); $lines = $email->message();
$messages = array(); $messages = array();
foreach ($lines as $line) { foreach ($lines as $line) {
if ((!empty($line)) && ($line[0] === '.')) { if ((!empty($line)) && ($line[0] === '.')) {
@ -287,14 +282,15 @@ class SmtpTransport extends AbstractTransport {
/** /**
* Send emails * Send emails
* *
* @param CakeEmail $email CakeEmail
* @return void * @return void
* @throws SocketException * @throws SocketException
*/ */
protected function _sendRcpt() { protected function _sendRcpt(CakeEmail $email) {
$from = $this->_prepareFromAddress(); $from = $this->_prepareFromAddress($email);
$this->_smtpSend($this->_prepareFromCmd(key($from))); $this->_smtpSend($this->_prepareFromCmd(key($from)));
$emails = $this->_prepareRecipientAddresses(); $emails = $this->_prepareRecipientAddresses($email);
foreach ($emails as $email) { foreach ($emails as $email) {
$this->_smtpSend($this->_prepareRcptCmd($email)); $this->_smtpSend($this->_prepareRcptCmd($email));
} }
@ -303,14 +299,15 @@ class SmtpTransport extends AbstractTransport {
/** /**
* Send Data * Send Data
* *
* @param CakeEmail $email CakeEmail
* @return void * @return void
* @throws SocketException * @throws SocketException
*/ */
protected function _sendData() { protected function _sendData(CakeEmail $email) {
$this->_smtpSend('DATA', '354'); $this->_smtpSend('DATA', '354');
$headers = $this->_headersToString($this->_prepareMessageHeaders()); $headers = $this->_headersToString($this->_prepareMessageHeaders($email));
$message = $this->_prepareMessage(); $message = $this->_prepareMessage($email);
$this->_smtpSend($headers . "\r\n\r\n" . $message . "\r\n\r\n\r\n."); $this->_smtpSend($headers . "\r\n\r\n" . $message . "\r\n\r\n\r\n.");
$this->_content = array('headers' => $headers, 'message' => $message); $this->_content = array('headers' => $headers, 'message' => $message);

View file

@ -359,4 +359,22 @@ class TestShellTest extends CakeTestCase {
); );
$this->Shell->main(); $this->Shell->main();
} }
/**
* Tests that the '--directive' parameter change to '-d' before calling PHPUnit
*
* @return void
*/
public function testRunnerOptionsDirective() {
$this->Shell->startup();
$this->Shell->args = array('core', 'Basics');
$this->Shell->params = array('directive' => 'memory_limit=128M');
$this->Shell->expects($this->once())->method('_run')
->with(
array('app' => false, 'plugin' => null, 'core' => true, 'output' => 'text', 'case' => 'Basics'),
array('-d', 'memory_limit=128M', '--colors')
);
$this->Shell->main();
}
} }

View file

@ -1722,6 +1722,27 @@ class AuthComponentTest extends CakeTestCase {
$this->Auth->startup($this->Controller); $this->Auth->startup($this->Controller);
} }
/**
* testStatelessLoginSetUserNoSessionStart method
*
* @return void
*/
public function testStatelessLoginSetUserNoSessionStart() {
$user = array(
'id' => 1,
'username' => 'mark'
);
AuthComponent::$sessionKey = false;
$result = $this->Auth->login($user);
$this->assertTrue($result);
$this->assertTrue($this->Auth->loggedIn());
$this->assertEquals($user, $this->Auth->user());
$this->assertFalse($this->Auth->Session->started());
}
/** /**
* testStatelessAuthNoSessionStart method * testStatelessAuthNoSessionStart method
* *

View file

@ -20,6 +20,7 @@ App::uses('ExceptionRenderer', 'Error');
App::uses('Controller', 'Controller'); App::uses('Controller', 'Controller');
App::uses('Component', 'Controller'); App::uses('Component', 'Controller');
App::uses('Router', 'Routing'); App::uses('Router', 'Routing');
App::uses('CakeEventManager', 'Event');
/** /**
* Short description for class. * Short description for class.
@ -877,4 +878,30 @@ class ExceptionRendererTest extends CakeTestCase {
$this->assertContains(h('SELECT * from poo_query < 5 and :seven'), $result); $this->assertContains(h('SELECT * from poo_query < 5 and :seven'), $result);
$this->assertContains("'seven' => (int) 7", $result); $this->assertContains("'seven' => (int) 7", $result);
} }
/**
* Test that rendering exceptions triggers shutdown events.
*
* @return void
*/
public function testRenderShutdownEvents() {
$fired = array();
$listener = function ($event) use (&$fired) {
$fired[] = $event->name();
};
$EventManager = CakeEventManager::instance();
$EventManager->attach($listener, 'Controller.shutdown');
$EventManager->attach($listener, 'Dispatcher.afterDispatch');
$exception = new Exception('Terrible');
$ExceptionRenderer = new ExceptionRenderer($exception);
ob_start();
$ExceptionRenderer->render();
ob_get_clean();
$expected = array('Controller.shutdown', 'Dispatcher.afterDispatch');
$this->assertEquals($expected, $fired);
}
} }

View file

@ -953,6 +953,63 @@ class CakeSchemaTest extends CakeTestCase {
$this->assertEquals($expected, $compare, 'Invalid SQL, datetime does not have length'); $this->assertEquals($expected, $compare, 'Invalid SQL, datetime does not have length');
} }
/**
* Test comparing with field length/limit changed from some non-default value to the default
*
* @return void
*/
public function testCompareLimitToDefault() {
$old = array(
'posts' => array(
'id' => array('type' => 'integer', 'null' => false, 'default' => 1, 'key' => 'primary'),
'author_id' => array('type' => 'integer', 'null' => false, 'limit' => 5),
'title' => array('type' => 'string', 'null' => true, 'length' => 45),
'indexes' => array(
'PRIMARY' => array('column' => 'id', 'unique' => true)
),
'tableParameters' => array(
'charset' => 'latin1',
'collate' => 'latin1_general_ci'
)
),
);
$new = array(
'posts' => array(
'id' => array('type' => 'integer', 'null' => false, 'key' => 'primary'),
'author_id' => array('type' => 'integer', 'null' => false),
'title' => array('type' => 'varchar', 'null' => true),
'indexes' => array(
'PRIMARY' => array('column' => 'id', 'unique' => true)
),
'tableParameters' => array(
'charset' => 'latin1',
'collate' => 'latin1_general_ci'
)
),
);
$compare = $this->Schema->compare($old, $new);
$expected = array(
'posts' => array(
'change' => array(
'id' => array(
'type' => 'integer',
'null' => false,
'key' => 'primary'
),
'author_id' => array(
'type' => 'integer',
'null' => false,
),
'title' => array(
'type' => 'varchar',
'null' => true,
)
)
),
);
$this->assertEquals($expected, $compare, 'Invalid SQL, field length change not detected');
}
/** /**
* testSchemaLoading method * testSchemaLoading method
* *

View file

@ -4045,6 +4045,32 @@ SQL;
$this->Dbo->delete($Article, '2=2'); $this->Dbo->delete($Article, '2=2');
} }
/**
* Test deletes without complex conditions.
*
* @return void
*/
public function testDeleteNoComplexCondition() {
$this->loadFixtures('Article', 'User');
$test = ConnectionManager::getDatasource('test');
$db = $test->config['database'];
$this->Dbo = $this->getMock('Mysql', array('execute'), array($test->config));
$this->Dbo->expects($this->at(0))->method('execute')
->with("DELETE `Article` FROM `$db`.`articles` AS `Article` WHERE `id` = 1");
$this->Dbo->expects($this->at(1))->method('execute')
->with("DELETE `Article` FROM `$db`.`articles` AS `Article` WHERE NOT (`id` = 1)");
$Article = new Article();
$conditions = array('id' => 1);
$this->Dbo->delete($Article, $conditions);
$conditions = array('NOT' => array('id' => 1));
$this->Dbo->delete($Article, $conditions);
}
/** /**
* Test truncate with a mock. * Test truncate with a mock.
* *

View file

@ -1617,10 +1617,12 @@ class ModelIntegrationTest extends BaseModelTest {
public function testAutoConstructPluginAssociations() { public function testAutoConstructPluginAssociations() {
$Comment = ClassRegistry::init('TestPluginComment'); $Comment = ClassRegistry::init('TestPluginComment');
$this->assertEquals(2, count($Comment->belongsTo), 'Too many associations'); $this->assertEquals(3, count($Comment->belongsTo), 'Too many associations');
$this->assertFalse(isset($Comment->belongsTo['TestPlugin.User'])); $this->assertFalse(isset($Comment->belongsTo['TestPlugin.User']));
$this->assertFalse(isset($Comment->belongsTo['TestPlugin.Source']));
$this->assertTrue(isset($Comment->belongsTo['User']), 'Missing association'); $this->assertTrue(isset($Comment->belongsTo['User']), 'Missing association');
$this->assertTrue(isset($Comment->belongsTo['TestPluginArticle']), 'Missing association'); $this->assertTrue(isset($Comment->belongsTo['TestPluginArticle']), 'Missing association');
$this->assertTrue(isset($Comment->belongsTo['Source']), 'Missing association');
} }
/** /**

View file

@ -2991,7 +2991,10 @@ class TestPluginComment extends CakeTestModel {
'className' => 'TestPlugin.TestPluginArticle', 'className' => 'TestPlugin.TestPluginArticle',
'foreignKey' => 'article_id', 'foreignKey' => 'article_id',
), ),
'TestPlugin.User' 'TestPlugin.User',
'TestPlugin.Source' => array(
'foreignKey' => 'source_id'
)
); );
} }

View file

@ -1147,11 +1147,13 @@ class CakeRequestTest extends CakeTestCase {
$_SERVER['HTTP_X_THING'] = ''; $_SERVER['HTTP_X_THING'] = '';
$_SERVER['HTTP_HOST'] = 'localhost'; $_SERVER['HTTP_HOST'] = 'localhost';
$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-ca) AppleWebKit/534.8+ (KHTML, like Gecko) Version/5.0 Safari/533.16'; $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-ca) AppleWebKit/534.8+ (KHTML, like Gecko) Version/5.0 Safari/533.16';
$_SERVER['AUTHORIZATION'] = 'foobar';
$request = new CakeRequest('/', false); $request = new CakeRequest('/', false);
$this->assertEquals($_SERVER['HTTP_HOST'], $request->header('host')); $this->assertEquals($_SERVER['HTTP_HOST'], $request->header('host'));
$this->assertEquals($_SERVER['HTTP_USER_AGENT'], $request->header('User-Agent')); $this->assertEquals($_SERVER['HTTP_USER_AGENT'], $request->header('User-Agent'));
$this->assertSame('', $request->header('X-thing')); $this->assertSame('', $request->header('X-thing'));
$this->assertEquals($_SERVER['AUTHORIZATION'], $request->header('Authorization'));
} }
/** /**

View file

@ -164,11 +164,15 @@ class CakeResponseTest extends CakeTestCase {
$headers += array('Location' => 'http://example.com'); $headers += array('Location' => 'http://example.com');
$this->assertEquals($headers, $response->header()); $this->assertEquals($headers, $response->header());
//Headers with the same name are overwritten // Headers with the same name are overwritten
$response->header('Location', 'http://example2.com'); $response->header('Location', 'http://example2.com');
$headers = array('Location' => 'http://example2.com'); $headers = array('Location' => 'http://example2.com');
$this->assertEquals($headers, $response->header()); $this->assertEquals($headers, $response->header());
$response->header('Date', null);
$headers += array('Date' => null);
$this->assertEquals($headers, $response->header());
$response->header(array('WWW-Authenticate' => 'Negotiate')); $response->header(array('WWW-Authenticate' => 'Negotiate'));
$headers += array('WWW-Authenticate' => 'Negotiate'); $headers += array('WWW-Authenticate' => 'Negotiate');
$this->assertEquals($headers, $response->header()); $this->assertEquals($headers, $response->header());

View file

@ -35,16 +35,6 @@ class SmtpTestTransport extends SmtpTransport {
$this->_socket = $socket; $this->_socket = $socket;
} }
/**
* Helper to change the CakeEmail
*
* @param CakeEmail $cakeEmail An email object.
* @return void
*/
public function setCakeEmail($cakeEmail) {
$this->_cakeEmail = $cakeEmail;
}
/** /**
* Disabled the socket change * Disabled the socket change
* *
@ -348,8 +338,7 @@ class SmtpTransportTest extends CakeTestCase {
$this->socket->expects($this->at(13))->method('read')->will($this->returnValue(false)); $this->socket->expects($this->at(13))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(14))->method('read')->will($this->returnValue("250 OK\r\n")); $this->socket->expects($this->at(14))->method('read')->will($this->returnValue("250 OK\r\n"));
$this->SmtpTransport->setCakeEmail($email); $this->SmtpTransport->sendRcpt($email);
$this->SmtpTransport->sendRcpt();
} }
/** /**
@ -370,8 +359,7 @@ class SmtpTransportTest extends CakeTestCase {
$this->socket->expects($this->at(4))->method('read')->will($this->returnValue(false)); $this->socket->expects($this->at(4))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(5))->method('read')->will($this->returnValue("250 OK\r\n")); $this->socket->expects($this->at(5))->method('read')->will($this->returnValue("250 OK\r\n"));
$this->SmtpTransport->setCakeEmail($email); $this->SmtpTransport->sendRcpt($email);
$this->SmtpTransport->sendRcpt();
} }
/** /**
@ -416,8 +404,7 @@ class SmtpTransportTest extends CakeTestCase {
$this->socket->expects($this->at(4))->method('read')->will($this->returnValue(false)); $this->socket->expects($this->at(4))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(5))->method('read')->will($this->returnValue("250 OK\r\n")); $this->socket->expects($this->at(5))->method('read')->will($this->returnValue("250 OK\r\n"));
$this->SmtpTransport->setCakeEmail($email); $this->SmtpTransport->sendData($email);
$this->SmtpTransport->sendData();
} }
/** /**
@ -498,8 +485,7 @@ class SmtpTransportTest extends CakeTestCase {
$this->socket->expects($this->at(4))->method('read')->will($this->returnValue(false)); $this->socket->expects($this->at(4))->method('read')->will($this->returnValue(false));
$this->socket->expects($this->at(5))->method('read')->will($this->returnValue("250 OK\r\n")); $this->socket->expects($this->at(5))->method('read')->will($this->returnValue("250 OK\r\n"));
$this->SmtpTransport->setCakeEmail($email); $this->SmtpTransport->sendRcpt($email);
$this->SmtpTransport->sendRcpt();
$expected = array( $expected = array(
array('code' => '250', 'message' => 'OK'), array('code' => '250', 'message' => 'OK'),

View file

@ -454,6 +454,19 @@ class CakeTimeTest extends CakeTestCase {
$this->_restoreSystemTimezone(); $this->_restoreSystemTimezone();
} }
/**
* testNiceShort translations
*
* @return void
*/
public function testNiceShortI18n() {
$restore = setlocale(LC_ALL, 0);
setlocale(LC_ALL, 'es_ES');
$time = strtotime('2015-01-07 03:05:00');
$this->assertEquals('ene 7th 2015, 03:05', $this->Time->niceShort($time));
setlocale(LC_ALL, $restore);
}
/** /**
* testDaysAsSql method * testDaysAsSql method
* *

View file

@ -1621,6 +1621,29 @@ class FormHelperTest extends CakeTestCase {
$this->assertEquals(1, $this->Form->fields['Contact.id'], 'Hidden input should be secured.'); $this->assertEquals(1, $this->Form->fields['Contact.id'], 'Hidden input should be secured.');
} }
/**
* test unlockField removing from fields array. multiple field version.
*
* @return void
*/
public function testUnlockMultipleFieldRemovingFromFields() {
$this->Form->request['_Token'] = array(
'key' => 'testKey',
'unlockedFields' => array()
);
$this->Form->create('Order');
$this->Form->hidden('Order.id', array('value' => 1));
$this->Form->checkbox('Ticked.id.');
$this->Form->checkbox('Ticked.id.');
$this->assertEquals(1, $this->Form->fields['Order.id'], 'Hidden input should be secured.');
$this->assertTrue(in_array('Ticked.id', $this->Form->fields), 'Field should be secured.');
$this->Form->unlockField('Order.id');
$this->Form->unlockField('Ticked.id');
$this->assertEquals(array(), $this->Form->fields);
}
/** /**
* testTagIsInvalid method * testTagIsInvalid method
* *

View file

@ -663,7 +663,10 @@ class FormHelper extends AppHelper {
if (!$field) { if (!$field) {
$field = $this->entity(); $field = $this->entity();
} elseif (is_string($field)) { } elseif (is_string($field)) {
$field = Hash::filter(explode('.', $field)); $field = explode('.', $field);
}
if (is_array($field)) {
$field = Hash::filter($field);
} }
foreach ($this->_unlockedFields as $unlockField) { foreach ($this->_unlockedFields as $unlockField) {

View file

@ -324,7 +324,7 @@ class HtmlHelper extends AppHelper {
* - `escapeTitle` Set to false to disable escaping of title. (Takes precedence over value of `escape`) * - `escapeTitle` Set to false to disable escaping of title. (Takes precedence over value of `escape`)
* - `confirm` JavaScript confirmation message. * - `confirm` JavaScript confirmation message.
* *
* @param string $title The content to be wrapped by <a> tags. * @param string $title The content to be wrapped by `<a>` tags.
* @param string|array $url Cake-relative URL or array of URL parameters, or external URL (starts with http://) * @param string|array $url Cake-relative URL or array of URL parameters, or external URL (starts with http://)
* @param array $options Array of options and HTML attributes. * @param array $options Array of options and HTML attributes.
* @param string $confirmMessage JavaScript confirmation message. This * @param string $confirmMessage JavaScript confirmation message. This
@ -412,7 +412,7 @@ class HtmlHelper extends AppHelper {
* CSS stylesheets. If `$path` is prefixed with '/', the path will be relative to the webroot * CSS stylesheets. If `$path` is prefixed with '/', the path will be relative to the webroot
* of your application. Otherwise, the path will be relative to your CSS path, usually webroot/css. * of your application. Otherwise, the path will be relative to your CSS path, usually webroot/css.
* @param array $options Array of options and HTML arguments. * @param array $options Array of options and HTML arguments.
* @return string CSS <link /> or <style /> tag, depending on the type of link. * @return string CSS `<link />` or `<style />` tag, depending on the type of link.
* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/html.html#HtmlHelper::css * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/html.html#HtmlHelper::css
*/ */
public function css($path, $options = array()) { public function css($path, $options = array()) {
@ -580,7 +580,7 @@ class HtmlHelper extends AppHelper {
* *
* ### Options * ### Options
* *
* - `safe` (boolean) Whether or not the $script should be wrapped in <![CDATA[ ]]> * - `safe` (boolean) Whether or not the $script should be wrapped in `<![CDATA[ ]]>`
* - `inline` (boolean) Whether or not the $script should be added to * - `inline` (boolean) Whether or not the $script should be added to
* `$scripts_for_layout` / `script` block, or output inline. (Deprecated, use `block` instead) * `$scripts_for_layout` / `script` block, or output inline. (Deprecated, use `block` instead)
* - `block` Which block you want this script block appended to. * - `block` Which block you want this script block appended to.