FileDocCategorySizeDatePackage
ContactsSyncAdapterTest.javaAPI DocAndroid 1.5 API38854Wed May 06 22:42:48 BST 2009com.android.providers.contacts

ContactsSyncAdapterTest

public class ContactsSyncAdapterTest extends android.test.ProviderTestCase

Fields Summary
private static final String
ACCOUNT
private MockSyncContext
mMockSyncContext
private ContactsSyncAdapter
mSyncAdapter
Constructors Summary
public ContactsSyncAdapterTest()


      
        super(ContactsProvider.class, Contacts.AUTHORITY);
    
Methods Summary
private static voidaddEmail(com.google.wireless.gdata.contacts.data.ContactEntry entry, java.lang.String address, boolean isPrimary, byte rel, java.lang.String label)

        EmailAddress item = new EmailAddress();
        item.setAddress(address);
        item.setIsPrimary(isPrimary);
        item.setType(rel);
        item.setLabel(label);
        entry.addEmailAddress(item);
    
private static voidaddExtendedProperty(com.google.wireless.gdata.contacts.data.ContactEntry entry, java.lang.String name, java.lang.String value, java.lang.String blob)

        ExtendedProperty extendedProperty = new ExtendedProperty();
        extendedProperty.setName(name);
        extendedProperty.setValue(value);
        extendedProperty.setXmlBlob(blob);
        entry.addExtendedProperty(extendedProperty);
    
private static voidaddGroupMembership(com.google.wireless.gdata.contacts.data.ContactEntry p, java.lang.String account, java.lang.String groupId)

        GroupMembershipInfo groupInfo = new GroupMembershipInfo();
        final String serverId =
                ContactsSyncAdapter.getCanonicalGroupsFeedForAccount(account) + "/" + groupId;
        groupInfo.setGroup(serverId);
        p.addGroup(groupInfo);
    
private static voidaddIm(com.google.wireless.gdata.contacts.data.ContactEntry entry, java.lang.String address, byte protocol, java.lang.String protocolString, boolean isPrimary, byte rel, java.lang.String label)

        ImAddress item = new ImAddress();
        item.setAddress(address);
        item.setProtocolPredefined(protocol);
        item.setProtocolCustom(protocolString);
        item.setLabel(label);
        item.setType(rel);
        item.setIsPrimary(isPrimary);
        entry.addImAddress(item);
    
private static voidaddOrganization(com.google.wireless.gdata.contacts.data.ContactEntry entry, java.lang.String name, java.lang.String title, boolean isPrimary, byte type, java.lang.String label)

        Organization organization = new Organization();
        organization.setName(name);
        organization.setTitle(title);
        organization.setIsPrimary(isPrimary);
        organization.setType(type);
        organization.setLabel(label);
        entry.addOrganization(organization);
    
private android.net.UriaddPerson(ContactsProvider provider, java.lang.String name, java.lang.String account, java.lang.String syncId)

        ContentValues values = new ContentValues();
        values.put(People.NAME, name);
        values.put(People._SYNC_ACCOUNT, account);
        values.put(People._SYNC_ID, syncId);
        return provider.insert(People.CONTENT_URI, values);
    
private static voidaddPhoneNumber(com.google.wireless.gdata.contacts.data.ContactEntry entry, java.lang.String number, boolean isPrimary, byte rel, java.lang.String label)

        PhoneNumber phoneNumber = new PhoneNumber();
        phoneNumber.setPhoneNumber(number);
        phoneNumber.setIsPrimary(isPrimary);
        phoneNumber.setType(rel);
        phoneNumber.setLabel(label);
        entry.addPhoneNumber(phoneNumber);
    
private static voidaddPostal(com.google.wireless.gdata.contacts.data.ContactEntry entry, java.lang.String address, boolean isPrimary, byte rel, java.lang.String label)

        PostalAddress item = new PostalAddress();
        item.setValue(address);
        item.setType(rel);
        item.setLabel(label);
        item.setIsPrimary(isPrimary);
        entry.addPostalAddress(item);
    
private voidassertByteArrayEquals(byte[] expected, byte[] actual, int lengthOfActual)

        assertEquals(expected.length, lengthOfActual);
        for (int i = 0; i < expected.length; i++) assertEquals(expected[i], actual[i]);
    
private voidcheckCursorToEntry(ContactsProvider provider, com.google.wireless.gdata.contacts.data.ContactEntry entry)

        copyTempProviderToReal(provider);
        final ContentProvider clientDiffsProvider = getClientDiffs();

        Cursor cursor = ContactsSyncAdapter.getCursorForTableImpl(clientDiffsProvider,
                entry.getClass());
        try {
            assertTrue(cursor.moveToFirst());
            assertEquals(dumpCursor(cursor), 1, cursor.getCount());
            ContactEntry newEntry = new ContactEntry();
            String editUrl = ContactsSyncAdapter.cursorToEntryImpl(getMockContentResolver(), cursor,
                    newEntry, ACCOUNT);
            entry.setId(null);
            entry.setEditUri(null);
            entry.setLinkEditPhoto(null, null);
            final String expected = entry.toString();
            final String actual = newEntry.toString();
            assertEquals("\nexpected:\n" + expected + "\nactual:\n" + actual, expected, actual);
        } finally {
            cursor.close();
        }
    
