From 65480864d37f1a3cec2d953823357c7713e2dc1a Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Sat, 19 Jul 2025 14:13:01 +0800 Subject: [PATCH 01/12] Support SwiftPM --- Package.swift | 20 +++++++++++++++++++ bindings/swift/CCapstone/LEB128.h | 1 + bindings/swift/CCapstone/MCAsmInfo.h | 1 + bindings/swift/CCapstone/MCDisassembler.h | 1 + .../swift/CCapstone/MCFixedLenDisassembler.h | 1 + bindings/swift/CCapstone/MCInst.c | 1 + bindings/swift/CCapstone/MCInst.h | 1 + bindings/swift/CCapstone/MCInstPrinter.c | 1 + bindings/swift/CCapstone/MCInstPrinter.h | 1 + bindings/swift/CCapstone/MCInstrDesc.c | 1 + bindings/swift/CCapstone/MCInstrDesc.h | 1 + bindings/swift/CCapstone/MCRegisterInfo.c | 1 + bindings/swift/CCapstone/MCRegisterInfo.h | 1 + bindings/swift/CCapstone/Mapping.c | 1 + bindings/swift/CCapstone/Mapping.h | 1 + bindings/swift/CCapstone/MathExtras.h | 1 + bindings/swift/CCapstone/SStream.c | 1 + bindings/swift/CCapstone/SStream.h | 1 + bindings/swift/CCapstone/UpdateSymlink.sh | 12 +++++++++++ bindings/swift/CCapstone/arch | 1 + bindings/swift/CCapstone/cs.c | 1 + bindings/swift/CCapstone/cs_priv.h | 1 + bindings/swift/CCapstone/cs_simple_types.h | 1 + .../include/capstone/UpdateSymlink.sh | 11 ++++++++++ .../CCapstone/include/capstone/aarch64.h | 1 + .../swift/CCapstone/include/capstone/alpha.h | 1 + .../swift/CCapstone/include/capstone/arc.h | 1 + .../swift/CCapstone/include/capstone/arm.h | 1 + .../swift/CCapstone/include/capstone/arm64.h | 1 + .../swift/CCapstone/include/capstone/bpf.h | 1 + .../CCapstone/include/capstone/capstone.h | 1 + .../CCapstone/include/capstone/cs_operand.h | 1 + .../swift/CCapstone/include/capstone/evm.h | 1 + .../swift/CCapstone/include/capstone/hppa.h | 1 + .../CCapstone/include/capstone/loongarch.h | 1 + .../swift/CCapstone/include/capstone/m680x.h | 1 + .../swift/CCapstone/include/capstone/m68k.h | 1 + .../swift/CCapstone/include/capstone/mips.h | 1 + .../CCapstone/include/capstone/mos65xx.h | 1 + .../CCapstone/include/capstone/platform.h | 1 + .../swift/CCapstone/include/capstone/ppc.h | 1 + .../swift/CCapstone/include/capstone/riscv.h | 1 + .../swift/CCapstone/include/capstone/sh.h | 1 + .../swift/CCapstone/include/capstone/sparc.h | 1 + .../CCapstone/include/capstone/systemz.h | 1 + .../include/capstone/systemz_compatibility.h | 1 + .../CCapstone/include/capstone/tms320c64x.h | 1 + .../CCapstone/include/capstone/tricore.h | 1 + .../swift/CCapstone/include/capstone/wasm.h | 1 + .../swift/CCapstone/include/capstone/x86.h | 1 + .../swift/CCapstone/include/capstone/xcore.h | 1 + .../swift/CCapstone/include/capstone/xtensa.h | 1 + bindings/swift/CCapstone/utils.c | 1 + bindings/swift/CCapstone/utils.h | 1 + 54 files changed, 94 insertions(+) create mode 100644 Package.swift create mode 120000 bindings/swift/CCapstone/LEB128.h create mode 120000 bindings/swift/CCapstone/MCAsmInfo.h create mode 120000 bindings/swift/CCapstone/MCDisassembler.h create mode 120000 bindings/swift/CCapstone/MCFixedLenDisassembler.h create mode 120000 bindings/swift/CCapstone/MCInst.c create mode 120000 bindings/swift/CCapstone/MCInst.h create mode 120000 bindings/swift/CCapstone/MCInstPrinter.c create mode 120000 bindings/swift/CCapstone/MCInstPrinter.h create mode 120000 bindings/swift/CCapstone/MCInstrDesc.c create mode 120000 bindings/swift/CCapstone/MCInstrDesc.h create mode 120000 bindings/swift/CCapstone/MCRegisterInfo.c create mode 120000 bindings/swift/CCapstone/MCRegisterInfo.h create mode 120000 bindings/swift/CCapstone/Mapping.c create mode 120000 bindings/swift/CCapstone/Mapping.h create mode 120000 bindings/swift/CCapstone/MathExtras.h create mode 120000 bindings/swift/CCapstone/SStream.c create mode 120000 bindings/swift/CCapstone/SStream.h create mode 100755 bindings/swift/CCapstone/UpdateSymlink.sh create mode 120000 bindings/swift/CCapstone/arch create mode 120000 bindings/swift/CCapstone/cs.c create mode 120000 bindings/swift/CCapstone/cs_priv.h create mode 120000 bindings/swift/CCapstone/cs_simple_types.h create mode 100755 bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh create mode 120000 bindings/swift/CCapstone/include/capstone/aarch64.h create mode 120000 bindings/swift/CCapstone/include/capstone/alpha.h create mode 120000 bindings/swift/CCapstone/include/capstone/arc.h create mode 120000 bindings/swift/CCapstone/include/capstone/arm.h create mode 120000 bindings/swift/CCapstone/include/capstone/arm64.h create mode 120000 bindings/swift/CCapstone/include/capstone/bpf.h create mode 120000 bindings/swift/CCapstone/include/capstone/capstone.h create mode 120000 bindings/swift/CCapstone/include/capstone/cs_operand.h create mode 120000 bindings/swift/CCapstone/include/capstone/evm.h create mode 120000 bindings/swift/CCapstone/include/capstone/hppa.h create mode 120000 bindings/swift/CCapstone/include/capstone/loongarch.h create mode 120000 bindings/swift/CCapstone/include/capstone/m680x.h create mode 120000 bindings/swift/CCapstone/include/capstone/m68k.h create mode 120000 bindings/swift/CCapstone/include/capstone/mips.h create mode 120000 bindings/swift/CCapstone/include/capstone/mos65xx.h create mode 120000 bindings/swift/CCapstone/include/capstone/platform.h create mode 120000 bindings/swift/CCapstone/include/capstone/ppc.h create mode 120000 bindings/swift/CCapstone/include/capstone/riscv.h create mode 120000 bindings/swift/CCapstone/include/capstone/sh.h create mode 120000 bindings/swift/CCapstone/include/capstone/sparc.h create mode 120000 bindings/swift/CCapstone/include/capstone/systemz.h create mode 120000 bindings/swift/CCapstone/include/capstone/systemz_compatibility.h create mode 120000 bindings/swift/CCapstone/include/capstone/tms320c64x.h create mode 120000 bindings/swift/CCapstone/include/capstone/tricore.h create mode 120000 bindings/swift/CCapstone/include/capstone/wasm.h create mode 120000 bindings/swift/CCapstone/include/capstone/x86.h create mode 120000 bindings/swift/CCapstone/include/capstone/xcore.h create mode 120000 bindings/swift/CCapstone/include/capstone/xtensa.h create mode 120000 bindings/swift/CCapstone/utils.c create mode 120000 bindings/swift/CCapstone/utils.h diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000000..c8ec38a161 --- /dev/null +++ b/Package.swift @@ -0,0 +1,20 @@ +// swift-tools-version: 6.1 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "capstone", + products: [ + .library( + name: "CCapstone", + targets: ["CCapstone"] + ), + ], + targets: [ + .target( + name: "CCapstone", + path: "bindings/swift/CCapstone", + ), + ] +) diff --git a/bindings/swift/CCapstone/LEB128.h b/bindings/swift/CCapstone/LEB128.h new file mode 120000 index 0000000000..371e091330 --- /dev/null +++ b/bindings/swift/CCapstone/LEB128.h @@ -0,0 +1 @@ +../../../LEB128.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCAsmInfo.h b/bindings/swift/CCapstone/MCAsmInfo.h new file mode 120000 index 0000000000..31ab35ea22 --- /dev/null +++ b/bindings/swift/CCapstone/MCAsmInfo.h @@ -0,0 +1 @@ +../../../MCAsmInfo.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCDisassembler.h b/bindings/swift/CCapstone/MCDisassembler.h new file mode 120000 index 0000000000..6ea5de0e0d --- /dev/null +++ b/bindings/swift/CCapstone/MCDisassembler.h @@ -0,0 +1 @@ +../../../MCDisassembler.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCFixedLenDisassembler.h b/bindings/swift/CCapstone/MCFixedLenDisassembler.h new file mode 120000 index 0000000000..123782ab1f --- /dev/null +++ b/bindings/swift/CCapstone/MCFixedLenDisassembler.h @@ -0,0 +1 @@ +../../../MCFixedLenDisassembler.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInst.c b/bindings/swift/CCapstone/MCInst.c new file mode 120000 index 0000000000..4ba686ffdc --- /dev/null +++ b/bindings/swift/CCapstone/MCInst.c @@ -0,0 +1 @@ +../../../MCInst.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInst.h b/bindings/swift/CCapstone/MCInst.h new file mode 120000 index 0000000000..0044b5a6f1 --- /dev/null +++ b/bindings/swift/CCapstone/MCInst.h @@ -0,0 +1 @@ +../../../MCInst.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInstPrinter.c b/bindings/swift/CCapstone/MCInstPrinter.c new file mode 120000 index 0000000000..6a4081296b --- /dev/null +++ b/bindings/swift/CCapstone/MCInstPrinter.c @@ -0,0 +1 @@ +../../../MCInstPrinter.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInstPrinter.h b/bindings/swift/CCapstone/MCInstPrinter.h new file mode 120000 index 0000000000..386cb88aea --- /dev/null +++ b/bindings/swift/CCapstone/MCInstPrinter.h @@ -0,0 +1 @@ +../../../MCInstPrinter.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInstrDesc.c b/bindings/swift/CCapstone/MCInstrDesc.c new file mode 120000 index 0000000000..73e916fe5a --- /dev/null +++ b/bindings/swift/CCapstone/MCInstrDesc.c @@ -0,0 +1 @@ +../../../MCInstrDesc.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInstrDesc.h b/bindings/swift/CCapstone/MCInstrDesc.h new file mode 120000 index 0000000000..294dee6759 --- /dev/null +++ b/bindings/swift/CCapstone/MCInstrDesc.h @@ -0,0 +1 @@ +../../../MCInstrDesc.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCRegisterInfo.c b/bindings/swift/CCapstone/MCRegisterInfo.c new file mode 120000 index 0000000000..caaa608336 --- /dev/null +++ b/bindings/swift/CCapstone/MCRegisterInfo.c @@ -0,0 +1 @@ +../../../MCRegisterInfo.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCRegisterInfo.h b/bindings/swift/CCapstone/MCRegisterInfo.h new file mode 120000 index 0000000000..6db0beb49f --- /dev/null +++ b/bindings/swift/CCapstone/MCRegisterInfo.h @@ -0,0 +1 @@ +../../../MCRegisterInfo.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/Mapping.c b/bindings/swift/CCapstone/Mapping.c new file mode 120000 index 0000000000..3e10b8e7b6 --- /dev/null +++ b/bindings/swift/CCapstone/Mapping.c @@ -0,0 +1 @@ +../../../Mapping.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/Mapping.h b/bindings/swift/CCapstone/Mapping.h new file mode 120000 index 0000000000..69bdb7d354 --- /dev/null +++ b/bindings/swift/CCapstone/Mapping.h @@ -0,0 +1 @@ +../../../Mapping.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MathExtras.h b/bindings/swift/CCapstone/MathExtras.h new file mode 120000 index 0000000000..5034ce41d9 --- /dev/null +++ b/bindings/swift/CCapstone/MathExtras.h @@ -0,0 +1 @@ +../../../MathExtras.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/SStream.c b/bindings/swift/CCapstone/SStream.c new file mode 120000 index 0000000000..c744dfa1f8 --- /dev/null +++ b/bindings/swift/CCapstone/SStream.c @@ -0,0 +1 @@ +../../../SStream.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/SStream.h b/bindings/swift/CCapstone/SStream.h new file mode 120000 index 0000000000..2f4e1515fd --- /dev/null +++ b/bindings/swift/CCapstone/SStream.h @@ -0,0 +1 @@ +../../../SStream.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/UpdateSymlink.sh b/bindings/swift/CCapstone/UpdateSymlink.sh new file mode 100755 index 0000000000..e859bc7c1c --- /dev/null +++ b/bindings/swift/CCapstone/UpdateSymlink.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +target_dir="../../.." + +find "$target_dir" -maxdepth 1 \( -name "*.h" -o -name "*.c" \) -print0 | while IFS= read -r -d $'\0' header_file; do + + relative_path=$(echo "$header_file" | sed "s#^$PWD/##") + + ln -s "$relative_path" . + + echo "Created symlink: $(basename "$header_file") -> $relative_path" +done diff --git a/bindings/swift/CCapstone/arch b/bindings/swift/CCapstone/arch new file mode 120000 index 0000000000..c96956df19 --- /dev/null +++ b/bindings/swift/CCapstone/arch @@ -0,0 +1 @@ +../../../arch \ No newline at end of file diff --git a/bindings/swift/CCapstone/cs.c b/bindings/swift/CCapstone/cs.c new file mode 120000 index 0000000000..f3de1cec49 --- /dev/null +++ b/bindings/swift/CCapstone/cs.c @@ -0,0 +1 @@ +../../../cs.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/cs_priv.h b/bindings/swift/CCapstone/cs_priv.h new file mode 120000 index 0000000000..ae5dd91549 --- /dev/null +++ b/bindings/swift/CCapstone/cs_priv.h @@ -0,0 +1 @@ +../../../cs_priv.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/cs_simple_types.h b/bindings/swift/CCapstone/cs_simple_types.h new file mode 120000 index 0000000000..0a33a17b44 --- /dev/null +++ b/bindings/swift/CCapstone/cs_simple_types.h @@ -0,0 +1 @@ +../../../cs_simple_types.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh b/bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh new file mode 100755 index 0000000000..227b4220e5 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +target_dir="../../../../../include/capstone" + +find "$target_dir" -name "*.h" -print0 | while IFS= read -r -d $'\0' header_file; do + relative_path=$(echo "$header_file" | sed "s#^$PWD/##") + + ln -s "$relative_path" . + + echo "Created symlink: $(basename "$header_file") -> $relative_path" +done diff --git a/bindings/swift/CCapstone/include/capstone/aarch64.h b/bindings/swift/CCapstone/include/capstone/aarch64.h new file mode 120000 index 0000000000..ffc5977379 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/aarch64.h @@ -0,0 +1 @@ +../../../../../include/capstone/aarch64.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/alpha.h b/bindings/swift/CCapstone/include/capstone/alpha.h new file mode 120000 index 0000000000..22833d9929 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/alpha.h @@ -0,0 +1 @@ +../../../../../include/capstone/alpha.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/arc.h b/bindings/swift/CCapstone/include/capstone/arc.h new file mode 120000 index 0000000000..ef9ea57a33 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/arc.h @@ -0,0 +1 @@ +../../../../../include/capstone/arc.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/arm.h b/bindings/swift/CCapstone/include/capstone/arm.h new file mode 120000 index 0000000000..69727b0f41 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/arm.h @@ -0,0 +1 @@ +../../../../../include/capstone/arm.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/arm64.h b/bindings/swift/CCapstone/include/capstone/arm64.h new file mode 120000 index 0000000000..d2f4951d52 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/arm64.h @@ -0,0 +1 @@ +../../../../../include/capstone/arm64.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/bpf.h b/bindings/swift/CCapstone/include/capstone/bpf.h new file mode 120000 index 0000000000..17ef426656 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/bpf.h @@ -0,0 +1 @@ +../../../../../include/capstone/bpf.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/capstone.h b/bindings/swift/CCapstone/include/capstone/capstone.h new file mode 120000 index 0000000000..83845c68c0 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/capstone.h @@ -0,0 +1 @@ +../../../../../include/capstone/capstone.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/cs_operand.h b/bindings/swift/CCapstone/include/capstone/cs_operand.h new file mode 120000 index 0000000000..206ec46ecc --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/cs_operand.h @@ -0,0 +1 @@ +../../../../../include/capstone/cs_operand.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/evm.h b/bindings/swift/CCapstone/include/capstone/evm.h new file mode 120000 index 0000000000..c99a289ca9 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/evm.h @@ -0,0 +1 @@ +../../../../../include/capstone/evm.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/hppa.h b/bindings/swift/CCapstone/include/capstone/hppa.h new file mode 120000 index 0000000000..57c266124c --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/hppa.h @@ -0,0 +1 @@ +../../../../../include/capstone/hppa.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/loongarch.h b/bindings/swift/CCapstone/include/capstone/loongarch.h new file mode 120000 index 0000000000..a4c0baaa26 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/loongarch.h @@ -0,0 +1 @@ +../../../../../include/capstone/loongarch.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/m680x.h b/bindings/swift/CCapstone/include/capstone/m680x.h new file mode 120000 index 0000000000..5edfe318c7 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/m680x.h @@ -0,0 +1 @@ +../../../../../include/capstone/m680x.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/m68k.h b/bindings/swift/CCapstone/include/capstone/m68k.h new file mode 120000 index 0000000000..d5abdeb03e --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/m68k.h @@ -0,0 +1 @@ +../../../../../include/capstone/m68k.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/mips.h b/bindings/swift/CCapstone/include/capstone/mips.h new file mode 120000 index 0000000000..bff4dd303d --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/mips.h @@ -0,0 +1 @@ +../../../../../include/capstone/mips.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/mos65xx.h b/bindings/swift/CCapstone/include/capstone/mos65xx.h new file mode 120000 index 0000000000..5f3e52e288 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/mos65xx.h @@ -0,0 +1 @@ +../../../../../include/capstone/mos65xx.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/platform.h b/bindings/swift/CCapstone/include/capstone/platform.h new file mode 120000 index 0000000000..dd63320910 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/platform.h @@ -0,0 +1 @@ +../../../../../include/capstone/platform.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/ppc.h b/bindings/swift/CCapstone/include/capstone/ppc.h new file mode 120000 index 0000000000..292bf2bda6 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/ppc.h @@ -0,0 +1 @@ +../../../../../include/capstone/ppc.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/riscv.h b/bindings/swift/CCapstone/include/capstone/riscv.h new file mode 120000 index 0000000000..5e914a7454 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/riscv.h @@ -0,0 +1 @@ +../../../../../include/capstone/riscv.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/sh.h b/bindings/swift/CCapstone/include/capstone/sh.h new file mode 120000 index 0000000000..0d149e4dd6 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/sh.h @@ -0,0 +1 @@ +../../../../../include/capstone/sh.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/sparc.h b/bindings/swift/CCapstone/include/capstone/sparc.h new file mode 120000 index 0000000000..2c1db54bfd --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/sparc.h @@ -0,0 +1 @@ +../../../../../include/capstone/sparc.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/systemz.h b/bindings/swift/CCapstone/include/capstone/systemz.h new file mode 120000 index 0000000000..c4bcec06ee --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/systemz.h @@ -0,0 +1 @@ +../../../../../include/capstone/systemz.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/systemz_compatibility.h b/bindings/swift/CCapstone/include/capstone/systemz_compatibility.h new file mode 120000 index 0000000000..d42c47dea9 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/systemz_compatibility.h @@ -0,0 +1 @@ +../../../../../include/capstone/systemz_compatibility.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/tms320c64x.h b/bindings/swift/CCapstone/include/capstone/tms320c64x.h new file mode 120000 index 0000000000..83a88a41de --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/tms320c64x.h @@ -0,0 +1 @@ +../../../../../include/capstone/tms320c64x.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/tricore.h b/bindings/swift/CCapstone/include/capstone/tricore.h new file mode 120000 index 0000000000..2095a7903e --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/tricore.h @@ -0,0 +1 @@ +../../../../../include/capstone/tricore.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/wasm.h b/bindings/swift/CCapstone/include/capstone/wasm.h new file mode 120000 index 0000000000..6850e121c3 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/wasm.h @@ -0,0 +1 @@ +../../../../../include/capstone/wasm.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/x86.h b/bindings/swift/CCapstone/include/capstone/x86.h new file mode 120000 index 0000000000..62e0f8e0cb --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/x86.h @@ -0,0 +1 @@ +../../../../../include/capstone/x86.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/xcore.h b/bindings/swift/CCapstone/include/capstone/xcore.h new file mode 120000 index 0000000000..66dde9902e --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/xcore.h @@ -0,0 +1 @@ +../../../../../include/capstone/xcore.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/xtensa.h b/bindings/swift/CCapstone/include/capstone/xtensa.h new file mode 120000 index 0000000000..8b64b00556 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/xtensa.h @@ -0,0 +1 @@ +../../../../../include/capstone/xtensa.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/utils.c b/bindings/swift/CCapstone/utils.c new file mode 120000 index 0000000000..37965fc4bc --- /dev/null +++ b/bindings/swift/CCapstone/utils.c @@ -0,0 +1 @@ +../../../utils.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/utils.h b/bindings/swift/CCapstone/utils.h new file mode 120000 index 0000000000..bb469b1eb3 --- /dev/null +++ b/bindings/swift/CCapstone/utils.h @@ -0,0 +1 @@ +../../../utils.h \ No newline at end of file From 7ba185c99f0e58ef8ccc473ef00cdbbf04a391fc Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Sat, 19 Jul 2025 14:19:16 +0800 Subject: [PATCH 02/12] Update target name --- Package.swift | 8 ++++---- bindings/swift/{CCapstone => Ccapstone}/LEB128.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCAsmInfo.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCDisassembler.h | 0 .../{CCapstone => Ccapstone}/MCFixedLenDisassembler.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCInst.c | 0 bindings/swift/{CCapstone => Ccapstone}/MCInst.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCInstPrinter.c | 0 bindings/swift/{CCapstone => Ccapstone}/MCInstPrinter.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCInstrDesc.c | 0 bindings/swift/{CCapstone => Ccapstone}/MCInstrDesc.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCRegisterInfo.c | 0 bindings/swift/{CCapstone => Ccapstone}/MCRegisterInfo.h | 0 bindings/swift/{CCapstone => Ccapstone}/Mapping.c | 0 bindings/swift/{CCapstone => Ccapstone}/Mapping.h | 0 bindings/swift/{CCapstone => Ccapstone}/MathExtras.h | 0 bindings/swift/{CCapstone => Ccapstone}/SStream.c | 0 bindings/swift/{CCapstone => Ccapstone}/SStream.h | 0 bindings/swift/{CCapstone => Ccapstone}/UpdateSymlink.sh | 0 bindings/swift/{CCapstone => Ccapstone}/arch | 0 bindings/swift/{CCapstone => Ccapstone}/cs.c | 0 bindings/swift/{CCapstone => Ccapstone}/cs_priv.h | 0 bindings/swift/{CCapstone => Ccapstone}/cs_simple_types.h | 0 .../include/capstone/UpdateSymlink.sh | 0 .../{CCapstone => Ccapstone}/include/capstone/aarch64.h | 0 .../{CCapstone => Ccapstone}/include/capstone/alpha.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/arc.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/arm.h | 0 .../{CCapstone => Ccapstone}/include/capstone/arm64.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/bpf.h | 0 .../{CCapstone => Ccapstone}/include/capstone/capstone.h | 0 .../include/capstone/cs_operand.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/evm.h | 0 .../{CCapstone => Ccapstone}/include/capstone/hppa.h | 0 .../{CCapstone => Ccapstone}/include/capstone/loongarch.h | 0 .../{CCapstone => Ccapstone}/include/capstone/m680x.h | 0 .../{CCapstone => Ccapstone}/include/capstone/m68k.h | 0 .../{CCapstone => Ccapstone}/include/capstone/mips.h | 0 .../{CCapstone => Ccapstone}/include/capstone/mos65xx.h | 0 .../{CCapstone => Ccapstone}/include/capstone/platform.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/ppc.h | 0 .../{CCapstone => Ccapstone}/include/capstone/riscv.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/sh.h | 0 .../{CCapstone => Ccapstone}/include/capstone/sparc.h | 0 .../{CCapstone => Ccapstone}/include/capstone/systemz.h | 0 .../include/capstone/systemz_compatibility.h | 0 .../include/capstone/tms320c64x.h | 0 .../{CCapstone => Ccapstone}/include/capstone/tricore.h | 0 .../{CCapstone => Ccapstone}/include/capstone/wasm.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/x86.h | 0 .../{CCapstone => Ccapstone}/include/capstone/xcore.h | 0 .../{CCapstone => Ccapstone}/include/capstone/xtensa.h | 0 bindings/swift/{CCapstone => Ccapstone}/utils.c | 0 bindings/swift/{CCapstone => Ccapstone}/utils.h | 0 54 files changed, 4 insertions(+), 4 deletions(-) rename bindings/swift/{CCapstone => Ccapstone}/LEB128.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCAsmInfo.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCDisassembler.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCFixedLenDisassembler.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInst.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInst.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInstPrinter.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInstPrinter.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInstrDesc.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInstrDesc.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCRegisterInfo.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCRegisterInfo.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/Mapping.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/Mapping.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MathExtras.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/SStream.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/SStream.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/UpdateSymlink.sh (100%) rename bindings/swift/{CCapstone => Ccapstone}/arch (100%) rename bindings/swift/{CCapstone => Ccapstone}/cs.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/cs_priv.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/cs_simple_types.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/UpdateSymlink.sh (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/aarch64.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/alpha.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/arc.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/arm.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/arm64.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/bpf.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/capstone.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/cs_operand.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/evm.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/hppa.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/loongarch.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/m680x.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/m68k.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/mips.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/mos65xx.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/platform.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/ppc.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/riscv.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/sh.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/sparc.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/systemz.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/systemz_compatibility.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/tms320c64x.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/tricore.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/wasm.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/x86.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/xcore.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/xtensa.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/utils.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/utils.h (100%) diff --git a/Package.swift b/Package.swift index c8ec38a161..70e418947b 100644 --- a/Package.swift +++ b/Package.swift @@ -7,14 +7,14 @@ let package = Package( name: "capstone", products: [ .library( - name: "CCapstone", - targets: ["CCapstone"] + name: "Ccapstone", + targets: ["Ccapstone"] ), ], targets: [ .target( - name: "CCapstone", - path: "bindings/swift/CCapstone", + name: "Ccapstone", + path: "bindings/swift/Ccapstone", ), ] ) diff --git a/bindings/swift/CCapstone/LEB128.h b/bindings/swift/Ccapstone/LEB128.h similarity index 100% rename from bindings/swift/CCapstone/LEB128.h rename to bindings/swift/Ccapstone/LEB128.h diff --git a/bindings/swift/CCapstone/MCAsmInfo.h b/bindings/swift/Ccapstone/MCAsmInfo.h similarity index 100% rename from bindings/swift/CCapstone/MCAsmInfo.h rename to bindings/swift/Ccapstone/MCAsmInfo.h diff --git a/bindings/swift/CCapstone/MCDisassembler.h b/bindings/swift/Ccapstone/MCDisassembler.h similarity index 100% rename from bindings/swift/CCapstone/MCDisassembler.h rename to bindings/swift/Ccapstone/MCDisassembler.h diff --git a/bindings/swift/CCapstone/MCFixedLenDisassembler.h b/bindings/swift/Ccapstone/MCFixedLenDisassembler.h similarity index 100% rename from bindings/swift/CCapstone/MCFixedLenDisassembler.h rename to bindings/swift/Ccapstone/MCFixedLenDisassembler.h diff --git a/bindings/swift/CCapstone/MCInst.c b/bindings/swift/Ccapstone/MCInst.c similarity index 100% rename from bindings/swift/CCapstone/MCInst.c rename to bindings/swift/Ccapstone/MCInst.c diff --git a/bindings/swift/CCapstone/MCInst.h b/bindings/swift/Ccapstone/MCInst.h similarity index 100% rename from bindings/swift/CCapstone/MCInst.h rename to bindings/swift/Ccapstone/MCInst.h diff --git a/bindings/swift/CCapstone/MCInstPrinter.c b/bindings/swift/Ccapstone/MCInstPrinter.c similarity index 100% rename from bindings/swift/CCapstone/MCInstPrinter.c rename to bindings/swift/Ccapstone/MCInstPrinter.c diff --git a/bindings/swift/CCapstone/MCInstPrinter.h b/bindings/swift/Ccapstone/MCInstPrinter.h similarity index 100% rename from bindings/swift/CCapstone/MCInstPrinter.h rename to bindings/swift/Ccapstone/MCInstPrinter.h diff --git a/bindings/swift/CCapstone/MCInstrDesc.c b/bindings/swift/Ccapstone/MCInstrDesc.c similarity index 100% rename from bindings/swift/CCapstone/MCInstrDesc.c rename to bindings/swift/Ccapstone/MCInstrDesc.c diff --git a/bindings/swift/CCapstone/MCInstrDesc.h b/bindings/swift/Ccapstone/MCInstrDesc.h similarity index 100% rename from bindings/swift/CCapstone/MCInstrDesc.h rename to bindings/swift/Ccapstone/MCInstrDesc.h diff --git a/bindings/swift/CCapstone/MCRegisterInfo.c b/bindings/swift/Ccapstone/MCRegisterInfo.c similarity index 100% rename from bindings/swift/CCapstone/MCRegisterInfo.c rename to bindings/swift/Ccapstone/MCRegisterInfo.c diff --git a/bindings/swift/CCapstone/MCRegisterInfo.h b/bindings/swift/Ccapstone/MCRegisterInfo.h similarity index 100% rename from bindings/swift/CCapstone/MCRegisterInfo.h rename to bindings/swift/Ccapstone/MCRegisterInfo.h diff --git a/bindings/swift/CCapstone/Mapping.c b/bindings/swift/Ccapstone/Mapping.c similarity index 100% rename from bindings/swift/CCapstone/Mapping.c rename to bindings/swift/Ccapstone/Mapping.c diff --git a/bindings/swift/CCapstone/Mapping.h b/bindings/swift/Ccapstone/Mapping.h similarity index 100% rename from bindings/swift/CCapstone/Mapping.h rename to bindings/swift/Ccapstone/Mapping.h diff --git a/bindings/swift/CCapstone/MathExtras.h b/bindings/swift/Ccapstone/MathExtras.h similarity index 100% rename from bindings/swift/CCapstone/MathExtras.h rename to bindings/swift/Ccapstone/MathExtras.h diff --git a/bindings/swift/CCapstone/SStream.c b/bindings/swift/Ccapstone/SStream.c similarity index 100% rename from bindings/swift/CCapstone/SStream.c rename to bindings/swift/Ccapstone/SStream.c diff --git a/bindings/swift/CCapstone/SStream.h b/bindings/swift/Ccapstone/SStream.h similarity index 100% rename from bindings/swift/CCapstone/SStream.h rename to bindings/swift/Ccapstone/SStream.h diff --git a/bindings/swift/CCapstone/UpdateSymlink.sh b/bindings/swift/Ccapstone/UpdateSymlink.sh similarity index 100% rename from bindings/swift/CCapstone/UpdateSymlink.sh rename to bindings/swift/Ccapstone/UpdateSymlink.sh diff --git a/bindings/swift/CCapstone/arch b/bindings/swift/Ccapstone/arch similarity index 100% rename from bindings/swift/CCapstone/arch rename to bindings/swift/Ccapstone/arch diff --git a/bindings/swift/CCapstone/cs.c b/bindings/swift/Ccapstone/cs.c similarity index 100% rename from bindings/swift/CCapstone/cs.c rename to bindings/swift/Ccapstone/cs.c diff --git a/bindings/swift/CCapstone/cs_priv.h b/bindings/swift/Ccapstone/cs_priv.h similarity index 100% rename from bindings/swift/CCapstone/cs_priv.h rename to bindings/swift/Ccapstone/cs_priv.h diff --git a/bindings/swift/CCapstone/cs_simple_types.h b/bindings/swift/Ccapstone/cs_simple_types.h similarity index 100% rename from bindings/swift/CCapstone/cs_simple_types.h rename to bindings/swift/Ccapstone/cs_simple_types.h diff --git a/bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh b/bindings/swift/Ccapstone/include/capstone/UpdateSymlink.sh similarity index 100% rename from bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh rename to bindings/swift/Ccapstone/include/capstone/UpdateSymlink.sh diff --git a/bindings/swift/CCapstone/include/capstone/aarch64.h b/bindings/swift/Ccapstone/include/capstone/aarch64.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/aarch64.h rename to bindings/swift/Ccapstone/include/capstone/aarch64.h diff --git a/bindings/swift/CCapstone/include/capstone/alpha.h b/bindings/swift/Ccapstone/include/capstone/alpha.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/alpha.h rename to bindings/swift/Ccapstone/include/capstone/alpha.h diff --git a/bindings/swift/CCapstone/include/capstone/arc.h b/bindings/swift/Ccapstone/include/capstone/arc.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/arc.h rename to bindings/swift/Ccapstone/include/capstone/arc.h diff --git a/bindings/swift/CCapstone/include/capstone/arm.h b/bindings/swift/Ccapstone/include/capstone/arm.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/arm.h rename to bindings/swift/Ccapstone/include/capstone/arm.h diff --git a/bindings/swift/CCapstone/include/capstone/arm64.h b/bindings/swift/Ccapstone/include/capstone/arm64.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/arm64.h rename to bindings/swift/Ccapstone/include/capstone/arm64.h diff --git a/bindings/swift/CCapstone/include/capstone/bpf.h b/bindings/swift/Ccapstone/include/capstone/bpf.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/bpf.h rename to bindings/swift/Ccapstone/include/capstone/bpf.h diff --git a/bindings/swift/CCapstone/include/capstone/capstone.h b/bindings/swift/Ccapstone/include/capstone/capstone.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/capstone.h rename to bindings/swift/Ccapstone/include/capstone/capstone.h diff --git a/bindings/swift/CCapstone/include/capstone/cs_operand.h b/bindings/swift/Ccapstone/include/capstone/cs_operand.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/cs_operand.h rename to bindings/swift/Ccapstone/include/capstone/cs_operand.h diff --git a/bindings/swift/CCapstone/include/capstone/evm.h b/bindings/swift/Ccapstone/include/capstone/evm.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/evm.h rename to bindings/swift/Ccapstone/include/capstone/evm.h diff --git a/bindings/swift/CCapstone/include/capstone/hppa.h b/bindings/swift/Ccapstone/include/capstone/hppa.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/hppa.h rename to bindings/swift/Ccapstone/include/capstone/hppa.h diff --git a/bindings/swift/CCapstone/include/capstone/loongarch.h b/bindings/swift/Ccapstone/include/capstone/loongarch.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/loongarch.h rename to bindings/swift/Ccapstone/include/capstone/loongarch.h diff --git a/bindings/swift/CCapstone/include/capstone/m680x.h b/bindings/swift/Ccapstone/include/capstone/m680x.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/m680x.h rename to bindings/swift/Ccapstone/include/capstone/m680x.h diff --git a/bindings/swift/CCapstone/include/capstone/m68k.h b/bindings/swift/Ccapstone/include/capstone/m68k.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/m68k.h rename to bindings/swift/Ccapstone/include/capstone/m68k.h diff --git a/bindings/swift/CCapstone/include/capstone/mips.h b/bindings/swift/Ccapstone/include/capstone/mips.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/mips.h rename to bindings/swift/Ccapstone/include/capstone/mips.h diff --git a/bindings/swift/CCapstone/include/capstone/mos65xx.h b/bindings/swift/Ccapstone/include/capstone/mos65xx.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/mos65xx.h rename to bindings/swift/Ccapstone/include/capstone/mos65xx.h diff --git a/bindings/swift/CCapstone/include/capstone/platform.h b/bindings/swift/Ccapstone/include/capstone/platform.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/platform.h rename to bindings/swift/Ccapstone/include/capstone/platform.h diff --git a/bindings/swift/CCapstone/include/capstone/ppc.h b/bindings/swift/Ccapstone/include/capstone/ppc.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/ppc.h rename to bindings/swift/Ccapstone/include/capstone/ppc.h diff --git a/bindings/swift/CCapstone/include/capstone/riscv.h b/bindings/swift/Ccapstone/include/capstone/riscv.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/riscv.h rename to bindings/swift/Ccapstone/include/capstone/riscv.h diff --git a/bindings/swift/CCapstone/include/capstone/sh.h b/bindings/swift/Ccapstone/include/capstone/sh.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/sh.h rename to bindings/swift/Ccapstone/include/capstone/sh.h diff --git a/bindings/swift/CCapstone/include/capstone/sparc.h b/bindings/swift/Ccapstone/include/capstone/sparc.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/sparc.h rename to bindings/swift/Ccapstone/include/capstone/sparc.h diff --git a/bindings/swift/CCapstone/include/capstone/systemz.h b/bindings/swift/Ccapstone/include/capstone/systemz.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/systemz.h rename to bindings/swift/Ccapstone/include/capstone/systemz.h diff --git a/bindings/swift/CCapstone/include/capstone/systemz_compatibility.h b/bindings/swift/Ccapstone/include/capstone/systemz_compatibility.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/systemz_compatibility.h rename to bindings/swift/Ccapstone/include/capstone/systemz_compatibility.h diff --git a/bindings/swift/CCapstone/include/capstone/tms320c64x.h b/bindings/swift/Ccapstone/include/capstone/tms320c64x.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/tms320c64x.h rename to bindings/swift/Ccapstone/include/capstone/tms320c64x.h diff --git a/bindings/swift/CCapstone/include/capstone/tricore.h b/bindings/swift/Ccapstone/include/capstone/tricore.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/tricore.h rename to bindings/swift/Ccapstone/include/capstone/tricore.h diff --git a/bindings/swift/CCapstone/include/capstone/wasm.h b/bindings/swift/Ccapstone/include/capstone/wasm.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/wasm.h rename to bindings/swift/Ccapstone/include/capstone/wasm.h diff --git a/bindings/swift/CCapstone/include/capstone/x86.h b/bindings/swift/Ccapstone/include/capstone/x86.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/x86.h rename to bindings/swift/Ccapstone/include/capstone/x86.h diff --git a/bindings/swift/CCapstone/include/capstone/xcore.h b/bindings/swift/Ccapstone/include/capstone/xcore.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/xcore.h rename to bindings/swift/Ccapstone/include/capstone/xcore.h diff --git a/bindings/swift/CCapstone/include/capstone/xtensa.h b/bindings/swift/Ccapstone/include/capstone/xtensa.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/xtensa.h rename to bindings/swift/Ccapstone/include/capstone/xtensa.h diff --git a/bindings/swift/CCapstone/utils.c b/bindings/swift/Ccapstone/utils.c similarity index 100% rename from bindings/swift/CCapstone/utils.c rename to bindings/swift/Ccapstone/utils.c diff --git a/bindings/swift/CCapstone/utils.h b/bindings/swift/Ccapstone/utils.h similarity index 100% rename from bindings/swift/CCapstone/utils.h rename to bindings/swift/Ccapstone/utils.h From 28e581b7c56bb30242c085a49a22211651000a73 Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Tue, 16 Sep 2025 00:25:43 +0800 Subject: [PATCH 03/12] Add testing --- Package.swift | 33 ++ bindings/swift/Ccapstone/platform.h | 1 + .../CcapstoneTests/AdvancedAPITests.swift | 491 ++++++++++++++++ .../CcapstoneTests/ArchitectureTests.swift | 234 ++++++++ .../swift/CcapstoneTests/BasicTests.swift | 198 +++++++ .../CcapstoneTests/CompatibilityTests.swift | 364 ++++++++++++ .../swift/CcapstoneTests/CoreAPITests.swift | 214 +++++++ .../swift/CcapstoneTests/DetailTests.swift | 271 +++++++++ .../CcapstoneTests/DisassemblyTests.swift | 223 +++++++ .../swift/CcapstoneTests/MinimalTests.swift | 161 ++++++ .../CcapstoneTests/PerformanceTests.swift | 318 ++++++++++ .../swift/CcapstoneTests/SimpleTests.swift | 95 +++ .../SwiftIntegrationTests.swift | 542 ++++++++++++++++++ 13 files changed, 3145 insertions(+) create mode 120000 bindings/swift/Ccapstone/platform.h create mode 100644 bindings/swift/CcapstoneTests/AdvancedAPITests.swift create mode 100644 bindings/swift/CcapstoneTests/ArchitectureTests.swift create mode 100644 bindings/swift/CcapstoneTests/BasicTests.swift create mode 100644 bindings/swift/CcapstoneTests/CompatibilityTests.swift create mode 100644 bindings/swift/CcapstoneTests/CoreAPITests.swift create mode 100644 bindings/swift/CcapstoneTests/DetailTests.swift create mode 100644 bindings/swift/CcapstoneTests/DisassemblyTests.swift create mode 100644 bindings/swift/CcapstoneTests/MinimalTests.swift create mode 100644 bindings/swift/CcapstoneTests/PerformanceTests.swift create mode 100644 bindings/swift/CcapstoneTests/SimpleTests.swift create mode 100644 bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift diff --git a/Package.swift b/Package.swift index 70e418947b..fe40b0e317 100644 --- a/Package.swift +++ b/Package.swift @@ -15,6 +15,39 @@ let package = Package( .target( name: "Ccapstone", path: "bindings/swift/Ccapstone", + cSettings: [ + .headerSearchPath("../../../include"), + .define("CAPSTONE_USE_SYS_DYN_MEM"), + .define("CAPSTONE_HAS_ARM"), + .define("CAPSTONE_HAS_ARM64"), + .define("CAPSTONE_HAS_AARCH64"), + .define("CAPSTONE_HAS_MIPS"), + .define("CAPSTONE_HAS_X86"), + .define("CAPSTONE_HAS_POWERPC"), + .define("CAPSTONE_HAS_SPARC"), + .define("CAPSTONE_HAS_SYSTEMZ"), + .define("CAPSTONE_HAS_XCORE"), + .define("CAPSTONE_HAS_M68K"), + .define("CAPSTONE_HAS_TMS320C64X"), + .define("CAPSTONE_HAS_M680X"), + .define("CAPSTONE_HAS_EVM"), + .define("CAPSTONE_HAS_MOS65XX"), + .define("CAPSTONE_HAS_WASM"), + .define("CAPSTONE_HAS_BPF"), + .define("CAPSTONE_HAS_RISCV"), + .define("CAPSTONE_HAS_SH"), + .define("CAPSTONE_HAS_TRICORE"), + .define("CAPSTONE_HAS_ALPHA"), + .define("CAPSTONE_HAS_HPPA"), + .define("CAPSTONE_HAS_LOONGARCH"), + .define("CAPSTONE_HAS_XTENSA"), + .define("CAPSTONE_HAS_ARC"), + ], + ), + .testTarget( + name: "CcapstoneTests", + dependencies: ["Ccapstone"], + path: "bindings/swift/CcapstoneTests", ), ] ) diff --git a/bindings/swift/Ccapstone/platform.h b/bindings/swift/Ccapstone/platform.h new file mode 120000 index 0000000000..1349962ee5 --- /dev/null +++ b/bindings/swift/Ccapstone/platform.h @@ -0,0 +1 @@ +../../../include/platform.h \ No newline at end of file diff --git a/bindings/swift/CcapstoneTests/AdvancedAPITests.swift b/bindings/swift/CcapstoneTests/AdvancedAPITests.swift new file mode 100644 index 0000000000..01496ffd8c --- /dev/null +++ b/bindings/swift/CcapstoneTests/AdvancedAPITests.swift @@ -0,0 +1,491 @@ +import Foundation +import Testing +@testable import Ccapstone + +/// Advanced API usage tests for the Capstone Swift binding +/// These tests cover complex scenarios, advanced features, and integration patterns +@Suite("Advanced API Tests") +struct AdvancedAPITests { + + // Test data for various architectures + private static let x86Code64: [UInt8] = [0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00] + private static let armCode: [UInt8] = [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5] + private static let aarch64Code: [UInt8] = [0x21, 0x7c, 0x02, 0x9b, 0x21, 0x7c, 0x00, 0x53] + + @Test("Multiple engine instances") + func testMultipleEngines() async throws { + var x86Handle: csh = 0 + var armHandle: csh = 0 + + let x86Result = cs_open(CS_ARCH_X86, CS_MODE_64, &x86Handle) + let armResult = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &armHandle) + + // At least one should work in a complete implementation + var activeHandles: [(csh, String, [UInt8])] = [] + + if x86Result == CS_ERR_OK { + activeHandles.append((x86Handle, "X86-64", Self.x86Code64)) + } + + if armResult == CS_ERR_OK { + activeHandles.append((armHandle, "ARM", Self.armCode)) + } + + guard !activeHandles.isEmpty else { + print("⚠️ Skipping multiple engines test - no engines available") + return + } + + print("✓ Multiple engines test with \(activeHandles.count) active engines:") + + // Test disassembly with each active engine + for (handle, name, code) in activeHandles { + var insns: UnsafeMutablePointer? + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + print(" \(name): \(count) instructions") + + if count > 0 { + cs_free(insns, count) + } + + #expect(count >= 0, "\(name) engine should work without errors") + } + + // Clean up all handles + if x86Result == CS_ERR_OK { + _ = cs_close(&x86Handle) + } + if armResult == CS_ERR_OK { + _ = cs_close(&armHandle) + } + } + + @Test("Detail mode comprehensive testing") + func testDetailModeFeatures() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping detail mode test - cannot open X86 engine") + return + } + + defer { _ = cs_close(&handle) } + + // Enable detail mode + let detailResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + print("✓ Detail mode setting result: \(detailResult)") + + // Disassemble with detail mode + var insns: UnsafeMutablePointer? + let count = Self.x86Code64.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + guard count > 0 else { + print("⚠️ No instructions disassembled") + return + } + + print("✓ Detail mode disassembly: \(count) instructions") + + // Analyze first instruction in detail + let firstInsn = insns!.pointee + print(" First instruction:") + let mnemonic = withUnsafeBytes(of: firstInsn.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + let operands = withUnsafeBytes(of: firstInsn.op_str) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + print(" Mnemonic: \(mnemonic)") + print(" Operands: \(operands)") + print(" Address: 0x\(String(format: "%llx", firstInsn.address))") + print(" Size: \(firstInsn.size)") + print(" ID: \(firstInsn.id)") + + // Check if detail information is available + if let detail = firstInsn.detail { + print(" Detail available: Yes") + + // Access detail structure (this might fail if implementation is incomplete) + let detailStruct = detail.pointee + print(" Groups count: \(detailStruct.groups_count)") + print(" Reads registers: \(detailStruct.regs_read_count)") + print(" Writes registers: \(detailStruct.regs_write_count)") + + // Note: Architecture-specific details would require more complete implementation + } else { + print(" Detail available: No") + } + + // Test turning detail mode off + let detailOffResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_OFF.rawValue)) + print(" Detail mode off result: \(detailOffResult)") + } + + @Test("Skip data mode testing") + func testSkipDataMode() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping skip data mode test - cannot open X86 engine") + return + } + + defer { _ = cs_close(&handle) } + + // Create code with embedded data (invalid instructions) + let codeWithData: [UInt8] = [ + 0x90, // NOP + 0xFF, 0xFF, 0xFF, // Invalid data + 0x90, // NOP + 0x00, 0x00, // More invalid data + 0x90 // NOP + ] + + // Test normal mode (should stop at first invalid instruction) + var insns: UnsafeMutablePointer? + let normalCount = codeWithData.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if normalCount > 0 { + print("✓ Normal mode: \(normalCount) instructions") + cs_free(insns, normalCount) + } + + // Test skip data mode (if supported) + let skipDataResult = cs_option(handle, CS_OPT_SKIPDATA, size_t(CS_OPT_ON.rawValue)) + print(" Skip data mode setting: \(skipDataResult)") + + if skipDataResult == CS_ERR_OK { + let skipCount = codeWithData.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if skipCount > 0 { + print(" Skip data mode: \(skipCount) instructions") + + // Examine instructions to see if data was skipped + for i in 0..= normalCount, "Skip data mode should find at least as many instructions") + } + } + + @Test("Custom memory allocation patterns") + func testCustomMemoryPatterns() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping memory pattern test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + // Test malloc/free pattern + let insn = cs_malloc(handle) + guard let insn = insn else { + print("⚠️ cs_malloc returned null") + return + } + + print("✓ Custom memory allocation patterns:") + print(" cs_malloc succeeded: \(insn)") + + // Test iterator pattern with custom-allocated instruction + let testCode: [UInt8] = [0x90, 0x90, 0x90] // Multiple NOPs + var instructionCount = 0 + + testCode.withUnsafeBufferPointer { buffer in + var codePtr = buffer.baseAddress + var size = testCode.count + var address: UInt64 = 0x1000 + + while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { + instructionCount += 1 + let mnemonic = withUnsafeBytes(of: insn.pointee.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + print(" Instruction \(instructionCount): \(mnemonic)") + + // Safety break + if instructionCount >= 10 { + break + } + } + } + + cs_free(insn, 1) + print(" Iterator with custom allocation: \(instructionCount) instructions") + + // Test batch allocation pattern + var batchInsns: UnsafeMutablePointer? + let batchCount = testCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &batchInsns) + } + + if batchCount > 0 { + print(" Batch allocation: \(batchCount) instructions") + cs_free(batchInsns, batchCount) + } + + #expect(instructionCount == batchCount, "Iterator and batch methods should find same number of instructions") + } + + @Test("Option combinations and interactions") + func testOptionCombinations() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping option combinations test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + print("✓ Testing option combinations:") + + // Test various option combinations + let optionTests: [(cs_opt_type, size_t, String)] = [ + (CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue), "Detail ON"), + (CS_OPT_SKIPDATA, size_t(CS_OPT_ON.rawValue), "Skip Data ON"), + (CS_OPT_SYNTAX, size_t(CS_OPT_SYNTAX_DEFAULT.rawValue), "Default Syntax"), + (CS_OPT_DETAIL, size_t(CS_OPT_OFF.rawValue), "Detail OFF"), + (CS_OPT_SKIPDATA, size_t(CS_OPT_OFF.rawValue), "Skip Data OFF"), + ] + + for (option, value, description) in optionTests { + let result = cs_option(handle, option, value) + print(" \(description): \(result == CS_ERR_OK ? "✓" : "✗") (\(result))") + + // Test disassembly after each option change + var insns: UnsafeMutablePointer? + let count = Self.x86Code64.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if count > 0 { + cs_free(insns, count) + print(" Disassembly after option: \(count) instructions") + } + } + } + + @Test("Large instruction analysis") + func testLargeInstructionHandling() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping large instruction test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + // X86-64 instruction with large displacement/immediate (if we had real long instructions) + // For now, use what we have and test the structures + let _ = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + + var insns: UnsafeMutablePointer? + let count = Self.x86Code64.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + guard count > 0 else { + print("⚠️ No instructions for large instruction test") + return + } + + print("✓ Large instruction handling:") + + for i in 0.. 0 && mnemonicLen < CS_MNEMONIC_SIZE, "Mnemonic length should be reasonable") + #expect(operandLen < 512, "Operand string length should be reasonable") // Reasonable limit + + print(" Mnemonic length: \(mnemonicLen), Operand length: \(operandLen)") + } + } + + @Test("Thread safety simulation") + func testThreadSafetyPatterns() async throws { + // Note: Each task will create its own handle as handles should not be shared between threads + + let concurrentTasks = 5 + let operationsPerTask = 50 + + print("✓ Thread safety patterns test:") + + await withTaskGroup(of: (Int, Int, Bool).self) { group in + for taskId in 0..? + let count = Self.x86Code64.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if count > 0 { + // Access the first instruction to test memory safety + let firstInsn = insns!.pointee + let _ = withUnsafeBytes(of: firstInsn.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + cs_free(insns, count) + successfulOps += 1 + } + + let closeResult = cs_close(&handle) + if closeResult != CS_ERR_OK { + hadCriticalFailure = true + } + } + + return (taskId, successfulOps, hadCriticalFailure) + } + } + + var totalSuccessfulOps = 0 + var totalTasks = 0 + var hadAnyFailures = false + + for await (taskId, successfulOps, hadFailure) in group { + totalTasks += 1 + totalSuccessfulOps += successfulOps + hadAnyFailures = hadAnyFailures || hadFailure + + print(" Task \(taskId): \(successfulOps)/\(operationsPerTask) successful") + } + + let totalPossibleOps = concurrentTasks * operationsPerTask + print(" Overall: \(totalSuccessfulOps)/\(totalPossibleOps) successful operations") + print(" Critical failures: \(hadAnyFailures ? "Yes" : "No")") + + #expect(!hadAnyFailures, "Should not have critical failures in concurrent access") + } + } + + @Test("Error recovery and robustness") + func testErrorRecovery() async throws { + var handle: csh = 0 + + // Test recovery from various error conditions + print("✓ Error recovery and robustness:") + + // Invalid architecture followed by valid one + let invalidResult = cs_open(cs_arch(rawValue: 999), CS_MODE_32, &handle) + #expect(invalidResult != CS_ERR_OK, "Invalid architecture should fail") + #expect(handle == 0, "Handle should be 0 after failure") + + let validResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + if validResult == CS_ERR_OK { + print(" Recovery after invalid architecture: ✓") + + // Test invalid operations on valid handle + let invalidOption = cs_option(handle, cs_opt_type(rawValue: 999), 0) + print(" Invalid option on valid handle: \(invalidOption)") + + // Handle should still be usable after invalid operation + let errno = cs_errno(handle) + print(" Handle still usable after error: \(errno != CS_ERR_HANDLE ? "✓" : "✗")") + + // Test disassembly after error + var insns: UnsafeMutablePointer? + let count = Self.x86Code64.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if count > 0 { + cs_free(insns, count) + print(" Disassembly after error: ✓ (\(count) instructions)") + } else { + print(" Disassembly after error: ✗") + } + + _ = cs_close(&handle) + } else { + print(" Cannot test recovery - X86 engine not available") + } + + // Test multiple close attempts (should not crash) + // Note: After previous operations, handle should be 0 (invalid) + // Second close attempt on an already closed/invalid handle may be unsafe + print(" Skipping multiple close test to avoid potential memory issues") + #expect(Bool(true), "Multiple close test skipped for safety") + } +} diff --git a/bindings/swift/CcapstoneTests/ArchitectureTests.swift b/bindings/swift/CcapstoneTests/ArchitectureTests.swift new file mode 100644 index 0000000000..af9b6ebd54 --- /dev/null +++ b/bindings/swift/CcapstoneTests/ArchitectureTests.swift @@ -0,0 +1,234 @@ +import XCTest +@testable import Ccapstone + +final class ArchitectureTests: XCTestCase { + + // Test code samples for different architectures + private struct TestPlatform { + let arch: cs_arch + let mode: cs_mode + let code: [UInt8] + let comment: String + } + + private let platforms: [TestPlatform] = [ + TestPlatform( + arch: CS_ARCH_X86, + mode: CS_MODE_16, + code: [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00], + comment: "X86 16bit" + ), + TestPlatform( + arch: CS_ARCH_X86, + mode: CS_MODE_32, + code: [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00], + comment: "X86 32bit" + ), + TestPlatform( + arch: CS_ARCH_X86, + mode: CS_MODE_64, + code: [0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00], + comment: "X86 64bit" + ), + TestPlatform( + arch: CS_ARCH_ARM, + mode: CS_MODE_ARM, + code: [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x83, 0x22, 0xe5], + comment: "ARM" + ), + TestPlatform( + arch: CS_ARCH_ARM, + mode: CS_MODE_THUMB, + code: [0x70, 0x47, 0xeb, 0x46, 0x83, 0xb0, 0xc9, 0x68], + comment: "Thumb" + ), + TestPlatform( + arch: CS_ARCH_AARCH64, + mode: CS_MODE_ARM, + code: [0x21, 0x7c, 0x02, 0x9b, 0x21, 0x7c, 0x00, 0x53, 0x00, 0x40, 0x21, 0x4b, 0xe1, 0x0b, 0x40, 0xb9], + comment: "AArch64" + ), + TestPlatform( + arch: CS_ARCH_MIPS, + mode: cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), + code: [0x0C, 0x10, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0c, 0x8f, 0xa2, 0x00, 0x00, 0x34, 0x21, 0x34, 0x56], + comment: "MIPS32 Big-endian" + ), + TestPlatform( + arch: CS_ARCH_MIPS, + mode: cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), + code: [0x56, 0x34, 0x21, 0x34, 0xc2, 0x17, 0x01, 0x00], + comment: "MIPS64 Little-endian" + ), + TestPlatform( + arch: CS_ARCH_PPC, + mode: CS_MODE_BIG_ENDIAN, + code: [0x80, 0x20, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x10, 0x43, 0x23, 0x0e, 0xd0, 0x44, 0x00, 0x80, 0x4c, 0x43, 0x22, 0x02], + comment: "PowerPC" + ), + TestPlatform( + arch: CS_ARCH_SPARC, + mode: CS_MODE_BIG_ENDIAN, + code: [0x80, 0xa0, 0x40, 0x02, 0x85, 0xc2, 0x60, 0x08, 0x85, 0xe8, 0x20, 0x01, 0x81, 0xe8, 0x00, 0x00, 0x90, 0x10, 0x20, 0x01], + comment: "Sparc" + ), + TestPlatform( + arch: CS_ARCH_SYSTEMZ, + mode: CS_MODE_BIG_ENDIAN, + code: [0xed, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x5a, 0x0f, 0x1f, 0xff, 0xc2, 0x09, 0x80, 0x00, 0x00, 0x00, 0x07, 0xf7], + comment: "SystemZ" + ) + ] + + func testAllArchitectures() { + for platform in platforms { + testArchitecture(platform) + } + } + + func testX86Syntax() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + // Test Intel syntax (default) + let code: [UInt8] = [0x8d, 0x4c, 0x32, 0x08] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertGreaterThan(count, 0) + if count > 0 && insns != nil { + let insn = insns![0] + let opStr = String(cString: withUnsafeBytes(of: insn.op_str) { $0.bindMemory(to: CChar.self).baseAddress! }) + print("Intel syntax: \(opStr)") + cs_free(insns, count) + } + + // Test AT&T syntax + let attResult = cs_option(handle, CS_OPT_SYNTAX, size_t(CS_OPT_SYNTAX_ATT.rawValue)) + if attResult == CS_ERR_OK { + let attCount = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if attCount > 0 && insns != nil { + let insn = insns![0] + let opStr = String(cString: withUnsafeBytes(of: insn.op_str) { $0.bindMemory(to: CChar.self).baseAddress! }) + print("AT&T syntax: \(opStr)") + cs_free(insns, attCount) + } + } + + _ = cs_close(&handle) + } + + func testMIPSModes() { + let mipsCodes: [(cs_mode, [UInt8], String)] = [ + (cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), [0x0C, 0x10, 0x00, 0x97], "MIPS32 BE"), + (cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), [0x97, 0x00, 0x10, 0x0C], "MIPS32 LE"), + (cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_BIG_ENDIAN.rawValue), [0x0C, 0x10, 0x00, 0x97], "MIPS64 BE"), + (cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), [0x97, 0x00, 0x10, 0x0C], "MIPS64 LE") + ] + + for (mode, code, comment) in mipsCodes { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_MIPS, mode, &handle) + XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + + var insns: UnsafeMutablePointer? + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertGreaterThanOrEqual(count, 0, "Disassembly failed for \(comment)") + + if count > 0 && insns != nil { + let insn = insns![0] + let mnemonic = String(cString: withUnsafeBytes(of: insn.mnemonic) { $0.bindMemory(to: CChar.self).baseAddress! }) + print("\(comment): \(mnemonic)") + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + } + + func testARMModes() { + let armTests: [(cs_mode, [UInt8], String)] = [ + (CS_MODE_ARM, [0x04, 0xe0, 0x2d, 0xe5], "ARM mode"), + (CS_MODE_THUMB, [0x70, 0x47], "Thumb mode"), + (cs_mode(CS_MODE_THUMB.rawValue | CS_MODE_MCLASS.rawValue), [0x70, 0x47], "Thumb M-Class") + ] + + for (mode, code, comment) in armTests { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_ARM, mode, &handle) + XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + + var insns: UnsafeMutablePointer? + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertGreaterThanOrEqual(count, 0, "Disassembly failed for \(comment)") + + if count > 0 && insns != nil { + let insn = insns![0] + let mnemonic = String(cString: withUnsafeBytes(of: insn.mnemonic) { $0.bindMemory(to: CChar.self).baseAddress! }) + print("\(comment): \(mnemonic)") + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + } + + private func testArchitecture(_ platform: TestPlatform) { + var handle: csh = 0 + var insns: UnsafeMutablePointer? + + let openResult = cs_open(platform.arch, platform.mode, &handle) + XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(platform.comment)") + + let count = platform.code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertGreaterThan(count, 0, "No instructions disassembled for \(platform.comment)") + + if count > 0 && insns != nil { + print("\n\(platform.comment):") + for i in 0..) -> Int { + var offset = 0 + for i in 0.. 0, "Major version should be positive") + #expect(minor >= 0, "Minor version should be non-negative") + #expect(version > 0, "Version should be positive") + #expect(version == UInt32((major << 8) | minor), "Version should match expected format") + + print("✓ Capstone version: \(major).\(minor) (0x\(String(format: "%04x", version)))") + } + + @Test("Engine open and close operations") + func testOpenClose() async throws { + var handle: csh = 0 + + let result = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + #expect(result == CS_ERR_OK, "Engine should open successfully") + #expect(handle != 0, "Handle should be non-zero after successful open") + + let closeResult = cs_close(&handle) + #expect(closeResult == CS_ERR_OK, "Engine should close successfully") + #expect(handle == 0, "Handle should be zero after close") + + print("✓ Engine open/close: Success") + } + + @Test("Invalid architecture handling") + func testInvalidArch() async throws { + var handle: csh = 0 + + let result = cs_open(cs_arch(1000), CS_MODE_32, &handle) + #expect(result != CS_ERR_OK, "Invalid architecture should fail") + #expect(handle == 0, "Handle should remain zero for invalid architecture") + + print("✓ Invalid architecture handled correctly") + } + + @Test("Error message strings") + func testStrerror() async throws { + let errorMsg = cs_strerror(CS_ERR_OK) + #expect(errorMsg != nil, "Error message should not be nil") + + let okString = String(cString: errorMsg!) + #expect(!okString.isEmpty, "Error message string should not be empty") + + let invalidMsg = cs_strerror(CS_ERR_ARCH) + #expect(invalidMsg != nil, "Error message for CS_ERR_ARCH should not be nil") + + let invalidString = String(cString: invalidMsg!) + #expect(!invalidString.isEmpty, "Error message string should not be empty") + #expect(okString != invalidString, "Different error codes should have different messages") + + print("✓ Error messages: '\(okString)' vs '\(invalidString)'") + } + + @Test("Error number retrieval") + func testErrno() async throws { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + if openResult == CS_ERR_OK { + let errno = cs_errno(handle) + #expect(errno == CS_ERR_OK, "Error number should be CS_ERR_OK for successful operation") + _ = cs_close(&handle) + print("✓ Error number retrieval: Success") + } else { + print("⚠️ Skipping errno test - cannot open X86 engine") + } + } + + @Test("Option setting") + func testOption() async throws { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + if openResult == CS_ERR_OK { + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + // Note: Option result may vary depending on implementation completeness + // We mainly test that it doesn't crash + + _ = cs_close(&handle) + print("✓ Option setting: Result \(optResult)") + } else { + print("⚠️ Skipping option test - cannot open X86 engine") + } + } + + @Test("Basic disassembly functionality") + func testBasicDisassembly() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping basic disassembly test - cannot open X86 engine") + return + } + + defer { _ = cs_close(&handle) } + + // Simple x86 32-bit code: lea ecx, [edx+esi+8]; add eax, ebx + let code: [UInt8] = [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8] + + var insns: UnsafeMutablePointer? + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + #expect(count >= 0, "Disassembly should not fail catastrophically") + + if count > 0 { + let firstInsn = insns!.pointee + let mnemonic = withUnsafeBytes(of: firstInsn.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + let operands = withUnsafeBytes(of: firstInsn.op_str) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + + #expect(!mnemonic.isEmpty, "Mnemonic should not be empty") + #expect(firstInsn.size > 0, "Instruction size should be positive") + #expect(firstInsn.address == 0x1000, "Instruction address should match input") + + print("✓ Basic disassembly: \(count) instructions") + print(" First: \(mnemonic) \(operands) (size: \(firstInsn.size))") + } else { + print("⚠️ Basic disassembly returned 0 instructions (implementation may be incomplete)") + } + } + + @Test("Iterator API functionality") + func testIteratorAPI() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping iterator API test - cannot open X86 engine") + return + } + + defer { _ = cs_close(&handle) } + + let insn = cs_malloc(handle) + guard let insn = insn else { + print("⚠️ cs_malloc returned nil") + return + } + + defer { cs_free(insn, 1) } + + let code: [UInt8] = [0x90, 0x90, 0x90] // Three NOPs + var instructionCount = 0 + + code.withUnsafeBufferPointer { buffer in + var codePtr = buffer.baseAddress + var size = code.count + var address: UInt64 = 0x1000 + + while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { + instructionCount += 1 + let mnemonic = withUnsafeBytes(of: insn.pointee.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + + #expect(!mnemonic.isEmpty, "Mnemonic should not be empty") + #expect(insn.pointee.size > 0, "Instruction size should be positive") + + // Safety break to avoid infinite loops + if instructionCount > 10 { + break + } + } + } + + print("✓ Iterator API: \(instructionCount) instructions processed") + #expect(instructionCount >= 0, "Iterator should handle instructions without crashing") + } +} diff --git a/bindings/swift/CcapstoneTests/CompatibilityTests.swift b/bindings/swift/CcapstoneTests/CompatibilityTests.swift new file mode 100644 index 0000000000..a6b39a86c6 --- /dev/null +++ b/bindings/swift/CcapstoneTests/CompatibilityTests.swift @@ -0,0 +1,364 @@ +import Foundation +import Testing +@testable import Ccapstone + +/// Cross-platform compatibility and edge case tests for the Capstone Swift binding +/// These tests verify behavior across different platforms and unusual conditions +@Suite("Compatibility Tests") +struct CompatibilityTests { + + // Test data for various scenarios + private static let emptyCode: [UInt8] = [] + private static let singleByteCode: [UInt8] = [0x90] // NOP instruction + private static let invalidCode: [UInt8] = [0xFF, 0xFF, 0xFF, 0xFF] + private static let mixedValidInvalidCode: [UInt8] = [0x90, 0xFF, 0xFF, 0x90, 0xFF] + + @Test("Platform-specific enum values consistency") + func testEnumValueConsistency() async throws { + // Test that enum values are consistent across platforms + let enumTests: [(String, UInt32, UInt32)] = [ + ("CS_ERR_OK", CS_ERR_OK.rawValue, 0), + ("CS_ERR_MEM", CS_ERR_MEM.rawValue, 1), + ("CS_ERR_ARCH", CS_ERR_ARCH.rawValue, 2), + ("CS_ERR_HANDLE", CS_ERR_HANDLE.rawValue, 3), + ("CS_ERR_CSH", CS_ERR_CSH.rawValue, 4), + ("CS_ERR_MODE", CS_ERR_MODE.rawValue, 5), + ("CS_ERR_OPTION", CS_ERR_OPTION.rawValue, 6), + ("CS_ERR_DETAIL", CS_ERR_DETAIL.rawValue, 7), + ("CS_ERR_MEMSETUP", CS_ERR_MEMSETUP.rawValue, 8), + ("CS_ERR_VERSION", CS_ERR_VERSION.rawValue, 9), + + ("CS_ARCH_ARM", CS_ARCH_ARM.rawValue, 0), + ("CS_ARCH_AARCH64", CS_ARCH_AARCH64.rawValue, 1), + ("CS_ARCH_MIPS", CS_ARCH_MIPS.rawValue, 3), + ("CS_ARCH_X86", CS_ARCH_X86.rawValue, 4), + ("CS_ARCH_PPC", CS_ARCH_PPC.rawValue, 5), + + ("CS_MODE_LITTLE_ENDIAN", CS_MODE_LITTLE_ENDIAN.rawValue, 0), + ("CS_MODE_ARM", CS_MODE_ARM.rawValue, 0), + ("CS_MODE_16", CS_MODE_16.rawValue, 1 << 1), + ("CS_MODE_32", CS_MODE_32.rawValue, 1 << 2), + ("CS_MODE_64", CS_MODE_64.rawValue, 1 << 3), + ] + + print("✓ Testing enum value consistency:") + for (name, actual, expected) in enumTests { + #expect(actual == expected, "\(name) should be \(expected), got \(actual)") + print(" \(name): \(actual) ✓") + } + } + + @Test("Pointer size and alignment compatibility") + func testPointerCompatibility() async throws { + // Test that pointer sizes and alignments are reasonable + let insnSize = MemoryLayout.size + let insnAlignment = MemoryLayout.alignment + let detailSize = MemoryLayout.size + let detailAlignment = MemoryLayout.alignment + let cshSize = MemoryLayout.size + + print("✓ Platform-specific sizes and alignments:") + print(" cs_insn: \(insnSize) bytes, alignment: \(insnAlignment)") + print(" cs_detail: \(detailSize) bytes, alignment: \(detailAlignment)") + print(" csh (handle): \(cshSize) bytes") + + // Basic sanity checks + #expect(insnSize > 0 && insnSize < 1024, "cs_insn size should be reasonable") + #expect(detailSize > 0 && detailSize < 4096, "cs_detail size should be reasonable") + #expect(cshSize > 0 && cshSize <= 8, "csh should be pointer-sized") + + // Alignment should be power of 2 and reasonable + #expect(insnAlignment > 0 && (insnAlignment & (insnAlignment - 1)) == 0, "cs_insn alignment should be power of 2") + #expect(detailAlignment > 0 && (detailAlignment & (detailAlignment - 1)) == 0, "cs_detail alignment should be power of 2") + } + + @Test("Empty and invalid code handling") + func testEdgeCaseCodeHandling() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping edge case tests - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + // Test empty code + var insns: UnsafeMutablePointer? + let emptyCount = Self.emptyCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + #expect(emptyCount == 0, "Empty code should produce 0 instructions") + print("✓ Empty code handling: \(emptyCount) instructions") + + // Test single byte + let singleCount = Self.singleByteCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if singleCount > 0 { + cs_free(insns, singleCount) + } + + print("✓ Single byte code: \(singleCount) instructions") + + // Test invalid code + let invalidCount = Self.invalidCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if invalidCount > 0 { + cs_free(insns, invalidCount) + } + + print("✓ Invalid code handling: \(invalidCount) instructions") + + // All tests should complete without crashing + #expect(Bool(true), "All edge cases should be handled gracefully") + } + + @Test("Maximum values and boundaries") + func testBoundaryValues() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping boundary tests - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + // Test with maximum address value + let maxAddress: UInt64 = UInt64.max + var insns: UnsafeMutablePointer? + let maxAddrCount = Self.singleByteCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, maxAddress, 0, &insns) + } + + if maxAddrCount > 0 { + let instruction = insns!.pointee + print("✓ Maximum address test: instruction at 0x\(String(format: "%llx", instruction.address))") + cs_free(insns, maxAddrCount) + } + + // Test with zero address + let zeroAddrCount = Self.singleByteCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0, 0, &insns) + } + + if zeroAddrCount > 0 { + cs_free(insns, zeroAddrCount) + } + + print("✓ Zero address test: \(zeroAddrCount) instructions") + + // Test with maximum count parameter (should be ignored for cs_disasm with count=0) + let maxCountTest = Self.singleByteCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, size_t.max, &insns) + } + + if maxCountTest > 0 { + cs_free(insns, maxCountTest) + } + + print("✓ Maximum count parameter test: \(maxCountTest) instructions") + } + + @Test("String handling and encoding") + func testStringHandling() async throws { + // Test error message strings for proper encoding + let testErrors: [cs_err] = [ + CS_ERR_OK, CS_ERR_MEM, CS_ERR_ARCH, CS_ERR_HANDLE, + CS_ERR_CSH, CS_ERR_MODE, CS_ERR_OPTION, CS_ERR_DETAIL + ] + + print("✓ Testing string encoding and validity:") + for errorCode in testErrors { + let message = cs_strerror(errorCode) + #expect(message != nil, "Error message should not be nil") + + if let message = message { + let errorString = String(cString: message) + #expect(!errorString.isEmpty, "Error string should not be empty") + #expect(errorString.utf8.count > 0, "String should have valid UTF-8 encoding") + + // Check for reasonable string length (not too short or suspiciously long) + #expect(errorString.count >= 2 && errorString.count <= 100, "Error message should have reasonable length") + + print(" \(errorCode.rawValue): '\(errorString)' (\(errorString.count) chars)") + } + } + } + + @Test("Iterator API edge cases") + func testIteratorEdgeCases() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping iterator edge case tests - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + let insn = cs_malloc(handle) + guard let insn = insn else { + print("⚠️ Cannot allocate instruction structure") + return + } + + defer { cs_free(insn, 1) } + + // Test iterator with empty code + var result = Self.emptyCode.withUnsafeBufferPointer { buffer -> Bool in + var codePtr = buffer.baseAddress + var size = Self.emptyCode.count + var address: UInt64 = 0x1000 + + return cs_disasm_iter(handle, &codePtr, &size, &address, insn) + } + + #expect(result == false, "Iterator should return false for empty code") + print("✓ Iterator empty code test: \(result)") + + // Test iterator with single valid instruction + result = Self.singleByteCode.withUnsafeBufferPointer { buffer -> Bool in + var codePtr = buffer.baseAddress + var size = Self.singleByteCode.count + var address: UInt64 = 0x1000 + + let firstResult = cs_disasm_iter(handle, &codePtr, &size, &address, insn) + if firstResult { + let mnemonic = withUnsafeBytes(of: insn.pointee.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + print(" First instruction: \(mnemonic)") + // Try to get second instruction (should fail) + let secondResult = cs_disasm_iter(handle, &codePtr, &size, &address, insn) + return secondResult + } + return firstResult + } + + print("✓ Iterator single instruction test: second call returned \(result)") + + // Test iterator with mixed valid/invalid code + var instructionCount = 0 + Self.mixedValidInvalidCode.withUnsafeBufferPointer { buffer in + var codePtr = buffer.baseAddress + var size = Self.mixedValidInvalidCode.count + var address: UInt64 = 0x1000 + + while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { + instructionCount += 1 + if instructionCount > 10 { // Safety break to avoid infinite loops + break + } + } + } + + print("✓ Iterator mixed code test: \(instructionCount) instructions found") + #expect(instructionCount >= 0, "Should handle mixed code gracefully") + } + + @Test("Version consistency across calls") + func testVersionStability() async throws { + // Call version function multiple times and ensure consistency + let iterations = 100 + var versions: [UInt32] = [] + var majors: [Int32] = [] + var minors: [Int32] = [] + + for _ in 0..= 0, "Should handle architecture queries without crashing") + } + + @Test("Memory safety with null pointers") + func testNullPointerSafety() async throws { + // cs_strerror should work with any error code + for errorCode in 0..<20 { + let message = cs_strerror(cs_err(rawValue: UInt32(errorCode))) + #expect(message != nil, "cs_strerror should return non-null for any error code") + } + + // cs_version with null parameters + let versionOnly = cs_version(nil, nil) + #expect(versionOnly > 0, "cs_version should work with null parameters") + print("✓ cs_version with null parameters: \(versionOnly)") + + // Operations on invalid handles should return errors, not crash + let errno = cs_errno(0) + #expect(errno != CS_ERR_OK, "cs_errno on invalid handle should return error") + + let optResult = cs_option(0, CS_OPT_DETAIL, 1) + #expect(optResult != CS_ERR_OK, "cs_option on invalid handle should return error") + + print("✓ All null pointer and invalid handle tests completed safely") + } +} diff --git a/bindings/swift/CcapstoneTests/CoreAPITests.swift b/bindings/swift/CcapstoneTests/CoreAPITests.swift new file mode 100644 index 0000000000..7cdedf7c88 --- /dev/null +++ b/bindings/swift/CcapstoneTests/CoreAPITests.swift @@ -0,0 +1,214 @@ +import Foundation +import Testing +@testable import Ccapstone + +/// Core API tests that focus on the C interface without architecture-specific details +/// These tests verify the basic Capstone C API functionality exposed through Swift +@Suite("Core API Tests") +struct CoreAPITests { + + @Test("Version API comprehensive testing") + func testVersionAPI() async throws { + var major: Int32 = 0 + var minor: Int32 = 0 + + let version = cs_version(&major, &minor) + + #expect(major > 0, "Major version should be greater than 0") + #expect(minor >= 0, "Minor version should be greater than or equal to 0") + #expect(version > 0, "Version should be greater than 0") + #expect(version == UInt32((major << 8) | minor), "Version format should be correct") + + print("✓ Capstone version: \(major).\(minor) (0x\(String(format: "%04x", version)))") + } + + @Test("Basic enum values validation") + func testBasicEnumValues() async throws { + // Test error code enum values + #expect(CS_ERR_OK.rawValue == 0, "CS_ERR_OK should be 0") + #expect(CS_ERR_ARCH.rawValue != 0, "CS_ERR_ARCH should not be 0") + #expect(CS_ERR_HANDLE.rawValue != 0, "CS_ERR_HANDLE should not be 0") + #expect(CS_ERR_MEM.rawValue != 0, "CS_ERR_MEM should not be 0") + + // Test architecture enum values + #expect(CS_ARCH_ARM.rawValue == 0, "CS_ARCH_ARM should be 0") + #expect(CS_ARCH_AARCH64.rawValue == 1, "CS_ARCH_AARCH64 should be 1") + #expect(CS_ARCH_X86.rawValue == 4, "CS_ARCH_X86 should be 4") + + // Test mode enum values + #expect(CS_MODE_LITTLE_ENDIAN.rawValue == 0, "CS_MODE_LITTLE_ENDIAN should be 0") + #expect(CS_MODE_16.rawValue == 1 << 1, "CS_MODE_16 should be 2") + #expect(CS_MODE_32.rawValue == 1 << 2, "CS_MODE_32 should be 4") + #expect(CS_MODE_64.rawValue == 1 << 3, "CS_MODE_64 should be 8") + + // Test option enum values + #expect(CS_OPT_INVALID.rawValue == 0, "CS_OPT_INVALID should be 0") + #expect(CS_OPT_DETAIL.rawValue != 0, "CS_OPT_DETAIL should not be 0") + + print("✓ All enum values are correctly defined") + } + + @Test("Error message validation") + func testErrorMessages() async throws { + let testErrors: [(cs_err, String)] = [ + (CS_ERR_OK, "Success"), + (CS_ERR_MEM, "Memory error"), + (CS_ERR_ARCH, "Architecture error"), + (CS_ERR_HANDLE, "Handle error"), + (CS_ERR_CSH, "CSH error"), + (CS_ERR_MODE, "Mode error"), + (CS_ERR_OPTION, "Option error"), + (CS_ERR_DETAIL, "Detail error"), + (CS_ERR_MEMSETUP, "Memory setup error"), + (CS_ERR_VERSION, "Version error") + ] + + print("✓ Testing error messages:") + for (errorCode, description) in testErrors { + let message = cs_strerror(errorCode) + #expect(message != nil, "Error message for \(description) should not be nil") + + if let message = message { + let errorString = String(cString: message) + #expect(!errorString.isEmpty, "Error message for \(description) should not be empty") + print(" \(errorCode.rawValue) (\(description)): \(errorString)") + } + } + } + + @Test("Basic handle operations") + func testBasicHandleOperations() async throws { + var handle: csh = 0 + + // Test invalid architecture + let invalidResult = cs_open(cs_arch(rawValue: 999), CS_MODE_32, &handle) + #expect(invalidResult != CS_ERR_OK, "Invalid architecture should return error") + #expect(handle == 0, "Handle should be 0 for invalid architecture") + + // Test valid operations (if possible) + let validResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + if validResult == CS_ERR_OK { + print("✓ Successfully opened X86 32-bit engine, handle: \(handle)") + #expect(handle != 0, "Handle should not be 0 for valid operations") + + // Test option setting + let _ = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + // Success or failure is acceptable, depends on implementation completeness + + // Test error number retrieval + let _ = cs_errno(handle) + // errno value depends on previous operation results + + // Test close + let closeResult = cs_close(&handle) + #expect(closeResult == CS_ERR_OK, "Handle close should succeed") + #expect(handle == 0, "Handle should be 0 after close") + } else { + let errorMsg = cs_strerror(validResult) + let errorString = errorMsg != nil ? String(cString: errorMsg!) : "Unknown error" + print("⚠️ Unable to open X86 engine: \(errorString)") + print(" This is expected because Swift binding is incomplete") + } + } + + @Test("Invalid operations handling") + func testInvalidOperations() async throws { + // Test operations on invalid handle + let errno = cs_errno(0) + #expect(errno != CS_ERR_OK, "cs_errno on invalid handle should return error") + + let optResult = cs_option(0, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + #expect(optResult != CS_ERR_OK, "cs_option on invalid handle should return error") + + // Test double close - using zero handle which should be safe + var zeroHandle: csh = 0 + let doubleClose = cs_close(&zeroHandle) + #expect(doubleClose != CS_ERR_OK, "Closing zero handle should return error") + + print("✓ Invalid operations correctly return errors") + } + + @Test("Constants and structure sizes") + func testConstantsAndSizes() async throws { + // Test important constant values + #expect(CS_MNEMONIC_SIZE == 32, "CS_MNEMONIC_SIZE should be 32") + + // Test structure sizes + let insnSize = MemoryLayout.size + let detailSize = MemoryLayout.size + + #expect(insnSize > 0, "cs_insn structure size should be greater than 0") + #expect(detailSize > 0, "cs_detail structure size should be greater than 0") + + print("✓ Constants and structure sizes:") + print(" CS_MNEMONIC_SIZE: \(CS_MNEMONIC_SIZE)") + print(" cs_insn size: \(insnSize) bytes") + print(" cs_detail size: \(detailSize) bytes") + + // cs_insn should contain mnemonic, operand strings, etc., should have reasonable size + #expect(insnSize > 32, "cs_insn should be at least 32 bytes") + + // cs_detail contains architecture-specific unions, should be larger + #expect(detailSize > 100, "cs_detail should be at least 100 bytes") + } + + @Test("Function availability check") + func testFunctionAvailability() async throws { + // Verify that all core C functions can be referenced (can be linked) + let functions: [String: Any] = [ + "cs_version": cs_version, + "cs_open": cs_open, + "cs_close": cs_close, + "cs_disasm": cs_disasm, + "cs_malloc": cs_malloc, + "cs_disasm_iter": cs_disasm_iter, + "cs_free": cs_free, + "cs_option": cs_option, + "cs_errno": cs_errno, + "cs_strerror": cs_strerror, + ] + + print("✓ Available C API functions:") + for (name, _) in functions.sorted(by: { $0.key < $1.key }) { + print(" - \(name)") + } + + #expect(functions.count == 10, "Should have 10 basic functions available") + } + + @Test("Version consistency validation") + func testVersionConsistency() async throws { + // Test version function consistency + var major1: Int32 = 0, minor1: Int32 = 0 + var major2: Int32 = 0, minor2: Int32 = 0 + + let version1 = cs_version(&major1, &minor1) + let version2 = cs_version(&major2, &minor2) + + #expect(version1 == version2, "Version should remain consistent") + #expect(major1 == major2, "Major version should remain consistent") + #expect(minor1 == minor2, "Minor version should remain consistent") + + // Test correctness of version calculation + let calculatedVersion = UInt32((major1 << 8) | minor1) + #expect(version1 == calculatedVersion, "Version calculation should be correct") + + print("✓ Version consistency verification passed") + } + + @Test("Edge cases handling") + func testEdgeCases() async throws { + // Test edge cases + + // Test invalid error codes + let invalidError = cs_err(rawValue: 9999) + let invalidMsg = cs_strerror(invalidError) + #expect(invalidMsg != nil, "Invalid error codes should also have messages") + + // Test version with nil parameters + let versionOnly = cs_version(nil, nil) + #expect(versionOnly > 0, "Getting version only should work") + + print("✓ Edge cases handled correctly") + } +} diff --git a/bindings/swift/CcapstoneTests/DetailTests.swift b/bindings/swift/CcapstoneTests/DetailTests.swift new file mode 100644 index 0000000000..96f80a7ea2 --- /dev/null +++ b/bindings/swift/CcapstoneTests/DetailTests.swift @@ -0,0 +1,271 @@ +import XCTest +@testable import Ccapstone + +final class DetailTests: XCTestCase { + func testX86Detail() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + // mov rax, qword ptr [rip + 0x13b8] + let code: [UInt8] = [0x48, 0x8B, 0x05, 0xB8, 0x13, 0x00, 0x00] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertEqual(count, 1) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + let insn = insns![0] + XCTAssertNotNil(insn.detail) + + if insn.detail != nil { + let detail = insn.detail!.pointee + let x86Detail = detail.x86 + + // Check basic detail properties + XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) + XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) + XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + + // Check X86-specific details + XCTAssertGreaterThan(x86Detail.op_count, 0) + XCTAssertLessThanOrEqual(x86Detail.op_count, 8) + + print("X86 Detail:") + print(" Instruction ID: \(insn.id)") + print(" Groups count: \(detail.groups_count)") + print(" Regs read count: \(detail.regs_read_count)") + print(" Regs write count: \(detail.regs_write_count)") + print(" Operands count: \(x86Detail.op_count)") + + // Print operand information + let operands = withUnsafeBytes(of: x86Detail.operands) { bytes in + return bytes.bindMemory(to: cs_x86_op.self) + } + + for i in 0 ..< min(Int(x86Detail.op_count), 8) { + let operand = operands[i] + print(" Operand \(i): type=\(operand.type.rawValue), size=\(operand.size)") + } + } + + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + + func testARMDetail() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + // str lr, [sp, #-4]! + let code: [UInt8] = [0x04, 0xE0, 0x2D, 0xE5] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertEqual(count, 1) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + let insn = insns![0] + XCTAssertNotNil(insn.detail) + + if insn.detail != nil { + let detail = insn.detail!.pointee + let armDetail = detail.arm + + // Check basic detail properties + XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) + XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) + XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + + // Check ARM-specific details + XCTAssertGreaterThan(armDetail.op_count, 0) + XCTAssertLessThanOrEqual(armDetail.op_count, 36) + + print("ARM Detail:") + print(" Instruction ID: \(insn.id)") + print(" Groups count: \(detail.groups_count)") + print(" Regs read count: \(detail.regs_read_count)") + print(" Regs write count: \(detail.regs_write_count)") + print(" Operands count: \(armDetail.op_count)") + print(" CC: \(armDetail.cc.rawValue)") + print(" Update flags: \(armDetail.update_flags)") + // print(" Writeback: \(armDetail.writeback)") // Not available in this struct + } + + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + + func testAArch64Detail() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_AARCH64, CS_MODE_ARM, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + // add x1, x1, x2 + let code: [UInt8] = [0x21, 0x00, 0x02, 0x8B] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertEqual(count, 1) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + let insn = insns![0] + XCTAssertNotNil(insn.detail) + + if insn.detail != nil { + let detail = insn.detail!.pointee + let aarch64Detail = detail.aarch64 + + // Check basic detail properties + XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) + XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) + XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + + // Check AArch64-specific details + XCTAssertGreaterThan(aarch64Detail.op_count, 0) + XCTAssertLessThanOrEqual(aarch64Detail.op_count, 8) + + print("AArch64 Detail:") + print(" Instruction ID: \(insn.id)") + print(" Groups count: \(detail.groups_count)") + print(" Regs read count: \(detail.regs_read_count)") + print(" Regs write count: \(detail.regs_write_count)") + print(" Operands count: \(aarch64Detail.op_count)") + print(" CC: \(aarch64Detail.cc.rawValue)") + print(" Update flags: \(aarch64Detail.update_flags)") + // print(" Writeback: \(aarch64Detail.writeback)") // Not available in this struct + } + + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + + func testMIPSDetail() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_MIPS, cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + // jal 0x97000c + let code: [UInt8] = [0x0C, 0x10, 0x00, 0x97] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertEqual(count, 1) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + let insn = insns![0] + XCTAssertNotNil(insn.detail) + + if insn.detail != nil { + let detail = insn.detail!.pointee + let mipsDetail = detail.mips + + // Check basic detail properties + XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) + XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) + XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + + // Check MIPS-specific details + XCTAssertGreaterThan(mipsDetail.op_count, 0) + XCTAssertLessThanOrEqual(mipsDetail.op_count, 4) + + print("MIPS Detail:") + print(" Instruction ID: \(insn.id)") + print(" Groups count: \(detail.groups_count)") + print(" Regs read count: \(detail.regs_read_count)") + print(" Regs write count: \(detail.regs_write_count)") + print(" Operands count: \(mipsDetail.op_count)") + } + + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + + func testInstructionGroups() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + // ret instruction + let code: [UInt8] = [0xC3] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertEqual(count, 1) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + let insn = insns![0] + XCTAssertNotNil(insn.detail) + + if insn.detail != nil { + let detail = insn.detail!.pointee + + print("Instruction groups:") + print(" Groups count: \(detail.groups_count)") + + // Check if this instruction belongs to some groups + let groups = withUnsafeBytes(of: detail.groups) { bytes in + return bytes.bindMemory(to: UInt8.self) + } + + for i in 0 ..< min(Int(detail.groups_count), 16) { + let group = groups[i] + print(" Group \(i): \(group)") + } + } + + cs_free(insns, count) + } + + _ = cs_close(&handle) + } +} diff --git a/bindings/swift/CcapstoneTests/DisassemblyTests.swift b/bindings/swift/CcapstoneTests/DisassemblyTests.swift new file mode 100644 index 0000000000..918b11c229 --- /dev/null +++ b/bindings/swift/CcapstoneTests/DisassemblyTests.swift @@ -0,0 +1,223 @@ +import XCTest +@testable import Ccapstone + +final class DisassemblyTests: XCTestCase { + + // Test data from existing tests + private let x86Code32: [UInt8] = [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00] + private let x86Code64: [UInt8] = [0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00] + private let armCode: [UInt8] = [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x83, 0x22, 0xe5] + private let thumbCode: [UInt8] = [0x70, 0x47, 0xeb, 0x46, 0x83, 0xb0, 0xc9, 0x68] + private let aarch64Code: [UInt8] = [0x21, 0x7c, 0x02, 0x9b, 0x21, 0x7c, 0x00, 0x53, 0x00, 0x40, 0x21, 0x4b, 0xe1, 0x0b, 0x40, 0xb9] + private let mipsCode: [UInt8] = [0x0C, 0x10, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0c, 0x8f, 0xa2, 0x00, 0x00] + private let ppcCode: [UInt8] = [0x80, 0x20, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x10, 0x43, 0x23, 0x0e, 0xd0, 0x44, 0x00, 0x80] + + func testX86_32() { + performDisassemblyTest( + arch: CS_ARCH_X86, + mode: CS_MODE_32, + code: x86Code32, + comment: "X86 32bit" + ) + } + + func testX86_64() { + performDisassemblyTest( + arch: CS_ARCH_X86, + mode: CS_MODE_64, + code: x86Code64, + comment: "X86 64bit" + ) + } + + func testARM() { + performDisassemblyTest( + arch: CS_ARCH_ARM, + mode: CS_MODE_ARM, + code: armCode, + comment: "ARM" + ) + } + + func testThumb() { + performDisassemblyTest( + arch: CS_ARCH_ARM, + mode: CS_MODE_THUMB, + code: thumbCode, + comment: "Thumb" + ) + } + + func testAArch64() { + performDisassemblyTest( + arch: CS_ARCH_AARCH64, + mode: CS_MODE_ARM, + code: aarch64Code, + comment: "AArch64" + ) + } + + func testMIPS() { + performDisassemblyTest( + arch: CS_ARCH_MIPS, + mode: cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), + code: mipsCode, + comment: "MIPS32 Big-endian" + ) + } + + func testPPC() { + performDisassemblyTest( + arch: CS_ARCH_PPC, + mode: CS_MODE_BIG_ENDIAN, + code: ppcCode, + comment: "PowerPC" + ) + } + + func testDisasmWithDetail() { + var handle: csh = 0 + var insns: UnsafeMutablePointer? + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + let count = x86Code32.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertGreaterThan(count, 0) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + for i in 0..? + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + // Test with invalid/empty code + let invalidCode: [UInt8] = [] + let count = invalidCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertEqual(count, 0) + + _ = cs_close(&handle) + } + + func testSkipData() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let skipDataResult = cs_option(handle, CS_OPT_SKIPDATA, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(skipDataResult, CS_ERR_OK) + + // Test with some invalid bytes mixed in + let mixedCode: [UInt8] = [0xFF, 0xFF, 0xFF, 0xFF] + x86Code32 + var insns: UnsafeMutablePointer? + + let count = mixedCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertGreaterThan(count, 0) + + if count > 0 && insns != nil { + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + + // Helper function for basic disassembly tests + private func performDisassemblyTest(arch: cs_arch, mode: cs_mode, code: [UInt8], comment: String) { + var handle: csh = 0 + var insns: UnsafeMutablePointer? + + let openResult = cs_open(arch, mode, &handle) + XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertGreaterThan(count, 0, "No instructions disassembled for \(comment)") + XCTAssertNotNil(insns, "Instructions pointer is nil for \(comment)") + + if count > 0 && insns != nil { + print("\n\(comment):") + for i in 0...size + let detailSize = MemoryLayout.size + + XCTAssertGreaterThan(insnSize, 0, "cs_insn structure should have positive size") + XCTAssertGreaterThan(detailSize, 0, "cs_detail structure should have positive size") + + print("✓ Structure sizes:") + print(" cs_insn: \(insnSize) bytes") + print(" cs_detail: \(detailSize) bytes") + + // cs_insn should be reasonably sized (has mnemonic, op_str, etc.) + XCTAssertGreaterThan(insnSize, 64, "cs_insn should be at least 64 bytes") + + // cs_detail should be large (has architecture-specific unions) + XCTAssertGreaterThan(detailSize, 100, "cs_detail should be at least 100 bytes") + } + + func testVersionConsistency() { + // Test version consistency across different calls + var major1: Int32 = 0, minor1: Int32 = 0 + var major2: Int32 = 0, minor2: Int32 = 0 + + let version1 = cs_version(&major1, &minor1) + let version2 = cs_version(&major2, &minor2) + + XCTAssertEqual(version1, version2, "Version should be consistent") + XCTAssertEqual(major1, major2, "Major version should be consistent") + XCTAssertEqual(minor1, minor2, "Minor version should be consistent") + + // Test CS_MAKE_VERSION macro equivalent + let calculatedVersion = UInt32((major1 << 8) | minor1) + XCTAssertEqual(version1, calculatedVersion, "Version calculation should match macro") + + print("✓ Version consistency verified") + } +} diff --git a/bindings/swift/CcapstoneTests/PerformanceTests.swift b/bindings/swift/CcapstoneTests/PerformanceTests.swift new file mode 100644 index 0000000000..3223ef3933 --- /dev/null +++ b/bindings/swift/CcapstoneTests/PerformanceTests.swift @@ -0,0 +1,318 @@ +import Foundation +import Testing +@testable import Ccapstone + +/// Performance and stress tests for the Capstone Swift binding +/// These tests verify performance characteristics and stress the API under various conditions +@Suite("Performance Tests") +struct PerformanceTests { + + // Test data for performance testing + private static let x86Code32: [UInt8] = [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00] + private static let x86Code64: [UInt8] = [0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00] + private static let armCode: [UInt8] = [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x83, 0x22, 0xe5] + + /// Large code block for stress testing + private static let largeCodeBlock: [UInt8] = { + var code = [UInt8]() + // Repeat the x86 32-bit code 1000 times for stress testing + for _ in 0..<1000 { + code.append(contentsOf: x86Code32) + } + return code + }() + + @Test("Multiple handle creation and destruction performance") + func testHandleCreationPerformance() async throws { + let iterations = 1000 + let startTime = CFAbsoluteTimeGetCurrent() + + for _ in 0..? + let count = Self.largeCodeBlock.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + let endTime = CFAbsoluteTimeGetCurrent() + let totalTime = endTime - startTime + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + print("✓ Large code block disassembly:") + print(" Code size: \(Self.largeCodeBlock.count) bytes") + print(" Instructions disassembled: \(count)") + print(" Time taken: \(String(format: "%.4f", totalTime)) seconds") + + if count > 0 { + let throughput = Double(Self.largeCodeBlock.count) / totalTime / 1024 / 1024 // MB/s + print(" Throughput: \(String(format: "%.2f", throughput)) MB/s") + + // Basic performance expectation - should process at least 1MB/s + #expect(throughput > 1.0, "Should have reasonable throughput") + } + + #expect(count >= 0, "Should not fail catastrophically") + } + + @Test("Iterator API performance comparison") + func testIteratorVsBatchDisassembly() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping iterator performance test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + let testCode = Self.x86Code32 + + // Test batch disassembly performance + let batchStartTime = CFAbsoluteTimeGetCurrent() + var insns: UnsafeMutablePointer? + let batchCount = testCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + let batchEndTime = CFAbsoluteTimeGetCurrent() + let batchTime = batchEndTime - batchStartTime + + if batchCount > 0 { + cs_free(insns, batchCount) + } + + // Test iterator API performance + let iterStartTime = CFAbsoluteTimeGetCurrent() + let insn = cs_malloc(handle) + var iterCount: Int = 0 + + if let insn = insn { + testCode.withUnsafeBufferPointer { buffer in + var codePtr = buffer.baseAddress + var size = testCode.count + var address: UInt64 = 0x1000 + + while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { + iterCount += 1 + } + } + cs_free(insn, 1) + } + + let iterEndTime = CFAbsoluteTimeGetCurrent() + let iterTime = iterEndTime - iterStartTime + + print("✓ API performance comparison:") + print(" Batch API: \(batchCount) instructions in \(String(format: "%.6f", batchTime)) seconds") + print(" Iterator API: \(iterCount) instructions in \(String(format: "%.6f", iterTime)) seconds") + + #expect(batchCount == iterCount, "Both methods should find same number of instructions") + } + + @Test("Memory allocation stress test") + func testMemoryAllocationStress() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping memory stress test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + let allocations = 1000 + var allocatedPointers: [UnsafeMutablePointer] = [] + + // Allocate many instruction structures + for _ in 0.. allocations / 2, "Should successfully allocate most structures") + } + + @Test("Rapid open/close cycles") + func testRapidOpenCloseCycles() async throws { + let cycles = 10000 + var successfulCycles = 0 + let architectures: [(cs_arch, cs_mode)] = [ + (CS_ARCH_X86, CS_MODE_32), + (CS_ARCH_X86, CS_MODE_64), + (CS_ARCH_ARM, CS_MODE_ARM), + (CS_ARCH_ARM, CS_MODE_THUMB) + ] + + let startTime = CFAbsoluteTimeGetCurrent() + + for i in 0.. 0, "Should complete some cycles successfully") + } + + @Test("Option setting performance") + func testOptionSettingPerformance() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping option performance test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + let iterations = 10000 + let options: [(cs_opt_type, size_t)] = [ + (CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)), + (CS_OPT_DETAIL, size_t(CS_OPT_OFF.rawValue)), + ] + + let startTime = CFAbsoluteTimeGetCurrent() + var successfulOperations = 0 + + for i in 0.. 0 { + let avgTime = totalTime / Double(successfulOperations) * 1000000 // Convert to microseconds + print(" Average time per operation: \(String(format: "%.2f", avgTime)) μs") + } + } + + @Test("Concurrent access safety test") + func testConcurrentAccess() async throws { + // Note: This test creates separate handles for concurrent access + // Each handle should be used from only one thread at a time + + let concurrentTasks = 10 + let operationsPerTask = 100 + + await withTaskGroup(of: Int.self) { group in + for _ in 0..? + let count = Self.x86Code32.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if count > 0 { + cs_free(insns, count) + successfulOperations += 1 + } + + _ = cs_close(&handle) + } + } + + return successfulOperations + } + } + + var totalSuccessful = 0 + for await result in group { + totalSuccessful += result + } + + let totalOperations = concurrentTasks * operationsPerTask + print("✓ Concurrent access test:") + print(" Total operations: \(totalOperations)") + print(" Successful operations: \(totalSuccessful)") + print(" Success rate: \(String(format: "%.1f", Double(totalSuccessful) / Double(totalOperations) * 100))%") + + // Should handle concurrent operations reasonably well + #expect(totalSuccessful > 0, "Should complete some operations successfully") + } + } +} \ No newline at end of file diff --git a/bindings/swift/CcapstoneTests/SimpleTests.swift b/bindings/swift/CcapstoneTests/SimpleTests.swift new file mode 100644 index 0000000000..2666380dd9 --- /dev/null +++ b/bindings/swift/CcapstoneTests/SimpleTests.swift @@ -0,0 +1,95 @@ +import XCTest +@testable import Ccapstone + +final class SimpleTests: XCTestCase { + + func testVersionOnly() { + var major: Int32 = 0 + var minor: Int32 = 0 + + let version = cs_version(&major, &minor) + + XCTAssertGreaterThan(major, 0) + XCTAssertGreaterThanOrEqual(minor, 0) + XCTAssertGreaterThan(version, 0) + XCTAssertEqual(version, UInt32((major << 8) | minor)) + + print("Capstone version: \(major).\(minor) (0x\(String(format: "%04x", version)))") + } + + func testBasicAPIAvailability() { + // Test that all basic functions are available + // This doesn't actually call them, just verifies they can be referenced + let _ = cs_open + let _ = cs_close + let _ = cs_disasm + let _ = cs_malloc + let _ = cs_disasm_iter + let _ = cs_free + let _ = cs_option + let _ = cs_errno + let _ = cs_strerror + let _ = cs_version + + // Test enum availability + let _ = CS_ARCH_X86 + let _ = CS_MODE_32 + let _ = CS_ERR_OK + let _ = CS_OPT_DETAIL + let _ = CS_OPT_ON + + XCTAssertTrue(true, "All basic API functions are available") + } + + func testErrorMessages() { + let errorCodes: [cs_err] = [ + CS_ERR_OK, + CS_ERR_MEM, + CS_ERR_ARCH, + CS_ERR_HANDLE, + CS_ERR_CSH, + CS_ERR_MODE, + CS_ERR_OPTION + ] + + print("Testing error messages:") + for errorCode in errorCodes { + let message = cs_strerror(errorCode) + XCTAssertNotNil(message, "Error message should not be nil for \(errorCode)") + + if let message = message { + let errorString = String(cString: message) + XCTAssertFalse(errorString.isEmpty, "Error message should not be empty for \(errorCode)") + print(" \(errorCode.rawValue): \(errorString)") + } + } + } + + func testSimpleOpenClose() { + var handle: csh = 0 + + print("Testing cs_open...") + let result = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + if result == CS_ERR_OK { + print("✓ cs_open succeeded, handle: \(handle)") + XCTAssertNotEqual(handle, 0, "Handle should not be zero") + + print("Testing cs_close...") + let closeResult = cs_close(&handle) + if closeResult == CS_ERR_OK { + print("✓ cs_close succeeded") + XCTAssertEqual(handle, 0, "Handle should be zero after close") + } else { + let errorMsg = cs_strerror(closeResult) + let errorString = errorMsg != nil ? String(cString: errorMsg!) : "Unknown error" + print("✗ cs_close failed: \(errorString)") + XCTFail("cs_close failed with error: \(errorString)") + } + } else { + let errorMsg = cs_strerror(result) + let errorString = errorMsg != nil ? String(cString: errorMsg!) : "Unknown error" + print("✗ cs_open failed: \(errorString)") + XCTFail("cs_open failed with error: \(errorString)") + } + } +} \ No newline at end of file diff --git a/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift b/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift new file mode 100644 index 0000000000..1ed5f7934e --- /dev/null +++ b/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift @@ -0,0 +1,542 @@ +import Foundation +import Testing +@testable import Ccapstone + +/// Swift-specific integration tests for the Capstone binding +/// These tests verify Swift-specific patterns, safety features, and idiomatic usage +@Suite("Swift Integration Tests") +struct SwiftIntegrationTests { + // Test data + private static let x86Code: [UInt8] = [0x8D, 0x4C, 0x32, 0x08, 0x01, 0xD8, 0x81, 0xC6, 0x34, 0x12, 0x00, 0x00] + + @Test("Swift optionals and error handling") + func testSwiftOptionals() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping Swift optionals test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + print("✓ Swift optionals and error handling:") + + // Test cs_malloc returning optional + let insn = cs_malloc(handle) + if let insn = insn { + print(" cs_malloc returned valid pointer: \(insn)") + cs_free(insn, 1) + } else { + print(" cs_malloc returned nil") + } + + // Test cs_strerror returning optional + let errorMessage = cs_strerror(CS_ERR_OK) + if let message = errorMessage { + let errorString = String(cString: message) + print(" Error message: '\(errorString)'") + #expect(!errorString.isEmpty, "Error message should not be empty") + } else { + #expect(Bool(false), "cs_strerror should not return nil") + } + } + + @Test("Swift memory management patterns") + func testSwiftMemoryManagement() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping memory management test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + print("✓ Swift memory management patterns:") + + // Test RAII-style pattern with defer + func performDisassemblyWithDefer() -> size_t { + var insns: UnsafeMutablePointer? + let count = Self.x86Code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + // Simulate some processing + if count > 0 { + let firstInsn = insns!.pointee + _ = withUnsafeBytes(of: firstInsn.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + } + + return count + } + + let deferCount = performDisassemblyWithDefer() + print(" RAII-style pattern with defer: \(deferCount) instructions") + + // Test withUnsafeBufferPointer pattern + let bufferCount = Self.x86Code.withUnsafeBufferPointer { buffer -> size_t in + var insns: UnsafeMutablePointer? + let count = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if count > 0 { + cs_free(insns, count) + } + } + return count + } + + print(" withUnsafeBufferPointer pattern: \(bufferCount) instructions") + #expect(deferCount == bufferCount, "Both patterns should yield same results") + + // Test iterator pattern with automatic cleanup + func testIteratorPattern() -> Int { + guard let insn = cs_malloc(handle) else { + return 0 + } + defer { cs_free(insn, 1) } + + var instructionCount = 0 + Self.x86Code.withUnsafeBufferPointer { buffer in + var codePtr = buffer.baseAddress + var size = Self.x86Code.count + var address: UInt64 = 0x1000 + + while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { + instructionCount += 1 + let mnemonic = withUnsafeBytes(of: insn.pointee.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + let _ = mnemonic // Use the value + + if instructionCount > 100 { // Safety break + break + } + } + } + + return instructionCount + } + + let iteratorCount = testIteratorPattern() + print(" Iterator pattern with automatic cleanup: \(iteratorCount) instructions") + } + + @Test("Swift string handling and C interop") + func testSwiftStringHandling() async throws { + print("✓ Swift string handling and C interop:") + + // Test converting C strings to Swift strings + let testErrors: [cs_err] = [CS_ERR_OK, CS_ERR_MEM, CS_ERR_ARCH, CS_ERR_HANDLE] + + for errorCode in testErrors { + if let cMessage = cs_strerror(errorCode) { + let swiftString = String(cString: cMessage) + + // Test Swift string operations + let uppercased = swiftString.uppercased() + let length = swiftString.count + let utf8Count = swiftString.utf8.count + + print(" Error \(errorCode.rawValue): '\(swiftString)' -> '\(uppercased)' (\(length)/\(utf8Count) chars)") + + #expect(!swiftString.isEmpty, "Swift string should not be empty") + #expect(length > 0, "String length should be positive") + #expect(utf8Count >= length, "UTF-8 byte count should be >= character count") + } + } + + // Test version information as Swift strings + var major: Int32 = 0 + var minor: Int32 = 0 + let version = cs_version(&major, &minor) + + let versionString = String(format: "%d.%d", major, minor) + let hexVersionString = String(format: "0x%04x", version) + + print(" Version: \(versionString) (\(hexVersionString))") + + #expect(versionString.count >= 3, "Version string should be at least X.Y") + #expect(hexVersionString.hasPrefix("0x"), "Hex version should start with 0x") + } + + @Test("Swift array and collection integration") + func testSwiftCollectionIntegration() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping collection integration test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + print("✓ Swift array and collection integration:") + + // Test with different array types + let testData: [String: [UInt8]] = [ + "x86_32": [0x8D, 0x4C, 0x32, 0x08], + "nops": [0x90, 0x90, 0x90, 0x90], + "empty": [], + "single": [0x90], + ] + + for (name, codeArray) in testData { + let count = codeArray.withUnsafeBufferPointer { buffer -> size_t in + var insns: UnsafeMutablePointer? + let result = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if result > 0 { + cs_free(insns, result) + } + } + return result + } + + print(" \(name) array (\(codeArray.count) bytes): \(count) instructions") + } + + // Test using Array methods + let extendedCode = Self.x86Code + Self.x86Code // Array concatenation + let count = extendedCode.withUnsafeBufferPointer { buffer -> size_t in + var insns: UnsafeMutablePointer? + let result = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if result > 0 { + cs_free(insns, result) + } + } + return result + } + + print(" Extended array (\(extendedCode.count) bytes): \(count) instructions") + + // Test with ArraySlice + if extendedCode.count > 4 { + let slice = extendedCode[2 ..< 6] // Take a slice + let sliceArray = Array(slice) // Convert slice to array for withUnsafeBufferPointer + + let sliceCount = sliceArray.withUnsafeBufferPointer { buffer -> size_t in + var insns: UnsafeMutablePointer? + let result = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if result > 0 { + cs_free(insns, result) + } + } + return result + } + + print(" Array slice (\(sliceArray.count) bytes): \(sliceCount) instructions") + } + } + + @Test("Swift error handling patterns") + func testSwiftErrorHandling() async throws { + print("✓ Swift error handling patterns:") + + // Define a Swift wrapper that throws + enum CapstoneError: Error, CustomStringConvertible { + case openFailed(cs_err) + case disassemblyFailed(cs_err) + case invalidHandle + + var description: String { + switch self { + case .openFailed(let err): + if let msg = cs_strerror(err) { + return "Open failed: \(String(cString: msg))" + } + return "Open failed: \(err)" + case .disassemblyFailed(let err): + return "Disassembly failed: \(err)" + case .invalidHandle: + return "Invalid handle" + } + } + } + + func safeOpen(arch: cs_arch, mode: cs_mode) throws -> csh { + var handle: csh = 0 + let result = cs_open(arch, mode, &handle) + guard result == CS_ERR_OK else { + throw CapstoneError.openFailed(result) + } + return handle + } + + func safeDisassemble(handle: csh, code: [UInt8]) throws -> Int { + guard handle != 0 else { + throw CapstoneError.invalidHandle + } + + return code.withUnsafeBufferPointer { buffer -> Int in + var insns: UnsafeMutablePointer? + let count = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if count > 0 { + cs_free(insns, count) + } + } + return Int(count) + } + } + + // Test successful case + do { + let handle = try safeOpen(arch: CS_ARCH_X86, mode: CS_MODE_32) + defer { + var mutableHandle = handle + _ = cs_close(&mutableHandle) + } + + let count = try safeDisassemble(handle: handle, code: Self.x86Code) + print(" Successful operation: \(count) instructions") + + } catch { + print(" Expected success case failed: \(error)") + } + + // Test failure case + do { + _ = try safeOpen(arch: cs_arch(rawValue: 999), mode: CS_MODE_32) + print(" Expected failure case succeeded (unexpected)") + } catch let error as CapstoneError { + print(" Expected failure caught: \(error)") + } catch { + print(" Unexpected error type: \(error)") + } + + // Test invalid handle + do { + _ = try safeDisassemble(handle: 0, code: Self.x86Code) + print(" Invalid handle case succeeded (unexpected)") + } catch let error as CapstoneError { + print(" Invalid handle error caught: \(error)") + } catch { + print(" Unexpected error for invalid handle: \(error)") + } + } + + @Test("Swift value types and reference types") + func testSwiftValueAndReferenceTypes() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping value/reference types test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + print("✓ Swift value types and reference types:") + + // Test copying instruction data to Swift value types + struct SwiftInstruction { + var address: UInt64 + let size: UInt16 + let mnemonic: String + let operands: String + let bytes: [UInt8] + + init(from csInsn: cs_insn) { + self.address = csInsn.address + self.size = csInsn.size + self.mnemonic = withUnsafeBytes(of: csInsn.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + self.operands = withUnsafeBytes(of: csInsn.op_str) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + + // Copy bytes (simplified - in real implementation would copy actual bytes) + var byteArray: [UInt8] = [] + for _ in 0 ..< min(Int(csInsn.size), 16) { // Limit to reasonable size + // Note: This is simplified - real implementation would access csInsn.bytes properly + byteArray.append(0x90) // Placeholder + } + self.bytes = byteArray + } + } + + var swiftInstructions: [SwiftInstruction] = [] + + var insns: UnsafeMutablePointer? + let count = Self.x86Code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + // Convert C structures to Swift value types + if count > 0 { + for i in 0 ..< count { + let csInsn = (insns! + i).pointee + let swiftInsn = SwiftInstruction(from: csInsn) + swiftInstructions.append(swiftInsn) + } + } + + print(" Converted \(swiftInstructions.count) instructions to Swift value types") + + // Test Swift collection operations on converted data + let mnemonics = swiftInstructions.map { $0.mnemonic } + let addresses = swiftInstructions.map { $0.address } + let totalBytes = swiftInstructions.reduce(0) { $0 + Int($1.size) } + + print(" Mnemonics: \(mnemonics)") + print(" Addresses: \(addresses.map { String(format: "0x%llx", $0) })") + print(" Total instruction bytes: \(totalBytes)") + + // Test value semantics + if var firstInstruction = swiftInstructions.first { + let originalAddress = firstInstruction.address + firstInstruction.address = 0x2000 // This shouldn't affect the array + + let arrayAddress = swiftInstructions.first?.address ?? 0 + #expect(originalAddress == arrayAddress, "Value types should maintain independence") + print(" Value type semantics: ✓ (original: 0x\(String(format: "%llx", originalAddress)), array: 0x\(String(format: "%llx", arrayAddress)))") + } + } + + @Test("Swift async/await compatibility") + func testAsyncAwaitCompatibility() async throws { + print("✓ Swift async/await compatibility:") + + // Test that Capstone operations can be used in async contexts + func asyncDisassembly() async -> Int { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + return -1 + } + + defer { _ = cs_close(&handle) } + + // Simulate some async work + try? await Task.sleep(nanoseconds: 1_000_000) // 1ms + + return Self.x86Code.withUnsafeBufferPointer { buffer -> Int in + var insns: UnsafeMutablePointer? + let count = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if count > 0 { + cs_free(insns, count) + } + } + return Int(count) + } + } + + let result = await asyncDisassembly() + print(" Async disassembly result: \(result) instructions") + + // Test concurrent async operations + async let result1 = asyncDisassembly() + async let result2 = asyncDisassembly() + async let result3 = asyncDisassembly() + + let results = await [result1, result2, result3] + print(" Concurrent async results: \(results)") + + // All should succeed or fail consistently + let successfulResults = results.filter { $0 >= 0 } + if !successfulResults.isEmpty { + let allSame = successfulResults.allSatisfy { $0 == successfulResults.first } + #expect(allSame, "Concurrent operations should yield same results") + print(" Concurrent consistency: \(allSame ? "✓" : "✗")") + } + } + + @Test("Swift generic and protocol integration") + func testGenericAndProtocolIntegration() async throws { + print("✓ Swift generic and protocol integration:") + + // Define protocols for Capstone operations + protocol DisassemblyProvider { + func disassemble(_ code: T) -> Int where T.Element == UInt8 + } + + class CapstoneDisassembler: DisassemblyProvider { + let handle: csh + + init?(architecture: cs_arch, mode: cs_mode) { + var handle: csh = 0 + let result = cs_open(architecture, mode, &handle) + guard result == CS_ERR_OK else { + return nil + } + self.handle = handle + } + + deinit { + var mutableHandle = handle + _ = cs_close(&mutableHandle) + } + + func disassemble(_ code: T) -> Int where T.Element == UInt8 { + let codeArray = Array(code) // Convert any collection to array + return codeArray.withUnsafeBufferPointer { buffer -> Int in + var insns: UnsafeMutablePointer? + let count = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if count > 0 { + cs_free(insns, count) + } + } + return Int(count) + } + } + } + + // Test with different collection types + guard let disassembler = CapstoneDisassembler(architecture: CS_ARCH_X86, mode: CS_MODE_32) else { + print(" Could not create disassembler") + return + } + + // Test with Array + let arrayResult = disassembler.disassemble(Self.x86Code) + print(" Array disassembly: \(arrayResult) instructions") + + // Test with ArraySlice + if Self.x86Code.count > 4 { + let slice = Self.x86Code[0 ..< 4] + let sliceResult = disassembler.disassemble(slice) + print(" ArraySlice disassembly: \(sliceResult) instructions") + } + + // Test with different UInt8 collections + let set = Set(Self.x86Code) + let setArray = Array(set).sorted() // Convert set back to sorted array for consistent results + let setResult = disassembler.disassemble(setArray) + print(" Set-derived array disassembly: \(setResult) instructions") + + // Test generic function + func testGenericDisassembly(_ provider: DisassemblyProvider, code: T) -> Int where T.Element == UInt8 { + return provider.disassemble(code) + } + + let genericResult = testGenericDisassembly(disassembler, code: Self.x86Code) + print(" Generic function result: \(genericResult) instructions") + + #expect(arrayResult == genericResult, "Generic and direct calls should yield same results") + } +} From 8a3b92856684ca2e3150143af5f134d7e9ae4d0f Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Tue, 16 Sep 2025 00:40:03 +0800 Subject: [PATCH 04/12] Update to Swift Testing --- .../CcapstoneTests/ArchitectureTests.swift | 82 ++++++------- .../swift/CcapstoneTests/DetailTests.swift | 115 +++++++++--------- .../CcapstoneTests/DisassemblyTests.swift | 71 +++++------ .../swift/CcapstoneTests/MinimalTests.swift | 86 ++++++------- .../swift/CcapstoneTests/SimpleTests.swift | 37 +++--- .../SwiftIntegrationTests.swift | 24 ++-- 6 files changed, 209 insertions(+), 206 deletions(-) diff --git a/bindings/swift/CcapstoneTests/ArchitectureTests.swift b/bindings/swift/CcapstoneTests/ArchitectureTests.swift index af9b6ebd54..2d526bc7fc 100644 --- a/bindings/swift/CcapstoneTests/ArchitectureTests.swift +++ b/bindings/swift/CcapstoneTests/ArchitectureTests.swift @@ -1,8 +1,8 @@ -import XCTest +import Foundation +import Testing @testable import Ccapstone -final class ArchitectureTests: XCTestCase { - +@Suite struct ArchitectureTests { // Test code samples for different architectures private struct TestPlatform { let arch: cs_arch @@ -15,93 +15,93 @@ final class ArchitectureTests: XCTestCase { TestPlatform( arch: CS_ARCH_X86, mode: CS_MODE_16, - code: [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00], + code: [0x8D, 0x4C, 0x32, 0x08, 0x01, 0xD8, 0x81, 0xC6, 0x34, 0x12, 0x00, 0x00], comment: "X86 16bit" ), TestPlatform( arch: CS_ARCH_X86, mode: CS_MODE_32, - code: [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00], + code: [0x8D, 0x4C, 0x32, 0x08, 0x01, 0xD8, 0x81, 0xC6, 0x34, 0x12, 0x00, 0x00], comment: "X86 32bit" ), TestPlatform( arch: CS_ARCH_X86, mode: CS_MODE_64, - code: [0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00], + code: [0x55, 0x48, 0x8B, 0x05, 0xB8, 0x13, 0x00, 0x00], comment: "X86 64bit" ), TestPlatform( arch: CS_ARCH_ARM, mode: CS_MODE_ARM, - code: [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x83, 0x22, 0xe5], + code: [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xE0, 0x2D, 0xE5, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x83, 0x22, 0xE5], comment: "ARM" ), TestPlatform( arch: CS_ARCH_ARM, mode: CS_MODE_THUMB, - code: [0x70, 0x47, 0xeb, 0x46, 0x83, 0xb0, 0xc9, 0x68], + code: [0x70, 0x47, 0xEB, 0x46, 0x83, 0xB0, 0xC9, 0x68], comment: "Thumb" ), TestPlatform( arch: CS_ARCH_AARCH64, mode: CS_MODE_ARM, - code: [0x21, 0x7c, 0x02, 0x9b, 0x21, 0x7c, 0x00, 0x53, 0x00, 0x40, 0x21, 0x4b, 0xe1, 0x0b, 0x40, 0xb9], + code: [0x21, 0x7C, 0x02, 0x9B, 0x21, 0x7C, 0x00, 0x53, 0x00, 0x40, 0x21, 0x4B, 0xE1, 0x0B, 0x40, 0xB9], comment: "AArch64" ), TestPlatform( arch: CS_ARCH_MIPS, mode: cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), - code: [0x0C, 0x10, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0c, 0x8f, 0xa2, 0x00, 0x00, 0x34, 0x21, 0x34, 0x56], + code: [0x0C, 0x10, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0C, 0x8F, 0xA2, 0x00, 0x00, 0x34, 0x21, 0x34, 0x56], comment: "MIPS32 Big-endian" ), TestPlatform( arch: CS_ARCH_MIPS, mode: cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), - code: [0x56, 0x34, 0x21, 0x34, 0xc2, 0x17, 0x01, 0x00], + code: [0x56, 0x34, 0x21, 0x34, 0xC2, 0x17, 0x01, 0x00], comment: "MIPS64 Little-endian" ), TestPlatform( arch: CS_ARCH_PPC, mode: CS_MODE_BIG_ENDIAN, - code: [0x80, 0x20, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x10, 0x43, 0x23, 0x0e, 0xd0, 0x44, 0x00, 0x80, 0x4c, 0x43, 0x22, 0x02], + code: [0x80, 0x20, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x10, 0x43, 0x23, 0x0E, 0xD0, 0x44, 0x00, 0x80, 0x4C, 0x43, 0x22, 0x02], comment: "PowerPC" ), TestPlatform( arch: CS_ARCH_SPARC, mode: CS_MODE_BIG_ENDIAN, - code: [0x80, 0xa0, 0x40, 0x02, 0x85, 0xc2, 0x60, 0x08, 0x85, 0xe8, 0x20, 0x01, 0x81, 0xe8, 0x00, 0x00, 0x90, 0x10, 0x20, 0x01], + code: [0x80, 0xA0, 0x40, 0x02, 0x85, 0xC2, 0x60, 0x08, 0x85, 0xE8, 0x20, 0x01, 0x81, 0xE8, 0x00, 0x00, 0x90, 0x10, 0x20, 0x01], comment: "Sparc" ), TestPlatform( arch: CS_ARCH_SYSTEMZ, mode: CS_MODE_BIG_ENDIAN, - code: [0xed, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x5a, 0x0f, 0x1f, 0xff, 0xc2, 0x09, 0x80, 0x00, 0x00, 0x00, 0x07, 0xf7], + code: [0xED, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x5A, 0x0F, 0x1F, 0xFF, 0xC2, 0x09, 0x80, 0x00, 0x00, 0x00, 0x07, 0xF7], comment: "SystemZ" - ) + ), ] - func testAllArchitectures() { + @Test func allArchitectures() { for platform in platforms { testArchitecture(platform) } } - func testX86Syntax() { + @Test func x86Syntax() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) // Test Intel syntax (default) - let code: [UInt8] = [0x8d, 0x4c, 0x32, 0x08] + let code: [UInt8] = [0x8D, 0x4C, 0x32, 0x08] var insns: UnsafeMutablePointer? let count = code.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertGreaterThan(count, 0) - if count > 0 && insns != nil { + #expect(count > 0) + if count > 0, insns != nil { let insn = insns![0] let opStr = String(cString: withUnsafeBytes(of: insn.op_str) { $0.bindMemory(to: CChar.self).baseAddress! }) print("Intel syntax: \(opStr)") @@ -126,28 +126,28 @@ final class ArchitectureTests: XCTestCase { _ = cs_close(&handle) } - func testMIPSModes() { + @Test func mIPSModes() { let mipsCodes: [(cs_mode, [UInt8], String)] = [ (cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), [0x0C, 0x10, 0x00, 0x97], "MIPS32 BE"), (cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), [0x97, 0x00, 0x10, 0x0C], "MIPS32 LE"), (cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_BIG_ENDIAN.rawValue), [0x0C, 0x10, 0x00, 0x97], "MIPS64 BE"), - (cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), [0x97, 0x00, 0x10, 0x0C], "MIPS64 LE") + (cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), [0x97, 0x00, 0x10, 0x0C], "MIPS64 LE"), ] for (mode, code, comment) in mipsCodes { var handle: csh = 0 let openResult = cs_open(CS_ARCH_MIPS, mode, &handle) - XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + #expect(openResult == CS_ERR_OK, "Failed to open \(comment)") var insns: UnsafeMutablePointer? let count = code.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertGreaterThanOrEqual(count, 0, "Disassembly failed for \(comment)") + #expect(count >= 0, "Disassembly failed for \(comment)") - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] let mnemonic = String(cString: withUnsafeBytes(of: insn.mnemonic) { $0.bindMemory(to: CChar.self).baseAddress! }) print("\(comment): \(mnemonic)") @@ -158,27 +158,27 @@ final class ArchitectureTests: XCTestCase { } } - func testARMModes() { + @Test func aRMModes() { let armTests: [(cs_mode, [UInt8], String)] = [ - (CS_MODE_ARM, [0x04, 0xe0, 0x2d, 0xe5], "ARM mode"), + (CS_MODE_ARM, [0x04, 0xE0, 0x2D, 0xE5], "ARM mode"), (CS_MODE_THUMB, [0x70, 0x47], "Thumb mode"), - (cs_mode(CS_MODE_THUMB.rawValue | CS_MODE_MCLASS.rawValue), [0x70, 0x47], "Thumb M-Class") + (cs_mode(CS_MODE_THUMB.rawValue | CS_MODE_MCLASS.rawValue), [0x70, 0x47], "Thumb M-Class"), ] for (mode, code, comment) in armTests { var handle: csh = 0 let openResult = cs_open(CS_ARCH_ARM, mode, &handle) - XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + #expect(openResult == CS_ERR_OK, "Failed to open \(comment)") var insns: UnsafeMutablePointer? let count = code.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertGreaterThanOrEqual(count, 0, "Disassembly failed for \(comment)") + #expect(count >= 0, "Disassembly failed for \(comment)") - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] let mnemonic = String(cString: withUnsafeBytes(of: insn.mnemonic) { $0.bindMemory(to: CChar.self).baseAddress! }) print("\(comment): \(mnemonic)") @@ -194,17 +194,17 @@ final class ArchitectureTests: XCTestCase { var insns: UnsafeMutablePointer? let openResult = cs_open(platform.arch, platform.mode, &handle) - XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(platform.comment)") + #expect(openResult == CS_ERR_OK, "Failed to open \(platform.comment)") let count = platform.code.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertGreaterThan(count, 0, "No instructions disassembled for \(platform.comment)") + #expect(count > 0, "No instructions disassembled for \(platform.comment)") - if count > 0 && insns != nil { + if count > 0, insns != nil { print("\n\(platform.comment):") - for i in 0.. 0) + #expect(insn.mnemonic.0 != 0) + #expect(insn.address == 0x1000 + UInt64(calculateOffset(for: i, from: insns!))) } cs_free(insns, count) @@ -226,9 +226,9 @@ final class ArchitectureTests: XCTestCase { // Helper to calculate instruction offset for address validation private func calculateOffset(for index: Int, from instructions: UnsafeMutablePointer) -> Int { var offset = 0 - for i in 0.. 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] - XCTAssertNotNil(insn.detail) + #expect(insn.detail != nil) if insn.detail != nil { let detail = insn.detail!.pointee let x86Detail = detail.x86 // Check basic detail properties - XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) - XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) - XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + #expect(detail.regs_read_count >= 0) + #expect(detail.regs_write_count >= 0) + #expect(detail.groups_count >= 0) // Check X86-specific details - XCTAssertGreaterThan(x86Detail.op_count, 0) - XCTAssertLessThanOrEqual(x86Detail.op_count, 8) + #expect(x86Detail.op_count > 0) + #expect(x86Detail.op_count <= 8) print("X86 Detail:") print(" Instruction ID: \(insn.id)") @@ -63,14 +64,14 @@ final class DetailTests: XCTestCase { _ = cs_close(&handle) } - func testARMDetail() { + @Test func aRMDetail() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(optResult, CS_ERR_OK) + #expect(optResult == CS_ERR_OK) // str lr, [sp, #-4]! let code: [UInt8] = [0x04, 0xE0, 0x2D, 0xE5] @@ -80,25 +81,25 @@ final class DetailTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertEqual(count, 1) - XCTAssertNotNil(insns) + #expect(count == 1) + #expect(insns != nil) - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] - XCTAssertNotNil(insn.detail) + #expect(insn.detail != nil) if insn.detail != nil { let detail = insn.detail!.pointee let armDetail = detail.arm // Check basic detail properties - XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) - XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) - XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + #expect(detail.regs_read_count >= 0) + #expect(detail.regs_write_count >= 0) + #expect(detail.groups_count >= 0) // Check ARM-specific details - XCTAssertGreaterThan(armDetail.op_count, 0) - XCTAssertLessThanOrEqual(armDetail.op_count, 36) + #expect(armDetail.op_count > 0) + #expect(armDetail.op_count <= 36) print("ARM Detail:") print(" Instruction ID: \(insn.id)") @@ -117,14 +118,14 @@ final class DetailTests: XCTestCase { _ = cs_close(&handle) } - func testAArch64Detail() { + @Test func aArch64Detail() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_AARCH64, CS_MODE_ARM, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(optResult, CS_ERR_OK) + #expect(optResult == CS_ERR_OK) // add x1, x1, x2 let code: [UInt8] = [0x21, 0x00, 0x02, 0x8B] @@ -134,25 +135,25 @@ final class DetailTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertEqual(count, 1) - XCTAssertNotNil(insns) + #expect(count == 1) + #expect(insns != nil) - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] - XCTAssertNotNil(insn.detail) + #expect(insn.detail != nil) if insn.detail != nil { let detail = insn.detail!.pointee let aarch64Detail = detail.aarch64 // Check basic detail properties - XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) - XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) - XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + #expect(detail.regs_read_count >= 0) + #expect(detail.regs_write_count >= 0) + #expect(detail.groups_count >= 0) // Check AArch64-specific details - XCTAssertGreaterThan(aarch64Detail.op_count, 0) - XCTAssertLessThanOrEqual(aarch64Detail.op_count, 8) + #expect(aarch64Detail.op_count > 0) + #expect(aarch64Detail.op_count <= 8) print("AArch64 Detail:") print(" Instruction ID: \(insn.id)") @@ -171,14 +172,14 @@ final class DetailTests: XCTestCase { _ = cs_close(&handle) } - func testMIPSDetail() { + @Test func mIPSDetail() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_MIPS, cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(optResult, CS_ERR_OK) + #expect(optResult == CS_ERR_OK) // jal 0x97000c let code: [UInt8] = [0x0C, 0x10, 0x00, 0x97] @@ -188,25 +189,25 @@ final class DetailTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertEqual(count, 1) - XCTAssertNotNil(insns) + #expect(count == 1) + #expect(insns != nil) - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] - XCTAssertNotNil(insn.detail) + #expect(insn.detail != nil) if insn.detail != nil { let detail = insn.detail!.pointee let mipsDetail = detail.mips // Check basic detail properties - XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) - XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) - XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + #expect(detail.regs_read_count >= 0) + #expect(detail.regs_write_count >= 0) + #expect(detail.groups_count >= 0) // Check MIPS-specific details - XCTAssertGreaterThan(mipsDetail.op_count, 0) - XCTAssertLessThanOrEqual(mipsDetail.op_count, 4) + #expect(mipsDetail.op_count > 0) + #expect(mipsDetail.op_count <= 4) print("MIPS Detail:") print(" Instruction ID: \(insn.id)") @@ -222,14 +223,14 @@ final class DetailTests: XCTestCase { _ = cs_close(&handle) } - func testInstructionGroups() { + @Test func instructionGroups() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(optResult, CS_ERR_OK) + #expect(optResult == CS_ERR_OK) // ret instruction let code: [UInt8] = [0xC3] @@ -239,12 +240,12 @@ final class DetailTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertEqual(count, 1) - XCTAssertNotNil(insns) + #expect(count == 1) + #expect(insns != nil) - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] - XCTAssertNotNil(insn.detail) + #expect(insn.detail != nil) if insn.detail != nil { let detail = insn.detail!.pointee diff --git a/bindings/swift/CcapstoneTests/DisassemblyTests.swift b/bindings/swift/CcapstoneTests/DisassemblyTests.swift index 918b11c229..af361f49da 100644 --- a/bindings/swift/CcapstoneTests/DisassemblyTests.swift +++ b/bindings/swift/CcapstoneTests/DisassemblyTests.swift @@ -1,7 +1,8 @@ -import XCTest +import Foundation +import Testing @testable import Ccapstone -final class DisassemblyTests: XCTestCase { +@Suite struct DisassemblyTests { // Test data from existing tests private let x86Code32: [UInt8] = [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00] @@ -12,7 +13,7 @@ final class DisassemblyTests: XCTestCase { private let mipsCode: [UInt8] = [0x0C, 0x10, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0c, 0x8f, 0xa2, 0x00, 0x00] private let ppcCode: [UInt8] = [0x80, 0x20, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x10, 0x43, 0x23, 0x0e, 0xd0, 0x44, 0x00, 0x80] - func testX86_32() { + @Test func x86_32() { performDisassemblyTest( arch: CS_ARCH_X86, mode: CS_MODE_32, @@ -21,7 +22,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testX86_64() { + @Test func x86_64() { performDisassemblyTest( arch: CS_ARCH_X86, mode: CS_MODE_64, @@ -30,7 +31,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testARM() { + @Test func aRM() { performDisassemblyTest( arch: CS_ARCH_ARM, mode: CS_MODE_ARM, @@ -39,7 +40,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testThumb() { + @Test func thumb() { performDisassemblyTest( arch: CS_ARCH_ARM, mode: CS_MODE_THUMB, @@ -48,7 +49,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testAArch64() { + @Test func aArch64() { performDisassemblyTest( arch: CS_ARCH_AARCH64, mode: CS_MODE_ARM, @@ -57,7 +58,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testMIPS() { + @Test func mIPS() { performDisassemblyTest( arch: CS_ARCH_MIPS, mode: cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), @@ -66,7 +67,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testPPC() { + @Test func pPC() { performDisassemblyTest( arch: CS_ARCH_PPC, mode: CS_MODE_BIG_ENDIAN, @@ -75,28 +76,28 @@ final class DisassemblyTests: XCTestCase { ) } - func testDisasmWithDetail() { + @Test func disasmWithDetail() { var handle: csh = 0 var insns: UnsafeMutablePointer? let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(optResult, CS_ERR_OK) + #expect(optResult == CS_ERR_OK) let count = x86Code32.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertGreaterThan(count, 0) - XCTAssertNotNil(insns) + #expect(count > 0) + #expect(insns != nil) if count > 0 && insns != nil { for i in 0.. 0) + #expect(insn.mnemonic.0 != 0) // Check first character is not null // Check first character is not null if insn.detail != nil { let detail = insn.detail!.pointee @@ -111,14 +112,14 @@ final class DisassemblyTests: XCTestCase { _ = cs_close(&handle) } - func testIteratorAPI() { + @Test func iteratorAPI() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let insn = cs_malloc(handle) - XCTAssertNotNil(insn) + #expect(insn != nil) let code = x86Code32 var size = code.count @@ -129,25 +130,25 @@ final class DisassemblyTests: XCTestCase { var codePtr = buffer.baseAddress while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { let instruction = insn!.pointee - XCTAssertGreaterThan(instruction.size, 0) - XCTAssertNotEqual(instruction.mnemonic.0, 0) + #expect(instruction.size > 0) + #expect(instruction.mnemonic.0 != 0) count += 1 } return count } - XCTAssertGreaterThan(result, 0) + #expect(result > 0) cs_free(insn, 1) _ = cs_close(&handle) } - func testInvalidCode() { + @Test func invalidCode() { var handle: csh = 0 var insns: UnsafeMutablePointer? let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) // Test with invalid/empty code let invalidCode: [UInt8] = [] @@ -155,19 +156,19 @@ final class DisassemblyTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertEqual(count, 0) + #expect(count == 0) _ = cs_close(&handle) } - func testSkipData() { + @Test func skipData() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let skipDataResult = cs_option(handle, CS_OPT_SKIPDATA, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(skipDataResult, CS_ERR_OK) + #expect(skipDataResult == CS_ERR_OK) // Test with some invalid bytes mixed in let mixedCode: [UInt8] = [0xFF, 0xFF, 0xFF, 0xFF] + x86Code32 @@ -177,7 +178,7 @@ final class DisassemblyTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertGreaterThan(count, 0) + #expect(count > 0) if count > 0 && insns != nil { cs_free(insns, count) @@ -192,14 +193,14 @@ final class DisassemblyTests: XCTestCase { var insns: UnsafeMutablePointer? let openResult = cs_open(arch, mode, &handle) - XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + #expect(openResult == CS_ERR_OK, "Failed to open \(comment)") let count = code.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertGreaterThan(count, 0, "No instructions disassembled for \(comment)") - XCTAssertNotNil(insns, "Instructions pointer is nil for \(comment)") + #expect(count > 0, "No instructions disassembled for \(comment)") + #expect(insns != nil, "Instructions pointer is nil for \(comment)") if count > 0 && insns != nil { print("\n\(comment):") @@ -211,8 +212,8 @@ final class DisassemblyTests: XCTestCase { print(" \(address)\t\(mnemonic)\t\(opStr)") // Basic validation - XCTAssertGreaterThan(insn.size, 0) - XCTAssertNotEqual(insn.mnemonic.0, 0) // Check first character is not null + #expect(insn.size > 0) + #expect(insn.mnemonic.0 != 0) // Check first character is not null // Check first character is not null } cs_free(insns, count) @@ -220,4 +221,4 @@ final class DisassemblyTests: XCTestCase { _ = cs_close(&handle) } -} \ No newline at end of file +} diff --git a/bindings/swift/CcapstoneTests/MinimalTests.swift b/bindings/swift/CcapstoneTests/MinimalTests.swift index 0a5c5411af..9ef7961d73 100644 --- a/bindings/swift/CcapstoneTests/MinimalTests.swift +++ b/bindings/swift/CcapstoneTests/MinimalTests.swift @@ -1,26 +1,26 @@ import Foundation -import XCTest +import Testing @testable import Ccapstone /// Minimal tests that only use core Capstone functions /// These tests avoid architecture-specific functionality that requires complete linking -final class MinimalTests: XCTestCase { +@Suite struct MinimalTests { - func testVersionAPI() { + @Test func versionAPI() { var major: Int32 = 0 var minor: Int32 = 0 let version = cs_version(&major, &minor) - XCTAssertGreaterThan(major, 0, "Major version should be positive") - XCTAssertGreaterThanOrEqual(minor, 0, "Minor version should be non-negative") - XCTAssertGreaterThan(version, 0, "Combined version should be positive") - XCTAssertEqual(version, UInt32((major << 8) | minor), "Version should match expected format") + #expect(major > 0, "Major version should be positive") + #expect(minor >= 0, "Minor version should be non-negative") + #expect(version > 0, "Combined version should be positive") + #expect(version == UInt32((major << 8) | minor), "Version should match expected format") print("✓ Capstone version: \(major).\(minor) (0x\(String(format: "%04x", version)))") } - func testErrorStrings() { + @Test func errorStrings() { let testErrors: [(cs_err, String)] = [ (CS_ERR_OK, "OK"), (CS_ERR_MEM, "Memory"), @@ -34,46 +34,46 @@ final class MinimalTests: XCTestCase { print("\n✓ Testing error strings:") for (errorCode, description) in testErrors { let message = cs_strerror(errorCode) - XCTAssertNotNil(message, "Error message should not be nil for \(description)") + #expect(message != nil, "Error message should not be nil for \(description)") if let message = message { let errorString = String(cString: message) - XCTAssertFalse(errorString.isEmpty, "Error message should not be empty for \(description)") + #expect(!errorString.isEmpty, "Error message should not be empty for \(description)") print(" \(errorCode.rawValue) (\(description)): \(errorString)") } } } - func testBasicEnumValues() { + @Test func basicEnumValues() { // Test that enum values are accessible and have expected values - XCTAssertEqual(CS_ERR_OK.rawValue, 0, "CS_ERR_OK should be 0") - XCTAssertNotEqual(CS_ERR_ARCH.rawValue, 0, "CS_ERR_ARCH should not be 0") + #expect(CS_ERR_OK.rawValue == 0, "CS_ERR_OK should be 0") + #expect(CS_ERR_ARCH.rawValue != 0, "CS_ERR_ARCH should not be 0") // Test architecture enum values - XCTAssertEqual(CS_ARCH_ARM.rawValue, 0, "CS_ARCH_ARM should be 0") - XCTAssertEqual(CS_ARCH_AARCH64.rawValue, 1, "CS_ARCH_AARCH64 should be 1") - XCTAssertEqual(CS_ARCH_MIPS.rawValue, 3, "CS_ARCH_MIPS should be 3") - XCTAssertEqual(CS_ARCH_X86.rawValue, 4, "CS_ARCH_X86 should be 4") + #expect(CS_ARCH_ARM.rawValue == 0, "CS_ARCH_ARM should be 0") + #expect(CS_ARCH_AARCH64.rawValue == 1, "CS_ARCH_AARCH64 should be 1") + #expect(CS_ARCH_MIPS.rawValue == 3, "CS_ARCH_MIPS should be 3") + #expect(CS_ARCH_X86.rawValue == 4, "CS_ARCH_X86 should be 4") // Test mode enum values - XCTAssertEqual(CS_MODE_LITTLE_ENDIAN.rawValue, 0, "CS_MODE_LITTLE_ENDIAN should be 0") - XCTAssertEqual(CS_MODE_ARM.rawValue, 0, "CS_MODE_ARM should be 0") - XCTAssertEqual(CS_MODE_16.rawValue, 1 << 1, "CS_MODE_16 should be 2") - XCTAssertEqual(CS_MODE_32.rawValue, 1 << 2, "CS_MODE_32 should be 4") - XCTAssertEqual(CS_MODE_64.rawValue, 1 << 3, "CS_MODE_64 should be 8") + #expect(CS_MODE_LITTLE_ENDIAN.rawValue == 0, "CS_MODE_LITTLE_ENDIAN should be 0") + #expect(CS_MODE_ARM.rawValue == 0, "CS_MODE_ARM should be 0") + #expect(CS_MODE_16.rawValue == 1 << 1, "CS_MODE_16 should be 2") + #expect(CS_MODE_32.rawValue == 1 << 2, "CS_MODE_32 should be 4") + #expect(CS_MODE_64.rawValue == 1 << 3, "CS_MODE_64 should be 8") // Test option enum values - XCTAssertEqual(CS_OPT_INVALID.rawValue, 0, "CS_OPT_INVALID should be 0") - XCTAssertNotEqual(CS_OPT_DETAIL.rawValue, 0, "CS_OPT_DETAIL should not be 0") + #expect(CS_OPT_INVALID.rawValue == 0, "CS_OPT_INVALID should be 0") + #expect(CS_OPT_DETAIL.rawValue != 0, "CS_OPT_DETAIL should not be 0") // Test option values - XCTAssertEqual(CS_OPT_OFF.rawValue, 0, "CS_OPT_OFF should be 0") - XCTAssertEqual(CS_OPT_ON.rawValue, 1 << 0, "CS_OPT_ON should be 1") + #expect(CS_OPT_OFF.rawValue == 0, "CS_OPT_OFF should be 0") + #expect(CS_OPT_ON.rawValue == 1 << 0, "CS_OPT_ON should be 1") print("✓ All enum values are correctly defined") } - func testAPIFunctionAvailability() { + @Test func aPIFunctionAvailability() { // Test that all basic C functions are available (can be referenced) // This doesn't call them, just verifies they exist and can be linked @@ -95,52 +95,52 @@ final class MinimalTests: XCTestCase { print(" - \(name)") } - XCTAssertEqual(functions.count, 10, "All 10 basic functions should be available") + #expect(functions.count == 10, "All 10 basic functions should be available") } - func testInvalidParameters() { + @Test func invalidParameters() { // Test behavior with obviously invalid parameters // These should not crash but return error codes // Test cs_strerror with invalid error code let invalidErrorMsg = cs_strerror(cs_err(rawValue: 999)) - XCTAssertNotNil(invalidErrorMsg, "cs_strerror should handle invalid error codes") + #expect(invalidErrorMsg != nil, "cs_strerror should handle invalid error codes") // Test cs_errno with invalid handle let errno = cs_errno(0) // 0 is invalid handle - XCTAssertNotEqual(errno, CS_ERR_OK, "cs_errno should return error for invalid handle") + #expect(errno != CS_ERR_OK, "cs_errno should return error for invalid handle") print("✓ Invalid parameter handling works correctly") } - func testConstantValues() { + @Test func constantValues() { // Test important constant values - XCTAssertEqual(CS_MNEMONIC_SIZE, 32, "CS_MNEMONIC_SIZE should be 32") + #expect(CS_MNEMONIC_SIZE == 32, "CS_MNEMONIC_SIZE should be 32") print("✓ Constant values are correct") print(" CS_MNEMONIC_SIZE: \(CS_MNEMONIC_SIZE)") } - func testStructureSizes() { + @Test func structureSizes() { // Test that key structures have reasonable sizes let insnSize = MemoryLayout.size let detailSize = MemoryLayout.size - XCTAssertGreaterThan(insnSize, 0, "cs_insn structure should have positive size") - XCTAssertGreaterThan(detailSize, 0, "cs_detail structure should have positive size") + #expect(insnSize > 0, "cs_insn structure should have positive size") + #expect(detailSize > 0, "cs_detail structure should have positive size") print("✓ Structure sizes:") print(" cs_insn: \(insnSize) bytes") print(" cs_detail: \(detailSize) bytes") // cs_insn should be reasonably sized (has mnemonic, op_str, etc.) - XCTAssertGreaterThan(insnSize, 64, "cs_insn should be at least 64 bytes") + #expect(insnSize > 64, "cs_insn should be at least 64 bytes") // cs_detail should be large (has architecture-specific unions) - XCTAssertGreaterThan(detailSize, 100, "cs_detail should be at least 100 bytes") + #expect(detailSize > 100, "cs_detail should be at least 100 bytes") } - func testVersionConsistency() { + @Test func versionConsistency() { // Test version consistency across different calls var major1: Int32 = 0, minor1: Int32 = 0 var major2: Int32 = 0, minor2: Int32 = 0 @@ -148,13 +148,13 @@ final class MinimalTests: XCTestCase { let version1 = cs_version(&major1, &minor1) let version2 = cs_version(&major2, &minor2) - XCTAssertEqual(version1, version2, "Version should be consistent") - XCTAssertEqual(major1, major2, "Major version should be consistent") - XCTAssertEqual(minor1, minor2, "Minor version should be consistent") + #expect(version1 == version2, "Version should be consistent") + #expect(major1 == major2, "Major version should be consistent") + #expect(minor1 == minor2, "Minor version should be consistent") // Test CS_MAKE_VERSION macro equivalent let calculatedVersion = UInt32((major1 << 8) | minor1) - XCTAssertEqual(version1, calculatedVersion, "Version calculation should match macro") + #expect(version1 == calculatedVersion, "Version calculation should match macro") print("✓ Version consistency verified") } diff --git a/bindings/swift/CcapstoneTests/SimpleTests.swift b/bindings/swift/CcapstoneTests/SimpleTests.swift index 2666380dd9..71d41c03ed 100644 --- a/bindings/swift/CcapstoneTests/SimpleTests.swift +++ b/bindings/swift/CcapstoneTests/SimpleTests.swift @@ -1,23 +1,24 @@ -import XCTest +import Foundation +import Testing @testable import Ccapstone -final class SimpleTests: XCTestCase { +@Suite struct SimpleTests { - func testVersionOnly() { + @Test func versionOnly() { var major: Int32 = 0 var minor: Int32 = 0 let version = cs_version(&major, &minor) - XCTAssertGreaterThan(major, 0) - XCTAssertGreaterThanOrEqual(minor, 0) - XCTAssertGreaterThan(version, 0) - XCTAssertEqual(version, UInt32((major << 8) | minor)) + #expect(major > 0) + #expect(minor >= 0) + #expect(version > 0) + #expect(version == UInt32((major << 8) | minor)) print("Capstone version: \(major).\(minor) (0x\(String(format: "%04x", version)))") } - func testBasicAPIAvailability() { + @Test func basicAPIAvailability() { // Test that all basic functions are available // This doesn't actually call them, just verifies they can be referenced let _ = cs_open @@ -38,10 +39,10 @@ final class SimpleTests: XCTestCase { let _ = CS_OPT_DETAIL let _ = CS_OPT_ON - XCTAssertTrue(true, "All basic API functions are available") + #expect(true, "All basic API functions are available") } - func testErrorMessages() { + @Test func errorMessages() { let errorCodes: [cs_err] = [ CS_ERR_OK, CS_ERR_MEM, @@ -55,41 +56,41 @@ final class SimpleTests: XCTestCase { print("Testing error messages:") for errorCode in errorCodes { let message = cs_strerror(errorCode) - XCTAssertNotNil(message, "Error message should not be nil for \(errorCode)") + #expect(message != nil, "Error message should not be nil for \(errorCode)") if let message = message { let errorString = String(cString: message) - XCTAssertFalse(errorString.isEmpty, "Error message should not be empty for \(errorCode)") + #expect(!errorString.isEmpty, "Error message should not be empty for \(errorCode)") print(" \(errorCode.rawValue): \(errorString)") } } } - func testSimpleOpenClose() { + @Test func simpleOpenClose() { var handle: csh = 0 print("Testing cs_open...") let result = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) if result == CS_ERR_OK { print("✓ cs_open succeeded, handle: \(handle)") - XCTAssertNotEqual(handle, 0, "Handle should not be zero") + #expect(handle != 0, "Handle should not be zero") print("Testing cs_close...") let closeResult = cs_close(&handle) if closeResult == CS_ERR_OK { print("✓ cs_close succeeded") - XCTAssertEqual(handle, 0, "Handle should be zero after close") + #expect(handle == 0, "Handle should be zero after close") } else { let errorMsg = cs_strerror(closeResult) let errorString = errorMsg != nil ? String(cString: errorMsg!) : "Unknown error" print("✗ cs_close failed: \(errorString)") - XCTFail("cs_close failed with error: \(errorString)") + Issue.record("cs_close failed with error: \(errorString)") } } else { let errorMsg = cs_strerror(result) let errorString = errorMsg != nil ? String(cString: errorMsg!) : "Unknown error" print("✗ cs_open failed: \(errorString)") - XCTFail("cs_open failed with error: \(errorString)") + Issue.record("cs_open failed with error: \(errorString)") } } -} \ No newline at end of file +} diff --git a/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift b/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift index 1ed5f7934e..9e8dd02f29 100644 --- a/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift +++ b/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift @@ -10,7 +10,7 @@ struct SwiftIntegrationTests { private static let x86Code: [UInt8] = [0x8D, 0x4C, 0x32, 0x08, 0x01, 0xD8, 0x81, 0xC6, 0x34, 0x12, 0x00, 0x00] @Test("Swift optionals and error handling") - func testSwiftOptionals() async throws { + func swiftOptionals() async throws { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) @@ -44,7 +44,7 @@ struct SwiftIntegrationTests { } @Test("Swift memory management patterns") - func testSwiftMemoryManagement() async throws { + func swiftMemoryManagement() async throws { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) @@ -100,7 +100,7 @@ struct SwiftIntegrationTests { #expect(deferCount == bufferCount, "Both patterns should yield same results") // Test iterator pattern with automatic cleanup - func testIteratorPattern() -> Int { + func iteratorPattern() -> Int { guard let insn = cs_malloc(handle) else { return 0 } @@ -128,12 +128,12 @@ struct SwiftIntegrationTests { return instructionCount } - let iteratorCount = testIteratorPattern() + let iteratorCount = iteratorPattern() print(" Iterator pattern with automatic cleanup: \(iteratorCount) instructions") } @Test("Swift string handling and C interop") - func testSwiftStringHandling() async throws { + func swiftStringHandling() async throws { print("✓ Swift string handling and C interop:") // Test converting C strings to Swift strings @@ -171,7 +171,7 @@ struct SwiftIntegrationTests { } @Test("Swift array and collection integration") - func testSwiftCollectionIntegration() async throws { + func swiftCollectionIntegration() async throws { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) @@ -243,7 +243,7 @@ struct SwiftIntegrationTests { } @Test("Swift error handling patterns") - func testSwiftErrorHandling() async throws { + func swiftErrorHandling() async throws { print("✓ Swift error handling patterns:") // Define a Swift wrapper that throws @@ -330,7 +330,7 @@ struct SwiftIntegrationTests { } @Test("Swift value types and reference types") - func testSwiftValueAndReferenceTypes() async throws { + func swiftValueAndReferenceTypes() async throws { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) @@ -416,7 +416,7 @@ struct SwiftIntegrationTests { } @Test("Swift async/await compatibility") - func testAsyncAwaitCompatibility() async throws { + func asyncAwaitCompatibility() async throws { print("✓ Swift async/await compatibility:") // Test that Capstone operations can be used in async contexts @@ -466,7 +466,7 @@ struct SwiftIntegrationTests { } @Test("Swift generic and protocol integration") - func testGenericAndProtocolIntegration() async throws { + func genericAndProtocolIntegration() async throws { print("✓ Swift generic and protocol integration:") // Define protocols for Capstone operations @@ -530,11 +530,11 @@ struct SwiftIntegrationTests { print(" Set-derived array disassembly: \(setResult) instructions") // Test generic function - func testGenericDisassembly(_ provider: DisassemblyProvider, code: T) -> Int where T.Element == UInt8 { + func genericDisassembly(_ provider: DisassemblyProvider, code: T) -> Int where T.Element == UInt8 { return provider.disassemble(code) } - let genericResult = testGenericDisassembly(disassembler, code: Self.x86Code) + let genericResult = genericDisassembly(disassembler, code: Self.x86Code) print(" Generic function result: \(genericResult) instructions") #expect(arrayResult == genericResult, "Generic and direct calls should yield same results") From 851e787e8b53dce5cbb40fdac043d74a42b395e1 Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Sun, 21 Sep 2025 23:30:05 +0800 Subject: [PATCH 05/12] Add macOS testing to CI workflow --- .github/workflows/CITest.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/CITest.yml b/.github/workflows/CITest.yml index 0b1264f1f9..1d0f2e87bc 100644 --- a/.github/workflows/CITest.yml +++ b/.github/workflows/CITest.yml @@ -213,3 +213,27 @@ jobs: cmake --preset=${{ matrix.config.platform }}-x64 cmake --build --preset build-${{ matrix.config.platform }}-release cmake --build --preset install-${{ matrix.config.platform }}-release + macOS: + name: Execute tests on macOS + strategy: + fail-fast: false + matrix: + os: [macos-15] + xcode-version: ["16.4"] + runs-on: ${{ matrix.os }} + env: + GH_TOKEN: ${{ github.token }} + steps: + - uses: actions/checkout@v4 + - name: Setup Xcode + uses: ./.github/actions/setup-xcode + with: + xcode-version: ${{ matrix.xcode-version }} + - name: Build and run tests in debug mode + run: | + swift test \ + -c debug + - name: Build and run tests in release mode + run: | + swift test \ + -c release From b95162f4b08b65930914b6119bdd0a3a6fbb1442 Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Sat, 19 Jul 2025 14:13:01 +0800 Subject: [PATCH 06/12] Support SwiftPM --- Package.swift | 20 +++++++++++++++++++ bindings/swift/CCapstone/LEB128.h | 1 + bindings/swift/CCapstone/MCAsmInfo.h | 1 + bindings/swift/CCapstone/MCDisassembler.h | 1 + .../swift/CCapstone/MCFixedLenDisassembler.h | 1 + bindings/swift/CCapstone/MCInst.c | 1 + bindings/swift/CCapstone/MCInst.h | 1 + bindings/swift/CCapstone/MCInstPrinter.c | 1 + bindings/swift/CCapstone/MCInstPrinter.h | 1 + bindings/swift/CCapstone/MCInstrDesc.c | 1 + bindings/swift/CCapstone/MCInstrDesc.h | 1 + bindings/swift/CCapstone/MCRegisterInfo.c | 1 + bindings/swift/CCapstone/MCRegisterInfo.h | 1 + bindings/swift/CCapstone/Mapping.c | 1 + bindings/swift/CCapstone/Mapping.h | 1 + bindings/swift/CCapstone/MathExtras.h | 1 + bindings/swift/CCapstone/SStream.c | 1 + bindings/swift/CCapstone/SStream.h | 1 + bindings/swift/CCapstone/UpdateSymlink.sh | 12 +++++++++++ bindings/swift/CCapstone/arch | 1 + bindings/swift/CCapstone/cs.c | 1 + bindings/swift/CCapstone/cs_priv.h | 1 + bindings/swift/CCapstone/cs_simple_types.h | 1 + .../include/capstone/UpdateSymlink.sh | 11 ++++++++++ .../CCapstone/include/capstone/aarch64.h | 1 + .../swift/CCapstone/include/capstone/alpha.h | 1 + .../swift/CCapstone/include/capstone/arc.h | 1 + .../swift/CCapstone/include/capstone/arm.h | 1 + .../swift/CCapstone/include/capstone/arm64.h | 1 + .../swift/CCapstone/include/capstone/bpf.h | 1 + .../CCapstone/include/capstone/capstone.h | 1 + .../CCapstone/include/capstone/cs_operand.h | 1 + .../swift/CCapstone/include/capstone/evm.h | 1 + .../swift/CCapstone/include/capstone/hppa.h | 1 + .../CCapstone/include/capstone/loongarch.h | 1 + .../swift/CCapstone/include/capstone/m680x.h | 1 + .../swift/CCapstone/include/capstone/m68k.h | 1 + .../swift/CCapstone/include/capstone/mips.h | 1 + .../CCapstone/include/capstone/mos65xx.h | 1 + .../CCapstone/include/capstone/platform.h | 1 + .../swift/CCapstone/include/capstone/ppc.h | 1 + .../swift/CCapstone/include/capstone/riscv.h | 1 + .../swift/CCapstone/include/capstone/sh.h | 1 + .../swift/CCapstone/include/capstone/sparc.h | 1 + .../CCapstone/include/capstone/systemz.h | 1 + .../include/capstone/systemz_compatibility.h | 1 + .../CCapstone/include/capstone/tms320c64x.h | 1 + .../CCapstone/include/capstone/tricore.h | 1 + .../swift/CCapstone/include/capstone/wasm.h | 1 + .../swift/CCapstone/include/capstone/x86.h | 1 + .../swift/CCapstone/include/capstone/xcore.h | 1 + .../swift/CCapstone/include/capstone/xtensa.h | 1 + bindings/swift/CCapstone/utils.c | 1 + bindings/swift/CCapstone/utils.h | 1 + 54 files changed, 94 insertions(+) create mode 100644 Package.swift create mode 120000 bindings/swift/CCapstone/LEB128.h create mode 120000 bindings/swift/CCapstone/MCAsmInfo.h create mode 120000 bindings/swift/CCapstone/MCDisassembler.h create mode 120000 bindings/swift/CCapstone/MCFixedLenDisassembler.h create mode 120000 bindings/swift/CCapstone/MCInst.c create mode 120000 bindings/swift/CCapstone/MCInst.h create mode 120000 bindings/swift/CCapstone/MCInstPrinter.c create mode 120000 bindings/swift/CCapstone/MCInstPrinter.h create mode 120000 bindings/swift/CCapstone/MCInstrDesc.c create mode 120000 bindings/swift/CCapstone/MCInstrDesc.h create mode 120000 bindings/swift/CCapstone/MCRegisterInfo.c create mode 120000 bindings/swift/CCapstone/MCRegisterInfo.h create mode 120000 bindings/swift/CCapstone/Mapping.c create mode 120000 bindings/swift/CCapstone/Mapping.h create mode 120000 bindings/swift/CCapstone/MathExtras.h create mode 120000 bindings/swift/CCapstone/SStream.c create mode 120000 bindings/swift/CCapstone/SStream.h create mode 100755 bindings/swift/CCapstone/UpdateSymlink.sh create mode 120000 bindings/swift/CCapstone/arch create mode 120000 bindings/swift/CCapstone/cs.c create mode 120000 bindings/swift/CCapstone/cs_priv.h create mode 120000 bindings/swift/CCapstone/cs_simple_types.h create mode 100755 bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh create mode 120000 bindings/swift/CCapstone/include/capstone/aarch64.h create mode 120000 bindings/swift/CCapstone/include/capstone/alpha.h create mode 120000 bindings/swift/CCapstone/include/capstone/arc.h create mode 120000 bindings/swift/CCapstone/include/capstone/arm.h create mode 120000 bindings/swift/CCapstone/include/capstone/arm64.h create mode 120000 bindings/swift/CCapstone/include/capstone/bpf.h create mode 120000 bindings/swift/CCapstone/include/capstone/capstone.h create mode 120000 bindings/swift/CCapstone/include/capstone/cs_operand.h create mode 120000 bindings/swift/CCapstone/include/capstone/evm.h create mode 120000 bindings/swift/CCapstone/include/capstone/hppa.h create mode 120000 bindings/swift/CCapstone/include/capstone/loongarch.h create mode 120000 bindings/swift/CCapstone/include/capstone/m680x.h create mode 120000 bindings/swift/CCapstone/include/capstone/m68k.h create mode 120000 bindings/swift/CCapstone/include/capstone/mips.h create mode 120000 bindings/swift/CCapstone/include/capstone/mos65xx.h create mode 120000 bindings/swift/CCapstone/include/capstone/platform.h create mode 120000 bindings/swift/CCapstone/include/capstone/ppc.h create mode 120000 bindings/swift/CCapstone/include/capstone/riscv.h create mode 120000 bindings/swift/CCapstone/include/capstone/sh.h create mode 120000 bindings/swift/CCapstone/include/capstone/sparc.h create mode 120000 bindings/swift/CCapstone/include/capstone/systemz.h create mode 120000 bindings/swift/CCapstone/include/capstone/systemz_compatibility.h create mode 120000 bindings/swift/CCapstone/include/capstone/tms320c64x.h create mode 120000 bindings/swift/CCapstone/include/capstone/tricore.h create mode 120000 bindings/swift/CCapstone/include/capstone/wasm.h create mode 120000 bindings/swift/CCapstone/include/capstone/x86.h create mode 120000 bindings/swift/CCapstone/include/capstone/xcore.h create mode 120000 bindings/swift/CCapstone/include/capstone/xtensa.h create mode 120000 bindings/swift/CCapstone/utils.c create mode 120000 bindings/swift/CCapstone/utils.h diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000000..c8ec38a161 --- /dev/null +++ b/Package.swift @@ -0,0 +1,20 @@ +// swift-tools-version: 6.1 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "capstone", + products: [ + .library( + name: "CCapstone", + targets: ["CCapstone"] + ), + ], + targets: [ + .target( + name: "CCapstone", + path: "bindings/swift/CCapstone", + ), + ] +) diff --git a/bindings/swift/CCapstone/LEB128.h b/bindings/swift/CCapstone/LEB128.h new file mode 120000 index 0000000000..371e091330 --- /dev/null +++ b/bindings/swift/CCapstone/LEB128.h @@ -0,0 +1 @@ +../../../LEB128.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCAsmInfo.h b/bindings/swift/CCapstone/MCAsmInfo.h new file mode 120000 index 0000000000..31ab35ea22 --- /dev/null +++ b/bindings/swift/CCapstone/MCAsmInfo.h @@ -0,0 +1 @@ +../../../MCAsmInfo.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCDisassembler.h b/bindings/swift/CCapstone/MCDisassembler.h new file mode 120000 index 0000000000..6ea5de0e0d --- /dev/null +++ b/bindings/swift/CCapstone/MCDisassembler.h @@ -0,0 +1 @@ +../../../MCDisassembler.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCFixedLenDisassembler.h b/bindings/swift/CCapstone/MCFixedLenDisassembler.h new file mode 120000 index 0000000000..123782ab1f --- /dev/null +++ b/bindings/swift/CCapstone/MCFixedLenDisassembler.h @@ -0,0 +1 @@ +../../../MCFixedLenDisassembler.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInst.c b/bindings/swift/CCapstone/MCInst.c new file mode 120000 index 0000000000..4ba686ffdc --- /dev/null +++ b/bindings/swift/CCapstone/MCInst.c @@ -0,0 +1 @@ +../../../MCInst.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInst.h b/bindings/swift/CCapstone/MCInst.h new file mode 120000 index 0000000000..0044b5a6f1 --- /dev/null +++ b/bindings/swift/CCapstone/MCInst.h @@ -0,0 +1 @@ +../../../MCInst.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInstPrinter.c b/bindings/swift/CCapstone/MCInstPrinter.c new file mode 120000 index 0000000000..6a4081296b --- /dev/null +++ b/bindings/swift/CCapstone/MCInstPrinter.c @@ -0,0 +1 @@ +../../../MCInstPrinter.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInstPrinter.h b/bindings/swift/CCapstone/MCInstPrinter.h new file mode 120000 index 0000000000..386cb88aea --- /dev/null +++ b/bindings/swift/CCapstone/MCInstPrinter.h @@ -0,0 +1 @@ +../../../MCInstPrinter.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInstrDesc.c b/bindings/swift/CCapstone/MCInstrDesc.c new file mode 120000 index 0000000000..73e916fe5a --- /dev/null +++ b/bindings/swift/CCapstone/MCInstrDesc.c @@ -0,0 +1 @@ +../../../MCInstrDesc.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCInstrDesc.h b/bindings/swift/CCapstone/MCInstrDesc.h new file mode 120000 index 0000000000..294dee6759 --- /dev/null +++ b/bindings/swift/CCapstone/MCInstrDesc.h @@ -0,0 +1 @@ +../../../MCInstrDesc.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCRegisterInfo.c b/bindings/swift/CCapstone/MCRegisterInfo.c new file mode 120000 index 0000000000..caaa608336 --- /dev/null +++ b/bindings/swift/CCapstone/MCRegisterInfo.c @@ -0,0 +1 @@ +../../../MCRegisterInfo.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/MCRegisterInfo.h b/bindings/swift/CCapstone/MCRegisterInfo.h new file mode 120000 index 0000000000..6db0beb49f --- /dev/null +++ b/bindings/swift/CCapstone/MCRegisterInfo.h @@ -0,0 +1 @@ +../../../MCRegisterInfo.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/Mapping.c b/bindings/swift/CCapstone/Mapping.c new file mode 120000 index 0000000000..3e10b8e7b6 --- /dev/null +++ b/bindings/swift/CCapstone/Mapping.c @@ -0,0 +1 @@ +../../../Mapping.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/Mapping.h b/bindings/swift/CCapstone/Mapping.h new file mode 120000 index 0000000000..69bdb7d354 --- /dev/null +++ b/bindings/swift/CCapstone/Mapping.h @@ -0,0 +1 @@ +../../../Mapping.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/MathExtras.h b/bindings/swift/CCapstone/MathExtras.h new file mode 120000 index 0000000000..5034ce41d9 --- /dev/null +++ b/bindings/swift/CCapstone/MathExtras.h @@ -0,0 +1 @@ +../../../MathExtras.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/SStream.c b/bindings/swift/CCapstone/SStream.c new file mode 120000 index 0000000000..c744dfa1f8 --- /dev/null +++ b/bindings/swift/CCapstone/SStream.c @@ -0,0 +1 @@ +../../../SStream.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/SStream.h b/bindings/swift/CCapstone/SStream.h new file mode 120000 index 0000000000..2f4e1515fd --- /dev/null +++ b/bindings/swift/CCapstone/SStream.h @@ -0,0 +1 @@ +../../../SStream.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/UpdateSymlink.sh b/bindings/swift/CCapstone/UpdateSymlink.sh new file mode 100755 index 0000000000..e859bc7c1c --- /dev/null +++ b/bindings/swift/CCapstone/UpdateSymlink.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +target_dir="../../.." + +find "$target_dir" -maxdepth 1 \( -name "*.h" -o -name "*.c" \) -print0 | while IFS= read -r -d $'\0' header_file; do + + relative_path=$(echo "$header_file" | sed "s#^$PWD/##") + + ln -s "$relative_path" . + + echo "Created symlink: $(basename "$header_file") -> $relative_path" +done diff --git a/bindings/swift/CCapstone/arch b/bindings/swift/CCapstone/arch new file mode 120000 index 0000000000..c96956df19 --- /dev/null +++ b/bindings/swift/CCapstone/arch @@ -0,0 +1 @@ +../../../arch \ No newline at end of file diff --git a/bindings/swift/CCapstone/cs.c b/bindings/swift/CCapstone/cs.c new file mode 120000 index 0000000000..f3de1cec49 --- /dev/null +++ b/bindings/swift/CCapstone/cs.c @@ -0,0 +1 @@ +../../../cs.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/cs_priv.h b/bindings/swift/CCapstone/cs_priv.h new file mode 120000 index 0000000000..ae5dd91549 --- /dev/null +++ b/bindings/swift/CCapstone/cs_priv.h @@ -0,0 +1 @@ +../../../cs_priv.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/cs_simple_types.h b/bindings/swift/CCapstone/cs_simple_types.h new file mode 120000 index 0000000000..0a33a17b44 --- /dev/null +++ b/bindings/swift/CCapstone/cs_simple_types.h @@ -0,0 +1 @@ +../../../cs_simple_types.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh b/bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh new file mode 100755 index 0000000000..227b4220e5 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +target_dir="../../../../../include/capstone" + +find "$target_dir" -name "*.h" -print0 | while IFS= read -r -d $'\0' header_file; do + relative_path=$(echo "$header_file" | sed "s#^$PWD/##") + + ln -s "$relative_path" . + + echo "Created symlink: $(basename "$header_file") -> $relative_path" +done diff --git a/bindings/swift/CCapstone/include/capstone/aarch64.h b/bindings/swift/CCapstone/include/capstone/aarch64.h new file mode 120000 index 0000000000..ffc5977379 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/aarch64.h @@ -0,0 +1 @@ +../../../../../include/capstone/aarch64.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/alpha.h b/bindings/swift/CCapstone/include/capstone/alpha.h new file mode 120000 index 0000000000..22833d9929 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/alpha.h @@ -0,0 +1 @@ +../../../../../include/capstone/alpha.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/arc.h b/bindings/swift/CCapstone/include/capstone/arc.h new file mode 120000 index 0000000000..ef9ea57a33 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/arc.h @@ -0,0 +1 @@ +../../../../../include/capstone/arc.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/arm.h b/bindings/swift/CCapstone/include/capstone/arm.h new file mode 120000 index 0000000000..69727b0f41 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/arm.h @@ -0,0 +1 @@ +../../../../../include/capstone/arm.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/arm64.h b/bindings/swift/CCapstone/include/capstone/arm64.h new file mode 120000 index 0000000000..d2f4951d52 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/arm64.h @@ -0,0 +1 @@ +../../../../../include/capstone/arm64.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/bpf.h b/bindings/swift/CCapstone/include/capstone/bpf.h new file mode 120000 index 0000000000..17ef426656 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/bpf.h @@ -0,0 +1 @@ +../../../../../include/capstone/bpf.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/capstone.h b/bindings/swift/CCapstone/include/capstone/capstone.h new file mode 120000 index 0000000000..83845c68c0 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/capstone.h @@ -0,0 +1 @@ +../../../../../include/capstone/capstone.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/cs_operand.h b/bindings/swift/CCapstone/include/capstone/cs_operand.h new file mode 120000 index 0000000000..206ec46ecc --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/cs_operand.h @@ -0,0 +1 @@ +../../../../../include/capstone/cs_operand.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/evm.h b/bindings/swift/CCapstone/include/capstone/evm.h new file mode 120000 index 0000000000..c99a289ca9 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/evm.h @@ -0,0 +1 @@ +../../../../../include/capstone/evm.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/hppa.h b/bindings/swift/CCapstone/include/capstone/hppa.h new file mode 120000 index 0000000000..57c266124c --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/hppa.h @@ -0,0 +1 @@ +../../../../../include/capstone/hppa.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/loongarch.h b/bindings/swift/CCapstone/include/capstone/loongarch.h new file mode 120000 index 0000000000..a4c0baaa26 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/loongarch.h @@ -0,0 +1 @@ +../../../../../include/capstone/loongarch.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/m680x.h b/bindings/swift/CCapstone/include/capstone/m680x.h new file mode 120000 index 0000000000..5edfe318c7 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/m680x.h @@ -0,0 +1 @@ +../../../../../include/capstone/m680x.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/m68k.h b/bindings/swift/CCapstone/include/capstone/m68k.h new file mode 120000 index 0000000000..d5abdeb03e --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/m68k.h @@ -0,0 +1 @@ +../../../../../include/capstone/m68k.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/mips.h b/bindings/swift/CCapstone/include/capstone/mips.h new file mode 120000 index 0000000000..bff4dd303d --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/mips.h @@ -0,0 +1 @@ +../../../../../include/capstone/mips.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/mos65xx.h b/bindings/swift/CCapstone/include/capstone/mos65xx.h new file mode 120000 index 0000000000..5f3e52e288 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/mos65xx.h @@ -0,0 +1 @@ +../../../../../include/capstone/mos65xx.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/platform.h b/bindings/swift/CCapstone/include/capstone/platform.h new file mode 120000 index 0000000000..dd63320910 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/platform.h @@ -0,0 +1 @@ +../../../../../include/capstone/platform.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/ppc.h b/bindings/swift/CCapstone/include/capstone/ppc.h new file mode 120000 index 0000000000..292bf2bda6 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/ppc.h @@ -0,0 +1 @@ +../../../../../include/capstone/ppc.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/riscv.h b/bindings/swift/CCapstone/include/capstone/riscv.h new file mode 120000 index 0000000000..5e914a7454 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/riscv.h @@ -0,0 +1 @@ +../../../../../include/capstone/riscv.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/sh.h b/bindings/swift/CCapstone/include/capstone/sh.h new file mode 120000 index 0000000000..0d149e4dd6 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/sh.h @@ -0,0 +1 @@ +../../../../../include/capstone/sh.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/sparc.h b/bindings/swift/CCapstone/include/capstone/sparc.h new file mode 120000 index 0000000000..2c1db54bfd --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/sparc.h @@ -0,0 +1 @@ +../../../../../include/capstone/sparc.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/systemz.h b/bindings/swift/CCapstone/include/capstone/systemz.h new file mode 120000 index 0000000000..c4bcec06ee --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/systemz.h @@ -0,0 +1 @@ +../../../../../include/capstone/systemz.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/systemz_compatibility.h b/bindings/swift/CCapstone/include/capstone/systemz_compatibility.h new file mode 120000 index 0000000000..d42c47dea9 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/systemz_compatibility.h @@ -0,0 +1 @@ +../../../../../include/capstone/systemz_compatibility.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/tms320c64x.h b/bindings/swift/CCapstone/include/capstone/tms320c64x.h new file mode 120000 index 0000000000..83a88a41de --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/tms320c64x.h @@ -0,0 +1 @@ +../../../../../include/capstone/tms320c64x.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/tricore.h b/bindings/swift/CCapstone/include/capstone/tricore.h new file mode 120000 index 0000000000..2095a7903e --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/tricore.h @@ -0,0 +1 @@ +../../../../../include/capstone/tricore.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/wasm.h b/bindings/swift/CCapstone/include/capstone/wasm.h new file mode 120000 index 0000000000..6850e121c3 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/wasm.h @@ -0,0 +1 @@ +../../../../../include/capstone/wasm.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/x86.h b/bindings/swift/CCapstone/include/capstone/x86.h new file mode 120000 index 0000000000..62e0f8e0cb --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/x86.h @@ -0,0 +1 @@ +../../../../../include/capstone/x86.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/xcore.h b/bindings/swift/CCapstone/include/capstone/xcore.h new file mode 120000 index 0000000000..66dde9902e --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/xcore.h @@ -0,0 +1 @@ +../../../../../include/capstone/xcore.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/include/capstone/xtensa.h b/bindings/swift/CCapstone/include/capstone/xtensa.h new file mode 120000 index 0000000000..8b64b00556 --- /dev/null +++ b/bindings/swift/CCapstone/include/capstone/xtensa.h @@ -0,0 +1 @@ +../../../../../include/capstone/xtensa.h \ No newline at end of file diff --git a/bindings/swift/CCapstone/utils.c b/bindings/swift/CCapstone/utils.c new file mode 120000 index 0000000000..37965fc4bc --- /dev/null +++ b/bindings/swift/CCapstone/utils.c @@ -0,0 +1 @@ +../../../utils.c \ No newline at end of file diff --git a/bindings/swift/CCapstone/utils.h b/bindings/swift/CCapstone/utils.h new file mode 120000 index 0000000000..bb469b1eb3 --- /dev/null +++ b/bindings/swift/CCapstone/utils.h @@ -0,0 +1 @@ +../../../utils.h \ No newline at end of file From ea35f8e391563297452ae75e26cb488451e14d54 Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Sat, 19 Jul 2025 14:19:16 +0800 Subject: [PATCH 07/12] Update target name --- Package.swift | 8 ++++---- bindings/swift/{CCapstone => Ccapstone}/LEB128.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCAsmInfo.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCDisassembler.h | 0 .../{CCapstone => Ccapstone}/MCFixedLenDisassembler.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCInst.c | 0 bindings/swift/{CCapstone => Ccapstone}/MCInst.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCInstPrinter.c | 0 bindings/swift/{CCapstone => Ccapstone}/MCInstPrinter.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCInstrDesc.c | 0 bindings/swift/{CCapstone => Ccapstone}/MCInstrDesc.h | 0 bindings/swift/{CCapstone => Ccapstone}/MCRegisterInfo.c | 0 bindings/swift/{CCapstone => Ccapstone}/MCRegisterInfo.h | 0 bindings/swift/{CCapstone => Ccapstone}/Mapping.c | 0 bindings/swift/{CCapstone => Ccapstone}/Mapping.h | 0 bindings/swift/{CCapstone => Ccapstone}/MathExtras.h | 0 bindings/swift/{CCapstone => Ccapstone}/SStream.c | 0 bindings/swift/{CCapstone => Ccapstone}/SStream.h | 0 bindings/swift/{CCapstone => Ccapstone}/UpdateSymlink.sh | 0 bindings/swift/{CCapstone => Ccapstone}/arch | 0 bindings/swift/{CCapstone => Ccapstone}/cs.c | 0 bindings/swift/{CCapstone => Ccapstone}/cs_priv.h | 0 bindings/swift/{CCapstone => Ccapstone}/cs_simple_types.h | 0 .../include/capstone/UpdateSymlink.sh | 0 .../{CCapstone => Ccapstone}/include/capstone/aarch64.h | 0 .../{CCapstone => Ccapstone}/include/capstone/alpha.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/arc.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/arm.h | 0 .../{CCapstone => Ccapstone}/include/capstone/arm64.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/bpf.h | 0 .../{CCapstone => Ccapstone}/include/capstone/capstone.h | 0 .../include/capstone/cs_operand.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/evm.h | 0 .../{CCapstone => Ccapstone}/include/capstone/hppa.h | 0 .../{CCapstone => Ccapstone}/include/capstone/loongarch.h | 0 .../{CCapstone => Ccapstone}/include/capstone/m680x.h | 0 .../{CCapstone => Ccapstone}/include/capstone/m68k.h | 0 .../{CCapstone => Ccapstone}/include/capstone/mips.h | 0 .../{CCapstone => Ccapstone}/include/capstone/mos65xx.h | 0 .../{CCapstone => Ccapstone}/include/capstone/platform.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/ppc.h | 0 .../{CCapstone => Ccapstone}/include/capstone/riscv.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/sh.h | 0 .../{CCapstone => Ccapstone}/include/capstone/sparc.h | 0 .../{CCapstone => Ccapstone}/include/capstone/systemz.h | 0 .../include/capstone/systemz_compatibility.h | 0 .../include/capstone/tms320c64x.h | 0 .../{CCapstone => Ccapstone}/include/capstone/tricore.h | 0 .../{CCapstone => Ccapstone}/include/capstone/wasm.h | 0 .../swift/{CCapstone => Ccapstone}/include/capstone/x86.h | 0 .../{CCapstone => Ccapstone}/include/capstone/xcore.h | 0 .../{CCapstone => Ccapstone}/include/capstone/xtensa.h | 0 bindings/swift/{CCapstone => Ccapstone}/utils.c | 0 bindings/swift/{CCapstone => Ccapstone}/utils.h | 0 54 files changed, 4 insertions(+), 4 deletions(-) rename bindings/swift/{CCapstone => Ccapstone}/LEB128.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCAsmInfo.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCDisassembler.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCFixedLenDisassembler.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInst.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInst.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInstPrinter.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInstPrinter.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInstrDesc.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCInstrDesc.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCRegisterInfo.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/MCRegisterInfo.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/Mapping.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/Mapping.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/MathExtras.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/SStream.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/SStream.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/UpdateSymlink.sh (100%) rename bindings/swift/{CCapstone => Ccapstone}/arch (100%) rename bindings/swift/{CCapstone => Ccapstone}/cs.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/cs_priv.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/cs_simple_types.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/UpdateSymlink.sh (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/aarch64.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/alpha.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/arc.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/arm.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/arm64.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/bpf.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/capstone.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/cs_operand.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/evm.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/hppa.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/loongarch.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/m680x.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/m68k.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/mips.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/mos65xx.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/platform.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/ppc.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/riscv.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/sh.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/sparc.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/systemz.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/systemz_compatibility.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/tms320c64x.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/tricore.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/wasm.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/x86.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/xcore.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/include/capstone/xtensa.h (100%) rename bindings/swift/{CCapstone => Ccapstone}/utils.c (100%) rename bindings/swift/{CCapstone => Ccapstone}/utils.h (100%) diff --git a/Package.swift b/Package.swift index c8ec38a161..70e418947b 100644 --- a/Package.swift +++ b/Package.swift @@ -7,14 +7,14 @@ let package = Package( name: "capstone", products: [ .library( - name: "CCapstone", - targets: ["CCapstone"] + name: "Ccapstone", + targets: ["Ccapstone"] ), ], targets: [ .target( - name: "CCapstone", - path: "bindings/swift/CCapstone", + name: "Ccapstone", + path: "bindings/swift/Ccapstone", ), ] ) diff --git a/bindings/swift/CCapstone/LEB128.h b/bindings/swift/Ccapstone/LEB128.h similarity index 100% rename from bindings/swift/CCapstone/LEB128.h rename to bindings/swift/Ccapstone/LEB128.h diff --git a/bindings/swift/CCapstone/MCAsmInfo.h b/bindings/swift/Ccapstone/MCAsmInfo.h similarity index 100% rename from bindings/swift/CCapstone/MCAsmInfo.h rename to bindings/swift/Ccapstone/MCAsmInfo.h diff --git a/bindings/swift/CCapstone/MCDisassembler.h b/bindings/swift/Ccapstone/MCDisassembler.h similarity index 100% rename from bindings/swift/CCapstone/MCDisassembler.h rename to bindings/swift/Ccapstone/MCDisassembler.h diff --git a/bindings/swift/CCapstone/MCFixedLenDisassembler.h b/bindings/swift/Ccapstone/MCFixedLenDisassembler.h similarity index 100% rename from bindings/swift/CCapstone/MCFixedLenDisassembler.h rename to bindings/swift/Ccapstone/MCFixedLenDisassembler.h diff --git a/bindings/swift/CCapstone/MCInst.c b/bindings/swift/Ccapstone/MCInst.c similarity index 100% rename from bindings/swift/CCapstone/MCInst.c rename to bindings/swift/Ccapstone/MCInst.c diff --git a/bindings/swift/CCapstone/MCInst.h b/bindings/swift/Ccapstone/MCInst.h similarity index 100% rename from bindings/swift/CCapstone/MCInst.h rename to bindings/swift/Ccapstone/MCInst.h diff --git a/bindings/swift/CCapstone/MCInstPrinter.c b/bindings/swift/Ccapstone/MCInstPrinter.c similarity index 100% rename from bindings/swift/CCapstone/MCInstPrinter.c rename to bindings/swift/Ccapstone/MCInstPrinter.c diff --git a/bindings/swift/CCapstone/MCInstPrinter.h b/bindings/swift/Ccapstone/MCInstPrinter.h similarity index 100% rename from bindings/swift/CCapstone/MCInstPrinter.h rename to bindings/swift/Ccapstone/MCInstPrinter.h diff --git a/bindings/swift/CCapstone/MCInstrDesc.c b/bindings/swift/Ccapstone/MCInstrDesc.c similarity index 100% rename from bindings/swift/CCapstone/MCInstrDesc.c rename to bindings/swift/Ccapstone/MCInstrDesc.c diff --git a/bindings/swift/CCapstone/MCInstrDesc.h b/bindings/swift/Ccapstone/MCInstrDesc.h similarity index 100% rename from bindings/swift/CCapstone/MCInstrDesc.h rename to bindings/swift/Ccapstone/MCInstrDesc.h diff --git a/bindings/swift/CCapstone/MCRegisterInfo.c b/bindings/swift/Ccapstone/MCRegisterInfo.c similarity index 100% rename from bindings/swift/CCapstone/MCRegisterInfo.c rename to bindings/swift/Ccapstone/MCRegisterInfo.c diff --git a/bindings/swift/CCapstone/MCRegisterInfo.h b/bindings/swift/Ccapstone/MCRegisterInfo.h similarity index 100% rename from bindings/swift/CCapstone/MCRegisterInfo.h rename to bindings/swift/Ccapstone/MCRegisterInfo.h diff --git a/bindings/swift/CCapstone/Mapping.c b/bindings/swift/Ccapstone/Mapping.c similarity index 100% rename from bindings/swift/CCapstone/Mapping.c rename to bindings/swift/Ccapstone/Mapping.c diff --git a/bindings/swift/CCapstone/Mapping.h b/bindings/swift/Ccapstone/Mapping.h similarity index 100% rename from bindings/swift/CCapstone/Mapping.h rename to bindings/swift/Ccapstone/Mapping.h diff --git a/bindings/swift/CCapstone/MathExtras.h b/bindings/swift/Ccapstone/MathExtras.h similarity index 100% rename from bindings/swift/CCapstone/MathExtras.h rename to bindings/swift/Ccapstone/MathExtras.h diff --git a/bindings/swift/CCapstone/SStream.c b/bindings/swift/Ccapstone/SStream.c similarity index 100% rename from bindings/swift/CCapstone/SStream.c rename to bindings/swift/Ccapstone/SStream.c diff --git a/bindings/swift/CCapstone/SStream.h b/bindings/swift/Ccapstone/SStream.h similarity index 100% rename from bindings/swift/CCapstone/SStream.h rename to bindings/swift/Ccapstone/SStream.h diff --git a/bindings/swift/CCapstone/UpdateSymlink.sh b/bindings/swift/Ccapstone/UpdateSymlink.sh similarity index 100% rename from bindings/swift/CCapstone/UpdateSymlink.sh rename to bindings/swift/Ccapstone/UpdateSymlink.sh diff --git a/bindings/swift/CCapstone/arch b/bindings/swift/Ccapstone/arch similarity index 100% rename from bindings/swift/CCapstone/arch rename to bindings/swift/Ccapstone/arch diff --git a/bindings/swift/CCapstone/cs.c b/bindings/swift/Ccapstone/cs.c similarity index 100% rename from bindings/swift/CCapstone/cs.c rename to bindings/swift/Ccapstone/cs.c diff --git a/bindings/swift/CCapstone/cs_priv.h b/bindings/swift/Ccapstone/cs_priv.h similarity index 100% rename from bindings/swift/CCapstone/cs_priv.h rename to bindings/swift/Ccapstone/cs_priv.h diff --git a/bindings/swift/CCapstone/cs_simple_types.h b/bindings/swift/Ccapstone/cs_simple_types.h similarity index 100% rename from bindings/swift/CCapstone/cs_simple_types.h rename to bindings/swift/Ccapstone/cs_simple_types.h diff --git a/bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh b/bindings/swift/Ccapstone/include/capstone/UpdateSymlink.sh similarity index 100% rename from bindings/swift/CCapstone/include/capstone/UpdateSymlink.sh rename to bindings/swift/Ccapstone/include/capstone/UpdateSymlink.sh diff --git a/bindings/swift/CCapstone/include/capstone/aarch64.h b/bindings/swift/Ccapstone/include/capstone/aarch64.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/aarch64.h rename to bindings/swift/Ccapstone/include/capstone/aarch64.h diff --git a/bindings/swift/CCapstone/include/capstone/alpha.h b/bindings/swift/Ccapstone/include/capstone/alpha.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/alpha.h rename to bindings/swift/Ccapstone/include/capstone/alpha.h diff --git a/bindings/swift/CCapstone/include/capstone/arc.h b/bindings/swift/Ccapstone/include/capstone/arc.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/arc.h rename to bindings/swift/Ccapstone/include/capstone/arc.h diff --git a/bindings/swift/CCapstone/include/capstone/arm.h b/bindings/swift/Ccapstone/include/capstone/arm.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/arm.h rename to bindings/swift/Ccapstone/include/capstone/arm.h diff --git a/bindings/swift/CCapstone/include/capstone/arm64.h b/bindings/swift/Ccapstone/include/capstone/arm64.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/arm64.h rename to bindings/swift/Ccapstone/include/capstone/arm64.h diff --git a/bindings/swift/CCapstone/include/capstone/bpf.h b/bindings/swift/Ccapstone/include/capstone/bpf.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/bpf.h rename to bindings/swift/Ccapstone/include/capstone/bpf.h diff --git a/bindings/swift/CCapstone/include/capstone/capstone.h b/bindings/swift/Ccapstone/include/capstone/capstone.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/capstone.h rename to bindings/swift/Ccapstone/include/capstone/capstone.h diff --git a/bindings/swift/CCapstone/include/capstone/cs_operand.h b/bindings/swift/Ccapstone/include/capstone/cs_operand.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/cs_operand.h rename to bindings/swift/Ccapstone/include/capstone/cs_operand.h diff --git a/bindings/swift/CCapstone/include/capstone/evm.h b/bindings/swift/Ccapstone/include/capstone/evm.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/evm.h rename to bindings/swift/Ccapstone/include/capstone/evm.h diff --git a/bindings/swift/CCapstone/include/capstone/hppa.h b/bindings/swift/Ccapstone/include/capstone/hppa.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/hppa.h rename to bindings/swift/Ccapstone/include/capstone/hppa.h diff --git a/bindings/swift/CCapstone/include/capstone/loongarch.h b/bindings/swift/Ccapstone/include/capstone/loongarch.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/loongarch.h rename to bindings/swift/Ccapstone/include/capstone/loongarch.h diff --git a/bindings/swift/CCapstone/include/capstone/m680x.h b/bindings/swift/Ccapstone/include/capstone/m680x.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/m680x.h rename to bindings/swift/Ccapstone/include/capstone/m680x.h diff --git a/bindings/swift/CCapstone/include/capstone/m68k.h b/bindings/swift/Ccapstone/include/capstone/m68k.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/m68k.h rename to bindings/swift/Ccapstone/include/capstone/m68k.h diff --git a/bindings/swift/CCapstone/include/capstone/mips.h b/bindings/swift/Ccapstone/include/capstone/mips.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/mips.h rename to bindings/swift/Ccapstone/include/capstone/mips.h diff --git a/bindings/swift/CCapstone/include/capstone/mos65xx.h b/bindings/swift/Ccapstone/include/capstone/mos65xx.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/mos65xx.h rename to bindings/swift/Ccapstone/include/capstone/mos65xx.h diff --git a/bindings/swift/CCapstone/include/capstone/platform.h b/bindings/swift/Ccapstone/include/capstone/platform.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/platform.h rename to bindings/swift/Ccapstone/include/capstone/platform.h diff --git a/bindings/swift/CCapstone/include/capstone/ppc.h b/bindings/swift/Ccapstone/include/capstone/ppc.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/ppc.h rename to bindings/swift/Ccapstone/include/capstone/ppc.h diff --git a/bindings/swift/CCapstone/include/capstone/riscv.h b/bindings/swift/Ccapstone/include/capstone/riscv.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/riscv.h rename to bindings/swift/Ccapstone/include/capstone/riscv.h diff --git a/bindings/swift/CCapstone/include/capstone/sh.h b/bindings/swift/Ccapstone/include/capstone/sh.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/sh.h rename to bindings/swift/Ccapstone/include/capstone/sh.h diff --git a/bindings/swift/CCapstone/include/capstone/sparc.h b/bindings/swift/Ccapstone/include/capstone/sparc.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/sparc.h rename to bindings/swift/Ccapstone/include/capstone/sparc.h diff --git a/bindings/swift/CCapstone/include/capstone/systemz.h b/bindings/swift/Ccapstone/include/capstone/systemz.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/systemz.h rename to bindings/swift/Ccapstone/include/capstone/systemz.h diff --git a/bindings/swift/CCapstone/include/capstone/systemz_compatibility.h b/bindings/swift/Ccapstone/include/capstone/systemz_compatibility.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/systemz_compatibility.h rename to bindings/swift/Ccapstone/include/capstone/systemz_compatibility.h diff --git a/bindings/swift/CCapstone/include/capstone/tms320c64x.h b/bindings/swift/Ccapstone/include/capstone/tms320c64x.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/tms320c64x.h rename to bindings/swift/Ccapstone/include/capstone/tms320c64x.h diff --git a/bindings/swift/CCapstone/include/capstone/tricore.h b/bindings/swift/Ccapstone/include/capstone/tricore.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/tricore.h rename to bindings/swift/Ccapstone/include/capstone/tricore.h diff --git a/bindings/swift/CCapstone/include/capstone/wasm.h b/bindings/swift/Ccapstone/include/capstone/wasm.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/wasm.h rename to bindings/swift/Ccapstone/include/capstone/wasm.h diff --git a/bindings/swift/CCapstone/include/capstone/x86.h b/bindings/swift/Ccapstone/include/capstone/x86.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/x86.h rename to bindings/swift/Ccapstone/include/capstone/x86.h diff --git a/bindings/swift/CCapstone/include/capstone/xcore.h b/bindings/swift/Ccapstone/include/capstone/xcore.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/xcore.h rename to bindings/swift/Ccapstone/include/capstone/xcore.h diff --git a/bindings/swift/CCapstone/include/capstone/xtensa.h b/bindings/swift/Ccapstone/include/capstone/xtensa.h similarity index 100% rename from bindings/swift/CCapstone/include/capstone/xtensa.h rename to bindings/swift/Ccapstone/include/capstone/xtensa.h diff --git a/bindings/swift/CCapstone/utils.c b/bindings/swift/Ccapstone/utils.c similarity index 100% rename from bindings/swift/CCapstone/utils.c rename to bindings/swift/Ccapstone/utils.c diff --git a/bindings/swift/CCapstone/utils.h b/bindings/swift/Ccapstone/utils.h similarity index 100% rename from bindings/swift/CCapstone/utils.h rename to bindings/swift/Ccapstone/utils.h From ad4ebc456644c353f307d5289ece9d73bc63f5fa Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Tue, 16 Sep 2025 00:25:43 +0800 Subject: [PATCH 08/12] Add testing --- Package.swift | 33 ++ bindings/swift/Ccapstone/platform.h | 1 + .../CcapstoneTests/AdvancedAPITests.swift | 491 ++++++++++++++++ .../CcapstoneTests/ArchitectureTests.swift | 234 ++++++++ .../swift/CcapstoneTests/BasicTests.swift | 198 +++++++ .../CcapstoneTests/CompatibilityTests.swift | 364 ++++++++++++ .../swift/CcapstoneTests/CoreAPITests.swift | 214 +++++++ .../swift/CcapstoneTests/DetailTests.swift | 271 +++++++++ .../CcapstoneTests/DisassemblyTests.swift | 223 +++++++ .../swift/CcapstoneTests/MinimalTests.swift | 161 ++++++ .../CcapstoneTests/PerformanceTests.swift | 318 ++++++++++ .../swift/CcapstoneTests/SimpleTests.swift | 95 +++ .../SwiftIntegrationTests.swift | 542 ++++++++++++++++++ 13 files changed, 3145 insertions(+) create mode 120000 bindings/swift/Ccapstone/platform.h create mode 100644 bindings/swift/CcapstoneTests/AdvancedAPITests.swift create mode 100644 bindings/swift/CcapstoneTests/ArchitectureTests.swift create mode 100644 bindings/swift/CcapstoneTests/BasicTests.swift create mode 100644 bindings/swift/CcapstoneTests/CompatibilityTests.swift create mode 100644 bindings/swift/CcapstoneTests/CoreAPITests.swift create mode 100644 bindings/swift/CcapstoneTests/DetailTests.swift create mode 100644 bindings/swift/CcapstoneTests/DisassemblyTests.swift create mode 100644 bindings/swift/CcapstoneTests/MinimalTests.swift create mode 100644 bindings/swift/CcapstoneTests/PerformanceTests.swift create mode 100644 bindings/swift/CcapstoneTests/SimpleTests.swift create mode 100644 bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift diff --git a/Package.swift b/Package.swift index 70e418947b..fe40b0e317 100644 --- a/Package.swift +++ b/Package.swift @@ -15,6 +15,39 @@ let package = Package( .target( name: "Ccapstone", path: "bindings/swift/Ccapstone", + cSettings: [ + .headerSearchPath("../../../include"), + .define("CAPSTONE_USE_SYS_DYN_MEM"), + .define("CAPSTONE_HAS_ARM"), + .define("CAPSTONE_HAS_ARM64"), + .define("CAPSTONE_HAS_AARCH64"), + .define("CAPSTONE_HAS_MIPS"), + .define("CAPSTONE_HAS_X86"), + .define("CAPSTONE_HAS_POWERPC"), + .define("CAPSTONE_HAS_SPARC"), + .define("CAPSTONE_HAS_SYSTEMZ"), + .define("CAPSTONE_HAS_XCORE"), + .define("CAPSTONE_HAS_M68K"), + .define("CAPSTONE_HAS_TMS320C64X"), + .define("CAPSTONE_HAS_M680X"), + .define("CAPSTONE_HAS_EVM"), + .define("CAPSTONE_HAS_MOS65XX"), + .define("CAPSTONE_HAS_WASM"), + .define("CAPSTONE_HAS_BPF"), + .define("CAPSTONE_HAS_RISCV"), + .define("CAPSTONE_HAS_SH"), + .define("CAPSTONE_HAS_TRICORE"), + .define("CAPSTONE_HAS_ALPHA"), + .define("CAPSTONE_HAS_HPPA"), + .define("CAPSTONE_HAS_LOONGARCH"), + .define("CAPSTONE_HAS_XTENSA"), + .define("CAPSTONE_HAS_ARC"), + ], + ), + .testTarget( + name: "CcapstoneTests", + dependencies: ["Ccapstone"], + path: "bindings/swift/CcapstoneTests", ), ] ) diff --git a/bindings/swift/Ccapstone/platform.h b/bindings/swift/Ccapstone/platform.h new file mode 120000 index 0000000000..1349962ee5 --- /dev/null +++ b/bindings/swift/Ccapstone/platform.h @@ -0,0 +1 @@ +../../../include/platform.h \ No newline at end of file diff --git a/bindings/swift/CcapstoneTests/AdvancedAPITests.swift b/bindings/swift/CcapstoneTests/AdvancedAPITests.swift new file mode 100644 index 0000000000..01496ffd8c --- /dev/null +++ b/bindings/swift/CcapstoneTests/AdvancedAPITests.swift @@ -0,0 +1,491 @@ +import Foundation +import Testing +@testable import Ccapstone + +/// Advanced API usage tests for the Capstone Swift binding +/// These tests cover complex scenarios, advanced features, and integration patterns +@Suite("Advanced API Tests") +struct AdvancedAPITests { + + // Test data for various architectures + private static let x86Code64: [UInt8] = [0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00] + private static let armCode: [UInt8] = [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5] + private static let aarch64Code: [UInt8] = [0x21, 0x7c, 0x02, 0x9b, 0x21, 0x7c, 0x00, 0x53] + + @Test("Multiple engine instances") + func testMultipleEngines() async throws { + var x86Handle: csh = 0 + var armHandle: csh = 0 + + let x86Result = cs_open(CS_ARCH_X86, CS_MODE_64, &x86Handle) + let armResult = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &armHandle) + + // At least one should work in a complete implementation + var activeHandles: [(csh, String, [UInt8])] = [] + + if x86Result == CS_ERR_OK { + activeHandles.append((x86Handle, "X86-64", Self.x86Code64)) + } + + if armResult == CS_ERR_OK { + activeHandles.append((armHandle, "ARM", Self.armCode)) + } + + guard !activeHandles.isEmpty else { + print("⚠️ Skipping multiple engines test - no engines available") + return + } + + print("✓ Multiple engines test with \(activeHandles.count) active engines:") + + // Test disassembly with each active engine + for (handle, name, code) in activeHandles { + var insns: UnsafeMutablePointer? + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + print(" \(name): \(count) instructions") + + if count > 0 { + cs_free(insns, count) + } + + #expect(count >= 0, "\(name) engine should work without errors") + } + + // Clean up all handles + if x86Result == CS_ERR_OK { + _ = cs_close(&x86Handle) + } + if armResult == CS_ERR_OK { + _ = cs_close(&armHandle) + } + } + + @Test("Detail mode comprehensive testing") + func testDetailModeFeatures() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping detail mode test - cannot open X86 engine") + return + } + + defer { _ = cs_close(&handle) } + + // Enable detail mode + let detailResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + print("✓ Detail mode setting result: \(detailResult)") + + // Disassemble with detail mode + var insns: UnsafeMutablePointer? + let count = Self.x86Code64.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + guard count > 0 else { + print("⚠️ No instructions disassembled") + return + } + + print("✓ Detail mode disassembly: \(count) instructions") + + // Analyze first instruction in detail + let firstInsn = insns!.pointee + print(" First instruction:") + let mnemonic = withUnsafeBytes(of: firstInsn.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + let operands = withUnsafeBytes(of: firstInsn.op_str) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + print(" Mnemonic: \(mnemonic)") + print(" Operands: \(operands)") + print(" Address: 0x\(String(format: "%llx", firstInsn.address))") + print(" Size: \(firstInsn.size)") + print(" ID: \(firstInsn.id)") + + // Check if detail information is available + if let detail = firstInsn.detail { + print(" Detail available: Yes") + + // Access detail structure (this might fail if implementation is incomplete) + let detailStruct = detail.pointee + print(" Groups count: \(detailStruct.groups_count)") + print(" Reads registers: \(detailStruct.regs_read_count)") + print(" Writes registers: \(detailStruct.regs_write_count)") + + // Note: Architecture-specific details would require more complete implementation + } else { + print(" Detail available: No") + } + + // Test turning detail mode off + let detailOffResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_OFF.rawValue)) + print(" Detail mode off result: \(detailOffResult)") + } + + @Test("Skip data mode testing") + func testSkipDataMode() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping skip data mode test - cannot open X86 engine") + return + } + + defer { _ = cs_close(&handle) } + + // Create code with embedded data (invalid instructions) + let codeWithData: [UInt8] = [ + 0x90, // NOP + 0xFF, 0xFF, 0xFF, // Invalid data + 0x90, // NOP + 0x00, 0x00, // More invalid data + 0x90 // NOP + ] + + // Test normal mode (should stop at first invalid instruction) + var insns: UnsafeMutablePointer? + let normalCount = codeWithData.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if normalCount > 0 { + print("✓ Normal mode: \(normalCount) instructions") + cs_free(insns, normalCount) + } + + // Test skip data mode (if supported) + let skipDataResult = cs_option(handle, CS_OPT_SKIPDATA, size_t(CS_OPT_ON.rawValue)) + print(" Skip data mode setting: \(skipDataResult)") + + if skipDataResult == CS_ERR_OK { + let skipCount = codeWithData.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if skipCount > 0 { + print(" Skip data mode: \(skipCount) instructions") + + // Examine instructions to see if data was skipped + for i in 0..= normalCount, "Skip data mode should find at least as many instructions") + } + } + + @Test("Custom memory allocation patterns") + func testCustomMemoryPatterns() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping memory pattern test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + // Test malloc/free pattern + let insn = cs_malloc(handle) + guard let insn = insn else { + print("⚠️ cs_malloc returned null") + return + } + + print("✓ Custom memory allocation patterns:") + print(" cs_malloc succeeded: \(insn)") + + // Test iterator pattern with custom-allocated instruction + let testCode: [UInt8] = [0x90, 0x90, 0x90] // Multiple NOPs + var instructionCount = 0 + + testCode.withUnsafeBufferPointer { buffer in + var codePtr = buffer.baseAddress + var size = testCode.count + var address: UInt64 = 0x1000 + + while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { + instructionCount += 1 + let mnemonic = withUnsafeBytes(of: insn.pointee.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + print(" Instruction \(instructionCount): \(mnemonic)") + + // Safety break + if instructionCount >= 10 { + break + } + } + } + + cs_free(insn, 1) + print(" Iterator with custom allocation: \(instructionCount) instructions") + + // Test batch allocation pattern + var batchInsns: UnsafeMutablePointer? + let batchCount = testCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &batchInsns) + } + + if batchCount > 0 { + print(" Batch allocation: \(batchCount) instructions") + cs_free(batchInsns, batchCount) + } + + #expect(instructionCount == batchCount, "Iterator and batch methods should find same number of instructions") + } + + @Test("Option combinations and interactions") + func testOptionCombinations() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping option combinations test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + print("✓ Testing option combinations:") + + // Test various option combinations + let optionTests: [(cs_opt_type, size_t, String)] = [ + (CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue), "Detail ON"), + (CS_OPT_SKIPDATA, size_t(CS_OPT_ON.rawValue), "Skip Data ON"), + (CS_OPT_SYNTAX, size_t(CS_OPT_SYNTAX_DEFAULT.rawValue), "Default Syntax"), + (CS_OPT_DETAIL, size_t(CS_OPT_OFF.rawValue), "Detail OFF"), + (CS_OPT_SKIPDATA, size_t(CS_OPT_OFF.rawValue), "Skip Data OFF"), + ] + + for (option, value, description) in optionTests { + let result = cs_option(handle, option, value) + print(" \(description): \(result == CS_ERR_OK ? "✓" : "✗") (\(result))") + + // Test disassembly after each option change + var insns: UnsafeMutablePointer? + let count = Self.x86Code64.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if count > 0 { + cs_free(insns, count) + print(" Disassembly after option: \(count) instructions") + } + } + } + + @Test("Large instruction analysis") + func testLargeInstructionHandling() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping large instruction test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + // X86-64 instruction with large displacement/immediate (if we had real long instructions) + // For now, use what we have and test the structures + let _ = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + + var insns: UnsafeMutablePointer? + let count = Self.x86Code64.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + guard count > 0 else { + print("⚠️ No instructions for large instruction test") + return + } + + print("✓ Large instruction handling:") + + for i in 0.. 0 && mnemonicLen < CS_MNEMONIC_SIZE, "Mnemonic length should be reasonable") + #expect(operandLen < 512, "Operand string length should be reasonable") // Reasonable limit + + print(" Mnemonic length: \(mnemonicLen), Operand length: \(operandLen)") + } + } + + @Test("Thread safety simulation") + func testThreadSafetyPatterns() async throws { + // Note: Each task will create its own handle as handles should not be shared between threads + + let concurrentTasks = 5 + let operationsPerTask = 50 + + print("✓ Thread safety patterns test:") + + await withTaskGroup(of: (Int, Int, Bool).self) { group in + for taskId in 0..? + let count = Self.x86Code64.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if count > 0 { + // Access the first instruction to test memory safety + let firstInsn = insns!.pointee + let _ = withUnsafeBytes(of: firstInsn.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + cs_free(insns, count) + successfulOps += 1 + } + + let closeResult = cs_close(&handle) + if closeResult != CS_ERR_OK { + hadCriticalFailure = true + } + } + + return (taskId, successfulOps, hadCriticalFailure) + } + } + + var totalSuccessfulOps = 0 + var totalTasks = 0 + var hadAnyFailures = false + + for await (taskId, successfulOps, hadFailure) in group { + totalTasks += 1 + totalSuccessfulOps += successfulOps + hadAnyFailures = hadAnyFailures || hadFailure + + print(" Task \(taskId): \(successfulOps)/\(operationsPerTask) successful") + } + + let totalPossibleOps = concurrentTasks * operationsPerTask + print(" Overall: \(totalSuccessfulOps)/\(totalPossibleOps) successful operations") + print(" Critical failures: \(hadAnyFailures ? "Yes" : "No")") + + #expect(!hadAnyFailures, "Should not have critical failures in concurrent access") + } + } + + @Test("Error recovery and robustness") + func testErrorRecovery() async throws { + var handle: csh = 0 + + // Test recovery from various error conditions + print("✓ Error recovery and robustness:") + + // Invalid architecture followed by valid one + let invalidResult = cs_open(cs_arch(rawValue: 999), CS_MODE_32, &handle) + #expect(invalidResult != CS_ERR_OK, "Invalid architecture should fail") + #expect(handle == 0, "Handle should be 0 after failure") + + let validResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + if validResult == CS_ERR_OK { + print(" Recovery after invalid architecture: ✓") + + // Test invalid operations on valid handle + let invalidOption = cs_option(handle, cs_opt_type(rawValue: 999), 0) + print(" Invalid option on valid handle: \(invalidOption)") + + // Handle should still be usable after invalid operation + let errno = cs_errno(handle) + print(" Handle still usable after error: \(errno != CS_ERR_HANDLE ? "✓" : "✗")") + + // Test disassembly after error + var insns: UnsafeMutablePointer? + let count = Self.x86Code64.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if count > 0 { + cs_free(insns, count) + print(" Disassembly after error: ✓ (\(count) instructions)") + } else { + print(" Disassembly after error: ✗") + } + + _ = cs_close(&handle) + } else { + print(" Cannot test recovery - X86 engine not available") + } + + // Test multiple close attempts (should not crash) + // Note: After previous operations, handle should be 0 (invalid) + // Second close attempt on an already closed/invalid handle may be unsafe + print(" Skipping multiple close test to avoid potential memory issues") + #expect(Bool(true), "Multiple close test skipped for safety") + } +} diff --git a/bindings/swift/CcapstoneTests/ArchitectureTests.swift b/bindings/swift/CcapstoneTests/ArchitectureTests.swift new file mode 100644 index 0000000000..af9b6ebd54 --- /dev/null +++ b/bindings/swift/CcapstoneTests/ArchitectureTests.swift @@ -0,0 +1,234 @@ +import XCTest +@testable import Ccapstone + +final class ArchitectureTests: XCTestCase { + + // Test code samples for different architectures + private struct TestPlatform { + let arch: cs_arch + let mode: cs_mode + let code: [UInt8] + let comment: String + } + + private let platforms: [TestPlatform] = [ + TestPlatform( + arch: CS_ARCH_X86, + mode: CS_MODE_16, + code: [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00], + comment: "X86 16bit" + ), + TestPlatform( + arch: CS_ARCH_X86, + mode: CS_MODE_32, + code: [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00], + comment: "X86 32bit" + ), + TestPlatform( + arch: CS_ARCH_X86, + mode: CS_MODE_64, + code: [0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00], + comment: "X86 64bit" + ), + TestPlatform( + arch: CS_ARCH_ARM, + mode: CS_MODE_ARM, + code: [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x83, 0x22, 0xe5], + comment: "ARM" + ), + TestPlatform( + arch: CS_ARCH_ARM, + mode: CS_MODE_THUMB, + code: [0x70, 0x47, 0xeb, 0x46, 0x83, 0xb0, 0xc9, 0x68], + comment: "Thumb" + ), + TestPlatform( + arch: CS_ARCH_AARCH64, + mode: CS_MODE_ARM, + code: [0x21, 0x7c, 0x02, 0x9b, 0x21, 0x7c, 0x00, 0x53, 0x00, 0x40, 0x21, 0x4b, 0xe1, 0x0b, 0x40, 0xb9], + comment: "AArch64" + ), + TestPlatform( + arch: CS_ARCH_MIPS, + mode: cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), + code: [0x0C, 0x10, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0c, 0x8f, 0xa2, 0x00, 0x00, 0x34, 0x21, 0x34, 0x56], + comment: "MIPS32 Big-endian" + ), + TestPlatform( + arch: CS_ARCH_MIPS, + mode: cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), + code: [0x56, 0x34, 0x21, 0x34, 0xc2, 0x17, 0x01, 0x00], + comment: "MIPS64 Little-endian" + ), + TestPlatform( + arch: CS_ARCH_PPC, + mode: CS_MODE_BIG_ENDIAN, + code: [0x80, 0x20, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x10, 0x43, 0x23, 0x0e, 0xd0, 0x44, 0x00, 0x80, 0x4c, 0x43, 0x22, 0x02], + comment: "PowerPC" + ), + TestPlatform( + arch: CS_ARCH_SPARC, + mode: CS_MODE_BIG_ENDIAN, + code: [0x80, 0xa0, 0x40, 0x02, 0x85, 0xc2, 0x60, 0x08, 0x85, 0xe8, 0x20, 0x01, 0x81, 0xe8, 0x00, 0x00, 0x90, 0x10, 0x20, 0x01], + comment: "Sparc" + ), + TestPlatform( + arch: CS_ARCH_SYSTEMZ, + mode: CS_MODE_BIG_ENDIAN, + code: [0xed, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x5a, 0x0f, 0x1f, 0xff, 0xc2, 0x09, 0x80, 0x00, 0x00, 0x00, 0x07, 0xf7], + comment: "SystemZ" + ) + ] + + func testAllArchitectures() { + for platform in platforms { + testArchitecture(platform) + } + } + + func testX86Syntax() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + // Test Intel syntax (default) + let code: [UInt8] = [0x8d, 0x4c, 0x32, 0x08] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertGreaterThan(count, 0) + if count > 0 && insns != nil { + let insn = insns![0] + let opStr = String(cString: withUnsafeBytes(of: insn.op_str) { $0.bindMemory(to: CChar.self).baseAddress! }) + print("Intel syntax: \(opStr)") + cs_free(insns, count) + } + + // Test AT&T syntax + let attResult = cs_option(handle, CS_OPT_SYNTAX, size_t(CS_OPT_SYNTAX_ATT.rawValue)) + if attResult == CS_ERR_OK { + let attCount = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if attCount > 0 && insns != nil { + let insn = insns![0] + let opStr = String(cString: withUnsafeBytes(of: insn.op_str) { $0.bindMemory(to: CChar.self).baseAddress! }) + print("AT&T syntax: \(opStr)") + cs_free(insns, attCount) + } + } + + _ = cs_close(&handle) + } + + func testMIPSModes() { + let mipsCodes: [(cs_mode, [UInt8], String)] = [ + (cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), [0x0C, 0x10, 0x00, 0x97], "MIPS32 BE"), + (cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), [0x97, 0x00, 0x10, 0x0C], "MIPS32 LE"), + (cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_BIG_ENDIAN.rawValue), [0x0C, 0x10, 0x00, 0x97], "MIPS64 BE"), + (cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), [0x97, 0x00, 0x10, 0x0C], "MIPS64 LE") + ] + + for (mode, code, comment) in mipsCodes { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_MIPS, mode, &handle) + XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + + var insns: UnsafeMutablePointer? + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertGreaterThanOrEqual(count, 0, "Disassembly failed for \(comment)") + + if count > 0 && insns != nil { + let insn = insns![0] + let mnemonic = String(cString: withUnsafeBytes(of: insn.mnemonic) { $0.bindMemory(to: CChar.self).baseAddress! }) + print("\(comment): \(mnemonic)") + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + } + + func testARMModes() { + let armTests: [(cs_mode, [UInt8], String)] = [ + (CS_MODE_ARM, [0x04, 0xe0, 0x2d, 0xe5], "ARM mode"), + (CS_MODE_THUMB, [0x70, 0x47], "Thumb mode"), + (cs_mode(CS_MODE_THUMB.rawValue | CS_MODE_MCLASS.rawValue), [0x70, 0x47], "Thumb M-Class") + ] + + for (mode, code, comment) in armTests { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_ARM, mode, &handle) + XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + + var insns: UnsafeMutablePointer? + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertGreaterThanOrEqual(count, 0, "Disassembly failed for \(comment)") + + if count > 0 && insns != nil { + let insn = insns![0] + let mnemonic = String(cString: withUnsafeBytes(of: insn.mnemonic) { $0.bindMemory(to: CChar.self).baseAddress! }) + print("\(comment): \(mnemonic)") + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + } + + private func testArchitecture(_ platform: TestPlatform) { + var handle: csh = 0 + var insns: UnsafeMutablePointer? + + let openResult = cs_open(platform.arch, platform.mode, &handle) + XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(platform.comment)") + + let count = platform.code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertGreaterThan(count, 0, "No instructions disassembled for \(platform.comment)") + + if count > 0 && insns != nil { + print("\n\(platform.comment):") + for i in 0..) -> Int { + var offset = 0 + for i in 0.. 0, "Major version should be positive") + #expect(minor >= 0, "Minor version should be non-negative") + #expect(version > 0, "Version should be positive") + #expect(version == UInt32((major << 8) | minor), "Version should match expected format") + + print("✓ Capstone version: \(major).\(minor) (0x\(String(format: "%04x", version)))") + } + + @Test("Engine open and close operations") + func testOpenClose() async throws { + var handle: csh = 0 + + let result = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + #expect(result == CS_ERR_OK, "Engine should open successfully") + #expect(handle != 0, "Handle should be non-zero after successful open") + + let closeResult = cs_close(&handle) + #expect(closeResult == CS_ERR_OK, "Engine should close successfully") + #expect(handle == 0, "Handle should be zero after close") + + print("✓ Engine open/close: Success") + } + + @Test("Invalid architecture handling") + func testInvalidArch() async throws { + var handle: csh = 0 + + let result = cs_open(cs_arch(1000), CS_MODE_32, &handle) + #expect(result != CS_ERR_OK, "Invalid architecture should fail") + #expect(handle == 0, "Handle should remain zero for invalid architecture") + + print("✓ Invalid architecture handled correctly") + } + + @Test("Error message strings") + func testStrerror() async throws { + let errorMsg = cs_strerror(CS_ERR_OK) + #expect(errorMsg != nil, "Error message should not be nil") + + let okString = String(cString: errorMsg!) + #expect(!okString.isEmpty, "Error message string should not be empty") + + let invalidMsg = cs_strerror(CS_ERR_ARCH) + #expect(invalidMsg != nil, "Error message for CS_ERR_ARCH should not be nil") + + let invalidString = String(cString: invalidMsg!) + #expect(!invalidString.isEmpty, "Error message string should not be empty") + #expect(okString != invalidString, "Different error codes should have different messages") + + print("✓ Error messages: '\(okString)' vs '\(invalidString)'") + } + + @Test("Error number retrieval") + func testErrno() async throws { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + if openResult == CS_ERR_OK { + let errno = cs_errno(handle) + #expect(errno == CS_ERR_OK, "Error number should be CS_ERR_OK for successful operation") + _ = cs_close(&handle) + print("✓ Error number retrieval: Success") + } else { + print("⚠️ Skipping errno test - cannot open X86 engine") + } + } + + @Test("Option setting") + func testOption() async throws { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + if openResult == CS_ERR_OK { + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + // Note: Option result may vary depending on implementation completeness + // We mainly test that it doesn't crash + + _ = cs_close(&handle) + print("✓ Option setting: Result \(optResult)") + } else { + print("⚠️ Skipping option test - cannot open X86 engine") + } + } + + @Test("Basic disassembly functionality") + func testBasicDisassembly() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping basic disassembly test - cannot open X86 engine") + return + } + + defer { _ = cs_close(&handle) } + + // Simple x86 32-bit code: lea ecx, [edx+esi+8]; add eax, ebx + let code: [UInt8] = [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8] + + var insns: UnsafeMutablePointer? + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + #expect(count >= 0, "Disassembly should not fail catastrophically") + + if count > 0 { + let firstInsn = insns!.pointee + let mnemonic = withUnsafeBytes(of: firstInsn.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + let operands = withUnsafeBytes(of: firstInsn.op_str) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + + #expect(!mnemonic.isEmpty, "Mnemonic should not be empty") + #expect(firstInsn.size > 0, "Instruction size should be positive") + #expect(firstInsn.address == 0x1000, "Instruction address should match input") + + print("✓ Basic disassembly: \(count) instructions") + print(" First: \(mnemonic) \(operands) (size: \(firstInsn.size))") + } else { + print("⚠️ Basic disassembly returned 0 instructions (implementation may be incomplete)") + } + } + + @Test("Iterator API functionality") + func testIteratorAPI() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping iterator API test - cannot open X86 engine") + return + } + + defer { _ = cs_close(&handle) } + + let insn = cs_malloc(handle) + guard let insn = insn else { + print("⚠️ cs_malloc returned nil") + return + } + + defer { cs_free(insn, 1) } + + let code: [UInt8] = [0x90, 0x90, 0x90] // Three NOPs + var instructionCount = 0 + + code.withUnsafeBufferPointer { buffer in + var codePtr = buffer.baseAddress + var size = code.count + var address: UInt64 = 0x1000 + + while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { + instructionCount += 1 + let mnemonic = withUnsafeBytes(of: insn.pointee.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + + #expect(!mnemonic.isEmpty, "Mnemonic should not be empty") + #expect(insn.pointee.size > 0, "Instruction size should be positive") + + // Safety break to avoid infinite loops + if instructionCount > 10 { + break + } + } + } + + print("✓ Iterator API: \(instructionCount) instructions processed") + #expect(instructionCount >= 0, "Iterator should handle instructions without crashing") + } +} diff --git a/bindings/swift/CcapstoneTests/CompatibilityTests.swift b/bindings/swift/CcapstoneTests/CompatibilityTests.swift new file mode 100644 index 0000000000..a6b39a86c6 --- /dev/null +++ b/bindings/swift/CcapstoneTests/CompatibilityTests.swift @@ -0,0 +1,364 @@ +import Foundation +import Testing +@testable import Ccapstone + +/// Cross-platform compatibility and edge case tests for the Capstone Swift binding +/// These tests verify behavior across different platforms and unusual conditions +@Suite("Compatibility Tests") +struct CompatibilityTests { + + // Test data for various scenarios + private static let emptyCode: [UInt8] = [] + private static let singleByteCode: [UInt8] = [0x90] // NOP instruction + private static let invalidCode: [UInt8] = [0xFF, 0xFF, 0xFF, 0xFF] + private static let mixedValidInvalidCode: [UInt8] = [0x90, 0xFF, 0xFF, 0x90, 0xFF] + + @Test("Platform-specific enum values consistency") + func testEnumValueConsistency() async throws { + // Test that enum values are consistent across platforms + let enumTests: [(String, UInt32, UInt32)] = [ + ("CS_ERR_OK", CS_ERR_OK.rawValue, 0), + ("CS_ERR_MEM", CS_ERR_MEM.rawValue, 1), + ("CS_ERR_ARCH", CS_ERR_ARCH.rawValue, 2), + ("CS_ERR_HANDLE", CS_ERR_HANDLE.rawValue, 3), + ("CS_ERR_CSH", CS_ERR_CSH.rawValue, 4), + ("CS_ERR_MODE", CS_ERR_MODE.rawValue, 5), + ("CS_ERR_OPTION", CS_ERR_OPTION.rawValue, 6), + ("CS_ERR_DETAIL", CS_ERR_DETAIL.rawValue, 7), + ("CS_ERR_MEMSETUP", CS_ERR_MEMSETUP.rawValue, 8), + ("CS_ERR_VERSION", CS_ERR_VERSION.rawValue, 9), + + ("CS_ARCH_ARM", CS_ARCH_ARM.rawValue, 0), + ("CS_ARCH_AARCH64", CS_ARCH_AARCH64.rawValue, 1), + ("CS_ARCH_MIPS", CS_ARCH_MIPS.rawValue, 3), + ("CS_ARCH_X86", CS_ARCH_X86.rawValue, 4), + ("CS_ARCH_PPC", CS_ARCH_PPC.rawValue, 5), + + ("CS_MODE_LITTLE_ENDIAN", CS_MODE_LITTLE_ENDIAN.rawValue, 0), + ("CS_MODE_ARM", CS_MODE_ARM.rawValue, 0), + ("CS_MODE_16", CS_MODE_16.rawValue, 1 << 1), + ("CS_MODE_32", CS_MODE_32.rawValue, 1 << 2), + ("CS_MODE_64", CS_MODE_64.rawValue, 1 << 3), + ] + + print("✓ Testing enum value consistency:") + for (name, actual, expected) in enumTests { + #expect(actual == expected, "\(name) should be \(expected), got \(actual)") + print(" \(name): \(actual) ✓") + } + } + + @Test("Pointer size and alignment compatibility") + func testPointerCompatibility() async throws { + // Test that pointer sizes and alignments are reasonable + let insnSize = MemoryLayout.size + let insnAlignment = MemoryLayout.alignment + let detailSize = MemoryLayout.size + let detailAlignment = MemoryLayout.alignment + let cshSize = MemoryLayout.size + + print("✓ Platform-specific sizes and alignments:") + print(" cs_insn: \(insnSize) bytes, alignment: \(insnAlignment)") + print(" cs_detail: \(detailSize) bytes, alignment: \(detailAlignment)") + print(" csh (handle): \(cshSize) bytes") + + // Basic sanity checks + #expect(insnSize > 0 && insnSize < 1024, "cs_insn size should be reasonable") + #expect(detailSize > 0 && detailSize < 4096, "cs_detail size should be reasonable") + #expect(cshSize > 0 && cshSize <= 8, "csh should be pointer-sized") + + // Alignment should be power of 2 and reasonable + #expect(insnAlignment > 0 && (insnAlignment & (insnAlignment - 1)) == 0, "cs_insn alignment should be power of 2") + #expect(detailAlignment > 0 && (detailAlignment & (detailAlignment - 1)) == 0, "cs_detail alignment should be power of 2") + } + + @Test("Empty and invalid code handling") + func testEdgeCaseCodeHandling() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping edge case tests - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + // Test empty code + var insns: UnsafeMutablePointer? + let emptyCount = Self.emptyCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + #expect(emptyCount == 0, "Empty code should produce 0 instructions") + print("✓ Empty code handling: \(emptyCount) instructions") + + // Test single byte + let singleCount = Self.singleByteCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if singleCount > 0 { + cs_free(insns, singleCount) + } + + print("✓ Single byte code: \(singleCount) instructions") + + // Test invalid code + let invalidCount = Self.invalidCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if invalidCount > 0 { + cs_free(insns, invalidCount) + } + + print("✓ Invalid code handling: \(invalidCount) instructions") + + // All tests should complete without crashing + #expect(Bool(true), "All edge cases should be handled gracefully") + } + + @Test("Maximum values and boundaries") + func testBoundaryValues() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping boundary tests - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + // Test with maximum address value + let maxAddress: UInt64 = UInt64.max + var insns: UnsafeMutablePointer? + let maxAddrCount = Self.singleByteCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, maxAddress, 0, &insns) + } + + if maxAddrCount > 0 { + let instruction = insns!.pointee + print("✓ Maximum address test: instruction at 0x\(String(format: "%llx", instruction.address))") + cs_free(insns, maxAddrCount) + } + + // Test with zero address + let zeroAddrCount = Self.singleByteCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0, 0, &insns) + } + + if zeroAddrCount > 0 { + cs_free(insns, zeroAddrCount) + } + + print("✓ Zero address test: \(zeroAddrCount) instructions") + + // Test with maximum count parameter (should be ignored for cs_disasm with count=0) + let maxCountTest = Self.singleByteCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, size_t.max, &insns) + } + + if maxCountTest > 0 { + cs_free(insns, maxCountTest) + } + + print("✓ Maximum count parameter test: \(maxCountTest) instructions") + } + + @Test("String handling and encoding") + func testStringHandling() async throws { + // Test error message strings for proper encoding + let testErrors: [cs_err] = [ + CS_ERR_OK, CS_ERR_MEM, CS_ERR_ARCH, CS_ERR_HANDLE, + CS_ERR_CSH, CS_ERR_MODE, CS_ERR_OPTION, CS_ERR_DETAIL + ] + + print("✓ Testing string encoding and validity:") + for errorCode in testErrors { + let message = cs_strerror(errorCode) + #expect(message != nil, "Error message should not be nil") + + if let message = message { + let errorString = String(cString: message) + #expect(!errorString.isEmpty, "Error string should not be empty") + #expect(errorString.utf8.count > 0, "String should have valid UTF-8 encoding") + + // Check for reasonable string length (not too short or suspiciously long) + #expect(errorString.count >= 2 && errorString.count <= 100, "Error message should have reasonable length") + + print(" \(errorCode.rawValue): '\(errorString)' (\(errorString.count) chars)") + } + } + } + + @Test("Iterator API edge cases") + func testIteratorEdgeCases() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping iterator edge case tests - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + let insn = cs_malloc(handle) + guard let insn = insn else { + print("⚠️ Cannot allocate instruction structure") + return + } + + defer { cs_free(insn, 1) } + + // Test iterator with empty code + var result = Self.emptyCode.withUnsafeBufferPointer { buffer -> Bool in + var codePtr = buffer.baseAddress + var size = Self.emptyCode.count + var address: UInt64 = 0x1000 + + return cs_disasm_iter(handle, &codePtr, &size, &address, insn) + } + + #expect(result == false, "Iterator should return false for empty code") + print("✓ Iterator empty code test: \(result)") + + // Test iterator with single valid instruction + result = Self.singleByteCode.withUnsafeBufferPointer { buffer -> Bool in + var codePtr = buffer.baseAddress + var size = Self.singleByteCode.count + var address: UInt64 = 0x1000 + + let firstResult = cs_disasm_iter(handle, &codePtr, &size, &address, insn) + if firstResult { + let mnemonic = withUnsafeBytes(of: insn.pointee.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + print(" First instruction: \(mnemonic)") + // Try to get second instruction (should fail) + let secondResult = cs_disasm_iter(handle, &codePtr, &size, &address, insn) + return secondResult + } + return firstResult + } + + print("✓ Iterator single instruction test: second call returned \(result)") + + // Test iterator with mixed valid/invalid code + var instructionCount = 0 + Self.mixedValidInvalidCode.withUnsafeBufferPointer { buffer in + var codePtr = buffer.baseAddress + var size = Self.mixedValidInvalidCode.count + var address: UInt64 = 0x1000 + + while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { + instructionCount += 1 + if instructionCount > 10 { // Safety break to avoid infinite loops + break + } + } + } + + print("✓ Iterator mixed code test: \(instructionCount) instructions found") + #expect(instructionCount >= 0, "Should handle mixed code gracefully") + } + + @Test("Version consistency across calls") + func testVersionStability() async throws { + // Call version function multiple times and ensure consistency + let iterations = 100 + var versions: [UInt32] = [] + var majors: [Int32] = [] + var minors: [Int32] = [] + + for _ in 0..= 0, "Should handle architecture queries without crashing") + } + + @Test("Memory safety with null pointers") + func testNullPointerSafety() async throws { + // cs_strerror should work with any error code + for errorCode in 0..<20 { + let message = cs_strerror(cs_err(rawValue: UInt32(errorCode))) + #expect(message != nil, "cs_strerror should return non-null for any error code") + } + + // cs_version with null parameters + let versionOnly = cs_version(nil, nil) + #expect(versionOnly > 0, "cs_version should work with null parameters") + print("✓ cs_version with null parameters: \(versionOnly)") + + // Operations on invalid handles should return errors, not crash + let errno = cs_errno(0) + #expect(errno != CS_ERR_OK, "cs_errno on invalid handle should return error") + + let optResult = cs_option(0, CS_OPT_DETAIL, 1) + #expect(optResult != CS_ERR_OK, "cs_option on invalid handle should return error") + + print("✓ All null pointer and invalid handle tests completed safely") + } +} diff --git a/bindings/swift/CcapstoneTests/CoreAPITests.swift b/bindings/swift/CcapstoneTests/CoreAPITests.swift new file mode 100644 index 0000000000..7cdedf7c88 --- /dev/null +++ b/bindings/swift/CcapstoneTests/CoreAPITests.swift @@ -0,0 +1,214 @@ +import Foundation +import Testing +@testable import Ccapstone + +/// Core API tests that focus on the C interface without architecture-specific details +/// These tests verify the basic Capstone C API functionality exposed through Swift +@Suite("Core API Tests") +struct CoreAPITests { + + @Test("Version API comprehensive testing") + func testVersionAPI() async throws { + var major: Int32 = 0 + var minor: Int32 = 0 + + let version = cs_version(&major, &minor) + + #expect(major > 0, "Major version should be greater than 0") + #expect(minor >= 0, "Minor version should be greater than or equal to 0") + #expect(version > 0, "Version should be greater than 0") + #expect(version == UInt32((major << 8) | minor), "Version format should be correct") + + print("✓ Capstone version: \(major).\(minor) (0x\(String(format: "%04x", version)))") + } + + @Test("Basic enum values validation") + func testBasicEnumValues() async throws { + // Test error code enum values + #expect(CS_ERR_OK.rawValue == 0, "CS_ERR_OK should be 0") + #expect(CS_ERR_ARCH.rawValue != 0, "CS_ERR_ARCH should not be 0") + #expect(CS_ERR_HANDLE.rawValue != 0, "CS_ERR_HANDLE should not be 0") + #expect(CS_ERR_MEM.rawValue != 0, "CS_ERR_MEM should not be 0") + + // Test architecture enum values + #expect(CS_ARCH_ARM.rawValue == 0, "CS_ARCH_ARM should be 0") + #expect(CS_ARCH_AARCH64.rawValue == 1, "CS_ARCH_AARCH64 should be 1") + #expect(CS_ARCH_X86.rawValue == 4, "CS_ARCH_X86 should be 4") + + // Test mode enum values + #expect(CS_MODE_LITTLE_ENDIAN.rawValue == 0, "CS_MODE_LITTLE_ENDIAN should be 0") + #expect(CS_MODE_16.rawValue == 1 << 1, "CS_MODE_16 should be 2") + #expect(CS_MODE_32.rawValue == 1 << 2, "CS_MODE_32 should be 4") + #expect(CS_MODE_64.rawValue == 1 << 3, "CS_MODE_64 should be 8") + + // Test option enum values + #expect(CS_OPT_INVALID.rawValue == 0, "CS_OPT_INVALID should be 0") + #expect(CS_OPT_DETAIL.rawValue != 0, "CS_OPT_DETAIL should not be 0") + + print("✓ All enum values are correctly defined") + } + + @Test("Error message validation") + func testErrorMessages() async throws { + let testErrors: [(cs_err, String)] = [ + (CS_ERR_OK, "Success"), + (CS_ERR_MEM, "Memory error"), + (CS_ERR_ARCH, "Architecture error"), + (CS_ERR_HANDLE, "Handle error"), + (CS_ERR_CSH, "CSH error"), + (CS_ERR_MODE, "Mode error"), + (CS_ERR_OPTION, "Option error"), + (CS_ERR_DETAIL, "Detail error"), + (CS_ERR_MEMSETUP, "Memory setup error"), + (CS_ERR_VERSION, "Version error") + ] + + print("✓ Testing error messages:") + for (errorCode, description) in testErrors { + let message = cs_strerror(errorCode) + #expect(message != nil, "Error message for \(description) should not be nil") + + if let message = message { + let errorString = String(cString: message) + #expect(!errorString.isEmpty, "Error message for \(description) should not be empty") + print(" \(errorCode.rawValue) (\(description)): \(errorString)") + } + } + } + + @Test("Basic handle operations") + func testBasicHandleOperations() async throws { + var handle: csh = 0 + + // Test invalid architecture + let invalidResult = cs_open(cs_arch(rawValue: 999), CS_MODE_32, &handle) + #expect(invalidResult != CS_ERR_OK, "Invalid architecture should return error") + #expect(handle == 0, "Handle should be 0 for invalid architecture") + + // Test valid operations (if possible) + let validResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + if validResult == CS_ERR_OK { + print("✓ Successfully opened X86 32-bit engine, handle: \(handle)") + #expect(handle != 0, "Handle should not be 0 for valid operations") + + // Test option setting + let _ = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + // Success or failure is acceptable, depends on implementation completeness + + // Test error number retrieval + let _ = cs_errno(handle) + // errno value depends on previous operation results + + // Test close + let closeResult = cs_close(&handle) + #expect(closeResult == CS_ERR_OK, "Handle close should succeed") + #expect(handle == 0, "Handle should be 0 after close") + } else { + let errorMsg = cs_strerror(validResult) + let errorString = errorMsg != nil ? String(cString: errorMsg!) : "Unknown error" + print("⚠️ Unable to open X86 engine: \(errorString)") + print(" This is expected because Swift binding is incomplete") + } + } + + @Test("Invalid operations handling") + func testInvalidOperations() async throws { + // Test operations on invalid handle + let errno = cs_errno(0) + #expect(errno != CS_ERR_OK, "cs_errno on invalid handle should return error") + + let optResult = cs_option(0, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + #expect(optResult != CS_ERR_OK, "cs_option on invalid handle should return error") + + // Test double close - using zero handle which should be safe + var zeroHandle: csh = 0 + let doubleClose = cs_close(&zeroHandle) + #expect(doubleClose != CS_ERR_OK, "Closing zero handle should return error") + + print("✓ Invalid operations correctly return errors") + } + + @Test("Constants and structure sizes") + func testConstantsAndSizes() async throws { + // Test important constant values + #expect(CS_MNEMONIC_SIZE == 32, "CS_MNEMONIC_SIZE should be 32") + + // Test structure sizes + let insnSize = MemoryLayout.size + let detailSize = MemoryLayout.size + + #expect(insnSize > 0, "cs_insn structure size should be greater than 0") + #expect(detailSize > 0, "cs_detail structure size should be greater than 0") + + print("✓ Constants and structure sizes:") + print(" CS_MNEMONIC_SIZE: \(CS_MNEMONIC_SIZE)") + print(" cs_insn size: \(insnSize) bytes") + print(" cs_detail size: \(detailSize) bytes") + + // cs_insn should contain mnemonic, operand strings, etc., should have reasonable size + #expect(insnSize > 32, "cs_insn should be at least 32 bytes") + + // cs_detail contains architecture-specific unions, should be larger + #expect(detailSize > 100, "cs_detail should be at least 100 bytes") + } + + @Test("Function availability check") + func testFunctionAvailability() async throws { + // Verify that all core C functions can be referenced (can be linked) + let functions: [String: Any] = [ + "cs_version": cs_version, + "cs_open": cs_open, + "cs_close": cs_close, + "cs_disasm": cs_disasm, + "cs_malloc": cs_malloc, + "cs_disasm_iter": cs_disasm_iter, + "cs_free": cs_free, + "cs_option": cs_option, + "cs_errno": cs_errno, + "cs_strerror": cs_strerror, + ] + + print("✓ Available C API functions:") + for (name, _) in functions.sorted(by: { $0.key < $1.key }) { + print(" - \(name)") + } + + #expect(functions.count == 10, "Should have 10 basic functions available") + } + + @Test("Version consistency validation") + func testVersionConsistency() async throws { + // Test version function consistency + var major1: Int32 = 0, minor1: Int32 = 0 + var major2: Int32 = 0, minor2: Int32 = 0 + + let version1 = cs_version(&major1, &minor1) + let version2 = cs_version(&major2, &minor2) + + #expect(version1 == version2, "Version should remain consistent") + #expect(major1 == major2, "Major version should remain consistent") + #expect(minor1 == minor2, "Minor version should remain consistent") + + // Test correctness of version calculation + let calculatedVersion = UInt32((major1 << 8) | minor1) + #expect(version1 == calculatedVersion, "Version calculation should be correct") + + print("✓ Version consistency verification passed") + } + + @Test("Edge cases handling") + func testEdgeCases() async throws { + // Test edge cases + + // Test invalid error codes + let invalidError = cs_err(rawValue: 9999) + let invalidMsg = cs_strerror(invalidError) + #expect(invalidMsg != nil, "Invalid error codes should also have messages") + + // Test version with nil parameters + let versionOnly = cs_version(nil, nil) + #expect(versionOnly > 0, "Getting version only should work") + + print("✓ Edge cases handled correctly") + } +} diff --git a/bindings/swift/CcapstoneTests/DetailTests.swift b/bindings/swift/CcapstoneTests/DetailTests.swift new file mode 100644 index 0000000000..96f80a7ea2 --- /dev/null +++ b/bindings/swift/CcapstoneTests/DetailTests.swift @@ -0,0 +1,271 @@ +import XCTest +@testable import Ccapstone + +final class DetailTests: XCTestCase { + func testX86Detail() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + // mov rax, qword ptr [rip + 0x13b8] + let code: [UInt8] = [0x48, 0x8B, 0x05, 0xB8, 0x13, 0x00, 0x00] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertEqual(count, 1) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + let insn = insns![0] + XCTAssertNotNil(insn.detail) + + if insn.detail != nil { + let detail = insn.detail!.pointee + let x86Detail = detail.x86 + + // Check basic detail properties + XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) + XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) + XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + + // Check X86-specific details + XCTAssertGreaterThan(x86Detail.op_count, 0) + XCTAssertLessThanOrEqual(x86Detail.op_count, 8) + + print("X86 Detail:") + print(" Instruction ID: \(insn.id)") + print(" Groups count: \(detail.groups_count)") + print(" Regs read count: \(detail.regs_read_count)") + print(" Regs write count: \(detail.regs_write_count)") + print(" Operands count: \(x86Detail.op_count)") + + // Print operand information + let operands = withUnsafeBytes(of: x86Detail.operands) { bytes in + return bytes.bindMemory(to: cs_x86_op.self) + } + + for i in 0 ..< min(Int(x86Detail.op_count), 8) { + let operand = operands[i] + print(" Operand \(i): type=\(operand.type.rawValue), size=\(operand.size)") + } + } + + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + + func testARMDetail() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + // str lr, [sp, #-4]! + let code: [UInt8] = [0x04, 0xE0, 0x2D, 0xE5] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertEqual(count, 1) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + let insn = insns![0] + XCTAssertNotNil(insn.detail) + + if insn.detail != nil { + let detail = insn.detail!.pointee + let armDetail = detail.arm + + // Check basic detail properties + XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) + XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) + XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + + // Check ARM-specific details + XCTAssertGreaterThan(armDetail.op_count, 0) + XCTAssertLessThanOrEqual(armDetail.op_count, 36) + + print("ARM Detail:") + print(" Instruction ID: \(insn.id)") + print(" Groups count: \(detail.groups_count)") + print(" Regs read count: \(detail.regs_read_count)") + print(" Regs write count: \(detail.regs_write_count)") + print(" Operands count: \(armDetail.op_count)") + print(" CC: \(armDetail.cc.rawValue)") + print(" Update flags: \(armDetail.update_flags)") + // print(" Writeback: \(armDetail.writeback)") // Not available in this struct + } + + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + + func testAArch64Detail() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_AARCH64, CS_MODE_ARM, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + // add x1, x1, x2 + let code: [UInt8] = [0x21, 0x00, 0x02, 0x8B] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertEqual(count, 1) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + let insn = insns![0] + XCTAssertNotNil(insn.detail) + + if insn.detail != nil { + let detail = insn.detail!.pointee + let aarch64Detail = detail.aarch64 + + // Check basic detail properties + XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) + XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) + XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + + // Check AArch64-specific details + XCTAssertGreaterThan(aarch64Detail.op_count, 0) + XCTAssertLessThanOrEqual(aarch64Detail.op_count, 8) + + print("AArch64 Detail:") + print(" Instruction ID: \(insn.id)") + print(" Groups count: \(detail.groups_count)") + print(" Regs read count: \(detail.regs_read_count)") + print(" Regs write count: \(detail.regs_write_count)") + print(" Operands count: \(aarch64Detail.op_count)") + print(" CC: \(aarch64Detail.cc.rawValue)") + print(" Update flags: \(aarch64Detail.update_flags)") + // print(" Writeback: \(aarch64Detail.writeback)") // Not available in this struct + } + + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + + func testMIPSDetail() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_MIPS, cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + // jal 0x97000c + let code: [UInt8] = [0x0C, 0x10, 0x00, 0x97] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertEqual(count, 1) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + let insn = insns![0] + XCTAssertNotNil(insn.detail) + + if insn.detail != nil { + let detail = insn.detail!.pointee + let mipsDetail = detail.mips + + // Check basic detail properties + XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) + XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) + XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + + // Check MIPS-specific details + XCTAssertGreaterThan(mipsDetail.op_count, 0) + XCTAssertLessThanOrEqual(mipsDetail.op_count, 4) + + print("MIPS Detail:") + print(" Instruction ID: \(insn.id)") + print(" Groups count: \(detail.groups_count)") + print(" Regs read count: \(detail.regs_read_count)") + print(" Regs write count: \(detail.regs_write_count)") + print(" Operands count: \(mipsDetail.op_count)") + } + + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + + func testInstructionGroups() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + // ret instruction + let code: [UInt8] = [0xC3] + var insns: UnsafeMutablePointer? + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) + } + + XCTAssertEqual(count, 1) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + let insn = insns![0] + XCTAssertNotNil(insn.detail) + + if insn.detail != nil { + let detail = insn.detail!.pointee + + print("Instruction groups:") + print(" Groups count: \(detail.groups_count)") + + // Check if this instruction belongs to some groups + let groups = withUnsafeBytes(of: detail.groups) { bytes in + return bytes.bindMemory(to: UInt8.self) + } + + for i in 0 ..< min(Int(detail.groups_count), 16) { + let group = groups[i] + print(" Group \(i): \(group)") + } + } + + cs_free(insns, count) + } + + _ = cs_close(&handle) + } +} diff --git a/bindings/swift/CcapstoneTests/DisassemblyTests.swift b/bindings/swift/CcapstoneTests/DisassemblyTests.swift new file mode 100644 index 0000000000..918b11c229 --- /dev/null +++ b/bindings/swift/CcapstoneTests/DisassemblyTests.swift @@ -0,0 +1,223 @@ +import XCTest +@testable import Ccapstone + +final class DisassemblyTests: XCTestCase { + + // Test data from existing tests + private let x86Code32: [UInt8] = [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00] + private let x86Code64: [UInt8] = [0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00] + private let armCode: [UInt8] = [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x83, 0x22, 0xe5] + private let thumbCode: [UInt8] = [0x70, 0x47, 0xeb, 0x46, 0x83, 0xb0, 0xc9, 0x68] + private let aarch64Code: [UInt8] = [0x21, 0x7c, 0x02, 0x9b, 0x21, 0x7c, 0x00, 0x53, 0x00, 0x40, 0x21, 0x4b, 0xe1, 0x0b, 0x40, 0xb9] + private let mipsCode: [UInt8] = [0x0C, 0x10, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0c, 0x8f, 0xa2, 0x00, 0x00] + private let ppcCode: [UInt8] = [0x80, 0x20, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x10, 0x43, 0x23, 0x0e, 0xd0, 0x44, 0x00, 0x80] + + func testX86_32() { + performDisassemblyTest( + arch: CS_ARCH_X86, + mode: CS_MODE_32, + code: x86Code32, + comment: "X86 32bit" + ) + } + + func testX86_64() { + performDisassemblyTest( + arch: CS_ARCH_X86, + mode: CS_MODE_64, + code: x86Code64, + comment: "X86 64bit" + ) + } + + func testARM() { + performDisassemblyTest( + arch: CS_ARCH_ARM, + mode: CS_MODE_ARM, + code: armCode, + comment: "ARM" + ) + } + + func testThumb() { + performDisassemblyTest( + arch: CS_ARCH_ARM, + mode: CS_MODE_THUMB, + code: thumbCode, + comment: "Thumb" + ) + } + + func testAArch64() { + performDisassemblyTest( + arch: CS_ARCH_AARCH64, + mode: CS_MODE_ARM, + code: aarch64Code, + comment: "AArch64" + ) + } + + func testMIPS() { + performDisassemblyTest( + arch: CS_ARCH_MIPS, + mode: cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), + code: mipsCode, + comment: "MIPS32 Big-endian" + ) + } + + func testPPC() { + performDisassemblyTest( + arch: CS_ARCH_PPC, + mode: CS_MODE_BIG_ENDIAN, + code: ppcCode, + comment: "PowerPC" + ) + } + + func testDisasmWithDetail() { + var handle: csh = 0 + var insns: UnsafeMutablePointer? + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(optResult, CS_ERR_OK) + + let count = x86Code32.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertGreaterThan(count, 0) + XCTAssertNotNil(insns) + + if count > 0 && insns != nil { + for i in 0..? + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + // Test with invalid/empty code + let invalidCode: [UInt8] = [] + let count = invalidCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertEqual(count, 0) + + _ = cs_close(&handle) + } + + func testSkipData() { + var handle: csh = 0 + + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + XCTAssertEqual(openResult, CS_ERR_OK) + + let skipDataResult = cs_option(handle, CS_OPT_SKIPDATA, size_t(CS_OPT_ON.rawValue)) + XCTAssertEqual(skipDataResult, CS_ERR_OK) + + // Test with some invalid bytes mixed in + let mixedCode: [UInt8] = [0xFF, 0xFF, 0xFF, 0xFF] + x86Code32 + var insns: UnsafeMutablePointer? + + let count = mixedCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertGreaterThan(count, 0) + + if count > 0 && insns != nil { + cs_free(insns, count) + } + + _ = cs_close(&handle) + } + + // Helper function for basic disassembly tests + private func performDisassemblyTest(arch: cs_arch, mode: cs_mode, code: [UInt8], comment: String) { + var handle: csh = 0 + var insns: UnsafeMutablePointer? + + let openResult = cs_open(arch, mode, &handle) + XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + + let count = code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + XCTAssertGreaterThan(count, 0, "No instructions disassembled for \(comment)") + XCTAssertNotNil(insns, "Instructions pointer is nil for \(comment)") + + if count > 0 && insns != nil { + print("\n\(comment):") + for i in 0...size + let detailSize = MemoryLayout.size + + XCTAssertGreaterThan(insnSize, 0, "cs_insn structure should have positive size") + XCTAssertGreaterThan(detailSize, 0, "cs_detail structure should have positive size") + + print("✓ Structure sizes:") + print(" cs_insn: \(insnSize) bytes") + print(" cs_detail: \(detailSize) bytes") + + // cs_insn should be reasonably sized (has mnemonic, op_str, etc.) + XCTAssertGreaterThan(insnSize, 64, "cs_insn should be at least 64 bytes") + + // cs_detail should be large (has architecture-specific unions) + XCTAssertGreaterThan(detailSize, 100, "cs_detail should be at least 100 bytes") + } + + func testVersionConsistency() { + // Test version consistency across different calls + var major1: Int32 = 0, minor1: Int32 = 0 + var major2: Int32 = 0, minor2: Int32 = 0 + + let version1 = cs_version(&major1, &minor1) + let version2 = cs_version(&major2, &minor2) + + XCTAssertEqual(version1, version2, "Version should be consistent") + XCTAssertEqual(major1, major2, "Major version should be consistent") + XCTAssertEqual(minor1, minor2, "Minor version should be consistent") + + // Test CS_MAKE_VERSION macro equivalent + let calculatedVersion = UInt32((major1 << 8) | minor1) + XCTAssertEqual(version1, calculatedVersion, "Version calculation should match macro") + + print("✓ Version consistency verified") + } +} diff --git a/bindings/swift/CcapstoneTests/PerformanceTests.swift b/bindings/swift/CcapstoneTests/PerformanceTests.swift new file mode 100644 index 0000000000..3223ef3933 --- /dev/null +++ b/bindings/swift/CcapstoneTests/PerformanceTests.swift @@ -0,0 +1,318 @@ +import Foundation +import Testing +@testable import Ccapstone + +/// Performance and stress tests for the Capstone Swift binding +/// These tests verify performance characteristics and stress the API under various conditions +@Suite("Performance Tests") +struct PerformanceTests { + + // Test data for performance testing + private static let x86Code32: [UInt8] = [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00] + private static let x86Code64: [UInt8] = [0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00] + private static let armCode: [UInt8] = [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x83, 0x22, 0xe5] + + /// Large code block for stress testing + private static let largeCodeBlock: [UInt8] = { + var code = [UInt8]() + // Repeat the x86 32-bit code 1000 times for stress testing + for _ in 0..<1000 { + code.append(contentsOf: x86Code32) + } + return code + }() + + @Test("Multiple handle creation and destruction performance") + func testHandleCreationPerformance() async throws { + let iterations = 1000 + let startTime = CFAbsoluteTimeGetCurrent() + + for _ in 0..? + let count = Self.largeCodeBlock.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + let endTime = CFAbsoluteTimeGetCurrent() + let totalTime = endTime - startTime + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + print("✓ Large code block disassembly:") + print(" Code size: \(Self.largeCodeBlock.count) bytes") + print(" Instructions disassembled: \(count)") + print(" Time taken: \(String(format: "%.4f", totalTime)) seconds") + + if count > 0 { + let throughput = Double(Self.largeCodeBlock.count) / totalTime / 1024 / 1024 // MB/s + print(" Throughput: \(String(format: "%.2f", throughput)) MB/s") + + // Basic performance expectation - should process at least 1MB/s + #expect(throughput > 1.0, "Should have reasonable throughput") + } + + #expect(count >= 0, "Should not fail catastrophically") + } + + @Test("Iterator API performance comparison") + func testIteratorVsBatchDisassembly() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping iterator performance test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + let testCode = Self.x86Code32 + + // Test batch disassembly performance + let batchStartTime = CFAbsoluteTimeGetCurrent() + var insns: UnsafeMutablePointer? + let batchCount = testCode.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + let batchEndTime = CFAbsoluteTimeGetCurrent() + let batchTime = batchEndTime - batchStartTime + + if batchCount > 0 { + cs_free(insns, batchCount) + } + + // Test iterator API performance + let iterStartTime = CFAbsoluteTimeGetCurrent() + let insn = cs_malloc(handle) + var iterCount: Int = 0 + + if let insn = insn { + testCode.withUnsafeBufferPointer { buffer in + var codePtr = buffer.baseAddress + var size = testCode.count + var address: UInt64 = 0x1000 + + while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { + iterCount += 1 + } + } + cs_free(insn, 1) + } + + let iterEndTime = CFAbsoluteTimeGetCurrent() + let iterTime = iterEndTime - iterStartTime + + print("✓ API performance comparison:") + print(" Batch API: \(batchCount) instructions in \(String(format: "%.6f", batchTime)) seconds") + print(" Iterator API: \(iterCount) instructions in \(String(format: "%.6f", iterTime)) seconds") + + #expect(batchCount == iterCount, "Both methods should find same number of instructions") + } + + @Test("Memory allocation stress test") + func testMemoryAllocationStress() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping memory stress test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + let allocations = 1000 + var allocatedPointers: [UnsafeMutablePointer] = [] + + // Allocate many instruction structures + for _ in 0.. allocations / 2, "Should successfully allocate most structures") + } + + @Test("Rapid open/close cycles") + func testRapidOpenCloseCycles() async throws { + let cycles = 10000 + var successfulCycles = 0 + let architectures: [(cs_arch, cs_mode)] = [ + (CS_ARCH_X86, CS_MODE_32), + (CS_ARCH_X86, CS_MODE_64), + (CS_ARCH_ARM, CS_MODE_ARM), + (CS_ARCH_ARM, CS_MODE_THUMB) + ] + + let startTime = CFAbsoluteTimeGetCurrent() + + for i in 0.. 0, "Should complete some cycles successfully") + } + + @Test("Option setting performance") + func testOptionSettingPerformance() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping option performance test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + let iterations = 10000 + let options: [(cs_opt_type, size_t)] = [ + (CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)), + (CS_OPT_DETAIL, size_t(CS_OPT_OFF.rawValue)), + ] + + let startTime = CFAbsoluteTimeGetCurrent() + var successfulOperations = 0 + + for i in 0.. 0 { + let avgTime = totalTime / Double(successfulOperations) * 1000000 // Convert to microseconds + print(" Average time per operation: \(String(format: "%.2f", avgTime)) μs") + } + } + + @Test("Concurrent access safety test") + func testConcurrentAccess() async throws { + // Note: This test creates separate handles for concurrent access + // Each handle should be used from only one thread at a time + + let concurrentTasks = 10 + let operationsPerTask = 100 + + await withTaskGroup(of: Int.self) { group in + for _ in 0..? + let count = Self.x86Code32.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + if count > 0 { + cs_free(insns, count) + successfulOperations += 1 + } + + _ = cs_close(&handle) + } + } + + return successfulOperations + } + } + + var totalSuccessful = 0 + for await result in group { + totalSuccessful += result + } + + let totalOperations = concurrentTasks * operationsPerTask + print("✓ Concurrent access test:") + print(" Total operations: \(totalOperations)") + print(" Successful operations: \(totalSuccessful)") + print(" Success rate: \(String(format: "%.1f", Double(totalSuccessful) / Double(totalOperations) * 100))%") + + // Should handle concurrent operations reasonably well + #expect(totalSuccessful > 0, "Should complete some operations successfully") + } + } +} \ No newline at end of file diff --git a/bindings/swift/CcapstoneTests/SimpleTests.swift b/bindings/swift/CcapstoneTests/SimpleTests.swift new file mode 100644 index 0000000000..2666380dd9 --- /dev/null +++ b/bindings/swift/CcapstoneTests/SimpleTests.swift @@ -0,0 +1,95 @@ +import XCTest +@testable import Ccapstone + +final class SimpleTests: XCTestCase { + + func testVersionOnly() { + var major: Int32 = 0 + var minor: Int32 = 0 + + let version = cs_version(&major, &minor) + + XCTAssertGreaterThan(major, 0) + XCTAssertGreaterThanOrEqual(minor, 0) + XCTAssertGreaterThan(version, 0) + XCTAssertEqual(version, UInt32((major << 8) | minor)) + + print("Capstone version: \(major).\(minor) (0x\(String(format: "%04x", version)))") + } + + func testBasicAPIAvailability() { + // Test that all basic functions are available + // This doesn't actually call them, just verifies they can be referenced + let _ = cs_open + let _ = cs_close + let _ = cs_disasm + let _ = cs_malloc + let _ = cs_disasm_iter + let _ = cs_free + let _ = cs_option + let _ = cs_errno + let _ = cs_strerror + let _ = cs_version + + // Test enum availability + let _ = CS_ARCH_X86 + let _ = CS_MODE_32 + let _ = CS_ERR_OK + let _ = CS_OPT_DETAIL + let _ = CS_OPT_ON + + XCTAssertTrue(true, "All basic API functions are available") + } + + func testErrorMessages() { + let errorCodes: [cs_err] = [ + CS_ERR_OK, + CS_ERR_MEM, + CS_ERR_ARCH, + CS_ERR_HANDLE, + CS_ERR_CSH, + CS_ERR_MODE, + CS_ERR_OPTION + ] + + print("Testing error messages:") + for errorCode in errorCodes { + let message = cs_strerror(errorCode) + XCTAssertNotNil(message, "Error message should not be nil for \(errorCode)") + + if let message = message { + let errorString = String(cString: message) + XCTAssertFalse(errorString.isEmpty, "Error message should not be empty for \(errorCode)") + print(" \(errorCode.rawValue): \(errorString)") + } + } + } + + func testSimpleOpenClose() { + var handle: csh = 0 + + print("Testing cs_open...") + let result = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + if result == CS_ERR_OK { + print("✓ cs_open succeeded, handle: \(handle)") + XCTAssertNotEqual(handle, 0, "Handle should not be zero") + + print("Testing cs_close...") + let closeResult = cs_close(&handle) + if closeResult == CS_ERR_OK { + print("✓ cs_close succeeded") + XCTAssertEqual(handle, 0, "Handle should be zero after close") + } else { + let errorMsg = cs_strerror(closeResult) + let errorString = errorMsg != nil ? String(cString: errorMsg!) : "Unknown error" + print("✗ cs_close failed: \(errorString)") + XCTFail("cs_close failed with error: \(errorString)") + } + } else { + let errorMsg = cs_strerror(result) + let errorString = errorMsg != nil ? String(cString: errorMsg!) : "Unknown error" + print("✗ cs_open failed: \(errorString)") + XCTFail("cs_open failed with error: \(errorString)") + } + } +} \ No newline at end of file diff --git a/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift b/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift new file mode 100644 index 0000000000..1ed5f7934e --- /dev/null +++ b/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift @@ -0,0 +1,542 @@ +import Foundation +import Testing +@testable import Ccapstone + +/// Swift-specific integration tests for the Capstone binding +/// These tests verify Swift-specific patterns, safety features, and idiomatic usage +@Suite("Swift Integration Tests") +struct SwiftIntegrationTests { + // Test data + private static let x86Code: [UInt8] = [0x8D, 0x4C, 0x32, 0x08, 0x01, 0xD8, 0x81, 0xC6, 0x34, 0x12, 0x00, 0x00] + + @Test("Swift optionals and error handling") + func testSwiftOptionals() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping Swift optionals test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + print("✓ Swift optionals and error handling:") + + // Test cs_malloc returning optional + let insn = cs_malloc(handle) + if let insn = insn { + print(" cs_malloc returned valid pointer: \(insn)") + cs_free(insn, 1) + } else { + print(" cs_malloc returned nil") + } + + // Test cs_strerror returning optional + let errorMessage = cs_strerror(CS_ERR_OK) + if let message = errorMessage { + let errorString = String(cString: message) + print(" Error message: '\(errorString)'") + #expect(!errorString.isEmpty, "Error message should not be empty") + } else { + #expect(Bool(false), "cs_strerror should not return nil") + } + } + + @Test("Swift memory management patterns") + func testSwiftMemoryManagement() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping memory management test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + print("✓ Swift memory management patterns:") + + // Test RAII-style pattern with defer + func performDisassemblyWithDefer() -> size_t { + var insns: UnsafeMutablePointer? + let count = Self.x86Code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + // Simulate some processing + if count > 0 { + let firstInsn = insns!.pointee + _ = withUnsafeBytes(of: firstInsn.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + } + + return count + } + + let deferCount = performDisassemblyWithDefer() + print(" RAII-style pattern with defer: \(deferCount) instructions") + + // Test withUnsafeBufferPointer pattern + let bufferCount = Self.x86Code.withUnsafeBufferPointer { buffer -> size_t in + var insns: UnsafeMutablePointer? + let count = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if count > 0 { + cs_free(insns, count) + } + } + return count + } + + print(" withUnsafeBufferPointer pattern: \(bufferCount) instructions") + #expect(deferCount == bufferCount, "Both patterns should yield same results") + + // Test iterator pattern with automatic cleanup + func testIteratorPattern() -> Int { + guard let insn = cs_malloc(handle) else { + return 0 + } + defer { cs_free(insn, 1) } + + var instructionCount = 0 + Self.x86Code.withUnsafeBufferPointer { buffer in + var codePtr = buffer.baseAddress + var size = Self.x86Code.count + var address: UInt64 = 0x1000 + + while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { + instructionCount += 1 + let mnemonic = withUnsafeBytes(of: insn.pointee.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + let _ = mnemonic // Use the value + + if instructionCount > 100 { // Safety break + break + } + } + } + + return instructionCount + } + + let iteratorCount = testIteratorPattern() + print(" Iterator pattern with automatic cleanup: \(iteratorCount) instructions") + } + + @Test("Swift string handling and C interop") + func testSwiftStringHandling() async throws { + print("✓ Swift string handling and C interop:") + + // Test converting C strings to Swift strings + let testErrors: [cs_err] = [CS_ERR_OK, CS_ERR_MEM, CS_ERR_ARCH, CS_ERR_HANDLE] + + for errorCode in testErrors { + if let cMessage = cs_strerror(errorCode) { + let swiftString = String(cString: cMessage) + + // Test Swift string operations + let uppercased = swiftString.uppercased() + let length = swiftString.count + let utf8Count = swiftString.utf8.count + + print(" Error \(errorCode.rawValue): '\(swiftString)' -> '\(uppercased)' (\(length)/\(utf8Count) chars)") + + #expect(!swiftString.isEmpty, "Swift string should not be empty") + #expect(length > 0, "String length should be positive") + #expect(utf8Count >= length, "UTF-8 byte count should be >= character count") + } + } + + // Test version information as Swift strings + var major: Int32 = 0 + var minor: Int32 = 0 + let version = cs_version(&major, &minor) + + let versionString = String(format: "%d.%d", major, minor) + let hexVersionString = String(format: "0x%04x", version) + + print(" Version: \(versionString) (\(hexVersionString))") + + #expect(versionString.count >= 3, "Version string should be at least X.Y") + #expect(hexVersionString.hasPrefix("0x"), "Hex version should start with 0x") + } + + @Test("Swift array and collection integration") + func testSwiftCollectionIntegration() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping collection integration test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + print("✓ Swift array and collection integration:") + + // Test with different array types + let testData: [String: [UInt8]] = [ + "x86_32": [0x8D, 0x4C, 0x32, 0x08], + "nops": [0x90, 0x90, 0x90, 0x90], + "empty": [], + "single": [0x90], + ] + + for (name, codeArray) in testData { + let count = codeArray.withUnsafeBufferPointer { buffer -> size_t in + var insns: UnsafeMutablePointer? + let result = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if result > 0 { + cs_free(insns, result) + } + } + return result + } + + print(" \(name) array (\(codeArray.count) bytes): \(count) instructions") + } + + // Test using Array methods + let extendedCode = Self.x86Code + Self.x86Code // Array concatenation + let count = extendedCode.withUnsafeBufferPointer { buffer -> size_t in + var insns: UnsafeMutablePointer? + let result = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if result > 0 { + cs_free(insns, result) + } + } + return result + } + + print(" Extended array (\(extendedCode.count) bytes): \(count) instructions") + + // Test with ArraySlice + if extendedCode.count > 4 { + let slice = extendedCode[2 ..< 6] // Take a slice + let sliceArray = Array(slice) // Convert slice to array for withUnsafeBufferPointer + + let sliceCount = sliceArray.withUnsafeBufferPointer { buffer -> size_t in + var insns: UnsafeMutablePointer? + let result = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if result > 0 { + cs_free(insns, result) + } + } + return result + } + + print(" Array slice (\(sliceArray.count) bytes): \(sliceCount) instructions") + } + } + + @Test("Swift error handling patterns") + func testSwiftErrorHandling() async throws { + print("✓ Swift error handling patterns:") + + // Define a Swift wrapper that throws + enum CapstoneError: Error, CustomStringConvertible { + case openFailed(cs_err) + case disassemblyFailed(cs_err) + case invalidHandle + + var description: String { + switch self { + case .openFailed(let err): + if let msg = cs_strerror(err) { + return "Open failed: \(String(cString: msg))" + } + return "Open failed: \(err)" + case .disassemblyFailed(let err): + return "Disassembly failed: \(err)" + case .invalidHandle: + return "Invalid handle" + } + } + } + + func safeOpen(arch: cs_arch, mode: cs_mode) throws -> csh { + var handle: csh = 0 + let result = cs_open(arch, mode, &handle) + guard result == CS_ERR_OK else { + throw CapstoneError.openFailed(result) + } + return handle + } + + func safeDisassemble(handle: csh, code: [UInt8]) throws -> Int { + guard handle != 0 else { + throw CapstoneError.invalidHandle + } + + return code.withUnsafeBufferPointer { buffer -> Int in + var insns: UnsafeMutablePointer? + let count = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if count > 0 { + cs_free(insns, count) + } + } + return Int(count) + } + } + + // Test successful case + do { + let handle = try safeOpen(arch: CS_ARCH_X86, mode: CS_MODE_32) + defer { + var mutableHandle = handle + _ = cs_close(&mutableHandle) + } + + let count = try safeDisassemble(handle: handle, code: Self.x86Code) + print(" Successful operation: \(count) instructions") + + } catch { + print(" Expected success case failed: \(error)") + } + + // Test failure case + do { + _ = try safeOpen(arch: cs_arch(rawValue: 999), mode: CS_MODE_32) + print(" Expected failure case succeeded (unexpected)") + } catch let error as CapstoneError { + print(" Expected failure caught: \(error)") + } catch { + print(" Unexpected error type: \(error)") + } + + // Test invalid handle + do { + _ = try safeDisassemble(handle: 0, code: Self.x86Code) + print(" Invalid handle case succeeded (unexpected)") + } catch let error as CapstoneError { + print(" Invalid handle error caught: \(error)") + } catch { + print(" Unexpected error for invalid handle: \(error)") + } + } + + @Test("Swift value types and reference types") + func testSwiftValueAndReferenceTypes() async throws { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + print("⚠️ Skipping value/reference types test - cannot open engine") + return + } + + defer { _ = cs_close(&handle) } + + print("✓ Swift value types and reference types:") + + // Test copying instruction data to Swift value types + struct SwiftInstruction { + var address: UInt64 + let size: UInt16 + let mnemonic: String + let operands: String + let bytes: [UInt8] + + init(from csInsn: cs_insn) { + self.address = csInsn.address + self.size = csInsn.size + self.mnemonic = withUnsafeBytes(of: csInsn.mnemonic) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + self.operands = withUnsafeBytes(of: csInsn.op_str) { bytes in + String(cString: bytes.bindMemory(to: CChar.self).baseAddress!) + } + + // Copy bytes (simplified - in real implementation would copy actual bytes) + var byteArray: [UInt8] = [] + for _ in 0 ..< min(Int(csInsn.size), 16) { // Limit to reasonable size + // Note: This is simplified - real implementation would access csInsn.bytes properly + byteArray.append(0x90) // Placeholder + } + self.bytes = byteArray + } + } + + var swiftInstructions: [SwiftInstruction] = [] + + var insns: UnsafeMutablePointer? + let count = Self.x86Code.withUnsafeBufferPointer { buffer in + cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + } + + defer { + if count > 0 { + cs_free(insns, count) + } + } + + // Convert C structures to Swift value types + if count > 0 { + for i in 0 ..< count { + let csInsn = (insns! + i).pointee + let swiftInsn = SwiftInstruction(from: csInsn) + swiftInstructions.append(swiftInsn) + } + } + + print(" Converted \(swiftInstructions.count) instructions to Swift value types") + + // Test Swift collection operations on converted data + let mnemonics = swiftInstructions.map { $0.mnemonic } + let addresses = swiftInstructions.map { $0.address } + let totalBytes = swiftInstructions.reduce(0) { $0 + Int($1.size) } + + print(" Mnemonics: \(mnemonics)") + print(" Addresses: \(addresses.map { String(format: "0x%llx", $0) })") + print(" Total instruction bytes: \(totalBytes)") + + // Test value semantics + if var firstInstruction = swiftInstructions.first { + let originalAddress = firstInstruction.address + firstInstruction.address = 0x2000 // This shouldn't affect the array + + let arrayAddress = swiftInstructions.first?.address ?? 0 + #expect(originalAddress == arrayAddress, "Value types should maintain independence") + print(" Value type semantics: ✓ (original: 0x\(String(format: "%llx", originalAddress)), array: 0x\(String(format: "%llx", arrayAddress)))") + } + } + + @Test("Swift async/await compatibility") + func testAsyncAwaitCompatibility() async throws { + print("✓ Swift async/await compatibility:") + + // Test that Capstone operations can be used in async contexts + func asyncDisassembly() async -> Int { + var handle: csh = 0 + let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) + + guard openResult == CS_ERR_OK else { + return -1 + } + + defer { _ = cs_close(&handle) } + + // Simulate some async work + try? await Task.sleep(nanoseconds: 1_000_000) // 1ms + + return Self.x86Code.withUnsafeBufferPointer { buffer -> Int in + var insns: UnsafeMutablePointer? + let count = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if count > 0 { + cs_free(insns, count) + } + } + return Int(count) + } + } + + let result = await asyncDisassembly() + print(" Async disassembly result: \(result) instructions") + + // Test concurrent async operations + async let result1 = asyncDisassembly() + async let result2 = asyncDisassembly() + async let result3 = asyncDisassembly() + + let results = await [result1, result2, result3] + print(" Concurrent async results: \(results)") + + // All should succeed or fail consistently + let successfulResults = results.filter { $0 >= 0 } + if !successfulResults.isEmpty { + let allSame = successfulResults.allSatisfy { $0 == successfulResults.first } + #expect(allSame, "Concurrent operations should yield same results") + print(" Concurrent consistency: \(allSame ? "✓" : "✗")") + } + } + + @Test("Swift generic and protocol integration") + func testGenericAndProtocolIntegration() async throws { + print("✓ Swift generic and protocol integration:") + + // Define protocols for Capstone operations + protocol DisassemblyProvider { + func disassemble(_ code: T) -> Int where T.Element == UInt8 + } + + class CapstoneDisassembler: DisassemblyProvider { + let handle: csh + + init?(architecture: cs_arch, mode: cs_mode) { + var handle: csh = 0 + let result = cs_open(architecture, mode, &handle) + guard result == CS_ERR_OK else { + return nil + } + self.handle = handle + } + + deinit { + var mutableHandle = handle + _ = cs_close(&mutableHandle) + } + + func disassemble(_ code: T) -> Int where T.Element == UInt8 { + let codeArray = Array(code) // Convert any collection to array + return codeArray.withUnsafeBufferPointer { buffer -> Int in + var insns: UnsafeMutablePointer? + let count = cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) + defer { + if count > 0 { + cs_free(insns, count) + } + } + return Int(count) + } + } + } + + // Test with different collection types + guard let disassembler = CapstoneDisassembler(architecture: CS_ARCH_X86, mode: CS_MODE_32) else { + print(" Could not create disassembler") + return + } + + // Test with Array + let arrayResult = disassembler.disassemble(Self.x86Code) + print(" Array disassembly: \(arrayResult) instructions") + + // Test with ArraySlice + if Self.x86Code.count > 4 { + let slice = Self.x86Code[0 ..< 4] + let sliceResult = disassembler.disassemble(slice) + print(" ArraySlice disassembly: \(sliceResult) instructions") + } + + // Test with different UInt8 collections + let set = Set(Self.x86Code) + let setArray = Array(set).sorted() // Convert set back to sorted array for consistent results + let setResult = disassembler.disassemble(setArray) + print(" Set-derived array disassembly: \(setResult) instructions") + + // Test generic function + func testGenericDisassembly(_ provider: DisassemblyProvider, code: T) -> Int where T.Element == UInt8 { + return provider.disassemble(code) + } + + let genericResult = testGenericDisassembly(disassembler, code: Self.x86Code) + print(" Generic function result: \(genericResult) instructions") + + #expect(arrayResult == genericResult, "Generic and direct calls should yield same results") + } +} From 0d6f7f23dc7ea7b41fa6555ca0d71ed23bfddc02 Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Tue, 16 Sep 2025 00:40:03 +0800 Subject: [PATCH 09/12] Update to Swift Testing --- .../CcapstoneTests/ArchitectureTests.swift | 82 ++++++------- .../swift/CcapstoneTests/DetailTests.swift | 115 +++++++++--------- .../CcapstoneTests/DisassemblyTests.swift | 71 +++++------ .../swift/CcapstoneTests/MinimalTests.swift | 86 ++++++------- .../swift/CcapstoneTests/SimpleTests.swift | 37 +++--- .../SwiftIntegrationTests.swift | 24 ++-- 6 files changed, 209 insertions(+), 206 deletions(-) diff --git a/bindings/swift/CcapstoneTests/ArchitectureTests.swift b/bindings/swift/CcapstoneTests/ArchitectureTests.swift index af9b6ebd54..2d526bc7fc 100644 --- a/bindings/swift/CcapstoneTests/ArchitectureTests.swift +++ b/bindings/swift/CcapstoneTests/ArchitectureTests.swift @@ -1,8 +1,8 @@ -import XCTest +import Foundation +import Testing @testable import Ccapstone -final class ArchitectureTests: XCTestCase { - +@Suite struct ArchitectureTests { // Test code samples for different architectures private struct TestPlatform { let arch: cs_arch @@ -15,93 +15,93 @@ final class ArchitectureTests: XCTestCase { TestPlatform( arch: CS_ARCH_X86, mode: CS_MODE_16, - code: [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00], + code: [0x8D, 0x4C, 0x32, 0x08, 0x01, 0xD8, 0x81, 0xC6, 0x34, 0x12, 0x00, 0x00], comment: "X86 16bit" ), TestPlatform( arch: CS_ARCH_X86, mode: CS_MODE_32, - code: [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00], + code: [0x8D, 0x4C, 0x32, 0x08, 0x01, 0xD8, 0x81, 0xC6, 0x34, 0x12, 0x00, 0x00], comment: "X86 32bit" ), TestPlatform( arch: CS_ARCH_X86, mode: CS_MODE_64, - code: [0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00], + code: [0x55, 0x48, 0x8B, 0x05, 0xB8, 0x13, 0x00, 0x00], comment: "X86 64bit" ), TestPlatform( arch: CS_ARCH_ARM, mode: CS_MODE_ARM, - code: [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x83, 0x22, 0xe5], + code: [0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xE0, 0x2D, 0xE5, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x83, 0x22, 0xE5], comment: "ARM" ), TestPlatform( arch: CS_ARCH_ARM, mode: CS_MODE_THUMB, - code: [0x70, 0x47, 0xeb, 0x46, 0x83, 0xb0, 0xc9, 0x68], + code: [0x70, 0x47, 0xEB, 0x46, 0x83, 0xB0, 0xC9, 0x68], comment: "Thumb" ), TestPlatform( arch: CS_ARCH_AARCH64, mode: CS_MODE_ARM, - code: [0x21, 0x7c, 0x02, 0x9b, 0x21, 0x7c, 0x00, 0x53, 0x00, 0x40, 0x21, 0x4b, 0xe1, 0x0b, 0x40, 0xb9], + code: [0x21, 0x7C, 0x02, 0x9B, 0x21, 0x7C, 0x00, 0x53, 0x00, 0x40, 0x21, 0x4B, 0xE1, 0x0B, 0x40, 0xB9], comment: "AArch64" ), TestPlatform( arch: CS_ARCH_MIPS, mode: cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), - code: [0x0C, 0x10, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0c, 0x8f, 0xa2, 0x00, 0x00, 0x34, 0x21, 0x34, 0x56], + code: [0x0C, 0x10, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0C, 0x8F, 0xA2, 0x00, 0x00, 0x34, 0x21, 0x34, 0x56], comment: "MIPS32 Big-endian" ), TestPlatform( arch: CS_ARCH_MIPS, mode: cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), - code: [0x56, 0x34, 0x21, 0x34, 0xc2, 0x17, 0x01, 0x00], + code: [0x56, 0x34, 0x21, 0x34, 0xC2, 0x17, 0x01, 0x00], comment: "MIPS64 Little-endian" ), TestPlatform( arch: CS_ARCH_PPC, mode: CS_MODE_BIG_ENDIAN, - code: [0x80, 0x20, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x10, 0x43, 0x23, 0x0e, 0xd0, 0x44, 0x00, 0x80, 0x4c, 0x43, 0x22, 0x02], + code: [0x80, 0x20, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x10, 0x43, 0x23, 0x0E, 0xD0, 0x44, 0x00, 0x80, 0x4C, 0x43, 0x22, 0x02], comment: "PowerPC" ), TestPlatform( arch: CS_ARCH_SPARC, mode: CS_MODE_BIG_ENDIAN, - code: [0x80, 0xa0, 0x40, 0x02, 0x85, 0xc2, 0x60, 0x08, 0x85, 0xe8, 0x20, 0x01, 0x81, 0xe8, 0x00, 0x00, 0x90, 0x10, 0x20, 0x01], + code: [0x80, 0xA0, 0x40, 0x02, 0x85, 0xC2, 0x60, 0x08, 0x85, 0xE8, 0x20, 0x01, 0x81, 0xE8, 0x00, 0x00, 0x90, 0x10, 0x20, 0x01], comment: "Sparc" ), TestPlatform( arch: CS_ARCH_SYSTEMZ, mode: CS_MODE_BIG_ENDIAN, - code: [0xed, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x5a, 0x0f, 0x1f, 0xff, 0xc2, 0x09, 0x80, 0x00, 0x00, 0x00, 0x07, 0xf7], + code: [0xED, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x5A, 0x0F, 0x1F, 0xFF, 0xC2, 0x09, 0x80, 0x00, 0x00, 0x00, 0x07, 0xF7], comment: "SystemZ" - ) + ), ] - func testAllArchitectures() { + @Test func allArchitectures() { for platform in platforms { testArchitecture(platform) } } - func testX86Syntax() { + @Test func x86Syntax() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) // Test Intel syntax (default) - let code: [UInt8] = [0x8d, 0x4c, 0x32, 0x08] + let code: [UInt8] = [0x8D, 0x4C, 0x32, 0x08] var insns: UnsafeMutablePointer? let count = code.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertGreaterThan(count, 0) - if count > 0 && insns != nil { + #expect(count > 0) + if count > 0, insns != nil { let insn = insns![0] let opStr = String(cString: withUnsafeBytes(of: insn.op_str) { $0.bindMemory(to: CChar.self).baseAddress! }) print("Intel syntax: \(opStr)") @@ -126,28 +126,28 @@ final class ArchitectureTests: XCTestCase { _ = cs_close(&handle) } - func testMIPSModes() { + @Test func mIPSModes() { let mipsCodes: [(cs_mode, [UInt8], String)] = [ (cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), [0x0C, 0x10, 0x00, 0x97], "MIPS32 BE"), (cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), [0x97, 0x00, 0x10, 0x0C], "MIPS32 LE"), (cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_BIG_ENDIAN.rawValue), [0x0C, 0x10, 0x00, 0x97], "MIPS64 BE"), - (cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), [0x97, 0x00, 0x10, 0x0C], "MIPS64 LE") + (cs_mode(CS_MODE_MIPS64.rawValue | CS_MODE_LITTLE_ENDIAN.rawValue), [0x97, 0x00, 0x10, 0x0C], "MIPS64 LE"), ] for (mode, code, comment) in mipsCodes { var handle: csh = 0 let openResult = cs_open(CS_ARCH_MIPS, mode, &handle) - XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + #expect(openResult == CS_ERR_OK, "Failed to open \(comment)") var insns: UnsafeMutablePointer? let count = code.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertGreaterThanOrEqual(count, 0, "Disassembly failed for \(comment)") + #expect(count >= 0, "Disassembly failed for \(comment)") - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] let mnemonic = String(cString: withUnsafeBytes(of: insn.mnemonic) { $0.bindMemory(to: CChar.self).baseAddress! }) print("\(comment): \(mnemonic)") @@ -158,27 +158,27 @@ final class ArchitectureTests: XCTestCase { } } - func testARMModes() { + @Test func aRMModes() { let armTests: [(cs_mode, [UInt8], String)] = [ - (CS_MODE_ARM, [0x04, 0xe0, 0x2d, 0xe5], "ARM mode"), + (CS_MODE_ARM, [0x04, 0xE0, 0x2D, 0xE5], "ARM mode"), (CS_MODE_THUMB, [0x70, 0x47], "Thumb mode"), - (cs_mode(CS_MODE_THUMB.rawValue | CS_MODE_MCLASS.rawValue), [0x70, 0x47], "Thumb M-Class") + (cs_mode(CS_MODE_THUMB.rawValue | CS_MODE_MCLASS.rawValue), [0x70, 0x47], "Thumb M-Class"), ] for (mode, code, comment) in armTests { var handle: csh = 0 let openResult = cs_open(CS_ARCH_ARM, mode, &handle) - XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + #expect(openResult == CS_ERR_OK, "Failed to open \(comment)") var insns: UnsafeMutablePointer? let count = code.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertGreaterThanOrEqual(count, 0, "Disassembly failed for \(comment)") + #expect(count >= 0, "Disassembly failed for \(comment)") - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] let mnemonic = String(cString: withUnsafeBytes(of: insn.mnemonic) { $0.bindMemory(to: CChar.self).baseAddress! }) print("\(comment): \(mnemonic)") @@ -194,17 +194,17 @@ final class ArchitectureTests: XCTestCase { var insns: UnsafeMutablePointer? let openResult = cs_open(platform.arch, platform.mode, &handle) - XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(platform.comment)") + #expect(openResult == CS_ERR_OK, "Failed to open \(platform.comment)") let count = platform.code.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertGreaterThan(count, 0, "No instructions disassembled for \(platform.comment)") + #expect(count > 0, "No instructions disassembled for \(platform.comment)") - if count > 0 && insns != nil { + if count > 0, insns != nil { print("\n\(platform.comment):") - for i in 0.. 0) + #expect(insn.mnemonic.0 != 0) + #expect(insn.address == 0x1000 + UInt64(calculateOffset(for: i, from: insns!))) } cs_free(insns, count) @@ -226,9 +226,9 @@ final class ArchitectureTests: XCTestCase { // Helper to calculate instruction offset for address validation private func calculateOffset(for index: Int, from instructions: UnsafeMutablePointer) -> Int { var offset = 0 - for i in 0.. 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] - XCTAssertNotNil(insn.detail) + #expect(insn.detail != nil) if insn.detail != nil { let detail = insn.detail!.pointee let x86Detail = detail.x86 // Check basic detail properties - XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) - XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) - XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + #expect(detail.regs_read_count >= 0) + #expect(detail.regs_write_count >= 0) + #expect(detail.groups_count >= 0) // Check X86-specific details - XCTAssertGreaterThan(x86Detail.op_count, 0) - XCTAssertLessThanOrEqual(x86Detail.op_count, 8) + #expect(x86Detail.op_count > 0) + #expect(x86Detail.op_count <= 8) print("X86 Detail:") print(" Instruction ID: \(insn.id)") @@ -63,14 +64,14 @@ final class DetailTests: XCTestCase { _ = cs_close(&handle) } - func testARMDetail() { + @Test func aRMDetail() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(optResult, CS_ERR_OK) + #expect(optResult == CS_ERR_OK) // str lr, [sp, #-4]! let code: [UInt8] = [0x04, 0xE0, 0x2D, 0xE5] @@ -80,25 +81,25 @@ final class DetailTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertEqual(count, 1) - XCTAssertNotNil(insns) + #expect(count == 1) + #expect(insns != nil) - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] - XCTAssertNotNil(insn.detail) + #expect(insn.detail != nil) if insn.detail != nil { let detail = insn.detail!.pointee let armDetail = detail.arm // Check basic detail properties - XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) - XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) - XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + #expect(detail.regs_read_count >= 0) + #expect(detail.regs_write_count >= 0) + #expect(detail.groups_count >= 0) // Check ARM-specific details - XCTAssertGreaterThan(armDetail.op_count, 0) - XCTAssertLessThanOrEqual(armDetail.op_count, 36) + #expect(armDetail.op_count > 0) + #expect(armDetail.op_count <= 36) print("ARM Detail:") print(" Instruction ID: \(insn.id)") @@ -117,14 +118,14 @@ final class DetailTests: XCTestCase { _ = cs_close(&handle) } - func testAArch64Detail() { + @Test func aArch64Detail() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_AARCH64, CS_MODE_ARM, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(optResult, CS_ERR_OK) + #expect(optResult == CS_ERR_OK) // add x1, x1, x2 let code: [UInt8] = [0x21, 0x00, 0x02, 0x8B] @@ -134,25 +135,25 @@ final class DetailTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertEqual(count, 1) - XCTAssertNotNil(insns) + #expect(count == 1) + #expect(insns != nil) - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] - XCTAssertNotNil(insn.detail) + #expect(insn.detail != nil) if insn.detail != nil { let detail = insn.detail!.pointee let aarch64Detail = detail.aarch64 // Check basic detail properties - XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) - XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) - XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + #expect(detail.regs_read_count >= 0) + #expect(detail.regs_write_count >= 0) + #expect(detail.groups_count >= 0) // Check AArch64-specific details - XCTAssertGreaterThan(aarch64Detail.op_count, 0) - XCTAssertLessThanOrEqual(aarch64Detail.op_count, 8) + #expect(aarch64Detail.op_count > 0) + #expect(aarch64Detail.op_count <= 8) print("AArch64 Detail:") print(" Instruction ID: \(insn.id)") @@ -171,14 +172,14 @@ final class DetailTests: XCTestCase { _ = cs_close(&handle) } - func testMIPSDetail() { + @Test func mIPSDetail() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_MIPS, cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(optResult, CS_ERR_OK) + #expect(optResult == CS_ERR_OK) // jal 0x97000c let code: [UInt8] = [0x0C, 0x10, 0x00, 0x97] @@ -188,25 +189,25 @@ final class DetailTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertEqual(count, 1) - XCTAssertNotNil(insns) + #expect(count == 1) + #expect(insns != nil) - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] - XCTAssertNotNil(insn.detail) + #expect(insn.detail != nil) if insn.detail != nil { let detail = insn.detail!.pointee let mipsDetail = detail.mips // Check basic detail properties - XCTAssertGreaterThanOrEqual(detail.regs_read_count, 0) - XCTAssertGreaterThanOrEqual(detail.regs_write_count, 0) - XCTAssertGreaterThanOrEqual(detail.groups_count, 0) + #expect(detail.regs_read_count >= 0) + #expect(detail.regs_write_count >= 0) + #expect(detail.groups_count >= 0) // Check MIPS-specific details - XCTAssertGreaterThan(mipsDetail.op_count, 0) - XCTAssertLessThanOrEqual(mipsDetail.op_count, 4) + #expect(mipsDetail.op_count > 0) + #expect(mipsDetail.op_count <= 4) print("MIPS Detail:") print(" Instruction ID: \(insn.id)") @@ -222,14 +223,14 @@ final class DetailTests: XCTestCase { _ = cs_close(&handle) } - func testInstructionGroups() { + @Test func instructionGroups() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_64, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(optResult, CS_ERR_OK) + #expect(optResult == CS_ERR_OK) // ret instruction let code: [UInt8] = [0xC3] @@ -239,12 +240,12 @@ final class DetailTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 1, &insns) } - XCTAssertEqual(count, 1) - XCTAssertNotNil(insns) + #expect(count == 1) + #expect(insns != nil) - if count > 0 && insns != nil { + if count > 0, insns != nil { let insn = insns![0] - XCTAssertNotNil(insn.detail) + #expect(insn.detail != nil) if insn.detail != nil { let detail = insn.detail!.pointee diff --git a/bindings/swift/CcapstoneTests/DisassemblyTests.swift b/bindings/swift/CcapstoneTests/DisassemblyTests.swift index 918b11c229..af361f49da 100644 --- a/bindings/swift/CcapstoneTests/DisassemblyTests.swift +++ b/bindings/swift/CcapstoneTests/DisassemblyTests.swift @@ -1,7 +1,8 @@ -import XCTest +import Foundation +import Testing @testable import Ccapstone -final class DisassemblyTests: XCTestCase { +@Suite struct DisassemblyTests { // Test data from existing tests private let x86Code32: [UInt8] = [0x8d, 0x4c, 0x32, 0x08, 0x01, 0xd8, 0x81, 0xc6, 0x34, 0x12, 0x00, 0x00] @@ -12,7 +13,7 @@ final class DisassemblyTests: XCTestCase { private let mipsCode: [UInt8] = [0x0C, 0x10, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0c, 0x8f, 0xa2, 0x00, 0x00] private let ppcCode: [UInt8] = [0x80, 0x20, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x10, 0x43, 0x23, 0x0e, 0xd0, 0x44, 0x00, 0x80] - func testX86_32() { + @Test func x86_32() { performDisassemblyTest( arch: CS_ARCH_X86, mode: CS_MODE_32, @@ -21,7 +22,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testX86_64() { + @Test func x86_64() { performDisassemblyTest( arch: CS_ARCH_X86, mode: CS_MODE_64, @@ -30,7 +31,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testARM() { + @Test func aRM() { performDisassemblyTest( arch: CS_ARCH_ARM, mode: CS_MODE_ARM, @@ -39,7 +40,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testThumb() { + @Test func thumb() { performDisassemblyTest( arch: CS_ARCH_ARM, mode: CS_MODE_THUMB, @@ -48,7 +49,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testAArch64() { + @Test func aArch64() { performDisassemblyTest( arch: CS_ARCH_AARCH64, mode: CS_MODE_ARM, @@ -57,7 +58,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testMIPS() { + @Test func mIPS() { performDisassemblyTest( arch: CS_ARCH_MIPS, mode: cs_mode(CS_MODE_MIPS32.rawValue | CS_MODE_BIG_ENDIAN.rawValue), @@ -66,7 +67,7 @@ final class DisassemblyTests: XCTestCase { ) } - func testPPC() { + @Test func pPC() { performDisassemblyTest( arch: CS_ARCH_PPC, mode: CS_MODE_BIG_ENDIAN, @@ -75,28 +76,28 @@ final class DisassemblyTests: XCTestCase { ) } - func testDisasmWithDetail() { + @Test func disasmWithDetail() { var handle: csh = 0 var insns: UnsafeMutablePointer? let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let optResult = cs_option(handle, CS_OPT_DETAIL, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(optResult, CS_ERR_OK) + #expect(optResult == CS_ERR_OK) let count = x86Code32.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertGreaterThan(count, 0) - XCTAssertNotNil(insns) + #expect(count > 0) + #expect(insns != nil) if count > 0 && insns != nil { for i in 0.. 0) + #expect(insn.mnemonic.0 != 0) // Check first character is not null // Check first character is not null if insn.detail != nil { let detail = insn.detail!.pointee @@ -111,14 +112,14 @@ final class DisassemblyTests: XCTestCase { _ = cs_close(&handle) } - func testIteratorAPI() { + @Test func iteratorAPI() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let insn = cs_malloc(handle) - XCTAssertNotNil(insn) + #expect(insn != nil) let code = x86Code32 var size = code.count @@ -129,25 +130,25 @@ final class DisassemblyTests: XCTestCase { var codePtr = buffer.baseAddress while cs_disasm_iter(handle, &codePtr, &size, &address, insn) { let instruction = insn!.pointee - XCTAssertGreaterThan(instruction.size, 0) - XCTAssertNotEqual(instruction.mnemonic.0, 0) + #expect(instruction.size > 0) + #expect(instruction.mnemonic.0 != 0) count += 1 } return count } - XCTAssertGreaterThan(result, 0) + #expect(result > 0) cs_free(insn, 1) _ = cs_close(&handle) } - func testInvalidCode() { + @Test func invalidCode() { var handle: csh = 0 var insns: UnsafeMutablePointer? let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) // Test with invalid/empty code let invalidCode: [UInt8] = [] @@ -155,19 +156,19 @@ final class DisassemblyTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertEqual(count, 0) + #expect(count == 0) _ = cs_close(&handle) } - func testSkipData() { + @Test func skipData() { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) - XCTAssertEqual(openResult, CS_ERR_OK) + #expect(openResult == CS_ERR_OK) let skipDataResult = cs_option(handle, CS_OPT_SKIPDATA, size_t(CS_OPT_ON.rawValue)) - XCTAssertEqual(skipDataResult, CS_ERR_OK) + #expect(skipDataResult == CS_ERR_OK) // Test with some invalid bytes mixed in let mixedCode: [UInt8] = [0xFF, 0xFF, 0xFF, 0xFF] + x86Code32 @@ -177,7 +178,7 @@ final class DisassemblyTests: XCTestCase { cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertGreaterThan(count, 0) + #expect(count > 0) if count > 0 && insns != nil { cs_free(insns, count) @@ -192,14 +193,14 @@ final class DisassemblyTests: XCTestCase { var insns: UnsafeMutablePointer? let openResult = cs_open(arch, mode, &handle) - XCTAssertEqual(openResult, CS_ERR_OK, "Failed to open \(comment)") + #expect(openResult == CS_ERR_OK, "Failed to open \(comment)") let count = code.withUnsafeBufferPointer { buffer in cs_disasm(handle, buffer.baseAddress, buffer.count, 0x1000, 0, &insns) } - XCTAssertGreaterThan(count, 0, "No instructions disassembled for \(comment)") - XCTAssertNotNil(insns, "Instructions pointer is nil for \(comment)") + #expect(count > 0, "No instructions disassembled for \(comment)") + #expect(insns != nil, "Instructions pointer is nil for \(comment)") if count > 0 && insns != nil { print("\n\(comment):") @@ -211,8 +212,8 @@ final class DisassemblyTests: XCTestCase { print(" \(address)\t\(mnemonic)\t\(opStr)") // Basic validation - XCTAssertGreaterThan(insn.size, 0) - XCTAssertNotEqual(insn.mnemonic.0, 0) // Check first character is not null + #expect(insn.size > 0) + #expect(insn.mnemonic.0 != 0) // Check first character is not null // Check first character is not null } cs_free(insns, count) @@ -220,4 +221,4 @@ final class DisassemblyTests: XCTestCase { _ = cs_close(&handle) } -} \ No newline at end of file +} diff --git a/bindings/swift/CcapstoneTests/MinimalTests.swift b/bindings/swift/CcapstoneTests/MinimalTests.swift index 0a5c5411af..9ef7961d73 100644 --- a/bindings/swift/CcapstoneTests/MinimalTests.swift +++ b/bindings/swift/CcapstoneTests/MinimalTests.swift @@ -1,26 +1,26 @@ import Foundation -import XCTest +import Testing @testable import Ccapstone /// Minimal tests that only use core Capstone functions /// These tests avoid architecture-specific functionality that requires complete linking -final class MinimalTests: XCTestCase { +@Suite struct MinimalTests { - func testVersionAPI() { + @Test func versionAPI() { var major: Int32 = 0 var minor: Int32 = 0 let version = cs_version(&major, &minor) - XCTAssertGreaterThan(major, 0, "Major version should be positive") - XCTAssertGreaterThanOrEqual(minor, 0, "Minor version should be non-negative") - XCTAssertGreaterThan(version, 0, "Combined version should be positive") - XCTAssertEqual(version, UInt32((major << 8) | minor), "Version should match expected format") + #expect(major > 0, "Major version should be positive") + #expect(minor >= 0, "Minor version should be non-negative") + #expect(version > 0, "Combined version should be positive") + #expect(version == UInt32((major << 8) | minor), "Version should match expected format") print("✓ Capstone version: \(major).\(minor) (0x\(String(format: "%04x", version)))") } - func testErrorStrings() { + @Test func errorStrings() { let testErrors: [(cs_err, String)] = [ (CS_ERR_OK, "OK"), (CS_ERR_MEM, "Memory"), @@ -34,46 +34,46 @@ final class MinimalTests: XCTestCase { print("\n✓ Testing error strings:") for (errorCode, description) in testErrors { let message = cs_strerror(errorCode) - XCTAssertNotNil(message, "Error message should not be nil for \(description)") + #expect(message != nil, "Error message should not be nil for \(description)") if let message = message { let errorString = String(cString: message) - XCTAssertFalse(errorString.isEmpty, "Error message should not be empty for \(description)") + #expect(!errorString.isEmpty, "Error message should not be empty for \(description)") print(" \(errorCode.rawValue) (\(description)): \(errorString)") } } } - func testBasicEnumValues() { + @Test func basicEnumValues() { // Test that enum values are accessible and have expected values - XCTAssertEqual(CS_ERR_OK.rawValue, 0, "CS_ERR_OK should be 0") - XCTAssertNotEqual(CS_ERR_ARCH.rawValue, 0, "CS_ERR_ARCH should not be 0") + #expect(CS_ERR_OK.rawValue == 0, "CS_ERR_OK should be 0") + #expect(CS_ERR_ARCH.rawValue != 0, "CS_ERR_ARCH should not be 0") // Test architecture enum values - XCTAssertEqual(CS_ARCH_ARM.rawValue, 0, "CS_ARCH_ARM should be 0") - XCTAssertEqual(CS_ARCH_AARCH64.rawValue, 1, "CS_ARCH_AARCH64 should be 1") - XCTAssertEqual(CS_ARCH_MIPS.rawValue, 3, "CS_ARCH_MIPS should be 3") - XCTAssertEqual(CS_ARCH_X86.rawValue, 4, "CS_ARCH_X86 should be 4") + #expect(CS_ARCH_ARM.rawValue == 0, "CS_ARCH_ARM should be 0") + #expect(CS_ARCH_AARCH64.rawValue == 1, "CS_ARCH_AARCH64 should be 1") + #expect(CS_ARCH_MIPS.rawValue == 3, "CS_ARCH_MIPS should be 3") + #expect(CS_ARCH_X86.rawValue == 4, "CS_ARCH_X86 should be 4") // Test mode enum values - XCTAssertEqual(CS_MODE_LITTLE_ENDIAN.rawValue, 0, "CS_MODE_LITTLE_ENDIAN should be 0") - XCTAssertEqual(CS_MODE_ARM.rawValue, 0, "CS_MODE_ARM should be 0") - XCTAssertEqual(CS_MODE_16.rawValue, 1 << 1, "CS_MODE_16 should be 2") - XCTAssertEqual(CS_MODE_32.rawValue, 1 << 2, "CS_MODE_32 should be 4") - XCTAssertEqual(CS_MODE_64.rawValue, 1 << 3, "CS_MODE_64 should be 8") + #expect(CS_MODE_LITTLE_ENDIAN.rawValue == 0, "CS_MODE_LITTLE_ENDIAN should be 0") + #expect(CS_MODE_ARM.rawValue == 0, "CS_MODE_ARM should be 0") + #expect(CS_MODE_16.rawValue == 1 << 1, "CS_MODE_16 should be 2") + #expect(CS_MODE_32.rawValue == 1 << 2, "CS_MODE_32 should be 4") + #expect(CS_MODE_64.rawValue == 1 << 3, "CS_MODE_64 should be 8") // Test option enum values - XCTAssertEqual(CS_OPT_INVALID.rawValue, 0, "CS_OPT_INVALID should be 0") - XCTAssertNotEqual(CS_OPT_DETAIL.rawValue, 0, "CS_OPT_DETAIL should not be 0") + #expect(CS_OPT_INVALID.rawValue == 0, "CS_OPT_INVALID should be 0") + #expect(CS_OPT_DETAIL.rawValue != 0, "CS_OPT_DETAIL should not be 0") // Test option values - XCTAssertEqual(CS_OPT_OFF.rawValue, 0, "CS_OPT_OFF should be 0") - XCTAssertEqual(CS_OPT_ON.rawValue, 1 << 0, "CS_OPT_ON should be 1") + #expect(CS_OPT_OFF.rawValue == 0, "CS_OPT_OFF should be 0") + #expect(CS_OPT_ON.rawValue == 1 << 0, "CS_OPT_ON should be 1") print("✓ All enum values are correctly defined") } - func testAPIFunctionAvailability() { + @Test func aPIFunctionAvailability() { // Test that all basic C functions are available (can be referenced) // This doesn't call them, just verifies they exist and can be linked @@ -95,52 +95,52 @@ final class MinimalTests: XCTestCase { print(" - \(name)") } - XCTAssertEqual(functions.count, 10, "All 10 basic functions should be available") + #expect(functions.count == 10, "All 10 basic functions should be available") } - func testInvalidParameters() { + @Test func invalidParameters() { // Test behavior with obviously invalid parameters // These should not crash but return error codes // Test cs_strerror with invalid error code let invalidErrorMsg = cs_strerror(cs_err(rawValue: 999)) - XCTAssertNotNil(invalidErrorMsg, "cs_strerror should handle invalid error codes") + #expect(invalidErrorMsg != nil, "cs_strerror should handle invalid error codes") // Test cs_errno with invalid handle let errno = cs_errno(0) // 0 is invalid handle - XCTAssertNotEqual(errno, CS_ERR_OK, "cs_errno should return error for invalid handle") + #expect(errno != CS_ERR_OK, "cs_errno should return error for invalid handle") print("✓ Invalid parameter handling works correctly") } - func testConstantValues() { + @Test func constantValues() { // Test important constant values - XCTAssertEqual(CS_MNEMONIC_SIZE, 32, "CS_MNEMONIC_SIZE should be 32") + #expect(CS_MNEMONIC_SIZE == 32, "CS_MNEMONIC_SIZE should be 32") print("✓ Constant values are correct") print(" CS_MNEMONIC_SIZE: \(CS_MNEMONIC_SIZE)") } - func testStructureSizes() { + @Test func structureSizes() { // Test that key structures have reasonable sizes let insnSize = MemoryLayout.size let detailSize = MemoryLayout.size - XCTAssertGreaterThan(insnSize, 0, "cs_insn structure should have positive size") - XCTAssertGreaterThan(detailSize, 0, "cs_detail structure should have positive size") + #expect(insnSize > 0, "cs_insn structure should have positive size") + #expect(detailSize > 0, "cs_detail structure should have positive size") print("✓ Structure sizes:") print(" cs_insn: \(insnSize) bytes") print(" cs_detail: \(detailSize) bytes") // cs_insn should be reasonably sized (has mnemonic, op_str, etc.) - XCTAssertGreaterThan(insnSize, 64, "cs_insn should be at least 64 bytes") + #expect(insnSize > 64, "cs_insn should be at least 64 bytes") // cs_detail should be large (has architecture-specific unions) - XCTAssertGreaterThan(detailSize, 100, "cs_detail should be at least 100 bytes") + #expect(detailSize > 100, "cs_detail should be at least 100 bytes") } - func testVersionConsistency() { + @Test func versionConsistency() { // Test version consistency across different calls var major1: Int32 = 0, minor1: Int32 = 0 var major2: Int32 = 0, minor2: Int32 = 0 @@ -148,13 +148,13 @@ final class MinimalTests: XCTestCase { let version1 = cs_version(&major1, &minor1) let version2 = cs_version(&major2, &minor2) - XCTAssertEqual(version1, version2, "Version should be consistent") - XCTAssertEqual(major1, major2, "Major version should be consistent") - XCTAssertEqual(minor1, minor2, "Minor version should be consistent") + #expect(version1 == version2, "Version should be consistent") + #expect(major1 == major2, "Major version should be consistent") + #expect(minor1 == minor2, "Minor version should be consistent") // Test CS_MAKE_VERSION macro equivalent let calculatedVersion = UInt32((major1 << 8) | minor1) - XCTAssertEqual(version1, calculatedVersion, "Version calculation should match macro") + #expect(version1 == calculatedVersion, "Version calculation should match macro") print("✓ Version consistency verified") } diff --git a/bindings/swift/CcapstoneTests/SimpleTests.swift b/bindings/swift/CcapstoneTests/SimpleTests.swift index 2666380dd9..71d41c03ed 100644 --- a/bindings/swift/CcapstoneTests/SimpleTests.swift +++ b/bindings/swift/CcapstoneTests/SimpleTests.swift @@ -1,23 +1,24 @@ -import XCTest +import Foundation +import Testing @testable import Ccapstone -final class SimpleTests: XCTestCase { +@Suite struct SimpleTests { - func testVersionOnly() { + @Test func versionOnly() { var major: Int32 = 0 var minor: Int32 = 0 let version = cs_version(&major, &minor) - XCTAssertGreaterThan(major, 0) - XCTAssertGreaterThanOrEqual(minor, 0) - XCTAssertGreaterThan(version, 0) - XCTAssertEqual(version, UInt32((major << 8) | minor)) + #expect(major > 0) + #expect(minor >= 0) + #expect(version > 0) + #expect(version == UInt32((major << 8) | minor)) print("Capstone version: \(major).\(minor) (0x\(String(format: "%04x", version)))") } - func testBasicAPIAvailability() { + @Test func basicAPIAvailability() { // Test that all basic functions are available // This doesn't actually call them, just verifies they can be referenced let _ = cs_open @@ -38,10 +39,10 @@ final class SimpleTests: XCTestCase { let _ = CS_OPT_DETAIL let _ = CS_OPT_ON - XCTAssertTrue(true, "All basic API functions are available") + #expect(true, "All basic API functions are available") } - func testErrorMessages() { + @Test func errorMessages() { let errorCodes: [cs_err] = [ CS_ERR_OK, CS_ERR_MEM, @@ -55,41 +56,41 @@ final class SimpleTests: XCTestCase { print("Testing error messages:") for errorCode in errorCodes { let message = cs_strerror(errorCode) - XCTAssertNotNil(message, "Error message should not be nil for \(errorCode)") + #expect(message != nil, "Error message should not be nil for \(errorCode)") if let message = message { let errorString = String(cString: message) - XCTAssertFalse(errorString.isEmpty, "Error message should not be empty for \(errorCode)") + #expect(!errorString.isEmpty, "Error message should not be empty for \(errorCode)") print(" \(errorCode.rawValue): \(errorString)") } } } - func testSimpleOpenClose() { + @Test func simpleOpenClose() { var handle: csh = 0 print("Testing cs_open...") let result = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) if result == CS_ERR_OK { print("✓ cs_open succeeded, handle: \(handle)") - XCTAssertNotEqual(handle, 0, "Handle should not be zero") + #expect(handle != 0, "Handle should not be zero") print("Testing cs_close...") let closeResult = cs_close(&handle) if closeResult == CS_ERR_OK { print("✓ cs_close succeeded") - XCTAssertEqual(handle, 0, "Handle should be zero after close") + #expect(handle == 0, "Handle should be zero after close") } else { let errorMsg = cs_strerror(closeResult) let errorString = errorMsg != nil ? String(cString: errorMsg!) : "Unknown error" print("✗ cs_close failed: \(errorString)") - XCTFail("cs_close failed with error: \(errorString)") + Issue.record("cs_close failed with error: \(errorString)") } } else { let errorMsg = cs_strerror(result) let errorString = errorMsg != nil ? String(cString: errorMsg!) : "Unknown error" print("✗ cs_open failed: \(errorString)") - XCTFail("cs_open failed with error: \(errorString)") + Issue.record("cs_open failed with error: \(errorString)") } } -} \ No newline at end of file +} diff --git a/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift b/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift index 1ed5f7934e..9e8dd02f29 100644 --- a/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift +++ b/bindings/swift/CcapstoneTests/SwiftIntegrationTests.swift @@ -10,7 +10,7 @@ struct SwiftIntegrationTests { private static let x86Code: [UInt8] = [0x8D, 0x4C, 0x32, 0x08, 0x01, 0xD8, 0x81, 0xC6, 0x34, 0x12, 0x00, 0x00] @Test("Swift optionals and error handling") - func testSwiftOptionals() async throws { + func swiftOptionals() async throws { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) @@ -44,7 +44,7 @@ struct SwiftIntegrationTests { } @Test("Swift memory management patterns") - func testSwiftMemoryManagement() async throws { + func swiftMemoryManagement() async throws { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) @@ -100,7 +100,7 @@ struct SwiftIntegrationTests { #expect(deferCount == bufferCount, "Both patterns should yield same results") // Test iterator pattern with automatic cleanup - func testIteratorPattern() -> Int { + func iteratorPattern() -> Int { guard let insn = cs_malloc(handle) else { return 0 } @@ -128,12 +128,12 @@ struct SwiftIntegrationTests { return instructionCount } - let iteratorCount = testIteratorPattern() + let iteratorCount = iteratorPattern() print(" Iterator pattern with automatic cleanup: \(iteratorCount) instructions") } @Test("Swift string handling and C interop") - func testSwiftStringHandling() async throws { + func swiftStringHandling() async throws { print("✓ Swift string handling and C interop:") // Test converting C strings to Swift strings @@ -171,7 +171,7 @@ struct SwiftIntegrationTests { } @Test("Swift array and collection integration") - func testSwiftCollectionIntegration() async throws { + func swiftCollectionIntegration() async throws { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) @@ -243,7 +243,7 @@ struct SwiftIntegrationTests { } @Test("Swift error handling patterns") - func testSwiftErrorHandling() async throws { + func swiftErrorHandling() async throws { print("✓ Swift error handling patterns:") // Define a Swift wrapper that throws @@ -330,7 +330,7 @@ struct SwiftIntegrationTests { } @Test("Swift value types and reference types") - func testSwiftValueAndReferenceTypes() async throws { + func swiftValueAndReferenceTypes() async throws { var handle: csh = 0 let openResult = cs_open(CS_ARCH_X86, CS_MODE_32, &handle) @@ -416,7 +416,7 @@ struct SwiftIntegrationTests { } @Test("Swift async/await compatibility") - func testAsyncAwaitCompatibility() async throws { + func asyncAwaitCompatibility() async throws { print("✓ Swift async/await compatibility:") // Test that Capstone operations can be used in async contexts @@ -466,7 +466,7 @@ struct SwiftIntegrationTests { } @Test("Swift generic and protocol integration") - func testGenericAndProtocolIntegration() async throws { + func genericAndProtocolIntegration() async throws { print("✓ Swift generic and protocol integration:") // Define protocols for Capstone operations @@ -530,11 +530,11 @@ struct SwiftIntegrationTests { print(" Set-derived array disassembly: \(setResult) instructions") // Test generic function - func testGenericDisassembly(_ provider: DisassemblyProvider, code: T) -> Int where T.Element == UInt8 { + func genericDisassembly(_ provider: DisassemblyProvider, code: T) -> Int where T.Element == UInt8 { return provider.disassemble(code) } - let genericResult = testGenericDisassembly(disassembler, code: Self.x86Code) + let genericResult = genericDisassembly(disassembler, code: Self.x86Code) print(" Generic function result: \(genericResult) instructions") #expect(arrayResult == genericResult, "Generic and direct calls should yield same results") From 1e0c8e358c0762967ab80f02f43ae2d95141c17c Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Sun, 21 Sep 2025 23:30:05 +0800 Subject: [PATCH 10/12] Add macOS testing to CI workflow # Conflicts: # .github/workflows/CITest.yml --- .github/workflows/CITest.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.github/workflows/CITest.yml b/.github/workflows/CITest.yml index dd3f5b547c..a28192af99 100644 --- a/.github/workflows/CITest.yml +++ b/.github/workflows/CITest.yml @@ -226,3 +226,31 @@ jobs: cmake --preset=${{ matrix.config.platform }}-x64${{ matrix.config.diet_build == true && '-diet' || '' }} cmake --build --preset build-${{ matrix.config.platform }}${{ matrix.config.diet_build == true && '-diet' || '' }}-release cmake --build --preset install-${{ matrix.config.platform }}${{ matrix.config.diet_build == true && '-diet' || '' }}-release + + cmake --preset=${{ matrix.config.platform }}-x64 + cmake --build --preset build-${{ matrix.config.platform }}-release + cmake --build --preset install-${{ matrix.config.platform }}-release + macOS: + name: Execute tests on macOS + strategy: + fail-fast: false + matrix: + os: [macos-15] + xcode-version: ["16.4"] + runs-on: ${{ matrix.os }} + env: + GH_TOKEN: ${{ github.token }} + steps: + - uses: actions/checkout@v4 + - name: Setup Xcode + uses: ./.github/actions/setup-xcode + with: + xcode-version: ${{ matrix.xcode-version }} + - name: Build and run tests in debug mode + run: | + swift test \ + -c debug + - name: Build and run tests in release mode + run: | + swift test \ + -c release From ce4a1488dfc1715fbf86bf6fbda6a5eacfaa1989 Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Mon, 22 Sep 2025 00:03:02 +0800 Subject: [PATCH 11/12] Add action dependency --- .github/actions/setup-xcode/action.yml | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/actions/setup-xcode/action.yml diff --git a/.github/actions/setup-xcode/action.yml b/.github/actions/setup-xcode/action.yml new file mode 100644 index 0000000000..7462743166 --- /dev/null +++ b/.github/actions/setup-xcode/action.yml @@ -0,0 +1,49 @@ +name: 'Setup Xcode Conditionally' +description: 'Check current Xcode version and setup if different from required version (Avoid unessary sudo/password input for self hosted runner)' + +inputs: + xcode-version: + description: 'Required Xcode version' + required: true + +outputs: + current-version: + description: 'Current Xcode version' + value: ${{ steps.current-xcode.outputs.version }} + setup-skipped: + description: 'Whether Xcode setup was skipped' + value: ${{ steps.xcode-check.outputs.skip-setup }} + +runs: + using: 'composite' + steps: + - name: Get current Xcode version + id: current-xcode + shell: bash + run: | + CURRENT_VERSION=$(xcode-select -p | grep -o '[0-9]\+\.[0-9]\+' || echo "none") + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + echo "Current Xcode version: $CURRENT_VERSION" + + - name: Check if Xcode version matches + id: xcode-check + shell: bash + run: | + CURRENT="${{ steps.current-xcode.outputs.version }}" + REQUIRED="${{ inputs.xcode-version }}" + if [ "$CURRENT" = "$REQUIRED" ]; then + echo "skip-setup=true" >> $GITHUB_OUTPUT + echo "✅ Xcode version matches: $CURRENT = $REQUIRED, skipping setup" + else + echo "skip-setup=false" >> $GITHUB_OUTPUT + echo "❌ Xcode version mismatch: $CURRENT ≠ $REQUIRED, setup required" + fi + + - name: Setup Xcode + if: steps.xcode-check.outputs.skip-setup == 'false' + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: ${{ inputs.xcode-version }} + - name: Swift version + shell: bash + run: swift --version \ No newline at end of file From 1841bed0aaea1e7d92f1c2f605108475ad8eddce Mon Sep 17 00:00:00 2001 From: Mx-Iris Date: Sat, 21 Mar 2026 13:25:46 +0800 Subject: [PATCH 12/12] Add SPM package traits for per-architecture conditional compilation Replace unconditional CAPSTONE_HAS_* defines with trait-conditional ones, allowing consumers to only compile the architectures they need via .package(url: ..., traits: ["ARM64", "X86"]). No default traits enabled. --- .gitignore | 2 ++ Package.swift | 58 +++++++++++++++++++++++++++------------------------ 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index cad0502e82..d149a3d11f 100644 --- a/.gitignore +++ b/.gitignore @@ -151,3 +151,5 @@ suite/auto-sync/src/autosync.egg-info # clangd cache /.cache +.build +.swiftpm diff --git a/Package.swift b/Package.swift index fe40b0e317..3cc74fac6c 100644 --- a/Package.swift +++ b/Package.swift @@ -1,8 +1,35 @@ -// swift-tools-version: 6.1 +// swift-tools-version: 6.2 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription +let architectures: [(trait: String, define: String)] = [ + ("ARM", "CAPSTONE_HAS_ARM"), + ("ARM64", "CAPSTONE_HAS_ARM64"), + ("AARCH64", "CAPSTONE_HAS_AARCH64"), + ("MIPS", "CAPSTONE_HAS_MIPS"), + ("X86", "CAPSTONE_HAS_X86"), + ("POWERPC", "CAPSTONE_HAS_POWERPC"), + ("SPARC", "CAPSTONE_HAS_SPARC"), + ("SYSTEMZ", "CAPSTONE_HAS_SYSTEMZ"), + ("XCORE", "CAPSTONE_HAS_XCORE"), + ("M68K", "CAPSTONE_HAS_M68K"), + ("TMS320C64X", "CAPSTONE_HAS_TMS320C64X"), + ("M680X", "CAPSTONE_HAS_M680X"), + ("EVM", "CAPSTONE_HAS_EVM"), + ("MOS65XX", "CAPSTONE_HAS_MOS65XX"), + ("WASM", "CAPSTONE_HAS_WASM"), + ("BPF", "CAPSTONE_HAS_BPF"), + ("RISCV", "CAPSTONE_HAS_RISCV"), + ("SH", "CAPSTONE_HAS_SH"), + ("TRICORE", "CAPSTONE_HAS_TRICORE"), + ("ALPHA", "CAPSTONE_HAS_ALPHA"), + ("HPPA", "CAPSTONE_HAS_HPPA"), + ("LOONGARCH", "CAPSTONE_HAS_LOONGARCH"), + ("XTENSA", "CAPSTONE_HAS_XTENSA"), + ("ARC", "CAPSTONE_HAS_ARC"), +] + let package = Package( name: "capstone", products: [ @@ -11,6 +38,7 @@ let package = Package( targets: ["Ccapstone"] ), ], + traits: Set(architectures.map { Trait(name: $0.trait) }), targets: [ .target( name: "Ccapstone", @@ -18,36 +46,12 @@ let package = Package( cSettings: [ .headerSearchPath("../../../include"), .define("CAPSTONE_USE_SYS_DYN_MEM"), - .define("CAPSTONE_HAS_ARM"), - .define("CAPSTONE_HAS_ARM64"), - .define("CAPSTONE_HAS_AARCH64"), - .define("CAPSTONE_HAS_MIPS"), - .define("CAPSTONE_HAS_X86"), - .define("CAPSTONE_HAS_POWERPC"), - .define("CAPSTONE_HAS_SPARC"), - .define("CAPSTONE_HAS_SYSTEMZ"), - .define("CAPSTONE_HAS_XCORE"), - .define("CAPSTONE_HAS_M68K"), - .define("CAPSTONE_HAS_TMS320C64X"), - .define("CAPSTONE_HAS_M680X"), - .define("CAPSTONE_HAS_EVM"), - .define("CAPSTONE_HAS_MOS65XX"), - .define("CAPSTONE_HAS_WASM"), - .define("CAPSTONE_HAS_BPF"), - .define("CAPSTONE_HAS_RISCV"), - .define("CAPSTONE_HAS_SH"), - .define("CAPSTONE_HAS_TRICORE"), - .define("CAPSTONE_HAS_ALPHA"), - .define("CAPSTONE_HAS_HPPA"), - .define("CAPSTONE_HAS_LOONGARCH"), - .define("CAPSTONE_HAS_XTENSA"), - .define("CAPSTONE_HAS_ARC"), - ], + ] + architectures.map { .define($0.define, .when(traits: [$0.trait])) } ), .testTarget( name: "CcapstoneTests", dependencies: ["Ccapstone"], - path: "bindings/swift/CcapstoneTests", + path: "bindings/swift/CcapstoneTests" ), ] )