diff --git a/questdb-rs/Cargo.toml b/questdb-rs/Cargo.toml index 38825bea..4ad51345 100644 --- a/questdb-rs/Cargo.toml +++ b/questdb-rs/Cargo.toml @@ -58,6 +58,7 @@ chrono = "0.4.31" tempfile = "3" webpki-roots = "1.0.1" rstest = "0.26.1" +regex = "1" [features] default = ["sync-sender", "tls-webpki-certs", "ring-crypto"] diff --git a/questdb-rs/src/tests/buffer_opt.rs b/questdb-rs/src/tests/buffer_opt.rs index 1ecfe94c..d6db89b3 100644 --- a/questdb-rs/src/tests/buffer_opt.rs +++ b/questdb-rs/src/tests/buffer_opt.rs @@ -139,3 +139,49 @@ fn test_buffer_opt_array_some_binary_match() -> TestResult { Ok(()) } + +#[test] +fn test_every_column_writing_method_has_opt_variant() { + // Meta-test: scan buffer.rs and assert every column-writing method has a + // matching `_opt` sibling. Catches the case where someone adds a new + // method like `uuid` (à la `symbol`) or `column_uuid` without the + // `_opt` companion. + // + // Column writers are identified by the `N: TryInto>` bound + // rather than by name prefix - so `symbol` and any future unprefixed + // additions are caught too. The `[^{]*` segment in the writer regex + // matches across newlines (it does not exclude `\n`), so it spans + // multi-line `where` clauses without needing dotall. + // + // The `(?m)^\s*` anchor restricts matches to start at the indentation + // of an impl item, so a stray `pub fn ...` inside a `///` doc example + // can never be picked up. + let src = include_str!("../ingress/buffer.rs"); + + let pub_fn = regex::Regex::new(r"(?m)^\s*pub fn (\w+)").unwrap(); + let writer = regex::Regex::new(r"(?m)^\s*pub fn (\w+)[^{]*TryInto = pub_fn + .captures_iter(src) + .map(|c| c.get(1).unwrap().as_str()) + .collect(); + + let writers: Vec<&str> = writer + .captures_iter(src) + .map(|c| c.get(1).unwrap().as_str()) + .collect(); + + // Guard against a wrong include_str! path silently passing the test. + assert!(!writers.is_empty(), "no column writers found — wrong path?"); + + let missing: Vec<&&str> = writers + .iter() + .filter(|n| !n.ends_with("_opt")) + .filter(|n| !all_pub_fns.contains(format!("{n}_opt").as_str())) + .collect(); + + assert!( + missing.is_empty(), + "Buffer column-writing methods missing `_opt` variants: {missing:?}" + ); +}