use super::*;
#[test]
fn decompile_syscall_includes_human_name() {
let script = [0x41, 0xB2, 0x79, 0xFC, 0xF6, 0x40];
let nef_bytes = build_nef(&script);
let decompilation = Decompiler::new()
.decompile_bytes(&nef_bytes)
.expect("decompile succeeds");
assert!(decompilation
.pseudocode
.as_deref()
.expect("pseudocode output")
.contains("System.Runtime.Platform"));
assert!(decompilation
.high_level
.as_deref()
.expect("high-level output")
.contains("syscall(\"System.Runtime.Platform\")"));
}
#[test]
fn void_syscall_does_not_push_stack_value() {
let script = [0x10, 0x10, 0x41, 0x95, 0x01, 0x6F, 0x61, 0x40];
let nef_bytes = build_nef(&script);
let decompilation = Decompiler::new()
.decompile_bytes(&nef_bytes)
.expect("decompile succeeds");
let high_level = decompilation
.high_level
.as_deref()
.expect("high-level output");
assert!(
high_level.contains("syscall(\"System.Runtime.Notify\""),
"void syscall should be emitted as a statement"
);
assert!(
!high_level.contains("let t0 = syscall(\"System.Runtime.Notify\")"),
"void syscall should not push a temp onto the stack"
);
}
#[test]
fn unknown_syscall_is_assumed_to_return_value() {
let unknown_hash = 0xDEADBEEF;
assert!(
crate::syscalls::lookup(unknown_hash).is_none(),
"fixture hash should not be present in the syscall catalog"
);
let script = [0x41, 0xEF, 0xBE, 0xAD, 0xDE, 0x40];
let nef_bytes = build_nef(&script);
let decompilation = Decompiler::new()
.decompile_bytes(&nef_bytes)
.expect("decompile succeeds");
assert!(
decompilation
.high_level
.as_deref()
.expect("high-level output")
.contains("let t0 = syscall(0xDEADBEEF);"),
"unknown syscalls should conservatively push a stack value"
);
}
#[test]
fn void_storage_syscall_is_emitted_as_statement() {
let script = [0x10, 0x10, 0x10, 0x41, 0xE6, 0x3F, 0x18, 0x84, 0x40];
let nef_bytes = build_nef(&script);
let decompilation = Decompiler::new()
.decompile_bytes(&nef_bytes)
.expect("decompile succeeds");
let high_level = decompilation
.high_level
.as_deref()
.expect("high-level output");
assert!(
high_level.contains("syscall(\"System.Storage.Put\""),
"void storage syscall should be emitted as a statement"
);
assert!(
!high_level.contains("let t0 = syscall(\"System.Storage.Put\")"),
"void storage syscall should not push a temp onto the stack"
);
}
#[test]
fn void_storage_local_syscall_is_emitted_as_statement() {
let script = [0x10, 0x10, 0x41, 0x39, 0x0C, 0xE3, 0x0A, 0x40];
let nef_bytes = build_nef(&script);
let decompilation = Decompiler::new()
.decompile_bytes(&nef_bytes)
.expect("decompile succeeds");
let high_level = decompilation
.high_level
.as_deref()
.expect("high-level output");
assert!(
high_level.contains("syscall(\"System.Storage.Local.Put\""),
"void storage local syscall should be emitted as a statement"
);
assert!(
!high_level.contains("let t0 = syscall(\"System.Storage.Local.Put\")"),
"void storage local syscall should not push a temp onto the stack"
);
}
#[test]
fn syscall_contract_call_returns_value() {
let script = [0x10, 0x10, 0x10, 0x10, 0x41, 0x62, 0x7D, 0x5B, 0x52, 0x40];
let nef_bytes = build_nef(&script);
let decompilation = Decompiler::new()
.decompile_bytes(&nef_bytes)
.expect("decompile succeeds");
let high_level = decompilation
.high_level
.as_deref()
.expect("high-level output");
assert!(
high_level.contains("syscall(\"System.Contract.Call\""),
"System.Contract.Call should resolve to human name: {high_level}"
);
assert!(
high_level.contains("= syscall(\"System.Contract.Call\""),
"System.Contract.Call returns a value and should push a temp: {high_level}"
);
}
#[test]
fn syscall_runtime_log_is_void() {
let script = [0x10, 0x41, 0xCF, 0xE7, 0x47, 0x96, 0x40];
let nef_bytes = build_nef(&script);
let decompilation = Decompiler::new()
.decompile_bytes(&nef_bytes)
.expect("decompile succeeds");
let high_level = decompilation
.high_level
.as_deref()
.expect("high-level output");
assert!(
high_level.contains("syscall(\"System.Runtime.Log\""),
"System.Runtime.Log is void and should be emitted as statement: {high_level}"
);
assert!(
!high_level.contains("let t0 = syscall(\"System.Runtime.Log\")"),
"void syscall should not push a temp: {high_level}"
);
}
#[test]
fn syscall_runtime_log_missing_argument_emits_warning() {
let script = [0x41, 0xCF, 0xE7, 0x47, 0x96, 0x40];
let nef_bytes = build_nef(&script);
let decompilation = Decompiler::new()
.decompile_bytes(&nef_bytes)
.expect("decompile succeeds");
let high_level = decompilation
.high_level
.as_deref()
.expect("high-level output");
assert!(
high_level.contains("syscall(\"System.Runtime.Log\", ???)"),
"missing syscall argument should still be shown in output: {high_level}"
);
assert!(
high_level.contains("missing syscall argument values for System.Runtime.Log"),
"missing syscall argument should be called out inline in the output: {high_level}"
);
assert!(
decompilation
.warnings
.iter()
.any(|warning| warning.contains("missing syscall argument values")),
"missing syscall argument should emit a structured warning: {:?}",
decompilation.warnings
);
}
#[test]
fn syscall_runtime_log_after_packed_store_reports_consumed_slot_context() {
let script = [
0x57, 0x01, 0x00, 0x0C, 0x05, b'H', b'e', b'l', b'l', b'o', 0x11, 0xC0, 0x70, 0x41, 0xCF, 0xE7, 0x47, 0x96, 0x40, ];
let nef_bytes = build_nef(&script);
let decompilation = Decompiler::new()
.decompile_bytes(&nef_bytes)
.expect("decompile succeeds");
let high_level = decompilation
.high_level
.as_deref()
.expect("high-level output");
assert!(
high_level.contains("syscall(\"System.Runtime.Log\", ???)"),
"missing syscall argument should still be rendered: {high_level}"
);
assert!(
high_level.contains("preceding STLOC0 stored a packed value into loc0"),
"packed-store context should be surfaced inline: {high_level}"
);
assert!(
decompilation.warnings.iter().any(|warning| {
warning.contains("preceding STLOC0 stored a packed value into loc0")
}),
"packed-store context should also be emitted as a structured warning: {:?}",
decompilation.warnings
);
}
#[test]
fn syscall_check_witness_returns_value() {
let script = [0x10, 0x41, 0xF8, 0x27, 0xEC, 0x8C, 0x40];
let nef_bytes = build_nef(&script);
let decompilation = Decompiler::new()
.decompile_bytes(&nef_bytes)
.expect("decompile succeeds");
let high_level = decompilation
.high_level
.as_deref()
.expect("high-level output");
assert!(
high_level.contains("syscall(\"System.Runtime.CheckWitness\""),
"CheckWitness should resolve to human name: {high_level}"
);
assert!(
high_level.contains("= syscall(\"System.Runtime.CheckWitness\""),
"CheckWitness returns a value: {high_level}"
);
}