#![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 windjammer::codegen::rust::types::{type_to_rust, type_to_rust_with_lifetime};
use windjammer::parser::Type;
#[test]
fn test_hashmap_str_i32_emits_string_i64() {
let ty = Type::Parameterized(
"HashMap".to_string(),
vec![Type::Custom("str".to_string()), Type::Int],
);
let rust = type_to_rust(&ty);
assert_eq!(
rust, "HashMap<String, i64>",
"HashMap<str, i32> should emit HashMap<String, i64>, got {}",
rust
);
}
#[test]
fn test_hashmap_str_str_emits_string_string() {
let ty = Type::Parameterized(
"HashMap".to_string(),
vec![
Type::Custom("str".to_string()),
Type::Custom("str".to_string()),
],
);
let rust = type_to_rust(&ty);
assert_eq!(
rust, "HashMap<String, String>",
"HashMap<str, string> should emit HashMap<String, String>, got {}",
rust
);
}
#[test]
fn test_hashmap_string_i32_emits_string_i64() {
let ty = Type::Parameterized("HashMap".to_string(), vec![Type:: String, Type::Int]);
let rust = type_to_rust(&ty);
assert_eq!(
rust, "HashMap<String, i64>",
"HashMap<String, i32> should emit HashMap<String, i64>, got {}",
rust
);
}
#[test]
fn test_hashmap_i32_str_value_emits_string() {
let ty = Type::Parameterized(
"HashMap".to_string(),
vec![Type::Int, Type::Custom("str".to_string())],
);
let rust = type_to_rust(&ty);
assert_eq!(
rust, "HashMap<i64, String>",
"HashMap<i32, string> value should become String, got {}",
rust
);
}
#[test]
fn test_hashmap_str_in_struct_field() {
let ty = Type::Parameterized(
"HashMap".to_string(),
vec![
Type::Custom("str".to_string()),
Type::Custom("PropertyValue".to_string()),
],
);
let rust = type_to_rust(&ty);
assert_eq!(
rust, "HashMap<String, PropertyValue>",
"Struct field HashMap<str, PropertyValue> should emit HashMap<String, PropertyValue>, got {}",
rust
);
}
#[test]
fn test_hashmap_str_str_with_lifetime() {
let ty = Type::Parameterized(
"HashMap".to_string(),
vec![
Type::Custom("str".to_string()),
Type::Custom("str".to_string()),
],
);
let rust = type_to_rust_with_lifetime(&ty);
assert!(
rust == "HashMap<String, string>" || rust == "HashMap<&str, &str>",
"HashMap<str, string> mapping: expected String pair or &str pair, got {}",
rust
);
}
#[test]
fn test_hashmap_must_not_emit_ampersand_str_as_key() {
let ty = Type::Parameterized(
"HashMap".to_string(),
vec![Type::Custom("str".to_string()), Type::Int],
);
let rust = type_to_rust(&ty);
assert!(
!rust.contains("HashMap<&str"),
"Must NOT emit HashMap<&str, ...> - causes Borrow<&str> errors. Got: {}",
rust
);
}
#[test]
#[cfg(feature = "cli")]
fn test_hashmap_str_compiles_to_string_integration() {
use std::fs;
use std::process::Command;
let source = r#"
use std::collections::HashMap
struct Registry {
name_to_id: HashMap<string, i64>
}
impl Registry {
pub fn get_id(self, name: string) -> Option<i64> {
self.name_to_id.get(name)
}
}
fn main() {
let mut reg = Registry { name_to_id: HashMap::new() }
reg.name_to_id.insert("test".to_string(), 42)
let id = reg.get_id("test")
println("{:?}", id)
}
"#;
let tmp = tempfile::tempdir().expect("tempdir");
let test_dir = tmp.path();
let wj_file = test_dir.join("test.wj");
fs::write(&wj_file, source).unwrap();
let out_dir = test_dir.join("out");
let wj_binary = env!("CARGO_BIN_EXE_wj");
let _output = Command::new(wj_binary)
.arg("build")
.arg("--no-cargo")
.arg(&wj_file)
.arg("--target")
.arg("rust")
.arg("--output")
.arg(&out_dir)
.output()
.expect("Failed to run wj compiler");
let rust_file = out_dir.join("test.rs");
let generated = fs::read_to_string(&rust_file).expect("Failed to read generated Rust file");
assert!(
generated.contains("HashMap<String, i64>"),
"HashMap<str, i64> must emit HashMap<String, i64>. Got:\n{}",
generated
);
assert!(
!generated.contains("HashMap<&str"),
"Must NOT emit HashMap<&str, ...> - causes Borrow<&str> errors. Got:\n{}",
generated
);
}