Merge pull request #837 from gwenn/test_result

Make tests return Result
This commit is contained in:
gwenn 2020-11-06 20:30:50 +01:00 committed by GitHub
commit a376ae4895
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1040 additions and 1179 deletions

View File

@ -310,96 +310,84 @@ impl Drop for Backup<'_, '_> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::Backup; use super::Backup;
use crate::{Connection, DatabaseName}; use crate::{Connection, DatabaseName, Result};
use std::time::Duration; use std::time::Duration;
#[test] #[test]
fn test_backup() { fn test_backup() -> Result<()> {
let src = Connection::open_in_memory().unwrap(); let src = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER);
INSERT INTO foo VALUES(42); INSERT INTO foo VALUES(42);
END;"; END;";
src.execute_batch(sql).unwrap(); src.execute_batch(sql)?;
let mut dst = Connection::open_in_memory().unwrap(); let mut dst = Connection::open_in_memory()?;
{ {
let backup = Backup::new(&src, &mut dst).unwrap(); let backup = Backup::new(&src, &mut dst)?;
backup.step(-1).unwrap(); backup.step(-1)?;
} }
let the_answer: i64 = dst let the_answer: i64 = dst.query_row("SELECT x FROM foo", [], |r| r.get(0))?;
.query_row("SELECT x FROM foo", [], |r| r.get(0))
.unwrap();
assert_eq!(42, the_answer); assert_eq!(42, the_answer);
src.execute_batch("INSERT INTO foo VALUES(43)").unwrap(); src.execute_batch("INSERT INTO foo VALUES(43)")?;
{ {
let backup = Backup::new(&src, &mut dst).unwrap(); let backup = Backup::new(&src, &mut dst)?;
backup backup.run_to_completion(5, Duration::from_millis(250), None)?;
.run_to_completion(5, Duration::from_millis(250), None)
.unwrap();
} }
let the_answer: i64 = dst let the_answer: i64 = dst.query_row("SELECT SUM(x) FROM foo", [], |r| r.get(0))?;
.query_row("SELECT SUM(x) FROM foo", [], |r| r.get(0))
.unwrap();
assert_eq!(42 + 43, the_answer); assert_eq!(42 + 43, the_answer);
Ok(())
} }
#[test] #[test]
fn test_backup_temp() { fn test_backup_temp() -> Result<()> {
let src = Connection::open_in_memory().unwrap(); let src = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TEMPORARY TABLE foo(x INTEGER); CREATE TEMPORARY TABLE foo(x INTEGER);
INSERT INTO foo VALUES(42); INSERT INTO foo VALUES(42);
END;"; END;";
src.execute_batch(sql).unwrap(); src.execute_batch(sql)?;
let mut dst = Connection::open_in_memory().unwrap(); let mut dst = Connection::open_in_memory()?;
{ {
let backup = let backup =
Backup::new_with_names(&src, DatabaseName::Temp, &mut dst, DatabaseName::Main) Backup::new_with_names(&src, DatabaseName::Temp, &mut dst, DatabaseName::Main)?;
.unwrap(); backup.step(-1)?;
backup.step(-1).unwrap();
} }
let the_answer: i64 = dst let the_answer: i64 = dst.query_row("SELECT x FROM foo", [], |r| r.get(0))?;
.query_row("SELECT x FROM foo", [], |r| r.get(0))
.unwrap();
assert_eq!(42, the_answer); assert_eq!(42, the_answer);
src.execute_batch("INSERT INTO foo VALUES(43)").unwrap(); src.execute_batch("INSERT INTO foo VALUES(43)")?;
{ {
let backup = let backup =
Backup::new_with_names(&src, DatabaseName::Temp, &mut dst, DatabaseName::Main) Backup::new_with_names(&src, DatabaseName::Temp, &mut dst, DatabaseName::Main)?;
.unwrap(); backup.run_to_completion(5, Duration::from_millis(250), None)?;
backup
.run_to_completion(5, Duration::from_millis(250), None)
.unwrap();
} }
let the_answer: i64 = dst let the_answer: i64 = dst.query_row("SELECT SUM(x) FROM foo", [], |r| r.get(0))?;
.query_row("SELECT SUM(x) FROM foo", [], |r| r.get(0))
.unwrap();
assert_eq!(42 + 43, the_answer); assert_eq!(42 + 43, the_answer);
Ok(())
} }
#[test] #[test]
fn test_backup_attached() { fn test_backup_attached() -> Result<()> {
let src = Connection::open_in_memory().unwrap(); let src = Connection::open_in_memory()?;
let sql = "ATTACH DATABASE ':memory:' AS my_attached; let sql = "ATTACH DATABASE ':memory:' AS my_attached;
BEGIN; BEGIN;
CREATE TABLE my_attached.foo(x INTEGER); CREATE TABLE my_attached.foo(x INTEGER);
INSERT INTO my_attached.foo VALUES(42); INSERT INTO my_attached.foo VALUES(42);
END;"; END;";
src.execute_batch(sql).unwrap(); src.execute_batch(sql)?;
let mut dst = Connection::open_in_memory().unwrap(); let mut dst = Connection::open_in_memory()?;
{ {
let backup = Backup::new_with_names( let backup = Backup::new_with_names(
@ -407,17 +395,14 @@ mod test {
DatabaseName::Attached("my_attached"), DatabaseName::Attached("my_attached"),
&mut dst, &mut dst,
DatabaseName::Main, DatabaseName::Main,
) )?;
.unwrap(); backup.step(-1)?;
backup.step(-1).unwrap();
} }
let the_answer: i64 = dst let the_answer: i64 = dst.query_row("SELECT x FROM foo", [], |r| r.get(0))?;
.query_row("SELECT x FROM foo", [], |r| r.get(0))
.unwrap();
assert_eq!(42, the_answer); assert_eq!(42, the_answer);
src.execute_batch("INSERT INTO foo VALUES(43)").unwrap(); src.execute_batch("INSERT INTO foo VALUES(43)")?;
{ {
let backup = Backup::new_with_names( let backup = Backup::new_with_names(
@ -425,16 +410,12 @@ mod test {
DatabaseName::Attached("my_attached"), DatabaseName::Attached("my_attached"),
&mut dst, &mut dst,
DatabaseName::Main, DatabaseName::Main,
) )?;
.unwrap(); backup.run_to_completion(5, Duration::from_millis(250), None)?;
backup
.run_to_completion(5, Duration::from_millis(250), None)
.unwrap();
} }
let the_answer: i64 = dst let the_answer: i64 = dst.query_row("SELECT SUM(x) FROM foo", [], |r| r.get(0))?;
.query_row("SELECT SUM(x) FROM foo", [], |r| r.get(0))
.unwrap();
assert_eq!(42 + 43, the_answer); assert_eq!(42 + 43, the_answer);
Ok(())
} }
} }

View File

@ -434,22 +434,18 @@ mod test {
} }
#[test] #[test]
fn test_blob() { fn test_blob() -> Result<()> {
let (db, rowid) = db_with_test_blob().unwrap(); let (db, rowid) = db_with_test_blob()?;
let mut blob = db let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false)?;
.blob_open(DatabaseName::Main, "test", "content", rowid, false)
.unwrap();
assert_eq!(4, blob.write(b"Clob").unwrap()); assert_eq!(4, blob.write(b"Clob").unwrap());
assert_eq!(6, blob.write(b"567890xxxxxx").unwrap()); // cannot write past 10 assert_eq!(6, blob.write(b"567890xxxxxx").unwrap()); // cannot write past 10
assert_eq!(0, blob.write(b"5678").unwrap()); // still cannot write past 10 assert_eq!(0, blob.write(b"5678").unwrap()); // still cannot write past 10
blob.reopen(rowid).unwrap(); blob.reopen(rowid)?;
blob.close().unwrap(); blob.close()?;
blob = db blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true)?;
.blob_open(DatabaseName::Main, "test", "content", rowid, true)
.unwrap();
let mut bytes = [0u8; 5]; let mut bytes = [0u8; 5];
assert_eq!(5, blob.read(&mut bytes[..]).unwrap()); assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
assert_eq!(&bytes, b"Clob5"); assert_eq!(&bytes, b"Clob5");
@ -470,7 +466,7 @@ mod test {
assert_eq!(5, blob.read(&mut bytes[..]).unwrap()); assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
assert_eq!(&bytes, b"56789"); assert_eq!(&bytes, b"56789");
blob.reopen(rowid).unwrap(); blob.reopen(rowid)?;
assert_eq!(5, blob.read(&mut bytes[..]).unwrap()); assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
assert_eq!(&bytes, b"Clob5"); assert_eq!(&bytes, b"Clob5");
@ -481,20 +477,19 @@ mod test {
// write_all should detect when we return Ok(0) because there is no space left, // write_all should detect when we return Ok(0) because there is no space left,
// and return a write error // and return a write error
blob.reopen(rowid).unwrap(); blob.reopen(rowid)?;
assert!(blob.write_all(b"0123456789x").is_err()); assert!(blob.write_all(b"0123456789x").is_err());
Ok(())
} }
#[test] #[test]
fn test_blob_in_bufreader() { fn test_blob_in_bufreader() -> Result<()> {
let (db, rowid) = db_with_test_blob().unwrap(); let (db, rowid) = db_with_test_blob()?;
let mut blob = db let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false)?;
.blob_open(DatabaseName::Main, "test", "content", rowid, false)
.unwrap();
assert_eq!(8, blob.write(b"one\ntwo\n").unwrap()); assert_eq!(8, blob.write(b"one\ntwo\n").unwrap());
blob.reopen(rowid).unwrap(); blob.reopen(rowid)?;
let mut reader = BufReader::new(blob); let mut reader = BufReader::new(blob);
let mut line = String::new(); let mut line = String::new();
@ -508,16 +503,15 @@ mod test {
line.truncate(0); line.truncate(0);
assert_eq!(2, reader.read_line(&mut line).unwrap()); assert_eq!(2, reader.read_line(&mut line).unwrap());
assert_eq!("\0\0", line); assert_eq!("\0\0", line);
Ok(())
} }
#[test] #[test]
fn test_blob_in_bufwriter() { fn test_blob_in_bufwriter() -> Result<()> {
let (db, rowid) = db_with_test_blob().unwrap(); let (db, rowid) = db_with_test_blob()?;
{ {
let blob = db let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false)?;
.blob_open(DatabaseName::Main, "test", "content", rowid, false)
.unwrap();
let mut writer = BufWriter::new(blob); let mut writer = BufWriter::new(blob);
// trying to write too much and then flush should fail // trying to write too much and then flush should fail
@ -528,18 +522,14 @@ mod test {
{ {
// ... but it should've written the first 10 bytes // ... but it should've written the first 10 bytes
let mut blob = db let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false)?;
.blob_open(DatabaseName::Main, "test", "content", rowid, false)
.unwrap();
let mut bytes = [0u8; 10]; let mut bytes = [0u8; 10];
assert_eq!(10, blob.read(&mut bytes[..]).unwrap()); assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
assert_eq!(b"0123456701", &bytes); assert_eq!(b"0123456701", &bytes);
} }
{ {
let blob = db let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false)?;
.blob_open(DatabaseName::Main, "test", "content", rowid, false)
.unwrap();
let mut writer = BufWriter::new(blob); let mut writer = BufWriter::new(blob);
// trying to write_all too much should fail // trying to write_all too much should fail
@ -549,12 +539,11 @@ mod test {
{ {
// ... but it should've written the first 10 bytes // ... but it should've written the first 10 bytes
let mut blob = db let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false)?;
.blob_open(DatabaseName::Main, "test", "content", rowid, false)
.unwrap();
let mut bytes = [0u8; 10]; let mut bytes = [0u8; 10];
assert_eq!(10, blob.read(&mut bytes[..]).unwrap()); assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
assert_eq!(b"aaaaaaaaaa", &bytes); assert_eq!(b"aaaaaaaaaa", &bytes);
Ok(())
} }
} }
} }

View File

@ -194,22 +194,18 @@ impl<'conn> Blob<'conn> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::{Connection, DatabaseName}; use crate::{Connection, DatabaseName, Result};
// to ensure we don't modify seek pos // to ensure we don't modify seek pos
use std::io::Seek as _; use std::io::Seek as _;
#[test] #[test]
fn test_pos_io() { fn test_pos_io() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE test_table(content BLOB);") db.execute_batch("CREATE TABLE test_table(content BLOB);")?;
.unwrap(); db.execute("INSERT INTO test_table(content) VALUES (ZEROBLOB(10))", [])?;
db.execute("INSERT INTO test_table(content) VALUES (ZEROBLOB(10))", [])
.unwrap();
let rowid = db.last_insert_rowid(); let rowid = db.last_insert_rowid();
let mut blob = db let mut blob = db.blob_open(DatabaseName::Main, "test_table", "content", rowid, false)?;
.blob_open(DatabaseName::Main, "test_table", "content", rowid, false)
.unwrap();
// modify the seek pos to ensure we aren't using it or modifying it. // modify the seek pos to ensure we aren't using it or modifying it.
blob.seek(std::io::SeekFrom::Start(1)).unwrap(); blob.seek(std::io::SeekFrom::Start(1)).unwrap();
@ -274,5 +270,6 @@ mod test {
let end_pos = blob.seek(std::io::SeekFrom::Current(0)).unwrap(); let end_pos = blob.seek(std::io::SeekFrom::Current(0)).unwrap();
assert_eq!(end_pos, 1); assert_eq!(end_pos, 1);
Ok(())
} }
} }

View File

@ -86,15 +86,13 @@ mod test {
use crate::{Connection, Error, ErrorCode, Result, TransactionBehavior}; use crate::{Connection, Error, ErrorCode, Result, TransactionBehavior};
#[test] #[test]
fn test_default_busy() { fn test_default_busy() -> Result<()> {
let temp_dir = tempfile::tempdir().unwrap(); let temp_dir = tempfile::tempdir().unwrap();
let path = temp_dir.path().join("test.db3"); let path = temp_dir.path().join("test.db3");
let mut db1 = Connection::open(&path).unwrap(); let mut db1 = Connection::open(&path)?;
let tx1 = db1 let tx1 = db1.transaction_with_behavior(TransactionBehavior::Exclusive)?;
.transaction_with_behavior(TransactionBehavior::Exclusive) let db2 = Connection::open(&path)?;
.unwrap();
let db2 = Connection::open(&path).unwrap();
let r: Result<()> = db2.query_row("PRAGMA schema_version", [], |_| unreachable!()); let r: Result<()> = db2.query_row("PRAGMA schema_version", [], |_| unreachable!());
match r.unwrap_err() { match r.unwrap_err() {
Error::SqliteFailure(err, _) => { Error::SqliteFailure(err, _) => {
@ -102,7 +100,7 @@ mod test {
} }
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {}", err),
} }
tx1.rollback().unwrap(); tx1.rollback()
} }
#[test] #[test]

View File

@ -175,7 +175,7 @@ impl StatementCache {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::StatementCache; use super::StatementCache;
use crate::Connection; use crate::{Connection, Result};
use fallible_iterator::FallibleIterator; use fallible_iterator::FallibleIterator;
impl StatementCache { impl StatementCache {
@ -193,8 +193,8 @@ mod test {
} }
#[test] #[test]
fn test_cache() { fn test_cache() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let cache = &db.cache; let cache = &db.cache;
let initial_capacity = cache.capacity(); let initial_capacity = cache.capacity();
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
@ -202,34 +202,35 @@ mod test {
let sql = "PRAGMA schema_version"; let sql = "PRAGMA schema_version";
{ {
let mut stmt = db.prepare_cached(sql).unwrap(); let mut stmt = db.prepare_cached(sql)?;
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0)).unwrap()); assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
} }
assert_eq!(1, cache.len()); assert_eq!(1, cache.len());
{ {
let mut stmt = db.prepare_cached(sql).unwrap(); let mut stmt = db.prepare_cached(sql)?;
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0)).unwrap()); assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
} }
assert_eq!(1, cache.len()); assert_eq!(1, cache.len());
cache.clear(); cache.clear();
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
assert_eq!(initial_capacity, cache.capacity()); assert_eq!(initial_capacity, cache.capacity());
Ok(())
} }
#[test] #[test]
fn test_set_capacity() { fn test_set_capacity() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let cache = &db.cache; let cache = &db.cache;
let sql = "PRAGMA schema_version"; let sql = "PRAGMA schema_version";
{ {
let mut stmt = db.prepare_cached(sql).unwrap(); let mut stmt = db.prepare_cached(sql)?;
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0)).unwrap()); assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
} }
assert_eq!(1, cache.len()); assert_eq!(1, cache.len());
@ -237,55 +238,53 @@ mod test {
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
{ {
let mut stmt = db.prepare_cached(sql).unwrap(); let mut stmt = db.prepare_cached(sql)?;
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0)).unwrap()); assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
} }
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
db.set_prepared_statement_cache_capacity(8); db.set_prepared_statement_cache_capacity(8);
{ {
let mut stmt = db.prepare_cached(sql).unwrap(); let mut stmt = db.prepare_cached(sql)?;
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0)).unwrap()); assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
} }
assert_eq!(1, cache.len()); assert_eq!(1, cache.len());
Ok(())
} }
#[test] #[test]
fn test_discard() { fn test_discard() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let cache = &db.cache; let cache = &db.cache;
let sql = "PRAGMA schema_version"; let sql = "PRAGMA schema_version";
{ {
let mut stmt = db.prepare_cached(sql).unwrap(); let mut stmt = db.prepare_cached(sql)?;
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0)).unwrap()); assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
stmt.discard(); stmt.discard();
} }
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
Ok(())
} }
#[test] #[test]
fn test_ddl() { fn test_ddl() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch( db.execute_batch(
r#" r#"
CREATE TABLE foo (x INT); CREATE TABLE foo (x INT);
INSERT INTO foo VALUES (1); INSERT INTO foo VALUES (1);
"#, "#,
) )?;
.unwrap();
let sql = "SELECT * FROM foo"; let sql = "SELECT * FROM foo";
{ {
let mut stmt = db.prepare_cached(sql).unwrap(); let mut stmt = db.prepare_cached(sql)?;
assert_eq!( assert_eq!(Ok(Some(1i32)), stmt.query([])?.map(|r| r.get(0)).next());
Ok(Some(1i32)),
stmt.query([]).unwrap().map(|r| r.get(0)).next()
);
} }
db.execute_batch( db.execute_batch(
@ -293,55 +292,55 @@ mod test {
ALTER TABLE foo ADD COLUMN y INT; ALTER TABLE foo ADD COLUMN y INT;
UPDATE foo SET y = 2; UPDATE foo SET y = 2;
"#, "#,
) )?;
.unwrap();
{ {
let mut stmt = db.prepare_cached(sql).unwrap(); let mut stmt = db.prepare_cached(sql)?;
assert_eq!( assert_eq!(
Ok(Some((1i32, 2i32))), Ok(Some((1i32, 2i32))),
stmt.query([]) stmt.query([])?.map(|r| Ok((r.get(0)?, r.get(1)?))).next()
.unwrap()
.map(|r| Ok((r.get(0)?, r.get(1)?)))
.next()
); );
} }
Ok(())
} }
#[test] #[test]
fn test_connection_close() { fn test_connection_close() -> Result<()> {
let conn = Connection::open_in_memory().unwrap(); let conn = Connection::open_in_memory()?;
conn.prepare_cached("SELECT * FROM sqlite_master;").unwrap(); conn.prepare_cached("SELECT * FROM sqlite_master;")?;
conn.close().expect("connection not closed"); conn.close().expect("connection not closed");
Ok(())
} }
#[test] #[test]
fn test_cache_key() { fn test_cache_key() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let cache = &db.cache; let cache = &db.cache;
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
//let sql = " PRAGMA schema_version; -- comment"; //let sql = " PRAGMA schema_version; -- comment";
let sql = "PRAGMA schema_version; "; let sql = "PRAGMA schema_version; ";
{ {
let mut stmt = db.prepare_cached(sql).unwrap(); let mut stmt = db.prepare_cached(sql)?;
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0)).unwrap()); assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
} }
assert_eq!(1, cache.len()); assert_eq!(1, cache.len());
{ {
let mut stmt = db.prepare_cached(sql).unwrap(); let mut stmt = db.prepare_cached(sql)?;
assert_eq!(0, cache.len()); assert_eq!(0, cache.len());
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0)).unwrap()); assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
} }
assert_eq!(1, cache.len()); assert_eq!(1, cache.len());
Ok(())
} }
#[test] #[test]
fn test_empty_stmt() { fn test_empty_stmt() -> Result<()> {
let conn = Connection::open_in_memory().unwrap(); let conn = Connection::open_in_memory()?;
conn.prepare_cached("").unwrap(); conn.prepare_cached("")?;
Ok(())
} }
} }

