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 android.database.CharArrayBuffer; 20 import android.database.CursorWindow; 21 import android.database.MatrixCursor; 22 import android.database.sqlite.SQLiteException; 23 import android.os.Parcel; 24 import android.test.AndroidTestCase; 25 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.Random; 29 30 public class CursorWindowTest extends AndroidTestCase { 31 32 private static final String TEST_STRING = "Test String"; 33 testWriteCursorToWindow()34 public void testWriteCursorToWindow() throws Exception { 35 // create cursor 36 String[] colNames = new String[]{"_id", "name", "number", "profit"}; 37 int colsize = colNames.length; 38 ArrayList<ArrayList<Integer>> list = createTestList(10, colsize); 39 MatrixCursor cursor = new MatrixCursor(colNames, list.size()); 40 for (ArrayList<Integer> row : list) { 41 cursor.addRow(row); 42 } 43 44 // fill window 45 CursorWindow window = new CursorWindow(false); 46 cursor.fillWindow(0, window); 47 48 // read from cursor window 49 for (int i = 0; i < list.size(); i++) { 50 ArrayList<Integer> col = list.get(i); 51 for (int j = 0; j < colsize; j++) { 52 String s = window.getString(i, j); 53 int r2 = col.get(j); 54 int r1 = Integer.parseInt(s); 55 assertEquals(r2, r1); 56 } 57 } 58 59 // test cursor window handle startpos != 0 60 window.clear(); 61 cursor.fillWindow(1, window); 62 // read from cursor from window 63 for (int i = 1; i < list.size(); i++) { 64 ArrayList<Integer> col = list.get(i); 65 for (int j = 0; j < colsize; j++) { 66 String s = window.getString(i, j); 67 int r2 = col.get(j); 68 int r1 = Integer.parseInt(s); 69 assertEquals(r2, r1); 70 } 71 } 72 73 // Clear the window and make sure it's empty 74 window.clear(); 75 assertEquals(0, window.getNumRows()); 76 } 77 testNull()78 public void testNull() { 79 CursorWindow window = getOneByOneWindow(); 80 81 // Put in a null value and read it back as various types 82 assertTrue(window.putNull(0, 0)); 83 assertNull(window.getString(0, 0)); 84 assertEquals(0, window.getLong(0, 0)); 85 assertEquals(0.0, window.getDouble(0, 0)); 86 assertNull(window.getBlob(0, 0)); 87 } 88 testEmptyString()89 public void testEmptyString() { 90 CursorWindow window = getOneByOneWindow(); 91 92 // put size 0 string and read it back as various types 93 assertTrue(window.putString("", 0, 0)); 94 assertEquals("", window.getString(0, 0)); 95 assertEquals(0, window.getLong(0, 0)); 96 assertEquals(0.0, window.getDouble(0, 0)); 97 } 98 testConstructors()99 public void testConstructors() { 100 int TEST_NUMBER = 5; 101 CursorWindow cursorWindow; 102 103 // Test constructor with 'true' input, and getStartPosition should return 0 104 cursorWindow = new CursorWindow(true); 105 assertEquals(0, cursorWindow.getStartPosition()); 106 107 // Test constructor with 'false' input 108 cursorWindow = new CursorWindow(false); 109 assertEquals(0, cursorWindow.getStartPosition()); 110 111 // Test newFromParcel 112 Parcel parcel = Parcel.obtain(); 113 cursorWindow = new CursorWindow(true); 114 cursorWindow.setStartPosition(TEST_NUMBER); 115 cursorWindow.setNumColumns(1); 116 cursorWindow.allocRow(); 117 cursorWindow.putString(TEST_STRING, TEST_NUMBER, 0); 118 cursorWindow.writeToParcel(parcel, 0); 119 120 parcel.setDataPosition(0); 121 cursorWindow = CursorWindow.CREATOR.createFromParcel(parcel); 122 assertEquals(TEST_NUMBER, cursorWindow.getStartPosition()); 123 assertEquals(TEST_STRING, cursorWindow.getString(TEST_NUMBER, 0)); 124 } 125 testDataStructureOperations()126 public void testDataStructureOperations() { 127 CursorWindow cursorWindow = new CursorWindow(true); 128 129 // Test with normal values 130 assertTrue(cursorWindow.setNumColumns(0)); 131 // If the column has been set to zero, can't put String. 132 assertFalse(cursorWindow.putString(TEST_STRING, 0, 0)); 133 134 // Test allocRow(). 135 assertTrue(cursorWindow.allocRow()); 136 assertEquals(1, cursorWindow.getNumRows()); 137 assertTrue(cursorWindow.allocRow()); 138 assertEquals(2, cursorWindow.getNumRows()); 139 // Though allocate a row, but the column number is still 0, so can't putString. 140 assertFalse(cursorWindow.putString(TEST_STRING, 0, 0)); 141 142 // Test freeLstRow 143 cursorWindow.freeLastRow(); 144 assertEquals(1, cursorWindow.getNumRows()); 145 cursorWindow.freeLastRow(); 146 assertEquals(0, cursorWindow.getNumRows()); 147 148 cursorWindow = new CursorWindow(true); 149 assertTrue(cursorWindow.setNumColumns(6)); 150 assertTrue(cursorWindow.allocRow()); 151 // Column number set to negative number, so now can put values. 152 assertTrue(cursorWindow.putString(TEST_STRING, 0, 0)); 153 assertEquals(TEST_STRING, cursorWindow.getString(0, 0)); 154 155 // Test with negative value 156 assertFalse(cursorWindow.setNumColumns(-1)); 157 158 // Test with reference limitation 159 cursorWindow.releaseReference(); 160 try { 161 cursorWindow.setNumColumns(5); 162 fail("setNumColumns() should throws IllegalStateException here."); 163 } catch (IllegalStateException e) { 164 // expected 165 } 166 167 // Test close(), close will also minus references, that will lead acquireReference() 168 // related operation failed. 169 cursorWindow.close(); 170 try { 171 cursorWindow.acquireReference(); 172 fail("setNumColumns() should throws IllegalStateException here."); 173 } catch (IllegalStateException e) { 174 // expected 175 } 176 } 177 testAccessDataValues()178 public void testAccessDataValues() { 179 final long NUMBER_LONG_INTEGER = (long) 0xaabbccddffL; 180 final long NUMBER_INTEGER = (int) NUMBER_LONG_INTEGER; 181 final long NUMBER_SHORT = (short) NUMBER_INTEGER; 182 final float NUMBER_FLOAT_SCIENCE = 7.332952E11f; 183 final double NUMBER_DOUBLE_SCIENCE = 7.33295205887E11; 184 final String NUMBER_FLOAT_SCIENCE_STRING = "7.332952E11"; 185 final String NUMBER_DOUBLE_SCIENCE_STRING = "7.33295205887E11"; 186 final String NUMBER_FLOAT_SCIENCE_STRING2 = "7.33295e+11"; 187 188 byte[] originalBlob = new byte[Byte.MAX_VALUE]; 189 for (int i = 0; i < Byte.MAX_VALUE; i++) { 190 originalBlob[i] = (byte) i; 191 } 192 193 CursorWindow cursorWindow = new CursorWindow(true); 194 cursorWindow.setNumColumns(5); 195 cursorWindow.allocRow(); 196 197 // Test putString, getString, getLong, getInt, isBlob 198 assertTrue(cursorWindow.putString(Long.toString(NUMBER_LONG_INTEGER), 0, 0)); 199 assertEquals(Long.toString(NUMBER_LONG_INTEGER), cursorWindow.getString(0, 0)); 200 assertEquals(NUMBER_LONG_INTEGER, cursorWindow.getLong(0, 0)); 201 assertEquals(NUMBER_INTEGER, cursorWindow.getInt(0, 0)); 202 assertEquals(NUMBER_SHORT, cursorWindow.getShort(0, 0)); 203 // Converting of Float, there would be some little precision differences. So just compare 204 // first 6 digits. 205 assertEquals(NUMBER_FLOAT_SCIENCE_STRING.substring(0, 6), Float.toString( 206 cursorWindow.getFloat(0, 0)).substring(0, 6)); 207 assertEquals(NUMBER_DOUBLE_SCIENCE_STRING, Double.toString(cursorWindow.getDouble(0, 0))); 208 assertFalse(cursorWindow.isNull(0, 0)); 209 assertFalse(cursorWindow.isBlob(0, 0)); 210 211 // Test null String 212 assertTrue(cursorWindow.putString("", 0, 0)); 213 assertEquals("", cursorWindow.getString(0, 0)); 214 assertEquals(0, cursorWindow.getLong(0, 0)); 215 assertEquals(0, cursorWindow.getInt(0, 0)); 216 assertEquals(0, cursorWindow.getShort(0, 0)); 217 assertEquals(0.0, cursorWindow.getDouble(0, 0)); 218 assertEquals(0.0f, cursorWindow.getFloat(0, 0), 0.00000001f); 219 assertFalse(cursorWindow.isNull(0, 0)); 220 assertFalse(cursorWindow.isBlob(0, 0)); 221 222 // Test putNull, getString, getLong, getDouble, getBlob, getInd, getShort, getFloat, 223 // isBlob. 224 assertTrue(cursorWindow.putNull(0, 1)); 225 assertNull(cursorWindow.getString(0, 1)); 226 assertEquals(0, cursorWindow.getLong(0, 1)); 227 assertEquals(0, cursorWindow.getInt(0, 1)); 228 assertEquals(0, cursorWindow.getShort(0, 1)); 229 assertEquals(0.0, cursorWindow.getDouble(0, 1)); 230 assertEquals(0.0f, cursorWindow.getFloat(0, 1), 0.00000001f); 231 assertNull(cursorWindow.getBlob(0, 1)); 232 assertTrue(cursorWindow.isNull(0, 1)); 233 // If the field is null, isBlob will return true. 234 assertTrue(cursorWindow.isBlob(0, 1)); 235 236 // Test putLong, getLong, getInt, getString , getShort, getFloat, getDouble, isBlob. 237 assertTrue(cursorWindow.putLong(NUMBER_LONG_INTEGER, 0, 2)); 238 assertEquals(NUMBER_LONG_INTEGER, cursorWindow.getLong(0, 2)); 239 assertEquals(NUMBER_INTEGER, cursorWindow.getInt(0, 2)); 240 assertEquals(Long.toString(NUMBER_LONG_INTEGER), cursorWindow.getString(0, 2)); 241 assertEquals(NUMBER_SHORT, cursorWindow.getShort(0, 2)); 242 assertEquals(NUMBER_FLOAT_SCIENCE, cursorWindow.getFloat(0, 2), 0.00000001f); 243 assertEquals(NUMBER_DOUBLE_SCIENCE, cursorWindow.getDouble(0, 2), 0.00000001); 244 try { 245 cursorWindow.getBlob(0, 2); 246 fail("Can't get Blob from a Integer value."); 247 } catch (SQLiteException e) { 248 // expected 249 } 250 assertFalse(cursorWindow.isNull(0, 2)); 251 assertFalse(cursorWindow.isBlob(0, 2)); 252 253 // Test putDouble 254 assertTrue(cursorWindow.putDouble(NUMBER_DOUBLE_SCIENCE, 0, 3)); 255 assertEquals(NUMBER_LONG_INTEGER, cursorWindow.getLong(0, 3)); 256 assertEquals(NUMBER_INTEGER, cursorWindow.getInt(0, 3)); 257 // Converting from Double to String, there would be some little precision differences. So 258 // Just compare first 6 digits. 259 assertEquals(NUMBER_FLOAT_SCIENCE_STRING2.substring(0, 6), cursorWindow.getString(0, 3) 260 .substring(0, 6)); 261 assertEquals(NUMBER_SHORT, cursorWindow.getShort(0, 3)); 262 assertEquals(NUMBER_FLOAT_SCIENCE, cursorWindow.getFloat(0, 3), 0.00000001f); 263 assertEquals(NUMBER_DOUBLE_SCIENCE, cursorWindow.getDouble(0, 3), 0.00000001); 264 try { 265 cursorWindow.getBlob(0, 3); 266 fail("Can't get Blob from a Double value."); 267 } catch (SQLiteException e) { 268 // expected 269 } 270 assertFalse(cursorWindow.isNull(0, 3)); 271 assertFalse(cursorWindow.isBlob(0, 3)); 272 273 // Test putBlob 274 assertTrue(cursorWindow.putBlob(originalBlob, 0, 4)); 275 byte[] targetBlob = cursorWindow.getBlob(0, 4); 276 assertTrue(Arrays.equals(originalBlob, targetBlob)); 277 assertFalse(cursorWindow.isNull(0, 4)); 278 // Test isBlob 279 assertTrue(cursorWindow.isBlob(0, 4)); 280 } 281 testCopyStringToBuffer()282 public void testCopyStringToBuffer() { 283 int DEFAULT_ARRAY_LENGTH = 64; 284 String baseString = "0123456789"; 285 String expectedString = ""; 286 // Create a 60 characters string. 287 for (int i = 0; i < 6; i++) { 288 expectedString += baseString; 289 } 290 CharArrayBuffer charArrayBuffer = new CharArrayBuffer(null); 291 CursorWindow cursorWindow = new CursorWindow(true); 292 cursorWindow.setNumColumns(2); 293 cursorWindow.allocRow(); 294 295 assertEquals(null, charArrayBuffer.data); 296 cursorWindow.putString(expectedString, 0, 0); 297 cursorWindow.copyStringToBuffer(0, 0, charArrayBuffer); 298 assertNotNull(charArrayBuffer.data); 299 // By default, if the field's string is shorter than 64, array will be allocated as 64. 300 assertEquals(DEFAULT_ARRAY_LENGTH, charArrayBuffer.data.length); 301 assertEquals(expectedString, 302 new String(charArrayBuffer.data, 0, charArrayBuffer.sizeCopied)); 303 304 // Test in case of string is longer than 64, 305 expectedString += baseString; 306 charArrayBuffer = new CharArrayBuffer(null); 307 cursorWindow.putString(expectedString, 0, 1); 308 cursorWindow.copyStringToBuffer(0, 1, charArrayBuffer); 309 assertNotNull(charArrayBuffer.data); 310 // If the string is longer than 64, array will be allocated as needed(longer than 64). 311 assertEquals(expectedString, 312 new String(charArrayBuffer.data, 0, charArrayBuffer.sizeCopied)); 313 assertEquals(70, expectedString.length()); 314 assertEquals(expectedString.length(), charArrayBuffer.data.length); 315 } 316 testAccessStartPosition()317 public void testAccessStartPosition() { 318 final int TEST_POSITION_1 = 0; 319 final int TEST_POSITION_2 = 3; 320 321 CursorWindow cursorWindow = new CursorWindow(true); 322 fillCursorTestContents(cursorWindow, 5); 323 324 // Test setStartPosition 325 assertEquals(TEST_POSITION_1, cursorWindow.getStartPosition()); 326 assertEquals(3, cursorWindow.getInt(3, 0)); 327 assertEquals(TEST_STRING + "3", cursorWindow.getString(3, 1)); 328 assertEquals(4, cursorWindow.getInt(4, 0)); 329 assertEquals(TEST_STRING + "4", cursorWindow.getString(4, 1)); 330 cursorWindow.setStartPosition(TEST_POSITION_2); 331 332 assertEquals(TEST_POSITION_2, cursorWindow.getStartPosition()); 333 334 assertEquals(0, cursorWindow.getInt(3, 0)); 335 assertEquals(TEST_STRING + "0", cursorWindow.getString(3, 1)); 336 assertEquals(1, cursorWindow.getInt(4, 0)); 337 assertEquals(TEST_STRING + "1", cursorWindow.getString(4, 1)); 338 try { 339 cursorWindow.getBlob(0, 0); 340 fail("Row number is smaller than startPosition, will cause a IllegalStateException."); 341 } catch (IllegalStateException e) { 342 // expected 343 } 344 } 345 testClearAndOnAllReferencesReleased()346 public void testClearAndOnAllReferencesReleased() { 347 MockCursorWindow cursorWindow = new MockCursorWindow(true); 348 349 assertEquals(0, cursorWindow.getNumRows()); 350 fillCursorTestContents(cursorWindow, 10); 351 assertEquals(10, cursorWindow.getNumRows()); 352 assertEquals(0, cursorWindow.getStartPosition()); 353 cursorWindow.setStartPosition(5); 354 assertEquals(5, cursorWindow.getStartPosition()); 355 356 // Test clear(). a complete calling process of cursorWindow has a perfect acquiring and 357 // releasing pair, so the references number will be equal at the begin and the end. 358 assertFalse(cursorWindow.hasReleasedAllReferences()); 359 cursorWindow.clear(); 360 assertEquals(0, cursorWindow.getNumRows()); 361 assertEquals(0, cursorWindow.getStartPosition()); 362 assertFalse(cursorWindow.hasReleasedAllReferences()); 363 364 // Test onAllReferencesReleased. 365 // By default, cursorWindow's reference is 1, when it reachs 0, onAllReferencesReleased 366 // be invoked. 367 cursorWindow = new MockCursorWindow(true); 368 cursorWindow.releaseReference(); 369 assertTrue(cursorWindow.hasReleasedAllReferences()); 370 } 371 testDescribeContents()372 public void testDescribeContents() { 373 CursorWindow cursorWindow = new CursorWindow(true); 374 assertEquals(0, cursorWindow.describeContents()); 375 } 376 377 private class MockCursorWindow extends CursorWindow { 378 private boolean mHasReleasedAllReferences = false; 379 MockCursorWindow(boolean localWindow)380 public MockCursorWindow(boolean localWindow) { 381 super(localWindow); 382 } 383 384 @Override onAllReferencesReleased()385 protected void onAllReferencesReleased() { 386 super.onAllReferencesReleased(); 387 mHasReleasedAllReferences = true; 388 } 389 hasReleasedAllReferences()390 public boolean hasReleasedAllReferences() { 391 return mHasReleasedAllReferences; 392 } 393 resetStatus()394 public void resetStatus() { 395 mHasReleasedAllReferences = false; 396 } 397 } 398 fillCursorTestContents(CursorWindow cursorWindow, int length)399 private void fillCursorTestContents(CursorWindow cursorWindow, int length) { 400 cursorWindow.clear(); 401 cursorWindow.setStartPosition(0); 402 cursorWindow.setNumColumns(2); 403 for (int i = 0; i < length; i++) { 404 cursorWindow.allocRow(); 405 cursorWindow.putLong(i, i, 0); 406 cursorWindow.putString(TEST_STRING + i, i, 1); 407 } 408 } 409 createTestList(int rows, int cols)410 private static ArrayList<ArrayList<Integer>> createTestList(int rows, int cols) { 411 ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>(); 412 Random generator = new Random(); 413 414 for (int i = 0; i < rows; i++) { 415 ArrayList<Integer> col = new ArrayList<Integer>(); 416 list.add(col); 417 for (int j = 0; j < cols; j++) { 418 // generate random number 419 col.add(j == 0 ? i : generator.nextInt()); 420 } 421 } 422 return list; 423 } 424 425 /** 426 * The method comes from unit_test CursorWindowTest. 427 */ getOneByOneWindow()428 private CursorWindow getOneByOneWindow() { 429 CursorWindow window = new CursorWindow(false); 430 assertTrue(window.setNumColumns(1)); 431 assertTrue(window.allocRow()); 432 return window; 433 } 434 } 435