use std::fs;
use std::path::{Path, PathBuf};
use bynk::new::{
self, cannot_derive_message, clobber_message, invalid_name_message, next_steps_message,
};
fn bless_or_assert(name: &str, actual: &str) {
let path = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests/golden")
.join(name);
if std::env::var_os("BYNK_BLESS").is_some() {
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(&path, actual).unwrap();
return;
}
let expected = fs::read_to_string(&path).unwrap_or_else(|_| {
panic!(
"missing golden {}; regenerate with BYNK_BLESS=1 cargo test -p bynk",
path.display()
)
});
assert_eq!(
actual, expected,
"golden {name} drifted; re-bless with BYNK_BLESS=1 cargo test -p bynk"
);
}
#[test]
fn golden_next_steps() {
bless_or_assert("new-next-steps.txt", &next_steps_message("hello"));
}
#[test]
fn golden_errors() {
let mut out = String::new();
out.push_str(&invalid_name_message("my-app"));
out.push_str(&clobber_message("hello"));
out.push_str(&cannot_derive_message("."));
bless_or_assert("new-errors.txt", &out);
}
#[test]
fn golden_scaffold_tree() {
let mut out = String::new();
for (label, body) in [
(
"bynk.toml",
new::render(include_str!("../src/templates/bynk.toml"), "hello"),
),
(
".gitignore",
new::render(include_str!("../src/templates/gitignore"), "hello"),
),
("src/hello.bynk", new::starter_source("hello")),
] {
out.push_str(&format!("--- {label} ---\n{body}"));
if !body.ends_with('\n') {
out.push('\n');
}
}
bless_or_assert("new-scaffold.txt", &out);
}
#[test]
fn name_validation() {
let legal = ["hello", "hello_world", "Hello", "h2", "x", "todo"];
let illegal = [
"my-app", "2048", "hello.web", "", "has space", "service", "from", "café", ];
for n in legal {
assert!(new::is_legal_name(n), "`{n}` should be a legal Bynk name");
}
for n in illegal {
assert!(!new::is_legal_name(n), "`{n}` should be rejected");
}
}
#[test]
fn starter_renders_compiles_and_is_fmt_clean() {
let name = "demo";
let rendered = new::starter_source(name);
assert!(
!rendered.contains(new::PLACEHOLDER),
"placeholder `{}` survived rendering:\n{rendered}",
new::PLACEHOLDER
);
assert!(
rendered.contains(&format!("context {name}")),
"rendered starter should declare `context {name}`:\n{rendered}"
);
let formatted = bynk_fmt::format_source(&rendered, &bynk_fmt::FormatOptions::default())
.expect("rendered starter must format");
assert_eq!(
formatted, rendered,
"rendered starter is not bynk-fmt-clean; re-format bynk/src/templates/starter.bynk"
);
let root = PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("new-starter-compile");
let _ = fs::remove_dir_all(&root);
fs::create_dir_all(&root).unwrap();
fs::write(root.join(format!("{name}.bynk")), &rendered).unwrap();
let result = bynk_emit::project::compile_project(&bynk_emit::project::CompileOptions::single(
root.clone(),
))
.map(|_| ())
.map_err(|f| {
bynk_emit::project::ProjectFailure::flatten(f)
.iter()
.map(|e| format!("{}: {}", e.category, e.message))
.collect::<Vec<_>>()
.join("; ")
});
let _ = fs::remove_dir_all(&root);
result.expect("the scaffolded starter must compile");
}