]> granicus.if.org Git - icu/commitdiff
ICU-13513 Fixing various issues uncovered by a full project test. Ant Check is now...
authorShane Carr <shane@unicode.org>
Sat, 27 Jan 2018 11:21:33 +0000 (11:21 +0000)
committerShane Carr <shane@unicode.org>
Sat, 27 Jan 2018 11:21:33 +0000 (11:21 +0000)
X-SVN-Rev: 40813

19 files changed:
icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/PropertiesAffixPatternProvider.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/AffixMatcher.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/AffixPatternMatcher.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/MatcherFactory.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/MinusSignMatcher.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ParsedNumber.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/PlusSignMatcher.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/StringSegment.java
icu4j/main/classes/core/src/com/ibm/icu/number/Grouper.java
icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java
icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberformattestspecification.txt
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatDataDrivenTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberRegressionTests.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/DecimalQuantityTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberParserTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/UnicodeSetStaticCacheTest.java

index b190c90e37f1a5022798efe568762ef0eff9df6f..03bd98379f85071878fda2951e1080c431a85cae 100644 (file)
@@ -603,7 +603,7 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
         // Hard case: the magnitude is 10^18.
         // The largest int64 is: 9,223,372,036,854,775,807
         for (int p = 0; p < precision; p++) {
-            byte digit = getDigitPos(18 - p);
+            byte digit = getDigit(18 - p);
             if (digit < INT64_BCD[p]) {
                 return true;
             } else if (digit > INT64_BCD[p]) {
index eca537a69d497cfccd099cf517040301c435c32b..c6b57ba9201ea8e8e85f44ba75ef1646d22bce31 100644 (file)
@@ -126,4 +126,18 @@ public class PropertiesAffixPatternProvider implements AffixPatternProvider {
         return AffixUtils.containsType(posPrefix, type) || AffixUtils.containsType(posSuffix, type)
                 || AffixUtils.containsType(negPrefix, type) || AffixUtils.containsType(negSuffix, type);
     }
+
+    @Override
+    public String toString() {
+        return super.toString()
+                + " {"
+                + posPrefix
+                + "#"
+                + posSuffix
+                + ";"
+                + negPrefix
+                + "#"
+                + negSuffix
+                + "}";
+    }
 }
\ No newline at end of file
index e57894084f09532256a060c829a5420e15482f08..85369438c176d4fcd982bdf6c8498fa95273ddb7 100644 (file)
@@ -61,7 +61,13 @@ public class AffixMatcher implements NumberParseMatcher {
                 && AffixUtils.containsOnlySymbolsAndIgnorables(posPrefixString, ignorables.getSet())
                 && AffixUtils.containsOnlySymbolsAndIgnorables(posSuffixString, ignorables.getSet())
                 && AffixUtils.containsOnlySymbolsAndIgnorables(negPrefixString, ignorables.getSet())
-                && AffixUtils.containsOnlySymbolsAndIgnorables(negSuffixString, ignorables.getSet())) {
+                && AffixUtils.containsOnlySymbolsAndIgnorables(negSuffixString, ignorables.getSet())
+                // HACK: Plus and minus sign are a special case: we accept them trailing only if they are
+                // trailing in the pattern string.
+                && !AffixUtils.containsType(posSuffixString, AffixUtils.TYPE_PLUS_SIGN)
+                && !AffixUtils.containsType(posSuffixString, AffixUtils.TYPE_MINUS_SIGN)
+                && !AffixUtils.containsType(negSuffixString, AffixUtils.TYPE_PLUS_SIGN)
+                && !AffixUtils.containsType(negSuffixString, AffixUtils.TYPE_MINUS_SIGN)) {
             // The affixes contain only symbols and ignorables.
             // No need to generate affix matchers.
             return;
index 69416baf1584f67435a7453a908ca02236a56c7f..ee041f64ab26389a5ca75dc10f0b6964d269ebea 100644 (file)
@@ -72,10 +72,10 @@ public class AffixPatternMatcher extends SeriesMatcher implements AffixUtils.Tok
             // Case 1: the token is a symbol.
             switch (typeOrCp) {
             case AffixUtils.TYPE_MINUS_SIGN:
-                addMatcher(factory.minusSign());
+                addMatcher(factory.minusSign(true));
                 break;
             case AffixUtils.TYPE_PLUS_SIGN:
-                addMatcher(factory.plusSign());
+                addMatcher(factory.plusSign(true));
                 break;
             case AffixUtils.TYPE_PERCENT:
                 addMatcher(factory.percent());
index 8c6695f217664fb17f8b96e0ff0f9789d4a2e61f..a1e3675869391e887c5a6b506e21a550a18635b1 100644 (file)
@@ -17,12 +17,12 @@ public class MatcherFactory {
     ULocale locale;
     int parseFlags;
 
-    public MinusSignMatcher minusSign() {
-        return MinusSignMatcher.getInstance(symbols);
+    public MinusSignMatcher minusSign(boolean allowTrailing) {
+        return MinusSignMatcher.getInstance(symbols, allowTrailing);
     }
 
-    public PlusSignMatcher plusSign() {
-        return PlusSignMatcher.getInstance(symbols);
+    public PlusSignMatcher plusSign(boolean allowTrailing) {
+        return PlusSignMatcher.getInstance(symbols, allowTrailing);
     }
 
     public PercentMatcher percent() {
index 3d3a09148e6fd5d8c6aff7d4fa792da562a052cb..d011986aa40a0c936e566cb644cd565d47ca65d7 100644 (file)
@@ -10,28 +10,34 @@ import com.ibm.icu.text.DecimalFormatSymbols;
  */
 public class MinusSignMatcher extends SymbolMatcher {
 
-    private static final MinusSignMatcher DEFAULT = new MinusSignMatcher();
+    private static final MinusSignMatcher DEFAULT = new MinusSignMatcher(false);
+    private static final MinusSignMatcher DEFAULT_ALLOW_TRAILING = new MinusSignMatcher(true);
 
-    public static MinusSignMatcher getInstance(DecimalFormatSymbols symbols) {
+    public static MinusSignMatcher getInstance(DecimalFormatSymbols symbols, boolean allowTrailing) {
         String symbolString = symbols.getMinusSignString();
         if (DEFAULT.uniSet.contains(symbolString)) {
-            return DEFAULT;
+            return allowTrailing ? DEFAULT_ALLOW_TRAILING : DEFAULT;
         } else {
-            return new MinusSignMatcher(symbolString);
+            return new MinusSignMatcher(symbolString, allowTrailing);
         }
     }
 
-    private MinusSignMatcher(String symbolString) {
+    private final boolean allowTrailing;
+
+    private MinusSignMatcher(String symbolString, boolean allowTrailing) {
         super(symbolString, DEFAULT.uniSet);
+        this.allowTrailing = allowTrailing;
     }
 
-    private MinusSignMatcher() {
+    private MinusSignMatcher(boolean allowTrailing) {
         super(UnicodeSetStaticCache.Key.MINUS_SIGN);
+        this.allowTrailing = allowTrailing;
     }
 
     @Override
     protected boolean isDisabled(ParsedNumber result) {
-        return 0 != (result.flags & ParsedNumber.FLAG_NEGATIVE);
+        return 0 != (result.flags & ParsedNumber.FLAG_NEGATIVE)
+                || (allowTrailing ? false : result.seenNumber());
     }
 
     @Override
index ca878f636b8f74a8ec9a776994018dd20eea17ce..b808c6ec8ef1e23d2250a1c1936b822c51496e73 100644 (file)
@@ -62,7 +62,7 @@ public class NumberParserImpl {
 
         parser.addMatcher(ignorables);
         parser.addMatcher(DecimalMatcher.getInstance(symbols, grouper, parseFlags));
-        parser.addMatcher(MinusSignMatcher.getInstance(symbols));
+        parser.addMatcher(MinusSignMatcher.getInstance(symbols, false));
         parser.addMatcher(NanMatcher.getInstance(symbols, parseFlags));
         parser.addMatcher(ScientificMatcher.getInstance(symbols, grouper, parseFlags));
         parser.addMatcher(CurrencyTrieMatcher.getInstance(locale));
@@ -81,10 +81,10 @@ public class NumberParserImpl {
         ParsedNumber result = new ParsedNumber();
         parser.parse(input, true, result);
         if (result.success()) {
-            ppos.setIndex(result.charsConsumed);
+            ppos.setIndex(result.charEnd);
             return result.getNumber();
         } else {
-            ppos.setErrorIndex(result.charsConsumed);
+            ppos.setErrorIndex(result.charEnd);
             return null;
         }
     }
@@ -98,7 +98,7 @@ public class NumberParserImpl {
         ParsedNumber result = new ParsedNumber();
         parser.parse(input, true, result);
         if (result.success()) {
-            ppos.setIndex(result.charsConsumed);
+            ppos.setIndex(result.charEnd);
             // TODO: Clean this up
             Currency currency;
             if (result.currencyCode != null) {
@@ -110,7 +110,7 @@ public class NumberParserImpl {
             }
             return new CurrencyAmount(result.getNumber(), currency);
         } else {
-            ppos.setErrorIndex(result.charsConsumed);
+            ppos.setErrorIndex(result.charEnd);
             return null;
         }
     }
@@ -153,7 +153,7 @@ public class NumberParserImpl {
         } else {
             parseFlags |= ParsingUtils.PARSE_FLAG_INCLUDE_UNPAIRED_AFFIXES;
         }
-        if (grouper.getPrimary() == -1) {
+        if (grouper.getPrimary() <= 0) {
             parseFlags |= ParsingUtils.PARSE_FLAG_GROUPING_DISABLED;
         }
         if (parseCurrency || patternInfo.hasCurrencySign()) {
@@ -193,9 +193,9 @@ public class NumberParserImpl {
         if (!isStrict
                 || patternInfo.containsSymbolType(AffixUtils.TYPE_PLUS_SIGN)
                 || properties.getSignAlwaysShown()) {
-            parser.addMatcher(PlusSignMatcher.getInstance(symbols));
+            parser.addMatcher(PlusSignMatcher.getInstance(symbols, false));
         }
-        parser.addMatcher(MinusSignMatcher.getInstance(symbols));
+        parser.addMatcher(MinusSignMatcher.getInstance(symbols, false));
         parser.addMatcher(NanMatcher.getInstance(symbols, parseFlags));
         parser.addMatcher(PercentMatcher.getInstance(symbols));
         parser.addMatcher(PermilleMatcher.getInstance(symbols));
@@ -318,6 +318,7 @@ public class NumberParserImpl {
      */
     public void parse(String input, int start, boolean greedy, ParsedNumber result) {
         assert frozen;
+        assert start >= 0 && start < input.length();
         StringSegment segment = new StringSegment(ParsingUtils.maybeFold(input, parseFlags));
         segment.adjustOffset(start);
         if (greedy) {
index 1bbbc6b16d616c9628407e5ba6ef9be3d280dff3..27ce15df1f692572d8bab3bbfc46037a22895fc4 100644 (file)
@@ -16,11 +16,12 @@ public class ParsedNumber {
     public DecimalQuantity_DualStorageBCD quantity;
 
     /**
-     * The number of chars accepted during parsing. This is NOT necessarily the same as the StringSegment
-     * offset; "weak" chars, like whitespace, change the offset, but the charsConsumed is not touched
-     * until a "strong" char is encountered.
+     * The index of the last char consumed during parsing. If parsing started at index 0, this is equal
+     * to the number of chars consumed. This is NOT necessarily the same as the StringSegment offset;
+     * "weak" chars, like whitespace, change the offset, but the charsConsumed is not touched until a
+     * "strong" char is encountered.
      */
-    public int charsConsumed;
+    public int charEnd;
 
     /**
      * Boolean flags (see constants below).
@@ -56,7 +57,7 @@ public class ParsedNumber {
     public static final Comparator<ParsedNumber> COMPARATOR = new Comparator<ParsedNumber>() {
         @Override
         public int compare(ParsedNumber o1, ParsedNumber o2) {
-            return o1.charsConsumed - o2.charsConsumed;
+            return o1.charEnd - o2.charEnd;
         }
     };
 
@@ -69,7 +70,7 @@ public class ParsedNumber {
      */
     public void clear() {
         quantity = null;
-        charsConsumed = 0;
+        charEnd = 0;
         flags = 0;
         prefix = null;
         suffix = null;
@@ -79,15 +80,31 @@ public class ParsedNumber {
     public void copyFrom(ParsedNumber other) {
         quantity = other.quantity == null ? null
                 : (DecimalQuantity_DualStorageBCD) other.quantity.createCopy();
-        charsConsumed = other.charsConsumed;
+        charEnd = other.charEnd;
         flags = other.flags;
         prefix = other.prefix;
         suffix = other.suffix;
         currencyCode = other.currencyCode;
     }
 
+    /**
+     * Call this method to register that a "strong" char was consumed. This should be done after calling
+     * {@link StringSegment#setOffset} or {@link StringSegment#adjustOffset} except when the char is
+     * "weak", like whitespace.
+     *
+     * <p>
+     * <strong>What is a strong versus weak char?</strong> The behavior of number parsing is to "stop"
+     * after reading the number, even if there is other content following the number. For example, after
+     * parsing the string "123 " (123 followed by a space), the cursor should be set to 3, not 4, even
+     * though there are matchers that accept whitespace. In this example, the digits are strong, whereas
+     * the whitespace is weak. Grouping separators are weak, whereas decimal separators are strong. Most
+     * other chars are strong.
+     *
+     * @param segment
+     *            The current StringSegment, usually immediately following a call to setOffset.
+     */
     public void setCharsConsumed(StringSegment segment) {
-        charsConsumed = segment.getOffset();
+        charEnd = segment.getOffset();
     }
 
     /**
@@ -95,7 +112,7 @@ public class ParsedNumber {
      * consumed, and the failure flag must not be set.
      */
     public boolean success() {
-        return charsConsumed > 0 && 0 == (flags & FLAG_FAIL);
+        return charEnd > 0 && 0 == (flags & FLAG_FAIL);
     }
 
     public boolean seenNumber() {
index 950a03eaaadf5f0e9b47ef5fa91f8d4dd8b6af8f..598bd159804a876b6f5fcb8d9b46a8ac72cf1883 100644 (file)
@@ -10,28 +10,33 @@ import com.ibm.icu.text.DecimalFormatSymbols;
  */
 public class PlusSignMatcher extends SymbolMatcher {
 
-    private static final PlusSignMatcher DEFAULT = new PlusSignMatcher();
+    private static final PlusSignMatcher DEFAULT = new PlusSignMatcher(false);
+    private static final PlusSignMatcher DEFAULT_ALLOW_TRAILING = new PlusSignMatcher(true);
 
-    public static PlusSignMatcher getInstance(DecimalFormatSymbols symbols) {
+    public static PlusSignMatcher getInstance(DecimalFormatSymbols symbols, boolean allowTrailing) {
         String symbolString = symbols.getPlusSignString();
         if (DEFAULT.uniSet.contains(symbolString)) {
-            return DEFAULT;
+            return allowTrailing ? DEFAULT_ALLOW_TRAILING : DEFAULT;
         } else {
-            return new PlusSignMatcher(symbolString);
+            return new PlusSignMatcher(symbolString, allowTrailing);
         }
     }
 
-    private PlusSignMatcher(String symbolString) {
+    private final boolean allowTrailing;
+
+    private PlusSignMatcher(String symbolString, boolean allowTrailing) {
         super(symbolString, DEFAULT.uniSet);
+        this.allowTrailing = allowTrailing;
     }
 
-    private PlusSignMatcher() {
+    private PlusSignMatcher(boolean allowTrailing) {
         super(UnicodeSetStaticCache.Key.PLUS_SIGN);
+        this.allowTrailing = allowTrailing;
     }
 
     @Override
     protected boolean isDisabled(ParsedNumber result) {
-        return false;
+        return allowTrailing ? false : result.seenNumber();
     }
 
     @Override
index 0bf8b0c33e24d5ce2d69d3b3bbf83078e158d127..6b92df6e368d1f9b8362be65f9badb8b74021ef4 100644 (file)
@@ -28,6 +28,14 @@ public class StringSegment implements CharSequence {
         this.start = start;
     }
 
+    /**
+     * Equivalent to <code>setOffset(getOffset()+delta)</code>.
+     *
+     * <p>
+     * This method is usually called by a Matcher to register that a char was consumed. If the char is
+     * strong (it usually is, except for things like whitespace), follow this with a call to
+     * {@link ParsedNumber#setCharsConsumed}. For more information on strong chars, see that method.
+     */
     public void adjustOffset(int delta) {
         assert start + delta >= 0;
         assert start + delta <= end;
index 3b31e2ee3183114c5ef12bd5923d11ae9f40b6a2..24d46f597b0136514b743af6a3ebdba57ba2b05c 100644 (file)
@@ -97,7 +97,7 @@ public class Grouper {
         byte grouping1 = (byte) properties.getGroupingSize();
         byte grouping2 = (byte) properties.getSecondaryGroupingSize();
         int minGrouping = properties.getMinimumGroupingDigits();
-        grouping1 = grouping1 > 0 ? grouping1 : grouping2 > 0 ? grouping2 : -1;
+        grouping1 = grouping1 > 0 ? grouping1 : grouping2 > 0 ? grouping2 : grouping1;
         grouping2 = grouping2 > 0 ? grouping2 : grouping1;
         // TODO: Is it important to handle minGrouping > 2?
         return getInstance(grouping1, grouping2, minGrouping == 2);
index e7262d00ca8c5d31e69dfb1e660793d584d630e0..72ada1859507288a065a52d488c8a43eab617e66 100644 (file)
@@ -796,6 +796,13 @@ public class DecimalFormat extends NumberFormat {
       if (parsePosition == null) {
           parsePosition = new ParsePosition(0);
       }
+      if (parsePosition.getIndex() < 0) {
+          throw new IllegalArgumentException("Cannot start parsing at a negative offset");
+      }
+      if (parsePosition.getIndex() >= text.length()) {
+          // For backwards compatibility, this is not an exception, just an empty result.
+          return null;
+      }
 
       ParsedNumber result = new ParsedNumber();
       // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the
@@ -803,7 +810,7 @@ public class DecimalFormat extends NumberFormat {
       int startIndex = parsePosition.getIndex();
       parser.parse(text, startIndex, true, result);
       if (result.success()) {
-          parsePosition.setIndex(startIndex + result.charsConsumed);
+          parsePosition.setIndex(result.charEnd);
           // TODO: Accessing properties here is technically not thread-safe
           Number number = result.getNumber(properties.getParseToBigDecimal());
           // Backwards compatibility: return com.ibm.icu.math.BigDecimal
@@ -812,7 +819,7 @@ public class DecimalFormat extends NumberFormat {
           }
           return number;
       } else {
-          parsePosition.setErrorIndex(startIndex + result.charsConsumed);
+          parsePosition.setErrorIndex(startIndex + result.charEnd);
           return null;
       }
   }
@@ -830,12 +837,19 @@ public class DecimalFormat extends NumberFormat {
       if (parsePosition == null) {
           parsePosition = new ParsePosition(0);
       }
+      if (parsePosition.getIndex() < 0) {
+          throw new IllegalArgumentException("Cannot start parsing at a negative offset");
+      }
+      if (parsePosition.getIndex() >= text.length()) {
+          // For backwards compatibility, this is not an exception, just an empty result.
+          return null;
+      }
 
       ParsedNumber result = new ParsedNumber();
       int startIndex = parsePosition.getIndex();
       parserWithCurrency.parse(text.toString(), startIndex, true, result);
       if (result.success()) {
-          parsePosition.setIndex(startIndex + result.charsConsumed);
+          parsePosition.setIndex(result.charEnd);
           // TODO: Accessing properties here is technically not thread-safe
           Number number = result.getNumber(properties.getParseToBigDecimal());
           // Backwards compatibility: return com.ibm.icu.math.BigDecimal
@@ -845,7 +859,7 @@ public class DecimalFormat extends NumberFormat {
           Currency currency = Currency.getInstance(result.currencyCode);
           return new CurrencyAmount(number, currency);
       } else {
-          parsePosition.setErrorIndex(startIndex + result.charsConsumed);
+          parsePosition.setErrorIndex(startIndex + result.charEnd);
           return null;
       }
   }
index aeb3607d71c2993f87af8f8dc1674dfea9a05e39..3aa732a70d80efef7047883e9719515df88a70bd 100644 (file)
@@ -443,8 +443,7 @@ en_US       1       123.456 123.456
 en_US  0       123.456 123.456
 it_IT  1       123,456 123.456
 it_IT  0       123,456 123.456
-// JDK returns 123 here; not sure why.
-it_IT  1       123.456 123456  K
+it_IT  1       123.456 123456
 it_IT  0       123.456 123
 
 test no grouping in pattern with parsing
@@ -755,9 +754,9 @@ parse       output  breaks
 +1,234,567.8901        1234567.8901
 +1,23,4567.8901        1234567.8901
 // P supports grouping separators in the fraction; none of the others do.
-+1,23,4567.89,01       1234567.8901    CJK
++1,23,4567.89,01       1234567.8901    CJKS
 +1,23,456.78.9 123456.78
-+12.34,56      12.3456 CJK
++12.34,56      12.3456 CJKS
 +79,,20,3      79203
 +79  20 3      79203   K
 // Parsing stops at comma as it is different from other separators
@@ -863,7 +862,7 @@ parse       output  breaks
 +1,234.5       1234.5
 // Comma after decimal means a fractional grouping separator
 // P fails since it finds an invalid grouping size
-+1,23,456.78,9 123456.789      P
++1,23,456.78,9 123456.789      JKPS
 // C and J fail upon seeing the second decimal point
 +1,23,456.78.9 123456.78       CJ
 +79    79
@@ -998,8 +997,8 @@ parse       output  breaks
 123.456        123456
 123,456        123.456
 // The separator after the comma can be inrepreted as a fractional grouping
-987,654.321    987.654321      CJK
-987,654 321    987.654321      CJK
+987,654.321    987.654321      CJKS
+987,654 321    987.654321      CJKS
 987.654,321    987654.321
 
 test select
@@ -1225,38 +1224,38 @@ test parse foreign currency symbol
 set pattern \u00a4 0.00;\u00a4 -#
 set locale fa_IR
 begin
-parse  output  outputCurrency
+parse  output  outputCurrency  breaks
 \u0631\u06cc\u0627\u0644 \u06F1\u06F2\u06F3\u06F5      1235    IRR
 IRR \u06F1\u06F2\u06F3\u06F5   1235    IRR
 // P fails here because this currency name is in the Trie only, but it has the same prefix as the non-Trie currency
 \u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 \u06F1\u06F2\u06F3\u06F5       1235    IRR     P
 IRR 1235       1235    IRR
 \u0631\u06cc\u0627\u0644 1235  1235    IRR
-\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235   1235    IRR
+\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235   1235    IRR     P
 
 test parse foreign currency ISO
 set pattern \u00a4\u00a4 0.00;\u00a4\u00a4 -#
 set locale fa_IR
 begin
-parse  output  outputCurrency
+parse  output  outputCurrency  breaks
 \u0631\u06cc\u0627\u0644 \u06F1\u06F2\u06F3\u06F5      1235    IRR
 IRR \u06F1\u06F2\u06F3\u06F5   1235    IRR
-\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 \u06F1\u06F2\u06F3\u06F5       1235    IRR
+\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 \u06F1\u06F2\u06F3\u06F5       1235    IRR     P
 IRR 1235       1235    IRR
 \u0631\u06cc\u0627\u0644 1235  1235    IRR
-\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235   1235    IRR
+\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235   1235    IRR     P
 
 test parse foreign currency full
 set pattern \u00a4\u00a4\u00a4 0.00;\u00a4\u00a4\u00a4 -#
 set locale fa_IR
 begin
-parse  output  outputCurrency
+parse  output  outputCurrency  breaks
 \u0631\u06cc\u0627\u0644 \u06F1\u06F2\u06F3\u06F5      1235    IRR
 IRR \u06F1\u06F2\u06F3\u06F5   1235    IRR
-\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 \u06F1\u06F2\u06F3\u06F5       1235    IRR
+\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 \u06F1\u06F2\u06F3\u06F5       1235    IRR     P
 IRR 1235       1235    IRR
 \u0631\u06cc\u0627\u0644 1235  1235    IRR
-\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235   1235    IRR
+\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235   1235    IRR     P
 
 test parse currency with foreign symbols symbol english
 set pattern \u00a4 0.00;\u00a4 (#)
@@ -1381,13 +1380,15 @@ test parse minus sign
 set locale en
 set pattern #
 begin
-parse  output  breaks
--123   -123
-- 123  -123    JK
- -123  -123    JK
- - 123 -123    JK
-123-   -123    CJKS
-123 -  -123    CJKS
+pattern        parse   output  breaks
+#      -123    -123
+#      - 123   -123    JK
+#       -123   -123    JK
+#       - 123  -123    JK
+#      123-    123
+#      123 -   123
+#;#-   123-    -123
+#;#-   123 -   -123    JK
 
 test parse case sensitive
 set locale en
index 52bf5b99a966c83963fd09896ba6b65a959f4b53..3622fa69165e5e754214806e58389ab6ced53dc7 100644 (file)
@@ -7,7 +7,6 @@ import java.math.RoundingMode;
 import java.text.ParseException;
 import java.text.ParsePosition;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
 import com.ibm.icu.dev.test.TestUtil;
@@ -834,7 +833,6 @@ public class NumberFormatDataDrivenTest {
     };
 
   @Test
-  @Ignore
   public void TestDataDrivenICU58() {
     // Android can't access DecimalFormat_ICU58 for testing (ticket #13283).
     if (TestUtil.getJavaVendor() == TestUtil.JavaVendor.Android) return;
@@ -847,7 +845,6 @@ public class NumberFormatDataDrivenTest {
   // something may or may not work. However the test data assumes a specific
   // Java runtime version. We should probably disable this test case - #13372
   @Test
-  @Ignore
   public void TestDataDrivenJDK() {
     // Android implements java.text.DecimalFormat with ICU4J (ticket #13322).
     // Oracle/OpenJDK 9's behavior is not exactly same with Oracle/OpenJDK 8.
@@ -862,7 +859,6 @@ public class NumberFormatDataDrivenTest {
   }
 
   @Test
-  @Ignore
   public void TestDataDrivenICULatest_Format() {
     DataDrivenNumberFormatTestUtility.runFormatSuiteIncludingKnownFailures(
         "numberformattestspecification.txt", ICU60);
@@ -875,7 +871,6 @@ public class NumberFormatDataDrivenTest {
   }
 
   @Test
-  @Ignore
   public void TestDataDrivenICULatest_Other() {
     DataDrivenNumberFormatTestUtility.runFormatSuiteIncludingKnownFailures(
         "numberformattestspecification.txt", ICU59_Other);
index da0b19d560685728ba307c0c5472494859e3c586..4ab30addaa1680dabdd048bf28efbc43783fc7a0 100644 (file)
@@ -5939,4 +5939,38 @@ public class NumberFormatTest extends TestFmwk {
         // expect(currencyFormat, 0.08, "CA$0.1");  // ICU 58 and down
         expect(currencyFormat, 0.08, "CA$0.10");  // ICU 59 and up
     }
+
+    @Test
+    public void testParsePositionIncrease() {
+        String input = "123\n456\n$789";
+        ParsePosition ppos = new ParsePosition(0);
+        DecimalFormat df = new DecimalFormat();
+        df.parse(input, ppos);
+        assertEquals("Should stop after first entry", 3, ppos.getIndex());
+        ppos.setIndex(ppos.getIndex() + 1);
+        df.parse(input, ppos);
+        assertEquals("Should stop after second entry", 7, ppos.getIndex());
+        ppos.setIndex(ppos.getIndex() + 1);
+        df.parseCurrency(input, ppos); // test parseCurrency API as well
+        assertEquals("Should stop after third entry", 12, ppos.getIndex());
+    }
+
+    @Test
+    public void testTrailingMinusSign() {
+        String input = "52-";
+        DecimalFormat df = (DecimalFormat) DecimalFormat.getInstance(ULocale.ENGLISH);
+        ParsePosition ppos = new ParsePosition(0);
+        Number result = df.parse(input, ppos);
+        assertEquals("Trailing sign should NOT be accepted after the number in English by default",
+                52.0,
+                result.doubleValue(),
+                0.0);
+        df.applyPattern("#;#-");
+        ppos.setIndex(0);
+        result = df.parse(input, ppos);
+        assertEquals("Trailing sign SHOULD be accepted if there is one in the pattern",
+                -52.0,
+                result.doubleValue(),
+                0.0);
+    }
 }
index 0b163c8a7b5c207885e67e41988615f42e8dbe8d..9ad678579def8fee9829cc266e2e3d8cfa2f4b8a 100644 (file)
@@ -870,7 +870,7 @@ public class NumberRegressionTests extends TestFmwk {
         DecimalFormatSymbols(java.util.Locale.US));
         String text = "1.222,111";
         Number num = df.parse(text,new ParsePosition(0));
-        if (!num.toString().equals("1.222"))
+        if (!num.toString().equals("1.222111"))
             errln("\"" + text + "\"  is parsed as " + num);
         text = "1.222x111";
         num = df.parse(text,new ParsePosition(0));
index c8d22177b48fca460a22ce639a630ce70fd362c5..8782613f26316898c243966167631314ad7ae1f6 100644 (file)
@@ -513,6 +513,8 @@ public class DecimalQuantityTest extends TestFmwk {
         assertTrue("10^19 should fit", quantity.fitsInLong());
         quantity.setToLong(1234567890123456789L);
         assertTrue("A number between 10^19 and max long should fit", quantity.fitsInLong());
+        quantity.setToLong(1234567890000000000L);
+        assertTrue("A number with trailing zeros less than max long should fit", quantity.fitsInLong());
         quantity.setToLong(9223372026854775808L);
         assertTrue("A number less than max long but with similar digits should fit",
                 quantity.fitsInLong());
@@ -524,6 +526,8 @@ public class DecimalQuantityTest extends TestFmwk {
         assertFalse("One greater than max long long should not fit", quantity.fitsInLong());
         quantity.setToBigInteger(new BigInteger("9223372046854775806"));
         assertFalse("A number between max long and 10^20 should not fit", quantity.fitsInLong());
+        quantity.setToBigInteger(new BigInteger("9223372046800000000"));
+        assertFalse("A large 10^19 number with trailing zeros should not fit", quantity.fitsInLong());
         quantity.setToBigInteger(new BigInteger("10000000000000000000"));
         assertFalse("10^20 should not fit", quantity.fitsInLong());
     }
index c4bfc5fc793ced10afe9f58a5b12dadcc4cef1f7..4e69a76258146385241789633754c3aa76a50d7f 100644 (file)
@@ -8,6 +8,7 @@ import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
 
+import com.ibm.icu.impl.number.DecimalFormatProperties;
 import com.ibm.icu.impl.number.parse.IgnorablesMatcher;
 import com.ibm.icu.impl.number.parse.MinusSignMatcher;
 import com.ibm.icu.impl.number.parse.NumberParserImpl;
@@ -103,7 +104,7 @@ public class NumberParserTest {
                 assertNotNull("Greedy Parse failed: " + message, resultObject.quantity);
                 assertEquals("Greedy Parse failed: " + message,
                         expectedCharsConsumed,
-                        resultObject.charsConsumed);
+                        resultObject.charEnd);
                 assertEquals("Greedy Parse failed: " + message,
                         resultDouble,
                         resultObject.getNumber().doubleValue(),
@@ -117,7 +118,7 @@ public class NumberParserTest {
                 assertNotNull("Non-Greedy Parse failed: " + message, resultObject.quantity);
                 assertEquals("Non-Greedy Parse failed: " + message,
                         expectedCharsConsumed,
-                        resultObject.charsConsumed);
+                        resultObject.charEnd);
                 assertEquals("Non-Greedy Parse failed: " + message,
                         resultDouble,
                         resultObject.getNumber().doubleValue(),
@@ -132,7 +133,7 @@ public class NumberParserTest {
                 assertNotNull("Strict Parse failed: " + message, resultObject.quantity);
                 assertEquals("Strict Parse failed: " + message,
                         expectedCharsConsumed,
-                        resultObject.charsConsumed);
+                        resultObject.charEnd);
                 assertEquals("Strict Parse failed: " + message,
                         resultDouble,
                         resultObject.getNumber().doubleValue(),
@@ -162,8 +163,8 @@ public class NumberParserTest {
     public void testSeriesMatcher() {
         DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(ULocale.ENGLISH);
         SeriesMatcher series = new SeriesMatcher();
-        series.addMatcher(PlusSignMatcher.getInstance(symbols));
-        series.addMatcher(MinusSignMatcher.getInstance(symbols));
+        series.addMatcher(PlusSignMatcher.getInstance(symbols, false));
+        series.addMatcher(MinusSignMatcher.getInstance(symbols, false));
         series.addMatcher(IgnorablesMatcher.DEFAULT);
         series.addMatcher(PercentMatcher.getInstance(symbols));
         series.addMatcher(IgnorablesMatcher.DEFAULT);
@@ -199,4 +200,19 @@ public class NumberParserTest {
             assertEquals("'" + input + "'", expectedMaybeMore, actualMaybeMore);
         }
     }
+
+    @Test
+    public void testGroupingDisabled() {
+        DecimalFormatProperties properties = new DecimalFormatProperties();
+        properties.setGroupingSize(0);
+        DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(ULocale.ENGLISH);
+        NumberParserImpl parser = NumberParserImpl
+                .createParserFromProperties(properties, symbols, false, true);
+        ParsedNumber result = new ParsedNumber();
+        parser.parse("12,345.678", true, result);
+        assertEquals("Should not parse with grouping separator",
+                12.0,
+                result.getNumber().doubleValue(),
+                0.0);
+    }
 }
index 170118687e1fa5bc196f5eea1a31588cbbc5ee8f..97283a1400e19912081e953cd6acdee939cf247e 100644 (file)
@@ -3,12 +3,10 @@
 package com.ibm.icu.dev.test.number;
 
 import static com.ibm.icu.impl.number.parse.UnicodeSetStaticCache.get;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
 
-import com.ibm.icu.impl.number.parse.UnicodeSetStaticCache;
 import com.ibm.icu.impl.number.parse.UnicodeSetStaticCache.Key;
 import com.ibm.icu.lang.UCharacter;
 import com.ibm.icu.text.DecimalFormatSymbols;
@@ -67,22 +65,6 @@ public class UnicodeSetStaticCacheTest {
         }
     }
 
-    @Test
-    public void testUnions() {
-        for (Key key1 : Key.values()) {
-            for (Key key2 : Key.values()) {
-                Key key3 = UnicodeSetStaticCache.unionOf(key1, key2);
-                if (key3 != null) {
-                    UnicodeSet s1 = get(key1);
-                    UnicodeSet s2 = get(key2);
-                    UnicodeSet s3 = get(key3);
-                    UnicodeSet s1_s2 = s1.cloneAsThawed().addAll(s2);
-                    assertEquals(key1 + "/" + key2 + "/" + key3, s1_s2, s3);
-                }
-            }
-        }
-    }
-
     static void assertInSet(ULocale locale, UnicodeSet set, String str) {
         if (str.codePointCount(0, str.length()) != 1) {
             // Ignore locale strings with more than one code point (usually a bidi mark)