diff --git a/core/lib/Drupal/Component/Utility/Number.php b/core/lib/Drupal/Component/Utility/Number.php index 39143d9..7038017 100644 --- a/core/lib/Drupal/Component/Utility/Number.php +++ b/core/lib/Drupal/Component/Utility/Number.php @@ -17,9 +17,18 @@ class Number { * * This is based on the number/range verification methods of webkit. * - * @param float $value + * This is called by Drupal\Core\Render\Element\Number::validateNumber() to + * validate a numeric field. That function passes the $value parameter as a + * string, as provided on the text field of the form. Besides integers and + * floating numbers, we also support decimal numbers which are not stored in + * IEEE 754 format. In somewhat higher precisions for these numbers, the $step + * value cannot accurately represent the desired precision, when it is passed + * as a float. Passing it as a string bypasses this loss of precision and + * enables a correct calculation of the step validity. + * + * @param float|string $value * The value that needs to be checked. - * @param float $step + * @param float|string $step * The step scale factor. Must be positive. * @param float $offset * (optional) An offset, to which the difference must be a multiple of the diff --git a/core/modules/field/src/Tests/Number/NumberFieldTest.php b/core/modules/field/src/Tests/Number/NumberFieldTest.php index 09463d7..cd757b2 100644 --- a/core/modules/field/src/Tests/Number/NumberFieldTest.php +++ b/core/modules/field/src/Tests/Number/NumberFieldTest.php @@ -41,14 +41,14 @@ protected function setUp() { function testNumberDecimalField() { // Create a field with settings to validate. $field_name = Unicode::strtolower($this->randomMachineName()); - FieldStorageConfig::create(array( + FieldStorageConfig::create([ 'field_name' => $field_name, 'entity_type' => 'entity_test', 'type' => 'decimal', - 'settings' => array( + 'settings' => [ 'precision' => 10, 'scale' => 4, - ) - ))->save(); + ], + ])->save(); FieldConfig::create([ 'field_name' => $field_name, 'entity_type' => 'entity_test', @@ -74,24 +74,26 @@ function testNumberDecimalField() { $this->assertFieldByName("{$field_name}[0][value]", '', 'Widget is displayed'); $this->assertRaw('placeholder="0.00"'); - // Submit a signed decimal value within the allowed precision and scale. - $valid_entries = array( + // Submit a few signed decimal value within the allowed precision and scale. + $valid_entries = [ '-1234.5678', '19999.0000', '99999.0000', - ); + '9990009888.96', + '990088999.0099', + ]; foreach ($valid_entries as $valid_entry) { $this->drupalGet('entity_test/add'); - $edit = array( + $edit = [ "{$field_name}[0][value]" => $valid_entry, - ); + ]; $this->drupalPostForm(NULL, $edit, t('Save')); preg_match('|entity_test/manage/(\d+)|', $this->url, $match); $id = $match[1]; - $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created'); - $this->assertRaw($valid_entry, 'Value is displayed.'); - $this->assertNoRaw(t('%name is not a valid number.', array('%name' => $field_name)), 'Values are accepted'); + $this->assertText(t('entity_test @id has been created.', ['@id' => $id]), 'Entity was created'); + $this->assertRaw($valid_entry, t('Value @val is displayed.', ['@val' => $valid_entry])); + $this->assertNoRaw(t('%name is not a valid number.', ['%name' => $field_name]), 'Values are accepted'); } // Try to create entries with more than one decimal separator; assert fail. diff --git a/core/tests/Drupal/Tests/Component/Utility/NumberTest.php b/core/tests/Drupal/Tests/Component/Utility/NumberTest.php index 3e32629..a4414bb 100644 --- a/core/tests/Drupal/Tests/Component/Utility/NumberTest.php +++ b/core/tests/Drupal/Tests/Component/Utility/NumberTest.php @@ -89,6 +89,11 @@ public static function providerTestValidStep() { // Step mismatches very close to being valid. array(70 + 9e-7, 10 + 9e-7, FALSE), array(1936.5, 3e-8, FALSE), + + // These floats are valid, but might trigger FP math idiosyncracies. + // @see https://www.drupal.org/node/2230909 + [9990009888.96, 0.01, TRUE], + [990088999.0099, 0.0001, TRUE], ); }