` tags.
+- [[\yii\base\Formatter::asHtml()|html]] - the value is purified using [[HtmlPurifier]] to avoid XSS attacks. You can
+ pass additional options such as `['html', ['Attr.AllowedFrameTargets' => ['_blank']]]`.
+- [[\yii\base\Formatter::asEmail()|email]] - the value is formatted as a mailto link.
+- [[\yii\base\Formatter::asImage()|image]] - the value is formatted as an image tag.
+- [[\yii\base\Formatter::asUrl()|url]] - the value is formatted as a hyperlink.
+- [[\yii\base\Formatter::asBoolean()|boolean]] - the value is formatted as a boolean. You can set what's rendered for
+ true and false values by calling `Yii::$app->formatter->booleanFormat = ['No', 'Yes'];` before outputting GridView.
+- [[\yii\base\Formatter::asDate()|date]] - the value is formatted as date.
+- [[\yii\base\Formatter::asTime()|time]] - the value is formatted as time.
+- [[\yii\base\Formatter::asDatetime()|datetime]] - the value is formatted as datetime.
+- [[\yii\base\Formatter::asInteger()|integer]] - the value is formatted as an integer.
+- [[\yii\base\Formatter::asDouble()|double]] - the value is formatted as a double number.
+- [[\yii\base\Formatter::asNumber()|number]] - the value is formatted as a number with decimal and thousand separators.
+- [[\yii\base\Formatter::asSize()|size]] - the value that is a number of bytes is formatted as a human readable size.
+- [[\yii\base\Formatter::asRelativeTime()|relativeTime]] - the value is formatted as the time interval between a date
+ and now in human readable form.
#### Action column
diff --git a/docs/guide/test-acceptance.md b/docs/guide/test-acceptance.md
index 45ca7b1cb03..e3871549b77 100644
--- a/docs/guide/test-acceptance.md
+++ b/docs/guide/test-acceptance.md
@@ -7,5 +7,20 @@ Acceptance Tests
- https://github.com/yiisoft/yii2/blob/master/apps/advanced/README.md#testing
- https://github.com/yiisoft/yii2/blob/master/apps/basic/tests/README.md
-How to run php-server
----------------------
+How to run webserver
+--------------------
+
+In order to perform acceptance tests you need a web server. Since PHP 5.4 has built-in one, we can use it. For the basic
+application template it would be:
+
+```
+cd web
+php -S localhost:8080
+```
+
+In order for the tests to work correctly you need to adjust `TEST_ENTRY_URL` in `_bootstrap.php` file. It should point
+to `index-test.php` of your webserver. Since we're running directly from its directory the line would be:
+
+```php
+defined('TEST_ENTRY_URL') or define('TEST_ENTRY_URL', '/index-test.php');
+```
diff --git a/extensions/composer/CHANGELOG.md b/extensions/composer/CHANGELOG.md
index 5a972cd7695..c48e017e5ac 100644
--- a/extensions/composer/CHANGELOG.md
+++ b/extensions/composer/CHANGELOG.md
@@ -5,6 +5,7 @@ Yii Framework 2 composer extension Change Log
--------------------------
- Bug #3438: Fixed support for non-lowercase package names (cebe)
+- Enh #4597: `yii\composer\Installer::setPermission()` supports setting permission for both directories and files now (qiangxue)
2.0.0-beta April 13, 2014
-------------------------
diff --git a/extensions/composer/Installer.php b/extensions/composer/Installer.php
index b4b6ad80f4d..3ac378d0ac7 100644
--- a/extensions/composer/Installer.php
+++ b/extensions/composer/Installer.php
@@ -237,24 +237,22 @@ public static function setPermission($event)
foreach ((array) $options[self::EXTRA_WRITABLE] as $path) {
echo "Setting writable: $path ...";
- if (is_dir($path)) {
- chmod($path, 0777);
+ if (is_dir($path) || is_file($path)) {
+ chmod($path, is_file($path) ? 0666 : 0777);
echo "done\n";
} else {
- echo "The directory was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path;
-
+ echo "The directory or file was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path;
return;
}
}
foreach ((array) $options[self::EXTRA_EXECUTABLE] as $path) {
echo "Setting executable: $path ...";
- if (is_file($path)) {
+ if (is_dir($path) || is_file($path)) {
chmod($path, 0755);
echo "done\n";
} else {
- echo "\n\tThe file was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path . "\n";
-
+ echo "\n\tThe directory or file was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path . "\n";
return;
}
}
diff --git a/extensions/smarty/Extension.php b/extensions/smarty/Extension.php
index 4359dc799b9..b81099f57a3 100644
--- a/extensions/smarty/Extension.php
+++ b/extensions/smarty/Extension.php
@@ -10,6 +10,7 @@
use Smarty;
use Yii;
use yii\helpers\ArrayHelper;
+use yii\helpers\StringHelper;
use yii\helpers\Url;
use yii\web\View;
@@ -133,7 +134,7 @@ public function compilerUse($params, $template)
}
$class = $params['class'];
- $alias = ArrayHelper::getValue($params, 'as', basename($params['class']));
+ $alias = ArrayHelper::getValue($params, 'as', StringHelper::basename($params['class']));
$type = ArrayHelper::getValue($params, 'type', 'static');
// Register the class during compile time
diff --git a/extensions/smarty/README.md b/extensions/smarty/README.md
index d13f6092456..d5c2b8ea44c 100644
--- a/extensions/smarty/README.md
+++ b/extensions/smarty/README.md
@@ -39,3 +39,5 @@ or add
```
to the require section of your composer.json.
+
+Note that the smarty composer package is distributed using subversion so you may need to install subversion.
diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md
index 69a72a42f0e..74646acfc90 100644
--- a/framework/CHANGELOG.md
+++ b/framework/CHANGELOG.md
@@ -57,6 +57,7 @@ Yii Framework 2 Change Log
- Bug #3863: Fixed incorrect js selector for `\yii\widgets\ActiveForm::errorSummaryCssClass` when it contains multiple classes (creocoder, umneeq)
- Bug #3893: Headers did not overwrite default setting by webserver (cebe)
- Bug #3909: `Html::to()` should not prefix base URL to URLs that already contain scheme (qiangxue)
+- Bug #3920: Fixed issue with loading default values of PostgreSQL boolean columns (cebe)
- Bug #3934: yii.handleAction() in yii.js does not correctly detect if a hyperlink contains useful URL or not (joni-jones, qiangxue)
- Bug #3968: Messages logged in shutdown functions are not handled (qiangxue)
- Bug #3989: Fixed yii\log\FileTarget::$rotateByCopy to avoid any rename (cebe)
@@ -69,6 +70,7 @@ Yii Framework 2 Change Log
- Bug #4241: `yii\widgets\Pjax` was incorrectly setting container id (mitalcoi)
- Bug #4276: Added check for UPLOAD_ERR_NO_FILE in `yii\web\UploadedFile` and return null if no file was uploaded (OmgDef)
- Bug #4342: mssql (dblib) driver does not support getting attributes (tof06)
+- Bug #4371: Active form client validation wasn't working in case of two models having same named fields (abrahamy)
- Bug #4409: Upper case letters in subdirectory prefixes of controller IDs were not properly handled (qiangxue)
- Bug #4412: Formatter used SI Prefixes for base 1024, now uses binary prefixes (kmindi)
- Bug #4427: Formatter could do one division too much (kmindi)
@@ -79,6 +81,7 @@ Yii Framework 2 Change Log
- Bug #4514: Fixed Request class crashing when empty CSRF token value is sent in cookie (cebe)
- Bug #4519: `yii\base\Model::isAttributeRequired()` should check if the `when` option of the validator is set (thiagotalma)
- Bug #4592: Fixed `yii help` command was listing incorrect action names for methods like `actionSayNO` (samdark)
+- Bug #4654: Fixed issue with PostgreSQL and inserting boolean values with batch insert (cebe)
- Bug: Fixed inconsistent return of `\yii\console\Application::runAction()` (samdark)
- Bug: URL encoding for the route parameter added to `\yii\web\UrlManager` (klimov-paul)
- Bug: Fixed the bug that requesting protected or private action methods would cause 500 error instead of 404 (qiangxue)
@@ -157,6 +160,7 @@ Yii Framework 2 Change Log
- Enh #4080: Added proper handling and support of the symlinked directories in `FileHelper`, added $options parameter in `FileHelper::removeDirectory()` (resurtm)
- Enh #4086: changedAttributes of afterSave Event now contain old values (dizews)
- Enh #4114: Added `Security::generateRandomBytes()`, improved tests (samdark)
+- Enh #4122: `Html::error()` and `Html::errorSummary()` are now accepting `encode` option. If set to false it prevents encoding of error messages (samdark)
- Enh #4131: Security adjustments (tom--)
- Added HKDF to `yii\base\Security`.
- Reverted auto fallback to PHP PBKDF2.
@@ -172,7 +176,11 @@ Yii Framework 2 Change Log
- Enh #4559: Added `beforeValidateAll` and `afterValidateAll` callbacks to `ActiveForm` (Alex-Code)
- Enh #4566: Added client validation support for image validator (Skysplit, qiangxue)
- Enh #4581: Added ability to disable url encoding in `UrlRule` (tadaszelvys)
+- Enh #4597: `yii\composer\Installer::setPermission()` supports setting permission for both directories and files now (qiangxue)
- Enh #4602: Added $key param in ActionColumn buttons Closure call (disem)
+- Enh #4630: Added automatic generating of unique slug value to `yii\behaviors\Sluggable` (klimov-paul)
+- Enh #4644: Added `\yii\db\Schema::createColumnSchema()` to be able to customize column schema used (mcd-php)
+- Enh #4656: HtmlPurifier helper config can now be a closure to change the purifier config object after it was created (Alex-Code)
- Enh: Added support for using sub-queries when building a DB query with `IN` condition (qiangxue)
- Enh: Supported adding a new response formatter without the need to reconfigure existing formatters (qiangxue)
- Enh: Added `yii\web\UrlManager::addRules()` to simplify adding new URL rules (qiangxue)
@@ -218,6 +226,7 @@ Yii Framework 2 Change Log
- Chg #4310: Removed `$data` from signature of `yii\rbac\ManagerInterface` (samdark)
- Chg #4318: `yii\helpers\Html::ul()` and `ol()` will return an empty list tag if an empty item array is given (qiangxue)
- Chg #4331: `yii\helpers\Url` now uses `UrlManager` to determine base URL when generating URLs (qiangxue)
+- Chg #4586: Signed bigint and unsigned int will be converted into integers when they are loaded from DB by AR (qiangxue)
- Chg #4591: `yii\helpers\Url::to()` will no longer prefix relative URLs with the base URL (qiangxue)
- Chg #4595: `yii\widgets\LinkPager`'s `nextPageLabel`, `prevPageLabel`, `firstPageLabel`, `lastPageLabel` are now taking `false` instead of `null` for "no label" (samdark)
- Chg: Replaced `clearAll()` and `clearAllAssignments()` in `yii\rbac\ManagerInterface` with `removeAll()`, `removeAllRoles()`, `removeAllPermissions()`, `removeAllRules()` and `removeAllAssignments()` (qiangxue)
@@ -232,6 +241,7 @@ Yii Framework 2 Change Log
- New #3911: Added `yii\behaviors\SluggableBehavior` that fills the specified model attribute with the transliterated and adjusted version to use in URLs (creocoder)
- New #4193: Added `yii\filters\Cors` CORS filter to allow Cross Origin Resource Sharing (pgaultier)
- New: Added `yii\base\InvalidValueException` (qiangxue)
+- New: Added `yii\caching\ArrayCache` (cebe)
2.0.0-beta April 13, 2014
diff --git a/framework/behaviors/SluggableBehavior.php b/framework/behaviors/SluggableBehavior.php
index 8dd0a1261ec..3526d8480ce 100644
--- a/framework/behaviors/SluggableBehavior.php
+++ b/framework/behaviors/SluggableBehavior.php
@@ -10,6 +10,8 @@
use yii\base\InvalidConfigException;
use yii\db\BaseActiveRecord;
use yii\helpers\Inflector;
+use yii\validators\UniqueValidator;
+use Yii;
/**
* SluggableBehavior automatically fills the specified attribute with a value that can be used a slug in a URL.
@@ -46,7 +48,9 @@
* ];
* }
* ```
+ *
* @author Alexander Kochetov ' . Yii::t('yii', 'Please fix the following errors:') . ' ' . Yii::t('yii', 'Please fix the following errors:') . '";
@@ -1111,6 +1113,7 @@ public static function errorSummary($models, $options = [])
* The following options are specially handled:
*
* - tag: this specifies the tag name. If not set, "div" will be used.
+ * - encode: boolean, if set to false then value won't be encoded.
*
* See [[renderTagAttributes()]] for details on how attributes are being rendered.
*
@@ -1121,8 +1124,9 @@ public static function error($model, $attribute, $options = [])
$attribute = static::getAttributeName($attribute);
$error = $model->getFirstError($attribute);
$tag = isset($options['tag']) ? $options['tag'] : 'div';
- unset($options['tag']);
- return Html::tag($tag, Html::encode($error), $options);
+ $encode = !isset($options['encode']) || $options['encode'] !== false;
+ unset($options['tag'], $options['encode']);
+ return Html::tag($tag, $encode ? Html::encode($error) : $error, $options);
}
/**
diff --git a/framework/helpers/BaseHtmlPurifier.php b/framework/helpers/BaseHtmlPurifier.php
index 6f5b4509c84..30d8ead706b 100644
--- a/framework/helpers/BaseHtmlPurifier.php
+++ b/framework/helpers/BaseHtmlPurifier.php
@@ -19,17 +19,39 @@ class BaseHtmlPurifier
{
/**
* Passes markup through HTMLPurifier making it safe to output to end user
+ *
+ * @param string $content The HTML content to purify
+ * @param array|\Closure|null $config The config to use for HtmlPurifier.
+ * If not specified or `null` the default config will be used.
+ * You can use an array or an anonymous function to provide configuration options:
*
- * @param string $content
- * @param array|null $config
- * @return string
+ * - An array will be passed to the `HTMLPurifier_Config::create()` method.
+ * - An anonymous function will be called after the config was created.
+ * The signature should be: `function($config)` where `$config` will be an
+ * instance of `HTMLPurifier_Config`.
+ *
+ * Here is a usage example of such a function:
+ *
+ * ~~~
+ * // Allow the HTML5 data attribute `data-type` on `img` elements.
+ * $content = HtmlPurifier::process($content, function($config) {
+ * $config->getHTMLDefinition(true)
+ * ->addAttribute('img', 'data-type', 'Text');
+ * });
+ * ~~~
+ *
+ * @return string the purified HTML content.
*/
public static function process($content, $config = null)
{
- $configInstance = \HTMLPurifier_Config::create($config);
+ $configInstance = \HTMLPurifier_Config::create($config instanceof \Closure ? null : $config);
$configInstance->autoFinalize = false;
$purifier=\HTMLPurifier::instance($configInstance);
$purifier->config->set('Cache.SerializerPath', \Yii::$app->getRuntimePath());
+
+ if ($config instanceof \Closure) {
+ call_user_func($config, $configInstance);
+ }
return $purifier->purify($content);
}
diff --git a/framework/widgets/ActiveField.php b/framework/widgets/ActiveField.php
index 636db97fe5d..ffd0174e6e2 100644
--- a/framework/widgets/ActiveField.php
+++ b/framework/widgets/ActiveField.php
@@ -195,7 +195,7 @@ public function begin()
{
$clientOptions = $this->getClientOptions();
if (!empty($clientOptions)) {
- $this->form->attributes[$this->attribute] = $clientOptions;
+ $this->form->attributes[] = $clientOptions;
}
$inputID = Html::getInputId($this->model, $this->attribute);
diff --git a/tests/README.md b/tests/README.md
index fa6b3a411ab..028f74afe77 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -15,7 +15,7 @@ DIRECTORY STRUCTURE
HOW TO RUN THE TESTS
--------------------
-Make sure you have PHPUnit installed.
+Make sure you have PHPUnit installed and that you installed all composer dependencies (run `composer update` in the repo base directory).
Run PHPUnit in the yii repo base directory.
@@ -38,4 +38,14 @@ PHPUnit configuration is in `phpunit.xml.dist` in repository root folder.
You can create your own phpunit.xml to override dist config.
Database and other backend system configuration can be found in `unit/data/config.php`
-adjust them to your needs to allow testing databases and caching in your environment.
\ No newline at end of file
+adjust them to your needs to allow testing databases and caching in your environment.
+You can override configuration values by creating a `config.local.php` file
+and manipulate the `$config` variable.
+For example to change MySQL username and password your `config.local.php` should
+contain the following:
+
+```php
+ [
'cubrid' => [
'dsn' => 'cubrid:dbname=demodb;host=localhost;port=33000',
@@ -58,3 +72,9 @@
'options' => [],
]
];
+
+if (is_file(__DIR__ . '/config.local.php')) {
+ include(__DIR__ . '/config.local.php');
+}
+
+return $config;
\ No newline at end of file
diff --git a/tests/unit/data/postgres.sql b/tests/unit/data/postgres.sql
index c5656f2ad0f..73147df9c73 100644
--- a/tests/unit/data/postgres.sql
+++ b/tests/unit/data/postgres.sql
@@ -16,6 +16,7 @@ DROP TABLE IF EXISTS "profile" CASCADE;
DROP TABLE IF EXISTS "type" CASCADE;
DROP TABLE IF EXISTS "null_values" CASCADE;
DROP TABLE IF EXISTS "constraints" CASCADE;
+DROP TABLE IF EXISTS "bool_values" CASCADE;
CREATE TABLE "constraints"
(
@@ -113,6 +114,13 @@ CREATE TABLE "type" (
bit_col BIT(8) NOT NULL DEFAULT B'10000010'
);
+CREATE TABLE "bool_values" (
+ id serial not null primary key,
+ bool_col bool,
+ default_true bool not null default true,
+ default_false boolean not null default false
+);
+
INSERT INTO "profile" (description) VALUES ('profile customer 1');
INSERT INTO "profile" (description) VALUES ('profile customer 3');
diff --git a/tests/unit/extensions/smarty/ViewRendererTest.php b/tests/unit/extensions/smarty/ViewRendererTest.php
index 5fe11371039..02028f6785f 100644
--- a/tests/unit/extensions/smarty/ViewRendererTest.php
+++ b/tests/unit/extensions/smarty/ViewRendererTest.php
@@ -7,6 +7,7 @@
namespace yiiunit\extensions\smarty;
+use yii\helpers\FileHelper;
use yii\web\AssetManager;
use yii\web\View;
use Yii;
@@ -20,9 +21,17 @@ class ViewRendererTest extends TestCase
{
protected function setUp()
{
+ parent::setUp();
$this->mockApplication();
}
+ protected function tearDown()
+ {
+ parent::tearDown();
+ FileHelper::removeDirectory(Yii::getAlias('@runtime/assets'));
+ FileHelper::removeDirectory(Yii::getAlias('@runtime/Smarty'));
+ }
+
/**
* https://github.com/yiisoft/yii2/issues/2265
*/
diff --git a/tests/unit/extensions/sphinx/SphinxTestCase.php b/tests/unit/extensions/sphinx/SphinxTestCase.php
index 83b09848537..c01161a359c 100644
--- a/tests/unit/extensions/sphinx/SphinxTestCase.php
+++ b/tests/unit/extensions/sphinx/SphinxTestCase.php
@@ -48,6 +48,12 @@ protected function setUp()
if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) {
$this->markTestSkipped('pdo and pdo_mysql extension are required.');
}
+ // check whether sphinx is running and skip tests if not.
+ if (preg_match('/host=([\w\d.]+)/i', $this->sphinxConfig['dsn'], $hm) && preg_match('/port=(\d+)/i', $this->sphinxConfig['dsn'], $pm)) {
+ if (!@stream_socket_client($hm[1] . ':' . $pm[1], $errorNumber, $errorDescription, 0.5)) {
+ $this->markTestSkipped('No redis server running at ' . $hm[1] . ':' . $pm[1] . ' : ' . $errorNumber . ' - ' . $errorDescription);
+ }
+ }
$config = self::getParam('sphinx');
if (!empty($config)) {
$this->sphinxConfig = $config['sphinx'];
diff --git a/tests/unit/extensions/twig/ViewRendererTest.php b/tests/unit/extensions/twig/ViewRendererTest.php
index 7f4e03fa6fd..13fff38ff11 100644
--- a/tests/unit/extensions/twig/ViewRendererTest.php
+++ b/tests/unit/extensions/twig/ViewRendererTest.php
@@ -1,6 +1,7 @@
mockApplication();
}
+ protected function tearDown()
+ {
+ parent::tearDown();
+ FileHelper::removeDirectory(Yii::getAlias('@runtime/assets'));
+ }
+
/**
* https://github.com/yiisoft/yii2/issues/1755
*/
diff --git a/tests/unit/framework/behaviors/SluggableBehaviorTest.php b/tests/unit/framework/behaviors/SluggableBehaviorTest.php
new file mode 100644
index 00000000000..3bd6b7269f5
--- /dev/null
+++ b/tests/unit/framework/behaviors/SluggableBehaviorTest.php
@@ -0,0 +1,193 @@
+mockApplication([
+ 'components' => [
+ 'db' => [
+ 'class' => '\yii\db\Connection',
+ 'dsn' => 'sqlite::memory:',
+ ]
+ ]
+ ]);
+
+ $columns = [
+ 'id' => 'pk',
+ 'name' => 'string',
+ 'slug' => 'string',
+ 'category_id' => 'integer',
+ ];
+ Yii::$app->getDb()->createCommand()->createTable('test_slug', $columns)->execute();
+ }
+
+ public function tearDown()
+ {
+ Yii::$app->getDb()->close();
+ parent::tearDown();
+ }
+
+ // Tests :
+
+ public function testSlug()
+ {
+ $model = new ActiveRecordSluggable();
+ $model->name = 'test name';
+ $model->validate();
+
+ $this->assertEquals('test-name', $model->slug);
+ }
+
+ /**
+ * @depends testSlug
+ */
+ public function testSlugSeveralAttributes()
+ {
+ $model = new ActiveRecordSluggable();
+ $model->getBehavior('sluggable')->attribute = array('name', 'category_id');
+
+ $model->name = 'test';
+ $model->category_id = 10;
+
+ $model->validate();
+ $this->assertEquals('test-10', $model->slug);
+ }
+
+ /**
+ * @depends testSlug
+ */
+ public function testUniqueByIncrement()
+ {
+ $name = 'test name';
+
+ $model = new ActiveRecordSluggableUnique();
+ $model->name = $name;
+ $model->save();
+
+ $model = new ActiveRecordSluggableUnique();
+ $model->sluggable->uniqueSlugGenerator = 'increment';
+ $model->name = $name;
+ $model->save();
+
+ $this->assertEquals('test-name-2', $model->slug);
+ }
+
+ /**
+ * @depends testUniqueByIncrement
+ */
+ public function testUniqueByCallback()
+ {
+ $name = 'test name';
+
+ $model = new ActiveRecordSluggableUnique();
+ $model->name = $name;
+ $model->save();
+
+ $model = new ActiveRecordSluggableUnique();
+ $model->sluggable->uniqueSlugGenerator = function($baseSlug, $iteration) {return $baseSlug . '-callback';};
+ $model->name = $name;
+ $model->save();
+
+ $this->assertEquals('test-name-callback', $model->slug);
+ }
+
+ /**
+ * @depends testSlug
+ */
+ public function testUpdateUnique()
+ {
+ $name = 'test name';
+
+ $model = new ActiveRecordSluggableUnique();
+ $model->name = $name;
+ $model->save();
+
+ $model->save();
+ $this->assertEquals('test-name', $model->slug);
+
+ $model = ActiveRecordSluggableUnique::find()->one();
+ $model->save();
+ $this->assertEquals('test-name', $model->slug);
+
+ $model->name = 'test-name';
+ $model->save();
+ $this->assertEquals('test-name', $model->slug);
+ }
+}
+
+/**
+ * Test Active Record class with [[SluggableBehavior]] behavior attached.
+ *
+ * @property integer $id
+ * @property string $name
+ * @property string $slug
+ * @property integer $category_id
+ *
+ * @property SluggableBehavior $sluggable
+ */
+class ActiveRecordSluggable extends ActiveRecord
+{
+ public function behaviors()
+ {
+ return [
+ 'sluggable' => [
+ 'class' => SluggableBehavior::className(),
+ 'attribute' => 'name',
+ ],
+ ];
+ }
+
+ public static function tableName()
+ {
+ return 'test_slug';
+ }
+
+ /**
+ * @return SluggableBehavior
+ */
+ public function getSluggable()
+ {
+ return $this->getBehavior('sluggable');
+ }
+}
+
+class ActiveRecordSluggableUnique extends ActiveRecordSluggable
+{
+ public function behaviors()
+ {
+ return [
+ 'sluggable' => [
+ 'class' => SluggableBehavior::className(),
+ 'attribute' => 'name',
+ 'ensureUnique' => true,
+ ],
+ ];
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/framework/caching/ArrayCacheTest.php b/tests/unit/framework/caching/ArrayCacheTest.php
new file mode 100644
index 00000000000..5ec7d731b92
--- /dev/null
+++ b/tests/unit/framework/caching/ArrayCacheTest.php
@@ -0,0 +1,49 @@
+_cacheInstance === null) {
+ $this->_cacheInstance = new ArrayCache();
+ }
+ return $this->_cacheInstance;
+ }
+
+ public function testExpire()
+ {
+ $cache = $this->getCacheInstance();
+
+ static::$microtime = \microtime(true);
+ $this->assertTrue($cache->set('expire_test', 'expire_test', 2));
+ static::$microtime++;
+ $this->assertEquals('expire_test', $cache->get('expire_test'));
+ static::$microtime++;
+ $this->assertFalse($cache->get('expire_test'));
+ }
+
+ public function testExpireAdd()
+ {
+ $cache = $this->getCacheInstance();
+
+ static::$microtime = \microtime(true);
+ $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2));
+ static::$microtime++;
+ $this->assertEquals('expire_testa', $cache->get('expire_testa'));
+ static::$microtime++;
+ $this->assertFalse($cache->get('expire_testa'));
+ }
+}
diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php
index 40c77053081..f31d6004ff9 100644
--- a/tests/unit/framework/caching/CacheTestCase.php
+++ b/tests/unit/framework/caching/CacheTestCase.php
@@ -11,8 +11,19 @@ function time()
return \yiiunit\framework\caching\CacheTestCase::$time ?: \time();
}
+/**
+ * Mock for the microtime() function for caching classes
+ * @param bool $float
+ * @return float
+ */
+function microtime($float = false)
+{
+ return \yiiunit\framework\caching\CacheTestCase::$microtime ?: \microtime($float);
+}
+
namespace yiiunit\framework\caching;
+use yii\caching\Cache;
use yiiunit\TestCase;
/**
@@ -25,6 +36,12 @@ abstract class CacheTestCase extends TestCase
* Null means normal time() behavior.
*/
public static $time;
+ /**
+ * @var float virtual time to be returned by mocked microtime() function.
+ * Null means normal microtime() behavior.
+ */
+ public static $microtime;
+
/**
* @return Cache
@@ -40,6 +57,7 @@ protected function setUp()
protected function tearDown()
{
static::$time = null;
+ static::$microtime = null;
}
/**
diff --git a/tests/unit/framework/caching/MemCacheTest.php b/tests/unit/framework/caching/MemCacheTest.php
index 36d79043791..d3c35d3b1fb 100644
--- a/tests/unit/framework/caching/MemCacheTest.php
+++ b/tests/unit/framework/caching/MemCacheTest.php
@@ -21,6 +21,11 @@ protected function getCacheInstance()
$this->markTestSkipped("memcache not installed. Skipping.");
}
+ // check whether memcached is running and skip tests if not.
+ if (!@stream_socket_client('127.0.0.1:11211', $errorNumber, $errorDescription, 0.5)) {
+ $this->markTestSkipped('No redis server running at ' . '127.0.0.1:11211' . ' : ' . $errorNumber . ' - ' . $errorDescription);
+ }
+
if ($this->_cacheInstance === null) {
$this->_cacheInstance = new MemCache();
}
diff --git a/tests/unit/framework/caching/MemCachedTest.php b/tests/unit/framework/caching/MemCachedTest.php
index 35d9800f87d..56a55703550 100644
--- a/tests/unit/framework/caching/MemCachedTest.php
+++ b/tests/unit/framework/caching/MemCachedTest.php
@@ -21,6 +21,11 @@ protected function getCacheInstance()
$this->markTestSkipped("memcached not installed. Skipping.");
}
+ // check whether memcached is running and skip tests if not.
+ if (!@stream_socket_client('127.0.0.1:11211', $errorNumber, $errorDescription, 0.5)) {
+ $this->markTestSkipped('No redis server running at ' . '127.0.0.1:11211' . ' : ' . $errorNumber . ' - ' . $errorDescription);
+ }
+
if ($this->_cacheInstance === null) {
$this->_cacheInstance = new MemCache(['useMemcached' => true]);
}
diff --git a/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php b/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php
index 1b2a687b2af..a4cb39ed18b 100644
--- a/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php
+++ b/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php
@@ -2,6 +2,7 @@
namespace yiiunit\framework\db\pgsql;
+use yiiunit\data\ar\ActiveRecord;
use yiiunit\framework\db\ActiveRecordTest;
/**
@@ -11,4 +12,53 @@
class PostgreSQLActiveRecordTest extends ActiveRecordTest
{
protected $driverName = 'pgsql';
+
+
+ public function testBooleanValues()
+ {
+ $db = $this->getConnection();
+ $command = $db->createCommand();
+ $command->batchInsert('bool_values',
+ ['bool_col'], [
+ [true],
+ [false],
+ ]
+ )->execute();
+
+ $this->assertEquals(1, BoolAR::find()->where('bool_col = TRUE')->count('*', $db));
+ $this->assertEquals(1, BoolAR::find()->where('bool_col = FALSE')->count('*', $db));
+ $this->assertEquals(2, BoolAR::find()->where('bool_col IN (TRUE, FALSE)')->count('*', $db));
+
+ $this->assertEquals(1, BoolAR::find()->where(['bool_col' => true])->count('*', $db));
+ $this->assertEquals(1, BoolAR::find()->where(['bool_col' => false])->count('*', $db));
+ $this->assertEquals(2, BoolAR::find()->where(['bool_col' => [true, false]])->count('*', $db));
+
+ $this->assertEquals(1, BoolAR::find()->where('bool_col = :bool_col', ['bool_col' => true])->count('*', $db));
+ $this->assertEquals(1, BoolAR::find()->where('bool_col = :bool_col', ['bool_col' => false])->count('*', $db));
+
+ $this->assertSame(true, BoolAR::find()->where(['bool_col' => true])->one($db)->bool_col);
+ $this->assertSame(false, BoolAR::find()->where(['bool_col' => false])->one($db)->bool_col);
+ }
+
+ public function testBooleanDefaultValues()
+ {
+ $model = new BoolAR();
+ $this->assertNull($model->bool_col);
+ $this->assertNull($model->default_true);
+ $this->assertNull($model->default_false);
+ $model->loadDefaultValues();
+ $this->assertNull($model->bool_col);
+ $this->assertSame(true, $model->default_true);
+ $this->assertSame(false, $model->default_false);
+
+ $this->assertTrue($model->save(false));
+ }
}
+
+class BoolAR extends ActiveRecord
+{
+ public static function tableName()
+ {
+ return 'bool_values';
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/framework/db/pgsql/PostgreSQLCommandTest.php b/tests/unit/framework/db/pgsql/PostgreSQLCommandTest.php
index b810a0a770d..1382bd7d6e8 100644
--- a/tests/unit/framework/db/pgsql/PostgreSQLCommandTest.php
+++ b/tests/unit/framework/db/pgsql/PostgreSQLCommandTest.php
@@ -19,4 +19,39 @@ public function testAutoQuoting()
$command = $db->createCommand($sql);
$this->assertEquals('SELECT "id", "t"."name" FROM "customer" t', $command->sql);
}
+
+ public function testBooleanValuesInsert()
+ {
+ $db = $this->getConnection();
+ $command = $db->createCommand();
+ $command->insert('bool_values', ['bool_col' => true]);
+ $this->assertEquals(1, $command->execute());
+
+ $command = $db->createCommand();
+ $command->insert('bool_values', ['bool_col' => false]);
+ $this->assertEquals(1, $command->execute());
+
+ $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = TRUE;');
+ $this->assertEquals(1, $command->queryScalar());
+ $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = FALSE;');
+ $this->assertEquals(1, $command->queryScalar());
+ }
+
+ public function testBooleanValuesBatchInsert()
+ {
+ $db = $this->getConnection();
+ $command = $db->createCommand();
+ $command->batchInsert('bool_values',
+ ['bool_col'], [
+ [true],
+ [false],
+ ]
+ );
+ $this->assertEquals(2, $command->execute());
+
+ $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = TRUE;');
+ $this->assertEquals(1, $command->queryScalar());
+ $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = FALSE;');
+ $this->assertEquals(1, $command->queryScalar());
+ }
}
\ No newline at end of file
diff --git a/tests/unit/framework/db/pgsql/PostgreSQLQueryTest.php b/tests/unit/framework/db/pgsql/PostgreSQLQueryTest.php
index fbb84495917..af2c383d969 100644
--- a/tests/unit/framework/db/pgsql/PostgreSQLQueryTest.php
+++ b/tests/unit/framework/db/pgsql/PostgreSQLQueryTest.php
@@ -3,6 +3,7 @@
namespace yiiunit\framework\db\pgsql;
use yii\db\pgsql\Schema;
+use yii\db\Query;
use yiiunit\framework\db\QueryTest;
use yiiunit\framework\db\SchemaTest;
@@ -13,4 +14,27 @@
class PostgreSQLQueryTest extends QueryTest
{
public $driverName = 'pgsql';
+
+ public function testBooleanValues()
+ {
+ $db = $this->getConnection();
+ $command = $db->createCommand();
+ $command->batchInsert('bool_values',
+ ['bool_col'], [
+ [true],
+ [false],
+ ]
+ )->execute();
+
+ $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = TRUE')->count('*', $db));
+ $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = FALSE')->count('*', $db));
+ $this->assertEquals(2, (new Query())->from('bool_values')->where('bool_col IN (TRUE, FALSE)')->count('*', $db));
+
+ $this->assertEquals(1, (new Query())->from('bool_values')->where(['bool_col' => true])->count('*', $db));
+ $this->assertEquals(1, (new Query())->from('bool_values')->where(['bool_col' => false])->count('*', $db));
+ $this->assertEquals(2, (new Query())->from('bool_values')->where(['bool_col' => [true, false]])->count('*', $db));
+
+ $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = :bool_col', ['bool_col' => true])->count('*', $db));
+ $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = :bool_col', ['bool_col' => false])->count('*', $db));
+ }
}
diff --git a/tests/unit/framework/db/pgsql/PostgreSQLSchemaTest.php b/tests/unit/framework/db/pgsql/PostgreSQLSchemaTest.php
index a93027aad2d..1f154eec66c 100644
--- a/tests/unit/framework/db/pgsql/PostgreSQLSchemaTest.php
+++ b/tests/unit/framework/db/pgsql/PostgreSQLSchemaTest.php
@@ -80,4 +80,14 @@ public function testGetPDOType()
}
fclose($fp);
}
+
+ public function testBooleanDefaultValues()
+ {
+ /* @var $schema Schema */
+ $schema = $this->getConnection()->schema;
+
+ $table = $schema->getTableSchema('bool_values');
+ $this->assertSame(true, $table->getColumn('default_true')->defaultValue);
+ $this->assertSame(false, $table->getColumn('default_false')->defaultValue);
+ }
}
diff --git a/tests/unit/framework/db/sqlite/SqliteConnectionTest.php b/tests/unit/framework/db/sqlite/SqliteConnectionTest.php
index c75f58edab0..c36e5e66d50 100644
--- a/tests/unit/framework/db/sqlite/SqliteConnectionTest.php
+++ b/tests/unit/framework/db/sqlite/SqliteConnectionTest.php
@@ -122,7 +122,7 @@ protected function prepareMasterSlave($masterCount, $slaveCount)
$config = [
'class' => 'yii\db\Connection',
- 'dsn' => 'sqlite:memory:',
+ 'dsn' => "sqlite:$basePath/yii2test.sq3",
];
$this->prepareDatabase($config, $fixture)->close();