From b107622400d47eb5700cb8c332c2c68c4896dcb4 Mon Sep 17 00:00:00 2001 From: Michal Kleiner Date: Tue, 29 Nov 2022 15:07:56 +1300 Subject: [PATCH] FIX Improve rounding logic for storing of long decimal numbers (#10593) Co-authored-by: Michal Kleiner --- src/ORM/FieldType/DBDecimal.php | 2 +- tests/php/ORM/DecimalTest.php | 29 ++++++++++++++++++++++++ tests/php/ORM/DecimalTest/TestObject.php | 7 ++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/ORM/FieldType/DBDecimal.php b/src/ORM/FieldType/DBDecimal.php index 5af228bf8..eb2941afb 100644 --- a/src/ORM/FieldType/DBDecimal.php +++ b/src/ORM/FieldType/DBDecimal.php @@ -126,7 +126,7 @@ class DBDecimal extends DBField return 0; } - if (ctype_digit((string) $value)) { + if (abs((float) $value - (int) $value) < PHP_FLOAT_EPSILON) { return (int)$value; } diff --git a/tests/php/ORM/DecimalTest.php b/tests/php/ORM/DecimalTest.php index c61f81d9f..fffd2aecb 100644 --- a/tests/php/ORM/DecimalTest.php +++ b/tests/php/ORM/DecimalTest.php @@ -61,6 +61,35 @@ class DecimalTest extends SapphireTest ); } + public function testLongValueStoredCorrectly() + { + $this->assertEquals( + $this->testDataObject->MyDecimal5, + 1.0, + 'Long default long decimal value is rounded correctly' + ); + + $this->assertEqualsWithDelta( + $this->testDataObject->MyDecimal5, + 0.99999999999999999999, + PHP_FLOAT_EPSILON, + 'Long default long decimal value is correct within float epsilon' + ); + + $this->assertEquals( + $this->testDataObject->MyDecimal6, + 8.0, + 'Long decimal value with a default value is rounded correctly' + ); + + $this->assertEqualsWithDelta( + $this->testDataObject->MyDecimal6, + 7.99999999999999999999, + PHP_FLOAT_EPSILON, + 'Long decimal value is within epsilon if longer than allowed number of float digits' + ); + } + public function testScaffoldFormField() { /** @var DBDecimal $decimal */ diff --git a/tests/php/ORM/DecimalTest/TestObject.php b/tests/php/ORM/DecimalTest/TestObject.php index 1dce40f4b..2dd5da898 100644 --- a/tests/php/ORM/DecimalTest/TestObject.php +++ b/tests/php/ORM/DecimalTest/TestObject.php @@ -14,10 +14,13 @@ class TestObject extends DataObject implements TestOnly 'MyDecimal1' => 'Decimal', 'MyDecimal2' => 'Decimal(5,3,2.5)', 'MyDecimal3' => 'Decimal(4,2,"Invalid default value")', - 'MyDecimal4' => 'Decimal' + 'MyDecimal4' => 'Decimal', + 'MyDecimal5' => 'Decimal(20,18,0.99999999999999999999)', + 'MyDecimal6' => 'Decimal', ]; private static $defaults = [ - 'MyDecimal4' => 4 + 'MyDecimal4' => 4, + 'MyDecimal6' => 7.99999999999999999999, ]; }