blob: f5d4181d66c9cbebc7212bbf12757109f4cb4435 [file] [log] [blame]
Yorke Lee2644d942013-10-28 11:05:43 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Gary Mai0a49afa2016-12-05 15:53:58 -080017package com.android.contacts.model;
Yorke Lee2644d942013-10-28 11:05:43 -070018
Yorke Lee2644d942013-10-28 11:05:43 -070019import android.content.ContentProviderOperation;
Yorke Lee2644d942013-10-28 11:05:43 -070020import android.content.ContentValues;
21import android.content.Context;
Wenyi Wangf46a6192016-02-18 16:34:37 -080022import android.os.Build;
Yorke Lee2644d942013-10-28 11:05:43 -070023import android.os.Parcel;
24import android.provider.ContactsContract.CommonDataKinds.Phone;
25import android.provider.ContactsContract.Data;
26import android.provider.ContactsContract.RawContacts;
27import android.test.AndroidTestCase;
28import android.test.suitebuilder.annotation.LargeTest;
29
Gary Mai69c182a2016-12-05 13:07:03 -080030import com.android.contacts.compat.CompatUtils;
Gary Mai0a49afa2016-12-05 15:53:58 -080031
Yorke Lee2644d942013-10-28 11:05:43 -070032import com.google.common.collect.Lists;
33
34import java.util.ArrayList;
35
36/**
37 * Tests for {@link RawContactDelta} and {@link ValuesDelta}. These tests
38 * focus on passing changes across {@link Parcel}, and verifying that they
39 * correctly build expected "diff" operations.
40 */
41@LargeTest
42public class RawContactDeltaTests extends AndroidTestCase {
43 public static final String TAG = "EntityDeltaTests";
44
45 public static final long TEST_CONTACT_ID = 12;
46 public static final long TEST_PHONE_ID = 24;
47
48 public static final String TEST_PHONE_NUMBER_1 = "218-555-1111";
49 public static final String TEST_PHONE_NUMBER_2 = "218-555-2222";
50
51 public static final String TEST_ACCOUNT_NAME = "TEST";
52
53 public RawContactDeltaTests() {
54 super();
55 }
56
57 @Override
58 public void setUp() {
59 mContext = getContext();
60 }
61
62 public static RawContact getRawContact(Context context, long contactId, long phoneId) {
63 // Build an existing contact read from database
64 final ContentValues contact = new ContentValues();
65 contact.put(RawContacts.VERSION, 43);
66 contact.put(RawContacts._ID, contactId);
67
68 final ContentValues phone = new ContentValues();
69 phone.put(Data._ID, phoneId);
70 phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
71 phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
72 phone.put(Phone.TYPE, Phone.TYPE_HOME);
73
74 final RawContact before = new RawContact(contact);
75 before.addDataItemValues(phone);
76 return before;
77 }
78
79 /**
80 * Test that {@link RawContactDelta#mergeAfter(RawContactDelta)} correctly passes
81 * any changes through the {@link Parcel} object. This enforces that
82 * {@link RawContactDelta} should be identical when serialized against the same
83 * "before" {@link RawContact}.
84 */
85 public void testParcelChangesNone() {
86 final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
87 final RawContactDelta source = RawContactDelta.fromBefore(before);
88 final RawContactDelta dest = RawContactDelta.fromBefore(before);
89
90 // Merge modified values and assert they match
91 final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
92 assertEquals("Unexpected change when merging", source, merged);
93 }
94
95 public void testParcelChangesInsert() {
96 final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
97 final RawContactDelta source = RawContactDelta.fromBefore(before);
98 final RawContactDelta dest = RawContactDelta.fromBefore(before);
99
100 // Add a new row and pass across parcel, should be same
101 final ContentValues phone = new ContentValues();
102 phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
103 phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
104 phone.put(Phone.TYPE, Phone.TYPE_WORK);
105 source.addEntry(ValuesDelta.fromAfter(phone));
106
107 // Merge modified values and assert they match
108 final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
109 assertEquals("Unexpected change when merging", source, merged);
110 }
111
112 public void testParcelChangesUpdate() {
113 // Update existing row and pass across parcel, should be same
114 final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
115 final RawContactDelta source = RawContactDelta.fromBefore(before);
116 final RawContactDelta dest = RawContactDelta.fromBefore(before);
117
118 final ValuesDelta child = source.getEntry(TEST_PHONE_ID);
119 child.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
120
121 // Merge modified values and assert they match
122 final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
123 assertEquals("Unexpected change when merging", source, merged);
124 }
125
126 public void testParcelChangesDelete() {
127 // Delete a row and pass across parcel, should be same
128 final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
129 final RawContactDelta source = RawContactDelta.fromBefore(before);
130 final RawContactDelta dest = RawContactDelta.fromBefore(before);
131
132 final ValuesDelta child = source.getEntry(TEST_PHONE_ID);
133 child.markDeleted();
134
135 // Merge modified values and assert they match
136 final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
137 assertEquals("Unexpected change when merging", source, merged);
138 }
139
140 public void testValuesDiffDelete() {
141 final ContentValues before = new ContentValues();
142 before.put(Data._ID, TEST_PHONE_ID);
143 before.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
144
145 final ValuesDelta values = ValuesDelta.fromBefore(before);
146 values.markDeleted();
147
148 // Should produce a delete action
Wenyi Wangf46a6192016-02-18 16:34:37 -0800149 final BuilderWrapper builderWrapper = values.buildDiffWrapper(Data.CONTENT_URI);
150 final boolean isDelete = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
151 ? builderWrapper.getBuilder().build().isDelete()
152 : builderWrapper.getType() == CompatUtils.TYPE_DELETE;
Jay Shrauner7bae0632015-08-27 16:23:44 -0700153 assertTrue("Didn't produce delete action", isDelete);
Yorke Lee2644d942013-10-28 11:05:43 -0700154 }
155
156 /**
Wenyi Wang009d63c2016-02-18 16:45:08 -0800157 * Test that {@link RawContactDelta#buildDiffWrapper(ArrayList)} is correctly built for
Yorke Lee2644d942013-10-28 11:05:43 -0700158 * insert, update, and delete cases. This only tests a subset of possible
159 * {@link Data} row changes.
160 */
161 public void testEntityDiffNone() {
162 final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
163 final RawContactDelta source = RawContactDelta.fromBefore(before);
164
165 // Assert that writing unchanged produces few operations
Wenyi Wang009d63c2016-02-18 16:45:08 -0800166 final ArrayList<CPOWrapper> diff = Lists.newArrayList();
167 source.buildDiffWrapper(diff);
Yorke Lee2644d942013-10-28 11:05:43 -0700168
169 assertTrue("Created changes when none needed", (diff.size() == 0));
170 }
171
172 public void testEntityDiffNoneInsert() {
173 final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
174 final RawContactDelta source = RawContactDelta.fromBefore(before);
175
176 // Insert a new phone number
177 final ContentValues phone = new ContentValues();
178 phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
179 phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
180 phone.put(Phone.TYPE, Phone.TYPE_WORK);
181 source.addEntry(ValuesDelta.fromAfter(phone));
182
183 // Assert two operations: insert Data row and enforce version
Wenyi Wang009d63c2016-02-18 16:45:08 -0800184 final ArrayList<CPOWrapper> diff = Lists.newArrayList();
185 source.buildAssertWrapper(diff);
186 source.buildDiffWrapper(diff);
Yorke Lee2644d942013-10-28 11:05:43 -0700187 assertEquals("Unexpected operations", 4, diff.size());
188 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800189 final CPOWrapper cpoWrapper = diff.get(0);
190 assertTrue("Expected version enforcement", CompatUtils.isAssertQueryCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700191 }
192 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800193 final CPOWrapper cpoWrapper = diff.get(1);
194 final ContentProviderOperation oper = cpoWrapper.getOperation();
195 assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700196 assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
197 }
198 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800199 final CPOWrapper cpoWrapper = diff.get(2);
200 final ContentProviderOperation oper = cpoWrapper.getOperation();
201 assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700202 assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
203 }
204 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800205 final CPOWrapper cpoWrapper = diff.get(3);
206 final ContentProviderOperation oper = cpoWrapper.getOperation();
207 assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700208 assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
209 }
210 }
211
212 public void testEntityDiffUpdateInsert() {
213 final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
214 final RawContactDelta source = RawContactDelta.fromBefore(before);
215
216 // Update parent contact values
217 source.getValues().put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
218
219 // Insert a new phone number
220 final ContentValues phone = new ContentValues();
221 phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
222 phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
223 phone.put(Phone.TYPE, Phone.TYPE_WORK);
224 source.addEntry(ValuesDelta.fromAfter(phone));
225
226 // Assert three operations: update Contact, insert Data row, enforce version
Wenyi Wang009d63c2016-02-18 16:45:08 -0800227 final ArrayList<CPOWrapper> diff = Lists.newArrayList();
228 source.buildAssertWrapper(diff);
229 source.buildDiffWrapper(diff);
Yorke Lee2644d942013-10-28 11:05:43 -0700230 assertEquals("Unexpected operations", 5, diff.size());
231 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800232 final CPOWrapper cpoWrapper = diff.get(0);
233 assertTrue("Expected version enforcement", CompatUtils.isAssertQueryCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700234 }
235 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800236 final CPOWrapper cpoWrapper = diff.get(1);
237 final ContentProviderOperation oper = cpoWrapper.getOperation();
238 assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700239 assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
240 }
241 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800242 final CPOWrapper cpoWrapper = diff.get(2);
243 final ContentProviderOperation oper = cpoWrapper.getOperation();
244 assertTrue("Incorrect type", CompatUtils.isUpdateCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700245 assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
246 }
247 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800248 final CPOWrapper cpoWrapper = diff.get(3);
249 final ContentProviderOperation oper = cpoWrapper.getOperation();
250 assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700251 assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
252 }
253 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800254 final CPOWrapper cpoWrapper = diff.get(4);
255 final ContentProviderOperation oper = cpoWrapper.getOperation();
256 assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700257 assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
258 }
259 }
260
261 public void testEntityDiffNoneUpdate() {
262 final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
263 final RawContactDelta source = RawContactDelta.fromBefore(before);
264
265 // Update existing phone number
266 final ValuesDelta child = source.getEntry(TEST_PHONE_ID);
267 child.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
268
269 // Assert that version is enforced
Wenyi Wang009d63c2016-02-18 16:45:08 -0800270 final ArrayList<CPOWrapper> diff = Lists.newArrayList();
271 source.buildAssertWrapper(diff);
272 source.buildDiffWrapper(diff);
Yorke Lee2644d942013-10-28 11:05:43 -0700273 assertEquals("Unexpected operations", 4, diff.size());
274 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800275 final CPOWrapper cpoWrapper = diff.get(0);
276 assertTrue("Expected version enforcement", CompatUtils.isAssertQueryCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700277 }
278 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800279 final CPOWrapper cpoWrapper = diff.get(1);
280 final ContentProviderOperation oper = cpoWrapper.getOperation();
281 assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700282 assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
283 }
284 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800285 final CPOWrapper cpoWrapper = diff.get(2);
286 final ContentProviderOperation oper = cpoWrapper.getOperation();
287 assertTrue("Incorrect type", CompatUtils.isUpdateCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700288 assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
289 }
290 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800291 final CPOWrapper cpoWrapper = diff.get(3);
292 final ContentProviderOperation oper = cpoWrapper.getOperation();
293 assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700294 assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
295 }
296 }
297
298 public void testEntityDiffDelete() {
299 final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
300 final RawContactDelta source = RawContactDelta.fromBefore(before);
301
302 // Delete entire entity
303 source.getValues().markDeleted();
304
305 // Assert two operations: delete Contact and enforce version
Wenyi Wang009d63c2016-02-18 16:45:08 -0800306 final ArrayList<CPOWrapper> diff = Lists.newArrayList();
307 source.buildAssertWrapper(diff);
308 source.buildDiffWrapper(diff);
Yorke Lee2644d942013-10-28 11:05:43 -0700309 assertEquals("Unexpected operations", 2, diff.size());
310 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800311 final CPOWrapper cpoWrapper = diff.get(0);
312 assertTrue("Expected version enforcement", CompatUtils.isAssertQueryCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700313 }
314 {
Wenyi Wang009d63c2016-02-18 16:45:08 -0800315 final CPOWrapper cpoWrapper = diff.get(1);
316 final ContentProviderOperation oper = cpoWrapper.getOperation();
317 assertTrue("Incorrect type", CompatUtils.isDeleteCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700318 assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
319 }
320 }
321
322 public void testEntityDiffInsert() {
323 // Insert a RawContact
324 final ContentValues after = new ContentValues();
325 after.put(RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME);
326 after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
327
328 final ValuesDelta values = ValuesDelta.fromAfter(after);
329 final RawContactDelta source = new RawContactDelta(values);
330
Wenyi Wangf46a6192016-02-18 16:34:37 -0800331 // Assert two operations: insert Contact and enforce version
332 final ArrayList<CPOWrapper> diff = Lists.newArrayList();
333 source.buildAssertWrapper(diff);
334 source.buildDiffWrapper(diff);
Yorke Lee2644d942013-10-28 11:05:43 -0700335 assertEquals("Unexpected operations", 2, diff.size());
336 {
Wenyi Wangf46a6192016-02-18 16:34:37 -0800337 final CPOWrapper cpoWrapper = diff.get(0);
338 final ContentProviderOperation oper = cpoWrapper.getOperation();
339 assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700340 assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
341 }
342 }
343
344 public void testEntityDiffInsertInsert() {
345 // Insert a RawContact
346 final ContentValues after = new ContentValues();
347 after.put(RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME);
348 after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
349
350 final ValuesDelta values = ValuesDelta.fromAfter(after);
351 final RawContactDelta source = new RawContactDelta(values);
352
353 // Insert a new phone number
354 final ContentValues phone = new ContentValues();
355 phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
356 phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
357 phone.put(Phone.TYPE, Phone.TYPE_WORK);
358 source.addEntry(ValuesDelta.fromAfter(phone));
359
360 // Assert two operations: delete Contact and enforce version
Wenyi Wangf46a6192016-02-18 16:34:37 -0800361 final ArrayList<CPOWrapper> diff = Lists.newArrayList();
362 source.buildAssertWrapper(diff);
363 source.buildDiffWrapper(diff);
Yorke Lee2644d942013-10-28 11:05:43 -0700364 assertEquals("Unexpected operations", 3, diff.size());
365 {
Wenyi Wangf46a6192016-02-18 16:34:37 -0800366 final CPOWrapper cpoWrapper = diff.get(0);
367 final ContentProviderOperation oper = cpoWrapper.getOperation();
368 assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700369 assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
370 }
371 {
Wenyi Wangf46a6192016-02-18 16:34:37 -0800372 final CPOWrapper cpoWrapper = diff.get(1);
373 final ContentProviderOperation oper = cpoWrapper.getOperation();
374 assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
Yorke Lee2644d942013-10-28 11:05:43 -0700375 assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
376
377 }
378 }
379}