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