#![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 tempfile::TempDir;
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_mod_wj_trait_and_struct_codegen() {
let tmp = TempDir::new().unwrap();
let src_dir = tmp.path().join("src");
let plugin_dir = src_dir.join("plugin");
fs::create_dir_all(&plugin_dir).unwrap();
fs::write(
plugin_dir.join("mod.wj"),
r#"
pub mod audio
pub trait Plugin {
fn name(self) -> string
fn version(self) -> string
}
pub struct App {
pub plugin_count: i32,
}
impl App {
pub fn new() -> App {
App { plugin_count: 0 }
}
}
"#,
)
.unwrap();
fs::write(
plugin_dir.join("audio.wj"),
r#"
pub struct AudioPlugin {
pub name_str: string,
}
impl AudioPlugin {
pub fn new() -> AudioPlugin {
AudioPlugin { name_str: "audio" }
}
}
"#,
)
.unwrap();
fs::write(
src_dir.join("main.wj"),
r#"
pub mod plugin
pub fn create_app() -> i32 {
42
}
"#,
)
.unwrap();
let out_dir = tmp.path().join("build");
let output = std::process::Command::new(env!("CARGO_BIN_EXE_wj"))
.args([
"build",
src_dir.to_str().unwrap(),
"--output",
out_dir.to_str().unwrap(),
"--no-cargo",
])
.output()
.expect("Failed to run wj binary");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"Compilation failed.\nstderr: {}",
stderr
);
let mod_rs_path = out_dir.join("plugin").join("mod.rs");
assert!(
mod_rs_path.exists(),
"plugin/mod.rs should exist. Out dir contents: {:?}",
fs::read_dir(&out_dir)
.map(|e| e.flatten().map(|e| e.path()).collect::<Vec<_>>())
.unwrap_or_default()
);
let mod_rs_content = fs::read_to_string(&mod_rs_path).unwrap();
assert!(
mod_rs_content.contains("pub mod audio"),
"mod.rs must contain `pub mod audio`.\nActual content:\n{}",
mod_rs_content
);
assert!(
mod_rs_content.contains("pub trait Plugin"),
"mod.rs must contain `pub trait Plugin` from mod.wj.\nActual content:\n{}",
mod_rs_content
);
assert!(
mod_rs_content.contains("pub struct App"),
"mod.rs must contain `pub struct App` from mod.wj.\nActual content:\n{}",
mod_rs_content
);
assert!(
mod_rs_content.contains("impl App"),
"mod.rs must contain `impl App` from mod.wj.\nActual content:\n{}",
mod_rs_content
);
let pub_mod_count = mod_rs_content.matches("pub mod audio").count();
assert!(
pub_mod_count == 1,
"mod.rs should have exactly 1 `pub mod audio` declaration, found {}.\nActual content:\n{}",
pub_mod_count,
mod_rs_content
);
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_mod_wj_code_compiles_with_rustc() {
let tmp = TempDir::new().unwrap();
let src_dir = tmp.path().join("src");
let plugin_dir = src_dir.join("plugin");
fs::create_dir_all(&plugin_dir).unwrap();
fs::write(
plugin_dir.join("mod.wj"),
r#"
pub mod audio
pub trait Plugin {
fn name(self) -> string
fn version(self) -> string
}
pub struct App {
pub plugin_count: i32,
}
impl App {
pub fn new() -> App {
App { plugin_count: 0 }
}
}
"#,
)
.unwrap();
fs::write(
plugin_dir.join("audio.wj"),
r#"
pub struct AudioPlugin {
pub volume: f32,
}
"#,
)
.unwrap();
fs::write(
src_dir.join("lib.wj"),
r#"
pub mod plugin
"#,
)
.unwrap();
let out_dir = tmp.path().join("build");
let output = std::process::Command::new(env!("CARGO_BIN_EXE_wj"))
.args([
"build",
src_dir.to_str().unwrap(),
"--output",
out_dir.to_str().unwrap(),
"--no-cargo",
])
.output()
.expect("Failed to run wj binary");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"wj compilation failed.\nstderr: {}",
stderr
);
let rustc_output = std::process::Command::new("rustc")
.arg("--edition=2021")
.arg("--crate-type=lib")
.arg("--emit=metadata")
.arg("-o")
.arg(tmp.path().join("verify.rmeta"))
.arg(out_dir.join("lib.rs"))
.output()
.expect("Failed to run rustc");
let rustc_stderr = String::from_utf8_lossy(&rustc_output.stderr);
assert!(
rustc_output.status.success(),
"Generated Rust from mod.wj should compile with rustc.\nrustc stderr:\n{}",
rustc_stderr
);
}