voidcheckEntries(ContactsProvider provider, boolean deleted, java.lang.Object entriesAndLocalSyncIds)

        String table;
        String sortOrder = deleted ? "_sync_id" : "name";
        final Entry firstEntry = (Entry)entriesAndLocalSyncIds[0];
        if (firstEntry instanceof GroupEntry) {
            if (deleted) {
                table = ContactsProvider.sDeletedGroupsTable;
            } else {
                table = ContactsProvider.sGroupsTable;
            }
        } else {
            if (deleted) {
                table = ContactsProvider.sDeletedPeopleTable;
            } else {
                table = ContactsProvider.sPeopleTable;
            }
        }
        Cursor cursor;
         cursor = provider.getDatabase().query(table, null, null, null, null, null, sortOrder);
         try {
             for (int i = 0; i < entriesAndLocalSyncIds.length; i += 2) {
                 Entry entry = (Entry)entriesAndLocalSyncIds[i];
                 Long syncLocalId = (Long)entriesAndLocalSyncIds[i+1];
                 if (deleted) {
                     checkNextDeleted(cursor, entry, syncLocalId);
                 } else {
                     if (firstEntry instanceof GroupEntry) {
                         checkNextGroup(cursor, (GroupEntry)entry, null);
                     } else {
                         checkNextPerson(provider, cursor, (ContactEntry)entry, null);
                     }
                 }
             }
             assertTrue(dumpCursor(cursor), cursor.isLast());
         } finally {
             cursor.close();
         }
    
private static voidcheckNextContactMethod(android.database.Cursor cursor, long personId, java.lang.String data, java.lang.String auxData, int kind, boolean isPrimary, int type, java.lang.String label)

        assertTrue(cursor.moveToNext());
        assertEquals(dumpRow(cursor), personId, getLong(cursor, Contacts.ContactMethods.PERSON_ID));
        assertEquals(dumpRow(cursor), kind, getLong(cursor, Contacts.ContactMethods.KIND));
        assertEquals(dumpRow(cursor), data, getString(cursor, Contacts.ContactMethods.DATA));
        assertEquals(dumpRow(cursor), auxData, getString(cursor, Contacts.ContactMethods.AUX_DATA));
        assertEquals(dumpCursor(cursor), isPrimary,
                getLong(cursor, Contacts.ContactMethods.ISPRIMARY) != 0);
        assertEquals(dumpRow(cursor), type, getLong(cursor, Contacts.ContactMethods.TYPE));
        assertEquals(dumpRow(cursor), label, getString(cursor, Contacts.ContactMethods.LABEL));
    
private voidcheckNextCursorToEntry(android.database.Cursor cursor, com.google.wireless.gdata.data.Entry expectedEntry)

        Entry newEntry = newEmptyEntry(expectedEntry);
        assertTrue(cursor.moveToNext());
        String createUri = ContactsSyncAdapter.cursorToEntryImpl(getMockContentResolver(),
                cursor, newEntry, ACCOUNT);
        // since this is an update the createUri should be null
        assertNull(createUri);
        assertEquals(expectedEntry.getEditUri(), newEntry.getEditUri());
        if (expectedEntry instanceof ContactEntry) {
            ((ContactEntry)newEntry).setLinkEditPhoto(
                    ((ContactEntry)expectedEntry).getLinkEditPhotoHref(),
                    ((ContactEntry)expectedEntry).getLinkEditPhotoType());
        }
        final String expected = expectedEntry.toString();
        String actual = newEntry.toString();
        assertEquals("\nexpected:\n" + expected + "\nactual:\n" + actual, expected, actual);
    
private static voidcheckNextDeleted(android.database.Cursor cursor, com.google.wireless.gdata.data.Entry entry, java.lang.Long syncLocalId)

        assertTrue(cursor.moveToNext());
        assertEquals(dumpRow(cursor), entry.getId(),
                feedFromEntry(entry) + "/" + getString(cursor, SyncConstValue._SYNC_ID));
        assertEquals(dumpRow(cursor), entry.getEditUri(),
                entry.getId() + "/" + getString(cursor, SyncConstValue._SYNC_VERSION));
        assertEquals(dumpRow(cursor), ACCOUNT, getString(cursor, SyncConstValue._SYNC_ACCOUNT));
        if (syncLocalId != null) {
            assertEquals(dumpRow(cursor),
                    syncLocalId.toString(), getString(cursor, SyncConstValue._SYNC_LOCAL_ID));
        }
    