View File

@ -171,26 +171,24 @@ mod test {
} }
#[test] #[test]
fn test_unicase() { fn test_unicase() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.create_collation("unicase", unicase_compare).unwrap(); db.create_collation("unicase", unicase_compare)?;
collate(db); collate(db)
} }
fn collate(db: Connection) { fn collate(db: Connection) -> Result<()> {
db.execute_batch( db.execute_batch(
"CREATE TABLE foo (bar); "CREATE TABLE foo (bar);
INSERT INTO foo (bar) VALUES ('Maße'); INSERT INTO foo (bar) VALUES ('Maße');
INSERT INTO foo (bar) VALUES ('MASSE');", INSERT INTO foo (bar) VALUES ('MASSE');",
) )?;
.unwrap(); let mut stmt = db.prepare("SELECT DISTINCT bar COLLATE unicase FROM foo ORDER BY 1")?;
let mut stmt = db let rows = stmt.query([])?;
.prepare("SELECT DISTINCT bar COLLATE unicase FROM foo ORDER BY 1") assert_eq!(rows.count()?, 1);
.unwrap(); Ok(())
let rows = stmt.query([]).unwrap();
assert_eq!(rows.count().unwrap(), 1);
} }
fn collation_needed(db: &Connection, collation_name: &str) -> Result<()> { fn collation_needed(db: &Connection, collation_name: &str) -> Result<()> {
@ -202,9 +200,9 @@ mod test {
} }
#[test] #[test]
fn test_collation_needed() { fn test_collation_needed() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.collation_needed(collation_needed).unwrap(); db.collation_needed(collation_needed)?;
collate(db); collate(db)
} }
} }

View File

@ -176,15 +176,15 @@ impl<'stmt> Row<'stmt> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::Connection; use crate::{Connection, Result};
#[test] #[test]
#[cfg(feature = "column_decltype")] #[cfg(feature = "column_decltype")]
fn test_columns() { fn test_columns() -> Result<()> {
use super::Column; use super::Column;
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let query = db.prepare("SELECT * FROM sqlite_master").unwrap(); let query = db.prepare("SELECT * FROM sqlite_master")?;
let columns = query.columns(); let columns = query.columns();
let column_names: Vec<&str> = columns.iter().map(Column::name).collect(); let column_names: Vec<&str> = columns.iter().map(Column::name).collect();
assert_eq!( assert_eq!(
@ -196,22 +196,22 @@ mod test {
&column_types[..3], &column_types[..3],
&[Some("text"), Some("text"), Some("text"),] &[Some("text"), Some("text"), Some("text"),]
); );
Ok(())
} }
#[test] #[test]
fn test_column_name_in_error() { fn test_column_name_in_error() -> Result<()> {
use crate::{types::Type, Error}; use crate::{types::Type, Error};
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch( db.execute_batch(
"BEGIN; "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, NULL); INSERT INTO foo VALUES(4, NULL);
END;", END;",
) )?;
.unwrap(); let mut stmt = db.prepare("SELECT x as renamed, y FROM foo")?;
let mut stmt = db.prepare("SELECT x as renamed, y FROM foo").unwrap(); let mut rows = stmt.query([])?;
let mut rows = stmt.query([]).unwrap(); let row = rows.next()?.unwrap();
let row = rows.next().unwrap().unwrap();
match row.get::<_, String>(0).unwrap_err() { match row.get::<_, String>(0).unwrap_err() {
Error::InvalidColumnType(idx, name, ty) => { Error::InvalidColumnType(idx, name, ty) => {
assert_eq!(idx, 0); assert_eq!(idx, 0);
@ -232,5 +232,6 @@ mod test {
panic!("Unexpected error type: {:?}", e); panic!("Unexpected error type: {:?}", e);
} }
} }
Ok(())
} }
} }

View File

@ -122,13 +122,13 @@ impl Connection {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::DbConfig; use super::DbConfig;
use crate::Connection; use crate::{Connection, Result};
#[test] #[test]
fn test_db_config() { fn test_db_config() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let opposite = !db.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_FKEY).unwrap(); let opposite = !db.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_FKEY)?;
assert_eq!( assert_eq!(
db.set_db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_FKEY, opposite), db.set_db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_FKEY, opposite),
Ok(opposite) Ok(opposite)
@ -138,9 +138,7 @@ mod test {
Ok(opposite) Ok(opposite)
); );
let opposite = !db let opposite = !db.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_TRIGGER)?;
.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_TRIGGER)
.unwrap();
assert_eq!( assert_eq!(
db.set_db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_TRIGGER, opposite), db.set_db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_TRIGGER, opposite),
Ok(opposite) Ok(opposite)
@ -149,5 +147,6 @@ mod test {
db.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_TRIGGER), db.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_TRIGGER),
Ok(opposite) Ok(opposite)
); );
Ok(())
} }
} }

View File

@ -761,36 +761,36 @@ mod test {
} }
#[test] #[test]
fn test_function_half() { fn test_function_half() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.create_scalar_function( db.create_scalar_function(
"half", "half",
1, 1,
FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC, FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC,
half, half,
) )?;
.unwrap();
let result: Result<f64> = db.query_row("SELECT half(6)", [], |r| r.get(0)); let result: Result<f64> = db.query_row("SELECT half(6)", [], |r| r.get(0));
assert!((3f64 - result.unwrap()).abs() < EPSILON); assert!((3f64 - result?).abs() < EPSILON);
Ok(())
} }
#[test] #[test]
fn test_remove_function() { fn test_remove_function() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.create_scalar_function( db.create_scalar_function(
"half", "half",
1, 1,
FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC, FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC,
half, half,
) )?;
.unwrap();
let result: Result<f64> = db.query_row("SELECT half(6)", [], |r| r.get(0)); let result: Result<f64> = db.query_row("SELECT half(6)", [], |r| r.get(0));
assert!((3f64 - result.unwrap()).abs() < EPSILON); assert!((3f64 - result?).abs() < EPSILON);
db.remove_function("half", 1).unwrap(); db.remove_function("half", 1)?;
let result: Result<f64> = db.query_row("SELECT half(6)", [], |r| r.get(0)); let result: Result<f64> = db.query_row("SELECT half(6)", [], |r| r.get(0));
assert!(result.is_err()); assert!(result.is_err());
Ok(())
} }
// This implementation of a regexp scalar function uses SQLite's auxilliary data // This implementation of a regexp scalar function uses SQLite's auxilliary data
@ -817,8 +817,8 @@ mod test {
} }
#[test] #[test]
fn test_function_regexp_with_auxilliary() { fn test_function_regexp_with_auxilliary() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch( db.execute_batch(
"BEGIN; "BEGIN;
CREATE TABLE foo (x string); CREATE TABLE foo (x string);
@ -826,20 +826,18 @@ mod test {
INSERT INTO foo VALUES ('lXsi'); INSERT INTO foo VALUES ('lXsi');
INSERT INTO foo VALUES ('lisX'); INSERT INTO foo VALUES ('lisX');
END;", END;",
) )?;
.unwrap();
db.create_scalar_function( db.create_scalar_function(
"regexp", "regexp",
2, 2,
FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC, FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC,
regexp_with_auxilliary, regexp_with_auxilliary,
) )?;
.unwrap();
let result: Result<bool> = let result: Result<bool> =
db.query_row("SELECT regexp('l.s[aeiouy]', 'lisa')", [], |r| r.get(0)); db.query_row("SELECT regexp('l.s[aeiouy]', 'lisa')", [], |r| r.get(0));
assert_eq!(true, result.unwrap()); assert_eq!(true, result?);
let result: Result<i64> = db.query_row( let result: Result<i64> = db.query_row(
"SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1", "SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1",
@ -847,12 +845,13 @@ mod test {
|r| r.get(0), |r| r.get(0),
); );
assert_eq!(2, result.unwrap()); assert_eq!(2, result?);
Ok(())
} }
#[test] #[test]
fn test_varargs_function() { fn test_varargs_function() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.create_scalar_function( db.create_scalar_function(
"my_concat", "my_concat",
-1, -1,
@ -867,42 +866,40 @@ mod test {
Ok(ret) Ok(ret)
}, },
) )?;
.unwrap();
for &(expected, query) in &[ for &(expected, query) in &[
("", "SELECT my_concat()"), ("", "SELECT my_concat()"),
("onetwo", "SELECT my_concat('one', 'two')"), ("onetwo", "SELECT my_concat('one', 'two')"),
("abc", "SELECT my_concat('a', 'b', 'c')"), ("abc", "SELECT my_concat('a', 'b', 'c')"),
] { ] {
let result: String = db.query_row(query, [], |r| r.get(0)).unwrap(); let result: String = db.query_row(query, [], |r| r.get(0))?;
assert_eq!(expected, result); assert_eq!(expected, result);
} }
Ok(())
} }
#[test] #[test]
fn test_get_aux_type_checking() { fn test_get_aux_type_checking() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.create_scalar_function("example", 2, FunctionFlags::default(), |ctx| { db.create_scalar_function("example", 2, FunctionFlags::default(), |ctx| {
if !ctx.get::<bool>(1)? { if !ctx.get::<bool>(1)? {
ctx.set_aux::<i64>(0, 100)?; ctx.set_aux::<i64>(0, 100)?;
} else { } else {
assert_eq!(ctx.get_aux::<String>(0), Err(Error::GetAuxWrongType)); assert_eq!(ctx.get_aux::<String>(0), Err(Error::GetAuxWrongType));
assert_eq!(*ctx.get_aux::<i64>(0).unwrap().unwrap(), 100); assert_eq!(*ctx.get_aux::<i64>(0)?.unwrap(), 100);
} }
Ok(true) Ok(true)
}) })?;
.unwrap();
let res: bool = db let res: bool = db.query_row(
.query_row( "SELECT example(0, i) FROM (SELECT 0 as i UNION SELECT 1)",
"SELECT example(0, i) FROM (SELECT 0 as i UNION SELECT 1)", [],
[], |r| r.get(0),
|r| r.get(0), )?;
)
.unwrap();
// Doesn't actually matter, we'll assert in the function if there's a problem. // Doesn't actually matter, we'll assert in the function if there's a problem.
assert!(res); assert!(res);
Ok(())
} }
struct Sum; struct Sum;
@ -939,52 +936,50 @@ mod test {
} }
#[test] #[test]
fn test_sum() { fn test_sum() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.create_aggregate_function( db.create_aggregate_function(
"my_sum", "my_sum",
1, 1,
FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC, FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC,
Sum, Sum,
) )?;
.unwrap();
// sum should return NULL when given no columns (contrast with count below) // sum should return NULL when given no columns (contrast with count below)
let no_result = "SELECT my_sum(i) FROM (SELECT 2 AS i WHERE 1 <> 1)"; let no_result = "SELECT my_sum(i) FROM (SELECT 2 AS i WHERE 1 <> 1)";
let result: Option<i64> = db.query_row(no_result, [], |r| r.get(0)).unwrap(); let result: Option<i64> = db.query_row(no_result, [], |r| r.get(0))?;
assert!(result.is_none()); assert!(result.is_none());
let single_sum = "SELECT my_sum(i) FROM (SELECT 2 AS i UNION ALL SELECT 2)"; let single_sum = "SELECT my_sum(i) FROM (SELECT 2 AS i UNION ALL SELECT 2)";
let result: i64 = db.query_row(single_sum, [], |r| r.get(0)).unwrap(); let result: i64 = db.query_row(single_sum, [], |r| r.get(0))?;
assert_eq!(4, result); assert_eq!(4, result);
let dual_sum = "SELECT my_sum(i), my_sum(j) FROM (SELECT 2 AS i, 1 AS j UNION ALL SELECT \ let dual_sum = "SELECT my_sum(i), my_sum(j) FROM (SELECT 2 AS i, 1 AS j UNION ALL SELECT \
2, 1)"; 2, 1)";
let result: (i64, i64) = db let result: (i64, i64) = db.query_row(dual_sum, [], |r| Ok((r.get(0)?, r.get(1)?)))?;
.query_row(dual_sum, [], |r| Ok((r.get(0)?, r.get(1)?)))
.unwrap();
assert_eq!((4, 2), result); assert_eq!((4, 2), result);
Ok(())
} }
#[test] #[test]
fn test_count() { fn test_count() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.create_aggregate_function( db.create_aggregate_function(
"my_count", "my_count",
-1, -1,
FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC, FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC,
Count, Count,
) )?;
.unwrap();
// count should return 0 when given no columns (contrast with sum above) // count should return 0 when given no columns (contrast with sum above)
let no_result = "SELECT my_count(i) FROM (SELECT 2 AS i WHERE 1 <> 1)"; let no_result = "SELECT my_count(i) FROM (SELECT 2 AS i WHERE 1 <> 1)";
let result: i64 = db.query_row(no_result, [], |r| r.get(0)).unwrap(); let result: i64 = db.query_row(no_result, [], |r| r.get(0))?;
assert_eq!(result, 0); assert_eq!(result, 0);
let single_sum = "SELECT my_count(i) FROM (SELECT 2 AS i UNION ALL SELECT 2)"; let single_sum = "SELECT my_count(i) FROM (SELECT 2 AS i UNION ALL SELECT 2)";
let result: i64 = db.query_row(single_sum, [], |r| r.get(0)).unwrap(); let result: i64 = db.query_row(single_sum, [], |r| r.get(0))?;
assert_eq!(2, result); assert_eq!(2, result);
Ok(())
} }
#[cfg(feature = "window")] #[cfg(feature = "window")]
@ -1001,17 +996,16 @@ mod test {
#[test] #[test]
#[cfg(feature = "window")] #[cfg(feature = "window")]
fn test_window() { fn test_window() -> Result<()> {
use fallible_iterator::FallibleIterator; use fallible_iterator::FallibleIterator;
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.create_window_function( db.create_window_function(
"sumint", "sumint",
1, 1,
FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC, FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC,
Sum, Sum,
) )?;
.unwrap();
db.execute_batch( db.execute_batch(
"CREATE TABLE t3(x, y); "CREATE TABLE t3(x, y);
INSERT INTO t3 VALUES('a', 4), INSERT INTO t3 VALUES('a', 4),
@ -1019,24 +1013,19 @@ mod test {
('c', 3), ('c', 3),
('d', 8), ('d', 8),
('e', 1);", ('e', 1);",
) )?;
.unwrap();
let mut stmt = db let mut stmt = db.prepare(
.prepare( "SELECT x, sumint(y) OVER (
"SELECT x, sumint(y) OVER (
ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
) AS sum_y ) AS sum_y
FROM t3 ORDER BY x;", FROM t3 ORDER BY x;",
) )?;
.unwrap();
let results: Vec<(String, i64)> = stmt let results: Vec<(String, i64)> = stmt
.query([]) .query([])?
.unwrap()
.map(|row| Ok((row.get("x")?, row.get("sum_y")?))) .map(|row| Ok((row.get("x")?, row.get("sum_y")?)))
.collect() .collect()?;
.unwrap();
let expected = vec![ let expected = vec![
("a".to_owned(), 9), ("a".to_owned(), 9),
("b".to_owned(), 12), ("b".to_owned(), 12),
@ -1045,5 +1034,6 @@ mod test {
("e".to_owned(), 9), ("e".to_owned(), 9),
]; ];
assert_eq!(expected, results); assert_eq!(expected, results);
Ok(())
} }
} }

View File

@ -305,26 +305,26 @@ unsafe fn free_boxed_hook<F>(p: *mut c_void) {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::Action; use super::Action;
use crate::Connection; use crate::{Connection, Result};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
#[test] #[test]
fn test_commit_hook() { fn test_commit_hook() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let mut called = false; let mut called = false;
db.commit_hook(Some(|| { db.commit_hook(Some(|| {
called = true; called = true;
false false
})); }));
db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;") db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")?;
.unwrap();
assert!(called); assert!(called);
Ok(())
} }
#[test] #[test]
fn test_fn_commit_hook() { fn test_fn_commit_hook() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
fn hook() -> bool { fn hook() -> bool {
true true
@ -333,24 +333,25 @@ mod test {
db.commit_hook(Some(hook)); db.commit_hook(Some(hook));
db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;") db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")
.unwrap_err(); .unwrap_err();
Ok(())
} }
#[test] #[test]
fn test_rollback_hook() { fn test_rollback_hook() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let mut called = false; let mut called = false;
db.rollback_hook(Some(|| { db.rollback_hook(Some(|| {
called = true; called = true;
})); }));
db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); ROLLBACK;") db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); ROLLBACK;")?;
.unwrap();
assert!(called); assert!(called);
Ok(())
} }
#[test] #[test]
fn test_update_hook() { fn test_update_hook() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let mut called = false; let mut called = false;
db.update_hook(Some(|action, db: &str, tbl: &str, row_id| { db.update_hook(Some(|action, db: &str, tbl: &str, row_id| {
@ -360,14 +361,15 @@ mod test {
assert_eq!(1, row_id); assert_eq!(1, row_id);
called = true; called = true;
})); }));
db.execute_batch("CREATE TABLE foo (t TEXT)").unwrap(); db.execute_batch("CREATE TABLE foo (t TEXT)")?;
db.execute_batch("INSERT INTO foo VALUES ('lisa')").unwrap(); db.execute_batch("INSERT INTO foo VALUES ('lisa')")?;
assert!(called); assert!(called);
Ok(())
} }
#[test] #[test]
fn test_progress_handler() { fn test_progress_handler() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
static CALLED: AtomicBool = AtomicBool::new(false); static CALLED: AtomicBool = AtomicBool::new(false);
db.progress_handler( db.progress_handler(
@ -377,14 +379,14 @@ mod test {
false false
}), }),
); );
db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;") db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")?;
.unwrap();
assert!(CALLED.load(Ordering::Relaxed)); assert!(CALLED.load(Ordering::Relaxed));
Ok(())
} }
#[test] #[test]
fn test_progress_handler_interrupt() { fn test_progress_handler_interrupt() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
fn handler() -> bool { fn handler() -> bool {
true true
@ -393,5 +395,6 @@ mod test {
db.progress_handler(1, Some(handler)); db.progress_handler(1, Some(handler));
db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;") db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")
.unwrap_err(); .unwrap_err();
Ok(())
} }
} }

View File

