#![allow(clippy::unwrap_used, clippy::expect_used)]
const SURFACE: &[&str] = &[
"mod analytics",
"mod db",
"mod delete",
"mod error",
"mod export",
"mod macros",
"mod pipeline",
"mod prelude",
"mod promql",
"mod retention",
"mod rollup",
"mod timebucket",
"mod chronix_analytics",
"mod chronix_core",
"mod chronix_encoding",
"mod chronix_engine",
"mod chronix_query",
"mod chronix_security",
"mod chronix_streaming",
"AnomalyConfig",
"BackupManifest",
"Chronix",
"DatabaseStatistics",
"DbError",
"DeleteBuilder",
"DeleteOutcome",
"DeleteRequest",
"ForecastConfig",
"InsertResult",
"ParquetCompression",
"ParquetExportConfig",
"Pipeline",
"PipelineConfig",
"RollupAggFn",
"RollupBuilder",
"RollupConfig",
"RollupRegistry",
"RollupState",
"fields",
"tags",
];
const FEATURE_SURFACE: &[(&str, &[&str])] = &[
("object-store", &["mod cold_archive"]),
("sql", &["mod sql"]),
];
fn declared_surface() -> (Vec<String>, Vec<(String, String)>) {
let full = include_str!("../src/lib.rs");
let src = full
.split_once("pub mod prelude {")
.map_or(full, |(head, _)| head);
let mut always = Vec::new();
let mut gated: Vec<(String, String)> = Vec::new();
let mut pending_feature: Option<String> = None;
for line in src.lines() {
let trimmed = line.trim();
if let Some(rest) = trimmed.strip_prefix("#[cfg(feature = \"") {
if let Some(name) = rest.split('"').next() {
pending_feature = Some(name.to_string());
}
continue;
}
if trimmed.starts_with("//") || trimmed.is_empty() {
continue;
}
let mut names: Vec<String> = Vec::new();
if let Some(rest) = trimmed.strip_prefix("pub mod ") {
let name = rest.trim_end_matches(';').trim_end_matches('{').trim();
names.push(format!("mod {name}"));
} else if let Some(rest) = trimmed.strip_prefix("pub use ") {
let rest = rest.trim_end_matches(';');
if !rest.contains("::") {
names.push(format!("mod {rest}"));
} else {
let (_path, tail) = rest.rsplit_once("::").unwrap_or(("", rest));
if let Some(group) = tail.strip_prefix('{') {
for item in group.trim_end_matches('}').split(',') {
let item = item.trim();
if !item.is_empty() {
names.push(item.to_string());
}
}
} else {
names.push(tail.to_string());
}
}
}
for name in names {
match pending_feature.take() {
Some(f) => gated.push((f, name)),
None => always.push(name),
}
}
if !trimmed.starts_with('#') {
pending_feature = None;
}
}
(always, gated)
}
fn exported_macros() -> Vec<String> {
let src = include_str!("../src/macros.rs");
let mut out = Vec::new();
let mut armed = false;
for line in src.lines() {
let t = line.trim();
if t.starts_with("#[macro_export]") {
armed = true;
continue;
}
if armed {
if let Some(rest) = t.strip_prefix("macro_rules! ") {
out.push(rest.trim_end_matches(" {").trim().to_string());
armed = false;
} else if !t.starts_with('#') && !t.is_empty() && !t.starts_with("//") {
armed = false;
}
}
}
out
}
#[test]
fn the_public_surface_is_the_one_that_was_reviewed() {
let (always, _gated) = declared_surface();
let mut actual: Vec<String> = always;
actual.extend(exported_macros());
if include_str!("../src/lib.rs").contains("pub mod prelude {") {
actual.push("mod prelude".to_string());
}
actual.sort();
actual.dedup();
let mut expected: Vec<String> = SURFACE.iter().map(|s| (*s).to_string()).collect();
expected.sort();
expected.dedup();
let added: Vec<&String> = actual.iter().filter(|a| !expected.contains(a)).collect();
let removed: Vec<&String> = expected.iter().filter(|e| !actual.contains(e)).collect();
assert!(
added.is_empty() && removed.is_empty(),
"the public surface changed.\n added: {added:?}\n removed: {removed:?}\n\
If this was deliberate, update SURFACE in this file in the same commit; \
if it was not, the item probably wants `pub(crate)`."
);
}
#[test]
fn feature_gated_items_are_declared_under_their_feature() {
let (_, gated) = declared_surface();
for (feature, expected) in FEATURE_SURFACE {
let found: Vec<&String> = gated
.iter()
.filter(|(f, _)| f == feature)
.map(|(_, n)| n)
.collect();
for want in *expected {
assert!(
found.iter().any(|f| f.as_str() == *want),
"`{want}` should be gated behind `{feature}`, found {found:?}"
);
}
}
}
#[test]
fn the_prelude_is_the_one_that_was_reviewed() {
const PRELUDE: &[&str] = &[
"AggFn",
"ChronixConfig",
"ChronixConfigBuilder",
"ChronixError",
"Chronix",
"ColumnDef",
"ColumnRole",
"ColumnType",
"CompressionCodec",
"DbError",
"Decimal",
"FieldValue",
"FloatEncoding",
"FsyncPolicy",
"InsertResult",
"MeasurementSchema",
"Point",
"QueryBuilder",
"QueryPlan",
"RecordBatch",
"RollupAggFn",
"RollupBuilder",
"SeriesKey",
"Timestamp",
"fields",
"tags",
];
let src = include_str!("../src/lib.rs");
let body = src
.split_once("pub mod prelude {")
.expect("a prelude module")
.1;
let body = &body[..body.find("\n}").expect("a closing brace")];
let mut actual: Vec<String> = Vec::new();
for chunk in body.split("pub use ").skip(1) {
let stmt = chunk.split(';').next().unwrap_or_default();
let tail = stmt.rsplit_once("::").map_or(stmt, |(_, t)| t);
if let Some(group) = tail.trim().strip_prefix('{') {
for item in group.trim_end_matches('}').split(',') {
let item = item.trim();
if !item.is_empty() {
actual.push(item.to_string());
}
}
} else {
actual.push(tail.trim().to_string());
}
}
actual.sort();
actual.dedup();
let mut expected: Vec<String> = PRELUDE.iter().map(|s| (*s).to_string()).collect();
expected.sort();
assert_eq!(
actual, expected,
"the prelude changed; update PRELUDE in this file in the same commit"
);
}