private static voidcheckNextDeletedCursorToEntry(android.database.Cursor cursor, com.google.wireless.gdata.data.Entry expectedEntry)

        Entry newEntry = newEmptyEntry(expectedEntry);
        assertTrue(cursor.moveToNext());
        ContactsSyncAdapter.deletedCursorToEntryImpl(cursor, newEntry, ACCOUNT);
        assertEquals(expectedEntry.getEditUri(), newEntry.getEditUri());
    
private static voidcheckNextEmail(android.database.Cursor cursor, long personId, java.lang.String address, boolean isPrimary, int type, java.lang.String label)

        checkNextContactMethod(cursor, personId, address, null,
                Contacts.KIND_EMAIL, isPrimary, type, label);
    
private static voidcheckNextExtension(android.database.Cursor cursor, long personId, java.lang.String name, java.lang.String value)

        assertTrue(cursor.moveToNext());
        assertEquals(dumpRow(cursor), personId, getLong(cursor, Contacts.Extensions.PERSON_ID));
        assertEquals(dumpRow(cursor), name, getString(cursor, Contacts.Extensions.NAME));
        assertEquals(dumpRow(cursor), value, getString(cursor, Contacts.Extensions.VALUE));
    
private static voidcheckNextGroup(android.database.Cursor cursor, com.google.wireless.gdata.contacts.data.GroupEntry entry, java.lang.Long syncLocalId)

        assertTrue(cursor.moveToNext());
        assertEquals(dumpRow(cursor), entry.getId(),
                feedFromEntry(entry) + "/" + getString(cursor, SyncConstValue._SYNC_ID));
        assertEquals(dumpRow(cursor), entry.getEditUri(),
                entry.getId() + "/" + getString(cursor, SyncConstValue._SYNC_VERSION));
        assertEquals(dumpRow(cursor), ACCOUNT, getString(cursor, SyncConstValue._SYNC_ACCOUNT));
        assertEquals(dumpRow(cursor), entry.getTitle(), getString(cursor, Groups.NAME));
        assertEquals(dumpRow(cursor), entry.getSystemGroup(), getString(cursor, Groups.SYSTEM_ID));
        assertEquals(dumpRow(cursor), entry.getContent(), getString(cursor, Groups.NOTES));
        if (syncLocalId != null) {
            assertEquals(dumpRow(cursor),
                    syncLocalId, getString(cursor, SyncConstValue._SYNC_LOCAL_ID));
        }
    
private static voidcheckNextIm(android.database.Cursor cursor, long personId, java.lang.String address, java.lang.String auxData, boolean isPrimary, int type, java.lang.String label)

        checkNextContactMethod(cursor, personId, address, auxData,
                Contacts.KIND_IM, isPrimary, type, label);
    
private static voidcheckNextNumber(android.database.Cursor cursor, long personId, java.lang.String number, boolean isPrimary, int type, java.lang.String label)

        assertTrue(cursor.moveToNext());
        assertEquals(dumpRow(cursor), personId, getLong(cursor, Contacts.Phones.PERSON_ID));
        assertEquals(dumpRow(cursor), number, getString(cursor, Contacts.Phones.NUMBER));
        assertEquals(dumpRow(cursor), type, getLong(cursor, Contacts.Phones.TYPE));
        assertEquals(dumpCursor(cursor), isPrimary,
                getLong(cursor, Contacts.Phones.ISPRIMARY) != 0);
        assertEquals(dumpRow(cursor), label, getString(cursor, Contacts.Phones.LABEL));
    
private static voidcheckNextOrganization(android.database.Cursor cursor, long personId, java.lang.String company, java.lang.String title, boolean isPrimary, int type, java.lang.String label)

        assertTrue(cursor.moveToNext());
        assertEquals(dumpRow(cursor), personId, getLong(cursor, Contacts.Organizations.PERSON_ID));
        assertEquals(dumpRow(cursor), company, getString(cursor, Contacts.Organizations.COMPANY));
        assertEquals(dumpRow(cursor), title, getString(cursor, Contacts.Organizations.TITLE));
        assertEquals(dumpRow(cursor), isPrimary,
                getLong(cursor, Contacts.Organizations.ISPRIMARY) != 0);
        assertEquals(dumpRow(cursor), type, getLong(cursor, Contacts.Phones.TYPE));
        assertEquals(dumpRow(cursor), label, getString(cursor, Contacts.Phones.LABEL));
    
