use crate::pure::PureFile;
pub fn assert_valid_rust(source: &str) -> String {
let pure = PureFile::from_source(source).expect("Input should parse into PureFile");
let output = pure
.to_source()
.expect("to_source should succeed for valid PureFile");
syn::parse_str::<syn::File>(&output).unwrap_or_else(|_| {
panic!(
"Generated code must be valid Rust syntax.\nInput:\n{}\nOutput:\n{}",
source, output
)
});
output
}
pub fn assert_compiles(source: &str) -> String {
use std::io::Write;
use std::process::Command;
let output = assert_valid_rust(source);
let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let src_dir = temp_dir.path().join("src");
std::fs::create_dir_all(&src_dir).expect("Failed to create src dir");
let lib_path = src_dir.join("lib.rs");
let mut file = std::fs::File::create(&lib_path).expect("Failed to create lib.rs");
writeln!(file, "#![allow(unused, dead_code)]").unwrap();
write!(file, "{}", output).expect("Failed to write source");
let cargo_toml = temp_dir.path().join("Cargo.toml");
std::fs::write(
&cargo_toml,
r#"[package]
name = "roundtrip_test"
version = "0.1.0"
edition = "2021"
"#,
)
.expect("Failed to write Cargo.toml");
let result = Command::new("cargo")
.args(["check", "--message-format=short"])
.current_dir(temp_dir.path())
.output()
.expect("Failed to run cargo check");
if !result.status.success() {
let stderr = String::from_utf8_lossy(&result.stderr);
panic!(
"Generated code failed to compile.\n\
=== Input ===\n{}\n\
=== Generated ===\n{}\n\
=== Errors ===\n{}",
source, output, stderr
);
}
output
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_assert_valid_rust_simple() {
let output = assert_valid_rust("fn main() {}");
assert!(output.contains("fn main"));
}
#[test]
fn test_assert_valid_rust_struct() {
let output = assert_valid_rust("struct Foo { x: i32 }");
assert!(output.contains("struct Foo"));
}
#[test]
#[should_panic(expected = "Input should parse")]
fn test_assert_valid_rust_invalid_input() {
assert_valid_rust("this is not valid rust {{{{");
}
}