From 840b9dfe8b1354339851ba1dda8d21ecd00d9ee7 Mon Sep 17 00:00:00 2001
From: Alexey Andreev <Alexey.Andreev@jetbrains.com>
Date: Fri, 3 Nov 2017 21:59:21 +0300
Subject: [PATCH] Fix message format tests

---
 .../java/text/TDateFormatElement.java         | 180 +++++++++++++++++-
 .../java/text/TDateFormatSymbols.java         |  18 +-
 .../classlib/java/text/TDecimalFormat.java    |  57 ++++++
 .../classlib/java/text/TSimpleDateFormat.java |  29 +++
 .../classlib/java/text/MessageFormatTest.java |  17 +-
 5 files changed, 271 insertions(+), 30 deletions(-)

diff --git a/classlib/src/main/java/org/teavm/classlib/java/text/TDateFormatElement.java b/classlib/src/main/java/org/teavm/classlib/java/text/TDateFormatElement.java
index 6e946402b..337e5ab77 100644
--- a/classlib/src/main/java/org/teavm/classlib/java/text/TDateFormatElement.java
+++ b/classlib/src/main/java/org/teavm/classlib/java/text/TDateFormatElement.java
@@ -21,6 +21,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import org.teavm.classlib.java.util.TCalendar;
 import org.teavm.classlib.java.util.TGregorianCalendar;
 import org.teavm.classlib.java.util.TLocale;