@ -1060,38 +1060,32 @@ mod test {
} }
#[test] #[test]
fn test_concurrent_transactions_busy_commit() { fn test_concurrent_transactions_busy_commit() -> Result<()> {
use std::time::Duration; use std::time::Duration;
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let path = tmp.path().join("transactions.db3"); let path = tmp.path().join("transactions.db3");
Connection::open(&path) Connection::open(&path)?.execute_batch(
.expect("create temp db") "
.execute_batch(
"
BEGIN; CREATE TABLE foo(x INTEGER); BEGIN; CREATE TABLE foo(x INTEGER);
INSERT INTO foo VALUES(42); END;", INSERT INTO foo VALUES(42); END;",
) )?;
.expect("create temp db");
let mut db1 = let mut db1 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_WRITE).unwrap(); let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)?;
let mut db2 = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY).unwrap();
db1.busy_timeout(Duration::from_millis(0)).unwrap(); db1.busy_timeout(Duration::from_millis(0))?;
db2.busy_timeout(Duration::from_millis(0)).unwrap(); db2.busy_timeout(Duration::from_millis(0))?;
{ {
let tx1 = db1.transaction().unwrap(); let tx1 = db1.transaction()?;
let tx2 = db2.transaction().unwrap(); let tx2 = db2.transaction()?;
// SELECT first makes sqlite lock with a shared lock // SELECT first makes sqlite lock with a shared lock
tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(())) tx1.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
.unwrap(); tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))?;
tx2.query_row("SELECT x FROM foo LIMIT 1", [], |_| Ok(()))
.unwrap();
tx1.execute("INSERT INTO foo VALUES(?1)", &[&1]).unwrap(); tx1.execute("INSERT INTO foo VALUES(?1)", &[&1])?;
let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]); let _ = tx2.execute("INSERT INTO foo VALUES(?1)", [2]);
let _ = tx1.commit(); let _ = tx1.commit();
@ -1104,27 +1098,29 @@ mod test {
let _ = db2 let _ = db2
.transaction() .transaction()
.expect("commit should have closed transaction"); .expect("commit should have closed transaction");
Ok(())
} }
#[test] #[test]
fn test_persistence() { fn test_persistence() -> Result<()> {
let temp_dir = tempfile::tempdir().unwrap(); let temp_dir = tempfile::tempdir().unwrap();
let path = temp_dir.path().join("test.db3"); let path = temp_dir.path().join("test.db3");
{ {
let db = Connection::open(&path).unwrap(); let db = Connection::open(&path)?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER);
INSERT INTO foo VALUES(42); INSERT INTO foo VALUES(42);
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
} }
let path_string = path.to_str().unwrap(); let path_string = path.to_str().unwrap();
let db = Connection::open(&path_string).unwrap(); let db = Connection::open(&path_string)?;
let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", [], |r| r.get(0)); let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", [], |r| r.get(0));
assert_eq!(42i64, the_answer.unwrap()); assert_eq!(42i64, the_answer?);
Ok(())
} }
#[test] #[test]
@ -1157,7 +1153,7 @@ mod test {
#[cfg(unix)] #[cfg(unix)]
#[test] #[test]
fn test_invalid_unicode_file_names() { fn test_invalid_unicode_file_names() -> Result<()> {
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fs::File; use std::fs::File;
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
@ -1166,26 +1162,27 @@ mod test {
let path = temp_dir.path(); let path = temp_dir.path();
if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() { if File::create(path.join(OsStr::from_bytes(&[0xFE]))).is_err() {
// Skip test, filesystem doesn't support invalid Unicode // Skip test, filesystem doesn't support invalid Unicode
return; return Ok(());
} }
let db_path = path.join(OsStr::from_bytes(&[0xFF])); let db_path = path.join(OsStr::from_bytes(&[0xFF]));
{ {
let db = Connection::open(&db_path).unwrap(); let db = Connection::open(&db_path)?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER);
INSERT INTO foo VALUES(42); INSERT INTO foo VALUES(42);
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
} }
let db = Connection::open(&db_path).unwrap(); let db = Connection::open(&db_path)?;
let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", [], |r| r.get(0)); let the_answer: Result<i64> = db.query_row("SELECT x FROM foo", [], |r| r.get(0));
assert_eq!(42i64, the_answer.unwrap()); assert_eq!(42i64, the_answer?);
Ok(())
} }
#[test] #[test]
fn test_close_retry() { fn test_close_retry() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
// force the DB to be busy by preparing a statement; this must be done at the // force the DB to be busy by preparing a statement; this must be done at the
@ -1199,7 +1196,7 @@ mod test {
let raw_db = db.db.borrow_mut().db; let raw_db = db.db.borrow_mut().db;
let sql = "SELECT 1"; let sql = "SELECT 1";
let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut(); let mut raw_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
let cstring = str_to_cstring(sql).unwrap(); let cstring = str_to_cstring(sql)?;
let rc = unsafe { let rc = unsafe {
ffi::sqlite3_prepare_v2( ffi::sqlite3_prepare_v2(
raw_db, raw_db,
@ -1223,6 +1220,7 @@ mod test {
assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) }); assert_eq!(ffi::SQLITE_OK, unsafe { ffi::sqlite3_finalize(raw_stmt) });
db.close().unwrap(); db.close().unwrap();
Ok(())
} }
#[test] #[test]
@ -1237,7 +1235,7 @@ mod test {
} }
#[test] #[test]
fn test_execute_batch() { fn test_execute_batch() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER);
@ -1246,33 +1244,27 @@ mod test {
INSERT INTO foo VALUES(3); INSERT INTO foo VALUES(3);
INSERT INTO foo VALUES(4); INSERT INTO foo VALUES(4);
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3") db.execute_batch("UPDATE foo SET x = 3 WHERE x < 3")?;
.unwrap();
assert!(db.execute_batch("INVALID SQL").is_err()); assert!(db.execute_batch("INVALID SQL").is_err());
Ok(())
} }
#[test] #[test]
fn test_execute() { fn test_execute() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap(); db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
assert_eq!( assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?)", [1i32])?);
1, assert_eq!(1, db.execute("INSERT INTO foo(x) VALUES (?)", [2i32])?);
db.execute("INSERT INTO foo(x) VALUES (?)", [1i32]).unwrap()
);
assert_eq!(
1,
db.execute("INSERT INTO foo(x) VALUES (?)", [2i32]).unwrap()
);
assert_eq!( assert_eq!(
3i32, 3i32,
db.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0)) db.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?
.unwrap()
); );
Ok(())
} }
#[test] #[test]
@ -1302,77 +1294,78 @@ mod test {
} }
#[test] #[test]
fn test_prepare_column_names() { fn test_prepare_column_names() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute_batch("CREATE TABLE foo(x INTEGER);").unwrap(); db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
let stmt = db.prepare("SELECT * FROM foo").unwrap(); let stmt = db.prepare("SELECT * FROM foo")?;
assert_eq!(stmt.column_count(), 1); assert_eq!(stmt.column_count(), 1);
assert_eq!(stmt.column_names(), vec!["x"]); assert_eq!(stmt.column_names(), vec!["x"]);
let stmt = db.prepare("SELECT x AS a, x AS b FROM foo").unwrap(); let stmt = db.prepare("SELECT x AS a, x AS b FROM foo")?;
assert_eq!(stmt.column_count(), 2); assert_eq!(stmt.column_count(), 2);
assert_eq!(stmt.column_names(), vec!["a", "b"]); assert_eq!(stmt.column_names(), vec!["a", "b"]);
Ok(())
} }
#[test] #[test]
fn test_prepare_execute() { fn test_prepare_execute() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute_batch("CREATE TABLE foo(x INTEGER);").unwrap(); db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)").unwrap(); let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
assert_eq!(insert_stmt.execute([1i32]).unwrap(), 1); assert_eq!(insert_stmt.execute([1i32])?, 1);
assert_eq!(insert_stmt.execute([2i32]).unwrap(), 1); assert_eq!(insert_stmt.execute([2i32])?, 1);
assert_eq!(insert_stmt.execute([3i32]).unwrap(), 1); assert_eq!(insert_stmt.execute([3i32])?, 1);
assert_eq!(insert_stmt.execute(["hello".to_string()]).unwrap(), 1); assert_eq!(insert_stmt.execute(["hello".to_string()])?, 1);
assert_eq!(insert_stmt.execute(["goodbye".to_string()]).unwrap(), 1); assert_eq!(insert_stmt.execute(["goodbye".to_string()])?, 1);
assert_eq!(insert_stmt.execute([types::Null]).unwrap(), 1); assert_eq!(insert_stmt.execute([types::Null])?, 1);
let mut update_stmt = db.prepare("UPDATE foo SET x=? WHERE x<?").unwrap(); let mut update_stmt = db.prepare("UPDATE foo SET x=? WHERE x<?")?;
assert_eq!(update_stmt.execute([3i32, 3i32]).unwrap(), 2); assert_eq!(update_stmt.execute([3i32, 3i32])?, 2);
assert_eq!(update_stmt.execute([3i32, 3i32]).unwrap(), 0); assert_eq!(update_stmt.execute([3i32, 3i32])?, 0);
assert_eq!(update_stmt.execute([8i32, 8i32]).unwrap(), 3); assert_eq!(update_stmt.execute([8i32, 8i32])?, 3);
Ok(())
} }
#[test] #[test]
fn test_prepare_query() { fn test_prepare_query() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute_batch("CREATE TABLE foo(x INTEGER);").unwrap(); db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)").unwrap(); let mut insert_stmt = db.prepare("INSERT INTO foo(x) VALUES(?)")?;
assert_eq!(insert_stmt.execute([1i32]).unwrap(), 1); assert_eq!(insert_stmt.execute([1i32])?, 1);
assert_eq!(insert_stmt.execute([2i32]).unwrap(), 1); assert_eq!(insert_stmt.execute([2i32])?, 1);
assert_eq!(insert_stmt.execute([3i32]).unwrap(), 1); assert_eq!(insert_stmt.execute([3i32])?, 1);
let mut query = db let mut query = db.prepare("SELECT x FROM foo WHERE x < ? ORDER BY x DESC")?;
.prepare("SELECT x FROM foo WHERE x < ? ORDER BY x DESC")
.unwrap();
{ {
let mut rows = query.query([4i32]).unwrap(); let mut rows = query.query([4i32])?;
let mut v = Vec::<i32>::new(); let mut v = Vec::<i32>::new();
while let Some(row) = rows.next().unwrap() { while let Some(row) = rows.next()? {
v.push(row.get(0).unwrap()); v.push(row.get(0)?);
} }
assert_eq!(v, [3i32, 2, 1]); assert_eq!(v, [3i32, 2, 1]);
} }
{ {
let mut rows = query.query([3i32]).unwrap(); let mut rows = query.query([3i32])?;
let mut v = Vec::<i32>::new(); let mut v = Vec::<i32>::new();
while let Some(row) = rows.next().unwrap() { while let Some(row) = rows.next()? {
v.push(row.get(0).unwrap()); v.push(row.get(0)?);
} }
assert_eq!(v, [2i32, 1]); assert_eq!(v, [2i32, 1]);
} }
Ok(())
} }
#[test] #[test]
fn test_query_map() { fn test_query_map() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
@ -1381,16 +1374,17 @@ mod test {
INSERT INTO foo VALUES(2, \"world\"); INSERT INTO foo VALUES(2, \"world\");
INSERT INTO foo VALUES(1, \"!\"); INSERT INTO foo VALUES(1, \"!\");
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap(); let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
let results: Result<Vec<String>> = query.query([]).unwrap().map(|row| row.get(1)).collect(); let results: Result<Vec<String>> = query.query([])?.map(|row| row.get(1)).collect();
assert_eq!(results.unwrap().concat(), "hello, world!"); assert_eq!(results?.concat(), "hello, world!");
Ok(())
} }
#[test] #[test]
fn test_query_row() { fn test_query_row() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER);
@ -1399,12 +1393,11 @@ mod test {
INSERT INTO foo VALUES(3); INSERT INTO foo VALUES(3);
INSERT INTO foo VALUES(4); INSERT INTO foo VALUES(4);
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
assert_eq!( assert_eq!(
10i64, 10i64,
db.query_row::<i64, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0)) db.query_row::<i64, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?
.unwrap()
); );
let result: Result<i64> = db.query_row("SELECT x FROM foo WHERE x > 5", [], |r| r.get(0)); let result: Result<i64> = db.query_row("SELECT x FROM foo WHERE x > 5", [], |r| r.get(0));
@ -1416,22 +1409,23 @@ mod test {
let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(())); let bad_query_result = db.query_row("NOT A PROPER QUERY; test123", [], |_| Ok(()));
assert!(bad_query_result.is_err()); assert!(bad_query_result.is_err());
Ok(())
} }
#[test] #[test]
fn test_optional() { fn test_optional() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 <> 0", [], |r| r.get(0)); let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 <> 0", [], |r| r.get(0));
let result = result.optional(); let result = result.optional();
match result.unwrap() { match result? {
None => (), None => (),
_ => panic!("Unexpected result"), _ => panic!("Unexpected result"),
} }
let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 == 0", [], |r| r.get(0)); let result: Result<i64> = db.query_row("SELECT 1 WHERE 0 == 0", [], |r| r.get(0));
let result = result.optional(); let result = result.optional();
match result.unwrap() { match result? {
Some(1) => (), Some(1) => (),
_ => panic!("Unexpected result"), _ => panic!("Unexpected result"),
} }
@ -1439,47 +1433,48 @@ mod test {
let bad_query_result: Result<i64> = db.query_row("NOT A PROPER QUERY", [], |r| r.get(0)); let bad_query_result: Result<i64> = db.query_row("NOT A PROPER QUERY", [], |r| r.get(0));
let bad_query_result = bad_query_result.optional(); let bad_query_result = bad_query_result.optional();
assert!(bad_query_result.is_err()); assert!(bad_query_result.is_err());
Ok(())
} }
#[test] #[test]
fn test_pragma_query_row() { fn test_pragma_query_row() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
assert_eq!( assert_eq!(
"memory", "memory",
db.query_row::<String, _, _>("PRAGMA journal_mode", [], |r| r.get(0)) db.query_row::<String, _, _>("PRAGMA journal_mode", [], |r| r.get(0))?
.unwrap()
); );
assert_eq!( assert_eq!(
"off", "off",
db.query_row::<String, _, _>("PRAGMA journal_mode=off", [], |r| r.get(0)) db.query_row::<String, _, _>("PRAGMA journal_mode=off", [], |r| r.get(0))?
.unwrap()
); );
Ok(())
} }
#[test] #[test]
fn test_prepare_failures() { fn test_prepare_failures() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute_batch("CREATE TABLE foo(x INTEGER);").unwrap(); db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err(); let err = db.prepare("SELECT * FROM does_not_exist").unwrap_err();
assert!(format!("{}", err).contains("does_not_exist")); assert!(format!("{}", err).contains("does_not_exist"));
Ok(())
} }
#[test] #[test]
fn test_last_insert_rowid() { fn test_last_insert_rowid() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)") db.execute_batch("CREATE TABLE foo(x INTEGER PRIMARY KEY)")?;
.unwrap(); db.execute_batch("INSERT INTO foo DEFAULT VALUES")?;
db.execute_batch("INSERT INTO foo DEFAULT VALUES").unwrap();
assert_eq!(db.last_insert_rowid(), 1); assert_eq!(db.last_insert_rowid(), 1);
let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES").unwrap(); let mut stmt = db.prepare("INSERT INTO foo DEFAULT VALUES")?;
for _ in 0i32..9 { for _ in 0i32..9 {
stmt.execute([]).unwrap(); stmt.execute([])?;
} }
assert_eq!(db.last_insert_rowid(), 10); assert_eq!(db.last_insert_rowid(), 10);
Ok(())
} }
#[test] #[test]
@ -1493,32 +1488,34 @@ mod test {
#[test] #[test]
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
fn test_is_busy() { fn test_is_busy() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
assert!(!db.is_busy()); assert!(!db.is_busy());
let mut stmt = db.prepare("PRAGMA schema_version").unwrap(); let mut stmt = db.prepare("PRAGMA schema_version")?;
assert!(!db.is_busy()); assert!(!db.is_busy());
{ {
let mut rows = stmt.query([]).unwrap(); let mut rows = stmt.query([])?;
assert!(!db.is_busy()); assert!(!db.is_busy());
let row = rows.next().unwrap(); let row = rows.next()?;
assert!(db.is_busy()); assert!(db.is_busy());
assert!(row.is_some()); assert!(row.is_some());
} }
assert!(!db.is_busy()); assert!(!db.is_busy());
Ok(())
} }
#[test] #[test]
fn test_statement_debugging() { fn test_statement_debugging() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let query = "SELECT 12345"; let query = "SELECT 12345";
let stmt = db.prepare(query).unwrap(); let stmt = db.prepare(query)?;
assert!(format!("{:?}", stmt).contains(query)); assert!(format!("{:?}", stmt).contains(query));
Ok(())
} }
#[test] #[test]
fn test_notnull_constraint_error() { fn test_notnull_constraint_error() -> Result<()> {
// extended error codes for constraints were added in SQLite 3.7.16; if we're // extended error codes for constraints were added in SQLite 3.7.16; if we're
// running on our bundled version, we know the extended error code exists. // running on our bundled version, we know the extended error code exists.
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
@ -1529,7 +1526,7 @@ mod test {
fn check_extended_code(_extended_code: c_int) {} fn check_extended_code(_extended_code: c_int) {}
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute_batch("CREATE TABLE foo(x NOT NULL)").unwrap(); db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []); let result = db.execute("INSERT INTO foo (x) VALUES (NULL)", []);
assert!(result.is_err()); assert!(result.is_err());
@ -1541,6 +1538,7 @@ mod test {
} }
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {}", err),
} }
Ok(())
} }
#[test] #[test]
@ -1555,7 +1553,7 @@ mod test {
#[test] #[test]
#[cfg(feature = "functions")] #[cfg(feature = "functions")]
fn test_interrupt() { fn test_interrupt() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let interrupt_handle = db.get_interrupt_handle(); let interrupt_handle = db.get_interrupt_handle();
@ -1568,14 +1566,12 @@ mod test {
interrupt_handle.interrupt(); interrupt_handle.interrupt();
Ok(0) Ok(0)
}, },
) )?;
.unwrap();
let mut stmt = db let mut stmt =
.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)") db.prepare("SELECT interrupt() FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)")?;
.unwrap();
let result: Result<Vec<i32>> = stmt.query([]).unwrap().map(|r| r.get(0)).collect(); let result: Result<Vec<i32>> = stmt.query([])?.map(|r| r.get(0)).collect();
match result.unwrap_err() { match result.unwrap_err() {
Error::SqliteFailure(err, _) => { Error::SqliteFailure(err, _) => {
@ -1585,6 +1581,7 @@ mod test {
panic!("Unexpected error {}", err); panic!("Unexpected error {}", err);
} }
} }
Ok(())
} }
#[test] #[test]
@ -1604,36 +1601,38 @@ mod test {
} }
#[test] #[test]
fn test_get_raw() { fn test_get_raw() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute_batch("CREATE TABLE foo(i, x);").unwrap(); db.execute_batch("CREATE TABLE foo(i, x);")?;
let vals = ["foobar", "1234", "qwerty"]; let vals = ["foobar", "1234", "qwerty"];
let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?, ?)").unwrap(); let mut insert_stmt = db.prepare("INSERT INTO foo(i, x) VALUES(?, ?)")?;
for (i, v) in vals.iter().enumerate() { for (i, v) in vals.iter().enumerate() {
let i_to_insert = i as i64; let i_to_insert = i as i64;
assert_eq!(insert_stmt.execute(params![i_to_insert, v]).unwrap(), 1); assert_eq!(insert_stmt.execute(params![i_to_insert, v])?, 1);
} }
let mut query = db.prepare("SELECT i, x FROM foo").unwrap(); let mut query = db.prepare("SELECT i, x FROM foo")?;
let mut rows = query.query([]).unwrap(); let mut rows = query.query([])?;
while let Some(row) = rows.next().unwrap() { while let Some(row) = rows.next()? {
let i = row.get_raw(0).as_i64().unwrap(); let i = row.get_raw(0).as_i64()?;
let expect = vals[i as usize]; let expect = vals[i as usize];
let x = row.get_raw("x").as_str().unwrap(); let x = row.get_raw("x").as_str()?;
assert_eq!(x, expect); assert_eq!(x, expect);
} }
Ok(())
} }
#[test] #[test]
fn test_from_handle() { fn test_from_handle() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let handle = unsafe { db.handle() }; let handle = unsafe { db.handle() };
{ {
let db = unsafe { Connection::from_handle(handle) }.unwrap(); let db = unsafe { Connection::from_handle(handle) }?;
db.execute_batch("PRAGMA VACUUM").unwrap(); db.execute_batch("PRAGMA VACUUM")?;
} }
db.close().unwrap(); db.close().unwrap();
Ok(())
} }
mod query_and_then_tests { mod query_and_then_tests {
@ -1677,7 +1676,7 @@ mod test {
type CustomResult<T> = Result<T, CustomError>; type CustomResult<T> = Result<T, CustomError>;
#[test] #[test]
fn test_query_and_then() { fn test_query_and_then() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
@ -1686,19 +1685,18 @@ mod test {
INSERT INTO foo VALUES(2, \"world\"); INSERT INTO foo VALUES(2, \"world\");
INSERT INTO foo VALUES(1, \"!\"); INSERT INTO foo VALUES(1, \"!\");
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap(); let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
let results: Result<Vec<String>> = query let results: Result<Vec<String>> =
.query_and_then([], |row| row.get(1)) query.query_and_then([], |row| row.get(1))?.collect();
.unwrap()
.collect();
assert_eq!(results.unwrap().concat(), "hello, world!"); assert_eq!(results?.concat(), "hello, world!");
Ok(())
} }
#[test] #[test]
fn test_query_and_then_fails() { fn test_query_and_then_fails() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
@ -1707,32 +1705,28 @@ mod test {
INSERT INTO foo VALUES(2, \"world\"); INSERT INTO foo VALUES(2, \"world\");
INSERT INTO foo VALUES(1, \"!\"); INSERT INTO foo VALUES(1, \"!\");
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap(); let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
let bad_type: Result<Vec<f64>> = query let bad_type: Result<Vec<f64>> = query.query_and_then([], |row| row.get(1))?.collect();
.query_and_then([], |row| row.get(1))
.unwrap()
.collect();
match bad_type.unwrap_err() { match bad_type.unwrap_err() {
Error::InvalidColumnType(..) => (), Error::InvalidColumnType(..) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {}", err),
} }
let bad_idx: Result<Vec<String>> = query let bad_idx: Result<Vec<String>> =
.query_and_then([], |row| row.get(3)) query.query_and_then([], |row| row.get(3))?.collect();
.unwrap()
.collect();
match bad_idx.unwrap_err() { match bad_idx.unwrap_err() {
Error::InvalidColumnIndex(_) => (), Error::InvalidColumnIndex(_) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {}", err),
} }
Ok(())
} }
#[test] #[test]
fn test_query_and_then_custom_error() { fn test_query_and_then_custom_error() -> CustomResult<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
@ -1741,19 +1735,19 @@ mod test {
INSERT INTO foo VALUES(2, \"world\"); INSERT INTO foo VALUES(2, \"world\");
INSERT INTO foo VALUES(1, \"!\"); INSERT INTO foo VALUES(1, \"!\");
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap(); let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
let results: CustomResult<Vec<String>> = query let results: CustomResult<Vec<String>> = query
.query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite)) .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
.unwrap()
.collect(); .collect();
assert_eq!(results.unwrap().concat(), "hello, world!"); assert_eq!(results?.concat(), "hello, world!");
Ok(())
} }
#[test] #[test]
fn test_query_and_then_custom_error_fails() { fn test_query_and_then_custom_error_fails() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
@ -1762,12 +1756,11 @@ mod test {
INSERT INTO foo VALUES(2, \"world\"); INSERT INTO foo VALUES(2, \"world\");
INSERT INTO foo VALUES(1, \"!\"); INSERT INTO foo VALUES(1, \"!\");
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC").unwrap(); let mut query = db.prepare("SELECT x, y FROM foo ORDER BY x DESC")?;
let bad_type: CustomResult<Vec<f64>> = query let bad_type: CustomResult<Vec<f64>> = query
.query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite)) .query_and_then([], |row| row.get(1).map_err(CustomError::Sqlite))?
.unwrap()
.collect(); .collect();
match bad_type.unwrap_err() { match bad_type.unwrap_err() {
@ -1776,8 +1769,7 @@ mod test {
} }
let bad_idx: CustomResult<Vec<String>> = query let bad_idx: CustomResult<Vec<String>> = query
.query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite)) .query_and_then([], |row| row.get(3).map_err(CustomError::Sqlite))?
.unwrap()
.collect(); .collect();
match bad_idx.unwrap_err() { match bad_idx.unwrap_err() {
@ -1786,40 +1778,41 @@ mod test {
} }
let non_sqlite_err: CustomResult<Vec<String>> = query let non_sqlite_err: CustomResult<Vec<String>> = query
.query_and_then([], |_| Err(CustomError::SomeError)) .query_and_then([], |_| Err(CustomError::SomeError))?
.unwrap()
.collect(); .collect();
match non_sqlite_err.unwrap_err() { match non_sqlite_err.unwrap_err() {
CustomError::SomeError => (), CustomError::SomeError => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {}", err),
} }
Ok(())
} }
#[test] #[test]
fn test_query_row_and_then_custom_error() { fn test_query_row_and_then_custom_error() -> CustomResult<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, \"hello\"); INSERT INTO foo VALUES(4, \"hello\");
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let query = "SELECT x, y FROM foo ORDER BY x DESC"; let query = "SELECT x, y FROM foo ORDER BY x DESC";
let results: CustomResult<String> = let results: CustomResult<String> =
db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite)); db.query_row_and_then(query, [], |row| row.get(1).map_err(CustomError::Sqlite));
assert_eq!(results.unwrap(), "hello"); assert_eq!(results?, "hello");
Ok(())
} }
#[test] #[test]
fn test_query_row_and_then_custom_error_fails() { fn test_query_row_and_then_custom_error_fails() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, \"hello\"); INSERT INTO foo VALUES(4, \"hello\");
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let query = "SELECT x, y FROM foo ORDER BY x DESC"; let query = "SELECT x, y FROM foo ORDER BY x DESC";
let bad_type: CustomResult<f64> = let bad_type: CustomResult<f64> =
@ -1845,39 +1838,38 @@ mod test {
CustomError::SomeError => (), CustomError::SomeError => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {}", err),
} }
Ok(())
} }
} }
#[test] #[test]
fn test_dynamic() { fn test_dynamic() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y TEXT); CREATE TABLE foo(x INTEGER, y TEXT);
INSERT INTO foo VALUES(4, \"hello\"); INSERT INTO foo VALUES(4, \"hello\");
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
db.query_row("SELECT * FROM foo", [], |r| { db.query_row("SELECT * FROM foo", [], |r| {
assert_eq!(2, r.column_count()); assert_eq!(2, r.column_count());
Ok(()) Ok(())
}) })
.unwrap();
} }
#[test] #[test]
fn test_dyn_box() { fn test_dyn_box() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute_batch("CREATE TABLE foo(x INTEGER);").unwrap(); db.execute_batch("CREATE TABLE foo(x INTEGER);")?;
let b: Box<dyn ToSql> = Box::new(5); let b: Box<dyn ToSql> = Box::new(5);
db.execute("INSERT INTO foo VALUES(?)", [b]).unwrap(); db.execute("INSERT INTO foo VALUES(?)", [b])?;
db.query_row("SELECT x FROM foo", [], |r| { db.query_row("SELECT x FROM foo", [], |r| {
assert_eq!(5, r.get_unwrap::<_, i32>(0)); assert_eq!(5, r.get_unwrap::<_, i32>(0));
Ok(()) Ok(())
}) })
.unwrap();
} }
#[test] #[test]
fn test_params() { fn test_params() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.query_row( db.query_row(
"SELECT "SELECT
@ -1894,20 +1886,20 @@ mod test {
Ok(()) Ok(())
}, },
) )
.unwrap();
} }
#[test] #[test]
#[cfg(not(feature = "extra_check"))] #[cfg(not(feature = "extra_check"))]
fn test_alter_table() { fn test_alter_table() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
db.execute_batch("CREATE TABLE x(t);").unwrap(); db.execute_batch("CREATE TABLE x(t);")?;
// `execute_batch` should be used but `execute` should also work // `execute_batch` should be used but `execute` should also work
db.execute("ALTER TABLE x RENAME TO y;", []).unwrap(); db.execute("ALTER TABLE x RENAME TO y;", [])?;
Ok(())
} }
#[test] #[test]
fn test_batch() { fn test_batch() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle();
let sql = r" let sql = r"
CREATE TABLE tbl1 (col); CREATE TABLE tbl1 (col);
@ -1915,8 +1907,9 @@ mod test {
"; ";
let batch = Batch::new(&db, sql); let batch = Batch::new(&db, sql);
for stmt in batch { for stmt in batch {
let mut stmt = stmt.unwrap(); let mut stmt = stmt?;
stmt.execute([]).unwrap(); stmt.execute([])?;
} }
Ok(())
} }
} }

