1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.calendar.event;
18 
19 import android.content.ContentProvider;
20 import android.content.ContentProviderOperation;
21 import android.content.ContentProviderResult;
22 import android.content.ContentValues;
23 import android.content.res.Resources;
24 import android.database.Cursor;
25 import android.database.MatrixCursor;
26 import android.net.Uri;
27 import android.provider.CalendarContract.Attendees;
28 import android.provider.CalendarContract.Events;
29 import android.provider.CalendarContract.Reminders;
30 import android.test.AndroidTestCase;
31 import android.test.mock.MockResources;
32 import android.test.suitebuilder.annotation.SmallTest;
33 import android.test.suitebuilder.annotation.Smoke;
34 import android.text.format.DateUtils;
35 import android.text.format.Time;
36 import android.text.util.Rfc822Token;
37 
38 import com.android.calendar.AbstractCalendarActivity;
39 import com.android.calendar.AsyncQueryService;
40 import com.android.calendar.CalendarEventModel;
41 import com.android.calendar.CalendarEventModel.ReminderEntry;
42 import com.android.calendar.R;
43 import com.android.calendar.Utils;
44 import com.android.common.Rfc822Validator;
45 
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.Calendar;
49 import java.util.LinkedHashSet;
50 import java.util.TimeZone;
51 
52 public class EditEventHelperTest extends AndroidTestCase {
53     private static final int TEST_EVENT_ID = 1;
54     private static final int TEST_EVENT_INDEX_ID = 0;
55     private static final long TEST_END = 1272931200000L;
56     private static long TEST_END2 = 1272956400000L;
57     private static final long TEST_START = 1272844800000L;
58     private static long TEST_START2 = 1272870000000L;
59     private static final String LOCAL_TZ = TimeZone.getDefault().getID();
60 
61     private static final int SAVE_EVENT_NEW_EVENT = 1;
62     private static final int SAVE_EVENT_MOD_RECUR = 2;
63     private static final int SAVE_EVENT_RECUR_TO_NORECUR = 3;
64     private static final int SAVE_EVENT_NORECUR_TO_RECUR= 4;
65     private static final int SAVE_EVENT_MOD_NORECUR = 5;
66     private static final int SAVE_EVENT_MOD_INSTANCE = 6;
67     private static final int SAVE_EVENT_ALLFOLLOW_TO_NORECUR = 7;
68     private static final int SAVE_EVENT_FIRST_TO_NORECUR = 8;
69     private static final int SAVE_EVENT_FIRST_TO_RECUR = 9;
70     private static final int SAVE_EVENT_ALLFOLLOW_TO_RECUR = 10;
71 
72     /* These should match up with EditEventHelper.EVENT_PROJECTION.
73      * Note that spaces and commas have been removed to allow for easier sanitation.
74      */
75     private static String[] TEST_CURSOR_DATA = new String[] {
76             Integer.toString(TEST_EVENT_ID), // 0 _id
77             "The_Question", // 1 title
78             "Evaluating_Life_the_Universe_and_Everything", // 2 description
79             "Earth_Mk2", // 3 location
80             "1", // 4 All Day
81             "0", // 5 Has alarm
82             "2", // 6 Calendar id
83             "1272844800000", // 7 dtstart, Monday, May 3rd midnight UTC
84             "1272931200000", // 8 dtend, Tuesday, May 4th midnight UTC
85             "P3652421990D", // 9 duration, (10 million years)
86             "UTC", // 10 event timezone
87             "FREQ=DAILY;WKST=SU", // 11 rrule
88             "unique_per_calendar_stuff", // 12 sync id
89             "0", // 13 transparency/availability
90             "3", // 14 visibility/access level
91             "steve@gmail.com", // 15 owner account
92             "1", // 16 has attendee data
93             null, //17 originalSyncId
94             "organizer@gmail.com", // 18 organizer
95             "0", // 19 guest can modify
96             "-1", // 20 original id
97             "1", // 21 event status
98             "-339611", // 22 calendar color
99             "-2350809", // 23 event color
100             "11" // 24 event color key
101     };
102 
103     private static final String AUTHORITY_URI = "content://EditEventHelperAuthority/";
104     private static final String AUTHORITY = "EditEventHelperAuthority";
105 
106     private static final String TEST_ADDRESSES =
107             "no good, ad1@email.com, \"First Last\" <first@email.com> (comment), " +
108             "one.two.three@email.grue";
109     private static final String TEST_ADDRESSES2 =
110             "no good, ad1@email.com, \"First Last\" <first@email.com> (comment), " +
111             "different@email.bit";
112     private static final String TEST_ADDRESSES3 =
113             "ad1@email.com, \"First Last\" <first@email.com> (comment), " +
114             "different@email.bit";
115     private static final String TEST_ADDRESSES4 =
116             "ad1@email.com, \"First Last\" <first@email.com> (comment), " +
117             "one.two.three@email.grue";
118 
119 
120     private static final String TAG = "EEHTest";
121 
122     private Rfc822Validator mEmailValidator;
123     private CalendarEventModel mModel1;
124     private CalendarEventModel mModel2;
125 
126     private ContentValues mValues;
127     private ContentValues mExpectedValues;
128 
129     private EditEventHelper mHelper;
130     private AbstractCalendarActivity mActivity;
131     private int mCurrentSaveTest = 0;
132 
133     @Override
setUp()134     public void setUp() {
135         Time time = new Time(Time.TIMEZONE_UTC);
136         time.set(TEST_START);
137         time.timezone = LOCAL_TZ;
138         TEST_START2 = time.normalize(true);
139 
140         time.timezone = Time.TIMEZONE_UTC;
141         time.set(TEST_END);
142         time.timezone = LOCAL_TZ;
143         TEST_END2 = time.normalize(true);
144 
145         mEmailValidator = new Rfc822Validator(null);
146     }
147 
148     private class MockAbsCalendarActivity extends AbstractCalendarActivity {
149         @Override
getAsyncQueryService()150         public AsyncQueryService getAsyncQueryService() {
151             if (mService == null) {
152                 mService = new AsyncQueryService(this) {
153                     @Override
154                     public void startBatch(int token, Object cookie, String authority,
155                             ArrayList<ContentProviderOperation> cpo, long delayMillis) {
156                         mockApplyBatch(authority, cpo);
157                     }
158                 };
159             }
160             return mService;
161         }
162 
163         @Override
getResources()164         public Resources getResources() {
165             Resources res = new MockResources() {
166                 @Override
167                 // The actual selects singular vs plural as well and in the given language
168                 public String getQuantityString(int id, int quantity) {
169                     if (id == R.plurals.Nmins) {
170                         return quantity + " mins";
171                     }
172                     if (id == R.plurals.Nminutes) {
173                         return quantity + " minutes";
174                     }
175                     if (id == R.plurals.Nhours) {
176                         return quantity + " hours";
177                     }
178                     if (id == R.plurals.Ndays) {
179                         return quantity + " days";
180                     }
181                     return id + " " + quantity;
182                 }
183             };
184             return res;
185         }
186     }
187 
buildTestContext()188     private AbstractCalendarActivity buildTestContext() {
189         MockAbsCalendarActivity context = new MockAbsCalendarActivity();
190         return context;
191     }
192 
mockApplyBatch(String authority, ArrayList<ContentProviderOperation> operations)193     private ContentProviderResult[] mockApplyBatch(String authority,
194             ArrayList<ContentProviderOperation> operations) {
195         switch (mCurrentSaveTest) {
196             case SAVE_EVENT_NEW_EVENT:
197                 // new recurring event
198                 verifySaveEventNewEvent(operations);
199                 break;
200             case SAVE_EVENT_MOD_RECUR:
201                 // update to recurring event
202                 verifySaveEventModifyRecurring(operations);
203                 break;
204             case SAVE_EVENT_RECUR_TO_NORECUR:
205                 // replace recurring event with non-recurring event
206                 verifySaveEventRecurringToNonRecurring(operations);
207                 break;
208             case SAVE_EVENT_NORECUR_TO_RECUR:
209                 // update non-recurring event with recurring event
210                 verifySaveEventNonRecurringToRecurring(operations);
211                 break;
212             case SAVE_EVENT_MOD_NORECUR:
213                 // update to non-recurring
214                 verifySaveEventUpdateNonRecurring(operations);
215                 break;
216             case SAVE_EVENT_MOD_INSTANCE:
217                 // update to single instance of recurring event
218                 verifySaveEventModifySingleInstance(operations);
219                 break;
220             case SAVE_EVENT_ALLFOLLOW_TO_NORECUR:
221                 // update all following with non-recurring event
222                 verifySaveEventModifyAllFollowingWithNonRecurring(operations);
223                 break;
224             case SAVE_EVENT_FIRST_TO_NORECUR:
225                 // update all following with non-recurring event on first event in series
226                 verifySaveEventModifyAllFollowingFirstWithNonRecurring(operations);
227                 break;
228             case SAVE_EVENT_FIRST_TO_RECUR:
229                 // update all following with recurring event on first event in series
230                 verifySaveEventModifyAllFollowingFirstWithRecurring(operations);
231                 break;
232             case SAVE_EVENT_ALLFOLLOW_TO_RECUR:
233                 // update all following with recurring event on second event in series
234                 verifySaveEventModifyAllFollowingWithRecurring(operations);
235                 break;
236         }
237         return new ContentProviderResult[] {new ContentProviderResult(5)};
238     }
239 
addOwnerAttendeeToOps(ArrayList<ContentProviderOperation> expectedOps, int id)240     private void addOwnerAttendeeToOps(ArrayList<ContentProviderOperation> expectedOps, int id) {
241         addOwnerAttendee();
242         ContentProviderOperation.Builder b;
243         b = ContentProviderOperation.newInsert(Attendees.CONTENT_URI).withValues(mExpectedValues);
244         b.withValueBackReference(Reminders.EVENT_ID, id);
245         expectedOps.add(b.build());
246     }
247 
addOwnerAttendeeToOps(ArrayList<ContentProviderOperation> expectedOps)248     private void addOwnerAttendeeToOps(ArrayList<ContentProviderOperation> expectedOps) {
249         addOwnerAttendee();
250         mExpectedValues.put(Attendees.EVENT_ID, TEST_EVENT_ID);
251         ContentProviderOperation.Builder b;
252         b = ContentProviderOperation.newInsert(Attendees.CONTENT_URI).withValues(mExpectedValues);
253         expectedOps.add(b.build());
254     }
255 
256 
257     // Some tests set the time values to one day later, this does that move in the values
moveExpectedTimeValuesForwardOneDay()258     private void moveExpectedTimeValuesForwardOneDay() {
259         long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
260         mExpectedValues.put(Events.DTSTART, TEST_START + dayInMs);
261         mExpectedValues.put(Events.DTEND, TEST_END + dayInMs);
262     }
263 
264     // Duplicates the delete and add for changing a single email address
addAttendeeChangesOps(ArrayList<ContentProviderOperation> expectedOps)265     private void addAttendeeChangesOps(ArrayList<ContentProviderOperation> expectedOps) {
266         ContentProviderOperation.Builder b =
267             ContentProviderOperation.newDelete(Attendees.CONTENT_URI);
268         b.withSelection(EditEventHelper.ATTENDEES_DELETE_PREFIX + "?)",
269                 new String[] {"one.two.three@email.grue"});
270         expectedOps.add(b.build());
271 
272         mExpectedValues.clear();
273         mExpectedValues.put(Attendees.ATTENDEE_NAME, "different@email.bit");
274         mExpectedValues.put(Attendees.ATTENDEE_EMAIL, "different@email.bit");
275         mExpectedValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
276         mExpectedValues.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
277         mExpectedValues.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE);
278         mExpectedValues.put(Attendees.EVENT_ID, TEST_EVENT_ID);
279         b = ContentProviderOperation
280                 .newInsert(Attendees.CONTENT_URI)
281                 .withValues(mExpectedValues);
282         expectedOps.add(b.build());
283     }
284 
285     // This is a commonly added set of values
addOwnerAttendee()286     private void addOwnerAttendee() {
287         mExpectedValues.clear();
288         mExpectedValues.put(Attendees.ATTENDEE_EMAIL, mModel1.mOwnerAccount);
289         mExpectedValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ORGANIZER);
290         mExpectedValues.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
291         mExpectedValues.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_ACCEPTED);
292     }
293 
294     /** Some tests add all the attendees to the db, the names and emails should match
295      * with {@link #TEST_ADDRESSES2} minus the 'no good'
296      */
addTestAttendees(ArrayList<ContentProviderOperation> ops, boolean newEvent, int id)297     private void addTestAttendees(ArrayList<ContentProviderOperation> ops,
298             boolean newEvent, int id) {
299         ContentProviderOperation.Builder b;
300         mExpectedValues.clear();
301         mExpectedValues.put(Attendees.ATTENDEE_NAME, "ad1@email.com");
302         mExpectedValues.put(Attendees.ATTENDEE_EMAIL, "ad1@email.com");
303         mExpectedValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
304         mExpectedValues.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
305         mExpectedValues.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE);
306 
307         if (newEvent) {
308             b = ContentProviderOperation
309                     .newInsert(Attendees.CONTENT_URI)
310                     .withValues(mExpectedValues);
311             b.withValueBackReference(Attendees.EVENT_ID, id);
312         } else {
313             mExpectedValues.put(Attendees.EVENT_ID, id);
314             b = ContentProviderOperation
315                     .newInsert(Attendees.CONTENT_URI)
316                     .withValues(mExpectedValues);
317         }
318         ops.add(b.build());
319 
320         mExpectedValues.clear();
321         mExpectedValues.put(Attendees.ATTENDEE_NAME, "First Last");
322         mExpectedValues.put(Attendees.ATTENDEE_EMAIL, "first@email.com");
323         mExpectedValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
324         mExpectedValues.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
325         mExpectedValues.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE);
326 
327         if (newEvent) {
328             b = ContentProviderOperation
329                     .newInsert(Attendees.CONTENT_URI)
330                     .withValues(mExpectedValues);
331             b.withValueBackReference(Attendees.EVENT_ID, id);
332         } else {
333             mExpectedValues.put(Attendees.EVENT_ID, id);
334             b = ContentProviderOperation
335                     .newInsert(Attendees.CONTENT_URI)
336                     .withValues(mExpectedValues);
337         }
338         ops.add(b.build());
339 
340         mExpectedValues.clear();
341         mExpectedValues.put(Attendees.ATTENDEE_NAME, "different@email.bit");
342         mExpectedValues.put(Attendees.ATTENDEE_EMAIL, "different@email.bit");
343         mExpectedValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
344         mExpectedValues.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_REQUIRED);
345         mExpectedValues.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE);
346 
347         if (newEvent) {
348             b = ContentProviderOperation
349                     .newInsert(Attendees.CONTENT_URI)
350                     .withValues(mExpectedValues);
351             b.withValueBackReference(Attendees.EVENT_ID, id);
352         } else {
353             mExpectedValues.put(Attendees.EVENT_ID, id);
354             b = ContentProviderOperation
355                     .newInsert(Attendees.CONTENT_URI)
356                     .withValues(mExpectedValues);
357         }
358         ops.add(b.build());
359     }
360 
361     @Smoke
362     @SmallTest
testSaveEventFailures()363     public void testSaveEventFailures() {
364         mActivity = buildTestContext();
365         mHelper = new EditEventHelper(mActivity, null);
366 
367         mModel1 = buildTestModel();
368         mModel2 = buildTestModel();
369 
370         // saveEvent should return false early if:
371         // -it was set to not ok
372         // -the model was null
373         // -the event doesn't represent the same event as the original event
374         // -there's a uri but an original event is not provided
375         mHelper.mEventOk = false;
376         assertFalse(mHelper.saveEvent(null, null, 0));
377         mHelper.mEventOk = true;
378         assertFalse(mHelper.saveEvent(null, null, 0));
379         mModel2.mId = 13;
380         assertFalse(mHelper.saveEvent(mModel1, mModel2, 0));
381         mModel2.mId = mModel1.mId;
382         mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
383         mModel2.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
384         assertFalse(mHelper.saveEvent(mModel1, null, 0));
385     }
386 
387     @Smoke
388     @SmallTest
testSaveEventNewEvent()389     public void testSaveEventNewEvent() {
390         // Creates a model of a new event for saving
391         mActivity = buildTestContext();
392         mHelper = new EditEventHelper(mActivity, null);
393 
394         mModel1 = buildTestModel();
395         mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
396         mCurrentSaveTest = SAVE_EVENT_NEW_EVENT;
397 
398         assertTrue(mHelper.saveEvent(mModel1, null, 0));
399     }
400 
verifySaveEventNewEvent(ArrayList<ContentProviderOperation> ops)401     private boolean verifySaveEventNewEvent(ArrayList<ContentProviderOperation> ops) {
402         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
403         int br_id = 0;
404         mExpectedValues = buildTestValues();
405         mExpectedValues.put(Events.HAS_ALARM, 0);
406         mExpectedValues.put(Events.HAS_ATTENDEE_DATA, 1);
407         ContentProviderOperation.Builder b = ContentProviderOperation
408                 .newInsert(Events.CONTENT_URI)
409                 .withValues(mExpectedValues);
410         expectedOps.add(b.build());
411 
412         // This call has a separate unit test so we'll use it to simplify making the expected vals
413         mHelper.saveRemindersWithBackRef(expectedOps, br_id, mModel1.mReminders,
414                 new ArrayList<ReminderEntry>(), true);
415 
416         addOwnerAttendeeToOps(expectedOps, br_id);
417 
418         addTestAttendees(expectedOps, true, br_id);
419 
420         assertEquals(expectedOps, ops);
421         return true;
422     }
423 
424     @Smoke
425     @SmallTest
testSaveEventModifyRecurring()426     public void testSaveEventModifyRecurring() {
427         // Creates an original and an updated recurring event model
428         mActivity = buildTestContext();
429         mHelper = new EditEventHelper(mActivity, null);
430 
431         mModel1 = buildTestModel();
432         mModel2 = buildTestModel();
433         mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
434 
435         // Updating a recurring event with a new attendee list
436         mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
437         // And a new start time to ensure the time fields aren't removed
438         mModel1.mOriginalStart = TEST_START;
439 
440         // The original model is assumed correct so drop the no good bit
441         mModel2.addAttendees(TEST_ADDRESSES4, null);
442         mCurrentSaveTest = SAVE_EVENT_MOD_RECUR;
443 
444         assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL));
445     }
446 
verifySaveEventModifyRecurring(ArrayList<ContentProviderOperation> ops)447     private boolean verifySaveEventModifyRecurring(ArrayList<ContentProviderOperation> ops) {
448         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
449         int br_id = 0;
450         mExpectedValues = buildTestValues();
451         mExpectedValues.put(Events.HAS_ALARM, 0);
452         // This is tested elsewhere, used for convenience here
453         mHelper.checkTimeDependentFields(mModel2, mModel1, mExpectedValues,
454                 EditEventHelper.MODIFY_ALL);
455 
456         expectedOps.add(ContentProviderOperation.newUpdate(Uri.parse(mModel1.mUri)).withValues(
457                 mExpectedValues).build());
458 
459         // This call has a separate unit test so we'll use it to simplify making the expected vals
460         mHelper.saveReminders(expectedOps, TEST_EVENT_ID, mModel1.mReminders,
461                 mModel2.mReminders, false);
462 
463         addOwnerAttendeeToOps(expectedOps);
464         addAttendeeChangesOps(expectedOps);
465 
466         assertEquals(expectedOps, ops);
467         return true;
468     }
469 
470     @Smoke
471     @SmallTest
testSaveEventRecurringToNonRecurring()472     public void testSaveEventRecurringToNonRecurring() {
473         // Creates an original and an updated recurring event model
474         mActivity = buildTestContext();
475         mHelper = new EditEventHelper(mActivity, null);
476 
477         mModel1 = buildTestModel();
478         mModel2 = buildTestModel();
479         mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
480 
481         // Updating a recurring event with a new attendee list
482         mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
483         // And a new start time to ensure the time fields aren't removed
484         mModel1.mOriginalStart = TEST_START;
485 
486         // The original model is assumed correct so drop the no good bit
487         mModel2.addAttendees(TEST_ADDRESSES4, null);
488 
489         // Replace an existing recurring event with a non-recurring event
490         mModel1.mRrule = null;
491         mModel1.mEnd = TEST_END;
492         mCurrentSaveTest = SAVE_EVENT_RECUR_TO_NORECUR;
493 
494         assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL));
495     }
496 
verifySaveEventRecurringToNonRecurring(ArrayList<ContentProviderOperation> ops)497     private boolean verifySaveEventRecurringToNonRecurring(ArrayList<ContentProviderOperation> ops)
498             {
499         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
500         int id = 0;
501         mExpectedValues = buildNonRecurringTestValues();
502         mExpectedValues.put(Events.HAS_ALARM, 0);
503         // This is tested elsewhere, used for convenience here
504         mHelper.checkTimeDependentFields(mModel1, mModel1, mExpectedValues,
505                 EditEventHelper.MODIFY_ALL);
506 
507         expectedOps.add(ContentProviderOperation.newDelete(Uri.parse(mModel1.mUri)).build());
508         id = expectedOps.size();
509         expectedOps.add(ContentProviderOperation
510                         .newInsert(Events.CONTENT_URI)
511                         .withValues(mExpectedValues)
512                         .build());
513 
514         mHelper.saveRemindersWithBackRef(expectedOps, id, mModel1.mReminders,
515                 mModel2.mReminders, true);
516 
517         addOwnerAttendeeToOps(expectedOps, id);
518 
519         addTestAttendees(expectedOps, true, id);
520 
521         assertEquals(expectedOps, ops);
522         return true;
523     }
524 
525     @Smoke
526     @SmallTest
testSaveEventNonRecurringToRecurring()527     public void testSaveEventNonRecurringToRecurring() {
528         // Creates an original non-recurring and an updated recurring event model
529         mActivity = buildTestContext();
530         mHelper = new EditEventHelper(mActivity, null);
531 
532         mModel1 = buildTestModel();
533         mModel2 = buildTestModel();
534         mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
535 
536         // Updating a recurring event with a new attendee list
537         mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
538         // And a new start time to ensure the time fields aren't removed
539         mModel1.mOriginalStart = TEST_START;
540 
541         // The original model is assumed correct so drop the no good bit
542         mModel2.addAttendees(TEST_ADDRESSES4, null);
543 
544         mModel2.mRrule = null;
545         mModel2.mEnd = TEST_END;
546         mCurrentSaveTest = SAVE_EVENT_NORECUR_TO_RECUR;
547 
548         assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL));
549     }
550 
verifySaveEventNonRecurringToRecurring(ArrayList<ContentProviderOperation> ops)551     private boolean verifySaveEventNonRecurringToRecurring(ArrayList<ContentProviderOperation> ops)
552             {
553         // Changing a non-recurring event to a recurring event should generate the same operations
554         // as just modifying a recurring event.
555         return verifySaveEventModifyRecurring(ops);
556     }
557 
558     @Smoke
559     @SmallTest
testSaveEventUpdateNonRecurring()560     public void testSaveEventUpdateNonRecurring() {
561         // Creates an original non-recurring and an updated recurring event model
562         mActivity = buildTestContext();
563         mHelper = new EditEventHelper(mActivity, null);
564 
565         mModel1 = buildTestModel();
566         mModel2 = buildTestModel();
567         mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
568 
569         // Updating a recurring event with a new attendee list
570         mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
571         // And a new start time to ensure the time fields aren't removed
572         mModel1.mOriginalStart = TEST_START;
573 
574         // The original model is assumed correct so drop the no good bit
575         mModel2.addAttendees(TEST_ADDRESSES4, null);
576 
577         mModel2.mRrule = null;
578         mModel2.mEnd = TEST_END2;
579         mModel1.mRrule = null;
580         mModel1.mEnd = TEST_END2;
581         mCurrentSaveTest = SAVE_EVENT_MOD_NORECUR;
582 
583         assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL));
584     }
585 
verifySaveEventUpdateNonRecurring(ArrayList<ContentProviderOperation> ops)586     private boolean verifySaveEventUpdateNonRecurring(ArrayList<ContentProviderOperation> ops) {
587         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
588         int id = TEST_EVENT_ID;
589         mExpectedValues = buildNonRecurringTestValues();
590         mExpectedValues.put(Events.HAS_ALARM, 0);
591         // This is tested elsewhere, used for convenience here
592         mHelper.checkTimeDependentFields(mModel1, mModel1, mExpectedValues,
593                 EditEventHelper.MODIFY_ALL);
594         expectedOps.add(ContentProviderOperation.newUpdate(Uri.parse(mModel1.mUri)).withValues(
595                 mExpectedValues).build());
596         // This call has a separate unit test so we'll use it to simplify making the expected vals
597         mHelper.saveReminders(expectedOps, TEST_EVENT_ID, mModel1.mReminders,
598                 mModel2.mReminders, false);
599         addOwnerAttendeeToOps(expectedOps);
600         addAttendeeChangesOps(expectedOps);
601 
602         assertEquals(expectedOps, ops);
603         return true;
604     }
605 
606     @Smoke
607     @SmallTest
testSaveEventModifySingleInstance()608     public void testSaveEventModifySingleInstance() {
609         // Creates an original non-recurring and an updated recurring event model
610         mActivity = buildTestContext();
611         mHelper = new EditEventHelper(mActivity, null);
612 
613         mModel1 = buildTestModel();
614         mModel2 = buildTestModel();
615         mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
616 
617         mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
618         // And a new start time to ensure the time fields aren't removed
619         mModel1.mOriginalStart = TEST_START;
620 
621         // The original model is assumed correct so drop the no good bit
622         mModel2.addAttendees(TEST_ADDRESSES4, null);
623 
624         // Modify the second instance of the event
625         long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
626         mModel1.mRrule = null;
627         mModel1.mEnd = TEST_END + dayInMs;
628         mModel1.mStart += dayInMs;
629         mModel1.mOriginalStart = mModel1.mStart;
630 
631         mCurrentSaveTest = SAVE_EVENT_MOD_INSTANCE;
632         // Only modify this instance
633         assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_SELECTED));
634     }
635 
verifySaveEventModifySingleInstance(ArrayList<ContentProviderOperation> ops)636     private boolean verifySaveEventModifySingleInstance(ArrayList<ContentProviderOperation> ops) {
637         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
638         int id = 0;
639         mExpectedValues = buildNonRecurringTestValues();
640         mExpectedValues.put(Events.HAS_ALARM, 0);
641         // This is tested elsewhere, used for convenience here
642         mHelper.checkTimeDependentFields(mModel1, mModel1, mExpectedValues,
643                 EditEventHelper.MODIFY_ALL);
644 
645         moveExpectedTimeValuesForwardOneDay();
646         mExpectedValues.put(Events.ORIGINAL_SYNC_ID, mModel2.mSyncId);
647         mExpectedValues.put(Events.ORIGINAL_INSTANCE_TIME, mModel1.mOriginalStart);
648         mExpectedValues.put(Events.ORIGINAL_ALL_DAY, 1);
649 
650         ContentProviderOperation.Builder b = ContentProviderOperation
651                 .newInsert(Events.CONTENT_URI)
652                 .withValues(mExpectedValues);
653         expectedOps.add(b.build());
654 
655         mHelper.saveRemindersWithBackRef(expectedOps, id, mModel1.mReminders,
656                 mModel2.mReminders, true);
657 
658         addOwnerAttendeeToOps(expectedOps, id);
659 
660         addTestAttendees(expectedOps, true, id);
661 
662         assertEquals(expectedOps, ops);
663         return true;
664     }
665 
666     @Smoke
667     @SmallTest
testSaveEventModifyAllFollowingWithNonRecurring()668     public void testSaveEventModifyAllFollowingWithNonRecurring() {
669         // Creates an original and an updated recurring event model. The update starts on the 2nd
670         // instance of the original.
671         mActivity = buildTestContext();
672         mHelper = new EditEventHelper(mActivity, null);
673 
674         mModel1 = buildTestModel();
675         mModel2 = buildTestModel();
676         mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
677 
678         mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
679         mModel2.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
680 
681         // The original model is assumed correct so drop the no good bit
682         mModel2.addAttendees(TEST_ADDRESSES4, null);
683 
684         // Modify the second instance of the event
685         long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
686         mModel1.mRrule = null;
687         mModel1.mEnd = TEST_END + dayInMs;
688         mModel1.mStart += dayInMs;
689         mModel1.mOriginalStart = mModel1.mStart;
690 
691         mCurrentSaveTest = SAVE_EVENT_ALLFOLLOW_TO_NORECUR;
692         // Only modify this instance
693         assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL_FOLLOWING));
694     }
695 
verifySaveEventModifyAllFollowingWithNonRecurring( ArrayList<ContentProviderOperation> ops)696     private boolean verifySaveEventModifyAllFollowingWithNonRecurring(
697             ArrayList<ContentProviderOperation> ops) {
698         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
699         int id = 0;
700         mExpectedValues = buildNonRecurringTestValues();
701         mExpectedValues.put(Events.HAS_ALARM, 0);
702         moveExpectedTimeValuesForwardOneDay();
703         // This has a separate test
704         mHelper.updatePastEvents(expectedOps, mModel2, mModel1.mOriginalStart);
705         id = expectedOps.size();
706         expectedOps.add(ContentProviderOperation
707                 .newInsert(Events.CONTENT_URI)
708                 .withValues(mExpectedValues)
709                 .build());
710 
711         mHelper.saveRemindersWithBackRef(expectedOps, id, mModel1.mReminders,
712                 mModel2.mReminders, true);
713 
714         addOwnerAttendeeToOps(expectedOps, id);
715 
716         addTestAttendees(expectedOps, true, id);
717 
718         assertEquals(expectedOps, ops);
719         return true;
720     }
721 
722     @Smoke
723     @SmallTest
testSaveEventModifyAllFollowingFirstWithNonRecurring()724     public void testSaveEventModifyAllFollowingFirstWithNonRecurring() {
725         // Creates an original recurring and an updated non-recurring event model for the first
726         // instance. This should replace the original event with a non-recurring event.
727         mActivity = buildTestContext();
728         mHelper = new EditEventHelper(mActivity, null);
729 
730         mModel1 = buildTestModel();
731         mModel2 = buildTestModel();
732         mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
733 
734         mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
735         mModel2.mUri = mModel1.mUri;
736         // And a new start time to ensure the time fields aren't removed
737         mModel1.mOriginalStart = TEST_START;
738 
739         // The original model is assumed correct so drop the no good bit
740         mModel2.addAttendees(TEST_ADDRESSES3, null);
741 
742         // Move the event one day but keep original start set to the first instance
743         long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
744         mModel1.mRrule = null;
745         mModel1.mEnd = TEST_END + dayInMs;
746         mModel1.mStart += dayInMs;
747 
748         mCurrentSaveTest = SAVE_EVENT_FIRST_TO_NORECUR;
749         // Only modify this instance
750         assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL_FOLLOWING));
751     }
752 
verifySaveEventModifyAllFollowingFirstWithNonRecurring( ArrayList<ContentProviderOperation> ops)753     private boolean verifySaveEventModifyAllFollowingFirstWithNonRecurring(
754             ArrayList<ContentProviderOperation> ops) {
755 
756         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
757         int id = 0;
758         mExpectedValues = buildNonRecurringTestValues();
759         mExpectedValues.put(Events.HAS_ALARM, 0);
760         moveExpectedTimeValuesForwardOneDay();
761 
762         expectedOps.add(ContentProviderOperation.newDelete(Uri.parse(mModel1.mUri)).build());
763         id = expectedOps.size();
764         expectedOps.add(ContentProviderOperation
765                         .newInsert(Events.CONTENT_URI)
766                         .withValues(mExpectedValues)
767                         .build());
768 
769         mHelper.saveRemindersWithBackRef(expectedOps, id, mModel1.mReminders,
770                 mModel2.mReminders, true);
771 
772         addOwnerAttendeeToOps(expectedOps, id);
773 
774         addTestAttendees(expectedOps, true, id);
775 
776         assertEquals(expectedOps, ops);
777         return true;
778     }
779 
780     @Smoke
781     @SmallTest
testSaveEventModifyAllFollowingFirstWithRecurring()782     public void testSaveEventModifyAllFollowingFirstWithRecurring() {
783         // Creates an original recurring and an updated recurring event model for the first instance
784         // This should replace the original event with a new recurrence
785         mActivity = buildTestContext();
786         mHelper = new EditEventHelper(mActivity, null);
787 
788         mModel1 = buildTestModel();
789         mModel2 = buildTestModel();
790         mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
791 
792         mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
793         mModel2.mUri = mModel1.mUri;
794         // And a new start time to ensure the time fields aren't removed
795         mModel1.mOriginalStart = TEST_START;
796 
797         // The original model is assumed correct so drop the no good bit
798         mModel2.addAttendees(TEST_ADDRESSES4, null);
799 
800         // Move the event one day but keep original start set to the first instance
801         long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
802         mModel1.mStart += dayInMs;
803 
804         mCurrentSaveTest = SAVE_EVENT_FIRST_TO_RECUR;
805         // Only modify this instance
806         assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL_FOLLOWING));
807     }
808 
verifySaveEventModifyAllFollowingFirstWithRecurring( ArrayList<ContentProviderOperation> ops)809     private boolean verifySaveEventModifyAllFollowingFirstWithRecurring(
810             ArrayList<ContentProviderOperation> ops) {
811         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
812         int br_id = 0;
813         mExpectedValues = buildTestValues();
814         mExpectedValues.put(Events.HAS_ALARM, 0);
815         moveExpectedTimeValuesForwardOneDay();
816         mExpectedValues.put(Events.DTEND, (Long)null);
817         // This is tested elsewhere, used for convenience here
818         mHelper.checkTimeDependentFields(mModel2, mModel1, mExpectedValues,
819                 EditEventHelper.MODIFY_ALL_FOLLOWING);
820 
821         expectedOps.add(ContentProviderOperation.newUpdate(Uri.parse(mModel1.mUri)).withValues(
822                 mExpectedValues).build());
823 
824         // This call has a separate unit test so we'll use it to simplify making the expected vals
825         mHelper.saveReminders(expectedOps, TEST_EVENT_ID, mModel1.mReminders,
826                 mModel2.mReminders, true);
827 
828         addOwnerAttendeeToOps(expectedOps);
829         addAttendeeChangesOps(expectedOps);
830 
831         assertEquals(expectedOps, ops);
832         return true;
833     }
834 
835     @Smoke
836     @SmallTest
testSaveEventModifyAllFollowingWithRecurring()837     public void testSaveEventModifyAllFollowingWithRecurring() {
838         // Creates an original recurring and an updated recurring event model
839         // for the second instance. This should end the original recurrence and add a new
840         // recurrence.
841         mActivity = buildTestContext();
842         mHelper = new EditEventHelper(mActivity, null);
843 
844         mModel1 = buildTestModel();
845         mModel2 = buildTestModel();
846         mModel1.addAttendees(TEST_ADDRESSES2, mEmailValidator);
847 
848         mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
849         mModel2.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
850 
851         // The original model is assumed correct so drop the no good bit
852         mModel2.addAttendees(TEST_ADDRESSES4, null);
853 
854         // Move the event one day and the original start so it references the second instance
855         long dayInMs = EditEventHelper.DAY_IN_SECONDS*1000;
856         mModel1.mStart += dayInMs;
857         mModel1.mOriginalStart = mModel1.mStart;
858 
859         mCurrentSaveTest = SAVE_EVENT_ALLFOLLOW_TO_RECUR;
860         // Only modify this instance
861         assertTrue(mHelper.saveEvent(mModel1, mModel2, EditEventHelper.MODIFY_ALL_FOLLOWING));
862     }
863 
verifySaveEventModifyAllFollowingWithRecurring( ArrayList<ContentProviderOperation> ops)864     private boolean verifySaveEventModifyAllFollowingWithRecurring(
865             ArrayList<ContentProviderOperation> ops) {
866         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
867         int br_id = 0;
868         mExpectedValues = buildTestValues();
869         mExpectedValues.put(Events.HAS_ALARM, 0);
870         moveExpectedTimeValuesForwardOneDay();
871         mExpectedValues.put(Events.DTEND, (Long)null);
872         // This is tested elsewhere, used for convenience here
873         mHelper.updatePastEvents(expectedOps, mModel2, mModel1.mOriginalStart);
874 
875         br_id = expectedOps.size();
876         expectedOps.add(ContentProviderOperation
877                 .newInsert(Events.CONTENT_URI)
878                 .withValues(mExpectedValues)
879                 .build());
880 
881         // This call has a separate unit test so we'll use it to simplify making the expected vals
882         mHelper.saveRemindersWithBackRef(expectedOps, br_id, mModel1.mReminders,
883                 mModel2.mReminders, true);
884 
885         addOwnerAttendeeToOps(expectedOps, br_id);
886 
887         addTestAttendees(expectedOps, true, br_id);
888 
889         assertEquals(expectedOps, ops);
890         return true;
891     }
892 
893     @Smoke
894     @SmallTest
testGetAddressesFromList()895     public void testGetAddressesFromList() {
896         mActivity = buildTestContext();
897         mHelper = new EditEventHelper(mActivity, null);
898 
899         LinkedHashSet<Rfc822Token> expected = new LinkedHashSet<Rfc822Token>();
900         expected.add(new Rfc822Token(null, "ad1@email.com", ""));
901         expected.add(new Rfc822Token("First Last", "first@email.com", "comment"));
902         expected.add(new Rfc822Token(null, "one.two.three@email.grue", ""));
903 
904         LinkedHashSet<Rfc822Token> actual = mHelper.getAddressesFromList(TEST_ADDRESSES,
905                 new Rfc822Validator(null));
906         assertEquals(expected, actual);
907     }
908 
909     @Smoke
910     @SmallTest
testConstructDefaultStartTime()911     public void testConstructDefaultStartTime() {
912         mActivity = buildTestContext();
913         mHelper = new EditEventHelper(mActivity, null);
914 
915         long now = 0;
916         long expected = now + 30 * DateUtils.MINUTE_IN_MILLIS;
917         assertEquals(expected, mHelper.constructDefaultStartTime(now));
918 
919         // 2:00 -> 2:30
920         now = 1262340000000L; // Fri Jan 01 2010 02:00:00 GMT-0800 (PST)
921         expected = now + 30 * DateUtils.MINUTE_IN_MILLIS;
922         assertEquals(expected, mHelper.constructDefaultStartTime(now));
923 
924         // 2:01 -> 2:30
925         now += DateUtils.MINUTE_IN_MILLIS;
926         assertEquals(expected, mHelper.constructDefaultStartTime(now));
927 
928         // 2:02 -> 2:30
929         now += DateUtils.MINUTE_IN_MILLIS;
930         assertEquals(expected, mHelper.constructDefaultStartTime(now));
931 
932         // 2:32 -> 3:00
933         now += 30 * DateUtils.MINUTE_IN_MILLIS;
934         expected += 30 * DateUtils.MINUTE_IN_MILLIS;
935         assertEquals(expected, mHelper.constructDefaultStartTime(now));
936 
937         // 2:33 -> 3:00
938         now += DateUtils.MINUTE_IN_MILLIS;
939         assertEquals(expected, mHelper.constructDefaultStartTime(now));
940 
941     }
942 
943     @Smoke
944     @SmallTest
testConstructDefaultEndTime()945     public void testConstructDefaultEndTime() {
946         mActivity = buildTestContext();
947         mHelper = new EditEventHelper(mActivity, null);
948 
949         long start = 1262340000000L;
950         long expected = start + DateUtils.HOUR_IN_MILLIS;
951         assertEquals(expected, mHelper.constructDefaultEndTime(start));
952     }
953 
954     @Smoke
955     @SmallTest
testCheckTimeDependentFieldsNoChanges()956     public void testCheckTimeDependentFieldsNoChanges() {
957         mActivity = buildTestContext();
958         mHelper = new EditEventHelper(mActivity, null);
959 
960         mModel1 = buildTestModel();
961         mModel2 = buildTestModel();
962         mModel2.mRrule = null;
963 
964         mValues = buildTestValues();
965         mExpectedValues = buildTestValues();
966 
967         // if any time/recurrence vals are different but there's no new rrule it
968         // shouldn't change
969         mHelper.checkTimeDependentFields(mModel1, mModel2, mValues, EditEventHelper.MODIFY_ALL);
970         assertEquals(mExpectedValues, mValues);
971 
972         // also, if vals are different and it's not modifying all it shouldn't
973         // change.
974         mModel2.mRrule = "something else";
975         mHelper.checkTimeDependentFields(mModel1, mModel2, mValues,
976                 EditEventHelper.MODIFY_SELECTED);
977         assertEquals(mExpectedValues, mValues);
978 
979         // if vals changed and modify all is selected dtstart should be updated
980         // by the difference
981         // between originalStart and start
982         mModel2.mOriginalStart = mModel2.mStart + 60000; // set the old time to
983                                                          // one minute later
984         mModel2.mStart += 120000; // move the event another 1 minute.
985 
986         // shouldn't change for an allday event
987         // expectedVals.put(Events.DTSTART, mModel1.mStart + 60000); // should
988         // now be 1 minute later
989         // dtstart2 shouldn't change since it gets rezeroed in the local
990         // timezone for allDay events
991 
992         mHelper.checkTimeDependentFields(mModel1, mModel2, mValues,
993                 EditEventHelper.MODIFY_SELECTED);
994         assertEquals(mExpectedValues, mValues);
995     }
996 
997     @Smoke
998     @SmallTest
testCheckTimeDependentFieldsChanges()999     public void testCheckTimeDependentFieldsChanges() {
1000         mActivity = buildTestContext();
1001         mHelper = new EditEventHelper(mActivity, null);
1002 
1003         mModel1 = buildTestModel();
1004         mModel2 = buildTestModel();
1005         mModel2.mRrule = null;
1006 
1007         mValues = buildTestValues();
1008         mExpectedValues = buildTestValues();
1009 
1010         // if all the time values are the same it should remove them from vals
1011         mModel2.mRrule = mModel1.mRrule;
1012         mModel2.mStart = mModel1.mStart;
1013         mModel2.mOriginalStart = mModel2.mStart;
1014 
1015         mExpectedValues.remove(Events.DTSTART);
1016         mExpectedValues.remove(Events.DTEND);
1017         mExpectedValues.remove(Events.DURATION);
1018         mExpectedValues.remove(Events.ALL_DAY);
1019         mExpectedValues.remove(Events.RRULE);
1020         mExpectedValues.remove(Events.EVENT_TIMEZONE);
1021 
1022         mHelper.checkTimeDependentFields(mModel1, mModel2, mValues,
1023                 EditEventHelper.MODIFY_SELECTED);
1024         assertEquals(mExpectedValues, mValues);
1025 
1026     }
1027 
1028     @Smoke
1029     @SmallTest
testUpdatePastEvents()1030     public void testUpdatePastEvents() {
1031         ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
1032         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
1033         long initialBeginTime = 1472864400000L; // Sep 3, 2016, 12AM UTC time
1034         mValues = new ContentValues();
1035 
1036         mModel1 = buildTestModel();
1037         mModel1.mUri = (AUTHORITY_URI + TEST_EVENT_ID);
1038         mActivity = buildTestContext();
1039         mHelper = new EditEventHelper(mActivity, null);
1040 
1041         mValues.put(Events.RRULE, "FREQ=DAILY;UNTIL=20160903;WKST=SU"); // yyyymmddThhmmssZ
1042         mValues.put(Events.DTSTART, TEST_START);
1043 
1044         ContentProviderOperation.Builder b = ContentProviderOperation.newUpdate(
1045                 Uri.parse(mModel1.mUri)).withValues(mValues);
1046         expectedOps.add(b.build());
1047 
1048         mHelper.updatePastEvents(ops, mModel1, initialBeginTime);
1049         assertEquals(expectedOps, ops);
1050 
1051         mModel1.mAllDay = false;
1052 
1053         mValues.put(Events.RRULE, "FREQ=DAILY;UNTIL=20160903T005959Z;WKST=SU"); // yyyymmddThhmmssZ
1054 
1055         expectedOps.clear();
1056         b = ContentProviderOperation.newUpdate(Uri.parse(mModel1.mUri)).withValues(mValues);
1057         expectedOps.add(b.build());
1058 
1059         ops.clear();
1060         mHelper.updatePastEvents(ops, mModel1, initialBeginTime);
1061         assertEquals(expectedOps, ops);
1062     }
1063 
1064     @Smoke
1065     @SmallTest
testConstructReminderLabel()1066     public void testConstructReminderLabel() {
1067         mActivity = buildTestContext();
1068 
1069         String label = EventViewUtils.constructReminderLabel(mActivity, 35, true);
1070         assertEquals("35 mins", label);
1071 
1072         label = EventViewUtils.constructReminderLabel(mActivity, 72, false);
1073         assertEquals("72 minutes", label);
1074 
1075         label = EventViewUtils.constructReminderLabel(mActivity, 60, true);
1076         assertEquals("1 hours", label);
1077 
1078         label = EventViewUtils.constructReminderLabel(mActivity, 60 * 48, true);
1079         assertEquals("2 days", label);
1080     }
1081 
1082     @Smoke
1083     @SmallTest
testIsSameEvent()1084     public void testIsSameEvent() {
1085         mModel1 = new CalendarEventModel();
1086         mModel2 = new CalendarEventModel();
1087 
1088         mModel1.mId = 1;
1089         mModel1.mCalendarId = 1;
1090         mModel2.mId = 1;
1091         mModel2.mCalendarId = 1;
1092 
1093         // considered the same if the event and calendar ids both match
1094         assertTrue(EditEventHelper.isSameEvent(mModel1, mModel2));
1095 
1096         mModel2.mId = 2;
1097         assertFalse(EditEventHelper.isSameEvent(mModel1, mModel2));
1098 
1099         mModel2.mId = 1;
1100         mModel2.mCalendarId = 2;
1101         assertFalse(EditEventHelper.isSameEvent(mModel1, mModel2));
1102     }
1103 
1104     @Smoke
1105     @SmallTest
testSaveReminders()1106     public void testSaveReminders() {
1107         ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
1108         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
1109         long eventId = TEST_EVENT_ID;
1110         ArrayList<ReminderEntry> reminders = new ArrayList<ReminderEntry>();
1111         ArrayList<ReminderEntry> originalReminders = new ArrayList<ReminderEntry>();
1112         boolean forceSave = true;
1113         boolean result;
1114         mActivity = buildTestContext();
1115         mHelper = new EditEventHelper(mActivity, null);
1116         assertNotNull(mHelper);
1117 
1118         // First test forcing a delete with no reminders.
1119         String where = Reminders.EVENT_ID + "=?";
1120         String[] args = new String[] {Long.toString(eventId)};
1121         ContentProviderOperation.Builder b =
1122                 ContentProviderOperation.newDelete(Reminders.CONTENT_URI);
1123         b.withSelection(where, args);
1124         expectedOps.add(b.build());
1125 
1126         result = mHelper.saveReminders(ops, eventId, reminders, originalReminders, forceSave);
1127         assertTrue(result);
1128         assertEquals(expectedOps, ops);
1129 
1130         // Now test calling save with identical reminders and no forcing
1131         reminders.add(ReminderEntry.valueOf(5));
1132         reminders.add(ReminderEntry.valueOf(10));
1133         reminders.add(ReminderEntry.valueOf(15));
1134 
1135         originalReminders.add(ReminderEntry.valueOf(5));
1136         originalReminders.add(ReminderEntry.valueOf(10));
1137         originalReminders.add(ReminderEntry.valueOf(15));
1138 
1139         forceSave = false;
1140 
1141         ops.clear();
1142 
1143         // Should fail to create any ops since nothing changed
1144         result = mHelper.saveReminders(ops, eventId, reminders, originalReminders, forceSave);
1145         assertFalse(result);
1146         assertEquals(0, ops.size());
1147 
1148         //Now test adding a single reminder
1149         originalReminders.remove(2);
1150 
1151         addExpectedMinutes(expectedOps);
1152 
1153         result = mHelper.saveReminders(ops, eventId, reminders, originalReminders, forceSave);
1154         assertTrue(result);
1155         assertEquals(expectedOps, ops);
1156     }
1157 
1158     @Smoke
1159     @SmallTest
testSaveRemindersWithBackRef()1160     public void testSaveRemindersWithBackRef() {
1161         ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
1162         ArrayList<ContentProviderOperation> expectedOps = new ArrayList<ContentProviderOperation>();
1163         long eventId = TEST_EVENT_ID;
1164         ArrayList<ReminderEntry> reminders = new ArrayList<ReminderEntry>();
1165         ArrayList<ReminderEntry> originalReminders = new ArrayList<ReminderEntry>();
1166         boolean forceSave = true;
1167         boolean result;
1168         mActivity = buildTestContext();
1169         mHelper = new EditEventHelper(mActivity, null);
1170         assertNotNull(mHelper);
1171 
1172         // First test forcing a delete with no reminders.
1173         ContentProviderOperation.Builder b =
1174                 ContentProviderOperation.newDelete(Reminders.CONTENT_URI);
1175         b.withSelection(Reminders.EVENT_ID + "=?", new String[1]);
1176         b.withSelectionBackReference(0, TEST_EVENT_INDEX_ID);
1177         expectedOps.add(b.build());
1178 
1179         result =
1180                 mHelper.saveRemindersWithBackRef(ops, TEST_EVENT_INDEX_ID, reminders,
1181                         originalReminders, forceSave);
1182         assertTrue(result);
1183         assertEquals(expectedOps, ops);
1184 
1185         // Now test calling save with identical reminders and no forcing
1186         reminders.add(ReminderEntry.valueOf(5));
1187         reminders.add(ReminderEntry.valueOf(10));
1188         reminders.add(ReminderEntry.valueOf(15));
1189 
1190         originalReminders.add(ReminderEntry.valueOf(5));
1191         originalReminders.add(ReminderEntry.valueOf(10));
1192         originalReminders.add(ReminderEntry.valueOf(15));
1193 
1194         forceSave = false;
1195 
1196         ops.clear();
1197 
1198         result = mHelper.saveRemindersWithBackRef(ops, ops.size(), reminders, originalReminders,
1199                         forceSave);
1200         assertFalse(result);
1201         assertEquals(0, ops.size());
1202 
1203         //Now test adding a single reminder
1204         originalReminders.remove(2);
1205 
1206         addExpectedMinutesWithBackRef(expectedOps);
1207 
1208         result = mHelper.saveRemindersWithBackRef(ops, ops.size(), reminders, originalReminders,
1209                         forceSave);
1210         assertTrue(result);
1211         assertEquals(expectedOps, ops);
1212     }
1213 
1214     @Smoke
1215     @SmallTest
testIsFirstEventInSeries()1216     public void testIsFirstEventInSeries() {
1217         mModel1 = new CalendarEventModel();
1218         mModel2 = new CalendarEventModel();
1219 
1220         // It's considered the first event if the original start of the new model matches the
1221         // start of the old model
1222         mModel1.mOriginalStart = 100;
1223         mModel1.mStart = 200;
1224         mModel2.mOriginalStart = 100;
1225         mModel2.mStart = 100;
1226 
1227         assertTrue(EditEventHelper.isFirstEventInSeries(mModel1, mModel2));
1228 
1229         mModel1.mOriginalStart = 80;
1230         assertFalse(EditEventHelper.isFirstEventInSeries(mModel1, mModel2));
1231     }
1232 
1233     @Smoke
1234     @SmallTest
testAddRecurrenceRule()1235     public void testAddRecurrenceRule() {
1236         mActivity = buildTestContext();
1237         mHelper = new EditEventHelper(mActivity, null);
1238         mValues = new ContentValues();
1239         mExpectedValues = new ContentValues();
1240         mModel1 = new CalendarEventModel();
1241 
1242         mExpectedValues.put(Events.RRULE, "Weekly, Monday");
1243         mExpectedValues.put(Events.DURATION, "P60S");
1244         mExpectedValues.put(Events.DTEND, (Long) null);
1245 
1246         mModel1.mRrule = "Weekly, Monday";
1247         mModel1.mStart = 1;
1248         mModel1.mEnd = 60001;
1249         mModel1.mAllDay = false;
1250 
1251         mHelper.addRecurrenceRule(mValues, mModel1);
1252         assertEquals(mExpectedValues, mValues);
1253 
1254         mExpectedValues.put(Events.DURATION, "P1D");
1255 
1256         mModel1.mAllDay = true;
1257         mValues.clear();
1258 
1259         mHelper.addRecurrenceRule(mValues, mModel1);
1260         assertEquals(mExpectedValues, mValues);
1261 
1262     }
1263 
1264     @Smoke
1265     @SmallTest
testUpdateRecurrenceRule()1266     public void testUpdateRecurrenceRule() {
1267         int selection = EditEventHelper.DOES_NOT_REPEAT;
1268         int weekStart = Calendar.SUNDAY;
1269         mModel1 = new CalendarEventModel();
1270         mModel1.mTimezone = Time.TIMEZONE_UTC;
1271         mModel1.mStart = 1272665741000L; // Fri, April 30th ~ 3:17PM
1272 
1273         mModel1.mRrule = "This should go away";
1274 
1275         EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
1276         assertNull(mModel1.mRrule);
1277 
1278         mModel1.mRrule = "This shouldn't change";
1279         selection = EditEventHelper.REPEATS_CUSTOM;
1280 
1281         EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
1282         assertEquals("This shouldn't change", mModel1.mRrule);
1283 
1284         selection = EditEventHelper.REPEATS_DAILY;
1285 
1286         EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
1287         assertEquals("FREQ=DAILY;WKST=SU", mModel1.mRrule);
1288 
1289         selection = EditEventHelper.REPEATS_EVERY_WEEKDAY;
1290 
1291         EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
1292         assertEquals("FREQ=WEEKLY;WKST=SU;BYDAY=MO,TU,WE,TH,FR", mModel1.mRrule);
1293 
1294         selection = EditEventHelper.REPEATS_WEEKLY_ON_DAY;
1295 
1296         EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
1297         assertEquals("FREQ=WEEKLY;WKST=SU;BYDAY=FR", mModel1.mRrule);
1298 
1299         selection = EditEventHelper.REPEATS_MONTHLY_ON_DAY;
1300 
1301         EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
1302         assertEquals("FREQ=MONTHLY;WKST=SU;BYMONTHDAY=30", mModel1.mRrule);
1303 
1304         selection = EditEventHelper.REPEATS_MONTHLY_ON_DAY_COUNT;
1305 
1306         EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
1307         assertEquals("FREQ=MONTHLY;WKST=SU;BYDAY=-1FR", mModel1.mRrule);
1308 
1309         selection = EditEventHelper.REPEATS_YEARLY;
1310 
1311         EditEventHelper.updateRecurrenceRule(selection, mModel1, weekStart);
1312         assertEquals("FREQ=YEARLY;WKST=SU", mModel1.mRrule);
1313     }
1314 
1315     @Smoke
1316     @SmallTest
testSetModelFromCursor()1317     public void testSetModelFromCursor() {
1318         mActivity = buildTestContext();
1319         mHelper = new EditEventHelper(mActivity, null);
1320         MatrixCursor c = new MatrixCursor(EditEventHelper.EVENT_PROJECTION);
1321         c.addRow(TEST_CURSOR_DATA);
1322 
1323         mModel1 = new CalendarEventModel();
1324         mModel2 = buildTestModel();
1325 
1326         EditEventHelper.setModelFromCursor(mModel1, c);
1327         assertEquals(mModel1, mModel2);
1328 
1329         TEST_CURSOR_DATA[EditEventHelper.EVENT_INDEX_ALL_DAY] = "0";
1330         c.close();
1331         c = new MatrixCursor(EditEventHelper.EVENT_PROJECTION);
1332         c.addRow(TEST_CURSOR_DATA);
1333 
1334         mModel2.mAllDay = false;
1335         mModel2.mStart = TEST_START; // UTC time
1336 
1337         EditEventHelper.setModelFromCursor(mModel1, c);
1338         assertEquals(mModel1, mModel2);
1339 
1340         TEST_CURSOR_DATA[EditEventHelper.EVENT_INDEX_RRULE] = null;
1341         c.close();
1342         c = new MatrixCursor(EditEventHelper.EVENT_PROJECTION);
1343         c.addRow(TEST_CURSOR_DATA);
1344 
1345         mModel2.mRrule = null;
1346         mModel2.mEnd = TEST_END;
1347         mModel2.mDuration = null;
1348 
1349         EditEventHelper.setModelFromCursor(mModel1, c);
1350         assertEquals(mModel1, mModel2);
1351 
1352         TEST_CURSOR_DATA[EditEventHelper.EVENT_INDEX_ALL_DAY] = "1";
1353         c.close();
1354         c = new MatrixCursor(EditEventHelper.EVENT_PROJECTION);
1355         c.addRow(TEST_CURSOR_DATA);
1356 
1357         mModel2.mAllDay = true;
1358         mModel2.mStart = TEST_START; // Monday, May 3rd, midnight
1359         mModel2.mEnd = TEST_END; // Tuesday, May 4th, midnight
1360 
1361         EditEventHelper.setModelFromCursor(mModel1, c);
1362         assertEquals(mModel1, mModel2);
1363     }
1364 
1365     @Smoke
1366     @SmallTest
testGetContentValuesFromModel()1367     public void testGetContentValuesFromModel() {
1368         mActivity = buildTestContext();
1369         mHelper = new EditEventHelper(mActivity, null);
1370         mExpectedValues = buildTestValues();
1371         mModel1 = buildTestModel();
1372 
1373         ContentValues values = mHelper.getContentValuesFromModel(mModel1);
1374         assertEquals(mExpectedValues, values);
1375 
1376         mModel1.mRrule = null;
1377         mModel1.mEnd = TEST_END;
1378 
1379         mExpectedValues.put(Events.RRULE, (String) null);
1380         mExpectedValues.put(Events.DURATION, (String) null);
1381         mExpectedValues.put(Events.DTEND, TEST_END); // UTC time
1382 
1383         values = mHelper.getContentValuesFromModel(mModel1);
1384         assertEquals(mExpectedValues, values);
1385 
1386         mModel1.mAllDay = false;
1387 
1388         mExpectedValues.put(Events.ALL_DAY, 0);
1389         mExpectedValues.put(Events.DTSTART, TEST_START);
1390         mExpectedValues.put(Events.DTEND, TEST_END);
1391         // not an allday event so timezone isn't modified
1392         mExpectedValues.put(Events.EVENT_TIMEZONE, "UTC");
1393 
1394         values = mHelper.getContentValuesFromModel(mModel1);
1395         assertEquals(mExpectedValues, values);
1396     }
1397 
1398     @Smoke
1399     @SmallTest
testExtractDomain()1400     public void testExtractDomain() {
1401         String domain = EditEventHelper.extractDomain("test.email@gmail.com");
1402         assertEquals("gmail.com", domain);
1403 
1404         domain = EditEventHelper.extractDomain("bademail.no#$%at symbol");
1405         assertNull(domain);
1406     }
1407 
addExpectedMinutes(ArrayList<ContentProviderOperation> expectedOps)1408     private void addExpectedMinutes(ArrayList<ContentProviderOperation> expectedOps) {
1409         ContentProviderOperation.Builder b;
1410         mValues = new ContentValues();
1411 
1412         mValues.clear();
1413         mValues.put(Reminders.MINUTES, 5);
1414         mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
1415         mValues.put(Reminders.EVENT_ID, TEST_EVENT_ID);
1416         b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
1417         expectedOps.add(b.build());
1418 
1419         mValues.clear();
1420         mValues.put(Reminders.MINUTES, 10);
1421         mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
1422         mValues.put(Reminders.EVENT_ID, TEST_EVENT_ID);
1423         b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
1424         expectedOps.add(b.build());
1425 
1426         mValues.clear();
1427         mValues.put(Reminders.MINUTES, 15);
1428         mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
1429         mValues.put(Reminders.EVENT_ID, TEST_EVENT_ID);
1430         b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
1431         expectedOps.add(b.build());
1432     }
1433 
addExpectedMinutesWithBackRef(ArrayList<ContentProviderOperation> expectedOps)1434     private void addExpectedMinutesWithBackRef(ArrayList<ContentProviderOperation> expectedOps) {
1435         ContentProviderOperation.Builder b;
1436         mValues = new ContentValues();
1437 
1438         mValues.clear();
1439         mValues.put(Reminders.MINUTES, 5);
1440         mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
1441         b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
1442         b.withValueBackReference(Reminders.EVENT_ID, TEST_EVENT_INDEX_ID);
1443         expectedOps.add(b.build());
1444 
1445         mValues.clear();
1446         mValues.put(Reminders.MINUTES, 10);
1447         mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
1448         b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
1449         b.withValueBackReference(Reminders.EVENT_ID, TEST_EVENT_INDEX_ID);
1450         expectedOps.add(b.build());
1451 
1452         mValues.clear();
1453         mValues.put(Reminders.MINUTES, 15);
1454         mValues.put(Reminders.METHOD, Reminders.METHOD_DEFAULT);
1455         b = ContentProviderOperation.newInsert(Reminders.CONTENT_URI).withValues(mValues);
1456         b.withValueBackReference(Reminders.EVENT_ID, TEST_EVENT_INDEX_ID);
1457         expectedOps.add(b.build());
1458     }
1459 
assertEquals(ArrayList<ContentProviderOperation> expected, ArrayList<ContentProviderOperation> actual)1460     private static void assertEquals(ArrayList<ContentProviderOperation> expected,
1461             ArrayList<ContentProviderOperation> actual) {
1462         if (expected == null) {
1463             assertNull(actual);
1464         }
1465         int size = expected.size();
1466 
1467         assertEquals(size, actual.size());
1468 
1469         for (int i = 0; i < size; i++) {
1470             assertTrue("At index " + i + ", expected:\n" + String.valueOf(expected.get(i)) +
1471                     "\nActual:\n" + String.valueOf(actual.get(i)),
1472                     cpoEquals(expected.get(i), actual.get(i)));
1473         }
1474 
1475     }
1476 
cpoEquals(ContentProviderOperation cpo1, ContentProviderOperation cpo2)1477     private static boolean cpoEquals(ContentProviderOperation cpo1, ContentProviderOperation cpo2) {
1478         if (cpo1 == null && cpo2 != null) {
1479             return false;
1480         }
1481         if (cpo1 == cpo2) {
1482             return true;
1483         }
1484         if (cpo2 == null) {
1485             return false;
1486         }
1487 
1488         // It turns out we can't trust the toString() of the ContentProviderOperations to be
1489         // consistent, so we have to do the comparison manually.
1490         //
1491         // Start by splitting by commas, so that we can compare each key-value pair individually.
1492         String[] operations1 = cpo1.toString().split(",");
1493         String[] operations2 = cpo2.toString().split(",");
1494         // The two numbers of operations must be equal.
1495         if (operations1.length != operations2.length) {
1496             return false;
1497         }
1498         // Iterate through the key-value pairs and separate out the key and value.
1499         // The value may be either a single string, or a series of further key-value pairs
1500         // that are separated by " ", with a "=" between the key and value.
1501         for (int i = 0; i < operations1.length; i++) {
1502             String operation1 = operations1[i];
1503             String operation2 = operations2[i];
1504             // Limit the array to length 2 in case a ":" appears in the value.
1505             String[] keyValue1 = operation1.split(":", 2);
1506             String[] keyValue2 = operation2.split(":", 2);
1507             // If the key doesn't match, return false.
1508             if (!keyValue1[0].equals(keyValue2[0])) {
1509                 return false;
1510             }
1511             // First just check if the value matches up. If so, we're good to go.
1512             if (keyValue1[1].equals(keyValue2[1])) {
1513                 continue;
1514             }
1515             // If not, we need to try splitting the value by " " and sorting those keyvalue pairs.
1516             // Note that these are trimmed first to ensure we're not thrown off by extra whitespace.
1517             String[] valueKeyValuePairs1 = keyValue1[1].trim().split(" ");
1518             String[] valueKeyValuePairs2 = keyValue2[1].trim().split(" ");
1519             // Sort the value's keyvalue pairs alphabetically, and now compare them to each other.
1520             Arrays.sort(valueKeyValuePairs1);
1521             Arrays.sort(valueKeyValuePairs2);
1522             for (int j = 0; j < valueKeyValuePairs1.length; j++) {
1523                 if (!valueKeyValuePairs1[j].equals(valueKeyValuePairs2[j])) {
1524                     return false;
1525                 }
1526             }
1527         }
1528 
1529         // If we make it all the way through without finding anything different, return true.
1530         return true;
1531     }
1532 
1533     // Generates a default model for testing. Should match up with
1534     // generateTestValues
buildTestModel()1535     private CalendarEventModel buildTestModel() {
1536         CalendarEventModel model = new CalendarEventModel();
1537         model.mId = TEST_EVENT_ID;
1538         model.mTitle = "The_Question";
1539         model.mDescription = "Evaluating_Life_the_Universe_and_Everything";
1540         model.mLocation = "Earth_Mk2";
1541         model.mAllDay = true;
1542         model.mHasAlarm = false;
1543         model.mCalendarId = 2;
1544         model.mStart = TEST_START; // Monday, May 3rd, local Time
1545         model.mDuration = "P3652421990D";
1546         // The model uses the local timezone for allday
1547         model.mTimezone = "UTC";
1548         model.mRrule = "FREQ=DAILY;WKST=SU";
1549         model.mSyncId = "unique_per_calendar_stuff";
1550         model.mAvailability = 0;
1551         model.mAccessLevel = 2; // This is one less than the values written if >0
1552         model.mOwnerAccount = "steve@gmail.com";
1553         model.mHasAttendeeData = true;
1554         model.mOrganizer = "organizer@gmail.com";
1555         model.mIsOrganizer = false;
1556         model.mGuestsCanModify = false;
1557         model.mEventStatus = Events.STATUS_CONFIRMED;
1558         int displayColor = Utils.getDisplayColorFromColor(-2350809);
1559         model.setEventColor(displayColor);
1560         model.mCalendarAccountName = "steve.owner@gmail.com";
1561         model.mCalendarAccountType = "gmail.com";
1562         EventColorCache cache = new EventColorCache();
1563         cache.insertColor("steve.owner@gmail.com", "gmail.com", displayColor, 12);
1564         model.mEventColorCache = cache;
1565         model.mModelUpdatedWithEventCursor = true;
1566         return model;
1567     }
1568 
1569     // Generates a default set of values for testing. Should match up with
1570     // generateTestModel
buildTestValues()1571     private ContentValues buildTestValues() {
1572         ContentValues values = new ContentValues();
1573 
1574         values.put(Events.CALENDAR_ID, 2L);
1575         values.put(Events.EVENT_TIMEZONE, "UTC"); // Allday events are converted
1576                                                   // to UTC for the db
1577         values.put(Events.TITLE, "The_Question");
1578         values.put(Events.ALL_DAY, 1);
1579         values.put(Events.DTSTART, TEST_START); // Monday, May 3rd, midnight UTC time
1580         values.put(Events.HAS_ATTENDEE_DATA, 1);
1581 
1582         values.put(Events.RRULE, "FREQ=DAILY;WKST=SU");
1583         values.put(Events.DURATION, "P3652421990D");
1584         values.put(Events.DTEND, (Long) null);
1585         values.put(Events.DESCRIPTION, "Evaluating_Life_the_Universe_and_Everything");
1586         values.put(Events.EVENT_LOCATION, "Earth_Mk2");
1587         values.put(Events.AVAILABILITY, 0);
1588         values.put(Events.STATUS, Events.STATUS_CONFIRMED);
1589         values.put(Events.ACCESS_LEVEL, 3); // This is one more than the model if
1590                                           // >0
1591         values.put(Events.EVENT_COLOR_KEY, 12);
1592 
1593         return values;
1594     }
1595 
buildNonRecurringTestValues()1596     private ContentValues buildNonRecurringTestValues() {
1597         ContentValues values = buildTestValues();
1598         values.put(Events.DURATION, (String)null);
1599         values.put(Events.DTEND, TEST_END);
1600         values.put(Events.RRULE, (String)null);
1601         return values;
1602     }
1603 
1604     // This gets called by EditEventHelper to read or write the data
1605     class TestProvider extends ContentProvider {
1606         int index = 0;
1607 
TestProvider()1608         public TestProvider() {
1609         }
1610 
1611         @Override
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy)1612         public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
1613                 String orderBy) {
1614             return null;
1615         }
1616 
1617         @Override
delete(Uri uri, String selection, String[] selectionArgs)1618         public int delete(Uri uri, String selection, String[] selectionArgs) {
1619             return 0;
1620         }
1621 
1622         @Override
getType(Uri uri)1623         public String getType(Uri uri) {
1624             return null;
1625         }
1626 
1627         @Override
onCreate()1628         public boolean onCreate() {
1629             return false;
1630         }
1631 
1632         @Override
insert(Uri uri, ContentValues values)1633         public Uri insert(Uri uri, ContentValues values) {
1634             // TODO Auto-generated method stub
1635             return null;
1636         }
1637 
1638         @Override
update(Uri uri, ContentValues values, String selection, String[] selectionArgs)1639         public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
1640             // TODO Auto-generated method stub
1641             return 0;
1642         }
1643     }
1644 
1645 }
1646