diff --git a/lib/Cake/Test/Case/Utility/ValidationTest.php b/lib/Cake/Test/Case/Utility/ValidationTest.php index 6c87e08bf..d9886a663 100644 --- a/lib/Cake/Test/Case/Utility/ValidationTest.php +++ b/lib/Cake/Test/Case/Utility/ValidationTest.php @@ -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 * diff --git a/lib/Cake/Utility/Validation.php b/lib/Cake/Utility/Validation.php index bb33e2605..43347e37d 100644 --- a/lib/Cake/Utility/Validation.php +++ b/lib/Cake/Utility/Validation.php @@ -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 {