View File

@ -27,11 +27,11 @@ impl Connection {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::ffi::Limit; use crate::ffi::Limit;
use crate::Connection; use crate::{Connection, Result};
#[test] #[test]
fn test_limit() { fn test_limit() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.set_limit(Limit::SQLITE_LIMIT_LENGTH, 1024); db.set_limit(Limit::SQLITE_LIMIT_LENGTH, 1024);
assert_eq!(1024, db.limit(Limit::SQLITE_LIMIT_LENGTH)); assert_eq!(1024, db.limit(Limit::SQLITE_LIMIT_LENGTH));
@ -70,5 +70,6 @@ mod test {
db.set_limit(Limit::SQLITE_LIMIT_WORKER_THREADS, 2); db.set_limit(Limit::SQLITE_LIMIT_WORKER_THREADS, 2);
assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_WORKER_THREADS)); assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_WORKER_THREADS));
} }
Ok(())
} }
} }

View File

@ -314,95 +314,95 @@ fn is_identifier_continue(c: char) -> bool {
mod test { mod test {
use super::Sql; use super::Sql;
use crate::pragma; use crate::pragma;
use crate::{Connection, DatabaseName}; use crate::{Connection, DatabaseName, Result};
#[test] #[test]
fn pragma_query_value() { fn pragma_query_value() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let user_version: i32 = db let user_version: i32 = db.pragma_query_value(None, "user_version", |row| row.get(0))?;
.pragma_query_value(None, "user_version", |row| row.get(0))
.unwrap();
assert_eq!(0, user_version); assert_eq!(0, user_version);
Ok(())
} }
#[test] #[test]
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
fn pragma_func_query_value() { fn pragma_func_query_value() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let user_version: i32 = db let user_version: i32 =
.query_row("SELECT user_version FROM pragma_user_version", [], |row| { db.query_row("SELECT user_version FROM pragma_user_version", [], |row| {
row.get(0) row.get(0)
}) })?;
.unwrap();
assert_eq!(0, user_version); assert_eq!(0, user_version);
Ok(())
} }
#[test] #[test]
fn pragma_query_no_schema() { fn pragma_query_no_schema() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let mut user_version = -1; let mut user_version = -1;
db.pragma_query(None, "user_version", |row| { db.pragma_query(None, "user_version", |row| {
user_version = row.get(0)?; user_version = row.get(0)?;
Ok(()) Ok(())
}) })?;
.unwrap();
assert_eq!(0, user_version); assert_eq!(0, user_version);
Ok(())
} }
#[test] #[test]
fn pragma_query_with_schema() { fn pragma_query_with_schema() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let mut user_version = -1; let mut user_version = -1;
db.pragma_query(Some(DatabaseName::Main), "user_version", |row| { db.pragma_query(Some(DatabaseName::Main), "user_version", |row| {
user_version = row.get(0)?; user_version = row.get(0)?;
Ok(()) Ok(())
}) })?;
.unwrap();
assert_eq!(0, user_version); assert_eq!(0, user_version);
Ok(())
} }
#[test] #[test]
fn pragma() { fn pragma() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let mut columns = Vec::new(); let mut columns = Vec::new();
db.pragma(None, "table_info", &"sqlite_master", |row| { db.pragma(None, "table_info", &"sqlite_master", |row| {
let column: String = row.get(1)?; let column: String = row.get(1)?;
columns.push(column); columns.push(column);
Ok(()) Ok(())
}) })?;
.unwrap();
assert_eq!(5, columns.len()); assert_eq!(5, columns.len());
Ok(())
} }
#[test] #[test]
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
fn pragma_func() { fn pragma_func() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let mut table_info = db.prepare("SELECT * FROM pragma_table_info(?)").unwrap(); let mut table_info = db.prepare("SELECT * FROM pragma_table_info(?)")?;
let mut columns = Vec::new(); let mut columns = Vec::new();
let mut rows = table_info.query(&["sqlite_master"]).unwrap(); let mut rows = table_info.query(&["sqlite_master"])?;
while let Some(row) = rows.next().unwrap() { while let Some(row) = rows.next()? {
let row = row; let row = row;
let column: String = row.get(1).unwrap(); let column: String = row.get(1)?;
columns.push(column); columns.push(column);
} }
assert_eq!(5, columns.len()); assert_eq!(5, columns.len());
Ok(())
} }
#[test] #[test]
fn pragma_update() { fn pragma_update() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.pragma_update(None, "user_version", &1).unwrap(); db.pragma_update(None, "user_version", &1)
} }
#[test] #[test]
fn pragma_update_and_check() { fn pragma_update_and_check() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let journal_mode: String = db let journal_mode: String =
.pragma_update_and_check(None, "journal_mode", &"OFF", |row| row.get(0)) db.pragma_update_and_check(None, "journal_mode", &"OFF", |row| row.get(0))?;
.unwrap();
assert_eq!("off", &journal_mode); assert_eq!("off", &journal_mode);
Ok(())
} }
#[test] #[test]
@ -428,13 +428,14 @@ mod test {
} }
#[test] #[test]
fn locking_mode() { fn locking_mode() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let r = db.pragma_update(None, "locking_mode", &"exclusive"); let r = db.pragma_update(None, "locking_mode", &"exclusive");
if cfg!(feature = "extra_check") { if cfg!(feature = "extra_check") {
r.unwrap_err(); r.unwrap_err();
} else { } else {
r.unwrap(); r?;
} }
Ok(())
} }
} }

View File

@ -413,53 +413,46 @@ tuples_try_from_row!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(clippy::redundant_closure)] // false positives due to lifetime issues; clippy issue #5594 #![allow(clippy::redundant_closure)] // false positives due to lifetime issues; clippy issue #5594
use crate::{Connection, Result};
#[test] #[test]
fn test_try_from_row_for_tuple_1() { fn test_try_from_row_for_tuple_1() -> Result<()> {
use crate::{Connection, ToSql}; use crate::ToSql;
use std::convert::TryFrom; use std::convert::TryFrom;
let conn = Connection::open_in_memory().expect("failed to create in-memoory database"); let conn = Connection::open_in_memory()?;
conn.execute( conn.execute(
"CREATE TABLE test (a INTEGER)", "CREATE TABLE test (a INTEGER)",
crate::params_from_iter(std::iter::empty::<&dyn ToSql>()), crate::params_from_iter(std::iter::empty::<&dyn ToSql>()),
) )?;
.expect("failed to create table"); conn.execute("INSERT INTO test VALUES (42)", [])?;
conn.execute("INSERT INTO test VALUES (42)", []) let val = conn.query_row("SELECT a FROM test", [], |row| <(u32,)>::try_from(row))?;
.expect("failed to insert value");
let val = conn
.query_row("SELECT a FROM test", [], |row| <(u32,)>::try_from(row))
.expect("failed to query row");
assert_eq!(val, (42,)); assert_eq!(val, (42,));
let fail = conn.query_row("SELECT a FROM test", [], |row| <(u32, u32)>::try_from(row)); let fail = conn.query_row("SELECT a FROM test", [], |row| <(u32, u32)>::try_from(row));
assert!(fail.is_err()); assert!(fail.is_err());
Ok(())
} }
#[test] #[test]
fn test_try_from_row_for_tuple_2() { fn test_try_from_row_for_tuple_2() -> Result<()> {
use crate::Connection;
use std::convert::TryFrom; use std::convert::TryFrom;
let conn = Connection::open_in_memory().expect("failed to create in-memoory database"); let conn = Connection::open_in_memory()?;
conn.execute("CREATE TABLE test (a INTEGER, b INTEGER)", []) conn.execute("CREATE TABLE test (a INTEGER, b INTEGER)", [])?;
.expect("failed to create table"); conn.execute("INSERT INTO test VALUES (42, 47)", [])?;
conn.execute("INSERT INTO test VALUES (42, 47)", []) let val = conn.query_row("SELECT a, b FROM test", [], |row| {
.expect("failed to insert value"); <(u32, u32)>::try_from(row)
let val = conn })?;
.query_row("SELECT a, b FROM test", [], |row| {
<(u32, u32)>::try_from(row)
})
.expect("failed to query row");
assert_eq!(val, (42, 47)); assert_eq!(val, (42, 47));
let fail = conn.query_row("SELECT a, b FROM test", [], |row| { let fail = conn.query_row("SELECT a, b FROM test", [], |row| {
<(u32, u32, u32)>::try_from(row) <(u32, u32, u32)>::try_from(row)
}); });
assert!(fail.is_err()); assert!(fail.is_err());
Ok(())
} }
#[test] #[test]
fn test_try_from_row_for_tuple_16() { fn test_try_from_row_for_tuple_16() -> Result<()> {
use crate::Connection;
use std::convert::TryFrom; use std::convert::TryFrom;
let create_table = "CREATE TABLE test ( let create_table = "CREATE TABLE test (
@ -519,14 +512,10 @@ mod tests {
u32, u32,
); );
let conn = Connection::open_in_memory().expect("failed to create in-memoory database"); let conn = Connection::open_in_memory()?;
conn.execute(create_table, []) conn.execute(create_table, [])?;
.expect("failed to create table"); conn.execute(insert_values, [])?;
conn.execute(insert_values, []) let val = conn.query_row("SELECT * FROM test", [], |row| BigTuple::try_from(row))?;
.expect("failed to insert value");
let val = conn
.query_row("SELECT * FROM test", [], |row| BigTuple::try_from(row))
.expect("failed to query row");
// Debug is not implemented for tuples of 16 // Debug is not implemented for tuples of 16
assert_eq!(val.0, 0); assert_eq!(val.0, 0);
assert_eq!(val.1, 1); assert_eq!(val.1, 1);
@ -546,5 +535,6 @@ mod tests {
assert_eq!(val.15, 15); assert_eq!(val.15, 15);
// We don't test one bigger because it's unimplemented // We don't test one bigger because it's unimplemented
Ok(())
} }
} }

View File

