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