Port of CacheDataTest.java plus bugfixes
diff --git a/src/com/android/i18n/addressinput/CacheData.java b/src/com/android/i18n/addressinput/CacheData.java
index 3a32b17..db02e07 100644
--- a/src/com/android/i18n/addressinput/CacheData.java
+++ b/src/com/android/i18n/addressinput/CacheData.java
@@ -25,8 +25,10 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
+import java.net.URLEncoder;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
@@ -249,7 +251,13 @@
jsonp.setTimeout(TIMEOUT);
final JsonHandler handler = new JsonHandler(key.toString(),
existingJso, listener);
- jsonp.requestObject(serviceUrl + "/" + key.toString(),
+ String keyString;
+ try {
+ keyString = URLEncoder.encode(key.toString(), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ jsonp.requestObject(serviceUrl + "/" + keyString,
new AsyncCallback<JsoMap>() {
public void onFailure(Throwable caught) {
Log.w(TAG, "Request for key " + key + " failed");
diff --git a/src/com/android/i18n/addressinput/JsoMap.java b/src/com/android/i18n/addressinput/JsoMap.java
index 9a60766..c756801 100644
--- a/src/com/android/i18n/addressinput/JsoMap.java
+++ b/src/com/android/i18n/addressinput/JsoMap.java
@@ -21,6 +21,9 @@
import org.json.JSONObject;
import org.json.JSONTokener;
+import java.util.ArrayList;
+import java.util.Iterator;
+
/**
* Compatibility methods on top of the JSON data.
*
@@ -113,10 +116,21 @@
* @param key key name.
* @return JsoMap object.
*/
+ @SuppressWarnings("unchecked") // JSONObject.keys() has no type information.
public JsoMap getObj(String key) {
- String[] names = { key };
try {
- return new JsoMap(this, names);
+ Object o = super.get(key);
+ if (o instanceof JSONObject) {
+ JSONObject value = (JSONObject)o;
+ ArrayList<String> keys = new ArrayList<String>(value.length());
+ for (Iterator<String> it = value.keys(); it.hasNext(); ) {
+ keys.add(it.next());
+ }
+ String[] names = new String[keys.size()];
+ return new JsoMap(value, keys.toArray(names));
+ } else {
+ return null;
+ }
} catch (JSONException e) {
return null;
}
diff --git a/test/com/android/i18n/addressinput/CacheDataTest.java b/test/com/android/i18n/addressinput/CacheDataTest.java
new file mode 100644
index 0000000..abe778e
--- /dev/null
+++ b/test/com/android/i18n/addressinput/CacheDataTest.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.i18n.addressinput;
+
+import junit.framework.TestCase;
+
+public class CacheDataTest extends TestCase {
+ private CacheData cache;
+
+ private static final String DELIM = "~";
+
+ private static final String CANADA_KEY = "data/CA";
+
+ private static final String US_KEY = "data/US";
+
+ private static final String CALIFORNIA_KEY = "data/US/CA";
+
+ private static final String RANDOM_COUNTRY_KEY = "data/asIOSDxcowW";
+
+ private static final String EXAMPLE_LOCAL_US_KEY = "examples/US/local"
+ + "/_default";
+
+ // Data key for Da-an District, Taipei Taiwan
+ private static final String TW_KEY = "data/TW/\u53F0\u5317\u5E02/\u5927"
+ + "\u5B89\u5340";
+
+ private static final String FRANCE_KEY = "data/FR";
+
+ private static Integer listenerInvokeCount = 0;
+
+ private static boolean reachedMaxCount = false;
+
+ public void setUp() {
+ cache = new CacheData();
+ }
+
+ public void testSimpleFetching() {
+ final LookupKey key = new LookupKey.Builder(CANADA_KEY).build();
+
+ delayTestFinish(10000);
+
+ cache.fetchDynamicData(key, null, new DataLoadListener() {
+ boolean beginCalled = false;
+
+ public void dataLoadingBegin() {
+ beginCalled = true;
+ }
+
+ public void dataLoadingEnd() {
+ assertTrue("dataLoadingBegin should be called", beginCalled);
+ JsoMap map = cache.getObj(CANADA_KEY);
+
+ assertTrue(map.containsKey(AddressDataKey.ID.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.NAME.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.LANG.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.UPPER.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.ZIPEX.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.ZIP.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.FMT.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.LANGUAGES.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.SUB_KEYS.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.SUB_NAMES.name()
+ .toLowerCase()));
+ assertFalse(map.containsKey(AddressDataKey.SUB_LNAMES.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.SUB_ZIPS.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.POSTURL.name()
+ .toLowerCase()));
+
+ int namesSize = map.get(AddressDataKey.SUB_NAMES.name()
+ .toLowerCase()).split(DELIM).length;
+ int keysSize = map.get(AddressDataKey.SUB_KEYS.name()
+ .toLowerCase()).split(DELIM).length;
+
+ assertEquals("Expect 13 states in Canada.", 13, namesSize);
+ assertEquals(namesSize, keysSize);
+ finishTest();
+ }
+ });
+ }
+
+ public void testFetchingTaiwanData() {
+ final LookupKey key = new LookupKey.Builder(TW_KEY).build();
+
+ delayTestFinish(10000);
+
+ cache.fetchDynamicData(key, null, new DataLoadListener() {
+ boolean beginCalled = false;
+
+ public void dataLoadingBegin() {
+ beginCalled = true;
+ }
+
+ public void dataLoadingEnd() {
+ assertTrue("dataLoadingBegin should be called", beginCalled);
+
+ JsoMap map = cache.getObj(TW_KEY);
+
+ assertTrue(map.containsKey(AddressDataKey.ID.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.KEY.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.LNAME.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.LANG.name()
+ .toLowerCase()));
+ assertTrue(map.containsKey(AddressDataKey.ZIP.name()
+ .toLowerCase()));
+ assertFalse(map.containsKey(AddressDataKey.FMT.name()
+ .toLowerCase()));
+ assertFalse(map.containsKey(AddressDataKey.SUB_KEYS.name()
+ .toLowerCase()));
+ assertFalse(map.containsKey(AddressDataKey.SUB_NAMES.name()
+ .toLowerCase()));
+ assertFalse(map.containsKey(AddressDataKey.SUB_LNAMES.name()
+ .toLowerCase()));
+ assertFalse(map.containsKey(AddressDataKey.SUB_ZIPS.name()
+ .toLowerCase()));
+
+ // Da-an district.
+ assertEquals("\u5927\u5B89\u5340", map.get(AddressDataKey.KEY.name()
+ .toLowerCase()));
+
+ assertEquals("zh-hant", map.get(AddressDataKey.LANG.name()
+ .toLowerCase()));
+
+ finishTest();
+ }
+ });
+ }
+
+ public void testFetchingExamples() {
+ final LookupKey key = new LookupKey.Builder(EXAMPLE_LOCAL_US_KEY).build();
+
+ delayTestFinish(10000);
+
+ cache.fetchDynamicData(key, null, new DataLoadListener() {
+ boolean beginCalled = false;
+
+ public void dataLoadingBegin() {
+ beginCalled = true;
+ }
+
+ public void dataLoadingEnd() {
+ assertTrue("dataLoadingBegin should be called", beginCalled);
+
+ JsoMap map = cache.getObj(EXAMPLE_LOCAL_US_KEY);
+ assertTrue(map.containsKey(AddressDataKey.NAME.name().toLowerCase()));
+ finishTest();
+ }
+ });
+ }
+
+ public void testFetchingOneKeyManyTimes() {
+ final LookupKey key = new LookupKey.Builder(CALIFORNIA_KEY).build();
+ final int maxCount = 10;
+
+ class CounterListener implements DataLoadListener {
+ public void dataLoadingBegin() {
+ listenerInvokeCount++;
+ if (listenerInvokeCount == maxCount) {
+ reachedMaxCount = true;
+ }
+ assertTrue(
+ "CounterListener's dataLoadingBegin should not be invoked for more "
+ + "than " + maxCount + " times",
+ listenerInvokeCount <= maxCount);
+ }
+
+ public void dataLoadingEnd() {
+ listenerInvokeCount--;
+ assertTrue(listenerInvokeCount >= 0);
+ if (listenerInvokeCount == 0) {
+ assertTrue(
+ "Expect to see key " + key + " cached when CounterListener's "
+ + " dataLoadingEnd is invoked",
+ cache.containsKey(key.toString()));
+ /* TODO: Un-comment when CacheData is updated to be asynchronous.
+ assertTrue(
+ "Expect CounterListener's dataLoadingEnd to be triggered "
+ + maxCount + " times in total",
+ reachedMaxCount);
+ */
+ finishTest();
+ }
+ }
+ }
+
+ delayTestFinish(10000);
+
+ for (int i = 0; i < maxCount; ++i) {
+ cache.fetchDynamicData(key, null, new CounterListener());
+ }
+
+ // Null listeners should not affect results.
+ cache.fetchDynamicData(key, null, null);
+ cache.fetchDynamicData(key, null, null);
+ cache.fetchDynamicData(key, null, null);
+ }
+
+ public void testFetchAgainRighAfterOneFetchStart() {
+ final LookupKey key = new LookupKey.Builder(US_KEY).build();
+
+ delayTestFinish(10000);
+
+ cache.fetchDynamicData(key, null, null);
+
+ cache.fetchDynamicData(key, null, new DataLoadListener() {
+ boolean beginCalled = false;
+
+ public void dataLoadingBegin() {
+ /* TODO: Un-comment when CacheData is updated to be asynchronous.
+ assertFalse("data for key " + key + " should not be fetched yet",
+ cache.containsKey(key.toString()));
+ */
+ beginCalled = true;
+ }
+
+ public void dataLoadingEnd() {
+ assertTrue("dataLoadingBegin should be called", beginCalled);
+
+ assertTrue(cache.containsKey(key.toString()));
+
+ cache.fetchDynamicData(key, null, new DataLoadListener() {
+ boolean beginCalled2 = false;
+
+ public void dataLoadingBegin() {
+ beginCalled2 = true;
+ }
+
+ public void dataLoadingEnd() {
+ assertTrue("dataLoadingBegin should be called", beginCalled2);
+
+ assertTrue(cache.containsKey(key.toString()));
+ finishTest();
+ }
+ });
+ }
+ });
+ }
+
+ public void testInvalidKey() {
+ final LookupKey key = new LookupKey.Builder(RANDOM_COUNTRY_KEY).build();
+
+ delayTestFinish(15000);
+
+ cache.fetchDynamicData(key, null, new DataLoadListener() {
+ boolean beginCalled = false;
+
+ public void dataLoadingBegin() {
+ beginCalled = true;
+ }
+
+ public void dataLoadingEnd() {
+ assertTrue("dataLoadingBegin should be called", beginCalled);
+ assertFalse(cache.containsKey(key.toString()));
+
+ finishTest();
+ }
+ });
+ }
+
+ public void testSetUrl() {
+ final LookupKey key = new LookupKey.Builder(FRANCE_KEY).build();
+ final String originalUrl = cache.getUrl();
+
+ assertFalse(FRANCE_KEY + " should not be in the cache. Do you request "
+ + " it before this test?", cache.containsKey(key.toString()));
+
+ delayTestFinish(10000);
+ // Something that is not an URL.
+ cache.setUrl("FDSSfdfdsfasdfadsf");
+
+ cache.fetchDynamicData(key, null, new DataLoadListener() {
+ boolean beginCalled = false;
+
+ public void dataLoadingBegin() {
+ beginCalled = true;
+ }
+
+ public void dataLoadingEnd() {
+ assertTrue("dataLoadingBegin should be called", beginCalled);
+ assertFalse(cache.containsKey(key.toString()));
+ cache.setUrl(originalUrl);
+ finishTest();
+ }
+ });
+ }
+
+ //
+ // Temporary implementations of things that the GWT implementation depends on.
+ //
+ // TODO: Write real implementations and remove these.
+ //
+
+ // To be used when CacheData is updated to be asynchronous.
+ private static void delayTestFinish(int timeoutMillis) {
+ }
+
+ // To be used when CacheData is updated to be asynchronous.
+ private static void finishTest() {
+ }
+}