149d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey/*
249d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey * Copyright (C) 2009 The Android Open Source Project
349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey *
449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
549d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey * you may not use this file except in compliance with the License.
649d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey * You may obtain a copy of the License at
749d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey *
849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey *
1049d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
1149d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
1249d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey * See the License for the specific language governing permissions and
1449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey * limitations under the License.
1549d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey */
1649d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
1749d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkeypackage com.android.contacts;
1849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
1988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkeyimport static android.content.ContentProviderOperation.TYPE_ASSERT;
2088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkeyimport static android.content.ContentProviderOperation.TYPE_DELETE;
2188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkeyimport static android.content.ContentProviderOperation.TYPE_INSERT;
2288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkeyimport static android.content.ContentProviderOperation.TYPE_UPDATE;
2388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
2449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkeyimport android.content.ContentProviderOperation;
2549d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkeyimport android.content.ContentValues;
26851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport android.content.Context;
2788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkeyimport android.net.Uri;
2888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkeyimport android.provider.BaseColumns;
2949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkeyimport android.provider.ContactsContract.AggregationExceptions;
307173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Email;
3188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds.Phone;
32e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport android.provider.ContactsContract.Data;
33e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport android.provider.ContactsContract.RawContacts;
3449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkeyimport android.test.AndroidTestCase;
3549d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkeyimport android.test.suitebuilder.annotation.LargeTest;
3649d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
37851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.RawContactModifierTests.MockContactsSource;
38851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContact;
39851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactDelta;
40851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactDelta.ValuesDelta;
41851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactDeltaList;
42851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactModifier;
43851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.account.AccountType;
44e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.collect.Lists;
45e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
467173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkeyimport java.lang.reflect.Field;
4749d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkeyimport java.util.ArrayList;
4849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
4949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey/**
50851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu * Tests for {@link RawContactDeltaList} which focus on "diff" operations that should
5149d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey * create {@link AggregationExceptions} in certain cases.
5249d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey */
5349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey@LargeTest
54851222a96b5d68602fb361ea3527101e893f67e3Maurice Chupublic class RawContactDeltaListTests extends AndroidTestCase {
55851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    public static final String TAG = RawContactDeltaListTests.class.getSimpleName();
5649d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
5749d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    private static final long CONTACT_FIRST = 1;
5849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    private static final long CONTACT_SECOND = 2;
5949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
6088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public static final long CONTACT_BOB = 10;
6188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public static final long CONTACT_MARY = 11;
6288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
6388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public static final long PHONE_RED = 20;
6488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public static final long PHONE_GREEN = 21;
6588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public static final long PHONE_BLUE = 22;
6688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
677173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    public static final long EMAIL_YELLOW = 25;
687173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
6988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public static final long VER_FIRST = 100;
7088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public static final long VER_SECOND = 200;
7188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
727173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    public static final String TEST_PHONE = "555-1212";
737173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    public static final String TEST_ACCOUNT = "org.example.test";
747173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
75851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    public RawContactDeltaListTests() {
7649d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        super();
7749d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    }
7849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
7949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    @Override
8049d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    public void setUp() {
8149d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        mContext = getContext();
8249d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    }
8349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
847173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    /**
854597c92d655d45447780b32c7572acef110b6ed1Dmitri Plotnikov     * Build a {@link AccountType} that has various odd constraints for
867173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey     * testing purposes.
877173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey     */
88b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov    protected AccountType getAccountType() {
89b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov        return new MockContactsSource();
907173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
917173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
92e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentValues getValues(ContentProviderOperation operation)
937173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey            throws NoSuchFieldException, IllegalAccessException {
947173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final Field field = ContentProviderOperation.class.getDeclaredField("mValues");
957173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        field.setAccessible(true);
967173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        return (ContentValues) field.get(operation);
977173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
987173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
99851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    static RawContactDelta getUpdate(Context context, long rawContactId) {
100851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContact before = RawContactDeltaTests.getRawContact(context, rawContactId,
101851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                RawContactDeltaTests.TEST_PHONE_ID);
102851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        return RawContactDelta.fromBefore(before);
10349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    }
10449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
105851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    static RawContactDelta getInsert() {
10649d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final ContentValues after = new ContentValues();
107851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        after.put(RawContacts.ACCOUNT_NAME, RawContactDeltaTests.TEST_ACCOUNT_NAME);
10849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
10949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
11049d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final ValuesDelta values = ValuesDelta.fromAfter(after);
111851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        return new RawContactDelta(values);
11249d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    }
11349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
114851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    static RawContactDeltaList buildSet(RawContactDelta... deltas) {
115851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList set = RawContactDeltaList.fromSingle(deltas[0]);
11649d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        for (int i = 1; i < deltas.length; i++) {
11749d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey            set.add(deltas[i]);
11849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        }
11949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        return set;
12049d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    }
12149d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
122851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    static RawContactDelta buildBeforeEntity(Context context, long rawContactId, long version,
12388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            ContentValues... entries) {
12488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Build an existing contact read from database
12588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        final ContentValues contact = new ContentValues();
12688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        contact.put(RawContacts.VERSION, version);
12788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        contact.put(RawContacts._ID, rawContactId);
128851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContact before = new RawContact(context, contact);
12988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        for (ContentValues entry : entries) {
130851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            before.addDataItemValues(entry);
13188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        }
132851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        return RawContactDelta.fromBefore(before);
13388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
13488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
135851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    static RawContactDelta buildAfterEntity(ContentValues... entries) {
13688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Build an existing contact read from database
13788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        final ContentValues contact = new ContentValues();
1387173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        contact.put(RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT);
139851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta after = new RawContactDelta(ValuesDelta.fromAfter(contact));
14088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        for (ContentValues entry : entries) {
14188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            after.addEntry(ValuesDelta.fromAfter(entry));
14288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        }
14388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        return after;
14488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
14588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
146e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentValues buildPhone(long phoneId) {
14788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        return buildPhone(phoneId, Long.toString(phoneId));
14888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
14988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
150e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentValues buildPhone(long phoneId, String value) {
15188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        final ContentValues values = new ContentValues();
15288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        values.put(Data._ID, phoneId);
15388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
15488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        values.put(Phone.NUMBER, value);
15588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        values.put(Phone.TYPE, Phone.TYPE_HOME);
15688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        return values;
15788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
15888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
159e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentValues buildEmail(long emailId) {
1607173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ContentValues values = new ContentValues();
1617173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        values.put(Data._ID, emailId);
1627173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
1637173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        values.put(Email.DATA, Long.toString(emailId));
1647173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        values.put(Email.TYPE, Email.TYPE_HOME);
1657173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        return values;
1667173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
1677173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
168851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    static void insertPhone(RawContactDeltaList set, long rawContactId, ContentValues values) {
169851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta match = set.getByRawContactId(rawContactId);
17088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        match.addEntry(ValuesDelta.fromAfter(values));
17188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
17288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
173851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    static ValuesDelta getPhone(RawContactDeltaList set, long rawContactId, long dataId) {
174851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta match = set.getByRawContactId(rawContactId);
17588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        return match.getEntry(dataId);
17688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
17788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
178851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    static void assertDiffPattern(RawContactDelta delta, ContentProviderOperation... pattern) {
179e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey        final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
180e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey        delta.buildAssert(diff);
181e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey        delta.buildDiff(diff);
182e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey        assertDiffPattern(diff, pattern);
183e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    }
184e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey
185851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    static void assertDiffPattern(RawContactDeltaList set, ContentProviderOperation... pattern) {
186e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey        assertDiffPattern(set.buildDiff(), pattern);
187e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    }
18888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
189e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static void assertDiffPattern(ArrayList<ContentProviderOperation> diff,
190e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey            ContentProviderOperation... pattern) {
19188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertEquals("Unexpected operations", pattern.length, diff.size());
19288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        for (int i = 0; i < pattern.length; i++) {
19388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            final ContentProviderOperation expected = pattern[i];
19488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            final ContentProviderOperation found = diff.get(i);
19588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
1967173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey            assertEquals("Unexpected uri", expected.getUri(), found.getUri());
1977173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
19888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            final String expectedType = getStringForType(expected.getType());
19988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            final String foundType = getStringForType(found.getType());
20088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            assertEquals("Unexpected type", expectedType, foundType);
2017173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
2027173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey            if (expected.getType() == TYPE_DELETE) continue;
2037173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
2047173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey            try {
2057173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                final ContentValues expectedValues = getValues(expected);
2067173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                final ContentValues foundValues = getValues(found);
2077173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
2087173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                expectedValues.remove(BaseColumns._ID);
2097173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                foundValues.remove(BaseColumns._ID);
2107173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
2117173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                assertEquals("Unexpected values", expectedValues, foundValues);
2127173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey            } catch (NoSuchFieldException e) {
2137173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                fail(e.toString());
2147173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey            } catch (IllegalAccessException e) {
2157173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                fail(e.toString());
2167173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey            }
21788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        }
21888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
21988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
220e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static String getStringForType(int type) {
22188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        switch (type) {
22288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            case TYPE_ASSERT: return "TYPE_ASSERT";
22388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            case TYPE_INSERT: return "TYPE_INSERT";
22488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            case TYPE_UPDATE: return "TYPE_UPDATE";
22588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            case TYPE_DELETE: return "TYPE_DELETE";
22688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            default: return Integer.toString(type);
22788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        }
22888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
22988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
230e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentProviderOperation buildAssertVersion(long version) {
2317173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ContentValues values = new ContentValues();
2327173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        values.put(RawContacts.VERSION, version);
2337173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        return buildOper(RawContacts.CONTENT_URI, TYPE_ASSERT, values);
2347173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
2357173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
236e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentProviderOperation buildAggregationModeUpdate(int mode) {
23788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        final ContentValues values = new ContentValues();
2387173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        values.put(RawContacts.AGGREGATION_MODE, mode);
2397173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        return buildOper(RawContacts.CONTENT_URI, TYPE_UPDATE, values);
2407173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
2417173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
242e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentProviderOperation buildUpdateAggregationSuspended() {
2437173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        return buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_SUSPENDED);
2447173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
2457173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
246e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentProviderOperation buildUpdateAggregationDefault() {
2477173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        return buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT);
2487173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
2497173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
250e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentProviderOperation buildUpdateAggregationKeepTogether(long rawContactId) {
2517173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ContentValues values = new ContentValues();
2527173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId);
2537173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        values.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
2547173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        return buildOper(AggregationExceptions.CONTENT_URI, TYPE_UPDATE, values);
2557173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
2567173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
257e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentValues buildDataInsert(ValuesDelta values, long rawContactId) {
2587173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ContentValues insertValues = values.getCompleteValues();
2597173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        insertValues.put(Data.RAW_CONTACT_ID, rawContactId);
2607173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        return insertValues;
2617173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
2627173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
263e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentProviderOperation buildDelete(Uri uri) {
2647173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        return buildOper(uri, TYPE_DELETE, (ContentValues)null);
2657173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
2667173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
267e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentProviderOperation buildOper(Uri uri, int type, ValuesDelta values) {
2687173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        return buildOper(uri, type, values.getCompleteValues());
2697173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
2707173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
271e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static ContentProviderOperation buildOper(Uri uri, int type, ContentValues values) {
27288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        switch (type) {
27388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            case TYPE_ASSERT:
27488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey                return ContentProviderOperation.newAssertQuery(uri).withValues(values).build();
27588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            case TYPE_INSERT:
27688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey                return ContentProviderOperation.newInsert(uri).withValues(values).build();
27788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            case TYPE_UPDATE:
27888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey                return ContentProviderOperation.newUpdate(uri).withValues(values).build();
27988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey            case TYPE_DELETE:
28088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey                return ContentProviderOperation.newDelete(uri).build();
28188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        }
28288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        return null;
28388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
28488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
285851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    static Long getVersion(RawContactDeltaList set, Long rawContactId) {
28688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        return set.getByRawContactId(rawContactId).getValues().getAsLong(RawContacts.VERSION);
28788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
28888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
28949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    /**
29049d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey     * Count number of {@link AggregationExceptions} updates contained in the
29149d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey     * given list of {@link ContentProviderOperation}.
29249d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey     */
293e31dac84479a4c7b356edfc062a447cdfb5efc69Jeff Sharkey    static int countExceptionUpdates(ArrayList<ContentProviderOperation> diff) {
29449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        int updateCount = 0;
29549d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        for (ContentProviderOperation oper : diff) {
29649d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey            if (AggregationExceptions.CONTENT_URI.equals(oper.getUri())
29749d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey                    && oper.getType() == ContentProviderOperation.TYPE_UPDATE) {
29849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey                updateCount++;
29949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey            }
30049d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        }
30149d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        return updateCount;
30249d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    }
30349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
30449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    public void testInsert() {
305851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta insert = getInsert();
306851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList set = buildSet(insert);
30749d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
30849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        // Inserting single shouldn't create rules
30949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final ArrayList<ContentProviderOperation> diff = set.buildDiff();
31049d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final int exceptionCount = countExceptionUpdates(diff);
31149d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        assertEquals("Unexpected exception updates", 0, exceptionCount);
31249d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    }
31349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
31449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    public void testUpdateUpdate() {
315851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta updateFirst = getUpdate(mContext, CONTACT_FIRST);
316851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta updateSecond = getUpdate(mContext, CONTACT_SECOND);
317851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList set = buildSet(updateFirst, updateSecond);
31849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
31949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        // Updating two existing shouldn't create rules
32049d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final ArrayList<ContentProviderOperation> diff = set.buildDiff();
32149d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final int exceptionCount = countExceptionUpdates(diff);
32249d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        assertEquals("Unexpected exception updates", 0, exceptionCount);
32349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    }
32449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
32549d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    public void testUpdateInsert() {
326851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta update = getUpdate(mContext, CONTACT_FIRST);
327851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta insert = getInsert();
328851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList set = buildSet(update, insert);
32949d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
33049d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        // New insert should only create one rule
33149d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final ArrayList<ContentProviderOperation> diff = set.buildDiff();
33249d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final int exceptionCount = countExceptionUpdates(diff);
33349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        assertEquals("Unexpected exception updates", 1, exceptionCount);
33449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    }
33549d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
33649d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    public void testInsertUpdateInsert() {
337851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta insertFirst = getInsert();
338851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta update = getUpdate(mContext, CONTACT_FIRST);
339851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta insertSecond = getInsert();
340851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList set = buildSet(insertFirst, update, insertSecond);
34149d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
34249d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        // Two inserts should create two rules to bind against single existing
34349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final ArrayList<ContentProviderOperation> diff = set.buildDiff();
34449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final int exceptionCount = countExceptionUpdates(diff);
34549d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        assertEquals("Unexpected exception updates", 2, exceptionCount);
34649d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    }
34749d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
34849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    public void testInsertInsertInsert() {
349851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta insertFirst = getInsert();
350851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta insertSecond = getInsert();
351851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta insertThird = getInsert();
352851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList set = buildSet(insertFirst, insertSecond, insertThird);
35349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey
35449d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        // Three new inserts should create only two binding rules
35549d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final ArrayList<ContentProviderOperation> diff = set.buildDiff();
35649d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        final int exceptionCount = countExceptionUpdates(diff);
35749d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey        assertEquals("Unexpected exception updates", 2, exceptionCount);
35849d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey    }
35988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
36088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public void testMergeDataRemoteInsert() {
361851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
362851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_FIRST, buildPhone(PHONE_RED)));
363851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
364851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_SECOND, buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
36588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
36688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Merge in second version, verify they match
367851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
36888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertEquals("Unexpected change when merging", second, merged);
36988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
37088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
37188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public void testMergeDataLocalUpdateRemoteInsert() {
372851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
373851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_FIRST, buildPhone(PHONE_RED)));
374851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
375851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_SECOND, buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
37688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
37788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Change the local number to trigger update
3787173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
3797173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        phone.put(Phone.NUMBER, TEST_PHONE);
3807173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
38188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(first,
3827173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_FIRST),
3837173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationSuspended(),
3847173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
3857173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationDefault());
38688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
38788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Merge in the second version, verify diff matches
388851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
38988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(merged,
3907173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_SECOND),
3917173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationSuspended(),
3927173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
3937173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationDefault());
39488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
39588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
39688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public void testMergeDataLocalUpdateRemoteDelete() {
397851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
398851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_FIRST, buildPhone(PHONE_RED)));
399851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
400851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_SECOND, buildPhone(PHONE_GREEN)));
40188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
40288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Change the local number to trigger update
4037173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
4047173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        phone.put(Phone.NUMBER, TEST_PHONE);
4057173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
40688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(first,
4077173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_FIRST),
4087173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationSuspended(),
4097173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
4107173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationDefault());
41188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
41288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Merge in the second version, verify that our update changed to
41388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // insert, since RED was deleted on remote side
414851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
41588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(merged,
4167173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_SECOND),
4177173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationSuspended(),
4187173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(phone, CONTACT_BOB)),
4197173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationDefault());
42088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
42188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
42288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public void testMergeDataLocalDeleteRemoteUpdate() {
423851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
424851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_FIRST, buildPhone(PHONE_RED)));
425851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
426851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_SECOND, buildPhone(PHONE_RED, TEST_PHONE)));
42788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
42888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Delete phone locally
4297173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
4307173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        phone.markDeleted();
4317173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
43288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(first,
4337173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_FIRST),
4347173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationSuspended(),
4357173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildDelete(Data.CONTENT_URI),
4367173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationDefault());
43788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
43888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Merge in the second version, verify that our delete remains
439851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
44088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(merged,
4417173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_SECOND),
4427173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationSuspended(),
4437173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildDelete(Data.CONTENT_URI),
4447173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationDefault());
44588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
44688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
44788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public void testMergeDataLocalInsertRemoteInsert() {
448851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
449851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_FIRST, buildPhone(PHONE_RED)));
450851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
451851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_SECOND, buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
45288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
45388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Insert new phone locally
45488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        final ValuesDelta bluePhone = ValuesDelta.fromAfter(buildPhone(PHONE_BLUE));
45588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        first.getByRawContactId(CONTACT_BOB).addEntry(bluePhone);
45688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(first,
4577173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_FIRST),
4587173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationSuspended(),
4597173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bluePhone, CONTACT_BOB)),
4607173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationDefault());
46188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
46288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Merge in the second version, verify that our insert remains
463851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
46488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(merged,
4657173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_SECOND),
4667173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationSuspended(),
4677173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bluePhone, CONTACT_BOB)),
4687173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationDefault());
46988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
47088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
47188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public void testMergeRawContactLocalInsertRemoteInsert() {
472851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
473851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_FIRST, buildPhone(PHONE_RED)));
474851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
475851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_SECOND, buildPhone(PHONE_RED)), buildBeforeEntity(mContext, CONTACT_MARY,
476851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                        VER_SECOND, buildPhone(PHONE_RED)));
47788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
47888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Add new contact locally, should remain insert
4797173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ContentValues joePhoneInsert = buildPhone(PHONE_BLUE);
480851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta joeContact = buildAfterEntity(joePhoneInsert);
4817173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ContentValues joeContactInsert = joeContact.getValues().getCompleteValues();
482c7c1905d60786936527e4baa0c131d435d8bbdb5Dmitri Plotnikov        joeContactInsert.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
48388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        first.add(joeContact);
48488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(first,
4857173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_FIRST),
4867173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(RawContacts.CONTENT_URI, TYPE_INSERT, joeContactInsert),
4877173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(Data.CONTENT_URI, TYPE_INSERT, joePhoneInsert),
4883aba36cc373e82ca3a3331bb77bd1278d0afde06Dmitri Plotnikov                buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
4897173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationKeepTogether(CONTACT_BOB));
49088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
49188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Merge in the second version, verify that our insert remains
492851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
49388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(merged,
4947173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_SECOND),
4957173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_SECOND),
4967173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(RawContacts.CONTENT_URI, TYPE_INSERT, joeContactInsert),
4977173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(Data.CONTENT_URI, TYPE_INSERT, joePhoneInsert),
4983aba36cc373e82ca3a3331bb77bd1278d0afde06Dmitri Plotnikov                buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
4997173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationKeepTogether(CONTACT_BOB));
50088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
50188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
50288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public void testMergeRawContactLocalDeleteRemoteDelete() {
503851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList first = buildSet(
504851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                buildBeforeEntity(mContext, CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
505851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                buildBeforeEntity(mContext, CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
506851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList second = buildSet(
507851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                buildBeforeEntity(mContext, CONTACT_BOB, VER_SECOND, buildPhone(PHONE_RED)));
50888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
50988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Remove contact locally
51088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        first.getByRawContactId(CONTACT_MARY).markDeleted();
51188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(first,
5127173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_FIRST),
5137173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_FIRST),
5147173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildDelete(RawContacts.CONTENT_URI));
51588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
51688d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Merge in the second version, verify that our delete isn't needed
517851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
51888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(merged);
51988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
52088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
52188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public void testMergeRawContactLocalUpdateRemoteDelete() {
522851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList first = buildSet(
523851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                buildBeforeEntity(mContext, CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
524851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                buildBeforeEntity(mContext, CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
525851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList second = buildSet(
526851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                buildBeforeEntity(mContext, CONTACT_BOB, VER_SECOND, buildPhone(PHONE_RED)));
52788d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
52888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Perform local update
5297173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ValuesDelta phone = getPhone(first, CONTACT_MARY, PHONE_RED);
5307173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        phone.put(Phone.NUMBER, TEST_PHONE);
53188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(first,
5327173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_FIRST),
5337173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_FIRST),
5347173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationSuspended(),
5357173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
5367173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationDefault());
5377173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
5387173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ContentValues phoneInsert = phone.getCompleteValues();
5397173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ContentValues contactInsert = first.getByRawContactId(CONTACT_MARY).getValues()
5407173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                .getCompleteValues();
541c7c1905d60786936527e4baa0c131d435d8bbdb5Dmitri Plotnikov        contactInsert.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
54288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
54388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        // Merge and verify that update turned into insert
544851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
54588d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertDiffPattern(merged,
5467173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_SECOND),
5477173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(RawContacts.CONTENT_URI, TYPE_INSERT, contactInsert),
5487173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(Data.CONTENT_URI, TYPE_INSERT, phoneInsert),
5493aba36cc373e82ca3a3331bb77bd1278d0afde06Dmitri Plotnikov                buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
5507173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationKeepTogether(CONTACT_BOB));
55188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
55288d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
55388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    public void testMergeUsesNewVersion() {
554851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
555851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_FIRST, buildPhone(PHONE_RED)));
556851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
557851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_SECOND, buildPhone(PHONE_RED)));
55888d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
55988d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertEquals((Long)VER_FIRST, getVersion(first, CONTACT_BOB));
56088d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertEquals((Long)VER_SECOND, getVersion(second, CONTACT_BOB));
56188d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey
562851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
56388d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey        assertEquals((Long)VER_SECOND, getVersion(merged, CONTACT_BOB));
56488d00c2450a0a16bf1dd35e9f3c9ba843a97ec62Jeff Sharkey    }
5657173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
5667173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    public void testMergeAfterEnsureAndTrim() {
567851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
568851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_FIRST, buildEmail(EMAIL_YELLOW)));
569851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
570851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                VER_SECOND, buildEmail(EMAIL_YELLOW)));
5717173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
5727173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        // Ensure we have at least one phone
573b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov        final AccountType source = getAccountType();
574851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta bobContact = first.getByRawContactId(CONTACT_BOB);
575851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.ensureKindExists(bobContact, source, Phone.CONTENT_ITEM_TYPE);
5767173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        final ValuesDelta bobPhone = bobContact.getSuperPrimaryEntry(Phone.CONTENT_ITEM_TYPE, true);
5777173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
5787173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        // Make sure the update would insert a row
5797173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        assertDiffPattern(first,
5807173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildAssertVersion(VER_FIRST),
5817173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationSuspended(),
5827173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bobPhone, CONTACT_BOB)),
5837173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey                buildUpdateAggregationDefault());
5847173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
5857173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        // Trim values and ensure that we don't insert things
586851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.trimEmpty(bobContact, source);
5877173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        assertDiffPattern(first);
5887173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey
5897173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        // Now re-parent the change, which should remain no-op
590851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
5917173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey        assertDiffPattern(merged);
5927173705177c421e0b2a3bc4579b2f8910a38a668Jeff Sharkey    }
59349d17b3e7692ae9442c342db236fa93d4a837c28Jeff Sharkey}
594