From cde97847f425840948a4bfbf267693063c14e103 Mon Sep 17 00:00:00 2001 From: Suralc Date: Mon, 29 Jul 2013 15:04:44 +0200 Subject: [PATCH 001/103] BooleanValidatorTest --- .../framework/validators/BooleanValidatorTest.php | 53 ++++++++++++++++++++++ .../validators/DefaultValueValidatorTest.php | 32 +++++++++++++ .../framework/validators/FakedValidationModel.php | 20 ++++++++ 3 files changed, 105 insertions(+) create mode 100644 tests/unit/framework/validators/BooleanValidatorTest.php create mode 100644 tests/unit/framework/validators/DefaultValueValidatorTest.php create mode 100644 tests/unit/framework/validators/FakedValidationModel.php diff --git a/tests/unit/framework/validators/BooleanValidatorTest.php b/tests/unit/framework/validators/BooleanValidatorTest.php new file mode 100644 index 0000000..e13635d --- /dev/null +++ b/tests/unit/framework/validators/BooleanValidatorTest.php @@ -0,0 +1,53 @@ +assertTrue($val->validateValue(true)); + $this->assertTrue($val->validateValue(false)); + $this->assertTrue($val->validateValue('0')); + $this->assertTrue($val->validateValue('1')); + $this->assertTrue($val->validateValue(null)); + $this->assertTrue($val->validateValue(array())); + $val->strict = true; + $this->assertTrue($val->validateValue('0')); + $this->assertTrue($val->validateValue('1')); + $this->assertFalse($val->validateValue(true)); + $this->assertFalse($val->validateValue(false)); + $val->trueValue = true; + $val->falseValue = false; + $this->assertFalse($val->validateValue('0')); + $this->assertFalse($val->validateValue(array())); + $this->assertTrue($val->validateValue(true)); + $this->assertTrue($val->validateValue(false)); + } + + public function testValidateAttributeAndError() + { + $obj = new FakedValidationModel; + $obj->attrA = true; + $obj->attrB = '1'; + $obj->attrC = '0'; + $obj->attrD = array(); + $val = new BooleanValidator; + $val->validateAttribute($obj, 'attrA'); + $this->assertFalse(isset($obj->errors['attrA'])); + $val->validateAttribute($obj, 'attrC'); + $this->assertFalse(isset($obj->errors['attrC'])); + $val->strict = true; + $val->validateAttribute($obj, 'attrB'); + $this->assertFalse(isset($obj->errors['attrB'])); + $val->validateAttribute($obj, 'attrD'); + $this->assertTrue(isset($obj->errors['attrD'])); + } +} diff --git a/tests/unit/framework/validators/DefaultValueValidatorTest.php b/tests/unit/framework/validators/DefaultValueValidatorTest.php new file mode 100644 index 0000000..05a71b5 --- /dev/null +++ b/tests/unit/framework/validators/DefaultValueValidatorTest.php @@ -0,0 +1,32 @@ +value = 'test_value'; + $obj = new \stdclass; + $obj->attrA = 'attrA'; + $obj->attrB = null; + $obj->attrC = ''; + // original values to chek which attritubes where modified + $objB = clone $obj; + $val->validateAttribute($obj, 'attrB'); + $this->assertEquals($val->value, $obj->attrB); + $this->assertEquals($objB->attrA, $obj->attrA); + $val->value = 'new_test_value'; + $obj = clone $objB; // get clean object + $val->validateAttribute($obj, 'attrC'); + $this->assertEquals('new_test_value', $obj->attrC); + $this->assertEquals($objB->attrA, $obj->attrA); + $val->validateAttribute($obj, 'attrA'); + $this->assertEquals($objB->attrA, $obj->attrA); + } +} diff --git a/tests/unit/framework/validators/FakedValidationModel.php b/tests/unit/framework/validators/FakedValidationModel.php new file mode 100644 index 0000000..d3c0424 --- /dev/null +++ b/tests/unit/framework/validators/FakedValidationModel.php @@ -0,0 +1,20 @@ +errors[$attribute] = $message; + } +} \ No newline at end of file From 09c5e6146273310ab3f885c595cbabd8f27c202a Mon Sep 17 00:00:00 2001 From: Suralc Date: Mon, 29 Jul 2013 15:20:07 +0200 Subject: [PATCH 002/103] fix test --- tests/unit/framework/validators/BooleanValidatorTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/framework/validators/BooleanValidatorTest.php b/tests/unit/framework/validators/BooleanValidatorTest.php index e13635d..655ef58 100644 --- a/tests/unit/framework/validators/BooleanValidatorTest.php +++ b/tests/unit/framework/validators/BooleanValidatorTest.php @@ -17,8 +17,8 @@ class BooleanValidatorTest extends TestCase $this->assertTrue($val->validateValue(false)); $this->assertTrue($val->validateValue('0')); $this->assertTrue($val->validateValue('1')); - $this->assertTrue($val->validateValue(null)); - $this->assertTrue($val->validateValue(array())); + $this->assertFalse($val->validateValue(null)); + $this->assertFalse($val->validateValue(array())); $val->strict = true; $this->assertTrue($val->validateValue('0')); $this->assertTrue($val->validateValue('1')); From fc1d2af36c28ff853faa59fc799bbf05f1ab9410 Mon Sep 17 00:00:00 2001 From: Suralc Date: Mon, 29 Jul 2013 16:21:07 +0200 Subject: [PATCH 003/103] UrlValidator Tests --- framework/yii/validators/UrlValidator.php | 2 + .../framework/validators/FakedValidationModel.php | 5 ++ .../unit/framework/validators/UrlValidatorTest.php | 89 ++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 tests/unit/framework/validators/UrlValidatorTest.php diff --git a/framework/yii/validators/UrlValidator.php b/framework/yii/validators/UrlValidator.php index aa3dad1..c9b3a2b 100644 --- a/framework/yii/validators/UrlValidator.php +++ b/framework/yii/validators/UrlValidator.php @@ -54,7 +54,9 @@ class UrlValidator extends Validator { parent::init(); if ($this->enableIDN && !function_exists('idn_to_ascii')) { + // @codeCoverageIgnoreStart throw new InvalidConfigException('In order to use IDN validation intl extension must be installed and enabled.'); + // @codeCoverageIgnoreEnd } if ($this->message === null) { $this->message = Yii::t('yii', '{attribute} is not a valid URL.'); diff --git a/tests/unit/framework/validators/FakedValidationModel.php b/tests/unit/framework/validators/FakedValidationModel.php index d3c0424..89632c7 100644 --- a/tests/unit/framework/validators/FakedValidationModel.php +++ b/tests/unit/framework/validators/FakedValidationModel.php @@ -17,4 +17,9 @@ class FakedValidationModel { $this->errors[$attribute] = $message; } + + public function resetErrors() + { + $this->errors = array(); + } } \ No newline at end of file diff --git a/tests/unit/framework/validators/UrlValidatorTest.php b/tests/unit/framework/validators/UrlValidatorTest.php new file mode 100644 index 0000000..81ddf41 --- /dev/null +++ b/tests/unit/framework/validators/UrlValidatorTest.php @@ -0,0 +1,89 @@ +assertFalse($val->validateValue('google.de')); + $this->assertTrue($val->validateValue('http://google.de')); + $this->assertTrue($val->validateValue('https://google.de')); + $this->assertFalse($val->validateValue('htp://yiiframework.com')); + $this->assertTrue($val->validateValue('https://www.google.de/search?q=yii+framework&ie=utf-8&oe=utf-8' + .'&rls=org.mozilla:de:official&client=firefox-a&gws_rd=cr')); + $this->assertFalse($val->validateValue('ftp://ftp.ruhr-uni-bochum.de/')); + $this->assertFalse($val->validateValue('http://invalid,domain')); + $this->assertFalse($val->validateValue('http://äüö?=!"§$%&/()=}][{³²€.edu')); + } + + public function testValidateValueWithDefaultScheme() + { + $val = new UrlValidator(array('defaultScheme' => 'https')); + $this->assertTrue($val->validateValue('yiiframework.com')); + $this->assertTrue($val->validateValue('http://yiiframework.com')); + } + + public function testValidateWithCustomScheme() + { + $val = new UrlValidator(array( + 'validSchemes' => array('http', 'https', 'ftp', 'ftps'), + 'defaultScheme' => 'http', + )); + $this->assertTrue($val->validateValue('ftp://ftp.ruhr-uni-bochum.de/')); + $this->assertTrue($val->validateValue('google.de')); + $this->assertTrue($val->validateValue('http://google.de')); + $this->assertTrue($val->validateValue('https://google.de')); + $this->assertFalse($val->validateValue('htp://yiiframework.com')); + // relative urls not supported + $this->assertFalse($val->validateValue('//yiiframework.com')); + } + + public function testValidateWithIdn() + { + if(!function_exists('idn_to_ascii')) { + $this->markTestSkipped('intl package required'); + return; + } + $val = new UrlValidator(array( + 'enableIDN' => true, + )); + $this->assertTrue($val->validateValue('http://äüößìà.de')); + // converted via http://mct.verisign-grs.com/convertServlet + $this->assertTrue($val->validateValue('http://xn--zcack7ayc9a.de')); + } + + public function testValidateLength() + { + $url = 'http://' . str_pad('base', 2000, 'url') . '.de'; + $val = new UrlValidator; + $this->assertFalse($val->validateValue($url)); + } + + public function testValidateAttributeAndError() + { + $obj = new FakedValidationModel; + $obj->url = 'http://google.de'; + $val = new UrlValidator; + $val->validateAttribute($obj, 'url'); + $this->assertFalse(isset($obj->errors['url'])); + $this->assertSame('http://google.de', $obj->url); + $obj->resetErrors(); + $val->defaultScheme = 'http'; + $obj->url = 'google.de'; + $val->validateAttribute($obj, 'url'); + $this->assertFalse(isset($obj->errors['url'])); + $this->assertTrue(stripos($obj->url, 'http') !== false); + $obj->resetErrors(); + $obj->url = 'gttp;/invalid string'; + $val->validateAttribute($obj, 'url'); + $this->assertTrue(isset($obj->errors['url'])); + } +} From ec1dfeaa587878fc8ae0dd02fcb2b444d12419f2 Mon Sep 17 00:00:00 2001 From: Suralc Date: Mon, 29 Jul 2013 16:40:33 +0200 Subject: [PATCH 004/103] Ignoring javascript generating methods in coverage for now. --- framework/yii/validators/BooleanValidator.php | 1 + framework/yii/validators/CaptchaValidator.php | 1 + framework/yii/validators/CompareValidator.php | 1 + framework/yii/validators/EmailValidator.php | 1 + framework/yii/validators/NumberValidator.php | 1 + framework/yii/validators/RangeValidator.php | 1 + framework/yii/validators/RegularExpressionValidator.php | 1 + framework/yii/validators/RequiredValidator.php | 1 + framework/yii/validators/StringValidator.php | 1 + framework/yii/validators/UrlValidator.php | 1 + 10 files changed, 10 insertions(+) diff --git a/framework/yii/validators/BooleanValidator.php b/framework/yii/validators/BooleanValidator.php index d1e81b8..6b6fded 100644 --- a/framework/yii/validators/BooleanValidator.php +++ b/framework/yii/validators/BooleanValidator.php @@ -82,6 +82,7 @@ class BooleanValidator extends Validator * @param \yii\base\View $view the view object that is going to be used to render views or view files * containing a model form with this validator applied. * @return string the client-side validation script. + * @codeCoverageIgnore */ public function clientValidateAttribute($object, $attribute, $view) { diff --git a/framework/yii/validators/CaptchaValidator.php b/framework/yii/validators/CaptchaValidator.php index 2a16f57..379859c 100644 --- a/framework/yii/validators/CaptchaValidator.php +++ b/framework/yii/validators/CaptchaValidator.php @@ -97,6 +97,7 @@ class CaptchaValidator extends Validator * @param \yii\base\View $view the view object that is going to be used to render views or view files * containing a model form with this validator applied. * @return string the client-side validation script. + * @codeCoverageIgnore */ public function clientValidateAttribute($object, $attribute, $view) { diff --git a/framework/yii/validators/CompareValidator.php b/framework/yii/validators/CompareValidator.php index 8c9e587..9d427ff 100644 --- a/framework/yii/validators/CompareValidator.php +++ b/framework/yii/validators/CompareValidator.php @@ -181,6 +181,7 @@ class CompareValidator extends Validator * @param \yii\base\View $view the view object that is going to be used to render views or view files * containing a model form with this validator applied. * @throws InvalidConfigException if CompareValidator::operator is invalid + * @codeCoverageIgnore */ public function clientValidateAttribute($object, $attribute, $view) { diff --git a/framework/yii/validators/EmailValidator.php b/framework/yii/validators/EmailValidator.php index c3d8480..dba1d7b 100644 --- a/framework/yii/validators/EmailValidator.php +++ b/framework/yii/validators/EmailValidator.php @@ -122,6 +122,7 @@ class EmailValidator extends Validator * @param \yii\base\View $view the view object that is going to be used to render views or view files * containing a model form with this validator applied. * @return string the client-side validation script. + * @codeCoverageIgnore */ public function clientValidateAttribute($object, $attribute, $view) { diff --git a/framework/yii/validators/NumberValidator.php b/framework/yii/validators/NumberValidator.php index 2fee133..2c96e49 100644 --- a/framework/yii/validators/NumberValidator.php +++ b/framework/yii/validators/NumberValidator.php @@ -117,6 +117,7 @@ class NumberValidator extends Validator * @param \yii\base\View $view the view object that is going to be used to render views or view files * containing a model form with this validator applied. * @return string the client-side validation script. + * @codeCoverageIgnore */ public function clientValidateAttribute($object, $attribute, $view) { diff --git a/framework/yii/validators/RangeValidator.php b/framework/yii/validators/RangeValidator.php index f89d420..5474d32 100644 --- a/framework/yii/validators/RangeValidator.php +++ b/framework/yii/validators/RangeValidator.php @@ -84,6 +84,7 @@ class RangeValidator extends Validator * @param \yii\base\View $view the view object that is going to be used to render views or view files * containing a model form with this validator applied. * @return string the client-side validation script. + * @codeCoverageIgnore */ public function clientValidateAttribute($object, $attribute, $view) { diff --git a/framework/yii/validators/RegularExpressionValidator.php b/framework/yii/validators/RegularExpressionValidator.php index 4ae2099..84fd292 100644 --- a/framework/yii/validators/RegularExpressionValidator.php +++ b/framework/yii/validators/RegularExpressionValidator.php @@ -83,6 +83,7 @@ class RegularExpressionValidator extends Validator * containing a model form with this validator applied. * @return string the client-side validation script. * @throws InvalidConfigException if the "pattern" is not a valid regular expression + * @codeCoverageIgnore */ public function clientValidateAttribute($object, $attribute, $view) { diff --git a/framework/yii/validators/RequiredValidator.php b/framework/yii/validators/RequiredValidator.php index 9ca0ecb..6cab6a9 100644 --- a/framework/yii/validators/RequiredValidator.php +++ b/framework/yii/validators/RequiredValidator.php @@ -105,6 +105,7 @@ class RequiredValidator extends Validator * @param \yii\base\View $view the view object that is going to be used to render views or view files * containing a model form with this validator applied. * @return string the client-side validation script. + * @codeCoverageIgnore */ public function clientValidateAttribute($object, $attribute, $view) { diff --git a/framework/yii/validators/StringValidator.php b/framework/yii/validators/StringValidator.php index 4cc9dba..ff8570e 100644 --- a/framework/yii/validators/StringValidator.php +++ b/framework/yii/validators/StringValidator.php @@ -129,6 +129,7 @@ class StringValidator extends Validator * @param \yii\base\View $view the view object that is going to be used to render views or view files * containing a model form with this validator applied. * @return string the client-side validation script. + * @codeCoverageIgnore */ public function clientValidateAttribute($object, $attribute, $view) { diff --git a/framework/yii/validators/UrlValidator.php b/framework/yii/validators/UrlValidator.php index c9b3a2b..29663f1 100644 --- a/framework/yii/validators/UrlValidator.php +++ b/framework/yii/validators/UrlValidator.php @@ -121,6 +121,7 @@ class UrlValidator extends Validator * containing a model form with this validator applied. * @return string the client-side validation script. * @see \yii\Web\ActiveForm::enableClientValidation + * @codeCoverageIgnore */ public function clientValidateAttribute($object, $attribute, $view) { From 1c6b64e7172cedc2733bd37eb0f329bd1d3fd47a Mon Sep 17 00:00:00 2001 From: Suralc Date: Wed, 31 Jul 2013 19:42:20 +0200 Subject: [PATCH 005/103] Added CompareValidatorTest and improved BooleanValidatorTest and UrlValidatorTest --- .../framework/validators/BooleanValidatorTest.php | 11 +- .../framework/validators/CompareValidatorTest.php | 160 +++++++++++++++++++++ .../framework/validators/FakedValidationModel.php | 30 ++-- .../unit/framework/validators/UrlValidatorTest.php | 26 ++-- 4 files changed, 197 insertions(+), 30 deletions(-) create mode 100644 tests/unit/framework/validators/CompareValidatorTest.php diff --git a/tests/unit/framework/validators/BooleanValidatorTest.php b/tests/unit/framework/validators/BooleanValidatorTest.php index 655ef58..e3fa3e5 100644 --- a/tests/unit/framework/validators/BooleanValidatorTest.php +++ b/tests/unit/framework/validators/BooleanValidatorTest.php @@ -1,5 +1,6 @@ assertTrue($val->validateValue(true)); $this->assertTrue($val->validateValue(false)); } - + public function testValidateAttributeAndError() { $obj = new FakedValidationModel; @@ -41,13 +42,13 @@ class BooleanValidatorTest extends TestCase $obj->attrD = array(); $val = new BooleanValidator; $val->validateAttribute($obj, 'attrA'); - $this->assertFalse(isset($obj->errors['attrA'])); + $this->assertFalse($obj->hasErrors('attrA')); $val->validateAttribute($obj, 'attrC'); - $this->assertFalse(isset($obj->errors['attrC'])); + $this->assertFalse($obj->hasErrors('attrC')); $val->strict = true; $val->validateAttribute($obj, 'attrB'); - $this->assertFalse(isset($obj->errors['attrB'])); + $this->assertFalse($obj->hasErrors('attrB')); $val->validateAttribute($obj, 'attrD'); - $this->assertTrue(isset($obj->errors['attrD'])); + $this->assertTrue($obj->hasErrors('attrD')); } } diff --git a/tests/unit/framework/validators/CompareValidatorTest.php b/tests/unit/framework/validators/CompareValidatorTest.php new file mode 100644 index 0000000..c91e7d6 --- /dev/null +++ b/tests/unit/framework/validators/CompareValidatorTest.php @@ -0,0 +1,160 @@ +setExpectedException('yii\base\InvalidConfigException'); + $val = new CompareValidator; + $val->validateValue('val'); + } + + public function testValidateValue() + { + $value = 18449; + // default config + $val = new CompareValidator(array('compareValue' => $value)); + $this->assertTrue($val->validateValue($value)); + $this->assertTrue($val->validateValue((string)$value)); + $this->assertFalse($val->validateValue($value + 1)); + foreach ($this->getOperationTestData($value) as $op => $tests) { + $val = new CompareValidator(array('compareValue' => $value)); + $val->operator = $op; + foreach ($tests as $test) { + $this->assertEquals($test[1], $val->validateValue($test[0])); + } + } + } + + protected function getOperationTestData($value) + { + return array( + '===' => array( + array($value, true), + array((string)$value, false), + array((float)$value, false), + array($value + 1, false), + ), + '!=' => array( + array($value, false), + array((string)$value, false), + array((float)$value, false), + array($value + 0.00001, true), + array(false, true), + ), + '!==' => array( + array($value, false), + array((string)$value, true), + array((float)$value, true), + array(false, true), + ), + '>' => array( + array($value, false), + array($value + 1, true), + array($value - 1, false), + ), + '>=' => array( + array($value, true), + array($value + 1, true), + array($value - 1, false), + ), + '<' => array( + array($value, false), + array($value + 1, false), + array($value - 1, true), + ), + '<=' => array( + array($value, true), + array($value + 1, false), + array($value - 1, true), + ), + + ); + } + + public function testValidateAttribute() + { + // invalid-array + $val = new CompareValidator; + $model = new FakedValidationModel; + $model->attr = array('test_val'); + $val->validateAttribute($model, 'attr'); + $this->assertTrue($model->hasErrors('attr')); + $val = new CompareValidator(array('compareValue' => 'test-string')); + $model = new FakedValidationModel; + $model->attr_test = 'test-string'; + $val->validateAttribute($model, 'attr_test'); + $this->assertFalse($model->hasErrors('attr_test')); + $val = new CompareValidator(array('compareAttribute' => 'attr_test_val')); + $model = new FakedValidationModel; + $model->attr_test = 'test-string'; + $model->attr_test_val = 'test-string'; + $val->validateAttribute($model, 'attr_test'); + $this->assertFalse($model->hasErrors('attr_test')); + $this->assertFalse($model->hasErrors('attr_test_val')); + $val = new CompareValidator(array('compareAttribute' => 'attr_test_val')); + $model = new FakedValidationModel; + $model->attr_test = 'test-string'; + $model->attr_test_val = 'test-string-false'; + $val->validateAttribute($model, 'attr_test'); + $this->assertTrue($model->hasErrors('attr_test')); + $this->assertFalse($model->hasErrors('attr_test_val')); + // assume: _repeat + $val = new CompareValidator; + $model = new FakedValidationModel; + $model->attr_test = 'test-string'; + $model->attr_test_repeat = 'test-string'; + $val->validateAttribute($model, 'attr_test'); + $this->assertFalse($model->hasErrors('attr_test')); + $this->assertFalse($model->hasErrors('attr_test_repeat')); + $val = new CompareValidator; + $model = new FakedValidationModel; + $model->attr_test = 'test-string'; + $model->attr_test_repeat = 'test-string2'; + $val->validateAttribute($model, 'attr_test'); + $this->assertTrue($model->hasErrors('attr_test')); + $this->assertFalse($model->hasErrors('attr_test_repeat')); + } + + public function testValidateAttributeOperators() + { + $value = 55; + foreach ($this->getOperationTestData($value) as $operator => $tests) { + $val = new CompareValidator(array('operator' => $operator, 'compareValue' => $value)); + foreach ($tests as $test) { + $model = new FakedValidationModel; + $model->attr_test = $test[0]; + $val->validateAttribute($model, 'attr_test'); + $this->assertEquals($test[1], !$model->hasErrors('attr_test')); + } + + } + } + + public function testEnsureMessageSetOnInit() + { + foreach ($this->getOperationTestData(1337) as $operator => $tests) { + $val = new CompareValidator(array('operator' => $operator)); + $this->assertTrue(strlen($val->message) > 1); + } + try { + $val = new CompareValidator(array('operator' => '<>')); + } catch (InvalidConfigException $e) { + return; + } + catch (\Exception $e) { + $this->fail('InvalidConfigException expected' . get_class($e) . 'received'); + return; + } + $this->fail('InvalidConfigException expected none received'); + } +} \ No newline at end of file diff --git a/tests/unit/framework/validators/FakedValidationModel.php b/tests/unit/framework/validators/FakedValidationModel.php index 89632c7..15a2a94 100644 --- a/tests/unit/framework/validators/FakedValidationModel.php +++ b/tests/unit/framework/validators/FakedValidationModel.php @@ -2,24 +2,30 @@ namespace yiiunit\framework\validators; +use yii\base\Model; + /** * @codeCoverageIgnore */ -class FakedValidationModel +class FakedValidationModel extends Model { - public $errors = array(); - public function getAttributeLabel($attr) - { - return 'Attr-Label: '.$attr; - } - - public function addError($attribute, $message) + private $attr = array(); + + public function __get($name) { - $this->errors[$attribute] = $message; + if (stripos($name, 'attr') === 0) { + return isset($this->attr[$name]) ? $this->attr[$name] : null; + } + + return parent::__get($name); } - - public function resetErrors() + + public function __set($name, $value) { - $this->errors = array(); + if (stripos($name, 'attr') === 0) { + $this->attr[$name] = $value; + } else { + parent::__set($name, $value); + } } } \ No newline at end of file diff --git a/tests/unit/framework/validators/UrlValidatorTest.php b/tests/unit/framework/validators/UrlValidatorTest.php index 81ddf41..f585590 100644 --- a/tests/unit/framework/validators/UrlValidatorTest.php +++ b/tests/unit/framework/validators/UrlValidatorTest.php @@ -70,20 +70,20 @@ class UrlValidatorTest extends TestCase public function testValidateAttributeAndError() { $obj = new FakedValidationModel; - $obj->url = 'http://google.de'; + $obj->attr_url = 'http://google.de'; $val = new UrlValidator; - $val->validateAttribute($obj, 'url'); - $this->assertFalse(isset($obj->errors['url'])); - $this->assertSame('http://google.de', $obj->url); - $obj->resetErrors(); + $val->validateAttribute($obj, 'attr_url'); + $this->assertFalse($obj->hasErrors('attr_url')); + $this->assertSame('http://google.de', $obj->attr_url); + $obj = new FakedValidationModel; $val->defaultScheme = 'http'; - $obj->url = 'google.de'; - $val->validateAttribute($obj, 'url'); - $this->assertFalse(isset($obj->errors['url'])); - $this->assertTrue(stripos($obj->url, 'http') !== false); - $obj->resetErrors(); - $obj->url = 'gttp;/invalid string'; - $val->validateAttribute($obj, 'url'); - $this->assertTrue(isset($obj->errors['url'])); + $obj->attr_url = 'google.de'; + $val->validateAttribute($obj, 'attr_url'); + $this->assertFalse($obj->hasErrors('attr_url')); + $this->assertTrue(stripos($obj->attr_url, 'http') !== false); + $obj = new FakedValidationModel; + $obj->attr_url = 'gttp;/invalid string'; + $val->validateAttribute($obj, 'attr_url'); + $this->assertTrue($obj->hasErrors('attr_url')); } } From 777ff792c4694926ce8b2795b5627be3c9bd34f4 Mon Sep 17 00:00:00 2001 From: Suralc Date: Wed, 31 Jul 2013 20:12:45 +0200 Subject: [PATCH 006/103] DateValidatorTest --- .../framework/validators/DateValidatorTest.php | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tests/unit/framework/validators/DateValidatorTest.php diff --git a/tests/unit/framework/validators/DateValidatorTest.php b/tests/unit/framework/validators/DateValidatorTest.php new file mode 100644 index 0000000..445d57d --- /dev/null +++ b/tests/unit/framework/validators/DateValidatorTest.php @@ -0,0 +1,61 @@ +assertTrue($val->message !== null && strlen($val->message) > 1); + } + + public function testValidateValue() + { + $val = new DateValidator; + $this->assertTrue($val->validateValue('2013-09-13')); + $this->assertFalse($val->validateValue('31.7.2013')); + $this->assertFalse($val->validateValue('31-7-2013')); + $this->assertFalse($val->validateValue(time())); + $val->format = 'U'; + $this->assertTrue($val->validateValue(time())); + $val->format = 'd.m.Y'; + $this->assertTrue($val->validateValue('31.7.2013')); + $val->format = 'Y-m-!d H:i:s'; + $this->assertTrue($val->validateValue('2009-02-15 15:16:17')); + } + + public function testValidateAttribute() + { + // error-array-add + $val = new DateValidator; + $model = new FakedValidationModel; + $model->attr_date = '2013-09-13'; + $val->validateAttribute($model, 'attr_date'); + $this->assertFalse($model->hasErrors('attr_date')); + $model = new FakedValidationModel; + $model->attr_date = '1375293913'; + $val->validateAttribute($model, 'attr_date'); + $this->assertTrue($model->hasErrors('attr_date')); + //// timestamp attribute + $val = new DateValidator(array('timestampAttribute' => 'attr_timestamp')); + $model = new FakedValidationModel; + $model->attr_date = '2013-09-13'; + $model->attr_timestamp = true; + $val->validateAttribute($model, 'attr_date'); + $this->assertFalse($model->hasErrors('attr_date')); + $this->assertFalse($model->hasErrors('attr_timestamp')); + $this->assertEquals( + DateTime::createFromFormat($val->format, '2013-09-13')->getTimestamp(), + $model->attr_timestamp + ); + + + } +} \ No newline at end of file From 1ce7344e184bfe3e8c0eedd473aed4cc4e5806c6 Mon Sep 17 00:00:00 2001 From: Suralc Date: Wed, 31 Jul 2013 21:14:14 +0200 Subject: [PATCH 007/103] Additional tests in EmailValidator. --- framework/yii/validators/EmailValidator.php | 2 ++ .../framework/validators/EmailValidatorTest.php | 30 ++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/framework/yii/validators/EmailValidator.php b/framework/yii/validators/EmailValidator.php index dba1d7b..116d8e3 100644 --- a/framework/yii/validators/EmailValidator.php +++ b/framework/yii/validators/EmailValidator.php @@ -64,7 +64,9 @@ class EmailValidator extends Validator { parent::init(); if ($this->enableIDN && !function_exists('idn_to_ascii')) { + // @codeCoverageIgnoreStart throw new InvalidConfigException('In order to use IDN validation intl extension must be installed and enabled.'); + // @codeCoverageIgnoreEnd } if ($this->message === null) { $this->message = Yii::t('yii', '{attribute} is not a valid email address.'); diff --git a/tests/unit/framework/validators/EmailValidatorTest.php b/tests/unit/framework/validators/EmailValidatorTest.php index 852b9f9..2a0de82 100644 --- a/tests/unit/framework/validators/EmailValidatorTest.php +++ b/tests/unit/framework/validators/EmailValidatorTest.php @@ -1,5 +1,6 @@ assertTrue($validator->validateValue('5011@gmail.com')); $this->assertFalse($validator->validateValue('test@example.com')); } + + public function testValidateAttribute() + { + $val = new EmailValidator(); + $model = new FakedValidationModel(); + $model->attr_email = '5011@gmail.com'; + $val->validateAttribute($model, 'attr_email'); + $this->assertFalse($model->hasErrors('attr_email')); + } + + public function testValidateValueIdn() + { + if (!function_exists('idn_to_ascii')) { + $this->markTestSkipped('Intl extension required'); + return; + } + $val = new EmailValidator(array('enableIDN' => true)); + $this->assertTrue($val->validateValue('5011@example.com')); + $this->assertTrue($val->validateValue('example@äüößìà.de')); + $this->assertTrue($val->validateValue('example@xn--zcack7ayc9a.de')); + } + + public function testValidateValueWithName() + { + $val = new EmailValidator(array('allowName' => true)); + $this->assertTrue($val->validateValue('test@example.com')); + $this->assertTrue($val->validateValue('John Smith ')); + $this->assertFalse($val->validateValue('John Smith ')); + } } From 467d88faf92c4b8232e6340eb2605f54bad7f84f Mon Sep 17 00:00:00 2001 From: Suralc Date: Wed, 31 Jul 2013 22:48:19 +0200 Subject: [PATCH 008/103] Added StringValidatorTest --- .../framework/validators/FakedValidationModel.php | 5 + .../framework/validators/StringValidatorTest.php | 110 +++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 tests/unit/framework/validators/StringValidatorTest.php diff --git a/tests/unit/framework/validators/FakedValidationModel.php b/tests/unit/framework/validators/FakedValidationModel.php index 15a2a94..f30735e 100644 --- a/tests/unit/framework/validators/FakedValidationModel.php +++ b/tests/unit/framework/validators/FakedValidationModel.php @@ -28,4 +28,9 @@ class FakedValidationModel extends Model parent::__set($name, $value); } } + + public function getAttributeLabel($attr) + { + return $attr; + } } \ No newline at end of file diff --git a/tests/unit/framework/validators/StringValidatorTest.php b/tests/unit/framework/validators/StringValidatorTest.php new file mode 100644 index 0000000..5336dfc --- /dev/null +++ b/tests/unit/framework/validators/StringValidatorTest.php @@ -0,0 +1,110 @@ +mockApplication(); + } + + public function testValidateValue() + { + $val = new StringValidator(); + $this->assertFalse($val->validateValue(array('not a string'))); + $this->assertTrue($val->validateValue('Just some string')); + } + + public function testValidateValueLength() + { + $val = new StringValidator(array('length' => 25)); + $this->assertTrue($val->validateValue(str_repeat('x', 25))); + $this->assertTrue($val->validateValue(str_repeat('€', 25))); + $this->assertFalse($val->validateValue(str_repeat('x', 125))); + $this->assertFalse($val->validateValue('')); + $val = new StringValidator(array('length' => array(25))); + $this->assertTrue($val->validateValue(str_repeat('x', 25))); + $this->assertTrue($val->validateValue(str_repeat('x', 1250))); + $this->assertFalse($val->validateValue(str_repeat('Ä', 24))); + $this->assertFalse($val->validateValue('')); + $val = new StringValidator(array('length' => array(10, 20))); + $this->assertTrue($val->validateValue(str_repeat('x', 15))); + $this->assertTrue($val->validateValue(str_repeat('x', 10))); + $this->assertTrue($val->validateValue(str_repeat('x', 20))); + $this->assertFalse($val->validateValue(str_repeat('x', 5))); + $this->assertFalse($val->validateValue(str_repeat('x', 25))); + $this->assertFalse($val->validateValue('')); + // make sure min/max are overridden + $val = new StringValidator(array('length' => array(10, 20), 'min' => 25, 'max' => 35)); + $this->assertTrue($val->validateValue(str_repeat('x', 15))); + $this->assertFalse($val->validateValue(str_repeat('x', 30))); + } + + public function testValidateValueMinMax() + { + $val = new StringValidator(array('min' => 10)); + $this->assertTrue($val->validateValue(str_repeat('x', 10))); + $this->assertFalse($val->validateValue('xxxx')); + $val = new StringValidator(array('max' => 10)); + $this->assertTrue($val->validateValue('xxxx')); + $this->assertFalse($val->validateValue(str_repeat('y', 20))); + $val = new StringValidator(array('min' => 10, 'max' => 20)); + $this->assertTrue($val->validateValue(str_repeat('y', 15))); + $this->assertFalse($val->validateValue('abc')); + $this->assertFalse($val->validateValue(str_repeat('b', 25))); + } + + public function testValidateAttribute() + { + $val = new StringValidator(); + $model = new FakedValidationModel(); + $model->attr_string = 'a tet string'; + $val->validateAttribute($model, 'attr_string'); + $this->assertFalse($model->hasErrors()); + $val = new StringValidator(array('length' => 20)); + $model = new FakedValidationModel(); + $model->attr_string = str_repeat('x', 20); + $val->validateAttribute($model, 'attr_string'); + $this->assertFalse($model->hasErrors()); + $model = new FakedValidationModel(); + $model->attr_string = 'abc'; + $val->validateAttribute($model, 'attr_string'); + $this->assertTrue($model->hasErrors('attr_string')); + $val = new StringValidator(array('max' => 2)); + $model = new FakedValidationModel(); + $model->attr_string = 'a'; + $val->validateAttribute($model, 'attr_string'); + $this->assertFalse($model->hasErrors()); + $model = new FakedValidationModel(); + $model->attr_string = 'abc'; + $val->validateAttribute($model, 'attr_string'); + $this->assertTrue($model->hasErrors('attr_string')); + } + + public function testEnsureMessagesOnInit() + { + $val = new StringValidator(array('min' => 1, 'max' => 2)); + $this->assertTrue(is_string($val->message)); + $this->assertTrue(is_string($val->tooLong)); + $this->assertTrue(is_string($val->tooShort)); + } + + public function testCustomErrorMessageInValidateAttribute() + { + $val = new StringValidator(array( + 'min' => 5, + 'tooShort' => '{attribute} to short. Min is {min}', + )); + $model = new FakedValidationModel(); + $model->attr_string = 'abc'; + $val->validateAttribute($model, 'attr_string'); + $this->assertTrue($model->hasErrors('attr_string')); + $this->assertEquals('attr_string to short. Min is 5', $model->getErrors('attr_string')[0]); + } +} \ No newline at end of file From f7bb54be1c5d31af369b39514ddc7486f4d8c07b Mon Sep 17 00:00:00 2001 From: Suralc Date: Wed, 31 Jul 2013 23:03:34 +0200 Subject: [PATCH 009/103] Test fix for Php 5.3 --- tests/unit/framework/validators/StringValidatorTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/framework/validators/StringValidatorTest.php b/tests/unit/framework/validators/StringValidatorTest.php index 5336dfc..e7c68bc 100644 --- a/tests/unit/framework/validators/StringValidatorTest.php +++ b/tests/unit/framework/validators/StringValidatorTest.php @@ -105,6 +105,7 @@ class StringValidatorTest extends TestCase $model->attr_string = 'abc'; $val->validateAttribute($model, 'attr_string'); $this->assertTrue($model->hasErrors('attr_string')); - $this->assertEquals('attr_string to short. Min is 5', $model->getErrors('attr_string')[0]); + $errorMsg = $model->getErrors('attr_string'); + $this->assertEquals('attr_string to short. Min is 5', $errorMsg[0]); } } \ No newline at end of file From 8f8de7cf604c292b799ad24acd95b22e48a3f6ab Mon Sep 17 00:00:00 2001 From: Suralc Date: Tue, 6 Aug 2013 13:13:58 +0200 Subject: [PATCH 010/103] Added NumberValidatorTest --- .../framework/validators/NumberValidatorTest.php | 155 +++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 tests/unit/framework/validators/NumberValidatorTest.php diff --git a/tests/unit/framework/validators/NumberValidatorTest.php b/tests/unit/framework/validators/NumberValidatorTest.php new file mode 100644 index 0000000..07a7a69 --- /dev/null +++ b/tests/unit/framework/validators/NumberValidatorTest.php @@ -0,0 +1,155 @@ +assertTrue(is_string($val->message)); + $this->assertTrue(is_null($val->max)); + $val = new NumberValidator(array('min' => -1, 'max' => 20, 'integerOnly' => true)); + $this->assertTrue(is_string($val->message)); + $this->assertTrue(is_string($val->tooSmall)); + $this->assertTrue(is_string($val->tooBig)); + } + + public function testValidateValueSimple() + { + $val = new NumberValidator(); + $this->assertTrue($val->validateValue(20)); + $this->assertTrue($val->validateValue(0)); + $this->assertTrue($val->validateValue(-20)); + $this->assertTrue($val->validateValue('20')); + $this->assertTrue($val->validateValue(25.45)); + $this->assertFalse($val->validateValue('25,45')); + $this->assertFalse($val->validateValue('12:45')); + $val = new NumberValidator(array('integerOnly' => true)); + $this->assertTrue($val->validateValue(20)); + $this->assertTrue($val->validateValue(0)); + $this->assertFalse($val->validateValue(25.45)); + $this->assertTrue($val->validateValue('20')); + $this->assertFalse($val->validateValue('25,45')); + $this->assertTrue($val->validateValue('020')); + $this->assertTrue($val->validateValue(0x14)); + $this->assertFalse($val->validateValue('0x14')); // todo check this + } + + public function testValidateValueAdvanced() + { + $val = new NumberValidator(); + $this->assertTrue($val->validateValue('-1.23')); // signed float + $this->assertTrue($val->validateValue('-4.423e-12')); // signed float + exponent + $this->assertTrue($val->validateValue('12E3')); // integer + exponent + $this->assertFalse($val->validateValue('e12')); // just exponent + $this->assertFalse($val->validateValue('-e3')); + $this->assertFalse($val->validateValue('-4.534-e-12')); // 'signed' exponent + $this->assertFalse($val->validateValue('12.23^4')); // expression instead of value + $val = new NumberValidator(array('integerOnly' => true)); + $this->assertFalse($val->validateValue('-1.23')); + $this->assertFalse($val->validateValue('-4.423e-12')); + $this->assertFalse($val->validateValue('12E3')); + $this->assertFalse($val->validateValue('e12')); + $this->assertFalse($val->validateValue('-e3')); + $this->assertFalse($val->validateValue('-4.534-e-12')); + $this->assertFalse($val->validateValue('12.23^4')); + } + + public function testValidateValueMin() + { + $val = new NumberValidator(array('min' => 1)); + $this->assertTrue($val->validateValue(1)); + $this->assertFalse($val->validateValue(-1)); + $this->assertFalse($val->validateValue('22e-12')); + $this->assertTrue($val->validateValue(PHP_INT_MAX + 1)); + $val = new NumberValidator(array('min' => 1), array('integerOnly' => true)); + $this->assertTrue($val->validateValue(1)); + $this->assertFalse($val->validateValue(-1)); + $this->assertFalse($val->validateValue('22e-12')); + $this->assertTrue($val->validateValue(PHP_INT_MAX + 1)); + } + + public function testValidateValueMax() + { + $val = new NumberValidator(array('max' => 1.25)); + $this->assertTrue($val->validateValue(1)); + $this->assertFalse($val->validateValue(1.5)); + $this->assertTrue($val->validateValue('22e-12')); + $this->assertTrue($val->validateValue('125e-2')); + $val = new NumberValidator(array('max' => 1.25, 'integerOnly' => true)); + $this->assertTrue($val->validateValue(1)); + $this->assertFalse($val->validateValue(1.5)); + $this->assertFalse($val->validateValue('22e-12')); + $this->assertFalse($val->validateValue('125e-2')); + } + + public function testValidateValueRange() + { + $val = new NumberValidator(array('min' => -10, 'max' => 20)); + $this->assertTrue($val->validateValue(0)); + $this->assertTrue($val->validateValue(-10)); + $this->assertFalse($val->validateValue(-11)); + $this->assertFalse($val->validateValue(21)); + $val = new NumberValidator(array('min' => -10, 'max' => 20, 'integerOnly' => true)); + $this->assertTrue($val->validateValue(0)); + $this->assertFalse($val->validateValue(-11)); + $this->assertFalse($val->validateValue(22)); + $this->assertFalse($val->validateValue('20e-1')); + } + + public function testValidateAttribute() + { + $val = new NumberValidator(); + $model = new FakedValidationModel(); + $model->attr_number = '5.5e1'; + $val->validateAttribute($model, 'attr_number'); + $this->assertFalse($model->hasErrors('attr_number')); + $model->attr_number = '43^32'; //expression + $val->validateAttribute($model, 'attr_number'); + $this->assertTrue($model->hasErrors('attr_number')); + $val = new NumberValidator(array('min' => 10)); + $model = new FakedValidationModel(); + $model->attr_number = 10; + $val->validateAttribute($model, 'attr_number'); + $this->assertFalse($model->hasErrors('attr_number')); + $model->attr_number = 5; + $val->validateAttribute($model, 'attr_number'); + $this->assertTrue($model->hasErrors('attr_number')); + $val = new NumberValidator(array('max' => 10)); + $model = new FakedValidationModel(); + $model->attr_number = 10; + $val->validateAttribute($model, 'attr_number'); + $this->assertFalse($model->hasErrors('attr_number')); + $model->attr_number = 15; + $val->validateAttribute($model, 'attr_number'); + $this->assertTrue($model->hasErrors('attr_number')); + $val = new NumberValidator(array('max' => 10, 'integerOnly' => true)); + $model = new FakedValidationModel(); + $model->attr_number = 10; + $val->validateAttribute($model, 'attr_number'); + $this->assertFalse($model->hasErrors('attr_number')); + $model->attr_number = 3.43; + $val->validateAttribute($model, 'attr_number'); + $this->assertTrue($model->hasErrors('attr_number')); + } + + public function testEnsureCustomMessageIsSetOnValidateAttribute() + { + $val = new NumberValidator(array( + 'toSmall' => '{attribute} is to small.', + 'min' => 5 + )); + $model = new FakedValidationModel(); + $model->attr_number = 0; + $val->validateAttribute($model, 'attr_number'); + $this->assertTrue($model->hasErrors('attr_number')); + $this->assertEquals(1, count($model->getErrors('attr_number'))); + $msgs = $model->getErrors('attr_number'); + $this->assertSame('attr_number is to small.', $msgs[0]); + } +} \ No newline at end of file From b5472c20e323ad2c51de8bf2af8c63d9e587f486 Mon Sep 17 00:00:00 2001 From: Suralc Date: Tue, 6 Aug 2013 15:21:29 +0200 Subject: [PATCH 011/103] Typo fix --- tests/unit/framework/validators/NumberValidatorTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/framework/validators/NumberValidatorTest.php b/tests/unit/framework/validators/NumberValidatorTest.php index 07a7a69..279b89e 100644 --- a/tests/unit/framework/validators/NumberValidatorTest.php +++ b/tests/unit/framework/validators/NumberValidatorTest.php @@ -141,7 +141,7 @@ class NumberValidatorTest extends TestCase public function testEnsureCustomMessageIsSetOnValidateAttribute() { $val = new NumberValidator(array( - 'toSmall' => '{attribute} is to small.', + 'tooSmall' => '{attribute} is to small.', 'min' => 5 )); $model = new FakedValidationModel(); From a81480d309cfea6a080982a5f4ffcdc3c97c0de2 Mon Sep 17 00:00:00 2001 From: Suralc Date: Tue, 6 Aug 2013 19:56:05 +0200 Subject: [PATCH 012/103] Improved ValidatorTest organization. --- .../validators/models/FakedValidationModel.php | 55 ++++++++++++++++++++++ .../framework/validators/BooleanValidatorTest.php | 3 +- .../framework/validators/CompareValidatorTest.php | 2 +- .../framework/validators/DateValidatorTest.php | 2 +- .../framework/validators/EmailValidatorTest.php | 1 + .../framework/validators/FakedValidationModel.php | 36 -------------- .../framework/validators/NumberValidatorTest.php | 1 + .../framework/validators/StringValidatorTest.php | 1 + .../unit/framework/validators/UrlValidatorTest.php | 3 +- 9 files changed, 62 insertions(+), 42 deletions(-) create mode 100644 tests/unit/data/validators/models/FakedValidationModel.php delete mode 100644 tests/unit/framework/validators/FakedValidationModel.php diff --git a/tests/unit/data/validators/models/FakedValidationModel.php b/tests/unit/data/validators/models/FakedValidationModel.php new file mode 100644 index 0000000..1e3366c --- /dev/null +++ b/tests/unit/data/validators/models/FakedValidationModel.php @@ -0,0 +1,55 @@ + 'reqTest'), + array('val_attr_c', 'integer'), + ); + } + + public function inlineVal($attribute, $params = array()) + { + return true; + } + + public function __get($name) + { + if (stripos($name, 'attr') === 0) { + return isset($this->attr[$name]) ? $this->attr[$name] : null; + } + + return parent::__get($name); + } + + public function __set($name, $value) + { + if (stripos($name, 'attr') === 0) { + $this->attr[$name] = $value; + } else { + parent::__set($name, $value); + } + } + + public function getAttributeLabel($attr) + { + return $attr; + } +} \ No newline at end of file diff --git a/tests/unit/framework/validators/BooleanValidatorTest.php b/tests/unit/framework/validators/BooleanValidatorTest.php index e3fa3e5..f37b39a 100644 --- a/tests/unit/framework/validators/BooleanValidatorTest.php +++ b/tests/unit/framework/validators/BooleanValidatorTest.php @@ -1,11 +1,10 @@ attr[$name]) ? $this->attr[$name] : null; - } - - return parent::__get($name); - } - - public function __set($name, $value) - { - if (stripos($name, 'attr') === 0) { - $this->attr[$name] = $value; - } else { - parent::__set($name, $value); - } - } - - public function getAttributeLabel($attr) - { - return $attr; - } -} \ No newline at end of file diff --git a/tests/unit/framework/validators/NumberValidatorTest.php b/tests/unit/framework/validators/NumberValidatorTest.php index 279b89e..4868503 100644 --- a/tests/unit/framework/validators/NumberValidatorTest.php +++ b/tests/unit/framework/validators/NumberValidatorTest.php @@ -4,6 +4,7 @@ namespace yiiunit\framework\validators; use yii\validators\NumberValidator; +use yiiunit\data\validators\models\FakedValidationModel; use yiiunit\TestCase; class NumberValidatorTest extends TestCase diff --git a/tests/unit/framework/validators/StringValidatorTest.php b/tests/unit/framework/validators/StringValidatorTest.php index e7c68bc..c7d2889 100644 --- a/tests/unit/framework/validators/StringValidatorTest.php +++ b/tests/unit/framework/validators/StringValidatorTest.php @@ -4,6 +4,7 @@ namespace yiiunit\framework\validators; use yii\validators\StringValidator; +use yiiunit\data\validators\models\FakedValidationModel; use yiiunit\TestCase; class StringValidatorTest extends TestCase diff --git a/tests/unit/framework/validators/UrlValidatorTest.php b/tests/unit/framework/validators/UrlValidatorTest.php index f585590..7b618c1 100644 --- a/tests/unit/framework/validators/UrlValidatorTest.php +++ b/tests/unit/framework/validators/UrlValidatorTest.php @@ -1,10 +1,9 @@ Date: Tue, 13 Aug 2013 16:49:53 +0200 Subject: [PATCH 013/103] Added RequiredValidatorTest --- .../framework/validators/RequiredValidatorTest.php | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/unit/framework/validators/RequiredValidatorTest.php diff --git a/tests/unit/framework/validators/RequiredValidatorTest.php b/tests/unit/framework/validators/RequiredValidatorTest.php new file mode 100644 index 0000000..198727b --- /dev/null +++ b/tests/unit/framework/validators/RequiredValidatorTest.php @@ -0,0 +1,34 @@ +assertFalse($val->validateValue(null)); + $this->assertFalse($val->validateValue(array())); + $this->assertTrue($val->validateValue('not empty')); + $this->assertTrue($val->validateValue(array('with', 'elements'))); + } + + public function testValidateValueWithValue() + { + $val = new RequiredValidator(array('requiredValue' => 55)); + $this->assertTrue($val->validateValue(55)); + $this->assertTrue($val->validateValue("55")); + $this->assertTrue($val->validateValue("0x37")); + $this->assertFalse($val->validateValue("should fail")); + $this->assertTrue($val->validateValue(true)); + $val->strict = true; + $this->assertTrue($val->validateValue(55)); + $this->assertFalse($val->validateValue("55")); + $this->assertFalse($val->validateValue("0x37")); + $this->assertFalse($val->validateValue("should fail")); + $this->assertFalse($val->validateValue(true)); + } +} \ No newline at end of file From bae79cd76c6459198e0d5b79cbb6b09e08b089e1 Mon Sep 17 00:00:00 2001 From: Suralc Date: Tue, 13 Aug 2013 16:51:53 +0200 Subject: [PATCH 014/103] Added ValidatorTest --- tests/unit/data/validators/TestValidator.php | 44 ++++ .../validators/models/FakedValidationModel.php | 15 +- tests/unit/framework/validators/ValidatorTest.php | 227 +++++++++++++++++++++ 3 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 tests/unit/data/validators/TestValidator.php create mode 100644 tests/unit/framework/validators/ValidatorTest.php diff --git a/tests/unit/data/validators/TestValidator.php b/tests/unit/data/validators/TestValidator.php new file mode 100644 index 0000000..13f12dc --- /dev/null +++ b/tests/unit/data/validators/TestValidator.php @@ -0,0 +1,44 @@ +markAttributeValidated($attribute); + if ($this->_setErrorOnValidateAttribute == true) { + $this->addError($object, $attribute, sprintf('%s##%s', $attribute, get_class($object))); + } + } + + protected function markAttributeValidated($attr, $increaseBy = 1) + { + if (!isset($this->_validatedAttributes[$attr])) { + $this->_validatedAttributes[$attr] = 1; + } else { + $this->_validatedAttributes[$attr] = $this->_validatedAttributes[$attr] + $increaseBy; + } + } + + public function countAttributeValidations($attr) + { + return isset($this->_validatedAttributes[$attr]) ? $this->_validatedAttributes[$attr] : 0; + } + + public function isAttributeValidated($attr) + { + return isset($this->_validatedAttributes[$attr]); + } + + public function enableErrorOnValidateAttribute() + { + $this->_setErrorOnValidateAttribute = true; + } +} \ No newline at end of file diff --git a/tests/unit/data/validators/models/FakedValidationModel.php b/tests/unit/data/validators/models/FakedValidationModel.php index 1e3366c..d2e3f52 100644 --- a/tests/unit/data/validators/models/FakedValidationModel.php +++ b/tests/unit/data/validators/models/FakedValidationModel.php @@ -9,13 +9,24 @@ use yii\base\Model; */ class FakedValidationModel extends Model { - private $attr = array(); - public $val_attr_a; public $val_attr_b; public $val_attr_c; public $val_attr_d; + private $attr = array(); + /** + * @param array $attributes + * @return self + */ + public static function createWithAttributes($attributes = array()) + { + $m = new static(); + foreach ($attributes as $attribute => $value) { + $m->$attribute = $value; + } + return $m; + } public function rules() { diff --git a/tests/unit/framework/validators/ValidatorTest.php b/tests/unit/framework/validators/ValidatorTest.php new file mode 100644 index 0000000..f0a114b --- /dev/null +++ b/tests/unit/framework/validators/ValidatorTest.php @@ -0,0 +1,227 @@ + true, 'attr_runMe2' => true, 'attr_skip' => true), + $additionalAttributes + ); + return FakedValidationModel::createWithAttributes($attributes); + } + + public function testCreateValidator() + { + $model = FakedValidationModel::createWithAttributes(array('attr_test1' => 'abc', 'attr_test2' => '2013')); + /** @var $numberVal NumberValidator */ + $numberVal = TestValidator::createValidator('number', $model, array('attr_test1')); + $this->assertInstanceOf(NumberValidator::className(), $numberVal); + $numberVal = TestValidator::createValidator('integer', $model, array('attr_test2')); + $this->assertInstanceOf(NumberValidator::className(), $numberVal); + $this->assertTrue($numberVal->integerOnly); + $val = TestValidator::createValidator( + 'boolean', + $model, + 'attr_test1, attr_test2', + array('on' => array('a', 'b')) + ); + $this->assertInstanceOf(BooleanValidator::className(), $val); + $this->assertSame(array('a', 'b'), $val->on); + $this->assertSame(array('attr_test1', 'attr_test2'), $val->attributes); + $val = TestValidator::createValidator( + 'boolean', + $model, + 'attr_test1, attr_test2', + array('on' => 'a, b', 'except' => 'c,d,e') + ); + $this->assertInstanceOf(BooleanValidator::className(), $val); + $this->assertSame(array('a', 'b'), $val->on); + $this->assertSame(array('c', 'd', 'e'), $val->except); + $val = TestValidator::createValidator('inlineVal', $model, 'val_attr_a'); + $this->assertInstanceOf(InlineValidator::className(), $val); + $this->assertSame('inlineVal', $val->method); + } + + public function testValidate() + { + $val = new TestValidator(array('attributes' => array('attr_runMe1', 'attr_runMe2'))); + $model = $this->getTestModel(); + $val->validate($model); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertTrue($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + } + + public function testValidateWithAttributeIntersect() + { + $val = new TestValidator(array('attributes' => array('attr_runMe1', 'attr_runMe2'))); + $model = $this->getTestModel(); + $val->validate($model, array('attr_runMe1')); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertFalse($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + } + + public function testValidateWithEmptyAttributes() + { + $val = new TestValidator(); + $model = $this->getTestModel(); + $val->validate($model, array('attr_runMe1')); + $this->assertFalse($val->isAttributeValidated('attr_runMe1')); + $this->assertFalse($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + $val->validate($model); + $this->assertFalse($val->isAttributeValidated('attr_runMe1')); + $this->assertFalse($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + } + + public function testValidateWithError() + { + $val = new TestValidator(array('attributes' => array('attr_runMe1', 'attr_runMe2'), 'skipOnError' => false)); + $model = $this->getTestModel(); + $val->validate($model); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertTrue($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe2')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); + $val->validate($model, array('attr_runMe2')); + $this->assertEquals(2, $val->countAttributeValidations('attr_runMe2')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); + $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); + $val = new TestValidator(array('attributes' => array('attr_runMe1', 'attr_runMe2'), 'skipOnError' => true)); + $model = $this->getTestModel(); + $val->enableErrorOnValidateAttribute(); + $val->validate($model); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertTrue($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); + $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); + $val->validate($model, array('attr_runMe2')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe2')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); + $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); + } + + public function testValidateWithEmpty() + { + $val = new TestValidator(array( + 'attributes' => array( + 'attr_runMe1', + 'attr_runMe2', + 'attr_empty1', + 'attr_empty2' + ), + 'skipOnEmpty' => true, + )); + $model = $this->getTestModel(array('attr_empty1' => '', 'attr_emtpy2' => ' ')); + $val->validate($model); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertTrue($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_empty1')); + $this->assertFalse($val->isAttributeValidated('attr_empty2')); + $model->attr_empty1 = 'not empty anymore'; + $val->validate($model); + $this->assertTrue($val->isAttributeValidated('attr_empty1')); + $this->assertFalse($val->isAttributeValidated('attr_empty2')); + $val = new TestValidator(array( + 'attributes' => array( + 'attr_runMe1', + 'attr_runMe2', + 'attr_empty1', + 'attr_empty2' + ), + 'skipOnEmpty' => false, + )); + $model = $this->getTestModel(array('attr_empty1' => '', 'attr_emtpy2' => ' ')); + $val->validate($model); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertTrue($val->isAttributeValidated('attr_runMe2')); + $this->assertTrue($val->isAttributeValidated('attr_empty1')); + $this->assertTrue($val->isAttributeValidated('attr_empty2')); + } + + public function testIsEmpty() + { + $val = new TestValidator(); + $this->assertTrue($val->isEmpty(null)); + $this->assertTrue($val->isEmpty(array())); + $this->assertTrue($val->isEmpty('')); + $this->assertFalse($val->isEmpty(5)); + $this->assertFalse($val->isEmpty(0)); + $this->assertFalse($val->isEmpty(new \stdClass())); + $this->assertFalse($val->isEmpty(' ')); + // trim + $this->assertTrue($val->isEmpty(' ', true)); + $this->assertTrue($val->isEmpty('', true)); + $this->assertTrue($val->isEmpty(" \t\n\r\0\x0B", true)); + $this->assertTrue($val->isEmpty('', true)); + $this->assertFalse($val->isEmpty('0', true)); + $this->assertFalse($val->isEmpty(0, true)); + $this->assertFalse($val->isEmpty('this ain\'t an empty value', true)); + } + + public function testValidateValue() + { + $this->setExpectedException( + 'yii\base\NotSupportedException', + TestValidator::className() . ' does not support validateValue().' + ); + $val = new TestValidator(); + $val->validateValue('abc'); + } + + public function testClientValidateAttribute() + { + $val = new TestValidator(); + $this->assertNull( + $val->clientValidateAttribute($this->getTestModel(), 'attr_runMe1', array()) + ); //todo pass a view instead of array + } + + public function testIsActive() + { + $val = new TestValidator(); + $this->assertTrue($val->isActive('scenA')); + $this->assertTrue($val->isActive('scenB')); + $val->except = array('scenB'); + $this->assertTrue($val->isActive('scenA')); + $this->assertFalse($val->isActive('scenB')); + $val->on = array('scenC'); + $this->assertFalse($val->isActive('scenA')); + $this->assertFalse($val->isActive('scenB')); + $this->assertTrue($val->isActive('scenC')); + } + + public function testAddError() + { + $val = new TestValidator(); + $m = $this->getTestModel(array('attr_msg_val' => 'abc')); + $val->addError($m, 'attr_msg_val', '{attribute}::{value}'); + $errors = $m->getErrors('attr_msg_val'); + $this->assertEquals('attr_msg_val::abc', $errors[0]); + $m = $this->getTestModel(array('attr_msg_val' => array('bcc'))); + $val->addError($m, 'attr_msg_val', '{attribute}::{value}'); + $errors = $m->getErrors('attr_msg_val'); + $this->assertEquals('attr_msg_val::array()', $errors[0]); + $m = $this->getTestModel(array('attr_msg_val' => 'abc')); + $val->addError($m, 'attr_msg_val', '{attribute}::{value}::{param}', array('{param}' => 'param_value')); + $errors = $m->getErrors('attr_msg_val'); + $this->assertEquals('attr_msg_val::abc::param_value', $errors[0]); + } +} \ No newline at end of file From 8e48f01c85517edca2951d7b413ca291313b6cc3 Mon Sep 17 00:00:00 2001 From: Suralc Date: Wed, 14 Aug 2013 21:20:20 +0200 Subject: [PATCH 015/103] Add RegularExpressionValidatorTest --- .../validators/RegularExpressionValidatorTest.php | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/unit/framework/validators/RegularExpressionValidatorTest.php diff --git a/tests/unit/framework/validators/RegularExpressionValidatorTest.php b/tests/unit/framework/validators/RegularExpressionValidatorTest.php new file mode 100644 index 0000000..fc89139 --- /dev/null +++ b/tests/unit/framework/validators/RegularExpressionValidatorTest.php @@ -0,0 +1,48 @@ + '/^[a-zA-Z0-9](\.)?([^\/]*)$/m')); + $this->assertTrue($val->validateValue('b.4')); + $this->assertFalse($val->validateValue('b./')); + $this->assertFalse($val->validateValue(array('a', 'b'))); + $val->not = true; + $this->assertFalse($val->validateValue('b.4')); + $this->assertTrue($val->validateValue('b./')); + $this->assertFalse($val->validateValue(array('a', 'b'))); + } + + public function testValidateAttribute() + { + $val = new RegularExpressionValidator(array('pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m')); + $m = FakedValidationModel::createWithAttributes(array('attr_reg1' => 'b.4')); + $val->validateAttribute($m, 'attr_reg1'); + $this->assertFalse($m->hasErrors('attr_reg1')); + $m->attr_reg1 = 'b./'; + $val->validateAttribute($m, 'attr_reg1'); + $this->assertTrue($m->hasErrors('attr_reg1')); + } + + public function testMessageSetOnInit() + { + $val = new RegularExpressionValidator(array('pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m')); + $this->assertTrue(is_string($val->message)); + } + + public function testInitException() + { + $this->setExpectedException('yii\base\InvalidConfigException'); + $val = new RegularExpressionValidator(); + $val->validateValue('abc'); + } + +} \ No newline at end of file From 5c8927af7d0e2d2748cbfba0b384257cf8299d19 Mon Sep 17 00:00:00 2001 From: Suralc Date: Sat, 17 Aug 2013 00:27:57 +0200 Subject: [PATCH 016/103] Added ExistValidatorTest and added new option to DatabaseTestCase --- tests/unit/data/mysql.sql | 32 ++++++++ tests/unit/data/postgres.sql | 29 +++++++ tests/unit/data/sqlite.sql | 33 +++++++- .../validators/models/ExistValidatorMainModel.php | 20 +++++ .../validators/models/ExistValidatorRefModel.php | 22 +++++ tests/unit/framework/db/DatabaseTestCase.php | 6 +- .../ExistValidatorPostgresTest.php | 10 +++ .../ExistValidatorSQliteTest.php | 10 +++ .../framework/validators/ExistValidatorTest.php | 94 ++++++++++++++++++++++ 9 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 tests/unit/data/validators/models/ExistValidatorMainModel.php create mode 100644 tests/unit/data/validators/models/ExistValidatorRefModel.php create mode 100644 tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php create mode 100644 tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorSQliteTest.php create mode 100644 tests/unit/framework/validators/ExistValidatorTest.php diff --git a/tests/unit/data/mysql.sql b/tests/unit/data/mysql.sql index 2e9458e..9a31083 100644 --- a/tests/unit/data/mysql.sql +++ b/tests/unit/data/mysql.sql @@ -100,3 +100,35 @@ INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 4, INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); + + +/** + * (MySQL-)Database Schema for ExistValidatorTest + */ + +DROP TABLE IF EXISTS tbl_validator_exist_main CASCADE; +DROP TABLE IF EXISTS tbl_validator_exist_ref CASCADE; + +CREATE TABLE `tbl_validator_exist_main` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `field1` VARCHAR(255), + PRIMARY KEY (`id`) +) ENGINE =InnoDB DEFAULT CHARSET =utf8; + +CREATE TABLE `tbl_validator_exist_ref` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `a_field` VARCHAR(255), + `ref` INT(11), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (1, 'just a string1'); +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (2, 'just a string2'); +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (3, 'just a string3'); +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (4, 'just a string4'); +INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_2', 2); +INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_2', 2); +INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_3', 3); +INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_4', 4); +INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_4', 4); +INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_5', 5); diff --git a/tests/unit/data/postgres.sql b/tests/unit/data/postgres.sql index f8fb0eb..fc306da 100644 --- a/tests/unit/data/postgres.sql +++ b/tests/unit/data/postgres.sql @@ -92,3 +92,32 @@ INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 4, INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); + +/** + * (Postgres-)Database Schema for ExistValidatorTest + */ + +DROP TABLE IF EXISTS tbl_validator_exist_main CASCADE; +DROP TABLE IF EXISTS tbl_validator_exist_ref CASCADE; + +CREATE TABLE tbl_validator_exist_main ( + id integer not null primary key, + field1 VARCHAR(255) +); + +CREATE TABLE tbl_validator_exist_ref ( + id integer not null primary key, + a_field VARCHAR(255), + ref integer +); + +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (1, 'just a string1'); +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (2, 'just a string2'); +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (3, 'just a string3'); +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (4, 'just a string4'); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (1, 'ref_to_2', 2); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (2, 'ref_to_2', 2); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (3, 'ref_to_3', 3); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (4, 'ref_to_4', 4); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (5, 'ref_to_4', 4); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (6, 'ref_to_5', 5); \ No newline at end of file diff --git a/tests/unit/data/sqlite.sql b/tests/unit/data/sqlite.sql index f75bfa6..c1111da 100644 --- a/tests/unit/data/sqlite.sql +++ b/tests/unit/data/sqlite.sql @@ -85,4 +85,35 @@ INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 2, INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); -INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); \ No newline at end of file +INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); + +/** + * (SqLite-)Database Schema for ExistValidatorTest + */ + +DROP TABLE IF EXISTS tbl_validator_exist_main; +DROP TABLE IF EXISTS tbl_validator_exist_ref; + +CREATE TABLE tbl_validator_exist_main ( + id INT(11) NOT NULL, + field1 VARCHAR(255), + PRIMARY KEY (id) +); + +CREATE TABLE tbl_validator_exist_ref ( + id INT(11) NOT NULL, + a_field VARCHAR(255), + ref INT(11), + PRIMARY KEY (id) +); + +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (1, 'just a string1'); +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (2, 'just a string2'); +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (3, 'just a string3'); +INSERT INTO tbl_validator_exist_main (id, field1) VALUES (4, 'just a string4'); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (1, 'ref_to_2', 2); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (2, 'ref_to_2', 2); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (3, 'ref_to_3', 3); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (4, 'ref_to_4', 4); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (5, 'ref_to_4', 4); +INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (6, 'ref_to_5', 5); \ No newline at end of file diff --git a/tests/unit/data/validators/models/ExistValidatorMainModel.php b/tests/unit/data/validators/models/ExistValidatorMainModel.php new file mode 100644 index 0000000..5f3ff00 --- /dev/null +++ b/tests/unit/data/validators/models/ExistValidatorMainModel.php @@ -0,0 +1,20 @@ +hasMany(ExistValidatorRefModel::className(), array('ref' => 'id')); + } +} \ No newline at end of file diff --git a/tests/unit/data/validators/models/ExistValidatorRefModel.php b/tests/unit/data/validators/models/ExistValidatorRefModel.php new file mode 100644 index 0000000..6cafa39 --- /dev/null +++ b/tests/unit/data/validators/models/ExistValidatorRefModel.php @@ -0,0 +1,22 @@ +hasOne(ExistValidatorMainModel::className(), array('id' => 'ref')); + } +} \ No newline at end of file diff --git a/tests/unit/framework/db/DatabaseTestCase.php b/tests/unit/framework/db/DatabaseTestCase.php index 1fd2d56..c3d4206 100644 --- a/tests/unit/framework/db/DatabaseTestCase.php +++ b/tests/unit/framework/db/DatabaseTestCase.php @@ -8,6 +8,7 @@ abstract class DatabaseTestCase extends TestCase protected $database; protected $driverName = 'mysql'; protected $db; + protected $initializeAppWithDb = false; protected function setUp() { @@ -18,7 +19,10 @@ abstract class DatabaseTestCase extends TestCase $pdo_database = 'pdo_'.$this->driverName; if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) { - $this->markTestSkipped('pdo and pdo_'.$pdo_database.' extension are required.'); + $this->markTestSkipped('pdo and '.$pdo_database.' extension are required.'); + } + if ($this->initializeAppWithDb === true) { + \Yii::$app->setComponent('db', $this->getConnection()); } } diff --git a/tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php b/tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php new file mode 100644 index 0000000..539b458 --- /dev/null +++ b/tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php @@ -0,0 +1,10 @@ +getComponent('db'); + } + + public function tearDown() + { + parent::tearDown(); + } + + public function testValidateValueExpectedException() + { + try { + $val = new ExistValidator(); + $result = $val->validateValue('ref'); + $this->fail('Exception should have been thrown at this time'); + } catch (Exception $e) { + $this->assertInstanceOf('yii\base\InvalidConfigException', $e); + $this->assertEquals('The "className" property must be set.', $e->getMessage()); + } + // combine to save the time creating a new db-fixture set (likely ~5 sec) + try { + $val = new ExistValidator(array('className' => ExistValidatorMainModel::className())); + $val->validateValue('ref'); + $this->fail('Exception should have been thrown at this time'); + } catch (Exception $e) { + $this->assertInstanceOf('yii\base\InvalidConfigException', $e); + $this->assertEquals('The "attributeName" property must be set.', $e->getMessage()); + } + } + + public function testValidateValue() + { + $val = new ExistValidator(array('className' => ExistValidatorRefModel::className(), 'attributeName' => 'id')); + $this->assertTrue($val->validateValue(2)); + $this->assertTrue($val->validateValue(5)); + $this->assertFalse($val->validateValue(99)); + $this->assertFalse($val->validateValue(array('1'))); + } + + public function testValidateAttribute() + { + // existing value on different table + $val = new ExistValidator(array('className' => ExistValidatorMainModel::className(), 'attributeName' => 'id')); + $m = ExistValidatorRefModel::find(array('id' => 1)); + $val->validateAttribute($m, 'ref'); + $this->assertFalse($m->hasErrors()); + // non-existing value on different table + $val = new ExistValidator(array('className' => ExistValidatorMainModel::className(), 'attributeName' => 'id')); + $m = ExistValidatorRefModel::find(array('id' => 6)); + $val->validateAttribute($m, 'ref'); + $this->assertTrue($m->hasErrors('ref')); + // existing value on same table + $val = new ExistValidator(array('attributeName' => 'ref')); + $m = ExistValidatorRefModel::find(array('id' => 2)); + $val->validateAttribute($m, 'test_val'); + $this->assertFalse($m->hasErrors()); + // non-existing value on same table + $val = new ExistValidator(array('attributeName' => 'ref')); + $m = ExistValidatorRefModel::find(array('id' => 5)); + $val->validateAttribute($m, 'test_val_fail'); + $this->assertTrue($m->hasErrors('test_val_fail')); + // check for given value (true) + $val = new ExistValidator(); + $m = ExistValidatorRefModel::find(array('id' => 3)); + $val->validateAttribute($m, 'ref'); + $this->assertFalse($m->hasErrors()); + // check for given defaults (false) + $val = new ExistValidator(); + $m = ExistValidatorRefModel::find(array('id' => 4)); + $m->a_field = 'some new value'; + $val->validateAttribute($m, 'a_field'); + $this->assertTrue($m->hasErrors('a_field')); + } +} \ No newline at end of file From 0c45765e7d53bdb18e5f90aa6cb441329474bfb1 Mon Sep 17 00:00:00 2001 From: Suralc Date: Sun, 18 Aug 2013 14:39:22 +0200 Subject: [PATCH 017/103] Added tests for uncovered lines. --- tests/unit/framework/validators/DateValidatorTest.php | 5 ++++- tests/unit/framework/validators/ExistValidatorTest.php | 6 ++++++ tests/unit/framework/validators/NumberValidatorTest.php | 4 ++++ tests/unit/framework/validators/StringValidatorTest.php | 4 ++++ tests/unit/framework/validators/UrlValidatorTest.php | 6 ++++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/unit/framework/validators/DateValidatorTest.php b/tests/unit/framework/validators/DateValidatorTest.php index 30a515e..a551889 100644 --- a/tests/unit/framework/validators/DateValidatorTest.php +++ b/tests/unit/framework/validators/DateValidatorTest.php @@ -55,7 +55,10 @@ class DateValidatorTest extends TestCase DateTime::createFromFormat($val->format, '2013-09-13')->getTimestamp(), $model->attr_timestamp ); - + $val = new DateValidator(); + $model = FakedValidationModel::createWithAttributes(array('attr_date' => array())); + $val->validateAttribute($model, 'attr_date'); + $this->assertTrue($model->hasErrors('attr_date')); } } \ No newline at end of file diff --git a/tests/unit/framework/validators/ExistValidatorTest.php b/tests/unit/framework/validators/ExistValidatorTest.php index 6a1e5fe..930712c 100644 --- a/tests/unit/framework/validators/ExistValidatorTest.php +++ b/tests/unit/framework/validators/ExistValidatorTest.php @@ -90,5 +90,11 @@ class ExistValidatorTest extends DatabaseTestCase $m->a_field = 'some new value'; $val->validateAttribute($m, 'a_field'); $this->assertTrue($m->hasErrors('a_field')); + // check array + $val = new ExistValidator(array('attributeName' => 'ref')); + $m = ExistValidatorRefModel::find(array('id' => 2)); + $m->test_val = array(1,2,3); + $val->validateAttribute($m, 'test_val'); + $this->assertTrue($m->hasErrors('test_val')); } } \ No newline at end of file diff --git a/tests/unit/framework/validators/NumberValidatorTest.php b/tests/unit/framework/validators/NumberValidatorTest.php index 4868503..fa158d3 100644 --- a/tests/unit/framework/validators/NumberValidatorTest.php +++ b/tests/unit/framework/validators/NumberValidatorTest.php @@ -137,6 +137,10 @@ class NumberValidatorTest extends TestCase $model->attr_number = 3.43; $val->validateAttribute($model, 'attr_number'); $this->assertTrue($model->hasErrors('attr_number')); + $val = new NumberValidator(array('min' => 1)); + $model = FakedValidationModel::createWithAttributes(array('attr_num' => array(1,2,3))); + $val->validateAttribute($model, 'attr_num'); + $this->assertTrue($model->hasErrors('attr_num')); } public function testEnsureCustomMessageIsSetOnValidateAttribute() diff --git a/tests/unit/framework/validators/StringValidatorTest.php b/tests/unit/framework/validators/StringValidatorTest.php index c7d2889..8beaf16 100644 --- a/tests/unit/framework/validators/StringValidatorTest.php +++ b/tests/unit/framework/validators/StringValidatorTest.php @@ -86,6 +86,10 @@ class StringValidatorTest extends TestCase $model->attr_string = 'abc'; $val->validateAttribute($model, 'attr_string'); $this->assertTrue($model->hasErrors('attr_string')); + $val = new StringValidator(array('max' => 1)); + $model = FakedValidationModel::createWithAttributes(array('attr_str' => array('abc'))); + $val->validateAttribute($model, 'attr_str'); + $this->assertTrue($model->hasErrors('attr_str')); } public function testEnsureMessagesOnInit() diff --git a/tests/unit/framework/validators/UrlValidatorTest.php b/tests/unit/framework/validators/UrlValidatorTest.php index 7b618c1..239c92b 100644 --- a/tests/unit/framework/validators/UrlValidatorTest.php +++ b/tests/unit/framework/validators/UrlValidatorTest.php @@ -29,6 +29,12 @@ class UrlValidatorTest extends TestCase $this->assertTrue($val->validateValue('yiiframework.com')); $this->assertTrue($val->validateValue('http://yiiframework.com')); } + + public function testValidateValueWithoutScheme() + { + $val = new UrlValidator(array('pattern' => '/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)/i')); + $this->assertTrue($val->validateValue('yiiframework.com')); + } public function testValidateWithCustomScheme() { From 3469b2cb60aa08093ef6fc2041e1583fc6df44b5 Mon Sep 17 00:00:00 2001 From: Suralc Date: Thu, 22 Aug 2013 16:12:09 +0200 Subject: [PATCH 018/103] RangeValidator tests. --- .../framework/validators/RangeValidatorTest.php | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 tests/unit/framework/validators/RangeValidatorTest.php diff --git a/tests/unit/framework/validators/RangeValidatorTest.php b/tests/unit/framework/validators/RangeValidatorTest.php new file mode 100644 index 0000000..a22d190 --- /dev/null +++ b/tests/unit/framework/validators/RangeValidatorTest.php @@ -0,0 +1,70 @@ +setExpectedException('yii\base\InvalidConfigException', 'The "range" property must be set.'); + $val = new RangeValidator(array('range' => 'not an array')); + } + + public function testAssureMessageSetOnInit() + { + $val = new RangeValidator(array('range' => array())); + $this->assertTrue(is_string($val->message)); + } + + public function testValidateValue() + { + $val = new RangeValidator(array('range' => range(1, 10, 1))); + $this->assertTrue($val->validateValue(1)); + $this->assertFalse($val->validateValue(0)); + $this->assertFalse($val->validateValue(11)); + $this->assertFalse($val->validateValue(5.5)); + $this->assertTrue($val->validateValue(10)); + $this->assertTrue($val->validateValue("10")); + $this->assertTrue($val->validateValue("5")); + } + + public function testValidateValueStrict() + { + $val = new RangeValidator(array('range' => range(1, 10, 1), 'strict' => true)); + $this->assertTrue($val->validateValue(1)); + $this->assertTrue($val->validateValue(5)); + $this->assertTrue($val->validateValue(10)); + $this->assertFalse($val->validateValue("1")); + $this->assertFalse($val->validateValue("10")); + $this->assertFalse($val->validateValue("5.5")); + } + + public function testValidateValueNot() + { + $val = new RangeValidator(array('range' => range(1, 10, 1), 'not' => true)); + $this->assertFalse($val->validateValue(1)); + $this->assertTrue($val->validateValue(0)); + $this->assertTrue($val->validateValue(11)); + $this->assertTrue($val->validateValue(5.5)); + $this->assertFalse($val->validateValue(10)); + $this->assertFalse($val->validateValue("10")); + $this->assertFalse($val->validateValue("5")); + } + + public function testValidateAttribute() + { + $val = new RangeValidator(array('range' => range(1, 10, 1))); + $m = FakedValidationModel::createWithAttributes(array('attr_r1' => 5, 'attr_r2' => 999)); + $val->validateAttribute($m, 'attr_r1'); + $this->assertFalse($m->hasErrors()); + $val->validateAttribute($m, 'attr_r2'); + $this->assertTrue($m->hasErrors('attr_r2')); + $err = $m->getErrors('attr_r2'); + $this->assertTrue(stripos($err[0], 'attr_r2') !== false); + } +} \ No newline at end of file From 3b07e4affcb13c12cf04bb4924a769b324925829 Mon Sep 17 00:00:00 2001 From: Suralc Date: Fri, 23 Aug 2013 17:24:56 +0200 Subject: [PATCH 019/103] Added FileValidator tests. --- .../framework/validators/FileValidatorTest.php | 275 +++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 tests/unit/framework/validators/FileValidatorTest.php diff --git a/tests/unit/framework/validators/FileValidatorTest.php b/tests/unit/framework/validators/FileValidatorTest.php new file mode 100644 index 0000000..820afb5 --- /dev/null +++ b/tests/unit/framework/validators/FileValidatorTest.php @@ -0,0 +1,275 @@ +mockApplication(); + } + + public function testAssureMessagesSetOnInit() + { + $val = new FileValidator(); + foreach (array('message', 'uploadRequired', 'tooMany', 'wrongType', 'tooBig', 'tooSmall') as $attr) { + $this->assertTrue(is_string($val->$attr)); + } + } + + public function testTypeSplitOnInit() + { + $val = new FileValidator(array('types' => 'jpeg, jpg, gif')); + $this->assertEquals(array('jpeg', 'jpg', 'gif'), $val->types); + $val = new FileValidator(array('types' => 'jpeg')); + $this->assertEquals(array('jpeg'), $val->types); + $val = new FileValidator(array('types' => '')); + $this->assertEquals(array(), $val->types); + $val = new FileValidator(array('types' => array())); + $this->assertEquals(array(), $val->types); + $val = new FileValidator(); + $this->assertEquals(array(), $val->types); + $val = new FileValidator(array('types' => array('jpeg', 'exe'))); + $this->assertEquals(array('jpeg', 'exe'), $val->types); + } + + public function testGetSizeLimit() + { + $size = $this->sizeToBytes(ini_get('upload_max_filesize')); + $val = new FileValidator(); + $this->assertEquals($size, $val->getSizeLimit()); + $val->maxSize = $size + 1; // set and test if value is overridden + $this->assertEquals($size, $val->getSizeLimit()); + $val->maxSize = abs($size - 1); + $this->assertEquals($size - 1, $val->getSizeLimit()); + $_POST['MAX_FILE_SIZE'] = $size + 1; + $this->assertEquals($size - 1, $val->getSizeLimit()); + $_POST['MAX_FILE_SIZE'] = abs($size - 2); + $this->assertSame($_POST['MAX_FILE_SIZE'], $val->getSizeLimit()); + } + + protected function sizeToBytes($sizeStr) + { + switch (substr($sizeStr, -1)) { + case 'M': + case 'm': + return (int)$sizeStr * 1048576; + case 'K': + case 'k': + return (int)$sizeStr * 1024; + case 'G': + case 'g': + return (int)$sizeStr * 1073741824; + default: + return (int)$sizeStr; + } + } + + public function testValidateAttributeMultiple() + { + $val = new FileValidator(array('maxFiles' => 2)); + $m = FakedValidationModel::createWithAttributes(array('attr_files' => 'path')); + $val->validateAttribute($m, 'attr_files'); + $this->assertTrue($m->hasErrors('attr_files')); + $m = FakedValidationModel::createWithAttributes(array('attr_files' => array())); + $val->validateAttribute($m, 'attr_files'); + $this->assertTrue($m->hasErrors('attr_files')); + $this->assertSame($val->uploadRequired, current($m->getErrors('attr_files'))); + $m = FakedValidationModel::createWithAttributes( + array( + 'attr_files' => $this->createTestFiles( + array( + array( + 'name' => 'test_up_1.txt', + 'size' => 1024, + ), + array( + 'error' => UPLOAD_ERR_NO_FILE, + ), + ) + ) + ) + ); + $val->validateAttribute($m, 'attr_files'); + $this->assertFalse($m->hasErrors('attr_files')); + $m = FakedValidationModel::createWithAttributes( + array('attr_files' => $this->createTestFiles(array(array(''), array(''), array(''),))) + ); + $val->validateAttribute($m, 'attr_files'); + $this->assertTrue($m->hasErrors()); + $this->assertTrue(stripos(current($m->getErrors('attr_files')), 'you can upload at most') !== false); + } + + /** + * @param array $params + * @return UploadedFile[] + */ + protected function createTestFiles($params = array()) + { + $rndString = function ($len = 10) { + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $randomString = ''; + for ($i = 0; $i < $len; $i++) { + $randomString .= $characters[rand(0, strlen($characters) - 1)]; + } + return $randomString; + }; + $files = array(); + foreach ($params as $param) { + if (empty($param) && count($params) != 1) { + $files[] = array('no instance of UploadedFile'); + continue; + } + $name = isset($param['name']) ? $param['name'] : $rndString(); + $tempName = \Yii::getAlias('@yiiunit/runtime/validators/file/tmp') . $name; + if (is_readable($tempName)) { + $size = filesize($tempName); + } else { + $size = isset($param['size']) ? $param['size'] : rand( + 1, + $this->sizeToBytes(ini_get('upload_max_filesize')) + ); + } + $type = isset($param['type']) ? $param['type'] : 'text/plain'; + $error = isset($param['error']) ? $param['error'] : UPLOAD_ERR_OK; + if (count($params) == 1) { + $error = empty($param) ? UPLOAD_ERR_NO_FILE : $error; + return new UploadedFile($name, $tempName, $type, $size, $error); + } + $files[] = new UploadedFile($name, $tempName, $type, $size, $error); + } + return $files; + } + + public function testValidateAttribute() + { + // single File + $val = new FileValidator(); + $m = $this->createModelForAttributeTest(); + $val->validateAttribute($m, 'attr_files'); + $this->assertFalse($m->hasErrors()); + $val->validateAttribute($m, 'attr_files_empty'); + $this->assertTrue($m->hasErrors('attr_files_empty')); + $this->assertSame($val->uploadRequired, current($m->getErrors('attr_files_empty'))); + $m = $this->createModelForAttributeTest(); + // too big + $val = new FileValidator(array('maxSize' => 128)); + $val->validateAttribute($m, 'attr_files'); + $this->assertTrue($m->hasErrors('attr_files')); + $this->assertTrue( + stripos( + current($m->getErrors('attr_files')), + str_ireplace(array('{file}', '{limit}'), array($m->attr_files->getName(), 128), $val->tooBig) + ) !== false + ); + // to Small + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(array('minSize' => 2048)); + $val->validateAttribute($m, 'attr_files'); + $this->assertTrue($m->hasErrors('attr_files')); + $this->assertTrue( + stripos( + current($m->getErrors('attr_files')), + str_ireplace(array('{file}', '{limit}'), array($m->attr_files->getName(), 2048), $val->tooSmall) + ) !== false + ); + // UPLOAD_ERR_INI_SIZE/UPLOAD_ERR_FORM_SIZE + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_ini'); + $this->assertTrue($m->hasErrors('attr_err_ini')); + $this->assertTrue( + stripos( + current($m->getErrors('attr_err_ini')), + str_ireplace( + array('{file}', '{limit}'), + array($m->attr_err_ini->getName(), $val->getSizeLimit()), + $val->tooBig + ) + ) !== false + ); + // UPLOAD_ERR_PARTIAL + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_part'); + $this->assertTrue($m->hasErrors('attr_err_part')); + $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_part'))); + $log = Yii::$app->getLog()->toArray(); + $this->assertSame(FileValidator::className() . '::validateFile', $log['messages'][0][2]); + } + + protected function createModelForAttributeTest() + { + return FakedValidationModel::createWithAttributes( + array( + 'attr_files' => $this->createTestFiles( + array( + array('name' => 'abc.jpg', 'size' => 1024, 'type' => 'image/jpeg'), + ) + ), + 'attr_files_empty' => $this->createTestFiles(array(array())), + 'attr_err_ini' => $this->createTestFiles(array(array('error' => UPLOAD_ERR_INI_SIZE))), + 'attr_err_part' => $this->createTestFiles(array(array('error' => UPLOAD_ERR_PARTIAL))), + 'attr_err_tmp' => $this->createTestFiles(array(array('error' => UPLOAD_ERR_NO_TMP_DIR))), + 'attr_err_write' => $this->createTestFiles(array(array('error' => UPLOAD_ERR_CANT_WRITE))), + 'attr_err_ext' => $this->createTestFiles(array(array('error' => UPLOAD_ERR_EXTENSION))), + + ) + ); + } + + public function testValidateAttributeErrPartial() + { + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_part'); + $this->assertTrue($m->hasErrors('attr_err_part')); + $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_part'))); + $log = Yii::$app->getLog()->toArray(); + $this->assertSame(FileValidator::className() . '::validateFile', $log['messages'][0][2]); + $this->assertContains('File was only', $log['messages'][0][0]); + } + + public function testValidateAttributeErrCantWrite() + { + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_write'); + $this->assertTrue($m->hasErrors('attr_err_write')); + $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_write'))); + $log = Yii::$app->getLog()->toArray(); + $this->assertSame(FileValidator::className() . '::validateFile', $log['messages'][0][2]); + $this->assertContains('Failed to write', $log['messages'][0][0]); + } + + public function testValidateAttributeErrExtension() + { + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_ext'); + $this->assertTrue($m->hasErrors('attr_err_ext')); + $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_ext'))); + $log = Yii::$app->getLog()->toArray(); + $this->assertSame(FileValidator::className() . '::validateFile', $log['messages'][0][2]); + $this->assertContains('PHP extension', $log['messages'][0][0]); + } + + public function testValidateAttributeErrNoTmpDir() + { + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_tmp'); + $this->assertTrue($m->hasErrors('attr_err_tmp')); + $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_tmp'))); + $log = Yii::$app->getLog()->toArray(); + $this->assertSame(FileValidator::className() . '::validateFile', $log['messages'][0][2]); + $this->assertContains('Missing the temporary folder', $log['messages'][0][0]); + } +} \ No newline at end of file From 7d5bb082ac32a0e3bf2df1a3a4fd52f85f264128 Mon Sep 17 00:00:00 2001 From: Suralc Date: Fri, 23 Aug 2013 22:33:39 +0200 Subject: [PATCH 020/103] FilterValidator test --- .../framework/validators/FilterValidatorTest.php | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/unit/framework/validators/FilterValidatorTest.php diff --git a/tests/unit/framework/validators/FilterValidatorTest.php b/tests/unit/framework/validators/FilterValidatorTest.php new file mode 100644 index 0000000..322f921 --- /dev/null +++ b/tests/unit/framework/validators/FilterValidatorTest.php @@ -0,0 +1,46 @@ +setExpectedException('yii\base\InvalidConfigException'); + $val = new FilterValidator(); + } + + public function testValidateAttribute() + { + $m = FakedValidationModel::createWithAttributes(array( + 'attr_one' => ' to be trimmed ', + 'attr_two' => 'set this to null', + 'attr_empty1' => '', + 'attr_empty2' => null + )); + $val = new FilterValidator(array('filter' => 'trim')); + $val->validateAttribute($m, 'attr_one'); + $this->assertSame('to be trimmed', $m->attr_one); + $val->filter = function ($value) { + return null; + }; + $val->validateAttribute($m, 'attr_two'); + $this->assertNull($m->attr_two); + $val->filter = array($this, 'notToBeNull'); + $val->validateAttribute($m, 'attr_empty1'); + $this->assertSame($this->notToBeNull(''), $m->attr_empty1); + $val->skipOnEmpty = true; + $val->validateAttribute($m, 'attr_empty2'); + $this->assertNotNull($m->attr_empty2); + } + + public function notToBeNull($value) + { + return 'not null'; + } +} \ No newline at end of file From 24e2f885037bca1de58cdf0b6e67e72966c6cbf3 Mon Sep 17 00:00:00 2001 From: Suralc Date: Fri, 23 Aug 2013 22:47:45 +0200 Subject: [PATCH 021/103] Renamed validator test models to be less specific. --- tests/unit/data/mysql.sql | 30 +++++++++++----------- tests/unit/data/postgres.sql | 30 +++++++++++----------- tests/unit/data/sqlite.sql | 30 +++++++++++----------- .../validators/models/ExistValidatorMainModel.php | 20 --------------- .../validators/models/ExistValidatorRefModel.php | 22 ---------------- .../validators/models/ValidatorTestMainModel.php | 21 +++++++++++++++ .../validators/models/ValidatorTestRefModel.php | 23 +++++++++++++++++ .../framework/validators/CompareValidatorTest.php | 5 ++++ .../framework/validators/ExistValidatorTest.php | 26 +++++++++---------- 9 files changed, 107 insertions(+), 100 deletions(-) delete mode 100644 tests/unit/data/validators/models/ExistValidatorMainModel.php delete mode 100644 tests/unit/data/validators/models/ExistValidatorRefModel.php create mode 100644 tests/unit/data/validators/models/ValidatorTestMainModel.php create mode 100644 tests/unit/data/validators/models/ValidatorTestRefModel.php diff --git a/tests/unit/data/mysql.sql b/tests/unit/data/mysql.sql index 9a31083..9ed0d90 100644 --- a/tests/unit/data/mysql.sql +++ b/tests/unit/data/mysql.sql @@ -103,32 +103,32 @@ INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, /** - * (MySQL-)Database Schema for ExistValidatorTest + * (MySQL-)Database Schema for validator tests */ -DROP TABLE IF EXISTS tbl_validator_exist_main CASCADE; -DROP TABLE IF EXISTS tbl_validator_exist_ref CASCADE; +DROP TABLE IF EXISTS tbl_validator_main CASCADE; +DROP TABLE IF EXISTS tbl_validator_ref CASCADE; -CREATE TABLE `tbl_validator_exist_main` ( +CREATE TABLE tbl_validator_main ( `id` INT(11) NOT NULL AUTO_INCREMENT, `field1` VARCHAR(255), PRIMARY KEY (`id`) ) ENGINE =InnoDB DEFAULT CHARSET =utf8; -CREATE TABLE `tbl_validator_exist_ref` ( +CREATE TABLE tbl_validator_ref ( `id` INT(11) NOT NULL AUTO_INCREMENT, `a_field` VARCHAR(255), `ref` INT(11), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (1, 'just a string1'); -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (2, 'just a string2'); -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (3, 'just a string3'); -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (4, 'just a string4'); -INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_2', 2); -INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_2', 2); -INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_3', 3); -INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_4', 4); -INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_4', 4); -INSERT INTO tbl_validator_exist_ref (a_field, ref) VALUES ('ref_to_5', 5); +INSERT INTO tbl_validator_main (id, field1) VALUES (1, 'just a string1'); +INSERT INTO tbl_validator_main (id, field1) VALUES (2, 'just a string2'); +INSERT INTO tbl_validator_main (id, field1) VALUES (3, 'just a string3'); +INSERT INTO tbl_validator_main (id, field1) VALUES (4, 'just a string4'); +INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_2', 2); +INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_2', 2); +INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_3', 3); +INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_4', 4); +INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_4', 4); +INSERT INTO tbl_validator_ref (a_field, ref) VALUES ('ref_to_5', 5); diff --git a/tests/unit/data/postgres.sql b/tests/unit/data/postgres.sql index fc306da..c2702c9 100644 --- a/tests/unit/data/postgres.sql +++ b/tests/unit/data/postgres.sql @@ -94,30 +94,30 @@ INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); /** - * (Postgres-)Database Schema for ExistValidatorTest + * (Postgres-)Database Schema for validator tests */ -DROP TABLE IF EXISTS tbl_validator_exist_main CASCADE; -DROP TABLE IF EXISTS tbl_validator_exist_ref CASCADE; +DROP TABLE IF EXISTS tbl_validator_main CASCADE; +DROP TABLE IF EXISTS tbl_validator_ref CASCADE; -CREATE TABLE tbl_validator_exist_main ( +CREATE TABLE tbl_validator_main ( id integer not null primary key, field1 VARCHAR(255) ); -CREATE TABLE tbl_validator_exist_ref ( +CREATE TABLE tbl_validator_ref ( id integer not null primary key, a_field VARCHAR(255), ref integer ); -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (1, 'just a string1'); -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (2, 'just a string2'); -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (3, 'just a string3'); -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (4, 'just a string4'); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (1, 'ref_to_2', 2); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (2, 'ref_to_2', 2); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (3, 'ref_to_3', 3); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (4, 'ref_to_4', 4); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (5, 'ref_to_4', 4); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (6, 'ref_to_5', 5); \ No newline at end of file +INSERT INTO tbl_validator_main (id, field1) VALUES (1, 'just a string1'); +INSERT INTO tbl_validator_main (id, field1) VALUES (2, 'just a string2'); +INSERT INTO tbl_validator_main (id, field1) VALUES (3, 'just a string3'); +INSERT INTO tbl_validator_main (id, field1) VALUES (4, 'just a string4'); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (1, 'ref_to_2', 2); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (2, 'ref_to_2', 2); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (3, 'ref_to_3', 3); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (4, 'ref_to_4', 4); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (5, 'ref_to_4', 4); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (6, 'ref_to_5', 5); \ No newline at end of file diff --git a/tests/unit/data/sqlite.sql b/tests/unit/data/sqlite.sql index c1111da..8976519 100644 --- a/tests/unit/data/sqlite.sql +++ b/tests/unit/data/sqlite.sql @@ -88,32 +88,32 @@ INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); /** - * (SqLite-)Database Schema for ExistValidatorTest + * (SqLite-)Database Schema for validator tests */ -DROP TABLE IF EXISTS tbl_validator_exist_main; -DROP TABLE IF EXISTS tbl_validator_exist_ref; +DROP TABLE IF EXISTS tbl_validator_main; +DROP TABLE IF EXISTS tbl_validator_ref; -CREATE TABLE tbl_validator_exist_main ( +CREATE TABLE tbl_validator_main ( id INT(11) NOT NULL, field1 VARCHAR(255), PRIMARY KEY (id) ); -CREATE TABLE tbl_validator_exist_ref ( +CREATE TABLE tbl_validator_ref ( id INT(11) NOT NULL, a_field VARCHAR(255), ref INT(11), PRIMARY KEY (id) ); -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (1, 'just a string1'); -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (2, 'just a string2'); -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (3, 'just a string3'); -INSERT INTO tbl_validator_exist_main (id, field1) VALUES (4, 'just a string4'); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (1, 'ref_to_2', 2); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (2, 'ref_to_2', 2); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (3, 'ref_to_3', 3); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (4, 'ref_to_4', 4); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (5, 'ref_to_4', 4); -INSERT INTO tbl_validator_exist_ref (id, a_field, ref) VALUES (6, 'ref_to_5', 5); \ No newline at end of file +INSERT INTO tbl_validator_main (id, field1) VALUES (1, 'just a string1'); +INSERT INTO tbl_validator_main (id, field1) VALUES (2, 'just a string2'); +INSERT INTO tbl_validator_main (id, field1) VALUES (3, 'just a string3'); +INSERT INTO tbl_validator_main (id, field1) VALUES (4, 'just a string4'); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (1, 'ref_to_2', 2); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (2, 'ref_to_2', 2); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (3, 'ref_to_3', 3); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (4, 'ref_to_4', 4); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (5, 'ref_to_4', 4); +INSERT INTO tbl_validator_ref (id, a_field, ref) VALUES (6, 'ref_to_5', 5); \ No newline at end of file diff --git a/tests/unit/data/validators/models/ExistValidatorMainModel.php b/tests/unit/data/validators/models/ExistValidatorMainModel.php deleted file mode 100644 index 5f3ff00..0000000 --- a/tests/unit/data/validators/models/ExistValidatorMainModel.php +++ /dev/null @@ -1,20 +0,0 @@ -hasMany(ExistValidatorRefModel::className(), array('ref' => 'id')); - } -} \ No newline at end of file diff --git a/tests/unit/data/validators/models/ExistValidatorRefModel.php b/tests/unit/data/validators/models/ExistValidatorRefModel.php deleted file mode 100644 index 6cafa39..0000000 --- a/tests/unit/data/validators/models/ExistValidatorRefModel.php +++ /dev/null @@ -1,22 +0,0 @@ -hasOne(ExistValidatorMainModel::className(), array('id' => 'ref')); - } -} \ No newline at end of file diff --git a/tests/unit/data/validators/models/ValidatorTestMainModel.php b/tests/unit/data/validators/models/ValidatorTestMainModel.php new file mode 100644 index 0000000..6f2808b --- /dev/null +++ b/tests/unit/data/validators/models/ValidatorTestMainModel.php @@ -0,0 +1,21 @@ +hasMany(ValidatorTestRefModel::className(), array('ref' => 'id')); + } +} \ No newline at end of file diff --git a/tests/unit/data/validators/models/ValidatorTestRefModel.php b/tests/unit/data/validators/models/ValidatorTestRefModel.php new file mode 100644 index 0000000..aa3d199 --- /dev/null +++ b/tests/unit/data/validators/models/ValidatorTestRefModel.php @@ -0,0 +1,23 @@ +hasOne(ValidatorTestMainModel::className(), array('id' => 'ref')); + } +} \ No newline at end of file diff --git a/tests/unit/framework/validators/CompareValidatorTest.php b/tests/unit/framework/validators/CompareValidatorTest.php index 7ae0263..46ab383 100644 --- a/tests/unit/framework/validators/CompareValidatorTest.php +++ b/tests/unit/framework/validators/CompareValidatorTest.php @@ -77,6 +77,11 @@ class CompareValidatorTest extends TestCase array($value + 1, false), array($value - 1, true), ), + //'non-op' => array( + // array($value, false), + // array($value + 1, false), + // array($value - 1, false), + //), ); } diff --git a/tests/unit/framework/validators/ExistValidatorTest.php b/tests/unit/framework/validators/ExistValidatorTest.php index 930712c..40d0935 100644 --- a/tests/unit/framework/validators/ExistValidatorTest.php +++ b/tests/unit/framework/validators/ExistValidatorTest.php @@ -7,8 +7,8 @@ use Yii; use yii\base\Exception; use yii\validators\ExistValidator; use yiiunit\data\ar\ActiveRecord; -use yiiunit\data\validators\models\ExistValidatorMainModel; -use yiiunit\data\validators\models\ExistValidatorRefModel; +use yiiunit\data\validators\models\ValidatorTestMainModel; +use yiiunit\data\validators\models\ValidatorTestRefModel; use yiiunit\framework\db\DatabaseTestCase; class ExistValidatorTest extends DatabaseTestCase @@ -39,7 +39,7 @@ class ExistValidatorTest extends DatabaseTestCase } // combine to save the time creating a new db-fixture set (likely ~5 sec) try { - $val = new ExistValidator(array('className' => ExistValidatorMainModel::className())); + $val = new ExistValidator(array('className' => ValidatorTestMainModel::className())); $val->validateValue('ref'); $this->fail('Exception should have been thrown at this time'); } catch (Exception $e) { @@ -50,7 +50,7 @@ class ExistValidatorTest extends DatabaseTestCase public function testValidateValue() { - $val = new ExistValidator(array('className' => ExistValidatorRefModel::className(), 'attributeName' => 'id')); + $val = new ExistValidator(array('className' => ValidatorTestRefModel::className(), 'attributeName' => 'id')); $this->assertTrue($val->validateValue(2)); $this->assertTrue($val->validateValue(5)); $this->assertFalse($val->validateValue(99)); @@ -60,39 +60,39 @@ class ExistValidatorTest extends DatabaseTestCase public function testValidateAttribute() { // existing value on different table - $val = new ExistValidator(array('className' => ExistValidatorMainModel::className(), 'attributeName' => 'id')); - $m = ExistValidatorRefModel::find(array('id' => 1)); + $val = new ExistValidator(array('className' => ValidatorTestMainModel::className(), 'attributeName' => 'id')); + $m = ValidatorTestRefModel::find(array('id' => 1)); $val->validateAttribute($m, 'ref'); $this->assertFalse($m->hasErrors()); // non-existing value on different table - $val = new ExistValidator(array('className' => ExistValidatorMainModel::className(), 'attributeName' => 'id')); - $m = ExistValidatorRefModel::find(array('id' => 6)); + $val = new ExistValidator(array('className' => ValidatorTestMainModel::className(), 'attributeName' => 'id')); + $m = ValidatorTestRefModel::find(array('id' => 6)); $val->validateAttribute($m, 'ref'); $this->assertTrue($m->hasErrors('ref')); // existing value on same table $val = new ExistValidator(array('attributeName' => 'ref')); - $m = ExistValidatorRefModel::find(array('id' => 2)); + $m = ValidatorTestRefModel::find(array('id' => 2)); $val->validateAttribute($m, 'test_val'); $this->assertFalse($m->hasErrors()); // non-existing value on same table $val = new ExistValidator(array('attributeName' => 'ref')); - $m = ExistValidatorRefModel::find(array('id' => 5)); + $m = ValidatorTestRefModel::find(array('id' => 5)); $val->validateAttribute($m, 'test_val_fail'); $this->assertTrue($m->hasErrors('test_val_fail')); // check for given value (true) $val = new ExistValidator(); - $m = ExistValidatorRefModel::find(array('id' => 3)); + $m = ValidatorTestRefModel::find(array('id' => 3)); $val->validateAttribute($m, 'ref'); $this->assertFalse($m->hasErrors()); // check for given defaults (false) $val = new ExistValidator(); - $m = ExistValidatorRefModel::find(array('id' => 4)); + $m = ValidatorTestRefModel::find(array('id' => 4)); $m->a_field = 'some new value'; $val->validateAttribute($m, 'a_field'); $this->assertTrue($m->hasErrors('a_field')); // check array $val = new ExistValidator(array('attributeName' => 'ref')); - $m = ExistValidatorRefModel::find(array('id' => 2)); + $m = ValidatorTestRefModel::find(array('id' => 2)); $m->test_val = array(1,2,3); $val->validateAttribute($m, 'test_val'); $this->assertTrue($m->hasErrors('test_val')); From c189e5ad3f4e7fbdd4f1bc7a2edda1a2b54813f6 Mon Sep 17 00:00:00 2001 From: Suralc Date: Sat, 24 Aug 2013 00:05:27 +0200 Subject: [PATCH 022/103] UniqueValidator test. --- .../UniqueValidatorPostgresTest.php | 11 +++ .../UniqueValidatorSQliteTest.php | 11 +++ .../framework/validators/UniqueValidatorTest.php | 88 ++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php create mode 100644 tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorSQliteTest.php create mode 100644 tests/unit/framework/validators/UniqueValidatorTest.php diff --git a/tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php b/tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php new file mode 100644 index 0000000..9adc57c --- /dev/null +++ b/tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php @@ -0,0 +1,11 @@ +getComponent('db'); + } + + public function testAssureMessageSetOnInit() + { + $val = new UniqueValidator(); + $this->assertTrue(is_string($val->message)); + } + + public function testValidateAttributeDefault() + { + $val = new UniqueValidator(); + $m = ValidatorTestMainModel::find()->one(); + $val->validateAttribute($m, 'id'); + $this->assertFalse($m->hasErrors('id')); + $m = ValidatorTestRefModel::find(1); + $val->validateAttribute($m, 'ref'); + $this->assertTrue($m->hasErrors('ref')); + // new record: + $m = new ValidatorTestRefModel(); + $m->ref = 5; + $val->validateAttribute($m, 'ref'); + $this->assertTrue($m->hasErrors('ref')); + $m = new ValidatorTestRefModel(); + $m->ref = 12121; + $val->validateAttribute($m, 'ref'); + $this->assertFalse($m->hasErrors('ref')); + $m->save(false); + $val->validateAttribute($m, 'ref'); + $this->assertFalse($m->hasErrors('ref')); + // array error + $m = FakedValidationModel::createWithAttributes(array('attr_arr' => array('a', 'b'))); + $val->validateAttribute($m, 'attr_arr'); + $this->assertTrue($m->hasErrors('attr_arr')); + } + + public function testValidateAttributeOfNonARModel() + { + $val = new UniqueValidator(array('className' => ValidatorTestRefModel::className(), 'attributeName' => 'ref')); + $m = FakedValidationModel::createWithAttributes(array('attr_1' => 5, 'attr_2' => 1313)); + $val->validateAttribute($m, 'attr_1'); + $this->assertTrue($m->hasErrors('attr_1')); + $val->validateAttribute($m, 'attr_2'); + $this->assertFalse($m->hasErrors('attr_2')); + } + + public function testValidateNonDatabaseAttribute() + { + $val = new UniqueValidator(array('className' => ValidatorTestRefModel::className(), 'attributeName' => 'ref')); + $m = ValidatorTestMainModel::find(1); + $val->validateAttribute($m, 'testMainVal'); + $this->assertFalse($m->hasErrors('testMainVal')); + $m = ValidatorTestMainModel::find(1); + $m->testMainVal = 4; + $val->validateAttribute($m, 'testMainVal'); + $this->assertTrue($m->hasErrors('testMainVal')); + } + + public function testValidateAttributeAttributeNotInTableException() + { + $this->setExpectedException('yii\base\InvalidConfigException'); + $val = new UniqueValidator(); + $m = new ValidatorTestMainModel(); + $val->validateAttribute($m, 'testMainVal'); + } +} \ No newline at end of file From 06682d0ba9407279c06005ccf96e09d04e1f5002 Mon Sep 17 00:00:00 2001 From: Suralc Date: Sat, 24 Aug 2013 00:05:55 +0200 Subject: [PATCH 023/103] coverage improvements --- tests/unit/data/sqlite.sql | 10 ++++------ .../framework/validators/CompareValidatorTest.php | 6 ++++++ .../unit/framework/validators/FileValidatorTest.php | 17 +++++++++++++++++ .../framework/validators/RequiredValidatorTest.php | 20 ++++++++++++++++++++ .../framework/validators/UniqueValidatorTest.php | 1 + 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/tests/unit/data/sqlite.sql b/tests/unit/data/sqlite.sql index 8976519..71eaf46 100644 --- a/tests/unit/data/sqlite.sql +++ b/tests/unit/data/sqlite.sql @@ -95,16 +95,14 @@ DROP TABLE IF EXISTS tbl_validator_main; DROP TABLE IF EXISTS tbl_validator_ref; CREATE TABLE tbl_validator_main ( - id INT(11) NOT NULL, - field1 VARCHAR(255), - PRIMARY KEY (id) + id INTEGER PRIMARY KEY , + field1 VARCHAR(255) ); CREATE TABLE tbl_validator_ref ( - id INT(11) NOT NULL, + id INTEGER PRIMARY KEY , a_field VARCHAR(255), - ref INT(11), - PRIMARY KEY (id) + ref INT(11) ); INSERT INTO tbl_validator_main (id, field1) VALUES (1, 'just a string1'); diff --git a/tests/unit/framework/validators/CompareValidatorTest.php b/tests/unit/framework/validators/CompareValidatorTest.php index 46ab383..5a16a30 100644 --- a/tests/unit/framework/validators/CompareValidatorTest.php +++ b/tests/unit/framework/validators/CompareValidatorTest.php @@ -128,6 +128,12 @@ class CompareValidatorTest extends TestCase $val->validateAttribute($model, 'attr_test'); $this->assertTrue($model->hasErrors('attr_test')); $this->assertFalse($model->hasErrors('attr_test_repeat')); + // not existing op + $val = new CompareValidator(); + $val->operator = '<>'; + $model = FakedValidationModel::createWithAttributes(array('attr_o' => 5, 'attr_o_repeat' => 5 )); + $val->validateAttribute($model, 'attr_o'); + $this->assertTrue($model->hasErrors('attr_o')); } public function testValidateAttributeOperators() diff --git a/tests/unit/framework/validators/FileValidatorTest.php b/tests/unit/framework/validators/FileValidatorTest.php index 820afb5..4d74383 100644 --- a/tests/unit/framework/validators/FileValidatorTest.php +++ b/tests/unit/framework/validators/FileValidatorTest.php @@ -205,6 +205,23 @@ class FileValidatorTest extends TestCase $this->assertSame(FileValidator::className() . '::validateFile', $log['messages'][0][2]); } + public function testValidateAttributeType() + { + $val = new FileValidator(array('types' => 'jpeg, jpg')); + $m = FakedValidationModel::createWithAttributes( + array( + 'attr_jpg' => $this->createTestFiles(array(array('name' => 'one.jpeg'))), + 'attr_exe' => $this->createTestFiles(array(array('name' => 'bad.exe'))), + ) + ); + $val->validateAttribute($m, 'attr_jpg'); + $this->assertFalse($m->hasErrors('attr_jpg')); + $val->validateAttribute($m, 'attr_exe'); + $this->assertTrue($m->hasErrors('attr_exe')); + $this->assertTrue(stripos(current($m->getErrors('attr_exe')), 'Only files with these extensions ') !== false); + } + + protected function createModelForAttributeTest() { return FakedValidationModel::createWithAttributes( diff --git a/tests/unit/framework/validators/RequiredValidatorTest.php b/tests/unit/framework/validators/RequiredValidatorTest.php index 198727b..22c9d0b 100644 --- a/tests/unit/framework/validators/RequiredValidatorTest.php +++ b/tests/unit/framework/validators/RequiredValidatorTest.php @@ -3,6 +3,7 @@ namespace yiiunit\framework\validators; use yii\validators\RequiredValidator; +use yiiunit\data\validators\models\FakedValidationModel; use yiiunit\TestCase; class RequiredValidatorTest extends TestCase @@ -31,4 +32,23 @@ class RequiredValidatorTest extends TestCase $this->assertFalse($val->validateValue("should fail")); $this->assertFalse($val->validateValue(true)); } + + public function testValidateAttribute() + { + // empty req-value + $val = new RequiredValidator(); + $m = FakedValidationModel::createWithAttributes(array('attr_val' => null)); + $val->validateAttribute($m, 'attr_val'); + $this->assertTrue($m->hasErrors('attr_val')); + $this->assertTrue(stripos(current($m->getErrors('attr_val')), 'blank') !== false); + $val = new RequiredValidator(array('requiredValue' => 55)); + $m = FakedValidationModel::createWithAttributes(array('attr_val' => 56)); + $val->validateAttribute($m, 'attr_val'); + $this->assertTrue($m->hasErrors('attr_val')); + $this->assertTrue(stripos(current($m->getErrors('attr_val')), 'must be') !== false); + $val = new RequiredValidator(array('requiredValue' => 55)); + $m = FakedValidationModel::createWithAttributes(array('attr_val' => 55)); + $val->validateAttribute($m, 'attr_val'); + $this->assertFalse($m->hasErrors('attr_val')); + } } \ No newline at end of file diff --git a/tests/unit/framework/validators/UniqueValidatorTest.php b/tests/unit/framework/validators/UniqueValidatorTest.php index 325a15c..b0d3554 100644 --- a/tests/unit/framework/validators/UniqueValidatorTest.php +++ b/tests/unit/framework/validators/UniqueValidatorTest.php @@ -44,6 +44,7 @@ class UniqueValidatorTest extends DatabaseTestCase $val->validateAttribute($m, 'ref'); $this->assertTrue($m->hasErrors('ref')); $m = new ValidatorTestRefModel(); + $m->id = 7; $m->ref = 12121; $val->validateAttribute($m, 'ref'); $this->assertFalse($m->hasErrors('ref')); From fc75ab87be5008807c529e0cb28a7911a71261d7 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sat, 28 Sep 2013 22:42:42 +0400 Subject: [PATCH 024/103] =?UTF-8?q?Renamed=20ListViewBase=20=E2=86=92=20Ba?= =?UTF-8?q?seListView?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- framework/yii/classes.php | 2 +- framework/yii/grid/GridView.php | 4 +- framework/yii/widgets/BaseListView.php | 191 +++++++++++++++++++++++++++++++++ framework/yii/widgets/ListView.php | 2 +- framework/yii/widgets/ListViewBase.php | 191 --------------------------------- 5 files changed, 195 insertions(+), 195 deletions(-) create mode 100644 framework/yii/widgets/BaseListView.php delete mode 100644 framework/yii/widgets/ListViewBase.php diff --git a/framework/yii/classes.php b/framework/yii/classes.php index d4f304c..1469910 100644 --- a/framework/yii/classes.php +++ b/framework/yii/classes.php @@ -235,7 +235,7 @@ return array( 'yii\widgets\LinkPager' => YII_PATH . '/widgets/LinkPager.php', 'yii\widgets\LinkSorter' => YII_PATH . '/widgets/LinkSorter.php', 'yii\widgets\ListView' => YII_PATH . '/widgets/ListView.php', - 'yii\widgets\ListViewBase' => YII_PATH . '/widgets/ListViewBase.php', + 'yii\widgets\BaseListView' => YII_PATH . '/widgets/BaseListView.php', 'yii\widgets\MaskedInput' => YII_PATH . '/widgets/MaskedInput.php', 'yii\widgets\MaskedInputAsset' => YII_PATH . '/widgets/MaskedInputAsset.php', 'yii\widgets\Menu' => YII_PATH . '/widgets/Menu.php', diff --git a/framework/yii/grid/GridView.php b/framework/yii/grid/GridView.php index a783a75..f4433bc 100644 --- a/framework/yii/grid/GridView.php +++ b/framework/yii/grid/GridView.php @@ -14,13 +14,13 @@ use yii\base\InvalidConfigException; use yii\base\Widget; use yii\db\ActiveRecord; use yii\helpers\Html; -use yii\widgets\ListViewBase; +use yii\widgets\BaseListView; /** * @author Qiang Xue * @since 2.0 */ -class GridView extends ListViewBase +class GridView extends BaseListView { const FILTER_POS_HEADER = 'header'; const FILTER_POS_FOOTER = 'footer'; diff --git a/framework/yii/widgets/BaseListView.php b/framework/yii/widgets/BaseListView.php new file mode 100644 index 0000000..7268fbc --- /dev/null +++ b/framework/yii/widgets/BaseListView.php @@ -0,0 +1,191 @@ + + * @since 2.0 + */ +abstract class BaseListView extends Widget +{ + /** + * @var array the HTML attributes for the container tag of the list view. + * The "tag" element specifies the tag name of the container element and defaults to "div". + */ + public $options = array(); + /** + * @var \yii\data\DataProviderInterface the data provider for the view. This property is required. + */ + public $dataProvider; + /** + * @var array the configuration for the pager widget. By default, [[LinkPager]] will be + * used to render the pager. You can use a different widget class by configuring the "class" element. + */ + public $pager = array(); + /** + * @var array the configuration for the sorter widget. By default, [[LinkSorter]] will be + * used to render the sorter. You can use a different widget class by configuring the "class" element. + */ + public $sorter = array(); + /** + * @var string the HTML content to be displayed as the summary of the list view. + * If you do not want to show the summary, you may set it with an empty string. + * + * The following tokens will be replaced with the corresponding values: + * + * - `{begin}`: the starting row number (1-based) currently being displayed + * - `{end}`: the ending row number (1-based) currently being displayed + * - `{count}`: the number of rows currently being displayed + * - `{totalCount}`: the total number of rows available + * - `{page}`: the page number (1-based) current being displayed + * - `{pageCount}`: the number of pages available + */ + public $summary; + /** + * @var string|boolean the HTML content to be displayed when [[dataProvider]] does not have any data. + * If false, the list view will still be displayed (without body content though). + */ + public $empty; + /** + * @var string the layout that determines how different sections of the list view should be organized. + * The following tokens will be replaced with the corresponding section contents: + * + * - `{summary}`: the summary section. See [[renderSummary()]]. + * - `{items}`: the list items. See [[renderItems()]]. + * - `{sorter}`: the sorter. See [[renderSorter()]]. + * - `{pager}`: the pager. See [[renderPager()]]. + */ + public $layout = "{summary}\n{items}\n{pager}"; + + + /** + * Renders the data models. + * @return string the rendering result. + */ + abstract public function renderItems(); + + /** + * Initializes the view. + */ + public function init() + { + if ($this->dataProvider === null) { + throw new InvalidConfigException('The "dataProvider" property must be set.'); + } + } + + /** + * Runs the widget. + */ + public function run() + { + if ($this->dataProvider->getCount() > 0 || $this->empty === false) { + $widget = $this; + $content = preg_replace_callback("/{\\w+}/", function ($matches) use ($widget) { + $content = $widget->renderSection($matches[0]); + return $content === false ? $matches[0] : $content; + }, $this->layout); + } else { + $content = '
' . ($this->empty === null ? Yii::t('yii', 'No results found.') : $this->empty) . '
'; + } + $tag = ArrayHelper::remove($this->options, 'tag', 'div'); + echo Html::tag($tag, $content, $this->options); + } + + /** + * Renders a section of the specified name. + * If the named section is not supported, false will be returned. + * @param string $name the section name, e.g., `{summary}`, `{items}`. + * @return string|boolean the rendering result of the section, or false if the named section is not supported. + */ + public function renderSection($name) + { + switch ($name) { + case '{summary}': + return $this->renderSummary(); + case '{items}': + return $this->renderItems(); + case '{pager}': + return $this->renderPager(); + case '{sorter}': + return $this->renderSorter(); + default: + return false; + } + } + + /** + * Renders the summary text. + */ + public function renderSummary() + { + $count = $this->dataProvider->getCount(); + if (($pagination = $this->dataProvider->getPagination()) !== false) { + $totalCount = $this->dataProvider->getTotalCount(); + $begin = $pagination->getPage() * $pagination->pageSize + 1; + $end = $begin + $count - 1; + $page = $pagination->getPage() + 1; + $pageCount = $pagination->pageCount; + if (($summaryContent = $this->summary) === null) { + $summaryContent = '
' . Yii::t('yii', 'Total 1 item.|Showing {begin}-{end} of {totalCount} items.', $totalCount) . '
'; + } + } else { + $begin = $page = $pageCount = 1; + $end = $totalCount = $count; + if (($summaryContent = $this->summary) === null) { + $summaryContent = '
' . Yii::t('yii', 'Total 1 item.|Total {count} items.', $count) . '
'; + } + } + return strtr($summaryContent, array( + '{begin}' => $begin, + '{end}' => $end, + '{count}' => $count, + '{totalCount}' => $totalCount, + '{page}' => $page, + '{pageCount}' => $pageCount, + )); + } + + /** + * Renders the pager. + * @return string the rendering result + */ + public function renderPager() + { + $pagination = $this->dataProvider->getPagination(); + if ($pagination === false || $this->dataProvider->getCount() <= 0) { + return ''; + } + /** @var LinkPager $class */ + $class = ArrayHelper::remove($this->pager, 'class', LinkPager::className()); + $this->pager['pagination'] = $pagination; + return $class::widget($this->pager); + } + + /** + * Renders the sorter. + * @return string the rendering result + */ + public function renderSorter() + { + $sort = $this->dataProvider->getSort(); + if ($sort === false || empty($sort->attributes) || $this->dataProvider->getCount() <= 0) { + return ''; + } + /** @var LinkSorter $class */ + $class = ArrayHelper::remove($this->sorter, 'class', LinkSorter::className()); + $this->sorter['sort'] = $sort; + return $class::widget($this->sorter); + } +} diff --git a/framework/yii/widgets/ListView.php b/framework/yii/widgets/ListView.php index c191389..1d8745d 100644 --- a/framework/yii/widgets/ListView.php +++ b/framework/yii/widgets/ListView.php @@ -16,7 +16,7 @@ use yii\helpers\Html; * @author Qiang Xue * @since 2.0 */ -class ListView extends ListViewBase +class ListView extends BaseListView { /** * @var array the HTML attributes for the container of the rendering result of each data model. diff --git a/framework/yii/widgets/ListViewBase.php b/framework/yii/widgets/ListViewBase.php deleted file mode 100644 index 33186ae..0000000 --- a/framework/yii/widgets/ListViewBase.php +++ /dev/null @@ -1,191 +0,0 @@ - - * @since 2.0 - */ -abstract class ListViewBase extends Widget -{ - /** - * @var array the HTML attributes for the container tag of the list view. - * The "tag" element specifies the tag name of the container element and defaults to "div". - */ - public $options = array(); - /** - * @var \yii\data\DataProviderInterface the data provider for the view. This property is required. - */ - public $dataProvider; - /** - * @var array the configuration for the pager widget. By default, [[LinkPager]] will be - * used to render the pager. You can use a different widget class by configuring the "class" element. - */ - public $pager = array(); - /** - * @var array the configuration for the sorter widget. By default, [[LinkSorter]] will be - * used to render the sorter. You can use a different widget class by configuring the "class" element. - */ - public $sorter = array(); - /** - * @var string the HTML content to be displayed as the summary of the list view. - * If you do not want to show the summary, you may set it with an empty string. - * - * The following tokens will be replaced with the corresponding values: - * - * - `{begin}`: the starting row number (1-based) currently being displayed - * - `{end}`: the ending row number (1-based) currently being displayed - * - `{count}`: the number of rows currently being displayed - * - `{totalCount}`: the total number of rows available - * - `{page}`: the page number (1-based) current being displayed - * - `{pageCount}`: the number of pages available - */ - public $summary; - /** - * @var string|boolean the HTML content to be displayed when [[dataProvider]] does not have any data. - * If false, the list view will still be displayed (without body content though). - */ - public $empty; - /** - * @var string the layout that determines how different sections of the list view should be organized. - * The following tokens will be replaced with the corresponding section contents: - * - * - `{summary}`: the summary section. See [[renderSummary()]]. - * - `{items}`: the list items. See [[renderItems()]]. - * - `{sorter}`: the sorter. See [[renderSorter()]]. - * - `{pager}`: the pager. See [[renderPager()]]. - */ - public $layout = "{summary}\n{items}\n{pager}"; - - - /** - * Renders the data models. - * @return string the rendering result. - */ - abstract public function renderItems(); - - /** - * Initializes the view. - */ - public function init() - { - if ($this->dataProvider === null) { - throw new InvalidConfigException('The "dataProvider" property must be set.'); - } - } - - /** - * Runs the widget. - */ - public function run() - { - if ($this->dataProvider->getCount() > 0 || $this->empty === false) { - $widget = $this; - $content = preg_replace_callback("/{\\w+}/", function ($matches) use ($widget) { - $content = $widget->renderSection($matches[0]); - return $content === false ? $matches[0] : $content; - }, $this->layout); - } else { - $content = '
' . ($this->empty === null ? Yii::t('yii', 'No results found.') : $this->empty) . '
'; - } - $tag = ArrayHelper::remove($this->options, 'tag', 'div'); - echo Html::tag($tag, $content, $this->options); - } - - /** - * Renders a section of the specified name. - * If the named section is not supported, false will be returned. - * @param string $name the section name, e.g., `{summary}`, `{items}`. - * @return string|boolean the rendering result of the section, or false if the named section is not supported. - */ - public function renderSection($name) - { - switch ($name) { - case '{summary}': - return $this->renderSummary(); - case '{items}': - return $this->renderItems(); - case '{pager}': - return $this->renderPager(); - case '{sorter}': - return $this->renderSorter(); - default: - return false; - } - } - - /** - * Renders the summary text. - */ - public function renderSummary() - { - $count = $this->dataProvider->getCount(); - if (($pagination = $this->dataProvider->getPagination()) !== false) { - $totalCount = $this->dataProvider->getTotalCount(); - $begin = $pagination->getPage() * $pagination->pageSize + 1; - $end = $begin + $count - 1; - $page = $pagination->getPage() + 1; - $pageCount = $pagination->pageCount; - if (($summaryContent = $this->summary) === null) { - $summaryContent = '
' . Yii::t('yii', 'Total 1 item.|Showing {begin}-{end} of {totalCount} items.', $totalCount) . '
'; - } - } else { - $begin = $page = $pageCount = 1; - $end = $totalCount = $count; - if (($summaryContent = $this->summary) === null) { - $summaryContent = '
' . Yii::t('yii', 'Total 1 item.|Total {count} items.', $count) . '
'; - } - } - return strtr($summaryContent, array( - '{begin}' => $begin, - '{end}' => $end, - '{count}' => $count, - '{totalCount}' => $totalCount, - '{page}' => $page, - '{pageCount}' => $pageCount, - )); - } - - /** - * Renders the pager. - * @return string the rendering result - */ - public function renderPager() - { - $pagination = $this->dataProvider->getPagination(); - if ($pagination === false || $this->dataProvider->getCount() <= 0) { - return ''; - } - /** @var LinkPager $class */ - $class = ArrayHelper::remove($this->pager, 'class', LinkPager::className()); - $this->pager['pagination'] = $pagination; - return $class::widget($this->pager); - } - - /** - * Renders the sorter. - * @return string the rendering result - */ - public function renderSorter() - { - $sort = $this->dataProvider->getSort(); - if ($sort === false || empty($sort->attributes) || $this->dataProvider->getCount() <= 0) { - return ''; - } - /** @var LinkSorter $class */ - $class = ArrayHelper::remove($this->sorter, 'class', LinkSorter::className()); - $this->sorter['sort'] = $sort; - return $class::widget($this->sorter); - } -} From 40629ca49bef1a864b2d94593335eac7c927b084 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sat, 28 Sep 2013 23:30:54 +0400 Subject: [PATCH 025/103] Added missing beforeCopy option to FileHelper::copyDirectory It was mentioned in AssetManager::publish phpdoc. --- framework/yii/helpers/BaseFileHelper.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/framework/yii/helpers/BaseFileHelper.php b/framework/yii/helpers/BaseFileHelper.php index 2c911b0..c71a1a9 100644 --- a/framework/yii/helpers/BaseFileHelper.php +++ b/framework/yii/helpers/BaseFileHelper.php @@ -155,6 +155,11 @@ class BaseFileHelper * and '.svn/' matches directory paths ending with '.svn'. Note, the '/' characters in a pattern matches * both '/' and '\' in the paths. * - recursive: boolean, whether the files under the subdirectories should also be copied. Defaults to true. + * - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file. + * This option is used only when publishing a directory. If the callback returns false, the copy + * operation for the sub-directory or file will be cancelled. + * The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or + * file to be copied from, while `$to` is the copy target. * - afterCopy: callback, a PHP callback that is called after each sub-directory or file is successfully copied. * The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or * file copied from, while `$to` is the copy target. @@ -173,6 +178,9 @@ class BaseFileHelper $from = $src . DIRECTORY_SEPARATOR . $file; $to = $dst . DIRECTORY_SEPARATOR . $file; if (static::filterPath($from, $options)) { + if (isset($options['beforeCopy'])) { + call_user_func($options['beforeCopy'], $from, $to); + } if (is_file($from)) { copy($from, $to); if (isset($options['fileMode'])) { From ba1496cd508ca003bff8ffbae5e1d055a652e5b0 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 28 Sep 2013 20:11:24 -0400 Subject: [PATCH 026/103] doc fix. --- framework/yii/web/Response.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/framework/yii/web/Response.php b/framework/yii/web/Response.php index e6505fd..f0d506b 100644 --- a/framework/yii/web/Response.php +++ b/framework/yii/web/Response.php @@ -559,7 +559,20 @@ class Response extends \yii\base\Response /** * Redirects the browser to the specified URL. * - * This method will send out a "Location" header to achieve the redirection. + * This method adds a "Location" header to the current response. Note that it does not send out + * the header until [[send()]] is called. In a controller action you may use this method as follows: + * + * ~~~ + * return Yii::$app->getResponse()->redirect($url); + * ~~~ + * + * In other places, if you want to send out the "Location" header immediately, you should use + * the following code: + * + * ~~~ + * Yii::$app->getResponse()->redirect($url)->send(); + * return; + * ~~~ * * In AJAX mode, this normally will not work as expected unless there are some * client-side JavaScript code handling the redirection. To help achieve this goal, @@ -578,12 +591,6 @@ class Response extends \yii\base\Response * }); * ~~~ * - * In a controller action you may use this method like this: - * - * ~~~ - * return Yii::$app->getResponse()->redirect($url); - * ~~~ - * * @param string|array $url the URL to be redirected to. This can be in one of the following formats: * * - a string representing a URL (e.g. "http://example.com") From efef0e52ca41ed16f52eefae8c24a1103ee020f6 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 28 Sep 2013 20:13:48 -0400 Subject: [PATCH 027/103] Fixed beforeCopy option. --- framework/yii/helpers/BaseFileHelper.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/framework/yii/helpers/BaseFileHelper.php b/framework/yii/helpers/BaseFileHelper.php index c71a1a9..caed59f 100644 --- a/framework/yii/helpers/BaseFileHelper.php +++ b/framework/yii/helpers/BaseFileHelper.php @@ -156,8 +156,7 @@ class BaseFileHelper * both '/' and '\' in the paths. * - recursive: boolean, whether the files under the subdirectories should also be copied. Defaults to true. * - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file. - * This option is used only when publishing a directory. If the callback returns false, the copy - * operation for the sub-directory or file will be cancelled. + * If the callback returns false, the copy operation for the sub-directory or file will be cancelled. * The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or * file to be copied from, while `$to` is the copy target. * - afterCopy: callback, a PHP callback that is called after each sub-directory or file is successfully copied. @@ -178,8 +177,8 @@ class BaseFileHelper $from = $src . DIRECTORY_SEPARATOR . $file; $to = $dst . DIRECTORY_SEPARATOR . $file; if (static::filterPath($from, $options)) { - if (isset($options['beforeCopy'])) { - call_user_func($options['beforeCopy'], $from, $to); + if (!isset($options['beforeCopy']) || !call_user_func($options['beforeCopy'], $from, $to)) { + continue; } if (is_file($from)) { copy($from, $to); From 6dc69e68b55e1eece655c4716f0969693b4aba0e Mon Sep 17 00:00:00 2001 From: ekerazha Date: Sun, 29 Sep 2013 17:21:41 +0200 Subject: [PATCH 028/103] Add data padding and key derivation. --- framework/yii/helpers/BaseSecurity.php | 85 ++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 9 deletions(-) diff --git a/framework/yii/helpers/BaseSecurity.php b/framework/yii/helpers/BaseSecurity.php index 3be07b4..41caade 100644 --- a/framework/yii/helpers/BaseSecurity.php +++ b/framework/yii/helpers/BaseSecurity.php @@ -24,20 +24,40 @@ use yii\base\InvalidParamException; class BaseSecurity { /** + * Uses AES, block size is 128-bit (16 bytes). + */ + const CRYPT_BLOCK_SIZE = 16; + + /** + * Uses AES-192, key size is 192-bit (24 bytes). + */ + const CRYPT_KEY_SIZE = 24; + + /** + * Uses SHA-256. + */ + const DERIVATION_HASH = 'sha256'; + + /** + * Uses 1000 iterations. + */ + const DERIVATION_ITERATIONS = 1000; + + /** * Encrypts data. * @param string $data data to be encrypted. - * @param string $key the encryption secret key + * @param string $password the encryption password * @return string the encrypted data * @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized * @see decrypt() */ - public static function encrypt($data, $key) + public static function encrypt($data, $password) { $module = static::openCryptModule(); - // 192-bit (24 bytes) key size - $key = StringHelper::substr($key, 0, 24); + $data = static::addPadding($data); srand(); $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND); + $key = static::deriveKey($password, $iv); mcrypt_generic_init($module, $key, $iv); $encrypted = $iv . mcrypt_generic($module, $data); mcrypt_generic_deinit($module); @@ -48,23 +68,70 @@ class BaseSecurity /** * Decrypts data * @param string $data data to be decrypted. - * @param string $key the decryption secret key + * @param string $password the decryption password * @return string the decrypted data * @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized * @see encrypt() */ - public static function decrypt($data, $key) + public static function decrypt($data, $password) { $module = static::openCryptModule(); - // 192-bit (24 bytes) key size - $key = StringHelper::substr($key, 0, 24); $ivSize = mcrypt_enc_get_iv_size($module); $iv = StringHelper::substr($data, 0, $ivSize); + $key = static::deriveKey($password, $iv); mcrypt_generic_init($module, $key, $iv); $decrypted = mdecrypt_generic($module, StringHelper::substr($data, $ivSize, StringHelper::strlen($data))); mcrypt_generic_deinit($module); mcrypt_module_close($module); - return rtrim($decrypted, "\0"); + return static::stripPadding($decrypted); + } + + /** + * Adds a padding to the given data (PKCS #7). + * @param string $data the data to pad + * @return string the padded data + */ + protected static function addPadding($data) + { + $pad = self::CRYPT_BLOCK_SIZE - (StringHelper::strlen($data) % self::CRYPT_BLOCK_SIZE); + return $data . str_repeat(chr($pad), $pad); + } + + /** + * Strips the padding from the given data. + * @param string $data the data to trim + * @return string the trimmed data + */ + protected static function stripPadding($data) + { + $end = StringHelper::substr($data, -1); + $last = ord($end); + $n = StringHelper::strlen($data) - $last; + if (StringHelper::substr($data, $n) == str_repeat($end, $last)) { + return StringHelper::substr($data, 0, $n); + } + return false; + } + + /** + * Derives a key from the given password (PBKDF2). + * @param string $password the source password + * @param string $salt the random salt + * @param int $iterations the number of iterations + * @return string the derived key + */ + protected static function deriveKey($password, $salt) + { + if (function_exists('hash_pbkdf2')) { + return hash_pbkdf2(self::DERIVATION_HASH, $password, $salt, self::DERIVATION_ITERATIONS, self::CRYPT_KEY_SIZE, true); + } + $hmac = hash_hmac(self::DERIVATION_HASH, $salt . pack('N', 1), $password, true); + $xorsum = $hmac; + for ($i = 1; $i < self::DERIVATION_ITERATIONS; $i++) { + $hmac = hash_hmac(self::DERIVATION_HASH, $hmac, $password, true); + $xorsum ^= $hmac; + } + return substr($xorsum, 0, self::CRYPT_KEY_SIZE); } /** From 5d7c37bd7ea2d0e467fabeff312bd184c6216d7d Mon Sep 17 00:00:00 2001 From: Jin Hu Date: Sun, 29 Sep 2013 23:27:14 +0800 Subject: [PATCH 029/103] Incorrect array representation when has previous --- framework/yii/base/Exception.php | 8 ++++---- tests/unit/framework/base/ExceptionTest.php | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 tests/unit/framework/base/ExceptionTest.php diff --git a/framework/yii/base/Exception.php b/framework/yii/base/Exception.php index 4f66e53..b771490 100644 --- a/framework/yii/base/Exception.php +++ b/framework/yii/base/Exception.php @@ -41,10 +41,10 @@ class Exception extends \Exception implements Arrayable { if ($exception instanceof self) { $array = array( - 'type' => get_class($this), - 'name' => $this->getName(), - 'message' => $this->getMessage(), - 'code' => $this->getCode(), + 'type' => get_class($exception), + 'name' => $exception->getName(), + 'message' => $exception->getMessage(), + 'code' => $exception->getCode(), ); } else { $array = array( diff --git a/tests/unit/framework/base/ExceptionTest.php b/tests/unit/framework/base/ExceptionTest.php new file mode 100644 index 0000000..af4293a --- /dev/null +++ b/tests/unit/framework/base/ExceptionTest.php @@ -0,0 +1,23 @@ +toArray(); + $this->assertEquals('bar', $array['message']); + $this->assertEquals('foo', $array['previous']['message']); + + $e = new InvalidCallException('bar', 0 ,new UserException('foo')); + $array = $e->toArray(); + $this->assertEquals('bar', $array['message']); + $this->assertEquals('foo', $array['previous']['message']); + } +} From cb7921b8a5ecd391076f869fd344b78f789adf70 Mon Sep 17 00:00:00 2001 From: ekerazha Date: Sun, 29 Sep 2013 17:59:31 +0200 Subject: [PATCH 030/103] Fix StringHelper::substr() call. --- framework/yii/helpers/BaseSecurity.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/yii/helpers/BaseSecurity.php b/framework/yii/helpers/BaseSecurity.php index 41caade..ca42d37 100644 --- a/framework/yii/helpers/BaseSecurity.php +++ b/framework/yii/helpers/BaseSecurity.php @@ -104,10 +104,10 @@ class BaseSecurity */ protected static function stripPadding($data) { - $end = StringHelper::substr($data, -1); + $end = StringHelper::substr($data, -1, NULL); $last = ord($end); $n = StringHelper::strlen($data) - $last; - if (StringHelper::substr($data, $n) == str_repeat($end, $last)) { + if (StringHelper::substr($data, $n, NULL) == str_repeat($end, $last)) { return StringHelper::substr($data, 0, $n); } return false; From 9e9b3548db5544c2b3df47985601c95fe3de6011 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sun, 29 Sep 2013 12:06:00 -0400 Subject: [PATCH 031/103] refactor Exception::toArrayRecursive(). --- framework/yii/base/Exception.php | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/framework/yii/base/Exception.php b/framework/yii/base/Exception.php index b771490..64f1d1b 100644 --- a/framework/yii/base/Exception.php +++ b/framework/yii/base/Exception.php @@ -39,21 +39,12 @@ class Exception extends \Exception implements Arrayable */ protected function toArrayRecursive($exception) { - if ($exception instanceof self) { - $array = array( - 'type' => get_class($exception), - 'name' => $exception->getName(), - 'message' => $exception->getMessage(), - 'code' => $exception->getCode(), - ); - } else { - $array = array( - 'type' => get_class($exception), - 'name' => 'Exception', - 'message' => $exception->getMessage(), - 'code' => $exception->getCode(), - ); - } + $array = array( + 'type' => get_class($exception), + 'name' => $exception instanceof self ? $exception->getName() : 'Exception', + 'message' => $exception->getMessage(), + 'code' => $exception->getCode(), + ); if (($prev = $exception->getPrevious()) !== null) { $array['previous'] = $this->toArrayRecursive($prev); } From c4f4e52a5aaadd3369865ac2151dc965c675ecbf Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sun, 29 Sep 2013 12:16:20 -0400 Subject: [PATCH 032/103] fixed test break. --- framework/yii/helpers/BaseFileHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/helpers/BaseFileHelper.php b/framework/yii/helpers/BaseFileHelper.php index caed59f..7540168 100644 --- a/framework/yii/helpers/BaseFileHelper.php +++ b/framework/yii/helpers/BaseFileHelper.php @@ -177,7 +177,7 @@ class BaseFileHelper $from = $src . DIRECTORY_SEPARATOR . $file; $to = $dst . DIRECTORY_SEPARATOR . $file; if (static::filterPath($from, $options)) { - if (!isset($options['beforeCopy']) || !call_user_func($options['beforeCopy'], $from, $to)) { + if (isset($options['beforeCopy']) && !call_user_func($options['beforeCopy'], $from, $to)) { continue; } if (is_file($from)) { From 64a33e78498197796cbda9150ec0cf3d846801f8 Mon Sep 17 00:00:00 2001 From: ekerazha Date: Sun, 29 Sep 2013 18:18:59 +0200 Subject: [PATCH 033/103] Fix phpdoc. --- framework/yii/helpers/BaseSecurity.php | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/yii/helpers/BaseSecurity.php b/framework/yii/helpers/BaseSecurity.php index ca42d37..a1b0ec4 100644 --- a/framework/yii/helpers/BaseSecurity.php +++ b/framework/yii/helpers/BaseSecurity.php @@ -117,7 +117,6 @@ class BaseSecurity * Derives a key from the given password (PBKDF2). * @param string $password the source password * @param string $salt the random salt - * @param int $iterations the number of iterations * @return string the derived key */ protected static function deriveKey($password, $salt) From 8d4d0ee0bcbd5986e5bc21e48b9c967665ee2e21 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Mon, 30 Sep 2013 12:53:04 +0200 Subject: [PATCH 034/103] Update RedisCache.php added version information --- framework/yii/caching/RedisCache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/caching/RedisCache.php b/framework/yii/caching/RedisCache.php index 5c778fc..7cb6451 100644 --- a/framework/yii/caching/RedisCache.php +++ b/framework/yii/caching/RedisCache.php @@ -10,7 +10,7 @@ namespace yii\caching; use yii\redis\Connection; /** - * RedisCache implements a cache application component based on [redis](http://redis.io/). + * RedisCache implements a cache application component based on [redis](http://redis.io/) version 2.6 or higher. * * RedisCache needs to be configured with [[hostname]], [[port]] and [[database]] of the server * to connect to. By default RedisCache assumes there is a redis server running on localhost at From b4b9ad483a8d33985a852af23993b9360b482ab0 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Mon, 30 Sep 2013 14:42:05 +0200 Subject: [PATCH 035/103] Added version information to redis --- docs/guide/caching.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/guide/caching.md b/docs/guide/caching.md index 0624d78..64c7e8d 100644 --- a/docs/guide/caching.md +++ b/docs/guide/caching.md @@ -60,7 +60,8 @@ is a summary of the available cache components: the fastest one when dealing with cache in a distributed applications (e.g. with several servers, load balancers, etc.) -* [[\yii\caching\RedisCache]]: implements a cache component based on [Redis](http://redis.io/) NoSQL database. +* [[\yii\caching\RedisCache]]: implements a cache component based on [Redis](http://redis.io/) key-value store + (redis version 2.6 or higher is required). * [[\yii\caching\WinCache]]: uses PHP [WinCache](http://iis.net/downloads/microsoft/wincache-extension) ([see also](http://php.net/manual/en/book.wincache.php)) extension. From d03d681583b1bdc8ea0246ca610bbb1bb3a6fd73 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 30 Sep 2013 10:14:08 -0400 Subject: [PATCH 036/103] Fixes #928: client validation should be applied to active attributes only. --- framework/yii/widgets/ActiveField.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/framework/yii/widgets/ActiveField.php b/framework/yii/widgets/ActiveField.php index ea8aa1b..7df67fa 100644 --- a/framework/yii/widgets/ActiveField.php +++ b/framework/yii/widgets/ActiveField.php @@ -589,9 +589,13 @@ class ActiveField extends Component */ protected function getClientOptions() { + $attribute = Html::getAttributeName($this->attribute); + if (!in_array($attribute, $this->model->activeAttributes(), true)) { + return array(); + } + $enableClientValidation = $this->enableClientValidation || $this->enableClientValidation === null && $this->form->enableClientValidation; if ($enableClientValidation) { - $attribute = Html::getAttributeName($this->attribute); $validators = array(); foreach ($this->model->getActiveValidators($attribute) as $validator) { /** @var \yii\validators\Validator $validator */ From 2c30ddfcb0621e74552e7f6628cb092f666c5709 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Tue, 1 Oct 2013 20:01:14 +0200 Subject: [PATCH 037/103] added web\Controller::goBack() as shortcut goBack() will redirect user to his returnUrl fixes #925 --- apps/basic/controllers/SiteController.php | 2 +- framework/yii/web/Controller.php | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/basic/controllers/SiteController.php b/apps/basic/controllers/SiteController.php index 1196280..e243223 100644 --- a/apps/basic/controllers/SiteController.php +++ b/apps/basic/controllers/SiteController.php @@ -61,7 +61,7 @@ class SiteController extends Controller { $model = new LoginForm(); if ($model->load($_POST) && $model->login()) { - return $this->goHome(); + return $this->goBack(); } else { return $this->render('login', array( 'model' => $model, diff --git a/framework/yii/web/Controller.php b/framework/yii/web/Controller.php index 6b8afa4..7509186 100644 --- a/framework/yii/web/Controller.php +++ b/framework/yii/web/Controller.php @@ -146,6 +146,19 @@ class Controller extends \yii\base\Controller } /** + * Redirects the browser to the last visited page. + * @param string|array $defaultUrl the default return URL in case it was not set previously. + * If this is null and the return URL was not set previously, [[Application::homeUrl]] will be redirected to. + * Please refer to [[User::setReturnUrl()]] on accepted format of the URL. + * @return Response the current response object + * @see User::getReturnUrl() + */ + public function goBack($defaultUrl = null) + { + return Yii::$app->getResponse()->redirect(Yii::$app->getUser()->getReturnUrl($defaultUrl)); + } + + /** * Refreshes the current page. * This method is a shortcut to [[Response::refresh()]]. * @param string $anchor the anchor that should be appended to the redirection URL. From 0035f23781750f2e598077e11fa8deb43b10bd21 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 1 Oct 2013 21:35:35 -0400 Subject: [PATCH 038/103] refactored data providers. --- framework/yii/classes.php | 27 +-- framework/yii/data/ActiveDataProvider.php | 158 ++++--------- framework/yii/data/ArrayDataProvider.php | 104 +++------ framework/yii/data/BaseDataProvider.php | 253 +++++++++++++++++++++ framework/yii/data/DataProvider.php | 133 ----------- framework/yii/data/DataProviderInterface.php | 12 + framework/yii/widgets/BaseListView.php | 1 + .../unit/framework/data/ActiveDataProviderTest.php | 5 +- 8 files changed, 357 insertions(+), 336 deletions(-) create mode 100644 framework/yii/data/BaseDataProvider.php delete mode 100644 framework/yii/data/DataProvider.php diff --git a/framework/yii/classes.php b/framework/yii/classes.php index 1469910..78cce95 100644 --- a/framework/yii/classes.php +++ b/framework/yii/classes.php @@ -85,7 +85,7 @@ return array( 'yii\captcha\CaptchaValidator' => YII_PATH . '/captcha/CaptchaValidator.php', 'yii\data\ActiveDataProvider' => YII_PATH . '/data/ActiveDataProvider.php', 'yii\data\ArrayDataProvider' => YII_PATH . '/data/ArrayDataProvider.php', - 'yii\data\DataProvider' => YII_PATH . '/data/DataProvider.php', + 'yii\data\BaseDataProvider' => YII_PATH . '/data/BaseDataProvider.php', 'yii\data\DataProviderInterface' => YII_PATH . '/data/DataProviderInterface.php', 'yii\data\Pagination' => YII_PATH . '/data/Pagination.php', 'yii\data\Sort' => YII_PATH . '/data/Sort.php', @@ -118,6 +118,7 @@ return array( 'yii\db\pgsql\Schema' => YII_PATH . '/db/pgsql/Schema.php', 'yii\db\sqlite\QueryBuilder' => YII_PATH . '/db/sqlite/QueryBuilder.php', 'yii\db\sqlite\Schema' => YII_PATH . '/db/sqlite/Schema.php', + 'yii\grid\ActionColumn' => YII_PATH . '/grid/ActionColumn.php', 'yii\grid\CheckboxColumn' => YII_PATH . '/grid/CheckboxColumn.php', 'yii\grid\Column' => YII_PATH . '/grid/Column.php', 'yii\grid\DataColumn' => YII_PATH . '/grid/DataColumn.php', @@ -126,26 +127,26 @@ return array( 'yii\grid\SerialColumn' => YII_PATH . '/grid/SerialColumn.php', 'yii\helpers\ArrayHelper' => YII_PATH . '/helpers/ArrayHelper.php', 'yii\helpers\BaseArrayHelper' => YII_PATH . '/helpers/BaseArrayHelper.php', - 'yii\helpers\Console' => YII_PATH . '/helpers/Console.php', 'yii\helpers\BaseConsole' => YII_PATH . '/helpers/BaseConsole.php', - 'yii\helpers\FileHelper' => YII_PATH . '/helpers/FileHelper.php', 'yii\helpers\BaseFileHelper' => YII_PATH . '/helpers/BaseFileHelper.php', - 'yii\helpers\Html' => YII_PATH . '/helpers/Html.php', 'yii\helpers\BaseHtml' => YII_PATH . '/helpers/BaseHtml.php', - 'yii\helpers\HtmlPurifier' => YII_PATH . '/helpers/HtmlPurifier.php', 'yii\helpers\BaseHtmlPurifier' => YII_PATH . '/helpers/BaseHtmlPurifier.php', - 'yii\helpers\Inflector' => YII_PATH . '/helpers/Inflector.php', 'yii\helpers\BaseInflector' => YII_PATH . '/helpers/BaseInflector.php', - 'yii\helpers\Json' => YII_PATH . '/helpers/Json.php', 'yii\helpers\BaseJson' => YII_PATH . '/helpers/BaseJson.php', - 'yii\helpers\Markdown' => YII_PATH . '/helpers/Markdown.php', 'yii\helpers\BaseMarkdown' => YII_PATH . '/helpers/BaseMarkdown.php', - 'yii\helpers\Security' => YII_PATH . '/helpers/Security.php', 'yii\helpers\BaseSecurity' => YII_PATH . '/helpers/BaseSecurity.php', - 'yii\helpers\StringHelper' => YII_PATH . '/helpers/StringHelper.php', 'yii\helpers\BaseStringHelper' => YII_PATH . '/helpers/BaseStringHelper.php', - 'yii\helpers\VarDumper' => YII_PATH . '/helpers/VarDumper.php', 'yii\helpers\BaseVarDumper' => YII_PATH . '/helpers/BaseVarDumper.php', + 'yii\helpers\Console' => YII_PATH . '/helpers/Console.php', + 'yii\helpers\FileHelper' => YII_PATH . '/helpers/FileHelper.php', + 'yii\helpers\Html' => YII_PATH . '/helpers/Html.php', + 'yii\helpers\HtmlPurifier' => YII_PATH . '/helpers/HtmlPurifier.php', + 'yii\helpers\Inflector' => YII_PATH . '/helpers/Inflector.php', + 'yii\helpers\Json' => YII_PATH . '/helpers/Json.php', + 'yii\helpers\Markdown' => YII_PATH . '/helpers/Markdown.php', + 'yii\helpers\Security' => YII_PATH . '/helpers/Security.php', + 'yii\helpers\StringHelper' => YII_PATH . '/helpers/StringHelper.php', + 'yii\helpers\VarDumper' => YII_PATH . '/helpers/VarDumper.php', 'yii\i18n\DbMessageSource' => YII_PATH . '/i18n/DbMessageSource.php', 'yii\i18n\Formatter' => YII_PATH . '/i18n/Formatter.php', 'yii\i18n\GettextFile' => YII_PATH . '/i18n/GettextFile.php', @@ -194,6 +195,7 @@ return array( 'yii\web\Application' => YII_PATH . '/web/Application.php', 'yii\web\AssetBundle' => YII_PATH . '/web/AssetBundle.php', 'yii\web\AssetConverter' => YII_PATH . '/web/AssetConverter.php', + 'yii\web\AssetConverterInterface' => YII_PATH . '/web/AssetConverterInterface.php', 'yii\web\AssetManager' => YII_PATH . '/web/AssetManager.php', 'yii\web\CacheSession' => YII_PATH . '/web/CacheSession.php', 'yii\web\Controller' => YII_PATH . '/web/Controller.php', @@ -204,7 +206,6 @@ return array( 'yii\web\HeaderCollection' => YII_PATH . '/web/HeaderCollection.php', 'yii\web\HttpCache' => YII_PATH . '/web/HttpCache.php', 'yii\web\HttpException' => YII_PATH . '/web/HttpException.php', - 'yii\web\AssetConverterInterface' => YII_PATH . '/web/AssetConverterInterface.php', 'yii\web\IdentityInterface' => YII_PATH . '/web/IdentityInterface.php', 'yii\web\JqueryAsset' => YII_PATH . '/web/JqueryAsset.php', 'yii\web\JsExpression' => YII_PATH . '/web/JsExpression.php', @@ -226,6 +227,7 @@ return array( 'yii\widgets\ActiveField' => YII_PATH . '/widgets/ActiveField.php', 'yii\widgets\ActiveForm' => YII_PATH . '/widgets/ActiveForm.php', 'yii\widgets\ActiveFormAsset' => YII_PATH . '/widgets/ActiveFormAsset.php', + 'yii\widgets\BaseListView' => YII_PATH . '/widgets/BaseListView.php', 'yii\widgets\Block' => YII_PATH . '/widgets/Block.php', 'yii\widgets\Breadcrumbs' => YII_PATH . '/widgets/Breadcrumbs.php', 'yii\widgets\ContentDecorator' => YII_PATH . '/widgets/ContentDecorator.php', @@ -235,7 +237,6 @@ return array( 'yii\widgets\LinkPager' => YII_PATH . '/widgets/LinkPager.php', 'yii\widgets\LinkSorter' => YII_PATH . '/widgets/LinkSorter.php', 'yii\widgets\ListView' => YII_PATH . '/widgets/ListView.php', - 'yii\widgets\BaseListView' => YII_PATH . '/widgets/BaseListView.php', 'yii\widgets\MaskedInput' => YII_PATH . '/widgets/MaskedInput.php', 'yii\widgets\MaskedInputAsset' => YII_PATH . '/widgets/MaskedInputAsset.php', 'yii\widgets\Menu' => YII_PATH . '/widgets/Menu.php', diff --git a/framework/yii/data/ActiveDataProvider.php b/framework/yii/data/ActiveDataProvider.php index 2fe0efb..c5f1bcd 100644 --- a/framework/yii/data/ActiveDataProvider.php +++ b/framework/yii/data/ActiveDataProvider.php @@ -48,16 +48,10 @@ use yii\db\Connection; * $posts = $provider->getModels(); * ~~~ * - * @property integer $count The number of data models in the current page. This property is read-only. - * @property array $keys The list of key values corresponding to [[models]]. Each data model in [[models]] is - * uniquely identified by the corresponding key value in this array. This property is read-only. - * @property array $models The list of data models in the current page. This property is read-only. - * @property integer $totalCount Total number of possible data models. - * * @author Qiang Xue * @since 2.0 */ -class ActiveDataProvider extends DataProvider +class ActiveDataProvider extends BaseDataProvider { /** * @var Query the query that is used to fetch data models and [[totalCount]] @@ -82,10 +76,6 @@ class ActiveDataProvider extends DataProvider */ public $db; - private $_models; - private $_keys; - private $_totalCount; - /** * Initializes the DbCache component. * This method will initialize the [[db]] property to make sure it refers to a valid DB connection. @@ -103,122 +93,72 @@ class ActiveDataProvider extends DataProvider } /** - * Returns the number of data models in the current page. - * This is equivalent to `count($provider->models)`. - * When [[pagination]] is false, this is the same as [[totalCount]]. - * @return integer the number of data models in the current page. - */ - public function getCount() - { - return count($this->getModels()); - } - - /** - * Returns the total number of data models. - * When [[pagination]] is false, this returns the same value as [[count]]. - * If [[totalCount]] is not explicitly set, it will be calculated - * using [[query]] with a COUNT query. - * @return integer total number of possible data models. - * @throws InvalidConfigException + * @inheritdoc */ - public function getTotalCount() + protected function prepareModels() { - if ($this->getPagination() === false) { - return $this->getCount(); - } elseif ($this->_totalCount === null) { - if (!$this->query instanceof Query) { - throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.'); - } - $query = clone $this->query; - $this->_totalCount = $query->limit(-1)->offset(-1)->count('*', $this->db); + if (!$this->query instanceof Query) { + throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.'); } - return $this->_totalCount; - } - - /** - * Sets the total number of data models. - * @param integer $value the total number of data models. - */ - public function setTotalCount($value) - { - $this->_totalCount = $value; - } - - /** - * Returns the data models in the current page. - * @return array the list of data models in the current page. - * @throws InvalidConfigException if [[query]] is not set or invalid. - */ - public function getModels() - { - if ($this->_models === null) { - if (!$this->query instanceof Query) { - throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.'); - } - if (($pagination = $this->getPagination()) !== false) { - $this->query->limit($pagination->getLimit())->offset($pagination->getOffset()); - } - if (($sort = $this->getSort()) !== false) { - $this->query->addOrderBy($sort->getOrders()); - } - $this->_models = $this->query->all($this->db); + if (($pagination = $this->getPagination()) !== false) { + $pagination->totalCount = $this->getTotalCount(); + $this->query->limit($pagination->getLimit())->offset($pagination->getOffset()); + } + if (($sort = $this->getSort()) !== false) { + $this->query->addOrderBy($sort->getOrders()); } - return $this->_models; + return $this->query->all($this->db); } /** - * Returns the key values associated with the data models. - * @return array the list of key values corresponding to [[models]]. Each data model in [[models]] - * is uniquely identified by the corresponding key value in this array. + * @inheritdoc */ - public function getKeys() + protected function prepareKeys($models) { - if ($this->_keys === null) { - $this->_keys = array(); - $models = $this->getModels(); - if ($this->key !== null) { + $keys = array(); + if ($this->key !== null) { + foreach ($models as $model) { + if (is_string($this->key)) { + $keys[] = $model[$this->key]; + } else { + $keys[] = call_user_func($this->key, $model); + } + } + return $keys; + } elseif ($this->query instanceof ActiveQuery) { + /** @var \yii\db\ActiveRecord $class */ + $class = $this->query->modelClass; + $pks = $class::primaryKey(); + if (count($pks) === 1) { + $pk = $pks[0]; foreach ($models as $model) { - if (is_string($this->key)) { - $this->_keys[] = $model[$this->key]; - } else { - $this->_keys[] = call_user_func($this->key, $model); - } + $keys[] = $model[$pk]; } - } elseif ($this->query instanceof ActiveQuery) { - /** @var \yii\db\ActiveRecord $class */ - $class = $this->query->modelClass; - $pks = $class::primaryKey(); - if (count($pks) === 1) { - $pk = $pks[0]; - foreach ($models as $model) { - $this->_keys[] = $model[$pk]; - } - } else { - foreach ($models as $model) { - $keys = array(); - foreach ($pks as $pk) { - $keys[] = $model[$pk]; - } - $this->_keys[] = json_encode($keys); + } else { + foreach ($models as $model) { + $kk = array(); + foreach ($pks as $pk) { + $kk[] = $model[$pk]; } + $keys[] = json_encode($kk); } - } else { - $this->_keys = array_keys($models); } + return $keys; + } else { + return array_keys($models); } - return $this->_keys; } /** - * Refreshes the data provider. - * After calling this method, if [[getModels()]], [[getKeys()]] or [[getTotalCount()]] is called again, - * they will re-execute the query and return the latest data available. + * @inheritdoc */ - public function refresh() + protected function prepareTotalCount() { - $this->_models = null; - $this->_totalCount = null; - $this->_keys = null; + if (!$this->query instanceof Query) { + throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.'); + } + $query = clone $this->query; + return $query->limit(-1)->offset(-1)->count('*', $this->db); } /** @@ -227,9 +167,7 @@ class ActiveDataProvider extends DataProvider public function setSort($value) { parent::setSort($value); - if (($sort = $this->getSort()) !== false && empty($sort->attributes) && - $this->query instanceof ActiveQuery) { - + if (($sort = $this->getSort()) !== false && empty($sort->attributes) && $this->query instanceof ActiveQuery) { /** @var Model $model */ $model = new $this->query->modelClass; foreach($model->attributes() as $attribute) { diff --git a/framework/yii/data/ArrayDataProvider.php b/framework/yii/data/ArrayDataProvider.php index 9534803..925c18e 100644 --- a/framework/yii/data/ArrayDataProvider.php +++ b/framework/yii/data/ArrayDataProvider.php @@ -47,15 +47,10 @@ use yii\helpers\ArrayHelper; * Note: if you want to use the sorting feature, you must configure the [[sort]] property * so that the provider knows which columns can be sorted. * - * @property array $keys The list of key values corresponding to [[models]]. Each data model in [[models]] is - * uniquely identified by the corresponding key value in this array. - * @property array $models The list of data models in the current page. - * @property integer $totalCount Total number of possible data models. - * * @author Qiang Xue * @since 2.0 */ -class ArrayDataProvider extends DataProvider +class ArrayDataProvider extends BaseDataProvider { /** * @var string|callable the column that is used as the key of the data models. @@ -71,100 +66,53 @@ class ArrayDataProvider extends DataProvider */ public $allModels; - private $_totalCount; /** - * Returns the total number of data models. - * @return integer total number of possible data models. + * @inheritdoc */ - public function getTotalCount() + protected function prepareModels() { - if ($this->getPagination() === false) { - return $this->getCount(); - } elseif ($this->_totalCount === null) { - $this->_totalCount = count($this->allModels); + if (($models = $this->allModels) === null) { + return array(); } - return $this->_totalCount; - } - - /** - * Sets the total number of data models. - * @param integer $value the total number of data models. - */ - public function setTotalCount($value) - { - $this->_totalCount = $value; - } - - private $_models; - /** - * Returns the data models in the current page. - * @return array the list of data models in the current page. - */ - public function getModels() - { - if ($this->_models === null) { - if (($models = $this->allModels) === null) { - return array(); - } - - if (($sort = $this->getSort()) !== false) { - $models = $this->sortModels($models, $sort); - } - - if (($pagination = $this->getPagination()) !== false) { - $models = array_slice($models, $pagination->getOffset(), $pagination->getLimit()); - } + if (($sort = $this->getSort()) !== false) { + $models = $this->sortModels($models, $sort); + } - $this->_models = $models; + if (($pagination = $this->getPagination()) !== false) { + $models = array_slice($models, $pagination->getOffset(), $pagination->getLimit()); } - return $this->_models; - } - /** - * Sets the data models in the current page. - * @param array $models the models in the current page - */ - public function setModels($models) - { - $this->_models = $models; + return $models; } - private $_keys; - /** - * Returns the key values associated with the data models. - * @return array the list of key values corresponding to [[models]]. Each data model in [[models]] - * is uniquely identified by the corresponding key value in this array. + * @inheritdoc */ - public function getKeys() + protected function prepareKeys($models) { - if ($this->_keys === null) { - $this->_keys = array(); - $models = $this->getModels(); - if ($this->key !== null) { - foreach ($models as $model) { - if (is_string($this->key)) { - $this->_keys[] = $model[$this->key]; - } else { - $this->_keys[] = call_user_func($this->key, $model); - } + if ($this->key !== null) { + $keys = array(); + foreach ($models as $model) { + if (is_string($this->key)) { + $keys[] = $model[$this->key]; + } else { + $keys[] = call_user_func($this->key, $model); } - } else { - $this->_keys = array_keys($models); } + return $keys; + } else { + return array_keys($models); } - return $this->_keys; } /** - * Sets the key values associated with the data models. - * @param array $keys the list of key values corresponding to [[models]]. + * @inheritdoc */ - public function setKeys($keys) + protected function prepareTotalCount() { - $this->_keys = $keys; + return count($this->allModels); } /** diff --git a/framework/yii/data/BaseDataProvider.php b/framework/yii/data/BaseDataProvider.php new file mode 100644 index 0000000..15705b7 --- /dev/null +++ b/framework/yii/data/BaseDataProvider.php @@ -0,0 +1,253 @@ + + * @since 2.0 + */ +abstract class BaseDataProvider extends Component implements DataProviderInterface +{ + /** + * @var string an ID that uniquely identifies the data provider among all data providers. + * You should set this property if the same page contains two or more different data providers. + * Otherwise, the [[pagination]] and [[sort]] mainly not work properly. + */ + public $id; + + private $_sort; + private $_pagination; + private $_keys; + private $_models; + private $_totalCount; + + + /** + * Prepares the data models that will be made available in the current page. + * @return array the available data models + */ + abstract protected function prepareModels(); + + /** + * Prepares the keys associated with the currently available data models. + * @param array $models the available data models + * @return array the keys + */ + abstract protected function prepareKeys($models); + + /** + * Returns a value indicating the total number of data models in this data provider. + * @return integer total number of data models in this data provider. + */ + abstract protected function prepareTotalCount(); + + /** + * Prepares the data models and keys. + * + * This method will prepare the data models and keys that can be retrieved via + * [[getModels()]] and [[getKeys()]]. + * + * This method will be implicitly called by [[getModels()]] and [[getKeys()]] if it has not been called before. + * + * @param boolean $forcePrepare whether to force data preparation even if it has been done before. + */ + public function prepare($forcePrepare = false) + { + if ($forcePrepare || $this->_models === null) { + $this->_models = $this->prepareModels(); + } + if ($forcePrepare || $this->_keys === null) { + $this->_keys = $this->prepareKeys($this->_models); + } + } + + /** + * Returns the data models in the current page. + * @return array the list of data models in the current page. + */ + public function getModels() + { + $this->prepare(); + return $this->_models; + } + + /** + * Sets the data models in the current page. + * @param array $models the models in the current page + */ + public function setModels($models) + { + $this->_models = $models; + } + + /** + * Returns the key values associated with the data models. + * @return array the list of key values corresponding to [[models]]. Each data model in [[models]] + * is uniquely identified by the corresponding key value in this array. + */ + public function getKeys() + { + $this->prepare(); + return $this->_keys; + } + + /** + * Sets the key values associated with the data models. + * @param array $keys the list of key values corresponding to [[models]]. + */ + public function setKeys($keys) + { + $this->_keys = $keys; + } + + /** + * Returns the number of data models in the current page. + * @return integer the number of data models in the current page. + */ + public function getCount() + { + return count($this->getModels()); + } + + /** + * Returns the total number of data models. + * When [[pagination]] is false, this returns the same value as [[count]]. + * Otherwise, it will call [[prepareTotalCount()]] to get the count. + * @return integer total number of possible data models. + */ + public function getTotalCount() + { + if ($this->getPagination() === false) { + return $this->getCount(); + } elseif ($this->_totalCount === null) { + $this->_totalCount = $this->prepareTotalCount(); + } + return $this->_totalCount; + } + + /** + * Sets the total number of data models. + * @param integer $value the total number of data models. + */ + public function setTotalCount($value) + { + $this->_totalCount = $value; + } + + /** + * @return Pagination|boolean the pagination object. If this is false, it means the pagination is disabled. + */ + public function getPagination() + { + if ($this->_pagination === null) { + $this->_pagination = new Pagination; + if ($this->id !== null) { + $this->_pagination->pageVar = $this->id . '-page'; + } + } + return $this->_pagination; + } + + /** + * Sets the pagination for this data provider. + * @param array|Pagination|boolean $value the pagination to be used by this data provider. + * This can be one of the following: + * + * - a configuration array for creating the pagination object. The "class" element defaults + * to 'yii\data\Pagination' + * - an instance of [[Pagination]] or its subclass + * - false, if pagination needs to be disabled. + * + * @throws InvalidParamException + */ + public function setPagination($value) + { + if (is_array($value)) { + $config = array( + 'class' => Pagination::className(), + ); + if ($this->id !== null) { + $config['pageVar'] = $this->id . '-page'; + } + $this->_pagination = Yii::createObject(array_merge($config, $value)); + } elseif ($value instanceof Pagination || $value === false) { + $this->_pagination = $value; + } else { + throw new InvalidParamException('Only Pagination instance, configuration array or false is allowed.'); + } + } + + /** + * @return Sort|boolean the sorting object. If this is false, it means the sorting is disabled. + */ + public function getSort() + { + if ($this->_sort === null) { + $this->setSort(array()); + } + return $this->_sort; + } + + /** + * Sets the sort definition for this data provider. + * @param array|Sort|boolean $value the sort definition to be used by this data provider. + * This can be one of the following: + * + * - a configuration array for creating the sort definition object. The "class" element defaults + * to 'yii\data\Sort' + * - an instance of [[Sort]] or its subclass + * - false, if sorting needs to be disabled. + * + * @throws InvalidParamException + */ + public function setSort($value) + { + if (is_array($value)) { + $config = array( + 'class' => Sort::className(), + ); + if ($this->id !== null) { + $config['sortVar'] = $this->id . '-sort'; + } + $this->_sort = Yii::createObject(array_merge($config, $value)); + } elseif ($value instanceof Sort || $value === false) { + $this->_sort = $value; + } else { + throw new InvalidParamException('Only Sort instance, configuration array or false is allowed.'); + } + } + + /** + * Refreshes the data provider. + * After calling this method, if [[getModels()]], [[getKeys()]] or [[getTotalCount()]] is called again, + * they will re-execute the query and return the latest data available. + */ + public function refresh() + { + $this->_totalCount = null; + $this->_models = null; + $this->_keys = null; + } +} diff --git a/framework/yii/data/DataProvider.php b/framework/yii/data/DataProvider.php deleted file mode 100644 index d75be6f..0000000 --- a/framework/yii/data/DataProvider.php +++ /dev/null @@ -1,133 +0,0 @@ - - * @since 2.0 - */ -abstract class DataProvider extends Component implements DataProviderInterface -{ - /** - * @var string an ID that uniquely identifies the data provider among all data providers. - * You should set this property if the same page contains two or more different data providers. - * Otherwise, the [[pagination]] and [[sort]] mainly not work properly. - */ - public $id; - - private $_sort; - private $_pagination; - - /** - * @return Pagination|boolean the pagination object. If this is false, it means the pagination is disabled. - */ - public function getPagination() - { - if ($this->_pagination === null) { - $this->_pagination = new Pagination; - if ($this->id !== null) { - $this->_pagination->pageVar = $this->id . '-page'; - } - $this->_pagination->totalCount = $this->getTotalCount(); - } - return $this->_pagination; - } - - /** - * Sets the pagination for this data provider. - * @param array|Pagination|boolean $value the pagination to be used by this data provider. - * This can be one of the following: - * - * - a configuration array for creating the pagination object. The "class" element defaults - * to 'yii\data\Pagination' - * - an instance of [[Pagination]] or its subclass - * - false, if pagination needs to be disabled. - * - * @throws InvalidParamException - */ - public function setPagination($value) - { - if (is_array($value)) { - $config = array( - 'class' => Pagination::className(), - ); - if ($this->id !== null) { - $config['pageVar'] = $this->id . '-page'; - } - $this->_pagination = Yii::createObject(array_merge($config, $value)); - } elseif ($value instanceof Pagination || $value === false) { - $this->_pagination = $value; - } else { - throw new InvalidParamException('Only Pagination instance, configuration array or false is allowed.'); - } - } - - /** - * @return Sort|boolean the sorting object. If this is false, it means the sorting is disabled. - */ - public function getSort() - { - if ($this->_sort === null) { - $this->setSort(array()); - } - return $this->_sort; - } - - /** - * Sets the sort definition for this data provider. - * @param array|Sort|boolean $value the sort definition to be used by this data provider. - * This can be one of the following: - * - * - a configuration array for creating the sort definition object. The "class" element defaults - * to 'yii\data\Sort' - * - an instance of [[Sort]] or its subclass - * - false, if sorting needs to be disabled. - * - * @throws InvalidParamException - */ - public function setSort($value) - { - if (is_array($value)) { - $config = array( - 'class' => Sort::className(), - ); - if ($this->id !== null) { - $config['sortVar'] = $this->id . '-sort'; - } - $this->_sort = Yii::createObject(array_merge($config, $value)); - } elseif ($value instanceof Sort || $value === false) { - $this->_sort = $value; - } else { - throw new InvalidParamException('Only Sort instance, configuration array or false is allowed.'); - } - } - - /** - * Returns the number of data models in the current page. - * @return integer the number of data models in the current page. - */ - public function getCount() - { - return count($this->getModels()); - } -} diff --git a/framework/yii/data/DataProviderInterface.php b/framework/yii/data/DataProviderInterface.php index f0bc39d..1dea1e6 100644 --- a/framework/yii/data/DataProviderInterface.php +++ b/framework/yii/data/DataProviderInterface.php @@ -19,6 +19,18 @@ namespace yii\data; interface DataProviderInterface { /** + * Prepares the data models and keys. + * + * This method will prepare the data models and keys that can be retrieved via + * [[getModels()]] and [[getKeys()]]. + * + * This method will be implicitly called by [[getModels()]] and [[getKeys()]] if it has not been called before. + * + * @param boolean $forcePrepare whether to force data preparation even if it has been done before. + */ + public function prepare($forcePrepare = false); + + /** * Returns the number of data models in the current page. * This is equivalent to `count($provider->getModels())`. * When [[pagination]] is false, this is the same as [[totalCount]]. diff --git a/framework/yii/widgets/BaseListView.php b/framework/yii/widgets/BaseListView.php index 7268fbc..d4647ff 100644 --- a/framework/yii/widgets/BaseListView.php +++ b/framework/yii/widgets/BaseListView.php @@ -83,6 +83,7 @@ abstract class BaseListView extends Widget if ($this->dataProvider === null) { throw new InvalidConfigException('The "dataProvider" property must be set.'); } + $this->dataProvider->prepare(); } /** diff --git a/tests/unit/framework/data/ActiveDataProviderTest.php b/tests/unit/framework/data/ActiveDataProviderTest.php index 79c0a39..276c525 100644 --- a/tests/unit/framework/data/ActiveDataProviderTest.php +++ b/tests/unit/framework/data/ActiveDataProviderTest.php @@ -94,9 +94,10 @@ class ActiveDataProviderTest extends DatabaseTestCase 'query' => $query->from('tbl_order')->orderBy('id'), )); $pagination = $provider->getPagination(); - $this->assertEquals(1, $pagination->getPageCount()); + $this->assertEquals(0, $pagination->getPageCount()); $this->assertCount(3, $provider->getModels()); - + $this->assertEquals(1, $pagination->getPageCount()); + $provider->getPagination()->pageSize = 2; $this->assertEquals(3, count($provider->getModels())); $provider->refresh(); From fe58cbd56a02af1dcd349356de5585ec78287bd3 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 1 Oct 2013 21:35:56 -0400 Subject: [PATCH 039/103] doc update. --- framework/yii/web/AssetManager.php | 4 ++-- framework/yii/web/Request.php | 2 ++ framework/yii/web/User.php | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/framework/yii/web/AssetManager.php b/framework/yii/web/AssetManager.php index 500848b..35e555f 100644 --- a/framework/yii/web/AssetManager.php +++ b/framework/yii/web/AssetManager.php @@ -16,8 +16,8 @@ use yii\helpers\FileHelper; /** * AssetManager manages asset bundles and asset publishing. * - * @property AssetConverterInterface $converter The asset converter. Note that the type of this property differs in - * getter and setter. See [[getConverter()]] and [[setConverter()]] for details. + * @property AssetConverterInterface $converter The asset converter. Note that the type of this property + * differs in getter and setter. See [[getConverter()]] and [[setConverter()]] for details. * * @author Qiang Xue * @since 2.0 diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php index 4fb6257..e5d9477 100644 --- a/framework/yii/web/Request.php +++ b/framework/yii/web/Request.php @@ -29,6 +29,8 @@ use yii\helpers\Security; * previously, a random key will be generated and used. * @property CookieCollection $cookies The cookie collection. This property is read-only. * @property string $csrfToken The random token for CSRF validation. This property is read-only. + * @property string $csrfTokenFromHeader The CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned + * if no such header is sent. This property is read-only. * @property string $hostInfo Schema and hostname part (with port number if needed) of the request URL (e.g. * `http://www.yiiframework.com`). * @property boolean $isAjax Whether this is an AJAX (XMLHttpRequest) request. This property is read-only. diff --git a/framework/yii/web/User.php b/framework/yii/web/User.php index f6a9bc8..0dd16d0 100644 --- a/framework/yii/web/User.php +++ b/framework/yii/web/User.php @@ -23,8 +23,8 @@ use yii\base\InvalidParamException; * * @property string|integer $id The unique identifier for the user. If null, it means the user is a guest. * This property is read-only. - * @property IdentityInterface $identity The identity object associated with the currently logged user. Null is - * returned if the user is not logged in (not authenticated). + * @property IdentityInterface $identity The identity object associated with the currently logged user. Null + * is returned if the user is not logged in (not authenticated). * @property boolean $isGuest Whether the current user is a guest. This property is read-only. * @property string $returnUrl The URL that the user should be redirected to after login. Note that the type * of this property differs in getter and setter. See [[getReturnUrl()]] and [[setReturnUrl()]] for details. From d798cc791b4c1195a042848485279e19fdebe589 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 1 Oct 2013 21:40:35 -0400 Subject: [PATCH 040/103] Set totalCount. --- framework/yii/data/ArrayDataProvider.php | 1 + 1 file changed, 1 insertion(+) diff --git a/framework/yii/data/ArrayDataProvider.php b/framework/yii/data/ArrayDataProvider.php index 925c18e..77f31cd 100644 --- a/framework/yii/data/ArrayDataProvider.php +++ b/framework/yii/data/ArrayDataProvider.php @@ -81,6 +81,7 @@ class ArrayDataProvider extends BaseDataProvider } if (($pagination = $this->getPagination()) !== false) { + $pagination->totalCount = $this->getTotalCount(); $models = array_slice($models, $pagination->getOffset(), $pagination->getLimit()); } From 09a91910866ef97bf78733ce70e995d666e69fee Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 1 Oct 2013 21:56:08 -0400 Subject: [PATCH 041/103] Fixes #927: doc typo. --- framework/yii/log/FileTarget.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/log/FileTarget.php b/framework/yii/log/FileTarget.php index 970c71b..5aa4c12 100644 --- a/framework/yii/log/FileTarget.php +++ b/framework/yii/log/FileTarget.php @@ -78,7 +78,7 @@ class FileTarget extends Target } /** - * Sends log messages to specified email addresses. + * Writes log messages to a file. * @throws InvalidConfigException if unable to open the log file for writing */ public function export() From c1f977cd459eb9997484d577de307c741305f0d4 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 1 Oct 2013 22:57:08 -0400 Subject: [PATCH 042/103] Simplified the default file map for PhpMessageSource. --- framework/yii/i18n/PhpMessageSource.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/yii/i18n/PhpMessageSource.php b/framework/yii/i18n/PhpMessageSource.php index f62939f..1cd2103 100644 --- a/framework/yii/i18n/PhpMessageSource.php +++ b/framework/yii/i18n/PhpMessageSource.php @@ -26,6 +26,8 @@ use Yii; * ); * ~~~ * + * You may use [[fileMap]] to customize the association between category names and the file names. + * * @author Qiang Xue * @since 2.0 */ @@ -60,10 +62,8 @@ class PhpMessageSource extends MessageSource $messageFile = Yii::getAlias($this->basePath) . "/$language/"; if (isset($this->fileMap[$category])) { $messageFile .= $this->fileMap[$category]; - } elseif (($pos = strrpos($category, '\\')) !== false) { - $messageFile .= (substr($category, $pos) . '.php'); } else { - $messageFile .= "$category.php"; + $messageFile .= str_replace('\\', '/', $category) . '.php'; } if (is_file($messageFile)) { $messages = include($messageFile); From 3f88320595023696fdbd30af625f325dac444a57 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 2 Oct 2013 12:27:04 +0200 Subject: [PATCH 043/103] second try to fix random memcache failure on travis issue #877 --- tests/unit/framework/caching/CacheTestCase.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php index 480941f..542999a 100644 --- a/tests/unit/framework/caching/CacheTestCase.php +++ b/tests/unit/framework/caching/CacheTestCase.php @@ -145,14 +145,9 @@ abstract class CacheTestCase extends TestCase $cache = $this->getCacheInstance(); $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); - sleep(1); + usleep(500000); $this->assertEquals('expire_test', $cache->get('expire_test')); - // wait a bit more than 2 sec to avoid random test failure - if (isset($_ENV['TRAVIS']) && substr(StringHelper::basename(get_class($this)), 0, 8) == 'MemCache') { - sleep(3); // usleep with 2,5 seconds does not work well on travis and memcache - } else { - usleep(2500000); - } + usleep(2500000); $this->assertFalse($cache->get('expire_test')); } From bcc0cbeba8648eb8eb41c4c5becc654bb476bc3d Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Wed, 2 Oct 2013 08:29:52 -0400 Subject: [PATCH 044/103] Added doc about BaseDataProvider::getPagination(). --- framework/yii/data/BaseDataProvider.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/framework/yii/data/BaseDataProvider.php b/framework/yii/data/BaseDataProvider.php index 15705b7..3b0669d 100644 --- a/framework/yii/data/BaseDataProvider.php +++ b/framework/yii/data/BaseDataProvider.php @@ -157,6 +157,9 @@ abstract class BaseDataProvider extends Component implements DataProviderInterfa } /** + * Returns the pagination object used by this data provider. + * Note that you should call [[prepare()]] or [[getModels()]] first to get correct values + * of [[Pagination::totalCount]] and [[Pagination::pageCount]]. * @return Pagination|boolean the pagination object. If this is false, it means the pagination is disabled. */ public function getPagination() From 618f9811123e680cba38616a18305bdd27136778 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 3 Oct 2013 01:41:38 +0400 Subject: [PATCH 045/103] Renamed i18n to be all lowecase when accessed as a property --- framework/yii/BaseYii.php | 2 +- framework/yii/base/Application.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/yii/BaseYii.php b/framework/yii/BaseYii.php index b586160..cf94166 100644 --- a/framework/yii/BaseYii.php +++ b/framework/yii/BaseYii.php @@ -541,7 +541,7 @@ class BaseYii public static function t($category, $message, $params = array(), $language = null) { if (self::$app !== null) { - return self::$app->getI18N()->translate($category, $message, $params, $language ?: self::$app->language); + return self::$app->getI18n()->translate($category, $message, $params, $language ?: self::$app->language); } else { return is_array($params) ? strtr($message, $params) : $message; } diff --git a/framework/yii/base/Application.php b/framework/yii/base/Application.php index e8c496c..3cc90d9 100644 --- a/framework/yii/base/Application.php +++ b/framework/yii/base/Application.php @@ -383,7 +383,7 @@ abstract class Application extends Module * Returns the internationalization (i18n) component * @return \yii\i18n\I18N the internationalization component */ - public function getI18N() + public function getI18n() { return $this->getComponent('i18n'); } From 8c9dadf36212bff6fef815a930dbcda4a4263bf5 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Wed, 2 Oct 2013 21:22:25 -0400 Subject: [PATCH 046/103] Fixed DB validation handling for model generator. --- framework/yii/gii/generators/model/Generator.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/framework/yii/gii/generators/model/Generator.php b/framework/yii/gii/generators/model/Generator.php index b9c8f23..7fba83f 100644 --- a/framework/yii/gii/generators/model/Generator.php +++ b/framework/yii/gii/generators/model/Generator.php @@ -464,6 +464,9 @@ class Generator extends \yii\gii\Generator return $this->_tableNames; } $db = $this->getDbConnection(); + if ($db === null) { + return array(); + } $tableNames = array(); if (strpos($this->tableName, '*') !== false) { if (($pos = strrpos($this->tableName, '.')) !== false) { From 38c0b197f9a10c9caec82dd4de194002f8219fa2 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Thu, 3 Oct 2013 11:01:52 -0400 Subject: [PATCH 047/103] Fixes #916: generation of class name from table name has problem. --- framework/yii/gii/generators/model/Generator.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/framework/yii/gii/generators/model/Generator.php b/framework/yii/gii/generators/model/Generator.php index 7fba83f..69edb5f 100644 --- a/framework/yii/gii/generators/model/Generator.php +++ b/framework/yii/gii/generators/model/Generator.php @@ -514,7 +514,8 @@ class Generator extends \yii\gii\Generator $patterns[] = '/^' . str_replace('*', '(\w+)', $pattern) . '$/'; } if (!empty($db->tablePrefix)) { - $patterns[] = "/^{$db->tablePrefix}(.*?)|(.*?){$db->tablePrefix}$/"; + $patterns[] = "/^{$db->tablePrefix}(.*?)$/"; + $patterns[] = "/^(.*?){$db->tablePrefix}$/"; } else { $patterns[] = "/^tbl_(.*?)$/"; } @@ -523,6 +524,7 @@ class Generator extends \yii\gii\Generator foreach ($patterns as $pattern) { if (preg_match($pattern, $tableName, $matches)) { $className = $matches[1]; + break; } } return $this->_classNames[$tableName] = Inflector::id2camel($className, '_'); From c5a34c534b987a5767db7757699453cb14991c14 Mon Sep 17 00:00:00 2001 From: Aaron Francis Date: Thu, 3 Oct 2013 16:33:28 -0500 Subject: [PATCH 048/103] Fix Issue #934 Fixes issue #934. Command is created for the selected database, not the default database. --- framework/yii/console/controllers/MigrateController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/console/controllers/MigrateController.php b/framework/yii/console/controllers/MigrateController.php index e2c771c..e9e3973 100644 --- a/framework/yii/console/controllers/MigrateController.php +++ b/framework/yii/console/controllers/MigrateController.php @@ -584,7 +584,7 @@ class MigrateController extends Controller ->from($this->migrationTable) ->orderBy('version DESC') ->limit($limit) - ->createCommand() + ->createCommand($this->db) ->queryAll(); $history = ArrayHelper::map($rows, 'version', 'apply_time'); unset($history[self::BASE_MIGRATION]); From 536075c0408e745fb285f86867062338d744128d Mon Sep 17 00:00:00 2001 From: egorpromo Date: Fri, 4 Oct 2013 21:17:13 +0700 Subject: [PATCH 049/103] Just simple correction of unintelligible description --- framework/yii/web/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/web/Application.php b/framework/yii/web/Application.php index 5fd2310..b0638a7 100644 --- a/framework/yii/web/Application.php +++ b/framework/yii/web/Application.php @@ -45,7 +45,7 @@ class Application extends \yii\base\Application * ) * ~~~ * - * Defaults to null, meaning catch-all is not effective. + * Defaults to null, meaning catch-all is not used. */ public $catchAll; /** From 293cb9d86f0f62f71a6943075d9a2985e09af655 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 4 Oct 2013 20:35:58 -0400 Subject: [PATCH 050/103] Fixed search form. --- framework/yii/gii/generators/crud/templates/views/_search.php | 5 ++++- framework/yii/grid/DataColumn.php | 2 +- framework/yii/helpers/BaseHtml.php | 2 +- framework/yii/web/Request.php | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/framework/yii/gii/generators/crud/templates/views/_search.php b/framework/yii/gii/generators/crud/templates/views/_search.php index a649589..13e2b82 100644 --- a/framework/yii/gii/generators/crud/templates/views/_search.php +++ b/framework/yii/gii/generators/crud/templates/views/_search.php @@ -23,7 +23,10 @@ use yii\widgets\ActiveForm;