use std::path::{Path, PathBuf};
use std::process::Command;
fn rustango_crate() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("crates/")
.join("rustango")
}
fn in_repo() -> bool {
rustango_crate().join("Cargo.toml").is_file()
}
fn scratch(tag: &str) -> PathBuf {
let dir = std::env::temp_dir().join(format!(
"rustango-scaffold-{}-{}-{tag}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos())
.unwrap_or(0),
));
std::fs::create_dir_all(&dir).expect("create scratch dir");
dir
}
fn generate(template: &str, flags: &[&str], tag: &str) -> (PathBuf, PathBuf) {
let work = scratch(tag);
let out = Command::new(env!("CARGO_BIN_EXE_cargo-rustango"))
.current_dir(&work)
.args(["rustango", "new", "probe", "--template", template])
.args(flags)
.arg("--rustango-path")
.arg(rustango_crate())
.output()
.expect("run the scaffolder");
assert!(
out.status.success(),
"scaffolding {template} {flags:?} failed:\n{}",
String::from_utf8_lossy(&out.stderr),
);
let root = work.join("probe");
(work, root)
}
fn check(root: &Path, extra: &[&str]) -> (bool, usize, String) {
let out = Command::new(env!("CARGO"))
.current_dir(root)
.args(["check", "--message-format=json-diagnostic-rendered-ansi"])
.args(extra)
.env(
"CARGO_TARGET_DIR",
std::env::temp_dir().join("rustango-scaffold-target"),
)
.env("CARGO_INCREMENTAL", "0")
.output()
.expect("run cargo check");
let stdout = String::from_utf8_lossy(&out.stdout);
let mut warnings = Vec::new();
for line in stdout.lines() {
if !line.contains(r#""reason":"compiler-message""#) {
continue;
}
if !line.contains("probe") {
continue; }
if line.contains(r#""level":"warning""#) {
warnings.push(line.to_owned());
}
}
let log = format!("{stdout}{}", String::from_utf8_lossy(&out.stderr));
(out.status.success(), warnings.len(), log)
}
fn assert_compiles(template: &str, extra: &[&str], label: &str) {
assert_compiles_with(template, &[], extra, label);
}
fn assert_compiles_with(template: &str, scaffold: &[&str], extra: &[&str], label: &str) {
if !in_repo() {
eprintln!("skipping: crates/rustango not alongside — not a repo checkout");
return;
}
let (work, root) = generate(template, scaffold, label);
let (ok, warnings, log) = check(&root, extra);
let _ = std::fs::remove_dir_all(&work);
assert!(ok, "`{template}` {label} did not compile:\n{log}");
assert_eq!(
warnings, 0,
"`{template}` {label} compiled but emitted {warnings} warning(s) — a \
freshly generated project must be clean (#1210):\n{log}"
);
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn api_template_compiles() {
assert_compiles("api", &[], "default");
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn fullstack_template_compiles() {
assert_compiles("fullstack", &[], "default");
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn tenant_template_compiles() {
assert_compiles("tenant", &[], "default");
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn api_template_compiles_on_sqlite() {
assert_compiles(
"api",
&["--no-default-features", "--features", "sqlite"],
"sqlite",
);
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn api_template_compiles_on_mysql() {
assert_compiles(
"api",
&["--no-default-features", "--features", "mysql"],
"mysql",
);
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn fullstack_template_compiles_on_sqlite() {
assert_compiles(
"fullstack",
&["--no-default-features", "--features", "sqlite"],
"sqlite",
);
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn tenant_template_compiles_on_sqlite() {
assert_compiles(
"tenant",
&["--no-default-features", "--features", "sqlite"],
"sqlite",
);
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn backend_sqlite_compiles_as_generated() {
assert_compiles_with("fullstack", &["--backend", "sqlite"], &[], "backend-sqlite");
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn backend_mysql_compiles_as_generated() {
assert_compiles_with("fullstack", &["--backend", "mysql"], &[], "backend-mysql");
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn tenant_on_sqlite_backend_compiles_as_generated() {
assert_compiles_with("tenant", &["--backend", "sqlite"], &[], "tenant-sqlite");
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn selected_features_compile() {
assert_compiles_with(
"fullstack",
&["--features", "csrf,cache-page,testkit"],
&[],
"features",
);
}
#[test]
#[ignore = "compiles rustango; run with --ignored"]
fn tenancy_feature_on_fullstack_compiles() {
assert_compiles_with(
"fullstack",
&["--features", "tenancy"],
&[],
"features-tenancy",
);
}