1 /* 2 * Copyright (C) 2008 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 17 package android.database.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertTrue; 22 import static org.junit.Assert.fail; 23 24 import android.content.Context; 25 import android.database.Cursor; 26 import android.database.CursorJoiner; 27 import android.database.CursorJoiner.Result; 28 import android.database.sqlite.SQLiteDatabase; 29 import android.platform.test.annotations.IgnoreUnderRavenwood; 30 import android.platform.test.ravenwood.RavenwoodRule; 31 32 import androidx.test.InstrumentationRegistry; 33 import androidx.test.runner.AndroidJUnit4; 34 35 import org.junit.After; 36 import org.junit.Before; 37 import org.junit.Rule; 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 41 import java.io.File; 42 43 @RunWith(AndroidJUnit4.class) 44 public class CursorJoinerTest { 45 @Rule public final RavenwoodRule mRavenwood = new RavenwoodRule(); 46 47 private static final int TEST_ITEM_COUNT = 10; 48 private static final int DEFAULT_TABLE1_VALUE_BEGINS = 1; 49 private static final int DEFAULT_TABLE2_VALUE_BEGINS = 11; 50 private static final int EQUAL_START = 18; 51 // Every table has 7 unique numbers, and 3 other numbers they all have. 52 private static final int UNIQUE_COUNT = 7; 53 private static final int MAX_VALUE = 20; 54 private static final int EQUAL_VALUE_COUNT = MAX_VALUE - EQUAL_START + 1; 55 private static final String TABLE_NAME_1 = "test1"; 56 private static final String TABLE_NAME_2 = "test2"; 57 private static final String TABLE1_COLUMNS = " number TEXT"; 58 private static final String TABLE2_COLUMNS = " number TEXT, int_number INTEGER"; 59 60 private SQLiteDatabase mDatabase; 61 private File mDatabaseFile; 62 63 @Before setUp()64 public void setUp() throws Exception { 65 if (mRavenwood.isUnderRavenwood()) return; 66 67 setupDatabase(); 68 } 69 70 @After tearDown()71 public void tearDown() throws Exception { 72 if (mRavenwood.isUnderRavenwood()) return; 73 74 mDatabase.close(); 75 mDatabaseFile.delete(); 76 } 77 getContext()78 private Context getContext() { 79 return InstrumentationRegistry.getTargetContext(); 80 } 81 82 @Test 83 @IgnoreUnderRavenwood(blockedBy = SQLiteDatabase.class) testCursorJoinerAndIterator()84 public void testCursorJoinerAndIterator() { 85 Cursor cursor1 = getCursor(TABLE_NAME_1, null, null); 86 Cursor cursor2 = getCursor(TABLE_NAME_2, null, null); 87 // Test with different length ColumenNAmes 88 try { 89 new CursorJoiner(cursor1, cursor1.getColumnNames(), cursor2, cursor2.getColumnNames()); 90 fail("CursorJoiner's constructor should throws IllegalArgumentException here."); 91 } catch (IllegalArgumentException e) { 92 //expected 93 } 94 closeCursor(cursor1); 95 closeCursor(cursor2); 96 97 String[] columnNames = new String[] { "number" }; 98 cursor1 = getCursor(TABLE_NAME_1, null, columnNames); 99 cursor2 = getCursor(TABLE_NAME_2, null, columnNames); 100 101 CursorJoiner cursorJoiner = new CursorJoiner(cursor1, cursor1.getColumnNames(), cursor2, 102 cursor2.getColumnNames()); 103 104 // Test remove() 105 try { 106 cursorJoiner.remove(); 107 fail("remove() should throws UnsupportedOperationException here"); 108 } catch (UnsupportedOperationException e) { 109 // expected 110 } 111 112 assertEquals(TEST_ITEM_COUNT, cursor1.getCount()); 113 assertEquals(TEST_ITEM_COUNT, cursor2.getCount()); 114 115 // Test iterator 116 for (CursorJoiner.Result joinResult : cursorJoiner) { 117 switch (joinResult) { 118 case LEFT: 119 // Add the values into table test1 which table test1 possess and table test2 don't. 120 assertTrue(cursor1.getString(0).compareTo(cursor2.getString(0)) < 0); 121 addValueIntoTable(TABLE_NAME_2, cursor1.getString(0)); 122 break; 123 case RIGHT: 124 // Add the values into table test2 which table test2 possess and table test1 don't. 125 assertTrue(cursor1.getString(0).compareTo(cursor2.getString(0)) > 0); 126 addValueIntoTable(TABLE_NAME_1, cursor2.getString(0)); 127 break; 128 case BOTH: 129 // Delete the values table test1 and test2 both possess. 130 assertEquals(cursor1.getString(0), cursor2.getString(0)); 131 deleteValueFromTable(TABLE_NAME_1, cursor1.getString(0)); 132 deleteValueFromTable(TABLE_NAME_2, cursor2.getString(0)); 133 break; 134 } 135 } 136 cursor1.requery(); 137 cursor2.requery(); 138 139 // Finally, two tables's number columns have the same contents 140 assertEquals(UNIQUE_COUNT * 2, cursor1.getCount()); 141 assertEquals(UNIQUE_COUNT * 2, cursor2.getCount()); 142 143 // For every table, merged with the other one's unique numbers, and deleted the originally 144 // mutual same numbers(EQUAL_START~MAX_VALUE); 145 cursor1.moveToFirst(); 146 cursor2.moveToFirst(); 147 for (int i = 0; i < UNIQUE_COUNT; i++) { 148 assertEquals(getOrderNumberString(DEFAULT_TABLE1_VALUE_BEGINS + i, MAX_VALUE), 149 cursor1.getString(0)); 150 assertEquals(cursor1.getString(0), cursor2.getString(0)); 151 cursor1.moveToNext(); 152 cursor2.moveToNext(); 153 } 154 closeCursor(cursor2); 155 closeCursor(cursor1); 156 } 157 158 @Test 159 @IgnoreUnderRavenwood(blockedBy = SQLiteDatabase.class) testNext()160 public void testNext() { 161 String[] columnNames = new String[] { "number" }; 162 Cursor cursor1 = getCursor(TABLE_NAME_1, null, columnNames); 163 Cursor cursor2 = getCursor(TABLE_NAME_2, null, columnNames); 164 165 // For cursor1 , values are '01'~'07' and 'EQUAL_START'~'MAX_VALUE' 166 assertEquals(TEST_ITEM_COUNT, cursor1.getCount()); 167 // For cursor2 , values are '11'~'17' and 'EQUAL_START'~'MAX_VALUE' 168 assertEquals(TEST_ITEM_COUNT, cursor2.getCount()); 169 CursorJoiner cursorJoiner = new CursorJoiner(cursor1, cursor1.getColumnNames(), cursor2, 170 cursor2.getColumnNames()); 171 for (int i = 0; i < UNIQUE_COUNT; i++) { 172 // For cursor1, value 1~7 result value as LEFT to cursor2 value '11' 173 assertTrue(cursorJoiner.hasNext()); 174 assertEquals(Result.LEFT, cursorJoiner.next()); 175 assertEquals(getOrderNumberString(DEFAULT_TABLE1_VALUE_BEGINS + i, MAX_VALUE), cursor1 176 .getString(0)); 177 assertEquals(getOrderNumberString(DEFAULT_TABLE2_VALUE_BEGINS, MAX_VALUE), cursor2 178 .getString(0)); 179 } 180 for (int i = 0; i < UNIQUE_COUNT; i++) { 181 // For cursor2, value 11~17 result a value as LEFT to cursor1 value '18' 182 assertTrue(cursorJoiner.hasNext()); 183 assertEquals(Result.RIGHT, cursorJoiner.next()); 184 assertEquals(getOrderNumberString(EQUAL_START, MAX_VALUE), cursor1.getString(0)); 185 assertEquals(getOrderNumberString(DEFAULT_TABLE2_VALUE_BEGINS + i, MAX_VALUE), cursor2 186 .getString(0)); 187 } 188 for (int i = 0; i < EQUAL_VALUE_COUNT; i++) { 189 // For cursor1 and cursor2, value 18~20 result a value as BOTH 190 assertTrue(cursorJoiner.hasNext()); 191 assertEquals(Result.BOTH, cursorJoiner.next()); 192 assertEquals(getOrderNumberString(EQUAL_START + i, MAX_VALUE), cursor1.getString(0)); 193 assertEquals(getOrderNumberString(EQUAL_START + i, MAX_VALUE), cursor2.getString(0)); 194 } 195 closeCursor(cursor1); 196 closeCursor(cursor2); 197 } 198 199 /** 200 * This function accepts integer maxValue to determine max length of number. 201 * Return a converted decimal number string of input integer parameter 'value', 202 * according to the max length, '0' will be placeholder(s). 203 * For example: if max length is 2, 1 -> '01', 10 -> '10'. 204 * @param value 205 * @param maxValue 206 * @return 207 */ getOrderNumberString(int value, int maxValue)208 private String getOrderNumberString(int value, int maxValue) { 209 // Convert decimal number as string, '0' as placeholder 210 int maxLength = Integer.toString(maxValue).length(); 211 int basicLength = Integer.toString(value).length(); 212 String placeHolders = ""; 213 for (int i = 0; i < (maxLength - basicLength); i++) { 214 placeHolders += "0"; 215 } 216 return placeHolders + Integer.toString(value); 217 } 218 initializeTables()219 private void initializeTables() { 220 // Add 1 to 7 into Table1 221 addValuesIntoTable(TABLE_NAME_1, DEFAULT_TABLE1_VALUE_BEGINS, 222 DEFAULT_TABLE1_VALUE_BEGINS + UNIQUE_COUNT - 1); 223 // Add 18 to 20 into Table1 224 addValuesIntoTable(TABLE_NAME_1, DEFAULT_TABLE2_VALUE_BEGINS + UNIQUE_COUNT, MAX_VALUE); 225 // Add 11 to 17 into Table2 226 addValuesIntoTable(TABLE_NAME_2, DEFAULT_TABLE2_VALUE_BEGINS, 227 DEFAULT_TABLE2_VALUE_BEGINS + UNIQUE_COUNT - 1); 228 // Add 18 to 20 into Table2 229 addValuesIntoTable(TABLE_NAME_2, DEFAULT_TABLE2_VALUE_BEGINS + UNIQUE_COUNT, MAX_VALUE); 230 } 231 setupDatabase()232 private void setupDatabase() { 233 File dbDir = getContext().getDir("tests", Context.MODE_PRIVATE); 234 mDatabaseFile = new File(dbDir, "database_test.db"); 235 if (mDatabaseFile.exists()) { 236 mDatabaseFile.delete(); 237 } 238 mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); 239 assertNotNull(mDatabaseFile); 240 createTable(TABLE_NAME_1, TABLE1_COLUMNS); 241 createTable(TABLE_NAME_2, TABLE2_COLUMNS); 242 initializeTables(); 243 } 244 closeCursor(Cursor cursor)245 private void closeCursor(Cursor cursor) { 246 if (null != cursor) { 247 cursor.close(); 248 cursor = null; 249 } 250 } 251 createTable(String tableName, String columnNames)252 private void createTable(String tableName, String columnNames) { 253 String sql = "Create TABLE " + tableName + " (_id INTEGER PRIMARY KEY, " + columnNames 254 + " );"; 255 mDatabase.execSQL(sql); 256 } 257 addValuesIntoTable(String tableName, int start, int end)258 private void addValuesIntoTable(String tableName, int start, int end) { 259 for (int i = start; i <= end; i++) { 260 mDatabase.execSQL("INSERT INTO " + tableName + "(number) VALUES ('" 261 + getOrderNumberString(i, MAX_VALUE) + "');"); 262 } 263 } 264 addValueIntoTable(String tableName, String value)265 private void addValueIntoTable(String tableName, String value) { 266 mDatabase.execSQL("INSERT INTO " + tableName + "(number) VALUES ('" + value + "');"); 267 } 268 deleteValueFromTable(String tableName, String value)269 private void deleteValueFromTable(String tableName, String value) { 270 mDatabase.execSQL("DELETE FROM " + tableName + " WHERE number = '" + value + "';"); 271 } 272 getCursor(String tableName, String selection, String[] columnNames)273 private Cursor getCursor(String tableName, String selection, String[] columnNames) { 274 return mDatabase.query(tableName, columnNames, selection, null, null, null, "number"); 275 } 276 } 277