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.adapter;
18b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
19b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.exchange.adapter.AbstractSyncAdapter.Operation;
20b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.exchange.adapter.CalendarSyncAdapter.CalendarOperations;
21b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.exchange.adapter.CalendarSyncAdapter.EasCalendarSyncParser;
22b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport com.android.exchange.provider.MockProvider;
23b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
24b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.content.ContentProviderOperation;
25b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.content.ContentValues;
26b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.content.Context;
27b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.content.OperationApplicationException;
28b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.content.res.Resources;
29b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.database.Cursor;
30b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.os.RemoteException;
31b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.provider.CalendarContract.Attendees;
32b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.provider.CalendarContract.Events;
33b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.test.IsolatedContext;
34b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.test.RenamingDelegatingContext;
35b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.test.mock.MockContentResolver;
36b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.test.mock.MockContext;
37b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport android.test.suitebuilder.annotation.MediumTest;
38b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
39b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.io.ByteArrayInputStream;
40b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.io.File;
41b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.io.IOException;
42b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.util.ArrayList;
43b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.util.GregorianCalendar;
44b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.util.List;
45b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookimport java.util.TimeZone;
46b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
47b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook/**
48b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook * You can run this entire test case with:
49b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook *   runtest -c com.android.exchange.adapter.CalendarSyncAdapterTests exchange
50b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook */
51b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook@MediumTest
52b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrookpublic class CalendarSyncAdapterTests extends SyncAdapterTestCase<CalendarSyncAdapter> {
53b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private static final String[] ATTENDEE_PROJECTION = new String[] {Attendees.ATTENDEE_EMAIL,
54b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            Attendees.ATTENDEE_NAME, Attendees.ATTENDEE_STATUS};
55b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private static final int ATTENDEE_EMAIL = 0;
56b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private static final int ATTENDEE_NAME = 1;
57b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private static final int ATTENDEE_STATUS = 2;
58b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
59b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private static final String SINGLE_ATTENDEE_EMAIL = "attendee@host.com";
60b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private static final String SINGLE_ATTENDEE_NAME = "Bill Attendee";
61b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
62b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private Context mMockContext;
63b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private MockContentResolver mMockResolver;
64b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
65b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    // This is the US/Pacific time zone as a base64-encoded TIME_ZONE_INFORMATION structure, as
66b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    // it would appear coming from an Exchange server
67b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private static final String TEST_TIME_ZONE = "4AEAAFAAYQBjAGkAZgBpAGMAIABTAHQAYQBuAGQAYQByA" +
68b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        "GQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAFAAY" +
69b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        "QBjAGkAZgBpAGMAIABEAGEAeQBsAGkAZwBoAHQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAAA" +
70b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        "AAAAAAAAAMAAAACAAIAAAAAAAAAxP///w==";
71b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
72b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private class MockContext2 extends MockContext {
73b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
74b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        @Override
75b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        public Resources getResources() {
76b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            return getContext().getResources();
77b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
78b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
79b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        @Override
80b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        public File getDir(String name, int mode) {
81b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            // name the directory so the directory will be separated from
82b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            // one created through the regular Context
83b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            return getContext().getDir("mockcontext2_" + name, mode);
84b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
85b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
86b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        @Override
87b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        public Context getApplicationContext() {
88b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            return this;
89b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
90b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
91b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
92b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    @Override
93b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void setUp() throws Exception {
94b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        super.setUp();
95b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
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));
105b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
106b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
107b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public CalendarSyncAdapterTests() {
108b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        super();
109b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
110b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
111b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void testSetTimeRelatedValues_NonRecurring() throws IOException {
112b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
113b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
114b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        ContentValues cv = new ContentValues();
115b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Basic, one-time meeting lasting an hour
116b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30);
117b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Long startTime = startCalendar.getTimeInMillis();
118b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 10, 9, 30);
119b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Long endTime = endCalendar.getTimeInMillis();
120b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
121b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        p.setTimeRelatedValues(cv, startTime, endTime, 0);
122b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertNull(cv.getAsInteger(Events.DURATION));
123b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(startTime, cv.getAsLong(Events.DTSTART));
124b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(endTime, cv.getAsLong(Events.DTEND));
125b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(endTime, cv.getAsLong(Events.LAST_DATE));
126b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertNull(cv.getAsString(Events.EVENT_TIMEZONE));
127b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
128b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
129b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void testSetTimeRelatedValues_Recurring() throws IOException {
130b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
131b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
132b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        ContentValues cv = new ContentValues();
133b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Recurring meeting lasting an hour
134b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30);
135b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Long startTime = startCalendar.getTimeInMillis();
136b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 10, 9, 30);
137b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Long endTime = endCalendar.getTimeInMillis();
138b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.RRULE, "FREQ=DAILY");
139b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        p.setTimeRelatedValues(cv, startTime, endTime, 0);
140b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals("P60M", cv.getAsString(Events.DURATION));
141b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(startTime, cv.getAsLong(Events.DTSTART));
142b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertNull(cv.getAsLong(Events.DTEND));
143b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertNull(cv.getAsLong(Events.LAST_DATE));
144b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertNull(cv.getAsString(Events.EVENT_TIMEZONE));
145b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
146b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
147b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void testSetTimeRelatedValues_AllDay() throws IOException {
148b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
149b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
150b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        ContentValues cv = new ContentValues();
151b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 10, 8, 30);
152b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Long startTime = startCalendar.getTimeInMillis();
153b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 11, 8, 30);
154b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Long endTime = endCalendar.getTimeInMillis();
155b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.RRULE, "FREQ=WEEKLY;BYDAY=MO");
156b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        p.setTimeRelatedValues(cv, startTime, endTime, 1);
157b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
158b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // The start time should have hour/min/sec zero'd out
159b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        startCalendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
160b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        startCalendar.set(2010, 5, 10, 0, 0, 0);
161b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        startCalendar.set(GregorianCalendar.MILLISECOND, 0);
162b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        startTime = startCalendar.getTimeInMillis();
163b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(startTime, cv.getAsLong(Events.DTSTART));
164b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
165b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // The duration should be in days
166b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals("P1D", cv.getAsString(Events.DURATION));
167b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertNull(cv.getAsLong(Events.DTEND));
168b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertNull(cv.getAsLong(Events.LAST_DATE));
169b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // There must be a timezone
170b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertNotNull(cv.getAsString(Events.EVENT_TIMEZONE));
171b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
172b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
173b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void testSetTimeRelatedValues_Recurring_AllDay_Exception () throws IOException {
174b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
175b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
176b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        ContentValues cv = new ContentValues();
177b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
178b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Recurrence exception for all-day event; the exception is NOT all-day
179b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        GregorianCalendar startCalendar = new GregorianCalendar(2010, 5, 17, 8, 30);
180b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Long startTime = startCalendar.getTimeInMillis();
181b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        GregorianCalendar endCalendar = new GregorianCalendar(2010, 5, 17, 9, 30);
182b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Long endTime = endCalendar.getTimeInMillis();
183b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.ORIGINAL_ALL_DAY, 1);
184b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        GregorianCalendar instanceCalendar = new GregorianCalendar(2010, 5, 17, 8, 30);
185b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.ORIGINAL_INSTANCE_TIME, instanceCalendar.getTimeInMillis());
186b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        p.setTimeRelatedValues(cv, startTime, endTime, 0);
187b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
188b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // The original instance time should have hour/min/sec zero'd out
189b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        GregorianCalendar testCalendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
190b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        testCalendar.set(2010, 5, 17, 0, 0, 0);
191b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        testCalendar.set(GregorianCalendar.MILLISECOND, 0);
192b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Long testTime = testCalendar.getTimeInMillis();
193b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(testTime, cv.getAsLong(Events.ORIGINAL_INSTANCE_TIME));
194b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
195b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // The exception isn't all-day, so we should have DTEND and LAST_DATE and no EVENT_TIMEZONE
196b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertNull(cv.getAsString(Events.DURATION));
197b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(endTime, cv.getAsLong(Events.DTEND));
198b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertEquals(endTime, cv.getAsLong(Events.LAST_DATE));
199b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertNull(cv.getAsString(Events.EVENT_TIMEZONE));
200b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
201b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
202b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    public void testIsValidEventValues() throws IOException {
203b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class);
204b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        EasCalendarSyncParser p = adapter.new EasCalendarSyncParser(getTestInputStream(), adapter);
205b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
206b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        long validTime = System.currentTimeMillis();
207b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        String validData = "foo-bar-bletch";
208b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        String validDuration = "P30M";
209b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        String validRrule = "FREQ=DAILY";
210b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
211b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        ContentValues cv = new ContentValues();
212b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
213b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.DTSTART, validTime);
214b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Needs _SYNC_DATA and DTEND/DURATION
215b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertFalse(p.isValidEventValues(cv));
216b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.SYNC_DATA2, validData);
217b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Needs DTEND/DURATION since not an exception
218b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertFalse(p.isValidEventValues(cv));
219b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.DURATION, validDuration);
220b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Valid (DTSTART, _SYNC_DATA, DURATION)
221b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertTrue(p.isValidEventValues(cv));
222b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.remove(Events.DURATION);
223b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.ORIGINAL_INSTANCE_TIME, validTime);
224b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Needs DTEND since it's an exception
225b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertFalse(p.isValidEventValues(cv));
226b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.DTEND, validTime);
227b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Valid (DTSTART, DTEND, ORIGINAL_INSTANCE_TIME)
228b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.remove(Events.ORIGINAL_INSTANCE_TIME);
229b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Valid (DTSTART, _SYNC_DATA, DTEND)
230b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertTrue(p.isValidEventValues(cv));
231b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.remove(Events.DTSTART);
232b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Needs DTSTART
233b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertFalse(p.isValidEventValues(cv));
234b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.DTSTART, validTime);
235b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.RRULE, validRrule);
236b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // With RRULE, needs DURATION
237b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertFalse(p.isValidEventValues(cv));
238b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.DURATION, "P30M");
239b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Valid (DTSTART, RRULE, DURATION)
240b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertTrue(p.isValidEventValues(cv));
241b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.ALL_DAY, "1");
242b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Needs DURATION in the form P<n>D
243b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertFalse(p.isValidEventValues(cv));
244b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // Valid (DTSTART, RRULE, ALL_DAY, DURATION(P<n>D)
245b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        cv.put(Events.DURATION, "P1D");
246b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        assertTrue(p.isValidEventValues(cv));
247b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
248b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
249b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private void addAttendeesToSerializer(Serializer s, int num) throws IOException {
250b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        for (int i = 0; i < num; i++) {
251b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            s.start(Tags.CALENDAR_ATTENDEE);
252b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            s.data(Tags.CALENDAR_ATTENDEE_EMAIL, "frederick" + num +
253b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                    ".flintstone@this.that.verylongservername.com");
254b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            s.data(Tags.CALENDAR_ATTENDEE_TYPE, "1");
255b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            s.data(Tags.CALENDAR_ATTENDEE_NAME, "Frederick" + num + " Flintstone, III");
256b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            s.end();
257b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
258b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
259b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
260b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private void addAttendeeToSerializer(Serializer s, String email, String name)
261b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            throws IOException {
262b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        s.start(Tags.CALENDAR_ATTENDEE);
263b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        s.data(Tags.CALENDAR_ATTENDEE_EMAIL, email);
264b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        s.data(Tags.CALENDAR_ATTENDEE_TYPE, "1");
265b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        s.data(Tags.CALENDAR_ATTENDEE_NAME, name);
266b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        s.end();
267b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
268b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
269b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    private int countInsertOperationsForTable(CalendarOperations ops, String tableName) {
270b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        int cnt = 0;
271b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        for (Operation op: ops) {
272b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            ContentProviderOperation cpo =
273b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                    AbstractSyncAdapter.operationToContentProviderOperation(op, 0);
274b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            List<String> segments = cpo.getUri().getPathSegments();
275b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            if (segments.get(0).equalsIgnoreCase(tableName) &&
276b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                    cpo.getType() == ContentProviderOperation.TYPE_INSERT) {
277b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                cnt++;
278b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            }
279b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
280b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        return cnt;
281b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
282b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
283b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    class TestEvent extends Serializer {
284b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        CalendarSyncAdapter mAdapter;
285b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        EasCalendarSyncParser mParser;
286b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        Serializer mSerializer;
287b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
288b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        TestEvent() throws IOException {
289b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            super(false);
290b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            mAdapter = getTestSyncAdapter(CalendarSyncAdapter.class);
291b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            mParser = mAdapter.new EasCalendarSyncParser(getTestInputStream(), mAdapter);
292b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
293b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
294b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        void setUserEmailAddress(String addr) {
295b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            mAdapter.mAccount.mEmailAddress = addr;
296b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            mAdapter.mEmailAddress = addr;
297b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
298b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
299b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        EasCalendarSyncParser getParser() throws IOException {
300b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            // Set up our parser's input and eat the initial tag
301b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            mParser.resetInput(new ByteArrayInputStream(toByteArray()));
302b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            mParser.nextTag(0);
303b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            return mParser;
304b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
305b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
306b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // setupPreAttendees and setupPostAttendees initialize calendar data in the order in which
307b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // they would appear in an actual EAS session.  Between these two calls, we initialize
308b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        // attendee data, which varies between the following tests
309b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        TestEvent setupPreAttendees() throws IOException {
310b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            start(Tags.SYNC_APPLICATION_DATA);
311b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_TIME_ZONE, TEST_TIME_ZONE);
312b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_DTSTAMP, "20100518T213156Z");
313b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_START_TIME, "20100518T220000Z");
314b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_SUBJECT, "Documentation");
315b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_UID, "4417556B-27DE-4ECE-B679-A63EFE1F9E85");
316b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_ORGANIZER_NAME, "Fred Squatibuquitas");
317b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_ORGANIZER_EMAIL, "fred.squatibuquitas@prettylongdomainname.com");
318b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            return this;
319b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
320b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
321b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        TestEvent setupPostAttendees()throws IOException {
322b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_LOCATION, "CR SF 601T2/North Shore Presentation Self Service (16)");
323b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_END_TIME, "20100518T223000Z");
324b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            start(Tags.BASE_BODY);
325b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.BASE_BODY_PREFERENCE, "1");
326b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.BASE_ESTIMATED_DATA_SIZE, "69105"); // The number is ignored by the parser
327b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.BASE_DATA,
328b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook                    "This is the event description; we should probably make it longer");
329b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            end(); // BASE_BODY
330b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            start(Tags.CALENDAR_RECURRENCE);
331b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_RECURRENCE_TYPE, "1"); // weekly
332b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_RECURRENCE_INTERVAL, "1");
333b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_RECURRENCE_OCCURRENCES, "10");
334b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_RECURRENCE_DAYOFWEEK, "12"); // tue, wed
335b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_RECURRENCE_UNTIL, "2005-04-14T00:00:00.000Z");
336b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            end();  // CALENDAR_RECURRENCE
337b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_SENSITIVITY, "0");
338b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_BUSY_STATUS, "2");
339b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_ALL_DAY_EVENT, "0");
340b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.CALENDAR_MEETING_STATUS, "3");
341b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            data(Tags.BASE_NATIVE_BODY_TYPE, "3");
342b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            end().done(); // SYNC_APPLICATION_DATA
343b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook            return this;
344b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook        }
345b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    }
346b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
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    }
404b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook
405b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook    /**
406b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook     * Setup for the following three tests, which check attendee status of an added event
407b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook     * @param userEmail the email address of the user
408b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook     * @param update whether or not the event is an update (rather than new)
409b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook     * @return a Cursor to the Attendee records added to our MockProvider
410b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook     * @throws IOException
411b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook     * @throws RemoteException
412b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook     * @throws OperationApplicationException
413b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook     */
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    }
477b931f82fa44c2e26e2645c0d5fde9eef3e666efdPaul Westbrook}
478