#![allow(clippy::unwrap_used, unsafe_code)]
use super::DebugSections;
use crate::{Config, Engine, Module};
const FIXTURE: &[u8] = include_bytes!("testdata/fixture.wasm");
fn debug_engine() -> Engine {
Engine::new(Config::new().debug_info(true)).unwrap()
}
#[test]
fn dwarf_fixture_resolves_source_line() {
let engine = debug_engine();
let module = Module::new(&engine, FIXTURE).unwrap();
let inner = module.inner();
let boom = module.code(0);
let offsets = boom.offsets().expect("debug retention is on");
let entry = inner
.debug
.lookup(offsets[0])
.expect("first op resolves to a source location");
assert!(
entry.file.ends_with("fixture.rs"),
"unexpected file: {}",
entry.file
);
assert_eq!(entry.line, 13, "boom's body is on line 13");
}
#[test]
fn name_section_resolves_func_name() {
let engine = Engine::default();
let module = Module::new(&engine, FIXTURE).unwrap();
assert_eq!(module.inner().debug.func_name(0), Some("boom"));
}
#[test]
fn debug_info_survives_serialize_round_trip() {
let engine = debug_engine();
let module = Module::new(&engine, FIXTURE).unwrap();
let artifact = module.serialize().unwrap();
let restored = unsafe { Module::deserialize(&engine, &artifact) }.unwrap();
let inner = restored.inner();
let boom = module.code(0);
let offsets = boom.offsets().expect("offsets kept");
let entry = inner.debug.lookup(offsets[0]).expect("line still resolves");
assert!(entry.file.ends_with("fixture.rs"));
assert_eq!(entry.line, 13);
assert_eq!(inner.debug.func_name(0), Some("boom"));
}
#[test]
fn name_section_from_wat() {
let bytes =
wat::parse_str(r#"(module (func $answer (export "answer") (result i32) i32.const 42))"#)
.unwrap();
let engine = Engine::default();
let module = Module::new(&engine, &bytes).unwrap();
assert_eq!(module.inner().debug.func_name(0), Some("answer"));
}
#[test]
fn malformed_dwarf_yields_none() {
let mut debug = DebugSections::default();
debug.set_code_base(0);
debug.add_dwarf_section(".debug_abbrev", &[0x00, 0xff, 0x13]);
debug.add_dwarf_section(".debug_info", &[0xff; 24]);
debug.add_dwarf_section(".debug_line", &[0xff; 32]);
assert!(debug.lookup(0).is_none());
assert!(debug.lookup(0x1000).is_none());
}
#[test]
fn no_debug_info_is_empty() {
let bytes = wat::parse_str("(module (func))").unwrap();
let engine = Engine::default();
let module = Module::new(&engine, &bytes).unwrap();
assert!(module.inner().debug.lookup(0).is_none());
assert_eq!(module.inner().debug.func_name(0), None);
}
#[test]
fn default_engine_keeps_offsets_and_names_not_dwarf() {
let engine = Engine::default();
let module = Module::new(&engine, FIXTURE).unwrap();
let inner = module.inner();
let boom = module.code(0);
let offsets = boom.offsets().expect("offsets kept by default");
assert_eq!(inner.debug.func_name(0), Some("boom"));
assert!(
inner.debug.lookup(offsets[0]).is_none(),
"no DWARF by default"
);
}
#[test]
fn wasm_backtrace_off_drops_offsets_and_names() {
let engine = Engine::new(Config::new().wasm_backtrace(false)).unwrap();
let module = Module::new(&engine, FIXTURE).unwrap();
let inner = module.inner();
assert!(module.code(0).offsets().is_none());
assert_eq!(inner.debug.func_name(0), None);
}
#[test]
fn module_name_from_name_section() {
let bytes = wat::parse_str(r#"(module $submilli_pkg (func (export "f")))"#).unwrap();
let engine = Engine::default();
let module = Module::new(&engine, &bytes).unwrap();
assert_eq!(module.name(), Some("submilli_pkg"));
}
#[test]
fn module_name_absent_is_none() {
let bytes = wat::parse_str(r#"(module (func (export "f")))"#).unwrap();
let engine = Engine::default();
let module = Module::new(&engine, &bytes).unwrap();
assert_eq!(module.name(), None);
}
#[test]
fn module_name_survives_wasm_backtrace_off() {
let bytes = wat::parse_str(r#"(module $submilli_pkg (func (export "f")))"#).unwrap();
let engine = Engine::new(Config::new().wasm_backtrace(false)).unwrap();
let module = Module::new(&engine, &bytes).unwrap();
assert_eq!(module.name(), Some("submilli_pkg"));
assert_eq!(module.inner().debug.func_name(0), None);
}
#[test]
fn module_name_survives_serialize_round_trip() {
let bytes = wat::parse_str(r#"(module $submilli_pkg (func (export "f")))"#).unwrap();
let engine = Engine::default();
let module = Module::new(&engine, &bytes).unwrap();
let artifact = module.serialize().unwrap();
let restored = unsafe { Module::deserialize(&engine, &artifact) }.unwrap();
assert_eq!(restored.name(), Some("submilli_pkg"));
}