12644d947574240b71c427d457f7a775dc160ec09Yorke Lee/*
22644d947574240b71c427d457f7a775dc160ec09Yorke Lee * Copyright (C) 2009 The Android Open Source Project
32644d947574240b71c427d457f7a775dc160ec09Yorke Lee *
42644d947574240b71c427d457f7a775dc160ec09Yorke Lee * Licensed under the Apache License, Version 2.0 (the "License");
52644d947574240b71c427d457f7a775dc160ec09Yorke Lee * you may not use this file except in compliance with the License.
62644d947574240b71c427d457f7a775dc160ec09Yorke Lee * You may obtain a copy of the License at
72644d947574240b71c427d457f7a775dc160ec09Yorke Lee *
82644d947574240b71c427d457f7a775dc160ec09Yorke Lee *      http://www.apache.org/licenses/LICENSE-2.0
92644d947574240b71c427d457f7a775dc160ec09Yorke Lee *
102644d947574240b71c427d457f7a775dc160ec09Yorke Lee * Unless required by applicable law or agreed to in writing, software
112644d947574240b71c427d457f7a775dc160ec09Yorke Lee * distributed under the License is distributed on an "AS IS" BASIS,
122644d947574240b71c427d457f7a775dc160ec09Yorke Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132644d947574240b71c427d457f7a775dc160ec09Yorke Lee * See the License for the specific language governing permissions and
142644d947574240b71c427d457f7a775dc160ec09Yorke Lee * limitations under the License.
152644d947574240b71c427d457f7a775dc160ec09Yorke Lee */
162644d947574240b71c427d457f7a775dc160ec09Yorke Lee
170a49afa2ad697307cc04ef4cb86570574fa720f2Gary Maipackage com.android.contacts.model;
182644d947574240b71c427d457f7a775dc160ec09Yorke Lee
192644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.content.ContentProviderOperation;
202644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.content.ContentValues;
212644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.content.Context;
222644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.net.Uri;
232644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.provider.BaseColumns;
242644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.provider.ContactsContract.AggregationExceptions;
252644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.provider.ContactsContract.CommonDataKinds.Email;
262644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.provider.ContactsContract.CommonDataKinds.Phone;
272644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.provider.ContactsContract.Data;
282644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.provider.ContactsContract.RawContacts;
292644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.test.AndroidTestCase;
302644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport android.test.suitebuilder.annotation.LargeTest;
312644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3269c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.compat.CompatUtils;
3369c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.model.account.AccountType;
342644d947574240b71c427d457f7a775dc160ec09Yorke Lee
350a49afa2ad697307cc04ef4cb86570574fa720f2Gary Maiimport com.google.common.collect.Lists;
362644d947574240b71c427d457f7a775dc160ec09Yorke Lee
372644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport java.lang.reflect.Field;
382644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport java.util.ArrayList;
392644d947574240b71c427d457f7a775dc160ec09Yorke Leeimport java.util.Collections;
402644d947574240b71c427d457f7a775dc160ec09Yorke Lee
412644d947574240b71c427d457f7a775dc160ec09Yorke Lee/**
422644d947574240b71c427d457f7a775dc160ec09Yorke Lee * Tests for {@link RawContactDeltaList} which focus on "diff" operations that should
432644d947574240b71c427d457f7a775dc160ec09Yorke Lee * create {@link AggregationExceptions} in certain cases.
442644d947574240b71c427d457f7a775dc160ec09Yorke Lee */
452644d947574240b71c427d457f7a775dc160ec09Yorke Lee@LargeTest
462644d947574240b71c427d457f7a775dc160ec09Yorke Leepublic class RawContactDeltaListTests extends AndroidTestCase {
477bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner    // From android.content.ContentProviderOperation
487bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner    public static final int TYPE_INSERT = 1;
497bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner    public static final int TYPE_UPDATE = 2;
507bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner    public static final int TYPE_DELETE = 3;
517bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner    public static final int TYPE_ASSERT = 4;
527bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner
532644d947574240b71c427d457f7a775dc160ec09Yorke Lee    private static final long CONTACT_FIRST = 1;
542644d947574240b71c427d457f7a775dc160ec09Yorke Lee    private static final long CONTACT_SECOND = 2;
552644d947574240b71c427d457f7a775dc160ec09Yorke Lee
562644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public static final long CONTACT_BOB = 10;
572644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public static final long CONTACT_MARY = 11;
582644d947574240b71c427d457f7a775dc160ec09Yorke Lee
592644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public static final long PHONE_RED = 20;
602644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public static final long PHONE_GREEN = 21;
612644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public static final long PHONE_BLUE = 22;
622644d947574240b71c427d457f7a775dc160ec09Yorke Lee
632644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public static final long EMAIL_YELLOW = 25;
642644d947574240b71c427d457f7a775dc160ec09Yorke Lee
652644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public static final long VER_FIRST = 100;
662644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public static final long VER_SECOND = 200;
672644d947574240b71c427d457f7a775dc160ec09Yorke Lee
682644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public static final String TEST_PHONE = "555-1212";
692644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public static final String TEST_ACCOUNT = "org.example.test";
702644d947574240b71c427d457f7a775dc160ec09Yorke Lee
712644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public RawContactDeltaListTests() {
722644d947574240b71c427d457f7a775dc160ec09Yorke Lee        super();
732644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
742644d947574240b71c427d457f7a775dc160ec09Yorke Lee
752644d947574240b71c427d457f7a775dc160ec09Yorke Lee    @Override
762644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void setUp() {
772644d947574240b71c427d457f7a775dc160ec09Yorke Lee        mContext = getContext();
782644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
792644d947574240b71c427d457f7a775dc160ec09Yorke Lee
802644d947574240b71c427d457f7a775dc160ec09Yorke Lee    /**
812644d947574240b71c427d457f7a775dc160ec09Yorke Lee     * Build a {@link AccountType} that has various odd constraints for
822644d947574240b71c427d457f7a775dc160ec09Yorke Lee     * testing purposes.
832644d947574240b71c427d457f7a775dc160ec09Yorke Lee     */
842644d947574240b71c427d457f7a775dc160ec09Yorke Lee    protected AccountType getAccountType() {
850a49afa2ad697307cc04ef4cb86570574fa720f2Gary Mai        return new RawContactModifierTests.MockContactsSource();
862644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
872644d947574240b71c427d457f7a775dc160ec09Yorke Lee
882644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static ContentValues getValues(ContentProviderOperation operation)
892644d947574240b71c427d457f7a775dc160ec09Yorke Lee            throws NoSuchFieldException, IllegalAccessException {
902644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final Field field = ContentProviderOperation.class.getDeclaredField("mValues");
912644d947574240b71c427d457f7a775dc160ec09Yorke Lee        field.setAccessible(true);
922644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return (ContentValues) field.get(operation);
932644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
942644d947574240b71c427d457f7a775dc160ec09Yorke Lee
952644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static RawContactDelta getUpdate(Context context, long rawContactId) {
962644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContact before = RawContactDeltaTests.getRawContact(context, rawContactId,
972644d947574240b71c427d457f7a775dc160ec09Yorke Lee                RawContactDeltaTests.TEST_PHONE_ID);
982644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return RawContactDelta.fromBefore(before);
992644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1002644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1012644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static RawContactDelta getInsert() {
1022644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues after = new ContentValues();
1032644d947574240b71c427d457f7a775dc160ec09Yorke Lee        after.put(RawContacts.ACCOUNT_NAME, RawContactDeltaTests.TEST_ACCOUNT_NAME);
1042644d947574240b71c427d457f7a775dc160ec09Yorke Lee        after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
1052644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1062644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ValuesDelta values = ValuesDelta.fromAfter(after);
1072644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return new RawContactDelta(values);
1082644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1092644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1102644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static RawContactDeltaList buildSet(RawContactDelta... deltas) {
1112644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList set = new RawContactDeltaList();
1122644d947574240b71c427d457f7a775dc160ec09Yorke Lee        Collections.addAll(set, deltas);
1132644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return set;
1142644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1152644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1162644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static RawContactDelta buildBeforeEntity(Context context, long rawContactId, long version,
1172644d947574240b71c427d457f7a775dc160ec09Yorke Lee            ContentValues... entries) {
1182644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Build an existing contact read from database
1192644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues contact = new ContentValues();
1202644d947574240b71c427d457f7a775dc160ec09Yorke Lee        contact.put(RawContacts.VERSION, version);
1212644d947574240b71c427d457f7a775dc160ec09Yorke Lee        contact.put(RawContacts._ID, rawContactId);
1222644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContact before = new RawContact(contact);
1232644d947574240b71c427d457f7a775dc160ec09Yorke Lee        for (ContentValues entry : entries) {
1242644d947574240b71c427d457f7a775dc160ec09Yorke Lee            before.addDataItemValues(entry);
1252644d947574240b71c427d457f7a775dc160ec09Yorke Lee        }
1262644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return RawContactDelta.fromBefore(before);
1272644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1282644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1292644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static RawContactDelta buildAfterEntity(ContentValues... entries) {
1302644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Build an existing contact read from database
1312644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues contact = new ContentValues();
1322644d947574240b71c427d457f7a775dc160ec09Yorke Lee        contact.put(RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT);
1332644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta after = new RawContactDelta(ValuesDelta.fromAfter(contact));
1342644d947574240b71c427d457f7a775dc160ec09Yorke Lee        for (ContentValues entry : entries) {
1352644d947574240b71c427d457f7a775dc160ec09Yorke Lee            after.addEntry(ValuesDelta.fromAfter(entry));
1362644d947574240b71c427d457f7a775dc160ec09Yorke Lee        }
1372644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return after;
1382644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1392644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1402644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static ContentValues buildPhone(long phoneId) {
1412644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return buildPhone(phoneId, Long.toString(phoneId));
1422644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1432644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1442644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static ContentValues buildPhone(long phoneId, String value) {
1452644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues values = new ContentValues();
1462644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(Data._ID, phoneId);
1472644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
1482644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(Phone.NUMBER, value);
1492644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(Phone.TYPE, Phone.TYPE_HOME);
1502644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return values;
1512644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1522644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1532644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static ContentValues buildEmail(long emailId) {
1542644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues values = new ContentValues();
1552644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(Data._ID, emailId);
1562644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
1572644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(Email.DATA, Long.toString(emailId));
1582644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(Email.TYPE, Email.TYPE_HOME);
1592644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return values;
1602644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1612644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1622644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static void insertPhone(RawContactDeltaList set, long rawContactId, ContentValues values) {
1632644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta match = set.getByRawContactId(rawContactId);
1642644d947574240b71c427d457f7a775dc160ec09Yorke Lee        match.addEntry(ValuesDelta.fromAfter(values));
1652644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1662644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1672644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static ValuesDelta getPhone(RawContactDeltaList set, long rawContactId, long dataId) {
1682644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta match = set.getByRawContactId(rawContactId);
1692644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return match.getEntry(dataId);
1702644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1712644d947574240b71c427d457f7a775dc160ec09Yorke Lee
172009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    static void assertDiffPattern(RawContactDelta delta, CPOWrapper... pattern) {
173009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        final ArrayList<CPOWrapper> diff = Lists.newArrayList();
174009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        delta.buildAssertWrapper(diff);
175009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        delta.buildDiffWrapper(diff);
1762644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(diff, pattern);
1772644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1782644d947574240b71c427d457f7a775dc160ec09Yorke Lee
179009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    static void assertDiffPattern(RawContactDeltaList set, CPOWrapper... pattern) {
180009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        assertDiffPattern(set.buildDiffWrapper(), pattern);
1812644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
1822644d947574240b71c427d457f7a775dc160ec09Yorke Lee
183009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    static void assertDiffPattern(ArrayList<CPOWrapper> diff, CPOWrapper... pattern) {
1842644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertEquals("Unexpected operations", pattern.length, diff.size());
1852644d947574240b71c427d457f7a775dc160ec09Yorke Lee        for (int i = 0; i < pattern.length; i++) {
186009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang            final CPOWrapper expected = pattern[i];
187009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang            final CPOWrapper found = diff.get(i);
1882644d947574240b71c427d457f7a775dc160ec09Yorke Lee
189009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang            assertEquals("Unexpected uri",
190009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                    expected.getOperation().getUri(), found.getOperation().getUri());
1912644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1927bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner            final String expectedType = getTypeString(expected);
1937bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner            final String foundType = getTypeString(found);
1942644d947574240b71c427d457f7a775dc160ec09Yorke Lee            assertEquals("Unexpected type", expectedType, foundType);
1952644d947574240b71c427d457f7a775dc160ec09Yorke Lee
196009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang            if (CompatUtils.isDeleteCompat(expected)) continue;
1972644d947574240b71c427d457f7a775dc160ec09Yorke Lee
1982644d947574240b71c427d457f7a775dc160ec09Yorke Lee            try {
199009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                final ContentValues expectedValues = getValues(expected.getOperation());
200009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                final ContentValues foundValues = getValues(found.getOperation());
2012644d947574240b71c427d457f7a775dc160ec09Yorke Lee
2022644d947574240b71c427d457f7a775dc160ec09Yorke Lee                expectedValues.remove(BaseColumns._ID);
2032644d947574240b71c427d457f7a775dc160ec09Yorke Lee                foundValues.remove(BaseColumns._ID);
2042644d947574240b71c427d457f7a775dc160ec09Yorke Lee
2052644d947574240b71c427d457f7a775dc160ec09Yorke Lee                assertEquals("Unexpected values", expectedValues, foundValues);
2062644d947574240b71c427d457f7a775dc160ec09Yorke Lee            } catch (NoSuchFieldException e) {
2072644d947574240b71c427d457f7a775dc160ec09Yorke Lee                fail(e.toString());
2082644d947574240b71c427d457f7a775dc160ec09Yorke Lee            } catch (IllegalAccessException e) {
2092644d947574240b71c427d457f7a775dc160ec09Yorke Lee                fail(e.toString());
2102644d947574240b71c427d457f7a775dc160ec09Yorke Lee            }
2112644d947574240b71c427d457f7a775dc160ec09Yorke Lee        }
2122644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2132644d947574240b71c427d457f7a775dc160ec09Yorke Lee
214009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    static String getTypeString(CPOWrapper cpoWrapper) {
215009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        if (CompatUtils.isAssertQueryCompat(cpoWrapper)) {
2167bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner            return "TYPE_ASSERT";
217009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        } else if (CompatUtils.isInsertCompat(cpoWrapper)) {
2187bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner            return "TYPE_INSERT";
219009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        } else if (CompatUtils.isUpdateCompat(cpoWrapper)) {
2207bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner            return "TYPE_UPDATE";
221009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        } else if (CompatUtils.isDeleteCompat(cpoWrapper)) {
2227bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner            return "TYPE_DELETE";
2232644d947574240b71c427d457f7a775dc160ec09Yorke Lee        }
2247bae063fae6b355fce1f91d342314f4d4798b30aJay Shrauner        return "TYPE_UNKNOWN";
2252644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2262644d947574240b71c427d457f7a775dc160ec09Yorke Lee
227009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    static CPOWrapper buildAssertVersion(long version) {
2282644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues values = new ContentValues();
2292644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(RawContacts.VERSION, version);
230009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        return buildCPOWrapper(RawContacts.CONTENT_URI, TYPE_ASSERT, values);
2312644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2322644d947574240b71c427d457f7a775dc160ec09Yorke Lee
233009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    static CPOWrapper buildAggregationModeUpdate(int mode) {
2342644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues values = new ContentValues();
2352644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(RawContacts.AGGREGATION_MODE, mode);
236009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        return buildCPOWrapper(RawContacts.CONTENT_URI, TYPE_UPDATE, values);
2372644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2382644d947574240b71c427d457f7a775dc160ec09Yorke Lee
239009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    static CPOWrapper buildUpdateAggregationSuspended() {
2402644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_SUSPENDED);
2412644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2422644d947574240b71c427d457f7a775dc160ec09Yorke Lee
243009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    static CPOWrapper buildUpdateAggregationDefault() {
2442644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT);
2452644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2462644d947574240b71c427d457f7a775dc160ec09Yorke Lee
247009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    static CPOWrapper buildUpdateAggregationKeepTogether(long rawContactId) {
2482644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues values = new ContentValues();
2492644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId);
2502644d947574240b71c427d457f7a775dc160ec09Yorke Lee        values.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
251009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        return buildCPOWrapper(AggregationExceptions.CONTENT_URI, TYPE_UPDATE, values);
2522644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2532644d947574240b71c427d457f7a775dc160ec09Yorke Lee
2542644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static ContentValues buildDataInsert(ValuesDelta values, long rawContactId) {
2552644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues insertValues = values.getCompleteValues();
2562644d947574240b71c427d457f7a775dc160ec09Yorke Lee        insertValues.put(Data.RAW_CONTACT_ID, rawContactId);
2572644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return insertValues;
2582644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2592644d947574240b71c427d457f7a775dc160ec09Yorke Lee
260009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    static CPOWrapper buildDelete(Uri uri) {
261009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        return buildCPOWrapper(uri, TYPE_DELETE, (ContentValues) null);
2622644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2632644d947574240b71c427d457f7a775dc160ec09Yorke Lee
2642644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static ContentProviderOperation buildOper(Uri uri, int type, ValuesDelta values) {
2652644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return buildOper(uri, type, values.getCompleteValues());
2662644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2672644d947574240b71c427d457f7a775dc160ec09Yorke Lee
2682644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static ContentProviderOperation buildOper(Uri uri, int type, ContentValues values) {
2692644d947574240b71c427d457f7a775dc160ec09Yorke Lee        switch (type) {
2702644d947574240b71c427d457f7a775dc160ec09Yorke Lee            case TYPE_ASSERT:
2712644d947574240b71c427d457f7a775dc160ec09Yorke Lee                return ContentProviderOperation.newAssertQuery(uri).withValues(values).build();
2722644d947574240b71c427d457f7a775dc160ec09Yorke Lee            case TYPE_INSERT:
2732644d947574240b71c427d457f7a775dc160ec09Yorke Lee                return ContentProviderOperation.newInsert(uri).withValues(values).build();
2742644d947574240b71c427d457f7a775dc160ec09Yorke Lee            case TYPE_UPDATE:
2752644d947574240b71c427d457f7a775dc160ec09Yorke Lee                return ContentProviderOperation.newUpdate(uri).withValues(values).build();
2762644d947574240b71c427d457f7a775dc160ec09Yorke Lee            case TYPE_DELETE:
2772644d947574240b71c427d457f7a775dc160ec09Yorke Lee                return ContentProviderOperation.newDelete(uri).build();
2782644d947574240b71c427d457f7a775dc160ec09Yorke Lee        }
2792644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return null;
2802644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2812644d947574240b71c427d457f7a775dc160ec09Yorke Lee
282009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    static CPOWrapper buildCPOWrapper(Uri uri, int type, ContentValues values) {
283009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        if (type == TYPE_ASSERT || type == TYPE_INSERT || type == TYPE_UPDATE
284009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                || type == TYPE_DELETE) {
285009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang            return new CPOWrapper(buildOper(uri, type, values), type);
286009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        }
287009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        return null;
288009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    }
289009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang
2902644d947574240b71c427d457f7a775dc160ec09Yorke Lee    static Long getVersion(RawContactDeltaList set, Long rawContactId) {
2912644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return set.getByRawContactId(rawContactId).getValues().getAsLong(RawContacts.VERSION);
2922644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
2932644d947574240b71c427d457f7a775dc160ec09Yorke Lee
2942644d947574240b71c427d457f7a775dc160ec09Yorke Lee    /**
2952644d947574240b71c427d457f7a775dc160ec09Yorke Lee     * Count number of {@link AggregationExceptions} updates contained in the
296f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang     * given list of {@link CPOWrapper}.
2972644d947574240b71c427d457f7a775dc160ec09Yorke Lee     */
298f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang    static int countExceptionUpdates(ArrayList<CPOWrapper> diff) {
2992644d947574240b71c427d457f7a775dc160ec09Yorke Lee        int updateCount = 0;
300f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        for (CPOWrapper cpoWrapper : diff) {
301f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang            final ContentProviderOperation oper = cpoWrapper.getOperation();
3022644d947574240b71c427d457f7a775dc160ec09Yorke Lee            if (AggregationExceptions.CONTENT_URI.equals(oper.getUri())
303f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang                    && CompatUtils.isUpdateCompat(cpoWrapper)) {
3042644d947574240b71c427d457f7a775dc160ec09Yorke Lee                updateCount++;
3052644d947574240b71c427d457f7a775dc160ec09Yorke Lee            }
3062644d947574240b71c427d457f7a775dc160ec09Yorke Lee        }
3072644d947574240b71c427d457f7a775dc160ec09Yorke Lee        return updateCount;
3082644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
3092644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3102644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testInsert() {
3112644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta insert = getInsert();
3122644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList set = buildSet(insert);
3132644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3142644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Inserting single shouldn't create rules
315f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        final ArrayList<CPOWrapper> diff = set.buildDiffWrapper();
3162644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final int exceptionCount = countExceptionUpdates(diff);
3172644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertEquals("Unexpected exception updates", 0, exceptionCount);
3182644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
3192644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3202644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testUpdateUpdate() {
3212644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta updateFirst = getUpdate(mContext, CONTACT_FIRST);
3222644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta updateSecond = getUpdate(mContext, CONTACT_SECOND);
3232644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList set = buildSet(updateFirst, updateSecond);
3242644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3252644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Updating two existing shouldn't create rules
326f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        final ArrayList<CPOWrapper> diff = set.buildDiffWrapper();
3272644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final int exceptionCount = countExceptionUpdates(diff);
3282644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertEquals("Unexpected exception updates", 0, exceptionCount);
3292644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
3302644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3312644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testUpdateInsert() {
3322644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta update = getUpdate(mContext, CONTACT_FIRST);
3332644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta insert = getInsert();
3342644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList set = buildSet(update, insert);
3352644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3362644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // New insert should only create one rule
337f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        final ArrayList<CPOWrapper> diff = set.buildDiffWrapper();
3382644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final int exceptionCount = countExceptionUpdates(diff);
3392644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertEquals("Unexpected exception updates", 1, exceptionCount);
3402644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
3412644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3422644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testInsertUpdateInsert() {
3432644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta insertFirst = getInsert();
3442644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta update = getUpdate(mContext, CONTACT_FIRST);
3452644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta insertSecond = getInsert();
3462644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList set = buildSet(insertFirst, update, insertSecond);
3472644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3482644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Two inserts should create two rules to bind against single existing
349f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        final ArrayList<CPOWrapper> diff = set.buildDiffWrapper();
3502644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final int exceptionCount = countExceptionUpdates(diff);
3512644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertEquals("Unexpected exception updates", 2, exceptionCount);
3522644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
3532644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3542644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testInsertInsertInsert() {
3552644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta insertFirst = getInsert();
3562644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta insertSecond = getInsert();
3572644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta insertThird = getInsert();
3582644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList set = buildSet(insertFirst, insertSecond, insertThird);
3592644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3602644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Three new inserts should create only two binding rules
361f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        final ArrayList<CPOWrapper> diff = set.buildDiffWrapper();
3622644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final int exceptionCount = countExceptionUpdates(diff);
3632644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertEquals("Unexpected exception updates", 2, exceptionCount);
3642644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
3652644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3662644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testMergeDataRemoteInsert() {
3672644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
3682644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_FIRST, buildPhone(PHONE_RED)));
3692644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
3702644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_SECOND, buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
3712644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3722644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Merge in second version, verify they match
3732644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
3742644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertEquals("Unexpected change when merging", second, merged);
3752644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
3762644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3772644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testMergeDataLocalUpdateRemoteInsert() {
3782644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
3792644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_FIRST, buildPhone(PHONE_RED)));
3802644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
3812644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_SECOND, buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
3822644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3832644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Change the local number to trigger update
3842644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
3852644d947574240b71c427d457f7a775dc160ec09Yorke Lee        phone.put(Phone.NUMBER, TEST_PHONE);
3862644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3872644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(first,
3882644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_FIRST),
3892644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationSuspended(),
390009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
3912644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationDefault());
3922644d947574240b71c427d457f7a775dc160ec09Yorke Lee
3932644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Merge in the second version, verify diff matches
3942644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
3952644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(merged,
3962644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_SECOND),
3972644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationSuspended(),
398009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
3992644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationDefault());
4002644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
4012644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4022644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testMergeDataLocalUpdateRemoteDelete() {
4032644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
4042644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_FIRST, buildPhone(PHONE_RED)));
4052644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
4062644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_SECOND, buildPhone(PHONE_GREEN)));
4072644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4082644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Change the local number to trigger update
4092644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
4102644d947574240b71c427d457f7a775dc160ec09Yorke Lee        phone.put(Phone.NUMBER, TEST_PHONE);
4112644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4122644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(first,
4132644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_FIRST),
4142644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationSuspended(),
415009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
4162644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationDefault());
4172644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4182644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Merge in the second version, verify that our update changed to
4192644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // insert, since RED was deleted on remote side
4202644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
4212644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(merged,
4222644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_SECOND),
4232644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationSuspended(),
424009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(phone, CONTACT_BOB)),
4252644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationDefault());
4262644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
4272644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4282644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testMergeDataLocalDeleteRemoteUpdate() {
4292644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
4302644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_FIRST, buildPhone(PHONE_RED)));
4312644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
4322644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_SECOND, buildPhone(PHONE_RED, TEST_PHONE)));
4332644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4342644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Delete phone locally
4352644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
4362644d947574240b71c427d457f7a775dc160ec09Yorke Lee        phone.markDeleted();
4372644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4382644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(first,
4392644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_FIRST),
4402644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationSuspended(),
4412644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildDelete(Data.CONTENT_URI),
4422644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationDefault());
4432644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4442644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Merge in the second version, verify that our delete remains
4452644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
4462644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(merged,
4472644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_SECOND),
4482644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationSuspended(),
4492644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildDelete(Data.CONTENT_URI),
4502644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationDefault());
4512644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
4522644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4532644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testMergeDataLocalInsertRemoteInsert() {
4542644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
4552644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_FIRST, buildPhone(PHONE_RED)));
4562644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
4572644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_SECOND, buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
4582644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4592644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Insert new phone locally
4602644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ValuesDelta bluePhone = ValuesDelta.fromAfter(buildPhone(PHONE_BLUE));
4612644d947574240b71c427d457f7a775dc160ec09Yorke Lee        first.getByRawContactId(CONTACT_BOB).addEntry(bluePhone);
4622644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(first,
4632644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_FIRST),
4642644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationSuspended(),
465009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bluePhone, CONTACT_BOB)),
4662644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationDefault());
4672644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4682644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Merge in the second version, verify that our insert remains
4692644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
4702644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(merged,
4712644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_SECOND),
4722644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationSuspended(),
473009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bluePhone, CONTACT_BOB)),
4742644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationDefault());
4752644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
4762644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4772644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testMergeRawContactLocalInsertRemoteInsert() {
4782644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
4792644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_FIRST, buildPhone(PHONE_RED)));
4802644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
4812644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_SECOND, buildPhone(PHONE_RED)), buildBeforeEntity(mContext, CONTACT_MARY,
4822644d947574240b71c427d457f7a775dc160ec09Yorke Lee                        VER_SECOND, buildPhone(PHONE_RED)));
4832644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4842644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Add new contact locally, should remain insert
4852644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues joePhoneInsert = buildPhone(PHONE_BLUE);
4862644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta joeContact = buildAfterEntity(joePhoneInsert);
4872644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues joeContactInsert = joeContact.getValues().getCompleteValues();
4882644d947574240b71c427d457f7a775dc160ec09Yorke Lee        joeContactInsert.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
4892644d947574240b71c427d457f7a775dc160ec09Yorke Lee        first.add(joeContact);
4902644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(first,
4912644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_FIRST),
492009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(RawContacts.CONTENT_URI, TYPE_INSERT, joeContactInsert),
493009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, joePhoneInsert),
4942644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
4952644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationKeepTogether(CONTACT_BOB));
4962644d947574240b71c427d457f7a775dc160ec09Yorke Lee
4972644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Merge in the second version, verify that our insert remains
4982644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
4992644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(merged,
5002644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_SECOND),
5012644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_SECOND),
502009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(RawContacts.CONTENT_URI, TYPE_INSERT, joeContactInsert),
503009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, joePhoneInsert),
5042644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
5052644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationKeepTogether(CONTACT_BOB));
5062644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
5072644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5082644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testMergeRawContactLocalDeleteRemoteDelete() {
5092644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList first = buildSet(
5102644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildBeforeEntity(mContext, CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
5112644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildBeforeEntity(mContext, CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
5122644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList second = buildSet(
5132644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildBeforeEntity(mContext, CONTACT_BOB, VER_SECOND, buildPhone(PHONE_RED)));
5142644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5152644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Remove contact locally
5162644d947574240b71c427d457f7a775dc160ec09Yorke Lee        first.getByRawContactId(CONTACT_MARY).markDeleted();
5172644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(first,
5182644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_FIRST),
5192644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_FIRST),
5202644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildDelete(RawContacts.CONTENT_URI));
5212644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5222644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Merge in the second version, verify that our delete isn't needed
5232644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
5242644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(merged);
5252644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
5262644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5272644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testMergeRawContactLocalUpdateRemoteDelete() {
5282644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList first = buildSet(
5292644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildBeforeEntity(mContext, CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
5302644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildBeforeEntity(mContext, CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
5312644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList second = buildSet(
5322644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildBeforeEntity(mContext, CONTACT_BOB, VER_SECOND, buildPhone(PHONE_RED)));
5332644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5342644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Perform local update
5352644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ValuesDelta phone = getPhone(first, CONTACT_MARY, PHONE_RED);
5362644d947574240b71c427d457f7a775dc160ec09Yorke Lee        phone.put(Phone.NUMBER, TEST_PHONE);
5372644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(first,
5382644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_FIRST),
5392644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_FIRST),
5402644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationSuspended(),
541009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
5422644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationDefault());
5432644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5442644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues phoneInsert = phone.getCompleteValues();
5452644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ContentValues contactInsert = first.getByRawContactId(CONTACT_MARY).getValues()
5462644d947574240b71c427d457f7a775dc160ec09Yorke Lee                .getCompleteValues();
5472644d947574240b71c427d457f7a775dc160ec09Yorke Lee        contactInsert.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
5482644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5492644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Merge and verify that update turned into insert
5502644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
5512644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(merged,
5522644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_SECOND),
553009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(RawContacts.CONTENT_URI, TYPE_INSERT, contactInsert),
554009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, phoneInsert),
5552644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
5562644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationKeepTogether(CONTACT_BOB));
5572644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
5582644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5592644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testMergeUsesNewVersion() {
5602644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
5612644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_FIRST, buildPhone(PHONE_RED)));
5622644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
5632644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_SECOND, buildPhone(PHONE_RED)));
5642644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5652644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertEquals((Long)VER_FIRST, getVersion(first, CONTACT_BOB));
5662644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertEquals((Long)VER_SECOND, getVersion(second, CONTACT_BOB));
5672644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5682644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
5692644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertEquals((Long)VER_SECOND, getVersion(merged, CONTACT_BOB));
5702644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
5712644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5722644d947574240b71c427d457f7a775dc160ec09Yorke Lee    public void testMergeAfterEnsureAndTrim() {
5732644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
5742644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_FIRST, buildEmail(EMAIL_YELLOW)));
5752644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
5762644d947574240b71c427d457f7a775dc160ec09Yorke Lee                VER_SECOND, buildEmail(EMAIL_YELLOW)));
5772644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5782644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Ensure we have at least one phone
5792644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final AccountType source = getAccountType();
5802644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDelta bobContact = first.getByRawContactId(CONTACT_BOB);
5812644d947574240b71c427d457f7a775dc160ec09Yorke Lee        RawContactModifier.ensureKindExists(bobContact, source, Phone.CONTENT_ITEM_TYPE);
5822644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final ValuesDelta bobPhone = bobContact.getSuperPrimaryEntry(Phone.CONTENT_ITEM_TYPE, true);
5832644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5842644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Make sure the update would insert a row
5852644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(first,
5862644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildAssertVersion(VER_FIRST),
5872644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationSuspended(),
588009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang                buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bobPhone, CONTACT_BOB)),
5892644d947574240b71c427d457f7a775dc160ec09Yorke Lee                buildUpdateAggregationDefault());
5902644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5912644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Trim values and ensure that we don't insert things
5922644d947574240b71c427d457f7a775dc160ec09Yorke Lee        RawContactModifier.trimEmpty(bobContact, source);
5932644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(first);
5942644d947574240b71c427d457f7a775dc160ec09Yorke Lee
5952644d947574240b71c427d457f7a775dc160ec09Yorke Lee        // Now re-parent the change, which should remain no-op
5962644d947574240b71c427d457f7a775dc160ec09Yorke Lee        final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
5972644d947574240b71c427d457f7a775dc160ec09Yorke Lee        assertDiffPattern(merged);
5982644d947574240b71c427d457f7a775dc160ec09Yorke Lee    }
5992644d947574240b71c427d457f7a775dc160ec09Yorke Lee}
600