summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/AndroidTests/res/raw/v21_simple_1.vcf3
-rw-r--r--tests/AndroidTests/res/raw/v21_simple_2.vcf3
-rw-r--r--tests/AndroidTests/res/raw/v21_simple_3.vcf (renamed from tests/AndroidTests/res/raw/v21_simple.vcf)0
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java322
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java (renamed from tests/AndroidTests/src/com/android/unit_tests/VCardTests.java)207
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/VNode.java30
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java313
7 files changed, 850 insertions, 28 deletions
diff --git a/tests/AndroidTests/res/raw/v21_simple_1.vcf b/tests/AndroidTests/res/raw/v21_simple_1.vcf
new file mode 100644
index 0000000..6aabb4c
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_simple_1.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+N:Ando;Roid;
+END:VCARD
diff --git a/tests/AndroidTests/res/raw/v21_simple_2.vcf b/tests/AndroidTests/res/raw/v21_simple_2.vcf
new file mode 100644
index 0000000..f0d5ab5
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_simple_2.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+FN:Ando Roid
+END:VCARD
diff --git a/tests/AndroidTests/res/raw/v21_simple.vcf b/tests/AndroidTests/res/raw/v21_simple_3.vcf
index beddabb..beddabb 100644
--- a/tests/AndroidTests/res/raw/v21_simple.vcf
+++ b/tests/AndroidTests/res/raw/v21_simple_3.vcf
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java
new file mode 100644
index 0000000..0ee74df
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.unit_tests.vcard;
+
+import android.content.ContentValues;
+
+import org.apache.commons.codec.binary.Base64;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+/**
+ * @hide old class just for test
+ */
+public class PropertyNode {
+ public String propName;
+ public String propValue;
+ public List<String> propValue_vector;
+
+ /** Store value as byte[],after decode.
+ * Used when propValue is encoded by something like BASE64, QUOTED-PRINTABLE, etc.
+ */
+ public byte[] propValue_bytes;
+
+ /** param store: key=paramType, value=paramValue
+ * Note that currently PropertyNode class does not support multiple param-values
+ * defined in vCard 3.0 (See also RFC 2426). multiple-values are stored as
+ * one String value like "A,B", not ["A", "B"]...
+ * TODO: fix this.
+ */
+ public ContentValues paramMap;
+
+ /** Only for TYPE=??? param store. */
+ public Set<String> paramMap_TYPE;
+
+ /** Store group values. Used only in VCard. */
+ public Set<String> propGroupSet;
+
+ public PropertyNode() {
+ propName = "";
+ propValue = "";
+ propValue_vector = new ArrayList<String>();
+ paramMap = new ContentValues();
+ paramMap_TYPE = new HashSet<String>();
+ propGroupSet = new HashSet<String>();
+ }
+
+ public PropertyNode(
+ String propName, String propValue, List<String> propValue_vector,
+ byte[] propValue_bytes, ContentValues paramMap, Set<String> paramMap_TYPE,
+ Set<String> propGroupSet) {
+ if (propName != null) {
+ this.propName = propName;
+ } else {
+ this.propName = "";
+ }
+ if (propValue != null) {
+ this.propValue = propValue;
+ } else {
+ this.propValue = "";
+ }
+ if (propValue_vector != null) {
+ this.propValue_vector = propValue_vector;
+ } else {
+ this.propValue_vector = new ArrayList<String>();
+ }
+ this.propValue_bytes = propValue_bytes;
+ if (paramMap != null) {
+ this.paramMap = paramMap;
+ } else {
+ this.paramMap = new ContentValues();
+ }
+ if (paramMap_TYPE != null) {
+ this.paramMap_TYPE = paramMap_TYPE;
+ } else {
+ this.paramMap_TYPE = new HashSet<String>();
+ }
+ if (propGroupSet != null) {
+ this.propGroupSet = propGroupSet;
+ } else {
+ this.propGroupSet = new HashSet<String>();
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof PropertyNode)) {
+ return false;
+ }
+
+ PropertyNode node = (PropertyNode)obj;
+
+ if (propName == null || !propName.equals(node.propName)) {
+ return false;
+ } else if (!paramMap.equals(node.paramMap)) {
+ return false;
+ } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
+ return false;
+ } else if (!propGroupSet.equals(node.propGroupSet)) {
+ return false;
+ }
+
+ if (propValue_bytes != null && Arrays.equals(propValue_bytes, node.propValue_bytes)) {
+ return true;
+ } else {
+ // Log.d("@@@", propValue + ", " + node.propValue);
+ if (!propValue.equals(node.propValue)) {
+ return false;
+ }
+
+ // The value in propValue_vector is not decoded even if it should be
+ // decoded by BASE64 or QUOTED-PRINTABLE. When the size of propValue_vector
+ // is 1, the encoded value is stored in propValue, so we do not have to
+ // check it.
+ return (propValue_vector.equals(node.propValue_vector) ||
+ propValue_vector.size() == 1 ||
+ node.propValue_vector.size() == 1);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("propName: ");
+ builder.append(propName);
+ builder.append(", paramMap: ");
+ builder.append(paramMap.toString());
+ builder.append(", propmMap_TYPE: ");
+ builder.append(paramMap_TYPE.toString());
+ builder.append(", propGroupSet: ");
+ builder.append(propGroupSet.toString());
+ if (propValue_vector != null && propValue_vector.size() > 1) {
+ builder.append(", propValue_vector size: ");
+ builder.append(propValue_vector.size());
+ }
+ if (propValue_bytes != null) {
+ builder.append(", propValue_bytes size: ");
+ builder.append(propValue_bytes.length);
+ }
+ builder.append(", propValue: ");
+ builder.append(propValue);
+ return builder.toString();
+ }
+
+ /**
+ * Encode this object into a string which can be decoded.
+ */
+ public String encode() {
+ // PropertyNode#toString() is for reading, not for parsing in the future.
+ // We construct appropriate String here.
+ StringBuilder builder = new StringBuilder();
+ if (propName.length() > 0) {
+ builder.append("propName:[");
+ builder.append(propName);
+ builder.append("],");
+ }
+ int size = propGroupSet.size();
+ if (size > 0) {
+ Set<String> set = propGroupSet;
+ builder.append("propGroup:[");
+ int i = 0;
+ for (String group : set) {
+ // We do not need to double quote groups.
+ // group = 1*(ALPHA / DIGIT / "-")
+ builder.append(group);
+ if (i < size - 1) {
+ builder.append(",");
+ }
+ i++;
+ }
+ builder.append("],");
+ }
+
+ if (paramMap.size() > 0 || paramMap_TYPE.size() > 0) {
+ ContentValues values = paramMap;
+ builder.append("paramMap:[");
+ size = paramMap.size();
+ int i = 0;
+ for (Entry<String, Object> entry : values.valueSet()) {
+ // Assuming param-key does not contain NON-ASCII nor symbols.
+ //
+ // According to vCard 3.0:
+ // param-name = iana-token / x-name
+ builder.append(entry.getKey());
+
+ // param-value may contain any value including NON-ASCIIs.
+ // We use the following replacing rule.
+ // \ -> \\
+ // , -> \,
+ // In String#replaceAll(), "\\\\" means a single backslash.
+ builder.append("=");
+ builder.append(entry.getValue().toString()
+ .replaceAll("\\\\", "\\\\\\\\")
+ .replaceAll(",", "\\\\,"));
+ if (i < size -1) {
+ builder.append(",");
+ }
+ i++;
+ }
+
+ Set<String> set = paramMap_TYPE;
+ size = paramMap_TYPE.size();
+ if (i > 0 && size > 0) {
+ builder.append(",");
+ }
+ i = 0;
+ for (String type : set) {
+ builder.append("TYPE=");
+ builder.append(type
+ .replaceAll("\\\\", "\\\\\\\\")
+ .replaceAll(",", "\\\\,"));
+ if (i < size - 1) {
+ builder.append(",");
+ }
+ i++;
+ }
+ builder.append("],");
+ }
+
+ size = propValue_vector.size();
+ if (size > 0) {
+ builder.append("propValue:[");
+ List<String> list = propValue_vector;
+ for (int i = 0; i < size; i++) {
+ builder.append(list.get(i)
+ .replaceAll("\\\\", "\\\\\\\\")
+ .replaceAll(",", "\\\\,"));
+ if (i < size -1) {
+ builder.append(",");
+ }
+ }
+ builder.append("],");
+ }
+
+ return builder.toString();
+ }
+
+ public static PropertyNode decode(String encodedString) {
+ PropertyNode propertyNode = new PropertyNode();
+ String trimed = encodedString.trim();
+ if (trimed.length() == 0) {
+ return propertyNode;
+ }
+ String[] elems = trimed.split("],");
+
+ for (String elem : elems) {
+ int index = elem.indexOf('[');
+ String name = elem.substring(0, index - 1);
+ Pattern pattern = Pattern.compile("(?<!\\\\),");
+ String[] values = pattern.split(elem.substring(index + 1), -1);
+ if (name.equals("propName")) {
+ propertyNode.propName = values[0];
+ } else if (name.equals("propGroupSet")) {
+ for (String value : values) {
+ propertyNode.propGroupSet.add(value);
+ }
+ } else if (name.equals("paramMap")) {
+ ContentValues paramMap = propertyNode.paramMap;
+ Set<String> paramMap_TYPE = propertyNode.paramMap_TYPE;
+ for (String value : values) {
+ String[] tmp = value.split("=", 2);
+ String mapKey = tmp[0];
+ // \, -> ,
+ // \\ -> \
+ // In String#replaceAll(), "\\\\" means a single backslash.
+ String mapValue =
+ tmp[1].replaceAll("\\\\,", ",").replaceAll("\\\\\\\\", "\\\\");
+ if (mapKey.equalsIgnoreCase("TYPE")) {
+ paramMap_TYPE.add(mapValue);
+ } else {
+ paramMap.put(mapKey, mapValue);
+ }
+ }
+ } else if (name.equals("propValue")) {
+ StringBuilder builder = new StringBuilder();
+ List<String> list = propertyNode.propValue_vector;
+ int length = values.length;
+ for (int i = 0; i < length; i++) {
+ String normValue = values[i]
+ .replaceAll("\\\\,", ",")
+ .replaceAll("\\\\\\\\", "\\\\");
+ list.add(normValue);
+ builder.append(normValue);
+ if (i < length - 1) {
+ builder.append(";");
+ }
+ }
+ propertyNode.propValue = builder.toString();
+ }
+ }
+
+ // At this time, QUOTED-PRINTABLE is already decoded to Java String.
+ // We just need to decode BASE64 String to binary.
+ String encoding = propertyNode.paramMap.getAsString("ENCODING");
+ if (encoding != null &&
+ (encoding.equalsIgnoreCase("BASE64") ||
+ encoding.equalsIgnoreCase("B"))) {
+ propertyNode.propValue_bytes =
+ Base64.decodeBase64(propertyNode.propValue_vector.get(0).getBytes());
+ }
+
+ return propertyNode;
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/VCardTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java
index b7f562d..200d9c1 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/VCardTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java
@@ -14,36 +14,130 @@
* limitations under the License.
*/
-package com.android.unit_tests;
+package com.android.unit_tests.vcard;
import android.content.ContentValues;
-import android.syncml.pim.PropertyNode;
-import android.syncml.pim.VDataBuilder;
-import android.syncml.pim.VNode;
-import android.syncml.pim.vcard.VCardException;
-import android.syncml.pim.vcard.VCardParser_V21;
-import android.syncml.pim.vcard.VCardParser_V30;
+import android.pim.vcard.ContactStruct;
+import android.pim.vcard.EntryHandler;
+import android.pim.vcard.VCardBuilder;
+import android.pim.vcard.VCardBuilderCollection;
+import android.pim.vcard.VCardConfig;
+import android.pim.vcard.VCardDataBuilder;
+import android.pim.vcard.VCardParser;
+import android.pim.vcard.VCardParser_V21;
+import android.pim.vcard.VCardParser_V30;
+import android.pim.vcard.exception.VCardException;
import android.test.AndroidTestCase;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Vector;
+import java.util.List;
+import java.util.Map;
public class VCardTests extends AndroidTestCase {
+ // TODO: Use EntityIterator, which is added in Eclair.
+ private static class EntryHolder implements EntryHandler {
+ public List<ContactStruct> contacts = new ArrayList<ContactStruct>();
+ public void onEntryCreated(ContactStruct contactStruct) {
+ contacts.add(contactStruct);
+ }
+ public void onFinal() {
+ }
+ }
+
+ static void verify(ContactStruct expected, ContactStruct actual) {
+ if (!equalsString(expected.getName(), actual.getName())) {
+ fail(String.format("Names do not equal: \"%s\" != \"%s\"",
+ expected.getName(), actual.getName()));
+ }
+ if (!equalsString(
+ expected.getPhoneticName(), actual.getPhoneticName())) {
+ fail(String.format("Phonetic names do not equal: \"%s\" != \"%s\"",
+ expected.getPhoneticName(), actual.getPhoneticName()));
+ }
+ {
+ final byte[] expectedPhotoBytes = expected.getPhotoBytes();
+ final byte[] actualPhotoBytes = actual.getPhotoBytes();
+ if (!((expectedPhotoBytes == null && actualPhotoBytes == null) ||
+ Arrays.equals(expectedPhotoBytes, actualPhotoBytes))) {
+ fail("photoBytes is not equal.");
+ }
+ }
+ verifyInternal(expected.getNotes(), actual.getNotes(), "notes");
+ verifyInternal(expected.getPhoneList(), actual.getPhoneList(), "phones");
+ verifyInternal(expected.getContactMethodList(), actual.getContactMethodList(),
+ "contact lists");
+ verifyInternal(expected.getOrganizationList(), actual.getOrganizationList(),
+ "organizations");
+ {
+ final Map<String, List<String>> expectedMap =
+ expected.getExtensionMap();
+ final Map<String, List<String>> actualMap =
+ actual.getExtensionMap();
+ if (verifySize((expectedMap == null ? 0 : expectedMap.size()),
+ (actualMap == null ? 0 : actualMap.size()), "extensions") > 0) {
+ for (String key : expectedMap.keySet()) {
+ if (!actualMap.containsKey(key)) {
+ fail(String.format(
+ "Actual does not have %s extension while expected has",
+ key));
+ }
+ final List<String> expectedList = expectedMap.get(key);
+ final List<String> actualList = actualMap.get(key);
+ verifyInternal(expectedList, actualList,
+ String.format("extension \"%s\"", key));
+ }
+ }
+ }
+ }
+
+ private static boolean equalsString(String a, String b) {
+ if (a == null || a.length() == 0) {
+ return b == null || b.length() == 0;
+ } else {
+ return a.equals(b);
+ }
+ }
+
+ private static int verifySize(int expectedSize, int actualSize, String name) {
+ if (expectedSize != actualSize) {
+ fail(String.format("Size of %s is different: %d != %d",
+ name, expectedSize, actualSize));
+ }
+ return expectedSize;
+ }
+
+ private static <T> void verifyInternal(final List<T> expected, final List<T> actual,
+ String name) {
+ if(verifySize((expected == null ? 0 : expected.size()),
+ (actual == null ? 0 : actual.size()), name) > 0) {
+ int size = expected.size();
+ for (int i = 0; i < size; i++) {
+ final T expectedObj = expected.get(i);
+ final T actualObj = actual.get(i);
+ if (!expected.equals(actual)) {
+ fail(String.format("The %i %s are different: %s != %s",
+ i, name, expectedObj, actualObj));
+ }
+ }
+ }
+ }
+
private class PropertyNodesVerifier {
- private HashMap<String, Vector<PropertyNode>> mPropertyNodeMap;
+ private HashMap<String, ArrayList<PropertyNode>> mPropertyNodeMap;
public PropertyNodesVerifier(PropertyNode... nodes) {
- mPropertyNodeMap = new HashMap<String, Vector<PropertyNode>>();
+ mPropertyNodeMap = new HashMap<String, ArrayList<PropertyNode>>();
for (PropertyNode propertyNode : nodes) {
String propName = propertyNode.propName;
- Vector<PropertyNode> expectedNodes =
+ ArrayList<PropertyNode> expectedNodes =
mPropertyNodeMap.get(propName);
if (expectedNodes == null) {
- expectedNodes = new Vector<PropertyNode>();
+ expectedNodes = new ArrayList<PropertyNode>();
mPropertyNodeMap.put(propName, expectedNodes);
}
expectedNodes.add(propertyNode);
@@ -53,7 +147,7 @@ public class VCardTests extends AndroidTestCase {
public void verify(VNode vnode) {
for (PropertyNode propertyNode : vnode.propList) {
String propName = propertyNode.propName;
- Vector<PropertyNode> nodes = mPropertyNodeMap.get(propName);
+ ArrayList<PropertyNode> nodes = mPropertyNodeMap.get(propName);
if (nodes == null) {
fail("Unexpected propName \"" + propName + "\" exists.");
}
@@ -81,8 +175,8 @@ public class VCardTests extends AndroidTestCase {
}
}
if (mPropertyNodeMap.size() != 0) {
- Vector<String> expectedProps = new Vector<String>();
- for (Vector<PropertyNode> nodes : mPropertyNodeMap.values()) {
+ ArrayList<String> expectedProps = new ArrayList<String>();
+ for (ArrayList<PropertyNode> nodes : mPropertyNodeMap.values()) {
for (PropertyNode node : nodes) {
expectedProps.add(node.propName);
}
@@ -93,25 +187,82 @@ public class VCardTests extends AndroidTestCase {
}
}
- public void testV21SimpleCase() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple);
+ public void testV21SimpleCase1_1() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH);
+ EntryHolder holder = new EntryHolder();
+ builder.addEntryHandler(holder);
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_1);
assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
is.close();
- assertEquals(1, builder.vNodeList.size());
+ assertEquals(1, holder.contacts.size());
+ verify(new ContactStruct("Roid Ando", null,
+ null, null, null, null, null, null),
+ holder.contacts.get(0));
+ }
+
+ public void testV21SimpleCase1_2() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_JAPANESE);
+ EntryHolder holder = new EntryHolder();
+ builder.addEntryHandler(holder);
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_1);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, holder.contacts.size());
+ verify(new ContactStruct("Ando Roid", null,
+ null, null, null, null, null, null),
+ holder.contacts.get(0));
+ }
+
+ public void testV21SimpleCase2() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH);
+ EntryHolder holder = new EntryHolder();
+ builder.addEntryHandler(holder);
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_2);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, holder.contacts.size());
+ verify(new ContactStruct("Ando Roid", null,
+ null, null, null, null, null, null),
+ holder.contacts.get(0));
+ }
+
+ public void testV21SimpleCase3() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder1 = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH);
+ EntryHolder holder = new EntryHolder();
+ builder1.addEntryHandler(holder);
+ VNodeBuilder builder2 = new VNodeBuilder();
+ VCardBuilderCollection collection =
+ new VCardBuilderCollection(
+ new ArrayList<VCardBuilder>(Arrays.asList(builder1, builder2)));
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_3);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", collection));
+ is.close();
+
+ assertEquals(1, builder2.vNodeList.size());
+ VNode vnode = builder2.vNodeList.get(0);
PropertyNodesVerifier verifier = new PropertyNodesVerifier(
new PropertyNode("N", "Ando;Roid;",
Arrays.asList("Ando", "Roid", ""),
null, null, null, null),
new PropertyNode("FN", "Ando Roid",
null, null, null, null, null));
- verifier.verify(builder.vNodeList.get(0));
+ verifier.verify(vnode);
+
+ // FN is prefered.
+ assertEquals(1, holder.contacts.size());
+ ContactStruct actual = holder.contacts.get(0);
+ verify(new ContactStruct("Ando Roid", null,
+ null, null, null, null, null, null),
+ actual);
}
-
+
public void testV21BackslashCase() throws IOException, VCardException {
VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
+ VNodeBuilder builder = new VNodeBuilder();
InputStream is = getContext().getResources().openRawResource(R.raw.v21_backslash);
assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
is.close();
@@ -129,7 +280,7 @@ public class VCardTests extends AndroidTestCase {
public void testV21ComplicatedCase() throws IOException, VCardException {
VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
+ VNodeBuilder builder = new VNodeBuilder();
InputStream is = getContext().getResources().openRawResource(R.raw.v21_complicated);
assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
is.close();
@@ -585,7 +736,7 @@ public class VCardTests extends AndroidTestCase {
public void testV21Japanese1() throws IOException, VCardException {
VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
+ VNodeBuilder builder = new VNodeBuilder();
InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_1);
assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
is.close();
@@ -616,7 +767,7 @@ public class VCardTests extends AndroidTestCase {
public void testV21Japanese2() throws IOException, VCardException {
VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
+ VNodeBuilder builder = new VNodeBuilder();
InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_2);
assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
is.close();
@@ -660,7 +811,7 @@ public class VCardTests extends AndroidTestCase {
public void testV21MultipleEntryCase() throws IOException, VCardException {
VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
+ VNodeBuilder builder = new VNodeBuilder();
InputStream is = getContext().getResources().openRawResource(R.raw.v21_multiple_entry);
assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
is.close();
@@ -741,7 +892,7 @@ public class VCardTests extends AndroidTestCase {
public void testV30SimpleCase() throws IOException, VCardException {
VCardParser_V21 parser = new VCardParser_V30();
- VDataBuilder builder = new VDataBuilder();
+ VNodeBuilder builder = new VNodeBuilder();
InputStream is = getContext().getResources().openRawResource(R.raw.v30_simple);
assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
is.close();
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VNode.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNode.java
new file mode 100644
index 0000000..3eb827b
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNode.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.unit_tests.vcard;
+
+import java.util.ArrayList;
+
+/**
+ * @hide old class. Just for testing
+ */
+public class VNode {
+ public String VName;
+
+ public ArrayList<PropertyNode> propList = new ArrayList<PropertyNode>();
+
+ /** 0:parse over. 1:parsing. */
+ public int parseStatus = 1;
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java
new file mode 100644
index 0000000..6d69223
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.unit_tests.vcard;
+
+import android.content.ContentValues;
+import android.pim.vcard.VCardBuilder;
+import android.pim.vcard.VCardConfig;
+import android.util.CharsetUtils;
+import android.util.Log;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.net.QuotedPrintableCodec;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Store the parse result to custom datastruct: VNode, PropertyNode
+ * Maybe several vcard instance, so use vNodeList to store.
+ * VNode: standy by a vcard instance.
+ * PropertyNode: standy by a property line of a card.
+ * @hide old class, just for testing use
+ */
+public class VNodeBuilder implements VCardBuilder {
+ static private String LOG_TAG = "VDATABuilder";
+
+ /**
+ * If there's no other information available, this class uses this charset for encoding
+ * byte arrays.
+ */
+ static public String TARGET_CHARSET = "UTF-8";
+
+ /** type=VNode */
+ public List<VNode> vNodeList = new ArrayList<VNode>();
+ private int mNodeListPos = 0;
+ private VNode mCurrentVNode;
+ private PropertyNode mCurrentPropNode;
+ private String mCurrentParamType;
+
+ /**
+ * The charset using which VParser parses the text.
+ */
+ private String mSourceCharset;
+
+ /**
+ * The charset with which byte array is encoded to String.
+ */
+ private String mTargetCharset;
+
+ private boolean mStrictLineBreakParsing;
+
+ public VNodeBuilder() {
+ this(VCardConfig.DEFAULT_CHARSET, TARGET_CHARSET, false);
+ }
+
+ public VNodeBuilder(String charset, boolean strictLineBreakParsing) {
+ this(null, charset, strictLineBreakParsing);
+ }
+
+ /**
+ * @hide sourceCharset is temporal.
+ */
+ public VNodeBuilder(String sourceCharset, String targetCharset,
+ boolean strictLineBreakParsing) {
+ if (sourceCharset != null) {
+ mSourceCharset = sourceCharset;
+ } else {
+ mSourceCharset = VCardConfig.DEFAULT_CHARSET;
+ }
+ if (targetCharset != null) {
+ mTargetCharset = targetCharset;
+ } else {
+ mTargetCharset = TARGET_CHARSET;
+ }
+ mStrictLineBreakParsing = strictLineBreakParsing;
+ }
+
+ public void start() {
+ }
+
+ public void end() {
+ }
+
+ // Note: I guess that this code assumes the Record may nest like this:
+ // START:VPOS
+ // ...
+ // START:VPOS2
+ // ...
+ // END:VPOS2
+ // ...
+ // END:VPOS
+ //
+ // However the following code has a bug.
+ // When error occurs after calling startRecord(), the entry which is probably
+ // the cause of the error remains to be in vNodeList, while endRecord() is not called.
+ //
+ // I leave this code as is since I'm not familiar with vcalendar specification.
+ // But I believe we should refactor this code in the future.
+ // Until this, the last entry has to be removed when some error occurs.
+ public void startRecord(String type) {
+
+ VNode vnode = new VNode();
+ vnode.parseStatus = 1;
+ vnode.VName = type;
+ // I feel this should be done in endRecord(), but it cannot be done because of
+ // the reason above.
+ vNodeList.add(vnode);
+ mNodeListPos = vNodeList.size() - 1;
+ mCurrentVNode = vNodeList.get(mNodeListPos);
+ }
+
+ public void endRecord() {
+ VNode endNode = vNodeList.get(mNodeListPos);
+ endNode.parseStatus = 0;
+ while(mNodeListPos > 0){
+ mNodeListPos--;
+ if((vNodeList.get(mNodeListPos)).parseStatus == 1)
+ break;
+ }
+ mCurrentVNode = vNodeList.get(mNodeListPos);
+ }
+
+ public void startProperty() {
+ mCurrentPropNode = new PropertyNode();
+ }
+
+ public void endProperty() {
+ mCurrentVNode.propList.add(mCurrentPropNode);
+ }
+
+ public void propertyName(String name) {
+ mCurrentPropNode.propName = name;
+ }
+
+ // Used only in VCard.
+ public void propertyGroup(String group) {
+ mCurrentPropNode.propGroupSet.add(group);
+ }
+
+ public void propertyParamType(String type) {
+ mCurrentParamType = type;
+ }
+
+ public void propertyParamValue(String value) {
+ if (mCurrentParamType == null ||
+ mCurrentParamType.equalsIgnoreCase("TYPE")) {
+ mCurrentPropNode.paramMap_TYPE.add(value);
+ } else {
+ mCurrentPropNode.paramMap.put(mCurrentParamType, value);
+ }
+
+ mCurrentParamType = null;
+ }
+
+ private String encodeString(String originalString, String targetCharset) {
+ if (mSourceCharset.equalsIgnoreCase(targetCharset)) {
+ return originalString;
+ }
+ Charset charset = Charset.forName(mSourceCharset);
+ ByteBuffer byteBuffer = charset.encode(originalString);
+ // byteBuffer.array() "may" return byte array which is larger than
+ // byteBuffer.remaining(). Here, we keep on the safe side.
+ byte[] bytes = new byte[byteBuffer.remaining()];
+ byteBuffer.get(bytes);
+ try {
+ return new String(bytes, targetCharset);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
+ return null;
+ }
+ }
+
+ private String handleOneValue(String value, String targetCharset, String encoding) {
+ if (encoding != null) {
+ if (encoding.equals("BASE64") || encoding.equals("B")) {
+ // Assume BASE64 is used only when the number of values is 1.
+ mCurrentPropNode.propValue_bytes =
+ Base64.decodeBase64(value.getBytes());
+ return value;
+ } else if (encoding.equals("QUOTED-PRINTABLE")) {
+ String quotedPrintable = value
+ .replaceAll("= ", " ").replaceAll("=\t", "\t");
+ String[] lines;
+ if (mStrictLineBreakParsing) {
+ lines = quotedPrintable.split("\r\n");
+ } else {
+ StringBuilder builder = new StringBuilder();
+ int length = quotedPrintable.length();
+ ArrayList<String> list = new ArrayList<String>();
+ for (int i = 0; i < length; i++) {
+ char ch = quotedPrintable.charAt(i);
+ if (ch == '\n') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ } else if (ch == '\r') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ if (i < length - 1) {
+ char nextCh = quotedPrintable.charAt(i + 1);
+ if (nextCh == '\n') {
+ i++;
+ }
+ }
+ } else {
+ builder.append(ch);
+ }
+ }
+ String finalLine = builder.toString();
+ if (finalLine.length() > 0) {
+ list.add(finalLine);
+ }
+ lines = list.toArray(new String[0]);
+ }
+ StringBuilder builder = new StringBuilder();
+ for (String line : lines) {
+ if (line.endsWith("=")) {
+ line = line.substring(0, line.length() - 1);
+ }
+ builder.append(line);
+ }
+ byte[] bytes;
+ try {
+ bytes = builder.toString().getBytes(mSourceCharset);
+ } catch (UnsupportedEncodingException e1) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + mSourceCharset);
+ bytes = builder.toString().getBytes();
+ }
+
+ try {
+ bytes = QuotedPrintableCodec.decodeQuotedPrintable(bytes);
+ } catch (DecoderException e) {
+ Log.e(LOG_TAG, "Failed to decode quoted-printable: " + e);
+ return "";
+ }
+
+ try {
+ return new String(bytes, targetCharset);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
+ return new String(bytes);
+ }
+ }
+ // Unknown encoding. Fall back to default.
+ }
+ return encodeString(value, targetCharset);
+ }
+
+ public void propertyValues(List<String> values) {
+ if (values == null || values.size() == 0) {
+ mCurrentPropNode.propValue_bytes = null;
+ mCurrentPropNode.propValue_vector.clear();
+ mCurrentPropNode.propValue_vector.add("");
+ mCurrentPropNode.propValue = "";
+ return;
+ }
+
+ ContentValues paramMap = mCurrentPropNode.paramMap;
+
+ String targetCharset = CharsetUtils.nameForDefaultVendor(paramMap.getAsString("CHARSET"));
+ String encoding = paramMap.getAsString("ENCODING");
+
+ if (targetCharset == null || targetCharset.length() == 0) {
+ targetCharset = mTargetCharset;
+ }
+
+ for (String value : values) {
+ mCurrentPropNode.propValue_vector.add(
+ handleOneValue(value, targetCharset, encoding));
+ }
+
+ mCurrentPropNode.propValue = listToString(mCurrentPropNode.propValue_vector);
+ }
+
+ private String listToString(List<String> list){
+ int size = list.size();
+ if (size > 1) {
+ StringBuilder typeListB = new StringBuilder();
+ for (String type : list) {
+ typeListB.append(type).append(";");
+ }
+ int len = typeListB.length();
+ if (len > 0 && typeListB.charAt(len - 1) == ';') {
+ return typeListB.substring(0, len - 1);
+ }
+ return typeListB.toString();
+ } else if (size == 1) {
+ return list.get(0);
+ } else {
+ return "";
+ }
+ }
+
+ public String getResult(){
+ return null;
+ }
+}