#![cfg(any(
not(any(
feature = "parser_tests",
feature = "analyzer_tests",
feature = "codegen_tests",
feature = "interpreter_tests",
feature = "conformance_tests",
feature = "integration_tests",
)),
feature = "analyzer_tests",
))]
use std::path::Path;
use std::process::Command;
fn compile_wj_to_rust(source: &str) -> String {
let test_id = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
let test_dir = std::env::temp_dir().join(format!("wj_unknown_method_mut_test_{}", test_id));
let _ = std::fs::remove_dir_all(&test_dir);
let _ = std::fs::create_dir_all(&test_dir);
let input_file = test_dir.join("test_input.wj");
std::fs::write(&input_file, source).unwrap();
let wj_binary = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("target")
.join("release")
.join("wj");
let _output = Command::new(&wj_binary)
.arg("build")
.arg("--no-cargo")
.arg("test_input.wj")
.current_dir(&test_dir)
.output()
.expect("Failed to run wj compiler");
for candidate in &[
test_dir.join("build").join("test_input.rs"),
test_dir.join("test_input.rs"),
] {
if candidate.exists() {
return std::fs::read_to_string(candidate).unwrap_or_default();
}
}
for dir in &[test_dir.join("build"), test_dir.clone()] {
if let Ok(entries) = std::fs::read_dir(dir) {
for entry in entries.flatten() {
if entry.path().extension().map(|x| x == "rs").unwrap_or(false) {
return std::fs::read_to_string(entry.path()).unwrap_or_default();
}
}
}
}
String::from("NO RS FILE FOUND")
}
#[test]
fn test_unknown_method_on_param_infers_mut() {
let source = r#"
pub struct Renderer {
pub count: i32,
}
impl Renderer {
pub fn add_item(self, x: f32, y: f32) {
self.count = self.count + 1
}
}
pub fn setup(renderer: Renderer) {
renderer.add_item(1.0, 2.0)
renderer.add_item(3.0, 4.0)
}
"#;
let output = compile_wj_to_rust(source);
assert!(
output.contains("renderer: &mut Renderer"),
"Parameter with mutating method calls should be inferred as &mut. Got:\n{}",
output
);
}
#[test]
fn test_known_readonly_method_stays_borrowed() {
let source = r#"
pub struct Data {
pub items: Vec<i32>,
}
impl Data {
pub fn len(self) -> i32 {
self.items.len() as i32
}
}
pub fn count_items(data: Data) -> i32 {
data.len()
}
"#;
let output = compile_wj_to_rust(source);
assert!(
output.contains("data: &Data"),
"Parameter with only readonly method calls should be &. Got:\n{}",
output
);
}
#[test]
fn test_unknown_method_on_typed_param_defaults_borrowed() {
let source = r#"
pub struct Grid {
pub name: string,
}
pub fn process(grid: Grid) {
grid.some_completely_unknown_method(42)
}
"#;
let output = compile_wj_to_rust(source);
assert!(
output.contains("grid: &Grid"),
"Unknown method on typed user param defaults to borrowed (multi-pass will refine). Got:\n{}",
output
);
}
#[test]
fn test_field_read_only_stays_borrowed() {
let source = r#"
pub struct Config {
pub name: string,
pub enabled: bool,
}
pub fn describe(config: Config) -> string {
config.name
}
"#;
let output = compile_wj_to_rust(source);
assert!(
!output.contains("config: &mut Config"),
"Parameter with only field reads should NOT be &mut. Got:\n{}",
output
);
}