Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ public static BigDecimalValidator getInstance() {
return VALIDATOR;
}

/**
* Tests whether the character at the given position of a pattern sits next to the currency symbol.
*
* @param pattern The pattern being stripped of its currency symbol.
* @param index The position to test.
* @return {@code true} if the character borders the currency symbol.
*/
private static boolean isNextToSymbol(final String pattern, final int index) {
return index > 0 && pattern.charAt(index - 1) == CURRENCY_SYMBOL
|| index + 1 < pattern.length() && pattern.charAt(index + 1) == CURRENCY_SYMBOL;
}
Comment thread
garydgregory marked this conversation as resolved.
Comment on lines +62 to +72

/**
* Constructs a <em>strict</em> instance.
*/
Expand Down Expand Up @@ -106,8 +118,11 @@ protected Object parse(final String value, final Format formatter) {
if (pattern.indexOf(CURRENCY_SYMBOL) >= 0) {
final StringBuilder buffer = new StringBuilder(pattern.length());
for (int i = 0; i < pattern.length(); i++) {
if (pattern.charAt(i) != CURRENCY_SYMBOL) {
buffer.append(pattern.charAt(i));
final char chr = pattern.charAt(i);
// A locale that suffixes the symbol usually separates it from the number with a (non-breaking)
// space. That space belongs to the symbol, so dropping only the symbol would leave it mandatory.
if (chr != CURRENCY_SYMBOL && !(Character.isSpaceChar(chr) && isNextToSymbol(pattern, i))) {
buffer.append(chr);
}
}
decimalFormat.applyPattern(buffer.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ public static BigDecimalValidator getInstance() {
return VALIDATOR;
}

/**
* Tests whether the character at the given position of a pattern sits next to the percent symbol.
*
* @param pattern The pattern being stripped of its percent symbol.
* @param index The position to test.
* @return {@code true} if the character borders the percent symbol.
*/
private static boolean isNextToSymbol(final String pattern, final int index) {
return index > 0 && pattern.charAt(index - 1) == PERCENT_SYMBOL
|| index + 1 < pattern.length() && pattern.charAt(index + 1) == PERCENT_SYMBOL;
}
Comment thread
garydgregory marked this conversation as resolved.

/**
* Constructs a <em>strict</em> instance.
*/
Expand Down Expand Up @@ -109,8 +121,11 @@ protected Object parse(final String value, final Format formatter) {
if (pattern.indexOf(PERCENT_SYMBOL) >= 0) {
final StringBuilder buffer = new StringBuilder(pattern.length());
for (int i = 0; i < pattern.length(); i++) {
if (pattern.charAt(i) != PERCENT_SYMBOL) {
buffer.append(pattern.charAt(i));
final char chr = pattern.charAt(i);
// A locale that suffixes the symbol usually separates it from the number with a (non-breaking)
// space. That space belongs to the symbol, so dropping only the symbol would leave it mandatory.
if (chr != PERCENT_SYMBOL && !(Character.isSpaceChar(chr) && isNextToSymbol(pattern, i))) {
buffer.append(chr);
}
}
decimalFormat.applyPattern(buffer.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ class CurrencyValidatorTest {

private static final char CURRENCY_SYMBOL = '\u00A4';

/** The character locales such as de-DE use between the number and a trailing currency symbol. */
private static final char NON_BREAKING_SPACE = '\u00A0';

private String usDollar;
private String ukPound;

Expand Down Expand Up @@ -176,6 +179,21 @@ void testPattern() {
assertFalse(validator.isValid(ukPound + "1,234.567", pattern, Locale.US), "invalid symbol");
}

/**
* Test currency values with a pattern that suffixes the symbol, which locales such as de-DE separate from the number with a non-breaking space. The symbol

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment make a claim about DE and the code about US. Add a test for each, or parameterize the current test for both, better yet, for all known currency symbols.

* is optional, so its separator has to be optional too.
*/
@Test
void testSuffixSymbolPattern() {
final BigDecimalValidator validator = CurrencyValidator.getInstance();
Comment on lines +187 to +188
final String pattern = "#,##0.00" + NON_BREAKING_SPACE + CURRENCY_SYMBOL;
final BigDecimal expected = new BigDecimal("1234.56");

assertEquals(expected, validator.validate("1,234.56" + NON_BREAKING_SPACE + usDollar, pattern, Locale.US), "symbol");
assertEquals(expected, validator.validate("1,234.56", pattern, Locale.US), "no symbol");
assertNull(validator.validate("1,234.56" + NON_BREAKING_SPACE, pattern, Locale.US), "separator without symbol");
}

/**
* Test Valid currency values
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
*/
class PercentValidatorTest {

private static final char PERCENT_SYMBOL = '%';

/** The character locales such as fr-FR use between the number and a trailing percent symbol. */
private static final char NON_BREAKING_SPACE = '\u00A0';

protected PercentValidator validator;
private Locale originalLocale;

Expand Down Expand Up @@ -100,6 +105,21 @@ void testNumberRangeExactBound() {
assertFalse(instance.minValue(new BigDecimal("5"), new BigDecimal("5.5")));
}

/**
* Test percentage values with a pattern that suffixes the symbol, which locales such as fr-FR separate from the number with a non-breaking space. The

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment make a claim about FR and the code about US. Add a test for each, or parameterize the current test for both, better yet, for all known currency symbols.

* symbol is optional, so its separator has to be optional too.
*/
@Test
void testSuffixSymbolPattern() {
final BigDecimalValidator validator = PercentValidator.getInstance();
Comment on lines +113 to +114
final String pattern = "#,##0" + NON_BREAKING_SPACE + PERCENT_SYMBOL;
final BigDecimal expected = new BigDecimal("0.12");

assertEquals(expected, validator.validate("12" + NON_BREAKING_SPACE + PERCENT_SYMBOL, pattern, Locale.US), "symbol");
assertEquals(expected, validator.validate("12", pattern, Locale.US), "no symbol");
assertNull(validator.validate("12" + NON_BREAKING_SPACE, pattern, Locale.US), "separator without symbol");
}

/**
* Test Valid percentage values
*/
Expand Down
Loading