/*
* Copyright (C) 2009 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.contacts;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts;
import android.test.mock.MockContext;
import android.test.suitebuilder.annotation.MediumTest;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
/**
* Unit tests for {@link LegacyContactImporter}.
*
* Run the test like this:
* <code>
* adb shell am instrument -e class com.android.providers.contacts.LegacyContactImporterTest -w \
* com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
* </code>
*
* Note that this SHOULD be a large test, but had to be bumped down to medium due to a bug in the
* SQLite cleanup code.
*/
@MediumTest
public class LegacyContactImporterTest extends BaseContactsProvider2Test {
private static class LegacyMockContext extends MockContext {
private String mFileName;
public LegacyMockContext(String fileName) {
mFileName = fileName;
}
@Override
public SQLiteDatabase openOrCreateDatabase(String file, int mode,
SQLiteDatabase.CursorFactory factory) {
return SQLiteDatabase.openDatabase(mFileName, factory, SQLiteDatabase.OPEN_READONLY);
}
@Override
public File getDatabasePath(String name) {
return new File(mFileName);
}
}
private LegacyMockContext createLegacyMockContext(String folder) throws IOException {
Context context = getTestContext();
File tempDb = new File(context.getFilesDir(), "legacy_contacts.db");
if (tempDb.exists()) {
tempDb.delete();
}
createSQLiteDatabaseFromDumpFile(tempDb.getPath(),
new File(folder, "legacy_contacts.sql").getPath());
return new LegacyMockContext(tempDb.getPath());
}
private void createSQLiteDatabaseFromDumpFile(String tempDbPath, String dumpFileAssetPath)
throws IOException {
final String[] ignoredTables = new String[] {"android_metadata", "sqlite_sequence"};
Context context = getTestContext();
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(tempDbPath, null);
try {
String data = readAssetAsString(dumpFileAssetPath);
String[] commands = data.split(";\r|;\n|;\r\n");
for (String command : commands) {
boolean ignore = false;
for (String ignoredTable : ignoredTables) {
if (command.contains(ignoredTable)) {
ignore = true;
break;
}
}
if (!ignore) {
database.execSQL(command);
}
}
assertTrue(
"Database Version not set. Be sure to add " +
"'PRAGMA user_version = <number>;' to the SQL Script",
database.getVersion() != 0);
} finally {
database.close();
}
}
@Override
protected void setUp() throws Exception {
SynchronousContactsProvider2.resetOpenHelper();
super.setUp();
addProvider(TestCallLogProvider.class, CallLog.AUTHORITY);
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
SynchronousContactsProvider2.resetOpenHelper();
}
public void testContactUpgrade1() throws Exception {
testAssetSet("test1");
}
public void testSyncedContactsUpgrade() throws Exception {
testAssetSet("testSynced");
}
public void testUnsyncedContactsUpgrade() throws Exception {
testAssetSet("testUnsynced");
}
private void testAssetSet(String folder) throws Exception {
ContactsProvider2 provider = (ContactsProvider2)getProvider();
LegacyContactImporter importer =
new LegacyContactImporter(createLegacyMockContext(folder), provider);
provider.importLegacyContacts(importer);
assertQueryResults(folder + "/expected_groups.txt", Groups.CONTENT_URI, new String[]{
Groups._ID,
Groups.ACCOUNT_NAME,
Groups.ACCOUNT_TYPE,
Groups.DIRTY,
Groups.GROUP_VISIBLE,
Groups.NOTES,
Groups.RES_PACKAGE,
Groups.SOURCE_ID,
Groups.SYSTEM_ID,
Groups.TITLE,
Groups.VERSION,
Groups.SYNC1,
Groups.SYNC2,
Groups.SYNC3,
Groups.SYNC4,
});
assertQueryResults(folder + "/expected_contacts.txt", Contacts.CONTENT_URI, new String[]{
Contacts._ID,
Contacts.DISPLAY_NAME_PRIMARY,
Contacts.SORT_KEY_PRIMARY,
Contacts.PHOTO_ID,
Contacts.TIMES_CONTACTED,
Contacts.LAST_TIME_CONTACTED,
Contacts.CUSTOM_RINGTONE,
Contacts.SEND_TO_VOICEMAIL,
Contacts.STARRED,
Contacts.IN_VISIBLE_GROUP,
Contacts.HAS_PHONE_NUMBER,
Contacts.IS_USER_PROFILE,
Contacts.LOOKUP_KEY,
});
assertQueryResults(folder + "/expected_raw_contacts.txt", RawContacts.CONTENT_URI,
new String[]{
RawContacts._ID,
RawContacts.ACCOUNT_NAME,
RawContacts.ACCOUNT_TYPE,
RawContacts.DELETED,
RawContacts.DIRTY,
RawContacts.SOURCE_ID,
RawContacts.VERSION,
RawContacts.SYNC1,
RawContacts.SYNC2,
RawContacts.SYNC3,
RawContacts.SYNC4,
RawContacts.DISPLAY_NAME_SOURCE,
RawContacts.DISPLAY_NAME_PRIMARY,
RawContacts.DISPLAY_NAME_ALTERNATIVE,
RawContacts.SORT_KEY_PRIMARY,
RawContacts.SORT_KEY_ALTERNATIVE,
});
assertQueryResults(folder + "/expected_data.txt", Data.CONTENT_URI, new String[]{
Data._ID,
Data.RAW_CONTACT_ID,
Data.MIMETYPE,
Data.DATA1,
Data.DATA2,
Data.DATA3,
Data.DATA4,
Data.DATA5,
Data.DATA6,
Data.DATA7,
Data.DATA8,
Data.DATA9,
Data.DATA10,
Data.DATA11,
Data.DATA12,
Data.DATA13,
Data.DATA14,
Data.DATA15,
Data.IS_PRIMARY,
Data.IS_SUPER_PRIMARY,
Data.DATA_VERSION,
Data.SYNC1,
Data.SYNC2,
Data.SYNC3,
Data.SYNC4,
});
assertQueryResults(folder + "/expected_calls.txt", Calls.CONTENT_URI, new String[]{
Calls._ID,
Calls.NUMBER,
Calls.DATE,
Calls.DURATION,
Calls.NEW,
Calls.TYPE,
Calls.CACHED_NAME,
Calls.CACHED_NUMBER_LABEL,
Calls.CACHED_NUMBER_TYPE,
});
provider.getDatabaseHelper().close();
}
private void assertQueryResults(String fileName, Uri uri, String[] projection)
throws Exception {
String expected = readAssetAsString(fileName).trim();
String actual = dumpCursorToString(uri, projection).trim();
assertEquals("Checking golden file " + fileName, expected, actual);
}
private String readAssetAsString(String fileName) throws IOException {
Context context = getTestContext();
InputStream input = context.getAssets().open(fileName);
ByteArrayOutputStream contents = new ByteArrayOutputStream();
int len;
byte[] data = new byte[1024];
do {
len = input.read(data);
if (len > 0) contents.write(data, 0, len);
} while (len == data.length);
return contents.toString();
}
private String dumpCursorToString(Uri uri, String[] projection) {
Cursor c = mResolver.query(uri, projection, null, null, BaseColumns._ID);
if (c == null) {
return "Null cursor";
}
String cursorDump = DatabaseUtils.dumpCursorToString(c);
c.close();
return insertLineNumbers(cursorDump);
}
private String insertLineNumbers(String multiline) {
String[] lines = multiline.split("\n");
StringBuilder sb = new StringBuilder();
// Ignore the first line that is a volatile header and the last line which is "<<<<<"
for (int i = 1; i < lines.length - 1; i++) {
sb.append(i).append(" ").append(lines[i]).append('\n');
}
return sb.toString();
}
public static class TestCallLogProvider extends CallLogProvider {
private static ContactsDatabaseHelper mDbHelper;
@Override
protected ContactsDatabaseHelper getDatabaseHelper(final Context context) {
if (mDbHelper == null) {
mDbHelper = new ContactsDatabaseHelper(context);
}
return mDbHelper;
}
}
}