use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.canonicalize()
.expect("repo root")
}
fn names_in_manifest() -> BTreeSet<String> {
let text = std::fs::read_to_string(repo_root().join("crates/aura-lang/stdlib.aura"))
.expect("the stdlib manifest");
text.lines()
.filter_map(|line| {
let rest = line.strip_prefix(" ")?;
let name = rest.strip_suffix(':')?;
let ok = !name.is_empty()
&& name
.chars()
.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_');
ok.then(|| name.to_string())
})
.collect()
}
fn names_in_book(rel: &str) -> BTreeSet<String> {
let text = std::fs::read_to_string(repo_root().join(rel)).expect("a book page");
let mut out = BTreeSet::new();
for (i, _) in text.match_indices('`') {
let rest = &text[i + 1..];
let name: String = rest
.chars()
.take_while(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || *c == '_')
.collect();
if name.is_empty() {
continue;
}
let after = rest[name.len()..].chars().next();
if matches!(after, Some('(') | Some(' ')) {
out.insert(name);
}
}
out
}
const BOOKS: &[(&str, &str)] = &[
("English", "docs/book/src/reference/methods.md"),
("Russian", "docs/book-ru/src/reference/methods.md"),
];
#[test]
fn every_book_documents_every_method() {
for (language, page) in BOOKS {
let documented = names_in_book(page);
let missing: Vec<_> = names_in_manifest()
.into_iter()
.filter(|n| !documented.contains(n))
.collect();
assert!(
missing.is_empty(),
"the {language} method reference does not mention: {missing:?}\n\
Add them to {page}, or remove them from stdlib.aura if they are gone."
);
}
}
#[test]
fn the_books_document_the_same_methods() {
let english = names_in_book(BOOKS[0].1);
let russian = names_in_book(BOOKS[1].1);
let manifest = names_in_manifest();
let only_english: Vec<_> = manifest
.iter()
.filter(|n| english.contains(*n) && !russian.contains(*n))
.collect();
let only_russian: Vec<_> = manifest
.iter()
.filter(|n| russian.contains(*n) && !english.contains(*n))
.collect();
assert!(
only_english.is_empty() && only_russian.is_empty(),
"the translations disagree — only in English: {only_english:?}, only in Russian: {only_russian:?}"
);
}