Merge branch 'master' into 2.7

This commit is contained in:
mark_story 2015-01-03 14:34:55 -05:00
commit 4cd2c8fdcb
14 changed files with 188 additions and 54 deletions

View file

@ -38,7 +38,7 @@ before_script:
- sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'CREATE SCHEMA test3;' -U postgres -d cakephp_test; fi"
- chmod -R 777 ./app/tmp
- sudo apt-get install lighttpd
- sh -c "if [ '$PHPCS' = '1' ]; then composer global require 'cakephp/cakephp-codesniffer:*'; fi"
- sh -c "if [ '$PHPCS' = '1' ]; then composer global require 'cakephp/cakephp-codesniffer:1.*'; fi"
- sh -c "if [ '$PHPCS' = '1' ]; then ~/.composer/vendor/bin/phpcs --config-set installed_paths ~/.composer/vendor/cakephp/cakephp-codesniffer; fi"
- echo "extension = memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- phpenv rehash

View file

@ -70,7 +70,7 @@ class ExtractTask extends AppShell {
protected $_tokens = array();
/**
* Extracted strings indexed by category and domain.
* Extracted strings indexed by category, domain, msgid and context.
*
* @var array
*/
@ -249,26 +249,26 @@ class ExtractTask extends AppShell {
* @return void
*/
protected function _addTranslation($category, $domain, $msgid, $details = array()) {
if (empty($this->_translations[$category][$domain][$msgid])) {
$this->_translations[$category][$domain][$msgid] = array(
$context = '';
if (isset($details['msgctxt'])) {
$context = $details['msgctxt'];
}
if (empty($this->_translations[$category][$domain][$msgid][$context])) {
$this->_translations[$category][$domain][$msgid][$context] = array(
'msgid_plural' => false,
'msgctxt' => ''
);
}
if (isset($details['msgid_plural'])) {
$this->_translations[$category][$domain][$msgid]['msgid_plural'] = $details['msgid_plural'];
$this->_translations[$category][$domain][$msgid][$context]['msgid_plural'] = $details['msgid_plural'];
}
if (isset($details['msgctxt'])) {
$this->_translations[$category][$domain][$msgid]['msgctxt'] = $details['msgctxt'];
}
if (isset($details['file'])) {
$line = 0;
if (isset($details['line'])) {
$line = $details['line'];
}
$this->_translations[$category][$domain][$msgid]['references'][$details['file']][] = $line;
$this->_translations[$category][$domain][$msgid][$context]['references'][$details['file']][] = $line;
}
}
@ -565,35 +565,36 @@ class ExtractTask extends AppShell {
$paths[] = realpath(APP) . DS;
foreach ($this->_translations as $category => $domains) {
foreach ($domains as $domain => $translations) {
foreach ($translations as $msgid => $details) {
$plural = $details['msgid_plural'];
$context = $details['msgctxt'];
$files = $details['references'];
$occurrences = array();
foreach ($files as $file => $lines) {
$lines = array_unique($lines);
$occurrences[] = $file . ':' . implode(';', $lines);
}
$occurrences = implode("\n#: ", $occurrences);
$header = '#: ' . str_replace(DS, '/', str_replace($paths, '', $occurrences)) . "\n";
foreach ($translations as $msgid => $contexts) {
foreach ($contexts as $context => $details) {
$plural = $details['msgid_plural'];
$files = $details['references'];
$occurrences = array();
foreach ($files as $file => $lines) {
$lines = array_unique($lines);
$occurrences[] = $file . ':' . implode(';', $lines);
}
$occurrences = implode("\n#: ", $occurrences);
$header = '#: ' . str_replace(DS, '/', str_replace($paths, '', $occurrences)) . "\n";
$sentence = '';
if ($context) {
$sentence .= "msgctxt \"{$context}\"\n";
}
if ($plural === false) {
$sentence .= "msgid \"{$msgid}\"\n";
$sentence .= "msgstr \"\"\n\n";
} else {
$sentence .= "msgid \"{$msgid}\"\n";
$sentence .= "msgid_plural \"{$plural}\"\n";
$sentence .= "msgstr[0] \"\"\n";
$sentence .= "msgstr[1] \"\"\n\n";
}
$sentence = '';
if ($context) {
$sentence .= "msgctxt \"{$context}\"\n";
}
if ($plural === false) {
$sentence .= "msgid \"{$msgid}\"\n";
$sentence .= "msgstr \"\"\n\n";
} else {
$sentence .= "msgid \"{$msgid}\"\n";
$sentence .= "msgid_plural \"{$plural}\"\n";
$sentence .= "msgstr[0] \"\"\n";
$sentence .= "msgstr[1] \"\"\n\n";
}
$this->_store($category, $domain, $header, $sentence);
if (($category !== 'LC_MESSAGES' || $domain !== 'default') && $this->_merge) {
$this->_store('LC_MESSAGES', 'default', $header, $sentence);
$this->_store($category, $domain, $header, $sentence);
if (($category !== 'LC_MESSAGES' || $domain !== 'default') && $this->_merge) {
$this->_store('LC_MESSAGES', 'default', $header, $sentence);
}
}
}
}

View file

@ -512,7 +512,12 @@ class CakeSession {
if (!empty($sessionConfig['handler'])) {
$sessionConfig['ini']['session.save_handler'] = 'user';
} elseif (!empty($sessionConfig['session.save_path']) && Configure::read('debug')) {
if (!is_dir($sessionConfig['session.save_path'])) {
mkdir($sessionConfig['session.save_path'], 0775, true);
}
}
if (!isset($sessionConfig['ini']['session.gc_maxlifetime'])) {
$sessionConfig['ini']['session.gc_maxlifetime'] = $sessionConfig['timeout'] * 60;
}

View file

@ -474,6 +474,9 @@ class Sqlserver extends DboSource {
if (in_array($length->Type, array('nchar', 'nvarchar'))) {
return floor($length->Length / 2);
}
if ($length->Type === 'text') {
return null;
}
return $length->Length;
}
return parent::length($length);

View file

@ -149,12 +149,11 @@ class AssetDispatcher extends DispatcherFilter {
}
$response->type($contentType);
}
if (!$compressionEnabled) {
$response->header('Content-Length', filesize($assetFile));
}
$response->length(false);
$response->cache(filemtime($assetFile));
$response->send();
ob_clean();
if ($ext === 'css' || $ext === 'js') {
include $assetFile;
} else {

View file

@ -162,9 +162,20 @@ class ExtractTaskTest extends CakeTestCase {
$this->assertContains('msgid "double \\"quoted\\""', $result, 'Strings with quotes not handled correctly');
$this->assertContains("msgid \"single 'quoted'\"", $result, 'Strings with quotes not handled correctly');
$pattern = '/\#: (\\\\|\/)extract\.ctp:33\n';
$pattern .= 'msgctxt "mail"/';
$this->assertRegExp($pattern, $result);
$pattern = '/\#: (\\\\|\/)extract\.ctp:34\nmsgid "letter"/';
$this->assertRegExp($pattern, $result, 'Strings with context should not overwrite strings without context');
$pattern = '/\#: (\\\\|\/)extract\.ctp:35;37\nmsgctxt "A"\nmsgid "letter"/';
$this->assertRegExp($pattern, $result, 'Should contain string with context "A"');
$pattern = '/\#: (\\\\|\/)extract\.ctp:36\nmsgctxt "B"\nmsgid "letter"/';
$this->assertRegExp($pattern, $result, 'Should contain string with context "B"');
$pattern = '/\#: (\\\\|\/)extract\.ctp:38\nmsgid "%d letter"\nmsgid_plural "%d letters"/';
$this->assertRegExp($pattern, $result, 'Plural strings with context should not overwrite strings without context');
$pattern = '/\#: (\\\\|\/)extract\.ctp:39\nmsgctxt "A"\nmsgid "%d letter"\nmsgid_plural "%d letters"/';
$this->assertRegExp($pattern, $result, 'Should contain plural string with context "A"');
// extract.ctp - reading the domain.pot
$result = file_get_contents($this->path . DS . 'domain.pot');

View file

@ -449,6 +449,15 @@ class SqlserverTest extends CakeTestCase {
'Null' => 'YES',
'Size' => '0',
),
(object)array(
'Default' => null,
'Field' => 'description',
'Key' => '0',
'Type' => 'text',
'Length' => 16,
'Null' => 'YES',
'Size' => '0',
),
));
$this->db->executeResultsStack = array($SqlserverTableDescription);
$dummyModel = $this->model;
@ -485,6 +494,12 @@ class SqlserverTest extends CakeTestCase {
'default' => null,
'length' => 8,
),
'description' => array(
'type' => 'text',
'null' => true,
'default' => null,
'length' => null,
)
);
$this->assertEquals($expected, $result);
$this->assertSame($expected['parent_id'], $result['parent_id']);

View file

@ -228,4 +228,39 @@ class AssetDispatcherTest extends CakeTestCase {
$this->assertFalse($event->isStopped());
}
/**
* Test asset content length is unset
*
* If content length is unset, then the webserver can figure it out.
*
* @outputBuffering enabled
* @return void
*/
public function testAssetContentLength() {
Router::reload();
Configure::write('Dispatcher.filters', array('AssetDispatcher'));
App::build(array(
'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS)
));
$url = 'theme/test_theme/css/test_asset.css';
$file = 'View/Themed/TestTheme/webroot/css/test_asset.css';
$request = new CakeRequest($url);
$response = $this->getMock('CakeResponse', array('_sendHeader', 'send'));
$event = new CakeEvent('Dispatcher.beforeRequest', $this, compact('request', 'response'));
$filter = new AssetDispatcher();
$filter->beforeDispatch($event);
$result = ob_get_clean();
$path = CAKE . 'Test' . DS . 'test_app' . DS . str_replace('/', DS, $file);
$file = file_get_contents($path);
$this->assertEquals($file, $result);
$expected = filesize($path);
$headers = $response->header();
$this->assertFalse($headers['Content-Length']);
}
}

View file

@ -119,7 +119,7 @@ class HtmlCoverageReportTest extends CakeTestCase {
);
$result = $this->Coverage->generateDiff('myfile.php', $file, $coverage);
$this->assertRegExp('/myfile\.php Code coverage\: \d+\.?\d*\%/', $result);
$this->assertRegExp('/<div class="code-coverage-results" id\="coverage\-myfile\.php"/', $result);
$this->assertRegExp('/<div class="code-coverage-results" id\="coverage\-myfile\.php-' . md5('myfile.php') . '"/', $result);
$this->assertRegExp('/<pre>/', $result);
foreach ($file as $i => $line) {
$this->assertTrue(strpos($line, $result) !== 0, 'Content is missing ' . $i);
@ -167,7 +167,7 @@ class HtmlCoverageReportTest extends CakeTestCase {
$result = $this->Coverage->generateDiff('myfile.php', $file, $coverage);
$this->assertRegExp('/myfile\.php Code coverage\: \d+\.?\d*\%/', $result);
$this->assertRegExp('/<div class="code-coverage-results" id\="coverage\-myfile\.php"/', $result);
$this->assertRegExp('/<div class="code-coverage-results" id\="coverage\-myfile\.php-' . md5('myfile.php') . '"/', $result);
$this->assertRegExp('/<pre>/', $result);
foreach ($file as $i => $line) {
$this->assertTrue(strpos($line, $result) !== 0, 'Content is missing ' . $i);

View file

@ -146,6 +146,31 @@ class TextHelperTest extends CakeTestCase {
$expected = 'This is a test text with URL <a href="http://www.cakephp.org">http://www.cakephp.org</a>(and some more text)';
$result = $this->Text->autoLink($text);
$this->assertEquals($expected, $result);
$text = 'This is a test text with URL (http://www.cakephp.org/page/4) in brackets';
$expected = 'This is a test text with URL (<a href="http://www.cakephp.org/page/4">http://www.cakephp.org/page/4</a>) in brackets';
$result = $this->Text->autoLink($text);
$this->assertEquals($expected, $result);
$text = 'This is a test text with URL [http://www.cakephp.org/page/4] in square brackets';
$expected = 'This is a test text with URL [<a href="http://www.cakephp.org/page/4">http://www.cakephp.org/page/4</a>] in square brackets';
$result = $this->Text->autoLink($text);
$this->assertEquals($expected, $result);
$text = 'This is a test text with URL [http://www.example.com?aParam[]=value1&aParam[]=value2&aParam[]=value3] in square brackets';
$expected = 'This is a test text with URL [<a href="http://www.example.com?aParam[]=value1&amp;aParam[]=value2&amp;aParam[]=value3">http://www.example.com?aParam[]=value1&amp;aParam[]=value2&amp;aParam[]=value3</a>] in square brackets';
$result = $this->Text->autoLink($text);
$this->assertEquals($expected, $result);
$text = 'This is a test text with URL ;http://www.cakephp.org/page/4; semi-colon';
$expected = 'This is a test text with URL ;<a href="http://www.cakephp.org/page/4">http://www.cakephp.org/page/4</a>; semi-colon';
$result = $this->Text->autoLink($text);
$this->assertEquals($expected, $result);
$text = 'This is a test text with URL (http://www.cakephp.org/page/4/other(thing)) brackets';
$expected = 'This is a test text with URL (<a href="http://www.cakephp.org/page/4/other(thing)">http://www.cakephp.org/page/4/other(thing)</a>) brackets';
$result = $this->Text->autoLink($text);
$this->assertEquals($expected, $result);
}
/**

View file

@ -30,4 +30,10 @@ __('Hot features!'
// Category
echo __c('You have a new message (category: LC_TIME).', 5);
echo __x('mail', 'letter');
// Context
echo __('letter');
echo __x('A', 'letter');
echo __x('B', 'letter');
echo __x('A', 'letter');
echo __n('%d letter', '%d letters', $count);
echo __xn('A', '%d letter', '%d letters', $count);

View file

@ -200,6 +200,7 @@ HTML;
* @return string
*/
public function coverageHeader($filename, $percent) {
$hash = md5($filename);
$filename = basename($filename);
list($file) = explode('.', $filename);
$display = in_array($file, $this->_testNames) ? 'block' : 'none';
@ -207,11 +208,11 @@ HTML;
return <<<HTML
<div class="coverage-container $primary" style="display:$display;">
<h4>
<a href="#coverage-$filename" onclick="coverage_show_hide('coverage-$filename');">
<a href="#coverage-$filename-$hash" onclick="coverage_show_hide('coverage-$filename-$hash');">
$filename Code coverage: $percent%
</a>
</h4>
<div class="code-coverage-results" id="coverage-$filename" style="display:none;">
<div class="code-coverage-results" id="coverage-$filename-$hash" style="display:none;">
<pre>
HTML;
}

View file

@ -199,12 +199,12 @@ class CakeHtmlReporter extends CakeBaseReporter {
if (!empty($this->params['case'])) {
$query['case'] = $this->params['case'];
}
$show = $this->_queryString($show);
$query = $this->_queryString($query);
list($show, $query) = $this->_getQueryLink();
echo "<p><a href='" . $this->baseUrl() . $show . "'>Run more tests</a> | <a href='" . $this->baseUrl() . $query . "&amp;show_passes=1'>Show Passes</a> | \n";
echo "<a href='" . $this->baseUrl() . $query . "&amp;debug=1'>Enable Debug Output</a> | \n";
echo "<a href='" . $this->baseUrl() . $query . "&amp;code_coverage=true'>Analyze Code Coverage</a></p>\n";
echo "<a href='" . $this->baseUrl() . $query . "&amp;code_coverage=true'>Analyze Code Coverage</a> | \n";
echo "<a href='" . $this->baseUrl() . $query . "&amp;code_coverage=true&amp;show_passes=1&amp;debug=1'>All options enabled</a></p>\n";
}
/**
@ -248,7 +248,8 @@ class CakeHtmlReporter extends CakeBaseReporter {
*/
public function paintFail($message, $test) {
$trace = $this->_getStackTrace($message);
$testName = get_class($test) . '(' . $test->getName() . ')';
$className = get_class($test);
$testName = $className . '::' . $test->getName() . '()';
$actualMsg = $expectedMsg = null;
if (method_exists($message, 'getComparisonFailure')) {
@ -269,6 +270,10 @@ class CakeHtmlReporter extends CakeBaseReporter {
echo "</pre></div>\n";
echo "<div class='msg'>" . __d('cake_dev', 'Test case: %s', $testName) . "</div>\n";
if (strpos($className, "PHPUnit_") === false) {
list($show, $query) = $this->_getQueryLink();
echo "<div class='msg'><a href='" . $this->baseUrl() . $query . "&amp;filter=" . $test->getName() . "'>" . __d('cake_dev', 'Rerun only this test: %s', $testName) . "</a></div>\n";
}
echo "<div class='msg'>" . __d('cake_dev', 'Stack trace:') . '<br />' . $trace . "</div>\n";
echo "</li>\n";
}
@ -380,4 +385,32 @@ class CakeHtmlReporter extends CakeBaseReporter {
echo '<h2>' . __d('cake_dev', 'Running %s', $suite->getName()) . '</h2>';
}
/**
* Returns the query string formatted for ouput in links
*
* @return string
*/
protected function _getQueryLink() {
$show = $query = array();
if (!empty($this->params['case'])) {
$show['show'] = 'cases';
}
if (!empty($this->params['core'])) {
$show['core'] = $query['core'] = 'true';
}
if (!empty($this->params['plugin'])) {
$show['plugin'] = $query['plugin'] = $this->params['plugin'];
}
if (!empty($this->params['case'])) {
$query['case'] = $this->params['case'];
}
if (!empty($this->params['filter'])) {
$query['filter'] = $this->params['filter'];
}
$show = $this->_queryString($show);
$query = $this->_queryString($query);
return array($show, $query);
}
}

View file

@ -107,7 +107,7 @@ class TextHelper extends AppHelper {
$this->_placeholders = array();
$options += array('escape' => true);
$pattern = '#(?<!href="|src="|">)((?:https?|ftp|nntp)://[\p{L}0-9.\-_:]+(?:[/?][^\s<]*)?)#ui';
$pattern = '#(?<!href="|src="|">)((?:https?|ftp|nntp)://[\p{L}0-9.\-_:]+(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))#i';
$text = preg_replace_callback(
$pattern,
array(&$this, '_insertPlaceHolder'),