#![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::PathBuf;
use std::process::Command;
fn compile_wj(source: &str) -> String {
use std::sync::atomic::{AtomicU64, Ordering};
static COUNTER: AtomicU64 = AtomicU64::new(0);
let id = COUNTER.fetch_add(1, Ordering::SeqCst);
let temp_dir = std::env::temp_dir().join(format!(
"wj_owned_param_insert_test_{}_{}",
std::process::id(),
id
));
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(&temp_dir).unwrap();
let source_file = temp_dir.join("test_input.wj");
std::fs::write(&source_file, source).unwrap();
let output_dir = temp_dir.join("output");
std::fs::create_dir_all(&output_dir).unwrap();
let wj_path = PathBuf::from(env!("CARGO_BIN_EXE_wj"));
let output = Command::new(&wj_path)
.arg("build")
.arg(source_file.to_str().unwrap())
.arg("-o")
.arg(output_dir.to_str().unwrap())
.arg("--no-cargo")
.output()
.expect("Failed to run wj");
assert!(
output.status.success(),
"wj build failed: {}",
String::from_utf8_lossy(&output.stderr)
);
let rs_file = output_dir.join("test_input.rs");
std::fs::read_to_string(&rs_file).expect("Failed to read generated Rust file")
}
#[test]
fn test_owned_param_read_then_insert() {
let source = r#"
use std::collections::HashMap
struct Quest {
id: string,
title: string,
}
impl Quest {
pub fn id(self) -> string {
self.id
}
}
struct QuestManager {
quests: HashMap<string, Quest>,
}
impl QuestManager {
pub fn add_quest(self, quest: Quest) {
let id = quest.id()
self.quests.insert(id, quest)
}
}
"#;
let rust = compile_wj(source);
assert!(
rust.contains("quest: Quest"),
"Expected owned 'quest: Quest' parameter, but got:\n{}",
rust
);
assert!(
!rust.contains("quest: &mut Quest"),
"Parameter should NOT be &mut Quest:\n{}",
rust
);
assert!(
!rust.contains("quest: &Quest"),
"Parameter should NOT be &Quest:\n{}",
rust
);
}
#[test]
fn test_owned_param_used_after_move_gets_cloned() {
let source = r#"
struct Item {
id: string,
name: string,
}
impl Item {
pub fn id(self) -> string {
self.id
}
}
fn process_item(item: Item) {
let id = item.id()
let name = item.name
println!("{}: {}", id, name)
}
"#;
let rust = compile_wj(source);
let has_valid_sig = rust.contains("item: Item")
|| rust.contains("mut item: Item")
|| rust.contains("item: &Item");
assert!(
has_valid_sig,
"Expected valid parameter signature (Item or &Item), but got:\n{}",
rust
);
if rust.contains("item: &Item") {
assert!(
rust.contains(".clone()"),
"Borrowed parameter requires auto-cloned field access, but got:\n{}",
rust
);
}
}
#[test]
fn test_self_field_reassignment_clones() {
let source = r#"
struct Dialog {
current_node_id: string,
start_node_id: string,
}
impl Dialog {
pub fn reset(self) {
self.current_node_id = self.start_node_id
}
}
"#;
let rust = compile_wj(source);
assert!(
rust.contains("self.start_node_id.clone()"),
"Expected auto-clone for self.field = self.other_field, but got:\n{}",
rust
);
}