@ -781,80 +781,77 @@ mod test {
use super::{Changeset, ChangesetIter, ConflictAction, ConflictType, Session}; use super::{Changeset, ChangesetIter, ConflictAction, ConflictType, Session};
use crate::hooks::Action; use crate::hooks::Action;
use crate::Connection; use crate::{Connection, Result};
fn one_changeset() -> Changeset { fn one_changeset() -> Result<Changeset> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);") db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);")?;
.unwrap();
let mut session = Session::new(&db).unwrap(); let mut session = Session::new(&db)?;
assert!(session.is_empty()); assert!(session.is_empty());
session.attach(None).unwrap(); session.attach(None)?;
db.execute("INSERT INTO foo (t) VALUES (?);", &["bar"]) db.execute("INSERT INTO foo (t) VALUES (?);", &["bar"])?;
.unwrap();
session.changeset().unwrap() session.changeset()
} }
fn one_changeset_strm() -> Vec<u8> { fn one_changeset_strm() -> Result<Vec<u8>> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);") db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);")?;
.unwrap();
let mut session = Session::new(&db).unwrap(); let mut session = Session::new(&db)?;
assert!(session.is_empty()); assert!(session.is_empty());
session.attach(None).unwrap(); session.attach(None)?;
db.execute("INSERT INTO foo (t) VALUES (?);", &["bar"]) db.execute("INSERT INTO foo (t) VALUES (?);", &["bar"])?;
.unwrap();
let mut output = Vec::new(); let mut output = Vec::new();
session.changeset_strm(&mut output).unwrap(); session.changeset_strm(&mut output)?;
output Ok(output)
} }
#[test] #[test]
fn test_changeset() { fn test_changeset() -> Result<()> {
let changeset = one_changeset(); let changeset = one_changeset()?;
let mut iter = changeset.iter().unwrap(); let mut iter = changeset.iter()?;
let item = iter.next().unwrap(); let item = iter.next()?;
assert!(item.is_some()); assert!(item.is_some());
let item = item.unwrap(); let item = item.unwrap();
let op = item.op().unwrap(); let op = item.op()?;
assert_eq!("foo", op.table_name()); assert_eq!("foo", op.table_name());
assert_eq!(1, op.number_of_columns()); assert_eq!(1, op.number_of_columns());
assert_eq!(Action::SQLITE_INSERT, op.code()); assert_eq!(Action::SQLITE_INSERT, op.code());
assert_eq!(false, op.indirect()); assert_eq!(false, op.indirect());
let pk = item.pk().unwrap(); let pk = item.pk()?;
assert_eq!(&[1], pk); assert_eq!(&[1], pk);
let new_value = item.new_value(0).unwrap(); let new_value = item.new_value(0)?;
assert_eq!(Ok("bar"), new_value.as_str()); assert_eq!(Ok("bar"), new_value.as_str());
Ok(())
} }
#[test] #[test]
fn test_changeset_strm() { fn test_changeset_strm() -> Result<()> {
let output = one_changeset_strm(); let output = one_changeset_strm()?;
assert!(!output.is_empty()); assert!(!output.is_empty());
assert_eq!(14, output.len()); assert_eq!(14, output.len());
let input: &mut dyn Read = &mut output.as_slice(); let input: &mut dyn Read = &mut output.as_slice();
let mut iter = ChangesetIter::start_strm(&input).unwrap(); let mut iter = ChangesetIter::start_strm(&input)?;
let item = iter.next().unwrap(); let item = iter.next()?;
assert!(item.is_some()); assert!(item.is_some());
Ok(())
} }
#[test] #[test]
fn test_changeset_apply() { fn test_changeset_apply() -> Result<()> {
let changeset = one_changeset(); let changeset = one_changeset()?;
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);") db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);")?;
.unwrap();
static CALLED: AtomicBool = AtomicBool::new(false); static CALLED: AtomicBool = AtomicBool::new(false);
db.apply( db.apply(
@ -864,15 +861,12 @@ mod test {
CALLED.store(true, Ordering::Relaxed); CALLED.store(true, Ordering::Relaxed);
ConflictAction::SQLITE_CHANGESET_OMIT ConflictAction::SQLITE_CHANGESET_OMIT
}, },
) )?;
.unwrap();
assert!(!CALLED.load(Ordering::Relaxed)); assert!(!CALLED.load(Ordering::Relaxed));
let check = db let check = db.query_row("SELECT 1 FROM foo WHERE t = ?", &["bar"], |row| {
.query_row("SELECT 1 FROM foo WHERE t = ?", &["bar"], |row| { row.get::<_, i32>(0)
row.get::<_, i32>(0) })?;
})
.unwrap();
assert_eq!(1, check); assert_eq!(1, check);
// conflict expected when same changeset applied again on the same db // conflict expected when same changeset applied again on the same db
@ -886,68 +880,66 @@ mod test {
assert_eq!(Ok("bar"), conflict.as_str()); assert_eq!(Ok("bar"), conflict.as_str());
ConflictAction::SQLITE_CHANGESET_OMIT ConflictAction::SQLITE_CHANGESET_OMIT
}, },
) )?;
.unwrap();
assert!(CALLED.load(Ordering::Relaxed)); assert!(CALLED.load(Ordering::Relaxed));
Ok(())
} }
#[test] #[test]
fn test_changeset_apply_strm() { fn test_changeset_apply_strm() -> Result<()> {
let output = one_changeset_strm(); let output = one_changeset_strm()?;
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);") db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);")?;
.unwrap();
let mut input = output.as_slice(); let mut input = output.as_slice();
db.apply_strm( db.apply_strm(
&mut input, &mut input,
None::<fn(&str) -> bool>, None::<fn(&str) -> bool>,
|_conflict_type, _item| ConflictAction::SQLITE_CHANGESET_OMIT, |_conflict_type, _item| ConflictAction::SQLITE_CHANGESET_OMIT,
) )?;
.unwrap();
let check = db let check = db.query_row("SELECT 1 FROM foo WHERE t = ?", &["bar"], |row| {
.query_row("SELECT 1 FROM foo WHERE t = ?", &["bar"], |row| { row.get::<_, i32>(0)
row.get::<_, i32>(0) })?;
})
.unwrap();
assert_eq!(1, check); assert_eq!(1, check);
Ok(())
} }
#[test] #[test]
fn test_session_empty() { fn test_session_empty() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);") db.execute_batch("CREATE TABLE foo(t TEXT PRIMARY KEY NOT NULL);")?;
.unwrap();
let mut session = Session::new(&db).unwrap(); let mut session = Session::new(&db)?;
assert!(session.is_empty()); assert!(session.is_empty());
session.attach(None).unwrap(); session.attach(None)?;
db.execute("INSERT INTO foo (t) VALUES (?);", &["bar"]) db.execute("INSERT INTO foo (t) VALUES (?);", &["bar"])?;
.unwrap();
assert!(!session.is_empty()); assert!(!session.is_empty());
Ok(())
} }
#[test] #[test]
fn test_session_set_enabled() { fn test_session_set_enabled() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let mut session = Session::new(&db).unwrap(); let mut session = Session::new(&db)?;
assert!(session.is_enabled()); assert!(session.is_enabled());
session.set_enabled(false); session.set_enabled(false);
assert!(!session.is_enabled()); assert!(!session.is_enabled());
Ok(())
} }
#[test] #[test]
fn test_session_set_indirect() { fn test_session_set_indirect() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let mut session = Session::new(&db).unwrap(); let mut session = Session::new(&db)?;
assert!(!session.is_indirect()); assert!(!session.is_indirect());
session.set_indirect(true); session.set_indirect(true);
assert!(session.is_indirect()); assert!(session.is_indirect());
Ok(())
} }
} }

View File

@ -940,26 +940,23 @@ mod test {
#[test] #[test]
#[allow(deprecated)] #[allow(deprecated)]
fn test_execute_named() { fn test_execute_named() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap(); db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
assert_eq!( assert_eq!(
db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)]) db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)])?,
.unwrap(),
1 1
); );
assert_eq!( assert_eq!(
db.execute("INSERT INTO foo(x) VALUES (:x)", &[(":x", &2i32)]) db.execute("INSERT INTO foo(x) VALUES (:x)", &[(":x", &2i32)])?,
.unwrap(),
1 1
); );
assert_eq!( assert_eq!(
db.execute( db.execute(
"INSERT INTO foo(x) VALUES (:x)", "INSERT INTO foo(x) VALUES (:x)",
crate::named_params! {":x": 3i32} crate::named_params! {":x": 3i32}
) )?,
.unwrap(),
1 1
); );
@ -969,8 +966,7 @@ mod test {
"SELECT SUM(x) FROM foo WHERE x > :x", "SELECT SUM(x) FROM foo WHERE x > :x",
&[(":x", &0i32)], &[(":x", &0i32)],
|r| r.get(0) |r| r.get(0)
) )?
.unwrap()
); );
assert_eq!( assert_eq!(
5i32, 5i32,
@ -978,133 +974,118 @@ mod test {
"SELECT SUM(x) FROM foo WHERE x > :x", "SELECT SUM(x) FROM foo WHERE x > :x",
&[(":x", &1i32)], &[(":x", &1i32)],
|r| r.get(0) |r| r.get(0)
) )?
.unwrap()
); );
Ok(())
} }
#[test] #[test]
#[allow(deprecated)] #[allow(deprecated)]
fn test_stmt_execute_named() { fn test_stmt_execute_named() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \ let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
INTEGER)"; INTEGER)";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut stmt = db let mut stmt = db.prepare("INSERT INTO test (name) VALUES (:name)")?;
.prepare("INSERT INTO test (name) VALUES (:name)") stmt.execute_named(&[(":name", &"one")])?;
.unwrap();
stmt.execute_named(&[(":name", &"one")]).unwrap();
let mut stmt = db let mut stmt = db.prepare("SELECT COUNT(*) FROM test WHERE name = :name")?;
.prepare("SELECT COUNT(*) FROM test WHERE name = :name")
.unwrap();
assert_eq!( assert_eq!(
1i32, 1i32,
stmt.query_row_named::<i32, _>(&[(":name", &"one")], |r| r.get(0)) stmt.query_row_named::<i32, _>(&[(":name", &"one")], |r| r.get(0))?
.unwrap()
); );
assert_eq!( assert_eq!(
1i32, 1i32,
stmt.query_row::<i32, _, _>(&[(":name", &"one")], |r| r.get(0)) stmt.query_row::<i32, _, _>(&[(":name", &"one")], |r| r.get(0))?
.unwrap()
); );
Ok(())
} }
#[test] #[test]
#[allow(deprecated)] #[allow(deprecated)]
fn test_query_named() { fn test_query_named() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let sql = r#" let sql = r#"
CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER); CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
INSERT INTO test(id, name) VALUES (1, "one"); INSERT INTO test(id, name) VALUES (1, "one");
"#; "#;
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut stmt = db let mut stmt = db.prepare("SELECT id FROM test where name = :name")?;
.prepare("SELECT id FROM test where name = :name")
.unwrap();
// legacy `_named` api // legacy `_named` api
{ {
let mut rows = stmt.query_named(&[(":name", &"one")]).unwrap(); let mut rows = stmt.query_named(&[(":name", &"one")])?;
let id: Result<i32> = rows.next().unwrap().unwrap().get(0); let id: Result<i32> = rows.next()?.unwrap().get(0);
assert_eq!(Ok(1), id); assert_eq!(Ok(1), id);
} }
// plain api // plain api
{ {
let mut rows = stmt.query(&[(":name", &"one")]).unwrap(); let mut rows = stmt.query(&[(":name", &"one")])?;
let id: Result<i32> = rows.next().unwrap().unwrap().get(0); let id: Result<i32> = rows.next()?.unwrap().get(0);
assert_eq!(Ok(1), id); assert_eq!(Ok(1), id);
} }
Ok(())
} }
#[test] #[test]
#[allow(deprecated)] #[allow(deprecated)]
fn test_query_map_named() { fn test_query_map_named() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let sql = r#" let sql = r#"
CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER); CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
INSERT INTO test(id, name) VALUES (1, "one"); INSERT INTO test(id, name) VALUES (1, "one");
"#; "#;
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut stmt = db let mut stmt = db.prepare("SELECT id FROM test where name = :name")?;
.prepare("SELECT id FROM test where name = :name")
.unwrap();
// legacy `_named` api // legacy `_named` api
{ {
let mut rows = stmt let mut rows = stmt.query_map_named(&[(":name", &"one")], |row| {
.query_map_named(&[(":name", &"one")], |row| { let id: Result<i32> = row.get(0);
let id: Result<i32> = row.get(0); id.map(|i| 2 * i)
id.map(|i| 2 * i) })?;
})
.unwrap();
let doubled_id: i32 = rows.next().unwrap().unwrap(); let doubled_id: i32 = rows.next().unwrap()?;
assert_eq!(2, doubled_id); assert_eq!(2, doubled_id);
} }
// plain api // plain api
{ {
let mut rows = stmt let mut rows = stmt.query_map(&[(":name", &"one")], |row| {
.query_map(&[(":name", &"one")], |row| { let id: Result<i32> = row.get(0);
let id: Result<i32> = row.get(0); id.map(|i| 2 * i)
id.map(|i| 2 * i) })?;
})
.unwrap();
let doubled_id: i32 = rows.next().unwrap().unwrap(); let doubled_id: i32 = rows.next().unwrap()?;
assert_eq!(2, doubled_id); assert_eq!(2, doubled_id);
} }
Ok(())
} }
#[test] #[test]
#[allow(deprecated)] #[allow(deprecated)]
fn test_query_and_then_named() { fn test_query_and_then_named() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let sql = r#" let sql = r#"
CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER); CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
INSERT INTO test(id, name) VALUES (1, "one"); INSERT INTO test(id, name) VALUES (1, "one");
INSERT INTO test(id, name) VALUES (2, "one"); INSERT INTO test(id, name) VALUES (2, "one");
"#; "#;
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut stmt = db let mut stmt = db.prepare("SELECT id FROM test where name = :name ORDER BY id ASC")?;
.prepare("SELECT id FROM test where name = :name ORDER BY id ASC") let mut rows = stmt.query_and_then_named(&[(":name", &"one")], |row| {
.unwrap(); let id: i32 = row.get(0)?;
let mut rows = stmt if id == 1 {
.query_and_then_named(&[(":name", &"one")], |row| { Ok(id)
let id: i32 = row.get(0)?; } else {
if id == 1 { Err(Error::SqliteSingleThreadedMode)
Ok(id) }
} else { })?;
Err(Error::SqliteSingleThreadedMode)
}
})
.unwrap();
// first row should be Ok // first row should be Ok
let doubled_id: i32 = rows.next().unwrap().unwrap(); let doubled_id: i32 = rows.next().unwrap()?;
assert_eq!(1, doubled_id); assert_eq!(1, doubled_id);
// second row should be Err // second row should be Err
@ -1114,34 +1095,31 @@ mod test {
Err(Error::SqliteSingleThreadedMode) => (), Err(Error::SqliteSingleThreadedMode) => (),
Err(_) => panic!("invalid Err"), Err(_) => panic!("invalid Err"),
} }
Ok(())
} }
#[test] #[test]
fn test_query_and_then_by_name() { fn test_query_and_then_by_name() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let sql = r#" let sql = r#"
CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER); CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
INSERT INTO test(id, name) VALUES (1, "one"); INSERT INTO test(id, name) VALUES (1, "one");
INSERT INTO test(id, name) VALUES (2, "one"); INSERT INTO test(id, name) VALUES (2, "one");
"#; "#;
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut stmt = db let mut stmt = db.prepare("SELECT id FROM test where name = :name ORDER BY id ASC")?;
.prepare("SELECT id FROM test where name = :name ORDER BY id ASC") let mut rows = stmt.query_and_then(&[(":name", &"one")], |row| {
.unwrap(); let id: i32 = row.get(0)?;
let mut rows = stmt if id == 1 {
.query_and_then(&[(":name", &"one")], |row| { Ok(id)
let id: i32 = row.get(0)?; } else {
if id == 1 { Err(Error::SqliteSingleThreadedMode)
Ok(id) }
} else { })?;
Err(Error::SqliteSingleThreadedMode)
}
})
.unwrap();
// first row should be Ok // first row should be Ok
let doubled_id: i32 = rows.next().unwrap().unwrap(); let doubled_id: i32 = rows.next().unwrap()?;
assert_eq!(1, doubled_id); assert_eq!(1, doubled_id);
// second row should be Err // second row should be Err
@ -1151,29 +1129,28 @@ mod test {
Err(Error::SqliteSingleThreadedMode) => (), Err(Error::SqliteSingleThreadedMode) => (),
Err(_) => panic!("invalid Err"), Err(_) => panic!("invalid Err"),
} }
Ok(())
} }
#[test] #[test]
#[allow(deprecated)] #[allow(deprecated)]
fn test_unbound_parameters_are_null() { fn test_unbound_parameters_are_null() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let sql = "CREATE TABLE test (x TEXT, y TEXT)"; let sql = "CREATE TABLE test (x TEXT, y TEXT)";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut stmt = db let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)")?;
.prepare("INSERT INTO test (x, y) VALUES (:x, :y)") stmt.execute_named(&[(":x", &"one")])?;
.unwrap();
stmt.execute_named(&[(":x", &"one")]).unwrap();
let result: Option<String> = db let result: Option<String> =
.query_row("SELECT y FROM test WHERE x = 'one'", [], |row| row.get(0)) db.query_row("SELECT y FROM test WHERE x = 'one'", [], |row| row.get(0))?;
.unwrap();
assert!(result.is_none()); assert!(result.is_none());
Ok(())
} }
#[test] #[test]
fn test_raw_binding() -> Result<()> { fn test_raw_binding() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE test (name TEXT, value INTEGER)")?; db.execute_batch("CREATE TABLE test (name TEXT, value INTEGER)")?;
{ {
let mut stmt = db.prepare("INSERT INTO test (name, value) VALUES (:name, ?3)")?; let mut stmt = db.prepare("INSERT INTO test (name, value) VALUES (:name, ?3)")?;
@ -1203,164 +1180,147 @@ mod test {
} }
#[test] #[test]
fn test_unbound_parameters_are_reused() { fn test_unbound_parameters_are_reused() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let sql = "CREATE TABLE test (x TEXT, y TEXT)"; let sql = "CREATE TABLE test (x TEXT, y TEXT)";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut stmt = db let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)")?;
.prepare("INSERT INTO test (x, y) VALUES (:x, :y)") stmt.execute(&[(":x", &"one")])?;
.unwrap(); stmt.execute(&[(":y", &"two")])?;
stmt.execute(&[(":x", &"one")]).unwrap();
stmt.execute(&[(":y", &"two")]).unwrap();
let result: String = db let result: String =
.query_row("SELECT x FROM test WHERE y = 'two'", [], |row| row.get(0)) db.query_row("SELECT x FROM test WHERE y = 'two'", [], |row| row.get(0))?;
.unwrap();
assert_eq!(result, "one"); assert_eq!(result, "one");
Ok(())
} }
#[test] #[test]
fn test_insert() { fn test_insert() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x INTEGER UNIQUE)") db.execute_batch("CREATE TABLE foo(x INTEGER UNIQUE)")?;
.unwrap(); let mut stmt = db.prepare("INSERT OR IGNORE INTO foo (x) VALUES (?)")?;
let mut stmt = db assert_eq!(stmt.insert(&[&1i32])?, 1);
.prepare("INSERT OR IGNORE INTO foo (x) VALUES (?)") assert_eq!(stmt.insert(&[&2i32])?, 2);
.unwrap();
assert_eq!(stmt.insert(&[&1i32]).unwrap(), 1);
assert_eq!(stmt.insert(&[&2i32]).unwrap(), 2);
match stmt.insert(&[&1i32]).unwrap_err() { match stmt.insert(&[&1i32]).unwrap_err() {
Error::StatementChangedRows(0) => (), Error::StatementChangedRows(0) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {}", err),
} }
let mut multi = db let mut multi = db.prepare("INSERT INTO foo (x) SELECT 3 UNION ALL SELECT 4")?;
.prepare("INSERT INTO foo (x) SELECT 3 UNION ALL SELECT 4")
.unwrap();
match multi.insert([]).unwrap_err() { match multi.insert([]).unwrap_err() {
Error::StatementChangedRows(2) => (), Error::StatementChangedRows(2) => (),
err => panic!("Unexpected error {}", err), err => panic!("Unexpected error {}", err),
} }
Ok(())
} }
#[test] #[test]
fn test_insert_different_tables() { fn test_insert_different_tables() -> Result<()> {
// Test for https://github.com/rusqlite/rusqlite/issues/171 // Test for https://github.com/rusqlite/rusqlite/issues/171
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch( db.execute_batch(
r" r"
CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER);
CREATE TABLE bar(x INTEGER); CREATE TABLE bar(x INTEGER);
", ",
) )?;
.unwrap();
assert_eq!( assert_eq!(db.prepare("INSERT INTO foo VALUES (10)")?.insert([])?, 1);
db.prepare("INSERT INTO foo VALUES (10)") assert_eq!(db.prepare("INSERT INTO bar VALUES (10)")?.insert([])?, 1);
.unwrap() Ok(())
.insert([])
.unwrap(),
1
);
assert_eq!(
db.prepare("INSERT INTO bar VALUES (10)")
.unwrap()
.insert([])
.unwrap(),
1
);
} }
#[test] #[test]
fn test_exists() { fn test_exists() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER); CREATE TABLE foo(x INTEGER);
INSERT INTO foo VALUES(1); INSERT INTO foo VALUES(1);
INSERT INTO foo VALUES(2); INSERT INTO foo VALUES(2);
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut stmt = db.prepare("SELECT 1 FROM foo WHERE x = ?").unwrap(); let mut stmt = db.prepare("SELECT 1 FROM foo WHERE x = ?")?;
assert!(stmt.exists([1i32]).unwrap()); assert!(stmt.exists([1i32])?);
assert!(stmt.exists(&[&2i32]).unwrap()); assert!(stmt.exists(&[&2i32])?);
assert!(!stmt.exists([&0i32]).unwrap()); assert!(!stmt.exists([&0i32])?);
Ok(())
} }
#[test] #[test]
fn test_query_row() { fn test_query_row() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y INTEGER); CREATE TABLE foo(x INTEGER, y INTEGER);
INSERT INTO foo VALUES(1, 3); INSERT INTO foo VALUES(1, 3);
INSERT INTO foo VALUES(2, 4); INSERT INTO foo VALUES(2, 4);
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?").unwrap(); let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?")?;
let y: Result<i64> = stmt.query_row([1i32], |r| r.get(0)); let y: Result<i64> = stmt.query_row([1i32], |r| r.get(0));
assert_eq!(3i64, y.unwrap()); assert_eq!(3i64, y?);
Ok(())
} }
#[test] #[test]
fn test_query_by_column_name() { fn test_query_by_column_name() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y INTEGER); CREATE TABLE foo(x INTEGER, y INTEGER);
INSERT INTO foo VALUES(1, 3); INSERT INTO foo VALUES(1, 3);
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut stmt = db.prepare("SELECT y FROM foo").unwrap(); let mut stmt = db.prepare("SELECT y FROM foo")?;
let y: Result<i64> = stmt.query_row([], |r| r.get("y")); let y: Result<i64> = stmt.query_row([], |r| r.get("y"));
assert_eq!(3i64, y.unwrap()); assert_eq!(3i64, y?);
Ok(())
} }
#[test] #[test]
fn test_query_by_column_name_ignore_case() { fn test_query_by_column_name_ignore_case() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let sql = "BEGIN; let sql = "BEGIN;
CREATE TABLE foo(x INTEGER, y INTEGER); CREATE TABLE foo(x INTEGER, y INTEGER);
INSERT INTO foo VALUES(1, 3); INSERT INTO foo VALUES(1, 3);
END;"; END;";
db.execute_batch(sql).unwrap(); db.execute_batch(sql)?;
let mut stmt = db.prepare("SELECT y as Y FROM foo").unwrap(); let mut stmt = db.prepare("SELECT y as Y FROM foo")?;
let y: Result<i64> = stmt.query_row([], |r| r.get("y")); let y: Result<i64> = stmt.query_row([], |r| r.get("y"));
assert_eq!(3i64, y.unwrap()); assert_eq!(3i64, y?);
Ok(())
} }
#[test] #[test]
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
fn test_expanded_sql() { fn test_expanded_sql() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let stmt = db.prepare("SELECT ?").unwrap(); let stmt = db.prepare("SELECT ?")?;
stmt.bind_parameter(&1, 1).unwrap(); stmt.bind_parameter(&1, 1)?;
assert_eq!(Some("SELECT 1".to_owned()), stmt.expanded_sql()); assert_eq!(Some("SELECT 1".to_owned()), stmt.expanded_sql());
Ok(())
} }
#[test] #[test]
fn test_bind_parameters() { fn test_bind_parameters() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
// dynamic slice: // dynamic slice:
db.query_row( db.query_row(
"SELECT ?1, ?2, ?3", "SELECT ?1, ?2, ?3",
&[&1u8 as &dyn ToSql, &"one", &Some("one")], &[&1u8 as &dyn ToSql, &"one", &Some("one")],
|row| row.get::<_, u8>(0), |row| row.get::<_, u8>(0),
) )?;
.unwrap();
// existing collection: // existing collection:
let data = vec![1, 2, 3]; let data = vec![1, 2, 3];
db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| { db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| {
row.get::<_, u8>(0) row.get::<_, u8>(0)
}) })?;
.unwrap();
db.query_row( db.query_row(
"SELECT ?1, ?2, ?3", "SELECT ?1, ?2, ?3",
params_from_iter(data.as_slice()), params_from_iter(data.as_slice()),
|row| row.get::<_, u8>(0), |row| row.get::<_, u8>(0),
) )?;
.unwrap();
db.query_row("SELECT ?1, ?2, ?3", params_from_iter(data), |row| { db.query_row("SELECT ?1, ?2, ?3", params_from_iter(data), |row| {
row.get::<_, u8>(0) row.get::<_, u8>(0)
}) })?;
.unwrap();
use std::collections::BTreeSet; use std::collections::BTreeSet;
let data: BTreeSet<String> = ["one", "two", "three"] let data: BTreeSet<String> = ["one", "two", "three"]
@ -1369,76 +1329,73 @@ mod test {
.collect(); .collect();
db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| { db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| {
row.get::<_, String>(0) row.get::<_, String>(0)
}) })?;
.unwrap();
let data = [0; 3]; let data = [0; 3];
db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| { db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| {
row.get::<_, u8>(0) row.get::<_, u8>(0)
}) })?;
.unwrap();
db.query_row("SELECT ?1, ?2, ?3", params_from_iter(data.iter()), |row| { db.query_row("SELECT ?1, ?2, ?3", params_from_iter(data.iter()), |row| {
row.get::<_, u8>(0) row.get::<_, u8>(0)
}) })?;
.unwrap(); Ok(())
} }
#[test] #[test]
fn test_empty_stmt() { fn test_empty_stmt() -> Result<()> {
let conn = Connection::open_in_memory().unwrap(); let conn = Connection::open_in_memory()?;
let mut stmt = conn.prepare("").unwrap(); let mut stmt = conn.prepare("")?;
assert_eq!(0, stmt.column_count()); assert_eq!(0, stmt.column_count());
assert!(stmt.parameter_index("test").is_ok()); assert!(stmt.parameter_index("test").is_ok());
assert!(stmt.step().is_err()); assert!(stmt.step().is_err());
stmt.reset(); stmt.reset();
assert!(stmt.execute([]).is_err()); assert!(stmt.execute([]).is_err());
Ok(())
} }
#[test] #[test]
fn test_comment_stmt() { fn test_comment_stmt() -> Result<()> {
let conn = Connection::open_in_memory().unwrap(); let conn = Connection::open_in_memory()?;
conn.prepare("/*SELECT 1;*/").unwrap(); conn.prepare("/*SELECT 1;*/")?;
Ok(())
} }
#[test] #[test]
fn test_comment_and_sql_stmt() { fn test_comment_and_sql_stmt() -> Result<()> {
let conn = Connection::open_in_memory().unwrap(); let conn = Connection::open_in_memory()?;
let stmt = conn.prepare("/*...*/ SELECT 1;").unwrap(); let stmt = conn.prepare("/*...*/ SELECT 1;")?;
assert_eq!(1, stmt.column_count()); assert_eq!(1, stmt.column_count());
Ok(())
} }
#[test] #[test]
fn test_semi_colon_stmt() { fn test_semi_colon_stmt() -> Result<()> {
let conn = Connection::open_in_memory().unwrap(); let conn = Connection::open_in_memory()?;
let stmt = conn.prepare(";").unwrap(); let stmt = conn.prepare(";")?;
assert_eq!(0, stmt.column_count()); assert_eq!(0, stmt.column_count());
Ok(())
} }
#[test] #[test]
fn test_utf16_conversion() { fn test_utf16_conversion() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.pragma_update(None, "encoding", &"UTF-16le").unwrap(); db.pragma_update(None, "encoding", &"UTF-16le")?;
let encoding: String = db let encoding: String = db.pragma_query_value(None, "encoding", |row| row.get(0))?;
.pragma_query_value(None, "encoding", |row| row.get(0))
.unwrap();
assert_eq!("UTF-16le", encoding); assert_eq!("UTF-16le", encoding);
db.execute_batch("CREATE TABLE foo(x TEXT)").unwrap(); db.execute_batch("CREATE TABLE foo(x TEXT)")?;
let expected = "テスト"; let expected = "テスト";
db.execute("INSERT INTO foo(x) VALUES (?)", &[&expected]) db.execute("INSERT INTO foo(x) VALUES (?)", &[&expected])?;
.unwrap(); let actual: String = db.query_row("SELECT x FROM foo", [], |row| row.get(0))?;
let actual: String = db
.query_row("SELECT x FROM foo", [], |row| row.get(0))
.unwrap();
assert_eq!(expected, actual); assert_eq!(expected, actual);
Ok(())
} }
#[test] #[test]
fn test_nul_byte() { fn test_nul_byte() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
let expected = "a\x00b"; let expected = "a\x00b";
let actual: String = db let actual: String = db.query_row("SELECT ?", [expected], |row| row.get(0))?;
.query_row("SELECT ?", [expected], |row| row.get(0))
.unwrap();
assert_eq!(expected, actual); assert_eq!(expected, actual);
Ok(())
} }
} }

