Refactor Validator::decimal() to be more flexible with decimal

separators and PHP magic.
Lots of testing added.
This commit is contained in:
Ber Clausen 2012-08-27 22:16:33 -03:00
parent 7135ff29fb
commit 63548267e9
2 changed files with 113 additions and 35 deletions

View file

@ -1487,39 +1487,77 @@ class ValidationTest extends CakeTestCase {
}
/**
* testDecimal method
* Test numbers with any number of decimal places, including none.
*
* @return void
*/
public function testDecimal() {
$this->assertTrue(Validation::decimal('+1234.54321'));
$this->assertTrue(Validation::decimal('-1234.54321'));
$this->assertTrue(Validation::decimal('1234.54321'));
$this->assertTrue(Validation::decimal('+0123.45e6'));
$this->assertTrue(Validation::decimal('-0123.45e6'));
$this->assertTrue(Validation::decimal('0123.45e6'));
$this->assertTrue(Validation::decimal(1234.56));
$this->assertTrue(Validation::decimal(1234.00));
$this->assertTrue(Validation::decimal('1234.00'));
$this->assertTrue(Validation::decimal(.0));
$this->assertTrue(Validation::decimal(.00));
$this->assertTrue(Validation::decimal('.00'));
$this->assertTrue(Validation::decimal(.01));
$this->assertTrue(Validation::decimal('.01'));
public function testDecimalWithPlacesNull() {
$this->assertTrue(Validation::decimal('+1234.54321', null));
$this->assertTrue(Validation::decimal('-1234.54321', null));
$this->assertTrue(Validation::decimal('1234.54321', null));
$this->assertTrue(Validation::decimal('+0123.45e6', null));
$this->assertTrue(Validation::decimal('-0123.45e6', null));
$this->assertTrue(Validation::decimal('0123.45e6', null));
$this->assertTrue(Validation::decimal(1234.56, null));
$this->assertTrue(Validation::decimal(1234.00, null));
$this->assertTrue(Validation::decimal(1234., null));
$this->assertTrue(Validation::decimal('1234.00', null));
$this->assertTrue(Validation::decimal(.0, null));
$this->assertTrue(Validation::decimal(.00, null));
$this->assertTrue(Validation::decimal('.00', null));
$this->assertTrue(Validation::decimal(.01, null));
$this->assertTrue(Validation::decimal('.01', null));
$this->assertTrue(Validation::decimal('1234', null));
$this->assertTrue(Validation::decimal('-1234', null));
$this->assertTrue(Validation::decimal('+1234', null));
$this->assertTrue(Validation::decimal((float) 1234, null));
$this->assertTrue(Validation::decimal((double) 1234, null));
$this->assertTrue(Validation::decimal((int) 1234, null));
$this->assertFalse(Validation::decimal(''));
$this->assertFalse(Validation::decimal('string'));
$this->assertFalse(Validation::decimal('1234'));
$this->assertFalse(Validation::decimal('-1234'));
$this->assertFalse(Validation::decimal('+1234'));
$this->assertFalse(Validation::decimal('', null));
$this->assertFalse(Validation::decimal('string', null));
$this->assertFalse(Validation::decimal('1234.', null));
}
/**
* testDecimalWithPlaces method
* Test numbers with any number of decimal places greater than 0, or a float|double.
*
* @return void
*/
public function testDecimalWithPlaces() {
public function testDecimalWithPlacesTrue() {
$this->assertTrue(Validation::decimal('+1234.54321', true));
$this->assertTrue(Validation::decimal('-1234.54321', true));
$this->assertTrue(Validation::decimal('1234.54321', true));
$this->assertTrue(Validation::decimal('+0123.45e6', true));
$this->assertTrue(Validation::decimal('-0123.45e6', true));
$this->assertTrue(Validation::decimal('0123.45e6', true));
$this->assertTrue(Validation::decimal(1234.56, true));
$this->assertTrue(Validation::decimal(1234.00, true));
$this->assertTrue(Validation::decimal(1234., true));
$this->assertTrue(Validation::decimal('1234.00', true));
$this->assertTrue(Validation::decimal(.0, true));
$this->assertTrue(Validation::decimal(.00, true));
$this->assertTrue(Validation::decimal('.00', true));
$this->assertTrue(Validation::decimal(.01, true));
$this->assertTrue(Validation::decimal('.01', true));
$this->assertTrue(Validation::decimal((float) 1234, true));
$this->assertTrue(Validation::decimal((double) 1234, true));
$this->assertFalse(Validation::decimal('', true));
$this->assertFalse(Validation::decimal('string', true));
$this->assertFalse(Validation::decimal('1234.', true));
$this->assertFalse(Validation::decimal((int) 1234, true));
$this->assertFalse(Validation::decimal('1234', true));
$this->assertFalse(Validation::decimal('-1234', true));
$this->assertFalse(Validation::decimal('+1234', true));
}
/**
* Test numbers with exactly that many number of decimal places.
*
* @return void
*/
public function testDecimalWithPlacesNumeric() {
$this->assertTrue(Validation::decimal('.27', '2'));
$this->assertTrue(Validation::decimal(0.27, 2));
$this->assertTrue(Validation::decimal(-0.27, 2));
@ -1532,12 +1570,36 @@ class ValidationTest extends CakeTestCase {
$this->assertTrue(Validation::decimal(1234.5678, 4));
$this->assertTrue(Validation::decimal(-1234.5678, 4));
$this->assertTrue(Validation::decimal(1234.5678, 4));
$this->assertTrue(Validation::decimal('.00', 2));
$this->assertTrue(Validation::decimal(.01, 2));
$this->assertTrue(Validation::decimal('.01', 2));
$this->assertFalse(Validation::decimal('', 1));
$this->assertFalse(Validation::decimal('string', 1));
$this->assertFalse(Validation::decimal(1234., 1));
$this->assertFalse(Validation::decimal('1234.', 1));
$this->assertFalse(Validation::decimal(.0, 1));
$this->assertFalse(Validation::decimal(.00, 2));
$this->assertFalse(Validation::decimal((float) 1234, 1));
$this->assertFalse(Validation::decimal((double) 1234, 1));
$this->assertFalse(Validation::decimal((int) 1234, 1));
$this->assertFalse(Validation::decimal('1234.5678', '3'));
$this->assertFalse(Validation::decimal(1234.5678, 3));
$this->assertFalse(Validation::decimal(-1234.5678, 3));
$this->assertFalse(Validation::decimal(1234.5678, 3));
}
/**
* Test decimal() with invalid places parameter.
*
* @return void
*/
public function testDecimalWithInvalidPlaces() {
$this->assertFalse(Validation::decimal('.27', 'string'));
$this->assertFalse(Validation::decimal(1234.5678, (array) true));
$this->assertFalse(Validation::decimal(-1234.5678, (object) true));
}
/**
* testDecimalCustomRegex method
*

View file

@ -372,23 +372,39 @@ class Validation {
}
/**
* Checks that a value is a valid decimal. If $places is null, the $check is allowed to be a scientific float
* If no decimal point is found a false will be returned. Both the sign and exponent are optional.
* Checks that a value is a valid decimal. Both the sign and exponent are optional.
*
* Valid Places:
*
* - null => Any number of decimal places, including none. The '.' is not required.
* - true => Any number of decimal places greater than 0, or a float|double. The '.' is required.
* - 1..N => Exactly that many number of decimal places. The '.' is required.
*
* @param integer $check The value the test for decimal
* @param integer $places if set $check value must have exactly $places after the decimal point
* @param string $regex If a custom regular expression is used this is the only validation that will occur.
* @param integer $places
* @param string $regex If a custom regular expression is used, this is the only validation that will occur.
* @return boolean Success
*/
public static function decimal($check, $places = null, $regex = null) {
if (is_float($check) && floor($check) === $check) {
$check = sprintf("%.1f", $check);
}
if (is_null($regex)) {
if (is_null($places)) {
$regex = '/^[-+]?[0-9]*\\.{1}[0-9]+(?:[eE][-+]?[0-9]+)?$/';
} else {
$regex = '/^[-+]?[0-9]*\\.{1}[0-9]{' . $places . '}$/';
$lnum = '[0-9]+';
$dnum = "[0-9]*[\.]{$lnum}";
$sign = '[+-]?';
$exp = "(?:[eE]{$sign}{$lnum})?";
if ($places === null) {
$regex = "/^{$sign}(?:{$lnum}|{$dnum}){$exp}$/";
} elseif ($places === true) {
if (is_float($check) && floor($check) === $check) {
$check = sprintf("%.1f", $check);
}
$regex = "/^{$sign}{$dnum}{$exp}$/";
} elseif (is_numeric($places)) {
$places = '[0-9]{' . $places . '}';
$dnum = "(?:[0-9]*[\.]{$places}|{$lnum}[\.]{$places})";
$regex = "/^{$sign}{$dnum}{$exp}$/";
}
}
return self::_check($check, $regex);
@ -796,7 +812,7 @@ class Validation {
* @return boolean Success of match
*/
protected static function _check($check, $regex) {
if (preg_match($regex, $check)) {
if (is_string($regex) && preg_match($regex, $check)) {
self::$errors[] = false;
return true;
} else {