private static voidcheckNextPerson(ContactsProvider provider, android.database.Cursor cursor, com.google.wireless.gdata.contacts.data.ContactEntry entry, java.lang.Long syncLocalId)

        assertTrue(cursor.moveToNext());
        assertEquals(dumpRow(cursor), entry.getId(),
                feedFromEntry(entry) + "/" + getString(cursor, SyncConstValue._SYNC_ID));
        assertEquals(dumpRow(cursor), entry.getEditUri(),
                entry.getId() + "/" + getString(cursor, SyncConstValue._SYNC_VERSION));
        assertEquals(dumpRow(cursor), ACCOUNT, getString(cursor, SyncConstValue._SYNC_ACCOUNT));
        assertEquals(dumpRow(cursor), entry.getTitle(), getString(cursor, People.NAME));
        assertEquals(dumpRow(cursor), entry.getContent(), getString(cursor, People.NOTES));
        if (syncLocalId != null) {
            assertEquals(dumpRow(cursor),
                    syncLocalId, getString(cursor, SyncConstValue._SYNC_LOCAL_ID));
        }

        Cursor groupCursor = provider.getDatabase().query(ContactsProvider.sGroupmembershipTable,
                null, Contacts.GroupMembership.PERSON_ID + "=?",
                new String[]{getString(cursor, People._ID)}, null, null, null);
        try {
            for (Object object : entry.getGroups()) {
                GroupMembershipInfo groupMembership = (GroupMembershipInfo) object;
                assertTrue(groupCursor.moveToNext());
                assertEquals(groupMembership.getGroup(),
                        ContactsSyncAdapter.getCanonicalGroupsFeedForAccount(ACCOUNT) + "/"
                                + getString(groupCursor, GroupMembership.GROUP_SYNC_ID));
            }
            assertFalse(groupCursor.moveToNext());
        } finally {
            groupCursor.close();
        }
    
private voidcheckNextPhoto(android.database.Cursor cursor, boolean expectedDirty, java.lang.String expectedLocalVersion, java.lang.String expectedServerVersion)

        assertTrue(cursor.moveToNext());
        assertEquals(expectedDirty, getLong(cursor, Photos._SYNC_DIRTY) != 0);
        assertEquals(expectedLocalVersion, getString(cursor, Photos.LOCAL_VERSION));
        assertEquals(expectedServerVersion, getString(cursor, Photos._SYNC_VERSION));
    
private static voidcheckNextPostal(android.database.Cursor cursor, long personId, java.lang.String address, boolean isPrimary, int type, java.lang.String label)

        checkNextContactMethod(cursor, personId, address, null,
                Contacts.KIND_POSTAL, isPrimary, type, label);
    
private voidcheckTableIsEmpty(ContactsProvider provider, android.net.Uri uri)

        Cursor cursor;
        cursor = getProvider().query(uri, null, null, null, null);
        try {
            assertEquals(0, cursor.getCount());
        } finally {
            cursor.close();
        }
    
private voidcheckTableIsEmpty(ContactsProvider provider, java.lang.String table)

        Cursor cursor;
        cursor = getProvider().getDatabase().query(table, null, null, null, null, null, null);
        try {
            assertEquals(DatabaseUtils.dumpCursorToString(cursor), 0, cursor.getCount());
        } finally {
            cursor.close();
        }
    
private voidcopyTempProviderToReal(ContactsProvider provider)

        // copy the server diffs into the provider
        getProvider().merge(mMockSyncContext, provider, null, new SyncResult());

        // clear the _sync_id and _sync_local_id to act as if these are locally inserted
        ContentValues values = new ContentValues();
        values.put(SyncConstValue._SYNC_ID, (String)null);
        values.put(SyncConstValue._SYNC_LOCAL_ID, (String)null);
        values.put(SyncConstValue._SYNC_DIRTY, "1");
        getProvider().getDatabase().update("people", values, null, null);
    
private static java.lang.StringdumpCursor(android.database.Cursor cursor)

        return DatabaseUtils.dumpCursorToString(cursor);
    
private static java.lang.StringdumpRow(android.database.Cursor cursor)

        return DatabaseUtils.dumpCurrentRowToString(cursor);
    
public static java.lang.StringfeedFromEntry(com.google.wireless.gdata.data.Entry expectedEntry)

        if (expectedEntry instanceof ContactEntry) {
            return ContactsSyncAdapter.getContactsFeedForAccount(ACCOUNT);
        } else {
            return ContactsSyncAdapter.getGroupsFeedForAccount(ACCOUNT);
        }
    
private android.content.ContentProvidergetClientDiffs()

        // query the provider for the client diffs
        TempProviderSyncResult result = new TempProviderSyncResult();
        getProvider().merge(mMockSyncContext, null, result, new SyncResult());
        return result.tempContentProvider;
    
private static longgetLong(android.database.Cursor cursor, java.lang.String column)

        return cursor.getLong(cursor.getColumnIndexOrThrow(column));
    
private static longgetSinglePersonId(ContactsProvider provider, java.lang.String entryTitle)

        long personId;
        Cursor cursor;
        cursor = provider.query(People.CONTENT_URI, null, null, null, null);
        try {
            assertTrue(cursor.moveToFirst());
            assertEquals(dumpCursor(cursor), 1, cursor.getCount());
            assertEquals(dumpRow(cursor), entryTitle, getString(cursor, People.NAME));
            personId = getLong(cursor, People._ID);
        } finally {
            cursor.close();
        }
        return personId;
    
