wasmrust 0.3.2

Rust WebAssembly plugin for Wasmrun - compile Rust projects to WebAssembly with wasm-bindgen support
Documentation
mod wasmrust_tests {
    use std::fs;
    use tempfile::TempDir;
    use wasmrust::{
        create_plugin, BuildConfig, OptimizationLevel, Plugin, PluginType, WasmBuilder,
        WasmrustBuilder, WasmrustPlugin,
    };

    fn create_test_rust_project(dir: &std::path::Path, project_type: &str) {
        let cargo_toml_content = match project_type {
            "standard" => {
                r#"
[package]
name = "test-project"
version = "0.1.0"
edition = "2021"

[[bin]]
name = "test-project"
path = "src/main.rs"
"#
            }
            "wasm-bindgen" => {
                r#"
[package]
name = "test-wasm-bindgen"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"
web-sys = "0.3"
"#
            }
            "yew" => {
                r#"
[package]
name = "test-yew-app"
version = "0.1.0"
edition = "2021"

[dependencies]
yew = "0.21"
wasm-bindgen = "0.2"
web-sys = "0.3"
"#
            }
            _ => panic!("Unknown project type"),
        };

        fs::write(dir.join("Cargo.toml"), cargo_toml_content).unwrap();

        let src_dir = dir.join("src");
        fs::create_dir_all(&src_dir).unwrap();

        let main_rs_content = match project_type {
            "standard" => {
                r#"
fn main() {
    println!("Hello from Rust WASM!");
}
"#
            }
            "wasm-bindgen" => {
                r#"
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}
"#
            }
            "yew" => {
                r#"
use yew::prelude::*;

#[function_component(App)]
fn app() -> Html {
    html! {
        <div>
            <h1>{ "Hello from Yew!" }</h1>
        </div>
    }
}

fn main() {
    yew::Renderer::<App>::new().render();
}
"#
            }
            _ => panic!("Unknown project type: {project_type}"),
        };

        let main_file = if project_type == "wasm-bindgen" {
            src_dir.join("lib.rs")
        } else {
            src_dir.join("main.rs")
        };

        fs::write(main_file, main_rs_content).unwrap();

