#![cfg(not(any(
feature = "parser_tests",
feature = "analyzer_tests",
feature = "codegen_tests",
feature = "interpreter_tests",
feature = "conformance_tests",
feature = "integration_tests",
)))]
use std::env;
use std::fs;
use std::path::PathBuf;
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_format_as_function_argument_extracts_to_variable() {
let _tmp = tempfile::tempdir().unwrap();
let test_dir = _tmp.path().join(format!(
"wj_format_fix_{}_{}",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos(),
std::process::id()
));
fs::create_dir_all(&test_dir).unwrap();
let windjammer_code = r#"
extern fn draw_text(text: string, x: f32, y: f32);
fn render(score: i32) {
draw_text(format!("Score: {}", score), 10.0, 20.0);
}
"#;
fs::write(test_dir.join("format_test.wj"), windjammer_code).unwrap();
let wj_binary = PathBuf::from(env!("CARGO_BIN_EXE_wj"));
let output = std::process::Command::new(&wj_binary)
.arg("build")
.arg("format_test.wj")
.arg("--no-cargo")
.current_dir(&test_dir)
.output()
.expect("Failed to run wj build");
assert!(
output.status.success(),
"wj build should succeed, stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let rust_code = fs::read_to_string(test_dir.join("build/format_test.rs"))
.expect("Should have generated Rust file");
println!("Generated Rust code:\n{}", rust_code);
assert!(
rust_code.contains("let") && rust_code.contains("format!("),
"Should extract format!() to a variable, got:\n{}",
rust_code
);
assert!(
rust_code.contains("_temp") || rust_code.contains("score_text"),
"Should pass temp variable to extern fn, got:\n{}",
rust_code
);
assert!(
!rust_code.contains("draw_text(format!("),
"Should NOT pass format!() directly as argument, got:\n{}",
rust_code
);
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_format_in_method_call_extracts_to_variable() {
let _tmp2 = tempfile::tempdir().unwrap();
let test_dir = _tmp2.path().join(format!(
"wj_format_method_{}_{}",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos(),
std::process::id()
));
fs::create_dir_all(&test_dir).unwrap();
let windjammer_code = r#"
struct Context {}
impl Context {
fn draw_text(text: string, x: f32, y: f32) {}
}
fn render(ctx: Context, lives: i32) {
ctx.draw_text(format!("Lives: {}", lives), 100.0, 20.0);
}
"#;
fs::write(test_dir.join("method_format.wj"), windjammer_code).unwrap();
let wj_binary = PathBuf::from(env!("CARGO_BIN_EXE_wj"));
let output = std::process::Command::new(&wj_binary)
.arg("build")
.arg("method_format.wj")
.arg("--no-cargo")
.current_dir(&test_dir)
.output()
.expect("Failed to run wj build");
assert!(output.status.success(), "wj build should succeed");
let rust_code = fs::read_to_string(test_dir.join("build/method_format.rs"))
.expect("Should have generated Rust file");
println!("Generated Rust code:\n{}", rust_code);
assert!(
rust_code.contains("let") && rust_code.contains("format!("),
"Should extract format!() to a variable for method calls too"
);
assert!(
rust_code.contains("&_temp") || rust_code.contains("&lives_text"),
"Should pass reference to temp variable"
);
assert!(
!rust_code.contains("draw_text(format!(") && !rust_code.contains(".draw_text(format!("),
"Should NOT pass format!() directly as argument"
);
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_format_as_variable_assignment_unchanged() {
let _tmp3 = tempfile::tempdir().unwrap();
let test_dir = _tmp3.path().join(format!(
"wj_format_var_{}_{}",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos(),
std::process::id()
));
fs::create_dir_all(&test_dir).unwrap();
let windjammer_code = r#"
extern fn draw_text(text: string, x: f32, y: f32);
fn render(score: i32) {
let msg = format!("Score: {}", score);
draw_text(msg, 10.0, 20.0);
}
"#;
fs::write(test_dir.join("var_format.wj"), windjammer_code).unwrap();
let wj_binary = PathBuf::from(env!("CARGO_BIN_EXE_wj"));
let output = std::process::Command::new(&wj_binary)
.arg("build")
.arg("var_format.wj")
.arg("--no-cargo")
.current_dir(&test_dir)
.output()
.expect("Failed to run wj build");
assert!(output.status.success(), "wj build should succeed");
let rust_code = fs::read_to_string(test_dir.join("build/var_format.rs"))
.expect("Should have generated Rust file");
println!("Generated Rust code:\n{}", rust_code);
assert!(
rust_code.contains("let msg = format!(") || rust_code.contains("let msg = {"),
"Should keep variable assignment for format! (may be optimized to write!)"
);
assert!(
rust_code.contains("draw_text(windjammer_runtime::ffi::string_to_ffi(msg)")
|| rust_code.contains("draw_text(&msg,")
|| rust_code.contains("draw_text(msg,"),
"Should pass msg variable without msg.to_string() inside string_to_ffi. Got:\n{}",
rust_code
);
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_multiple_format_calls_in_same_function() {
let _tmp4 = tempfile::tempdir().unwrap();
let test_dir = _tmp4.path().join(format!(
"wj_format_multi_{}_{}",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos(),
std::process::id()
));
fs::create_dir_all(&test_dir).unwrap();
let windjammer_code = r#"
extern fn draw_text(text: string, x: f32, y: f32);
fn render(score: i32, lives: i32) {
draw_text(format!("Score: {}", score), 10.0, 20.0);
draw_text(format!("Lives: {}", lives), 100.0, 20.0);
}
"#;
fs::write(test_dir.join("multi_format.wj"), windjammer_code).unwrap();
let wj_binary = PathBuf::from(env!("CARGO_BIN_EXE_wj"));
let output = std::process::Command::new(&wj_binary)
.arg("build")
.arg("multi_format.wj")
.arg("--no-cargo")
.current_dir(&test_dir)
.output()
.expect("Failed to run wj build");
assert!(output.status.success(), "wj build should succeed");
let rust_code = fs::read_to_string(test_dir.join("build/multi_format.rs"))
.expect("Should have generated Rust file");
println!("Generated Rust code:\n{}", rust_code);
let temp_count = rust_code.matches("let _temp").count()
+ rust_code.matches("let score_text").count()
+ rust_code.matches("let lives_text").count();
assert!(
temp_count >= 2,
"Should create 2 separate temp variables for 2 format! calls"
);
}