use std::path::PathBuf;
fn repo_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
}
fn read_lf(path: &std::path::Path) -> Option<String> {
Some(std::fs::read_to_string(path).ok()?.replace("\r\n", "\n"))
}
fn our_manifest() -> String {
read_lf(&repo_root().join("Cargo.toml")).expect("read Cargo.toml")
}
fn patch_is_active(manifest: &str) -> bool {
manifest
.split("[patch.crates-io]")
.nth(1)
.is_some_and(|patch| {
patch
.lines()
.take_while(|line| !line.starts_with('['))
.any(|line| line.starts_with("libsql") && line.contains("vendor/libsql"))
})
}
fn package_version(manifest: &str) -> Option<String> {
manifest
.lines()
.skip_while(|line| line.trim() != "[package]")
.skip(1)
.take_while(|line| !line.trim_start().starts_with('['))
.find_map(|line| {
let value = line
.trim()
.strip_prefix("version")?
.trim_start()
.strip_prefix('=')?;
Some(value.trim().trim_matches('"').to_string())
})
}
#[test]
fn patch_entry_and_vendored_copy_agree_on_existing() {
let vendored = repo_root().join("vendor/libsql");
assert_eq!(
patch_is_active(&our_manifest()),
vendored.is_dir(),
"the `[patch.crates-io]` entry for libsql and {} must be added and removed \
together — one without the other either silently drops the double-close \
fix (#367) or leaves dead vendored source behind.",
vendored.display()
);
}
#[test]
fn a_source_checkout_must_carry_the_patch() {
if !repo_root().join(".git").exists() {
return;
}
assert!(
patch_is_active(&our_manifest()),
"this is a source checkout, so Cargo.toml must route libsql through \
vendor/libsql. Without it every database connection is closed twice, \
which is the Windows STATUS_ACCESS_VIOLATION of #367. Remove this test, \
the `[patch.crates-io]` entry, and vendor/libsql together — and only \
once an upstream libsql release carries the fix."
);
}
#[test]
fn vendored_libsql_matches_the_requested_version() {
let ours = our_manifest();
if !patch_is_active(&ours) {
return;
}
let requested = ours
.lines()
.find_map(|line| line.strip_prefix("libsql = \""))
.and_then(|rest| rest.split('"').next())
.expect("Cargo.toml declares `libsql = \"<version>\"`");
let vendored = read_lf(&repo_root().join("vendor/libsql/Cargo.toml"))
.expect("read vendor/libsql/Cargo.toml");
let vendored = package_version(&vendored).expect("vendor/libsql declares a package version");
assert_eq!(
vendored, requested,
"vendor/libsql is {vendored} but Cargo.toml asks for libsql {requested}. \
Re-vendor the new version and re-apply the double-close fix (#367), or \
drop the patch entirely if the release already carries it."
);
}
#[test]
fn vendored_libsql_still_carries_the_double_close_fix() {
if !patch_is_active(&our_manifest()) {
return;
}
let connection = repo_root().join("vendor/libsql/src/local/connection.rs");
let source = read_lf(&connection).expect("read vendored connection.rs");
let disconnect = source
.split("pub fn disconnect(&mut self)")
.nth(1)
.expect("vendored libsql defines `Connection::disconnect`");
let body = disconnect
.split("\n }")
.next()
.expect("`disconnect` has a body");
let close = body.find("sqlite3_close_v2(self.raw)");
let null = body.find("self.raw = std::ptr::null_mut()");
assert!(
null.is_some(),
"the double-close fix is missing from {}: `disconnect` must null `raw` \
after `sqlite3_close_v2`, or the handle is closed twice (#367).",
connection.display()
);
assert!(
body.contains("!self.raw.is_null()"),
"the double-close fix is incomplete in {}: `disconnect` must skip an \
already-closed handle (#367).",
connection.display()
);
assert!(
close.is_some() && close < null,
"the double-close fix is inverted in {}: `disconnect` must close the \
handle and only then null `raw`, otherwise no connection is ever closed \
(#367).",
connection.display()
);
}
#[test]
fn manifest_parsing_survives_crlf() {
let lf = "# generated\n[package]\nname = \"libsql\"\nversion = \"0.9.30\"\n";
let crlf = lf.replace('\n', "\r\n");
assert!(crlf.contains("\r\n"), "the fixture must actually be CRLF");
assert_eq!(package_version(lf).as_deref(), Some("0.9.30"));
assert_eq!(package_version(&crlf).as_deref(), Some("0.9.30"));
let bare = "[package]\nversion = \"1.2.3\"\n";
assert_eq!(package_version(bare).as_deref(), Some("1.2.3"));
let patch = "[patch.crates-io]\nlibsql = { path = \"vendor/libsql\" }\n";
assert!(patch_is_active(patch));
assert!(patch_is_active(&patch.replace('\n', "\r\n")));
}