diff --git a/.travis.yml b/.travis.yml index bcee2e21c..c62fd7bde 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/lib/Cake/Console/Command/Task/ExtractTask.php b/lib/Cake/Console/Command/Task/ExtractTask.php index bbf5a4fb7..7a6ff14d1 100644 --- a/lib/Cake/Console/Command/Task/ExtractTask.php +++ b/lib/Cake/Console/Command/Task/ExtractTask.php @@ -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); + } } } } diff --git a/lib/Cake/Model/Datasource/CakeSession.php b/lib/Cake/Model/Datasource/CakeSession.php index 536b10730..3451642a3 100644 --- a/lib/Cake/Model/Datasource/CakeSession.php +++ b/lib/Cake/Model/Datasource/CakeSession.php @@ -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; } diff --git a/lib/Cake/Model/Datasource/Database/Sqlserver.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php index 393184460..eb7dad8c0 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlserver.php +++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php @@ -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); diff --git a/lib/Cake/Routing/Filter/AssetDispatcher.php b/lib/Cake/Routing/Filter/AssetDispatcher.php index 8778d25fd..3a4908bcf 100644 --- a/lib/Cake/Routing/Filter/AssetDispatcher.php +++ b/lib/Cake/Routing/Filter/AssetDispatcher.php @@ -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 { diff --git a/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php index 7013771fb..238803acf 100644 --- a/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php +++ b/lib/Cake/Test/Case/Console/Command/Task/ExtractTaskTest.php @@ -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'); diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php index 14a52fb2e..eb63c259b 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php @@ -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']); diff --git a/lib/Cake/Test/Case/Routing/Filter/AssetDispatcherTest.php b/lib/Cake/Test/Case/Routing/Filter/AssetDispatcherTest.php index 638700535..e9e5b5ddd 100644 --- a/lib/Cake/Test/Case/Routing/Filter/AssetDispatcherTest.php +++ b/lib/Cake/Test/Case/Routing/Filter/AssetDispatcherTest.php @@ -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']); + } + } diff --git a/lib/Cake/Test/Case/TestSuite/HtmlCoverageReportTest.php b/lib/Cake/Test/Case/TestSuite/HtmlCoverageReportTest.php index 9f8d37e11..6763d2f1f 100644 --- a/lib/Cake/Test/Case/TestSuite/HtmlCoverageReportTest.php +++ b/lib/Cake/Test/Case/TestSuite/HtmlCoverageReportTest.php @@ -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('/
/', $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('/assertRegExp('/assertRegExp('//', $result); foreach ($file as $i => $line) { $this->assertTrue(strpos($line, $result) !== 0, 'Content is missing ' . $i); diff --git a/lib/Cake/Test/Case/View/Helper/TextHelperTest.php b/lib/Cake/Test/Case/View/Helper/TextHelperTest.php index c4e36aaa7..41ef4b296 100644 --- a/lib/Cake/Test/Case/View/Helper/TextHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/TextHelperTest.php @@ -146,6 +146,31 @@ class TextHelperTest extends CakeTestCase { $expected = 'This is a test text with URL http://www.cakephp.org(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 (http://www.cakephp.org/page/4) 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 [http://www.cakephp.org/page/4] 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 [http://www.example.com?aParam[]=value1&aParam[]=value2&aParam[]=value3] 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 ;http://www.cakephp.org/page/4; 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 (http://www.cakephp.org/page/4/other(thing)) brackets'; + $result = $this->Text->autoLink($text); + $this->assertEquals($expected, $result); } /** diff --git a/lib/Cake/Test/test_app/View/Pages/extract.ctp b/lib/Cake/Test/test_app/View/Pages/extract.ctp index bee786c9c..3331f2fd4 100644 --- a/lib/Cake/Test/test_app/View/Pages/extract.ctp +++ b/lib/Cake/Test/test_app/View/Pages/extract.ctp @@ -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); diff --git a/lib/Cake/TestSuite/Coverage/HtmlCoverageReport.php b/lib/Cake/TestSuite/Coverage/HtmlCoverageReport.php index 8f83f8521..0d194f795 100644 --- a/lib/Cake/TestSuite/Coverage/HtmlCoverageReport.php +++ b/lib/Cake/TestSuite/Coverage/HtmlCoverageReport.php @@ -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 <<- + $filename Code coverage: $percent%
-