/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.ui.ridgets.validation;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.Locale;
import org.eclipse.riena.core.test.RienaTestCase;
import org.eclipse.riena.core.test.collect.NonUITestCase;
import org.eclipse.riena.core.util.ReflectionUtils;
/**
* Tests for the ValidCharacters rule.
*/
@NonUITestCase
public class ValidDecimalTest extends RienaTestCase {
/**
* @throws Exception
* Handled by JUnit.
*/
public final void testUSlocale() throws Exception {
final ValidDecimal rule = new ValidDecimal(false, 3, 15, true, Locale.US);
assertTrue(rule.validate(null).isOK());
assertTrue(rule.validate("0.00").isOK());
assertTrue(rule.validate("1.01").isOK());
assertTrue(rule.validate("1.000").isOK());
assertTrue(rule.validate("123.31").isOK());
assertTrue(rule.validate("1,234.31").isOK());
assertTrue(rule.validate("1,234.31").isOK());
assertTrue(rule.validate("-0.00").isOK());
assertTrue(rule.validate("-1.01").isOK());
assertTrue(rule.validate("-1.000").isOK());
assertTrue(rule.validate("-123.31").isOK());
assertTrue(rule.validate("-1,234.31").isOK());
assertTrue(rule.validate("- 0.00").isOK());
assertTrue(rule.validate("- 1.01").isOK());
assertTrue(rule.validate("- 1.000").isOK());
assertTrue(rule.validate("- 123.31").isOK());
assertTrue(rule.validate("- 1,234.31").isOK());
// only fraction
assertTrue(rule.validate(".123").isOK());
// reason why this is accepted:
assertEquals(0.123d, DecimalFormat.getInstance(Locale.US).parse(".123").doubleValue());
// only decimal-separator char:
assertFalse(rule.validate(".").isOK());
try { // reason why this must fail:
assertEquals(0.0d, DecimalFormat.getInstance(Locale.US).parse(".").doubleValue());
fail("expected a ParseException");
} catch (final ParseException e) {
ok("passed test");
}
// last char is fraction digit
assertTrue(rule.validate("0.").isOK());
assertEquals(0d, DecimalFormat.getInstance(Locale.US).parse("0.").doubleValue());
// missing fraction, no partial checks
assertFalse(rule.validate("0").isOK());
assertFalse(rule.validate("1").isOK());
assertFalse(rule.validate("123").isOK());
assertFalse(rule.validate("145").isOK());
assertFalse(rule.validate("156").isOK());
// Validate German Locale numbers with US locale rule:
// these will not pass, as they contain no decimal separator from the
// view of an US locale, but only grouping characters
assertFalse(rule.validate("0,00").isOK());
assertFalse(rule.validate("1,01").isOK());
assertFalse(rule.validate("1,000").isOK());
assertFalse(rule.validate("123,31").isOK());
// for the US locale it appears that the German grouping-character is
// behind the decimal-separator:
assertFalse(rule.validate("1.234,31").isOK());
// wrong symbols
assertFalse(rule.validate("A").isOK());
assertFalse(rule.validate("A123").isOK());
assertFalse(rule.validate("123A").isOK());
assertFalse(rule.validate("1.23A").isOK());
assertFalse(rule.validate("123A321").isOK());
assertFalse(rule.validate("abcdefghijklmnopqrstuvwxyz").isOK());
assertFalse(rule.validate("ABCDEFGHIJKLMBNOPQRSTUVWXYZ").isOK());
try {
rule.validate(new Object());
fail("expected a thrown ValidationFailure");
} catch (final ValidationFailure f) {
ok("expected a thrown ValidationFailure");
}
}
/**
* @throws Exception
* Handled by JUnit.
*/
public final void testGermanLocale() throws Exception {
final ValidDecimal rule = new ValidDecimal(false, 3, 15, true, Locale.GERMANY);
assertTrue(rule.validate(null).isOK());
assertTrue(rule.validate("0,00").isOK());
assertTrue(rule.validate("1,01").isOK());
assertTrue(rule.validate("1,000").isOK());
assertTrue(rule.validate("123,31").isOK());
assertTrue(rule.validate("1.234,31").isOK());
assertTrue(rule.validate("-0,00").isOK());
assertTrue(rule.validate("-1,01").isOK());
assertTrue(rule.validate("-1,000").isOK());
assertTrue(rule.validate("-123,31").isOK());
assertTrue(rule.validate("-1.234,31").isOK());
assertTrue(rule.validate("- 0,00").isOK());
assertTrue(rule.validate("- 1,01").isOK());
assertTrue(rule.validate("- 1,000").isOK());
assertTrue(rule.validate("- 123,31").isOK());
assertTrue(rule.validate("- 1.234,31").isOK());
// only fraction
assertTrue(rule.validate(",123").isOK());
// only decimal-separator char:
assertFalse(rule.validate(",").isOK());
// missing fraction, no partial checks
assertFalse(rule.validate("0").isOK());
assertFalse(rule.validate("1").isOK());
assertFalse(rule.validate("123").isOK());
assertFalse(rule.validate("145").isOK());
assertFalse(rule.validate("156").isOK());
// Validate US Locale numbers with German locale rule:
// these will not pass, as they contain no decimal separator from the
// view of a German locale, but only grouping characters
assertFalse(rule.validate("0.00").isOK());
assertFalse(rule.validate("1.01").isOK());
assertFalse(rule.validate("1.000").isOK());
assertFalse(rule.validate("123.31").isOK());
// for the German locale it appears that the US grouping-character is
// behind the decimal-separator:
assertFalse(rule.validate("1,234.31").isOK());
// wrong symbols
assertFalse(rule.validate("A").isOK());
assertFalse(rule.validate("A123").isOK());
assertFalse(rule.validate("123A").isOK());
assertFalse(rule.validate("1,23A").isOK());
assertFalse(rule.validate("123A321").isOK());
assertFalse(rule.validate("abcdefghijklmnopqrstuvwxyz").isOK());
assertFalse(rule.validate("ABCDEFGHIJKLMBNOPQRSTUVWXYZ").isOK());
try {
rule.validate(new Object());
fail("expected a thrown ValidationFailure");
} catch (final ValidationFailure f) {
ok("expected a thrown ValidationFailure");
}
}
/**
* @throws Exception
* Handled by JUnit.
*/
public final void testSwissLocale() throws Exception {
final ValidDecimal rule = new ValidDecimal(false, 3, 15, true, new Locale("de", "CH"));
assertTrue(rule.validate(null).isOK());
assertTrue(rule.validate("0.00").isOK());
assertTrue(rule.validate("1.01").isOK());
assertTrue(rule.validate("1.000").isOK());
assertTrue(rule.validate("123.31").isOK());
assertTrue(rule.validate("1'234.31").isOK());
assertTrue(rule.validate("-0.00").isOK());
assertTrue(rule.validate("-1.01").isOK());
assertTrue(rule.validate("-1.000").isOK());
assertTrue(rule.validate("-123.31").isOK());
assertTrue(rule.validate("-1'234.31").isOK());
assertTrue(rule.validate("- 0.00").isOK());
assertTrue(rule.validate("- 1.01").isOK());
assertTrue(rule.validate("- 1.000").isOK());
assertTrue(rule.validate("- 123.31").isOK());
assertTrue(rule.validate("- 1'234.31").isOK());
// only fraction
assertTrue(rule.validate(".123").isOK());
// only decimal-separator char:
assertFalse(rule.validate(".").isOK());
// only decimal-separator char:
assertFalse(rule.validate(",").isOK());
// missing fraction, no partial checks
assertFalse(rule.validate("0").isOK());
assertFalse(rule.validate("1").isOK());
assertFalse(rule.validate("123").isOK());
assertFalse(rule.validate("145").isOK());
assertFalse(rule.validate("156").isOK());
// Validate German Locale numbers with Swiss locale rule:
// these will not pass, as they contain no decimal separator from the
// view of a Swiss locale, but an alien character
assertFalse(rule.validate("0,00").isOK());
assertFalse(rule.validate("1,01").isOK());
assertFalse(rule.validate("1,000").isOK());
assertFalse(rule.validate("123,31").isOK());
// for the Swiss locale it appears that the German grouping-character is
// a decimal-separator, the alien character ',' makes the validation
// fail.
assertFalse(rule.validate("1.234,31").isOK());
// wrong symbols
assertFalse(rule.validate("A").isOK());
assertFalse(rule.validate("A123").isOK());
assertFalse(rule.validate("123A").isOK());
assertFalse(rule.validate("1,23A").isOK());
assertFalse(rule.validate("123A321").isOK());
assertFalse(rule.validate("abcdefghijklmnopqrstuvwxyz").isOK());
assertFalse(rule.validate("ABCDEFGHIJKLMBNOPQRSTUVWXYZ").isOK());
try {
rule.validate(new Object());
fail("expected a thrown ValidationFailure");
} catch (final ValidationFailure f) {
ok("expected a thrown ValidationFailure");
}
}
/**
* @throws Exception
* Handled by JUnit.
*/
public final void testFrenchLocale() throws Exception {
final ValidDecimal rule = new ValidDecimal(false, 3, 15, true, Locale.FRANCE);
assertTrue(rule.validate(null).isOK());
assertTrue(rule.validate("0,00").isOK());
assertTrue(rule.validate("1,01").isOK());
assertTrue(rule.validate("1,000").isOK());
assertTrue(rule.validate("123,31").isOK());
assertTrue(rule.validate("1 234,31").isOK());
assertTrue(rule.validate("-0,00").isOK());
assertTrue(rule.validate("-1,01").isOK());
assertTrue(rule.validate("-1,000").isOK());
assertTrue(rule.validate("-123,31").isOK());
assertTrue(rule.validate("-1 234,31").isOK());
assertTrue(rule.validate("- 0,00").isOK());
assertTrue(rule.validate("- 1,01").isOK());
assertTrue(rule.validate("- 1,000").isOK());
assertTrue(rule.validate("- 123,31").isOK());
assertTrue(rule.validate("- 1 234,31").isOK());
// only fraction
assertTrue(rule.validate(",123").isOK());
// only decimal-separator char:
assertFalse(rule.validate(",").isOK());
// missing fraction, no partial checks
assertFalse(rule.validate("0").isOK());
assertFalse(rule.validate("1").isOK());
assertFalse(rule.validate("123").isOK());
assertFalse(rule.validate("145").isOK());
assertFalse(rule.validate("156").isOK());
// Validate US Locale numbers with French locale rule:
// these will not pass, as they contain no decimal separator from the
// view of a French locale, but the US grouping-character is
// alien, so it won't parse the number:
assertFalse(rule.validate("0.00").isOK());
assertFalse(rule.validate("1.01").isOK());
assertFalse(rule.validate("1.000").isOK());
assertFalse(rule.validate("123.31").isOK());
// for the French locale it appears that the US grouping-character ','
// is a decimal-separator, the alien character '.' behind makes the
// validation fail.
assertFalse(rule.validate("1,234.31").isOK());
// wrong symbols
assertFalse(rule.validate("A").isOK());
assertFalse(rule.validate("A123").isOK());
assertFalse(rule.validate("123A").isOK());
assertFalse(rule.validate("1.23A").isOK());
assertFalse(rule.validate("123A321").isOK());
assertFalse(rule.validate("abcdefghijklmnopqrstuvwxyz").isOK());
assertFalse(rule.validate("ABCDEFGHIJKLMBNOPQRSTUVWXYZ").isOK());
try {
rule.validate(new Object());
fail("expected a thrown ValidationFailure");
} catch (final ValidationFailure f) {
ok("expected a thrown ValidationFailure");
}
}
public void testPartialCheckUSlocale() throws Exception {
final ValidDecimal rule = new ValidDecimal(true, Locale.US);
assertTrue(rule.validate(null).isOK());
assertTrue(rule.validate("0.00").isOK());
assertTrue(rule.validate("1.23").isOK());
assertTrue(rule.validate("1.").isOK());
assertTrue(rule.validate(".1").isOK());
assertTrue(rule.validate("1").isOK());
assertTrue(rule.validate("10").isOK());
assertTrue(rule.validate("1,000").isOK());
assertTrue(rule.validate("-0.00").isOK());
assertTrue(rule.validate("-1.23").isOK());
assertTrue(rule.validate("-1.").isOK());
assertTrue(rule.validate("-.1").isOK());
assertTrue(rule.validate("-1").isOK());
assertTrue(rule.validate("-10").isOK());
assertTrue(rule.validate("-1,000").isOK());
assertTrue(rule.validate("- 0.00").isOK());
assertTrue(rule.validate("- 1.23").isOK());
assertTrue(rule.validate("- 1.").isOK());
assertTrue(rule.validate("- .1").isOK());
assertTrue(rule.validate("- 1").isOK());
assertTrue(rule.validate("- 10").isOK());
assertTrue(rule.validate("- 1,000").isOK());
assertFalse(rule.validate(".").isOK());
// wrong symbols
assertFalse(rule.validate("A").isOK());
assertFalse(rule.validate("A123").isOK());
assertFalse(rule.validate("123A").isOK());
assertFalse(rule.validate("1.23A").isOK());
assertFalse(rule.validate("123A321").isOK());
assertFalse(rule.validate("abcdefghijklmnopqrstuvwxyz").isOK());
assertFalse(rule.validate("ABCDEFGHIJKLMBNOPQRSTUVWXYZ").isOK());
try {
rule.validate(new Object());
fail("expected a thrown ValidationFailure");
} catch (final ValidationFailure f) {
ok("expected a thrown ValidationFailure");
}
}
public final void testHindiLocale() throws Exception {
// this language has unusual digits
final Locale hindi = new Locale("hi", "IN");
final ValidDecimal rule = new ValidDecimal(hindi);
final DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance(hindi);
assertTrue(rule.validate(format.format(12.3d)).isOK());
assertTrue(rule.validate(format.format(12345.67d)).isOK());
assertTrue(rule.validate(format.format(-12.3d)).isOK());
assertTrue(rule.validate(format.format(-12345.67d)).isOK());
assertFalse(rule.validate(format.format(10)).isOK());
final ValidDecimal partial = new ValidDecimal(true, hindi);
assertTrue(partial.validate(format.format(12.3d)).isOK());
assertTrue(partial.validate(format.format(-12.3d)).isOK());
assertTrue(rule.validate(format.format(-12345.67d)).isOK());
assertTrue(partial.validate(format.format(10)).isOK());
// TODO: more Tests for for Hindi(Indian)
}
public final void testThailandLocale() throws Exception {
// this language has unusual digits
final Locale thailand = new Locale("th", "TH");
final ValidDecimal rule = new ValidDecimal(thailand);
final DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance(thailand);
assertTrue(rule.validate(format.format(12.3d)).isOK());
assertTrue(rule.validate(format.format(12345.67d)).isOK());
assertTrue(rule.validate(format.format(-12.3d)).isOK());
assertTrue(rule.validate(format.format(-12345.67d)).isOK());
assertFalse(rule.validate(format.format(10)).isOK());
final ValidDecimal partial = new ValidDecimal(true, thailand);
assertTrue(partial.validate(format.format(12.3d)).isOK());
assertTrue(rule.validate(format.format(12345.67d)).isOK());
assertTrue(partial.validate(format.format(-12.3d)).isOK());
assertTrue(rule.validate(format.format(-12345.67d)).isOK());
assertTrue(partial.validate(format.format(10)).isOK());
// TODO: more tests for Thai (Thailand,TH)
}
public final void testArabLocale() throws Exception {
// Arab countries seem to have a unified format
// They have trailing minus signs, instead of leading
final Locale arabEmirates = new Locale("ar", "AE");
final ValidDecimal rule = new ValidDecimal(arabEmirates);
final DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance(arabEmirates);
assertTrue(rule.validate(format.format(12.3d)).isOK());
assertTrue(rule.validate(format.format(12345.67d)).isOK());
assertTrue(rule.validate(format.format(-12.3d)).isOK());
assertTrue(rule.validate(format.format(-12345.67d)).isOK());
assertFalse(rule.validate(format.format(10)).isOK());
final ValidDecimal partial = new ValidDecimal(true, arabEmirates);
assertTrue(partial.validate(format.format(12.3d)).isOK());
assertTrue(rule.validate(format.format(12345.67d)).isOK());
assertTrue(partial.validate(format.format(-12.3d)).isOK());
assertTrue(rule.validate(format.format(-12345.67d)).isOK());
assertTrue(partial.validate(format.format(10)).isOK());
// TODO: more tests for Arab.
}
// TODO: Tests for Macedonia (mk_MK) with surrounding brackets
// public void testPrintAvailableLocaleFormats() {
// final double number = -1234.56;
// for (final Locale locale : NumberFormat.getAvailableLocales()) {
// if (locale.getCountry().length() != 0) {
// System.out.print(locale.getDisplayName() + "(" + locale + "): ");
// final NumberFormat format = DecimalFormat.getInstance(locale);
// System.out.print('"' + format.format(number) + '"');
// try {
// System.out.println(" = [" + format.parse(format.format(number)) + ']');
// } catch (ParseException e) {
// System.out.println(" = [cannot reformat to Number]");
// }
// }
// }
// }
/**
* Tests the method {@code setLocal(String[])}.
*/
public final void testSetLocalStringArray() throws Exception {
final MyValidDecimal validator = new MyValidDecimal();
Locale locale = ReflectionUtils.getHidden(validator, "locale");
assertSame(locale, Locale.getDefault());
validator.setLocale(new String[] {});
locale = ReflectionUtils.getHidden(validator, "locale");
assertSame(locale, Locale.getDefault());
validator.setLocale(new String[] { "hi" });
locale = ReflectionUtils.getHidden(validator, "locale");
assertEquals("hi", locale.getLanguage());
assertEquals("", locale.getCountry());
assertEquals("", locale.getVariant());
validator.setLocale(new String[] { "hi", "IND" });
locale = ReflectionUtils.getHidden(validator, "locale");
assertEquals("hi", locale.getLanguage());
assertEquals("IND", locale.getCountry());
assertEquals("", locale.getVariant());
validator.setLocale(new String[] { "es", "ES", "Traditional_WIN" });
locale = ReflectionUtils.getHidden(validator, "locale");
assertEquals("es", locale.getLanguage());
assertEquals("ES", locale.getCountry());
assertEquals("Traditional_WIN", locale.getVariant());
}
public void testSetInitializationData() throws Exception {
ValidDecimal validator = new ValidDecimal();
String localString = Locale.US.getLanguage() + "," + Locale.US.getCountry();
validator.setInitializationData(null, null, "false," + localString);
assertTrue(validator.validate("1,234.31").isOK());
assertFalse(validator.validate("1").isOK());
assertTrue(validator.validate("1.").isOK());
validator = new ValidDecimal();
validator.setInitializationData(null, null, "true," + localString);
assertTrue(validator.validate("1,234.31").isOK());
assertTrue(validator.validate("1").isOK());
assertTrue(validator.validate("1.").isOK());
validator = new ValidDecimal();
localString = Locale.GERMANY.getLanguage() + "," + Locale.GERMANY.getCountry();
validator.setInitializationData(null, null, "false," + localString);
assertTrue(validator.validate("1.234,31").isOK());
assertFalse(validator.validate("1").isOK());
assertTrue(validator.validate("1,").isOK());
}
public void testMaxLengthAndFractionDigitsDifferentLocales() {
testMaxLengthAndFractionDigits(Locale.US, '.');
testMaxLengthAndFractionDigits(Locale.GERMAN, ',');
testMaxLengthAndFractionDigits(new Locale("hi", "IN"), '.');
testMaxLengthAndFractionDigits(new Locale("de", "CH"), '.');
testMaxLengthAndFractionDigits(new Locale("ar", "AE"), '.');
testMaxLengthAndFractionDigits(Locale.FRANCE, ',');
testMaxLengthAndFractionDigits(new Locale("th", "TH"), '.');
}
private void testMaxLengthAndFractionDigits(final Locale locale, final char separator) {
final ValidDecimal rule = new ValidDecimal(false, 2, 4, true, locale);
assertTrue(rule.validate("0" + separator + "0").isOK());
assertTrue(rule.validate("0" + separator + "00").isOK());
assertFalse(rule.validate("0" + separator + "000").isOK());
assertTrue(rule.validate("00" + separator + "00").isOK());
assertTrue(rule.validate("000" + separator + "00").isOK());
assertTrue(rule.validate("0000" + separator + "00").isOK());
assertFalse(rule.validate("00000" + separator + "00").isOK());
assertFalse(rule.validate("00000" + separator + "000").isOK());
}
private static class MyValidDecimal extends ValidDecimal {
@Override
public void setLocale(final String[] localArgs) {
super.setLocale(localArgs);
}
}
}