Fix #19735: Fix yii\validators\NumberValidator to use programmable message for the value validation

This commit is contained in:
Bizley
2023-01-13 07:57:03 +01:00
committed by GitHub
parent 55ea8eee1e
commit 581a7b2543
3 changed files with 185 additions and 67 deletions

View File

@@ -61,12 +61,15 @@ class NumberValidatorTest extends TestCase
public function testEnsureMessageOnInit()
{
$val = new NumberValidator();
$this->assertInternalType('string', $val->message);
$this->assertTrue($val->max === null);
$this->assertSame('{attribute} must be a number.', $val->message);
$this->assertNull($val->max);
$this->assertNull($val->min);
$this->assertNull($val->tooSmall);
$this->assertNull($val->tooBig);
$val = new NumberValidator(['min' => -1, 'max' => 20, 'integerOnly' => true]);
$this->assertInternalType('string', $val->message);
$this->assertInternalType('string', $val->tooSmall);
$this->assertInternalType('string', $val->tooBig);
$this->assertSame('{attribute} must be an integer.', $val->message);
$this->assertSame('{attribute} must be no less than {min}.', $val->tooSmall);
$this->assertSame('{attribute} must be no greater than {max}.', $val->tooBig);
}
public function testValidateValueSimple()
@@ -77,39 +80,69 @@ class NumberValidatorTest extends TestCase
$this->assertTrue($val->validate(-20));
$this->assertTrue($val->validate('20'));
$this->assertTrue($val->validate(25.45));
$this->assertFalse($val->validate(false));
$this->assertFalse($val->validate(true));
$this->assertFalse($val->validate(false, $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate(true, $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate('0x14', $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertTrue($val->validate(0x14));
$this->assertTrue($val->validate('0123'));
$this->assertTrue($val->validate(0123));
$this->assertFalse($val->validate('0b111', $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertTrue($val->validate(0b111));
$this->setPointDecimalLocale();
$this->assertFalse($val->validate('25,45'));
$this->assertFalse($val->validate('25,45', $error));
$this->assertSame('the input value must be a number.', $error);
$this->setCommaDecimalLocale();
$this->assertTrue($val->validate('25,45'));
$this->restoreLocale();
$this->assertFalse($val->validate('12:45'));
$this->assertFalse($val->validate('12:45', $error));
$this->assertSame('the input value must be a number.', $error);
$val = new NumberValidator(['integerOnly' => true]);
$this->assertTrue($val->validate(20));
$this->assertTrue($val->validate(0));
$this->assertFalse($val->validate(25.45));
$this->assertFalse($val->validate(25.45, $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertTrue($val->validate('20'));
$this->assertFalse($val->validate('25,45'));
$this->assertFalse($val->validate('25,45', $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertTrue($val->validate('020'));
$this->assertFalse($val->validate('0x14', $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertTrue($val->validate(0x14));
$this->assertFalse($val->validate('0x14')); // todo check this
$this->assertFalse($val->validate(false));
$this->assertFalse($val->validate(true));
$this->assertTrue($val->validate('0123'));
$this->assertTrue($val->validate(0123));
$this->assertFalse($val->validate('0b111', $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertTrue($val->validate(0b111));
$this->assertFalse($val->validate(false, $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate(true, $error));
$this->assertSame('the input value must be an integer.', $error);
}
public function testValidateValueArraySimple()
{
$val = new NumberValidator();
$this->assertFalse($val->validate([20]));
$this->assertFalse($val->validate([0]));
$this->assertFalse($val->validate([-20]));
$this->assertFalse($val->validate(['20']));
$this->assertFalse($val->validate([25.45]));
$this->assertFalse($val->validate([false]));
$this->assertFalse($val->validate([true]));
$this->assertFalse($val->validate([20], $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate([0], $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate([-20], $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate(['20'], $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate([25.45], $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate([false], $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate([true], $error));
$this->assertSame('the input value must be a number.', $error);
$val = new NumberValidator();
$val->allowArray = true;
@@ -118,28 +151,38 @@ class NumberValidatorTest extends TestCase
$this->assertTrue($val->validate([-20]));
$this->assertTrue($val->validate(['20']));
$this->assertTrue($val->validate([25.45]));
$this->assertFalse($val->validate([false]));
$this->assertFalse($val->validate([true]));
$this->assertFalse($val->validate([false], $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate([true], $error));
$this->assertSame('the input value must be a number.', $error);
$this->setPointDecimalLocale();
$this->assertFalse($val->validate(['25,45']));
$this->assertFalse($val->validate(['25,45'], $error));
$this->assertSame('the input value must be a number.', $error);
$this->setCommaDecimalLocale();
$this->assertTrue($val->validate(['25,45']));
$this->restoreLocale();
$this->assertFalse($val->validate(['12:45']));
$this->assertFalse($val->validate(['12:45'], $error));
$this->assertSame('the input value must be a number.', $error);
$val = new NumberValidator(['integerOnly' => true]);
$val->allowArray = true;
$this->assertTrue($val->validate([20]));
$this->assertTrue($val->validate([0]));
$this->assertFalse($val->validate([25.45]));
$this->assertFalse($val->validate([25.45], $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertTrue($val->validate(['20']));
$this->assertFalse($val->validate(['25,45']));
$this->assertFalse($val->validate(['25,45'], $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertTrue($val->validate(['020']));
$this->assertTrue($val->validate([0x14]));
$this->assertFalse($val->validate(['0x14'])); // todo check this
$this->assertFalse($val->validate([false]));
$this->assertFalse($val->validate([true]));
$this->assertFalse($val->validate(['0x14'], $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate([false], $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate([true], $error));
$this->assertSame('the input value must be an integer.', $error);
}
public function testValidateValueAdvanced()
@@ -148,18 +191,30 @@ class NumberValidatorTest extends TestCase
$this->assertTrue($val->validate('-1.23')); // signed float
$this->assertTrue($val->validate('-4.423e-12')); // signed float + exponent
$this->assertTrue($val->validate('12E3')); // integer + exponent
$this->assertFalse($val->validate('e12')); // just exponent
$this->assertFalse($val->validate('-e3'));
$this->assertFalse($val->validate('-4.534-e-12')); // 'signed' exponent
$this->assertFalse($val->validate('12.23^4')); // expression instead of value
$this->assertFalse($val->validate('e12', $error)); // just exponent
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate('-e3', $error));
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate('-4.534-e-12', $error)); // 'signed' exponent
$this->assertSame('the input value must be a number.', $error);
$this->assertFalse($val->validate('12.23^4', $error)); // expression instead of value
$this->assertSame('the input value must be a number.', $error);
$val = new NumberValidator(['integerOnly' => true]);
$this->assertFalse($val->validate('-1.23'));
$this->assertFalse($val->validate('-4.423e-12'));
$this->assertFalse($val->validate('12E3'));
$this->assertFalse($val->validate('e12'));
$this->assertFalse($val->validate('-e3'));
$this->assertFalse($val->validate('-4.534-e-12'));
$this->assertFalse($val->validate('12.23^4'));
$this->assertFalse($val->validate('-1.23', $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate('-4.423e-12', $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate('12E3', $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate('e12', $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate('-e3', $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate('-4.534-e-12', $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate('12.23^4', $error));
$this->assertSame('the input value must be an integer.', $error);
}
public function testValidateValueWithLocaleWhereDecimalPointIsComma()
@@ -180,28 +235,37 @@ class NumberValidatorTest extends TestCase
$val = new NumberValidator(['min' => 1]);
$this->assertTrue($val->validate(1));
$this->assertFalse($val->validate(-1, $error));
$this->assertContains('the input value must be no less than 1.', $error);
$this->assertFalse($val->validate('22e-12'));
$this->assertSame('the input value must be no less than 1.', $error);
$this->assertFalse($val->validate('22e-12', $error));
$this->assertSame('the input value must be no less than 1.', $error);
$this->assertTrue($val->validate(PHP_INT_MAX + 1));
$val = new NumberValidator(['min' => 1], ['integerOnly' => true]);
$val = new NumberValidator(['min' => 1, 'integerOnly' => true]);
$this->assertTrue($val->validate(1));
$this->assertFalse($val->validate(-1));
$this->assertFalse($val->validate('22e-12'));
$this->assertTrue($val->validate(PHP_INT_MAX + 1));
$this->assertFalse($val->validate(-1, $error));
$this->assertSame('the input value must be no less than 1.', $error);
$this->assertFalse($val->validate('22e-12', $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate(PHP_INT_MAX + 1, $error));
$this->assertSame('the input value must be an integer.', $error);
}
public function testValidateValueMax()
{
$val = new NumberValidator(['max' => 1.25]);
$this->assertTrue($val->validate(1));
$this->assertFalse($val->validate(1.5));
$this->assertFalse($val->validate(1.5, $error));
$this->assertSame('the input value must be no greater than 1.25.', $error);
$this->assertTrue($val->validate('22e-12'));
$this->assertTrue($val->validate('125e-2'));
$val = new NumberValidator(['max' => 1.25, 'integerOnly' => true]);
$this->assertTrue($val->validate(1));
$this->assertFalse($val->validate(1.5));
$this->assertFalse($val->validate('22e-12'));
$this->assertFalse($val->validate('125e-2'));
$this->assertFalse($val->validate(1.5, $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate('22e-12', $error));
$this->assertSame('the input value must be an integer.', $error);
$this->assertFalse($val->validate('125e-2', $error));
$this->assertSame('the input value must be an integer.', $error);
}
public function testValidateValueRange()
@@ -209,13 +273,19 @@ class NumberValidatorTest extends TestCase
$val = new NumberValidator(['min' => -10, 'max' => 20]);
$this->assertTrue($val->validate(0));
$this->assertTrue($val->validate(-10));
$this->assertFalse($val->validate(-11));
$this->assertFalse($val->validate(21));
$this->assertFalse($val->validate(-11, $error));
$this->assertSame('the input value must be no less than -10.', $error);
$this->assertFalse($val->validate(21, $error));
$this->assertSame('the input value must be no greater than 20.', $error);
$val = new NumberValidator(['min' => -10, 'max' => 20, 'integerOnly' => true]);
$this->assertTrue($val->validate(0));
$this->assertFalse($val->validate(-11));
$this->assertFalse($val->validate(22));
$this->assertFalse($val->validate('20e-1'));
$this->assertFalse($val->validate(-11, $error));
$this->assertSame('the input value must be no less than -10.', $error);
$this->assertFalse($val->validate(22, $error));
$this->assertSame('the input value must be no greater than 20.', $error);
$this->assertFalse($val->validate('20e-1', $error));
$this->assertSame('the input value must be an integer.', $error);
}
public function testValidateAttribute()
@@ -228,6 +298,7 @@ class NumberValidatorTest extends TestCase
$model->attr_number = '43^32'; //expression
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be a number.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['min' => 10]);
$model = new FakedValidationModel();
$model->attr_number = 10;
@@ -236,6 +307,7 @@ class NumberValidatorTest extends TestCase
$model->attr_number = 5;
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be no less than 10.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['max' => 10]);
$model = new FakedValidationModel();
$model->attr_number = 10;
@@ -244,6 +316,7 @@ class NumberValidatorTest extends TestCase
$model->attr_number = 15;
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be no greater than 10.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['max' => 10, 'integerOnly' => true]);
$model = new FakedValidationModel();
$model->attr_number = 10;
@@ -252,10 +325,12 @@ class NumberValidatorTest extends TestCase
$model->attr_number = 3.43;
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be an integer.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['min' => 1]);
$model = FakedValidationModel::createWithAttributes(['attr_num' => [1, 2, 3]]);
$val->validateAttribute($model, 'attr_num');
$this->assertTrue($model->hasErrors('attr_num'));
$this->assertSame('attr_num must be a number.', $model->getFirstError('attr_num'));
// @see https://github.com/yiisoft/yii2/issues/11672
$model = new FakedValidationModel();
@@ -275,6 +350,7 @@ class NumberValidatorTest extends TestCase
$model->attr_number = ['43^32']; //expression
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be a number.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['min' => 10]);
$val->allowArray = true;
$model = new FakedValidationModel();
@@ -284,6 +360,7 @@ class NumberValidatorTest extends TestCase
$model->attr_number = [5];
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be no less than 10.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['max' => 10]);
$val->allowArray = true;
$model = new FakedValidationModel();
@@ -293,6 +370,7 @@ class NumberValidatorTest extends TestCase
$model->attr_number = [15];
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be no greater than 10.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['max' => 10, 'integerOnly' => true]);
$val->allowArray = true;
$model = new FakedValidationModel();
@@ -302,61 +380,73 @@ class NumberValidatorTest extends TestCase
$model->attr_number = [3.43];
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be an integer.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['min' => 1]);
$val->allowArray = true;
$model = FakedValidationModel::createWithAttributes(['attr_num' => [[1], [2], [3]]]);
$val->validateAttribute($model, 'attr_num');
$this->assertTrue($model->hasErrors('attr_num'));
$this->assertSame('attr_num must be a number.', $model->getFirstError('attr_num'));
// @see https://github.com/yiisoft/yii2/issues/11672
$model = new FakedValidationModel();
$model->attr_number = new \stdClass();
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be a number.', $model->getFirstError('attr_number'));
$val = new NumberValidator();
$model = new FakedValidationModel();
$model->attr_number = ['5.5e1'];
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be a number.', $model->getFirstError('attr_number'));
$model->attr_number = ['43^32']; //expression
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be a number.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['min' => 10]);
$model = new FakedValidationModel();
$model->attr_number = [10];
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be a number.', $model->getFirstError('attr_number'));
$model->attr_number = [5];
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be a number.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['max' => 10]);
$model = new FakedValidationModel();
$model->attr_number = [10];
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be a number.', $model->getFirstError('attr_number'));
$model->attr_number = [15];
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be a number.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['max' => 10, 'integerOnly' => true]);
$model = new FakedValidationModel();
$model->attr_number = [10];
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be an integer.', $model->getFirstError('attr_number'));
$model->attr_number = [3.43];
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be an integer.', $model->getFirstError('attr_number'));
$val = new NumberValidator(['min' => 1]);
$model = FakedValidationModel::createWithAttributes(['attr_num' => [[1], [2], [3]]]);
$val->validateAttribute($model, 'attr_num');
$this->assertTrue($model->hasErrors('attr_num'));
$this->assertSame('attr_num must be a number.', $model->getFirstError('attr_num'));
// @see https://github.com/yiisoft/yii2/issues/11672
$model = new FakedValidationModel();
$model->attr_number = new \stdClass();
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertSame('attr_number must be a number.', $model->getFirstError('attr_number'));
}
public function testValidateAttributeWithLocaleWhereDecimalPointIsComma()
@@ -376,10 +466,22 @@ class NumberValidatorTest extends TestCase
$this->restoreLocale();
}
public function testEnsureCustomMessageIsSetOnValidateAttribute()
public function testEnsureCustomMessageIsSetOnValidateAttributeGeneral()
{
$val = new NumberValidator(['message' => '{attribute} is not integer.']);
$model = new FakedValidationModel();
$model->attr_number = 'as';
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertCount(1, $model->getErrors('attr_number'));
$msgs = $model->getErrors('attr_number');
$this->assertSame('attr_number is not integer.', $msgs[0]);
}
public function testEnsureCustomMessageIsSetOnValidateAttributeMin()
{
$val = new NumberValidator([
'tooSmall' => '{attribute} is to small.',
'tooSmall' => '{attribute} is too small.',
'min' => 5,
]);
$model = new FakedValidationModel();
@@ -388,7 +490,22 @@ class NumberValidatorTest extends TestCase
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertCount(1, $model->getErrors('attr_number'));
$msgs = $model->getErrors('attr_number');
$this->assertSame('attr_number is to small.', $msgs[0]);
$this->assertSame('attr_number is too small.', $msgs[0]);
}
public function testEnsureCustomMessageIsSetOnValidateAttributeMax()
{
$val = new NumberValidator([
'tooBig' => '{attribute} is too big.',
'max' => 5,
]);
$model = new FakedValidationModel();
$model->attr_number = 6;
$val->validateAttribute($model, 'attr_number');
$this->assertTrue($model->hasErrors('attr_number'));
$this->assertCount(1, $model->getErrors('attr_number'));
$msgs = $model->getErrors('attr_number');
$this->assertSame('attr_number is too big.', $msgs[0]);
}
/**