use super::*;
use crate::instruction::OpCode;
#[test]
fn csharp_escapes_control_chars_in_pushdata_string_literal() {
let nef_bytes = build_nef(&[
OpCode::Pushdata1.byte(),
0x03,
b'a',
b'\n',
b'b',
OpCode::Ret.byte(),
]);
let decompilation = Decompiler::new()
.decompile_bytes_with_manifest(&nef_bytes, None, OutputFormat::All)
.expect("decompile succeeds");
let csharp = decompilation.csharp.as_deref().expect("csharp output");
assert!(
csharp.contains(r#""a\nb""#),
"newline in PUSHDATA string must be escaped as \\n: {csharp}"
);
assert!(
!csharp.contains("a\nb"),
"a raw newline must not appear inside the C# string literal: {csharp}"
);
}
#[test]
fn csharp_wraps_only_oversized_integer_literals() {
let mut script = vec![OpCode::Pushint256.byte()];
let mut operand = vec![0u8; 32];
operand[25] = 0x01; script.extend_from_slice(&operand);
script.push(OpCode::Ret.byte());
let nef_bytes = build_nef(&script);
let csharp = Decompiler::new()
.with_inline_single_use_temps(true)
.with_trace_comments(false)
.decompile_bytes_with_manifest(&nef_bytes, None, OutputFormat::All)
.expect("decompile succeeds")
.csharp
.expect("csharp output");
assert!(
csharp.contains(
r#"BigInteger.Parse("1606938044258990275541962092341162602522202993782792835301376")"#
),
"oversized integer literal must be wrapped in BigInteger.Parse: {csharp}"
);
assert_eq!(
csharpize_statement("return 18446744073709551615;"),
"return 18446744073709551615;"
);
assert_eq!(
csharpize_statement("return 18446744073709551616;"),
r#"return BigInteger.Parse("18446744073709551616");"#
);
assert_eq!(csharpize_statement("return 42;"), "return 42;");
assert!(!csharpize_statement("let t0 = syscall(0xDEADBEEF);").contains("BigInteger.Parse"));
assert!(!csharpize_statement("goto label_0x0010;").contains("BigInteger.Parse"));
}
#[test]
fn csharp_renders_oversized_hex_blob_as_byte_array() {
let blob: Vec<u8> = (0..20).map(|i| 0xA0 + i).collect();
let mut script = vec![OpCode::Pushdata1.byte(), 20];
script.extend_from_slice(&blob);
script.push(OpCode::Ret.byte());
let nef_bytes = build_nef(&script);
let csharp = Decompiler::new()
.with_inline_single_use_temps(true)
.with_trace_comments(false)
.decompile_bytes_with_manifest(&nef_bytes, None, OutputFormat::All)
.expect("decompile succeeds")
.csharp
.expect("csharp output");
assert!(
csharp.contains("new byte[] { 0xA0, 0xA1,") && csharp.contains("0xB3 }"),
"wide hex blob must render as a byte[] literal: {csharp}"
);
assert!(!csharpize_statement("let t0 = syscall(0xEFBEADDE);").contains("byte[]"));
assert!(!csharpize_statement("let t0 = callt(0x0000);").contains("byte[]"));
assert!(!csharpize_statement("goto label_0x0010;").contains("byte[]"));
}
#[test]
fn csharp_renders_map_literal_as_collection_initializer() {
let script = [
OpCode::Push4.byte(),
OpCode::Push3.byte(),
OpCode::Push2.byte(),
OpCode::Push1.byte(),
OpCode::Push2.byte(),
OpCode::Packmap.byte(),
OpCode::Ret.byte(),
];
let nef_bytes = build_nef(&script);
let csharp = Decompiler::new()
.with_inline_single_use_temps(true)
.with_trace_comments(false)
.decompile_bytes_with_manifest(&nef_bytes, None, OutputFormat::All)
.expect("decompile succeeds")
.csharp
.expect("csharp output");
assert!(
csharp.contains("new Map<object, object> { [1] = 2, [3] = 4 }"),
"non-empty map literal must render as a C# collection initializer: {csharp}"
);
assert!(
!csharp.contains("Map(1: 2"),
"the invalid `Map(k: v)` form must not appear: {csharp}"
);
assert_eq!(
csharpize_statement("let t0 = Map();"),
"var t0 = new Map<object, object>();"
);
}