        if project_type == "yew" {
            let index_html = r#"
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Yew App</title>
</head>
<body></body>
</html>
"#;
            fs::write(dir.join("index.html"), index_html).unwrap();
        }
    }

    #[test]
    fn test_plugin_info() {
        let plugin = WasmrustPlugin::new();
        let info = plugin.info();

        assert_eq!(info.name, "wasmrust");
        assert_eq!(info.version, "0.3.0");
        assert_eq!(info.plugin_type, PluginType::External);
        assert!(info.capabilities.compile_wasm);
        assert!(info.capabilities.compile_webapp);
        assert!(info.capabilities.live_reload);
        assert!(info.capabilities.optimization);
        assert!(info.extensions.contains(&"rs".to_string()));
        assert!(info.entry_files.contains(&"Cargo.toml".to_string()));
    }

    #[test]
    fn test_can_handle_project() {
        let temp_dir = TempDir::new().unwrap();
        let project_dir = temp_dir.path();

        let plugin = WasmrustPlugin::new();

        assert!(!plugin.can_handle_project(project_dir.to_str().unwrap()));

        create_test_rust_project(project_dir, "standard");
        assert!(plugin.can_handle_project(project_dir.to_str().unwrap()));
    }

    #[test]
    fn test_builder_creation() {
        let plugin = WasmrustPlugin::new();
        let builder = plugin.get_builder();

        assert_eq!(builder.language_name(), "rust");
        assert!(builder.supported_extensions().contains(&"rs"));
        assert!(builder.entry_file_candidates().contains(&"Cargo.toml"));
    }

    #[test]
    fn test_dependency_checking() {
        let builder = WasmrustBuilder::new();
        let missing_deps = builder.check_dependencies();

        assert!(missing_deps.is_empty() || !missing_deps.is_empty());
    }

    #[test]
    fn test_project_validation() {
        let temp_dir = TempDir::new().unwrap();
        let project_dir = temp_dir.path();

        let builder = WasmrustBuilder::new();

        assert!(builder
            .validate_project(project_dir.to_str().unwrap())
            .is_err());

        create_test_rust_project(project_dir, "standard");
        assert!(builder
            .validate_project(project_dir.to_str().unwrap())
            .is_ok());
    }

    #[test]
    fn test_framework_detection() {
        let temp_dir = TempDir::new().unwrap();

        let standard_dir = temp_dir.path().join("standard");
        fs::create_dir_all(&standard_dir).unwrap();
        create_test_rust_project(&standard_dir, "standard");

        let plugin = wasmrust::WasmRustPlugin::new();
        assert!(!plugin.supports_web_app(standard_dir.to_str().unwrap()));

        let yew_dir = temp_dir.path().join("yew");
        fs::create_dir_all(&yew_dir).unwrap();
        create_test_rust_project(&yew_dir, "yew");

        assert!(plugin.supports_web_app(yew_dir.to_str().unwrap()));
    }

    #[test]
    fn test_create_plugin_function() {
        let plugin = create_plugin();
        assert_eq!(plugin.info().name, "wasmrust");
        assert_eq!(plugin.info().plugin_type, PluginType::External);
    }

    #[test]
    fn test_optimization_level_conversion() {
        let debug = OptimizationLevel::Debug;
        let release = OptimizationLevel::Release;
        let size = OptimizationLevel::Size;

        assert_eq!(debug, OptimizationLevel::Debug);
        assert_eq!(release, OptimizationLevel::Release);
        assert_eq!(size, OptimizationLevel::Size);
    }

    #[test]
    #[ignore]
    fn test_actual_compilation() {
        let temp_dir = TempDir::new().unwrap();
        let project_dir = temp_dir.path();
        let output_dir = temp_dir.path().join("output");

        create_test_rust_project(project_dir, "standard");

        let builder = WasmrustBuilder::new();

        let missing_deps = builder.check_dependencies();
        if !missing_deps.is_empty() {
            println!("Skipping compilation test due to missing dependencies: {missing_deps:?}");
            return;
        }

        let config = BuildConfig {
            input: project_dir.to_str().unwrap().to_string(),
            output_dir: output_dir.to_str().unwrap().to_string(),
            optimization: OptimizationLevel::Debug,
            target_type: "wasm".to_string(),
            verbose: true,
            watch: false,
        };

        match builder.build(&config) {
            Ok(result) => {
                assert!(std::path::Path::new(&result.output_path).exists());
                assert_eq!(result.language, "rust");
                assert!(result.file_size > 0);
            }
            Err(e) => {
                panic!("Compilation failed: {e:?}");
            }
        }
    }

    #[test]
    fn test_clean_functionality() {
        let temp_dir = TempDir::new().unwrap();
        let project_dir = temp_dir.path();

        create_test_rust_project(project_dir, "standard");

        let builder = WasmrustBuilder::new();

        if builder.check_dependencies().is_empty() {
            match builder.clean(project_dir.to_str().unwrap()) {
                Ok(()) => println!("Clean successful"),
                Err(e) => println!("Clean failed (expected if no target dir): {e}"),
            }
        }
    }
}

mod standalone_tests {
    use std::fs;
    use tempfile::TempDir;
    use wasmrust::WasmRustPlugin;

    #[test]
    fn test_standalone_plugin() {
        let plugin = WasmRustPlugin::new();

        let temp_dir = TempDir::new().unwrap();
        let project_dir = temp_dir.path();

        assert!(!plugin.can_handle(project_dir.to_str().unwrap()));

        fs::write(
            project_dir.join("Cargo.toml"),
            r#"
[package]
name = "test"
version = "0.1.0"
edition = "2021"
"#,
        )
        .unwrap();

        assert!(plugin.can_handle(project_dir.to_str().unwrap()));

        let deps = plugin.check_dependencies();
        assert!(deps.is_empty() || !deps.is_empty());
    }

    #[test]
    fn test_project_inspection() {
        let temp_dir = TempDir::new().unwrap();
        let project_dir = temp_dir.path();

        fs::write(
            project_dir.join("Cargo.toml"),
            r#"
[package]
name = "test-project"
version = "1.0.0"
edition = "2021"

[dependencies]
yew = "0.21"
wasm-bindgen = "0.2"
"#,
        )
        .unwrap();

        let plugin = WasmRustPlugin::new();

        match plugin.inspect_project(project_dir.to_str().unwrap()) {
            Ok(info) => {
                assert_eq!(info.name, "test-project");
                assert_eq!(info.version, "1.0.0");
                assert!(info.frameworks.contains(&"yew".to_string()));
            }
            Err(e) => {
                println!("Inspection failed: {e}");
            }
        }
    }
}