@@ -82,6 +83,25 @@ abstract class TDateFormatElement {
                 date.set(TCalendar.MONTH, month);
             }
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            MonthText monthText = (MonthText) o;
+            return abbreviated == monthText.abbreviated
+                    && Arrays.equals(months, monthText.months)
+                    && Arrays.equals(shortMonths, monthText.shortMonths);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(months, shortMonths, abbreviated);
+        }
     }
 
     public static class WeekdayText extends TDateFormatElement {
@@ -113,6 +133,25 @@ abstract class TDateFormatElement {
                 date.set(TCalendar.WEEK_OF_MONTH, weekday + 1);
             }
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            WeekdayText that = (WeekdayText) o;
+            return abbreviated == that.abbreviated
+                    && Arrays.equals(weeks, that.weeks)
+                    && Arrays.equals(shortWeeks, that.shortWeeks);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(weeks, shortWeeks, abbreviated);
+        }
     }
 
     public static class EraText extends TDateFormatElement {
@@ -137,6 +176,23 @@ abstract class TDateFormatElement {
                 date.set(TCalendar.ERA, era);
             }
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            EraText eraText = (EraText) o;
+            return Arrays.equals(eras, eraText.eras);
+        }
+
+        @Override
+        public int hashCode() {
+            return Arrays.hashCode(eras);
+        }
     }
 
     public static class AmPmText extends TDateFormatElement {
@@ -161,6 +217,23 @@ abstract class TDateFormatElement {
                 date.set(TCalendar.AM_PM, ampm);
             }
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            AmPmText amPmText = (AmPmText) o;
+            return Arrays.equals(ampms, amPmText.ampms);
+        }
+
+        @Override
+        public int hashCode() {
+            return Arrays.hashCode(ampms);
+        }
     }
 
     public static class Numeric extends TDateFormatElement {
@@ -212,6 +285,23 @@ abstract class TDateFormatElement {
         protected int processAfterParse(int num) {
             return num;
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            Numeric numeric = (Numeric) o;
+            return field == numeric.field && length == numeric.length;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(field, length);
+        }
     }
 
     public static class NumericMonth extends Numeric {
@@ -263,6 +353,26 @@ abstract class TDateFormatElement {
         protected int processAfterParse(int num) {
             return num == limit ? 0 : num;
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            if (!super.equals(o)) {
+                return false;
+            }
+            NumericHour that = (NumericHour) o;
+            return limit == that.limit;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(super.hashCode(), limit);
+        }
     }
 
     public static class Year extends TDateFormatElement {
@@ -285,7 +395,7 @@ abstract class TDateFormatElement {
 
         @Override
         public void parse(String text, TCalendar date, TParsePosition position) {
-            int num = 0;
+            int num;
             int pos = position.getIndex();
             char c = text.charAt(pos++);
             if (c < '0' || c > '9') {
@@ -314,6 +424,23 @@ abstract class TDateFormatElement {
             }
             date.set(field, num + century * 100);
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            Year year = (Year) o;
+            return field == year.field;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(field);
+        }
     }
 
     public static class ConstantText extends TDateFormatElement {
@@ -336,6 +463,23 @@ abstract class TDateFormatElement {
                 position.setErrorIndex(position.getIndex());
             }
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            ConstantText that = (ConstantText) o;
+            return Objects.equals(textConstant, that.textConstant);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(textConstant);
+        }
     }
 
     public static abstract class BaseTimezone extends TDateFormatElement {
@@ -426,6 +570,23 @@ abstract class TDateFormatElement {
             }
             idSearchTrie = builder.build();
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            BaseTimezone that = (BaseTimezone) o;
+            return Objects.equals(locale, that.locale) && Objects.equals(searchTrie, that.searchTrie);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(locale, searchTrie);
+        }
     }
 
     public static class GeneralTimezone extends BaseTimezone {
@@ -556,6 +717,23 @@ abstract class TDateFormatElement {
             position.setIndex(index);
             date.setTimeZone(getStaticTimeZone(sign * hours, minutes));
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            Iso8601Timezone that = (Iso8601Timezone) o;
+            return size == that.size;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(size);
+        }
     }
 
     static boolean tryParseFixedTimeZone(String text, TCalendar date, TParsePosition position) {
diff --git a/classlib/src/main/java/org/teavm/classlib/java/text/TDateFormatSymbols.java b/classlib/src/main/java/org/teavm/classlib/java/text/TDateFormatSymbols.java
index 69c7e83a6..9f867f6bd 100644
--- a/classlib/src/main/java/org/teavm/classlib/java/text/TDateFormatSymbols.java
+++ b/classlib/src/main/java/org/teavm/classlib/java/text/TDateFormatSymbols.java
@@ -16,6 +16,7 @@
 package org.teavm.classlib.java.text;
 
 import java.util.Arrays;
+import java.util.Objects;
 import org.teavm.classlib.impl.unicode.CLDRHelper;
 import org.teavm.classlib.java.io.TSerializable;
 import org.teavm.classlib.java.lang.TCloneable;
@@ -84,7 +85,7 @@ public class TDateFormatSymbols implements TSerializable, TCloneable {
         if (!locale.equals(obj.locale)) {
             return false;
         }
-        if (!localPatternChars.equals(obj.localPatternChars)) {
+        if (!Objects.equals(localPatternChars, obj.localPatternChars)) {
             return false;
         }
         if (!Arrays.equals(ampms, obj.ampms)) {
@@ -105,20 +106,7 @@ public class TDateFormatSymbols implements TSerializable, TCloneable {
         if (!Arrays.equals(weekdays, obj.weekdays)) {
             return false;
         }
-        if (zoneStrings.length != obj.zoneStrings.length) {
-            return false;
-        }
-        for (String[] element : zoneStrings) {
-            if (element.length != element.length) {
-                return false;
-            }
-            for (int j = 0; j < element.length; j++) {
-                if (!(element[j].equals(element[j]))) {
-                    return false;
-                }
-            }
-        }
-        return true;
+        return Arrays.equals(zoneStrings, obj.zoneStrings);
     }
 
     public String[] getAmPmStrings() {
diff --git a/classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java b/classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java
index 185b30082..e9fffaf2b 100644
--- a/classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java
+++ b/classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java
@@ -1226,6 +1226,23 @@ public class TDecimalFormat extends TNumberFormat {
         public void render(TDecimalFormat format, StringBuffer buffer) {
             buffer.append(text);
         }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof TextField)) {
+                return false;
+            }
+            TextField other = (TextField) obj;
+            return text.equals(other.text);
+        }
+
+        @Override
+        public int hashCode() {
+            return text.hashCode();
+        }
     }
 
     static class CurrencyField implements FormatField {
@@ -1237,6 +1254,16 @@ public class TDecimalFormat extends TNumberFormat {
                 buffer.append(format.getCurrency().getSymbol(format.symbols.getLocale()));
             }
         }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof CurrencyField;
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
     }
 
     static class PercentField implements FormatField {
@@ -1244,6 +1271,16 @@ public class TDecimalFormat extends TNumberFormat {
         public void render(TDecimalFormat format, StringBuffer buffer) {
             buffer.append(format.symbols.getPercent());
         }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof PercentField;
+        }
+
+        @Override
+        public int hashCode() {
+            return 1;
+        }
     }
 
     static class PerMillField implements FormatField {
@@ -1251,6 +1288,16 @@ public class TDecimalFormat extends TNumberFormat {
         public void render(TDecimalFormat format, StringBuffer buffer) {
             buffer.append(format.symbols.getPerMill());
         }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof PerMillField;
+        }
+
+        @Override
+        public int hashCode() {
+            return 2;
+        }
     }
 
     static class MinusField implements FormatField {
@@ -1258,5 +1305,15 @@ public class TDecimalFormat extends TNumberFormat {
         public void render(TDecimalFormat format, StringBuffer buffer) {
             buffer.append(format.symbols.getMinusSign());
         }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof MinusField;
+        }
+
+        @Override
+        public int hashCode() {
+            return 3;
+        }
     }
 }
diff --git a/classlib/src/main/java/org/teavm/classlib/java/text/TSimpleDateFormat.java b/classlib/src/main/java/org/teavm/classlib/java/text/TSimpleDateFormat.java
index f16404123..bbd2954d0 100644
--- a/classlib/src/main/java/org/teavm/classlib/java/text/TSimpleDateFormat.java
+++ b/classlib/src/main/java/org/teavm/classlib/java/text/TSimpleDateFormat.java
@@ -15,6 +15,7 @@
  */
 package org.teavm.classlib.java.text;
 
+import java.util.Arrays;
 import org.teavm.classlib.impl.unicode.CLDRHelper;
 import org.teavm.classlib.java.util.TCalendar;
 import org.teavm.classlib.java.util.TDate;
@@ -110,4 +111,32 @@ public class TSimpleDateFormat extends TDateFormat {
     public String toPattern() {
         return pattern;
     }
+
+    @Override
+    public boolean equals(Object object) {
+        if (object == this) {
+            return true;
+        }
+        if (!(object instanceof TSimpleDateFormat)) {
+            return false;
+        }
+
+        TSimpleDateFormat other = (TSimpleDateFormat) object;
+        if (!super.equals(other)) {
+            return false;
+        }
+
+        return Arrays.equals(elements, other.elements)
+                && dateFormatSymbols.equals(other.dateFormatSymbols)
+                && locale.equals(other.locale);
+    }
+
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(new int[] {
+                super.hashCode(),
+                dateFormatSymbols.hashCode(),
+                Arrays.hashCode(elements),
+                locale.hashCode() });
+    }
 }
diff --git a/tests/src/test/java/org/teavm/classlib/java/text/MessageFormatTest.java b/tests/src/test/java/org/teavm/classlib/java/text/MessageFormatTest.java
index a0301f809..533fc0064 100644
--- a/tests/src/test/java/org/teavm/classlib/java/text/MessageFormatTest.java
+++ b/tests/src/test/java/org/teavm/classlib/java/text/MessageFormatTest.java
@@ -38,12 +38,9 @@ import java.util.TimeZone;
 import org.junit.After;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.teavm.junit.TeaVMProperties;
-import org.teavm.junit.TeaVMProperty;
 import org.teavm.junit.TeaVMTestRunner;
 
 @RunWith(TeaVMTestRunner.class)
-@TeaVMProperties(value = { @TeaVMProperty(key = "java.util.Locale.available", value = "en, en_US, fr") })
 public class MessageFormatTest {
     private MessageFormat format1;
     private MessageFormat format2;
@@ -173,13 +170,6 @@ public class MessageFormatTest {
         assertTrue("Wrong long time format", format.getFormats()[0].equals(
                 DateFormat.getTimeInstance(DateFormat.LONG)));
         assertEquals("Wrong long time pattern", "{0,time,long}", format.toPattern());
-        format.setLocale(Locale.FRENCH); // use French since English has the
-        // same LONG and FULL time patterns
-        format.applyPattern("{0,time, Full}");
-        assertTrue("Wrong full time format", format.getFormats()[0]
-                .equals(DateFormat.getTimeInstance(DateFormat.FULL, Locale.FRENCH)));
-        assertEquals("Wrong full time pattern", "{0,time,full}", format.toPattern());
-        format.setLocale(Locale.getDefault());
 
         format.applyPattern("{0, date}");
         assertTrue("Wrong date format", format.getFormats()[0].equals(DateFormat.getDateInstance()));
@@ -203,10 +193,9 @@ public class MessageFormatTest {
         assertEquals("Wrong full date pattern", "{0,date,full}", format.toPattern());
 
         format.applyPattern("{0, date, MMM d {hh:mm:ss}}");
-        assertEquals("Wrong time/date format", " MMM d {hh:mm:ss}", ((SimpleDateFormat) (format
-                .getFormats()[0])).toPattern());
-        assertEquals("Wrong time/date pattern",
-                "{0,date, MMM d {hh:mm:ss}}", format.toPattern());
+        assertEquals("Wrong time/date format", " MMM d {hh:mm:ss}",
+                ((SimpleDateFormat) (format.getFormats()[0])).toPattern());
+        assertEquals("Wrong time/date pattern", "{0,date, MMM d {hh:mm:ss}}", format.toPattern());
 
         format.applyPattern("{0, number}");
         assertTrue("Wrong number format", format.getFormats()[0].equals(NumberFormat.getNumberInstance()));