| /* |
| ********************************************************************** |
| * Copyright (c) 2009, International Business Machines |
| * Corporation and others. All Rights Reserved. |
| ********************************************************************** |
| * Author: Alan Liu |
| * Created: January 14 2004 |
| * Since: ICU 2.8 |
| ********************************************************************** |
| */ |
| package com.ibm.icu.dev.test.util; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.Locale; |
| |
| import com.ibm.icu.dev.test.TestFmwk; |
| import com.ibm.icu.text.Collator; |
| import com.ibm.icu.util.ULocale; |
| |
| public class ULocaleCollationTest extends TestFmwk { |
| |
| public static void main(String[] args) throws Exception { |
| new ULocaleCollationTest().run(args); |
| } |
| |
| public void TestCollator() { |
| checkService("ja_JP_YOKOHAMA", new ServiceFacade() { |
| public Object create(ULocale req) { |
| return Collator.getInstance(req); |
| } |
| }, null, new Registrar() { |
| public Object register(ULocale loc, Object prototype) { |
| return Collator.registerInstance((Collator) prototype, loc); |
| } |
| public boolean unregister(Object key) { |
| return Collator.unregister(key); |
| } |
| }); |
| } |
| |
| |
| /** |
| * Interface used by checkService defining a protocol to create an |
| * object, given a requested locale. |
| */ |
| interface ServiceFacade { |
| Object create(ULocale requestedLocale); |
| } |
| |
| /** |
| * Interface used by checkService defining a protocol to get a |
| * contained subobject, given its parent object. |
| */ |
| interface Subobject { |
| Object get(Object parent); |
| } |
| |
| /** |
| * Interface used by checkService defining a protocol to register |
| * and unregister a service object prototype. |
| */ |
| interface Registrar { |
| Object register(ULocale loc, Object prototype); |
| boolean unregister(Object key); |
| } |
| |
| |
| |
| /** |
| * Compare two locale IDs. If they are equal, return 0. If `string' |
| * starts with `prefix' plus an additional element, that is, string == |
| * prefix + '_' + x, then return 1. Otherwise return a value < 0. |
| */ |
| static int loccmp(String string, String prefix) { |
| int slen = string.length(), |
| plen = prefix.length(); |
| /* 'root' is "less than" everything */ |
| if (prefix.equals("root")) { |
| return string.equals("root") ? 0 : 1; |
| } |
| // ON JAVA (only -- not on C -- someone correct me if I'm wrong) |
| // consider "" to be an alternate name for "root". |
| if (plen == 0) { |
| return slen == 0 ? 0 : 1; |
| } |
| if (!string.startsWith(prefix)) return -1; /* mismatch */ |
| if (slen == plen) return 0; |
| if (string.charAt(plen) == '_') return 1; |
| return -2; /* false match, e.g. "en_USX" cmp "en_US" */ |
| } |
| |
| /** |
| * Check the relationship between requested locales, and report problems. |
| * The caller specifies the expected relationships between requested |
| * and valid (expReqValid) and between valid and actual (expValidActual). |
| * Possible values are: |
| * "gt" strictly greater than, e.g., en_US > en |
| * "ge" greater or equal, e.g., en >= en |
| * "eq" equal, e.g., en == en |
| */ |
| void checklocs(String label, |
| String req, |
| Locale validLoc, |
| Locale actualLoc, |
| String expReqValid, |
| String expValidActual) { |
| String valid = validLoc.toString(); |
| String actual = actualLoc.toString(); |
| int reqValid = loccmp(req, valid); |
| int validActual = loccmp(valid, actual); |
| boolean reqOK = (expReqValid.equals("gt") && reqValid > 0) || |
| (expReqValid.equals("ge") && reqValid >= 0) || |
| (expReqValid.equals("eq") && reqValid == 0); |
| boolean valOK = (expValidActual.equals("gt") && validActual > 0) || |
| (expValidActual.equals("ge") && validActual >= 0) || |
| (expValidActual.equals("eq") && validActual == 0); |
| if (reqOK && valOK) { |
| logln("Ok: " + label + "; req=" + req + ", valid=" + valid + |
| ", actual=" + actual); |
| } else { |
| errln("FAIL: " + label + "; req=" + req + ", valid=" + valid + |
| ", actual=" + actual + |
| (reqOK ? "" : "\n req !" + expReqValid + " valid") + |
| (valOK ? "" : "\n val !" + expValidActual + " actual")); |
| } |
| } |
| |
| /** |
| * Use reflection to call getLocale() on the given object to |
| * determine both the valid and the actual locale. Verify these |
| * for correctness. |
| */ |
| void checkObject(String requestedLocale, Object obj, |
| String expReqValid, String expValidActual) { |
| Class[] getLocaleParams = new Class[] { ULocale.Type.class }; |
| try { |
| Class cls = obj.getClass(); |
| Method getLocale = cls.getMethod("getLocale", getLocaleParams); |
| ULocale valid = (ULocale) getLocale.invoke(obj, new Object[] { |
| ULocale.VALID_LOCALE }); |
| ULocale actual = (ULocale) getLocale.invoke(obj, new Object[] { |
| ULocale.ACTUAL_LOCALE }); |
| checklocs(cls.getName(), requestedLocale, |
| valid.toLocale(), actual.toLocale(), |
| expReqValid, expValidActual); |
| } |
| |
| // Make the following exceptions _specific_ -- do not |
| // catch(Exception), since that will catch the exception |
| // that errln throws. |
| catch(NoSuchMethodException e1) { |
| // no longer an error, Currency has no getLocale |
| // errln("FAIL: reflection failed: " + e1); |
| } catch(SecurityException e2) { |
| errln("FAIL: reflection failed: " + e2); |
| } catch(IllegalAccessException e3) { |
| errln("FAIL: reflection failed: " + e3); |
| } catch(IllegalArgumentException e4) { |
| errln("FAIL: reflection failed: " + e4); |
| } catch(InvocationTargetException e5) { |
| // no longer an error, Currency has no getLocale |
| // errln("FAIL: reflection failed: " + e5); |
| } |
| } |
| |
| /** |
| * Verify the correct getLocale() behavior for the given service. |
| * @param requestedLocale the locale to request. This MUST BE |
| * FAKE. In other words, it should be something like |
| * en_US_FAKEVARIANT so this method can verify correct fallback |
| * behavior. |
| * @param svc a factory object that can create the object to be |
| * tested. This isn't necessary here (one could just pass in the |
| * object) but is required for the overload of this method that |
| * takes a Registrar. |
| */ |
| void checkService(String requestedLocale, ServiceFacade svc) { |
| checkService(requestedLocale, svc, null, null); |
| } |
| |
| /** |
| * Verify the correct getLocale() behavior for the given service. |
| * @param requestedLocale the locale to request. This MUST BE |
| * FAKE. In other words, it should be something like |
| * en_US_FAKEVARIANT so this method can verify correct fallback |
| * behavior. |
| * @param svc a factory object that can create the object to be |
| * tested. |
| * @param sub an object that can be used to retrieve a subobject |
| * which should also be tested. May be null. |
| * @param reg an object that supplies the registration and |
| * unregistration functionality to be tested. May be null. |
| */ |
| void checkService(String requestedLocale, ServiceFacade svc, |
| Subobject sub, Registrar reg) { |
| ULocale req = new ULocale(requestedLocale); |
| Object obj = svc.create(req); |
| checkObject(requestedLocale, obj, "gt", "ge"); |
| if (sub != null) { |
| Object subobj = sub.get(obj); |
| checkObject(requestedLocale, subobj, "gt", "ge"); |
| } |
| if (reg != null) { |
| logln("Info: Registering service"); |
| Object key = reg.register(req, obj); |
| Object objReg = svc.create(req); |
| checkObject(requestedLocale, objReg, "eq", "eq"); |
| if (sub != null) { |
| Object subobj = sub.get(obj); |
| // Assume subobjects don't come from services, so |
| // their metadata should be structured normally. |
| checkObject(requestedLocale, subobj, "gt", "ge"); |
| } |
| logln("Info: Unregistering service"); |
| if (!reg.unregister(key)) { |
| errln("FAIL: unregister failed"); |
| } |
| Object objUnreg = svc.create(req); |
| checkObject(requestedLocale, objUnreg, "gt", "ge"); |
| } |
| } |
| } |