#![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::fs;
use std::process::Command;
use tempfile::TempDir;
use windjammer::codegen::backend::{CodegenBackend, CodegenConfig, Target};
use windjammer::codegen::javascript::{minifier, polyfills, tree_shaker, v8_optimizer};
use windjammer::lexer::Lexer;
use windjammer::parser::Parser;
fn compile_to_js(source: &str, config: &CodegenConfig) -> Result<String, String> {
let mut lexer = Lexer::new(source);
let tokens = lexer.tokenize_with_locations();
let mut parser = Parser::new(tokens);
let program = parser
.parse()
.map_err(|e| format!("Parser error: {:?}", e))?;
let backend = windjammer::codegen::javascript::JavaScriptBackend::new();
let output = backend
.generate(&program, config)
.map_err(|e| format!("Codegen error: {}", e))?;
Ok(output.source)
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_minification_basic() {
let code = r#"
// This is a comment
function add ( a , b ) {
return a + b ;
}
"#;
let mut minifier = minifier::Minifier::new();
let minified = minifier.minify(code);
assert!(!minified.contains("This is a comment"));
assert!(minified.len() < code.len());
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_minification_preserves_functionality() {
let code = r#"
function test() {
return 42;
}
"#;
let mut minifier = minifier::Minifier::new();
let minified = minifier.minify(code);
assert!(minified.contains("function"));
assert!(minified.contains("42"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_tree_shaking_removes_unused() {
let source = r#"
fn used() -> int {
42
}
fn unused() -> int {
100
}
fn main() {
let x = used()
}
"#;
let mut lexer = Lexer::new(source);
let tokens = lexer.tokenize_with_locations();
let mut parser = Parser::new(tokens);
let program = parser.parse().unwrap();
let shaken = tree_shaker::shake_tree(&program);
let function_count = shaken
.items
.iter()
.filter(|item| matches!(item, windjammer::parser::Item::Function { .. }))
.count();
assert_eq!(function_count, 2);
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_tree_shaking_analysis() {
let source = r#"
fn used() -> int {
42
}
fn unused() -> int {
100
}
fn main() {
let x = used()
}
"#;
let mut lexer = Lexer::new(source);
let tokens = lexer.tokenize_with_locations();
let mut parser = Parser::new(tokens);
let program = parser.parse().unwrap();
let analysis = tree_shaker::analyze_usage(&program);
assert_eq!(analysis.total_functions, 3);
assert_eq!(analysis.unused_functions.len(), 1);
assert!(analysis.unused_functions.contains(&"unused".to_string()));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_polyfills_generation() {
let config = polyfills::PolyfillConfig {
target: polyfills::PolyfillTarget::ES5,
include_promise: true,
include_array_methods: true,
include_object_methods: true,
include_symbol: false,
};
let polyfill_code = polyfills::generate_polyfills(&config);
assert!(polyfill_code.contains("Promise"));
assert!(polyfill_code.contains("Array.from"));
assert!(polyfill_code.contains("Object.assign"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_polyfills_es2015_target() {
let config = polyfills::PolyfillConfig {
target: polyfills::PolyfillTarget::ES2015,
include_promise: true,
include_array_methods: true,
include_object_methods: true,
include_symbol: false,
};
let polyfill_code = polyfills::generate_polyfills(&config);
assert!(polyfill_code.contains("Promise"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_v8_optimizations() {
let code = r#"
function test(x) {
return x * x;
}
"#;
let optimizer = v8_optimizer::V8Optimizer::new();
let optimized = optimizer.optimize(code);
assert!(!optimized.is_empty());
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_v8_optimization_hints() {
let hints = v8_optimizer::V8Optimizer::generate_optimization_hints();
assert!(hints.contains("V8"));
assert!(hints.contains("Monomorphic"));
assert!(hints.contains("TurboFan"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_v8_optimized_array_loop() {
let loop_code = v8_optimizer::patterns::optimized_array_loop("items", "process(item);");
assert!(loop_code.contains("items_length"));
assert!(loop_code.contains("for"));
assert!(loop_code.contains("process(item)"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_v8_optimized_object_creation() {
let fields = vec![("x", "number"), ("y", "number")];
let class_code = v8_optimizer::patterns::optimized_object_creation("Point", &fields);
assert!(class_code.contains("class Point"));
assert!(class_code.contains("constructor"));
assert!(class_code.contains("this.x"));
assert!(class_code.contains("this.y"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_integrated_minify_build() {
let source = r#"
fn add(a: int, b: int) -> int {
a + b
}
fn main() {
let result = add(2, 3)
}
"#;
let config = CodegenConfig {
target: Target::JavaScript,
minify: true,
tree_shake: false,
source_maps: false,
polyfills: false,
v8_optimize: false,
..Default::default()
};
let js_code = compile_to_js(source, &config).unwrap();
assert!(!js_code.is_empty());
assert!(js_code.contains("add") || js_code.contains("function"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_integrated_tree_shake_build() {
let source = r#"
fn used() -> int {
42
}
fn unused() -> int {
100
}
fn main() {
let x = used()
}
"#;
let config = CodegenConfig {
target: Target::JavaScript,
minify: false,
tree_shake: true,
source_maps: false,
polyfills: false,
v8_optimize: false,
..Default::default()
};
let js_code = compile_to_js(source, &config).unwrap();
assert!(js_code.contains("used"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_integrated_polyfills_build() {
let source = r#"
fn main() {
println!("Hello")
}
"#;
let config = CodegenConfig {
target: Target::JavaScript,
minify: false,
tree_shake: false,
source_maps: false,
polyfills: true,
v8_optimize: false,
..Default::default()
};
let js_code = compile_to_js(source, &config).unwrap();
assert!(js_code.contains("Windjammer Polyfills") || js_code.contains("Promise"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_integrated_all_features() {
let source = r#"
fn add(a: int, b: int) -> int {
a + b
}
fn main() {
let result = add(2, 3)
}
"#;
let config = CodegenConfig {
target: Target::JavaScript,
minify: true,
tree_shake: true,
source_maps: true,
polyfills: true,
v8_optimize: true,
..Default::default()
};
let js_code = compile_to_js(source, &config).unwrap();
assert!(!js_code.is_empty());
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_source_map_generation() {
use windjammer::codegen::javascript::source_maps;
let source_map = source_maps::generate_source_map(
"output.js",
"input.wj",
"fn main() {}",
"function main() {}",
);
assert_eq!(source_map.version, 3);
assert_eq!(source_map.file, "output.js");
assert_eq!(source_map.sources[0], "input.wj");
assert!(!source_map.mappings.is_empty());
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_cli_flags_minify() {
let temp_dir = TempDir::new().unwrap();
let source_file = temp_dir.path().join("test.wj");
fs::write(&source_file, "fn main() { }").unwrap();
let wj_path = env!("CARGO_BIN_EXE_wj");
let output = Command::new(wj_path)
.arg("build")
.arg("--no-cargo")
.arg(&source_file)
.arg("--target=javascript")
.arg("--minify")
.arg("--output")
.arg(temp_dir.path())
.output();
assert!(output.is_ok());
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_cli_flags_tree_shake() {
let temp_dir = TempDir::new().unwrap();
let source_file = temp_dir.path().join("test.wj");
fs::write(&source_file, "fn main() { }").unwrap();
let wj_path = env!("CARGO_BIN_EXE_wj");
let output = Command::new(wj_path)
.arg("build")
.arg("--no-cargo")
.arg(&source_file)
.arg("--target=javascript")
.arg("--tree-shake")
.arg("--output")
.arg(temp_dir.path())
.output();
assert!(output.is_ok());
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_cli_flags_all_enhanced_features() {
let temp_dir = TempDir::new().unwrap();
let source_file = temp_dir.path().join("test.wj");
fs::write(&source_file, "fn main() { }").unwrap();
let wj_path = env!("CARGO_BIN_EXE_wj");
let output = Command::new(wj_path)
.arg("build")
.arg("--no-cargo")
.arg(&source_file)
.arg("--target=javascript")
.arg("--minify")
.arg("--tree-shake")
.arg("--source-maps")
.arg("--polyfills")
.arg("--v8-optimize")
.arg("--output")
.arg(temp_dir.path())
.output();
assert!(output.is_ok());
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_constant_folding() {
use windjammer::codegen::javascript::minifier;
let code = "let x = 1 + 1; let y = 2 + 2; let z = true && false;";
let mut minifier = minifier::Minifier::new();
let result = minifier.minify(code);
assert!(result.contains("2") || !result.contains("1 + 1"));
assert!(result.contains("4") || !result.contains("2 + 2"));
assert!(result.contains("false"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_dead_code_elimination() {
use windjammer::codegen::javascript::minifier;
let code = r#"
function test() {
return 42;
console.log("unreachable");
}
"#;
let mut minifier = minifier::Minifier::new();
let result = minifier.minify(code);
assert!(result.contains("function"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_code_splitting() {
use windjammer::codegen::javascript::code_splitter::{CodeSplitConfig, CodeSplitter};
use windjammer::parser::Program;
let config = CodeSplitConfig::default();
let mut splitter = CodeSplitter::new(config);
let program = Program { items: Vec::new() };
let chunks = splitter.split(&program, "function main() {}");
assert!(!chunks.is_empty());
assert!(chunks[0].is_entry);
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_code_splitter_loader() {
use windjammer::codegen::javascript::code_splitter::{CodeSplitConfig, CodeSplitter};
let config = CodeSplitConfig::default();
let splitter = CodeSplitter::new(config);
let loader = splitter.generate_chunk_loader();
assert!(loader.contains("__wj_load_chunk"));
assert!(loader.contains("async function"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_differential_loading_modern_bundle() {
use windjammer::codegen::javascript::differential_loading::{
DifferentialConfig, DifferentialLoader,
};
let code = "const x = () => 42;";
let config = DifferentialConfig::default();
let loader = DifferentialLoader::new(config);
let bundles = loader.generate_bundles(code, "app");
assert_eq!(bundles.len(), 2);
assert!(bundles[0].filename.contains(".modern.js"));
assert!(bundles[1].filename.contains(".legacy.js"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_differential_loading_legacy_transpilation() {
use windjammer::codegen::javascript::differential_loading::{
DifferentialConfig, DifferentialLoader,
};
let code = "const x = 42;";
let config = DifferentialConfig::default();
let loader = DifferentialLoader::new(config);
let bundles = loader.generate_bundles(code, "app");
assert!(bundles[1].code.contains("var") || bundles[1].code.contains("Polyfill"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_differential_html_loader() {
use windjammer::codegen::javascript::differential_loading::{
DifferentialConfig, DifferentialLoader,
};
let config = DifferentialConfig::default();
let loader = DifferentialLoader::new(config);
let html = loader.generate_html_loader("app");
assert!(html.contains("type=\"module\""));
assert!(html.contains("nomodule"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_module_federation_config() {
use windjammer::codegen::javascript::module_federation::FederationConfig;
let config = FederationConfig::default();
assert_eq!(config.name, "app");
assert_eq!(config.filename, "remoteEntry.js");
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_module_federation_remote_entry() {
use std::collections::HashMap;
use windjammer::codegen::javascript::module_federation::{FederationConfig, ModuleFederation};
let mut config = FederationConfig {
name: "myapp".to_string(),
exposes: HashMap::new(),
..Default::default()
};
config
.exposes
.insert("./Button".to_string(), "./src/Button.js".to_string());
let federation = ModuleFederation::new(config);
let entry = federation.generate_remote_entry();
assert!(entry.contains("myappContainer"));
assert!(entry.contains("./Button"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_module_federation_consumer() {
use windjammer::codegen::javascript::module_federation::{FederationConfig, ModuleFederation};
let config = FederationConfig::default();
let federation = ModuleFederation::new(config);
let consumer = federation.generate_consumer_code();
assert!(consumer.contains("__wj_federation"));
assert!(consumer.contains("loadRemote"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_module_federation_shared_scope() {
use windjammer::codegen::javascript::module_federation::{FederationConfig, ModuleFederation};
let mut config = FederationConfig::default();
config.shared.push("react".to_string());
let federation = ModuleFederation::new(config);
let shared = federation.generate_shared_scope();
assert!(shared.contains("react"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_source_map_inline() {
use windjammer::codegen::javascript::source_maps::{generate_source_map, source_map_to_inline};
let source_map = generate_source_map("output.js", "input.wj", "", "");
let inline = source_map_to_inline(&source_map);
assert!(inline.contains("sourceMappingURL=data:application/json"));
assert!(inline.contains("base64,"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_source_map_external_reference() {
use windjammer::codegen::javascript::source_maps::source_map_external_reference;
let reference = source_map_external_reference("output.js.map");
assert!(reference.contains("sourceMappingURL=output.js.map"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_source_map_mode_inline() {
use windjammer::codegen::javascript::source_maps::{
apply_source_map, generate_source_map, SourceMapMode,
};
let code = "function test() {}";
let source_map = generate_source_map("output.js", "input.wj", "", code);
let result = apply_source_map(code, &source_map, SourceMapMode::Inline, "output.js.map");
assert!(result.contains("sourceMappingURL=data:"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_source_map_mode_external() {
use windjammer::codegen::javascript::source_maps::{
apply_source_map, generate_source_map, SourceMapMode,
};
let code = "function test() {}";
let source_map = generate_source_map("output.js", "input.wj", "", code);
let result = apply_source_map(code, &source_map, SourceMapMode::External, "output.js.map");
assert!(result.contains("sourceMappingURL=output.js.map"));
assert!(!result.contains("data:application/json"));
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_source_map_mode_both() {
use windjammer::codegen::javascript::source_maps::{
apply_source_map, generate_source_map, SourceMapMode,
};
let code = "function test() {}";
let source_map = generate_source_map("output.js", "input.wj", "", code);
let result = apply_source_map(code, &source_map, SourceMapMode::Both, "output.js.map");
assert!(result.contains("sourceMappingURL=output.js.map"));
assert!(result.contains("sourceMappingURL=data:"));
}