1 package org.robolectric.shadows;
2 
3 import static com.google.common.truth.Truth.assertThat;
4 import static java.nio.charset.StandardCharsets.UTF_8;
5 
6 import android.database.Cursor;
7 import android.database.sqlite.SQLiteCursor;
8 import android.database.sqlite.SQLiteDatabase;
9 import android.database.sqlite.SQLiteException;
10 import androidx.test.ext.junit.runners.AndroidJUnit4;
11 import org.junit.After;
12 import org.junit.Before;
13 import org.junit.Test;
14 import org.junit.runner.RunWith;
15 
16 @RunWith(AndroidJUnit4.class)
17 public class SQLiteCursorTest {
18 
19   private SQLiteDatabase database;
20   private Cursor cursor;
21 
22   @Before
setUp()23   public void setUp() throws Exception {
24     database = SQLiteDatabase.create(null);
25 
26     database.execSQL("CREATE TABLE table_name(" +
27         "id INTEGER PRIMARY KEY, " +
28         "name VARCHAR(255), " +
29         "long_value BIGINT," +
30         "float_value REAL," +
31         "double_value DOUBLE, " +
32         "blob_value BINARY, " +
33         "clob_value CLOB );");
34 
35     addPeople();
36     cursor = createCursor();
37   }
38 
39   @After
tearDown()40   public void tearDown() throws Exception {
41     database.close();
42   }
43 
44   @Test
testGetColumnNames()45   public void testGetColumnNames() throws Exception {
46     String[] columnNames = cursor.getColumnNames();
47 
48     assertColumnNames(columnNames);
49   }
50 
51   @Test
testGetColumnNamesEmpty()52   public void testGetColumnNamesEmpty() throws Exception {
53     setupEmptyResult();
54     String[] columnNames = cursor.getColumnNames();
55 
56     // Column names are present even with an empty result.
57     assertThat(columnNames).isNotNull();
58     assertColumnNames(columnNames);
59   }
60 
61   @Test
testGetColumnIndex()62   public void testGetColumnIndex() throws Exception {
63     assertThat(cursor.getColumnIndex("id")).isEqualTo(0);
64     assertThat(cursor.getColumnIndex("name")).isEqualTo(1);
65   }
66 
67   @Test
testGetColumnIndexNotFound()68   public void testGetColumnIndexNotFound() throws Exception {
69     assertThat(cursor.getColumnIndex("Fred")).isEqualTo(-1);
70   }
71 
72   @Test
testGetColumnIndexEmpty()73   public void testGetColumnIndexEmpty() throws Exception {
74     setupEmptyResult();
75 
76     assertThat(cursor.getColumnIndex("id")).isEqualTo(0);
77     assertThat(cursor.getColumnIndex("name")).isEqualTo(1);
78   }
79 
80   @Test
testGetColumnIndexOrThrow()81   public void testGetColumnIndexOrThrow() throws Exception {
82     assertThat(cursor.getColumnIndexOrThrow("id")).isEqualTo(0);
83     assertThat(cursor.getColumnIndexOrThrow("name")).isEqualTo(1);
84   }
85 
86   @Test(expected = IllegalArgumentException.class)
testGetColumnIndexOrThrowNotFound()87   public void testGetColumnIndexOrThrowNotFound() throws Exception {
88     cursor.getColumnIndexOrThrow("Fred");
89   }
90 
91   @Test
testGetColumnIndexOrThrowEmpty()92   public void testGetColumnIndexOrThrowEmpty() throws Exception {
93     setupEmptyResult();
94 
95     assertThat(cursor.getColumnIndexOrThrow("name")).isEqualTo(1);
96   }
97 
98   @Test(expected = IllegalArgumentException.class)
testGetColumnIndexOrThrowNotFoundEmpty()99   public void testGetColumnIndexOrThrowNotFoundEmpty() throws Exception {
100     setupEmptyResult();
101 
102     cursor.getColumnIndexOrThrow("Fred");
103   }
104 
105   @Test
testMoveToFirst()106   public void testMoveToFirst() throws Exception {
107     assertThat(cursor.moveToFirst()).isTrue();
108     assertThat(cursor.getInt(0)).isEqualTo(1234);
109     assertThat(cursor.getString(1)).isEqualTo("Chuck");
110   }
111 
112   @Test
testMoveToFirstEmpty()113   public void testMoveToFirstEmpty() throws Exception {
114     setupEmptyResult();
115 
116     assertThat(cursor.moveToFirst()).isFalse();
117   }
118 
119   @Test
testMoveToNext()120   public void testMoveToNext() throws Exception {
121     assertThat(cursor.moveToFirst()).isTrue();
122 
123     assertThat(cursor.moveToNext()).isTrue();
124     assertThat(cursor.getInt(0)).isEqualTo(1235);
125     assertThat(cursor.getString(1)).isEqualTo("Julie");
126   }
127 
128   @Test
testMoveToNextPastEnd()129   public void testMoveToNextPastEnd() throws Exception {
130     assertThat(cursor.moveToFirst()).isTrue();
131 
132     assertThat(cursor.moveToNext()).isTrue();
133     assertThat(cursor.moveToNext()).isTrue();
134     assertThat(cursor.moveToNext()).isFalse();
135   }
136 
137   @Test
testMoveBackwards()138   public void testMoveBackwards() throws Exception {
139     assertThat(cursor.getPosition()).isEqualTo(-1);
140 
141     assertThat(cursor.moveToFirst()).isTrue();
142     assertThat(cursor.getPosition()).isEqualTo(0);
143     assertThat(cursor.moveToNext()).isTrue();
144     assertThat(cursor.getPosition()).isEqualTo(1);
145     assertThat(cursor.moveToNext()).isTrue();
146     assertThat(cursor.getPosition()).isEqualTo(2);
147 
148     assertThat(cursor.moveToFirst()).isTrue();
149     assertThat(cursor.getPosition()).isEqualTo(0);
150     assertThat(cursor.moveToNext()).isTrue();
151     assertThat(cursor.getPosition()).isEqualTo(1);
152     assertThat(cursor.moveToNext()).isTrue();
153     assertThat(cursor.getPosition()).isEqualTo(2);
154 
155     assertThat(cursor.moveToPosition(1)).isTrue();
156     assertThat(cursor.getPosition()).isEqualTo(1);
157   }
158 
159   @Test
testMoveToNextEmpty()160   public void testMoveToNextEmpty() throws Exception {
161     setupEmptyResult();
162 
163     assertThat(cursor.moveToFirst()).isFalse();
164     assertThat(cursor.moveToNext()).isFalse();
165   }
166 
167   @Test
testMoveToPrevious()168   public void testMoveToPrevious() throws Exception {
169     assertThat(cursor.moveToFirst()).isTrue();
170     assertThat(cursor.moveToNext()).isTrue();
171 
172     assertThat(cursor.moveToPrevious()).isTrue();
173     assertThat(cursor.getInt(0)).isEqualTo(1234);
174     assertThat(cursor.getString(1)).isEqualTo("Chuck");
175   }
176 
177   @Test
testMoveToPreviousPastStart()178   public void testMoveToPreviousPastStart() throws Exception {
179     assertThat(cursor.moveToFirst()).isTrue();
180 
181     // Impossible to move cursor before the first item
182     assertThat(cursor.moveToPrevious()).isFalse();
183   }
184 
185   @Test
testMoveToPreviousEmpty()186   public void testMoveToPreviousEmpty() throws Exception {
187     setupEmptyResult();
188     assertThat(cursor.moveToFirst()).isFalse();
189 
190     assertThat(cursor.moveToPrevious()).isFalse();
191   }
192 
193   @Test
testGetPosition()194   public void testGetPosition() throws Exception {
195     assertThat(cursor.moveToFirst()).isTrue();
196     assertThat(cursor.getPosition()).isEqualTo(0);
197 
198     assertThat(cursor.moveToNext()).isTrue();
199     assertThat(cursor.getPosition()).isEqualTo(1);
200   }
201 
202   @Test
testGetBlob()203   public void testGetBlob() throws Exception {
204     String sql = "UPDATE table_name set blob_value=? where id=1234";
205     byte[] byteData = sql.getBytes(UTF_8);
206 
207     database.execSQL(sql, new Object[]{byteData});
208 
209     assertThat(cursor.moveToFirst()).isTrue();
210 
211     byte[] retrievedByteData = cursor.getBlob(5);
212     assertThat(byteData.length).isEqualTo(retrievedByteData.length);
213 
214     for (int i = 0; i < byteData.length; i++) {
215       assertThat(byteData[i]).isEqualTo(retrievedByteData[i]);
216     }
217   }
218 
219   @Test
testGetClob()220   public void testGetClob() throws Exception {
221     String sql = "UPDATE table_name set clob_value=? where id=1234";
222     String s = "Don't CLOBber my data, please. Thank you.";
223 
224     database.execSQL(sql, new Object[]{s});
225 
226     assertThat(cursor.moveToFirst()).isTrue();
227 
228     String actual = cursor.getString(6);
229     assertThat(s).isEqualTo(actual);
230   }
231 
232   @Test
testGetString()233   public void testGetString() throws Exception {
234     assertThat(cursor.moveToFirst()).isTrue();
235 
236     String[] data = {"Chuck", "Julie", "Chris"};
237 
238     for (String aData : data) {
239       assertThat(cursor.getString(1)).isEqualTo(aData);
240       cursor.moveToNext();
241     }
242   }
243 
244   @Test
testGetStringWhenInteger()245   public void testGetStringWhenInteger() throws Exception {
246     assertThat(cursor.moveToFirst()).isTrue();
247 
248     assertThat(cursor.getString(0)).isEqualTo("1234");
249   }
250 
251   @Test
testGetStringWhenLong()252   public void testGetStringWhenLong() throws Exception {
253     assertThat(cursor.moveToFirst()).isTrue();
254 
255     assertThat(cursor.getString(2)).isEqualTo("3463");
256   }
257 
258   @Test
testGetStringWhenFloat()259   public void testGetStringWhenFloat() throws Exception {
260     assertThat(cursor.moveToFirst()).isTrue();
261 
262     assertThat(cursor.getString(3)).isEqualTo("1.5");
263   }
264 
265   @Test
testGetStringWhenDouble()266   public void testGetStringWhenDouble() throws Exception {
267     assertThat(cursor.moveToFirst()).isTrue();
268 
269     assertThat(cursor.getString(4)).isEqualTo("3.14159");
270   }
271 
272   @Test(expected = SQLiteException.class)
testGetStringWhenBlob()273   public void testGetStringWhenBlob() throws Exception {
274     String sql = "UPDATE table_name set blob_value=? where id=1234";
275     byte[] byteData = sql.getBytes(UTF_8);
276 
277     database.execSQL(sql, new Object[]{byteData});
278 
279     assertThat(cursor.moveToFirst()).isTrue();
280 
281     cursor.getString(5);
282   }
283 
284   @Test(expected = SQLiteException.class)
testGetIntWhenBlob()285   public void testGetIntWhenBlob() throws Exception {
286     String sql = "UPDATE table_name set blob_value=? where id=1234";
287     byte[] byteData = sql.getBytes(UTF_8);
288 
289     database.execSQL(sql, new Object[]{byteData});
290 
291     assertThat(cursor.moveToFirst()).isTrue();
292 
293     cursor.getInt(5);
294   }
295 
296   @Test
testGetStringWhenNull()297   public void testGetStringWhenNull() throws Exception {
298     assertThat(cursor.moveToFirst()).isTrue();
299 
300     assertThat(cursor.getString(5)).isNull();
301   }
302 
303   @Test
testGetInt()304   public void testGetInt() throws Exception {
305     assertThat(cursor.moveToFirst()).isTrue();
306 
307     int[] data = {1234, 1235, 1236};
308 
309     for (int aData : data) {
310       assertThat(cursor.getInt(0)).isEqualTo(aData);
311       cursor.moveToNext();
312     }
313   }
314 
315   @Test
testGetNumbersFromStringField()316   public void testGetNumbersFromStringField() throws Exception {
317     database.execSQL("update table_name set name = '1.2'");
318     assertThat(cursor.moveToFirst()).isTrue();
319 
320     assertThat(cursor.getInt(1)).isEqualTo(1);
321     assertThat(cursor.getDouble(1)).isEqualTo(1.2d);
322     assertThat(cursor.getFloat(1)).isEqualTo(1.2f);
323   }
324 
325   @Test
testGetNumbersFromBlobField()326   public void testGetNumbersFromBlobField() throws Exception {
327     database.execSQL("update table_name set name = '1.2'");
328     assertThat(cursor.moveToFirst()).isTrue();
329 
330     assertThat(cursor.getInt(1)).isEqualTo(1);
331     assertThat(cursor.getDouble(1)).isEqualTo(1.2d);
332     assertThat(cursor.getFloat(1)).isEqualTo(1.2f);
333   }
334 
335   @Test
testGetLong()336   public void testGetLong() throws Exception {
337     assertThat(cursor.moveToFirst()).isTrue();
338 
339     assertThat(cursor.getLong(2)).isEqualTo(3463L);
340   }
341 
342   @Test
testGetFloat()343   public void testGetFloat() throws Exception {
344     assertThat(cursor.moveToFirst()).isTrue();
345 
346     assertThat(cursor.getFloat(3)).isEqualTo((float) 1.5);
347   }
348 
349   @Test
testGetDouble()350   public void testGetDouble() throws Exception {
351     assertThat(cursor.moveToFirst()).isTrue();
352 
353     assertThat(cursor.getDouble(4)).isEqualTo(3.14159);
354   }
355 
356   @Test
testClose()357   public void testClose() throws Exception {
358     assertThat(cursor.isClosed()).isFalse();
359     cursor.close();
360     assertThat(cursor.isClosed()).isTrue();
361   }
362 
363   @Test
testIsNullWhenNull()364   public void testIsNullWhenNull() throws Exception {
365     assertThat(cursor.moveToFirst()).isTrue();
366     assertThat(cursor.moveToNext()).isTrue();
367 
368     assertThat(cursor.isNull(cursor.getColumnIndex("id"))).isFalse();
369     assertThat(cursor.isNull(cursor.getColumnIndex("name"))).isFalse();
370 
371     assertThat(cursor.isNull(cursor.getColumnIndex("long_value"))).isTrue();
372     assertThat(cursor.isNull(cursor.getColumnIndex("float_value"))).isTrue();
373     assertThat(cursor.isNull(cursor.getColumnIndex("double_value"))).isTrue();
374   }
375 
376   @Test
testIsNullWhenNotNull()377   public void testIsNullWhenNotNull() throws Exception {
378     assertThat(cursor.moveToFirst()).isTrue();
379 
380     for (int i = 0; i < 5; i++) {
381       assertThat(cursor.isNull(i)).isFalse();
382     }
383   }
384 
385   @Test
testIsNullWhenIndexOutOfBounds()386   public void testIsNullWhenIndexOutOfBounds() throws Exception {
387     assertThat(cursor.moveToFirst()).isTrue();
388 
389     // column index 5 is out-of-bounds
390     assertThat(cursor.isNull(5)).isTrue();
391   }
392 
393   @Test
testGetTypeWhenInteger()394   public void testGetTypeWhenInteger() throws Exception {
395     assertThat(cursor.moveToFirst()).isTrue();
396 
397     assertThat(cursor.getType(0)).isEqualTo(Cursor.FIELD_TYPE_INTEGER);
398   }
399 
400   @Test
testGetTypeWhenString()401   public void testGetTypeWhenString() throws Exception {
402     assertThat(cursor.moveToFirst()).isTrue();
403 
404     assertThat(cursor.getType(1)).isEqualTo(Cursor.FIELD_TYPE_STRING);
405   }
406 
407   @Test
testGetTypeWhenLong()408   public void testGetTypeWhenLong() throws Exception {
409     assertThat(cursor.moveToFirst()).isTrue();
410 
411     assertThat(cursor.getType(2)).isEqualTo(Cursor.FIELD_TYPE_INTEGER);
412   }
413 
414   @Test
testGetTypeWhenFloat()415   public void testGetTypeWhenFloat() throws Exception {
416     assertThat(cursor.moveToFirst()).isTrue();
417 
418     assertThat(cursor.getType(3)).isEqualTo(Cursor.FIELD_TYPE_FLOAT);
419   }
420 
421   @Test
testGetTypeWhenDouble()422   public void testGetTypeWhenDouble() throws Exception {
423     assertThat(cursor.moveToFirst()).isTrue();
424 
425     assertThat(cursor.getType(4)).isEqualTo(Cursor.FIELD_TYPE_FLOAT);
426   }
427 
428   @Test
testGetTypeWhenBlob()429   public void testGetTypeWhenBlob() throws Exception {
430     String sql = "UPDATE table_name set blob_value=? where id=1234";
431     byte[] byteData = sql.getBytes(UTF_8);
432 
433     database.execSQL(sql, new Object[]{byteData});
434 
435     assertThat(cursor.moveToFirst()).isTrue();
436     assertThat(cursor.getType(5)).isEqualTo(Cursor.FIELD_TYPE_BLOB);
437   }
438 
439   @Test
testGetTypeWhenNull()440   public void testGetTypeWhenNull() throws Exception {
441     assertThat(cursor.moveToFirst()).isTrue();
442 
443     assertThat(cursor.getType(5)).isEqualTo(Cursor.FIELD_TYPE_NULL);
444   }
445 
446   @Test
testGetNullNumberValues()447   public void testGetNullNumberValues() throws Exception {
448     String sql = "UPDATE table_name set long_value=NULL, float_value=NULL, double_value=NULL";
449     database.execSQL(sql);
450 
451     assertThat(cursor.moveToFirst()).isTrue();
452 
453     assertThat(cursor.getType(2)).isEqualTo(Cursor.FIELD_TYPE_NULL);
454     assertThat(cursor.getLong(2)).isEqualTo(0);
455 
456     assertThat(cursor.getType(3)).isEqualTo(Cursor.FIELD_TYPE_NULL);
457     assertThat(cursor.getFloat(3)).isEqualTo(0f);
458 
459     assertThat(cursor.getType(4)).isEqualTo(Cursor.FIELD_TYPE_NULL);
460     assertThat(cursor.getDouble(4)).isEqualTo(0d);
461   }
462 
addPeople()463   private void addPeople() throws Exception {
464     String[] inserts = {
465         "INSERT INTO table_name (id, name, long_value, float_value, double_value) VALUES(1234, 'Chuck', 3463, 1.5, 3.14159);",
466         "INSERT INTO table_name (id, name) VALUES(1235, 'Julie');",
467         "INSERT INTO table_name (id, name) VALUES(1236, 'Chris');"
468     };
469 
470     for (String insert : inserts) {
471       database.execSQL(insert);
472     }
473   }
474 
createCursor()475   private Cursor createCursor() throws Exception {
476     String sql ="SELECT * FROM table_name;";
477     Cursor cursor = database.rawQuery(sql, null);
478     assertThat(cursor).isInstanceOf(SQLiteCursor.class);
479     return cursor;
480   }
481 
setupEmptyResult()482   private void setupEmptyResult() throws Exception {
483     database.execSQL("DELETE FROM table_name;");
484     cursor = createCursor();
485   }
486 
assertColumnNames(String[] columnNames)487   private void assertColumnNames(String[] columnNames) {
488     assertThat(columnNames.length).isEqualTo(7);
489     assertThat(columnNames[0]).isEqualTo("id");
490     assertThat(columnNames[1]).isEqualTo("name");
491     assertThat(columnNames[2]).isEqualTo("long_value");
492     assertThat(columnNames[3]).isEqualTo("float_value");
493     assertThat(columnNames[4]).isEqualTo("double_value");
494     assertThat(columnNames[5]).isEqualTo("blob_value");
495     assertThat(columnNames[6]).isEqualTo("clob_value");
496   }
497 }
498