blob: af8b718a727dca16beb91e942157fece26ff29bd [file] [log] [blame]
/*
* 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.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.ContactStruct;
import android.pim.vcard.EntryCommitter;
import android.pim.vcard.EntryHandler;
import android.pim.vcard.VCardBuilder;
import android.pim.vcard.VCardBuilderCollection;
import android.pim.vcard.VCardComposer;
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.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Nickname;
import android.provider.ContactsContract.CommonDataKinds.Note;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.CommonDataKinds.Relation;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
import android.test.AndroidTestCase;
import android.test.mock.MockContentResolver;
import android.test.mock.MockContext;
import android.test.mock.MockCursor;
import android.text.TextUtils;
import junit.framework.TestCase;
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.HashMap;
import java.util.HashSet;
import java.util.Iterator;
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;
/**
* 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");
}
}
class CustomMockContext extends MockContext {
final ContentResolver mResolver;
public CustomMockContext(ContentResolver resolver) {
mResolver = resolver;
}
@Override
public ContentResolver getContentResolver() {
return mResolver;
}
}
/**
* BaseClass for vCard unit tests with utility classes.
* Please do not add each unit test here.
*/
/* package */ class VCardTestsBase extends AndroidTestCase {
public static final int V21 = VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8;
public static final int V30 = VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8;
// Do not modify these during tests.
protected final ContentValues mContentValuesForQP;
protected final ContentValues mContentValuesForSJis;
protected final ContentValues mContentValuesForUtf8;
protected final ContentValues mContentValuesForQPAndSJis;
protected final ContentValues mContentValuesForQPAndUtf8;
protected final ContentValues mContentValuesForBase64V21;
protected final ContentValues mContentValuesForBase64V30;
public VCardTestsBase() {
super();
mContentValuesForQP = new ContentValues();
mContentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
mContentValuesForSJis = new ContentValues();
mContentValuesForSJis.put("CHARSET", "SHIFT_JIS");
mContentValuesForUtf8 = new ContentValues();
mContentValuesForUtf8.put("CHARSET", "UTF-8");
mContentValuesForQPAndSJis = new ContentValues();
mContentValuesForQPAndSJis.put("ENCODING", "QUOTED-PRINTABLE");
mContentValuesForQPAndSJis.put("CHARSET", "SHIFT_JIS");
mContentValuesForQPAndUtf8 = new ContentValues();
mContentValuesForQPAndUtf8.put("ENCODING", "QUOTED-PRINTABLE");
mContentValuesForQPAndUtf8.put("CHARSET", "UTF-8");
mContentValuesForBase64V21 = new ContentValues();
mContentValuesForBase64V21.put("ENCODING", "BASE64");
mContentValuesForBase64V30 = new ContentValues();
mContentValuesForBase64V30.put("ENCODING", "b");
}
public class ImportTestResolver extends MockContentResolver {
ImportTestProvider mProvider = new ImportTestProvider();
@Override
public ContentProviderResult[] applyBatch(String authority,
ArrayList<ContentProviderOperation> operations) {
equalsString(authority, RawContacts.CONTENT_URI.toString());
return mProvider.applyBatch(operations);
}
public void addExpectedContentValues(ContentValues expectedContentValues) {
mProvider.addExpectedContentValues(expectedContentValues);
}
public void verify() {
mProvider.verify();
}
}
private static final Set<String> sKnownMimeTypeSet =
new HashSet<String>(Arrays.asList(StructuredName.CONTENT_ITEM_TYPE,
Nickname.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE,
Email.CONTENT_ITEM_TYPE, StructuredPostal.CONTENT_ITEM_TYPE,
Im.CONTENT_ITEM_TYPE, Organization.CONTENT_ITEM_TYPE,
Event.CONTENT_ITEM_TYPE, Photo.CONTENT_ITEM_TYPE,
Note.CONTENT_ITEM_TYPE, Website.CONTENT_ITEM_TYPE,
Relation.CONTENT_ITEM_TYPE, Event.CONTENT_ITEM_TYPE,
GroupMembership.CONTENT_ITEM_TYPE));
public class ImportTestProvider extends MockContentProvider {
final Map<String, Collection<ContentValues>> mMimeTypeToExpectedContentValues;
public ImportTestProvider() {
mMimeTypeToExpectedContentValues =
new HashMap<String, Collection<ContentValues>>();
for (String acceptanbleMimeType : sKnownMimeTypeSet) {
// Do not use HashSet since the current implementation changes the content of
// ContentValues after the insertion, which make the result of hashCode()
// changes...
mMimeTypeToExpectedContentValues.put(
acceptanbleMimeType, new ArrayList<ContentValues>());
}
}
public void addExpectedContentValues(ContentValues expectedContentValues) {
final String mimeType = expectedContentValues.getAsString(Data.MIMETYPE);
if (!sKnownMimeTypeSet.contains(mimeType)) {
fail(String.format(
"Unknow MimeType %s in the test code. Test code should be broken.",
mimeType));
}
final Collection<ContentValues> contentValuesCollection =
mMimeTypeToExpectedContentValues.get(mimeType);
contentValuesCollection.add(expectedContentValues);
}
@Override
public ContentProviderResult[] applyBatch(
ArrayList<ContentProviderOperation> operations) {
if (operations == null) {
fail("There is no operation.");
}
final int size = operations.size();
ContentProviderResult[] fakeResultArray = new ContentProviderResult[size];
for (int i = 0; i < size; i++) {
Uri uri = Uri.withAppendedPath(RawContacts.CONTENT_URI, String.valueOf(i));
fakeResultArray[i] = new ContentProviderResult(uri);
}
for (int i = 0; i < size; i++) {
ContentProviderOperation operation = operations.get(i);
ContentValues contentValues = operation.resolveValueBackReferences(
fakeResultArray, i);
}
for (int i = 0; i < size; i++) {
ContentProviderOperation operation = operations.get(i);
ContentValues actualContentValues = operation.resolveValueBackReferences(
fakeResultArray, i);
final Uri uri = operation.getUri();
if (uri.equals(RawContacts.CONTENT_URI)) {
assertNull(actualContentValues.get(RawContacts.ACCOUNT_NAME));
assertNull(actualContentValues.get(RawContacts.ACCOUNT_TYPE));
} else if (uri.equals(Data.CONTENT_URI)) {
final String mimeType = actualContentValues.getAsString(Data.MIMETYPE);
if (!sKnownMimeTypeSet.contains(mimeType)) {
fail(String.format(
"Unknown MimeType %s. Probably added after developing this test",
mimeType));
}
// Remove data meaningless in this unit tests.
// Specifically, Data.DATA1 - DATA7 are set to null or empty String
// regardless of the input, but it may change depending on how
// resolver-related code handles it.
// Here, we ignore these implementation-dependent specs and
// just check whether vCard importer correctly inserts rellevent data.
Set<String> keyToBeRemoved = new HashSet<String>();
for (Entry<String, Object> entry : actualContentValues.valueSet()) {
Object value = entry.getValue();
if (value == null || TextUtils.isEmpty(value.toString())) {
keyToBeRemoved.add(entry.getKey());
}
}
for (String key: keyToBeRemoved) {
actualContentValues.remove(key);
}
/* for testing
Log.d("@@@",
String.format("MimeType: %s, data: %s",
mimeType, actualContentValues.toString())); */
// Remove RAW_CONTACT_ID entry just for safety, since we do not care
// how resolver-related code handles the entry in this unit test,
if (actualContentValues.containsKey(Data.RAW_CONTACT_ID)) {
actualContentValues.remove(Data.RAW_CONTACT_ID);
}
final Collection<ContentValues> contentValuesCollection =
mMimeTypeToExpectedContentValues.get(mimeType);
if (contentValuesCollection.isEmpty()) {
fail("ContentValues for MimeType " + mimeType
+ " is not expected at all (" + actualContentValues + ")");
}
boolean checked = false;
for (ContentValues expectedContentValues : contentValuesCollection) {
/*for testing
Log.d("@@@", "expected: "
+ convertToEasilyReadableString(expectedContentValues));
Log.d("@@@", "actual : "
+ convertToEasilyReadableString(actualContentValues));*/
if (equalsForContentValues(expectedContentValues,
actualContentValues)) {
assertTrue(contentValuesCollection.remove(expectedContentValues));
checked = true;
break;
}
}
if (!checked) {
final StringBuilder builder = new StringBuilder();
builder.append("Unexpected: ");
builder.append(convertToEasilyReadableString(actualContentValues));
builder.append("\nExpected: ");
for (ContentValues expectedContentValues : contentValuesCollection) {
builder.append(convertToEasilyReadableString(expectedContentValues));
}
fail(builder.toString());
}
} else {
fail("Unexpected Uri has come: " + uri);
}
} // for (int i = 0; i < size; i++) {
return null;
}
public void verify() {
StringBuilder builder = new StringBuilder();
for (Collection<ContentValues> contentValuesCollection :
mMimeTypeToExpectedContentValues.values()) {
for (ContentValues expectedContentValues: contentValuesCollection) {
builder.append(convertToEasilyReadableString(expectedContentValues));
builder.append("\n");
}
}
if (builder.length() > 0) {
final String failMsg =
"There is(are) remaining expected ContentValues instance(s): \n"
+ builder.toString();
fail(failMsg);
}
}
}
class ImportVerifierElem {
private final ImportTestResolver mResolver;
private final EntryHandler mHandler;
public ImportVerifierElem() {
mResolver = new ImportTestResolver();
mHandler = new EntryCommitter(mResolver);
}
public ContentValuesBuilder addExpected(String mimeType) {
ContentValues contentValues = new ContentValues();
contentValues.put(Data.MIMETYPE, mimeType);
mResolver.addExpectedContentValues(contentValues);
return new ContentValuesBuilder(contentValues);
}
public void verify(int resId, int vCardType)
throws IOException, VCardException {
verify(getContext().getResources().openRawResource(resId), vCardType);
}
public void verify(InputStream is, int vCardType) throws IOException, VCardException {
final VCardParser vCardParser;
if (VCardConfig.isV30(vCardType)) {
vCardParser = new VCardParser_V30(true); // use StrictParsing
} else {
vCardParser = new VCardParser_V21();
}
VCardDataBuilder builder =
new VCardDataBuilder(null, null, false, vCardType, null);
builder.addEntryHandler(mHandler);
try {
vCardParser.parse(is, builder);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
verifyResolver();
}
public void verifyResolver() {
mResolver.verify();
}
public void onParsingStart() {
mHandler.onParsingStart();
}
public void onEntryCreated(ContactStruct entry) {
mHandler.onEntryCreated(entry);
}
public void onParsingEnd() {
mHandler.onParsingEnd();
}
}
class ImportVerifier implements EntryHandler {
private List<ImportVerifierElem> mImportVerifierElemList =
new ArrayList<ImportVerifierElem>();
private int mIndex;
public ImportVerifierElem addImportVerifierElem() {
ImportVerifierElem importVerifier = new ImportVerifierElem();
mImportVerifierElemList.add(importVerifier);
return importVerifier;
}
public void verify(int resId, int vCardType) throws IOException, VCardException {
verify(getContext().getResources().openRawResource(resId), vCardType);
}
public void verify(int resId, int vCardType, final VCardParser vCardParser)
throws IOException, VCardException {
verify(getContext().getResources().openRawResource(resId), vCardType, vCardParser);
}
public void verify(InputStream is, int vCardType) throws IOException, VCardException {
final VCardParser vCardParser;
if (VCardConfig.isV30(vCardType)) {
vCardParser = new VCardParser_V30(true); // use StrictParsing
} else {
vCardParser = new VCardParser_V21();
}
verify(is, vCardType, vCardParser);
}
public void verify(InputStream is, int vCardType, final VCardParser vCardParser)
throws IOException, VCardException {
VCardDataBuilder builder =
new VCardDataBuilder(null, null, false, vCardType, null);
builder.addEntryHandler(this);
try {
vCardParser.parse(is, builder);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
}
public void onParsingStart() {
for (ImportVerifierElem elem : mImportVerifierElemList) {
elem.onParsingStart();
}
}
public void onEntryCreated(ContactStruct entry) {
assertTrue(mIndex < mImportVerifierElemList.size());
mImportVerifierElemList.get(mIndex).onEntryCreated(entry);
mIndex++;
}
public void onParsingEnd() {
for (ImportVerifierElem elem : mImportVerifierElemList) {
elem.onParsingEnd();
elem.verifyResolver();
}
}
}
public class ExportTestResolver extends MockContentResolver {
ExportTestProvider mProvider = new ExportTestProvider();
public ExportTestResolver() {
addProvider(VCardComposer.VCARD_TEST_AUTHORITY, mProvider);
addProvider(RawContacts.CONTENT_URI.getAuthority(), mProvider);
}
public ContactEntry buildContactEntry() {
return mProvider.buildInputEntry();
}
}
public static class MockEntityIterator implements EntityIterator {
List<Entity> mEntityList;
Iterator<Entity> mIterator;
public MockEntityIterator(List<ContentValues> contentValuesList) {
mEntityList = new ArrayList<Entity>();
Entity entity = new Entity(new ContentValues());
for (ContentValues contentValues : contentValuesList) {
entity.addSubValue(Data.CONTENT_URI, contentValues);
}
mEntityList.add(entity);
mIterator = mEntityList.iterator();
}
public boolean hasNext() {
return mIterator.hasNext();
}
public Entity next() {
return mIterator.next();
}
public void reset() {
mIterator = mEntityList.iterator();
}
public void close() {
}
}
/**
* Represents one contact, which should contain multiple ContentValues like
* StructuredName, Email, etc.
*/
static class ContactEntry {
private final List<ContentValues> mContentValuesList = new ArrayList<ContentValues>();
public ContentValuesBuilder buildData(String mimeType) {
ContentValues contentValues = new ContentValues();
contentValues.put(Data.MIMETYPE, mimeType);
mContentValuesList.add(contentValues);
return new ContentValuesBuilder(contentValues);
}
public List<ContentValues> getList() {
return mContentValuesList;
}
}
class ExportTestProvider extends MockContentProvider {
ArrayList<ContactEntry> mContactEntryList = new ArrayList<ContactEntry>();
public ContactEntry buildInputEntry() {
ContactEntry contactEntry = new ContactEntry();
mContactEntryList.add(contactEntry);
return contactEntry;
}
@Override
public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
String sortOrder) {
assertTrue(uri != null);
assertTrue(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()));
final String authority = uri.getAuthority();
assertTrue(RawContacts.CONTENT_URI.getAuthority().equals(authority));
assertTrue((Data.CONTACT_ID + "=?").equals(selection));
assertEquals(1, selectionArgs.length);
int id = Integer.parseInt(selectionArgs[0]);
assertTrue(id >= 0 && id < mContactEntryList.size());
return new MockEntityIterator(mContactEntryList.get(id).getList());
}
@Override
public Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
assertTrue(VCardComposer.CONTACTS_TEST_CONTENT_URI.equals(uri));
// In this test, following arguments are not supported.
assertNull(selection);
assertNull(selectionArgs);
assertNull(sortOrder);
return new MockCursor() {
int mCurrentPosition = -1;
@Override
public int getCount() {
return mContactEntryList.size();
}
@Override
public boolean moveToFirst() {
mCurrentPosition = 0;
return true;
}
@Override
public boolean moveToNext() {
if (mCurrentPosition < mContactEntryList.size()) {
mCurrentPosition++;
return true;
} else {
return false;
}
}
@Override
public boolean isBeforeFirst() {
return mCurrentPosition < 0;
}
@Override
public boolean isAfterLast() {
return mCurrentPosition >= mContactEntryList.size();
}
@Override
public int getColumnIndex(String columnName) {
assertEquals(Contacts._ID, columnName);
return 0;
}
@Override
public int getInt(int columnIndex) {
assertEquals(0, columnIndex);
assertTrue(mCurrentPosition >= 0
&& mCurrentPosition < mContactEntryList.size());
return mCurrentPosition;
}
@Override
public String getString(int columnIndex) {
return String.valueOf(getInt(columnIndex));
}
@Override
public void close() {
}
};
}
}
class LineVerifierElem {
private final List<String> mExpectedLineList = new ArrayList<String>();
private final boolean mIsV30;
public LineVerifierElem(boolean isV30) {
mIsV30 = isV30;
}
public LineVerifierElem addExpected(final String line) {
if (!TextUtils.isEmpty(line)) {
mExpectedLineList.add(line);
}
return this;
}
public void verify(final String vcard) {
final String[] lineArray = vcard.split("\\r?\\n");
final int length = lineArray.length;
final TestCase testCase = VCardTestsBase.this;
boolean beginExists = false;
boolean endExists = false;
boolean versionExists = false;
for (int i = 0; i < length; i++) {
final String line = lineArray[i];
if (TextUtils.isEmpty(line)) {
continue;
}
if ("BEGIN:VCARD".equalsIgnoreCase(line)) {
if (beginExists) {
testCase.fail("Multiple \"BEGIN:VCARD\" line found");
} else {
beginExists = true;
continue;
}
} else if ("END:VCARD".equalsIgnoreCase(line)) {
if (endExists) {
testCase.fail("Multiple \"END:VCARD\" line found");
} else {
endExists = true;
continue;
}
} else if (
(mIsV30 ? "VERSION:3.0" : "VERSION:2.1").equalsIgnoreCase(line)) {
if (versionExists) {
testCase.fail("Multiple VERSION line + found");
} else {
versionExists = true;
continue;
}
}
if (!beginExists) {
testCase.fail(
"Property other than BEGIN came before BEGIN property: " + line);
} else if (endExists) {
testCase.fail("Property other than END came after END property: " + line);
}
final int index = mExpectedLineList.indexOf(line);
if (index >= 0) {
mExpectedLineList.remove(index);
} else {
testCase.fail("Unexpected line: " + line);
}
}
if (!mExpectedLineList.isEmpty()) {
StringBuffer buffer = new StringBuffer();
for (String expectedLine : mExpectedLineList) {
buffer.append(expectedLine);
buffer.append("\n");
}
testCase.fail("Expected line(s) not found:" + buffer.toString());
}
}
}
class LineVerifier implements VCardComposer.OneEntryHandler {
private final ArrayList<LineVerifierElem> mLineVerifierElemList;
private final boolean mIsV30;
private int index;
public LineVerifier(final boolean isV30) {
mLineVerifierElemList = new ArrayList<LineVerifierElem>();
mIsV30 = isV30;
}
public LineVerifierElem addLineVerifierElem() {
LineVerifierElem lineVerifier = new LineVerifierElem(mIsV30);
mLineVerifierElemList.add(lineVerifier);
return lineVerifier;
}
public void verify(String vcard) {
if (index >= mLineVerifierElemList.size()) {
VCardTestsBase.this.fail("Insufficient number of LineVerifier (" + index + ")");
}
LineVerifierElem lineVerifier = mLineVerifierElemList.get(index);
lineVerifier.verify(vcard);
index++;
}
public boolean onEntryCreated(String vcard) {
verify(vcard);
return true;
}
public boolean onInit(Context context) {
return true;
}
public void onTerminate() {
}
}
class VCardVerifier {
private class VCardVerifierInternal implements VCardComposer.OneEntryHandler {
public boolean onInit(Context context) {
return true;
}
public boolean onEntryCreated(String vcard) {
verifyOneVCard(vcard);
return true;
}
public void onTerminate() {
}
}
private final VCardVerifierInternal mVCardVerifierInternal;
private final ExportTestResolver mResolver;
private final int mVCardType;
private final boolean mIsV30;
// To allow duplication, use list instead of set.
// When null, we don't need to do the verification.
private PropertyNodesVerifier mPropertyNodesVerifier;
private LineVerifier mLineVerificationHandler;
private ImportVerifier mImportVerifier;
public VCardVerifier(ExportTestResolver resolver, int vcardType) {
mVCardVerifierInternal = new VCardVerifierInternal();
mResolver = resolver;
mIsV30 = VCardConfig.isV30(vcardType);
mVCardType = vcardType;
}
public PropertyNodesVerifierElem addPropertyNodesVerifierElem() {
if (mPropertyNodesVerifier == null) {
mPropertyNodesVerifier = new PropertyNodesVerifier(VCardTestsBase.this);
}
PropertyNodesVerifierElem elem =
mPropertyNodesVerifier.addPropertyNodesVerifierElem();
elem.addNodeWithOrder("VERSION", (mIsV30 ? "3.0" : "2.1"));
return elem;
}
public PropertyNodesVerifierElem addPropertyNodesVerifierElemWithEmptyName() {
PropertyNodesVerifierElem elem = addPropertyNodesVerifierElem();
if (mIsV30) {
elem.addNodeWithOrder("N", "").addNodeWithOrder("FN", "");
}
return elem;
}
public LineVerifierElem addLineVerifier() {
if (mLineVerificationHandler == null) {
mLineVerificationHandler = new LineVerifier(mIsV30);
}
return mLineVerificationHandler.addLineVerifierElem();
}
public ImportVerifierElem addImportVerifier() {
if (mImportVerifier == null) {
mImportVerifier = new ImportVerifier();
}
return mImportVerifier.addImportVerifierElem();
}
private void verifyOneVCard(final String vcard) {
// Log.d("@@@", vcard);
final VCardBuilder builder;
if (mImportVerifier != null) {
final VNodeBuilder vnodeBuilder = mPropertyNodesVerifier;
final VCardDataBuilder vcardDataBuilder =
new VCardDataBuilder(mVCardType);
vcardDataBuilder.addEntryHandler(mImportVerifier);
if (mPropertyNodesVerifier != null) {
builder = new VCardBuilderCollection(Arrays.asList(
mPropertyNodesVerifier, vcardDataBuilder));
} else {
builder = vnodeBuilder;
}
} else {
if (mPropertyNodesVerifier != null) {
builder = mPropertyNodesVerifier;
} else {
return;
}
}
final VCardParser parser =
(mIsV30 ? new VCardParser_V30(true) : new VCardParser_V21());
final TestCase testCase = VCardTestsBase.this;
InputStream is = null;
try {
String charset =
(VCardConfig.usesShiftJis(mVCardType) ? "SHIFT_JIS" : "UTF-8");
is = new ByteArrayInputStream(vcard.getBytes(charset));
testCase.assertEquals(true, parser.parse(is, null, builder));
} catch (IOException e) {
testCase.fail("Unexpected IOException: " + e.getMessage());
} catch (VCardException e) {
testCase.fail("Unexpected VCardException: " + e.getMessage());
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
}
public void verify() {
VCardComposer composer =
new VCardComposer(new CustomMockContext(mResolver), mVCardType);
composer.addHandler(mLineVerificationHandler);
composer.addHandler(mVCardVerifierInternal);
if (!composer.init(VCardComposer.CONTACTS_TEST_CONTENT_URI, null, null, null)) {
fail("init() failed. Reason: " + composer.getErrorReason());
}
assertFalse(composer.isAfterLast());
try {
while (!composer.isAfterLast()) {
assertTrue(composer.createOneEntry());
}
} finally {
composer.terminate();
}
}
}
/**
* Utility method to print ContentValues whose content is printed with sorted keys.
*/
private static String convertToEasilyReadableString(ContentValues contentValues) {
if (contentValues == null) {
return "null";
}
String mimeTypeValue = "";
SortedMap<String, String> sortedMap = new TreeMap<String, String>();
for (Entry<String, Object> entry : contentValues.valueSet()) {
final String key = entry.getKey();
final Object value = entry.getValue();
final String valueString = (value != null ? value.toString() : null);
if (Data.MIMETYPE.equals(key)) {
mimeTypeValue = valueString;
} else {
assertNotNull(key);
sortedMap.put(key, valueString);
}
}
StringBuilder builder = new StringBuilder();
builder.append(Data.MIMETYPE);
builder.append('=');
builder.append(mimeTypeValue);
for (Entry<String, String> entry : sortedMap.entrySet()) {
final String key = entry.getKey();
final String value = entry.getValue();
builder.append(' ');
builder.append(key);
builder.append('=');
builder.append(value);
}
return builder.toString();
}
private static boolean equalsForContentValues(
ContentValues expected, ContentValues actual) {
if (expected == actual) {
return true;
} else if (expected == null || actual == null || expected.size() != actual.size()) {
return false;
}
for (Entry<String, Object> entry : expected.valueSet()) {
final String key = entry.getKey();
final Object value = entry.getValue();
if (!actual.containsKey(key)) {
return false;
}
if (value instanceof byte[]) {
Object actualValue = actual.get(key);
if (!Arrays.equals((byte[])value, (byte[])actualValue)) {
return false;
}
} else if (!value.equals(actual.get(key))) {
return false;
}
}
return true;
}
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);
}
}
}