1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 package com.android.providers.contacts; 17 18 import android.database.Cursor; 19 import android.database.sqlite.SQLiteDatabase; 20 21 import junit.framework.AssertionFailedError; 22 23 import java.util.HashMap; 24 25 /** 26 * Unit tests for database create/upgrade operations. 27 * 28 * Run the test like this: <code> runtest -c com.android.providers.contacts.BaseDatabaseHelperUpgradeTest 29 * contactsprov </code> 30 */ 31 public abstract class BaseDatabaseHelperUpgradeTest extends FixedAndroidTestCase { 32 33 protected static final String INTEGER = "INTEGER"; 34 protected static final String TEXT = "TEXT"; 35 protected static final String STRING = "STRING"; 36 protected static final String BLOB = "BLOB"; 37 38 protected SQLiteDatabase mDb; 39 40 /** 41 * The column info returned by PRAGMA table_info() 42 */ 43 protected static class TableColumn { 44 45 public int cid; 46 public String name; 47 public String type; 48 public boolean notnull; 49 // default value 50 public String dflt_value; 51 // primary key. Not tested. 52 public int pk; 53 TableColumn()54 public TableColumn() { 55 56 } 57 TableColumn(String name, String type, boolean notnull, String defaultValue)58 public TableColumn(String name, String type, boolean notnull, String defaultValue) { 59 this.name = name; 60 this.type = type; 61 this.notnull = notnull; 62 this.dflt_value = defaultValue; 63 } 64 } 65 66 protected static class TableStructure { 67 68 private final HashMap<String, TableColumn> mColumns = new HashMap<String, TableColumn>(); 69 private final String mName; 70 TableStructure(SQLiteDatabase db, String tableName)71 public TableStructure(SQLiteDatabase db, String tableName) { 72 mName = tableName; 73 try (final Cursor cursor = db.rawQuery("PRAGMA table_info(" + tableName + ");", null)) { 74 final int cidIndex = cursor.getColumnIndex("cid"); 75 final int nameIndex = cursor.getColumnIndex("name"); 76 final int typeIndex = cursor.getColumnIndex("type"); 77 final int notNullIndex = cursor.getColumnIndex("notnull"); 78 final int dfltValueIndex = cursor.getColumnIndex("dflt_value"); 79 final int pkIndex = cursor.getColumnIndex("pk"); 80 cursor.moveToPosition(-1); 81 while (cursor.moveToNext()) { 82 TableColumn column = new TableColumn(); 83 column.cid = cursor.getInt(cidIndex); 84 column.name = cursor.getString(nameIndex); 85 column.type = cursor.getString(typeIndex); 86 column.notnull = cursor.getInt(notNullIndex) != 0; 87 column.dflt_value = cursor.getString(dfltValueIndex); 88 column.pk = cursor.getInt(pkIndex); 89 90 addColumn(column); 91 } 92 } 93 } 94 TableStructure()95 private TableStructure() { 96 mName = ""; 97 } 98 addColumn(TableColumn column)99 private void addColumn(TableColumn column) { 100 mColumns.put(column.name, column); 101 } 102 assertHasColumn(String name, String type, boolean notnull, String defaultValue)103 public void assertHasColumn(String name, String type, boolean notnull, 104 String defaultValue) { 105 final TableColumn column = mColumns.get(name); 106 if (column == null) { 107 throw new AssertionFailedError("Table " + mName + ": Column missing: " + name); 108 } 109 if (!type.equals(column.type)) { 110 throw new AssertionFailedError("Table " + mName + ": Column " + name + " type:" 111 + column.type + ", " + type + " expected"); 112 } 113 if (!notnull == column.notnull) { 114 throw new AssertionFailedError("Table " + mName + ": Column " + name + " notnull:" 115 + column.notnull + ", " + notnull + " expected"); 116 } 117 if (defaultValue == null) { 118 if (column.dflt_value != null) { 119 throw new AssertionFailedError("Table " + mName + ": Column " + name 120 + " defaultValue: " + column.dflt_value + ", null expected"); 121 } 122 } else if (!defaultValue.equals(column.dflt_value)) { 123 throw new AssertionFailedError("Table " + mName + ": Column " + name 124 + " defaultValue:" + column.dflt_value + ", " + defaultValue + " expected"); 125 } 126 } 127 128 assertHasColumns(TableColumn[] columns)129 public void assertHasColumns(TableColumn[] columns) { 130 for (final TableColumn column : columns) { 131 assertHasColumn(column.name, column.type, column.notnull, column.dflt_value); 132 } 133 } 134 135 /** 136 * Assert the TableStructure has every column in @param columns, and nothing else. 137 */ assertSame(TableColumn[] columns)138 public void assertSame(TableColumn[] columns) { 139 assertHasColumns(columns); 140 if (columns.length != mColumns.size()) { 141 throw new RuntimeException("column count mismatch"); 142 } 143 } 144 145 } 146 147 /** 148 * Used to store a tables' name and its' current structure in a array. 149 */ 150 protected static class TableListEntry { 151 152 public final String name; 153 public final TableColumn[] columns; 154 public final boolean shouldBeInNewDb; 155 TableListEntry(String name, TableColumn[] columns)156 public TableListEntry(String name, TableColumn[] columns) { 157 this(name, columns, /* shouldBeInNewDb = */ true); 158 } 159 TableListEntry(String name, TableColumn[] columns, boolean shouldBeInNewDb)160 public TableListEntry(String name, TableColumn[] columns, boolean shouldBeInNewDb) { 161 this.name = name; 162 this.columns = columns; 163 this.shouldBeInNewDb = shouldBeInNewDb; 164 } 165 } 166 167 @Override setUp()168 protected void setUp() throws Exception { 169 super.setUp(); 170 171 final String filename = getDatabaseFilename(); 172 if (filename == null) { 173 mDb = SQLiteDatabase.create(null); 174 } else { 175 getContext().deleteDatabase(filename); 176 mDb = SQLiteDatabase.openOrCreateDatabase(filename, null); 177 } 178 } 179 180 @Override tearDown()181 protected void tearDown() throws Exception { 182 mDb.close(); 183 super.tearDown(); 184 } 185 getDatabaseFilename()186 protected abstract String getDatabaseFilename(); 187 assertDatabaseStructureSameAsList(TableListEntry[] list, boolean isNewDatabase)188 protected void assertDatabaseStructureSameAsList(TableListEntry[] list, boolean isNewDatabase) { 189 for (TableListEntry entry : list) { 190 if (!entry.shouldBeInNewDb) { 191 if (isNewDatabase) { 192 continue; 193 } 194 } 195 TableStructure structure = new TableStructure(mDb, entry.name); 196 structure.assertSame(entry.columns); 197 } 198 } 199 testAssertHasColumn_Match()200 public void testAssertHasColumn_Match() { 201 TableStructure table = createOneColumnTable("foo", INTEGER, false, null); 202 table.assertHasColumn("foo", INTEGER, false, null); 203 } 204 testAssertHasColumn_Empty()205 public void testAssertHasColumn_Empty() { 206 TableStructure table = new TableStructure(); 207 208 try { 209 table.assertHasColumn("bar", INTEGER, false, null); 210 throw new AssertionError("Assert should fail"); 211 } catch (AssertionFailedError e) { 212 // Should fail 213 } 214 } 215 testAssertHasColumn_ColumnNotExist()216 public void testAssertHasColumn_ColumnNotExist() { 217 TableStructure table = createOneColumnTable("foo", INTEGER, false, null); 218 219 try { 220 table.assertHasColumn("bar", INTEGER, false, null); 221 throw new AssertionError("Assert should fail"); 222 } catch (AssertionFailedError e) { 223 // Should fail 224 } 225 } 226 testAssertHasColumn_TypeMismatch()227 public void testAssertHasColumn_TypeMismatch() { 228 TableStructure table = createOneColumnTable("foo", INTEGER, false, null); 229 230 try { 231 table.assertHasColumn("foo", TEXT, false, null); 232 throw new AssertionError("Assert should fail"); 233 } catch (AssertionFailedError e) { 234 // Should fail 235 } 236 } 237 testAssertHasColumn_NotNullMismatch()238 public void testAssertHasColumn_NotNullMismatch() { 239 TableStructure table = createOneColumnTable("foo", INTEGER, false, null); 240 241 try { 242 table.assertHasColumn("foo", INTEGER, true, null); 243 throw new AssertionError("Assert should fail"); 244 } catch (AssertionFailedError e) { 245 // Should fail 246 } 247 } 248 testAssertHasColumn_DefaultMatch()249 public void testAssertHasColumn_DefaultMatch() { 250 TableStructure table = createOneColumnTable("foo", INTEGER, false, "baz"); 251 table.assertHasColumn("foo", INTEGER, false, "baz"); 252 } 253 testAssertHasColumn_DefaultMismatch()254 public void testAssertHasColumn_DefaultMismatch() { 255 TableStructure table = createOneColumnTable("foo", INTEGER, false, "bar"); 256 257 try { 258 table.assertHasColumn("foo", INTEGER, false, "baz"); 259 throw new AssertionError("Assert should fail"); 260 } catch (AssertionFailedError e) { 261 // Should fail 262 } 263 } 264 testAssertHasColumn_DefaultMismatch_Null1()265 public void testAssertHasColumn_DefaultMismatch_Null1() { 266 TableStructure table = createOneColumnTable("foo", INTEGER, false, null); 267 268 try { 269 table.assertHasColumn("foo", INTEGER, false, "baz"); 270 throw new AssertionError("Assert should fail"); 271 } catch (AssertionFailedError e) { 272 // Should fail 273 } 274 } 275 testAssertHasColumn_DefaultMismatch_Null2()276 public void testAssertHasColumn_DefaultMismatch_Null2() { 277 TableStructure table = createOneColumnTable("foo", INTEGER, false, "baz"); 278 279 try { 280 table.assertHasColumn("foo", INTEGER, false, null); 281 throw new AssertionError("Assert should fail"); 282 } catch (AssertionFailedError e) { 283 // Should fail 284 } 285 } 286 createOneColumnTable(String name, String type, boolean notnull, String defaultValue)287 private TableStructure createOneColumnTable(String name, String type, boolean notnull, 288 String defaultValue) { 289 TableStructure table = new TableStructure(); 290 table.addColumn(new TableColumn(name, type, notnull, defaultValue)); 291 return table; 292 } 293 294 } 295