Home | History | Annotate | Download | only in util
      1 /* GENERATED SOURCE. DO NOT MODIFY. */
      2 //  2016 and later: Unicode, Inc. and others.
      3 // License & terms of use: http://www.unicode.org/copyright.html#License
      4 /**
      5  *******************************************************************************
      6  * Copyright (C) 2001-2013, International Business Machines Corporation and    *
      7  * others. All Rights Reserved.                                                *
      8  *******************************************************************************
      9  */
     10 package android.icu.dev.test.util;
     11 
     12 import java.text.Collator;
     13 import java.util.Arrays;
     14 import java.util.Collections;
     15 import java.util.Comparator;
     16 import java.util.EventListener;
     17 import java.util.HashMap;
     18 import java.util.HashSet;
     19 import java.util.Iterator;
     20 import java.util.List;
     21 import java.util.Map;
     22 import java.util.Map.Entry;
     23 import java.util.Set;
     24 import java.util.SortedMap;
     25 
     26 import org.junit.Test;
     27 import org.junit.runner.RunWith;
     28 import org.junit.runners.JUnit4;
     29 
     30 import android.icu.dev.test.TestFmwk;
     31 import android.icu.impl.ICULocaleService;
     32 import android.icu.impl.ICULocaleService.ICUResourceBundleFactory;
     33 import android.icu.impl.ICULocaleService.LocaleKey;
     34 import android.icu.impl.ICULocaleService.LocaleKeyFactory;
     35 import android.icu.impl.ICUNotifier;
     36 import android.icu.impl.ICURWLock;
     37 import android.icu.impl.ICUResourceBundle;
     38 import android.icu.impl.ICUService;
     39 import android.icu.impl.ICUService.Factory;
     40 import android.icu.impl.ICUService.Key;
     41 import android.icu.impl.ICUService.ServiceListener;
     42 import android.icu.impl.ICUService.SimpleFactory;
     43 import android.icu.impl.LocaleUtility;
     44 import android.icu.util.ULocale;
     45 import android.icu.testsharding.MainTestShard;
     46 
     47 @MainTestShard
     48 @RunWith(JUnit4.class)
     49 public class ICUServiceTest extends TestFmwk
     50 {
     51     private String lrmsg(String message, Object lhs, Object rhs) {
     52     return message + " lhs: " + lhs + " rhs: " + rhs;
     53     }
     54 
     55     public void confirmBoolean(String message, boolean val) {
     56     msg(message, val ? LOG : ERR, !val, true);
     57     }
     58 
     59     public void confirmEqual(String message, Object lhs, Object rhs) {
     60         msg(lrmsg(message, lhs, rhs), (lhs == null ? rhs == null : lhs.equals(rhs)) ? LOG : ERR, true, true);
     61     }
     62 
     63     public void confirmIdentical(String message, Object lhs, Object rhs) {
     64     msg(lrmsg(message, lhs, rhs), lhs == rhs ? LOG : ERR, true, true);
     65     }
     66 
     67     public void confirmIdentical(String message, int lhs, int rhs) {
     68     msg(message + " lhs: " + lhs + " rhs: " + rhs, lhs == rhs ? LOG : ERR, true, true);
     69     }
     70 
     71     /**
     72      * Convenience override of getDisplayNames(ULocale, Comparator, String) that
     73      * uses the current default ULocale as the locale, the default collator for
     74      * the locale as the comparator to sort the display names, and null for
     75      * the matchID.
     76      */
     77     public SortedMap getDisplayNames(ICUService service) {
     78         ULocale locale = ULocale.getDefault();
     79         Collator col = Collator.getInstance(locale.toLocale());
     80         return service.getDisplayNames(locale, col, null);
     81     }
     82 
     83     /**
     84      * Convenience override of getDisplayNames(ULocale, Comparator, String) that
     85      * uses the default collator for the locale as the comparator to
     86      * sort the display names, and null for the matchID.
     87      */
     88     public SortedMap getDisplayNames(ICUService service, ULocale locale) {
     89         Collator col = Collator.getInstance(locale.toLocale());
     90         return service.getDisplayNames(locale, col, null);
     91     }
     92     /**
     93      * Convenience override of getDisplayNames(ULocale, Comparator, String) that
     94      * uses the default collator for the locale as the comparator to
     95      * sort the display names.
     96      */
     97     public SortedMap getDisplayNames(ICUService service, ULocale locale, String matchID) {
     98         Collator col = Collator.getInstance(locale.toLocale());
     99         return service.getDisplayNames(locale, col, matchID);
    100     }
    101 
    102     // use locale keys
    103     static final class TestService extends ICUService {
    104         public TestService() {
    105             super("Test Service");
    106         }
    107 
    108     @Override
    109     public Key createKey(String id) {
    110         return LocaleKey.createWithCanonicalFallback(id, null); // no fallback locale
    111     }
    112     }
    113 
    114     @Test
    115     public void TestAPI() {
    116     // create a service using locale keys,
    117     ICUService service = new TestService();
    118 
    119         logln("service name:" + service.getName());
    120 
    121     // register an object with one locale,
    122     // search for an object with a more specific locale
    123     // should return the original object
    124     Integer singleton0 = new Integer(0);
    125     service.registerObject(singleton0, "en_US");
    126     Object result = service.get("en_US_FOO");
    127     confirmIdentical("1) en_US_FOO -> en_US", result, singleton0);
    128 
    129     // register a new object with the more specific locale
    130     // search for an object with that locale
    131     // should return the new object
    132     Integer singleton1 = new Integer(1);
    133     service.registerObject(singleton1, "en_US_FOO");
    134     result = service.get("en_US_FOO");
    135     confirmIdentical("2) en_US_FOO -> en_US_FOO", result, singleton1);
    136 
    137     // search for an object that falls back to the first registered locale
    138     result = service.get("en_US_BAR");
    139     confirmIdentical("3) en_US_BAR -> en_US", result, singleton0);
    140 
    141     // get a list of the factories, should be two
    142     List factories = service.factories();
    143     confirmIdentical("4) factory size", factories.size(), 2);
    144 
    145     // register a new object with yet another locale
    146     // original factory list is unchanged
    147     Integer singleton2 = new Integer(2);
    148     service.registerObject(singleton2, "en");
    149     confirmIdentical("5) factory size", factories.size(), 2);
    150 
    151     // search for an object with the new locale
    152     // stack of factories is now en, en_US_FOO, en_US
    153     // search for en_US should still find en_US object
    154     result = service.get("en_US_BAR");
    155     confirmIdentical("6) en_US_BAR -> en_US", result, singleton0);
    156 
    157     // register a new object with an old id, should hide earlier factory using this id, but leave it there
    158     Integer singleton3 = new Integer(3);
    159     service.registerObject(singleton3, "en_US");
    160     factories = service.factories();
    161     confirmIdentical("9) factory size", factories.size(), 4);
    162 
    163     // should get data from that new factory
    164     result = service.get("en_US_BAR");
    165     confirmIdentical("10) en_US_BAR -> (3)", result, singleton3);
    166 
    167     // remove new factory
    168     // should have fewer factories again
    169     service.unregisterFactory((Factory)factories.get(0));
    170     factories = service.factories();
    171     confirmIdentical("11) factory size", factories.size(), 3);
    172 
    173     // should get original data again after remove factory
    174     result = service.get("en_US_BAR");
    175     confirmIdentical("12) en_US_BAR -> 0", result, singleton0);
    176 
    177     // shouldn't find unregistered ids
    178     result = service.get("foo");
    179     confirmIdentical("13) foo -> null", result, null);
    180 
    181     // should find non-canonical strings
    182     String[] resultID = new String[1];
    183     result = service.get("EN_us_fOo", resultID);
    184     confirmEqual("14) find non-canonical", resultID[0], "en_US_FOO");
    185 
    186     // should be able to register non-canonical strings and get them canonicalized
    187     service.registerObject(singleton3, "eN_ca_dUde");
    188     result = service.get("En_Ca_DuDe", resultID);
    189     confirmEqual("15) register non-canonical", resultID[0], "en_CA_DUDE");
    190 
    191     // should be able to register invisible factories, these will not
    192     // be visible by default, but if you know the secret password you
    193     // can still access these services...
    194     Integer singleton4 = new Integer(4);
    195     service.registerObject(singleton4, "en_US_BAR", false);
    196     result = service.get("en_US_BAR");
    197     confirmIdentical("17) get invisible", result, singleton4);
    198 
    199     // should not be able to locate invisible services
    200     Set ids = service.getVisibleIDs();
    201     confirmBoolean("18) find invisible", !ids.contains("en_US_BAR"));
    202 
    203     service.reset();
    204     // an anonymous factory than handles all ids
    205     {
    206         Factory factory = new Factory() {
    207             @Override
    208             public Object create(Key key, ICUService unusedService) {
    209                 return new ULocale(key.currentID());
    210             }
    211 
    212             @Override
    213             public void updateVisibleIDs(Map unusedResult) {
    214             }
    215 
    216             @Override
    217             public String getDisplayName(String id, ULocale l) {
    218                 return null;
    219             }
    220         };
    221         service.registerFactory(factory);
    222 
    223         // anonymous factory will still handle the id
    224         result = service.get(ULocale.US.toString());
    225         confirmEqual("21) locale", result, ULocale.US);
    226 
    227         // still normalizes id
    228         result = service.get("EN_US_BAR");
    229         confirmEqual("22) locale", result, new ULocale("en_US_BAR"));
    230 
    231         // we can override for particular ids
    232         service.registerObject(singleton3, "en_US_BAR");
    233         result = service.get("en_US_BAR");
    234         confirmIdentical("23) override super", result, singleton3);
    235 
    236     }
    237 
    238     // empty service should not recognize anything
    239     service.reset();
    240     result = service.get("en_US");
    241     confirmIdentical("24) empty", result, null);
    242 
    243     // create a custom multiple key factory
    244     {
    245         String[] xids = { "en_US_VALLEY_GIRL",
    246                   "en_US_VALLEY_BOY",
    247                   "en_US_SURFER_GAL",
    248                   "en_US_SURFER_DUDE"
    249         };
    250         service.registerFactory(new TestLocaleKeyFactory(xids, "Later"));
    251     }
    252 
    253     // iterate over the visual ids returned by the multiple factory
    254     {
    255         Set vids = service.getVisibleIDs();
    256         Iterator iter = vids.iterator();
    257         int count = 0;
    258         while (iter.hasNext()) {
    259         ++count;
    260                 String id = (String)iter.next();
    261         logln("  " + id + " --> " + service.get(id));
    262         }
    263         // four visible ids
    264         confirmIdentical("25) visible ids", count, 4);
    265     }
    266 
    267     // iterate over the display names
    268     {
    269         Map dids = getDisplayNames(service, ULocale.GERMANY);
    270         Iterator iter = dids.entrySet().iterator();
    271         int count = 0;
    272         while (iter.hasNext()) {
    273         ++count;
    274         Entry e = (Entry)iter.next();
    275         logln("  " + e.getKey() + " -- > " + e.getValue());
    276         }
    277         // four display names, in german
    278         confirmIdentical("26) display names", count, 4);
    279     }
    280 
    281     // no valid display name
    282     confirmIdentical("27) get display name", service.getDisplayName("en_US_VALLEY_GEEK"), null);
    283 
    284     {
    285         String name = service.getDisplayName("en_US_SURFER_DUDE", ULocale.US);
    286         confirmEqual("28) get display name", name, "English (United States, SURFER_DUDE)");
    287     }
    288 
    289     // register another multiple factory
    290     {
    291         String[] xids = {
    292         "en_US_SURFER", "en_US_SURFER_GAL", "en_US_SILICON", "en_US_SILICON_GEEK"
    293         };
    294         service.registerFactory(new TestLocaleKeyFactory(xids, "Rad dude"));
    295     }
    296 
    297     // this time, we have seven display names
    298         // Rad dude's surfer gal 'replaces' later's surfer gal
    299     {
    300         Map dids = getDisplayNames(service);
    301         Iterator iter = dids.entrySet().iterator();
    302         int count = 0;
    303         while (iter.hasNext()) {
    304         ++count;
    305         Entry e = (Entry)iter.next();
    306         logln("  " + e.getKey() + " --> " + e.getValue());
    307         }
    308         // seven display names, in spanish
    309         confirmIdentical("29) display names", count, 7);
    310     }
    311 
    312     // we should get the display name corresponding to the actual id
    313     // returned by the id we used.
    314     {
    315         String[] actualID = new String[1];
    316         String id = "en_us_surfer_gal";
    317         String gal = (String)service.get(id, actualID);
    318         if (gal != null) {
    319                 logln("actual id: " + actualID[0]);
    320         String displayName = service.getDisplayName(actualID[0], ULocale.US);
    321         logln("found actual: " + gal + " with display name: " + displayName);
    322         confirmBoolean("30) found display name for actual", displayName != null);
    323 
    324         displayName = service.getDisplayName(id, ULocale.US);
    325         logln("found query: " + gal + " with display name: " + displayName);
    326         // this is no longer a bug, we want to return display names for anything
    327         // that a factory handles.  since we handle it, we should return a display
    328         // name.  see jb3549
    329         // confirmBoolean("31) found display name for query", displayName == null);
    330         } else {
    331         errln("30) service could not find entry for " + id);
    332         }
    333 
    334             // this should be handled by the 'dude' factory, since it overrides en_US_SURFER.
    335         id = "en_US_SURFER_BOZO";
    336         String bozo = (String)service.get(id, actualID);
    337         if (bozo != null) {
    338         String displayName = service.getDisplayName(actualID[0], ULocale.US);
    339         logln("found actual: " + bozo + " with display name: " + displayName);
    340         confirmBoolean("32) found display name for actual", displayName != null);
    341 
    342         displayName = service.getDisplayName(id, ULocale.US);
    343         logln("found actual: " + bozo + " with display name: " + displayName);
    344         // see above and jb3549
    345         // confirmBoolean("33) found display name for query", displayName == null);
    346         } else {
    347         errln("32) service could not find entry for " + id);
    348         }
    349 
    350             confirmBoolean("34) is default ", !service.isDefault());
    351     }
    352 
    353         /*
    354       // disallow hiding for now
    355 
    356       // hiding factory should obscure 'sublocales'
    357       {
    358       String[] xids = {
    359       "en_US_VALLEY", "en_US_SILICON"
    360       };
    361       service.registerFactory(new TestHidingFactory(xids, "hiding"));
    362       }
    363 
    364       {
    365       Map dids = service.getDisplayNames();
    366       Iterator iter = dids.entrySet().iterator();
    367       int count = 0;
    368       while (iter.hasNext()) {
    369       ++count;
    370       Entry e = (Entry)iter.next();
    371       logln("  " + e.getKey() + " -- > " + e.getValue());
    372       }
    373       confirmIdentical("35) hiding factory", count, 5);
    374       }
    375         */
    376 
    377     {
    378         Set xids = service.getVisibleIDs();
    379         Iterator iter = xids.iterator();
    380         while (iter.hasNext()) {
    381         String xid = (String)iter.next();
    382         logln(xid + "?  " + service.get(xid));
    383         }
    384 
    385         logln("valleygirl?  " + service.get("en_US_VALLEY_GIRL"));
    386         logln("valleyboy?   " + service.get("en_US_VALLEY_BOY"));
    387         logln("valleydude?  " + service.get("en_US_VALLEY_DUDE"));
    388         logln("surfergirl?  " + service.get("en_US_SURFER_GIRL"));
    389     }
    390 
    391     // resource bundle factory.
    392     service.reset();
    393     service.registerFactory(new ICUResourceBundleFactory());
    394 
    395     // list all of the resources
    396     {
    397             logln("all visible ids: " + service.getVisibleIDs());
    398             /*
    399           Set xids = service.getVisibleIDs();
    400           StringBuffer buf = new StringBuffer("{");
    401           boolean notfirst = false;
    402           Iterator iter = xids.iterator();
    403           while (iter.hasNext()) {
    404           String xid = (String)iter.next();
    405           if (notfirst) {
    406           buf.append(", ");
    407           } else {
    408           notfirst = true;
    409           }
    410           buf.append(xid);
    411           }
    412           buf.append("}");
    413           logln(buf.toString());
    414             */
    415     }
    416 
    417         // list only the resources for es, default locale
    418         // since we're using the default Key, only "es" is matched
    419         {
    420             logln("visible ids for es locale: " + service.getVisibleIDs("es"));
    421         }
    422 
    423         // list only the spanish display names for es, spanish collation order
    424         // since we're using the default Key, only "es" is matched
    425         {
    426             logln("display names: " + getDisplayNames(service, new ULocale("es"), "es"));
    427         }
    428 
    429         // list the display names in reverse order
    430         {
    431             logln("display names in reverse order: " +
    432                   service.getDisplayNames(ULocale.US, new Comparator() {
    433                           @Override
    434                         public int compare(Object lhs, Object rhs) {
    435                               return -String.CASE_INSENSITIVE_ORDER.compare((String)lhs, (String)rhs);
    436                           }
    437                       }));
    438         }
    439 
    440     // get all the display names of these resources
    441     // this should be fast since the display names were cached.
    442     {
    443             logln("service display names for de_DE");
    444         Map names = getDisplayNames(service, new ULocale("de_DE"));
    445         StringBuffer buf = new StringBuffer("{");
    446         Iterator iter = names.entrySet().iterator();
    447         while (iter.hasNext()) {
    448         Entry e = (Entry)iter.next();
    449         String name = (String)e.getKey();
    450         String id = (String)e.getValue();
    451         buf.append("\n   " + name + " --> " + id);
    452         }
    453         buf.append("\n}");
    454         logln(buf.toString());
    455     }
    456 
    457         CalifornioLanguageFactory califactory = new CalifornioLanguageFactory();
    458         service.registerFactory(califactory);
    459     // get all the display names of these resources
    460     {
    461             logln("californio language factory");
    462         StringBuffer buf = new StringBuffer("{");
    463             String[] idNames = {
    464                 CalifornioLanguageFactory.californio,
    465         CalifornioLanguageFactory.valley,
    466         CalifornioLanguageFactory.surfer,
    467         CalifornioLanguageFactory.geek
    468             };
    469             for (int i = 0; i < idNames.length; ++i) {
    470                 String idName = idNames[i];
    471                 buf.append("\n  --- " + idName + " ---");
    472                 Map names = getDisplayNames(service, new ULocale(idName));
    473                 Iterator iter = names.entrySet().iterator();
    474                 while (iter.hasNext()) {
    475                     Entry e = (Entry)iter.next();
    476                     String name = (String)e.getKey();
    477                     String id = (String)e.getValue();
    478                     buf.append("\n    " + name + " --> " + id);
    479                 }
    480         }
    481         buf.append("\n}");
    482         logln(buf.toString());
    483     }
    484 
    485     // test notification
    486     // simple registration
    487     {
    488             logln("simple registration notification");
    489         ICULocaleService ls = new ICULocaleService();
    490         ServiceListener l1 = new ServiceListener() {
    491             private int n;
    492             @Override
    493             public void serviceChanged(ICUService s) {
    494             logln("listener 1 report " + n++ + " service changed: " + s);
    495             }
    496         };
    497         ls.addListener(l1);
    498         ServiceListener l2 = new ServiceListener() {
    499             private int n;
    500             @Override
    501             public void serviceChanged(ICUService s) {
    502             logln("listener 2 report " + n++ + " service changed: " + s);
    503             }
    504         };
    505         ls.addListener(l2);
    506         logln("registering foo... ");
    507         ls.registerObject("Foo", "en_FOO");
    508         logln("registering bar... ");
    509         ls.registerObject("Bar", "en_BAR");
    510         logln("getting foo...");
    511         logln((String)ls.get("en_FOO"));
    512         logln("removing listener 2...");
    513         ls.removeListener(l2);
    514         logln("registering baz...");
    515         ls.registerObject("Baz", "en_BAZ");
    516         logln("removing listener 1");
    517         ls.removeListener(l1);
    518         logln("registering burp...");
    519         ls.registerObject("Burp", "en_BURP");
    520 
    521         // should only get one notification even if register multiple times
    522         logln("... trying multiple registration");
    523         ls.addListener(l1);
    524         ls.addListener(l1);
    525         ls.addListener(l1);
    526         ls.addListener(l2);
    527         ls.registerObject("Foo", "en_FOO");
    528         logln("... registered foo");
    529 
    530         // since in a separate thread, we can callback and not deadlock
    531         ServiceListener l3 = new ServiceListener() {
    532             private int n;
    533             @Override
    534             public void serviceChanged(ICUService s) {
    535             logln("listener 3 report " + n++ + " service changed...");
    536             if (s.get("en_BOINK") == null) { // don't recurse on ourselves!!!
    537                 logln("registering boink...");
    538                 s.registerObject("boink", "en_BOINK");
    539             }
    540             }
    541         };
    542         ls.addListener(l3);
    543         logln("registering boo...");
    544         ls.registerObject("Boo", "en_BOO");
    545         logln("...done");
    546 
    547         try {
    548         Thread.sleep(100);
    549         }
    550         catch (InterruptedException e) {
    551         }
    552     }
    553     }
    554 
    555     static class TestLocaleKeyFactory extends LocaleKeyFactory {
    556     protected final Set ids;
    557     protected final String factoryID;
    558 
    559     public TestLocaleKeyFactory(String[] ids, String factoryID) {
    560             super(VISIBLE, factoryID);
    561 
    562         this.ids = Collections.unmodifiableSet(new HashSet(Arrays.asList(ids)));
    563             this.factoryID = factoryID + ": ";
    564     }
    565 
    566     @Override
    567     protected Object handleCreate(ULocale loc, int kind, ICUService service) {
    568             return factoryID + loc.toString();
    569     }
    570 
    571     @Override
    572     protected Set getSupportedIDs() {
    573             return ids;
    574     }
    575     }
    576 
    577     /*
    578       // Disallow hiding for now since it causes gnarly problems, like
    579       // how do you localize the hidden (but still exported) names.
    580 
    581       static class TestHidingFactory implements ICUService.Factory {
    582       protected final String[] ids;
    583       protected final String factoryID;
    584 
    585       public TestHidingFactory(String[] ids) {
    586       this(ids, "Hiding");
    587       }
    588 
    589       public TestHidingFactory(String[] ids, String factoryID) {
    590       this.ids = (String[])ids.clone();
    591 
    592       if (factoryID == null || factoryID.length() == 0) {
    593       this.factoryID = "";
    594       } else {
    595       this.factoryID = factoryID + ": ";
    596       }
    597       }
    598 
    599       public Object create(Key key, ICUService service) {
    600       for (int i = 0; i < ids.length; ++i) {
    601       if (LocaleUtility.isFallbackOf(ids[i], key.currentID())) {
    602       return factoryID + key.canonicalID();
    603       }
    604       }
    605       return null;
    606       }
    607 
    608       public void updateVisibleIDs(Map result) {
    609       for (int i = 0; i < ids.length; ++i) {
    610       String id = ids[i];
    611       Iterator iter = result.keySet().iterator();
    612       while (iter.hasNext()) {
    613       if (LocaleUtility.isFallbackOf(id, (String)iter.next())) {
    614       iter.remove();
    615       }
    616       }
    617       result.put(id, this);
    618       }
    619       }
    620 
    621       public String getDisplayName(String id, ULocale locale) {
    622       return factoryID + new ULocale(id).getDisplayName(locale);
    623       }
    624       }
    625     */
    626 
    627     static class CalifornioLanguageFactory extends ICUResourceBundleFactory {
    628     public static String californio = "en_US_CA";
    629     public static String valley = californio + "_VALLEY";
    630     public static String surfer = californio + "_SURFER";
    631     public static String geek = californio + "_GEEK";
    632         public static Set supportedIDs;
    633         static {
    634             HashSet result = new HashSet();
    635             result.addAll(ICUResourceBundle.getAvailableLocaleNameSet());
    636         result.add(californio);
    637         result.add(valley);
    638         result.add(surfer);
    639         result.add(geek);
    640             supportedIDs = Collections.unmodifiableSet(result);
    641         }
    642 
    643     @Override
    644     public Set getSupportedIDs() {
    645             return supportedIDs;
    646     }
    647 
    648     @Override
    649     public String getDisplayName(String id, ULocale locale) {
    650         String prefix = "";
    651         String suffix = "";
    652         String ls = locale.toString();
    653         if (LocaleUtility.isFallbackOf(californio, ls)) {
    654         if (ls.equalsIgnoreCase(valley)) {
    655             prefix = "Like, you know, it's so totally ";
    656         } else if (ls.equalsIgnoreCase(surfer)) {
    657             prefix = "Dude, its ";
    658         } else if (ls.equalsIgnoreCase(geek)) {
    659             prefix = "I'd estimate it's approximately ";
    660         } else {
    661             prefix = "Huh?  Maybe ";
    662         }
    663         }
    664         if (LocaleUtility.isFallbackOf(californio, id)) {
    665         if (id.equalsIgnoreCase(valley)) {
    666             suffix = "like the Valley, you know?  Let's go to the mall!";
    667         } else if (id.equalsIgnoreCase(surfer)) {
    668             suffix = "time to hit those gnarly waves, Dude!!!";
    669         } else if (id.equalsIgnoreCase(geek)) {
    670             suffix = "all systems go.  T-Minus 9, 8, 7...";
    671         } else {
    672             suffix = "No Habla Englais";
    673         }
    674         } else {
    675         suffix = super.getDisplayName(id, locale);
    676         }
    677 
    678         return prefix + suffix;
    679     }
    680     }
    681 
    682     @Test
    683     public void TestLocale() {
    684     ICULocaleService service = new ICULocaleService("test locale");
    685     service.registerObject("root", ULocale.ROOT);
    686     service.registerObject("german", "de");
    687     service.registerObject("german_Germany", ULocale.GERMANY);
    688     service.registerObject("japanese", "ja");
    689     service.registerObject("japanese_Japan", ULocale.JAPAN);
    690 
    691     Object target = service.get("de_US");
    692     confirmEqual("test de_US", "german", target);
    693 
    694         ULocale de = new ULocale("de");
    695         ULocale de_US = new ULocale("de_US");
    696 
    697         target = service.get(de_US);
    698     confirmEqual("test de_US 2", "german", target);
    699 
    700         target = service.get(de_US, LocaleKey.KIND_ANY);
    701     confirmEqual("test de_US 3", "german", target);
    702 
    703         target = service.get(de_US, 1234);
    704     confirmEqual("test de_US 4", "german", target);
    705 
    706         ULocale[] actualReturn = new ULocale[1];
    707         target = service.get(de_US, actualReturn);
    708         confirmEqual("test de_US 5", "german", target);
    709         confirmEqual("test de_US 6", actualReturn[0], de);
    710 
    711         actualReturn[0] = null;
    712         target = service.get(de_US, LocaleKey.KIND_ANY, actualReturn);
    713         confirmEqual("test de_US 7", actualReturn[0], de);
    714 
    715         actualReturn[0] = null;
    716         target = service.get(de_US, 1234, actualReturn);
    717     confirmEqual("test de_US 8", "german", target);
    718         confirmEqual("test de_US 9", actualReturn[0], de);
    719 
    720         service.registerObject("one/de_US", de_US, 1);
    721         service.registerObject("two/de_US", de_US, 2);
    722 
    723         target = service.get(de_US, 1);
    724         confirmEqual("test de_US kind 1", "one/de_US", target);
    725 
    726         target = service.get(de_US, 2);
    727         confirmEqual("test de_US kind 2", "two/de_US", target);
    728 
    729         target = service.get(de_US);
    730         confirmEqual("test de_US kind 3", "german", target);
    731 
    732         LocaleKey lkey = LocaleKey.createWithCanonicalFallback("en", null, 1234);
    733         logln("lkey prefix: " + lkey.prefix());
    734         logln("lkey descriptor: " + lkey.currentDescriptor());
    735         logln("lkey current locale: " + lkey.currentLocale());
    736 
    737         lkey.fallback();
    738         logln("lkey descriptor 2: " + lkey.currentDescriptor());
    739 
    740         lkey.fallback();
    741         logln("lkey descriptor 3: " + lkey.currentDescriptor());
    742 
    743     target = service.get("za_PPP");
    744     confirmEqual("test zappp", "root", target);
    745 
    746     ULocale loc = ULocale.getDefault();
    747     ULocale.setDefault(ULocale.JAPANESE);
    748     target = service.get("za_PPP");
    749     confirmEqual("test with ja locale", "japanese", target);
    750 
    751     Set ids = service.getVisibleIDs();
    752     for (Iterator iter = ids.iterator(); iter.hasNext();) {
    753         logln("id: " + iter.next());
    754     }
    755 
    756     ULocale.setDefault(loc);
    757     ids = service.getVisibleIDs();
    758     for (Iterator iter = ids.iterator(); iter.hasNext();) {
    759         logln("id: " + iter.next());
    760     }
    761 
    762     target = service.get("za_PPP");
    763     confirmEqual("test with en locale", "root", target);
    764 
    765         ULocale[] locales = service.getAvailableULocales();
    766         confirmIdentical("test available locales", locales.length, 6);
    767         logln("locales: ");
    768         for (int i = 0; i < locales.length; ++i) {
    769             log("\n  [" + i + "] " + locales[i]);
    770         }
    771         logln(" ");
    772 
    773         service.registerFactory(new ICUResourceBundleFactory());
    774         target = service.get(ULocale.JAPAN);
    775 
    776         {
    777             int n = 0;
    778             List factories = service.factories();
    779             Iterator iter = factories.iterator();
    780             while (iter.hasNext()) {
    781                 logln("[" + n++ + "] " + iter.next());
    782             }
    783         }
    784 
    785         // list only the english display names for es, in reverse order
    786         // since we're using locale keys, we should get all and only the es locales
    787         // hmmm, the default toString function doesn't print in sorted order for TreeMap
    788         {
    789             SortedMap map = service.getDisplayNames(ULocale.US,
    790                             new Comparator() {
    791                                 @Override
    792                                 public int compare(Object lhs, Object rhs) {
    793                                 return -String.CASE_INSENSITIVE_ORDER.compare((String)lhs, (String)rhs);
    794                                 }
    795                             },
    796                             "es");
    797 
    798             logln("es display names in reverse order " + map);
    799         }
    800     }
    801 
    802     @Test
    803     public void TestWrapFactory() {
    804         final String greeting = "Hello There";
    805         final String greetingID = "greeting";
    806 
    807         ICUService service = new ICUService("wrap");
    808         service.registerObject(greeting, greetingID);
    809 
    810         logln("test one: " + service.get(greetingID));
    811 
    812         class WrapFactory implements Factory {
    813             @Override
    814             public Object create(Key key, ICUService serviceArg) {
    815                 if (key.currentID().equals(greetingID)) {
    816                     Object previous = serviceArg.getKey(key, null, this);
    817                     return "A different greeting: \"" + previous + "\"";
    818                 }
    819                 return null;
    820             }
    821 
    822             @Override
    823             public void updateVisibleIDs(Map result) {
    824                 result.put("greeting", this);
    825             }
    826 
    827             @Override
    828             public String getDisplayName(String id, ULocale locale) {
    829                 return "wrap '" + id + "'";
    830             }
    831         }
    832         service.registerFactory(new WrapFactory());
    833 
    834         confirmEqual("wrap test: ", service.get(greetingID), "A different greeting: \"" + greeting + "\"");
    835     }
    836 
    837     // misc coverage tests
    838     @Test
    839     public void TestCoverage() {
    840     // Key
    841     Key key = new Key("foobar");
    842     logln("ID: " + key.id());
    843     logln("canonicalID: " + key.canonicalID());
    844     logln("currentID: " + key.currentID());
    845     logln("has fallback: " + key.fallback());
    846 
    847     // SimpleFactory
    848     Object obj = new Object();
    849     SimpleFactory sf = new SimpleFactory(obj, "object");
    850     try {
    851         sf = new SimpleFactory(null, null);
    852         errln("didn't throw exception");
    853     }
    854     catch (IllegalArgumentException e) {
    855         logln("OK: " + e.getMessage());
    856     }
    857     catch (Exception e) {
    858         errln("threw wrong exception" + e);
    859     }
    860     logln(sf.getDisplayName("object", null));
    861 
    862     // ICUService
    863     ICUService service = new ICUService();
    864     service.registerFactory(sf);
    865 
    866     try {
    867         service.get(null, null);
    868         errln("didn't throw exception");
    869     }
    870     catch (NullPointerException e) {
    871         logln("OK: " + e.getMessage());
    872     }
    873         /*
    874       catch (Exception e) {
    875       errln("threw wrong exception" + e);
    876       }
    877         */
    878     try {
    879         service.registerFactory(null);
    880         errln("didn't throw exception");
    881     }
    882     catch (NullPointerException e) {
    883         logln("OK: " + e.getMessage());
    884     }
    885     catch (Exception e) {
    886         errln("threw wrong exception" + e);
    887     }
    888 
    889     try {
    890         service.unregisterFactory(null);
    891         errln("didn't throw exception");
    892     }
    893     catch (NullPointerException e) {
    894         logln("OK: " + e.getMessage());
    895     }
    896     catch (Exception e) {
    897         errln("threw wrong exception" + e);
    898     }
    899 
    900     logln("object is: " + service.get("object"));
    901 
    902     logln("stats: " + service.stats());
    903 
    904     // ICURWLock
    905 
    906     ICURWLock rwlock = new ICURWLock();
    907     rwlock.resetStats();
    908 
    909     rwlock.acquireRead();
    910     rwlock.releaseRead();
    911 
    912     rwlock.acquireWrite();
    913     rwlock.releaseWrite();
    914     logln("stats: " + rwlock.getStats());
    915     logln("stats: " + rwlock.clearStats());
    916     rwlock.acquireRead();
    917     rwlock.releaseRead();
    918     rwlock.acquireWrite();
    919     rwlock.releaseWrite();
    920     logln("stats: " + rwlock.getStats());
    921 
    922     try {
    923         rwlock.releaseRead();
    924         errln("no error thrown");
    925     }
    926     catch (Exception e) {
    927         logln("OK: " + e.getMessage());
    928     }
    929 
    930     try {
    931         rwlock.releaseWrite();
    932         errln("no error thrown");
    933     }
    934     catch (Exception e) {
    935         logln("OK: " + e.getMessage());
    936     }
    937 
    938         // ICULocaleService
    939 
    940     // LocaleKey
    941 
    942     // LocaleKey lkey = LocaleKey.create("en_US", "ja_JP");
    943     // lkey = LocaleKey.create(null, null);
    944     LocaleKey lkey = LocaleKey.createWithCanonicalFallback("en_US", "ja_JP");
    945         logln("lkey: " + lkey);
    946 
    947         lkey = LocaleKey.createWithCanonicalFallback(null, null);
    948         logln("lkey from null,null: " + lkey);
    949 
    950     // LocaleKeyFactory
    951     LocaleKeyFactory lkf = new LKFSubclass(false);
    952         logln("lkf: " + lkf);
    953     logln("obj: " + lkf.create(lkey, null));
    954     logln(lkf.getDisplayName("foo", null));
    955     logln(lkf.getDisplayName("bar", null));
    956     lkf.updateVisibleIDs(new HashMap());
    957 
    958     LocaleKeyFactory invisibleLKF = new LKFSubclass(false);
    959     logln("obj: " + invisibleLKF.create(lkey, null));
    960     logln(invisibleLKF.getDisplayName("foo", null));
    961     logln(invisibleLKF.getDisplayName("bar", null));
    962     invisibleLKF.updateVisibleIDs(new HashMap());
    963 
    964     // ResourceBundleFactory
    965     ICUResourceBundleFactory rbf = new ICUResourceBundleFactory();
    966     logln("RB: " + rbf.create(lkey, null));
    967 
    968     // ICUNotifier
    969     ICUNotifier nf = new ICUNSubclass();
    970     try {
    971         nf.addListener(null);
    972         errln("added null listener");
    973     }
    974     catch (NullPointerException e) {
    975         logln(e.getMessage());
    976     }
    977     catch (Exception e) {
    978         errln("got wrong exception");
    979     }
    980 
    981     try {
    982         nf.addListener(new WrongListener());
    983         errln("added wrong listener");
    984     }
    985     catch (IllegalStateException e) {
    986         logln(e.getMessage());
    987     }
    988     catch (Exception e) {
    989         errln("got wrong exception");
    990     }
    991 
    992     try {
    993         nf.removeListener(null);
    994         errln("removed null listener");
    995     }
    996     catch (NullPointerException e) {
    997         logln(e.getMessage());
    998     }
    999     catch (Exception e) {
   1000         errln("got wrong exception");
   1001     }
   1002 
   1003     nf.removeListener(new MyListener());
   1004     nf.notifyChanged();
   1005     nf.addListener(new MyListener());
   1006     nf.removeListener(new MyListener());
   1007     }
   1008 
   1009     static class MyListener implements EventListener {
   1010     }
   1011 
   1012     static class WrongListener implements EventListener {
   1013     }
   1014 
   1015     static class ICUNSubclass extends ICUNotifier {
   1016         @Override
   1017         public boolean acceptsListener(EventListener l) {
   1018             return l instanceof MyListener;
   1019         }
   1020 
   1021         // not used, just needed to implement abstract base
   1022         @Override
   1023         public void notifyListener(EventListener l) {
   1024         }
   1025     }
   1026 
   1027     static class LKFSubclass extends LocaleKeyFactory {
   1028     LKFSubclass(boolean visible) {
   1029         super(visible ? VISIBLE : INVISIBLE);
   1030     }
   1031 
   1032     @Override
   1033     protected Set getSupportedIDs() {
   1034             return Collections.EMPTY_SET;
   1035     }
   1036     }
   1037 }
   1038