Home | History | Annotate | Download | only in event
      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 (at) gmail.com", // 15 owner account
     92             "1", // 16 has attendee data
     93             null, //17 originalSyncId
     94             "organizer (at) 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 (at) email.com, \"First Last\" <first (at) email.com> (comment), " +
    108             "one.two.three (at) email.grue";
    109     private static final String TEST_ADDRESSES2 =
    110             "no good, ad1 (at) email.com, \"First Last\" <first (at) email.com> (comment), " +
    111             "different (at) email.bit";
    112     private static final String TEST_ADDRESSES3 =
    113             "ad1 (at) email.com, \"First Last\" <first (at) email.com> (comment), " +
    114             "different (at) email.bit";
    115     private static final String TEST_ADDRESSES4 =
    116             "ad1 (at) email.com, \"First Last\" <first (at) email.com> (comment), " +
    117             "one.two.three (at) 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
    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
    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
    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 
    188     private AbstractCalendarActivity buildTestContext() {
    189         MockAbsCalendarActivity context = new MockAbsCalendarActivity();
    190         return context;
    191     }
    192 
    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 
    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 
    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
    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
    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 (at) email.grue"});
    270         expectedOps.add(b.build());
    271 
    272         mExpectedValues.clear();
    273         mExpectedValues.put(Attendees.ATTENDEE_NAME, "different (at) email.bit");
    274         mExpectedValues.put(Attendees.ATTENDEE_EMAIL, "different (at) 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
    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      */
    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 (at) email.com");
    302         mExpectedValues.put(Attendees.ATTENDEE_EMAIL, "ad1 (at) 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 (at) 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 (at) email.bit");
    342         mExpectedValues.put(Attendees.ATTENDEE_EMAIL, "different (at) 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
    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
    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 
    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
    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 
    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
    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 
    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
    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 
    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
    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 
    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
    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 
    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
    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 
    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
    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 
    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
    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 
    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
    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 
    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
    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 (at) email.com", ""));
    901         expected.add(new Rfc822Token("First Last", "first (at) email.com", "comment"));
    902         expected.add(new Rfc822Token(null, "one.two.three (at) 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
    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
    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
    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
    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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   1400     public void testExtractDomain() {
   1401         String domain = EditEventHelper.extractDomain("test.email (at) gmail.com");
   1402         assertEquals("gmail.com", domain);
   1403 
   1404         domain = EditEventHelper.extractDomain("bademail.no#$%at symbol");
   1405         assertNull(domain);
   1406     }
   1407 
   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 
   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 
   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 
   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
   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 (at) gmail.com";
   1553         model.mHasAttendeeData = true;
   1554         model.mOrganizer = "organizer (at) 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 (at) gmail.com";
   1561         model.mCalendarAccountType = "gmail.com";
   1562         EventColorCache cache = new EventColorCache();
   1563         cache.insertColor("steve.owner (at) 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
   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 
   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 
   1608         public TestProvider() {
   1609         }
   1610 
   1611         @Override
   1612         public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
   1613                 String orderBy) {
   1614             return null;
   1615         }
   1616 
   1617         @Override
   1618         public int delete(Uri uri, String selection, String[] selectionArgs) {
   1619             return 0;
   1620         }
   1621 
   1622         @Override
   1623         public String getType(Uri uri) {
   1624             return null;
   1625         }
   1626 
   1627         @Override
   1628         public boolean onCreate() {
   1629             return false;
   1630         }
   1631 
   1632         @Override
   1633         public Uri insert(Uri uri, ContentValues values) {
   1634             // TODO Auto-generated method stub
   1635             return null;
   1636         }
   1637 
   1638         @Override
   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