private static java.lang.StringgetString(android.database.Cursor cursor, java.lang.String column)

        return cursor.getString(cursor.getColumnIndexOrThrow(column));
    
private static booleanisNull(android.database.Cursor cursor, java.lang.String column)

        return cursor.isNull(cursor.getColumnIndexOrThrow(column));
    
private static com.google.wireless.gdata.contacts.data.GroupEntrynewDeletedGroup(java.lang.String id, java.lang.String version)

        GroupEntry entry = new GroupEntry();
        entry.setDeleted(true);
        entry.setId(ContactsSyncAdapter.getGroupsFeedForAccount(ACCOUNT) + "/" + id);
        entry.setEditUri(entry.getId() + "/" + version);
        return entry;
    
private static com.google.wireless.gdata.contacts.data.ContactEntrynewDeletedPerson(java.lang.String id, java.lang.String version)

        ContactEntry entry = new ContactEntry();
        entry.setDeleted(true);
        entry.setId(ContactsSyncAdapter.getContactsFeedForAccount(ACCOUNT) + "/" + id);
        entry.setEditUri(entry.getId() + "/" + version);
        return entry;
    
private static com.google.wireless.gdata.data.EntrynewEmptyEntry(com.google.wireless.gdata.data.Entry expectedEntry)

        if (expectedEntry instanceof ContactEntry) {
            return new ContactEntry();
        } else {
            return new GroupEntry();
        }
    
private static com.google.wireless.gdata.contacts.data.GroupEntrynewGroup(java.lang.String title, java.lang.String notes, java.lang.String id, java.lang.String version)

        GroupEntry entry = new GroupEntry();
        entry.setTitle(title);
        entry.setContent(notes);
        entry.setId(ContactsSyncAdapter.getGroupsFeedForAccount(ACCOUNT) + "/" + id);
        entry.setEditUri(entry.getId() + "/" + version);
        return entry;
    
private static com.google.wireless.gdata.contacts.data.ContactEntrynewPerson(java.lang.String title, java.lang.String notes, java.lang.String id, java.lang.String version)

        ContactEntry entry = new ContactEntry();
        entry.setTitle(title);
        entry.setContent(notes);
        entry.setId(ContactsSyncAdapter.getContactsFeedForAccount(ACCOUNT) + "/" + id);
        entry.setEditUri(entry.getId() + "/" + version);
        entry.setLinkEditPhoto(ContactsSyncAdapter.getContactsFeedForAccount(ACCOUNT)
                + "/" + id + "/v1", "image/jpg");
        return entry;
    
private ContactsProvidernewTemporaryProvider()

        return (ContactsProvider)getProvider().getTemporaryInstance();
    
protected voidsetUp()

        super.setUp();

        mSyncAdapter = (ContactsSyncAdapter)getProvider().getSyncAdapter();
        getProvider().onSyncStart(mMockSyncContext, ACCOUNT);
    
public voidtestPhotoAccess()

        // add a person to the real provider
        Uri p = addPerson(getProvider(), ACCOUNT, "si1", "p1");
        Uri ph = Uri.withAppendedPath(p, Contacts.Photos.CONTENT_DIRECTORY);

        ContentValues values = new ContentValues();
        values.put(Photos._SYNC_DIRTY, 1);
        values.put(Photos._SYNC_VERSION, "pv1");
        values.put(Photos.LOCAL_VERSION, "pv0");
        getMockContentResolver().update(ph, values, null, null);
        // check that the photos rows look correct
        Cursor cursor = getProvider().getDatabase().query(ContactsProvider.sPhotosTable,
                null, null, null, null, null, null);
        try {
            checkNextPhoto(cursor, true, "pv0", "pv1");
            assertFalse(cursor.moveToNext());
        } finally {
            cursor.close();
        }

        values.clear();
        values.put(Photos._SYNC_DIRTY, 0);
        getMockContentResolver().update(ph, values, null, null);
        // check that the photos rows look correct
        cursor = getProvider().getDatabase().query(ContactsProvider.sPhotosTable,
                null, null, null, null, null, null);
        try {
            checkNextPhoto(cursor, false, "pv0", "pv1");
            assertFalse(cursor.moveToNext());
        } finally {
            cursor.close();
        }

        // save a downloaded photo for that person using the ContactsSyncAdapter
        byte[] remotePhotoData = "remote photo data".getBytes();
        InputStream photoStream = new ByteArrayInputStream(remotePhotoData);
        mSyncAdapter.savePhoto(ContentUris.parseId(p), photoStream, "pv1");

        // check that the photos rows look correct
        cursor = getProvider().getDatabase().query(ContactsProvider.sPhotosTable, 
                null, null, null, null, null, null);
        try {
            checkNextPhoto(cursor, false, "pv1", "pv1");
            assertFalse(cursor.moveToNext());
        } finally {
            cursor.close();
        }

        InputStream inputStream =
                Contacts.People.openContactPhotoInputStream(getMockContentResolver(), p);
        byte[] inputBytes = new byte[100];
        int totalBytesRead = 0;
        while (true) {
            int numBytesRead = inputStream.read(inputBytes, totalBytesRead, 
                    inputBytes.length - totalBytesRead);
            if (numBytesRead < 0) break;
            totalBytesRead += numBytesRead;
        }
        inputStream.close();

        assertByteArrayEquals(remotePhotoData, inputBytes, totalBytesRead);
    