View File

@ -128,10 +128,10 @@ mod test {
use std::sync::Mutex; use std::sync::Mutex;
use std::time::Duration; use std::time::Duration;
use crate::Connection; use crate::{Connection, Result};
#[test] #[test]
fn test_trace() { fn test_trace() -> Result<()> {
lazy_static! { lazy_static! {
static ref TRACED_STMTS: Mutex<Vec<String>> = Mutex::new(Vec::new()); static ref TRACED_STMTS: Mutex<Vec<String>> = Mutex::new(Vec::new());
} }
@ -140,7 +140,7 @@ mod test {
traced_stmts.push(s.to_owned()); traced_stmts.push(s.to_owned());
} }
let mut db = Connection::open_in_memory().unwrap(); let mut db = Connection::open_in_memory()?;
db.trace(Some(tracer)); db.trace(Some(tracer));
{ {
let _ = db.query_row("SELECT ?", &[&1i32], |_| Ok(())); let _ = db.query_row("SELECT ?", &[&1i32], |_| Ok(()));
@ -156,10 +156,11 @@ mod test {
assert_eq!(traced_stmts.len(), 2); assert_eq!(traced_stmts.len(), 2);
assert_eq!(traced_stmts[0], "SELECT 1"); assert_eq!(traced_stmts[0], "SELECT 1");
assert_eq!(traced_stmts[1], "SELECT 'hello'"); assert_eq!(traced_stmts[1], "SELECT 'hello'");
Ok(())
} }
#[test] #[test]
fn test_profile() { fn test_profile() -> Result<()> {
lazy_static! { lazy_static! {
static ref PROFILED: Mutex<Vec<(String, Duration)>> = Mutex::new(Vec::new()); static ref PROFILED: Mutex<Vec<(String, Duration)>> = Mutex::new(Vec::new());
} }
@ -168,14 +169,15 @@ mod test {
profiled.push((s.to_owned(), d)); profiled.push((s.to_owned(), d));
} }
let mut db = Connection::open_in_memory().unwrap(); let mut db = Connection::open_in_memory()?;
db.profile(Some(profiler)); db.profile(Some(profiler));
db.execute_batch("PRAGMA application_id = 1").unwrap(); db.execute_batch("PRAGMA application_id = 1")?;
db.profile(None); db.profile(None);
db.execute_batch("PRAGMA application_id = 2").unwrap(); db.execute_batch("PRAGMA application_id = 2")?;
let profiled = PROFILED.lock().unwrap(); let profiled = PROFILED.lock().unwrap();
assert_eq!(profiled.len(), 1); assert_eq!(profiled.len(), 1);
assert_eq!(profiled[0].0, "PRAGMA application_id = 1"); assert_eq!(profiled[0].0, "PRAGMA application_id = 1");
Ok(())
} }
} }

View File

@ -500,35 +500,35 @@ impl Connection {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::DropBehavior; use super::DropBehavior;
use crate::{Connection, Error}; use crate::{Connection, Error, Result};
fn checked_memory_handle() -> Connection { fn checked_memory_handle() -> Result<Connection> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (x INTEGER)").unwrap(); db.execute_batch("CREATE TABLE foo (x INTEGER)")?;
db Ok(db)
} }
#[test] #[test]
fn test_drop() { fn test_drop() -> Result<()> {
let mut db = checked_memory_handle(); let mut db = checked_memory_handle()?;
{ {
let tx = db.transaction().unwrap(); let tx = db.transaction()?;
tx.execute_batch("INSERT INTO foo VALUES(1)").unwrap(); tx.execute_batch("INSERT INTO foo VALUES(1)")?;
// default: rollback // default: rollback
} }
{ {
let mut tx = db.transaction().unwrap(); let mut tx = db.transaction()?;
tx.execute_batch("INSERT INTO foo VALUES(2)").unwrap(); tx.execute_batch("INSERT INTO foo VALUES(2)")?;
tx.set_drop_behavior(DropBehavior::Commit) tx.set_drop_behavior(DropBehavior::Commit)
} }
{ {
let tx = db.transaction().unwrap(); let tx = db.transaction()?;
assert_eq!( assert_eq!(
2i32, 2i32,
tx.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0)) tx.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?
.unwrap()
); );
} }
Ok(())
} }
fn assert_nested_tx_error(e: crate::Error) { fn assert_nested_tx_error(e: crate::Error) {
if let Error::SqliteFailure(e, Some(m)) = &e { if let Error::SqliteFailure(e, Some(m)) = &e {
@ -542,165 +542,168 @@ mod test {
} }
#[test] #[test]
fn test_unchecked_nesting() { fn test_unchecked_nesting() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
{ {
let tx = db.unchecked_transaction().unwrap(); let tx = db.unchecked_transaction()?;
let e = tx.unchecked_transaction().unwrap_err(); let e = tx.unchecked_transaction().unwrap_err();
assert_nested_tx_error(e); assert_nested_tx_error(e);
// default: rollback // default: rollback
} }
{ {
let tx = db.unchecked_transaction().unwrap(); let tx = db.unchecked_transaction()?;
tx.execute_batch("INSERT INTO foo VALUES(1)").unwrap(); tx.execute_batch("INSERT INTO foo VALUES(1)")?;
// Ensure this doesn't interfere with ongoing transaction // Ensure this doesn't interfere with ongoing transaction
let e = tx.unchecked_transaction().unwrap_err(); let e = tx.unchecked_transaction().unwrap_err();
assert_nested_tx_error(e); assert_nested_tx_error(e);
tx.execute_batch("INSERT INTO foo VALUES(1)").unwrap(); tx.execute_batch("INSERT INTO foo VALUES(1)")?;
tx.commit().unwrap(); tx.commit()?;
} }
assert_eq!( assert_eq!(
2i32, 2i32,
db.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0)) db.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?
.unwrap()
); );
Ok(())
} }
#[test] #[test]
fn test_explicit_rollback_commit() { fn test_explicit_rollback_commit() -> Result<()> {
let mut db = checked_memory_handle(); let mut db = checked_memory_handle()?;
{ {
let mut tx = db.transaction().unwrap(); let mut tx = db.transaction()?;
{ {
let mut sp = tx.savepoint().unwrap(); let mut sp = tx.savepoint()?;
sp.execute_batch("INSERT INTO foo VALUES(1)").unwrap(); sp.execute_batch("INSERT INTO foo VALUES(1)")?;
sp.rollback().unwrap(); sp.rollback()?;
sp.execute_batch("INSERT INTO foo VALUES(2)").unwrap(); sp.execute_batch("INSERT INTO foo VALUES(2)")?;
sp.commit().unwrap(); sp.commit()?;
} }
tx.commit().unwrap(); tx.commit()?;
} }
{ {
let tx = db.transaction().unwrap(); let tx = db.transaction()?;
tx.execute_batch("INSERT INTO foo VALUES(4)").unwrap(); tx.execute_batch("INSERT INTO foo VALUES(4)")?;
tx.commit().unwrap(); tx.commit()?;
} }
{ {
let tx = db.transaction().unwrap(); let tx = db.transaction()?;
assert_eq!( assert_eq!(
6i32, 6i32,
tx.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0)) tx.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?
.unwrap()
); );
} }
Ok(())
} }
#[test] #[test]
fn test_savepoint() { fn test_savepoint() -> Result<()> {
let mut db = checked_memory_handle(); let mut db = checked_memory_handle()?;
{ {
let mut tx = db.transaction().unwrap(); let mut tx = db.transaction()?;
tx.execute_batch("INSERT INTO foo VALUES(1)").unwrap(); tx.execute_batch("INSERT INTO foo VALUES(1)")?;
assert_current_sum(1, &tx); assert_current_sum(1, &tx)?;
tx.set_drop_behavior(DropBehavior::Commit); tx.set_drop_behavior(DropBehavior::Commit);
{ {
let mut sp1 = tx.savepoint().unwrap(); let mut sp1 = tx.savepoint()?;
sp1.execute_batch("INSERT INTO foo VALUES(2)").unwrap(); sp1.execute_batch("INSERT INTO foo VALUES(2)")?;
assert_current_sum(3, &sp1); assert_current_sum(3, &sp1)?;
// will rollback sp1 // will rollback sp1
{ {
let mut sp2 = sp1.savepoint().unwrap(); let mut sp2 = sp1.savepoint()?;
sp2.execute_batch("INSERT INTO foo VALUES(4)").unwrap(); sp2.execute_batch("INSERT INTO foo VALUES(4)")?;
assert_current_sum(7, &sp2); assert_current_sum(7, &sp2)?;
// will rollback sp2 // will rollback sp2
{ {
let sp3 = sp2.savepoint().unwrap(); let sp3 = sp2.savepoint()?;
sp3.execute_batch("INSERT INTO foo VALUES(8)").unwrap(); sp3.execute_batch("INSERT INTO foo VALUES(8)")?;
assert_current_sum(15, &sp3); assert_current_sum(15, &sp3)?;
sp3.commit().unwrap(); sp3.commit()?;
// committed sp3, but will be erased by sp2 rollback // committed sp3, but will be erased by sp2 rollback
} }
assert_current_sum(15, &sp2); assert_current_sum(15, &sp2)?;
} }
assert_current_sum(3, &sp1); assert_current_sum(3, &sp1)?;
} }
assert_current_sum(1, &tx); assert_current_sum(1, &tx)?;
} }
assert_current_sum(1, &db); assert_current_sum(1, &db)?;
Ok(())
} }
#[test] #[test]
fn test_ignore_drop_behavior() { fn test_ignore_drop_behavior() -> Result<()> {
let mut db = checked_memory_handle(); let mut db = checked_memory_handle()?;
let mut tx = db.transaction().unwrap(); let mut tx = db.transaction()?;
{ {
let mut sp1 = tx.savepoint().unwrap(); let mut sp1 = tx.savepoint()?;
insert(1, &sp1); insert(1, &sp1)?;
sp1.rollback().unwrap(); sp1.rollback()?;
insert(2, &sp1); insert(2, &sp1)?;
{ {
let mut sp2 = sp1.savepoint().unwrap(); let mut sp2 = sp1.savepoint()?;
sp2.set_drop_behavior(DropBehavior::Ignore); sp2.set_drop_behavior(DropBehavior::Ignore);
insert(4, &sp2); insert(4, &sp2)?;
} }
assert_current_sum(6, &sp1); assert_current_sum(6, &sp1)?;
sp1.commit().unwrap(); sp1.commit()?;
} }
assert_current_sum(6, &tx); assert_current_sum(6, &tx)?;
Ok(())
} }
#[test] #[test]
fn test_savepoint_names() { fn test_savepoint_names() -> Result<()> {
let mut db = checked_memory_handle(); let mut db = checked_memory_handle()?;
{ {
let mut sp1 = db.savepoint_with_name("my_sp").unwrap(); let mut sp1 = db.savepoint_with_name("my_sp")?;
insert(1, &sp1); insert(1, &sp1)?;
assert_current_sum(1, &sp1); assert_current_sum(1, &sp1)?;
{ {
let mut sp2 = sp1.savepoint_with_name("my_sp").unwrap(); let mut sp2 = sp1.savepoint_with_name("my_sp")?;
sp2.set_drop_behavior(DropBehavior::Commit); sp2.set_drop_behavior(DropBehavior::Commit);
insert(2, &sp2); insert(2, &sp2)?;
assert_current_sum(3, &sp2); assert_current_sum(3, &sp2)?;
sp2.rollback().unwrap(); sp2.rollback()?;
assert_current_sum(1, &sp2); assert_current_sum(1, &sp2)?;
insert(4, &sp2); insert(4, &sp2)?;
} }
assert_current_sum(5, &sp1); assert_current_sum(5, &sp1)?;
sp1.rollback().unwrap(); sp1.rollback()?;
{ {
let mut sp2 = sp1.savepoint_with_name("my_sp").unwrap(); let mut sp2 = sp1.savepoint_with_name("my_sp")?;
sp2.set_drop_behavior(DropBehavior::Ignore); sp2.set_drop_behavior(DropBehavior::Ignore);
insert(8, &sp2); insert(8, &sp2)?;
} }
assert_current_sum(8, &sp1); assert_current_sum(8, &sp1)?;
sp1.commit().unwrap(); sp1.commit()?;
} }
assert_current_sum(8, &db); assert_current_sum(8, &db)?;
Ok(())
} }
#[test] #[test]
fn test_rc() { fn test_rc() -> Result<()> {
use std::rc::Rc; use std::rc::Rc;
let mut conn = Connection::open_in_memory().unwrap(); let mut conn = Connection::open_in_memory()?;
let rc_txn = Rc::new(conn.transaction().unwrap()); let rc_txn = Rc::new(conn.transaction()?);
// This will compile only if Transaction is Debug // This will compile only if Transaction is Debug
Rc::try_unwrap(rc_txn).unwrap(); Rc::try_unwrap(rc_txn).unwrap();
Ok(())
} }
fn insert(x: i32, conn: &Connection) { fn insert(x: i32, conn: &Connection) -> Result<usize> {
conn.execute("INSERT INTO foo VALUES(?)", [x]).unwrap(); conn.execute("INSERT INTO foo VALUES(?)", [x])
} }
fn assert_current_sum(x: i32, conn: &Connection) { fn assert_current_sum(x: i32, conn: &Connection) -> Result<()> {
let i = conn let i = conn.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))?;
.query_row::<i32, _, _>("SELECT SUM(x) FROM foo", [], |r| r.get(0))
.unwrap();
assert_eq!(x, i); assert_eq!(x, i);
Ok(())
} }
} }

