use std::collections::BTreeSet;
use std::path::PathBuf;
const EXPECTED_ROUTES: &[&str] = &[
"/v1/graphs/{id}/ancestors",
"/v1/graphs/{id}/blast-radius",
"/v1/graphs/{id}/descendants",
"/v1/graphs/{id}/diagnostics",
"/v1/graphs/{id}/diff",
"/v1/graphs/{id}/neighborhood",
"/v1/graphs/{id}/path",
"/v1/graphs/{id}/rank",
"/v1/graphs/{id}/search",
"/v1/graphs/{id}/snapshot",
"/v1/graphs/{id}/stats",
"/v1/graphs/{id}/symbol",
"/v1/graphs/{id}/verify",
"/v1/index",
"/v1/schema",
];
fn openapi_text() -> String {
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../schemas/openapi.yaml");
std::fs::read_to_string(path).expect("schemas/openapi.yaml must exist")
}
fn info_version(text: &str) -> Option<String> {
let mut in_info = false;
for line in text.lines() {
if line == "info:" {
in_info = true;
continue;
}
if in_info {
if !line.starts_with(' ') && !line.is_empty() {
break; }
let trimmed = line.trim();
if let Some(v) = trimmed.strip_prefix("version:") {
return Some(v.trim().to_string());
}
}
}
None
}
fn declared_paths(text: &str) -> BTreeSet<String> {
let mut in_paths = false;
let mut out = BTreeSet::new();
for line in text.lines() {
if line == "paths:" {
in_paths = true;
continue;
}
if in_paths {
if !line.starts_with(' ') && !line.is_empty() {
break; }
if let Some(rest) = line.strip_prefix(" ") {
if !rest.starts_with(' ') && rest.ends_with(':') {
out.insert(rest.trim_end_matches(':').to_string());
}
}
}
}
out
}
#[test]
fn openapi_version_matches_the_crate() {
let text = openapi_text();
assert_eq!(
info_version(&text).as_deref(),
Some(env!("CARGO_PKG_VERSION")),
"schemas/openapi.yaml info.version has drifted from the crate version"
);
}
#[test]
fn openapi_paths_match_the_router() {
let text = openapi_text();
let declared = declared_paths(&text);
let expected: BTreeSet<String> = EXPECTED_ROUTES.iter().map(|s| s.to_string()).collect();
assert_eq!(
declared, expected,
"schemas/openapi.yaml paths have drifted from the routes in handlers.rs \
(update the YAML and EXPECTED_ROUTES together)"
);
}