use mielin_hal::capabilities::HardwareCapabilities;
use mielin_wasm::{
debug::{inspect_memory, DebugContext, MemoryInspector, SourceMap, SourceMapEntry},
executor::WasmExecutor,
};
#[test]
fn test_memory_inspection_integration() {
let wasm = wat::parse_str(
r#"
(module
(memory (export "memory") 1)
(func (export "write_data")
;; Write "Hello World" to offset 100
i32.const 100
i64.const 0x6f57206f6c6c6548 ;; "Hello Wo" in little-endian
i64.store
i32.const 108
i32.const 0x646c72 ;; "rld" in little-endian (3 bytes + padding)
i32.store
)
)
"#,
)
.unwrap();
let executor = WasmExecutor::new().unwrap();
let module = executor.compile_module(&wasm).unwrap();
let (instance, mut store) = executor
.instantiate(&module, HardwareCapabilities::NONE)
.unwrap();
let write_data = instance.get_func(&mut store, "write_data").unwrap();
write_data.call(&mut store, &[], &mut []).unwrap();
let dump = inspect_memory(&mut store, &instance, 100, 16).unwrap();
assert!(dump.contains("48 65 6c 6c")); assert!(dump.contains("Hello"));
}
#[test]
fn test_memory_inspector_typed_reads() {
let wasm = wat::parse_str(
r#"
(module
(memory (export "memory") 1)
(func (export "write_numbers")
;; Write u32: 0x12345678 at offset 0
i32.const 0
i32.const 0x12345678
i32.store
;; Write f32: 3.14 at offset 4
i32.const 4
f32.const 3.14
f32.store
;; Write u64: 0x123456789ABCDEF0 at offset 8
i32.const 8
i64.const 0x123456789ABCDEF0
i64.store
)
)
"#,
)
.unwrap();
let executor = WasmExecutor::new().unwrap();
let module = executor.compile_module(&wasm).unwrap();
let (instance, mut store) = executor
.instantiate(&module, HardwareCapabilities::NONE)
.unwrap();
let write_nums = instance.get_func(&mut store, "write_numbers").unwrap();
write_nums.call(&mut store, &[], &mut []).unwrap();
let memory_data = mielin_wasm::debug::get_memory_data(&mut store, &instance).unwrap();
let inspector = MemoryInspector::new(0, 16);
let u32_val = inspector.read_u32(&memory_data, 0).unwrap();
assert_eq!(u32_val, 0x12345678);
let f32_val = inspector.read_f32(&memory_data, 4).unwrap();
assert!((f32_val - std::f32::consts::PI).abs() < 0.01);
let u64_val = inspector.read_u64(&memory_data, 8).unwrap();
assert_eq!(u64_val, 0x123456789ABCDEF0);
}
#[test]
fn test_memory_inspector_cstring_read() {
let wasm = wat::parse_str(
r#"
(module
(memory (export "memory") 1)
(data (i32.const 0) "Hello, MielinOS!\00")
(func (export "_start"))
)
"#,
)
.unwrap();
let executor = WasmExecutor::new().unwrap();
let module = executor.compile_module(&wasm).unwrap();
let (instance, mut store) = executor
.instantiate(&module, HardwareCapabilities::NONE)
.unwrap();
let memory_data = mielin_wasm::debug::get_memory_data(&mut store, &instance).unwrap();
let inspector = MemoryInspector::new(0, memory_data.len());
let string = inspector.read_cstring(&memory_data, 0).unwrap();
assert_eq!(string, "Hello, MielinOS!");
}
#[test]
fn test_source_map_integration() {
let mut source_map = SourceMap::new("test_module".to_string());
source_map.add_source(
"main.rs".to_string(),
r#"fn main() {
let x = 42;
println!("x = {}", x);
}
"#
.to_string(),
);
source_map.add_entry(SourceMapEntry {
wasm_offset: 0,
file: "main.rs".to_string(),
line: 1,
column: 1,
function_name: Some("main".to_string()),
});
source_map.add_entry(SourceMapEntry {
wasm_offset: 50,
file: "main.rs".to_string(),
line: 2,
column: 5,
function_name: Some("main".to_string()),
});
source_map.add_entry(SourceMapEntry {
wasm_offset: 100,
file: "main.rs".to_string(),
line: 3,
column: 5,
function_name: Some("main".to_string()),
});
let entry = source_map.lookup(0).unwrap();
assert_eq!(entry.line, 1);
assert_eq!(entry.file, "main.rs");
let entry = source_map.lookup(75).unwrap();
assert_eq!(entry.line, 2);
let entry = source_map.lookup(150).unwrap();
assert_eq!(entry.line, 3);
let line = source_map.get_source_line("main.rs", 2).unwrap();
assert!(line.contains("let x = 42"));
}
#[test]
fn test_debug_context_with_breakpoints() {
let mut ctx = DebugContext::new();
let mut source_map = SourceMap::new("test".to_string());
source_map.add_entry(SourceMapEntry {
wasm_offset: 100,
file: "test.rs".to_string(),
line: 10,
column: 5,
function_name: Some("test_func".to_string()),
});
ctx.add_source_map("test_module".to_string(), source_map);
let bp1 = ctx.add_breakpoint(mielin_wasm::debug::BreakpointType::Offset(100));
let bp2 = ctx.add_breakpoint(mielin_wasm::debug::BreakpointType::FunctionEntry(5));
let breakpoints = ctx.list_breakpoints();
assert_eq!(breakpoints.len(), 2);
ctx.set_breakpoint_enabled(bp1, false).unwrap();
let breakpoints = ctx.list_breakpoints();
let bp = breakpoints.iter().find(|b| b.id == bp1).unwrap();
assert!(!bp.enabled);
assert!(ctx.remove_breakpoint(bp2));
assert_eq!(ctx.list_breakpoints().len(), 1);
let sm = ctx.get_source_map("test_module").unwrap();
assert_eq!(sm.module_name(), "test");
}
#[test]
fn test_debugger_state_transitions() {
let mut ctx = DebugContext::new();
assert_eq!(ctx.state(), mielin_wasm::debug::DebuggerState::Running);
ctx.set_state(mielin_wasm::debug::DebuggerState::Stepping);
assert_eq!(ctx.state(), mielin_wasm::debug::DebuggerState::Stepping);
assert!(ctx.should_stop(0, 0));
ctx.set_state(mielin_wasm::debug::DebuggerState::Stopped);
assert_eq!(ctx.state(), mielin_wasm::debug::DebuggerState::Stopped);
ctx.set_state(mielin_wasm::debug::DebuggerState::Running);
assert_eq!(ctx.state(), mielin_wasm::debug::DebuggerState::Running);
}
#[test]
fn test_memory_hex_dump_formatting() {
let mut memory = vec![0u8; 256];
for (i, byte) in memory.iter_mut().take(16).enumerate() {
*byte = i as u8;
}
memory[16] = b'T';
memory[17] = b'E';
memory[18] = b'S';
memory[19] = b'T';
let inspector = MemoryInspector::new(0, 32).with_bytes_per_row(16);
let dump = inspector.dump_hex(&memory);
assert!(dump.contains("00 01 02 03"));
assert!(dump.contains("TEST"));
assert!(dump.contains("00000000 "));
assert!(dump.contains("|"));
}
#[test]
fn test_stack_trace_formatting() {
let mut trace = mielin_wasm::debug::StackTrace {
message: "Division by zero".to_string(),
frames: Vec::new(),
};
trace.add_frame(mielin_wasm::debug::StackFrame {
func_index: 0,
func_name: Some("divide".to_string()),
wasm_offset: 0x100,
source_location: Some(SourceMapEntry {
wasm_offset: 0x100,
file: "math.rs".to_string(),
line: 42,
column: 10,
function_name: Some("divide".to_string()),
}),
module_name: "math_module".to_string(),
});
trace.add_frame(mielin_wasm::debug::StackFrame {
func_index: 1,
func_name: Some("main".to_string()),
wasm_offset: 0x50,
source_location: Some(SourceMapEntry {
wasm_offset: 0x50,
file: "main.rs".to_string(),
line: 10,
column: 5,
function_name: Some("main".to_string()),
}),
module_name: "main_module".to_string(),
});
let formatted = trace.format();
assert!(formatted.contains("Division by zero"));
assert!(formatted.contains("divide"));
assert!(formatted.contains("math.rs:42:10"));
assert!(formatted.contains("main"));
assert!(formatted.contains("main.rs:10:5"));
}