View File

@ -137,114 +137,109 @@ mod test {
use crate::{Connection, Result}; use crate::{Connection, Result};
use chrono::{DateTime, Duration, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc}; use chrono::{DateTime, Duration, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
fn checked_memory_handle() -> Connection { fn checked_memory_handle() -> Result<Connection> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT, b BLOB)") db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT, b BLOB)")?;
.unwrap(); Ok(db)
db
} }
#[test] #[test]
fn test_naive_date() { fn test_naive_date() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let date = NaiveDate::from_ymd(2016, 2, 23); let date = NaiveDate::from_ymd(2016, 2, 23);
db.execute("INSERT INTO foo (t) VALUES (?)", &[&date]) db.execute("INSERT INTO foo (t) VALUES (?)", &[&date])?;
.unwrap();
let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!("2016-02-23", s); assert_eq!("2016-02-23", s);
let t: NaiveDate = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let t: NaiveDate = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!(date, t); assert_eq!(date, t);
Ok(())
} }
#[test] #[test]
fn test_naive_time() { fn test_naive_time() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let time = NaiveTime::from_hms(23, 56, 4); let time = NaiveTime::from_hms(23, 56, 4);
db.execute("INSERT INTO foo (t) VALUES (?)", &[&time]) db.execute("INSERT INTO foo (t) VALUES (?)", &[&time])?;
.unwrap();
let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!("23:56:04", s); assert_eq!("23:56:04", s);
let v: NaiveTime = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let v: NaiveTime = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!(time, v); assert_eq!(time, v);
Ok(())
} }
#[test] #[test]
fn test_naive_date_time() { fn test_naive_date_time() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let date = NaiveDate::from_ymd(2016, 2, 23); let date = NaiveDate::from_ymd(2016, 2, 23);
let time = NaiveTime::from_hms(23, 56, 4); let time = NaiveTime::from_hms(23, 56, 4);
let dt = NaiveDateTime::new(date, time); let dt = NaiveDateTime::new(date, time);
db.execute("INSERT INTO foo (t) VALUES (?)", &[&dt]) db.execute("INSERT INTO foo (t) VALUES (?)", &[&dt])?;
.unwrap();
let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!("2016-02-23T23:56:04", s); assert_eq!("2016-02-23T23:56:04", s);
let v: NaiveDateTime = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let v: NaiveDateTime = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!(dt, v); assert_eq!(dt, v);
db.execute("UPDATE foo set b = datetime(t)", []).unwrap(); // "YYYY-MM-DD HH:MM:SS" db.execute("UPDATE foo set b = datetime(t)", [])?; // "YYYY-MM-DD HH:MM:SS"
let hms: NaiveDateTime = db.query_row("SELECT b FROM foo", [], |r| r.get(0)).unwrap(); let hms: NaiveDateTime = db.query_row("SELECT b FROM foo", [], |r| r.get(0))?;
assert_eq!(dt, hms); assert_eq!(dt, hms);
Ok(())
} }
#[test] #[test]
fn test_date_time_utc() { fn test_date_time_utc() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let date = NaiveDate::from_ymd(2016, 2, 23); let date = NaiveDate::from_ymd(2016, 2, 23);
let time = NaiveTime::from_hms_milli(23, 56, 4, 789); let time = NaiveTime::from_hms_milli(23, 56, 4, 789);
let dt = NaiveDateTime::new(date, time); let dt = NaiveDateTime::new(date, time);
let utc = Utc.from_utc_datetime(&dt); let utc = Utc.from_utc_datetime(&dt);
db.execute("INSERT INTO foo (t) VALUES (?)", &[&utc]) db.execute("INSERT INTO foo (t) VALUES (?)", &[&utc])?;
.unwrap();
let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!("2016-02-23T23:56:04.789+00:00", s); assert_eq!("2016-02-23T23:56:04.789+00:00", s);
let v1: DateTime<Utc> = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let v1: DateTime<Utc> = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!(utc, v1); assert_eq!(utc, v1);
let v2: DateTime<Utc> = db let v2: DateTime<Utc> =
.query_row("SELECT '2016-02-23 23:56:04.789'", [], |r| r.get(0)) db.query_row("SELECT '2016-02-23 23:56:04.789'", [], |r| r.get(0))?;
.unwrap();
assert_eq!(utc, v2); assert_eq!(utc, v2);
let v3: DateTime<Utc> = db let v3: DateTime<Utc> = db.query_row("SELECT '2016-02-23 23:56:04'", [], |r| r.get(0))?;
.query_row("SELECT '2016-02-23 23:56:04'", [], |r| r.get(0))
.unwrap();
assert_eq!(utc - Duration::milliseconds(789), v3); assert_eq!(utc - Duration::milliseconds(789), v3);
let v4: DateTime<Utc> = db let v4: DateTime<Utc> =
.query_row("SELECT '2016-02-23 23:56:04.789+00:00'", [], |r| r.get(0)) db.query_row("SELECT '2016-02-23 23:56:04.789+00:00'", [], |r| r.get(0))?;
.unwrap();
assert_eq!(utc, v4); assert_eq!(utc, v4);
Ok(())
} }
#[test] #[test]
fn test_date_time_local() { fn test_date_time_local() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let date = NaiveDate::from_ymd(2016, 2, 23); let date = NaiveDate::from_ymd(2016, 2, 23);
let time = NaiveTime::from_hms_milli(23, 56, 4, 789); let time = NaiveTime::from_hms_milli(23, 56, 4, 789);
let dt = NaiveDateTime::new(date, time); let dt = NaiveDateTime::new(date, time);
let local = Local.from_local_datetime(&dt).single().unwrap(); let local = Local.from_local_datetime(&dt).single().unwrap();
db.execute("INSERT INTO foo (t) VALUES (?)", &[&local]) db.execute("INSERT INTO foo (t) VALUES (?)", &[&local])?;
.unwrap();
// Stored string should be in UTC // Stored string should be in UTC
let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let s: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert!(s.ends_with("+00:00")); assert!(s.ends_with("+00:00"));
let v: DateTime<Local> = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let v: DateTime<Local> = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!(local, v); assert_eq!(local, v);
Ok(())
} }
#[test] #[test]
fn test_sqlite_functions() { fn test_sqlite_functions() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let result: Result<NaiveTime> = db.query_row("SELECT CURRENT_TIME", [], |r| r.get(0)); let result: Result<NaiveTime> = db.query_row("SELECT CURRENT_TIME", [], |r| r.get(0));
assert!(result.is_ok()); assert!(result.is_ok());
let result: Result<NaiveDate> = db.query_row("SELECT CURRENT_DATE", [], |r| r.get(0)); let result: Result<NaiveDate> = db.query_row("SELECT CURRENT_DATE", [], |r| r.get(0));
@ -255,5 +250,6 @@ mod test {
let result: Result<DateTime<Utc>> = let result: Result<DateTime<Utc>> =
db.query_row("SELECT CURRENT_TIMESTAMP", [], |r| r.get(0)); db.query_row("SELECT CURRENT_TIMESTAMP", [], |r| r.get(0));
assert!(result.is_ok()); assert!(result.is_ok());
Ok(())
} }
} }

View File

@ -235,15 +235,11 @@ impl FromSql for Value {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::FromSql; use super::FromSql;
use crate::{Connection, Error}; use crate::{Connection, Error, Result};
fn checked_memory_handle() -> Connection {
Connection::open_in_memory().unwrap()
}
#[test] #[test]
fn test_integral_ranges() { fn test_integral_ranges() -> Result<()> {
let db = checked_memory_handle(); let db = Connection::open_in_memory()?;
fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64]) fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64])
where where
@ -278,5 +274,6 @@ mod test {
check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]); check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]);
check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]); check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]);
check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]); check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
Ok(())
} }
} }

View File

@ -131,95 +131,92 @@ impl fmt::Display for Type {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::Value; use super::Value;
use crate::{params, Connection, Error, Statement}; use crate::{params, Connection, Error, Result, Statement};
use std::f64::EPSILON; use std::f64::EPSILON;
use std::os::raw::{c_double, c_int}; use std::os::raw::{c_double, c_int};
fn checked_memory_handle() -> Connection { fn checked_memory_handle() -> Result<Connection> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (b BLOB, t TEXT, i INTEGER, f FLOAT, n)") db.execute_batch("CREATE TABLE foo (b BLOB, t TEXT, i INTEGER, f FLOAT, n)")?;
.unwrap(); Ok(db)
db
} }
#[test] #[test]
fn test_blob() { fn test_blob() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let v1234 = vec![1u8, 2, 3, 4]; let v1234 = vec![1u8, 2, 3, 4];
db.execute("INSERT INTO foo(b) VALUES (?)", &[&v1234]) db.execute("INSERT INTO foo(b) VALUES (?)", &[&v1234])?;
.unwrap();
let v: Vec<u8> = db.query_row("SELECT b FROM foo", [], |r| r.get(0)).unwrap(); let v: Vec<u8> = db.query_row("SELECT b FROM foo", [], |r| r.get(0))?;
assert_eq!(v, v1234); assert_eq!(v, v1234);
Ok(())
} }
#[test] #[test]
fn test_empty_blob() { fn test_empty_blob() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let empty = vec![]; let empty = vec![];
db.execute("INSERT INTO foo(b) VALUES (?)", &[&empty]) db.execute("INSERT INTO foo(b) VALUES (?)", &[&empty])?;
.unwrap();
let v: Vec<u8> = db.query_row("SELECT b FROM foo", [], |r| r.get(0)).unwrap(); let v: Vec<u8> = db.query_row("SELECT b FROM foo", [], |r| r.get(0))?;
assert_eq!(v, empty); assert_eq!(v, empty);
Ok(())
} }
#[test] #[test]
fn test_str() { fn test_str() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let s = "hello, world!"; let s = "hello, world!";
db.execute("INSERT INTO foo(t) VALUES (?)", &[&s]).unwrap(); db.execute("INSERT INTO foo(t) VALUES (?)", &[&s])?;
let from: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let from: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!(from, s); assert_eq!(from, s);
Ok(())
} }
#[test] #[test]
fn test_string() { fn test_string() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let s = "hello, world!"; let s = "hello, world!";
db.execute("INSERT INTO foo(t) VALUES (?)", [s.to_owned()]) db.execute("INSERT INTO foo(t) VALUES (?)", [s.to_owned()])?;
.unwrap();
let from: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let from: String = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!(from, s); assert_eq!(from, s);
Ok(())
} }
#[test] #[test]
fn test_value() { fn test_value() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
db.execute("INSERT INTO foo(i) VALUES (?)", [Value::Integer(10)]) db.execute("INSERT INTO foo(i) VALUES (?)", [Value::Integer(10)])?;
.unwrap();
assert_eq!( assert_eq!(
10i64, 10i64,
db.query_row::<i64, _, _>("SELECT i FROM foo", [], |r| r.get(0)) db.query_row::<i64, _, _>("SELECT i FROM foo", [], |r| r.get(0))?
.unwrap()
); );
Ok(())
} }
#[test] #[test]
fn test_option() { fn test_option() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let s = Some("hello, world!"); let s = Some("hello, world!");
let b = Some(vec![1u8, 2, 3, 4]); let b = Some(vec![1u8, 2, 3, 4]);
db.execute("INSERT INTO foo(t) VALUES (?)", &[&s]).unwrap(); db.execute("INSERT INTO foo(t) VALUES (?)", &[&s])?;
db.execute("INSERT INTO foo(b) VALUES (?)", &[&b]).unwrap(); db.execute("INSERT INTO foo(b) VALUES (?)", &[&b])?;
let mut stmt = db let mut stmt = db.prepare("SELECT t, b FROM foo ORDER BY ROWID ASC")?;
.prepare("SELECT t, b FROM foo ORDER BY ROWID ASC") let mut rows = stmt.query([])?;
.unwrap();
let mut rows = stmt.query([]).unwrap();
{ {
let row1 = rows.next().unwrap().unwrap(); let row1 = rows.next()?.unwrap();
let s1: Option<String> = row1.get_unwrap(0); let s1: Option<String> = row1.get_unwrap(0);
let b1: Option<Vec<u8>> = row1.get_unwrap(1); let b1: Option<Vec<u8>> = row1.get_unwrap(1);
assert_eq!(s.unwrap(), s1.unwrap()); assert_eq!(s.unwrap(), s1.unwrap());
@ -227,42 +224,42 @@ mod test {
} }
{ {
let row2 = rows.next().unwrap().unwrap(); let row2 = rows.next()?.unwrap();
let s2: Option<String> = row2.get_unwrap(0); let s2: Option<String> = row2.get_unwrap(0);
let b2: Option<Vec<u8>> = row2.get_unwrap(1); let b2: Option<Vec<u8>> = row2.get_unwrap(1);
assert!(s2.is_none()); assert!(s2.is_none());
assert_eq!(b, b2); assert_eq!(b, b2);
} }
Ok(())
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
fn test_mismatched_types() { fn test_mismatched_types() -> Result<()> {
fn is_invalid_column_type(err: Error) -> bool { fn is_invalid_column_type(err: Error) -> bool {
matches!(err, Error::InvalidColumnType(..)) matches!(err, Error::InvalidColumnType(..))
} }
let db = checked_memory_handle(); let db = checked_memory_handle()?;
db.execute( db.execute(
"INSERT INTO foo(b, t, i, f) VALUES (X'0102', 'text', 1, 1.5)", "INSERT INTO foo(b, t, i, f) VALUES (X'0102', 'text', 1, 1.5)",
[], [],
) )?;
.unwrap();
let mut stmt = db.prepare("SELECT b, t, i, f, n FROM foo").unwrap(); let mut stmt = db.prepare("SELECT b, t, i, f, n FROM foo")?;
let mut rows = stmt.query([]).unwrap(); let mut rows = stmt.query([])?;
let row = rows.next().unwrap().unwrap(); let row = rows.next()?.unwrap();
// check the correct types come back as expected // check the correct types come back as expected
assert_eq!(vec![1, 2], row.get::<_, Vec<u8>>(0).unwrap()); assert_eq!(vec![1, 2], row.get::<_, Vec<u8>>(0)?);
assert_eq!("text", row.get::<_, String>(1).unwrap()); assert_eq!("text", row.get::<_, String>(1)?);
assert_eq!(1, row.get::<_, c_int>(2).unwrap()); assert_eq!(1, row.get::<_, c_int>(2)?);
assert!((1.5 - row.get::<_, c_double>(3).unwrap()).abs() < EPSILON); assert!((1.5 - row.get::<_, c_double>(3)?).abs() < EPSILON);
assert_eq!(row.get::<_, Option<c_int>>(4).unwrap(), None); assert_eq!(row.get::<_, Option<c_int>>(4)?, None);
assert_eq!(row.get::<_, Option<c_double>>(4).unwrap(), None); assert_eq!(row.get::<_, Option<c_double>>(4)?, None);
assert_eq!(row.get::<_, Option<String>>(4).unwrap(), None); assert_eq!(row.get::<_, Option<String>>(4)?, None);
// check some invalid types // check some invalid types
@ -347,58 +344,50 @@ mod test {
assert!(is_invalid_column_type( assert!(is_invalid_column_type(
row.get::<_, time::OffsetDateTime>(4).err().unwrap() row.get::<_, time::OffsetDateTime>(4).err().unwrap()
)); ));
Ok(())
} }
#[test] #[test]
fn test_dynamic_type() { fn test_dynamic_type() -> Result<()> {
use super::Value; use super::Value;
let db = checked_memory_handle(); let db = checked_memory_handle()?;
db.execute( db.execute(
"INSERT INTO foo(b, t, i, f) VALUES (X'0102', 'text', 1, 1.5)", "INSERT INTO foo(b, t, i, f) VALUES (X'0102', 'text', 1, 1.5)",
[], [],
) )?;
.unwrap();
let mut stmt = db.prepare("SELECT b, t, i, f, n FROM foo").unwrap(); let mut stmt = db.prepare("SELECT b, t, i, f, n FROM foo")?;
let mut rows = stmt.query([]).unwrap(); let mut rows = stmt.query([])?;
let row = rows.next().unwrap().unwrap(); let row = rows.next()?.unwrap();
assert_eq!(Value::Blob(vec![1, 2]), row.get::<_, Value>(0).unwrap()); assert_eq!(Value::Blob(vec![1, 2]), row.get::<_, Value>(0)?);
assert_eq!( assert_eq!(Value::Text(String::from("text")), row.get::<_, Value>(1)?);
Value::Text(String::from("text")), assert_eq!(Value::Integer(1), row.get::<_, Value>(2)?);
row.get::<_, Value>(1).unwrap() match row.get::<_, Value>(3)? {
);
assert_eq!(Value::Integer(1), row.get::<_, Value>(2).unwrap());
match row.get::<_, Value>(3).unwrap() {
Value::Real(val) => assert!((1.5 - val).abs() < EPSILON), Value::Real(val) => assert!((1.5 - val).abs() < EPSILON),
x => panic!("Invalid Value {:?}", x), x => panic!("Invalid Value {:?}", x),
} }
assert_eq!(Value::Null, row.get::<_, Value>(4).unwrap()); assert_eq!(Value::Null, row.get::<_, Value>(4)?);
Ok(())
} }
macro_rules! test_conversion { macro_rules! test_conversion {
($db_etc:ident, $insert_value:expr, $get_type:ty,expect $expected_value:expr) => { ($db_etc:ident, $insert_value:expr, $get_type:ty,expect $expected_value:expr) => {
$db_etc $db_etc.insert_statement.execute(params![$insert_value])?;
.insert_statement
.execute(params![$insert_value])
.unwrap();
let res = $db_etc let res = $db_etc
.query_statement .query_statement
.query_row([], |row| row.get::<_, $get_type>(0)); .query_row([], |row| row.get::<_, $get_type>(0));
assert_eq!(res.unwrap(), $expected_value); assert_eq!(res?, $expected_value);
$db_etc.delete_statement.execute([]).unwrap(); $db_etc.delete_statement.execute([])?;
}; };
($db_etc:ident, $insert_value:expr, $get_type:ty,expect_from_sql_error) => { ($db_etc:ident, $insert_value:expr, $get_type:ty,expect_from_sql_error) => {
$db_etc $db_etc.insert_statement.execute(params![$insert_value])?;
.insert_statement
.execute(params![$insert_value])
.unwrap();
let res = $db_etc let res = $db_etc
.query_statement .query_statement
.query_row([], |row| row.get::<_, $get_type>(0)); .query_row([], |row| row.get::<_, $get_type>(0));
res.unwrap_err(); res.unwrap_err();
$db_etc.delete_statement.execute([]).unwrap(); $db_etc.delete_statement.execute([])?;
}; };
($db_etc:ident, $insert_value:expr, $get_type:ty,expect_to_sql_error) => { ($db_etc:ident, $insert_value:expr, $get_type:ty,expect_to_sql_error) => {
$db_etc $db_etc
@ -409,12 +398,12 @@ mod test {
} }
#[test] #[test]
fn test_numeric_conversions() { fn test_numeric_conversions() -> Result<()> {
#![allow(clippy::float_cmp)] #![allow(clippy::float_cmp)]
// Test what happens when we store an f32 and retrieve an i32 etc. // Test what happens when we store an f32 and retrieve an i32 etc.
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (x)").unwrap(); db.execute_batch("CREATE TABLE foo (x)")?;
// SQLite actually ignores the column types, so we just need to test // SQLite actually ignores the column types, so we just need to test
// different numeric values. // different numeric values.
@ -426,9 +415,9 @@ mod test {
} }
let mut db_etc = DbEtc { let mut db_etc = DbEtc {
insert_statement: db.prepare("INSERT INTO foo VALUES (?1)").unwrap(), insert_statement: db.prepare("INSERT INTO foo VALUES (?1)")?,
query_statement: db.prepare("SELECT x FROM foo").unwrap(), query_statement: db.prepare("SELECT x FROM foo")?,
delete_statement: db.prepare("DELETE FROM foo").unwrap(), delete_statement: db.prepare("DELETE FROM foo")?,
}; };
// Basic non-converting test. // Basic non-converting test.
@ -466,5 +455,6 @@ mod test {
// FromSql float to int conversion, never works even if the actual value // FromSql float to int conversion, never works even if the actual value
// is an integer. // is an integer.
test_conversion!(db_etc, 0f64, i64, expect_from_sql_error); test_conversion!(db_etc, 0f64, i64, expect_from_sql_error);
Ok(())
} }
} }

View File

@ -29,30 +29,29 @@ impl FromSql for Value {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::types::ToSql; use crate::types::ToSql;
use crate::Connection; use crate::{Connection, Result};
fn checked_memory_handle() -> Connection { fn checked_memory_handle() -> Result<Connection> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (t TEXT, b BLOB)") db.execute_batch("CREATE TABLE foo (t TEXT, b BLOB)")?;
.unwrap(); Ok(db)
db
} }
#[test] #[test]
fn test_json_value() { fn test_json_value() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let json = r#"{"foo": 13, "bar": "baz"}"#; let json = r#"{"foo": 13, "bar": "baz"}"#;
let data: serde_json::Value = serde_json::from_str(json).unwrap(); let data: serde_json::Value = serde_json::from_str(json).unwrap();
db.execute( db.execute(
"INSERT INTO foo (t, b) VALUES (?, ?)", "INSERT INTO foo (t, b) VALUES (?, ?)",
&[&data as &dyn ToSql, &json.as_bytes()], &[&data as &dyn ToSql, &json.as_bytes()],
) )?;
.unwrap();
let t: serde_json::Value = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let t: serde_json::Value = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
assert_eq!(data, t); assert_eq!(data, t);
let b: serde_json::Value = db.query_row("SELECT b FROM foo", [], |r| r.get(0)).unwrap(); let b: serde_json::Value = db.query_row("SELECT b FROM foo", [], |r| r.get(0))?;
assert_eq!(data, b); assert_eq!(data, b);
Ok(())
} }
} }

View File

@ -37,16 +37,15 @@ mod test {
use std::time::Duration; use std::time::Duration;
use time::OffsetDateTime; use time::OffsetDateTime;
fn checked_memory_handle() -> Connection { fn checked_memory_handle() -> Result<Connection> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT)") db.execute_batch("CREATE TABLE foo (t TEXT, i INTEGER, f FLOAT)")?;
.unwrap(); Ok(db)
db
} }
#[test] #[test]
fn test_offset_date_time() { fn test_offset_date_time() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let mut ts_vec = vec![]; let mut ts_vec = vec![];
@ -61,21 +60,23 @@ mod test {
ts_vec.push(make_datetime(10_000_000_000, 0)); //November 20, 2286 ts_vec.push(make_datetime(10_000_000_000, 0)); //November 20, 2286
for ts in ts_vec { for ts in ts_vec {
db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts]).unwrap(); db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts])?;
let from: OffsetDateTime = db.query_row("SELECT t FROM foo", [], |r| r.get(0)).unwrap(); let from: OffsetDateTime = db.query_row("SELECT t FROM foo", [], |r| r.get(0))?;
db.execute("DELETE FROM foo", []).unwrap(); db.execute("DELETE FROM foo", [])?;
assert_eq!(from, ts); assert_eq!(from, ts);
} }
Ok(())
} }
#[test] #[test]
fn test_sqlite_functions() { fn test_sqlite_functions() -> Result<()> {
let db = checked_memory_handle(); let db = checked_memory_handle()?;
let result: Result<OffsetDateTime> = let result: Result<OffsetDateTime> =
db.query_row("SELECT CURRENT_TIMESTAMP", [], |r| r.get(0)); db.query_row("SELECT CURRENT_TIMESTAMP", [], |r| r.get(0));
assert!(result.is_ok()); assert!(result.is_ok());
Ok(())
} }
} }

