From 1301341f13fab2ced33a6f4dc0f0e8f609217105 Mon Sep 17 00:00:00 2001 From: Daisuke Miyakawa Date: Tue, 5 Jan 2010 12:38:52 +0900 Subject: [PATCH] Fix test breakage in vCard exporter. Due to the change Iae8dbac1, all tests for vCard exporeter has failed. This change fixes the breakage by using a kind of dirty Dependency Injection. Current test framework for vCard exporter strongly depends on the assumption that ContentValues objects are able to be directly passed to objects which use ContentResolver, while the change above disabled the feature by removing queryEntities(). This change makes VCardComposer forcibly uses queryEntities() via Reflection. I agree that this change is not so clean, but works fine for now. --- .../java/android/pim/vcard/VCardComposer.java | 52 +++++++++++++++---- .../unit_tests/vcard/ExportTestResolver.java | 35 ++++++++++++- .../unit_tests/vcard/VCardVerifier.java | 31 ++++++++++- 3 files changed, 105 insertions(+), 13 deletions(-) diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java index 4eaea6a77ed13..389c9f4f05539 100644 --- a/core/java/android/pim/vcard/VCardComposer.java +++ b/core/java/android/pim/vcard/VCardComposer.java @@ -54,6 +54,7 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; +import java.lang.reflect.Method; import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; import java.util.Arrays; @@ -197,7 +198,7 @@ public class VCardComposer { if (mIsDoCoMo) { try { // Create one empty entry. - mWriter.write(createOneEntryInternal("-1")); + mWriter.write(createOneEntryInternal("-1", null)); } catch (IOException e) { Log.e(LOG_TAG, "IOException occurred during exportOneContactData: " @@ -428,6 +429,14 @@ public class VCardComposer { } public boolean createOneEntry() { + return createOneEntry(null); + } + + /** + * @param getEntityIteratorMethod For Dependency Injection. + * @hide just for testing. + */ + public boolean createOneEntry(Method getEntityIteratorMethod) { if (mCursor == null || mCursor.isAfterLast()) { mErrorReason = FAILURE_REASON_NOT_INITIALIZED; return false; @@ -439,7 +448,8 @@ public class VCardComposer { vcard = createOneCallLogEntryInternal(); } else { if (mIdColumn >= 0) { - vcard = createOneEntryInternal(mCursor.getString(mIdColumn)); + vcard = createOneEntryInternal(mCursor.getString(mIdColumn), + getEntityIteratorMethod); } else { Log.e(LOG_TAG, "Incorrect mIdColumn: " + mIdColumn); return true; @@ -475,7 +485,8 @@ public class VCardComposer { return true; } - private String createOneEntryInternal(final String contactId) { + private String createOneEntryInternal(final String contactId, + Method getEntityIteratorMethod) { final Map> contentValuesListMap = new HashMap>(); // The resolver may return the entity iterator with no data. It is possiible. @@ -484,13 +495,34 @@ public class VCardComposer { boolean dataExists = false; EntityIterator entityIterator = null; try { - final Uri uri = RawContacts.CONTENT_URI.buildUpon() - .appendEncodedPath(contactId) - .appendEncodedPath(RawContacts.Entity.CONTENT_DIRECTORY) - .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1") - .build(); - entityIterator = RawContacts.newEntityIterator(mContentResolver.query( - uri, null, null, null, null)); + + if (getEntityIteratorMethod != null) { + try { + final Uri uri = RawContacts.CONTENT_URI.buildUpon() + .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1") + .build(); + final String selection = Data.CONTACT_ID + "=?"; + final String[] selectionArgs = new String[] {contactId}; + entityIterator = (EntityIterator)getEntityIteratorMethod.invoke(null, + mContentResolver, uri, selection, selectionArgs, null); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + final Uri uri = RawContacts.CONTENT_URI.buildUpon() + .appendEncodedPath(contactId) + .appendEncodedPath(RawContacts.Entity.CONTENT_DIRECTORY) + .appendQueryParameter(Data.FOR_EXPORT_ONLY, "1") + .build(); + entityIterator = RawContacts.newEntityIterator(mContentResolver.query( + uri, null, null, null, null)); + } + + if (entityIterator == null) { + Log.e(LOG_TAG, "EntityIterator is null"); + return ""; + } + dataExists = entityIterator.hasNext(); while (entityIterator.hasNext()) { Entity entity = entityIterator.next(); diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/ExportTestResolver.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/ExportTestResolver.java index 38aed6f5cdd8d..a76dfd8b69114 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/ExportTestResolver.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/ExportTestResolver.java @@ -110,8 +110,41 @@ import java.util.List; return contactEntry; } + /** + *

+ * An old method which had existed but was removed from ContentResolver. + *

+ *

+ * We still keep using this method since we don't have a propeer way to know + * which value in the ContentValue corresponds to the entry in Contacts database. + *

+ *

+ * Detail: + * There's an easy way to know which index "family name" corresponds to, via + * {@link android.provider.ContactsContract}. + * FAMILY_NAME equals DATA3, so the corresponding index + * for "family name" should be 2 (note that index is 0-origin). + * However, we cannot know what the index 2 corresponds to; it may be "family name", + * "label" for now, but may be the other some column in the future. We don't have + * convenient way to know the original data structure. + *

+ */ + public EntityIterator queryEntities(Uri uri, + String selection, String[] selectionArgs, String sortOrder) { + mTestCase.assertTrue(uri != null); + mTestCase.assertTrue(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())); + final String authority = uri.getAuthority(); + mTestCase.assertTrue(RawContacts.CONTENT_URI.getAuthority().equals(authority)); + mTestCase.assertTrue((Data.CONTACT_ID + "=?").equals(selection)); + mTestCase.assertEquals(1, selectionArgs.length); + final int id = Integer.parseInt(selectionArgs[0]); + mTestCase.assertTrue(id >= 0 && id < mContactEntryList.size()); + + return new MockEntityIterator(mContactEntryList.get(id).getList()); + } + @Override - public Cursor query(Uri uri, String[] projection, + public Cursor query(Uri uri,String[] projection, String selection, String[] selectionArgs, String sortOrder) { mTestCase.assertTrue(VCardComposer.CONTACTS_TEST_CONTENT_URI.equals(uri)); // In this test, following arguments are not supported. diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardVerifier.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardVerifier.java index e5cdf63f66b7b..4b97750aa74d1 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardVerifier.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardVerifier.java @@ -15,8 +15,11 @@ */ package com.android.unit_tests.vcard; +import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; +import android.content.EntityIterator; +import android.net.Uri; import android.pim.vcard.VCardComposer; import android.pim.vcard.VCardConfig; import android.pim.vcard.VCardEntryConstructor; @@ -32,6 +35,7 @@ import android.test.mock.MockContext; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Method; import java.util.Arrays; /* package */ class CustomMockContext extends MockContext { @@ -259,8 +263,24 @@ import java.util.Arrays; } } + public static EntityIterator mockGetEntityIteratorMethod( + final ContentResolver resolver, + final Uri uri, final String selection, + final String[] selectionArgs, final String sortOrder) { + final ContentProvider provider = + resolver.acquireContentProviderClient(uri).getLocalContentProvider(); + return ((ExportTestProvider)provider).queryEntities( + uri, selection, selectionArgs, sortOrder); + } + + private Method getMockGetEntityIteratorMethod() + throws SecurityException, NoSuchMethodException { + return this.getClass().getMethod("mockGetEntityIteratorMethod", + ContentResolver.class, Uri.class, String.class, String[].class, String.class); + } + private void verifyForExportTest() { - VCardComposer composer = + final VCardComposer composer = new VCardComposer(new CustomMockContext(mExportTestResolver), mVCardType); composer.addHandler(mLineVerifier); composer.addHandler(mVCardVerifierInternal); @@ -270,7 +290,14 @@ import java.util.Arrays; mTestCase.assertFalse(composer.isAfterLast()); try { while (!composer.isAfterLast()) { - mTestCase.assertTrue(composer.createOneEntry()); + try { + final Method mockGetEntityIteratorMethod = getMockGetEntityIteratorMethod(); + mTestCase.assertTrue( + composer.createOneEntry(getMockGetEntityIteratorMethod())); + } catch (Exception e) { + e.printStackTrace(); + mTestCase.fail(); + } } } finally { composer.terminate();