blob: 828045a829c59a99031117f0298b81b8dee183f7 [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.database.sqlite.cts;
import dalvik.annotation.TestLevel;
import dalvik.annotation.TestTargetClass;
import dalvik.annotation.TestTargetNew;
import dalvik.annotation.TestTargets;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDoneException;
import android.database.sqlite.SQLiteStatement;
import android.os.ParcelFileDescriptor;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
import java.io.IOException;
import java.io.InputStream;
@TestTargetClass(android.database.sqlite.SQLiteStatement.class)
public class SQLiteStatementTest extends AndroidTestCase {
private static final String STRING1 = "this is a test";
private static final String STRING2 = "another test";
private static final byte[][] BLOBS = new byte [][] {
parseBlob("86FADCF1A820666AEBD0789F47932151A2EF734269E8AC4E39630AB60519DFD8"),
new byte[0],
null,
parseBlob("00"),
parseBlob("FF"),
parseBlob("D7B500FECF25F7A4D83BF823D3858690790F2526013DE6CAE9A69170E2A1E47238"),
};
private static final String DATABASE_NAME = "database_test.db";
private static final int CURRENT_DATABASE_VERSION = 42;
private SQLiteDatabase mDatabase;
@Override
protected void setUp() throws Exception {
super.setUp();
getContext().deleteDatabase(DATABASE_NAME);
mDatabase = getContext().openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null);
assertNotNull(mDatabase);
mDatabase.setVersion(CURRENT_DATABASE_VERSION);
}
@Override
protected void tearDown() throws Exception {
mDatabase.close();
getContext().deleteDatabase(DATABASE_NAME);
super.tearDown();
}
private void populateDefaultTable() {
mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
}
private void populateBlobTable() {
mDatabase.execSQL("CREATE TABLE blob_test (_id INTEGER PRIMARY KEY, data BLOB)");
for (int i = 0; i < BLOBS.length; i++) {
ContentValues values = new ContentValues();
values.put("_id", i);
values.put("data", BLOBS[i]);
mDatabase.insert("blob_test", null, values);
}
}
@TestTargetNew(
level = TestLevel.COMPLETE,
method = "executeUpdateDelete",
args = {}
)
public void testExecute() {
mDatabase.disableWriteAheadLogging();
populateDefaultTable();
assertEquals(0, DatabaseUtils.longForQuery(mDatabase, "select count(*) from test", null));
// test update
// insert 2 rows and then update them.
SQLiteStatement statement1 = mDatabase.compileStatement(
"INSERT INTO test (data) VALUES ('" + STRING2 + "')");
assertEquals(1, statement1.executeInsert());
assertEquals(2, statement1.executeInsert());
SQLiteStatement statement2 =
mDatabase.compileStatement("UPDATE test set data = 'a' WHERE _id > 0");
assertEquals(2, statement2.executeUpdateDelete());
statement2.close();
// should still have 2 rows in the table
assertEquals(2, DatabaseUtils.longForQuery(mDatabase, "select count(*) from test", null));
// test delete
// insert 2 more rows and delete 3 of them
assertEquals(3, statement1.executeInsert());
assertEquals(4, statement1.executeInsert());
statement1.close();
statement2 = mDatabase.compileStatement("DELETE from test WHERE _id < 4");
assertEquals(3, statement2.executeUpdateDelete());
statement2.close();
// should still have 1 row1 in the table
assertEquals(1, DatabaseUtils.longForQuery(mDatabase, "select count(*) from test", null));
// if the SQL statement is something that causes rows of data to
// be returned, executeUpdateDelete() (and execute()) throw an exception.
statement2 = mDatabase.compileStatement("SELECT count(*) FROM test");
try {
statement2.executeUpdateDelete();
fail("exception expected");
} catch (SQLException e) {
// expected
} finally {
statement2.close();
}
}
@TestTargets({
@TestTargetNew(
level = TestLevel.COMPLETE,
method = "executeInsert",
args = {}
),
@TestTargetNew(
level = TestLevel.COMPLETE,
method = "execute",
args = {}
)
})
public void testExecuteInsert() {
populateDefaultTable();
Cursor c = mDatabase.query("test", null, null, null, null, null, null);
assertEquals(0, c.getCount());
// test insert
SQLiteStatement statement = mDatabase.compileStatement(
"INSERT INTO test (data) VALUES ('" + STRING2 + "')");
assertEquals(1, statement.executeInsert());
statement.close();
// try to insert another row with the same id. last inserted rowid should be -1
statement = mDatabase.compileStatement("insert or ignore into test values(1, 1);");
assertEquals(-1, statement.executeInsert());
statement.close();
c = mDatabase.query("test", null, null, null, null, null, null);
assertEquals(1, c.getCount());
c.moveToFirst();
assertEquals(STRING2, c.getString(c.getColumnIndex("data")));
c.close();
// if the sql statement is something that causes rows of data to
// be returned, executeInsert() throws an exception
statement = mDatabase.compileStatement(
"SELECT * FROM test WHERE data=\"" + STRING2 + "\"");
try {
statement.executeInsert();
fail("exception expected");
} catch (SQLException e) {
// expected
} finally {
statement.close();
}
}
@TestTargetNew(
level = TestLevel.COMPLETE,
method = "simpleQueryForLong",
args = {}
)
public void testSimpleQueryForLong() {
mDatabase.execSQL("CREATE TABLE test (num INTEGER NOT NULL, str TEXT NOT NULL);");
mDatabase.execSQL("INSERT INTO test VALUES (1234, 'hello');");
SQLiteStatement statement =
mDatabase.compileStatement("SELECT num FROM test WHERE str = ?");
// test query long
statement.bindString(1, "hello");
long value = statement.simpleQueryForLong();
assertEquals(1234, value);
// test query returns zero rows
statement.bindString(1, "world");
try {
statement.simpleQueryForLong();
fail("There should be a SQLiteDoneException thrown out.");
} catch (SQLiteDoneException e) {
// expected.
}
statement.close();
}
@TestTargetNew(
level = TestLevel.COMPLETE,
method = "simpleQueryForString",
args = {}
)
public void testSimpleQueryForString() {
mDatabase.execSQL("CREATE TABLE test (num INTEGER NOT NULL, str TEXT NOT NULL);");
mDatabase.execSQL("INSERT INTO test VALUES (1234, 'hello');");
SQLiteStatement statement =
mDatabase.compileStatement("SELECT str FROM test WHERE num = ?");
// test query String
statement.bindLong(1, 1234);
String value = statement.simpleQueryForString();
assertEquals("hello", value);
// test query returns zero rows
statement.bindLong(1, 5678);
try {
statement.simpleQueryForString();
fail("There should be a SQLiteDoneException thrown out.");
} catch (SQLiteDoneException e) {
// expected.
}
statement.close();
}
@TestTargetNew(
level = TestLevel.PARTIAL_COMPLETE,
method = "simpleQueryForBlobFileDescriptor",
args = {}
)
public void testSimpleQueryForBlobFileDescriptorSuccessNormal() throws IOException {
doTestSimpleQueryForBlobFileDescriptorSuccess(0);
}
@TestTargetNew(
level = TestLevel.PARTIAL_COMPLETE,
method = "simpleQueryForBlobFileDescriptor",
args = {}
)
public void testSimpleQueryForBlobFileDescriptorSuccessEmpty() throws IOException {
doTestSimpleQueryForBlobFileDescriptorSuccess(1);
}
@TestTargetNew(
level = TestLevel.PARTIAL_COMPLETE,
method = "simpleQueryForBlobFileDescriptor",
args = {}
)
public void testSimpleQueryForBlobFileDescriptorSuccessNull() {
populateBlobTable();
String sql = "SELECT data FROM blob_test WHERE _id = " + 2;
SQLiteStatement stm = mDatabase.compileStatement(sql);
assertNull(stm.simpleQueryForBlobFileDescriptor());
}
@TestTargetNew(
level = TestLevel.PARTIAL_COMPLETE,
method = "simpleQueryForBlobFileDescriptor",
args = {}
)
public void testSimpleQueryForBlobFileDescriptorSuccess00() throws IOException {
doTestSimpleQueryForBlobFileDescriptorSuccess(3);
}
@TestTargetNew(
level = TestLevel.PARTIAL_COMPLETE,
method = "simpleQueryForBlobFileDescriptor",
args = {}
)
public void testSimpleQueryForBlobFileDescriptorSuccessFF() throws IOException {
doTestSimpleQueryForBlobFileDescriptorSuccess(4);
}
@TestTargetNew(
level = TestLevel.PARTIAL_COMPLETE,
method = "simpleQueryForBlobFileDescriptor",
args = {}
)
public void testSimpleQueryForBlobFileDescriptorSuccessEmbeddedNul() throws IOException {
doTestSimpleQueryForBlobFileDescriptorSuccess(5);
}
private void doTestSimpleQueryForBlobFileDescriptorSuccess(int i) throws IOException {
populateBlobTable();
String sql = "SELECT data FROM blob_test WHERE _id = " + i;
SQLiteStatement stm = mDatabase.compileStatement(sql);
ParcelFileDescriptor fd = stm.simpleQueryForBlobFileDescriptor();
assertFileDescriptorContent(BLOBS[i], fd);
}
@TestTargetNew(
level = TestLevel.PARTIAL_COMPLETE,
method = "simpleQueryForBlobFileDescriptor",
args = {}
)
public void testSimpleQueryForBlobFileDescriptorSuccessParam() throws IOException {
populateBlobTable();
String sql = "SELECT data FROM blob_test WHERE _id = ?";
SQLiteStatement stm = mDatabase.compileStatement(sql);
stm.bindLong(1, 0);
ParcelFileDescriptor fd = stm.simpleQueryForBlobFileDescriptor();
assertFileDescriptorContent(BLOBS[0], fd);
}
@TestTargetNew(
level = TestLevel.PARTIAL_COMPLETE,
method = "simpleQueryForBlobFileDescriptor",
args = {}
)
public void testGetBlobFailureNoParam() throws Exception {
populateBlobTable();
String sql = "SELECT data FROM blob_test WHERE _id = 100";
SQLiteStatement stm = mDatabase.compileStatement(sql);
ParcelFileDescriptor fd = null;
SQLiteDoneException expectedException = null;
try {
fd = stm.simpleQueryForBlobFileDescriptor();
} catch (SQLiteDoneException ex) {
expectedException = ex;
} finally {
if (fd != null) {
fd.close();
fd = null;
}
}
assertNotNull("Should have thrown SQLiteDoneException", expectedException);
}
@TestTargetNew(
level = TestLevel.PARTIAL_COMPLETE,
method = "simpleQueryForBlobFileDescriptor",
args = {}
)
public void testGetBlobFailureParam() throws Exception {
populateBlobTable();
String sql = "SELECT data FROM blob_test WHERE _id = ?";
SQLiteStatement stm = mDatabase.compileStatement(sql);
stm.bindLong(1, 100);
ParcelFileDescriptor fd = null;
SQLiteDoneException expectedException = null;
try {
fd = stm.simpleQueryForBlobFileDescriptor();
} catch (SQLiteDoneException ex) {
expectedException = ex;
} finally {
if (fd != null) {
fd.close();
fd = null;
}
}
assertNotNull("Should have thrown SQLiteDoneException", expectedException);
}
/*
* Convert string of hex digits to byte array.
* Results are undefined for poorly formed string.
*
* @param src hex string
*/
private static byte[] parseBlob(String src) {
int len = src.length();
byte[] result = new byte[len / 2];
for (int i = 0; i < len/2; i++) {
int val;
char c1 = src.charAt(i*2);
char c2 = src.charAt(i*2+1);
int val1 = Character.digit(c1, 16);
int val2 = Character.digit(c2, 16);
val = (val1 << 4) | val2;
result[i] = (byte)val;
}
return result;
}
private static void assertFileDescriptorContent(byte[] expected, ParcelFileDescriptor fd)
throws IOException {
assertInputStreamContent(expected, new ParcelFileDescriptor.AutoCloseInputStream(fd));
}
private static void assertInputStreamContent(byte[] expected, InputStream is)
throws IOException {
try {
byte[] observed = new byte[expected.length];
int count = is.read(observed);
assertEquals(expected.length, count);
assertEquals(-1, is.read());
MoreAsserts.assertEquals(expected, observed);
} finally {
is.close();
}
}
}