1b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook/* 2b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * Copyright (C) 2010 The Android Open Source Project 3b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * 4b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * Licensed under the Apache License, Version 2.0 (the "License"); 5b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * you may not use this file except in compliance with the License. 6b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * You may obtain a copy of the License at 7b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * 8b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * http://www.apache.org/licenses/LICENSE-2.0 9b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * 10b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * Unless required by applicable law or agreed to in writing, software 11b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * distributed under the License is distributed on an "AS IS" BASIS, 12b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * See the License for the specific language governing permissions and 14b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * limitations under the License. 15b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook */ 16b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 17b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookpackage com.android.exchange.utility; 18b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 19b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.content.ContentValues; 20b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.content.Entity; 21b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.content.res.Resources; 22b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.provider.CalendarContract.Attendees; 23b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.provider.CalendarContract.Events; 24b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.test.suitebuilder.annotation.MediumTest; 25b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.util.Log; 26b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 27b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.emailcommon.mail.Address; 28b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.emailcommon.provider.Account; 29b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.emailcommon.provider.EmailContent.Attachment; 30b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.emailcommon.provider.EmailContent.Message; 31b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.emailcommon.utility.Utility; 32b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.exchange.R; 33b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.exchange.adapter.CalendarSyncAdapter; 34b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.exchange.adapter.CalendarSyncAdapter.EasCalendarSyncParser; 35b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.exchange.adapter.Parser; 36b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.exchange.adapter.Serializer; 37b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.exchange.adapter.SyncAdapterTestCase; 38b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.exchange.adapter.Tags; 39b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 40b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.io.BufferedReader; 41b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.io.ByteArrayInputStream; 42b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.io.IOException; 43b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.io.StringReader; 44b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.text.DateFormat; 45b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.util.ArrayList; 46b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.util.Calendar; 47b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.util.Date; 48b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.util.GregorianCalendar; 49b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.util.HashMap; 50b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.util.TimeZone; 51b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 52b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook/** 53b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * Tests of EAS Calendar Utilities 54b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * You can run this entire test case with: 55b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * runtest -c com.android.exchange.utility.CalendarUtilitiesTests exchange 56b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * 57b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * Please see RFC2445 for RRULE definition 58b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * http://www.ietf.org/rfc/rfc2445.txt 59b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook */ 60b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook@MediumTest 61b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookpublic class CalendarUtilitiesTests extends SyncAdapterTestCase<CalendarSyncAdapter> { 62b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 63b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Some prebuilt time zones, Base64 encoded (as they arrive from EAS) 64b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // More time zones to be added over time 65b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 66b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Not all time zones are appropriate for testing. For example, ISRAEL_STANDARD_TIME cannot be 67b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // used because DST is determined from year to year in a non-standard way (related to the lunar 68b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // calendar); therefore, the test would only work during the year in which it was created 69b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 70b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This time zone has no DST 71b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private static final String ASIA_CALCUTTA_TIME = 72b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "tv7//0kAbgBkAGkAYQAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 73b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEkAbgBkAGkAYQAgAEQAYQB5AGwAaQBnAGgAdAAgAFQAaQBtAGUA" + 74b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; 75b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 76b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This time zone is equivalent to PST and uses DST 77b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private static final String AMERICA_DAWSON_TIME = 78b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "4AEAAFAAYQBjAGkAZgBpAGMAIABTAHQAYQBuAGQAYQByAGQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAA" + 79b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "AAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAFAAYQBjAGkAZgBpAGMAIABEAGEAeQBsAGkAZwBoAHQAIABUAGkA" + 80b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "bQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAAAAxP///w=="; 81b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 82b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Test a southern hemisphere time zone w/ DST 83b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private static final String AUSTRALIA_ACT_TIME = 84b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "qP3//0EAVQBTACAARQBhAHMAdABlAHIAbgAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAA" + 85b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "AAAAAAAAAAQAAAABAAMAAAAAAAAAAAAAAEEAVQBTACAARQBhAHMAdABlAHIAbgAgAEQAYQB5AGwAaQBnAGgA" + 86b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "dAAgAFQAaQBtAGUAAAAAAAAAAAAAAAAAAAAAAAoAAAABAAIAAAAAAAAAxP///w=="; 87b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 88b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Test a timezone with GMT bias but bogus DST parameters (there is no equivalent time zone 89b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // in the database) 90b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private static final String GMT_UNKNOWN_DAYLIGHT_TIME = 91b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "AAAAACgARwBNAFQAKwAwADAAOgAwADAAKQAgAFQAaQBtAGUAIABaAG8AbgBlAAAAAAAAAAAAAAAAAAAAAAAA" + 92b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "AAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAACgARwBNAFQAKwAwADAAOgAwADAAKQAgAFQAaQBtAGUAIABaAG8A" + 93b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "bgBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAEAAAAAAAAAxP///w=="; 94b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 95b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This time zone has no DST, but earlier, buggy code retrieved a TZ WITH DST 96b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private static final String ARIZONA_TIME = 97b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "pAEAAFUAUwAgAE0AbwB1AG4AdABhAGkAbgAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAA" + 98b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFUAUwAgAE0AbwB1AG4AdABhAGkAbgAgAEQAYQB5AGwAaQBnAGgA" + 99b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "dAAgAFQAaQBtAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; 100b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 101b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private static final String HAWAII_TIME = 102b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "WAIAAEgAYQB3AGEAaQBpAGEAbgAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAAAAAAAAAA" + 103b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEgAYQB3AGEAaQBpAGEAbgAgAEQAYQB5AGwAaQBnAGgAdAAgAFQA" + 104b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "aQBtAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; 105b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 106b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This is time zone sent by Exchange 2007, apparently; the start time of DST for the eastern 107b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // time zone (EST) is off by two hours, which we should correct in our new "lenient" code 108b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private static final String LENIENT_EASTERN_TIME = 109b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "LAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 110b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "AAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 111b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAAAAAAAAAAAxP///w=="; 112b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 113b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private static final String ORGANIZER = "organizer@server.com"; 114b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private static final String ATTENDEE = "attendee@server.com"; 115b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 116b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testGetSet() { 117b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook byte[] bytes = new byte[] {0, 1, 2, 3, 4, 5, 6, 7}; 118b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 119b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // First, check that getWord/Long are properly little endian 120b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(0x0100, CalendarUtilities.getWord(bytes, 0)); 121b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(0x03020100, CalendarUtilities.getLong(bytes, 0)); 122b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(0x07060504, CalendarUtilities.getLong(bytes, 4)); 123b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 124b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Set some words and longs 125b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.setWord(bytes, 0, 0xDEAD); 126b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.setLong(bytes, 2, 0xBEEFBEEF); 127b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.setWord(bytes, 6, 0xCEDE); 128b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 129b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Retrieve them 130b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(0xDEAD, CalendarUtilities.getWord(bytes, 0)); 131b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(0xBEEFBEEF, CalendarUtilities.getLong(bytes, 2)); 132b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(0xCEDE, CalendarUtilities.getWord(bytes, 6)); 133b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 134b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 135b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testParseTimeZoneEndToEnd() { 136b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone tz = CalendarUtilities.tziStringToTimeZone(AMERICA_DAWSON_TIME); 137b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("America/Dawson", tz.getID()); 138b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook tz = CalendarUtilities.tziStringToTimeZone(ASIA_CALCUTTA_TIME); 139b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("Asia/Calcutta", tz.getID()); 140b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook tz = CalendarUtilities.tziStringToTimeZone(AUSTRALIA_ACT_TIME); 141b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("Australia/ACT", tz.getID()); 142b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 143b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Test peculiar MS sent EST data with and without lenient precision; send standard 144b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // precision + 1 (i.e. 1ms) to make sure the code doesn't automatically flip to lenient 145b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // when the tz isn't found 146b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook tz = CalendarUtilities.tziStringToTimeZoneImpl(LENIENT_EASTERN_TIME, 147b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.STANDARD_DST_PRECISION+1); 148b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("America/Atikokan", tz.getID()); 149b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook tz = CalendarUtilities.tziStringToTimeZoneImpl(LENIENT_EASTERN_TIME, 150b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.LENIENT_DST_PRECISION); 151b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("America/Detroit", tz.getID()); 152b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 153b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook tz = CalendarUtilities.tziStringToTimeZone(GMT_UNKNOWN_DAYLIGHT_TIME); 154b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook int bias = tz.getOffset(System.currentTimeMillis()); 155b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(0, bias); 156b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Make sure non-DST TZ's work properly when the tested zone is the default zone 157b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone.setDefault(TimeZone.getTimeZone("America/Phoenix")); 158b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook tz = CalendarUtilities.tziStringToTimeZone(ARIZONA_TIME); 159b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("America/Phoenix", tz.getID()); 160b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone.setDefault(TimeZone.getTimeZone("Pacific/Honolulu")); 161b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook tz = CalendarUtilities.tziStringToTimeZone(HAWAII_TIME); 162b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("Pacific/Honolulu", tz.getID()); 163b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Make sure non-DST TZ's get the proper offset and DST status otherwise 164b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.clearTimeZoneCache(); 165b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone azTime = TimeZone.getTimeZone("America/Phoenix"); 166b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); 167b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook tz = CalendarUtilities.tziStringToTimeZone(ARIZONA_TIME); 168b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertFalse("America/Phoenix".equals(tz.getID())); 169b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertFalse(tz.useDaylightTime()); 170b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // It doesn't matter what time is passed in, since neither TZ has dst 171b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long now = System.currentTimeMillis(); 172b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(azTime.getOffset(now), tz.getOffset(now)); 173b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 174b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 175b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testGenerateEasDayOfWeek() { 176b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String byDay = "TU,WE,SA"; 177b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // TU = 4, WE = 8; SA = 64; 178b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("76", CalendarUtilities.generateEasDayOfWeek(byDay)); 179b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // MO = 2, TU = 4; WE = 8; TH = 16; FR = 32 180b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook byDay = "MO,TU,WE,TH,FR"; 181b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("62", CalendarUtilities.generateEasDayOfWeek(byDay)); 182b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // SU = 1 183b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook byDay = "SU"; 184b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("1", CalendarUtilities.generateEasDayOfWeek(byDay)); 185b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 186b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 187b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testTokenFromRrule() { 188b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String rrule = "FREQ=DAILY;INTERVAL=1;BYDAY=WE,TH,SA;BYMONTHDAY=17"; 189b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("DAILY", CalendarUtilities.tokenFromRrule(rrule, "FREQ=")); 190b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("1", CalendarUtilities.tokenFromRrule(rrule, "INTERVAL=")); 191b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("17", CalendarUtilities.tokenFromRrule(rrule, "BYMONTHDAY=")); 192b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("WE,TH,SA", CalendarUtilities.tokenFromRrule(rrule, "BYDAY=")); 193b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNull(CalendarUtilities.tokenFromRrule(rrule, "UNTIL=")); 194b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 195b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 196b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testRecurrenceUntilToEasUntil() { 197b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); 198b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Case where local time crosses into next day in GMT 199b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("20110730T000000Z", 200b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.recurrenceUntilToEasUntil("20110731T025959Z")); 201b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Case where local time does not cross into next day in GMT 202b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("20110730T000000Z", 203b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.recurrenceUntilToEasUntil("20110730T235959Z")); 204b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 205b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 206b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testParseEmailDateTimeToMillis(String date) { 207b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Format for email date strings is 2010-02-23T16:00:00.000Z 208b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String dateString = "2010-02-23T15:16:17.000Z"; 209b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long dateTime = Utility.parseEmailDateTimeToMillis(dateString); 210b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook GregorianCalendar cal = new GregorianCalendar(); 211b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook cal.setTimeInMillis(dateTime); 212b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook cal.setTimeZone(TimeZone.getTimeZone("GMT")); 213b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.YEAR), 2010); 214b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.MONTH), 1); // 0 based 215b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.DAY_OF_MONTH), 23); 216b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.HOUR_OF_DAY), 16); 217b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.MINUTE), 16); 218b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.SECOND), 17); 219b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 220b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 221b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testParseDateTimeToMillis(String date) { 222b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Format for calendar date strings is 20100223T160000000Z 223b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String dateString = "20100223T151617000Z"; 224b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long dateTime = Utility.parseDateTimeToMillis(dateString); 225b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook GregorianCalendar cal = new GregorianCalendar(); 226b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook cal.setTimeInMillis(dateTime); 227b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook cal.setTimeZone(TimeZone.getTimeZone("GMT")); 228b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.YEAR), 2010); 229b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.MONTH), 1); // 0 based 230b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.DAY_OF_MONTH), 23); 231b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.HOUR_OF_DAY), 16); 232b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.MINUTE), 16); 233b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cal.get(Calendar.SECOND), 17); 234b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 235b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 236b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private Entity setupTestEventEntity(String organizer, String attendee, String title) { 237b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Create an Entity for an Event 238b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook ContentValues entityValues = new ContentValues(); 239b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Entity entity = new Entity(entityValues); 240b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 241b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Set up values for the Event 242b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String location = "Meeting Location"; 243b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 244b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Fill in times, location, title, and organizer 245b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put("DTSTAMP", 246b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.convertEmailDateTimeToCalendarDateTime("2010-04-05T14:30:51Z")); 247b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.DTSTART, 248b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Utility.parseEmailDateTimeToMillis("2010-04-12T18:30:00Z")); 249b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.DTEND, 250b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Utility.parseEmailDateTimeToMillis("2010-04-12T19:30:00Z")); 251b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.EVENT_LOCATION, location); 252b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.TITLE, title); 253b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.ORGANIZER, organizer); 254b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.SYNC_DATA2, "31415926535"); 255b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 256b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Add the attendee 257b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook ContentValues attendeeValues = new ContentValues(); 258b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook attendeeValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE); 259b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook attendeeValues.put(Attendees.ATTENDEE_EMAIL, attendee); 260b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entity.addSubValue(Attendees.CONTENT_URI, attendeeValues); 261b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 262b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Add the organizer 263b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook ContentValues organizerValues = new ContentValues(); 264b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook organizerValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ORGANIZER); 265b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook organizerValues.put(Attendees.ATTENDEE_EMAIL, organizer); 266b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entity.addSubValue(Attendees.CONTENT_URI, organizerValues); 267b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook return entity; 268b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 269b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 270b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private Entity setupTestExceptionEntity(String organizer, String attendee, String title) { 271b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Entity entity = setupTestEventEntity(organizer, attendee, title); 272b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook ContentValues entityValues = entity.getEntityValues(); 273b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.ORIGINAL_SYNC_ID, 69); 274b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // The exception will be on April 26th 275b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.ORIGINAL_INSTANCE_TIME, 276b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Utility.parseEmailDateTimeToMillis("2010-04-26T18:30:00Z")); 277b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook return entity; 278b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 279b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 280b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testCreateMessageForEntity_Reply() { 281b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Set up the "event" 282b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String title = "Discuss Unit Tests"; 283b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Entity entity = setupTestEventEntity(ORGANIZER, ATTENDEE, title); 284b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 285b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Create a dummy account for the attendee 286b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Account account = new Account(); 287b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook account.mEmailAddress = ATTENDEE; 288b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 289b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // The uid is required, but can be anything 290b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String uid = "31415926535"; 291b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 292b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Create the outgoing message 293b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Message msg = CalendarUtilities.createMessageForEntity(mContext, entity, 294b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Message.FLAG_OUTGOING_MEETING_ACCEPT, uid, account); 295b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 296b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // First, we should have a message 297b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(msg); 298b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 299b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Now check some of the fields of the message 300b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Address.pack(new Address[] {new Address(ORGANIZER)}), msg.mTo); 301b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Resources resources = getContext().getResources(); 302b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String accept = resources.getString(R.string.meeting_accepted, title); 303b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(accept, msg.mSubject); 304b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(msg.mText); 305b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertTrue(msg.mText.contains(resources.getString(R.string.meeting_where, ""))); 306b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 307b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // And make sure we have an attachment 308b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(msg.mAttachments); 309b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(1, msg.mAttachments.size()); 310b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Attachment att = msg.mAttachments.get(0); 311b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // And that the attachment has the correct elements 312b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("invite.ics", att.mFileName); 313b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART, 314b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART); 315b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("text/calendar; method=REPLY", att.mMimeType); 316b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(att.mContentBytes); 317b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(att.mSize, att.mContentBytes.length); 318b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 319b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook //TODO Check the contents of the attachment using an iCalendar parser 320b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 321b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 322b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testCreateMessageForEntity_Invite_AllDay() throws IOException { 323b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Set up the "event" 324b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String title = "Discuss Unit Tests"; 325b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Entity entity = setupTestEventEntity(ORGANIZER, ATTENDEE, title); 326b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook ContentValues entityValues = entity.getEntityValues(); 327b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.ALL_DAY, 1); 328b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.DURATION, "P1D"); 329b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.remove(Events.DTEND); 330b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 331b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Create a dummy account for the attendee 332b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Account account = new Account(); 333b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook account.mEmailAddress = ORGANIZER; 334b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 335b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // The uid is required, but can be anything 336b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String uid = "31415926535"; 337b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 338b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Create the outgoing message 339b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Message msg = CalendarUtilities.createMessageForEntity(mContext, entity, 340b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Message.FLAG_OUTGOING_MEETING_INVITE, uid, account); 341b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 342b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // First, we should have a message 343b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(msg); 344b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 345b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Now check some of the fields of the message 346b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Address.pack(new Address[] {new Address(ATTENDEE)}), msg.mTo); 347b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(title, msg.mSubject); 348b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 349b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // And make sure we have an attachment 350b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(msg.mAttachments); 351b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(1, msg.mAttachments.size()); 352b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Attachment att = msg.mAttachments.get(0); 353b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // And that the attachment has the correct elements 354b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("invite.ics", att.mFileName); 355b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART, 356b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART); 357b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("text/calendar; method=REQUEST", att.mMimeType); 358b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(att.mContentBytes); 359b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(att.mSize, att.mContentBytes.length); 360b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 361b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We'll check the contents of the ics file here 362b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BlockHash vcalendar = parseIcsContent(att.mContentBytes); 363b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(vcalendar); 364b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 365b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We should have a VCALENDAR with a REQUEST method 366b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("VCALENDAR", vcalendar.name); 367b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("REQUEST", vcalendar.get("METHOD")); 368b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 369b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We should have one block under VCALENDAR 370b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(1, vcalendar.blocks.size()); 371b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BlockHash vevent = vcalendar.blocks.get(0); 372b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // It's a VEVENT with the following fields 373b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("VEVENT", vevent.name); 374b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("Meeting Location", vevent.get("LOCATION")); 375b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("0", vevent.get("SEQUENCE")); 376b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("Discuss Unit Tests", vevent.get("SUMMARY")); 377b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(uid, vevent.get("UID")); 378b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("MAILTO:" + ATTENDEE, 379b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook vevent.get("ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE")); 380b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 381b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // These next two fields should have a date only 382b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("20100412", vevent.get("DTSTART;VALUE=DATE")); 383b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("20100413", vevent.get("DTEND;VALUE=DATE")); 384b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This should be set to TRUE for all-day events 385b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("TRUE", vevent.get("X-MICROSOFT-CDO-ALLDAYEVENT")); 386b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 387b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 388b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testCreateMessageForEntity_Invite() throws IOException { 389b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Set up the "event" 390b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String title = "Discuss Unit Tests"; 391b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Entity entity = setupTestEventEntity(ORGANIZER, ATTENDEE, title); 392b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 393b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Create a dummy account for the attendee 394b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Account account = new Account(); 395b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook account.mEmailAddress = ORGANIZER; 396b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 397b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // The uid is required, but can be anything 398b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String uid = "31415926535"; 399b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 400b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Create the outgoing message 401b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Message msg = CalendarUtilities.createMessageForEntity(mContext, entity, 402b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Message.FLAG_OUTGOING_MEETING_INVITE, uid, account); 403b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 404b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // First, we should have a message 405b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(msg); 406b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 407b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Now check some of the fields of the message 408b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Address.pack(new Address[] {new Address(ATTENDEE)}), msg.mTo); 409b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(title, msg.mSubject); 410b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 411b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // And make sure we have an attachment 412b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(msg.mAttachments); 413b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(1, msg.mAttachments.size()); 414b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Attachment att = msg.mAttachments.get(0); 415b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // And that the attachment has the correct elements 416b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("invite.ics", att.mFileName); 417b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART, 418b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART); 419b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("text/calendar; method=REQUEST", att.mMimeType); 420b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(att.mContentBytes); 421b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(att.mSize, att.mContentBytes.length); 422b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 423b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We'll check the contents of the ics file here 424b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BlockHash vcalendar = parseIcsContent(att.mContentBytes); 425b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(vcalendar); 426b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 427b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We should have a VCALENDAR with a REQUEST method 428b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("VCALENDAR", vcalendar.name); 429b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("REQUEST", vcalendar.get("METHOD")); 430b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 431b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We should have one block under VCALENDAR 432b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(1, vcalendar.blocks.size()); 433b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BlockHash vevent = vcalendar.blocks.get(0); 434b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // It's a VEVENT with the following fields 435b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("VEVENT", vevent.name); 436b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("Meeting Location", vevent.get("LOCATION")); 437b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("0", vevent.get("SEQUENCE")); 438b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("Discuss Unit Tests", vevent.get("SUMMARY")); 439b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(uid, vevent.get("UID")); 440b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("MAILTO:" + ATTENDEE, 441b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook vevent.get("ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE")); 442b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 443b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // These next two fields should exist (without the VALUE=DATE suffix) 444b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(vevent.get("DTSTART")); 445b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(vevent.get("DTEND")); 446b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNull(vevent.get("DTSTART;VALUE=DATE")); 447b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNull(vevent.get("DTEND;VALUE=DATE")); 448b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This shouldn't exist for this event 449b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNull(vevent.get("X-MICROSOFT-CDO-ALLDAYEVENT")); 450b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 451b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 452b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testCreateMessageForEntity_Recurring() throws IOException { 453b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Set up the "event" 454b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String title = "Discuss Unit Tests"; 455b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Entity entity = setupTestEventEntity(ORGANIZER, ATTENDEE, title); 456b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Set up a RRULE for this event 457b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entity.getEntityValues().put(Events.RRULE, "FREQ=DAILY"); 458b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 459b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Create a dummy account for the attendee 460b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Account account = new Account(); 461b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook account.mEmailAddress = ORGANIZER; 462b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 463b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // The uid is required, but can be anything 464b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String uid = "31415926535"; 465b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 466b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Create the outgoing message 467b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Message msg = CalendarUtilities.createMessageForEntity(mContext, entity, 468b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Message.FLAG_OUTGOING_MEETING_INVITE, uid, account); 469b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 470b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // First, we should have a message 471b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(msg); 472b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 473b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Now check some of the fields of the message 474b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Address.pack(new Address[] {new Address(ATTENDEE)}), msg.mTo); 475b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(title, msg.mSubject); 476b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 477b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // And make sure we have an attachment 478b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(msg.mAttachments); 479b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(1, msg.mAttachments.size()); 480b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Attachment att = msg.mAttachments.get(0); 481b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // And that the attachment has the correct elements 482b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("invite.ics", att.mFileName); 483b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART, 484b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART); 485b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("text/calendar; method=REQUEST", att.mMimeType); 486b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(att.mContentBytes); 487b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(att.mSize, att.mContentBytes.length); 488b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 489b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We'll check the contents of the ics file here 490b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BlockHash vcalendar = parseIcsContent(att.mContentBytes); 491b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(vcalendar); 492b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 493b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We should have a VCALENDAR with a REQUEST method 494b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("VCALENDAR", vcalendar.name); 495b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("REQUEST", vcalendar.get("METHOD")); 496b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 497b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We should have two blocks under VCALENDAR (VTIMEZONE and VEVENT) 498b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(2, vcalendar.blocks.size()); 499b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 500b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This is the time zone that should be used 501b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone timeZone = TimeZone.getDefault(); 502b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 503b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BlockHash vtimezone = vcalendar.blocks.get(0); 504b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // It should be a VTIMEZONE for timeZone 505b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("VTIMEZONE", vtimezone.name); 506b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(timeZone.getID(), vtimezone.get("TZID")); 507b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 508b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BlockHash vevent = vcalendar.blocks.get(1); 509b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // It's a VEVENT with the following fields 510b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("VEVENT", vevent.name); 511b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("Meeting Location", vevent.get("LOCATION")); 512b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("0", vevent.get("SEQUENCE")); 513b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("Discuss Unit Tests", vevent.get("SUMMARY")); 514b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(uid, vevent.get("UID")); 515b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("MAILTO:" + ATTENDEE, 516b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook vevent.get("ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE")); 517b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 518b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We should have DTSTART/DTEND with time zone 519b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(vevent.get("DTSTART;TZID=" + timeZone.getID())); 520b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(vevent.get("DTEND;TZID=" + timeZone.getID())); 521b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNull(vevent.get("DTSTART")); 522b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNull(vevent.get("DTEND")); 523b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNull(vevent.get("DTSTART;VALUE=DATE")); 524b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNull(vevent.get("DTEND;VALUE=DATE")); 525b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This shouldn't exist for this event 526b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNull(vevent.get("X-MICROSOFT-CDO-ALLDAYEVENT")); 527b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 528b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 529b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testCreateMessageForEntity_Exception_Cancel() throws IOException { 530b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Set up the "exception"... 531b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String title = "Discuss Unit Tests"; 532b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Entity entity = setupTestExceptionEntity(ORGANIZER, ATTENDEE, title); 533b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 534b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook ContentValues entityValues = entity.getEntityValues(); 535b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Mark the Exception as dirty 536b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.DIRTY, 1); 537b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // And mark it canceled 538b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entityValues.put(Events.STATUS, Events.STATUS_CANCELED); 539b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 540b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Create a dummy account for the attendee 541b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Account account = new Account(); 542b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook account.mEmailAddress = ORGANIZER; 543b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 544b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // The uid is required, but can be anything 545b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String uid = "31415926535"; 546b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 547b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Create the outgoing message 548b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Message msg = CalendarUtilities.createMessageForEntity(mContext, entity, 549b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Message.FLAG_OUTGOING_MEETING_CANCEL, uid, account); 550b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 551b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // First, we should have a message 552b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(msg); 553b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 554b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Now check some of the fields of the message 555b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Address.pack(new Address[] {new Address(ATTENDEE)}), msg.mTo); 556b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String cancel = getContext().getResources().getString(R.string.meeting_canceled, title); 557b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(cancel, msg.mSubject); 558b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 559b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // And make sure we have an attachment 560b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(msg.mAttachments); 561b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(1, msg.mAttachments.size()); 562b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Attachment att = msg.mAttachments.get(0); 563b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // And that the attachment has the correct elements 564b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("invite.ics", att.mFileName); 565b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART, 566b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART); 567b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("text/calendar; method=CANCEL", att.mMimeType); 568b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(att.mContentBytes); 569b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 570b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We'll check the contents of the ics file here 571b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BlockHash vcalendar = parseIcsContent(att.mContentBytes); 572b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotNull(vcalendar); 573b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 574b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We should have a VCALENDAR with a CANCEL method 575b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("VCALENDAR", vcalendar.name); 576b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("CANCEL", vcalendar.get("METHOD")); 577b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 578b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This is the time zone that should be used 579b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone timeZone = TimeZone.getDefault(); 580b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 581b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We should have two blocks under VCALENDAR (VTIMEZONE and VEVENT) 582b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(2, vcalendar.blocks.size()); 583b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 584b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BlockHash vtimezone = vcalendar.blocks.get(0); 585b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // It should be a VTIMEZONE for timeZone 586b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("VTIMEZONE", vtimezone.name); 587b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(timeZone.getID(), vtimezone.get("TZID")); 588b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 589b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BlockHash vevent = vcalendar.blocks.get(1); 590b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // It's a VEVENT with the following fields 591b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("VEVENT", vevent.name); 592b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("Meeting Location", vevent.get("LOCATION")); 593b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("0", vevent.get("SEQUENCE")); 594b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("Discuss Unit Tests", vevent.get("SUMMARY")); 595b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(uid, vevent.get("UID")); 596b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("MAILTO:" + ATTENDEE, 597b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook vevent.get("ATTENDEE;ROLE=REQ-PARTICIPANT")); 598b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long originalTime = entityValues.getAsLong(Events.ORIGINAL_INSTANCE_TIME); 599b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNotSame(0, originalTime); 600b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // For an exception, RECURRENCE-ID is critical 601b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(CalendarUtilities.millisToEasDateTime(originalTime, timeZone, 602b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook true /*withTime*/), vevent.get("RECURRENCE-ID" + ";TZID=" + timeZone.getID())); 603b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 604b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 605b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testUtcOffsetString() { 606b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(CalendarUtilities.utcOffsetString(540), "+0900"); 607b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(CalendarUtilities.utcOffsetString(-480), "-0800"); 608b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(CalendarUtilities.utcOffsetString(0), "+0000"); 609b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 610b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 611b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testFindTransitionDate() { 612b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We'll find some transitions and make sure that we're properly in or out of daylight time 613b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // on either side of the transition. 614b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Use CST for testing (any other will do as well, as long as it has DST) 615b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone tz = TimeZone.getTimeZone("US/Central"); 616b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Confirm that this time zone uses DST 617b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertTrue(tz.useDaylightTime()); 618b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Get a calendar at January 1st of the current year 619b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook GregorianCalendar calendar = new GregorianCalendar(tz); 620b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook calendar.set(CalendarUtilities.sCurrentYear, Calendar.JANUARY, 1); 621b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Get start and end times at start and end of year 622b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long startTime = calendar.getTimeInMillis(); 623b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long endTime = startTime + (365*CalendarUtilities.DAYS); 624b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Find the first transition 625b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook GregorianCalendar transitionCalendar = 626b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.findTransitionDate(tz, startTime, endTime, false); 627b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long transitionTime = transitionCalendar.getTimeInMillis(); 628b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Before should be in standard time; after in daylight time 629b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Date beforeDate = new Date(transitionTime - CalendarUtilities.HOURS); 630b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Date afterDate = new Date(transitionTime + CalendarUtilities.HOURS); 631b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertFalse(tz.inDaylightTime(beforeDate)); 632b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertTrue(tz.inDaylightTime(afterDate)); 633b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 634b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Find the next one... 635b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook transitionCalendar = CalendarUtilities.findTransitionDate(tz, transitionTime + 636b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.DAYS, endTime, true); 637b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook transitionTime = transitionCalendar.getTimeInMillis(); 638b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This time, Before should be in daylight time; after in standard time 639b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook beforeDate = new Date(transitionTime - CalendarUtilities.HOURS); 640b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook afterDate = new Date(transitionTime + CalendarUtilities.HOURS); 641b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertTrue(tz.inDaylightTime(beforeDate)); 642b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertFalse(tz.inDaylightTime(afterDate)); 643b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 644b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Kinshasa has no daylight savings time 645b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook tz = TimeZone.getTimeZone("Africa/Kinshasa"); 646b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Confirm that there's no DST for this time zone 647b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertFalse(tz.useDaylightTime()); 648b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Get a calendar at January 1st of the current year 649b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook calendar = new GregorianCalendar(tz); 650b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook calendar.set(CalendarUtilities.sCurrentYear, Calendar.JANUARY, 1); 651b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Get start and end times at start and end of year 652b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook startTime = calendar.getTimeInMillis(); 653b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook endTime = startTime + (365*CalendarUtilities.DAYS); 654b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Find the first transition 655b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook transitionCalendar = CalendarUtilities.findTransitionDate(tz, startTime, endTime, false); 656b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // There had better not be one 657b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertNull(transitionCalendar); 658b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 659b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 660b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testRruleFromRecurrence() { 661b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Every Monday for 2 weeks 662b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String rrule = CalendarUtilities.rruleFromRecurrence( 663b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 1 /*Weekly*/, 2 /*Occurrences*/, 1 /*Interval*/, 2 /*Monday*/, 0, 0, 0, null); 664b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("FREQ=WEEKLY;COUNT=2;INTERVAL=1;BYDAY=MO", rrule); 665b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Every Tuesday and Friday 666b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook rrule = CalendarUtilities.rruleFromRecurrence( 667b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 1 /*Weekly*/, 0 /*Occurrences*/, 0 /*Interval*/, 36 /*Tue&Fri*/, 0, 0, 0, null); 668b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("FREQ=WEEKLY;BYDAY=TU,FR", rrule); 669b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // The last Saturday of the month 670b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook rrule = CalendarUtilities.rruleFromRecurrence( 671b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 1 /*Weekly*/, 0, 0, 64 /*Sat*/, 0, 5 /*Last*/, 0, null); 672b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("FREQ=WEEKLY;BYDAY=-1SA", rrule); 673b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // The third Wednesday and Thursday of the month 674b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook rrule = CalendarUtilities.rruleFromRecurrence( 675b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 1 /*Weekly*/, 0, 0, 24 /*Wed&Thu*/, 0, 3 /*3rd*/, 0, null); 676b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("FREQ=WEEKLY;BYDAY=3WE,3TH", rrule); 677b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook rrule = CalendarUtilities.rruleFromRecurrence( 678b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 3 /*Monthly/Day*/, 0, 0, 127 /*LastDay*/, 0, 0, 0, null); 679b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("FREQ=MONTHLY;BYMONTHDAY=-1", rrule); 680b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook rrule = CalendarUtilities.rruleFromRecurrence( 681b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 3 /*Monthly/Day*/, 0, 0, 62 /*M-F*/, 0, 5 /*Last week*/, 0, null); 682b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1", rrule); 683b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // The 14th of the every month 684b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook rrule = CalendarUtilities.rruleFromRecurrence( 685b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 2 /*Monthly/Date*/, 0, 0, 0, 14 /*14th*/, 0, 0, null); 686b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("FREQ=MONTHLY;BYMONTHDAY=14", rrule); 687b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Every 31st of October 688b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook rrule = CalendarUtilities.rruleFromRecurrence( 689b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 5 /*Yearly/Date*/, 0, 0, 0, 31 /*31st*/, 0, 10 /*October*/, null); 690b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("FREQ=YEARLY;BYMONTHDAY=31;BYMONTH=10", rrule); 691b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // The first Tuesday of June 692b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook rrule = CalendarUtilities.rruleFromRecurrence( 693b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 6 /*Yearly/Month/DayOfWeek*/, 0, 0, 4 /*Tue*/, 0, 1 /*1st*/, 6 /*June*/, null); 694b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals("FREQ=YEARLY;BYDAY=1TU;BYMONTH=6", rrule); 695b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 696b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 697b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook /** 698b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * Given a CalendarSyncAdapter and an RRULE, serialize the RRULE via recurrentFromRrule and 699b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * then parse the result. Assert that the resulting RRULE is the same as the original. 700b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * @param adapter a CalendarSyncAdapter 701b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * @param rrule an RRULE string that will be tested 702b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * @throws IOException 703b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook */ 704b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private void testSingleRecurrenceFromRrule(CalendarSyncAdapter adapter, String rrule) 705b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook throws IOException { 706b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Serializer s = new Serializer(); 707b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.recurrenceFromRrule(rrule, 0, s); 708b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook s.done(); 709b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook EasCalendarSyncParser parser = adapter.new EasCalendarSyncParser( 710b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook new ByteArrayInputStream(s.toByteArray()), adapter); 711b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // The first element should be the outer CALENDAR_RECURRENCE tag 712b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Tags.CALENDAR_RECURRENCE, parser.nextTag(Parser.START_DOCUMENT)); 713b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(rrule, parser.recurrenceParser()); 714b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 715b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 716b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook /** 717b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * Round-trip test of RRULE handling; we serialize an RRULE and then parse the result; the 718b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * result should be identical to the original RRULE 719b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook */ 720b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testRecurrenceFromRrule() throws IOException { 721b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // A test sync adapter we can use throughout the test 722b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class); 723b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 724b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook testSingleRecurrenceFromRrule(adapter, "FREQ=WEEKLY;COUNT=2;INTERVAL=1;BYDAY=MO"); 725b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook testSingleRecurrenceFromRrule(adapter, "FREQ=WEEKLY;BYDAY=TU,FR"); 726b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook testSingleRecurrenceFromRrule(adapter, "FREQ=WEEKLY;BYDAY=-1SA"); 727b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook testSingleRecurrenceFromRrule(adapter, "FREQ=WEEKLY;BYDAY=3WE,3TH"); 728b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook testSingleRecurrenceFromRrule(adapter, "FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1"); 729b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook testSingleRecurrenceFromRrule(adapter, "FREQ=MONTHLY;BYMONTHDAY=17"); 730b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook testSingleRecurrenceFromRrule(adapter, "FREQ=YEARLY;BYMONTHDAY=31;BYMONTH=10"); 731b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook testSingleRecurrenceFromRrule(adapter, "FREQ=YEARLY;BYDAY=1TU;BYMONTH=6"); 732b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 733b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 734b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook /** 735b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * For debugging purposes, to help keep track of parsing errors. 736b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook */ 737b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private class UnterminatedBlockException extends IOException { 738b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private static final long serialVersionUID = 1L; 739b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook UnterminatedBlockException(String name) { 740b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook super(name); 741b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 742b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 743b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 744b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook /** 745b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * A lightweight representation of block object containing a hash of individual values and an 746b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * array of inner blocks. The object is build by pulling elements from a BufferedReader. 747b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * NOTE: Multiple values of a given field are not supported. We'd see this with ATTENDEEs, for 748b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * example, and possibly RDATEs in VTIMEZONEs without an RRULE; these cases will be handled 749b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * at a later time. 750b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook */ 751b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private class BlockHash { 752b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String name; 753b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook HashMap<String, String> hash = new HashMap<String, String>(); 754b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook ArrayList<BlockHash> blocks = new ArrayList<BlockHash>(); 755b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 756b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BlockHash (String _name, BufferedReader reader) throws IOException { 757b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook name = _name; 758b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String lastField = null; 759b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String lastValue = null; 760b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook while (true) { 761b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Get a line; we're done if it's null 762b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String line = reader.readLine(); 763b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook if (line == null) { 764b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook throw new UnterminatedBlockException(name); 765b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 766b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook int length = line.length(); 767b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook if (length == 0) { 768b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We shouldn't ever see an empty line 769b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook throw new IllegalArgumentException(); 770b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 771b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // A line starting with tab is a continuation 772b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook if (line.charAt(0) == '\t') { 773b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Remember the line and length 774b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook lastValue = line.substring(1); 775b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Save the concatenation of old and new values 776b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook hash.put(lastField, hash.get(lastField) + lastValue); 777b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook continue; 778b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 779b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Find the field delimiter 780b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook int pos = line.indexOf(':'); 781b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // If not found, or at EOL, this is a bad ics 782b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook if (pos < 0 || pos >= length) { 783b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook throw new IllegalArgumentException(); 784b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 785b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Remember the field, value, and length 786b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook lastField = line.substring(0, pos); 787b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook lastValue = line.substring(pos + 1); 788b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook if (lastField.equals("BEGIN")) { 789b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook blocks.add(new BlockHash(lastValue, reader)); 790b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook continue; 791b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } else if (lastField.equals("END")) { 792b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook if (!lastValue.equals(name)) { 793b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook throw new UnterminatedBlockException(name); 794b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 795b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook break; 796b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 797b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 798b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Save it away and continue 799b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook hash.put(lastField, lastValue); 800b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 801b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 802b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 803b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String get(String field) { 804b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook return hash.get(field); 805b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 806b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 807b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 808b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook private BlockHash parseIcsContent(byte[] bytes) throws IOException { 809b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook BufferedReader reader = new BufferedReader(new StringReader(Utility.fromUtf8(bytes))); 810b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String line = reader.readLine(); 811b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook if (!line.equals("BEGIN:VCALENDAR")) { 812b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook throw new IllegalArgumentException(); 813b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 814b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook return new BlockHash("VCALENDAR", reader); 815b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 816b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 817b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testBuildMessageTextFromEntityValues() { 818b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Set up a test event 819b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String title = "Event Title"; 820b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Entity entity = setupTestEventEntity(ORGANIZER, ATTENDEE, title); 821b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook ContentValues entityValues = entity.getEntityValues(); 822b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 823b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Save this away; we'll use it a few times below 824b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Resources resources = mContext.getResources(); 825b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Date date = new Date(entityValues.getAsLong(Events.DTSTART)); 826b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String dateTimeString = DateFormat.getDateTimeInstance().format(date); 827b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 828b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Get the text for this message 829b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook StringBuilder sb = new StringBuilder(); 830b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.buildMessageTextFromEntityValues(mContext, entityValues, sb); 831b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String text = sb.toString(); 832b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // We'll just check the when and where 833b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertTrue(text.contains(resources.getString(R.string.meeting_when, dateTimeString))); 834b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String location = entityValues.getAsString(Events.EVENT_LOCATION); 835b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertTrue(text.contains(resources.getString(R.string.meeting_where, location))); 836b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 837b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Make this event recurring 838b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook entity.getEntityValues().put(Events.RRULE, "FREQ=WEEKLY;BYDAY=MO"); 839b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook sb = new StringBuilder(); 840b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.buildMessageTextFromEntityValues(mContext, entityValues, sb); 841b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook text = sb.toString(); 842b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertTrue(text.contains(resources.getString(R.string.meeting_recurring, dateTimeString))); 843b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 844b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 845b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook /** 846b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * Sanity test for time zone generation. Most important, make sure that we can run through 847b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * all of the time zones without generating an exception. Second, make sure that we're finding 848b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * rules for at least 90% of time zones that use daylight time (empirically, it's more like 849b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * 95%). Log those without rules. 850b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * @throws IOException 851b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook */ 852b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testTimeZoneToVTimezone() throws IOException { 853b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook SimpleIcsWriter writer = new SimpleIcsWriter(); 854b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook int rule = 0; 855b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook int nodst = 0; 856b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook int norule = 0; 857b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook ArrayList<String> norulelist = new ArrayList<String>(); 858b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook for (String tzs: TimeZone.getAvailableIDs()) { 859b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone tz = TimeZone.getTimeZone(tzs); 860b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook writer = new SimpleIcsWriter(); 861b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.timeZoneToVTimezone(tz, writer); 862b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String vc = writer.toString(); 863b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook boolean hasRule = vc.indexOf("RRULE") > 0; 864b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook if (hasRule) { 865b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook rule++; 866b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } else if (tz.useDaylightTime()) { 867b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook norule++; 868b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook norulelist.add(tz.getID()); 869b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } else { 870b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook nodst++; 871b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 872b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 873b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Log.d("TimeZoneGeneration", 874b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "Rule: " + rule + ", No DST: " + nodst + ", No rule: " + norule); 875b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook for (String nr: norulelist) { 876b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Log.d("TimeZoneGeneration", "No rule: " + nr); 877b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 878b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This is an empirical sanity test; we shouldn't have too many time zones with DST and 879b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // without a rule. 880b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertTrue(norule < rule/8); 881b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 882b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 883b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testGetUidFromGlobalObjId() { 884b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This is a "foreign" uid (from some vCalendar client) 885b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String globalObjId = "BAAAAIIA4AB0xbcQGoLgCAAAAAAAAAAAAAAAAAAAAAAAAAAAMQAAA" + 886b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "HZDYWwtVWlkAQAAADI3NjU1NmRkLTg1MzAtNGZiZS1iMzE0LThiM2JlYTYwMjE0OQA="; 887b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook String uid = CalendarUtilities.getUidFromGlobalObjId(globalObjId); 888b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(uid, "276556dd-8530-4fbe-b314-8b3bea602149"); 889b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // This is a native EAS uid 890b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook globalObjId = 891b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "BAAAAIIA4AB0xbcQGoLgCAAAAADACTu7KbPKAQAAAAAAAAAAEAAAAObgsG6HVt1Fmy+7GlLbGhY="; 892b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook uid = CalendarUtilities.getUidFromGlobalObjId(globalObjId); 893b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(uid, "040000008200E00074C5B7101A82E00800000000C0093BBB29B3CA" + 894b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook "01000000000000000010000000E6E0B06E8756DD459B2FBB1A52DB1A16"); 895b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 896b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 897b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testSelfAttendeeStatusFromBusyStatus() { 898b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, 899b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.attendeeStatusFromBusyStatus( 900b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.BUSY_STATUS_BUSY)); 901b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Attendees.ATTENDEE_STATUS_TENTATIVE, 902b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.attendeeStatusFromBusyStatus( 903b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.BUSY_STATUS_TENTATIVE)); 904b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Attendees.ATTENDEE_STATUS_NONE, 905b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.attendeeStatusFromBusyStatus( 906b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.BUSY_STATUS_FREE)); 907b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(Attendees.ATTENDEE_STATUS_NONE, 908b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.attendeeStatusFromBusyStatus( 909b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.BUSY_STATUS_OUT_OF_OFFICE)); 910b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 911b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 912b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testBusyStatusFromSelfStatus() { 913b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(CalendarUtilities.BUSY_STATUS_FREE, 914b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.busyStatusFromAttendeeStatus( 915b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Attendees.ATTENDEE_STATUS_DECLINED)); 916b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(CalendarUtilities.BUSY_STATUS_FREE, 917b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.busyStatusFromAttendeeStatus( 918b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Attendees.ATTENDEE_STATUS_NONE)); 919b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(CalendarUtilities.BUSY_STATUS_FREE, 920b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.busyStatusFromAttendeeStatus( 921b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Attendees.ATTENDEE_STATUS_INVITED)); 922b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(CalendarUtilities.BUSY_STATUS_TENTATIVE, 923b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.busyStatusFromAttendeeStatus( 924b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Attendees.ATTENDEE_STATUS_TENTATIVE)); 925b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(CalendarUtilities.BUSY_STATUS_BUSY, 926b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.busyStatusFromAttendeeStatus( 927b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook Attendees.ATTENDEE_STATUS_ACCEPTED)); 928b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 929b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 930b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testGetUtcAllDayCalendarTime() { 931b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook GregorianCalendar correctUtc = new GregorianCalendar(TimeZone.getTimeZone("UTC")); 932b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook correctUtc.set(2011, 2, 10, 0, 0, 0); 933b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long correctUtcTime = correctUtc.getTimeInMillis(); 934b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 935b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone localTimeZone = TimeZone.getTimeZone("GMT-0700"); 936b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook GregorianCalendar localCalendar = new GregorianCalendar(localTimeZone); 937b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook localCalendar.set(2011, 2, 10, 12, 23, 34); 938b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long localTimeMillis = localCalendar.getTimeInMillis(); 939b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long convertedUtcTime = 940b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.getUtcAllDayCalendarTime(localTimeMillis, localTimeZone); 941b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Milliseconds aren't zeroed out and may not be the same 942b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(convertedUtcTime/1000, correctUtcTime/1000); 943b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 944b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook localTimeZone = TimeZone.getTimeZone("GMT+0700"); 945b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook localCalendar = new GregorianCalendar(localTimeZone); 946b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook localCalendar.set(2011, 2, 10, 12, 23, 34); 947b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook localTimeMillis = localCalendar.getTimeInMillis(); 948b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook convertedUtcTime = 949b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.getUtcAllDayCalendarTime(localTimeMillis, localTimeZone); 950b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(convertedUtcTime/1000, correctUtcTime/1000); 951b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 952b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 953b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testGetLocalAllDayCalendarTime() { 954b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone utcTimeZone = TimeZone.getTimeZone("UTC"); 955b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook TimeZone localTimeZone = TimeZone.getTimeZone("GMT-0700"); 956b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook GregorianCalendar correctLocal = new GregorianCalendar(localTimeZone); 957b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook correctLocal.set(2011, 2, 10, 0, 0, 0); 958b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long correctLocalTime = correctLocal.getTimeInMillis(); 959b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 960b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook GregorianCalendar utcCalendar = new GregorianCalendar(utcTimeZone); 961b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook utcCalendar.set(2011, 2, 10, 12, 23, 34); 962b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long utcTimeMillis = utcCalendar.getTimeInMillis(); 963b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook long convertedLocalTime = 964b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.getLocalAllDayCalendarTime(utcTimeMillis, localTimeZone); 965b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Milliseconds aren't zeroed out and may not be the same 966b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(convertedLocalTime/1000, correctLocalTime/1000); 967b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 968b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook localTimeZone = TimeZone.getTimeZone("GMT+0700"); 969b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook correctLocal = new GregorianCalendar(localTimeZone); 970b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook correctLocal.set(2011, 2, 10, 0, 0, 0); 971b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook correctLocalTime = correctLocal.getTimeInMillis(); 972b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 973b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook utcCalendar = new GregorianCalendar(utcTimeZone); 974b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook utcCalendar.set(2011, 2, 10, 12, 23, 34); 975b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook utcTimeMillis = utcCalendar.getTimeInMillis(); 976b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook convertedLocalTime = 977b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook CalendarUtilities.getLocalAllDayCalendarTime(utcTimeMillis, localTimeZone); 978b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // Milliseconds aren't zeroed out and may not be the same 979b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertEquals(convertedLocalTime/1000, correctLocalTime/1000); 980b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 981b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 982b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook public void testGetIntegerValueAsBoolean() { 983b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook ContentValues cv = new ContentValues(); 984b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook cv.put("A", 1); 985b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook cv.put("B", 69); 986b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook cv.put("C", 0); 987b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertTrue(CalendarUtilities.getIntegerValueAsBoolean(cv, "A")); 988b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertTrue(CalendarUtilities.getIntegerValueAsBoolean(cv, "B")); 989b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertFalse(CalendarUtilities.getIntegerValueAsBoolean(cv, "C")); 990b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook assertFalse(CalendarUtilities.getIntegerValueAsBoolean(cv, "D")); 991b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook } 992b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook} 993b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 994b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // TODO Planned unit tests 995b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // findNextTransition 996b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // recurrenceFromRrule 997b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // timeZoneToTziStringImpl 998b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // getDSTCalendars 999b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // millisToVCalendarTime 1000b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // millisToEasDateTime 1001b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // getTrueTransitionMinute 1002b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook // getTrueTransitionHour 1003b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook 1004