Merge change I2a52a60a into eclair-mr2

* changes:
  Implement unit tests for vCard exporter, which depends on the sucess in vCard importer.
This commit is contained in:
Android (Google) Code Review
2009-10-12 17:03:12 -04:00
9 changed files with 1102 additions and 383 deletions

View File

@@ -111,6 +111,10 @@ public class VCardComposer {
public static final String FAILURE_REASON_NOT_INITIALIZED =
"The vCard composer object is not correctly initialized";
/** Should be visible only from developers... (no need to translate, hopefully) */
public static final String FAILURE_REASON_UNSUPPORTED_URI =
"The Uri vCard composer received is not supported by the composer.";
public static final String NO_ERROR = "No error";
public static final String VCARD_TYPE_STRING_DOCOMO = "docomo";
@@ -138,6 +142,15 @@ public class VCardComposer {
private static final String SHIFT_JIS = "SHIFT_JIS";
/**
* Special URI for testing.
*/
public static final String VCARD_TEST_AUTHORITY = "com.android.unit_tests.vcard";
public static final Uri VCARD_TEST_AUTHORITY_URI =
Uri.parse("content://" + VCARD_TEST_AUTHORITY);
public static final Uri CONTACTS_TEST_CONTENT_URI =
Uri.withAppendedPath(VCARD_TEST_AUTHORITY_URI, "contacts");
private static final Uri sDataRequestUri;
private static final Map<Integer, String> sImMap;
@@ -286,7 +299,7 @@ public class VCardComposer {
private String mErrorReason = NO_ERROR;
private boolean mIsCallLogComposer = false;
private boolean mIsCallLogComposer;
private static final String[] sContactsProjection = new String[] {
Contacts._ID,
@@ -307,30 +320,24 @@ public class VCardComposer {
private static final String FLAG_TIMEZONE_UTC = "Z";
public VCardComposer(Context context) {
this(context, VCardConfig.VCARD_TYPE_DEFAULT, true, false);
this(context, VCardConfig.VCARD_TYPE_DEFAULT, true);
}
public VCardComposer(Context context, String vcardTypeStr,
boolean careHandlerErrors) {
this(context, VCardConfig.getVCardTypeFromString(vcardTypeStr),
careHandlerErrors, false);
public VCardComposer(Context context, int vcardType) {
this(context, vcardType, true);
}
public VCardComposer(Context context, int vcardType, boolean careHandlerErrors) {
this(context, vcardType, careHandlerErrors, false);
public VCardComposer(Context context, String vcardTypeStr, boolean careHandlerErrors) {
this(context, VCardConfig.getVCardTypeFromString(vcardTypeStr), careHandlerErrors);
}
/**
* Construct for supporting call log entry vCard composing.
*
* @param isCallLogComposer true if this composer is for creating Call Log vCard.
*/
public VCardComposer(Context context, int vcardType, boolean careHandlerErrors,
boolean isCallLogComposer) {
public VCardComposer(Context context, int vcardType, boolean careHandlerErrors) {
mContext = context;
mVCardType = vcardType;
mCareHandlerErrors = careHandlerErrors;
mIsCallLogComposer = isCallLogComposer;
mContentResolver = context.getContentResolver();
mIsV30 = VCardConfig.isV30(vcardType);
@@ -370,15 +377,26 @@ public class VCardComposer {
mHandlerList.add(handler);
}
public boolean init() {
return init(null, null);
}
/**
* @return Returns true when initialization is successful and all the other
* methods are available. Returns false otherwise.
*/
public boolean init() {
return init(null, null);
}
public boolean init(final String selection, final String[] selectionArgs) {
return init(Contacts.CONTENT_URI, selection, selectionArgs, null);
}
/**
* Note that this is unstable interface, may be deleted in the future.
*/
public boolean init(final Uri contentUri, final String selection,
final String[] selectionArgs, final String sortOrder) {
if (contentUri == null) {
return false;
}
if (mCareHandlerErrors) {
List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
mHandlerList.size());
@@ -397,13 +415,19 @@ public class VCardComposer {
}
}
if (mIsCallLogComposer) {
mCursor = mContentResolver.query(CallLog.Calls.CONTENT_URI, sCallLogProjection,
selection, selectionArgs, null);
final String[] projection;
if (CallLog.Calls.CONTENT_URI.equals(contentUri)) {
projection = sCallLogProjection;
mIsCallLogComposer = true;
} else if (Contacts.CONTENT_URI.equals(contentUri) ||
CONTACTS_TEST_CONTENT_URI.equals(contentUri)) {
projection = sContactsProjection;
} else {
mCursor = mContentResolver.query(Contacts.CONTENT_URI, sContactsProjection,
selection, selectionArgs, null);
mErrorReason = FAILURE_REASON_UNSUPPORTED_URI;
return false;
}
mCursor = mContentResolver.query(
contentUri, projection, selection, selectionArgs, sortOrder);
if (mCursor == null) {
mErrorReason = FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO;
@@ -496,8 +520,7 @@ public class VCardComposer {
dataExists = entityIterator.hasNext();
while (entityIterator.hasNext()) {
Entity entity = entityIterator.next();
for (NamedContentValues namedContentValues : entity
.getSubValues()) {
for (NamedContentValues namedContentValues : entity.getSubValues()) {
ContentValues contentValues = namedContentValues.values;
String key = contentValues.getAsString(Data.MIMETYPE);
if (key != null) {

View File

@@ -525,10 +525,18 @@ public class VCardParser_V21 extends VCardParser {
throw new VCardException("Unknown type \"" + paramName + "\"");
}
} else {
handleType(strArray[0]);
handleParamWithoutName(strArray[0]);
}
}
/**
* vCard 3.0 parser may throw VCardException.
*/
@SuppressWarnings("unused")
protected void handleParamWithoutName(final String paramValue) throws VCardException {
handleType(paramValue);
}
/**
* ptypeval = knowntype / "X-" word
*/
@@ -832,6 +840,9 @@ public class VCardParser_V21 extends VCardParser {
@Override
public boolean parse(InputStream is, String charset, VCardBuilder builder)
throws IOException, VCardException {
if (charset == null) {
charset = VCardConfig.DEFAULT_CHARSET;
}
final InputStreamReader tmpReader = new InputStreamReader(is, charset);
if (VCardConfig.showPerformanceLog()) {
mReader = new CustomBufferedReader(tmpReader);

View File

@@ -46,9 +46,32 @@ public class VCardParser_V30 extends VCardParser_V21 {
private static final HashSet<String> acceptablePropsWithoutParam = new HashSet<String>();
private String mPreviousLine;
private boolean mEmittedAgentWarning = false;
/**
* True when the caller wants the parser to be strict about the input.
* Currently this is only for testing.
*/
private final boolean mStrictParsing;
public VCardParser_V30() {
super();
mStrictParsing = false;
}
/**
* @param strictParsing when true, this object throws VCardException when the vcard is not
* valid from the view of vCard 3.0 specification (defined in RFC 2426). Note that this class
* is not fully yet for being used with this flag and may not notice invalid line(s).
*
* @hide currently only for testing!
*/
public VCardParser_V30(boolean strictParsing) {
super();
mStrictParsing = strictParsing;
}
@Override
protected int getVersion() {
return VCardConfig.FLAG_V30;
@@ -204,7 +227,16 @@ public class VCardParser_V30 extends VCardParser_V21 {
// TODO: fix this.
super.handleAnyParam(paramName, paramValue);
}
@Override
protected void handleParamWithoutName(final String paramValue) throws VCardException {
if (mStrictParsing) {
throw new VCardException("Parameter without name is not acceptable in vCard 3.0");
} else {
super.handleParamWithoutName(paramValue);
}
}
/**
* vCard 3.0 defines
*

View File

@@ -0,0 +1,254 @@
/*
* 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.ContentResolver;
import android.database.CharArrayBuffer;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;
import java.util.Map;
public class MockCursor implements Cursor {
public int getColumnCount() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public int getColumnIndex(String columnName) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public int getColumnIndexOrThrow(String columnName) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public String getColumnName(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public String[] getColumnNames() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public int getCount() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean isNull(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public int getInt(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public long getLong(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public short getShort(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public float getFloat(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public double getDouble(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public byte[] getBlob(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public String getString(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public Bundle getExtras() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public int getPosition() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean isAfterLast() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean isBeforeFirst() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean isFirst() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean isLast() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean move(int offset) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean moveToFirst() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean moveToLast() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean moveToNext() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean moveToPrevious() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean moveToPosition(int position) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public void deactivate() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public void close() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean isClosed() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean requery() {
throw new UnsupportedOperationException("unimplemented mock method");
}
public void registerContentObserver(ContentObserver observer) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public void registerDataSetObserver(DataSetObserver observer) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public Bundle respond(Bundle extras) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public boolean getWantsAllOnMoveCalls() {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean commitUpdates() {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean commitUpdates(Map<? extends Long, ? extends Map<String, Object>> values) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean hasUpdates() {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public void setNotificationUri(ContentResolver cr, Uri uri) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean supportsUpdates() {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean deleteRow() {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public void unregisterContentObserver(ContentObserver observer) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public void unregisterDataSetObserver(DataSetObserver observer) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean updateBlob(int columnIndex, byte[] value) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean updateDouble(int columnIndex, double value) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean updateFloat(int columnIndex, float value) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean updateInt(int columnIndex, int value) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean updateLong(int columnIndex, long value) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean updateShort(int columnIndex, short value) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean updateString(int columnIndex, String value) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public boolean updateToNull(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("deprecation")
public void abortUpdates() {
throw new UnsupportedOperationException("unimplemented mock method");
}
}

View File

@@ -18,15 +18,11 @@ package com.android.unit_tests.vcard;
import android.content.ContentValues;
import android.pim.vcard.ContactStruct;
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;
/**
* Previously used in main vCard handling code but now exists only for testing.
@@ -106,6 +102,15 @@ public class PropertyNode {
}
}
@Override
public int hashCode() {
// vCard may contain more than one same line in one entry, while HashSet or any other
// library which utilize hashCode() does not honor that, so intentionally throw an
// Exception.
throw new UnsupportedOperationException(
"PropertyNode does not provide hashCode() implementation intentionally.");
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PropertyNode)) {
@@ -165,164 +170,4 @@ public class PropertyNode {
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;
}
}

View File

@@ -0,0 +1,235 @@
/*
* 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 java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import junit.framework.TestCase;
/**
* Utility class which verifies input VNode.
*
* This class first checks whether each propertyNode in the VNode is in the
* "ordered expected property list".
* If the node does not exist in the "ordered list", the class refers to
* "unorderd expected property set" and checks the node is expected somewhere.
*/
public class PropertyNodesVerifier {
public static class TypeSet extends HashSet<String> {
public TypeSet(String ... array) {
super(Arrays.asList(array));
}
}
public static class GroupSet extends HashSet<String> {
public GroupSet(String ... array) {
super(Arrays.asList(array));
}
}
private final HashMap<String, List<PropertyNode>> mOrderedNodeMap;
// Intentionally use ArrayList instead of Set, assuming there may be more than one
// exactly same objects.
private final ArrayList<PropertyNode> mUnorderedNodeList;
private final TestCase mTestCase;
public PropertyNodesVerifier(TestCase testCase) {
mOrderedNodeMap = new HashMap<String, List<PropertyNode>>();
mUnorderedNodeList = new ArrayList<PropertyNode>();
mTestCase = testCase;
}
// WithOrder
public PropertyNodesVerifier addNodeWithOrder(String propName, String propValue) {
return addNodeWithOrder(propName, propValue, null, null, null, null, null);
}
public PropertyNodesVerifier addNodeWithOrder(String propName, String propValue,
List<String> propValueList) {
return addNodeWithOrder(propName, propValue, propValueList, null, null, null, null);
}
public PropertyNodesVerifier addNodeWithOrder(String propName, String propValue,
TypeSet paramMap_TYPE) {
return addNodeWithOrder(propName, propValue, null, null, null, paramMap_TYPE, null);
}
public PropertyNodesVerifier addNodeWithOrder(String propName, String propValue,
List<String> propValueList, TypeSet paramMap_TYPE) {
return addNodeWithOrder(propName, propValue, propValueList, null, null,
paramMap_TYPE, null);
}
public PropertyNodesVerifier addNodeWithOrder(String propName, String propValue,
List<String> propValueList, byte[] propValue_bytes,
ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) {
PropertyNode propertyNode = new PropertyNode(propName,
propValue, propValueList, propValue_bytes,
paramMap, paramMap_TYPE, propGroupSet);
List<PropertyNode> expectedNodeList = mOrderedNodeMap.get(propName);
if (expectedNodeList == null) {
expectedNodeList = new ArrayList<PropertyNode>();
mOrderedNodeMap.put(propName, expectedNodeList);
}
expectedNodeList.add(propertyNode);
return this;
}
// WithoutOrder
public PropertyNodesVerifier addNodeWithoutOrder(String propName, String propValue) {
return addNodeWithoutOrder(propName, propValue, null, null, null, null, null);
}
public PropertyNodesVerifier addNodeWithoutOrder(String propName, String propValue,
List<String> propValueList) {
return addNodeWithoutOrder(propName, propValue, propValueList, null, null, null, null);
}
public PropertyNodesVerifier addNodeWithoutOrder(String propName, String propValue,
TypeSet paramMap_TYPE) {
return addNodeWithoutOrder(propName, propValue, null, null, null, paramMap_TYPE, null);
}
public PropertyNodesVerifier addNodeWithoutOrder(String propName, String propValue,
List<String> propValueList, TypeSet paramMap_TYPE) {
return addNodeWithoutOrder(propName, propValue, propValueList, null, null,
paramMap_TYPE, null);
}
public PropertyNodesVerifier addNodeWithoutOrder(String propName, String propValue,
List<String> propValueList, byte[] propValue_bytes,
ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) {
mUnorderedNodeList.add(new PropertyNode(propName, propValue,
propValueList, propValue_bytes, paramMap, paramMap_TYPE, propGroupSet));
return this;
}
public void verify(VNode vnode) {
for (PropertyNode actualNode : vnode.propList) {
verifyNode(actualNode.propName, actualNode);
}
if (!mOrderedNodeMap.isEmpty() || !mUnorderedNodeList.isEmpty()) {
List<String> expectedProps = new ArrayList<String>();
for (List<PropertyNode> nodes : mOrderedNodeMap.values()) {
for (PropertyNode node : nodes) {
if (!expectedProps.contains(node.propName)) {
expectedProps.add(node.propName);
}
}
}
for (PropertyNode node : mUnorderedNodeList) {
if (!expectedProps.contains(node.propName)) {
expectedProps.add(node.propName);
}
}
mTestCase.fail("Expected property " + Arrays.toString(expectedProps.toArray())
+ " was not found.");
}
}
private void verifyNode(final String propName, final PropertyNode actualNode) {
List<PropertyNode> expectedNodeList = mOrderedNodeMap.get(propName);
final int size = (expectedNodeList != null ? expectedNodeList.size() : 0);
if (size > 0) {
for (int i = 0; i < size; i++) {
PropertyNode expectedNode = expectedNodeList.get(i);
List<PropertyNode> expectedButDifferentValueList =
new ArrayList<PropertyNode>();
if (expectedNode.propName.equals(propName)) {
if (expectedNode.equals(actualNode)) {
expectedNodeList.remove(i);
if (expectedNodeList.size() == 0) {
mOrderedNodeMap.remove(propName);
}
return;
} else {
expectedButDifferentValueList.add(expectedNode);
}
}
// "actualNode" is not in ordered expected list.
// Try looking over unordered expected list.
if (tryFoundExpectedNodeFromUnorderedList(actualNode,
expectedButDifferentValueList)) {
return;
}
if (!expectedButDifferentValueList.isEmpty()) {
// Same propName exists but with different value(s).
failWithExpectedNodeList(propName, actualNode,
expectedButDifferentValueList);
} else {
// There's no expected node with same propName.
mTestCase.fail("Unexpected property \"" + propName + "\" exists.");
}
}
} else {
List<PropertyNode> expectedButDifferentValueList =
new ArrayList<PropertyNode>();
if (tryFoundExpectedNodeFromUnorderedList(actualNode, expectedButDifferentValueList)) {
return;
} else {
if (!expectedButDifferentValueList.isEmpty()) {
// Same propName exists but with different value(s).
failWithExpectedNodeList(propName, actualNode,
expectedButDifferentValueList);
} else {
// There's no expected node with same propName.
mTestCase.fail("Unexpected property \"" + propName + "\" exists.");
}
}
}
}
private boolean tryFoundExpectedNodeFromUnorderedList(PropertyNode actualNode,
List<PropertyNode> expectedButDifferentValueList) {
final String propName = actualNode.propName;
int unorderedListSize = mUnorderedNodeList.size();
for (int i = 0; i < unorderedListSize; i++) {
PropertyNode unorderedExpectedNode = mUnorderedNodeList.get(i);
if (unorderedExpectedNode.propName.equals(propName)) {
if (unorderedExpectedNode.equals(actualNode)) {
mUnorderedNodeList.remove(i);
return true;
}
expectedButDifferentValueList.add(unorderedExpectedNode);
}
}
return false;
}
private void failWithExpectedNodeList(String propName, PropertyNode actualNode,
List<PropertyNode> expectedNodeList) {
StringBuilder builder = new StringBuilder();
for (PropertyNode expectedNode : expectedNodeList) {
builder.append("expected: ");
builder.append(expectedNode.toString());
builder.append("\n");
}
mTestCase.fail("Property \"" + propName + "\" has wrong value.\n"
+ builder.toString()
+ " actual: " + actualNode.toString());
}
}

View File

@@ -0,0 +1,409 @@
/*
* 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 com.android.unit_tests.vcard.PropertyNodesVerifier.TypeSet;
import android.content.ContentProvider;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Entity;
import android.content.EntityIterator;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.IBulkCursor;
import android.database.IContentObserver;
import android.net.Uri;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.pim.vcard.VCardComposer;
import android.pim.vcard.VCardConfig;
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.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.test.AndroidTestCase;
import android.test.mock.MockContentResolver;
import android.test.mock.MockContext;
import android.util.Log;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
/**
* Almost a dead copy of android.test.mock.MockContentProvider, but different in that this
* class extends ContentProvider, not implementing IContentProvider,
* so that MockContentResolver is able to accept this class :(
*/
class MockContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
return true;
}
@Override
public int bulkInsert(Uri url, ContentValues[] initialValues) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("unused")
public IBulkCursor bulkQuery(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder, IContentObserver observer,
CursorWindow window) throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
@SuppressWarnings("unused")
public int delete(Uri url, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
public String getType(Uri url) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
public Uri insert(Uri url, ContentValues initialValues) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
public ParcelFileDescriptor openFile(Uri url, String mode) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
throw new UnsupportedOperationException("unimplemented mock method");
}
/**
* @hide
*/
@Override
public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs,
String sortOrder) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
public int update(Uri url, ContentValues values, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public IBinder asBinder() {
throw new UnsupportedOperationException("unimplemented mock method");
}
}
/**
* Tests for the code related to vCard exporter, inculding vCard composer.
* This test class depends on vCard importer code, so if tests for vCard importer fail,
* the result of this class will not be reliable.
*/
public class VCardExporterTests extends AndroidTestCase {
/* package */ static final byte[] sPhotoByteArray =
VCardImporterTests.sPhotoByteArrayForComplicatedCase;
public class ExportTestResolver extends MockContentResolver {
ExportTestProvider mProvider = new ExportTestProvider();
public ExportTestResolver() {
addProvider(VCardComposer.VCARD_TEST_AUTHORITY, mProvider);
addProvider(RawContacts.CONTENT_URI.getAuthority(), mProvider);
}
public ContentValues buildData(String mimeType) {
return mProvider.buildData(mimeType);
}
}
public static class MockEntityIterator implements EntityIterator {
Collection<Entity> mEntityCollection;
Iterator<Entity> mIterator;
// TODO: Support multiple vCard entries.
public MockEntityIterator(Collection<ContentValues> contentValuesCollection) {
mEntityCollection = new ArrayList<Entity>();
Entity entity = new Entity(new ContentValues());
for (ContentValues contentValues : contentValuesCollection) {
entity.addSubValue(Data.CONTENT_URI, contentValues);
}
mEntityCollection.add(entity);
mIterator = mEntityCollection.iterator();
}
public boolean hasNext() {
return mIterator.hasNext();
}
public Entity next() {
return mIterator.next();
}
public void reset() {
mIterator = mEntityCollection.iterator();
}
public void close() {
}
}
public class ExportTestProvider extends MockContentProvider {
List<ContentValues> mContentValuesList = new ArrayList<ContentValues>();
public ContentValues buildData(String mimeType) {
ContentValues contentValues = new ContentValues();
contentValues.put(Data.MIMETYPE, mimeType);
mContentValuesList.add(contentValues);
return contentValues;
}
@Override
public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
String sortOrder) {
assert(uri != null);
assert(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()));
final String authority = uri.getAuthority();
assert(RawContacts.CONTENT_URI.getAuthority().equals(authority));
return new MockEntityIterator(mContentValuesList);
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
assert(VCardComposer.CONTACTS_TEST_CONTENT_URI.equals(uri));
// Support multiple rows.
return new MockCursor() {
int mCurrentPosition = -1;
@Override
public int getCount() {
return 1;
}
@Override
public boolean moveToFirst() {
mCurrentPosition = 0;
return true;
}
@Override
public boolean moveToNext() {
if (mCurrentPosition == 0 || mCurrentPosition == -1) {
mCurrentPosition++;
return true;
} else {
return false;
}
}
@Override
public boolean isBeforeFirst() {
return mCurrentPosition < 0;
}
@Override
public boolean isAfterLast() {
return mCurrentPosition > 0;
}
@Override
public int getColumnIndex(String columnName) {
assertEquals(Contacts._ID, columnName);
return 0;
}
@Override
public int getInt(int columnIndex) {
assertEquals(0, columnIndex);
return 0;
}
@Override
public String getString(int columnIndex) {
return String.valueOf(getInt(columnIndex));
}
@Override
public void close() {
}
};
}
}
public static class VCardVerificationHandler implements VCardComposer.OneEntryHandler {
final private TestCase mTestCase;
final private List<PropertyNodesVerifier> mPropertyNodesVerifierList;
final private boolean mIsV30;
int mCount;
public VCardVerificationHandler(TestCase testCase, boolean isV30) {
mTestCase = testCase;
mPropertyNodesVerifierList = new ArrayList<PropertyNodesVerifier>();
mIsV30 = isV30;
mCount = 1;
}
public PropertyNodesVerifier addNewPropertyNodesVerifier() {
PropertyNodesVerifier propertyNodesVerifier = new PropertyNodesVerifier(mTestCase);
mPropertyNodesVerifierList.add(propertyNodesVerifier);
return propertyNodesVerifier;
}
public boolean onInit(Context context) {
return true;
}
public boolean onEntryCreated(String vcard) {
if (mPropertyNodesVerifierList.size() == 0) {
mTestCase.fail("Too many vCard entries seems to be inserted(No."
+ mCount + " of the entries (No.1 is the first entry))");
}
PropertyNodesVerifier propertyNodesVerifier =
mPropertyNodesVerifierList.get(0);
mPropertyNodesVerifierList.remove(0);
VCardParser parser = (mIsV30 ? new VCardParser_V30(true) : new VCardParser_V21());
VNodeBuilder builder = new VNodeBuilder();
InputStream is;
try {
is = new ByteArrayInputStream(vcard.getBytes("UTF-8"));
mTestCase.assertEquals(true, parser.parse(is, null, builder));
is.close();
mTestCase.assertEquals(1, builder.vNodeList.size());
propertyNodesVerifier.verify(builder.vNodeList.get(0));
} catch (IOException e) {
mTestCase.fail("Unexpected IOException: " + e.getMessage());
} catch (VCardException e) {
mTestCase.fail("Unexpected VCardException: " + e.getMessage());
} finally {
mCount++;
}
return true;
}
public void onTerminate() {
}
}
private class CustomMockContext extends MockContext {
final ContentResolver mResolver;
public CustomMockContext(ContentResolver resolver) {
mResolver = resolver;
}
@Override
public ContentResolver getContentResolver() {
return mResolver;
}
}
//// Followings are actual tests ////
public void testSimple() {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "Ando");
contentValues.put(StructuredName.GIVEN_NAME, "Roid");
VCardVerificationHandler handler = new VCardVerificationHandler(this, false);
handler.addNewPropertyNodesVerifier()
.addNodeWithOrder("VERSION", "2.1")
.addNodeWithoutOrder("FN", "Roid Ando")
.addNodeWithoutOrder("N", "Ando;Roid;;;", Arrays.asList("Ando", "Roid", "", "", ""));
VCardComposer composer = new VCardComposer(new CustomMockContext(resolver),
VCardConfig.VCARD_TYPE_V21_GENERIC);
composer.addHandler(handler);
if (!composer.init(VCardComposer.CONTACTS_TEST_CONTENT_URI, null, null, null)) {
fail("init failed. Reason: " + composer.getErrorReason());
}
assertFalse(composer.isAfterLast());
assertTrue(composer.createOneEntry());
assertTrue(composer.isAfterLast());
composer.terminate();
}
private void testPhotoCommon(boolean isV30) {
ExportTestResolver resolver = new ExportTestResolver();
ContentValues contentValues = resolver.buildData(StructuredName.CONTENT_ITEM_TYPE);
contentValues.put(StructuredName.FAMILY_NAME, "PhotoTest");
contentValues = resolver.buildData(Photo.CONTENT_ITEM_TYPE);
contentValues.put(Photo.PHOTO, sPhotoByteArray);
ContentValues contentValuesForPhoto = new ContentValues();
contentValuesForPhoto.put("ENCODING", (isV30 ? "b" : "BASE64"));
VCardVerificationHandler handler = new VCardVerificationHandler(this, isV30);
handler.addNewPropertyNodesVerifier()
.addNodeWithOrder("VERSION", (isV30 ? "3.0" : "2.1"))
.addNodeWithoutOrder("FN", "PhotoTest")
.addNodeWithoutOrder("N", "PhotoTest;;;;", Arrays.asList("PhotoTest", "", "", "", ""))
.addNodeWithOrder("PHOTO", null, null, sPhotoByteArray,
contentValuesForPhoto, new TypeSet("JPEG"), null);
int vcardType = (isV30 ? VCardConfig.VCARD_TYPE_V30_GENERIC
: VCardConfig.VCARD_TYPE_V21_GENERIC);
VCardComposer composer = new VCardComposer(new CustomMockContext(resolver), vcardType);
composer.addHandler(handler);
if (!composer.init(VCardComposer.CONTACTS_TEST_CONTENT_URI, null, null, null)) {
fail("init() failed. Reason: " + composer.getErrorReason());
}
assertFalse(composer.isAfterLast());
assertTrue(composer.createOneEntry());
assertTrue(composer.isAfterLast());
composer.terminate();
}
public void testPhotoV21() {
testPhotoCommon(false);
}
public void testPhotoV30() {
testPhotoCommon(true);
}
}

View File

@@ -17,6 +17,7 @@
package com.android.unit_tests.vcard;
import com.android.unit_tests.R;
import com.android.unit_tests.vcard.PropertyNodesVerifier.TypeSet;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
@@ -56,14 +57,13 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;
public class VCardImportTests extends AndroidTestCase {
public class VCardImporterTests extends AndroidTestCase {
// Push data into int array at first since values like 0x80 are
// interpreted as int by the compiler and casting all of them is
// cumbersome...
@@ -423,7 +423,7 @@ public class VCardImportTests extends AndroidTestCase {
0x55, 0x25, 0x15, 0x2c, 0x68, 0xa3, 0x30, 0xeb, 0x54, 0xa5, 0x15,
0x0c, 0xd1, 0x00, 0xff, 0xd9};
private static final byte[] sPhotoByteArrayForComplicatedCase;
/* package */ static final byte[] sPhotoByteArrayForComplicatedCase;
static {
final int length = sPhotoIntArrayForComplicatedCase.length;
@@ -433,69 +433,7 @@ public class VCardImportTests extends AndroidTestCase {
}
}
private class PropertyNodesVerifier {
private HashMap<String, List<PropertyNode>> mPropertyNodeMap;
public PropertyNodesVerifier() {
mPropertyNodeMap = new HashMap<String, List<PropertyNode>>();
}
public PropertyNodesVerifier addPropertyNode(String propName, String propValue,
List<String> propValue_vector, byte[] propValue_bytes,
ContentValues paramMap, Set<String> paramMap_TYPE, Set<String> propGroupSet) {
PropertyNode propertyNode = new PropertyNode(propName,
propValue, propValue_vector, propValue_bytes,
paramMap, paramMap_TYPE, propGroupSet);
List<PropertyNode> expectedNodeList = mPropertyNodeMap.get(propName);
if (expectedNodeList == null) {
expectedNodeList = new ArrayList<PropertyNode>();
mPropertyNodeMap.put(propName, expectedNodeList);
}
expectedNodeList.add(propertyNode);
return this;
}
public void verify(VNode vnode) {
for (PropertyNode propertyNode : vnode.propList) {
String propName = propertyNode.propName;
List<PropertyNode> nodes = mPropertyNodeMap.get(propName);
if (nodes == null) {
fail("Unexpected propName \"" + propName + "\" exists.");
}
boolean successful = false;
int size = nodes.size();
for (int i = 0; i < size; i++) {
PropertyNode expectedNode = nodes.get(i);
if (expectedNode.propName.equals(propName)) {
if (expectedNode.equals(propertyNode)) {
successful = true;
nodes.remove(i);
if (nodes.size() == 0) {
mPropertyNodeMap.remove(propName);
}
break;
} else {
fail("Property \"" + propName + "\" has wrong value.\n"
+ "expected: " + expectedNode.toString()
+ "\n actual: " + propertyNode.toString());
}
}
}
if (!successful) {
fail("Unexpected property \"" + propName + "\" exists.");
}
}
if (mPropertyNodeMap.size() != 0) {
List<String> expectedProps = new ArrayList<String>();
for (List<PropertyNode> nodes : mPropertyNodeMap.values()) {
for (PropertyNode node : nodes) {
expectedProps.add(node.propName);
}
}
fail("expected props " + Arrays.toString(expectedProps.toArray()) +
" was not found");
}
}
}
public class VerificationResolver extends MockContentResolver {
VerificationProvider mVerificationProvider = new VerificationProvider();
@@ -749,7 +687,7 @@ public class VCardImportTests extends AndroidTestCase {
InputStream is = getContext().getResources().openRawResource(mResourceId);
final VCardParser vCardParser;
if (VCardConfig.isV30(mVCardType)) {
vCardParser = new VCardParser_V30();
vCardParser = new VCardParser_V30(true); // use StrictParsing
} else {
vCardParser = new VCardParser_V21();
}
@@ -777,9 +715,8 @@ public class VCardImportTests extends AndroidTestCase {
assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
is.close();
assertEquals(1, builder.vNodeList.size());
PropertyNodesVerifier verifier = new PropertyNodesVerifier()
.addPropertyNode("N", "Ando;Roid;", Arrays.asList("Ando", "Roid", ""),
null, null, null, null);
PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
.addNodeWithOrder("N", "Ando;Roid;", Arrays.asList("Ando", "Roid", ""));
verifier.verify(builder.vNodeList.get(0));
}
@@ -839,12 +776,11 @@ public class VCardImportTests extends AndroidTestCase {
assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
is.close();
assertEquals(1, builder.vNodeList.size());
PropertyNodesVerifier verifier = new PropertyNodesVerifier()
.addPropertyNode("VERSION", "2.1", null, null, null, null, null)
.addPropertyNode("N", ";A;B\\;C\\;;D;:E;\\\\;",
Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""),
null, null, null, null)
.addPropertyNode("FN", "A;B\\C\\;D:E\\\\", null, null, null, null, null);
PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
.addNodeWithOrder("VERSION", "2.1")
.addNodeWithOrder("N", ";A;B\\;C\\;;D;:E;\\\\;",
Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""))
.addNodeWithOrder("FN", "A;B\\C\\;D:E\\\\");
verifier.verify(builder.vNodeList.get(0));
}
@@ -962,63 +898,51 @@ public class VCardImportTests extends AndroidTestCase {
contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
ContentValues contentValuesForPhoto = new ContentValues();
contentValuesForPhoto.put("ENCODING", "BASE64");
PropertyNodesVerifier verifier = new PropertyNodesVerifier()
.addPropertyNode("VERSION", "2.1", null, null, null, null, null)
.addPropertyNode("N", "Gump;Forrest;Hoge;Pos;Tao",
Arrays.asList("Gump", "Forrest", "Hoge", "Pos", "Tao"),
null, null, null, null)
.addPropertyNode("FN", "Joe Due", null, null, null, null, null)
.addPropertyNode("ORG", "Gump Shrimp Co.;Sales Dept.;Manager;Fish keeper",
Arrays.asList("Gump Shrimp Co.", "Sales Dept.;Manager", "Fish keeper"),
null, null, null, null)
.addPropertyNode("ROLE", "Fish Cake Keeper!", null, null, null, null, null)
.addPropertyNode("TITLE", "Shrimp Man", null, null, null, null, null)
.addPropertyNode("X-CLASS", "PUBLIC", null, null, null, null, null)
.addPropertyNode("TEL", "(111) 555-1212", null, null, null,
new HashSet<String>(Arrays.asList("WORK", "VOICE")), null)
.addPropertyNode("TEL", "(404) 555-1212", null, null, null,
new HashSet<String>(Arrays.asList("HOME", "VOICE")), null)
.addPropertyNode("TEL", "0311111111", null, null, null,
new HashSet<String>(Arrays.asList("CELL")), null)
.addPropertyNode("TEL", "0322222222", null, null, null,
new HashSet<String>(Arrays.asList("VIDEO")), null)
.addPropertyNode("TEL", "0333333333", null, null, null,
new HashSet<String>(Arrays.asList("VOICE")), null)
.addPropertyNode("ADR", ";;100 Waters Edge;Baytown;LA;30314;United States of America",
PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
.addNodeWithOrder("VERSION", "2.1")
.addNodeWithOrder("N", "Gump;Forrest;Hoge;Pos;Tao",
Arrays.asList("Gump", "Forrest", "Hoge", "Pos", "Tao"))
.addNodeWithOrder("FN", "Joe Due")
.addNodeWithOrder("ORG", "Gump Shrimp Co.;Sales Dept.;Manager;Fish keeper",
Arrays.asList("Gump Shrimp Co.", "Sales Dept.;Manager", "Fish keeper"))
.addNodeWithOrder("ROLE", "Fish Cake Keeper!")
.addNodeWithOrder("TITLE", "Shrimp Man")
.addNodeWithOrder("X-CLASS", "PUBLIC")
.addNodeWithOrder("TEL", "(111) 555-1212", new TypeSet("WORK", "VOICE"))
.addNodeWithOrder("TEL", "(404) 555-1212", new TypeSet("HOME", "VOICE"))
.addNodeWithOrder("TEL", "0311111111", new TypeSet("CELL"))
.addNodeWithOrder("TEL", "0322222222", new TypeSet("VIDEO"))
.addNodeWithOrder("TEL", "0333333333", new TypeSet("VOICE"))
.addNodeWithOrder("ADR", ";;100 Waters Edge;Baytown;LA;30314;United States of America",
Arrays.asList("", "", "100 Waters Edge", "Baytown",
"LA", "30314", "United States of America"),
null, null, new HashSet<String>(Arrays.asList("WORK")), null)
.addPropertyNode("LABEL",
null, null, new TypeSet("WORK"), null)
.addNodeWithOrder("LABEL",
"100 Waters Edge\r\nBaytown, LA 30314\r\nUnited States of America",
null, null, contentValuesForQP,
new HashSet<String>(Arrays.asList("WORK")), null)
.addPropertyNode("ADR",
null, null, contentValuesForQP, new TypeSet("WORK"), null)
.addNodeWithOrder("ADR",
";;42 Plantation St.;Baytown;LA;30314;United States of America",
Arrays.asList("", "", "42 Plantation St.", "Baytown",
"LA", "30314", "United States of America"), null, null,
new HashSet<String>(Arrays.asList("HOME")), null)
.addPropertyNode("LABEL",
new TypeSet("HOME"), null)
.addNodeWithOrder("LABEL",
"42 Plantation St.\r\nBaytown, LA 30314\r\nUnited States of America",
null, null, contentValuesForQP,
new HashSet<String>(Arrays.asList("HOME")), null)
.addPropertyNode("EMAIL", "forrestgump@walladalla.com",
null, null, null,
new HashSet<String>(Arrays.asList("PREF", "INTERNET")), null)
.addPropertyNode("EMAIL", "cell@example.com", null, null, null,
new HashSet<String>(Arrays.asList("CELL")), null)
.addPropertyNode("NOTE", "The following note is the example from RFC 2045.",
null, null, null, null, null)
.addPropertyNode("NOTE",
new TypeSet("HOME"), null)
.addNodeWithOrder("EMAIL", "forrestgump@walladalla.com", new TypeSet("PREF", "INTERNET"))
.addNodeWithOrder("EMAIL", "cell@example.com", new TypeSet("CELL"))
.addNodeWithOrder("NOTE", "The following note is the example from RFC 2045.")
.addNodeWithOrder("NOTE",
"Now's the time for all folk to come to the aid of their country.",
null, null, contentValuesForQP, null, null)
.addPropertyNode("PHOTO", null,
.addNodeWithOrder("PHOTO", null,
null, sPhotoByteArrayForComplicatedCase, contentValuesForPhoto,
new HashSet<String>(Arrays.asList("JPEG")), null)
.addPropertyNode("X-ATTRIBUTE", "Some String", null, null, null, null, null)
.addPropertyNode("BDAY", "19800101", null, null, null, null, null)
.addPropertyNode("GEO", "35.6563854,139.6994233", null, null, null, null, null)
.addPropertyNode("URL", "http://www.example.com/", null, null, null, null, null)
.addPropertyNode("REV", "20080424T195243Z", null, null, null, null, null);
new TypeSet("JPEG"), null)
.addNodeWithOrder("X-ATTRIBUTE", "Some String")
.addNodeWithOrder("BDAY", "19800101")
.addNodeWithOrder("GEO", "35.6563854,139.6994233")
.addNodeWithOrder("URL", "http://www.example.com/")
.addNodeWithOrder("REV", "20080424T195243Z");
verifier.verify(builder.vNodeList.get(0));
}
@@ -1126,22 +1050,19 @@ public class VCardImportTests extends AndroidTestCase {
assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
is.close();
assertEquals(1, builder.vNodeList.size());
PropertyNodesVerifier verifier = new PropertyNodesVerifier()
.addPropertyNode("VERSION", "3.0", null, null, null, null, null)
.addPropertyNode("FN", "And Roid", null, null, null, null, null)
.addPropertyNode("N", "And;Roid;;;", Arrays.asList("And", "Roid", "", "", ""),
null, null, null, null)
.addPropertyNode("ORG", "Open;Handset; Alliance",
Arrays.asList("Open", "Handset", " Alliance"),
null, null, null, null)
.addPropertyNode("SORT-STRING", "android", null, null, null, null, null)
.addPropertyNode("TEL", "0300000000", null, null, null,
new HashSet<String>(Arrays.asList("PREF", "VOICE")), null)
.addPropertyNode("CLASS", "PUBLIC", null, null, null, null, null)
.addPropertyNode("X-GNO", "0", null, null, null, null, null)
.addPropertyNode("X-GN", "group0", null, null, null, null, null)
.addPropertyNode("X-REDUCTION", "0", null, null, null, null, null)
.addPropertyNode("REV", "20081031T065854Z", null, null, null, null, null);
PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
.addNodeWithOrder("VERSION", "3.0")
.addNodeWithOrder("FN", "And Roid")
.addNodeWithOrder("N", "And;Roid;;;", Arrays.asList("And", "Roid", "", "", ""))
.addNodeWithOrder("ORG", "Open;Handset; Alliance",
Arrays.asList("Open", "Handset", " Alliance"))
.addNodeWithOrder("SORT-STRING", "android")
.addNodeWithOrder("TEL", "0300000000", new TypeSet("PREF", "VOICE"))
.addNodeWithOrder("CLASS", "PUBLIC")
.addNodeWithOrder("X-GNO", "0")
.addNodeWithOrder("X-GN", "group0")
.addNodeWithOrder("X-REDUCTION", "0")
.addNodeWithOrder("REV", "20081031T065854Z");
verifier.verify(builder.vNodeList.get(0));
}
@@ -1182,16 +1103,16 @@ public class VCardImportTests extends AndroidTestCase {
// Though Japanese careers append ";;;;" at the end of the value of "SOUND",
// vCard 2.1/3.0 specification does not allow multiple values.
// Do not need to handle it as multiple values.
PropertyNodesVerifier verifier = new PropertyNodesVerifier()
.addPropertyNode("VERSION", "2.1", null, null, null, null, null)
.addPropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
.addNodeWithOrder("VERSION", "2.1", null, null, null, null, null)
.addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9", "", "", "", ""),
null, contentValuesForShiftJis, null, null)
.addPropertyNode("SOUND", "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E;;;;",
.addNodeWithOrder("SOUND", "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E;;;;",
null, null, contentValuesForShiftJis,
new HashSet<String>(Arrays.asList("X-IRMC-N")), null)
.addPropertyNode("TEL", "0300000000", null, null, null,
new HashSet<String>(Arrays.asList("VOICE", "PREF")), null);
new TypeSet("X-IRMC-N"), null)
.addNodeWithOrder("TEL", "0300000000", null, null, null,
new TypeSet("VOICE", "PREF"), null);
verifier.verify(builder.vNodeList.get(0));
}
@@ -1257,19 +1178,19 @@ public class VCardImportTests extends AndroidTestCase {
ContentValues contentValuesForQP = new ContentValues();
contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
contentValuesForQP.put("CHARSET", "SHIFT_JIS");
PropertyNodesVerifier verifier = new PropertyNodesVerifier()
.addPropertyNode("VERSION", "2.1", null, null, null, null, null)
.addPropertyNode("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
.addNodeWithOrder("VERSION", "2.1")
.addNodeWithOrder("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
Arrays.asList("\u5B89\u85E4", "\u30ED\u30A4\u30C9\u0031",
"", "", ""),
null, contentValuesForShiftJis, null, null)
.addPropertyNode("FN", "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031",
.addNodeWithOrder("FN", "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031",
null, null, contentValuesForShiftJis, null, null)
.addPropertyNode("SOUND",
.addNodeWithOrder("SOUND",
"\uFF71\uFF9D\uFF84\uFF9E\uFF73;\uFF9B\uFF72\uFF84\uFF9E\u0031;;;",
null, null, contentValuesForShiftJis,
new HashSet<String>(Arrays.asList("X-IRMC-N")), null)
.addPropertyNode("ADR",
new TypeSet("X-IRMC-N"), null)
.addNodeWithOrder("ADR",
";\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
"\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
"\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC\u0036" +
@@ -1279,8 +1200,8 @@ public class VCardImportTests extends AndroidTestCase {
"\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
"\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
"\u0036\u968E", "", "", "", "150-8512", ""),
null, contentValuesForQP, new HashSet<String>(Arrays.asList("HOME")), null)
.addPropertyNode("NOTE", "\u30E1\u30E2", null, null, contentValuesForQP, null, null);
null, contentValuesForQP, new TypeSet("HOME"), null)
.addNodeWithOrder("NOTE", "\u30E1\u30E2", null, null, contentValuesForQP, null, null);
verifier.verify(builder.vNodeList.get(0));
}
@@ -1329,60 +1250,48 @@ public class VCardImportTests extends AndroidTestCase {
assertEquals(3, builder.vNodeList.size());
ContentValues contentValuesForShiftJis = new ContentValues();
contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
PropertyNodesVerifier verifier = new PropertyNodesVerifier()
.addPropertyNode("VERSION", "2.1", null, null, null, null, null)
.addPropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
.addNodeWithOrder("VERSION", "2.1")
.addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0033", "", "", "", ""),
null, contentValuesForShiftJis, null, null)
.addPropertyNode("SOUND",
.addNodeWithOrder("SOUND",
"\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033;;;;",
null, null, contentValuesForShiftJis,
new HashSet<String>(Arrays.asList("X-IRMC-N")), null)
.addPropertyNode("TEL", "9", null, null, null,
new HashSet<String>(Arrays.asList("X-NEC-SECRET")), null)
.addPropertyNode("TEL", "10", null, null, null,
new HashSet<String>(Arrays.asList("X-NEC-HOTEL")), null)
.addPropertyNode("TEL", "11", null, null, null,
new HashSet<String>(Arrays.asList("X-NEC-SCHOOL")), null)
.addPropertyNode("TEL", "12", null, null, null,
new HashSet<String>(Arrays.asList("FAX", "HOME")), null);
new TypeSet("X-IRMC-N"), null)
.addNodeWithOrder("TEL", "9", new TypeSet("X-NEC-SECRET"))
.addNodeWithOrder("TEL", "10", new TypeSet("X-NEC-HOTEL"))
.addNodeWithOrder("TEL", "11", new TypeSet("X-NEC-SCHOOL"))
.addNodeWithOrder("TEL", "12", new TypeSet("FAX", "HOME"));
verifier.verify(builder.vNodeList.get(0));
verifier = new PropertyNodesVerifier()
.addPropertyNode("VERSION", "2.1", null, null, null, null, null)
.addPropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
verifier = new PropertyNodesVerifier(this)
.addNodeWithOrder("VERSION", "2.1")
.addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0034", "", "", "", ""),
null, contentValuesForShiftJis, null, null)
.addPropertyNode("SOUND",
.addNodeWithOrder("SOUND",
"\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034;;;;",
null, null, contentValuesForShiftJis,
new HashSet<String>(Arrays.asList("X-IRMC-N")), null)
.addPropertyNode("TEL", "13", null, null, null,
new HashSet<String>(Arrays.asList("MODEM")), null)
.addPropertyNode("TEL", "14", null, null, null,
new HashSet<String>(Arrays.asList("PAGER")), null)
.addPropertyNode("TEL", "15", null, null, null,
new HashSet<String>(Arrays.asList("X-NEC-FAMILY")), null)
.addPropertyNode("TEL", "16", null, null, null,
new HashSet<String>(Arrays.asList("X-NEC-GIRL")), null);
new TypeSet("X-IRMC-N"), null)
.addNodeWithOrder("TEL", "13", new TypeSet("MODEM"))
.addNodeWithOrder("TEL", "14", new TypeSet("PAGER"))
.addNodeWithOrder("TEL", "15", new TypeSet("X-NEC-FAMILY"))
.addNodeWithOrder("TEL", "16", new TypeSet("X-NEC-GIRL"));
verifier.verify(builder.vNodeList.get(1));
verifier = new PropertyNodesVerifier()
.addPropertyNode("VERSION", "2.1", null, null, null, null, null)
.addPropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
verifier = new PropertyNodesVerifier(this)
.addNodeWithOrder("VERSION", "2.1")
.addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0035", "", "", "", ""),
null, contentValuesForShiftJis, null, null)
.addPropertyNode("SOUND",
.addNodeWithOrder("SOUND",
"\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035;;;;",
null, null, contentValuesForShiftJis,
new HashSet<String>(Arrays.asList("X-IRMC-N")), null)
.addPropertyNode("TEL", "17", null, null, null,
new HashSet<String>(Arrays.asList("X-NEC-BOY")), null)
.addPropertyNode("TEL", "18", null, null, null,
new HashSet<String>(Arrays.asList("X-NEC-FRIEND")), null)
.addPropertyNode("TEL", "19", null, null, null,
new HashSet<String>(Arrays.asList("X-NEC-PHS")), null)
.addPropertyNode("TEL", "20", null, null, null,
new HashSet<String>(Arrays.asList("X-NEC-RESTAURANT")), null);
new TypeSet("X-IRMC-N"), null)
.addNodeWithOrder("TEL", "17", new TypeSet("X-NEC-BOY"))
.addNodeWithOrder("TEL", "18", new TypeSet("X-NEC-FRIEND"))
.addNodeWithOrder("TEL", "19", new TypeSet("X-NEC-PHS"))
.addNodeWithOrder("TEL", "20", new TypeSet("X-NEC-RESTAURANT"));
verifier.verify(builder.vNodeList.get(2));
}
}

View File

@@ -190,6 +190,7 @@ public class VNodeBuilder implements VCardBuilder {
private String handleOneValue(String value, String targetCharset, String encoding) {
if (encoding != null) {
encoding = encoding.toUpperCase();
if (encoding.equals("BASE64") || encoding.equals("B")) {
// Assume BASE64 is used only when the number of values is 1.
mCurrentPropNode.propValue_bytes =