uce/site/tests/sqlite.uce

94 lines
4.4 KiB
Plaintext

#include "testlib.h"
RENDER(Request& context)
{
u64 passed = 0;
u64 failed = 0;
u64 skipped = 0;
auto check = [&](String name, bool ok, String detail)
{
site_tests_case(name, ok ? "pass" : "fail", detail);
if(ok)
passed++;
else
failed++;
};
site_tests_page_start("SQLite", "SQLite connector coverage for prepared params, result typing, metadata, and cleanup.");
String db_path = "/tmp/uce-site-tests-sqlite.sqlite";
file_unlink(db_path);
file_unlink(db_path + "-wal");
file_unlink(db_path + "-shm");
SQLite* db = sqlite_connect(db_path);
check("sqlite_connect()", db && db->connection != 0 && sqlite_error(db) == "connected", sqlite_error(db));
sqlite_query(db, "create table users(id integer primary key autoincrement, email text not null unique, visits integer not null, rating real not null)");
check("sqlite create table", sqlite_error(db) == "ok", sqlite_error(db));
sqlite_query(db, "create table dropped(id integer); insert into dropped values(1);");
String multi_statement_error = sqlite_error(db);
StringMap dropped_params;
dropped_params["name"] = "dropped";
DTree dropped_tables = sqlite_query(db, "select name from sqlite_master where type = 'table' and name = :name", dropped_params);
check("sqlite_query() rejects multi-statement SQL", multi_statement_error.find("exactly one SQL statement") != String::npos && dropped_tables["0"]["name"].to_string() == "", multi_statement_error + " tables=" + json_encode(dropped_tables));
StringMap ada;
ada["email"] = "ada@example.test";
ada["visits"] = "7";
ada["rating"] = "4.5";
sqlite_query(db, "insert into users(email, visits, rating) values(:email, :visits, :rating)", ada);
u64 ada_id = sqlite_insert_id(db);
check("sqlite named insert", ada_id == 1 && sqlite_affected_rows(db) == 1, "id=" + std::to_string(ada_id) + " affected=" + std::to_string((u64)sqlite_affected_rows(db)) + " error=" + sqlite_error(db));
StringMap bob;
bob["email"] = "bob@example.test";
bob["visits"] = "3";
bob["rating"] = "2.25";
sqlite_query(db, "insert into users(email, visits, rating) values(:email, :visits, :rating)", bob);
check("sqlite second insert", sqlite_insert_id(db) == 2 && sqlite_affected_rows(db) == 1, "id=" + std::to_string(sqlite_insert_id(db)));
StringMap query_params;
query_params["min_visits"] = "4";
DTree rows = sqlite_query(db, "select id, email, visits, rating from users where visits >= :min_visits order by id", query_params);
check("sqlite_query() rows", rows.is_array() && rows["0"]["email"].to_string() == "ada@example.test" && rows["0"]["visits"].to_s64() == 7 && rows["0"]["rating"].to_f64() > 4.49, json_encode(rows));
sqlite_query(db, "select id from users where id = ?", query_params);
String positional_error = sqlite_error(db);
check("sqlite_query() rejects positional placeholders", positional_error.find("positional ? placeholders are not supported") != String::npos, positional_error);
sqlite_query(db, "select id from users where id = @id", query_params);
String non_colon_error = sqlite_error(db);
check("sqlite_query() rejects non-colon placeholders", non_colon_error.find("only supports :name placeholders") != String::npos, non_colon_error);
sqlite_query(db, "update users set visits = visits + 1 where email = :email", ada);
check("sqlite_affected_rows()", sqlite_affected_rows(db) == 1, std::to_string((u64)sqlite_affected_rows(db)));
sqlite_query(db, "select nope from missing_table");
check("sqlite_error()", sqlite_error(db).find("sqlite prepare failed") != String::npos && sqlite_error(db).find("no such table") != String::npos, sqlite_error(db));
sqlite_disconnect(db);
String cleanup_db_path = db_path + ".cleanup";
file_unlink(cleanup_db_path);
file_unlink(cleanup_db_path + "-wal");
file_unlink(cleanup_db_path + "-shm");
SQLite* cleanup_db = sqlite_connect(cleanup_db_path);
sqlite_query(cleanup_db, "create table cleanup_probe(id integer)");
cleanup_sqlite_connections();
check("sqlite request cleanup releases tracked wrappers", context.resources.sqlite_connections.size() == 0, "tracked=" + std::to_string((u64)context.resources.sqlite_connections.size()));
sqlite_disconnect(cleanup_db);
file_unlink(cleanup_db_path);
file_unlink(cleanup_db_path + "-wal");
file_unlink(cleanup_db_path + "-shm");
file_unlink(db_path);
file_unlink(db_path + "-wal");
file_unlink(db_path + "-shm");
site_tests_summary(passed, failed, skipped, "SQLite tests write only under /tmp/uce-site-tests-sqlite.sqlite and clean up WAL/SHM sidecars.");
site_tests_page_end();
}