public voidtestUpdateProviderContactMethods()

        final String entryTitle = "title1";
        ContactEntry entry = newPerson(entryTitle, "note1", "2", "3");

        addEmail(entry, "a11111", false, EmailAddress.TYPE_HOME, null);
        addEmail(entry, "a22222", true, EmailAddress.TYPE_WORK, null);
        addEmail(entry, "a33333", false, EmailAddress.TYPE_OTHER, null);
        addEmail(entry, "a44444", false, EmailAddress.TYPE_NONE, "lucky");

        addPostal(entry, "b11111", false, PostalAddress.TYPE_HOME, null);
        addPostal(entry, "b22222", false, PostalAddress.TYPE_WORK, null);
        addPostal(entry, "b33333", true, PostalAddress.TYPE_OTHER, null);
        addPostal(entry, "b44444", false, PostalAddress.TYPE_NONE, "lucky");

        addIm(entry, "c11111", ImAddress.PROTOCOL_CUSTOM, "p1", false, ImAddress.TYPE_HOME, null);
        addIm(entry, "c22222", ImAddress.PROTOCOL_NONE, null, true, ImAddress.TYPE_WORK, null);
        addIm(entry, "c33333", ImAddress.PROTOCOL_SKYPE, null, false, ImAddress.TYPE_OTHER, null);
        addIm(entry, "c44444", ImAddress.PROTOCOL_ICQ, null, false, ImAddress.TYPE_NONE, "l2");

        final ContactsProvider provider = newTemporaryProvider();
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, entry, provider);

        checkTableIsEmpty(getProvider(), Contacts.Phones.CONTENT_URI);
        checkTableIsEmpty(getProvider(), Contacts.Organizations.CONTENT_URI);

        long personId = getSinglePersonId(provider, entryTitle);

        Cursor cursor;
        cursor = provider.query(Contacts.ContactMethods.CONTENT_URI, null, null, null,
                Contacts.ContactMethods.DATA);
        try {
            checkNextEmail(cursor, personId, "a11111",
                    false, Contacts.ContactMethods.TYPE_HOME, null);
            checkNextEmail(cursor, personId, "a22222",
                    true, Contacts.ContactMethods.TYPE_WORK, null);
            checkNextEmail(cursor, personId, "a33333",
                    false, Contacts.ContactMethods.TYPE_OTHER, null);
            checkNextEmail(cursor, personId, "a44444",
                    false, Contacts.ContactMethods.TYPE_CUSTOM, "lucky");

            checkNextPostal(cursor, personId, "b11111",
                    false, Contacts.ContactMethods.TYPE_HOME, null);
            checkNextPostal(cursor, personId, "b22222",
                    false, Contacts.ContactMethods.TYPE_WORK, null);
            checkNextPostal(cursor, personId, "b33333",
                    true, Contacts.ContactMethods.TYPE_OTHER, null);
            checkNextPostal(cursor, personId, "b44444",
                    false, Contacts.ContactMethods.TYPE_CUSTOM, "lucky");

            checkNextIm(cursor, personId, "c11111", ContactMethods.encodeCustomImProtocol("p1"),
                    false, Contacts.ContactMethods.TYPE_HOME, null);
            checkNextIm(cursor, personId, "c22222", null,
                    true, Contacts.ContactMethods.TYPE_WORK, null);
            checkNextIm(cursor, personId, "c33333",
                    ContactMethods.encodePredefinedImProtocol(ContactMethods.PROTOCOL_SKYPE),
                    false, Contacts.ContactMethods.TYPE_OTHER, null);
            checkNextIm(cursor, personId, "c44444",
                    ContactMethods.encodePredefinedImProtocol(ContactMethods.PROTOCOL_ICQ),
                    false, Contacts.ContactMethods.TYPE_CUSTOM, "l2");

            assertTrue(dumpCursor(cursor), cursor.isLast());
        } finally {
            cursor.close();
        }

        checkCursorToEntry(provider, entry);
    
