/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.providers.calendar; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.provider.Calendar; import android.test.suitebuilder.annotation.MediumTest; import android.text.TextUtils; import android.util.Log; import junit.framework.TestCase; public class CalendarDatabaseHelperTest extends TestCase { private SQLiteDatabase mBadDb; private SQLiteDatabase mGoodDb; private DatabaseUtils.InsertHelper mBadEventsInserter; private DatabaseUtils.InsertHelper mGoodEventsInserter; @Override public void setUp() { mBadDb = SQLiteDatabase.create(null); assertNotNull(mBadDb); mGoodDb = SQLiteDatabase.create(null); assertNotNull(mGoodDb); } private void createVersion67EventsTable(SQLiteDatabase db) { db.execSQL("CREATE TABLE Events (" + "_id INTEGER PRIMARY KEY," + "_sync_account TEXT," + "_sync_account_type TEXT," + "_sync_id TEXT," + "_sync_version TEXT," + "_sync_time TEXT," + // UTC "_sync_local_id INTEGER," + "_sync_dirty INTEGER," + "_sync_mark INTEGER," + // To filter out new rows "calendar_id INTEGER NOT NULL," + "htmlUri TEXT," + "title TEXT," + "eventLocation TEXT," + "description TEXT," + "eventStatus INTEGER," + "selfAttendeeStatus INTEGER NOT NULL DEFAULT 0," + "commentsUri TEXT," + "dtstart INTEGER," + // millis since epoch "dtend INTEGER," + // millis since epoch "eventTimezone TEXT," + // timezone for event "duration TEXT," + "allDay INTEGER NOT NULL DEFAULT 0," + "visibility INTEGER NOT NULL DEFAULT 0," + "transparency INTEGER NOT NULL DEFAULT 0," + "hasAlarm INTEGER NOT NULL DEFAULT 0," + "hasExtendedProperties INTEGER NOT NULL DEFAULT 0," + "rrule TEXT," + "rdate TEXT," + "exrule TEXT," + "exdate TEXT," + "originalEvent TEXT," + // _sync_id of recurring event "originalInstanceTime INTEGER," + // millis since epoch "originalAllDay INTEGER," + "lastDate INTEGER," + // millis since epoch "hasAttendeeData INTEGER NOT NULL DEFAULT 0," + "guestsCanModify INTEGER NOT NULL DEFAULT 0," + "guestsCanInviteOthers INTEGER NOT NULL DEFAULT 1," + "guestsCanSeeGuests INTEGER NOT NULL DEFAULT 1," + "organizer STRING," + "deleted INTEGER NOT NULL DEFAULT 0," + "dtstart2 INTEGER," + //millis since epoch, allDay events in local timezone "dtend2 INTEGER," + //millis since epoch, allDay events in local timezone "eventTimezone2 TEXT," + //timezone for event with allDay events in local timezone "syncAdapterData TEXT" + //available for use by sync adapters ");"); } private void addVersion67Events() { // April 5th 1:01:01 AM to April 6th 1:01:01 mBadDb.execSQL("INSERT INTO Events (_id,dtstart,dtend,duration,dtstart2,dtend2," + "eventTimezone,eventTimezone2,allDay,calendar_id) " + "VALUES (1,1270454471000,1270540872000,'P10S'," + "1270454460000,1270540861000,'America/Los_Angeles','America/Los_Angeles',1,1);"); // April 5th midnight to April 6th midnight, duration cleared mGoodDb.execSQL("INSERT INTO Events (_id,dtstart,dtend,duration,dtstart2,dtend2," + "eventTimezone,eventTimezone2,allDay,calendar_id) " + "VALUES (1,1270425600000,1270512000000,null," + "1270450800000,1270537200000,'UTC','America/Los_Angeles',1,1);"); // April 5th 1:01:01 AM to April 6th 1:01:01, recurring weekly (We only check for the // existence of an rrule so it doesn't matter if the day is correct) mBadDb.execSQL("INSERT INTO Events (_id,dtstart,dtend,duration,dtstart2,dtend2," + "eventTimezone,eventTimezone2,allDay,rrule,calendar_id) " + "VALUES (2,1270454462000,1270540863000," + "'P10S',1270454461000,1270540861000,'America/Los_Angeles','America/Los_Angeles',1," + "'WEEKLY:MON',1);"); // April 5th midnight with 1 day duration, if only dtend was wrong we wouldn't fix it, but // if anything else is wrong we clear dtend to be sure. mGoodDb.execSQL("INSERT INTO Events (" + "_id,dtstart,dtend,duration,dtstart2,dtend2," + "eventTimezone,eventTimezone2,allDay,rrule,calendar_id)" + "VALUES (2,1270425600000,null,'P1D',1270450800000,null," + "'UTC','America/Los_Angeles',1," + "'WEEKLY:MON',1);"); assertEquals(mBadDb.rawQuery("SELECT _id FROM Events;", null).getCount(), 2); assertEquals(mGoodDb.rawQuery("SELECT _id FROM Events;", null).getCount(), 2); } @MediumTest public void testUpgradeToVersion69() { // Create event tables createVersion67EventsTable(mBadDb); createVersion67EventsTable(mGoodDb); // Fill in good and bad events addVersion67Events(); // Run the upgrade on the bad events CalendarDatabaseHelper.upgradeToVersion69(mBadDb); Cursor badCursor = null; Cursor goodCursor = null; try { badCursor = mBadDb.rawQuery("SELECT _id,dtstart,dtend,duration,dtstart2,dtend2," + "eventTimezone,eventTimezone2,rrule FROM Events WHERE allDay=?", new String[] {"1"}); goodCursor = mGoodDb.rawQuery("SELECT _id,dtstart,dtend,duration,dtstart2,dtend2," + "eventTimezone,eventTimezone2,rrule FROM Events WHERE allDay=?", new String[] {"1"}); // Check that we get the correct results back assertTrue(compareCursors(badCursor, goodCursor)); } finally { if (badCursor != null) { badCursor.close(); } if (goodCursor != null) { goodCursor.close(); } } } /** * Compares two cursors to see if they contain the same data. * * @return Returns true of the cursors contain the same data and are not null, false * otherwise */ private static boolean compareCursors(Cursor c1, Cursor c2) { if(c1 == null || c2 == null) { Log.d("CDBT","c1 is " + c1 + " and c2 is " + c2); return false; } int numColumns = c1.getColumnCount(); if (numColumns != c2.getColumnCount()) { Log.d("CDBT","c1 has " + numColumns + " columns and c2 has " + c2.getColumnCount()); return false; } if (c1.getCount() != c2.getCount()) { Log.d("CDBT","c1 has " + c1.getCount() + " rows and c2 has " + c2.getCount()); return false; } c1.moveToPosition(-1); c2.moveToPosition(-1); while(c1.moveToNext() && c2.moveToNext()) { for(int i = 0; i < numColumns; i++) { if(!TextUtils.equals(c1.getString(i),c2.getString(i))) { Log.d("CDBT", c1.getString(i) + "\n" + c2.getString(i)); return false; } } } return true; } }