1/* GENERATED SOURCE. DO NOT MODIFY. */
2// © 2016 and later: Unicode, Inc. and others.
3// License & terms of use: http://www.unicode.org/copyright.html#License
4/*
5 *******************************************************************************
6 * Copyright (C) 1996-2014, International Business Machines Corporation and
7 * others. All Rights Reserved.
8 *******************************************************************************
9 *
10 */
11
12package android.icu.dev.test.serializable;
13
14import java.io.ByteArrayInputStream;
15import java.io.ByteArrayOutputStream;
16import java.io.File;
17import java.io.FileInputStream;
18import java.io.FileOutputStream;
19import java.io.IOException;
20import java.io.InputStream;
21import java.io.ObjectInputStream;
22import java.io.ObjectOutputStream;
23import java.lang.reflect.Modifier;
24import java.net.URL;
25import java.util.ArrayList;
26import java.util.Date;
27import java.util.Enumeration;
28import java.util.HashMap;
29import java.util.List;
30import java.util.Locale;
31
32import android.icu.dev.test.format.MeasureUnitTest;
33import android.icu.dev.test.format.PluralRulesTest;
34import android.icu.impl.JavaTimeZone;
35import android.icu.impl.OlsonTimeZone;
36import android.icu.impl.TimeZoneAdapter;
37import android.icu.impl.URLHandler;
38import android.icu.impl.Utility;
39import android.icu.math.BigDecimal;
40import android.icu.math.MathContext;
41import android.icu.util.AnnualTimeZoneRule;
42import android.icu.util.Calendar;
43import android.icu.util.Currency;
44import android.icu.util.DateInterval;
45import android.icu.util.DateTimeRule;
46import android.icu.util.GregorianCalendar;
47import android.icu.util.ICUCloneNotSupportedException;
48import android.icu.util.ICUException;
49import android.icu.util.ICUUncheckedIOException;
50import android.icu.util.InitialTimeZoneRule;
51import android.icu.util.RuleBasedTimeZone;
52import android.icu.util.SimpleTimeZone;
53import android.icu.util.TimeArrayTimeZoneRule;
54import android.icu.util.TimeZone;
55import android.icu.util.TimeZoneRule;
56import android.icu.util.ULocale;
57import android.icu.util.VTimeZone;
58
59/**
60 * @author emader
61 *
62 * TODO To change the template for this generated type comment go to
63 * Window - Preferences - Java - Code Style - Code Templates
64 */
65public class SerializableTestUtility {
66    private static Class serializable;
67    static {
68        try {
69            serializable = Class.forName("java.io.Serializable");
70        } catch (ClassNotFoundException e) {
71            // TODO Auto-generated catch block
72            e.printStackTrace();
73        }
74    }
75
76    public interface Handler
77    {
78        public Object[] getTestObjects();
79
80        public boolean hasSameBehavior(Object a, Object b);
81    }
82
83    public static Handler getHandler(String className)
84    {
85        return (Handler) map.get(className);
86    }
87
88    private static class TimeZoneHandler implements Handler
89    {
90        String[] ZONES = { "GMT", "MET", "IST" };
91
92        @Override
93        public Object[] getTestObjects()
94        {
95            TimeZone zones[] = new TimeZone[ZONES.length];
96
97            for(int z = 0; z < ZONES.length; z += 1) {
98                zones[z] = TimeZone.getTimeZone(ZONES[z]);
99            }
100
101            return zones;
102        }
103
104        @Override
105        public boolean hasSameBehavior(Object a, Object b)
106        {
107            TimeZone zone_a = (TimeZone) a;
108            TimeZone zone_b = (TimeZone) b;
109
110            if (!(zone_a.getDisplayName().equals(zone_b.getDisplayName()))) {
111                return false;
112            }
113
114            int a_offsets[] = {0, 0};
115            int b_offsets[] = {0, 0};
116
117            boolean bSame = true;
118            for (int i = 0; i < sampleTimes.length; i++) {
119                zone_a.getOffset(sampleTimes[i], false, a_offsets);
120                zone_b.getOffset(sampleTimes[i], false, b_offsets);
121                if (a_offsets[0] != b_offsets[0] || a_offsets[1] != b_offsets[1]) {
122                    bSame = false;
123                    break;
124                }
125            }
126            return bSame;
127        }
128    }
129
130    private static Locale locales[] = {
131        Locale.CANADA, Locale.CANADA_FRENCH, Locale.CHINA,
132        Locale.CHINESE, Locale.ENGLISH, Locale.FRANCE, Locale.FRENCH,
133        Locale.GERMAN, Locale.GERMANY, Locale.ITALIAN, Locale.ITALY,
134        Locale.JAPAN, Locale.JAPANESE, Locale.KOREA, Locale.KOREAN,
135        Locale.PRC, Locale.SIMPLIFIED_CHINESE, Locale.TAIWAN,
136        Locale.TRADITIONAL_CHINESE, Locale.UK, Locale.US
137    };
138
139    private static Locale places[] = {
140        Locale.CANADA, Locale.CANADA_FRENCH, Locale.CHINA,
141        Locale.FRANCE, Locale.GERMANY, Locale.ITALY,
142        Locale.JAPAN, Locale.KOREA, Locale.PRC, Locale.TAIWAN,
143        Locale.UK, Locale.US
144    };
145
146    public static Locale[] getLocales()
147    {
148        return locales;
149    }
150
151    public static boolean compareStrings(String a[], String b[])
152    {
153        if (a.length != b.length) {
154            return false;
155        }
156
157        for (int i = 0; i < a.length; i += 1) {
158            if (! a[i].equals(b[i])) {
159                return false;
160            }
161        }
162
163        return true;
164    }
165
166    public static boolean compareChars(char a[], char b[])
167    {
168        if (a.length != b.length) {
169            return false;
170        }
171
172        for (int i = 0; i < a.length; i += 1) {
173            if (a[i] != b[i]) {
174                return false;
175            }
176        }
177
178        return true;
179    }
180
181    private static class SimpleTimeZoneHandler extends TimeZoneHandler
182    {
183        @Override
184        public Object[] getTestObjects()
185        {
186            SimpleTimeZone simpleTimeZones[] = new SimpleTimeZone[6];
187
188            simpleTimeZones[0] = new SimpleTimeZone(32400000, "MyTimeZone");
189
190            simpleTimeZones[1] = new SimpleTimeZone(32400000, "Asia/Tokyo");
191
192            simpleTimeZones[2] = new SimpleTimeZone(32400000, "Asia/Tokyo");
193            simpleTimeZones[2].setRawOffset(0);
194
195            simpleTimeZones[3] = new SimpleTimeZone(32400000, "Asia/Tokyo");
196            simpleTimeZones[3].setStartYear(100);
197
198            simpleTimeZones[4] = new SimpleTimeZone(32400000, "Asia/Tokyo");
199            simpleTimeZones[4].setStartYear(1000);
200            simpleTimeZones[4].setDSTSavings(1800000);
201            simpleTimeZones[4].setStartRule(3, 4, 180000);
202            simpleTimeZones[4].setEndRule(6, 3, 4, 360000);
203
204            simpleTimeZones[5] = new SimpleTimeZone(32400000, "Asia/Tokyo");
205            simpleTimeZones[5].setStartRule(2, 3, 4, 360000);
206            simpleTimeZones[5].setEndRule(6, 3, 4, 360000);
207
208            return simpleTimeZones;
209        }
210    }
211
212    private static class VTimeZoneHandler extends TimeZoneHandler {
213        @Override
214        public Object[] getTestObjects() {
215            //TODO
216            VTimeZone[] vtzs = new VTimeZone[1];
217            vtzs[0] = VTimeZone.create("America/New_York");
218            return vtzs;
219        }
220    }
221
222    private static final int HOUR = 60*60*1000;
223    private static final AnnualTimeZoneRule[] TEST_US_EASTERN = {
224        new AnnualTimeZoneRule("EST", -5*HOUR, 0,
225                new DateTimeRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*HOUR, DateTimeRule.WALL_TIME),
226                1967, 2006),
227
228        new AnnualTimeZoneRule("EST", -5*HOUR, 0,
229                new DateTimeRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, true, 2*HOUR, DateTimeRule.WALL_TIME),
230                2007, AnnualTimeZoneRule.MAX_YEAR),
231
232        new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR,
233                new DateTimeRule(Calendar.APRIL, -1, Calendar.SUNDAY, 2*HOUR, DateTimeRule.WALL_TIME),
234                1967, 1973),
235
236        new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR,
237                new DateTimeRule(Calendar.JANUARY, 6, 2*HOUR, DateTimeRule.WALL_TIME),
238                1974, 1974),
239
240        new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR,
241                new DateTimeRule(Calendar.FEBRUARY, 23, 2*HOUR, DateTimeRule.WALL_TIME),
242                1975, 1975),
243
244        new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR,
245                new DateTimeRule(Calendar.APRIL, -1, Calendar.SUNDAY, 2*HOUR, DateTimeRule.WALL_TIME),
246                1976, 1986),
247
248        new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR,
249                new DateTimeRule(Calendar.APRIL, 1, Calendar.SUNDAY, true, 2*HOUR, DateTimeRule.WALL_TIME),
250                1987, 2006),
251
252        new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR,
253                new DateTimeRule(Calendar.MARCH, 8, Calendar.SUNDAY, true, 2*HOUR, DateTimeRule.WALL_TIME),
254                2007, AnnualTimeZoneRule.MAX_YEAR)
255    };
256
257    private static class RuleBasedTimeZoneHandler extends TimeZoneHandler
258    {
259        @Override
260        public Object[] getTestObjects()
261        {
262            RuleBasedTimeZone ruleBasedTimeZones[] = new RuleBasedTimeZone[2];
263
264            InitialTimeZoneRule ir = new InitialTimeZoneRule("GMT-5", -5*HOUR, 0);
265
266            // GMT-5, no transition
267            ruleBasedTimeZones[0] = new RuleBasedTimeZone("GMT-5", ir);
268
269
270            // US Eastern since 1967
271            ruleBasedTimeZones[1] = new RuleBasedTimeZone("US_East", ir);
272            for (int i = 0; i < TEST_US_EASTERN.length; i++) {
273                ruleBasedTimeZones[1].addTransitionRule(TEST_US_EASTERN[i]);
274            }
275            return ruleBasedTimeZones;
276        }
277    }
278
279    private static class DateTimeRuleHandler implements Handler {
280        @Override
281        public Object[] getTestObjects() {
282            DateTimeRule[] rules = new DateTimeRule[4];
283
284            // DOM + UTC
285            rules[0] = new DateTimeRule(Calendar.OCTOBER, 10, 13*HOUR, DateTimeRule.UTC_TIME);
286
287            // DOW + WALL
288            rules[1] = new DateTimeRule(Calendar.MARCH, 2, Calendar.SUNDAY, 2*HOUR, DateTimeRule.WALL_TIME);
289
290            // DOW_GEQ_DOM + STD
291            rules[2] = new DateTimeRule(Calendar.MAY, 1, Calendar.MONDAY, true, 0*HOUR, DateTimeRule.STANDARD_TIME);
292
293            // DOW_LEQ_DOM + WALL
294            rules[3] = new DateTimeRule(Calendar.AUGUST, 31, Calendar.SATURDAY, false, 1*HOUR, DateTimeRule.WALL_TIME);
295
296            return rules;
297        }
298
299        @Override
300        public boolean hasSameBehavior(Object a, Object b) {
301            return hasSameRule((DateTimeRule)a, (DateTimeRule)b);
302        }
303
304        static boolean hasSameRule(DateTimeRule dtra, DateTimeRule dtrb) {
305            boolean bSame = false;
306            if (dtra.getDateRuleType() == dtrb.getDateRuleType()
307                    && dtra.getRuleMonth() == dtrb.getRuleMonth()
308                    && dtra.getTimeRuleType() == dtrb.getTimeRuleType()
309                    && dtra.getRuleMillisInDay() == dtrb.getRuleMillisInDay()) {
310                switch (dtra.getDateRuleType()) {
311                case DateTimeRule.DOM:
312                    bSame = (dtra.getRuleDayOfMonth() == dtrb.getRuleDayOfMonth());
313                    break;
314                case DateTimeRule.DOW:
315                    bSame = (dtra.getRuleDayOfWeek() == dtrb.getRuleDayOfWeek() &&
316                                dtra.getRuleWeekInMonth() == dtrb.getRuleWeekInMonth());
317                    break;
318                case DateTimeRule.DOW_GEQ_DOM:
319                case DateTimeRule.DOW_LEQ_DOM:
320                    bSame = (dtra.getRuleDayOfMonth() == dtrb.getRuleDayOfMonth() &&
321                                dtra.getRuleDayOfWeek() == dtrb.getRuleDayOfWeek());
322                    break;
323                }
324            }
325            return bSame;
326        }
327    }
328
329    private static boolean compareTimeZoneRules(TimeZoneRule ra, TimeZoneRule rb) {
330        if (ra.getName().equals(rb.getName()) &&
331                ra.getRawOffset() == rb.getRawOffset() &&
332                ra.getDSTSavings() == rb.getDSTSavings()) {
333            return true;
334        }
335        return false;
336    }
337
338    private static class AnnualTimeZoneRuleHandler implements Handler {
339        @Override
340        public Object[] getTestObjects() {
341            return TEST_US_EASTERN;
342        }
343
344        @Override
345        public boolean hasSameBehavior(Object a, Object b) {
346            AnnualTimeZoneRule ra = (AnnualTimeZoneRule)a;
347            AnnualTimeZoneRule rb = (AnnualTimeZoneRule)b;
348            if (DateTimeRuleHandler.hasSameRule(ra.getRule(), rb.getRule()) &&
349                    ra.getStartYear() == rb.getStartYear() &&
350                    ra.getEndYear() == rb.getEndYear()) {
351                return compareTimeZoneRules(ra, rb);
352            }
353            return false;
354        }
355    }
356
357    private static class InitialTimeZoneRuleHandler implements Handler {
358        @Override
359        public Object[] getTestObjects() {
360            TimeZoneRule[] rules = new TimeZoneRule[2];
361            rules[0] = new InitialTimeZoneRule("EST", -5*HOUR, 0);
362            rules[1] = new InitialTimeZoneRule("PST", -8*HOUR, 0);
363            return rules;
364        }
365
366        @Override
367        public boolean hasSameBehavior(Object a, Object b) {
368            return compareTimeZoneRules((TimeZoneRule)a, (TimeZoneRule)b);
369        }
370    }
371
372    private static class TimeArrayTimeZoneRuleHandler implements Handler {
373        @Override
374        public Object[] getTestObjects() {
375            TimeArrayTimeZoneRule[] rules = new TimeArrayTimeZoneRule[1];
376            long[] ttime = new long[] {-631152000000L, 0L, 946684800000L}; /* {1950-1-1, 1970-1-1, 2000-1-1} */
377            rules[0] = new TimeArrayTimeZoneRule("Foo", 1*HOUR, 1*HOUR, ttime, DateTimeRule.UTC_TIME);
378
379            return rules;
380        }
381        @Override
382        public boolean hasSameBehavior(Object a, Object b) {
383            TimeArrayTimeZoneRule ra = (TimeArrayTimeZoneRule)a;
384            TimeArrayTimeZoneRule rb = (TimeArrayTimeZoneRule)b;
385
386            Date da = ra.getFirstStart(0, 0);
387            Date db = rb.getFirstStart(0, 0);
388            long t = da.getTime();
389            if (da.equals(db)) {
390                da = ra.getFinalStart(0, 0);
391                db = rb.getFinalStart(0, 0);
392                long end = da.getTime();
393                if (da.equals(db)) {
394                    while (t < end) {
395                        da = ra.getNextStart(t, 0, 0, false);
396                        db = ra.getNextStart(t, 0, 0, false);
397                        if (da == null || db == null || !da.equals(db)) {
398                            break;
399                        }
400                        t = da.getTime();
401                    }
402                    return compareTimeZoneRules(ra, rb);
403                }
404            }
405            return false;
406        }
407    }
408
409    private static class ULocaleHandler implements Handler
410    {
411        @Override
412        public Object[] getTestObjects()
413        {
414            ULocale uLocales[] = new ULocale[locales.length];
415
416            for (int i = 0; i < locales.length; i += 1) {
417                uLocales[i] = ULocale.forLocale(locales[i]);
418            }
419
420            return uLocales;
421        }
422
423        @Override
424        public boolean hasSameBehavior(Object a, Object b)
425        {
426            ULocale uloc_a = (ULocale) a;
427            ULocale uloc_b = (ULocale) b;
428
429            return uloc_a.getName().equals(uloc_b.getName());
430        }
431    }
432
433    public static class DateIntervalHandler implements Handler
434    {
435        private DateInterval dateInterval[] = {
436                new DateInterval(0L, 1164931200000L/*20061201T000000Z*/)
437        };
438        @Override
439        public Object[] getTestObjects()
440        {
441            return dateInterval;
442        }
443
444        @Override
445        public boolean hasSameBehavior(Object a, Object b)
446        {
447            return a.equals(b);
448        }
449    }
450
451    private static class CurrencyHandler implements Handler
452    {
453        @Override
454        public Object[] getTestObjects()
455        {
456            Currency currencies[] = new Currency[places.length];
457
458            for (int i = 0; i < places.length; i += 1) {
459                currencies[i] = Currency.getInstance(places[i]);
460            }
461
462            return currencies;
463        }
464
465        @Override
466        public boolean hasSameBehavior(Object a, Object b)
467        {
468
469            Currency curr_a = (Currency) a;
470            Currency curr_b = (Currency) b;
471
472            return a == b
473                    || a != null && b != null
474                    && curr_a.getCurrencyCode() != null
475                    && curr_a.getCurrencyCode().equals(curr_b.getCurrencyCode());
476
477        }
478    }
479
480    private static String zoneIDs[] = {
481        "Pacific/Honolulu", "America/Anchorage", "America/Los_Angeles", "America/Denver",
482        "America/Chicago", "America/New_York", "Africa/Cairo", "Africa/Addis_Ababa", "Africa/Dar_es_Salaam",
483        "Africa/Freetown", "Africa/Johannesburg", "Africa/Nairobi", "Asia/Bangkok", "Asia/Baghdad",
484        "Asia/Calcutta", "Asia/Hong_Kong", "Asia/Jakarta", "Asia/Jerusalem", "Asia/Manila", "Asia/Tokyo",
485        "Europe/Amsterdam", "Europe/Athens", "Europe/Berlin", "Europe/London", "Europe/Malta", "Europe/Moscow",
486        "Europe/Paris", "Europe/Rome"
487    };
488
489    private static long sampleTimes[] = {
490        1136073600000L, // 20060101T000000Z
491        1138752000000L, // 20060201T000000Z
492        1141171200000L, // 20060301T000000Z
493        1143849600000L, // 20060401T000000Z
494        1146441600000L, // 20060501T000000Z
495        1149120000000L, // 20060601T000000Z
496        1151712000000L, // 20060701T000000Z
497        1154390400000L, // 20060801T000000Z
498        1157068800000L, // 20060901T000000Z
499        1159660800000L, // 20061001T000000Z
500        1162339200000L, // 20061101T000000Z
501        1164931200000L, // 20061201T000000Z
502    };
503
504    private static class OlsonTimeZoneHandler implements Handler
505    {
506        @Override
507        public Object[] getTestObjects()
508        {
509            OlsonTimeZone timeZones[] = new OlsonTimeZone[zoneIDs.length];
510
511            for (int i = 0; i < zoneIDs.length; i += 1) {
512                timeZones[i] = new OlsonTimeZone(zoneIDs[i]);
513            }
514
515            return timeZones;
516
517        }
518
519        @Override
520        public boolean hasSameBehavior(Object a, Object b)
521        {
522            OlsonTimeZone otz_a = (OlsonTimeZone) a;
523            OlsonTimeZone otz_b = (OlsonTimeZone) b;
524            int a_offsets[] = {0, 0};
525            int b_offsets[] = {0, 0};
526
527            boolean bSame = true;
528            for (int i = 0; i < sampleTimes.length; i++) {
529                otz_a.getOffset(sampleTimes[i], false, a_offsets);
530                otz_b.getOffset(sampleTimes[i], false, b_offsets);
531                if (a_offsets[0] != b_offsets[0] || a_offsets[1] != b_offsets[1]) {
532                    bSame = false;
533                    break;
534                }
535            }
536            return bSame;
537        }
538    }
539
540    private static class TimeZoneAdapterHandler implements Handler
541    {
542        @Override
543        public Object[] getTestObjects()
544        {
545            TimeZoneAdapter timeZones[] = new TimeZoneAdapter[zoneIDs.length];
546
547            for (int i = 0; i < zoneIDs.length; i += 1) {
548                timeZones[i] = new TimeZoneAdapter(TimeZone.getTimeZone(zoneIDs[i]));
549            }
550
551            return timeZones;
552
553        }
554
555        @Override
556        public boolean hasSameBehavior(Object a, Object b)
557        {
558            GregorianCalendar cal = new GregorianCalendar();
559            TimeZoneAdapter tza_a = (TimeZoneAdapter) a;
560            TimeZoneAdapter tza_b = (TimeZoneAdapter) b;
561
562            int a_offset, b_offset;
563            boolean a_dst, b_dst;
564            boolean bSame = true;
565            for (int i = 0; i < sampleTimes.length; i++) {
566                cal.setTimeInMillis(sampleTimes[i]);
567                int era = cal.get(Calendar.ERA);
568                int year = cal.get(Calendar.YEAR);
569                int month = cal.get(Calendar.MONTH);
570                int day = cal.get(Calendar.DAY_OF_MONTH);
571                int dow = cal.get(Calendar.DAY_OF_WEEK);
572                int mid = cal.get(Calendar.MILLISECONDS_IN_DAY);
573                a_offset = tza_a.getOffset(era, year, month, day, dow, mid);
574                b_offset = tza_b.getOffset(era, year, month, day, dow, mid);
575                Date d = new Date(sampleTimes[i]);
576                a_dst = tza_a.inDaylightTime(d);
577                b_dst = tza_b.inDaylightTime(d);
578                if (a_offset != b_offset || a_dst != b_dst) {
579                    bSame = false;
580                    break;
581                }
582            }
583            return bSame;
584        }
585    }
586
587    private static class JavaTimeZoneHandler implements Handler {
588        String[] ZONES = { "GMT", "America/New_York", "GMT+05:45" };
589
590        @Override
591        public Object[] getTestObjects() {
592            JavaTimeZone zones[] = new JavaTimeZone[ZONES.length];
593            for(int z = 0; z < ZONES.length; z += 1) {
594                java.util.TimeZone tz = java.util.TimeZone.getTimeZone(ZONES[z]);
595                zones[z] = new JavaTimeZone(tz, ZONES[z]);
596            }
597            return zones;
598        }
599
600        @Override
601        public boolean hasSameBehavior(Object a, Object b)
602        {
603            TimeZone zone_a = (TimeZone) a;
604            TimeZone zone_b = (TimeZone) b;
605
606            if (!(TimeZone.getCanonicalID(zone_a.getID()).equals(TimeZone.getCanonicalID(zone_b.getID())))) {
607                return false;
608            }
609
610            int a_offsets[] = {0, 0};
611            int b_offsets[] = {0, 0};
612
613            boolean bSame = true;
614            for (int i = 0; i < sampleTimes.length; i++) {
615                zone_a.getOffset(sampleTimes[i], false, a_offsets);
616                zone_b.getOffset(sampleTimes[i], false, b_offsets);
617                if (a_offsets[0] != b_offsets[0] || a_offsets[1] != b_offsets[1]) {
618                    bSame = false;
619                    break;
620                }
621            }
622            return bSame;
623        }
624    }
625
626    private static class BigDecimalHandler implements Handler
627    {
628        String values[] = {
629            "1234567890.",
630            "123456789.0",
631            "12345678.90",
632            "1234567.890",
633            "123456.7890",
634            "12345.67890",
635            "1234.567890",
636            "123.4567890",
637            "12.34567890",
638            "1.234567890",
639            ".1234567890"};
640
641        @Override
642        public Object[] getTestObjects()
643        {
644            BigDecimal bds[] = new BigDecimal[values.length];
645
646            for (int i = 0; i < values.length; i += 1) {
647                bds[i] = new BigDecimal(values[i]);
648            }
649
650            return bds;
651        }
652
653        @Override
654        public boolean hasSameBehavior(Object a, Object b) {
655            BigDecimal bda = (BigDecimal) a;
656            BigDecimal bdb = (BigDecimal) b;
657
658            return bda.toString().equals(bdb.toString());
659        }
660    }
661
662    private static class MathContextHandler implements Handler
663    {
664        int forms[] = {MathContext.PLAIN, MathContext.ENGINEERING, MathContext.SCIENTIFIC};
665        int rounds[] = {
666            MathContext.ROUND_CEILING, MathContext.ROUND_DOWN, MathContext.ROUND_FLOOR,
667            MathContext.ROUND_HALF_DOWN, MathContext.ROUND_HALF_EVEN, MathContext.ROUND_HALF_UP,
668            MathContext.ROUND_UNNECESSARY, MathContext.ROUND_UP};
669
670        @Override
671        public Object[] getTestObjects()
672        {
673            int objectCount = forms.length * rounds.length;
674            MathContext contexts[] = new MathContext[objectCount];
675            int i = 0;
676
677            for (int f = 0; f < forms.length; f += 1) {
678                for (int r = 0; r < rounds.length; r += 1) {
679                    int digits = f * r;
680                    boolean lostDigits = (r & 1) != 0;
681
682                    contexts[i++] = new MathContext(digits, forms[f], lostDigits, rounds[r]);
683                }
684            }
685
686            return contexts;
687        }
688
689        @Override
690        public boolean hasSameBehavior(Object a, Object b)
691        {
692            MathContext mca = (MathContext) a;
693            MathContext mcb = (MathContext) b;
694
695            return mca.toString().equals(mcb.toString());
696        }
697    }
698
699    private static abstract class ExceptionHandlerBase implements Handler {
700        @Override
701        public boolean hasSameBehavior(Object a, Object b) {
702            return sameThrowable((Exception) a, (Exception) b);
703        }
704
705        // Exception.equals() does not seem to work.
706        private static final boolean sameThrowable(Throwable a, Throwable b) {
707            return a == null ? b == null :
708                    b == null ? false :
709                            a.getClass().equals(b.getClass()) &&
710                            Utility.objectEquals(a.getMessage(), b.getMessage()) &&
711                            sameThrowable(a.getCause(), b.getCause());
712        }
713    }
714
715    private static class ICUExceptionHandler extends ExceptionHandlerBase {
716        @Override
717        public Object[] getTestObjects() {
718            return new ICUException[] {
719                    new ICUException(),
720                    new ICUException("msg1"),
721                    new ICUException(new RuntimeException("rte1")),
722                    new ICUException("msg2", new RuntimeException("rte2"))
723            };
724        }
725    }
726
727    private static class ICUUncheckedIOExceptionHandler extends ExceptionHandlerBase {
728        @Override
729        public Object[] getTestObjects() {
730            return new ICUUncheckedIOException[] {
731                    new ICUUncheckedIOException(),
732                    new ICUUncheckedIOException("msg1"),
733                    new ICUUncheckedIOException(new RuntimeException("rte1")),
734                    new ICUUncheckedIOException("msg2", new RuntimeException("rte2"))
735            };
736        }
737    }
738
739    private static class ICUCloneNotSupportedExceptionHandler extends ExceptionHandlerBase {
740        @Override
741        public Object[] getTestObjects() {
742            return new ICUCloneNotSupportedException[] {
743                    new ICUCloneNotSupportedException(),
744                    new ICUCloneNotSupportedException("msg1"),
745                    new ICUCloneNotSupportedException(new RuntimeException("rte1")),
746                    new ICUCloneNotSupportedException("msg2", new RuntimeException("rte2"))
747            };
748        }
749    }
750
751    private static HashMap map = new HashMap();
752
753    static {
754        map.put("android.icu.util.TimeZone", new TimeZoneHandler());
755        map.put("android.icu.util.SimpleTimeZone", new SimpleTimeZoneHandler());
756        map.put("android.icu.util.RuleBasedTimeZone", new RuleBasedTimeZoneHandler());
757        map.put("android.icu.util.VTimeZone", new VTimeZoneHandler());
758        map.put("android.icu.util.DateTimeRule", new DateTimeRuleHandler());
759        map.put("android.icu.util.AnnualTimeZoneRule", new AnnualTimeZoneRuleHandler());
760        map.put("android.icu.util.InitialTimeZoneRule", new InitialTimeZoneRuleHandler());
761        map.put("android.icu.util.TimeArrayTimeZoneRule", new TimeArrayTimeZoneRuleHandler());
762        map.put("android.icu.util.ULocale", new ULocaleHandler());
763        map.put("android.icu.util.Currency", new CurrencyHandler());
764        map.put("android.icu.impl.JavaTimeZone", new JavaTimeZoneHandler());
765        map.put("android.icu.impl.OlsonTimeZone", new OlsonTimeZoneHandler());
766        map.put("android.icu.impl.TimeZoneAdapter", new TimeZoneAdapterHandler());
767        map.put("android.icu.math.BigDecimal", new BigDecimalHandler());
768        map.put("android.icu.math.MathContext", new MathContextHandler());
769
770        map.put("android.icu.text.NumberFormat", new FormatHandler.NumberFormatHandler());
771        map.put("android.icu.text.DecimalFormat", new FormatHandler.DecimalFormatHandler());
772        map.put("android.icu.text.CompactDecimalFormat", new FormatHandler.CompactDecimalFormatHandler());
773        map.put("android.icu.text.RuleBasedNumberFormat", new FormatHandler.RuleBasedNumberFormatHandler());
774        map.put("android.icu.text.CurrencyPluralInfo", new FormatHandler.CurrencyPluralInfoHandler());
775        map.put("android.icu.text.DecimalFormatSymbols", new FormatHandler.DecimalFormatSymbolsHandler());
776        map.put("android.icu.text.MessageFormat", new FormatHandler.MessageFormatHandler());
777        map.put("android.icu.text.DateFormat", new FormatHandler.DateFormatHandler());
778        map.put("android.icu.text.DateFormatSymbols", new FormatHandler.DateFormatSymbolsHandler());
779        map.put("android.icu.util.DateInterval", new DateIntervalHandler());
780        map.put("android.icu.text.DateIntervalFormat", new FormatHandler.DateIntervalFormatHandler());
781        map.put("android.icu.text.DateIntervalInfo", new FormatHandler.DateIntervalInfoHandler());
782        map.put("android.icu.text.DateIntervalInfo$PatternInfo", new FormatHandler.PatternInfoHandler());
783        map.put("android.icu.text.SimpleDateFormat", new FormatHandler.SimpleDateFormatHandler());
784        map.put("android.icu.text.ChineseDateFormat", new FormatHandler.ChineseDateFormatHandler());
785        map.put("android.icu.text.ChineseDateFormatSymbols", new FormatHandler.ChineseDateFormatSymbolsHandler());
786        map.put("android.icu.impl.DateNumberFormat", new FormatHandler.DateNumberFormatHandler());
787        map.put("android.icu.text.PluralFormat", new FormatHandler.PluralFormatHandler());
788        map.put("android.icu.text.PluralRules", new FormatHandler.PluralRulesHandler());
789        map.put("android.icu.text.PluralRulesSerialProxy", new FormatHandler.PluralRulesSerialProxyHandler());
790        map.put("android.icu.text.TimeUnitFormat", new FormatHandler.TimeUnitFormatHandler());
791        map.put("android.icu.text.SelectFormat", new FormatHandler.SelectFormatHandler());
792        map.put("android.icu.impl.TimeZoneNamesImpl", new FormatHandler.TimeZoneNamesHandler());
793        map.put("android.icu.text.TimeZoneFormat", new FormatHandler.TimeZoneFormatHandler());
794        map.put("android.icu.impl.TimeZoneGenericNames", new FormatHandler.TimeZoneGenericNamesHandler());
795        map.put("android.icu.impl.TZDBTimeZoneNames", new FormatHandler.TZDBTimeZoneNamesHandler());
796
797        map.put("android.icu.util.Calendar", new CalendarHandler.BasicCalendarHandler());
798        map.put("android.icu.util.BuddhistCalendar", new CalendarHandler.BuddhistCalendarHandler());
799        map.put("android.icu.util.ChineseCalendar", new CalendarHandler.ChineseCalendarHandler());
800        map.put("android.icu.util.CopticCalendar", new CalendarHandler.CopticCalendarHandler());
801        map.put("android.icu.util.DangiCalendar", new CalendarHandler.DangiCalendarHandler());
802        map.put("android.icu.util.EthiopicCalendar", new CalendarHandler.EthiopicCalendarHandler());
803        map.put("android.icu.util.GregorianCalendar", new CalendarHandler.GregorianCalendarHandler());
804        map.put("android.icu.util.HebrewCalendar", new CalendarHandler.HebrewCalendarHandler());
805        map.put("android.icu.util.IndianCalendar", new CalendarHandler.IndianCalendarHandler());
806        map.put("android.icu.util.IslamicCalendar", new CalendarHandler.IslamicCalendarHandler());
807        map.put("android.icu.util.JapaneseCalendar", new CalendarHandler.JapaneseCalendarHandler());
808        map.put("android.icu.util.PersianCalendar", new CalendarHandler.PersianCalendarHandler());
809        map.put("android.icu.util.TaiwanCalendar", new CalendarHandler.TaiwanCalendarHandler());
810
811        map.put("android.icu.text.ArabicShapingException", new ExceptionHandler.ArabicShapingExceptionHandler());
812        map.put("android.icu.text.StringPrepParseException", new ExceptionHandler.StringPrepParseExceptionHandler());
813        map.put("android.icu.util.UResourceTypeMismatchException", new ExceptionHandler.UResourceTypeMismatchExceptionHandler());
814        map.put("android.icu.impl.InvalidFormatException", new ExceptionHandler.InvalidFormatExceptionHandler());
815
816        map.put("android.icu.text.NumberFormat$Field", new FormatHandler.NumberFormatFieldHandler());
817        map.put("android.icu.text.DateFormat$Field", new FormatHandler.DateFormatFieldHandler());
818        map.put("android.icu.text.ChineseDateFormat$Field", new FormatHandler.ChineseDateFormatFieldHandler());
819        map.put("android.icu.text.MessageFormat$Field", new FormatHandler.MessageFormatFieldHandler());
820
821        map.put("android.icu.impl.duration.BasicDurationFormat", new FormatHandler.BasicDurationFormatHandler());
822        map.put("android.icu.impl.RelativeDateFormat", new FormatHandler.RelativeDateFormatHandler());
823        map.put("android.icu.util.IllformedLocaleException", new ExceptionHandler.IllformedLocaleExceptionHandler());
824        map.put("android.icu.impl.locale.LocaleSyntaxException", new ExceptionHandler.LocaleSyntaxExceptionHandler());
825        map.put("android.icu.impl.IllegalIcuArgumentException", new ExceptionHandler.IllegalIcuArgumentExceptionHandler());
826
827        map.put("android.icu.text.PluralRules$FixedDecimal", new PluralRulesTest.FixedDecimalHandler());
828        map.put("android.icu.util.MeasureUnit", new MeasureUnitTest.MeasureUnitHandler());
829        map.put("android.icu.util.TimeUnit", new MeasureUnitTest.MeasureUnitHandler());
830        map.put("android.icu.text.MeasureFormat", new MeasureUnitTest.MeasureFormatHandler());
831
832        map.put("android.icu.util.ICUException", new ICUExceptionHandler());
833        map.put("android.icu.util.ICUUncheckedIOException", new ICUUncheckedIOExceptionHandler());
834        map.put("android.icu.util.ICUCloneNotSupportedException", new ICUCloneNotSupportedExceptionHandler());
835    }
836
837    /*
838     * Serialization Helpers
839     */
840    static Object[] getSerializedObjects(byte[] serializedBytes) throws ClassNotFoundException, IOException {
841        ByteArrayInputStream bis = new ByteArrayInputStream(serializedBytes);
842        ObjectInputStream ois = new ObjectInputStream(bis);
843        Object inputObjects[] = (Object[]) ois.readObject();
844
845        ois.close();
846        return inputObjects;
847    }
848
849    static byte[] getSerializedBytes(Object[] objectsOut) throws IOException {
850        ByteArrayOutputStream bos = new ByteArrayOutputStream();
851        ObjectOutputStream oos = new ObjectOutputStream(bos);
852        oos.writeObject(objectsOut);
853
854        byte[] serializedBytes = bos.toByteArray();
855        oos.close();
856        return serializedBytes;
857    }
858
859    static Object[] getSerializedObjects(File testFile) throws IOException, ClassNotFoundException {
860        FileInputStream fis = new FileInputStream(testFile);
861        ObjectInputStream ois = new ObjectInputStream(fis);
862        Object[] objects = (Object[]) ois.readObject();
863        fis.close();
864        return objects;
865    }
866
867    static byte[] copyStreamBytes(InputStream is) throws IOException {
868        byte[] buffer = new byte[1024];
869
870        ByteArrayOutputStream bos = new ByteArrayOutputStream();
871        int len;
872        while((len = is.read(buffer, 0, buffer.length)) >= 0) {
873            bos.write(buffer, 0, len);
874        }
875        return bos.toByteArray();
876    }
877
878    static List<String> getSerializationClassList(Object caller) throws IOException {
879        List<String> classList = new ArrayList();
880        Enumeration<URL> urlEnum = caller.getClass().getClassLoader().getResources("android/icu");
881        while (urlEnum.hasMoreElements()) {
882            URL url = urlEnum.nextElement();
883            URLHandler handler  = URLHandler.get(url);
884            if (handler == null) {
885                System.out.println("Unsupported URL: " + url);
886                continue;
887            }
888            CoverageClassVisitor visitor = new CoverageClassVisitor(classList);
889            handler.guide(visitor, true, false);
890        }
891        return classList;
892    }
893
894    private static class CoverageClassVisitor implements URLHandler.URLVisitor {
895        private List<String> classNames;
896
897        public CoverageClassVisitor(List<String> classNamesList) {
898            this.classNames = classNamesList;
899        }
900
901        /* (non-Javadoc)
902         * @see android.icu.impl.URLHandler.URLVisitor#visit(java.lang.String)
903         */
904        @Override
905        public void visit(String classPath) {
906            int ix = classPath.lastIndexOf(".class");
907            if (ix < 0) {
908                return;
909            }
910            String className = "android.icu" + classPath.substring(0, ix).replace('/', '.');
911
912            // Skip things in android.icu.dev; they're not relevant.
913            if (className.startsWith("android.icu.dev.")) {
914                return;
915            }
916            Class c;
917            try {
918                c = Class.forName(className);
919            } catch (ClassNotFoundException e) {
920                return;
921            }
922            int m = c.getModifiers();
923
924            if (className.equals("android.icu.text.PluralRules$FixedDecimal")) {
925                // Known Issue: "10268", "Serializable interface is not implemented in PluralRules$FixedDecimal"
926                return;
927            }
928
929            if (c.isEnum() || !serializable.isAssignableFrom(c)) {
930                //System.out.println("@@@ Skipping: " + className);
931                return;
932            }
933            if (!Modifier.isPublic(m) || Modifier.isInterface(m)) {
934                //System.out.println("@@@ Skipping: " + className);
935                return;
936            }
937
938            this.classNames.add(className);
939        }
940    }
941
942    public static void serializeObjects(File oof, Object[] objectsOut) throws IOException {
943        FileOutputStream fos = new FileOutputStream(oof);
944        ObjectOutputStream oos = new ObjectOutputStream(fos);
945        oos.writeObject(objectsOut);
946
947        oos.close();
948    }
949}
950