diff --git a/Makefile b/Makefile index db3c3acdb..245c57b12 100644 --- a/Makefile +++ b/Makefile @@ -7,21 +7,6 @@ UNAME_S := $(shell uname -s) # Executable used to execute the compatibility tests. SQLITE_EXEC ?= scripts/limbo-sqlite3 -# Static library to use for SQLite C API compatibility tests. -BASE_SQLITE_LIB = ./target/$(CURRENT_RUST_TARGET)/debug/liblimbo_sqlite3.a -# Static library headers to use for SQLITE C API compatibility tests -BASE_SQLITE_LIB_HEADERS = ./target/$(CURRENT_RUST_TARGET)/debug/include/limbo_sqlite3 - - -# On darwin link core foundation -ifeq ($(UNAME_S),Darwin) - SQLITE_LIB ?= ../../$(BASE_SQLITE_LIB) -framework CoreFoundation -else - SQLITE_LIB ?= ../../$(BASE_SQLITE_LIB) -endif - -SQLITE_LIB_HEADERS ?= ../../$(BASE_SQLITE_LIB_HEADERS) - all: check-rust-version check-wasm-target limbo limbo-wasm .PHONY: all @@ -89,8 +74,9 @@ test-time: SQLITE_EXEC=$(SQLITE_EXEC) ./testing/time.test .PHONY: test-time -test-sqlite3: limbo-c - LIBS="$(SQLITE_LIB)" HEADERS="$(SQLITE_LIB_HEADERS)" make -C sqlite3/tests test +test-sqlite3: + cargo test -p limbo_sqlite3 --test compat + cargo test -p limbo_sqlite3 --test compat --features sqlite3 .PHONY: test-sqlite3 test-json: diff --git a/sqlite3/Cargo.toml b/sqlite3/Cargo.toml index 444698d66..8d17ad77c 100644 --- a/sqlite3/Cargo.toml +++ b/sqlite3/Cargo.toml @@ -7,10 +7,12 @@ authors.workspace = true edition.workspace = true license.workspace = true repository.workspace = true +build = "build.rs" [features] capi = [] lfs = [] +sqlite3 = [] [package.metadata.dist] dist = true @@ -25,6 +27,11 @@ libc = "0.2.169" limbo_core = { path = "../core" } log = "0.4.22" - [package.metadata.capi.header] name = "sqlite3.h" + +[[test]] +name = "compat" +path = "tests/compat/mod.rs" + +[build-dependencies] diff --git a/sqlite3/build.rs b/sqlite3/build.rs new file mode 100644 index 000000000..c00f4d679 --- /dev/null +++ b/sqlite3/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rustc-link-search=native=target/debug"); +} diff --git a/sqlite3/src/lib.rs b/sqlite3/src/lib.rs index f54e6bdb2..f1393f390 100644 --- a/sqlite3/src/lib.rs +++ b/sqlite3/src/lib.rs @@ -124,7 +124,7 @@ pub unsafe extern "C" fn sqlite3_open( SQLITE_OK } Err(e) => { - log::error!("error opening database {:?}", e); + log::trace!("error opening database {}: {:?}", filename, e); SQLITE_CANTOPEN } } @@ -1083,187 +1083,3 @@ pub unsafe extern "C" fn sqlite3_wal_checkpoint_v2( } SQLITE_OK } - -#[cfg(test)] -mod tests { - use super::*; - use std::ptr; - - #[test] - fn test_libversion() { - unsafe { - let version = sqlite3_libversion(); - assert!(!version.is_null()); - } - } - - #[test] - fn test_libversion_number() { - unsafe { - let version_num = sqlite3_libversion_number(); - assert_eq!(version_num, 3042000); - } - } - - #[test] - fn test_open_misuse() { - unsafe { - let mut db = ptr::null_mut(); - assert_eq!(sqlite3_open(ptr::null(), &mut db), SQLITE_MISUSE); - } - } - - #[test] - fn test_open_not_found() { - unsafe { - let mut db = ptr::null_mut(); - assert_eq!( - sqlite3_open(b"not-found/local.db\0".as_ptr() as *const i8, &mut db), - SQLITE_CANTOPEN - ); - } - } - - #[test] - #[ignore] - fn test_open_existing() { - unsafe { - let mut db = ptr::null_mut(); - assert_eq!( - sqlite3_open(b"../testing/testing.db\0".as_ptr() as *const i8, &mut db), - SQLITE_OK - ); - assert_eq!(sqlite3_close(db), SQLITE_OK); - } - } - - #[test] - fn test_close() { - unsafe { - assert_eq!(sqlite3_close(ptr::null_mut()), SQLITE_OK); - } - } - - #[test] - #[ignore] - fn test_prepare_misuse() { - unsafe { - let mut db = ptr::null_mut(); - assert_eq!( - sqlite3_open(b"../testing/testing.db\0".as_ptr() as *const i8, &mut db), - SQLITE_OK - ); - - let mut stmt = ptr::null_mut(); - assert_eq!( - sqlite3_prepare_v2( - db, - b"SELECT 1\0".as_ptr() as *const i8, - -1, - &mut stmt, - ptr::null_mut() - ), - SQLITE_OK - ); - - assert_eq!(sqlite3_finalize(stmt), SQLITE_OK); - assert_eq!(sqlite3_close(db), SQLITE_OK); - } - } - - #[test] - #[ignore] - fn test_wal_checkpoint() { - unsafe { - // Test with NULL db handle - assert_eq!( - sqlite3_wal_checkpoint(ptr::null_mut(), ptr::null()), - SQLITE_MISUSE - ); - - // Test with valid db - let mut db = ptr::null_mut(); - assert_eq!( - sqlite3_open(b"../testing/testing.db\0".as_ptr() as *const i8, &mut db), - SQLITE_OK - ); - assert_eq!(sqlite3_wal_checkpoint(db, ptr::null()), SQLITE_OK); - assert_eq!(sqlite3_close(db), SQLITE_OK); - } - } - - #[test] - #[ignore] - fn test_wal_checkpoint_v2() { - unsafe { - // Test with NULL db handle - assert_eq!( - sqlite3_wal_checkpoint_v2( - ptr::null_mut(), - ptr::null(), - SQLITE_CHECKPOINT_PASSIVE, - ptr::null_mut(), - ptr::null_mut() - ), - SQLITE_MISUSE - ); - - // Test with valid db - let mut db = ptr::null_mut(); - assert_eq!( - sqlite3_open(b"../testing/testing.db\0".as_ptr() as *const i8, &mut db), - SQLITE_OK - ); - - let mut log_size = 0; - let mut checkpoint_count = 0; - - // Test different checkpoint modes - assert_eq!( - sqlite3_wal_checkpoint_v2( - db, - ptr::null(), - SQLITE_CHECKPOINT_PASSIVE, - &mut log_size, - &mut checkpoint_count - ), - SQLITE_OK - ); - - assert_eq!( - sqlite3_wal_checkpoint_v2( - db, - ptr::null(), - SQLITE_CHECKPOINT_FULL, - &mut log_size, - &mut checkpoint_count - ), - SQLITE_OK - ); - - assert_eq!( - sqlite3_wal_checkpoint_v2( - db, - ptr::null(), - SQLITE_CHECKPOINT_RESTART, - &mut log_size, - &mut checkpoint_count - ), - SQLITE_OK - ); - - assert_eq!( - sqlite3_wal_checkpoint_v2( - db, - ptr::null(), - SQLITE_CHECKPOINT_TRUNCATE, - &mut log_size, - &mut checkpoint_count - ), - SQLITE_OK - ); - - assert_eq!(sqlite3_close(db), SQLITE_OK); - } - } -} diff --git a/sqlite3/tests/Makefile b/sqlite3/tests/Makefile deleted file mode 100644 index 44786a3f2..000000000 --- a/sqlite3/tests/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# Compiler settings -CC = gcc -CFLAGS = -g -Wall -std=c17 -I../include - -# Libraries -LIBS ?= -lsqlite3 -LIBS += -lm - -# Target program -PROGRAM = sqlite3-tests - -# Object files -OBJS = main.o \ - test-aux.o \ - test-close.o \ - test-open.o \ - test-prepare.o \ - test-wal.o - -# Default target -all: $(PROGRAM) - -# Test target -test: $(PROGRAM) - ./$(PROGRAM) - -# Compile source files -%.o: %.c - $(CC) $(CFLAGS) -c $< -o $@ - -# Link program -$(PROGRAM): $(OBJS) - $(CC) -o $@ $(OBJS) $(LIBS) - -# Clean target -clean: - rm -f $(PROGRAM) $(OBJS) - -.PHONY: all test clean diff --git a/sqlite3/tests/check.h b/sqlite3/tests/check.h deleted file mode 100644 index dbf69e11c..000000000 --- a/sqlite3/tests/check.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef CHECK_H - -#define CHECK_EQUAL(expected, actual) \ - do { \ - if ((expected) != (actual)) { \ - fprintf(stderr, "%s:%d: Assertion failed: %d != %d\n", __FILE__, __LINE__, (expected), (actual)); \ - exit(1); \ - } \ - } while (0) - -#endif diff --git a/sqlite3/tests/compat/mod.rs b/sqlite3/tests/compat/mod.rs new file mode 100644 index 000000000..1166e4a15 --- /dev/null +++ b/sqlite3/tests/compat/mod.rs @@ -0,0 +1,198 @@ +#![allow(non_camel_case_types)] + +use std::ptr; + +#[repr(C)] +struct sqlite3 { + _private: [u8; 0], +} + +#[repr(C)] +struct sqlite3_stmt { + _private: [u8; 0], +} + +#[cfg_attr(not(feature = "sqlite3"), link(name = "limbo_sqlite3"))] +#[cfg_attr(feature = "sqlite3", link(name = "sqlite3"))] +extern "C" { + fn sqlite3_libversion() -> *const libc::c_char; + fn sqlite3_libversion_number() -> i32; + fn sqlite3_close(db: *mut sqlite3) -> i32; + fn sqlite3_open(filename: *const libc::c_char, db: *mut *mut sqlite3) -> i32; + fn sqlite3_prepare_v2( + db: *mut sqlite3, + sql: *const libc::c_char, + n_bytes: i32, + stmt: *mut *mut sqlite3_stmt, + tail: *mut *const libc::c_char, + ) -> i32; + fn sqlite3_finalize(stmt: *mut sqlite3_stmt) -> i32; + fn sqlite3_wal_checkpoint(db: *mut sqlite3, db_name: *const libc::c_char) -> i32; + fn sqlite3_wal_checkpoint_v2( + db: *mut sqlite3, + db_name: *const libc::c_char, + mode: i32, + log_size: *mut i32, + checkpoint_count: *mut i32, + ) -> i32; +} + +const SQLITE_OK: i32 = 0; +const SQLITE_CANTOPEN: i32 = 14; +const SQLITE_CHECKPOINT_PASSIVE: i32 = 0; +const SQLITE_CHECKPOINT_FULL: i32 = 1; +const SQLITE_CHECKPOINT_RESTART: i32 = 2; +const SQLITE_CHECKPOINT_TRUNCATE: i32 = 3; + +#[cfg(not(target_os = "windows"))] +mod tests { + use super::*; + + #[test] + fn test_libversion() { + unsafe { + let version = sqlite3_libversion(); + assert!(!version.is_null()); + } + } + + #[test] + fn test_libversion_number() { + unsafe { + let version_num = sqlite3_libversion_number(); + assert!(version_num >= 3042000); + } + } + + #[test] + fn test_open_not_found() { + unsafe { + let mut db = ptr::null_mut(); + assert_eq!( + sqlite3_open(b"not-found/local.db\0".as_ptr() as *const i8, &mut db), + SQLITE_CANTOPEN + ); + } + } + + #[test] + fn test_open_existing() { + unsafe { + let mut db = ptr::null_mut(); + assert_eq!( + sqlite3_open(b"../testing/testing.db\0".as_ptr() as *const i8, &mut db), + SQLITE_OK + ); + assert_eq!(sqlite3_close(db), SQLITE_OK); + } + } + + #[test] + fn test_close() { + unsafe { + assert_eq!(sqlite3_close(ptr::null_mut()), SQLITE_OK); + } + } + + #[test] + fn test_prepare_misuse() { + unsafe { + let mut db = ptr::null_mut(); + assert_eq!( + sqlite3_open(b"../testing/testing.db\0".as_ptr() as *const i8, &mut db), + SQLITE_OK + ); + + let mut stmt = ptr::null_mut(); + assert_eq!( + sqlite3_prepare_v2( + db, + b"SELECT 1\0".as_ptr() as *const i8, + -1, + &mut stmt, + ptr::null_mut() + ), + SQLITE_OK + ); + + assert_eq!(sqlite3_finalize(stmt), SQLITE_OK); + assert_eq!(sqlite3_close(db), SQLITE_OK); + } + } + + #[test] + fn test_wal_checkpoint() { + unsafe { + // Test with valid db + let mut db = ptr::null_mut(); + assert_eq!( + sqlite3_open(b"../testing/testing.db\0".as_ptr() as *const i8, &mut db), + SQLITE_OK + ); + assert_eq!(sqlite3_wal_checkpoint(db, ptr::null()), SQLITE_OK); + assert_eq!(sqlite3_close(db), SQLITE_OK); + } + } + + #[test] + fn test_wal_checkpoint_v2() { + unsafe { + // Test with valid db + let mut db = ptr::null_mut(); + assert_eq!( + sqlite3_open(b"../testing/testing.db\0".as_ptr() as *const i8, &mut db), + SQLITE_OK + ); + + let mut log_size = 0; + let mut checkpoint_count = 0; + + // Test different checkpoint modes + assert_eq!( + sqlite3_wal_checkpoint_v2( + db, + ptr::null(), + SQLITE_CHECKPOINT_PASSIVE, + &mut log_size, + &mut checkpoint_count + ), + SQLITE_OK + ); + + assert_eq!( + sqlite3_wal_checkpoint_v2( + db, + ptr::null(), + SQLITE_CHECKPOINT_FULL, + &mut log_size, + &mut checkpoint_count + ), + SQLITE_OK + ); + + assert_eq!( + sqlite3_wal_checkpoint_v2( + db, + ptr::null(), + SQLITE_CHECKPOINT_RESTART, + &mut log_size, + &mut checkpoint_count + ), + SQLITE_OK + ); + + assert_eq!( + sqlite3_wal_checkpoint_v2( + db, + ptr::null(), + SQLITE_CHECKPOINT_TRUNCATE, + &mut log_size, + &mut checkpoint_count + ), + SQLITE_OK + ); + + assert_eq!(sqlite3_close(db), SQLITE_OK); + } + } +} diff --git a/sqlite3/tests/main.c b/sqlite3/tests/main.c deleted file mode 100644 index 4cbf19f5e..000000000 --- a/sqlite3/tests/main.c +++ /dev/null @@ -1,24 +0,0 @@ -extern void test_libversion(); -extern void test_libversion_number(); -extern void test_open_misuse(); -extern void test_open_not_found(); -extern void test_open_existing(); -extern void test_close(); -extern void test_prepare_misuse(); -extern void test_wal_checkpoint(); -extern void test_wal_checkpoint_v2(); - -int main(int argc, char *argv[]) -{ - test_libversion(); - test_libversion_number(); - test_open_misuse(); - test_open_not_found(); - test_open_existing(); - test_close(); - test_prepare_misuse(); - test_wal_checkpoint(); - test_wal_checkpoint_v2(); - - return 0; -} diff --git a/sqlite3/tests/test-aux.c b/sqlite3/tests/test-aux.c deleted file mode 100644 index 77c1c3b7a..000000000 --- a/sqlite3/tests/test-aux.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "check.h" - -#include - -void test_libversion(void) { - sqlite3_libversion(); -} - -void test_libversion_number(void) { - sqlite3_libversion_number(); -} diff --git a/sqlite3/tests/test-close.c b/sqlite3/tests/test-close.c deleted file mode 100644 index c444eea01..000000000 --- a/sqlite3/tests/test-close.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include -#include -#include - -#include "check.h" - -void test_close(void) -{ - CHECK_EQUAL(SQLITE_OK, sqlite3_close(NULL)); -} diff --git a/sqlite3/tests/test-open.c b/sqlite3/tests/test-open.c deleted file mode 100644 index fe8d7ddc2..000000000 --- a/sqlite3/tests/test-open.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "check.h" - -#include -#include -#include -#include - -void test_open_misuse(void) -{ - // TODO: SIGSEGV with sqlite3 -// CHECK_EQUAL(SQLITE_MISUSE, sqlite3_open(NULL, NULL)); - -// CHECK_EQUAL(SQLITE_MISUSE, sqlite3_open("local.db", NULL)); -} - -void test_open_not_found(void) -{ - sqlite3 *db; - - CHECK_EQUAL(SQLITE_CANTOPEN, sqlite3_open("not-found/local.db", &db)); -} - -// TODO: test_open_create - -void test_open_existing(void) -{ - sqlite3 *db; - - CHECK_EQUAL(SQLITE_OK, sqlite3_open("../../testing/testing.db", &db)); - CHECK_EQUAL(SQLITE_OK, sqlite3_close(db)); -} diff --git a/sqlite3/tests/test-prepare.c b/sqlite3/tests/test-prepare.c deleted file mode 100644 index 7fa978da3..000000000 --- a/sqlite3/tests/test-prepare.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "check.h" - -#include -#include -#include -#include - -void test_prepare_misuse(void) -{ - sqlite3 *db; - - CHECK_EQUAL(SQLITE_OK, sqlite3_open("../../testing/testing.db", &db)); - - // Database handle is NULL. - // TODO: SIGSEGV with sqlite3 -// CHECK_EQUAL(SQLITE_MISUSE, sqlite3_prepare_v2(NULL, "SELECT 1", -1, NULL, NULL)); - - // Output statement is NULL. - // TODO: SIGSEGV with sqlite3 -// CHECK_EQUAL(SQLITE_MISUSE, sqlite3_prepare_v2(db, "SELECT 1", -1, NULL, NULL)); - - // SQL string length is too short, truncating the statement. - // TODO: SIGSEGV with sqlite3 -// CHECK_EQUAL(SQLITE_MISUSE, sqlite3_prepare_v2(db, "SELECT 1", 7, NULL, NULL)); - - CHECK_EQUAL(SQLITE_OK, sqlite3_close(db)); -} diff --git a/sqlite3/tests/test-wal.c b/sqlite3/tests/test-wal.c deleted file mode 100644 index 490277e02..000000000 --- a/sqlite3/tests/test-wal.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "check.h" - -#include -#include -#include -#include - -void test_wal_checkpoint(void) -{ - sqlite3 *db; - - // Test with NULL db handle - CHECK_EQUAL(SQLITE_MISUSE, sqlite3_wal_checkpoint(NULL, NULL)); - - // Test with valid db - CHECK_EQUAL(SQLITE_OK, sqlite3_open("../../testing/testing.db", &db)); - CHECK_EQUAL(SQLITE_OK, sqlite3_wal_checkpoint(db, NULL)); - CHECK_EQUAL(SQLITE_OK, sqlite3_close(db)); -} - -void test_wal_checkpoint_v2(void) -{ - sqlite3 *db; - int log_size, checkpoint_count; - - // Test with NULL db handle - CHECK_EQUAL(SQLITE_MISUSE, sqlite3_wal_checkpoint_v2(NULL, NULL, SQLITE_CHECKPOINT_PASSIVE, NULL, NULL)); - - // Test with valid db - CHECK_EQUAL(SQLITE_OK, sqlite3_open("../../testing/testing.db", &db)); - - // Test different checkpoint modes - CHECK_EQUAL(SQLITE_OK, sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_PASSIVE, &log_size, &checkpoint_count)); - CHECK_EQUAL(SQLITE_OK, sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_FULL, &log_size, &checkpoint_count)); - CHECK_EQUAL(SQLITE_OK, sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_RESTART, &log_size, &checkpoint_count)); - CHECK_EQUAL(SQLITE_OK, sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_TRUNCATE, &log_size, &checkpoint_count)); - - CHECK_EQUAL(SQLITE_OK, sqlite3_close(db)); -} \ No newline at end of file