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
6 files changed