#![cfg(any(
not(any(
feature = "parser_tests",
feature = "analyzer_tests",
feature = "codegen_tests",
feature = "interpreter_tests",
feature = "conformance_tests",
feature = "integration_tests",
)),
feature = "codegen_tests",
))]
#[path = "common/test_utils.rs"]
mod test_utils;
use std::fs;
use std::process::Command;
use tempfile::TempDir;
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_ensures_can_access_moved_parameters() {
let source = r#"
struct User {
pub name: string,
pub age: i32,
}
@requires(name.len() > 0)
@ensures(result.name == name)
fn create_user(name: string, age: i32) -> User {
User { name: name, age: age }
}
@test
fn test_create_user() {
let user = create_user("Alice", 25)
assert_eq(user.name, "Alice")
}
"#;
let temp_dir = TempDir::new().unwrap();
let input_path = temp_dir.path().join("test.wj");
fs::write(&input_path, source).unwrap();
let output = Command::new(test_utils::wj_binary())
.args(["build", input_path.to_str().unwrap(), "--no-cargo"])
.current_dir(&temp_dir)
.output()
.expect("Failed to run wj compiler");
if !output.status.success() {
panic!(
"Windjammer compilation failed: {}",
String::from_utf8_lossy(&output.stderr)
);
}
let rust_path = temp_dir.path().join("build/test.rs");
let rust_code = fs::read_to_string(&rust_path).unwrap();
println!("Generated Rust:\n{}", rust_code);
let rust_code_for_rustc = rust_code
.lines()
.filter(|line| !line.trim().starts_with("use windjammer_runtime::test::"))
.collect::<Vec<_>>()
.join("\n")
.replace("windjammer_runtime::test::requires", "let _ = ")
.replace("windjammer_runtime::test::ensures", "let _ = ");
let rustc_test_path = temp_dir.path().join("test_rustc.rs");
fs::write(&rustc_test_path, &rust_code_for_rustc).unwrap();
let rustc_output = Command::new("rustc")
.args([
rustc_test_path.to_str().unwrap(),
"--crate-type",
"lib",
"--test",
"-o",
temp_dir.path().join("test_binary").to_str().unwrap(),
])
.output()
.expect("Failed to run rustc");
if !rustc_output.status.success() {
let stderr = String::from_utf8_lossy(&rustc_output.stderr);
if stderr.contains("E0382") {
panic!(
"BUG CONFIRMED: E0382 borrow of moved value in @ensures!\n\nRust code:\n{}\n\nRustc errors:\n{}",
rust_code, stderr
);
}
panic!(
"Generated Rust code failed to compile!\n\nRust code:\n{}\n\nRustc errors:\n{}",
rust_code, stderr
);
}
assert!(
rust_code.contains("__name__for_ensures") || rust_code.contains("name.clone()"),
"Expected parameter to be cloned for @ensures access"
);
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_ensures_with_multiple_moved_parameters() {
let source = r#"
struct Point {
pub x: i32,
pub y: i32,
}
@requires(label.len() > 0)
@ensures(result.x == x && result.y == y)
fn create_point(label: string, x: i32, y: i32) -> Point {
Point { x: x, y: y }
}
"#;
let temp_dir = TempDir::new().unwrap();
let input_path = temp_dir.path().join("test.wj");
fs::write(&input_path, source).unwrap();
let output = Command::new(test_utils::wj_binary())
.args(["build", input_path.to_str().unwrap(), "--no-cargo"])
.current_dir(&temp_dir)
.output()
.expect("Failed to run wj compiler");
if !output.status.success() {
panic!(
"Windjammer compilation failed: {}",
String::from_utf8_lossy(&output.stderr)
);
}
let rust_path = temp_dir.path().join("build/test.rs");
let rust_code = fs::read_to_string(&rust_path).unwrap();
let rust_code_for_rustc = rust_code
.lines()
.filter(|line| !line.trim().starts_with("use windjammer_runtime::test::"))
.collect::<Vec<_>>()
.join("\n")
.replace("windjammer_runtime::test::requires", "let _ = ")
.replace("windjammer_runtime::test::ensures", "let _ = ");
let rustc_test_path = temp_dir.path().join("test_rustc.rs");
fs::write(&rustc_test_path, &rust_code_for_rustc).unwrap();
let rustc_output = Command::new("rustc")
.args([
rustc_test_path.to_str().unwrap(),
"--crate-type",
"lib",
"-o",
temp_dir.path().join("test_binary").to_str().unwrap(),
])
.output()
.expect("Failed to run rustc");
if !rustc_output.status.success() {
let stderr = String::from_utf8_lossy(&rustc_output.stderr);
panic!(
"Generated Rust code failed to compile!\n\nRustc errors:\n{}",
stderr
);
}
}