2013-05-11 12:51:39 +02:00
|
|
|
<?php
|
2016-06-15 06:03:16 +02:00
|
|
|
|
2016-10-14 03:30:05 +02:00
|
|
|
namespace SilverStripe\Forms\Tests;
|
|
|
|
|
2016-08-19 00:51:35 +02:00
|
|
|
use SilverStripe\Dev\SapphireTest;
|
|
|
|
use SilverStripe\Forms\NumericField;
|
|
|
|
use SilverStripe\Forms\RequiredFields;
|
|
|
|
use SilverStripe\i18n\i18n;
|
|
|
|
|
2016-12-16 05:34:21 +01:00
|
|
|
class NumericFieldTest extends SapphireTest
|
|
|
|
{
|
|
|
|
protected $usesDatabase = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* In some cases and locales, validation expects non-breaking spaces.
|
2020-10-08 23:33:51 +02:00
|
|
|
* This homogenises narrow and regular NBSPs to a regular space character
|
2016-12-16 05:34:21 +01:00
|
|
|
*
|
|
|
|
* Duplicates non-public NumericField::clean method
|
|
|
|
*
|
|
|
|
* @param string $input
|
2020-10-08 23:33:51 +02:00
|
|
|
* @return string The input value, with all non-breaking spaces replaced with spaces
|
2016-12-16 05:34:21 +01:00
|
|
|
*/
|
|
|
|
protected function clean($input)
|
|
|
|
{
|
2020-10-08 23:33:51 +02:00
|
|
|
return str_replace(
|
|
|
|
[
|
2022-04-06 01:34:34 +02:00
|
|
|
html_entity_decode(' ', 0, 'UTF-8'),
|
|
|
|
html_entity_decode(' ', 0, 'UTF-8'), // narrow non-breaking space
|
2020-10-08 23:33:51 +02:00
|
|
|
],
|
|
|
|
' ',
|
|
|
|
trim($input)
|
|
|
|
);
|
2016-12-16 05:34:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test that data loaded in via Form::loadDataFrom(DataObject) will populate the field correctly,
|
|
|
|
* and can format the database value appropriately for the frontend
|
|
|
|
*
|
2017-01-26 05:20:08 +01:00
|
|
|
* @dataProvider dataForTestSetValue
|
|
|
|
* @param string $locale Locale to test in
|
|
|
|
* @param int $scale Scale size (number of decimal places)
|
|
|
|
* @param string $input Input string
|
|
|
|
* @param int|float $output Expected data value
|
2016-12-16 05:34:21 +01:00
|
|
|
*/
|
2017-01-26 05:20:08 +01:00
|
|
|
public function testSetValue($locale, $scale, $input, $output)
|
2016-12-16 05:34:21 +01:00
|
|
|
{
|
|
|
|
$field = new NumericField('Number');
|
2017-01-26 05:20:08 +01:00
|
|
|
if ($locale === 'html5') {
|
|
|
|
$field->setHTML5(true);
|
|
|
|
} else {
|
|
|
|
$field->setLocale($locale);
|
2016-12-16 05:34:21 +01:00
|
|
|
}
|
2017-01-26 05:20:08 +01:00
|
|
|
$field->setScale($scale);
|
2016-12-16 05:34:21 +01:00
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
// Load from DB via setValue
|
|
|
|
$field->setValue($input);
|
2016-12-16 05:34:21 +01:00
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
// Test value
|
|
|
|
$this->assertEquals(
|
|
|
|
$input,
|
|
|
|
$field->dataValue(),
|
|
|
|
"Expected $input loaded via dataobject to be left intact in locale $locale"
|
2016-12-16 05:34:21 +01:00
|
|
|
);
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
// Test expected formatted value
|
|
|
|
$this->assertEquals(
|
|
|
|
$this->clean($output),
|
|
|
|
$this->clean($field->Value()),
|
|
|
|
"Expected $input to be formatted as $output in locale $locale"
|
2016-12-16 05:34:21 +01:00
|
|
|
);
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
// Input values are always valid
|
|
|
|
$this->assertTrue($field->validate(new RequiredFields()));
|
2016-12-16 05:34:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-26 05:20:08 +01:00
|
|
|
* Test formatting of numbers
|
2016-12-16 05:34:21 +01:00
|
|
|
*/
|
2017-01-26 05:20:08 +01:00
|
|
|
public function dataForTestSetValue()
|
2016-12-16 05:34:21 +01:00
|
|
|
{
|
2017-01-26 05:20:08 +01:00
|
|
|
return [
|
|
|
|
// de
|
|
|
|
['de_DE', 0, '13000', "13.000"],
|
|
|
|
['de_DE', 0, '15', '15'],
|
|
|
|
['de_DE', null, '12.0', '12,0'],
|
|
|
|
['de_DE', null, '12.1', '12,1'],
|
|
|
|
['de_DE', 1, '14000.5', "14.000,5"],
|
|
|
|
// nl
|
|
|
|
['nl_NL', 0, '13000', "13.000"],
|
|
|
|
['nl_NL', 0, '15', '15'],
|
|
|
|
['nl_NL', null, '12.0', '12,0'],
|
|
|
|
['nl_NL', null, '12.1', '12,1'],
|
|
|
|
['nl_NL', 1, '14000.5', "14.000,5"],
|
|
|
|
// fr
|
|
|
|
['fr_FR', 0, '13000', "13 000"],
|
|
|
|
['fr_FR', 0, '15', '15'],
|
|
|
|
['fr_FR', null, '12.0', '12,0'],
|
|
|
|
['fr_FR', null, '12.1', '12,1'],
|
|
|
|
['fr_FR', 1, '14000.5', "14 000,5"],
|
|
|
|
// us
|
|
|
|
['en_US', 0, '13000', "13,000"],
|
|
|
|
['en_US', 0, '15', '15'],
|
|
|
|
['en_US', null, '12.0', '12.0'],
|
|
|
|
['en_US', null, '12.1', '12.1'],
|
|
|
|
['en_US', 1, '14000.5', "14,000.5"],
|
|
|
|
// html5
|
|
|
|
['html5', 0, '13000', "13000"],
|
|
|
|
['html5', 0, '15', '15'],
|
|
|
|
['html5', null, '12.0', '12.0'],
|
|
|
|
['html5', null, '12.1', '12.1'],
|
|
|
|
['html5', 1, '14000.5', "14000.5"],
|
|
|
|
];
|
2016-12-16 05:34:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testReadonly()
|
|
|
|
{
|
|
|
|
$field = new NumericField('Number');
|
2017-02-14 06:19:09 +01:00
|
|
|
$field->setLocale('de_DE');
|
|
|
|
$field->setScale(2);
|
|
|
|
$field->setValue(1001.3);
|
|
|
|
$html = $field->performReadonlyTransformation()->Field()->forTemplate();
|
2021-10-27 04:39:47 +02:00
|
|
|
$this->assertStringContainsString('value="1.001,30"', $html);
|
|
|
|
$this->assertStringContainsString('readonly="readonly"', $html);
|
2016-12-16 05:34:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testNumberTypeOnInputHtml()
|
|
|
|
{
|
|
|
|
$field = new NumericField('Number');
|
|
|
|
|
|
|
|
$html = $field->Field();
|
|
|
|
|
|
|
|
// @todo - Revert to number one day when html5 number supports proper localisation
|
|
|
|
// See https://github.com/silverstripe/silverstripe-framework/pull/4565
|
2021-10-27 04:39:47 +02:00
|
|
|
$this->assertStringContainsString('type="text"', $html, 'number type not set');
|
2016-12-16 05:34:21 +01:00
|
|
|
}
|
2017-01-26 05:20:08 +01:00
|
|
|
|
2017-07-05 12:45:29 +02:00
|
|
|
public function testNullSet()
|
|
|
|
{
|
2017-07-04 21:35:13 +02:00
|
|
|
$field = new NumericField('Number');
|
|
|
|
$field->setValue('');
|
|
|
|
$this->assertEquals('', $field->Value());
|
|
|
|
$this->assertNull($field->dataValue());
|
|
|
|
$field->setValue(null);
|
|
|
|
$this->assertNull($field->Value());
|
|
|
|
$this->assertNull($field->dataValue());
|
|
|
|
$field->setValue(0);
|
|
|
|
$this->assertEquals(0, $field->Value());
|
|
|
|
$this->assertEquals(0, $field->dataValue());
|
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
public function dataForTestSubmittedValue()
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
['de_DE', 0, '13000', 13000, '13.000'],
|
|
|
|
['de_DE', 2, '12,00', 12.00],
|
|
|
|
['de_DE', 2, '12.00', false],
|
|
|
|
['de_DE', 1, '11 000', 11000, '11.000,0'],
|
|
|
|
['de_DE', 0, '11.000', 11000],
|
|
|
|
['de_DE', null, '11,000', 11.0, '11,0'],
|
|
|
|
['de_DE', 1, '15 000,5', 15000.5, '15.000,5'],
|
|
|
|
['de_DE', 1, '15 000.5', false],
|
|
|
|
['de_DE', 1, '15.000,5', 15000.5],
|
|
|
|
['de_DE', 1, '15,000.5', false],
|
|
|
|
|
|
|
|
// nl_nl (same as de)
|
|
|
|
['nl_NL', 0, '13000', 13000, '13.000'],
|
|
|
|
['nl_NL', 2, '12,00', 12.00],
|
|
|
|
['nl_NL', 2, '12.00', false],
|
|
|
|
['nl_NL', 1, '11 000', 11000, '11.000,0'],
|
|
|
|
['nl_NL', 0, '11.000', 11000],
|
|
|
|
['nl_NL', null, '11,000', 11.0, '11,0'],
|
|
|
|
['nl_NL', 1, '15 000,5', 15000.5, '15.000,5'],
|
|
|
|
['nl_NL', 1, '15 000.5', false],
|
|
|
|
['nl_NL', 1, '15.000,5', 15000.5],
|
|
|
|
['nl_NL', 1, '15,000.5', false],
|
|
|
|
|
|
|
|
// fr
|
|
|
|
['fr_FR', 0, '13000', 13000, '13 000'],
|
|
|
|
['fr_FR', 2, '12,00', 12.0],
|
|
|
|
['fr_FR', 2, '12.00', false],
|
|
|
|
['fr_FR', 1, '11 000', 11000, '11 000,0'],
|
|
|
|
['fr_FR', 0, '11.000', 11000, '11 000'],
|
|
|
|
['fr_FR', null, '11,000', 11.000, '11,0'],
|
|
|
|
['fr_FR', 1, '15 000,5', 15000.5],
|
|
|
|
['fr_FR', 1, '15 000.5', false],
|
|
|
|
['fr_FR', 1, '15.000,5', 15000.5, '15 000,5'],
|
|
|
|
['fr_FR', 1, '15,000.5', false],
|
|
|
|
// us
|
|
|
|
['en_US', 0, '13000', 13000, '13,000'],
|
|
|
|
['en_US', 2, '12,00', false],
|
|
|
|
['en_US', 2, '12.00', 12.00],
|
|
|
|
['en_US', 1, '11 000', 11000.0, '11,000.0'],
|
|
|
|
['en_US', 0, '11.000', 11, '11'],
|
|
|
|
['en_US', null, '11,000', 11000, '11,000.0'],
|
|
|
|
['en_US', 1, '15 000,5', false],
|
|
|
|
['en_US', 1, '15 000.5', 15000.5, '15,000.5'],
|
|
|
|
['en_US', 1, '15.000,5', false],
|
|
|
|
['en_US', 1, '15,000.5', 15000.5],
|
|
|
|
// 'html5'
|
|
|
|
['html5', 0, '13000', 13000, '13000'],
|
|
|
|
['html5', 2, '12,00', false],
|
|
|
|
['html5', 2, '12.00', 12.00],
|
|
|
|
['html5', 1, '11 000', false, '11 000'],
|
|
|
|
['html5', 0, '11.000', 11, '11'],
|
|
|
|
['html5', null, '11,000', false],
|
|
|
|
['html5', 1, '15 000,5', false],
|
|
|
|
['html5', 1, '15 000.5', false],
|
|
|
|
['html5', 1, '15.000,5', false],
|
|
|
|
['html5', 1, '15,000.5', false],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider dataForTestSubmittedValue
|
|
|
|
* @param string $locale Locale to test in
|
|
|
|
* @param int $scale Scale size (number of decimal places)
|
|
|
|
* @param string $submittedValue Input string
|
|
|
|
* @param int|float $dataValue Expected data value
|
|
|
|
* @param string $cleanedInput
|
|
|
|
*/
|
|
|
|
public function testSetSubmittedValue($locale, $scale, $submittedValue, $dataValue, $cleanedInput = null)
|
|
|
|
{
|
|
|
|
$field = new NumericField('Number');
|
|
|
|
if ($locale === 'html5') {
|
|
|
|
$field->setHTML5(true);
|
|
|
|
} else {
|
|
|
|
$field->setLocale($locale);
|
|
|
|
}
|
|
|
|
$field->setScale($scale);
|
|
|
|
$validator = new RequiredFields('Number');
|
|
|
|
|
|
|
|
// Both decimal and thousands B
|
|
|
|
$field->setSubmittedValue($submittedValue);
|
|
|
|
|
|
|
|
// Check failure specific behaviour
|
|
|
|
if ($dataValue === false) {
|
|
|
|
$this->assertFalse(
|
|
|
|
$field->validate($validator),
|
|
|
|
"Expect validation to fail for input $submittedValue in locale $locale"
|
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
0,
|
|
|
|
$field->dataValue(),
|
|
|
|
"Expect invalid value to be rewritten to 0 in locale $locale"
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$this->assertTrue(
|
|
|
|
$field->validate($validator),
|
|
|
|
"Expect validation to succeed for $submittedValue in locale $locale"
|
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
$dataValue,
|
|
|
|
$field->dataValue(),
|
|
|
|
"Expect value $submittedValue to be mapped to $dataValue in locale $locale"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that small errors are corrected for
|
|
|
|
if (!$cleanedInput) {
|
|
|
|
$cleanedInput = $submittedValue;
|
|
|
|
}
|
|
|
|
$this->assertEquals(
|
|
|
|
$this->clean($cleanedInput),
|
|
|
|
$this->clean($field->Value()),
|
|
|
|
"Expected input $submittedValue to be cleaned up as $cleanedInput in locale $locale"
|
|
|
|
);
|
|
|
|
}
|
2014-11-03 10:13:54 +01:00
|
|
|
}
|