1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html#License
3/*
4 *******************************************************************************
5 * Copyright (C) 2013-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 */
9package com.ibm.icu.dev.test.format;
10
11import java.io.ByteArrayInputStream;
12import java.io.ByteArrayOutputStream;
13import java.io.IOException;
14import java.io.ObjectInputStream;
15import java.io.ObjectOutputStream;
16import java.io.Serializable;
17import java.lang.reflect.Field;
18import java.text.FieldPosition;
19import java.util.ArrayList;
20import java.util.Collections;
21import java.util.Comparator;
22import java.util.HashMap;
23import java.util.HashSet;
24import java.util.List;
25import java.util.Locale;
26import java.util.Map;
27import java.util.Set;
28import java.util.TreeMap;
29
30import org.junit.Test;
31
32import com.ibm.icu.dev.test.TestFmwk;
33import com.ibm.icu.dev.test.serializable.SerializableTestUtility;
34import com.ibm.icu.impl.Pair;
35import com.ibm.icu.impl.Utility;
36import com.ibm.icu.math.BigDecimal;
37import com.ibm.icu.text.MeasureFormat;
38import com.ibm.icu.text.MeasureFormat.FormatWidth;
39import com.ibm.icu.text.NumberFormat;
40import com.ibm.icu.util.Currency;
41import com.ibm.icu.util.Measure;
42import com.ibm.icu.util.MeasureUnit;
43import com.ibm.icu.util.TimeUnit;
44import com.ibm.icu.util.TimeUnitAmount;
45import com.ibm.icu.util.ULocale;
46
47/**
48 * See https://sites.google.com/site/icusite/processes/release/tasks/standards?pli=1
49 * for information on how to update with each new release.
50 * @author markdavis
51 */
52public class MeasureUnitTest extends TestFmwk {
53
54    static class OrderedPair<F extends Comparable, S extends Comparable> extends Pair<F, S> implements Comparable<OrderedPair<F, S>> {
55
56        OrderedPair(F first, S second) {
57            super(first, second);
58        }
59
60        public static <F extends Comparable, S extends Comparable> OrderedPair<F, S> of(F first, S second) {
61            if (first == null || second == null) {
62                throw new IllegalArgumentException("OrderedPair.of requires non null values.");
63            }
64            return new OrderedPair<F, S>(first, second);
65        }
66
67        @Override
68        public int compareTo(OrderedPair<F, S> other) {
69            int result = first.compareTo(other.first);
70            if (result != 0) {
71                return result;
72            }
73            return second.compareTo(other.second);
74        }
75    }
76
77    private static final String[] DRAFT_VERSIONS = {"57", "58"};
78
79    private static final HashSet<String> DRAFT_VERSION_SET = new HashSet<String>();
80
81    private static final HashSet<String> TIME_CODES = new HashSet<String>();
82
83    private static final String[][] JAVA_VERSIONS = {
84        {"G_FORCE", "53"},
85        {"DEGREE", "53"},
86        {"ARC_MINUTE", "53"},
87        {"ARC_SECOND", "53"},
88        {"ACRE", "53"},
89        {"HECTARE", "53"},
90        {"SQUARE_FOOT", "53"},
91        {"SQUARE_KILOMETER", "53"},
92        {"SQUARE_METER", "53"},
93        {"SQUARE_MILE", "53"},
94        {"MILLISECOND", "53"},
95        {"CENTIMETER", "53"},
96        {"FOOT", "53"},
97        {"INCH", "53"},
98        {"KILOMETER", "53"},
99        {"LIGHT_YEAR", "53"},
100        {"METER", "53"},
101        {"MILE", "53"},
102        {"MILLIMETER", "53"},
103        {"PICOMETER", "53"},
104        {"YARD", "53"},
105        {"GRAM", "53"},
106        {"KILOGRAM", "53"},
107        {"OUNCE", "53"},
108        {"POUND", "53"},
109        {"HORSEPOWER", "53"},
110        {"KILOWATT", "53"},
111        {"WATT", "53"},
112        {"HECTOPASCAL", "53"},
113        {"INCH_HG", "53"},
114        {"MILLIBAR", "53"},
115        {"KILOMETER_PER_HOUR", "53"},
116        {"METER_PER_SECOND", "53"},
117        {"MILE_PER_HOUR", "53"},
118        {"CELSIUS", "53"},
119        {"FAHRENHEIT", "53"},
120        {"CUBIC_KILOMETER", "53"},
121        {"CUBIC_MILE", "53"},
122        {"LITER", "53"},
123        {"YEAR", "53"},
124        {"MONTH", "53"},
125        {"WEEK", "53"},
126        {"DAY", "53"},
127        {"HOUR", "53"},
128        {"MINUTE", "53"},
129        {"SECOND", "53"},
130        {"METER_PER_SECOND_SQUARED", "54"},
131        {"RADIAN", "54"},
132        {"SQUARE_CENTIMETER", "54"},
133        {"SQUARE_INCH", "54"},
134        {"SQUARE_YARD", "54"},
135        {"LITER_PER_KILOMETER", "54"},
136        {"MILE_PER_GALLON", "54"},
137        {"BIT", "54"},
138        {"BYTE", "54"},
139        {"GIGABIT", "54"},
140        {"GIGABYTE", "54"},
141        {"KILOBIT", "54"},
142        {"KILOBYTE", "54"},
143        {"MEGABIT", "54"},
144        {"MEGABYTE", "54"},
145        {"TERABIT", "54"},
146        {"TERABYTE", "54"},
147        {"MICROSECOND", "54"},
148        {"NANOSECOND", "54"},
149        {"AMPERE", "54"},
150        {"MILLIAMPERE", "54"},
151        {"OHM", "54"},
152        {"VOLT", "54"},
153        {"CALORIE", "54"},
154        {"FOODCALORIE", "54"},
155        {"JOULE", "54"},
156        {"KILOCALORIE", "54"},
157        {"KILOJOULE", "54"},
158        {"KILOWATT_HOUR", "54"},
159        {"GIGAHERTZ", "54"},
160        {"HERTZ", "54"},
161        {"KILOHERTZ", "54"},
162        {"MEGAHERTZ", "54"},
163        {"ASTRONOMICAL_UNIT", "54"},
164        {"DECIMETER", "54"},
165        {"FATHOM", "54"},
166        {"FURLONG", "54"},
167        {"MICROMETER", "54"},
168        {"NANOMETER", "54"},
169        {"NAUTICAL_MILE", "54"},
170        {"PARSEC", "54"},
171        {"LUX", "54"},
172        {"CARAT", "54"},
173        {"METRIC_TON", "54"},
174        {"MICROGRAM", "54"},
175        {"MILLIGRAM", "54"},
176        {"OUNCE_TROY", "54"},
177        {"STONE", "54"},
178        {"TON", "54"},
179        {"GIGAWATT", "54"},
180        {"MEGAWATT", "54"},
181        {"MILLIWATT", "54"},
182        {"MILLIMETER_OF_MERCURY", "54"},
183        {"POUND_PER_SQUARE_INCH", "54"},
184        {"KARAT", "54"},
185        {"KELVIN", "54"},
186        {"ACRE_FOOT", "54"},
187        {"BUSHEL", "54"},
188        {"CENTILITER", "54"},
189        {"CUBIC_CENTIMETER", "54"},
190        {"CUBIC_FOOT", "54"},
191        {"CUBIC_INCH", "54"},
192        {"CUBIC_METER", "54"},
193        {"CUBIC_YARD", "54"},
194        {"CUP", "54"},
195        {"DECILITER", "54"},
196        {"FLUID_OUNCE", "54"},
197        {"GALLON", "54"},
198        {"HECTOLITER", "54"},
199        {"MEGALITER", "54"},
200        {"MILLILITER", "54"},
201        {"PINT", "54"},
202        {"QUART", "54"},
203        {"TABLESPOON", "54"},
204        {"TEASPOON", "54"},
205        {"GENERIC_TEMPERATURE", "56"},
206        {"REVOLUTION_ANGLE", "56"},
207        {"LITER_PER_100KILOMETERS", "56"},
208        {"CENTURY", "56"},
209        {"MILE_SCANDINAVIAN", "56"},
210        {"KNOT", "56"},
211        {"CUP_METRIC", "56"},
212        {"PINT_METRIC", "56"},
213        {"MILLIGRAM_PER_DECILITER", "57"},
214        {"MILLIMOLE_PER_LITER", "57"},
215        {"PART_PER_MILLION", "57"},
216        {"MILE_PER_GALLON_IMPERIAL", "57"},
217        {"GALLON_IMPERIAL", "57"},
218        {"EAST", "58"},
219        {"NORTH", "58"},
220        {"SOUTH", "58"},
221        {"WEST", "58"},
222    };
223
224    private static final HashMap<String, String> JAVA_VERSION_MAP = new HashMap<String, String>();
225
226    static {
227        TIME_CODES.add("year");
228        TIME_CODES.add("month");
229        TIME_CODES.add("week");
230        TIME_CODES.add("day");
231        TIME_CODES.add("hour");
232        TIME_CODES.add("minute");
233        TIME_CODES.add("second");
234        for (String verNum : DRAFT_VERSIONS) {
235            DRAFT_VERSION_SET.add(verNum);
236        }
237        for (String[] funcNameAndVersion : JAVA_VERSIONS) {
238            JAVA_VERSION_MAP.put(funcNameAndVersion[0], funcNameAndVersion[1]);
239        }
240    }
241
242    /**
243     * @author markdavis
244     *
245     */
246    // TODO(junit): resolve
247//    public static void main(String[] args) {
248//        //generateConstants(); if (true) return;
249//
250//        // Ticket #12034 deadlock on multi-threaded static init of MeasureUnit.
251//        // The code below reliably deadlocks with ICU 56.
252//        // The test is here in main() rather than in a test function so it can be made to run
253//        // before anything else.
254//        Thread thread = new Thread()  {
255//            @Override
256//            public void run() {
257//                @SuppressWarnings("unused")
258//                Set<String> measureUnitTypes = MeasureUnit.getAvailableTypes();
259//            }
260//        };
261//        thread.start();
262//        @SuppressWarnings("unused")
263//        Currency cur = Currency.getInstance(ULocale.ENGLISH);
264//        try {thread.join();} catch(InterruptedException e) {};
265//        // System.out.println("Done with MeasureUnit thread test.");
266//
267//        new MeasureUnitTest().run(args);
268//    }
269
270/*
271    @Test
272    public void testZZZ() {
273        // various generateXXX calls go here, see
274        // http://site.icu-project.org/design/formatting/measureformat/updating-measure-unit
275        // use this test to run each of the ollowing in succession
276        //generateConstants("58"); // for MeasureUnit.java, update generated MeasureUnit constants
277        //generateBackwardCompatibilityTest("58.1"); // for MeasureUnitTest.java, create TestCompatible58_1
278        //generateCXXHConstants("58"); // for measunit.h, update generated createXXX methods
279        //generateCXXConstants(); // for measunit.cpp, update generated code
280        //generateCXXBackwardCompatibilityTest("58.1"); // for measfmttest.cpp, create TestCompatible58_1
281        updateJAVAVersions("58"); // for MeasureUnitTest.java, JAVA_VERSIONS
282    }
283*/
284
285    @Test
286    public void TestCompatible53_1() {
287        MeasureUnit[] units = {
288                MeasureUnit.G_FORCE,
289                MeasureUnit.DEGREE,
290                MeasureUnit.ARC_MINUTE,
291                MeasureUnit.ARC_SECOND,
292                MeasureUnit.ACRE,
293                MeasureUnit.HECTARE,
294                MeasureUnit.SQUARE_FOOT,
295                MeasureUnit.SQUARE_KILOMETER,
296                MeasureUnit.SQUARE_METER,
297                MeasureUnit.SQUARE_MILE,
298                MeasureUnit.MILLISECOND,
299                MeasureUnit.CENTIMETER,
300                MeasureUnit.FOOT,
301                MeasureUnit.INCH,
302                MeasureUnit.KILOMETER,
303                MeasureUnit.LIGHT_YEAR,
304                MeasureUnit.METER,
305                MeasureUnit.MILE,
306                MeasureUnit.MILLIMETER,
307                MeasureUnit.PICOMETER,
308                MeasureUnit.YARD,
309                MeasureUnit.GRAM,
310                MeasureUnit.KILOGRAM,
311                MeasureUnit.OUNCE,
312                MeasureUnit.POUND,
313                MeasureUnit.HORSEPOWER,
314                MeasureUnit.KILOWATT,
315                MeasureUnit.WATT,
316                MeasureUnit.HECTOPASCAL,
317                MeasureUnit.INCH_HG,
318                MeasureUnit.MILLIBAR,
319                MeasureUnit.KILOMETER_PER_HOUR,
320                MeasureUnit.METER_PER_SECOND,
321                MeasureUnit.MILE_PER_HOUR,
322                MeasureUnit.CELSIUS,
323                MeasureUnit.FAHRENHEIT,
324                MeasureUnit.CUBIC_KILOMETER,
325                MeasureUnit.CUBIC_MILE,
326                MeasureUnit.LITER,
327                MeasureUnit.YEAR,
328                MeasureUnit.MONTH,
329                MeasureUnit.WEEK,
330                MeasureUnit.DAY,
331                MeasureUnit.HOUR,
332                MeasureUnit.MINUTE,
333                MeasureUnit.SECOND,
334        };
335        assertEquals("", 46, units.length);
336    }
337
338    @Test
339    public void TestCompatible54_1() {
340        MeasureUnit[] units = {
341                MeasureUnit.G_FORCE,
342                MeasureUnit.METER_PER_SECOND_SQUARED,
343                MeasureUnit.ARC_MINUTE,
344                MeasureUnit.ARC_SECOND,
345                MeasureUnit.DEGREE,
346                MeasureUnit.RADIAN,
347                MeasureUnit.ACRE,
348                MeasureUnit.HECTARE,
349                MeasureUnit.SQUARE_CENTIMETER,
350                MeasureUnit.SQUARE_FOOT,
351                MeasureUnit.SQUARE_INCH,
352                MeasureUnit.SQUARE_KILOMETER,
353                MeasureUnit.SQUARE_METER,
354                MeasureUnit.SQUARE_MILE,
355                MeasureUnit.SQUARE_YARD,
356                MeasureUnit.LITER_PER_KILOMETER,
357                MeasureUnit.MILE_PER_GALLON,
358                MeasureUnit.BIT,
359                MeasureUnit.BYTE,
360                MeasureUnit.GIGABIT,
361                MeasureUnit.GIGABYTE,
362                MeasureUnit.KILOBIT,
363                MeasureUnit.KILOBYTE,
364                MeasureUnit.MEGABIT,
365                MeasureUnit.MEGABYTE,
366                MeasureUnit.TERABIT,
367                MeasureUnit.TERABYTE,
368                MeasureUnit.DAY,
369                MeasureUnit.HOUR,
370                MeasureUnit.MICROSECOND,
371                MeasureUnit.MILLISECOND,
372                MeasureUnit.MINUTE,
373                MeasureUnit.MONTH,
374                MeasureUnit.NANOSECOND,
375                MeasureUnit.SECOND,
376                MeasureUnit.WEEK,
377                MeasureUnit.YEAR,
378                MeasureUnit.AMPERE,
379                MeasureUnit.MILLIAMPERE,
380                MeasureUnit.OHM,
381                MeasureUnit.VOLT,
382                MeasureUnit.CALORIE,
383                MeasureUnit.FOODCALORIE,
384                MeasureUnit.JOULE,
385                MeasureUnit.KILOCALORIE,
386                MeasureUnit.KILOJOULE,
387                MeasureUnit.KILOWATT_HOUR,
388                MeasureUnit.GIGAHERTZ,
389                MeasureUnit.HERTZ,
390                MeasureUnit.KILOHERTZ,
391                MeasureUnit.MEGAHERTZ,
392                MeasureUnit.ASTRONOMICAL_UNIT,
393                MeasureUnit.CENTIMETER,
394                MeasureUnit.DECIMETER,
395                MeasureUnit.FATHOM,
396                MeasureUnit.FOOT,
397                MeasureUnit.FURLONG,
398                MeasureUnit.INCH,
399                MeasureUnit.KILOMETER,
400                MeasureUnit.LIGHT_YEAR,
401                MeasureUnit.METER,
402                MeasureUnit.MICROMETER,
403                MeasureUnit.MILE,
404                MeasureUnit.MILLIMETER,
405                MeasureUnit.NANOMETER,
406                MeasureUnit.NAUTICAL_MILE,
407                MeasureUnit.PARSEC,
408                MeasureUnit.PICOMETER,
409                MeasureUnit.YARD,
410                MeasureUnit.LUX,
411                MeasureUnit.CARAT,
412                MeasureUnit.GRAM,
413                MeasureUnit.KILOGRAM,
414                MeasureUnit.METRIC_TON,
415                MeasureUnit.MICROGRAM,
416                MeasureUnit.MILLIGRAM,
417                MeasureUnit.OUNCE,
418                MeasureUnit.OUNCE_TROY,
419                MeasureUnit.POUND,
420                MeasureUnit.STONE,
421                MeasureUnit.TON,
422                MeasureUnit.GIGAWATT,
423                MeasureUnit.HORSEPOWER,
424                MeasureUnit.KILOWATT,
425                MeasureUnit.MEGAWATT,
426                MeasureUnit.MILLIWATT,
427                MeasureUnit.WATT,
428                MeasureUnit.HECTOPASCAL,
429                MeasureUnit.INCH_HG,
430                MeasureUnit.MILLIBAR,
431                MeasureUnit.MILLIMETER_OF_MERCURY,
432                MeasureUnit.POUND_PER_SQUARE_INCH,
433                MeasureUnit.KARAT,
434                MeasureUnit.KILOMETER_PER_HOUR,
435                MeasureUnit.METER_PER_SECOND,
436                MeasureUnit.MILE_PER_HOUR,
437                MeasureUnit.CELSIUS,
438                MeasureUnit.FAHRENHEIT,
439                MeasureUnit.KELVIN,
440                MeasureUnit.ACRE_FOOT,
441                MeasureUnit.BUSHEL,
442                MeasureUnit.CENTILITER,
443                MeasureUnit.CUBIC_CENTIMETER,
444                MeasureUnit.CUBIC_FOOT,
445                MeasureUnit.CUBIC_INCH,
446                MeasureUnit.CUBIC_KILOMETER,
447                MeasureUnit.CUBIC_METER,
448                MeasureUnit.CUBIC_MILE,
449                MeasureUnit.CUBIC_YARD,
450                MeasureUnit.CUP,
451                MeasureUnit.DECILITER,
452                MeasureUnit.FLUID_OUNCE,
453                MeasureUnit.GALLON,
454                MeasureUnit.HECTOLITER,
455                MeasureUnit.LITER,
456                MeasureUnit.MEGALITER,
457                MeasureUnit.MILLILITER,
458                MeasureUnit.PINT,
459                MeasureUnit.QUART,
460                MeasureUnit.TABLESPOON,
461                MeasureUnit.TEASPOON,
462        };
463        assertEquals("",  121, units.length);
464    }
465
466    @Test
467    public void TestCompatible55_1() {
468        MeasureUnit[] units = {
469                MeasureUnit.G_FORCE,
470                MeasureUnit.METER_PER_SECOND_SQUARED,
471                MeasureUnit.ARC_MINUTE,
472                MeasureUnit.ARC_SECOND,
473                MeasureUnit.DEGREE,
474                MeasureUnit.RADIAN,
475                MeasureUnit.ACRE,
476                MeasureUnit.HECTARE,
477                MeasureUnit.SQUARE_CENTIMETER,
478                MeasureUnit.SQUARE_FOOT,
479                MeasureUnit.SQUARE_INCH,
480                MeasureUnit.SQUARE_KILOMETER,
481                MeasureUnit.SQUARE_METER,
482                MeasureUnit.SQUARE_MILE,
483                MeasureUnit.SQUARE_YARD,
484                MeasureUnit.LITER_PER_KILOMETER,
485                MeasureUnit.MILE_PER_GALLON,
486                MeasureUnit.BIT,
487                MeasureUnit.BYTE,
488                MeasureUnit.GIGABIT,
489                MeasureUnit.GIGABYTE,
490                MeasureUnit.KILOBIT,
491                MeasureUnit.KILOBYTE,
492                MeasureUnit.MEGABIT,
493                MeasureUnit.MEGABYTE,
494                MeasureUnit.TERABIT,
495                MeasureUnit.TERABYTE,
496                MeasureUnit.DAY,
497                MeasureUnit.HOUR,
498                MeasureUnit.MICROSECOND,
499                MeasureUnit.MILLISECOND,
500                MeasureUnit.MINUTE,
501                MeasureUnit.MONTH,
502                MeasureUnit.NANOSECOND,
503                MeasureUnit.SECOND,
504                MeasureUnit.WEEK,
505                MeasureUnit.YEAR,
506                MeasureUnit.AMPERE,
507                MeasureUnit.MILLIAMPERE,
508                MeasureUnit.OHM,
509                MeasureUnit.VOLT,
510                MeasureUnit.CALORIE,
511                MeasureUnit.FOODCALORIE,
512                MeasureUnit.JOULE,
513                MeasureUnit.KILOCALORIE,
514                MeasureUnit.KILOJOULE,
515                MeasureUnit.KILOWATT_HOUR,
516                MeasureUnit.GIGAHERTZ,
517                MeasureUnit.HERTZ,
518                MeasureUnit.KILOHERTZ,
519                MeasureUnit.MEGAHERTZ,
520                MeasureUnit.ASTRONOMICAL_UNIT,
521                MeasureUnit.CENTIMETER,
522                MeasureUnit.DECIMETER,
523                MeasureUnit.FATHOM,
524                MeasureUnit.FOOT,
525                MeasureUnit.FURLONG,
526                MeasureUnit.INCH,
527                MeasureUnit.KILOMETER,
528                MeasureUnit.LIGHT_YEAR,
529                MeasureUnit.METER,
530                MeasureUnit.MICROMETER,
531                MeasureUnit.MILE,
532                MeasureUnit.MILLIMETER,
533                MeasureUnit.NANOMETER,
534                MeasureUnit.NAUTICAL_MILE,
535                MeasureUnit.PARSEC,
536                MeasureUnit.PICOMETER,
537                MeasureUnit.YARD,
538                MeasureUnit.LUX,
539                MeasureUnit.CARAT,
540                MeasureUnit.GRAM,
541                MeasureUnit.KILOGRAM,
542                MeasureUnit.METRIC_TON,
543                MeasureUnit.MICROGRAM,
544                MeasureUnit.MILLIGRAM,
545                MeasureUnit.OUNCE,
546                MeasureUnit.OUNCE_TROY,
547                MeasureUnit.POUND,
548                MeasureUnit.STONE,
549                MeasureUnit.TON,
550                MeasureUnit.GIGAWATT,
551                MeasureUnit.HORSEPOWER,
552                MeasureUnit.KILOWATT,
553                MeasureUnit.MEGAWATT,
554                MeasureUnit.MILLIWATT,
555                MeasureUnit.WATT,
556                MeasureUnit.HECTOPASCAL,
557                MeasureUnit.INCH_HG,
558                MeasureUnit.MILLIBAR,
559                MeasureUnit.MILLIMETER_OF_MERCURY,
560                MeasureUnit.POUND_PER_SQUARE_INCH,
561                MeasureUnit.KARAT,
562                MeasureUnit.KILOMETER_PER_HOUR,
563                MeasureUnit.METER_PER_SECOND,
564                MeasureUnit.MILE_PER_HOUR,
565                MeasureUnit.CELSIUS,
566                MeasureUnit.FAHRENHEIT,
567                MeasureUnit.GENERIC_TEMPERATURE,
568                MeasureUnit.KELVIN,
569                MeasureUnit.ACRE_FOOT,
570                MeasureUnit.BUSHEL,
571                MeasureUnit.CENTILITER,
572                MeasureUnit.CUBIC_CENTIMETER,
573                MeasureUnit.CUBIC_FOOT,
574                MeasureUnit.CUBIC_INCH,
575                MeasureUnit.CUBIC_KILOMETER,
576                MeasureUnit.CUBIC_METER,
577                MeasureUnit.CUBIC_MILE,
578                MeasureUnit.CUBIC_YARD,
579                MeasureUnit.CUP,
580                MeasureUnit.DECILITER,
581                MeasureUnit.FLUID_OUNCE,
582                MeasureUnit.GALLON,
583                MeasureUnit.HECTOLITER,
584                MeasureUnit.LITER,
585                MeasureUnit.MEGALITER,
586                MeasureUnit.MILLILITER,
587                MeasureUnit.PINT,
588                MeasureUnit.QUART,
589                MeasureUnit.TABLESPOON,
590                MeasureUnit.TEASPOON,
591        };
592        assertEquals("",  122, units.length);
593    }
594
595    @Test
596    public void TestCompatible56_1() {
597        MeasureUnit[] units = {
598                MeasureUnit.G_FORCE,
599                MeasureUnit.METER_PER_SECOND_SQUARED,
600                MeasureUnit.ARC_MINUTE,
601                MeasureUnit.ARC_SECOND,
602                MeasureUnit.DEGREE,
603                MeasureUnit.RADIAN,
604                MeasureUnit.REVOLUTION_ANGLE,
605                MeasureUnit.ACRE,
606                MeasureUnit.HECTARE,
607                MeasureUnit.SQUARE_CENTIMETER,
608                MeasureUnit.SQUARE_FOOT,
609                MeasureUnit.SQUARE_INCH,
610                MeasureUnit.SQUARE_KILOMETER,
611                MeasureUnit.SQUARE_METER,
612                MeasureUnit.SQUARE_MILE,
613                MeasureUnit.SQUARE_YARD,
614                MeasureUnit.LITER_PER_100KILOMETERS,
615                MeasureUnit.LITER_PER_KILOMETER,
616                MeasureUnit.MILE_PER_GALLON,
617                MeasureUnit.BIT,
618                MeasureUnit.BYTE,
619                MeasureUnit.GIGABIT,
620                MeasureUnit.GIGABYTE,
621                MeasureUnit.KILOBIT,
622                MeasureUnit.KILOBYTE,
623                MeasureUnit.MEGABIT,
624                MeasureUnit.MEGABYTE,
625                MeasureUnit.TERABIT,
626                MeasureUnit.TERABYTE,
627                MeasureUnit.CENTURY,
628                MeasureUnit.DAY,
629                MeasureUnit.HOUR,
630                MeasureUnit.MICROSECOND,
631                MeasureUnit.MILLISECOND,
632                MeasureUnit.MINUTE,
633                MeasureUnit.MONTH,
634                MeasureUnit.NANOSECOND,
635                MeasureUnit.SECOND,
636                MeasureUnit.WEEK,
637                MeasureUnit.YEAR,
638                MeasureUnit.AMPERE,
639                MeasureUnit.MILLIAMPERE,
640                MeasureUnit.OHM,
641                MeasureUnit.VOLT,
642                MeasureUnit.CALORIE,
643                MeasureUnit.FOODCALORIE,
644                MeasureUnit.JOULE,
645                MeasureUnit.KILOCALORIE,
646                MeasureUnit.KILOJOULE,
647                MeasureUnit.KILOWATT_HOUR,
648                MeasureUnit.GIGAHERTZ,
649                MeasureUnit.HERTZ,
650                MeasureUnit.KILOHERTZ,
651                MeasureUnit.MEGAHERTZ,
652                MeasureUnit.ASTRONOMICAL_UNIT,
653                MeasureUnit.CENTIMETER,
654                MeasureUnit.DECIMETER,
655                MeasureUnit.FATHOM,
656                MeasureUnit.FOOT,
657                MeasureUnit.FURLONG,
658                MeasureUnit.INCH,
659                MeasureUnit.KILOMETER,
660                MeasureUnit.LIGHT_YEAR,
661                MeasureUnit.METER,
662                MeasureUnit.MICROMETER,
663                MeasureUnit.MILE,
664                MeasureUnit.MILE_SCANDINAVIAN,
665                MeasureUnit.MILLIMETER,
666                MeasureUnit.NANOMETER,
667                MeasureUnit.NAUTICAL_MILE,
668                MeasureUnit.PARSEC,
669                MeasureUnit.PICOMETER,
670                MeasureUnit.YARD,
671                MeasureUnit.LUX,
672                MeasureUnit.CARAT,
673                MeasureUnit.GRAM,
674                MeasureUnit.KILOGRAM,
675                MeasureUnit.METRIC_TON,
676                MeasureUnit.MICROGRAM,
677                MeasureUnit.MILLIGRAM,
678                MeasureUnit.OUNCE,
679                MeasureUnit.OUNCE_TROY,
680                MeasureUnit.POUND,
681                MeasureUnit.STONE,
682                MeasureUnit.TON,
683                MeasureUnit.GIGAWATT,
684                MeasureUnit.HORSEPOWER,
685                MeasureUnit.KILOWATT,
686                MeasureUnit.MEGAWATT,
687                MeasureUnit.MILLIWATT,
688                MeasureUnit.WATT,
689                MeasureUnit.HECTOPASCAL,
690                MeasureUnit.INCH_HG,
691                MeasureUnit.MILLIBAR,
692                MeasureUnit.MILLIMETER_OF_MERCURY,
693                MeasureUnit.POUND_PER_SQUARE_INCH,
694                MeasureUnit.KARAT,
695                MeasureUnit.KILOMETER_PER_HOUR,
696                MeasureUnit.KNOT,
697                MeasureUnit.METER_PER_SECOND,
698                MeasureUnit.MILE_PER_HOUR,
699                MeasureUnit.CELSIUS,
700                MeasureUnit.FAHRENHEIT,
701                MeasureUnit.GENERIC_TEMPERATURE,
702                MeasureUnit.KELVIN,
703                MeasureUnit.ACRE_FOOT,
704                MeasureUnit.BUSHEL,
705                MeasureUnit.CENTILITER,
706                MeasureUnit.CUBIC_CENTIMETER,
707                MeasureUnit.CUBIC_FOOT,
708                MeasureUnit.CUBIC_INCH,
709                MeasureUnit.CUBIC_KILOMETER,
710                MeasureUnit.CUBIC_METER,
711                MeasureUnit.CUBIC_MILE,
712                MeasureUnit.CUBIC_YARD,
713                MeasureUnit.CUP,
714                MeasureUnit.CUP_METRIC,
715                MeasureUnit.DECILITER,
716                MeasureUnit.FLUID_OUNCE,
717                MeasureUnit.GALLON,
718                MeasureUnit.HECTOLITER,
719                MeasureUnit.LITER,
720                MeasureUnit.MEGALITER,
721                MeasureUnit.MILLILITER,
722                MeasureUnit.PINT,
723                MeasureUnit.PINT_METRIC,
724                MeasureUnit.QUART,
725                MeasureUnit.TABLESPOON,
726                MeasureUnit.TEASPOON,
727        };
728        assertEquals("",  129, units.length);
729    }
730
731    @Test
732    public void TestCompatible57_1() {
733        MeasureUnit[] units = {
734                MeasureUnit.G_FORCE,
735                MeasureUnit.METER_PER_SECOND_SQUARED,
736                MeasureUnit.ARC_MINUTE,
737                MeasureUnit.ARC_SECOND,
738                MeasureUnit.DEGREE,
739                MeasureUnit.RADIAN,
740                MeasureUnit.REVOLUTION_ANGLE,
741                MeasureUnit.ACRE,
742                MeasureUnit.HECTARE,
743                MeasureUnit.SQUARE_CENTIMETER,
744                MeasureUnit.SQUARE_FOOT,
745                MeasureUnit.SQUARE_INCH,
746                MeasureUnit.SQUARE_KILOMETER,
747                MeasureUnit.SQUARE_METER,
748                MeasureUnit.SQUARE_MILE,
749                MeasureUnit.SQUARE_YARD,
750                MeasureUnit.KARAT,
751                MeasureUnit.MILLIGRAM_PER_DECILITER,
752                MeasureUnit.MILLIMOLE_PER_LITER,
753                MeasureUnit.PART_PER_MILLION,
754                MeasureUnit.LITER_PER_100KILOMETERS,
755                MeasureUnit.LITER_PER_KILOMETER,
756                MeasureUnit.MILE_PER_GALLON,
757                MeasureUnit.MILE_PER_GALLON_IMPERIAL,
758                MeasureUnit.BIT,
759                MeasureUnit.BYTE,
760                MeasureUnit.GIGABIT,
761                MeasureUnit.GIGABYTE,
762                MeasureUnit.KILOBIT,
763                MeasureUnit.KILOBYTE,
764                MeasureUnit.MEGABIT,
765                MeasureUnit.MEGABYTE,
766                MeasureUnit.TERABIT,
767                MeasureUnit.TERABYTE,
768                MeasureUnit.CENTURY,
769                MeasureUnit.DAY,
770                MeasureUnit.HOUR,
771                MeasureUnit.MICROSECOND,
772                MeasureUnit.MILLISECOND,
773                MeasureUnit.MINUTE,
774                MeasureUnit.MONTH,
775                MeasureUnit.NANOSECOND,
776                MeasureUnit.SECOND,
777                MeasureUnit.WEEK,
778                MeasureUnit.YEAR,
779                MeasureUnit.AMPERE,
780                MeasureUnit.MILLIAMPERE,
781                MeasureUnit.OHM,
782                MeasureUnit.VOLT,
783                MeasureUnit.CALORIE,
784                MeasureUnit.FOODCALORIE,
785                MeasureUnit.JOULE,
786                MeasureUnit.KILOCALORIE,
787                MeasureUnit.KILOJOULE,
788                MeasureUnit.KILOWATT_HOUR,
789                MeasureUnit.GIGAHERTZ,
790                MeasureUnit.HERTZ,
791                MeasureUnit.KILOHERTZ,
792                MeasureUnit.MEGAHERTZ,
793                MeasureUnit.ASTRONOMICAL_UNIT,
794                MeasureUnit.CENTIMETER,
795                MeasureUnit.DECIMETER,
796                MeasureUnit.FATHOM,
797                MeasureUnit.FOOT,
798                MeasureUnit.FURLONG,
799                MeasureUnit.INCH,
800                MeasureUnit.KILOMETER,
801                MeasureUnit.LIGHT_YEAR,
802                MeasureUnit.METER,
803                MeasureUnit.MICROMETER,
804                MeasureUnit.MILE,
805                MeasureUnit.MILE_SCANDINAVIAN,
806                MeasureUnit.MILLIMETER,
807                MeasureUnit.NANOMETER,
808                MeasureUnit.NAUTICAL_MILE,
809                MeasureUnit.PARSEC,
810                MeasureUnit.PICOMETER,
811                MeasureUnit.YARD,
812                MeasureUnit.LUX,
813                MeasureUnit.CARAT,
814                MeasureUnit.GRAM,
815                MeasureUnit.KILOGRAM,
816                MeasureUnit.METRIC_TON,
817                MeasureUnit.MICROGRAM,
818                MeasureUnit.MILLIGRAM,
819                MeasureUnit.OUNCE,
820                MeasureUnit.OUNCE_TROY,
821                MeasureUnit.POUND,
822                MeasureUnit.STONE,
823                MeasureUnit.TON,
824                MeasureUnit.GIGAWATT,
825                MeasureUnit.HORSEPOWER,
826                MeasureUnit.KILOWATT,
827                MeasureUnit.MEGAWATT,
828                MeasureUnit.MILLIWATT,
829                MeasureUnit.WATT,
830                MeasureUnit.HECTOPASCAL,
831                MeasureUnit.INCH_HG,
832                MeasureUnit.MILLIBAR,
833                MeasureUnit.MILLIMETER_OF_MERCURY,
834                MeasureUnit.POUND_PER_SQUARE_INCH,
835                MeasureUnit.KILOMETER_PER_HOUR,
836                MeasureUnit.KNOT,
837                MeasureUnit.METER_PER_SECOND,
838                MeasureUnit.MILE_PER_HOUR,
839                MeasureUnit.CELSIUS,
840                MeasureUnit.FAHRENHEIT,
841                MeasureUnit.GENERIC_TEMPERATURE,
842                MeasureUnit.KELVIN,
843                MeasureUnit.ACRE_FOOT,
844                MeasureUnit.BUSHEL,
845                MeasureUnit.CENTILITER,
846                MeasureUnit.CUBIC_CENTIMETER,
847                MeasureUnit.CUBIC_FOOT,
848                MeasureUnit.CUBIC_INCH,
849                MeasureUnit.CUBIC_KILOMETER,
850                MeasureUnit.CUBIC_METER,
851                MeasureUnit.CUBIC_MILE,
852                MeasureUnit.CUBIC_YARD,
853                MeasureUnit.CUP,
854                MeasureUnit.CUP_METRIC,
855                MeasureUnit.DECILITER,
856                MeasureUnit.FLUID_OUNCE,
857                MeasureUnit.GALLON,
858                MeasureUnit.GALLON_IMPERIAL,
859                MeasureUnit.HECTOLITER,
860                MeasureUnit.LITER,
861                MeasureUnit.MEGALITER,
862                MeasureUnit.MILLILITER,
863                MeasureUnit.PINT,
864                MeasureUnit.PINT_METRIC,
865                MeasureUnit.QUART,
866                MeasureUnit.TABLESPOON,
867                MeasureUnit.TEASPOON,
868        };
869        assertEquals("",  134, units.length);
870    }
871
872    @Test
873    public void TestCompatible58_1() {
874        MeasureUnit[] units = {
875                MeasureUnit.G_FORCE,
876                MeasureUnit.METER_PER_SECOND_SQUARED,
877                MeasureUnit.ARC_MINUTE,
878                MeasureUnit.ARC_SECOND,
879                MeasureUnit.DEGREE,
880                MeasureUnit.RADIAN,
881                MeasureUnit.REVOLUTION_ANGLE,
882                MeasureUnit.ACRE,
883                MeasureUnit.HECTARE,
884                MeasureUnit.SQUARE_CENTIMETER,
885                MeasureUnit.SQUARE_FOOT,
886                MeasureUnit.SQUARE_INCH,
887                MeasureUnit.SQUARE_KILOMETER,
888                MeasureUnit.SQUARE_METER,
889                MeasureUnit.SQUARE_MILE,
890                MeasureUnit.SQUARE_YARD,
891                MeasureUnit.KARAT,
892                MeasureUnit.MILLIGRAM_PER_DECILITER,
893                MeasureUnit.MILLIMOLE_PER_LITER,
894                MeasureUnit.PART_PER_MILLION,
895                MeasureUnit.LITER_PER_100KILOMETERS,
896                MeasureUnit.LITER_PER_KILOMETER,
897                MeasureUnit.MILE_PER_GALLON,
898                MeasureUnit.MILE_PER_GALLON_IMPERIAL,
899                MeasureUnit.EAST,
900                MeasureUnit.NORTH,
901                MeasureUnit.SOUTH,
902                MeasureUnit.WEST,
903                MeasureUnit.BIT,
904                MeasureUnit.BYTE,
905                MeasureUnit.GIGABIT,
906                MeasureUnit.GIGABYTE,
907                MeasureUnit.KILOBIT,
908                MeasureUnit.KILOBYTE,
909                MeasureUnit.MEGABIT,
910                MeasureUnit.MEGABYTE,
911                MeasureUnit.TERABIT,
912                MeasureUnit.TERABYTE,
913                MeasureUnit.CENTURY,
914                MeasureUnit.DAY,
915                MeasureUnit.HOUR,
916                MeasureUnit.MICROSECOND,
917                MeasureUnit.MILLISECOND,
918                MeasureUnit.MINUTE,
919                MeasureUnit.MONTH,
920                MeasureUnit.NANOSECOND,
921                MeasureUnit.SECOND,
922                MeasureUnit.WEEK,
923                MeasureUnit.YEAR,
924                MeasureUnit.AMPERE,
925                MeasureUnit.MILLIAMPERE,
926                MeasureUnit.OHM,
927                MeasureUnit.VOLT,
928                MeasureUnit.CALORIE,
929                MeasureUnit.FOODCALORIE,
930                MeasureUnit.JOULE,
931                MeasureUnit.KILOCALORIE,
932                MeasureUnit.KILOJOULE,
933                MeasureUnit.KILOWATT_HOUR,
934                MeasureUnit.GIGAHERTZ,
935                MeasureUnit.HERTZ,
936                MeasureUnit.KILOHERTZ,
937                MeasureUnit.MEGAHERTZ,
938                MeasureUnit.ASTRONOMICAL_UNIT,
939                MeasureUnit.CENTIMETER,
940                MeasureUnit.DECIMETER,
941                MeasureUnit.FATHOM,
942                MeasureUnit.FOOT,
943                MeasureUnit.FURLONG,
944                MeasureUnit.INCH,
945                MeasureUnit.KILOMETER,
946                MeasureUnit.LIGHT_YEAR,
947                MeasureUnit.METER,
948                MeasureUnit.MICROMETER,
949                MeasureUnit.MILE,
950                MeasureUnit.MILE_SCANDINAVIAN,
951                MeasureUnit.MILLIMETER,
952                MeasureUnit.NANOMETER,
953                MeasureUnit.NAUTICAL_MILE,
954                MeasureUnit.PARSEC,
955                MeasureUnit.PICOMETER,
956                MeasureUnit.YARD,
957                MeasureUnit.LUX,
958                MeasureUnit.CARAT,
959                MeasureUnit.GRAM,
960                MeasureUnit.KILOGRAM,
961                MeasureUnit.METRIC_TON,
962                MeasureUnit.MICROGRAM,
963                MeasureUnit.MILLIGRAM,
964                MeasureUnit.OUNCE,
965                MeasureUnit.OUNCE_TROY,
966                MeasureUnit.POUND,
967                MeasureUnit.STONE,
968                MeasureUnit.TON,
969                MeasureUnit.GIGAWATT,
970                MeasureUnit.HORSEPOWER,
971                MeasureUnit.KILOWATT,
972                MeasureUnit.MEGAWATT,
973                MeasureUnit.MILLIWATT,
974                MeasureUnit.WATT,
975                MeasureUnit.HECTOPASCAL,
976                MeasureUnit.INCH_HG,
977                MeasureUnit.MILLIBAR,
978                MeasureUnit.MILLIMETER_OF_MERCURY,
979                MeasureUnit.POUND_PER_SQUARE_INCH,
980                MeasureUnit.KILOMETER_PER_HOUR,
981                MeasureUnit.KNOT,
982                MeasureUnit.METER_PER_SECOND,
983                MeasureUnit.MILE_PER_HOUR,
984                MeasureUnit.CELSIUS,
985                MeasureUnit.FAHRENHEIT,
986                MeasureUnit.GENERIC_TEMPERATURE,
987                MeasureUnit.KELVIN,
988                MeasureUnit.ACRE_FOOT,
989                MeasureUnit.BUSHEL,
990                MeasureUnit.CENTILITER,
991                MeasureUnit.CUBIC_CENTIMETER,
992                MeasureUnit.CUBIC_FOOT,
993                MeasureUnit.CUBIC_INCH,
994                MeasureUnit.CUBIC_KILOMETER,
995                MeasureUnit.CUBIC_METER,
996                MeasureUnit.CUBIC_MILE,
997                MeasureUnit.CUBIC_YARD,
998                MeasureUnit.CUP,
999                MeasureUnit.CUP_METRIC,
1000                MeasureUnit.DECILITER,
1001                MeasureUnit.FLUID_OUNCE,
1002                MeasureUnit.GALLON,
1003                MeasureUnit.GALLON_IMPERIAL,
1004                MeasureUnit.HECTOLITER,
1005                MeasureUnit.LITER,
1006                MeasureUnit.MEGALITER,
1007                MeasureUnit.MILLILITER,
1008                MeasureUnit.PINT,
1009                MeasureUnit.PINT_METRIC,
1010                MeasureUnit.QUART,
1011                MeasureUnit.TABLESPOON,
1012                MeasureUnit.TEASPOON,
1013        };
1014        assertEquals("",  138, units.length);
1015    }
1016
1017    @Test
1018    public void TestExamplesInDocs() {
1019        MeasureFormat fmtFr = MeasureFormat.getInstance(
1020                ULocale.FRENCH, FormatWidth.SHORT);
1021        Measure measure = new Measure(23, MeasureUnit.CELSIUS);
1022        assertEquals("23 °C", "23 °C", fmtFr.format(measure));
1023        Measure measureF = new Measure(70, MeasureUnit.FAHRENHEIT);
1024        assertEquals("70 °F", "70 °F", fmtFr.format(measureF));
1025        MeasureFormat fmtFrFull = MeasureFormat.getInstance(
1026                ULocale.FRENCH, FormatWidth.WIDE);
1027        assertEquals(
1028                "70 pied et 5,3 pouces",
1029                "70 pieds et 5,3 pouces",
1030                fmtFrFull.formatMeasures(
1031                        new Measure(70, MeasureUnit.FOOT),
1032                        new Measure(5.3, MeasureUnit.INCH)));
1033        assertEquals(
1034                "1 pied et 1 pouce",
1035                "1 pied et 1 pouce",
1036                fmtFrFull.formatMeasures(
1037                        new Measure(1, MeasureUnit.FOOT),
1038                        new Measure(1, MeasureUnit.INCH)));
1039        MeasureFormat fmtFrNarrow = MeasureFormat.getInstance(
1040                ULocale.FRENCH, FormatWidth.NARROW);
1041        assertEquals(
1042                "1′ 1″",
1043                "1′ 1″",
1044                fmtFrNarrow.formatMeasures(
1045                        new Measure(1, MeasureUnit.FOOT),
1046                        new Measure(1, MeasureUnit.INCH)));
1047        MeasureFormat fmtEn = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.WIDE);
1048        assertEquals(
1049                "1 inch, 2 feet",
1050                "1 inch, 2 feet",
1051                fmtEn.formatMeasures(
1052                        new Measure(1, MeasureUnit.INCH),
1053                        new Measure(2, MeasureUnit.FOOT)));
1054    }
1055
1056    @Test
1057    public void TestFormatPeriodEn() {
1058        TimeUnitAmount[] _19m = {new TimeUnitAmount(19.0, TimeUnit.MINUTE)};
1059        TimeUnitAmount[] _1h_23_5s = {
1060                new TimeUnitAmount(1.0, TimeUnit.HOUR),
1061                new TimeUnitAmount(23.5, TimeUnit.SECOND)};
1062        TimeUnitAmount[] _1h_23_5m = {
1063                new TimeUnitAmount(1.0, TimeUnit.HOUR),
1064                new TimeUnitAmount(23.5, TimeUnit.MINUTE)};
1065        TimeUnitAmount[] _1h_0m_23s = {
1066                new TimeUnitAmount(1.0, TimeUnit.HOUR),
1067                new TimeUnitAmount(0.0, TimeUnit.MINUTE),
1068                new TimeUnitAmount(23.0, TimeUnit.SECOND)};
1069        TimeUnitAmount[] _2y_5M_3w_4d = {
1070                new TimeUnitAmount(2.0, TimeUnit.YEAR),
1071                new TimeUnitAmount(5.0, TimeUnit.MONTH),
1072                new TimeUnitAmount(3.0, TimeUnit.WEEK),
1073                new TimeUnitAmount(4.0, TimeUnit.DAY)};
1074        TimeUnitAmount[] _1m_59_9996s = {
1075                new TimeUnitAmount(1.0, TimeUnit.MINUTE),
1076                new TimeUnitAmount(59.9996, TimeUnit.SECOND)};
1077        TimeUnitAmount[] _5h_17m = {
1078                new TimeUnitAmount(5.0, TimeUnit.HOUR),
1079                new TimeUnitAmount(17.0, TimeUnit.MINUTE)};
1080        TimeUnitAmount[] _neg5h_17m = {
1081                new TimeUnitAmount(-5.0, TimeUnit.HOUR),
1082                new TimeUnitAmount(17.0, TimeUnit.MINUTE)};
1083        TimeUnitAmount[] _19m_28s = {
1084                new TimeUnitAmount(19.0, TimeUnit.MINUTE),
1085                new TimeUnitAmount(28.0, TimeUnit.SECOND)};
1086        TimeUnitAmount[] _0h_0m_9s = {
1087                new TimeUnitAmount(0.0, TimeUnit.HOUR),
1088                new TimeUnitAmount(0.0, TimeUnit.MINUTE),
1089                new TimeUnitAmount(9.0, TimeUnit.SECOND)};
1090        TimeUnitAmount[] _0h_0m_17s = {
1091                new TimeUnitAmount(0.0, TimeUnit.HOUR),
1092                new TimeUnitAmount(0.0, TimeUnit.MINUTE),
1093                new TimeUnitAmount(17.0, TimeUnit.SECOND)};
1094        TimeUnitAmount[] _6h_56_92m = {
1095                new TimeUnitAmount(6.0, TimeUnit.HOUR),
1096                new TimeUnitAmount(56.92, TimeUnit.MINUTE)};
1097        TimeUnitAmount[] _3h_4s_5m = {
1098                new TimeUnitAmount(3.0, TimeUnit.HOUR),
1099                new TimeUnitAmount(4.0, TimeUnit.SECOND),
1100                new TimeUnitAmount(5.0, TimeUnit.MINUTE)};
1101        TimeUnitAmount[] _6_7h_56_92m = {
1102                new TimeUnitAmount(6.7, TimeUnit.HOUR),
1103                new TimeUnitAmount(56.92, TimeUnit.MINUTE)};
1104        TimeUnitAmount[] _3h_5h = {
1105                new TimeUnitAmount(3.0, TimeUnit.HOUR),
1106                new TimeUnitAmount(5.0, TimeUnit.HOUR)};
1107
1108        Object[][] fullData = {
1109                {_1m_59_9996s, "1 minute, 59.9996 seconds"},
1110                {_19m, "19 minutes"},
1111                {_1h_23_5s, "1 hour, 23.5 seconds"},
1112                {_1h_23_5m, "1 hour, 23.5 minutes"},
1113                {_1h_0m_23s, "1 hour, 0 minutes, 23 seconds"},
1114                {_2y_5M_3w_4d, "2 years, 5 months, 3 weeks, 4 days"}};
1115        Object[][] abbrevData = {
1116                {_1m_59_9996s, "1 min, 59.9996 sec"},
1117                {_19m, "19 min"},
1118                {_1h_23_5s, "1 hr, 23.5 sec"},
1119                {_1h_23_5m, "1 hr, 23.5 min"},
1120                {_1h_0m_23s, "1 hr, 0 min, 23 sec"},
1121                {_2y_5M_3w_4d, "2 yrs, 5 mths, 3 wks, 4 days"}};
1122        Object[][] narrowData = {
1123                {_1m_59_9996s, "1m 59.9996s"},
1124                {_19m, "19m"},
1125                {_1h_23_5s, "1h 23.5s"},
1126                {_1h_23_5m, "1h 23.5m"},
1127                {_1h_0m_23s, "1h 0m 23s"},
1128                {_2y_5M_3w_4d, "2y 5m 3w 4d"}};
1129
1130
1131        Object[][] numericData = {
1132                {_1m_59_9996s, "1:59.9996"},
1133                {_19m, "19m"},
1134                {_1h_23_5s, "1:00:23.5"},
1135                {_1h_0m_23s, "1:00:23"},
1136                {_1h_23_5m, "1:23.5"},
1137                {_5h_17m, "5:17"},
1138                {_neg5h_17m, "-5h 17m"},
1139                {_19m_28s, "19:28"},
1140                {_2y_5M_3w_4d, "2y 5m 3w 4d"},
1141                {_0h_0m_9s, "0:00:09"},
1142                {_6h_56_92m, "6:56.92"},
1143                {_6_7h_56_92m, "6:56.92"},
1144                {_3h_4s_5m, "3h 4s 5m"},
1145                {_3h_5h, "3h 5h"}};
1146        Object[][] fullDataDe = {
1147                {_1m_59_9996s, "1 Minute, 59,9996 Sekunden"},
1148                {_19m, "19 Minuten"},
1149                {_1h_23_5s, "1 Stunde, 23,5 Sekunden"},
1150                {_1h_23_5m, "1 Stunde, 23,5 Minuten"},
1151                {_1h_0m_23s, "1 Stunde, 0 Minuten und 23 Sekunden"},
1152                {_2y_5M_3w_4d, "2 Jahre, 5 Monate, 3 Wochen und 4 Tage"}};
1153        Object[][] numericDataDe = {
1154                {_1m_59_9996s, "1:59,9996"},
1155                {_19m, "19 Min."},
1156                {_1h_23_5s, "1:00:23,5"},
1157                {_1h_0m_23s, "1:00:23"},
1158                {_1h_23_5m, "1:23,5"},
1159                {_5h_17m, "5:17"},
1160                {_19m_28s, "19:28"},
1161                {_2y_5M_3w_4d, "2 J, 5 M, 3 W und 4 T"},
1162                {_0h_0m_17s, "0:00:17"},
1163                {_6h_56_92m, "6:56,92"},
1164                {_3h_5h, "3 Std., 5 Std."}};
1165
1166        NumberFormat nf = NumberFormat.getNumberInstance(ULocale.ENGLISH);
1167        nf.setMaximumFractionDigits(4);
1168        MeasureFormat mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.WIDE, nf);
1169        verifyFormatPeriod("en FULL", mf, fullData);
1170        mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.SHORT, nf);
1171        verifyFormatPeriod("en SHORT", mf, abbrevData);
1172        mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.NARROW, nf);
1173        verifyFormatPeriod("en NARROW", mf, narrowData);
1174        mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.NUMERIC, nf);
1175        verifyFormatPeriod("en NUMERIC", mf, numericData);
1176
1177        nf = NumberFormat.getNumberInstance(ULocale.GERMAN);
1178        nf.setMaximumFractionDigits(4);
1179        mf = MeasureFormat.getInstance(ULocale.GERMAN, FormatWidth.WIDE, nf);
1180        verifyFormatPeriod("de FULL", mf, fullDataDe);
1181        mf = MeasureFormat.getInstance(ULocale.GERMAN, FormatWidth.NUMERIC, nf);
1182        verifyFormatPeriod("de NUMERIC", mf, numericDataDe);
1183
1184        // Same tests, with Java Locale
1185        nf = NumberFormat.getNumberInstance(Locale.GERMAN);
1186        nf.setMaximumFractionDigits(4);
1187        mf = MeasureFormat.getInstance(Locale.GERMAN, FormatWidth.WIDE, nf);
1188        verifyFormatPeriod("de FULL(Java Locale)", mf, fullDataDe);
1189        mf = MeasureFormat.getInstance(Locale.GERMAN, FormatWidth.NUMERIC, nf);
1190        verifyFormatPeriod("de NUMERIC(Java Locale)", mf, numericDataDe);
1191
1192    }
1193
1194    private void verifyFormatPeriod(String desc, MeasureFormat mf, Object[][] testData) {
1195        StringBuilder builder = new StringBuilder();
1196        boolean failure = false;
1197        for (Object[] testCase : testData) {
1198            String actual = mf.format(testCase[0]);
1199            if (!testCase[1].equals(actual)) {
1200                builder.append(String.format("%s: Expected: '%s', got: '%s'\n", desc, testCase[1], actual));
1201                failure = true;
1202            }
1203        }
1204        if (failure) {
1205            errln(builder.toString());
1206        }
1207    }
1208
1209    @Test
1210    public void Test10219FractionalPlurals() {
1211        double[] values = {1.588, 1.011};
1212        String[][] expected = {
1213                {"1 minute", "1.5 minutes", "1.58 minutes"},
1214                {"1 minute", "1.0 minutes", "1.01 minutes"}
1215        };
1216        for (int j = 0; j < values.length; j++) {
1217            for (int i = 0; i < expected[j].length; i++) {
1218                NumberFormat nf = NumberFormat.getNumberInstance(ULocale.ENGLISH);
1219                nf.setRoundingMode(BigDecimal.ROUND_DOWN);
1220                nf.setMinimumFractionDigits(i);
1221                nf.setMaximumFractionDigits(i);
1222                MeasureFormat mf = MeasureFormat.getInstance(
1223                        ULocale.ENGLISH, FormatWidth.WIDE, nf);
1224                assertEquals("Test10219", expected[j][i], mf.format(new Measure(values[j], MeasureUnit.MINUTE)));
1225            }
1226        }
1227    }
1228
1229    @Test
1230    public void TestGreek() {
1231        String[] locales = {"el_GR", "el"};
1232        final MeasureUnit[] units = new MeasureUnit[]{
1233                MeasureUnit.SECOND,
1234                MeasureUnit.MINUTE,
1235                MeasureUnit.HOUR,
1236                MeasureUnit.DAY,
1237                MeasureUnit.WEEK,
1238                MeasureUnit.MONTH,
1239                MeasureUnit.YEAR};
1240        FormatWidth[] styles = new FormatWidth[] {FormatWidth.WIDE, FormatWidth.SHORT};
1241        int[] numbers = new int[] {1, 7};
1242        String[] expected = {
1243                // "el_GR" 1 wide
1244                "1 δευτερόλεπτο",
1245                "1 λεπτό",
1246                "1 ώρα",
1247                "1 ημέρα",
1248                "1 εβδομάδα",
1249                "1 μήνας",
1250                "1 έτος",
1251                // "el_GR" 1 short
1252                "1 δευτ.",
1253                "1 λεπ.",
1254                "1 ώρα",
1255                "1 ημέρα",
1256                "1 εβδ.",
1257                "1 μήν.",
1258                "1 έτ.",	        // year (one)
1259                // "el_GR" 7 wide
1260                "7 δευτερόλεπτα",
1261                "7 λεπτά",
1262                "7 ώρες",
1263                "7 ημέρες",
1264                "7 εβδομάδες",
1265                "7 μήνες",
1266                "7 έτη",
1267                // "el_GR" 7 short
1268                "7 δευτ.",
1269                "7 λεπ.",
1270                "7 ώρ.",		    // hour (other)
1271                "7 ημέρες",
1272                "7 εβδ.",
1273                "7 μήν.",
1274                "7 έτ.",            // year (other)
1275                // "el" 1 wide
1276                "1 δευτερόλεπτο",
1277                "1 λεπτό",
1278                "1 ώρα",
1279                "1 ημέρα",
1280                "1 εβδομάδα",
1281                "1 μήνας",
1282                "1 έτος",
1283                // "el" 1 short
1284                "1 δευτ.",
1285                "1 λεπ.",
1286                "1 ώρα",
1287                "1 ημέρα",
1288                "1 εβδ.",
1289                "1 μήν.",
1290                "1 έτ.",	        // year (one)
1291                // "el" 7 wide
1292                "7 δευτερόλεπτα",
1293                "7 λεπτά",
1294                "7 ώρες",
1295                "7 ημέρες",
1296                "7 εβδομάδες",
1297                "7 μήνες",
1298                "7 έτη",
1299                // "el" 7 short
1300                "7 δευτ.",
1301                "7 λεπ.",
1302                "7 ώρ.",		    // hour (other)
1303                "7 ημέρες",
1304                "7 εβδ.",
1305                "7 μήν.",
1306                "7 έτ."};           // year (other
1307        int counter = 0;
1308        String formatted;
1309        for ( int locIndex = 0; locIndex < locales.length; ++locIndex ) {
1310            for( int numIndex = 0; numIndex < numbers.length; ++numIndex ) {
1311                for ( int styleIndex = 0; styleIndex < styles.length; ++styleIndex ) {
1312                    for ( int unitIndex = 0; unitIndex < units.length; ++unitIndex ) {
1313                        Measure m = new Measure(numbers[numIndex], units[unitIndex]);
1314                        MeasureFormat fmt = MeasureFormat.getInstance(new ULocale(locales[locIndex]), styles[styleIndex]);
1315                        formatted = fmt.format(m);
1316                        assertEquals(
1317                                "locale: " + locales[locIndex]
1318                                        + ", style: " + styles[styleIndex]
1319                                                + ", units: " + units[unitIndex]
1320                                                        + ", value: " + numbers[numIndex],
1321                                                expected[counter], formatted);
1322                        ++counter;
1323                    }
1324                }
1325            }
1326        }
1327    }
1328
1329    @Test
1330    public void testAUnit() {
1331        String lastType = null;
1332        for (MeasureUnit expected : MeasureUnit.getAvailable()) {
1333            String type = expected.getType();
1334            String code = expected.getSubtype();
1335            if (!type.equals(lastType)) {
1336                logln(type);
1337                lastType = type;
1338            }
1339            MeasureUnit actual = MeasureUnit.internalGetInstance(type, code);
1340            assertSame("Identity check", expected, actual);
1341        }
1342    }
1343
1344    @Test
1345    public void testFormatSingleArg() {
1346        MeasureFormat mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.WIDE);
1347        assertEquals("", "5 meters", mf.format(new Measure(5, MeasureUnit.METER)));
1348    }
1349
1350    @Test
1351    public void testFormatMeasuresZeroArg() {
1352        MeasureFormat mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.WIDE);
1353        assertEquals("", "", mf.formatMeasures());
1354    }
1355
1356    @Test
1357    public void testFormatMeasuresOneArg() {
1358        MeasureFormat mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.WIDE);
1359        assertEquals("", "5 meters", mf.formatMeasures(new Measure(5, MeasureUnit.METER)));
1360    }
1361
1362
1363
1364    @Test
1365    public void testMultiples() {
1366        ULocale russia = new ULocale("ru");
1367        Object[][] data = new Object[][] {
1368                {ULocale.ENGLISH, FormatWidth.WIDE, "2 miles, 1 foot, 2.3 inches"},
1369                {ULocale.ENGLISH, FormatWidth.SHORT, "2 mi, 1 ft, 2.3 in"},
1370                {ULocale.ENGLISH, FormatWidth.NARROW, "2mi 1\u2032 2.3\u2033"},
1371                {russia, FormatWidth.WIDE,   "2 \u043C\u0438\u043B\u0438 1 \u0444\u0443\u0442 \u0438 2,3 \u0434\u044E\u0439\u043C\u0430"},
1372                {russia, FormatWidth.SHORT,  "2 \u043C\u0438\u043B\u0438 1 \u0444\u0443\u0442 \u0438 2,3 \u0434\u044E\u0439\u043C."},
1373                {russia, FormatWidth.NARROW, "2 \u043C\u0438\u043B\u044C 1 \u0444\u0443\u0442 2,3 \u0434\u044E\u0439\u043C\u0430"},
1374        };
1375        for (Object[] row : data) {
1376            MeasureFormat mf = MeasureFormat.getInstance(
1377                    (ULocale) row[0], (FormatWidth) row[1]);
1378            assertEquals(
1379                    "testMultiples",
1380                    row[2],
1381                    mf.formatMeasures(
1382                            new Measure(2, MeasureUnit.MILE),
1383                            new Measure(1, MeasureUnit.FOOT),
1384                            new Measure(2.3, MeasureUnit.INCH)));
1385        }
1386    }
1387
1388    @Test
1389    public void testManyLocaleDurations() {
1390        Measure hours   = new Measure(5, MeasureUnit.HOUR);
1391        Measure minutes = new Measure(37, MeasureUnit.MINUTE);
1392        ULocale ulocDanish       = new ULocale("da");
1393        ULocale ulocSpanish      = new ULocale("es");
1394        ULocale ulocFinnish      = new ULocale("fi");
1395        ULocale ulocIcelandic    = new ULocale("is");
1396        ULocale ulocNorwegianBok = new ULocale("nb");
1397        ULocale ulocNorwegianNyn = new ULocale("nn");
1398        ULocale ulocDutch        = new ULocale("nl");
1399        ULocale ulocSwedish      = new ULocale("sv");
1400        Object[][] data = new Object[][] {
1401            { ulocDanish,       FormatWidth.NARROW,  "5 t og 37 min" },
1402            { ulocDanish,       FormatWidth.NUMERIC, "5.37" },
1403            { ULocale.GERMAN,   FormatWidth.NARROW,  "5 Std., 37 Min." },
1404            { ULocale.GERMAN,   FormatWidth.NUMERIC, "5:37" },
1405            { ULocale.ENGLISH,  FormatWidth.NARROW,  "5h 37m" },
1406            { ULocale.ENGLISH,  FormatWidth.NUMERIC, "5:37" },
1407            { ulocSpanish,      FormatWidth.NARROW,  "5h 37min" },
1408            { ulocSpanish,      FormatWidth.NUMERIC, "5:37" },
1409            { ulocFinnish,      FormatWidth.NARROW,  "5t 37min" },
1410            { ulocFinnish,      FormatWidth.NUMERIC, "5.37" },
1411            { ULocale.FRENCH,   FormatWidth.NARROW,  "5h 37m" },
1412            { ULocale.FRENCH,   FormatWidth.NUMERIC, "05:37" },
1413            { ulocIcelandic,    FormatWidth.NARROW,  "5 klst. og 37 m\u00EDn." },
1414            { ulocIcelandic,    FormatWidth.NUMERIC, "5:37" },
1415            { ULocale.JAPANESE, FormatWidth.NARROW,  "5h37m" },
1416            { ULocale.JAPANESE, FormatWidth.NUMERIC, "5:37" },
1417            { ulocNorwegianBok, FormatWidth.NARROW,  "5t, 37m" },
1418            { ulocNorwegianBok, FormatWidth.NUMERIC, "5:37" },
1419            { ulocDutch,        FormatWidth.NARROW,  "5 u, 37 m" },
1420            { ulocDutch,        FormatWidth.NUMERIC, "5:37" },
1421            { ulocNorwegianNyn, FormatWidth.NARROW,  "5 h og 37 min" },
1422            { ulocNorwegianNyn, FormatWidth.NUMERIC, "5:37" },
1423            { ulocSwedish,      FormatWidth.NARROW,  "5h 37m" },
1424            { ulocSwedish,      FormatWidth.NUMERIC, "5:37" },
1425            { ULocale.CHINESE,  FormatWidth.NARROW,  "5\u5C0F\u65F637\u5206\u949F" },
1426            { ULocale.CHINESE,  FormatWidth.NUMERIC, "5:37" },
1427        };
1428        for (Object[] row : data) {
1429            MeasureFormat mf = null;
1430            try{
1431                mf = MeasureFormat.getInstance( (ULocale)row[0], (FormatWidth)row[1] );
1432            } catch(Exception e) {
1433                errln("Exception creating MeasureFormat for locale " + row[0] + ", width " +
1434                        row[1] + ": " + e);
1435                continue;
1436            }
1437            String result = mf.formatMeasures(hours, minutes);
1438            if (!result.equals(row[2])) {
1439                errln("MeasureFormat.formatMeasures for locale " + row[0] + ", width " +
1440                        row[1] + ", expected \"" + (String)row[2] + "\", got \"" + result + "\"" );
1441            }
1442        }
1443    }
1444
1445    @Test
1446    public void testSimplePer() {
1447        Object DONT_CARE = null;
1448        Object[][] data = new Object[][] {
1449                // per unit pattern
1450                {FormatWidth.WIDE, 1.0, MeasureUnit.SECOND, "1 pound per second", DONT_CARE, 0, 0},
1451                {FormatWidth.WIDE, 2.0, MeasureUnit.SECOND, "2 pounds per second", DONT_CARE, 0, 0},
1452                // compound pattern
1453                {FormatWidth.WIDE, 1.0, MeasureUnit.MINUTE, "1 pound per minute", DONT_CARE, 0, 0},
1454                {FormatWidth.WIDE, 2.0, MeasureUnit.MINUTE, "2 pounds per minute", DONT_CARE, 0, 0},
1455                // per unit
1456                {FormatWidth.SHORT, 1.0, MeasureUnit.SECOND, "1 lb/s", DONT_CARE, 0, 0},
1457                {FormatWidth.SHORT, 2.0, MeasureUnit.SECOND, "2 lb/s", DONT_CARE, 0, 0},
1458                // compound
1459                {FormatWidth.SHORT, 1.0, MeasureUnit.MINUTE, "1 lb/min", DONT_CARE, 0, 0},
1460                {FormatWidth.SHORT, 2.0, MeasureUnit.MINUTE, "2 lb/min", DONT_CARE, 0, 0},
1461                // per unit
1462                {FormatWidth.NARROW, 1.0, MeasureUnit.SECOND, "1#/s", DONT_CARE, 0, 0},
1463                {FormatWidth.NARROW, 2.0, MeasureUnit.SECOND, "2#/s", DONT_CARE, 0, 0},
1464                // compound
1465                {FormatWidth.NARROW, 1.0, MeasureUnit.MINUTE, "1#/min", DONT_CARE, 0, 0},
1466                {FormatWidth.NARROW, 2.0, MeasureUnit.MINUTE, "2#/min", DONT_CARE, 0, 0},
1467                // field positions
1468                {FormatWidth.SHORT, 23.3, MeasureUnit.SECOND, "23.3 lb/s", NumberFormat.Field.DECIMAL_SEPARATOR, 2, 3},
1469                {FormatWidth.SHORT, 23.3, MeasureUnit.SECOND, "23.3 lb/s", NumberFormat.Field.INTEGER, 0, 2},
1470                {FormatWidth.SHORT, 23.3, MeasureUnit.MINUTE, "23.3 lb/min", NumberFormat.Field.DECIMAL_SEPARATOR, 2, 3},
1471                {FormatWidth.SHORT, 23.3, MeasureUnit.MINUTE, "23.3 lb/min", NumberFormat.Field.INTEGER, 0, 2},
1472
1473        };
1474
1475        for (Object[] row : data) {
1476            FormatWidth formatWidth = (FormatWidth) row[0];
1477            Number amount = (Number) row[1];
1478            MeasureUnit perUnit = (MeasureUnit) row[2];
1479            String expected = row[3].toString();
1480            NumberFormat.Field field = (NumberFormat.Field) row[4];
1481            int startOffset = ((Integer) row[5]).intValue();
1482            int endOffset = ((Integer) row[6]).intValue();
1483            MeasureFormat mf = MeasureFormat.getInstance(
1484                    ULocale.ENGLISH, formatWidth);
1485            FieldPosition pos = field != null ? new FieldPosition(field) : new FieldPosition(0);
1486            String prefix = "Prefix: ";
1487            assertEquals(
1488                    "",
1489                    prefix + expected,
1490                    mf.formatMeasurePerUnit(
1491                            new Measure(amount, MeasureUnit.POUND),
1492                            perUnit,
1493                            new StringBuilder(prefix),
1494                            pos).toString());
1495            if (field != DONT_CARE) {
1496                assertEquals("startOffset", startOffset, pos.getBeginIndex() - prefix.length());
1497                assertEquals("endOffset", endOffset, pos.getEndIndex() - prefix.length());
1498            }
1499        }
1500    }
1501
1502    @Test
1503    public void testNumeratorPlurals() {
1504        ULocale polish = new ULocale("pl");
1505        Object[][] data = new Object[][] {
1506                {1, "1 stopa na sekundę"},
1507                {2, "2 stopy na sekundę"},
1508                {5, "5 stóp na sekundę"},
1509                {1.5, "1,5 stopy na sekundę"}};
1510
1511        for (Object[] row : data) {
1512            MeasureFormat mf = MeasureFormat.getInstance(polish, FormatWidth.WIDE);
1513            assertEquals(
1514                    "",
1515                    row[1],
1516                    mf.formatMeasurePerUnit(
1517                            new Measure((Number) row[0], MeasureUnit.FOOT),
1518                            MeasureUnit.SECOND,
1519                            new StringBuilder(),
1520                            new FieldPosition(0)).toString());
1521        }
1522    }
1523
1524    @Test
1525    public void testGram() {
1526        MeasureFormat mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.SHORT);
1527        assertEquals(
1528                "testGram",
1529                "1 g",
1530                mf.format(new Measure(1, MeasureUnit.GRAM)));
1531        assertEquals(
1532                "testGram",
1533                "1 G",
1534                mf.format(new Measure(1, MeasureUnit.G_FORCE)));
1535    }
1536
1537    @Test
1538    public void testCurrencies() {
1539        Measure USD_1 = new Measure(1.0, Currency.getInstance("USD"));
1540        Measure USD_2 = new Measure(2.0, Currency.getInstance("USD"));
1541        Measure USD_NEG_1 = new Measure(-1.0, Currency.getInstance("USD"));
1542        MeasureFormat mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.WIDE);
1543        assertEquals("Wide currency", "-1.00 US dollars", mf.format(USD_NEG_1));
1544        assertEquals("Wide currency", "1.00 US dollars", mf.format(USD_1));
1545        assertEquals("Wide currency", "2.00 US dollars", mf.format(USD_2));
1546        mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.SHORT);
1547        assertEquals("short currency", "-USD1.00", mf.format(USD_NEG_1));
1548        assertEquals("short currency", "USD1.00", mf.format(USD_1));
1549        assertEquals("short currency", "USD2.00", mf.format(USD_2));
1550        mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.NARROW);
1551        assertEquals("narrow currency", "-$1.00", mf.format(USD_NEG_1));
1552        assertEquals("narrow currency", "$1.00", mf.format(USD_1));
1553        assertEquals("narrow currency", "$2.00", mf.format(USD_2));
1554        mf = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.NUMERIC);
1555        assertEquals("numeric currency", "-$1.00", mf.format(USD_NEG_1));
1556        assertEquals("numeric currency", "$1.00", mf.format(USD_1));
1557        assertEquals("numeric currency", "$2.00", mf.format(USD_2));
1558
1559        mf = MeasureFormat.getInstance(ULocale.JAPAN, FormatWidth.WIDE);
1560        assertEquals("Wide currency", "-1.00\u7C73\u30C9\u30EB", mf.format(USD_NEG_1));
1561        assertEquals("Wide currency", "1.00\u7C73\u30C9\u30EB", mf.format(USD_1));
1562        assertEquals("Wide currency", "2.00\u7C73\u30C9\u30EB", mf.format(USD_2));
1563
1564        Measure CAD_1 = new Measure(1.0, Currency.getInstance("CAD"));
1565        mf = MeasureFormat.getInstance(ULocale.CANADA, FormatWidth.SHORT);
1566        assertEquals("short currency", "CAD1.00", mf.format(CAD_1));
1567    }
1568
1569    @Test
1570    public void testDisplayNames() {
1571        Object[][] data = new Object[][] {
1572            // Unit, locale, width, expected result
1573            { MeasureUnit.YEAR, "en", FormatWidth.WIDE, "years" },
1574            { MeasureUnit.YEAR, "ja", FormatWidth.WIDE, "年" },
1575            { MeasureUnit.YEAR, "es", FormatWidth.WIDE, "años" },
1576            { MeasureUnit.YEAR, "pt", FormatWidth.WIDE, "anos" },
1577            { MeasureUnit.YEAR, "pt-PT", FormatWidth.WIDE, "anos" },
1578            { MeasureUnit.AMPERE, "en", FormatWidth.WIDE, "amperes" },
1579            { MeasureUnit.AMPERE, "ja", FormatWidth.WIDE, "アンペア" },
1580            { MeasureUnit.AMPERE, "es", FormatWidth.WIDE, "amperios" },
1581            { MeasureUnit.AMPERE, "pt", FormatWidth.WIDE, "amperes" },
1582            { MeasureUnit.AMPERE, "pt-PT", FormatWidth.WIDE, "amperes" },
1583            { MeasureUnit.METER_PER_SECOND_SQUARED, "pt", FormatWidth.WIDE, "metros por segundo ao quadrado" },
1584            { MeasureUnit.METER_PER_SECOND_SQUARED, "pt-PT", FormatWidth.WIDE, "metros por segundo quadrado" },
1585            { MeasureUnit.SQUARE_KILOMETER, "pt", FormatWidth.NARROW, "km²" },
1586            { MeasureUnit.SQUARE_KILOMETER, "pt", FormatWidth.SHORT, "km²" },
1587            { MeasureUnit.SQUARE_KILOMETER, "pt", FormatWidth.WIDE, "quilômetros quadrados" },
1588            { MeasureUnit.SECOND, "pt-PT", FormatWidth.NARROW, "s" },
1589            { MeasureUnit.SECOND, "pt-PT", FormatWidth.SHORT, "s" },
1590            { MeasureUnit.SECOND, "pt-PT", FormatWidth.WIDE, "segundos" },
1591            { MeasureUnit.SECOND, "pt", FormatWidth.NARROW, "seg" },
1592            { MeasureUnit.SECOND, "pt", FormatWidth.SHORT, "segs" },
1593            { MeasureUnit.SECOND, "pt", FormatWidth.WIDE, "segundos" },
1594        };
1595
1596        for (Object[] test : data) {
1597            MeasureUnit unit = (MeasureUnit) test[0];
1598            ULocale locale = ULocale.forLanguageTag((String) test[1]);
1599            FormatWidth formatWidth = (FormatWidth) test[2];
1600            String expected = (String) test[3];
1601
1602            MeasureFormat mf = MeasureFormat.getInstance(locale, formatWidth);
1603            String actual = mf.getUnitDisplayName(unit);
1604            assertEquals(String.format("Unit Display Name for %s, %s, %s", unit, locale, formatWidth),
1605                    expected, actual);
1606        }
1607    }
1608
1609    @Test
1610    public void testFieldPosition() {
1611        MeasureFormat fmt = MeasureFormat.getInstance(
1612                ULocale.ENGLISH, FormatWidth.SHORT);
1613        FieldPosition pos = new FieldPosition(NumberFormat.Field.DECIMAL_SEPARATOR);
1614        fmt.format(new Measure(43.5, MeasureUnit.FOOT), new StringBuffer("123456: "), pos);
1615        assertEquals("beginIndex", 10, pos.getBeginIndex());
1616        assertEquals("endIndex", 11, pos.getEndIndex());
1617
1618        pos = new FieldPosition(NumberFormat.Field.DECIMAL_SEPARATOR);
1619        fmt.format(new Measure(43, MeasureUnit.FOOT), new StringBuffer(), pos);
1620        assertEquals("beginIndex", 0, pos.getBeginIndex());
1621        assertEquals("endIndex", 0, pos.getEndIndex());
1622    }
1623
1624    @Test
1625    public void testFieldPositionMultiple() {
1626        MeasureFormat fmt = MeasureFormat.getInstance(
1627                ULocale.ENGLISH, FormatWidth.SHORT);
1628        FieldPosition pos = new FieldPosition(NumberFormat.Field.INTEGER);
1629        String result = fmt.formatMeasures(
1630                new StringBuilder(),
1631                pos,
1632                new Measure(354, MeasureUnit.METER),
1633                new Measure(23, MeasureUnit.CENTIMETER)).toString();
1634        assertEquals("result", "354 m, 23 cm", result);
1635
1636        // According to javadocs for {@link Format#format} FieldPosition is set to
1637        // beginning and end of first such field encountered instead of the last
1638        // such field encountered.
1639        assertEquals("beginIndex", 0, pos.getBeginIndex());
1640        assertEquals("endIndex", 3, pos.getEndIndex());
1641
1642        pos = new FieldPosition(NumberFormat.Field.DECIMAL_SEPARATOR);
1643        result = fmt.formatMeasures(
1644                new StringBuilder("123456: "),
1645                pos,
1646                new Measure(354, MeasureUnit.METER),
1647                new Measure(23, MeasureUnit.CENTIMETER),
1648                new Measure(5.4, MeasureUnit.MILLIMETER)).toString();
1649        assertEquals("result", "123456: 354 m, 23 cm, 5.4 mm", result);
1650        assertEquals("beginIndex", 23, pos.getBeginIndex());
1651        assertEquals("endIndex", 24, pos.getEndIndex());
1652
1653        result = fmt.formatMeasures(
1654                new StringBuilder(),
1655                pos,
1656                new Measure(3, MeasureUnit.METER),
1657                new Measure(23, MeasureUnit.CENTIMETER),
1658                new Measure(5.4, MeasureUnit.MILLIMETER)).toString();
1659        assertEquals("result", "3 m, 23 cm, 5.4 mm", result);
1660        assertEquals("beginIndex", 13, pos.getBeginIndex());
1661        assertEquals("endIndex", 14, pos.getEndIndex());
1662
1663        pos = new FieldPosition(NumberFormat.Field.DECIMAL_SEPARATOR);
1664        result = fmt.formatMeasures(
1665                new StringBuilder("123456: "),
1666                pos,
1667                new Measure(3, MeasureUnit.METER),
1668                new Measure(23, MeasureUnit.CENTIMETER),
1669                new Measure(5, MeasureUnit.MILLIMETER)).toString();
1670        assertEquals("result", "123456: 3 m, 23 cm, 5 mm", result);
1671        assertEquals("beginIndex", 0, pos.getBeginIndex());
1672        assertEquals("endIndex", 0, pos.getEndIndex());
1673
1674        pos = new FieldPosition(NumberFormat.Field.INTEGER);
1675        result = fmt.formatMeasures(
1676                new StringBuilder("123456: "),
1677                pos,
1678                new Measure(57, MeasureUnit.MILLIMETER)).toString();
1679        assertEquals("result", "123456: 57 mm", result);
1680        assertEquals("beginIndex", 8, pos.getBeginIndex());
1681        assertEquals("endIndex", 10, pos.getEndIndex());
1682
1683    }
1684
1685    @Test
1686    public void testOldFormatWithList() {
1687        List<Measure> measures = new ArrayList<Measure>(2);
1688        measures.add(new Measure(5, MeasureUnit.ACRE));
1689        measures.add(new Measure(3000, MeasureUnit.SQUARE_FOOT));
1690        MeasureFormat fmt = MeasureFormat.getInstance(
1691                ULocale.ENGLISH, FormatWidth.WIDE);
1692        assertEquals("", "5 acres, 3,000 square feet", fmt.format(measures));
1693        assertEquals("", "5 acres", fmt.format(measures.subList(0, 1)));
1694        List<String> badList = new ArrayList<String>();
1695        badList.add("be");
1696        badList.add("you");
1697        try {
1698            fmt.format(badList);
1699            fail("Expected IllegalArgumentException.");
1700        } catch (IllegalArgumentException expected) {
1701           // Expected
1702        }
1703    }
1704
1705    @Test
1706    public void testOldFormatWithArray() {
1707        Measure[] measures = new Measure[] {
1708                new Measure(5, MeasureUnit.ACRE),
1709                new Measure(3000, MeasureUnit.SQUARE_FOOT),
1710        };
1711        MeasureFormat fmt = MeasureFormat.getInstance(
1712                ULocale.ENGLISH, FormatWidth.WIDE);
1713        assertEquals("", "5 acres, 3,000 square feet", fmt.format(measures));
1714    }
1715
1716    @Test
1717    public void testOldFormatBadArg() {
1718        MeasureFormat fmt = MeasureFormat.getInstance(
1719                ULocale.ENGLISH, FormatWidth.WIDE);
1720        try {
1721            fmt.format("be");
1722            fail("Expected IllegalArgumentExceptino.");
1723        } catch (IllegalArgumentException e) {
1724            // Expected
1725        }
1726    }
1727
1728    @Test
1729    public void testUnitPerUnitResolution() {
1730        // Ticket 11274
1731        MeasureFormat fmt = MeasureFormat.getInstance(Locale.ENGLISH, FormatWidth.SHORT);
1732
1733        // This fails unless we resolve to MeasureUnit.POUND_PER_SQUARE_INCH
1734        assertEquals("", "50 psi",
1735                fmt.formatMeasurePerUnit(
1736                        new Measure(50, MeasureUnit.POUND),
1737                        MeasureUnit.SQUARE_INCH,
1738                        new StringBuilder(),
1739                        new FieldPosition(0)).toString());
1740    }
1741
1742    @Test
1743    public void testEqHashCode() {
1744        MeasureFormat mf = MeasureFormat.getInstance(ULocale.CANADA, FormatWidth.SHORT);
1745        MeasureFormat mfeq = MeasureFormat.getInstance(ULocale.CANADA, FormatWidth.SHORT);
1746        MeasureFormat mfne = MeasureFormat.getInstance(ULocale.CANADA, FormatWidth.WIDE);
1747        MeasureFormat mfne2 = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.SHORT);
1748        verifyEqualsHashCode(mf, mfeq, mfne);
1749        verifyEqualsHashCode(mf, mfeq, mfne2);
1750    }
1751
1752    @Test
1753    public void testEqHashCodeOfMeasure() {
1754        Measure _3feetDouble = new Measure(3.0, MeasureUnit.FOOT);
1755        Measure _3feetInt = new Measure(3, MeasureUnit.FOOT);
1756        Measure _4feetInt = new Measure(4, MeasureUnit.FOOT);
1757        verifyEqualsHashCode(_3feetDouble, _3feetInt, _4feetInt);
1758    }
1759
1760    @Test
1761    public void testGetLocale() {
1762        MeasureFormat mf = MeasureFormat.getInstance(ULocale.GERMAN, FormatWidth.SHORT);
1763        assertEquals("", ULocale.GERMAN, mf.getLocale(ULocale.VALID_LOCALE));
1764    }
1765
1766    @Test
1767    public void TestSerial() {
1768        checkStreamingEquality(MeasureUnit.CELSIUS);
1769        checkStreamingEquality(MeasureFormat.getInstance(ULocale.FRANCE, FormatWidth.NARROW));
1770        checkStreamingEquality(Currency.getInstance("EUR"));
1771        checkStreamingEquality(MeasureFormat.getInstance(ULocale.GERMAN, FormatWidth.SHORT));
1772        checkStreamingEquality(MeasureFormat.getCurrencyFormat(ULocale.ITALIAN));
1773    }
1774
1775    @Test
1776    public void TestSerialFormatWidthEnum() {
1777        // FormatWidth enum values must map to the same ordinal values for all time in order for
1778        // serialization to work.
1779        assertEquals("FormatWidth.WIDE", 0, FormatWidth.WIDE.ordinal());
1780        assertEquals("FormatWidth.SHORT", 1, FormatWidth.SHORT.ordinal());
1781        assertEquals("FormatWidth.NARROW", 2, FormatWidth.NARROW.ordinal());
1782        assertEquals("FormatWidth.NUMERIC", 3, FormatWidth.NUMERIC.ordinal());
1783    }
1784
1785    @Test
1786    public void testCurrencyFormatStandInForMeasureFormat() {
1787        MeasureFormat mf = MeasureFormat.getCurrencyFormat(ULocale.ENGLISH);
1788        assertEquals(
1789                "70 feet, 5.3 inches",
1790                "70 feet, 5.3 inches",
1791                mf.formatMeasures(
1792                        new Measure(70, MeasureUnit.FOOT),
1793                        new Measure(5.3, MeasureUnit.INCH)));
1794        assertEquals("getLocale", ULocale.ENGLISH, mf.getLocale());
1795        assertEquals("getNumberFormat", ULocale.ENGLISH, mf.getNumberFormat().getLocale(ULocale.VALID_LOCALE));
1796        assertEquals("getWidth", MeasureFormat.FormatWidth.WIDE, mf.getWidth());
1797    }
1798
1799    @Test
1800    public void testCurrencyFormatLocale() {
1801        MeasureFormat mfu = MeasureFormat.getCurrencyFormat(ULocale.FRANCE);
1802        MeasureFormat mfj = MeasureFormat.getCurrencyFormat(Locale.FRANCE);
1803
1804        assertEquals("getCurrencyFormat ULocale/Locale", mfu, mfj);
1805    }
1806
1807    @Test
1808    public void testDoubleZero() {
1809        ULocale en = new ULocale("en");
1810        NumberFormat nf = NumberFormat.getInstance(en);
1811        nf.setMinimumFractionDigits(2);
1812        nf.setMaximumFractionDigits(2);
1813        MeasureFormat mf = MeasureFormat.getInstance(en, FormatWidth.WIDE, nf);
1814        assertEquals(
1815                "Positive Rounding",
1816                "4 hours, 23 minutes, 16.00 seconds",
1817                mf.formatMeasures(
1818                        new Measure(4.7, MeasureUnit.HOUR),
1819                        new Measure(23, MeasureUnit.MINUTE),
1820                        new Measure(16, MeasureUnit.SECOND)));
1821        assertEquals(
1822                "Negative Rounding",
1823                "-4 hours, 23 minutes, 16.00 seconds",
1824                mf.formatMeasures(
1825                        new Measure(-4.7, MeasureUnit.HOUR),
1826                        new Measure(23, MeasureUnit.MINUTE),
1827                        new Measure(16, MeasureUnit.SECOND)));
1828
1829    }
1830
1831    @Test
1832    public void testIndividualPluralFallback() {
1833        // See ticket #11986 "incomplete fallback in MeasureFormat".
1834        // In CLDR 28, fr_CA temperature-generic/short has only the "one" form,
1835        // and falls back to fr for the "other" form.
1836        MeasureFormat mf = MeasureFormat.getInstance(new ULocale("fr_CA"), FormatWidth.SHORT);
1837        Measure twoDeg = new Measure(2, MeasureUnit.GENERIC_TEMPERATURE);
1838        assertEquals("2 deg temp in fr_CA", "2°", mf.format(twoDeg));
1839    }
1840
1841    @Test
1842    public void testPopulateCache() {
1843        // Quick check that the lazily added additions to the MeasureUnit cache are present.
1844        assertTrue("MeasureUnit: unexpectedly few currencies defined", MeasureUnit.getAvailable("currency").size() > 50);
1845    }
1846
1847    @Test
1848    public void testParseObject() {
1849        MeasureFormat mf = MeasureFormat.getInstance(Locale.GERMAN, FormatWidth.NARROW);
1850        try {
1851            mf.parseObject("3m", null);
1852            fail("MeasureFormat.parseObject(String, ParsePosition) " +
1853                    "should throw an UnsupportedOperationException");
1854        } catch (UnsupportedOperationException expected) {
1855        }
1856    }
1857
1858    @Test
1859    public void testCLDRUnitAvailability() {
1860        Set<MeasureUnit> knownUnits = new HashSet<MeasureUnit>();
1861        Class cMeasureUnit, cTimeUnit;
1862        try {
1863            cMeasureUnit = Class.forName("com.ibm.icu.util.MeasureUnit");
1864            cTimeUnit = Class.forName("com.ibm.icu.util.TimeUnit");
1865        } catch (ClassNotFoundException e) {
1866            fail("Count not load MeasureUnit or TimeUnit class: " + e.getMessage());
1867            return;
1868        }
1869        for (Field field : cMeasureUnit.getFields()) {
1870            if (field.getGenericType() == cMeasureUnit || field.getGenericType() == cTimeUnit) {
1871                try {
1872                    MeasureUnit unit = (MeasureUnit) field.get(cMeasureUnit);
1873                    knownUnits.add(unit);
1874                } catch (IllegalArgumentException e) {
1875                    fail(e.getMessage());
1876                    return;
1877                } catch (IllegalAccessException e) {
1878                    fail(e.getMessage());
1879                    return;
1880                }
1881            }
1882        }
1883        for (String type : MeasureUnit.getAvailableTypes()) {
1884            if (type.equals("currency") || type.equals("compound")) {
1885                continue;
1886            }
1887            for (MeasureUnit unit : MeasureUnit.getAvailable(type)) {
1888                if (!knownUnits.contains(unit)) {
1889                    fail("Unit present in CLDR but not available via constant in MeasureUnit: " + unit);
1890                }
1891            }
1892        }
1893    }
1894
1895    // DO NOT DELETE THIS FUNCTION! It may appear as dead code, but we use this to generate code
1896    // for MeasureFormat during the release process.
1897    static Map<MeasureUnit, Pair<MeasureUnit, MeasureUnit>> getUnitsToPerParts() {
1898        TreeMap<String, List<MeasureUnit>> allUnits = getAllUnits();
1899        Map<MeasureUnit, Pair<String, String>> unitsToPerStrings =
1900                new HashMap<MeasureUnit, Pair<String, String>>();
1901        Map<String, MeasureUnit> namesToUnits = new HashMap<String, MeasureUnit>();
1902        for (Map.Entry<String, List<MeasureUnit>> entry : allUnits.entrySet()) {
1903            String type = entry.getKey();
1904            // Currency types are always atomic units, so we can skip these
1905            if (type.equals("currency")) {
1906                continue;
1907            }
1908            for (MeasureUnit unit : entry.getValue()) {
1909                String javaName = toJAVAName(unit);
1910                String[] nameParts = javaName.split("_PER_");
1911                if (nameParts.length == 1) {
1912                    namesToUnits.put(nameParts[0], unit);
1913                } else if (nameParts.length == 2) {
1914                    unitsToPerStrings.put(unit, Pair.of(nameParts[0], nameParts[1]));
1915                }
1916            }
1917        }
1918        Map<MeasureUnit, Pair<MeasureUnit, MeasureUnit>> unitsToPerUnits =
1919                new HashMap<MeasureUnit, Pair<MeasureUnit, MeasureUnit>>();
1920        for (Map.Entry<MeasureUnit, Pair<String, String>> entry : unitsToPerStrings.entrySet()) {
1921            Pair<String, String> perStrings = entry.getValue();
1922            MeasureUnit unit = namesToUnits.get(perStrings.first);
1923            MeasureUnit perUnit = namesToUnits.get(perStrings.second);
1924            if (unit != null && perUnit != null) {
1925                unitsToPerUnits.put(entry.getKey(), Pair.of(unit, perUnit));
1926            }
1927        }
1928        return unitsToPerUnits;
1929    }
1930
1931    // DO NOT DELETE THIS FUNCTION! It may appear as dead code, but we use this to generate code
1932    // for MeasureFormat during the release process.
1933    static void generateCXXHConstants(String thisVersion) {
1934        Map<String, MeasureUnit> seen = new HashMap<String, MeasureUnit>();
1935        System.out.println();
1936        TreeMap<String, List<MeasureUnit>> allUnits = getAllUnits();
1937        for (Map.Entry<String, List<MeasureUnit>> entry : allUnits.entrySet()) {
1938            String type = entry.getKey();
1939            if (type.equals("currency")) {
1940                continue;
1941            }
1942            for (MeasureUnit unit : entry.getValue()) {
1943                String code = unit.getSubtype();
1944                String name = toCamelCase(unit);
1945                String javaName = toJAVAName(unit);
1946                checkForDup(seen, name, unit);
1947                if (isDraft(javaName)) {
1948                    System.out.println("#ifndef U_HIDE_DRAFT_API");
1949                }
1950                System.out.println("    /**");
1951                System.out.println("     * Returns unit of " + type + ": " + code + ".");
1952                System.out.println("     * Caller owns returned value and must free it.");
1953                System.out.println("     * @param status ICU error code.");
1954                if (isDraft(javaName)) {
1955                    System.out.println("     * @draft ICU " + getVersion(javaName, thisVersion));
1956                } else {
1957                    System.out.println("     * @stable ICU " + getVersion(javaName, thisVersion));
1958                }
1959                System.out.println("     */");
1960                System.out.printf("    static MeasureUnit *create%s(UErrorCode &status);\n\n", name);
1961                if (isDraft(javaName)) {
1962                    System.out.println("#endif /* U_HIDE_DRAFT_API */");
1963                }
1964            }
1965        }
1966    }
1967
1968    private static void checkForDup(
1969            Map<String, MeasureUnit> seen, String name, MeasureUnit unit) {
1970        if (seen.containsKey(name)) {
1971            throw new RuntimeException("\nCollision!!" + unit + ", " + seen.get(name));
1972        } else {
1973            seen.put(name, unit);
1974        }
1975    }
1976
1977    // DO NOT DELETE THIS FUNCTION! It may appear as dead code, but we use this to generate code
1978    // for MeasureFormat during the release process.
1979    static void updateJAVAVersions(String thisVersion) {
1980        System.out.println();
1981        Map<String, MeasureUnit> seen = new HashMap<String, MeasureUnit>();
1982        TreeMap<String, List<MeasureUnit>> allUnits = getAllUnits();
1983        for (Map.Entry<String, List<MeasureUnit>> entry : allUnits.entrySet()) {
1984            String type = entry.getKey();
1985            if (type.equals("currency")) {
1986                continue;
1987            }
1988            for (MeasureUnit unit : entry.getValue()) {
1989                String javaName = toJAVAName(unit);
1990                checkForDup(seen, javaName, unit);
1991                if (!JAVA_VERSION_MAP.containsKey(javaName)) {
1992                    System.out.printf("        {\"%s\", \"%s\"},\n", javaName, thisVersion);
1993                }
1994            }
1995        }
1996    }
1997
1998    static TreeMap<String, List<MeasureUnit>> getAllUnits() {
1999        TreeMap<String, List<MeasureUnit>> allUnits = new TreeMap<String, List<MeasureUnit>>();
2000        for (String type : MeasureUnit.getAvailableTypes()) {
2001            ArrayList<MeasureUnit> units = new ArrayList<MeasureUnit>(MeasureUnit.getAvailable(type));
2002            Collections.sort(
2003                    units,
2004                    new Comparator<MeasureUnit>() {
2005
2006                        @Override
2007                        public int compare(MeasureUnit o1, MeasureUnit o2) {
2008                            return o1.getSubtype().compareTo(o2.getSubtype());
2009                        }
2010
2011                    });
2012            allUnits.put(type, units);
2013        }
2014        return allUnits;
2015    }
2016
2017    // DO NOT DELETE THIS FUNCTION! It may appear as dead code, but we use this to generate code
2018    // for MeasureFormat during the release process.
2019    static void generateCXXConstants() {
2020        System.out.println("");
2021        TreeMap<String, List<MeasureUnit>> allUnits = getAllUnits();
2022
2023        System.out.println("static const int32_t gOffsets[] = {");
2024        int index = 0;
2025        for (Map.Entry<String, List<MeasureUnit>> entry : allUnits.entrySet()) {
2026            System.out.printf("    %d,\n", index);
2027            index += entry.getValue().size();
2028        }
2029        System.out.printf("    %d\n", index);
2030        System.out.println("};");
2031        System.out.println();
2032        System.out.println("static const int32_t gIndexes[] = {");
2033        index = 0;
2034        for (Map.Entry<String, List<MeasureUnit>> entry : allUnits.entrySet()) {
2035            System.out.printf("    %d,\n", index);
2036            if (!entry.getKey().equals("currency")) {
2037                index += entry.getValue().size();
2038            }
2039        }
2040        System.out.printf("    %d\n", index);
2041        System.out.println("};");
2042        System.out.println();
2043        System.out.println("// Must be sorted alphabetically.");
2044        System.out.println("static const char * const gTypes[] = {");
2045        boolean first = true;
2046        for (Map.Entry<String, List<MeasureUnit>> entry : allUnits.entrySet()) {
2047            if (!first) {
2048                System.out.println(",");
2049            }
2050            System.out.print("    \"" + entry.getKey() + "\"");
2051            first = false;
2052        }
2053        System.out.println();
2054        System.out.println("};");
2055        System.out.println();
2056        System.out.println("// Must be grouped by type and sorted alphabetically within each type.");
2057        System.out.println("static const char * const gSubTypes[] = {");
2058        first = true;
2059        int offset = 0;
2060        int typeIdx = 0;
2061        Map<MeasureUnit, Integer> measureUnitToOffset = new HashMap<MeasureUnit, Integer>();
2062        Map<MeasureUnit, Pair<Integer, Integer>> measureUnitToTypeSubType =
2063                new HashMap<MeasureUnit, Pair<Integer, Integer>>();
2064        for (Map.Entry<String, List<MeasureUnit>> entry : allUnits.entrySet()) {
2065            int subTypeIdx = 0;
2066            for (MeasureUnit unit : entry.getValue()) {
2067                if (!first) {
2068                    System.out.println(",");
2069                }
2070                System.out.print("    \"" + unit.getSubtype() + "\"");
2071                first = false;
2072                measureUnitToOffset.put(unit, offset);
2073                measureUnitToTypeSubType.put(unit, Pair.of(typeIdx, subTypeIdx));
2074                offset++;
2075                subTypeIdx++;
2076            }
2077            typeIdx++;
2078        }
2079        System.out.println();
2080        System.out.println("};");
2081        System.out.println();
2082
2083        // Build unit per unit offsets to corresponding type sub types sorted by
2084        // unit first and then per unit.
2085        TreeMap<OrderedPair<Integer, Integer>, Pair<Integer, Integer>> unitPerUnitOffsetsToTypeSubType
2086                = new TreeMap<OrderedPair<Integer, Integer>, Pair<Integer, Integer>>();
2087        for (Map.Entry<MeasureUnit, Pair<MeasureUnit, MeasureUnit>> entry
2088                : getUnitsToPerParts().entrySet()) {
2089            Pair<MeasureUnit, MeasureUnit> unitPerUnit = entry.getValue();
2090            unitPerUnitOffsetsToTypeSubType.put(
2091                    OrderedPair.of(
2092                            measureUnitToOffset.get(unitPerUnit.first),
2093                            measureUnitToOffset.get(unitPerUnit.second)),
2094                    measureUnitToTypeSubType.get(entry.getKey()));
2095        }
2096
2097        System.out.println("// Must be sorted by first value and then second value.");
2098        System.out.println("static int32_t unitPerUnitToSingleUnit[][4] = {");
2099        first = true;
2100        for (Map.Entry<OrderedPair<Integer, Integer>, Pair<Integer, Integer>> entry
2101                : unitPerUnitOffsetsToTypeSubType.entrySet()) {
2102            if (!first) {
2103                System.out.println(",");
2104            }
2105            first = false;
2106            OrderedPair<Integer, Integer> unitPerUnitOffsets = entry.getKey();
2107            Pair<Integer, Integer> typeSubType = entry.getValue();
2108            System.out.printf("        {%d, %d, %d, %d}",
2109                    unitPerUnitOffsets.first,
2110                    unitPerUnitOffsets.second,
2111                    typeSubType.first,
2112                    typeSubType.second);
2113        }
2114        System.out.println();
2115        System.out.println("};");
2116        System.out.println();
2117
2118        Map<String, MeasureUnit> seen = new HashMap<String, MeasureUnit>();
2119        for (Map.Entry<String, List<MeasureUnit>> entry : allUnits.entrySet()) {
2120
2121            String type = entry.getKey();
2122            if (type.equals("currency")) {
2123                continue;
2124            }
2125            for (MeasureUnit unit : entry.getValue()) {
2126                String name = toCamelCase(unit);
2127                Pair<Integer, Integer> typeSubType = measureUnitToTypeSubType.get(unit);
2128                if (typeSubType == null) {
2129                    throw new IllegalStateException();
2130                }
2131                checkForDup(seen, name, unit);
2132                System.out.printf("MeasureUnit *MeasureUnit::create%s(UErrorCode &status) {\n", name);
2133                System.out.printf("    return MeasureUnit::create(%d, %d, status);\n",
2134                        typeSubType.first, typeSubType.second);
2135                System.out.println("}");
2136                System.out.println();
2137            }
2138        }
2139    }
2140
2141    private static String toCamelCase(MeasureUnit unit) {
2142        StringBuilder result = new StringBuilder();
2143        boolean caps = true;
2144        String code = unit.getSubtype();
2145        int len = code.length();
2146        for (int i = 0; i < len; i++) {
2147            char ch = code.charAt(i);
2148            if (ch == '-') {
2149                caps = true;
2150            } else if (caps) {
2151                result.append(Character.toUpperCase(ch));
2152                caps = false;
2153            } else {
2154                result.append(ch);
2155            }
2156        }
2157        return result.toString();
2158    }
2159
2160    static boolean isTypeHidden(String type) {
2161        return "currency".equals(type);
2162    }
2163
2164    // DO NOT DELETE THIS FUNCTION! It may appear as dead code, but we use this to generate code
2165    // for MeasureFormat during the release process.
2166    static void generateBackwardCompatibilityTest(String version) {
2167        Map<String, MeasureUnit> seen = new HashMap<String, MeasureUnit>();
2168        System.out.println();
2169        System.out.printf("    public void TestCompatible%s() {\n", version.replace(".", "_"));
2170        System.out.println("        MeasureUnit[] units = {");
2171        TreeMap<String, List<MeasureUnit>> allUnits = getAllUnits();
2172        int count = 0;
2173        for (Map.Entry<String, List<MeasureUnit>> entry : allUnits.entrySet()) {
2174            if (isTypeHidden(entry.getKey())) {
2175                continue;
2176            }
2177            for (MeasureUnit unit : entry.getValue()) {
2178                String javaName = toJAVAName(unit);
2179                checkForDup(seen, javaName, unit);
2180                System.out.printf("                MeasureUnit.%s,\n", javaName);
2181                count++;
2182            }
2183        }
2184        System.out.println("        };");
2185        System.out.printf("        assertEquals(\"\",  %d, units.length);\n", count);
2186        System.out.println("    }");
2187    }
2188
2189    // DO NOT DELETE THIS FUNCTION! It may appear as dead code, but we use this to generate code
2190    // for MeasureFormat during the release process.
2191    static void generateCXXBackwardCompatibilityTest(String version) {
2192        System.out.println();
2193        Map<String, MeasureUnit> seen = new HashMap<String, MeasureUnit>();
2194        System.out.printf("void MeasureFormatTest::TestCompatible%s() {\n", version.replace(".", "_"));
2195        System.out.println("    UErrorCode status = U_ZERO_ERROR;");
2196        System.out.println("    LocalPointer<MeasureUnit> measureUnit;");
2197        TreeMap<String, List<MeasureUnit>> allUnits = getAllUnits();
2198        for (Map.Entry<String, List<MeasureUnit>> entry : allUnits.entrySet()) {
2199            if (isTypeHidden(entry.getKey())) {
2200                continue;
2201            }
2202            for (MeasureUnit unit : entry.getValue()) {
2203                String camelCase = toCamelCase(unit);
2204                checkForDup(seen, camelCase, unit);
2205                System.out.printf("    measureUnit.adoptInstead(MeasureUnit::create%s(status));\n", camelCase);
2206            }
2207        }
2208        System.out.println("    assertSuccess(\"\", status);");
2209        System.out.println("}");
2210    }
2211
2212    static String toJAVAName(MeasureUnit unit) {
2213        String code = unit.getSubtype();
2214        String type = unit.getType();
2215        String name = code.toUpperCase(Locale.ENGLISH).replace("-", "_");
2216        if (type.equals("angle")) {
2217            if (code.equals("minute") || code.equals("second")) {
2218                name = "ARC_" + name;
2219            }
2220        }
2221        return name;
2222    }
2223
2224    // DO NOT DELETE THIS FUNCTION! It may appear as dead code, but we use this to generate code
2225    // for MeasureFormat during the release process.
2226    static void generateConstants(String thisVersion) {
2227        System.out.println();
2228        Map<String, MeasureUnit> seen = new HashMap<String, MeasureUnit>();
2229        TreeMap<String, List<MeasureUnit>> allUnits = getAllUnits();
2230        for (Map.Entry<String, List<MeasureUnit>> entry : allUnits.entrySet()) {
2231            String type = entry.getKey();
2232            if (isTypeHidden(type)) {
2233                continue;
2234            }
2235            for (MeasureUnit unit : entry.getValue()) {
2236                String name = toJAVAName(unit);
2237                String code = unit.getSubtype();
2238                checkForDup(seen, name, unit);
2239                System.out.println("    /**");
2240                System.out.println("     * Constant for unit of " + type +
2241                        ": " +
2242                        code);
2243                // Special case JAVA had old constants for time from before.
2244                if ("duration".equals(type) && TIME_CODES.contains(code)) {
2245                    System.out.println("     * @stable ICU 4.0");
2246                }
2247                else if (isDraft(name)) {
2248                    System.out.println("     * @draft ICU " + getVersion(name, thisVersion));
2249                    System.out.println("     * @provisional This API might change or be removed in a future release.");
2250                } else {
2251                    System.out.println("     * @stable ICU " + getVersion(name, thisVersion));
2252                }
2253                System.out.println("    */");
2254                if ("duration".equals(type) && TIME_CODES.contains(code)) {
2255                    System.out.println("    public static final TimeUnit " + name + " = (TimeUnit) MeasureUnit.internalGetInstance(\"" +
2256                            type +
2257                            "\", \"" +
2258                            code +
2259                            "\");");
2260                } else {
2261                    System.out.println("    public static final MeasureUnit " + name + " = MeasureUnit.internalGetInstance(\"" +
2262                            type +
2263                            "\", \"" +
2264                            code +
2265                            "\");");
2266                }
2267                System.out.println();
2268            }
2269        }
2270        System.out.println("    private static HashMap<Pair<MeasureUnit, MeasureUnit>, MeasureUnit>unitPerUnitToSingleUnit =");
2271        System.out.println("            new HashMap<Pair<MeasureUnit, MeasureUnit>, MeasureUnit>();");
2272        System.out.println();
2273        System.out.println("    static {");
2274        for (Map.Entry<MeasureUnit, Pair<MeasureUnit, MeasureUnit>> unitPerUnitEntry
2275                : getUnitsToPerParts().entrySet()) {
2276            Pair<MeasureUnit, MeasureUnit> unitPerUnit = unitPerUnitEntry.getValue();
2277            System.out.println("        unitPerUnitToSingleUnit.put(Pair.<MeasureUnit, MeasureUnit>of(MeasureUnit." + toJAVAName(unitPerUnit.first) + ", MeasureUnit." + toJAVAName(unitPerUnit.second) + "), MeasureUnit." + toJAVAName(unitPerUnitEntry.getKey()) + ");");
2278        }
2279        System.out.println("    }");
2280    }
2281
2282    private static String getVersion(String javaName, String thisVersion) {
2283        String version = JAVA_VERSION_MAP.get(javaName);
2284        if (version == null) {
2285            return thisVersion;
2286        }
2287        return version;
2288    }
2289
2290    private static boolean isDraft(String javaName) {
2291        String version = JAVA_VERSION_MAP.get(javaName);
2292        if (version == null) {
2293            return true;
2294        }
2295        return DRAFT_VERSION_SET.contains(version);
2296    }
2297
2298    public <T extends Serializable> void checkStreamingEquality(T item) {
2299        try {
2300          ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
2301          ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOut);
2302          objectOutputStream.writeObject(item);
2303          objectOutputStream.close();
2304          byte[] contents = byteOut.toByteArray();
2305          logln("bytes: " + contents.length + "; " + item.getClass() + ": " + showBytes(contents));
2306          ByteArrayInputStream byteIn = new ByteArrayInputStream(contents);
2307          ObjectInputStream objectInputStream = new ObjectInputStream(byteIn);
2308          Object obj = objectInputStream.readObject();
2309          assertEquals("Streamed Object equals ", item, obj);
2310        } catch (IOException e) {
2311          e.printStackTrace();
2312          assertNull("Test Serialization " + item.getClass(), e);
2313        } catch (ClassNotFoundException e) {
2314          assertNull("Test Serialization " + item.getClass(), e);
2315        }
2316      }
2317
2318    /**
2319     * @param contents
2320     * @return
2321     */
2322    private String showBytes(byte[] contents) {
2323      StringBuilder b = new StringBuilder('[');
2324      for (int i = 0; i < contents.length; ++i) {
2325        int item = contents[i] & 0xFF;
2326        if (item >= 0x20 && item <= 0x7F) {
2327          b.append((char) item);
2328        } else {
2329          b.append('(').append(Utility.hex(item, 2)).append(')');
2330        }
2331      }
2332      return b.append(']').toString();
2333    }
2334
2335    private void verifyEqualsHashCode(Object o, Object eq, Object ne) {
2336        assertEquals("verifyEqualsHashCodeSame", o, o);
2337        assertEquals("verifyEqualsHashCodeEq", o, eq);
2338        assertNotEquals("verifyEqualsHashCodeNe", o, ne);
2339        assertNotEquals("verifyEqualsHashCodeEqTrans", eq, ne);
2340        assertEquals("verifyEqualsHashCodeHashEq", o.hashCode(), eq.hashCode());
2341
2342        // May be a flaky test, but generally should be true.
2343        // May need to comment this out later.
2344        assertNotEquals("verifyEqualsHashCodeHashNe", o.hashCode(), ne.hashCode());
2345    }
2346
2347    public static class MeasureUnitHandler implements SerializableTestUtility.Handler
2348    {
2349        @Override
2350        public Object[] getTestObjects()
2351        {
2352            MeasureUnit items[] = {
2353                    MeasureUnit.CELSIUS,
2354                    Currency.getInstance("EUR")
2355            };
2356            return items;
2357        }
2358        @Override
2359        public boolean hasSameBehavior(Object a, Object b)
2360        {
2361            MeasureUnit a1 = (MeasureUnit) a;
2362            MeasureUnit b1 = (MeasureUnit) b;
2363            return a1.getType().equals(b1.getType())
2364                    && a1.getSubtype().equals(b1.getSubtype());
2365        }
2366    }
2367
2368    public static class MeasureFormatHandler  implements SerializableTestUtility.Handler
2369    {
2370        @Override
2371        public Object[] getTestObjects()
2372        {
2373            MeasureFormat items[] = {
2374                    MeasureFormat.getInstance(ULocale.FRANCE, FormatWidth.SHORT),
2375                    MeasureFormat.getInstance(
2376                            ULocale.FRANCE,
2377                            FormatWidth.WIDE,
2378                            NumberFormat.getIntegerInstance(ULocale.CANADA_FRENCH)),
2379            };
2380            return items;
2381        }
2382        @Override
2383        public boolean hasSameBehavior(Object a, Object b)
2384        {
2385            MeasureFormat a1 = (MeasureFormat) a;
2386            MeasureFormat b1 = (MeasureFormat) b;
2387            return a1.getLocale().equals(b1.getLocale())
2388                    && a1.getWidth().equals(b1.getWidth())
2389                    && a1.getNumberFormat().equals(b1.getNumberFormat())
2390                    ;
2391        }
2392    }
2393}
2394