public voidtestUpdateProviderExtensions()

        final String entryTitle = "title1";
        ContactEntry entry = newPerson(entryTitle, "note1", "2", "3");
        addExtendedProperty(entry, "android", null, "{\"other\":\"that\",\"more\":\"hello.mp3\"}");
        final ContactsProvider provider = newTemporaryProvider();
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, entry, provider);

        long personId = getSinglePersonId(provider, entryTitle);

        Cursor cursor;
        cursor = provider.query(Contacts.Extensions.CONTENT_URI, null, null, null,
                Contacts.Extensions.NAME);
        try {
            checkNextExtension(cursor, personId, "more", "hello.mp3");
            checkNextExtension(cursor, personId, "other", "that");
            assertTrue(dumpCursor(cursor), cursor.isLast());
        } finally {
            cursor.close();
        }

        checkCursorToEntry(provider, entry);
    
public voidtestUpdateProviderGroupMembership()

        final ContactsProvider serverDiffs = newTemporaryProvider();

        ContactEntry p = newPerson("p1", "pn1", "pi1", "pv1");

        addGroupMembership(p, ACCOUNT, "gsi1");
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 31L, p, serverDiffs);

        // The provider should now have:
        // - a row in the people table
        // - a row in the groupmembership table

        checkEntries(serverDiffs, false, p, 31L);

        checkTableIsEmpty(serverDiffs, ContactsProvider.sPeopleTable);
        checkTableIsEmpty(serverDiffs, ContactsProvider.sGroupmembershipTable);

        // copy the server diffs into the provider
        getProvider().merge(mMockSyncContext, serverDiffs, null, new SyncResult());
        getProvider().getDatabase().execSQL("UPDATE people SET _sync_dirty=1");
        ContentProvider clientDiffs = getClientDiffs();

        // Convert the provider back to an entry and check that they match
        Cursor cursor = ContactsSyncAdapter.getCursorForTableImpl(clientDiffs, ContactEntry.class);
        try {
            checkNextCursorToEntry(cursor, p);
            assertTrue(dumpCursor(cursor), cursor.isLast());
        } finally {
            cursor.close();
        }
    
public voidtestUpdateProviderGroups()

        final ContactsProvider serverDiffs = newTemporaryProvider();

        GroupEntry g1 = newGroup("g1", "n1", "i1", "v1");
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 21L, g1, serverDiffs);

        GroupEntry g2 = newGroup("g2", "n2", "i2", "v2");
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, g2, serverDiffs);

        GroupEntry g3 = newGroup("g3", "n3", "i3", "v3");
        g3.setDeleted(true);
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 23L, g3, serverDiffs);

        GroupEntry g4 = newDeletedGroup("i4", "v4");
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 24L, g4, serverDiffs);

        // confirm that the entries we expect are in the Groups and DeletedGroups
        // tables
        checkEntries(serverDiffs, false, g1, 21L, g2, null);
        checkEntries(serverDiffs, true, g3, 23L, g4, 24L);

        // Convert the provider back to an entry and check that they match
        Cursor cursor;
        cursor = ContactsSyncAdapter.getCursorForTableImpl(serverDiffs, GroupEntry.class);
        try {
            checkNextCursorToEntry(cursor, g1);
            checkNextCursorToEntry(cursor, g2);
            assertTrue(dumpCursor(cursor), cursor.isLast());
        } finally {
            cursor.close();
        }

        cursor = ContactsSyncAdapter.getCursorForDeletedTableImpl(serverDiffs, GroupEntry.class);
        try {
            checkNextDeletedCursorToEntry(cursor, g3);
            checkNextDeletedCursorToEntry(cursor, g4);
            assertTrue(dumpCursor(cursor), cursor.isLast());
        } finally {
            cursor.close();
        }
    
public voidtestUpdateProviderOrganization()

        final String entryTitle = "title1";
        ContactEntry entry = newPerson(entryTitle, "note1", "2", "3");
        addOrganization(entry, "11111", "title1", true, Organization.TYPE_WORK, null);
        addOrganization(entry, "22222", "title2", false, Organization.TYPE_OTHER, null);
        addOrganization(entry, "33333", "title3", false, Organization.TYPE_NONE, "label1");
        final ContactsProvider provider = newTemporaryProvider();
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, entry, provider);

        checkTableIsEmpty(getProvider(), Contacts.ContactMethods.CONTENT_URI);
        checkTableIsEmpty(getProvider(), Contacts.Phones.CONTENT_URI);

        long personId = getSinglePersonId(provider, entryTitle);

        Cursor cursor;
        cursor = provider.query(Contacts.Organizations.CONTENT_URI, null, null, null,
                Contacts.Organizations.COMPANY);
        try {
            checkNextOrganization(cursor, personId, "11111", "title1", true,
                    Contacts.Organizations.TYPE_WORK, null);
            checkNextOrganization(cursor, personId, "22222", "title2", false,
                    Contacts.Organizations.TYPE_OTHER, null);
            checkNextOrganization(cursor, personId, "33333", "title3", false,
                    Contacts.Organizations.TYPE_CUSTOM, "label1");
            assertTrue(dumpCursor(cursor), cursor.isLast());
        } finally {
            cursor.close();
        }

        checkCursorToEntry(provider, entry);
    
