1d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank/*
2d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * Copyright (C) 2010 The Android Open Source Project
3d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank *
4d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * Licensed under the Apache License, Version 2.0 (the "License");
5d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * you may not use this file except in compliance with the License.
6d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * You may obtain a copy of the License at
7d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank *
8d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank *      http://www.apache.org/licenses/LICENSE-2.0
9d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank *
10d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * Unless required by applicable law or agreed to in writing, software
11d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * distributed under the License is distributed on an "AS IS" BASIS,
12d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * See the License for the specific language governing permissions and
14d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * limitations under the License.
15d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank */
16d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
17d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankpackage com.android.exchange.adapter;
18d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
19d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport com.android.exchange.adapter.AbstractSyncAdapter.Operation;
20d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport com.android.exchange.adapter.CalendarSyncAdapter.CalendarOperations;
21d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport com.android.exchange.adapter.CalendarSyncAdapter.EasCalendarSyncParser;
22d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport com.android.exchange.provider.MockProvider;
23d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
24d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.content.ContentProviderOperation;
25d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.content.ContentValues;
26d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.content.Context;
27d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.content.OperationApplicationException;
28d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.content.res.Resources;
29d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.database.Cursor;
30d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.os.RemoteException;
31d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.provider.CalendarContract.Attendees;
32d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.provider.CalendarContract.Events;
33d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.test.IsolatedContext;
34d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.test.RenamingDelegatingContext;
35d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.test.mock.MockContentResolver;
36d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.test.mock.MockContext;
37d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport android.test.suitebuilder.annotation.MediumTest;
38d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
39d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport java.io.ByteArrayInputStream;
40d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport java.io.File;
41d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport java.io.IOException;
42d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport java.util.ArrayList;
43d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport java.util.GregorianCalendar;
44d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport java.util.List;
45d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankimport java.util.TimeZone;
46d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
47d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank/**
48d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank * You can run this entire test case with:
49d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank *   runtest -c com.android.exchange.adapter.CalendarSyncAdapterTests exchange
50d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank */
51d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank@MediumTest
52d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blankpublic class CalendarSyncAdapterTests extends SyncAdapterTestCase<CalendarSyncAdapter> {
53d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private static final String[] ATTENDEE_PROJECTION = new String[] {Attendees.ATTENDEE_EMAIL,
54d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            Attendees.ATTENDEE_NAME, Attendees.ATTENDEE_STATUS};
55d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private static final int ATTENDEE_EMAIL = 0;
56d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private static final int ATTENDEE_NAME = 1;
57d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private static final int ATTENDEE_STATUS = 2;
58d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
59d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private static final String SINGLE_ATTENDEE_EMAIL = "attendee@host.com";
60d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private static final String SINGLE_ATTENDEE_NAME = "Bill Attendee";
61d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
62d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private Context mMockContext;
63b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private MockContentResolver mMockResolver;
64d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
65d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    // This is the US/Pacific time zone as a base64-encoded TIME_ZONE_INFORMATION structure, as
66d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    // it would appear coming from an Exchange server
67d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private static final String TEST_TIME_ZONE = "4AEAAFAAYQBjAGkAZgBpAGMAIABTAHQAYQBuAGQAYQByA" +
68d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        "GQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAFAAY" +
69d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        "QBjAGkAZgBpAGMAIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAA" +
70d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        "AAAAAAAAAMAAAACAAIAAAAAAAAAxP///w==";
71d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
72d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private class MockContext2 extends MockContext {
73d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
74d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        @Override
75d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        public Resources getResources() {
76d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            return getContext().getResources();
77d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
78d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
79d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        @Override
80d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        public File getDir(String name, int mode) {
81d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            // name the directory so the directory will be separated from
82d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            // one created through the regular Context
83d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            return getContext().getDir("mockcontext2_" + name, mode);
84d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
85d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
86d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        @Override
87d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        public Context getApplicationContext() {
88d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            return this;
89d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
90d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
91d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
92d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    @Override
93d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public void setUp() throws Exception {
94d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        super.setUp();
95d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
96b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        mMockResolver = new MockContentResolver();
97b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        final String filenamePrefix = "test.";
98b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        RenamingDelegatingContext targetContextWrapper = new
99b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        RenamingDelegatingContext(
100b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                new MockContext2(), // The context that most methods are delegated to
101b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                getContext(), // The context that file methods are delegated to
102b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                filenamePrefix);
103b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        mMockContext = new IsolatedContext(mMockResolver, targetContextWrapper);
104b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        mMockResolver.addProvider(MockProvider.AUTHORITY, new MockProvider(mMockContext));
105d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
106d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
107d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public CalendarSyncAdapterTests() {
108d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        super();
109d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
110d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
111d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public void testSetTimeRelatedValues_NonRecurring() throws IOException {
112d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
113d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
114d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        ContentValues cv = new ContentValues();
115d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Basic, one-time meeting lasting an hour
116d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30);
117d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        Long startTime = startCalendar.getTimeInMillis();
118d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 10, 9, 30);
119d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        Long endTime = endCalendar.getTimeInMillis();
120d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
121d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        p.setTimeRelatedValues(cv, startTime, endTime, 0);
122d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertNull(cv.getAsInteger(Events.DURATION));
123d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertEquals(startTime, cv.getAsLong(Events.DTSTART));
124d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertEquals(endTime, cv.getAsLong(Events.DTEND));
125d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertEquals(endTime, cv.getAsLong(Events.LAST_DATE));
126d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertNull(cv.getAsString(Events.EVENT_TIMEZONE));
127d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
128d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
129d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public void testSetTimeRelatedValues_Recurring() throws IOException {
130d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
131d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
132d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        ContentValues cv = new ContentValues();
133d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Recurring meeting lasting an hour
134d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30);
135d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        Long startTime = startCalendar.getTimeInMillis();
136d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 10, 9, 30);
137d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        Long endTime = endCalendar.getTimeInMillis();
138d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.RRULE, "FREQ=DAILY");
139d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        p.setTimeRelatedValues(cv, startTime, endTime, 0);
140d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertEquals("P60M", cv.getAsString(Events.DURATION));
141d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertEquals(startTime, cv.getAsLong(Events.DTSTART));
142d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertNull(cv.getAsLong(Events.DTEND));
143d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertNull(cv.getAsLong(Events.LAST_DATE));
144d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertNull(cv.getAsString(Events.EVENT_TIMEZONE));
145d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
146d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
147d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public void testSetTimeRelatedValues_AllDay() throws IOException {
148d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
149d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
150d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        ContentValues cv = new ContentValues();
151d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30);
152d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        Long startTime = startCalendar.getTimeInMillis();
153d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 11, 8, 30);
154d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        Long endTime = endCalendar.getTimeInMillis();
155d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.RRULE, "FREQ=WEEKLY;BYDAY=MO");
156d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        p.setTimeRelatedValues(cv, startTime, endTime, 1);
157d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
158d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // The start time should have hour/min/sec zero'd out
159d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        startCalendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
160d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        startCalendar.set(2010, 5, 10, 0, 0, 0);
161d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        startCalendar.set(GregorianCalendar.MILLISECOND, 0);
162d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        startTime = startCalendar.getTimeInMillis();
163d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertEquals(startTime, cv.getAsLong(Events.DTSTART));
164d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
165d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // The duration should be in days
166d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertEquals("P1D", cv.getAsString(Events.DURATION));
167d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertNull(cv.getAsLong(Events.DTEND));
168d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertNull(cv.getAsLong(Events.LAST_DATE));
169d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // There must be a timezone
170d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertNotNull(cv.getAsString(Events.EVENT_TIMEZONE));
171d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
172d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
173d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public void testSetTimeRelatedValues_Recurring_AllDay_Exception () throws IOException {
174d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
175d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
176d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        ContentValues cv = new ContentValues();
177d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
178d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Recurrence exception for all-day event; the exception is NOT all-day
179d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 17, 8, 30);
180d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        Long startTime = startCalendar.getTimeInMillis();
181d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 17, 9, 30);
182d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        Long endTime = endCalendar.getTimeInMillis();
183d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.ORIGINAL_ALL_DAY, 1);
184d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        GregorianCalendar instanceCalendar = new GregorianCalendar(2010, 5, 17, 8, 30);
185d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.ORIGINAL_INSTANCE_TIME, instanceCalendar.getTimeInMillis());
186d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        p.setTimeRelatedValues(cv, startTime, endTime, 0);
187d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
188d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // The original instance time should have hour/min/sec zero'd out
189d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        GregorianCalendar testCalendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
190d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        testCalendar.set(2010, 5, 17, 0, 0, 0);
191d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        testCalendar.set(GregorianCalendar.MILLISECOND, 0);
192d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        Long testTime = testCalendar.getTimeInMillis();
193d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertEquals(testTime, cv.getAsLong(Events.ORIGINAL_INSTANCE_TIME));
194d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
195d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // The exception isn't all-day, so we should have DTEND and LAST_DATE and no EVENT_TIMEZONE
196d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertNull(cv.getAsString(Events.DURATION));
197d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertEquals(endTime, cv.getAsLong(Events.DTEND));
198d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertEquals(endTime, cv.getAsLong(Events.LAST_DATE));
199d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertNull(cv.getAsString(Events.EVENT_TIMEZONE));
200d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
201d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
202d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    public void testIsValidEventValues() throws IOException {
203d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
204d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
205d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
206d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        long validTime = System.currentTimeMillis();
207d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        String validData = "foo-bar-bletch";
208d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        String validDuration = "P30M";
209d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        String validRrule = "FREQ=DAILY";
210d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
211d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        ContentValues cv = new ContentValues();
212d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
213d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.DTSTART, validTime);
214d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Needs _SYNC_DATA and DTEND/DURATION
215d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertFalse(p.isValidEventValues(cv));
216d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.SYNC_DATA2, validData);
217d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Needs DTEND/DURATION since not an exception
218d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertFalse(p.isValidEventValues(cv));
219d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.DURATION, validDuration);
220d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Valid (DTSTART, _SYNC_DATA, DURATION)
221d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertTrue(p.isValidEventValues(cv));
222d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.remove(Events.DURATION);
223d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.ORIGINAL_INSTANCE_TIME, validTime);
224d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Needs DTEND since it's an exception
225d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertFalse(p.isValidEventValues(cv));
226d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.DTEND, validTime);
227d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Valid (DTSTART, DTEND, ORIGINAL_INSTANCE_TIME)
228d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.remove(Events.ORIGINAL_INSTANCE_TIME);
229d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Valid (DTSTART, _SYNC_DATA, DTEND)
230d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertTrue(p.isValidEventValues(cv));
231d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.remove(Events.DTSTART);
232d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Needs DTSTART
233d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertFalse(p.isValidEventValues(cv));
234d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.DTSTART, validTime);
235d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.RRULE, validRrule);
236d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // With RRULE, needs DURATION
237d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertFalse(p.isValidEventValues(cv));
238d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.DURATION, "P30M");
239d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Valid (DTSTART, RRULE, DURATION)
240d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertTrue(p.isValidEventValues(cv));
241d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.ALL_DAY, "1");
242d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Needs DURATION in the form P<n>D
243d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertFalse(p.isValidEventValues(cv));
244d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // Valid (DTSTART, RRULE, ALL_DAY, DURATION(P<n>D)
245d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        cv.put(Events.DURATION, "P1D");
246d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        assertTrue(p.isValidEventValues(cv));
247d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
248d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
249d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private void addAttendeesToSerializer(Serializer s, int num) throws IOException {
250d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        for (int i = 0; i < num; i++) {
251d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            s.start(Tags.CALENDAR_ATTENDEE);
252d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            s.data(Tags.CALENDAR_ATTENDEE_EMAIL, "frederick" + num +
253d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    ".flintstone@this.that.verylongservername.com");
254d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            s.data(Tags.CALENDAR_ATTENDEE_TYPE, "1");
255d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            s.data(Tags.CALENDAR_ATTENDEE_NAME, "Frederick" + num + " Flintstone, III");
256d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            s.end();
257d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
258d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
259d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
260d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private void addAttendeeToSerializer(Serializer s, String email, String name)
261d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            throws IOException {
262d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        s.start(Tags.CALENDAR_ATTENDEE);
263d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        s.data(Tags.CALENDAR_ATTENDEE_EMAIL, email);
264d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        s.data(Tags.CALENDAR_ATTENDEE_TYPE, "1");
265d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        s.data(Tags.CALENDAR_ATTENDEE_NAME, name);
266d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        s.end();
267d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
268d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
269d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    private int countInsertOperationsForTable(CalendarOperations ops, String tableName) {
270d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        int cnt = 0;
271d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        for (Operation op: ops) {
272d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            ContentProviderOperation cpo =
273d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    AbstractSyncAdapter.operationToContentProviderOperation(op, 0);
274d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            List<String> segments = cpo.getUri().getPathSegments();
275b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            if (segments.get(0).equalsIgnoreCase(tableName) &&
276b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                    cpo.getType() == ContentProviderOperation.TYPE_INSERT) {
277d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                cnt++;
278d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            }
279d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
280d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        return cnt;
281d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
282d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
283d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    class TestEvent extends Serializer {
284d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        CalendarSyncAdapter mAdapter;
285d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        EasCalendarSyncParser mParser;
286d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        Serializer mSerializer;
287d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
288d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        TestEvent() throws IOException {
289d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            super(false);
290d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            mAdapter = getTestSyncAdapter(CalendarSyncAdapter.class);
291d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            mParser = mAdapter.new EasCalendarSyncParser(getTestInputStream(), mAdapter);
292d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
293d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
294d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        void setUserEmailAddress(String addr) {
295d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            mAdapter.mAccount.mEmailAddress = addr;
296d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            mAdapter.mEmailAddress = addr;
297d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
298d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
299d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        EasCalendarSyncParser getParser() throws IOException {
300d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            // Set up our parser's input and eat the initial tag
301d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            mParser.resetInput(new ByteArrayInputStream(toByteArray()));
302d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            mParser.nextTag(0);
303d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            return mParser;
304d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
305d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
306d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // setupPreAttendees and setupPostAttendees initialize calendar data in the order in which
307d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // they would appear in an actual EAS session.  Between these two calls, we initialize
308d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        // attendee data, which varies between the following tests
309d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        TestEvent setupPreAttendees() throws IOException {
310d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            start(Tags.SYNC_APPLICATION_DATA);
311d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_TIME_ZONE, TEST_TIME_ZONE);
312d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_DTSTAMP, "20100518T213156Z");
313d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_START_TIME, "20100518T220000Z");
314d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_SUBJECT, "Documentation");
315d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_UID, "4417556B-27DE-4ECE-B679-A63EFE1F9E85");
316d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_ORGANIZER_NAME, "Fred Squatibuquitas");
317d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_ORGANIZER_EMAIL, "fred.squatibuquitas@prettylongdomainname.com");
318d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            return this;
319d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
320d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
321d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        TestEvent setupPostAttendees()throws IOException {
322d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_LOCATION, "CR SF 601T2/North Shore Presentation Self Service (16)");
323d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_END_TIME, "20100518T223000Z");
324d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            start(Tags.BASE_BODY);
325d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.BASE_BODY_PREFERENCE, "1");
326d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.BASE_ESTIMATED_DATA_SIZE, "69105"); // The number is ignored by the parser
327d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.BASE_DATA,
328d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank                    "This is the event description; we should probably make it longer");
329d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            end(); // BASE_BODY
330d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            start(Tags.CALENDAR_RECURRENCE);
331d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_RECURRENCE_TYPE, "1"); // weekly
332d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_RECURRENCE_INTERVAL, "1");
333d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_RECURRENCE_OCCURRENCES, "10");
334d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_RECURRENCE_DAYOFWEEK, "12"); // tue, wed
335d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_RECURRENCE_UNTIL, "2005-04-14T00:00:00.000Z");
336d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            end();  // CALENDAR_RECURRENCE
337d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_SENSITIVITY, "0");
338d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_BUSY_STATUS, "2");
339d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_ALL_DAY_EVENT, "0");
340d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.CALENDAR_MEETING_STATUS, "3");
341d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            data(Tags.BASE_NATIVE_BODY_TYPE, "3");
342d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            end().done(); // SYNC_APPLICATION_DATA
343d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank            return this;
344d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank        }
345d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    }
346d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
347b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void testAddEvent() throws IOException {
348b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        TestEvent event = new TestEvent();
349b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.setupPreAttendees();
350b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.start(Tags.CALENDAR_ATTENDEES);
351b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        addAttendeesToSerializer(event, 10);
352b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.end(); // CALENDAR_ATTENDEES
353b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.setupPostAttendees();
354b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
355b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        EasCalendarSyncParser p = event.getParser();
356b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        p.addEvent(p.mOps, "1:1", false);
357b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // There should be 1 event
358b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(1, countInsertOperationsForTable(p.mOps, "events"));
359b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Two attendees (organizer and 10 attendees)
360b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(11, countInsertOperationsForTable(p.mOps, "attendees"));
361b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // dtstamp, meeting status, attendees, attendees redacted, and upsync prohibited
362b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(5, countInsertOperationsForTable(p.mOps, "extendedproperties"));
363b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
364b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
365b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void testAddEventIllegal() throws IOException {
366b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // We don't send a start time; the event is illegal and nothing should be added
367b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        TestEvent event = new TestEvent();
368b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.start(Tags.SYNC_APPLICATION_DATA);
369b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.data(Tags.CALENDAR_TIME_ZONE, TEST_TIME_ZONE);
370b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.data(Tags.CALENDAR_DTSTAMP, "20100518T213156Z");
371b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.data(Tags.CALENDAR_SUBJECT, "Documentation");
372b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.data(Tags.CALENDAR_UID, "4417556B-27DE-4ECE-B679-A63EFE1F9E85");
373b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.data(Tags.CALENDAR_ORGANIZER_NAME, "Fred Squatibuquitas");
374b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.data(Tags.CALENDAR_ORGANIZER_EMAIL, "fred.squatibuquitas@prettylongdomainname.com");
375b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.start(Tags.CALENDAR_ATTENDEES);
376b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        addAttendeesToSerializer(event, 10);
377b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.end(); // CALENDAR_ATTENDEES
378b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.setupPostAttendees();
379b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
380b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        EasCalendarSyncParser p = event.getParser();
381b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        p.addEvent(p.mOps, "1:1", false);
382b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(0, countInsertOperationsForTable(p.mOps, "events"));
383b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(0, countInsertOperationsForTable(p.mOps, "attendees"));
384b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(0, countInsertOperationsForTable(p.mOps, "extendedproperties"));
385b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
386b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
387b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void testAddEventRedactedAttendees() throws IOException {
388b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        TestEvent event = new TestEvent();
389b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.setupPreAttendees();
390b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.start(Tags.CALENDAR_ATTENDEES);
391b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        addAttendeesToSerializer(event, 100);
392b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.end(); // CALENDAR_ATTENDEES
393b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.setupPostAttendees();
394b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
395b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        EasCalendarSyncParser p = event.getParser();
396b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        p.addEvent(p.mOps, "1:1", false);
397b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // There should be 1 event
398b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(1, countInsertOperationsForTable(p.mOps, "events"));
399b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // One attendees (organizer; all others are redacted)
400b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(1, countInsertOperationsForTable(p.mOps, "attendees"));
401b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // dtstamp, meeting status, and attendees redacted
402b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(3, countInsertOperationsForTable(p.mOps, "extendedproperties"));
403b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
404d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank
405d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank    /**
406d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * Setup for the following three tests, which check attendee status of an added event
407d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @param userEmail the email address of the user
408d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @param update whether or not the event is an update (rather than new)
409d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @return a Cursor to the Attendee records added to our MockProvider
410d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @throws IOException
411d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @throws RemoteException
412d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     * @throws OperationApplicationException
413d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank     */
414b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private Cursor setupAddEventOneAttendee(String userEmail, boolean update)
415b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            throws IOException, RemoteException, OperationApplicationException {
416b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        TestEvent event = new TestEvent();
417b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.setupPreAttendees();
418b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.start(Tags.CALENDAR_ATTENDEES);
419b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        addAttendeeToSerializer(event, SINGLE_ATTENDEE_EMAIL, SINGLE_ATTENDEE_NAME);
420b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.setUserEmailAddress(userEmail);
421b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.end(); // CALENDAR_ATTENDEES
422b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        event.setupPostAttendees();
423b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
424b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        EasCalendarSyncParser p = event.getParser();
425b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        p.addEvent(p.mOps, "1:1", update);
426b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Send the CPO's to the mock provider
427b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        ArrayList<ContentProviderOperation> cpos = new ArrayList<ContentProviderOperation>();
428b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        for (Operation op: p.mOps) {
429b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            cpos.add(AbstractSyncAdapter.operationToContentProviderOperation(op, 0));
430b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
431b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        mMockResolver.applyBatch(MockProvider.AUTHORITY, cpos);
432b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        return mMockResolver.query(MockProvider.uri(Attendees.CONTENT_URI), ATTENDEE_PROJECTION,
433b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                null, null, null);
434b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
435b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
436b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void testAddEventOneAttendee() throws IOException, RemoteException,
437b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            OperationApplicationException {
438b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Cursor c = setupAddEventOneAttendee("foo@bar.com", false);
439b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(2, c.getCount());
440b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // The organizer should be "accepted", the unknown attendee "none"
441b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        while (c.moveToNext()) {
442b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            if (SINGLE_ATTENDEE_EMAIL.equals(c.getString(ATTENDEE_EMAIL))) {
443b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                assertEquals(Attendees.ATTENDEE_STATUS_NONE, c.getInt(ATTENDEE_STATUS));
444b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            } else {
445b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS));
446b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            }
447b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
448b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
449b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
450b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void testAddEventSelfAttendee() throws IOException, RemoteException,
451b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            OperationApplicationException {
452b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Cursor c = setupAddEventOneAttendee(SINGLE_ATTENDEE_EMAIL, false);
453b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // The organizer should be "accepted", and our user/attendee should be "done" even though
454b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // the busy status = 2 (because we can't tell from a status of 2 on new events)
455b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        while (c.moveToNext()) {
456b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            if (SINGLE_ATTENDEE_EMAIL.equals(c.getString(ATTENDEE_EMAIL))) {
457b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                assertEquals(Attendees.ATTENDEE_STATUS_NONE, c.getInt(ATTENDEE_STATUS));
458b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            } else {
459b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS));
460b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            }
461b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
462b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
463b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
464b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void testAddEventSelfAttendeeUpdate() throws IOException, RemoteException,
465b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            OperationApplicationException {
466b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Cursor c = setupAddEventOneAttendee(SINGLE_ATTENDEE_EMAIL, true);
467b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // The organizer should be "accepted", and our user/attendee should be "accepted" (because
468b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // busy status = 2 and this is an update
469b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        while (c.moveToNext()) {
470b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            if (SINGLE_ATTENDEE_EMAIL.equals(c.getString(ATTENDEE_EMAIL))) {
471b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS));
472b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            } else {
473b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, c.getInt(ATTENDEE_STATUS));
474b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            }
475b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
476b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
477d2e4d4675d04e78591ebd38fd084fc2cdbe144a0Marc Blank}
478