1use std::collections::HashMap;
6
7use super::types::{
8 CanonicalOptions, ComponentExport, ComponentImport, ComponentInstance, CoreModule,
9 WCAnalysisCache, WCConstantFoldingHelper, WCDepGraph, WCDominatorTree, WCLivenessInfo,
10 WCPassConfig, WCPassPhase, WCPassRegistry, WCPassStats, WCWorklist, WasmCExtCache,
11 WasmCExtConstFolder, WasmCExtDepGraph, WasmCExtDomTree, WasmCExtLiveness, WasmCExtPassConfig,
12 WasmCExtPassPhase, WasmCExtPassRegistry, WasmCExtPassStats, WasmCExtWorklist,
13 WasmCompExtConfig, WasmCompExtDiagCollector, WasmCompExtDiagMsg, WasmCompExtEmitStats,
14 WasmCompExtEventLog, WasmCompExtFeatures, WasmCompExtIdGen, WasmCompExtIncrKey,
15 WasmCompExtNameScope, WasmCompExtPassTiming, WasmCompExtProfiler, WasmCompExtSourceBuffer,
16 WasmCompExtVersion, WasmComponentBackend, WasmComponentExpr, WasmComponentType, WitInterface,
17 WitResource,
18};
19
20pub fn build_math_interface() -> WitInterface {
22 let mut iface = WitInterface::new("oxilean:math/", "arithmetic");
23 iface.add_type("num", WasmComponentType::F64);
24 iface.add_function(
25 "add",
26 WasmComponentType::Func(
27 vec![
28 ("a".to_string(), WasmComponentType::F64),
29 ("b".to_string(), WasmComponentType::F64),
30 ],
31 vec![("result".to_string(), WasmComponentType::F64)],
32 ),
33 );
34 iface.add_function(
35 "sqrt",
36 WasmComponentType::Func(
37 vec![("x".to_string(), WasmComponentType::F64)],
38 vec![(
39 "result".to_string(),
40 WasmComponentType::Option(Box::new(WasmComponentType::F64)),
41 )],
42 ),
43 );
44 iface
45}
46pub fn build_streams_interface() -> WitInterface {
48 let mut iface = WitInterface::new("wasi:io/", "streams");
49 iface.add_resource(
50 WitResource::new("output-stream")
51 .with_constructor(vec![])
52 .with_method(
53 "write",
54 WasmComponentType::Func(
55 vec![(
56 "bytes".to_string(),
57 WasmComponentType::List(Box::new(WasmComponentType::U8)),
58 )],
59 vec![(
60 "result".to_string(),
61 WasmComponentType::Result(
62 Box::new(None),
63 Box::new(Some(WasmComponentType::TypeRef("stream-error".to_string()))),
64 ),
65 )],
66 ),
67 ),
68 );
69 iface.add_type(
70 "stream-error",
71 WasmComponentType::Variant(vec![
72 ("last-operation-failed".to_string(), None),
73 ("closed".to_string(), None),
74 ]),
75 );
76 iface
77}
78#[cfg(test)]
79mod tests {
80 use super::*;
81 #[test]
82 pub(super) fn test_component_type_display_primitives() {
83 assert_eq!(WasmComponentType::Bool.to_string(), "bool");
84 assert_eq!(WasmComponentType::U32.to_string(), "u32");
85 assert_eq!(WasmComponentType::S64.to_string(), "s64");
86 assert_eq!(WasmComponentType::F32.to_string(), "f32");
87 assert_eq!(WasmComponentType::String.to_string(), "string");
88 assert_eq!(WasmComponentType::Char.to_string(), "char");
89 }
90 #[test]
91 pub(super) fn test_component_type_display_compound() {
92 let list_ty = WasmComponentType::List(Box::new(WasmComponentType::U8));
93 assert_eq!(list_ty.to_string(), "list<u8>");
94 let opt_ty = WasmComponentType::Option(Box::new(WasmComponentType::String));
95 assert_eq!(opt_ty.to_string(), "option<string>");
96 let res_ty = WasmComponentType::Result(
97 Box::new(Some(WasmComponentType::U32)),
98 Box::new(Some(WasmComponentType::String)),
99 );
100 assert_eq!(res_ty.to_string(), "result<u32, string>");
101 let result_no_err =
102 WasmComponentType::Result(Box::new(Some(WasmComponentType::Bool)), Box::new(None));
103 assert_eq!(result_no_err.to_string(), "result<bool>");
104 }
105 #[test]
106 pub(super) fn test_component_type_display_record() {
107 let record = WasmComponentType::Record(vec![
108 ("x".to_string(), WasmComponentType::F32),
109 ("y".to_string(), WasmComponentType::F32),
110 ]);
111 let s = record.to_string();
112 assert!(s.starts_with("record {"));
113 assert!(s.contains("x: f32"));
114 assert!(s.contains("y: f32"));
115 }
116 #[test]
117 pub(super) fn test_component_type_display_variant() {
118 let variant = WasmComponentType::Variant(vec![
119 ("none".to_string(), None),
120 ("some".to_string(), Some(WasmComponentType::U32)),
121 ]);
122 let s = variant.to_string();
123 assert!(s.starts_with("variant {"));
124 assert!(s.contains("none"));
125 assert!(s.contains("some(u32)"));
126 }
127 #[test]
128 pub(super) fn test_component_type_display_enum_flags() {
129 let enum_ty = WasmComponentType::Enum(vec![
130 "red".to_string(),
131 "green".to_string(),
132 "blue".to_string(),
133 ]);
134 let s = enum_ty.to_string();
135 assert!(s.contains("red"));
136 assert!(s.contains("green"));
137 let flags_ty = WasmComponentType::Flags(vec![
138 "read".to_string(),
139 "write".to_string(),
140 "exec".to_string(),
141 ]);
142 let fs = flags_ty.to_string();
143 assert!(fs.contains("read"));
144 assert!(fs.contains("write"));
145 }
146 #[test]
147 pub(super) fn test_component_export_emit() {
148 let export = ComponentExport::func("my-func", "my_func_impl");
149 let s = export.emit();
150 assert!(s.contains("my-func"));
151 assert!(s.contains("func"));
152 assert!(s.contains("my_func_impl"));
153 }
154 #[test]
155 pub(super) fn test_component_instance_construction() {
156 let mut inst = ComponentInstance::new("my-component");
157 assert_eq!(inst.export_count(), 0);
158 assert_eq!(inst.import_count(), 0);
159 inst.add_export(ComponentExport::func("greet", "greet_impl"));
160 inst.add_import(ComponentImport::func(
161 "wasi:io/",
162 "write",
163 vec![(
164 "data".to_string(),
165 WasmComponentType::List(Box::new(WasmComponentType::U8)),
166 )],
167 vec![],
168 ));
169 assert_eq!(inst.export_count(), 1);
170 assert_eq!(inst.import_count(), 1);
171 }
172 #[test]
173 pub(super) fn test_wit_interface_emit() {
174 let mut iface = WitInterface::new("oxilean:core/", "types");
175 iface.add_type("idx", WasmComponentType::U32);
176 iface.add_function(
177 "identity",
178 WasmComponentType::Func(
179 vec![("x".to_string(), WasmComponentType::U32)],
180 vec![("result".to_string(), WasmComponentType::U32)],
181 ),
182 );
183 let wit = iface.emit_wit();
184 assert!(wit.contains("interface types {"));
185 assert!(wit.contains("type idx = u32"));
186 assert!(wit.contains("identity:"));
187 assert!(wit.contains("func(x: u32)"));
188 }
189 #[test]
190 pub(super) fn test_backend_emit_component_wat() {
191 let mut backend = WasmComponentBackend::new("my-app");
192 backend.define_type("size", WasmComponentType::U64);
193 backend.add_export(ComponentExport::func("run", "run_impl"));
194 let wat = backend.emit_component_wat();
195 assert!(wat.contains("(component $my-app"));
196 assert!(wat.contains("$size"));
197 assert!(wat.contains("run"));
198 }
199 #[test]
200 pub(super) fn test_backend_wit_package() {
201 let mut backend = WasmComponentBackend::new("math-lib");
202 backend.add_interface(build_math_interface());
203 let pkg = backend.emit_wit_package("oxilean:math", Some("0.1.0"));
204 assert!(pkg.contains("package oxilean:math@0.1.0"));
205 assert!(pkg.contains("interface arithmetic {"));
206 assert!(pkg.contains("type num = f64"));
207 }
208 #[test]
209 pub(super) fn test_core_module_inline() {
210 let module =
211 CoreModule::inline_text("core", "(module (func $add (param i32 i32) (result i32)))");
212 let s = module.emit();
213 assert!(s.contains("(core module $core"));
214 assert!(s.contains("func $add"));
215 }
216 #[test]
217 pub(super) fn test_canonical_options_emit() {
218 let opts = CanonicalOptions::with_memory_and_realloc("$mem", "$realloc");
219 let s = opts.emit();
220 assert!(s.contains("(memory $mem)"));
221 assert!(s.contains("(realloc $realloc)"));
222 }
223 #[test]
224 pub(super) fn test_wit_resource_emit() {
225 let resource = WitResource::new("connection")
226 .with_constructor(vec![
227 ("host".to_string(), WasmComponentType::String),
228 ("port".to_string(), WasmComponentType::U16),
229 ])
230 .with_method(
231 "send",
232 WasmComponentType::Func(
233 vec![(
234 "data".to_string(),
235 WasmComponentType::List(Box::new(WasmComponentType::U8)),
236 )],
237 vec![(
238 "n".to_string(),
239 WasmComponentType::Result(
240 Box::new(Some(WasmComponentType::U32)),
241 Box::new(None),
242 ),
243 )],
244 ),
245 );
246 let s = resource.emit_wit();
247 assert!(s.contains("resource connection {"));
248 assert!(s.contains("constructor(host: string, port: u16)"));
249 assert!(s.contains("send:"));
250 }
251 #[test]
252 pub(super) fn test_component_expr_display() {
253 let expr = WasmComponentExpr::Call {
254 instance: "wasi-io".to_string(),
255 func: "write".to_string(),
256 args: vec![
257 WasmComponentExpr::Var("buf".to_string()),
258 WasmComponentExpr::IntLit(1024),
259 ],
260 };
261 let s = expr.to_string();
262 assert!(s.contains("wasi-io.write"));
263 assert!(s.contains("buf"));
264 assert!(s.contains("1024"));
265 let some_expr = WasmComponentExpr::OptionSome(Box::new(WasmComponentExpr::BoolLit(true)));
266 assert_eq!(some_expr.to_string(), "(some true)");
267 let none_expr = WasmComponentExpr::OptionNone;
268 assert_eq!(none_expr.to_string(), "none");
269 }
270 #[test]
271 pub(super) fn test_streams_interface() {
272 let iface = build_streams_interface();
273 let wit = iface.emit_wit();
274 assert!(wit.contains("interface streams {"));
275 assert!(wit.contains("resource output-stream {"));
276 assert!(wit.contains("stream-error"));
277 }
278 #[test]
279 pub(super) fn test_backend_add_lifted_func() {
280 let mut backend = WasmComponentBackend::new("compute");
281 backend.set_canonical_opts("$memory", "$realloc");
282 backend.add_lifted_func(
283 "compute-sum",
284 "core_compute_sum",
285 vec![
286 ("a".to_string(), WasmComponentType::S64),
287 ("b".to_string(), WasmComponentType::S64),
288 ],
289 vec![("result".to_string(), WasmComponentType::S64)],
290 );
291 assert_eq!(backend.func_count(), 1);
292 let wat = backend.emit_component_wat();
293 assert!(wat.contains("canon lift"));
294 assert!(wat.contains("core_compute_sum"));
295 }
296}
297#[cfg(test)]
298mod tests_wasm_comp_ext_extra {
299 use super::*;
300 #[test]
301 pub(super) fn test_wasm_comp_ext_config() {
302 let mut cfg = WasmCompExtConfig::new();
303 cfg.set("mode", "release");
304 cfg.set("verbose", "true");
305 assert_eq!(cfg.get("mode"), Some("release"));
306 assert!(cfg.get_bool("verbose"));
307 assert!(cfg.get_int("mode").is_none());
308 assert_eq!(cfg.len(), 2);
309 }
310 #[test]
311 pub(super) fn test_wasm_comp_ext_source_buffer() {
312 let mut buf = WasmCompExtSourceBuffer::new();
313 buf.push_line("fn main() {");
314 buf.indent();
315 buf.push_line("println!(\"hello\");");
316 buf.dedent();
317 buf.push_line("}");
318 assert!(buf.as_str().contains("fn main()"));
319 assert!(buf.as_str().contains(" println!"));
320 assert_eq!(buf.line_count(), 3);
321 buf.reset();
322 assert!(buf.is_empty());
323 }
324 #[test]
325 pub(super) fn test_wasm_comp_ext_name_scope() {
326 let mut scope = WasmCompExtNameScope::new();
327 assert!(scope.declare("x"));
328 assert!(!scope.declare("x"));
329 assert!(scope.is_declared("x"));
330 let scope = scope.push_scope();
331 assert_eq!(scope.depth(), 1);
332 let mut scope = scope.pop_scope();
333 assert_eq!(scope.depth(), 0);
334 scope.declare("y");
335 assert_eq!(scope.len(), 2);
336 }
337 #[test]
338 pub(super) fn test_wasm_comp_ext_diag_collector() {
339 let mut col = WasmCompExtDiagCollector::new();
340 col.emit(WasmCompExtDiagMsg::warning("pass_a", "slow"));
341 col.emit(WasmCompExtDiagMsg::error("pass_b", "fatal"));
342 assert!(col.has_errors());
343 assert_eq!(col.errors().len(), 1);
344 assert_eq!(col.warnings().len(), 1);
345 col.clear();
346 assert!(col.is_empty());
347 }
348 #[test]
349 pub(super) fn test_wasm_comp_ext_id_gen() {
350 let mut gen = WasmCompExtIdGen::new();
351 assert_eq!(gen.next_id(), 0);
352 assert_eq!(gen.next_id(), 1);
353 gen.skip(10);
354 assert_eq!(gen.next_id(), 12);
355 gen.reset();
356 assert_eq!(gen.peek_next(), 0);
357 }
358 #[test]
359 pub(super) fn test_wasm_comp_ext_incr_key() {
360 let k1 = WasmCompExtIncrKey::new(100, 200);
361 let k2 = WasmCompExtIncrKey::new(100, 200);
362 let k3 = WasmCompExtIncrKey::new(999, 200);
363 assert!(k1.matches(&k2));
364 assert!(!k1.matches(&k3));
365 }
366 #[test]
367 pub(super) fn test_wasm_comp_ext_profiler() {
368 let mut p = WasmCompExtProfiler::new();
369 p.record(WasmCompExtPassTiming::new("pass_a", 1000, 50, 200, 100));
370 p.record(WasmCompExtPassTiming::new("pass_b", 500, 30, 100, 200));
371 assert_eq!(p.total_elapsed_us(), 1500);
372 assert_eq!(
373 p.slowest_pass()
374 .expect("slowest pass should exist")
375 .pass_name,
376 "pass_a"
377 );
378 assert_eq!(p.profitable_passes().len(), 1);
379 }
380 #[test]
381 pub(super) fn test_wasm_comp_ext_event_log() {
382 let mut log = WasmCompExtEventLog::new(3);
383 log.push("event1");
384 log.push("event2");
385 log.push("event3");
386 assert_eq!(log.len(), 3);
387 log.push("event4");
388 assert_eq!(log.len(), 3);
389 assert_eq!(
390 log.iter()
391 .next()
392 .expect("iterator should have next element"),
393 "event2"
394 );
395 }
396 #[test]
397 pub(super) fn test_wasm_comp_ext_version() {
398 let v = WasmCompExtVersion::new(1, 2, 3).with_pre("alpha");
399 assert!(!v.is_stable());
400 assert_eq!(format!("{}", v), "1.2.3-alpha");
401 let stable = WasmCompExtVersion::new(2, 0, 0);
402 assert!(stable.is_stable());
403 assert!(stable.is_compatible_with(&WasmCompExtVersion::new(2, 0, 0)));
404 assert!(!stable.is_compatible_with(&WasmCompExtVersion::new(3, 0, 0)));
405 }
406 #[test]
407 pub(super) fn test_wasm_comp_ext_features() {
408 let mut f = WasmCompExtFeatures::new();
409 f.enable("sse2");
410 f.enable("avx2");
411 assert!(f.is_enabled("sse2"));
412 assert!(!f.is_enabled("avx512"));
413 f.disable("avx2");
414 assert!(!f.is_enabled("avx2"));
415 let mut g = WasmCompExtFeatures::new();
416 g.enable("sse2");
417 g.enable("neon");
418 let union = f.union(&g);
419 assert!(union.is_enabled("sse2") && union.is_enabled("neon"));
420 let inter = f.intersection(&g);
421 assert!(inter.is_enabled("sse2"));
422 }
423 #[test]
424 pub(super) fn test_wasm_comp_ext_emit_stats() {
425 let mut s = WasmCompExtEmitStats::new();
426 s.bytes_emitted = 50_000;
427 s.items_emitted = 500;
428 s.elapsed_ms = 100;
429 assert!(s.is_clean());
430 assert!((s.throughput_bps() - 500_000.0).abs() < 1.0);
431 let disp = format!("{}", s);
432 assert!(disp.contains("bytes=50000"));
433 }
434}
435#[cfg(test)]
436mod WC_infra_tests {
437 use super::*;
438 #[test]
439 pub(super) fn test_pass_config() {
440 let config = WCPassConfig::new("test_pass", WCPassPhase::Transformation);
441 assert!(config.enabled);
442 assert!(config.phase.is_modifying());
443 assert_eq!(config.phase.name(), "transformation");
444 }
445 #[test]
446 pub(super) fn test_pass_stats() {
447 let mut stats = WCPassStats::new();
448 stats.record_run(10, 100, 3);
449 stats.record_run(20, 200, 5);
450 assert_eq!(stats.total_runs, 2);
451 assert!((stats.average_changes_per_run() - 15.0).abs() < 0.01);
452 assert!((stats.success_rate() - 1.0).abs() < 0.01);
453 let s = stats.format_summary();
454 assert!(s.contains("Runs: 2/2"));
455 }
456 #[test]
457 pub(super) fn test_pass_registry() {
458 let mut reg = WCPassRegistry::new();
459 reg.register(WCPassConfig::new("pass_a", WCPassPhase::Analysis));
460 reg.register(WCPassConfig::new("pass_b", WCPassPhase::Transformation).disabled());
461 assert_eq!(reg.total_passes(), 2);
462 assert_eq!(reg.enabled_count(), 1);
463 reg.update_stats("pass_a", 5, 50, 2);
464 let stats = reg.get_stats("pass_a").expect("stats should exist");
465 assert_eq!(stats.total_changes, 5);
466 }
467 #[test]
468 pub(super) fn test_analysis_cache() {
469 let mut cache = WCAnalysisCache::new(10);
470 cache.insert("key1".to_string(), vec![1, 2, 3]);
471 assert!(cache.get("key1").is_some());
472 assert!(cache.get("key2").is_none());
473 assert!((cache.hit_rate() - 0.5).abs() < 0.01);
474 cache.invalidate("key1");
475 assert!(!cache.entries["key1"].valid);
476 assert_eq!(cache.size(), 1);
477 }
478 #[test]
479 pub(super) fn test_worklist() {
480 let mut wl = WCWorklist::new();
481 assert!(wl.push(1));
482 assert!(wl.push(2));
483 assert!(!wl.push(1));
484 assert_eq!(wl.len(), 2);
485 assert_eq!(wl.pop(), Some(1));
486 assert!(!wl.contains(1));
487 assert!(wl.contains(2));
488 }
489 #[test]
490 pub(super) fn test_dominator_tree() {
491 let mut dt = WCDominatorTree::new(5);
492 dt.set_idom(1, 0);
493 dt.set_idom(2, 0);
494 dt.set_idom(3, 1);
495 assert!(dt.dominates(0, 3));
496 assert!(dt.dominates(1, 3));
497 assert!(!dt.dominates(2, 3));
498 assert!(dt.dominates(3, 3));
499 }
500 #[test]
501 pub(super) fn test_liveness() {
502 let mut liveness = WCLivenessInfo::new(3);
503 liveness.add_def(0, 1);
504 liveness.add_use(1, 1);
505 assert!(liveness.defs[0].contains(&1));
506 assert!(liveness.uses[1].contains(&1));
507 }
508 #[test]
509 pub(super) fn test_constant_folding() {
510 assert_eq!(WCConstantFoldingHelper::fold_add_i64(3, 4), Some(7));
511 assert_eq!(WCConstantFoldingHelper::fold_div_i64(10, 0), None);
512 assert_eq!(WCConstantFoldingHelper::fold_div_i64(10, 2), Some(5));
513 assert_eq!(
514 WCConstantFoldingHelper::fold_bitand_i64(0b1100, 0b1010),
515 0b1000
516 );
517 assert_eq!(WCConstantFoldingHelper::fold_bitnot_i64(0), -1);
518 }
519 #[test]
520 pub(super) fn test_dep_graph() {
521 let mut g = WCDepGraph::new();
522 g.add_dep(1, 2);
523 g.add_dep(2, 3);
524 g.add_dep(1, 3);
525 assert_eq!(g.dependencies_of(2), vec![1]);
526 let topo = g.topological_sort();
527 assert_eq!(topo.len(), 3);
528 assert!(!g.has_cycle());
529 let pos: std::collections::HashMap<u32, usize> =
530 topo.iter().enumerate().map(|(i, &n)| (n, i)).collect();
531 assert!(pos[&1] < pos[&2]);
532 assert!(pos[&1] < pos[&3]);
533 assert!(pos[&2] < pos[&3]);
534 }
535}
536#[cfg(test)]
537mod wasmcext_pass_tests {
538 use super::*;
539 #[test]
540 pub(super) fn test_wasmcext_phase_order() {
541 assert_eq!(WasmCExtPassPhase::Early.order(), 0);
542 assert_eq!(WasmCExtPassPhase::Middle.order(), 1);
543 assert_eq!(WasmCExtPassPhase::Late.order(), 2);
544 assert_eq!(WasmCExtPassPhase::Finalize.order(), 3);
545 assert!(WasmCExtPassPhase::Early.is_early());
546 assert!(!WasmCExtPassPhase::Early.is_late());
547 }
548 #[test]
549 pub(super) fn test_wasmcext_config_builder() {
550 let c = WasmCExtPassConfig::new("p")
551 .with_phase(WasmCExtPassPhase::Late)
552 .with_max_iter(50)
553 .with_debug(1);
554 assert_eq!(c.name, "p");
555 assert_eq!(c.max_iterations, 50);
556 assert!(c.is_debug_enabled());
557 assert!(c.enabled);
558 let c2 = c.disabled();
559 assert!(!c2.enabled);
560 }
561 #[test]
562 pub(super) fn test_wasmcext_stats() {
563 let mut s = WasmCExtPassStats::new();
564 s.visit();
565 s.visit();
566 s.modify();
567 s.iterate();
568 assert_eq!(s.nodes_visited, 2);
569 assert_eq!(s.nodes_modified, 1);
570 assert!(s.changed);
571 assert_eq!(s.iterations, 1);
572 let e = s.efficiency();
573 assert!((e - 0.5).abs() < 1e-9);
574 }
575 #[test]
576 pub(super) fn test_wasmcext_registry() {
577 let mut r = WasmCExtPassRegistry::new();
578 r.register(WasmCExtPassConfig::new("a").with_phase(WasmCExtPassPhase::Early));
579 r.register(WasmCExtPassConfig::new("b").disabled());
580 assert_eq!(r.len(), 2);
581 assert_eq!(r.enabled_passes().len(), 1);
582 assert_eq!(r.passes_in_phase(&WasmCExtPassPhase::Early).len(), 1);
583 }
584 #[test]
585 pub(super) fn test_wasmcext_cache() {
586 let mut c = WasmCExtCache::new(4);
587 assert!(c.get(99).is_none());
588 c.put(99, vec![1, 2, 3]);
589 let v = c.get(99).expect("v should be present in map");
590 assert_eq!(v, &[1u8, 2, 3]);
591 assert!(c.hit_rate() > 0.0);
592 assert_eq!(c.live_count(), 1);
593 }
594 #[test]
595 pub(super) fn test_wasmcext_worklist() {
596 let mut w = WasmCExtWorklist::new(10);
597 w.push(5);
598 w.push(3);
599 w.push(5);
600 assert_eq!(w.len(), 2);
601 assert!(w.contains(5));
602 let first = w.pop().expect("first should be available to pop");
603 assert!(!w.contains(first));
604 }
605 #[test]
606 pub(super) fn test_wasmcext_dom_tree() {
607 let mut dt = WasmCExtDomTree::new(5);
608 dt.set_idom(1, 0);
609 dt.set_idom(2, 0);
610 dt.set_idom(3, 1);
611 dt.set_idom(4, 1);
612 assert!(dt.dominates(0, 3));
613 assert!(dt.dominates(1, 4));
614 assert!(!dt.dominates(2, 3));
615 assert_eq!(dt.depth_of(3), 2);
616 }
617 #[test]
618 pub(super) fn test_wasmcext_liveness() {
619 let mut lv = WasmCExtLiveness::new(3);
620 lv.add_def(0, 1);
621 lv.add_use(1, 1);
622 assert!(lv.var_is_def_in_block(0, 1));
623 assert!(lv.var_is_used_in_block(1, 1));
624 assert!(!lv.var_is_def_in_block(1, 1));
625 }
626 #[test]
627 pub(super) fn test_wasmcext_const_folder() {
628 let mut cf = WasmCExtConstFolder::new();
629 assert_eq!(cf.add_i64(3, 4), Some(7));
630 assert_eq!(cf.div_i64(10, 0), None);
631 assert_eq!(cf.mul_i64(6, 7), Some(42));
632 assert_eq!(cf.and_i64(0b1100, 0b1010), 0b1000);
633 assert_eq!(cf.fold_count(), 3);
634 assert_eq!(cf.failure_count(), 1);
635 }
636 #[test]
637 pub(super) fn test_wasmcext_dep_graph() {
638 let mut g = WasmCExtDepGraph::new(4);
639 g.add_edge(0, 1);
640 g.add_edge(1, 2);
641 g.add_edge(2, 3);
642 assert!(!g.has_cycle());
643 assert_eq!(g.topo_sort(), Some(vec![0, 1, 2, 3]));
644 assert_eq!(g.reachable(0).len(), 4);
645 let sccs = g.scc();
646 assert_eq!(sccs.len(), 4);
647 }
648}