public voidtestUpdateProviderPeople()

        final ContactsProvider serverDiffs = newTemporaryProvider();

        ContactEntry entry1 = newPerson("title1", "note1", "1", "a");
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 11L, entry1, serverDiffs);

        ContactEntry entry2 = newPerson("title2", "note2", "2", "b");
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, entry2, serverDiffs);

        ContactEntry entry3 = newPerson("title3", "note3", "3", "c");
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 13L, entry3, serverDiffs);

        ContactEntry entry4 = newPerson("title4", "note4", "4", "d");
        entry4.setDeleted(true);
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 14L, entry4, serverDiffs);

        ContactEntry entry5 = newDeletedPerson("5", "e");
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, 15L, entry5, serverDiffs);

        checkTableIsEmpty(getProvider(), Contacts.ContactMethods.CONTENT_URI);
        checkTableIsEmpty(getProvider(), Contacts.Organizations.CONTENT_URI);
        checkTableIsEmpty(getProvider(), Contacts.Phones.CONTENT_URI);

        checkEntries(serverDiffs, false, entry1, 11L, entry2, null, entry3, 13L);
        checkEntries(serverDiffs, true, entry4, 14L, entry5, 15L);

        // Convert the provider back to an entry and check that they match
        Cursor cursor;
        cursor = ContactsSyncAdapter.getCursorForTableImpl(serverDiffs, ContactEntry.class);
        try {
            checkNextCursorToEntry(cursor, entry1);
            checkNextCursorToEntry(cursor, entry2);
            checkNextCursorToEntry(cursor, entry3);
            assertTrue(dumpCursor(cursor), cursor.isLast());
        } finally {
            cursor.close();
        }

        cursor = ContactsSyncAdapter.getCursorForDeletedTableImpl(serverDiffs, ContactEntry.class);
        try {
            checkNextDeletedCursorToEntry(cursor, entry4);
            checkNextDeletedCursorToEntry(cursor, entry5);
            assertTrue(dumpCursor(cursor), cursor.isLast());
        } finally {
            cursor.close();
        }
    
public voidtestUpdateProviderPhones()

        final String entryTitle = "title1";
        ContactEntry entry = newPerson(entryTitle, "note1", "2", "3");
        addPhoneNumber(entry, "11111", false, PhoneNumber.TYPE_HOME, null);
        addPhoneNumber(entry, "22222", false, PhoneNumber.TYPE_HOME_FAX, null);
        addPhoneNumber(entry, "33333", false, PhoneNumber.TYPE_MOBILE, null);
        addPhoneNumber(entry, "44444", true, PhoneNumber.TYPE_PAGER, null);
        addPhoneNumber(entry, "55555", false, PhoneNumber.TYPE_WORK, null);
        addPhoneNumber(entry, "66666", false, PhoneNumber.TYPE_WORK_FAX, null);
        addPhoneNumber(entry, "77777", false, PhoneNumber.TYPE_OTHER, null);
        addPhoneNumber(entry, "88888", false, PhoneNumber.TYPE_NONE, "lucky");
        final ContactsProvider provider = newTemporaryProvider();
        ContactsSyncAdapter.updateProviderImpl(ACCOUNT, null, entry, provider);

        checkTableIsEmpty(getProvider(), Contacts.ContactMethods.CONTENT_URI);
        checkTableIsEmpty(getProvider(), Contacts.Organizations.CONTENT_URI);

        long personId = getSinglePersonId(provider, entryTitle);

        Cursor cursor;
        cursor = provider.query(Contacts.Phones.CONTENT_URI, null, null, null,
                Contacts.Phones.NUMBER);
        try {
            checkNextNumber(cursor, personId, "11111", false, Contacts.Phones.TYPE_HOME, null);
            checkNextNumber(cursor, personId, "22222", false, Contacts.Phones.TYPE_FAX_HOME, null);
            checkNextNumber(cursor, personId, "33333", false, Contacts.Phones.TYPE_MOBILE, null);
            checkNextNumber(cursor, personId, "44444", true, Contacts.Phones.TYPE_PAGER, null);
            checkNextNumber(cursor, personId, "55555", false, Contacts.Phones.TYPE_WORK, null);
            checkNextNumber(cursor, personId, "66666", false, Contacts.Phones.TYPE_FAX_WORK, null);
            checkNextNumber(cursor, personId, "77777", false, Contacts.Phones.TYPE_OTHER, null);
            checkNextNumber(cursor, personId, "88888", false, Contacts.Phones.TYPE_CUSTOM, "lucky");
            assertTrue(dumpCursor(cursor), cursor.isLast());
        } finally {
            cursor.close();
        }

        checkCursorToEntry(provider, entry);