a6db4699f7
Add compile-fail coverage for generated APIs: a surface include that exposes only one class must reject references to absent generated class names during cargo check. req: codegen/001 req: style/002 req: test/003
167 lines
4.3 KiB
Rust
167 lines
4.3 KiB
Rust
use std::path::{Path, PathBuf};
|
|
use std::process::Command;
|
|
|
|
#[test]
|
|
fn handler_macro_reports_unknown_handle_and_bad_shape() {
|
|
// req: derive_handler/001 req: test/003
|
|
let fixture = Fixture::new("slhx-derive-handler-fail");
|
|
fixture.write(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"[package]
|
|
name = "slhx-derive-handler-fail"
|
|
version = "0.0.0"
|
|
edition = "2021"
|
|
|
|
[lib]
|
|
path = "src/lib.rs"
|
|
|
|
[dependencies]
|
|
slhx = {{ path = {:?} }}
|
|
"#,
|
|
repo_path("slhx")
|
|
),
|
|
);
|
|
fixture.write(
|
|
"build.rs",
|
|
r#"fn main() {
|
|
let out = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
|
|
std::fs::write(
|
|
out.join("slhx.syms"),
|
|
"slhx-syms-v1\nhandle\ttemplates/app.heml::known\tknown\t1\n",
|
|
)
|
|
.unwrap();
|
|
}
|
|
"#,
|
|
);
|
|
fixture.write(
|
|
"src/lib.rs",
|
|
r#"#[slhx::handler]
|
|
fn missing() -> impl slhx::IntoEffect {
|
|
slhx::EffectBatch::default()
|
|
}
|
|
|
|
#[slhx::handler]
|
|
fn known() {}
|
|
"#,
|
|
);
|
|
|
|
let output = Command::new("cargo")
|
|
.arg("check")
|
|
.arg("--quiet")
|
|
.arg("--manifest-path")
|
|
.arg(fixture.path.join("Cargo.toml"))
|
|
.env("CARGO_TARGET_DIR", fixture.path.join("target"))
|
|
.output()
|
|
.expect("cargo check fixture runs");
|
|
|
|
assert!(!output.status.success(), "fixture unexpectedly compiled");
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(
|
|
stderr.contains("unknown slhx handle `missing`; add `data-slhx-handle=\"missing\"`"),
|
|
"missing unknown-handle diagnostic in stderr:\n{stderr}"
|
|
);
|
|
assert!(
|
|
stderr.contains("slhx handler `known` must accept a form/context parameter or return a value implementing IntoEffect"),
|
|
"missing handler-shape diagnostic in stderr:\n{stderr}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn generated_resource_references_fail_when_name_is_absent() {
|
|
// req: style/002 req: codegen/001 req: test/003
|
|
let fixture = Fixture::new("slhx-derive-generated-resource-fail");
|
|
fixture.write(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"[package]
|
|
name = "slhx-derive-generated-resource-fail"
|
|
version = "0.0.0"
|
|
edition = "2021"
|
|
|
|
[lib]
|
|
path = "src/lib.rs"
|
|
|
|
[dependencies]
|
|
slhx = {{ path = {:?} }}
|
|
"#,
|
|
repo_path("slhx")
|
|
),
|
|
);
|
|
fixture.write(
|
|
"build.rs",
|
|
r#"fn main() {
|
|
let out = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
|
|
std::fs::write(
|
|
out.join("slhx.generated.rs"),
|
|
"pub mod classes { pub const card: ::slhx::CssClass = ::slhx::CssClass::new(\"card\"); }\n",
|
|
)
|
|
.unwrap();
|
|
}
|
|
"#,
|
|
);
|
|
fixture.write(
|
|
"src/lib.rs",
|
|
r#"#[slhx::surface]
|
|
pub mod ui {}
|
|
|
|
pub const KNOWN: slhx::CssClass = ui::classes::card;
|
|
pub const MISSING: slhx::CssClass = ui::classes::missing;
|
|
"#,
|
|
);
|
|
|
|
let output = Command::new("cargo")
|
|
.arg("check")
|
|
.arg("--quiet")
|
|
.arg("--manifest-path")
|
|
.arg(fixture.path.join("Cargo.toml"))
|
|
.env("CARGO_TARGET_DIR", fixture.path.join("target"))
|
|
.output()
|
|
.expect("cargo check fixture runs");
|
|
|
|
assert!(!output.status.success(), "fixture unexpectedly compiled");
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(
|
|
stderr.contains("cannot find value `missing` in module `ui::classes`"),
|
|
"missing generated-resource diagnostic in stderr:\n{stderr}"
|
|
);
|
|
}
|
|
|
|
fn repo_path(crate_name: &str) -> PathBuf {
|
|
Path::new(env!("CARGO_MANIFEST_DIR"))
|
|
.parent()
|
|
.expect("crate has workspace parent")
|
|
.join(crate_name)
|
|
}
|
|
|
|
struct Fixture {
|
|
path: PathBuf,
|
|
}
|
|
|
|
impl Fixture {
|
|
fn new(name: &str) -> Self {
|
|
let path = std::env::temp_dir().join(format!(
|
|
"{name}-{}-{}",
|
|
std::process::id(),
|
|
std::thread::current().name().unwrap_or("test")
|
|
));
|
|
let _ = std::fs::remove_dir_all(&path);
|
|
std::fs::create_dir_all(path.join("src")).unwrap();
|
|
Self { path }
|
|
}
|
|
|
|
fn write(&self, relative: &str, contents: &str) {
|
|
let path = self.path.join(relative);
|
|
if let Some(parent) = path.parent() {
|
|
std::fs::create_dir_all(parent).unwrap();
|
|
}
|
|
std::fs::write(path, contents).unwrap();
|
|
}
|
|
}
|
|
|
|
impl Drop for Fixture {
|
|
fn drop(&mut self) {
|
|
let _ = std::fs::remove_dir_all(&self.path);
|
|
}
|
|
}
|