summaryrefslogtreecommitdiffstats
path: root/tests/src/com/android/contacts/common/RawContactModifierTests.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/com/android/contacts/common/RawContactModifierTests.java')
-rw-r--r--tests/src/com/android/contacts/common/RawContactModifierTests.java1235
1 files changed, 1235 insertions, 0 deletions
diff --git a/tests/src/com/android/contacts/common/RawContactModifierTests.java b/tests/src/com/android/contacts/common/RawContactModifierTests.java
new file mode 100644
index 00000000..2e972cfb
--- /dev/null
+++ b/tests/src/com/android/contacts/common/RawContactModifierTests.java
@@ -0,0 +1,1235 @@
+/*
+ * 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.contacts.common;
+
+import static android.content.ContentProviderOperation.TYPE_DELETE;
+import static android.content.ContentProviderOperation.TYPE_INSERT;
+import static android.content.ContentProviderOperation.TYPE_UPDATE;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Intents.Insert;
+import android.provider.ContactsContract.RawContacts;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.RawContact;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountType.EditType;
+import com.android.contacts.common.model.account.ExchangeAccountType;
+import com.android.contacts.common.model.account.GoogleAccountType;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.test.mocks.ContactsMockContext;
+import com.android.contacts.common.test.mocks.MockAccountTypeManager;
+import com.android.contacts.common.test.mocks.MockContentProvider;
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link RawContactModifier} to verify that {@link AccountType}
+ * constraints are being enforced correctly.
+ */
+@LargeTest
+public class RawContactModifierTests extends AndroidTestCase {
+ public static final String TAG = "EntityModifierTests";
+
+ public static final long VER_FIRST = 100;
+
+ private static final long TEST_ID = 4;
+ private static final String TEST_PHONE = "218-555-1212";
+ private static final String TEST_NAME = "Adam Young";
+ private static final String TEST_NAME2 = "Breanne Duren";
+ private static final String TEST_IM = "example@example.com";
+ private static final String TEST_POSTAL = "1600 Amphitheatre Parkway";
+
+ private static final String TEST_ACCOUNT_NAME = "unittest@example.com";
+ private static final String TEST_ACCOUNT_TYPE = "com.example.unittest";
+
+ private static final String EXCHANGE_ACCT_TYPE = "com.android.exchange";
+
+ @Override
+ public void setUp() {
+ mContext = getContext();
+ }
+
+ public static class MockContactsSource extends AccountType {
+
+ MockContactsSource() {
+ try {
+ this.accountType = TEST_ACCOUNT_TYPE;
+
+ final DataKind nameKind = new DataKind(StructuredName.CONTENT_ITEM_TYPE,
+ R.string.nameLabelsGroup, -1, true);
+ nameKind.typeOverallMax = 1;
+ addKind(nameKind);
+
+ // Phone allows maximum 2 home, 1 work, and unlimited other, with
+ // constraint of 5 numbers maximum.
+ final DataKind phoneKind = new DataKind(
+ Phone.CONTENT_ITEM_TYPE, -1, 10, true);
+
+ phoneKind.typeOverallMax = 5;
+ phoneKind.typeColumn = Phone.TYPE;
+ phoneKind.typeList = Lists.newArrayList();
+ phoneKind.typeList.add(new EditType(Phone.TYPE_HOME, -1).setSpecificMax(2));
+ phoneKind.typeList.add(new EditType(Phone.TYPE_WORK, -1).setSpecificMax(1));
+ phoneKind.typeList.add(new EditType(Phone.TYPE_FAX_WORK, -1).setSecondary(true));
+ phoneKind.typeList.add(new EditType(Phone.TYPE_OTHER, -1));
+
+ phoneKind.fieldList = Lists.newArrayList();
+ phoneKind.fieldList.add(new EditField(Phone.NUMBER, -1, -1));
+ phoneKind.fieldList.add(new EditField(Phone.LABEL, -1, -1));
+
+ addKind(phoneKind);
+
+ // Email is unlimited
+ final DataKind emailKind = new DataKind(Email.CONTENT_ITEM_TYPE, -1, 10, true);
+ emailKind.typeOverallMax = -1;
+ emailKind.fieldList = Lists.newArrayList();
+ emailKind.fieldList.add(new EditField(Email.DATA, -1, -1));
+ addKind(emailKind);
+
+ // IM is only one
+ final DataKind imKind = new DataKind(Im.CONTENT_ITEM_TYPE, -1, 10, true);
+ imKind.typeOverallMax = 1;
+ imKind.fieldList = Lists.newArrayList();
+ imKind.fieldList.add(new EditField(Im.DATA, -1, -1));
+ addKind(imKind);
+
+ // Organization is only one
+ final DataKind orgKind = new DataKind(Organization.CONTENT_ITEM_TYPE, -1, 10, true);
+ orgKind.typeOverallMax = 1;
+ orgKind.fieldList = Lists.newArrayList();
+ orgKind.fieldList.add(new EditField(Organization.COMPANY, -1, -1));
+ orgKind.fieldList.add(new EditField(Organization.TITLE, -1, -1));
+ addKind(orgKind);
+ } catch (DefinitionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean isGroupMembershipEditable() {
+ return false;
+ }
+
+ @Override
+ public boolean areContactsWritable() {
+ return true;
+ }
+ }
+
+ /**
+ * Build a {@link AccountType} that has various odd constraints for
+ * testing purposes.
+ */
+ protected AccountType getAccountType() {
+ return new MockContactsSource();
+ }
+
+ /**
+ * Build {@link AccountTypeManager} instance.
+ */
+ protected AccountTypeManager getAccountTypes(AccountType... types) {
+ return new MockAccountTypeManager(types, null);
+ }
+
+ /**
+ * Build an {@link RawContact} with the requested set of phone numbers.
+ */
+ protected RawContactDelta getRawContact(Long existingId, ContentValues... entries) {
+ final ContentValues contact = new ContentValues();
+ if (existingId != null) {
+ contact.put(RawContacts._ID, existingId);
+ }
+ contact.put(RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME);
+ contact.put(RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE);
+
+ final RawContact before = new RawContact(contact);
+ for (ContentValues values : entries) {
+ before.addDataItemValues(values);
+ }
+ return RawContactDelta.fromBefore(before);
+ }
+
+ /**
+ * Assert this {@link List} contains the given {@link Object}.
+ */
+ protected void assertContains(List<?> list, Object object) {
+ assertTrue("Missing expected value", list.contains(object));
+ }
+
+ /**
+ * Assert this {@link List} does not contain the given {@link Object}.
+ */
+ protected void assertNotContains(List<?> list, Object object) {
+ assertFalse("Contained unexpected value", list.contains(object));
+ }
+
+ /**
+ * Insert various rows to test
+ * {@link RawContactModifier#getValidTypes(RawContactDelta, DataKind, EditType)}
+ */
+ public void testValidTypes() {
+ // Build a source and pull specific types
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
+ final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
+
+ List<EditType> validTypes;
+
+ // Add first home, first work
+ final RawContactDelta state = getRawContact(TEST_ID);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeWork);
+
+ // Expecting home, other
+ validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
+ assertContains(validTypes, typeHome);
+ assertNotContains(validTypes, typeWork);
+ assertContains(validTypes, typeOther);
+
+ // Add second home
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+
+ // Expecting other
+ validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
+ assertNotContains(validTypes, typeHome);
+ assertNotContains(validTypes, typeWork);
+ assertContains(validTypes, typeOther);
+
+ // Add third and fourth home (invalid, but possible)
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+
+ // Expecting none
+ validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
+ assertNotContains(validTypes, typeHome);
+ assertNotContains(validTypes, typeWork);
+ assertNotContains(validTypes, typeOther);
+ }
+
+ /**
+ * Test {@link RawContactModifier#canInsert(RawContactDelta, DataKind)} by
+ * inserting various rows.
+ */
+ public void testCanInsert() {
+ // Build a source and pull specific types
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
+ final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
+
+ // Add first home, first work
+ final RawContactDelta state = getRawContact(TEST_ID);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeWork);
+ assertTrue("Unable to insert", RawContactModifier.canInsert(state, kindPhone));
+
+ // Add two other, which puts us just under "5" overall limit
+ RawContactModifier.insertChild(state, kindPhone, typeOther);
+ RawContactModifier.insertChild(state, kindPhone, typeOther);
+ assertTrue("Unable to insert", RawContactModifier.canInsert(state, kindPhone));
+
+ // Add second home, which should push to snug limit
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ assertFalse("Able to insert", RawContactModifier.canInsert(state, kindPhone));
+ }
+
+ /**
+ * Test
+ * {@link RawContactModifier#getBestValidType(RawContactDelta, DataKind, boolean, int)}
+ * by asserting expected best options in various states.
+ */
+ public void testBestValidType() {
+ // Build a source and pull specific types
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
+ final EditType typeFaxWork = RawContactModifier.getType(kindPhone, Phone.TYPE_FAX_WORK);
+ final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
+
+ EditType suggested;
+
+ // Default suggestion should be home
+ final RawContactDelta state = getRawContact(TEST_ID);
+ suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeHome, suggested);
+
+ // Add first home, should now suggest work
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeWork, suggested);
+
+ // Add work fax, should still suggest work
+ RawContactModifier.insertChild(state, kindPhone, typeFaxWork);
+ suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeWork, suggested);
+
+ // Add other, should still suggest work
+ RawContactModifier.insertChild(state, kindPhone, typeOther);
+ suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeWork, suggested);
+
+ // Add work, now should suggest other
+ RawContactModifier.insertChild(state, kindPhone, typeWork);
+ suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeOther, suggested);
+ }
+
+ public void testIsEmptyEmpty() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+
+ // Test entirely empty row
+ final ContentValues after = new ContentValues();
+ final ValuesDelta values = ValuesDelta.fromAfter(after);
+
+ assertTrue("Expected empty", RawContactModifier.isEmpty(values, kindPhone));
+ }
+
+ public void testIsEmptyDirectFields() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values, but core fields are empty
+ final RawContactDelta state = getRawContact(TEST_ID);
+ final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
+
+ assertTrue("Expected empty", RawContactModifier.isEmpty(values, kindPhone));
+
+ // Insert some data to trigger non-empty state
+ values.put(Phone.NUMBER, TEST_PHONE);
+
+ assertFalse("Expected non-empty", RawContactModifier.isEmpty(values, kindPhone));
+ }
+
+ public void testTrimEmptySingle() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values, but core fields are empty
+ final RawContactDelta state = getRawContact(TEST_ID);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+
+ // Build diff, expecting insert for data row and update enforcement
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Trim empty rows and try again, expecting delete of overall contact
+ RawContactModifier.trimEmpty(state, source);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 1, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testTrimEmptySpaces() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values, but values are spaces
+ final RawContactDelta state = RawContactDeltaListTests.buildBeforeEntity(mContext, TEST_ID,
+ VER_FIRST);
+ final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
+ values.put(Phone.NUMBER, " ");
+
+ // Build diff, expecting insert for data row and update enforcement
+ RawContactDeltaListTests.assertDiffPattern(state,
+ RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
+ RawContactDeltaListTests.buildUpdateAggregationSuspended(),
+ RawContactDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
+ RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
+ RawContactDeltaListTests.buildUpdateAggregationDefault());
+
+ // Trim empty rows and try again, expecting delete of overall contact
+ RawContactModifier.trimEmpty(state, source);
+ RawContactDeltaListTests.assertDiffPattern(state,
+ RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
+ RawContactDeltaListTests.buildDelete(RawContacts.CONTENT_URI));
+ }
+
+ public void testTrimLeaveValid() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values with valid number
+ final RawContactDelta state = RawContactDeltaListTests.buildBeforeEntity(mContext, TEST_ID,
+ VER_FIRST);
+ final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
+ values.put(Phone.NUMBER, TEST_PHONE);
+
+ // Build diff, expecting insert for data row and update enforcement
+ RawContactDeltaListTests.assertDiffPattern(state,
+ RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
+ RawContactDeltaListTests.buildUpdateAggregationSuspended(),
+ RawContactDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
+ RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
+ RawContactDeltaListTests.buildUpdateAggregationDefault());
+
+ // Trim empty rows and try again, expecting no differences
+ RawContactModifier.trimEmpty(state, source);
+ RawContactDeltaListTests.assertDiffPattern(state,
+ RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
+ RawContactDeltaListTests.buildUpdateAggregationSuspended(),
+ RawContactDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
+ RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
+ RawContactDeltaListTests.buildUpdateAggregationDefault());
+ }
+
+ public void testTrimEmptyUntouched() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Build "before" that has empty row
+ final RawContactDelta state = getRawContact(TEST_ID);
+ final ContentValues before = new ContentValues();
+ before.put(Data._ID, TEST_ID);
+ before.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ state.addEntry(ValuesDelta.fromBefore(before));
+
+ // Build diff, expecting no changes
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+
+ // Try trimming existing empty, which we shouldn't touch
+ RawContactModifier.trimEmpty(state, source);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+ }
+
+ public void testTrimEmptyAfterUpdate() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Build "before" that has row with some phone number
+ final ContentValues before = new ContentValues();
+ before.put(Data._ID, TEST_ID);
+ before.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ before.put(kindPhone.typeColumn, typeHome.rawValue);
+ before.put(Phone.NUMBER, TEST_PHONE);
+ final RawContactDelta state = getRawContact(TEST_ID, before);
+
+ // Build diff, expecting no changes
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+
+ // Now update row by changing number to empty string, expecting single update
+ final ValuesDelta child = state.getEntry(TEST_ID);
+ child.put(Phone.NUMBER, "");
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Now run trim, which should turn that update into delete
+ RawContactModifier.trimEmpty(state, source);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 1, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testTrimInsertEmpty() {
+ final AccountType accountType = getAccountType();
+ final AccountTypeManager accountTypes = getAccountTypes(accountType);
+ final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Try creating a contact without any child entries
+ final RawContactDelta state = getRawContact(null);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
+
+
+ // Build diff, expecting single insert
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 2, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Trim empty rows and try again, expecting no insert
+ RawContactModifier.trimEmpty(set, accountTypes);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+ }
+
+ public void testTrimInsertInsert() {
+ final AccountType accountType = getAccountType();
+ final AccountTypeManager accountTypes = getAccountTypes(accountType);
+ final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Try creating a contact with single empty entry
+ final RawContactDelta state = getRawContact(null);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
+
+ // Build diff, expecting two insert operations
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+
+ // Trim empty rows and try again, expecting silence
+ RawContactModifier.trimEmpty(set, accountTypes);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+ }
+
+ public void testTrimUpdateRemain() {
+ final AccountType accountType = getAccountType();
+ final AccountTypeManager accountTypes = getAccountTypes(accountType);
+ final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Build "before" with two phone numbers
+ final ContentValues first = new ContentValues();
+ first.put(Data._ID, TEST_ID);
+ first.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ first.put(kindPhone.typeColumn, typeHome.rawValue);
+ first.put(Phone.NUMBER, TEST_PHONE);
+
+ final ContentValues second = new ContentValues();
+ second.put(Data._ID, TEST_ID);
+ second.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ second.put(kindPhone.typeColumn, typeHome.rawValue);
+ second.put(Phone.NUMBER, TEST_PHONE);
+
+ final RawContactDelta state = getRawContact(TEST_ID, first, second);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
+
+ // Build diff, expecting no changes
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+
+ // Now update row by changing number to empty string, expecting single update
+ final ValuesDelta child = state.getEntry(TEST_ID);
+ child.put(Phone.NUMBER, "");
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Now run trim, which should turn that update into delete
+ RawContactModifier.trimEmpty(set, accountTypes);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testTrimUpdateUpdate() {
+ final AccountType accountType = getAccountType();
+ final AccountTypeManager accountTypes = getAccountTypes(accountType);
+ final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Build "before" with two phone numbers
+ final ContentValues first = new ContentValues();
+ first.put(Data._ID, TEST_ID);
+ first.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ first.put(kindPhone.typeColumn, typeHome.rawValue);
+ first.put(Phone.NUMBER, TEST_PHONE);
+
+ final RawContactDelta state = getRawContact(TEST_ID, first);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
+
+ // Build diff, expecting no changes
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+
+ // Now update row by changing number to empty string, expecting single update
+ final ValuesDelta child = state.getEntry(TEST_ID);
+ child.put(Phone.NUMBER, "");
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Now run trim, which should turn into deleting the whole contact
+ RawContactModifier.trimEmpty(set, accountTypes);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 1, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testParseExtrasExistingName() {
+ final AccountType accountType = getAccountType();
+
+ // Build "before" name
+ final ContentValues first = new ContentValues();
+ first.put(Data._ID, TEST_ID);
+ first.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ first.put(StructuredName.GIVEN_NAME, TEST_NAME);
+
+ // Parse extras, making sure we keep single name
+ final RawContactDelta state = getRawContact(TEST_ID, first);
+ final Bundle extras = new Bundle();
+ extras.putString(Insert.NAME, TEST_NAME2);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
+
+ final int nameCount = state.getMimeEntriesCount(StructuredName.CONTENT_ITEM_TYPE, true);
+ assertEquals("Unexpected names", 1, nameCount);
+ }
+
+ public void testParseExtrasIgnoreLimit() {
+ final AccountType accountType = getAccountType();
+
+ // Build "before" IM
+ final ContentValues first = new ContentValues();
+ first.put(Data._ID, TEST_ID);
+ first.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ first.put(Im.DATA, TEST_IM);
+
+ final RawContactDelta state = getRawContact(TEST_ID, first);
+ final int beforeCount = state.getMimeEntries(Im.CONTENT_ITEM_TYPE).size();
+
+ // We should ignore data that doesn't fit account type rules, since account type
+ // only allows single Im
+ final Bundle extras = new Bundle();
+ extras.putInt(Insert.IM_PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
+ extras.putString(Insert.IM_HANDLE, TEST_IM);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
+
+ final int afterCount = state.getMimeEntries(Im.CONTENT_ITEM_TYPE).size();
+ assertEquals("Broke account type rules", beforeCount, afterCount);
+ }
+
+ public void testParseExtrasIgnoreUnhandled() {
+ final AccountType accountType = getAccountType();
+ final RawContactDelta state = getRawContact(TEST_ID);
+
+ // We should silently ignore types unsupported by account type
+ final Bundle extras = new Bundle();
+ extras.putString(Insert.POSTAL, TEST_POSTAL);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
+
+ assertNull("Broke accoun type rules",
+ state.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE));
+ }
+
+ public void testParseExtrasJobTitle() {
+ final AccountType accountType = getAccountType();
+ final RawContactDelta state = getRawContact(TEST_ID);
+
+ // Make sure that we create partial Organizations
+ final Bundle extras = new Bundle();
+ extras.putString(Insert.JOB_TITLE, TEST_NAME);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
+
+ final int count = state.getMimeEntries(Organization.CONTENT_ITEM_TYPE).size();
+ assertEquals("Expected to create organization", 1, count);
+ }
+
+ public void testMigrateWithDisplayNameFromGoogleToExchange1() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
+
+ ContactsMockContext context = new ContactsMockContext(getContext());
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredName.PREFIX, "prefix");
+ mockNameValues.put(StructuredName.GIVEN_NAME, "given");
+ mockNameValues.put(StructuredName.MIDDLE_NAME, "middle");
+ mockNameValues.put(StructuredName.FAMILY_NAME, "family");
+ mockNameValues.put(StructuredName.SUFFIX, "suffix");
+ mockNameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "PHONETIC_FAMILY");
+ mockNameValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "PHONETIC_MIDDLE");
+ mockNameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "PHONETIC_GIVEN");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
+ List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
+ assertEquals(1, list.size());
+
+ ContentValues output = list.get(0).getAfter();
+ assertEquals("prefix", output.getAsString(StructuredName.PREFIX));
+ assertEquals("given", output.getAsString(StructuredName.GIVEN_NAME));
+ assertEquals("middle", output.getAsString(StructuredName.MIDDLE_NAME));
+ assertEquals("family", output.getAsString(StructuredName.FAMILY_NAME));
+ assertEquals("suffix", output.getAsString(StructuredName.SUFFIX));
+ // Phonetic middle name isn't supported by Exchange.
+ assertEquals("PHONETIC_FAMILY", output.getAsString(StructuredName.PHONETIC_FAMILY_NAME));
+ assertEquals("PHONETIC_GIVEN", output.getAsString(StructuredName.PHONETIC_GIVEN_NAME));
+ }
+
+ public void testMigrateWithDisplayNameFromGoogleToExchange2() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
+
+ ContactsMockContext context = new ContactsMockContext(getContext());
+ MockContentProvider provider = context.getContactsProvider();
+
+ String inputDisplayName = "prefix given middle family suffix";
+ // The method will ask the provider to split/join StructuredName.
+ Uri uriForBuildDisplayName =
+ ContactsContract.AUTHORITY_URI
+ .buildUpon()
+ .appendPath("complete_name")
+ .appendQueryParameter(StructuredName.DISPLAY_NAME, inputDisplayName)
+ .build();
+ provider.expectQuery(uriForBuildDisplayName)
+ .returnRow("prefix", "given", "middle", "family", "suffix")
+ .withProjection(StructuredName.PREFIX, StructuredName.GIVEN_NAME,
+ StructuredName.MIDDLE_NAME, StructuredName.FAMILY_NAME,
+ StructuredName.SUFFIX);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredName.DISPLAY_NAME, inputDisplayName);
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
+ List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
+ assertEquals(1, list.size());
+
+ ContentValues outputValues = list.get(0).getAfter();
+ assertEquals("prefix", outputValues.getAsString(StructuredName.PREFIX));
+ assertEquals("given", outputValues.getAsString(StructuredName.GIVEN_NAME));
+ assertEquals("middle", outputValues.getAsString(StructuredName.MIDDLE_NAME));
+ assertEquals("family", outputValues.getAsString(StructuredName.FAMILY_NAME));
+ assertEquals("suffix", outputValues.getAsString(StructuredName.SUFFIX));
+ }
+
+ public void testMigrateWithStructuredNameFromExchangeToGoogle() {
+ AccountType oldAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ AccountType newAccountType = new GoogleAccountType(getContext(), "");
+ DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
+
+ ContactsMockContext context = new ContactsMockContext(getContext());
+ MockContentProvider provider = context.getContactsProvider();
+
+ // The method will ask the provider to split/join StructuredName.
+ Uri uriForBuildDisplayName =
+ ContactsContract.AUTHORITY_URI
+ .buildUpon()
+ .appendPath("complete_name")
+ .appendQueryParameter(StructuredName.PREFIX, "prefix")
+ .appendQueryParameter(StructuredName.GIVEN_NAME, "given")
+ .appendQueryParameter(StructuredName.MIDDLE_NAME, "middle")
+ .appendQueryParameter(StructuredName.FAMILY_NAME, "family")
+ .appendQueryParameter(StructuredName.SUFFIX, "suffix")
+ .build();
+ provider.expectQuery(uriForBuildDisplayName)
+ .returnRow("prefix given middle family suffix")
+ .withProjection(StructuredName.DISPLAY_NAME);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredName.PREFIX, "prefix");
+ mockNameValues.put(StructuredName.GIVEN_NAME, "given");
+ mockNameValues.put(StructuredName.MIDDLE_NAME, "middle");
+ mockNameValues.put(StructuredName.FAMILY_NAME, "family");
+ mockNameValues.put(StructuredName.SUFFIX, "suffix");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size());
+ ContentValues outputValues = list.get(0).getAfter();
+ assertEquals("prefix given middle family suffix",
+ outputValues.getAsString(StructuredName.DISPLAY_NAME));
+ }
+
+ public void testMigratePostalFromGoogleToExchange() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredPostal.FORMATTED_ADDRESS, "formatted_address");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migratePostal(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size());
+ ContentValues outputValues = list.get(0).getAfter();
+ // FORMATTED_ADDRESS isn't supported by Exchange.
+ assertNull(outputValues.getAsString(StructuredPostal.FORMATTED_ADDRESS));
+ assertEquals("formatted_address", outputValues.getAsString(StructuredPostal.STREET));
+ }
+
+ public void testMigratePostalFromExchangeToGoogle() {
+ AccountType oldAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ AccountType newAccountType = new GoogleAccountType(getContext(), "");
+ DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredPostal.COUNTRY, "country");
+ mockNameValues.put(StructuredPostal.POSTCODE, "postcode");
+ mockNameValues.put(StructuredPostal.REGION, "region");
+ mockNameValues.put(StructuredPostal.CITY, "city");
+ mockNameValues.put(StructuredPostal.STREET, "street");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migratePostal(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size());
+ ContentValues outputValues = list.get(0).getAfter();
+
+ // Check FORMATTED_ADDRESS contains all info.
+ String formattedAddress = outputValues.getAsString(StructuredPostal.FORMATTED_ADDRESS);
+ assertNotNull(formattedAddress);
+ assertTrue(formattedAddress.contains("country"));
+ assertTrue(formattedAddress.contains("postcode"));
+ assertTrue(formattedAddress.contains("region"));
+ assertTrue(formattedAddress.contains("postcode"));
+ assertTrue(formattedAddress.contains("city"));
+ assertTrue(formattedAddress.contains("street"));
+ }
+
+ public void testMigrateEventFromGoogleToExchange1() {
+ testMigrateEventCommon(new GoogleAccountType(getContext(), ""),
+ new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE));
+ }
+
+ public void testMigrateEventFromExchangeToGoogle() {
+ testMigrateEventCommon(new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE),
+ new GoogleAccountType(getContext(), ""));
+ }
+
+ private void testMigrateEventCommon(AccountType oldAccountType, AccountType newAccountType) {
+ DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Event.START_DATE, "1972-02-08");
+ mockNameValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateEvent(oldState, newState, kind, 1990);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Event.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size()); // Anniversary should be dropped.
+ ContentValues outputValues = list.get(0).getAfter();
+
+ assertEquals("1972-02-08", outputValues.getAsString(Event.START_DATE));
+ assertEquals(Event.TYPE_BIRTHDAY, outputValues.getAsInteger(Event.TYPE).intValue());
+ }
+
+ public void testMigrateEventFromGoogleToExchange2() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
+ // No year format is not supported by Exchange.
+ mockNameValues.put(Event.START_DATE, "--06-01");
+ mockNameValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Event.START_DATE, "1980-08-02");
+ // Anniversary is not supported by Exchange
+ mockNameValues.put(Event.TYPE, Event.TYPE_ANNIVERSARY);
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateEvent(oldState, newState, kind, 1990);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Event.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size()); // Anniversary should be dropped.
+ ContentValues outputValues = list.get(0).getAfter();
+
+ // Default year should be used.
+ assertEquals("1990-06-01", outputValues.getAsString(Event.START_DATE));
+ assertEquals(Event.TYPE_BIRTHDAY, outputValues.getAsInteger(Event.TYPE).intValue());
+ }
+
+ public void testMigrateEmailFromGoogleToExchange() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(Email.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Email.TYPE, Email.TYPE_CUSTOM);
+ mockNameValues.put(Email.LABEL, "custom_type");
+ mockNameValues.put(Email.ADDRESS, "address1");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Email.TYPE, Email.TYPE_HOME);
+ mockNameValues.put(Email.ADDRESS, "address2");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Email.TYPE, Email.TYPE_WORK);
+ mockNameValues.put(Email.ADDRESS, "address3");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ // Exchange can have up to 3 email entries. This 4th entry should be dropped.
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Email.TYPE, Email.TYPE_OTHER);
+ mockNameValues.put(Email.ADDRESS, "address4");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Email.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(3, list.size());
+
+ ContentValues outputValues = list.get(0).getAfter();
+ assertEquals(Email.TYPE_CUSTOM, outputValues.getAsInteger(Email.TYPE).intValue());
+ assertEquals("custom_type", outputValues.getAsString(Email.LABEL));
+ assertEquals("address1", outputValues.getAsString(Email.ADDRESS));
+
+ outputValues = list.get(1).getAfter();
+ assertEquals(Email.TYPE_HOME, outputValues.getAsInteger(Email.TYPE).intValue());
+ assertEquals("address2", outputValues.getAsString(Email.ADDRESS));
+
+ outputValues = list.get(2).getAfter();
+ assertEquals(Email.TYPE_WORK, outputValues.getAsInteger(Email.TYPE).intValue());
+ assertEquals("address3", outputValues.getAsString(Email.ADDRESS));
+ }
+
+ public void testMigrateImFromGoogleToExchange() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(Im.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ // Exchange doesn't support TYPE_HOME
+ mockNameValues.put(Im.TYPE, Im.TYPE_HOME);
+ mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_JABBER);
+ mockNameValues.put(Im.DATA, "im1");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ // Exchange doesn't support TYPE_WORK
+ mockNameValues.put(Im.TYPE, Im.TYPE_WORK);
+ mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_YAHOO);
+ mockNameValues.put(Im.DATA, "im2");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Im.TYPE, Im.TYPE_OTHER);
+ mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM);
+ mockNameValues.put(Im.CUSTOM_PROTOCOL, "custom_protocol");
+ mockNameValues.put(Im.DATA, "im3");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ // Exchange can have up to 3 IM entries. This 4th entry should be dropped.
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Im.TYPE, Im.TYPE_OTHER);
+ mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
+ mockNameValues.put(Im.DATA, "im4");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Im.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(3, list.size());
+
+ assertNotNull(kind.defaultValues.getAsInteger(Im.TYPE));
+
+ int defaultType = kind.defaultValues.getAsInteger(Im.TYPE);
+
+ ContentValues outputValues = list.get(0).getAfter();
+ // HOME should become default type.
+ assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
+ assertEquals(Im.PROTOCOL_JABBER, outputValues.getAsInteger(Im.PROTOCOL).intValue());
+ assertEquals("im1", outputValues.getAsString(Im.DATA));
+
+ outputValues = list.get(1).getAfter();
+ assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
+ assertEquals(Im.PROTOCOL_YAHOO, outputValues.getAsInteger(Im.PROTOCOL).intValue());
+ assertEquals("im2", outputValues.getAsString(Im.DATA));
+
+ outputValues = list.get(2).getAfter();
+ assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
+ assertEquals(Im.PROTOCOL_CUSTOM, outputValues.getAsInteger(Im.PROTOCOL).intValue());
+ assertEquals("custom_protocol", outputValues.getAsString(Im.CUSTOM_PROTOCOL));
+ assertEquals("im3", outputValues.getAsString(Im.DATA));
+ }
+
+ public void testMigratePhoneFromGoogleToExchange() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+
+ // Create 5 numbers.
+ // - "1" -- HOME
+ // - "2" -- WORK
+ // - "3" -- CUSTOM
+ // - "4" -- WORK
+ // - "5" -- WORK_MOBILE
+ // Then we convert it to Exchange account type.
+ // - "1" -- HOME
+ // - "2" -- WORK
+ // - "3" -- Because CUSTOM is not supported, it'll be changed to the default, MOBILE
+ // - "4" -- WORK
+ // - "5" -- WORK_MOBILE not suppoted again, so will be MOBILE.
+ // But then, Exchange doesn't support multiple MOBILE numbers, so "5" will be removed.
+ // i.e. the result will be:
+ // - "1" -- HOME
+ // - "2" -- WORK
+ // - "3" -- MOBILE
+ // - "4" -- WORK
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Phone.TYPE, Phone.TYPE_HOME);
+ mockNameValues.put(Phone.NUMBER, "1");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK);
+ mockNameValues.put(Phone.NUMBER, "2");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ // Exchange doesn't support this type. Default to MOBILE
+ mockNameValues.put(Phone.TYPE, Phone.TYPE_CUSTOM);
+ mockNameValues.put(Phone.LABEL, "custom_type");
+ mockNameValues.put(Phone.NUMBER, "3");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK);
+ mockNameValues.put(Phone.NUMBER, "4");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+
+ mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK_MOBILE);
+ mockNameValues.put(Phone.NUMBER, "5");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(4, list.size());
+
+ int defaultType = Phone.TYPE_MOBILE;
+
+ ContentValues outputValues = list.get(0).getAfter();
+ assertEquals(Phone.TYPE_HOME, outputValues.getAsInteger(Phone.TYPE).intValue());
+ assertEquals("1", outputValues.getAsString(Phone.NUMBER));
+ outputValues = list.get(1).getAfter();
+ assertEquals(Phone.TYPE_WORK, outputValues.getAsInteger(Phone.TYPE).intValue());
+ assertEquals("2", outputValues.getAsString(Phone.NUMBER));
+ outputValues = list.get(2).getAfter();
+ assertEquals(defaultType, outputValues.getAsInteger(Phone.TYPE).intValue());
+ assertNull(outputValues.getAsInteger(Phone.LABEL));
+ assertEquals("3", outputValues.getAsString(Phone.NUMBER));
+ outputValues = list.get(3).getAfter();
+ assertEquals(Phone.TYPE_WORK, outputValues.getAsInteger(Phone.TYPE).intValue());
+ assertEquals("4", outputValues.getAsString(Phone.NUMBER));
+ }
+
+ public void testMigrateOrganizationFromGoogleToExchange() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Organization.COMPANY, "company1");
+ mockNameValues.put(Organization.DEPARTMENT, "department1");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithoutTypeColumn(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Organization.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size());
+
+ ContentValues outputValues = list.get(0).getAfter();
+ assertEquals("company1", outputValues.getAsString(Organization.COMPANY));
+ assertEquals("department1", outputValues.getAsString(Organization.DEPARTMENT));
+ }
+}