View File

@ -339,12 +339,11 @@ mod test {
#[cfg(feature = "i128_blob")] #[cfg(feature = "i128_blob")]
#[test] #[test]
fn test_i128() { fn test_i128() -> crate::Result<()> {
use crate::Connection; use crate::Connection;
use std::i128; use std::i128;
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (i128 BLOB, desc TEXT)") db.execute_batch("CREATE TABLE foo (i128 BLOB, desc TEXT)")?;
.unwrap();
db.execute( db.execute(
" "
INSERT INTO foo(i128, desc) VALUES INSERT INTO foo(i128, desc) VALUES
@ -353,20 +352,15 @@ mod test {
(?, 'pos one'), (?, 'pos two'), (?, 'pos one'), (?, 'pos two'),
(?, 'min'), (?, 'max')", (?, 'min'), (?, 'max')",
[0i128, -1i128, -2i128, 1i128, 2i128, i128::MIN, i128::MAX], [0i128, -1i128, -2i128, 1i128, 2i128, i128::MIN, i128::MAX],
) )?;
.unwrap();
let mut stmt = db let mut stmt = db.prepare("SELECT i128, desc FROM foo ORDER BY i128 ASC")?;
.prepare("SELECT i128, desc FROM foo ORDER BY i128 ASC")
.unwrap();
let res = stmt let res = stmt
.query_map([], |row| { .query_map([], |row| {
Ok((row.get::<_, i128>(0)?, row.get::<_, String>(1)?)) Ok((row.get::<_, i128>(0)?, row.get::<_, String>(1)?))
}) })?
.unwrap() .collect::<Result<Vec<_>, _>>()?;
.collect::<Result<Vec<_>, _>>()
.unwrap();
assert_eq!( assert_eq!(
res, res,
@ -380,37 +374,35 @@ mod test {
(i128::MAX, "max".to_owned()), (i128::MAX, "max".to_owned()),
] ]
); );
Ok(())
} }
#[cfg(feature = "uuid")] #[cfg(feature = "uuid")]
#[test] #[test]
fn test_uuid() { fn test_uuid() -> crate::Result<()> {
use crate::{params, Connection}; use crate::{params, Connection};
use uuid::Uuid; use uuid::Uuid;
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (id BLOB CHECK(length(id) = 16), label TEXT);") db.execute_batch("CREATE TABLE foo (id BLOB CHECK(length(id) = 16), label TEXT);")?;
.unwrap();
let id = Uuid::new_v4(); let id = Uuid::new_v4();
db.execute( db.execute(
"INSERT INTO foo (id, label) VALUES (?, ?)", "INSERT INTO foo (id, label) VALUES (?, ?)",
params![id, "target"], params![id, "target"],
) )?;
.unwrap();
let mut stmt = db let mut stmt = db.prepare("SELECT id, label FROM foo WHERE id = ?")?;
.prepare("SELECT id, label FROM foo WHERE id = ?")
.unwrap();
let mut rows = stmt.query(params![id]).unwrap(); let mut rows = stmt.query(params![id])?;
let row = rows.next().unwrap().unwrap(); let row = rows.next()?.unwrap();
let found_id: Uuid = row.get_unwrap(0); let found_id: Uuid = row.get_unwrap(0);
let found_label: String = row.get_unwrap(1); let found_label: String = row.get_unwrap(1);
assert_eq!(found_id, id); assert_eq!(found_id, id);
assert_eq!(found_label, "target"); assert_eq!(found_label, "target");
Ok(())
} }
} }

View File

@ -30,11 +30,10 @@ mod test {
use crate::{params, Connection, Error, Result}; use crate::{params, Connection, Error, Result};
use url::{ParseError, Url}; use url::{ParseError, Url};
fn checked_memory_handle() -> Connection { fn checked_memory_handle() -> Result<Connection> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE urls (i INTEGER, v TEXT)") db.execute_batch("CREATE TABLE urls (i INTEGER, v TEXT)")?;
.unwrap(); Ok(db)
db
} }
fn get_url(db: &Connection, id: i64) -> Result<Url> { fn get_url(db: &Connection, id: i64) -> Result<Url> {
@ -42,8 +41,8 @@ mod test {
} }
#[test] #[test]
fn test_sql_url() { fn test_sql_url() -> Result<()> {
let db = &checked_memory_handle(); let db = &checked_memory_handle()?;
let url0 = Url::parse("http://www.example1.com").unwrap(); let url0 = Url::parse("http://www.example1.com").unwrap();
let url1 = Url::parse("http://www.example1.com/👌").unwrap(); let url1 = Url::parse("http://www.example1.com/👌").unwrap();
@ -54,16 +53,15 @@ mod test {
// also insert a non-hex encoded url (which might be present if it was // also insert a non-hex encoded url (which might be present if it was
// inserted separately) // inserted separately)
params![url0, url1, url2, "illegal"], params![url0, url1, url2, "illegal"],
) )?;
.unwrap();
assert_eq!(get_url(db, 0).unwrap(), url0); assert_eq!(get_url(db, 0)?, url0);
assert_eq!(get_url(db, 1).unwrap(), url1); assert_eq!(get_url(db, 1)?, url1);
// Should successfully read it, even though it wasn't inserted as an // Should successfully read it, even though it wasn't inserted as an
// escaped url. // escaped url.
let out_url2: Url = get_url(db, 2).unwrap(); let out_url2: Url = get_url(db, 2)?;
assert_eq!(out_url2, Url::parse(url2).unwrap()); assert_eq!(out_url2, Url::parse(url2).unwrap());
// Make sure the conversion error comes through correctly. // Make sure the conversion error comes through correctly.
@ -79,5 +77,6 @@ mod test {
panic!("Expected conversion failure, got {}", e); panic!("Expected conversion failure, got {}", e);
} }
} }
Ok(())
} }
} }

View File

@ -106,11 +106,11 @@ mod test {
use std::time; use std::time;
#[test] #[test]
fn test_unlock_notify() { fn test_unlock_notify() -> Result<()> {
let url = "file::memory:?cache=shared"; let url = "file::memory:?cache=shared";
let flags = OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_URI; let flags = OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_URI;
let db1 = Connection::open_with_flags(url, flags).unwrap(); let db1 = Connection::open_with_flags(url, flags)?;
db1.execute_batch("CREATE TABLE foo (x)").unwrap(); db1.execute_batch("CREATE TABLE foo (x)")?;
let (rx, tx) = sync_channel(0); let (rx, tx) = sync_channel(0);
let child = thread::spawn(move || { let child = thread::spawn(move || {
let mut db2 = Connection::open_with_flags(url, flags).unwrap(); let mut db2 = Connection::open_with_flags(url, flags).unwrap();
@ -123,7 +123,8 @@ mod test {
}); });
assert_eq!(tx.recv().unwrap(), 1); assert_eq!(tx.recv().unwrap(), 1);
let the_answer: Result<i64> = db1.query_row("SELECT x FROM foo", [], |r| r.get(0)); let the_answer: Result<i64> = db1.query_row("SELECT x FROM foo", [], |r| r.get(0));
assert_eq!(42i64, the_answer.unwrap()); assert_eq!(42i64, the_answer?);
child.join().unwrap(); child.join().unwrap();
Ok(())
} }
} }

View File

@ -197,29 +197,30 @@ unsafe impl VTabCursor for ArrayTabCursor<'_> {
mod test { mod test {
use crate::types::Value; use crate::types::Value;
use crate::vtab::array; use crate::vtab::array;
use crate::Connection; use crate::{Connection, Result};
use std::rc::Rc; use std::rc::Rc;
#[test] #[test]
fn test_array_module() { fn test_array_module() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
array::load_module(&db).unwrap(); array::load_module(&db)?;
let v = vec![1i64, 2, 3, 4]; let v = vec![1i64, 2, 3, 4];
let values: Vec<Value> = v.into_iter().map(Value::from).collect(); let values: Vec<Value> = v.into_iter().map(Value::from).collect();
let ptr = Rc::new(values); let ptr = Rc::new(values);
{ {
let mut stmt = db.prepare("SELECT value from rarray(?);").unwrap(); let mut stmt = db.prepare("SELECT value from rarray(?);")?;
let rows = stmt.query_map(&[&ptr], |row| row.get::<_, i64>(0)).unwrap(); let rows = stmt.query_map(&[&ptr], |row| row.get::<_, i64>(0))?;
assert_eq!(2, Rc::strong_count(&ptr)); assert_eq!(2, Rc::strong_count(&ptr));
let mut count = 0; let mut count = 0;
for (i, value) in rows.enumerate() { for (i, value) in rows.enumerate() {
assert_eq!(i as i64, value.unwrap() - 1); assert_eq!(i as i64, value? - 1);
count += 1; count += 1;
} }
assert_eq!(4, count); assert_eq!(4, count);
} }
assert_eq!(1, Rc::strong_count(&ptr)); assert_eq!(1, Rc::strong_count(&ptr));
Ok(())
} }
} }

View File

@ -367,49 +367,41 @@ mod test {
use fallible_iterator::FallibleIterator; use fallible_iterator::FallibleIterator;
#[test] #[test]
fn test_csv_module() { fn test_csv_module() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
csvtab::load_module(&db).unwrap(); csvtab::load_module(&db)?;
db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)") db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)")?;
.unwrap();
{ {
let mut s = db.prepare("SELECT rowid, * FROM vtab").unwrap(); let mut s = db.prepare("SELECT rowid, * FROM vtab")?;
{ {
let headers = s.column_names(); let headers = s.column_names();
assert_eq!(vec!["rowid", "colA", "colB", "colC"], headers); assert_eq!(vec!["rowid", "colA", "colB", "colC"], headers);
} }
let ids: Result<Vec<i32>> = s let ids: Result<Vec<i32>> = s.query([])?.map(|row| row.get::<_, i32>(0)).collect();
.query([]) let sum = ids?.iter().sum::<i32>();
.unwrap()
.map(|row| row.get::<_, i32>(0))
.collect();
let sum = ids.unwrap().iter().sum::<i32>();
assert_eq!(sum, 15); assert_eq!(sum, 15);
} }
db.execute_batch("DROP TABLE vtab").unwrap(); db.execute_batch("DROP TABLE vtab")
} }
#[test] #[test]
fn test_csv_cursor() { fn test_csv_cursor() -> Result<()> {
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
csvtab::load_module(&db).unwrap(); csvtab::load_module(&db)?;
db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)") db.execute_batch("CREATE VIRTUAL TABLE vtab USING csv(filename='test.csv', header=yes)")?;
.unwrap();
{ {
let mut s = db let mut s = db.prepare(
.prepare( "SELECT v1.rowid, v1.* FROM vtab v1 NATURAL JOIN vtab v2 WHERE \
"SELECT v1.rowid, v1.* FROM vtab v1 NATURAL JOIN vtab v2 WHERE \
v1.rowid < v2.rowid", v1.rowid < v2.rowid",
) )?;
.unwrap();
let mut rows = s.query([]).unwrap(); let mut rows = s.query([])?;
let row = rows.next().unwrap().unwrap(); let row = rows.next()?.unwrap();
assert_eq!(row.get_unwrap::<_, i32>(0), 2); assert_eq!(row.get_unwrap::<_, i32>(0), 2);
} }
db.execute_batch("DROP TABLE vtab").unwrap(); db.execute_batch("DROP TABLE vtab")
} }
} }

View File

@ -273,26 +273,27 @@ unsafe impl VTabCursor for SeriesTabCursor<'_> {
mod test { mod test {
use crate::ffi; use crate::ffi;
use crate::vtab::series; use crate::vtab::series;
use crate::Connection; use crate::{Connection, Result};
#[test] #[test]
fn test_series_module() { fn test_series_module() -> Result<()> {
let version = unsafe { ffi::sqlite3_libversion_number() }; let version = unsafe { ffi::sqlite3_libversion_number() };
if version < 3_008_012 { if version < 3_008_012 {
return; return Ok(());
} }
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
series::load_module(&db).unwrap(); series::load_module(&db)?;
let mut s = db.prepare("SELECT * FROM generate_series(0,20,5)").unwrap(); let mut s = db.prepare("SELECT * FROM generate_series(0,20,5)")?;
let series = s.query_map([], |row| row.get::<_, i32>(0)).unwrap(); let series = s.query_map([], |row| row.get::<_, i32>(0))?;
let mut expected = 0; let mut expected = 0;
for value in series { for value in series {
assert_eq!(expected, value.unwrap()); assert_eq!(expected, value?);
expected += 5; expected += 5;
} }
Ok(())
} }
} }

View File

@ -2,7 +2,7 @@
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]
#[test] #[test]
fn test_dummy_module() { fn test_dummy_module() -> rusqlite::Result<()> {
use rusqlite::types::ToSql; use rusqlite::types::ToSql;
use rusqlite::vtab::{ use rusqlite::vtab::{
eponymous_only_module, sqlite3_vtab, sqlite3_vtab_cursor, Context, IndexInfo, VTab, eponymous_only_module, sqlite3_vtab, sqlite3_vtab_cursor, Context, IndexInfo, VTab,
@ -84,20 +84,18 @@ fn test_dummy_module() {
} }
} }
let db = Connection::open_in_memory().unwrap(); let db = Connection::open_in_memory()?;
db.create_module::<DummyTab>("dummy", &module, None) db.create_module::<DummyTab>("dummy", &module, None)?;
.unwrap();
let version = version_number(); let version = version_number();
if version < 3_008_012 { if version < 3_008_012 {
return; return Ok(());
} }
let mut s = db.prepare("SELECT * FROM dummy()").unwrap(); let mut s = db.prepare("SELECT * FROM dummy()")?;
let dummy = s let dummy = s.query_row(&[] as &[&dyn ToSql], |row| row.get::<_, i32>(0))?;
.query_row(&[] as &[&dyn ToSql], |row| row.get::<_, i32>(0))
.unwrap();
assert_eq!(1, dummy); assert_eq!(1, dummy);
Ok(())
} }