summaryrefslogtreecommitdiff
path: root/harmony-tests
diff options
context:
space:
mode:
authorVictor Chang <vichang@google.com>2018-07-27 13:41:43 +0100
committerVictor Chang <vichang@google.com>2019-05-22 13:32:58 +0100
commitcb77bb428e5867f96716c8695241bd5433a99403 (patch)
tree8d64c7e661c68f87cbdead4dad36ad1d9f231172 /harmony-tests
parentca4325f8918f0ead1e39b71d755112ad5a0c9a4e (diff)
Replace DecimalFormat_ICU58_Android with ICU4J DecimalFormat in compat mode
DecimalFormat_ICU58_Android is a technical debt and is not guaranteed to be compiled and work in the future due to internal dependency in ICU. The goal is to replace it with slightly patched ICU4J DecimalFormat, while the j.t.DecimalFormat has a behavior close to the current version. 1. Introduction of a new parse mode called "compatibility" Parse mode is an existing concept in ICU, but it has only strict mode or not. Android adds 3rd parse mode called "compatibility" to ICU4J. The current version of j.t.DecimalFormat exhibits some behaviors that strict mode ICU4J DecimalFormat doesn't have. The difference between strict and compatibility mode: a. Compatibility mode ignores grouping size in parsing. b. Compatibility mode does NOT ignore bidi control characters. It's stricter than strict mode. 2. Update DecimalFormat prefix/suffix setter API to throw NPE - In Android Q, when null prefix/suffix is set, DecimalFormat becomes an invalid object effectively, and throws NPE when format/parse is called. To avoid crashes in apps expecting old Android behavior, NPE is only thrown when target SDK level > 29 (API level in Q). - For target SDK level <= 29, the behavior is more permissive than Android Q was, i.e. doesn't throw NPE when calling {prefix|suffix} setter/format /parse. In Android Q, it throws NPE when calling format/parse. - For target SDK level > 29, the behavior is more restrictive than Android Q was, i.e. throws NPE immediately when calling prefix setter. - Test changes libcore.java.text.DecimalFormatTest#testPatternSeparator - Bug fix. The input and output pattern are now consistent in the test. libcore.java.text.DecimalFormatTest#testWhitespaceTolerated - Extra space before prefix of " " could be parsed inconsistently. Example: Whitespace(U+0020) before + sign prefix or no prefix is not tolerated before this change. With pattern " 0", input " 1 " could be parsed. Now it can't. This new behavior is consistent with RI, i.e. DecimalFormatTest#testWhitespaceError and #testWhitespaceTolerated pass on RI. libcore.java.text.OldDecimalFormatTestICU#test_sigDigitPatterns - The test has been asserting undefined behavior. Now Pattern "@.###" (undefined behavior) doesn't cause IllegalArgumentException. libcore.java.text.OldNumberFormatTest#test_setMaximumIntegerDigits - Bug fix. No more integer digit in output format when the maximum integer digits is <= 0 org.apache.harmony.tests.java.text.DecimalFormatTest#test_applyLocalizedPattern org.apache.harmony.tests.java.text.DecimalFormatTest#test_applyPattern org.apache.harmony.tests.java.text.DecimalFormatTest#test_applyPattern_icu2GroupingSizes org.apache.harmony.tests.java.text.DecimalFormatTest#test_toLocalizedPattern org.apache.harmony.tests.java.text.DecimalFormatTest#test_toPattern - Undefined behavior. Remove unnecessary leading # optional integer digit in output pattern. Leading # optional integer digit has always ignored, when no other symbol, e.g. grouping separator, is given. Now the change is also reflected in the output pattern. The return value of DecimalFormat.getMaximumIntegerDigits is not affected by this change. libcore.java.text.DecimalFormatTest#testBug15081434 org.apache.harmony.tests.java.text.DecimalFormatTest#test_setNegativePrefix org.apache.harmony.tests.java.text.DecimalFormatTest#test_setNegativeSuffix org.apache.harmony.tests.java.text.DecimalFormatTest#test_setPositivePrefix org.apache.harmony.tests.java.text.DecimalFormatTest#test_setPositiveSuffix - DecimalFormat prefix/suffix setter API to throw NPE libcore.java.text.OldNumberFormatTest#test_equals - DecimalFormat.equals has always been broken, e.g. the implementation wasn't symmetric in ICU 58. The following bugs are the examples. https://unicode-org.atlassian.net/browse/ICU-12567 https://unicode-org.atlassian.net/browse/ICU-11646 The new ICU DecimalFormat implementation fixed the above bugs, but broke the weak guarantee of equals(), which return false even though the MaximumIntegerDigits is set back to the original value (See the reason below.) This old behavior is not guaranteed by the java doc. Internally, the new ICU DecimalFormat implementation keeps tracking both input properties and the exported properties. After calling the setter, the input property is no longer the same. In general, a class can freely define their own internal states, and compare the states in equals() implementation. In favour of new behavior as it's now symmetric, but breaks weak guarantee that the instances externally returns the same state, e.g. MaximumIntegerDigits, but the internal states are still different, and becomes not equal. The test case ensures that setting the same state, e.g. call setMaximumIntegerDigits(100), makes 2 instances equal. Detailed discussion: https://unicode-org.atlassian.net/browse/ICU-13266 org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDouble_scientificNotation org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDouble_scientificNotationMinusZero org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatLong_scientificNotation - New test expectation is more aligned to the following java doc in DecimalFormat - The doc says "The number of significant digits in the mantissa is the sum of the minimum integer and maximum fraction digits, and is unaffected by the maximum integer digits." - #.0E0 pattern has min integer digit of 0 and max fraction digit of 1. According to the spec, the number of significant digits should be 1 instead of 2. Thus, the test expectation is changed accordingly. Bug: 69445420 Bug: 112023169 Bug: 112127077 Bug: 112355520 Test: CtsLibcoreTestCases Test: CtsLibcoreOjTestCases: Change-Id: I8178b6b46205146647bf9b79c8efca72a9cc70f9 Merged-In: Iddcaa94c6949b5c6c6550d9a865f5e0e7ee0b4a8 Merged-In: I4becc7fa077ff6699f3d737b52c3ee000db752b5 Merged-In: Ie8530c816e47a15abef011823cd3f2cb90d4c88b Merged-In: I1c6c33707404fe94bcf51d54e98254b1a5bc8127 Merged-In: Ia223a6a9f920aff12ea23835eca5739ff17daa28 Merged-In: I136612050e3f18c28572029bccc006401b6d4e28
Diffstat (limited to 'harmony-tests')
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java104
1 files changed, 64 insertions, 40 deletions
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
index 29470d1127..8b36163437 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
@@ -689,8 +689,12 @@ public class DecimalFormatTest extends TestCase {
format.setPositivePrefix("");
assertEquals("", format.getPositivePrefix());
- format.setPositivePrefix(null);
- assertNull(format.getPositivePrefix());
+ try {
+ format.setPositivePrefix(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ assertNotNull(format.getPositivePrefix());
}
public void test_setPositiveSuffix() throws Exception {
@@ -704,8 +708,12 @@ public class DecimalFormatTest extends TestCase {
format.setPositiveSuffix("");
assertEquals("", format.getPositiveSuffix());
- format.setPositiveSuffix(null);
- assertNull(format.getPositiveSuffix());
+ try {
+ format.setPositiveSuffix(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ assertNotNull(format.getPositiveSuffix());
}
public void test_setNegativePrefix() throws Exception {
@@ -718,8 +726,12 @@ public class DecimalFormatTest extends TestCase {
format.setNegativePrefix("");
assertEquals("", format.getNegativePrefix());
- format.setNegativePrefix(null);
- assertNull(format.getNegativePrefix());
+ try {
+ format.setNegativePrefix(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ assertNotNull(format.getNegativePrefix());
}
public void test_setNegativeSuffix() throws Exception {
@@ -733,8 +745,12 @@ public class DecimalFormatTest extends TestCase {
format.setNegativeSuffix("");
assertEquals("", format.getNegativeSuffix());
- format.setNegativeSuffix(null);
- assertNull(format.getNegativeSuffix());
+ try {
+ format.setNegativeSuffix(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ assertNotNull(format.getNegativeSuffix());
}
public void test_setGroupingUsed() {
@@ -867,13 +883,18 @@ public class DecimalFormatTest extends TestCase {
}
}
+ /**
+ * Test the constructor and applyPattern with various format patterns and what toPattern()
+ * returns. These have changed on Android over time: we are not particularly opinionated about
+ * the output of toPattern() in invalid cases.
+ */
public void test_applyPattern() {
DecimalFormat format = new DecimalFormat("#.#");
- assertEquals("Wrong pattern 1", "#0.#", format.toPattern());
+ assertEquals("Wrong pattern 1", "0.#", format.toPattern());
format = new DecimalFormat("#.");
- assertEquals("Wrong pattern 2", "#0.", format.toPattern());
+ assertEquals("Wrong pattern 2", "0.", format.toPattern());
format = new DecimalFormat("#");
- assertEquals("Wrong pattern 3", "#", format.toPattern());
+ assertEquals("Wrong pattern 3", "0", format.toPattern());
format = new DecimalFormat(".#");
assertEquals("Wrong pattern 4", "#.0", format.toPattern());
@@ -906,7 +927,10 @@ public class DecimalFormatTest extends TestCase {
}
}
- // AndroidOnly: icu supports 2 grouping sizes
+ /**
+ * Test applyPattern() with different grouping sizes and what toPattern() returns.
+ * AndroidOnly: icu supports 2 grouping sizes
+ */
public void test_applyPattern_icu2GroupingSizes() {
DecimalFormat decFormat = new DecimalFormat("#.#");
String[] patterns = {
@@ -917,12 +941,12 @@ public class DecimalFormatTest extends TestCase {
};
String[] expResult = {
- "#0.##", "#0.######", "#000000.000000",
- "#.000000", "#000000.######", " #0.###", "$#0.######",
- "$$#0.######",
- "%#,###,####", // icu only. icu supports two grouping sizes
+ "0.##", "0.######", "000000.000000",
+ "#.000000", "000000.######", " 0.###", "$0.######",
+ "$$0.######",
+ "%#,###,###0", // icu only. icu supports two grouping sizes
"#,##0.00;(#,##0.00)",
- "#0.##-E"
+ "0.##-E"
// icu only. E in the suffix does not need to be quoted.
};
@@ -940,11 +964,11 @@ public class DecimalFormatTest extends TestCase {
// case 1: Try to apply correct variants of pattern.
format.applyLocalizedPattern("#.#");
- assertEquals("Wrong pattern 1", "#0.#", format.toLocalizedPattern());
+ assertEquals("Wrong pattern 1", "0.#", format.toLocalizedPattern());
format.applyLocalizedPattern("#.");
- assertEquals("Wrong pattern 2", "#0.", format.toLocalizedPattern());
+ assertEquals("Wrong pattern 2", "0.", format.toLocalizedPattern());
format.applyLocalizedPattern("#");
- assertEquals("Wrong pattern 3", "#", format.toLocalizedPattern());
+ assertEquals("Wrong pattern 3", "0", format.toLocalizedPattern());
format.applyLocalizedPattern(".#");
assertEquals("Wrong pattern 4", "#.0", format.toLocalizedPattern());
@@ -966,11 +990,11 @@ public class DecimalFormatTest extends TestCase {
public void test_toPattern() {
DecimalFormat format = new DecimalFormat();
format.applyPattern("#.#");
- assertEquals("Wrong pattern 1", "#0.#", format.toPattern());
+ assertEquals("Wrong pattern 1", "0.#", format.toPattern());
format.applyPattern("#.");
- assertEquals("Wrong pattern 2", "#0.", format.toPattern());
+ assertEquals("Wrong pattern 2", "0.", format.toPattern());
format.applyPattern("#");
- assertEquals("Wrong pattern 3", "#", format.toPattern());
+ assertEquals("Wrong pattern 3", "0", format.toPattern());
format.applyPattern(".#");
assertEquals("Wrong pattern 4", "#.0", format.toPattern());
}
@@ -979,11 +1003,11 @@ public class DecimalFormatTest extends TestCase {
DecimalFormat format = new DecimalFormat();
format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
format.applyLocalizedPattern("#.#");
- assertEquals("Wrong pattern 1", "#0.#", format.toLocalizedPattern());
+ assertEquals("Wrong pattern 1", "0.#", format.toLocalizedPattern());
format.applyLocalizedPattern("#.");
- assertEquals("Wrong pattern 2", "#0.", format.toLocalizedPattern());
+ assertEquals("Wrong pattern 2", "0.", format.toLocalizedPattern());
format.applyLocalizedPattern("#");
- assertEquals("Wrong pattern 3", "#", format.toLocalizedPattern());
+ assertEquals("Wrong pattern 3", "0", format.toLocalizedPattern());
format.applyLocalizedPattern(".#");
assertEquals("Wrong pattern 4", "#.0", format.toLocalizedPattern());
}
@@ -1136,12 +1160,12 @@ public class DecimalFormatTest extends TestCase {
// Scientific notation => use significant digit logic
// '@' not present: Significant digits: Min: 1,
// Max: "min integer digits" (0) + "max fractional digits (1) == 1
- formatTester.format(df, "0.0E0", 0.0);
- formatTester.format(df, "1.0E0", 1.0);
- formatTester.format(df, "1.0E1", 12.0);
- formatTester.format(df, "1.0E2", 123.0);
- formatTester.format(df, "1.0E3", 1234.0);
- formatTester.format(df, "1.0E4", 9999.0);
+ formatTester.format(df, "0E0", 0.0);
+ formatTester.format(df, "1E0", 1.0);
+ formatTester.format(df, "1E1", 12.0);
+ formatTester.format(df, "1E2", 123.0);
+ formatTester.format(df, "1E3", 1234.0);
+ formatTester.format(df, "1E4", 9999.0);
df = new DecimalFormat("0.E0", dfs);
// ["0.E0",isDecimalSeparatorAlwaysShown=true,groupingSize=0,multiplier=1,negativePrefix=-,
@@ -1308,8 +1332,8 @@ public class DecimalFormatTest extends TestCase {
// Because maximum integer digit count is set: The exponent must be a multiple of it (1).
// Scientific notation => use significant digit logic
// '@' not present: Significant digits: Min: 1,
- // Max: "min integer digits" (0) + "max fractional digits (1) == 2
- formatTester.format(df, "-0.0E0", -0.0);
+ // Max: "min integer digits" (0) + "max fractional digits (1) == 1
+ formatTester.format(df, "-0E0", -0.0);
df = new DecimalFormat("0.#E0", dfs);
// ["0.#E0",isDecimalSeparatorAlwaysShown=false,groupingSize=0,multiplier=1,
@@ -1425,12 +1449,12 @@ public class DecimalFormatTest extends TestCase {
// Scientific notation => use significant digit logic
// '@' not present: Significant digits: Min: 1,
// Max: "min integer digits" (0) + "max fractional digits (1) == 1
- formatTester.format(df, "0.0E0", 0);
- formatTester.format(df, "1.0E0", 1);
- formatTester.format(df, "1.0E1", 12);
- formatTester.format(df, "1.0E2", 123);
- formatTester.format(df, "1.0E3", 1234);
- formatTester.format(df, "1.0E4", 9999);
+ formatTester.format(df, "0E0", 0);
+ formatTester.format(df, "1E0", 1);
+ formatTester.format(df, "1E1", 12);
+ formatTester.format(df, "1E2", 123);
+ formatTester.format(df, "1E3", 1234);
+ formatTester.format(df, "1E4", 9999);
df = new DecimalFormat("0.#E0", dfs);
// ["0.#E0",isDecimalSeparatorAlwaysShown=false,groupingSize=0,multiplier=1,