getConnection()->createCommand($sql)->execute();
+
+ $schema = $this->getConnection()->getTableSchema('datetime_test');
+
+ $dt = $schema->columns['dt'];
+
+ $this->assertInstanceOf(Expression::className(),$dt->defaultValue);
+ }
+
public function testGetSchemaNames()
{
$this->markTestSkipped('Schemas are not supported in MySQL.');
diff --git a/tests/framework/db/sqlite/CommandTest.php b/tests/framework/db/sqlite/CommandTest.php
index acd730d..b5bdfb9 100644
--- a/tests/framework/db/sqlite/CommandTest.php
+++ b/tests/framework/db/sqlite/CommandTest.php
@@ -43,4 +43,47 @@ class CommandTest extends \yiiunit\framework\db\CommandTest
{
$this->markTestSkipped('SQLite does not support adding/dropping check constraints.');
}
+
+ public function testMultiStatementSupport()
+ {
+ $db = $this->getConnection(false);
+ $sql = <<<'SQL'
+DROP TABLE IF EXISTS {{T_multistatement}};
+CREATE TABLE {{T_multistatement}} (
+ [[intcol]] INTEGER,
+ [[textcol]] TEXT
+);
+INSERT INTO {{T_multistatement}} VALUES(41, :val1);
+INSERT INTO {{T_multistatement}} VALUES(42, :val2);
+SQL;
+ $db->createCommand($sql, [
+ 'val1' => 'foo',
+ 'val2' => 'bar',
+ ])->execute();
+ $this->assertSame([
+ [
+ 'intcol' => '41',
+ 'textcol' => 'foo',
+ ],
+ [
+ 'intcol' => '42',
+ 'textcol' => 'bar',
+ ],
+ ], $db->createCommand('SELECT * FROM {{T_multistatement}}')->queryAll());
+ $sql = <<<'SQL'
+UPDATE {{T_multistatement}} SET [[intcol]] = :newInt WHERE [[textcol]] = :val1;
+DELETE FROM {{T_multistatement}} WHERE [[textcol]] = :val2;
+SELECT * FROM {{T_multistatement}}
+SQL;
+ $this->assertSame([
+ [
+ 'intcol' => '410',
+ 'textcol' => 'foo',
+ ],
+ ], $db->createCommand($sql, [
+ 'newInt' => 410,
+ 'val1' => 'foo',
+ 'val2' => 'bar',
+ ])->queryAll());
+ }
}
diff --git a/tests/framework/di/ContainerTest.php b/tests/framework/di/ContainerTest.php
index b952ed8..0f7be22 100644
--- a/tests/framework/di/ContainerTest.php
+++ b/tests/framework/di/ContainerTest.php
@@ -15,7 +15,9 @@ use yiiunit\data\ar\Cat;
use yiiunit\data\ar\Order;
use yiiunit\data\ar\Type;
use yiiunit\framework\di\stubs\Bar;
+use yiiunit\framework\di\stubs\BarSetter;
use yiiunit\framework\di\stubs\Foo;
+use yiiunit\framework\di\stubs\FooProperty;
use yiiunit\framework\di\stubs\Qux;
use yiiunit\framework\di\stubs\QuxInterface;
use yiiunit\TestCase;
@@ -95,6 +97,19 @@ class ContainerTest extends TestCase
$this->assertInstanceOf($Bar, $foo->bar);
$this->assertInstanceOf($Qux, $foo->bar->qux);
+ // predefined property parameters
+ $fooSetter = FooProperty::className();
+ $barSetter = BarSetter::className();
+
+ $container = new Container();
+ $container->set('foo', ['class' => $fooSetter, 'bar' => Instance::of('bar')]);
+ $container->set('bar', ['class' => $barSetter, 'qux' => Instance::of('qux')]);
+ $container->set('qux', $Qux);
+ $foo = $container->get('foo');
+ $this->assertInstanceOf($fooSetter, $foo);
+ $this->assertInstanceOf($barSetter, $foo->bar);
+ $this->assertInstanceOf($Qux, $foo->bar->qux);
+
// wiring by closure
$container = new Container();
$container->set('qux', new Qux());
diff --git a/tests/framework/di/stubs/BarSetter.php b/tests/framework/di/stubs/BarSetter.php
new file mode 100644
index 0000000..355d41d
--- /dev/null
+++ b/tests/framework/di/stubs/BarSetter.php
@@ -0,0 +1,40 @@
+
+ * @since 2.0
+ *
+ * @property QuxInterface $qux
+ */
+class BarSetter extends BaseObject
+{
+ /**
+ * @var QuxInterface
+ */
+ private $qux;
+
+ /**
+ * @return QuxInterface
+ */
+ public function getQux()
+ {
+ return $this->qux;
+ }
+
+ /**
+ * @param mixed $qux
+ */
+ public function setQux(QuxInterface $qux)
+ {
+ $this->qux = $qux;
+ }
+}
diff --git a/tests/framework/di/stubs/FooProperty.php b/tests/framework/di/stubs/FooProperty.php
new file mode 100644
index 0000000..022d2e3
--- /dev/null
+++ b/tests/framework/di/stubs/FooProperty.php
@@ -0,0 +1,24 @@
+
+ * @since 2.0
+ *
+ * @property BarSetter $bar
+ */
+class FooProperty extends BaseObject
+{
+ /**
+ * @var BarSetter
+ */
+ public $bar;
+}
diff --git a/tests/framework/filters/CorsTest.php b/tests/framework/filters/CorsTest.php
new file mode 100644
index 0000000..5fb1f94
--- /dev/null
+++ b/tests/framework/filters/CorsTest.php
@@ -0,0 +1,45 @@
+mockWebApplication();
+ $controller = new Controller('id', Yii::$app);
+ $action = new Action('test', $controller);
+ $request = new Request();
+
+ $cors = new Cors();
+ $cors->request = $request;
+
+ $_SERVER['REQUEST_METHOD'] = 'OPTIONS';
+ $request->headers->set('Access-Control-Request-Method', 'GET');
+ $this->assertFalse($cors->beforeAction($action));
+ $this->assertEquals(200, $cors->response->getStatusCode());
+
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $request->headers->set('Access-Control-Request-Method', 'GET');
+ $this->assertTrue($cors->beforeAction($action));
+
+ $request->headers->remove('Access-Control-Request-Method');
+ $this->assertTrue($cors->beforeAction($action));
+ }
+}
diff --git a/tests/framework/filters/PageCacheTest.php b/tests/framework/filters/PageCacheTest.php
index c549222..4189a0a 100644
--- a/tests/framework/filters/PageCacheTest.php
+++ b/tests/framework/filters/PageCacheTest.php
@@ -447,4 +447,18 @@ class PageCacheTest extends TestCase
ob_end_clean();
}
}
+
+ public function testCalculateCacheKey()
+ {
+ $expected = ['yii\filters\PageCache', 'test', 'ru'];
+ Yii::$app->requestedRoute = 'test';
+ $keys = $this->invokeMethod(new PageCache(['variations' => ['ru']]), 'calculateCacheKey');
+ $this->assertEquals($expected, $keys);
+
+ $keys = $this->invokeMethod(new PageCache(['variations' => 'ru']), 'calculateCacheKey');
+ $this->assertEquals($expected, $keys);
+
+ $keys = $this->invokeMethod(new PageCache(), 'calculateCacheKey');
+ $this->assertEquals(['yii\filters\PageCache', 'test'], $keys);
+ }
}
diff --git a/tests/framework/filters/RateLimiterTest.php b/tests/framework/filters/RateLimiterTest.php
index 7998511..b678f9f 100644
--- a/tests/framework/filters/RateLimiterTest.php
+++ b/tests/framework/filters/RateLimiterTest.php
@@ -127,16 +127,16 @@ class RateLimiterTest extends TestCase
/* @var $user UserIdentity|\Prophecy\ObjectProphecy */
$rateLimit = new RateLimit();
$rateLimit
- ->setRateLimit([1, 1])
- ->setAllowance([1, time()]);
- $rateLimiter = $this->getMockBuilder(RateLimiter::class)
- ->setMethods(['addRateLimitHeaders'])
- ->getMock();
- $rateLimiter->expects(self::at(0))
- ->method('addRateLimitHeaders')
- ->willReturn(null);
+ ->setRateLimit([2, 10])
+ ->setAllowance([2, time()]);
- $rateLimiter->checkRateLimit($rateLimit, Yii::$app->request, Yii::$app->response, 'testAction');
+ $rateLimiter = new RateLimiter();
+ $response = Yii::$app->response;
+ $rateLimiter->checkRateLimit($rateLimit, Yii::$app->request, $response, 'testAction');
+ $headers = $response->getHeaders();
+ $this->assertEquals(2, $headers->get('X-Rate-Limit-Limit'));
+ $this->assertEquals(1, $headers->get('X-Rate-Limit-Remaining'));
+ $this->assertEquals(5, $headers->get('X-Rate-Limit-Reset'));
}
public function testAddRateLimitHeadersDisabledRateLimitHeaders()
diff --git a/tests/framework/filters/auth/AuthTest.php b/tests/framework/filters/auth/AuthTest.php
index 9826777..2133e52 100644
--- a/tests/framework/filters/auth/AuthTest.php
+++ b/tests/framework/filters/auth/AuthTest.php
@@ -13,6 +13,7 @@ use yii\filters\auth\AuthMethod;
use yii\filters\auth\HttpBasicAuth;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\QueryParamAuth;
+use yii\filters\auth\HttpHeaderAuth;
use yii\helpers\ArrayHelper;
use yii\rest\Controller;
use yii\web\UnauthorizedHttpException;
@@ -148,6 +149,18 @@ class AuthTest extends \yiiunit\TestCase
* @param string|null $token
* @param string|null $login
*/
+ public function testHttpHeaderAuth($token, $login)
+ {
+ Yii::$app->request->headers->set('X-Api-Key', $token);
+ $filter = ['class' => HttpHeaderAuth::className()];
+ $this->ensureFilterApplies($token, $login, $filter);
+ }
+
+ /**
+ * @dataProvider tokenProvider
+ * @param string|null $token
+ * @param string|null $login
+ */
public function testHttpBearerAuth($token, $login)
{
Yii::$app->request->addHeader('Authorization', "Bearer $token");
@@ -163,6 +176,7 @@ class AuthTest extends \yiiunit\TestCase
['yii\filters\auth\CompositeAuth'],
['yii\filters\auth\HttpBearerAuth'],
['yii\filters\auth\QueryParamAuth'],
+ ['yii\filters\auth\HttpHeaderAuth'],
];
}
diff --git a/tests/framework/helpers/BaseConsoleTest.php b/tests/framework/helpers/BaseConsoleTest.php
new file mode 100644
index 0000000..874c237
--- /dev/null
+++ b/tests/framework/helpers/BaseConsoleTest.php
@@ -0,0 +1,29 @@
+assertEquals($expected, $actual);
+
+ $actual = BaseConsole::renderColoredString($data, false);
+ $expected = "foo";
+ $this->assertEquals($expected, $actual);
+ }
+}
diff --git a/tests/framework/helpers/ConsoleTest.php b/tests/framework/helpers/ConsoleTest.php
index bd9767f..88cac6d 100644
--- a/tests/framework/helpers/ConsoleTest.php
+++ b/tests/framework/helpers/ConsoleTest.php
@@ -10,6 +10,7 @@ namespace yiiunit\framework\helpers;
use Yii;
use yii\helpers\Console;
use yiiunit\TestCase;
+use yii\base\DynamicModel;
/**
* @group helpers
@@ -204,6 +205,39 @@ class ConsoleTest extends TestCase
$this->assertEquals($html, Console::ansiToHtml($ansi));
}
+ public function testErrorSummary()
+ {
+ $model = new TestConsoleModel();
+ $model->name = 'not_an_integer';
+ $model->addError('name', 'Error message. Here are some chars: < >');
+ $model->addError('name', 'Error message. Here are even more chars: ""');
+ $model->validate(null, false);
+ $options = ['showAllErrors' => true];
+ $expectedHtml = "Error message. Here are some chars: < >\nError message. Here are even more chars: \"\"";
+ $this->assertEquals($expectedHtml, Console::errorSummary($model, $options));
+ }
+}
+
+/**
+ * @property string name
+ * @property array types
+ * @property string description
+ */
+class TestConsoleModel extends DynamicModel
+{
+ public function rules()
+ {
+ return [
+ ['name', 'required'],
+ ['name', 'string', 'max' => 100]
+ ];
+ }
+
+ public function init()
+ {
+ $this->defineAttribute('name');
+ }
+
/**
* @covers \yii\helpers\BaseConsole::input()
*/
diff --git a/tests/framework/helpers/FormatConverterTest.php b/tests/framework/helpers/FormatConverterTest.php
index 49c8f14..4b1b8c2 100644
--- a/tests/framework/helpers/FormatConverterTest.php
+++ b/tests/framework/helpers/FormatConverterTest.php
@@ -127,13 +127,13 @@ class FormatConverterTest extends TestCase
public function testEscapedIcuToPhp()
{
- $this->assertEquals('l, F j, Y \\a\\t g:i:s a T', FormatConverter::convertDateIcuToPhp('EEEE, MMMM d, y \'at\' h:mm:ss a zzzz'));
+ $this->assertEquals('l, F j, Y \\a\\t g:i:s A T', FormatConverter::convertDateIcuToPhp('EEEE, MMMM d, y \'at\' h:mm:ss a zzzz'));
$this->assertEquals('\\o\\\'\\c\\l\\o\\c\\k', FormatConverter::convertDateIcuToPhp('\'o\'\'clock\''));
}
public function testEscapedIcuToJui()
{
- $this->assertEquals('l, F j, Y \\a\\t g:i:s a T', FormatConverter::convertDateIcuToPhp('EEEE, MMMM d, y \'at\' h:mm:ss a zzzz'));
+ $this->assertEquals('l, F j, Y \\a\\t g:i:s A T', FormatConverter::convertDateIcuToPhp('EEEE, MMMM d, y \'at\' h:mm:ss a zzzz'));
$this->assertEquals('\'o\'\'clock\'', FormatConverter::convertDateIcuToJui('\'o\'\'clock\''));
}
diff --git a/tests/framework/helpers/HtmlTest.php b/tests/framework/helpers/HtmlTest.php
index 8b44067..a0a33df 100644
--- a/tests/framework/helpers/HtmlTest.php
+++ b/tests/framework/helpers/HtmlTest.php
@@ -1214,6 +1214,30 @@ EOD;
$this->assertEqualsWithoutLE($expectedHtml, Html::errorSummary($model, $options));
}
+ public function testError()
+ {
+ $model = new HtmlTestModel();
+ $model->validate();
+ $this->assertEquals(
+ 'Name cannot be blank.
',
+ Html::error($model, 'name'),
+ 'Default error message after calling $model->getFirstError()'
+ );
+
+ $this->assertEquals(
+ 'this is custom error message
',
+ Html::error($model, 'name', ['errorSource' => [$model, 'customError']]),
+ 'Custom error message generated by callback'
+ );
+ $this->assertEquals(
+ 'Error in yiiunit\framework\helpers\HtmlTestModel - name
',
+ Html::error($model, 'name', ['errorSource' => function ($model, $attribute) {
+ return 'Error in ' . get_class($model) . ' - ' . $attribute;
+ }]),
+ 'Custom error message generated by closure'
+ );
+ }
+
/**
* Data provider for [[testActiveTextArea()]].
* @return array test data
@@ -1582,6 +1606,24 @@ HTML;
['uk', 'Powered by Yii Framework'],
];
}
+
+ public function testActiveTextInput_placeholderFillFromModel()
+ {
+ $model = new HtmlTestModel();
+
+ $html = Html::activeTextInput($model, 'name', ['placeholder' => true]);
+
+ $this->assertContains('placeholder="Name"', $html);
+ }
+
+ public function testActiveTextInput_customPlaceholder()
+ {
+ $model = new HtmlTestModel();
+
+ $html = Html::activeTextInput($model, 'name', ['placeholder' => 'Custom placeholder']);
+
+ $this->assertContains('placeholder="Custom placeholder"', $html);
+ }
}
/**
@@ -1607,4 +1649,9 @@ class HtmlTestModel extends DynamicModel
[['radio', 'checkbox'], 'boolean'],
];
}
+
+ public function customError()
+ {
+ return 'this is custom error message';
+ }
}
diff --git a/tests/framework/helpers/JsonTest.php b/tests/framework/helpers/JsonTest.php
index 70d7c85..58f8df4 100644
--- a/tests/framework/helpers/JsonTest.php
+++ b/tests/framework/helpers/JsonTest.php
@@ -7,7 +7,7 @@
namespace yiiunit\framework\helpers;
-use yii\base\Model;
+use yii\base\DynamicModel;
use yii\helpers\BaseJson;
use yii\helpers\Json;
use yii\web\JsExpression;
@@ -208,9 +208,21 @@ class JsonTest extends TestCase
}
}
}
+
+ public function testErrorSummary()
+ {
+ $model = new JsonModel();
+ $model->name = 'not_an_integer';
+ $model->addError('name', 'Error message. Here are some chars: < >');
+ $model->addError('name', 'Error message. Here are even more chars: ""');
+ $model->validate(null, false);
+ $options = ['showAllErrors' => true];
+ $expectedHtml = '["Error message. Here are some chars: < >","Error message. Here are even more chars: \"\""]';
+ $this->assertEquals($expectedHtml, Json::errorSummary($model, $options));
+ }
}
-class JsonModel extends Model implements \JsonSerializable
+class JsonModel extends DynamicModel implements \JsonSerializable
{
public $data = ['json' => 'serializable'];
@@ -218,4 +230,17 @@ class JsonModel extends Model implements \JsonSerializable
{
return $this->data;
}
+
+ public function rules()
+ {
+ return [
+ ['name', 'required'],
+ ['name', 'string', 'max' => 100]
+ ];
+ }
+
+ public function init()
+ {
+ $this->defineAttribute('name');
+ }
}
diff --git a/tests/framework/helpers/StringHelperTest.php b/tests/framework/helpers/StringHelperTest.php
index fbe3d28..419c1e0 100644
--- a/tests/framework/helpers/StringHelperTest.php
+++ b/tests/framework/helpers/StringHelperTest.php
@@ -312,4 +312,91 @@ class StringHelperTest extends TestCase
['Это закодированная строка', '0K3RgtC-INC30LDQutC-0LTQuNGA0L7QstCw0L3QvdCw0Y8g0YHRgtGA0L7QutCw'],
];
}
+
+ /**
+ * Data provider for [[testMatchWildcard()]]
+ * @return array test data.
+ */
+ public function dataProviderMatchWildcard()
+ {
+ return [
+ // *
+ ['*', 'any', true],
+ ['*', '', true],
+ ['begin*end', 'begin-middle-end', true],
+ ['begin*end', 'beginend', true],
+ ['begin*end', 'begin-d', false],
+ ['*end', 'beginend', true],
+ ['*end', 'begin', false],
+ ['begin*', 'begin-end', true],
+ ['begin*', 'end', false],
+ ['begin*', 'before-begin', false],
+ // ?
+ ['begin?end', 'begin1end', true],
+ ['begin?end', 'beginend', false],
+ ['begin??end', 'begin12end', true],
+ ['begin??end', 'begin1end', false],
+ // []
+ ['gr[ae]y', 'gray', true],
+ ['gr[ae]y', 'grey', true],
+ ['gr[ae]y', 'groy', false],
+ ['a[2-8]', 'a1', false],
+ ['a[2-8]', 'a3', true],
+ ['[][!]', ']', true],
+ ['[-1]', '-', true],
+ // [!]
+ ['gr[!ae]y', 'gray', false],
+ ['gr[!ae]y', 'grey', false],
+ ['gr[!ae]y', 'groy', true],
+ ['a[!2-8]', 'a1', true],
+ ['a[!2-8]', 'a3', false],
+ // -
+ ['a-z', 'a-z', true],
+ ['a-z', 'a-c', false],
+ // slashes
+ ['begin/*/end', 'begin/middle/end', true],
+ ['begin/*/end', 'begin/two/steps/end', true],
+ ['begin/*/end', 'begin/end', false],
+ ['begin\\\\*\\\\end', 'begin\middle\end', true],
+ ['begin\\\\*\\\\end', 'begin\two\steps\end', true],
+ ['begin\\\\*\\\\end', 'begin\end', false],
+ // dots
+ ['begin.*.end', 'begin.middle.end', true],
+ ['begin.*.end', 'begin.two.steps.end', true],
+ ['begin.*.end', 'begin.end', false],
+ // case
+ ['begin*end', 'BEGIN-middle-END', false],
+ ['begin*end', 'BEGIN-middle-END', true, ['caseSensitive' => false]],
+ // file path
+ ['begin/*/end', 'begin/middle/end', true, ['filePath' => true]],
+ ['begin/*/end', 'begin/two/steps/end', false, ['filePath' => true]],
+ ['begin\\\\*\\\\end', 'begin\middle\end', true, ['filePath' => true]],
+ ['begin\\\\*\\\\end', 'begin\two\steps\end', false, ['filePath' => true]],
+ ['*', 'any', true, ['filePath' => true]],
+ ['*', 'any/path', false, ['filePath' => true]],
+ ['[.-0]', 'any/path', false, ['filePath' => true]],
+ ['*', '.dotenv', true, ['filePath' => true]],
+ // escaping
+ ['\*\?', '*?', true],
+ ['\*\?', 'zz', false],
+ ['begin\*\end', 'begin\middle\end', true, ['escape' => false]],
+ ['begin\*\end', 'begin\two\steps\end', true, ['escape' => false]],
+ ['begin\*\end', 'begin\end', false, ['escape' => false]],
+ ['begin\*\end', 'begin\middle\end', true, ['filePath' => true, 'escape' => false]],
+ ['begin\*\end', 'begin\two\steps\end', false, ['filePath' => true, 'escape' => false]],
+ ];
+ }
+
+ /**
+ * @dataProvider dataProviderMatchWildcard
+ *
+ * @param string $pattern
+ * @param string $string
+ * @param bool $expectedResult
+ * @param array $options
+ */
+ public function testMatchWildcard($pattern, $string, $expectedResult, $options = [])
+ {
+ $this->assertSame($expectedResult, StringHelper::matchWildcard($pattern, $string, $options));
+ }
}
diff --git a/tests/framework/helpers/UrlTest.php b/tests/framework/helpers/UrlTest.php
index 1e0e74a..ada986b 100644
--- a/tests/framework/helpers/UrlTest.php
+++ b/tests/framework/helpers/UrlTest.php
@@ -29,6 +29,7 @@ class UrlTest extends TestCase
'components' => [
'request' => [
'class' => 'yii\web\Request',
+ 'cookieValidationKey' => '123',
'scriptUrl' => '/base/index.php',
'hostInfo' => 'http://example.com/',
'url' => '/base/index.php&r=site%2Fcurrent&id=42',
diff --git a/tests/framework/i18n/MessageFormatterTest.php b/tests/framework/i18n/MessageFormatterTest.php
index 386a85e..3091027 100644
--- a/tests/framework/i18n/MessageFormatterTest.php
+++ b/tests/framework/i18n/MessageFormatterTest.php
@@ -259,6 +259,12 @@ _MSG_
'offers',
[13],
],
+ [
+ '{gender, select, female{Уважаемая} other{Уважаемый}} {firstname},',
+ 'Уважаемый Vadim,',
+ ['gender' => null,
+ 'firstname' => 'Vadim'],
+ ],
];
}
diff --git a/tests/framework/rbac/ManagerTestCase.php b/tests/framework/rbac/ManagerTestCase.php
index 031f217..227726e 100644
--- a/tests/framework/rbac/ManagerTestCase.php
+++ b/tests/framework/rbac/ManagerTestCase.php
@@ -7,6 +7,7 @@
namespace yiiunit\framework\rbac;
+use yii\base\InvalidParamException;
use yii\rbac\Item;
use yii\rbac\Permission;
use yii\rbac\Role;
@@ -613,4 +614,27 @@ abstract class ManagerTestCase extends TestCase
$rule = $this->auth->getRule('action_rule');
$this->assertInstanceOf(ActionRule::class, $rule);
}
+
+ public function testDefaultRoles()
+ {
+ try {
+ $this->auth->defaultRoles = 'test';
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('\yii\base\InvalidParamException', $e);
+ $this->assertEquals('Default roles must be either an array or a callable', $e->getMessage());
+
+ try {
+ $this->auth->defaultRoles = function () {
+ return 'test';
+ };
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('\yii\base\InvalidParamException', $e);
+ $this->assertEquals('Default roles closure must return an array', $e->getMessage());
+ }
+
+ return;
+ }
+
+ $this->fail('Not rise an exception');
+ }
}
diff --git a/tests/framework/rest/UrlRuleTest.php b/tests/framework/rest/UrlRuleTest.php
index 7f99b88..38f8ff4 100644
--- a/tests/framework/rest/UrlRuleTest.php
+++ b/tests/framework/rest/UrlRuleTest.php
@@ -344,10 +344,10 @@ class UrlRuleTest extends TestCase
/**
* @dataProvider createUrlDataProvider
- * @param array $rule
+ * @param array $ruleConfig
* @param array $tests
*/
- public function testCreateUrl($rule, $tests)
+ public function testCreateUrl($ruleConfig, $tests)
{
foreach ($tests as [$params, $expected]) {
$this->mockWebApplication();
@@ -357,17 +357,17 @@ class UrlRuleTest extends TestCase
$manager = new UrlManager([
'cache' => null,
]);
- $rule = new UrlRule($rule);
+ $rule = new UrlRule($ruleConfig);
$this->assertEquals($expected, $rule->createUrl($manager, $route, $params));
}
}
/**
* @dataProvider dataProviderGetCreateUrlStatus
- * @param array $config
+ * @param array $ruleConfig
* @param array $tests
*/
- public function testGetCreateUrlStatus($config, $tests)
+ public function testGetCreateUrlStatus($ruleConfig, $tests)
{
foreach ($tests as $test) {
list($params, $expected, $status) = $test;
@@ -379,7 +379,7 @@ class UrlRuleTest extends TestCase
$manager = new UrlManager([
'cache' => null,
]);
- $rule = new UrlRule($config);
+ $rule = new UrlRule($ruleConfig);
$errorMessage = 'Failed test: ' . VarDumper::dumpAsString($test);
$this->assertSame($expected, $rule->createUrl($manager, $route, $params), $errorMessage);
$this->assertNotNull($status, $errorMessage);
diff --git a/tests/framework/validators/FileValidatorTest.php b/tests/framework/validators/FileValidatorTest.php
index aaa872d..37314e5 100644
--- a/tests/framework/validators/FileValidatorTest.php
+++ b/tests/framework/validators/FileValidatorTest.php
@@ -238,6 +238,85 @@ class FileValidatorTest extends TestCase
$this->assertFalse($m->validate());
}
+ public function testValidateAttribute_minFilesGreaterThanOneMaxFilesUnlimited_notError()
+ {
+ $validator = new FileValidator(['minFiles' => 2, 'maxFiles' => 0]);
+ $model = FakedValidationModel::createWithAttributes(
+ [
+ 'attr_images' => $this->createTestFiles(
+ [
+ [
+ 'name' => 'image.png',
+ 'size' => 1024,
+ 'type' => 'image/png',
+ ],
+ [
+ 'name' => 'image.png',
+ 'size' => 1024,
+ 'type' => 'image/png',
+ ],
+ ]
+ )
+ ]
+ );
+
+ $validator->validateAttribute($model, 'attr_images');
+
+ $this->assertFalse($model->hasErrors('attr_images'));
+ }
+
+ public function testValidateAttribute_minFilesTwoMaxFilesFour_notError()
+ {
+ $validator = new FileValidator(['minFiles' => 2, 'maxFiles' => 4]);
+ $model = FakedValidationModel::createWithAttributes(
+ [
+ 'attr_images' => $this->createTestFiles(
+ [
+ [
+ 'name' => 'image.png',
+ 'size' => 1024,
+ 'type' => 'image/png',
+ ],
+ [
+ 'name' => 'image.png',
+ 'size' => 1024,
+ 'type' => 'image/png',
+ ],
+ ]
+ )
+ ]
+ );
+
+ $validator->validateAttribute($model, 'attr_images');
+
+ $this->assertFalse($model->hasErrors('attr_images'));
+ }
+
+ public function testValidateAttribute_minFilesTwoMaxFilesUnlimited_hasError()
+ {
+ $validator = new FileValidator(['minFiles' => 2, 'maxFiles' => 0]);
+ $model = FakedValidationModel::createWithAttributes(
+ [
+ 'attr_images' => $this->createTestFiles(
+ [
+ [
+ 'name' => 'image.png',
+ 'size' => 1024,
+ 'type' => 'image/png',
+ ],
+ [
+ 'error' => UPLOAD_ERR_NO_FILE,
+ ],
+ ]
+ )
+ ]
+ );
+
+ $validator->validateAttribute($model, 'attr_images');
+
+ $this->assertTrue($model->hasErrors('attr_images'));
+ }
+
/**
* @param array $params
* @return UploadedFile[]
diff --git a/tests/framework/validators/UniqueValidatorTest.php b/tests/framework/validators/UniqueValidatorTest.php
index b97f41b..9afba6b 100644
--- a/tests/framework/validators/UniqueValidatorTest.php
+++ b/tests/framework/validators/UniqueValidatorTest.php
@@ -434,4 +434,33 @@ abstract class UniqueValidatorTest extends DatabaseTestCase
$validator->validateAttribute($model, 'title');
$this->assertFalse($model->hasErrors(), 'There were errors: ' . json_encode($model->getErrors()));
}
+
+ /**
+ * Test validating a class with default scope
+ * @see https://github.com/yiisoft/yii2/issues/14484
+ */
+ public function testFindModelWith()
+ {
+ $validator = new UniqueValidator([
+ 'targetAttribute' => ['status', 'profile_id']
+ ]);
+ $model = WithCustomer::find()->one();
+ try {
+ $validator->validateAttribute($model, 'email');
+ } catch (\Exception $exception) {
+ $this->fail('Query is crashed because "with" relation cannot be loaded');
+ }
+
+
+ }
+}
+
+class WithCustomer extends Customer {
+ public static function find() {
+ $res = parent::find();
+
+ $res->with('profile');
+
+ return $res;
+ }
}
diff --git a/tests/framework/web/GroupUrlRuleTest.php b/tests/framework/web/GroupUrlRuleTest.php
index 7a9e631..ae75e6d 100644
--- a/tests/framework/web/GroupUrlRuleTest.php
+++ b/tests/framework/web/GroupUrlRuleTest.php
@@ -59,6 +59,52 @@ class GroupUrlRuleTest extends TestCase
}
}
+ public function testParseVerb()
+ {
+ $config = [
+ 'prefix' => 'admin',
+ 'rules' => [
+ 'login' => 'user/login'
+ ],
+ ];
+ $rules = new GroupUrlRule($config);
+ $this->assertNull($rules->rules[0]->verb);
+
+ $config = [
+ 'prefix' => 'admin',
+ 'rules' => [
+ 'login' => ['route' => 'user/login', 'pattern' => 'login', 'verb' => 'POST'],
+ ],
+ ];
+ $rules = new GroupUrlRule($config);
+ $this->assertCount(1, $rules->rules[0]->verb);
+ $this->assertContains('POST', $rules->rules[0]->verb);
+ $this->assertEquals('admin/user/login', $rules->rules[0]->route);
+
+ $config = [
+ 'prefix' => 'admin',
+ 'rules' => [
+ 'POST login' => 'user/login'
+ ],
+ ];
+ $rules = new GroupUrlRule($config);
+ $this->assertCount(1, $rules->rules[0]->verb);
+ $this->assertContains('POST', $rules->rules[0]->verb);
+ $this->assertEquals('admin/user/login', $rules->rules[0]->route);
+
+ $config = [
+ 'prefix' => 'admin',
+ 'rules' => [
+ 'POST,GET login' => 'user/login'
+ ],
+ ];
+ $rules = new GroupUrlRule($config);
+ $this->assertCount(2, $rules->rules[0]->verb);
+ $this->assertContains('POST', $rules->rules[0]->verb);
+ $this->assertContains('GET', $rules->rules[0]->verb);
+ $this->assertEquals('admin/user/login', $rules->rules[0]->route);
+ }
+
protected function getTestsForCreateUrl()
{
// structure of each test
diff --git a/tests/framework/web/RequestTest.php b/tests/framework/web/RequestTest.php
index 0018efa..e002962 100644
--- a/tests/framework/web/RequestTest.php
+++ b/tests/framework/web/RequestTest.php
@@ -141,6 +141,22 @@ class RequestTest extends TestCase
}
}
+ public function testIssue15317()
+ {
+ $this->mockWebApplication();
+ $_COOKIE[(new Request())->csrfParam] = '';
+ $request = new Request();
+ $request->enableCsrfCookie = true;
+ $request->enableCookieValidation = false;
+
+ $_SERVER['REQUEST_METHOD'] = 'POST';
+ \Yii::$app->security->unmaskToken('');
+ $this->assertFalse($request->validateCsrfToken(''));
+
+ // When an empty CSRF token is given it is regenerated.
+ $this->assertNotEmpty($request->getCsrfToken());
+
+ }
/**
* Test CSRF token validation by POST param.
*/
diff --git a/tests/framework/web/UserTest.php b/tests/framework/web/UserTest.php
index 457fe6e..2001ea1 100644
--- a/tests/framework/web/UserTest.php
+++ b/tests/framework/web/UserTest.php
@@ -19,6 +19,8 @@ function time()
namespace yiiunit\framework\web;
use Yii;
+use yii\base\BaseObject;
+use yii\rbac\CheckAccessInterface;
use yii\rbac\PhpManager;
use yii\http\Cookie;
use yii\http\CookieCollection;
@@ -347,6 +349,22 @@ class UserTest extends TestCase
$this->expectException('yii\\web\\ForbiddenHttpException');
Yii::$app->user->loginRequired();
}
+
+ public function testAccessChecker()
+ {
+ $appConfig = [
+ 'components' => [
+ 'user' => [
+ 'identityClass' => UserIdentity::className(),
+ 'accessChecker' => AccessChecker::className()
+ ]
+ ],
+ ];
+
+ $this->mockWebApplication($appConfig);
+ $this->assertInstanceOf(AccessChecker::className(), Yii::$app->user->accessChecker);
+ }
+
}
static $cookiesMock;
@@ -370,3 +388,12 @@ class MockResponse extends \yii\web\Response
return $cookiesMock;
}
}
+
+class AccessChecker extends BaseObject implements CheckAccessInterface
+{
+
+ public function checkAccess($userId, $permissionName, $params = [])
+ {
+ // Implement checkAccess() method.
+ }
+}
diff --git a/tests/framework/widgets/FragmentCacheTest.php b/tests/framework/widgets/FragmentCacheTest.php
index 5a23d40..3e49b83 100644
--- a/tests/framework/widgets/FragmentCacheTest.php
+++ b/tests/framework/widgets/FragmentCacheTest.php
@@ -196,5 +196,50 @@ class FragmentCacheTest extends \yiiunit\TestCase
}
}
+ public function testVariations()
+ {
+ ob_start();
+ ob_implicit_flush(false);
+ $view = new View();
+ $this->assertTrue($view->beginCache('test', ['variations' => ['ru']]), 'Cached fragment should not be exist');
+ echo 'cached fragment';
+ $view->endCache();
+
+ $cached = ob_get_clean();
+ $this->assertEquals('cached fragment', $cached);
+
+ ob_start();
+ ob_implicit_flush(false);
+ $this->assertFalse($view->beginCache('test', ['variations' => ['ru']]), 'Cached fragment should be exist');
+
+ $cachedEn = ob_get_clean();
+ $this->assertEquals($cached, $cachedEn);
+
+ $this->assertTrue($view->beginCache('test', ['variations' => ['en']]), 'Cached fragment should not be exist');
+ echo 'cached fragment';
+ $view->endCache();
+ $this->assertFalse($view->beginCache('test', ['variations' => ['en']]), 'Cached fragment should be exist');
+
+ //without variations
+ ob_start();
+ ob_implicit_flush(false);
+ $view = new View();
+ $this->assertTrue($view->beginCache('test'), 'Cached fragment should not be exist');
+ echo 'cached fragment';
+ $view->endCache();
+ $cached = ob_get_clean();
+ $this->assertEquals('cached fragment', $cached);
+
+ //with variations as a string
+ ob_start();
+ ob_implicit_flush(false);
+ $this->assertTrue($view->beginCache('test', ['variations' => 'uz']), 'Cached fragment should not be exist');
+ echo 'cached fragment';
+ $view->endCache();
+ $cached = ob_get_clean();
+ $this->assertEquals('cached fragment', $cached);
+ $this->assertFalse($view->beginCache('test', ['variations' => 'uz']), 'Cached fragment should be exist');
+ }
+
// TODO test dynamic replacements
}