Skip to content

Commit 3d2d972

Browse files
authored
Add Unit Tests (#35)
Add unit tests for x86, ARM, and ARM64.
1 parent 36f005a commit 3d2d972

File tree

11 files changed

+804
-27
lines changed

11 files changed

+804
-27
lines changed

.editorconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[*.{cs,vb}]
2+
indent_style=space
3+
end_of_line=lf
4+
tab_width=4
5+
indent_size=4

.github/workflows/pr.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: PR Workflow
2+
on:
3+
pull_request:
4+
branches:
5+
- "*"
6+
jobs:
7+
linux:
8+
name: Linux Job
9+
defaults:
10+
run:
11+
shell: bash
12+
working-directory: .
13+
runs-on: ubuntu-22.04
14+
steps:
15+
- id: checkout
16+
name: Checkout Repository
17+
uses: actions/checkout@v2
18+
19+
- id: run-tests
20+
name: Run Tests
21+
working-directory: ./Tests.Gee.External.Capstone
22+
run: dotnet test -c Debug --runtime linux-x64
23+
24+
mac:
25+
name: MacOS Job
26+
defaults:
27+
run:
28+
shell: bash
29+
working-directory: .
30+
runs-on: macos-12
31+
steps:
32+
- id: checkout
33+
name: Checkout Repository
34+
uses: actions/checkout@v2
35+
36+
- id: run-tests
37+
name: Run Tests
38+
working-directory: ./Tests.Gee.External.Capstone
39+
run: dotnet test -c Debug --runtime mac-x64
40+
41+
windows:
42+
name: Windows Job
43+
defaults:
44+
run:
45+
shell: bash
46+
working-directory: .
47+
runs-on: windows-2022
48+
steps:
49+
- id: checkout
50+
name: Checkout Repository
51+
uses: actions/checkout@v2
52+
53+
- id: run-tests
54+
name: Run Tests
55+
working-directory: ./Tests.Gee.External.Capstone
56+
run: dotnet test -c Debug --runtime win-x64

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
x64/
2626
x86/
2727
!Gee.External.Capstone/X86/
28+
!Tests.Gee.External.Capstone/X86/
2829
bld/
2930
[Bb]in/
3031
[Oo]bj/

Capstone.NET.sln

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,31 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio 15
4-
VisualStudioVersion = 15.0.28306.52
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.32014.148
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gee.External.Capstone", "Gee.External.Capstone\Gee.External.Capstone.csproj", "{52ECA690-0077-4E38-9139-31C7CF3B6853}"
77
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.Gee.External.Capstone", "Tests.Gee.External.Capstone\Tests.Gee.External.Capstone.csproj", "{D920FCBD-4861-4E3F-AE75-C56E13DB10F1}"
9+
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D9F2E61D-5337-44E8-BA13-3A7AF2FB0F34}"
11+
ProjectSection(SolutionItems) = preProject
12+
.editorconfig = .editorconfig
13+
EndProjectSection
14+
EndProject
815
Global
916
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1017
Debug|Any CPU = Debug|Any CPU
11-
Debug|x64 = Debug|x64
12-
Debug|x86 = Debug|x86
1318
Release|Any CPU = Release|Any CPU
14-
Release|x64 = Release|x64
15-
Release|x86 = Release|x86
1619
EndGlobalSection
1720
GlobalSection(ProjectConfigurationPlatforms) = postSolution
1821
{52ECA690-0077-4E38-9139-31C7CF3B6853}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1922
{52ECA690-0077-4E38-9139-31C7CF3B6853}.Debug|Any CPU.Build.0 = Debug|Any CPU
2023
{52ECA690-0077-4E38-9139-31C7CF3B6853}.Release|Any CPU.ActiveCfg = Release|Any CPU
2124
{52ECA690-0077-4E38-9139-31C7CF3B6853}.Release|Any CPU.Build.0 = Release|Any CPU
25+
{D920FCBD-4861-4E3F-AE75-C56E13DB10F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26+
{D920FCBD-4861-4E3F-AE75-C56E13DB10F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
27+
{D920FCBD-4861-4E3F-AE75-C56E13DB10F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
28+
{D920FCBD-4861-4E3F-AE75-C56E13DB10F1}.Release|Any CPU.Build.0 = Release|Any CPU
2229
EndGlobalSection
2330
GlobalSection(SolutionProperties) = preSolution
2431
HideSolutionNode = FALSE

Capstone.NET.sln.DotSettings

Lines changed: 462 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFrameworks>netstandard2.0;netstandard2.1;net5.0;net6.0</TargetFrameworks>
4+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
25

3-
<PropertyGroup>
4-
<TargetFrameworks>netstandard2.0;netstandard2.1;net5.0;net6.0</TargetFrameworks>
5-
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
6+
<Version>2.2.0</Version>
7+
<Authors>Ahmed Garhy (@9ee1)</Authors>
8+
<Title>Capstone.NET</Title>
9+
<Description>Capstone.NET is a .NET Core and a .NET Framework binding for the Capstone disassembly framework. It is written in C#, supports Capstone 4, and has a friendly and simple type safe API that is ridiculously easy to learn and quick to pick up.</Description>
10+
<Copyright>Copyright (c) Ahmed Garhy</Copyright>
11+
<PackageLicenseExpression>MIT</PackageLicenseExpression>
12+
<PackageProjectUrl>https://github.com/9ee1/Capstone.NET</PackageProjectUrl>
13+
<RepositoryUrl>https://github.com/9ee1/Capstone.NET</RepositoryUrl>
14+
<PackageTags>capstone disassembler reverse-engineering security arm x86</PackageTags>
15+
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
16+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
17+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
18+
<NoWarn>1591</NoWarn>
19+
</PropertyGroup>
620

7-
<Version>2.2.0</Version>
8-
<Authors>Ahmed Garhy (@9ee1)</Authors>
9-
<Title>Capstone.NET</Title>
10-
<Description>Capstone.NET is a .NET Core and a .NET Framework binding for the Capstone disassembly framework. It is written in C#, supports Capstone 4, and has a friendly and simple type safe API that is ridiculously easy to learn and quick to pick up.</Description>
11-
<Copyright>Copyright (c) Ahmed Garhy</Copyright>
12-
<PackageLicenseExpression>MIT</PackageLicenseExpression>
13-
<PackageProjectUrl>https://github.com/9ee1/Capstone.NET</PackageProjectUrl>
14-
<RepositoryUrl>https://github.com/9ee1/Capstone.NET</RepositoryUrl>
15-
<PackageTags>capstone disassembler reverse-engineering security arm x86</PackageTags>
16-
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
17-
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
18-
<GenerateDocumentationFile>true</GenerateDocumentationFile>
19-
<NoWarn>1591</NoWarn>
20-
</PropertyGroup>
21-
22-
<ItemGroup>
23-
<Content CopyToOutputDirectory="PreserveNewest" Include="runtimes/*/native/*" Pack="true" PackagePath="runtimes" />
24-
</ItemGroup>
21+
<ItemGroup>
22+
<Content CopyToOutputDirectory="PreserveNewest" Include="runtimes/*/native/*" Pack="true" PackagePath="runtimes" />
23+
</ItemGroup>
2524
</Project>

Gee.External.Capstone/Instruction.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,5 +186,8 @@ private protected Instruction(InstructionBuilder<TDetail, TDisassembleMode, TGro
186186
this._mnemonic = builder.Mnemonic;
187187
this._operand = builder.Operand;
188188
}
189+
190+
/// <inheritdoc />
191+
public override string ToString() => !this.IsDietModeEnabled ? $"{this.Mnemonic} {this.Operand}" : this.GetType().Name;
189192
}
190193
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using FluentAssertions;
2+
using Gee.External.Capstone;
3+
using Gee.External.Capstone.Arm;
4+
using System.Diagnostics.CodeAnalysis;
5+
using Xunit;
6+
7+
namespace Tests.Gee.External.Capstone.Arm;
8+
9+
[ExcludeFromCodeCoverage]
10+
public sealed class CapstoneArmDisassemblerTests {
11+
[Fact]
12+
public void DisassembleArm_A() {
13+
var binaryCode = new byte[] { 0x04, 0xE0, 0x2D, 0xE5 };
14+
using var disassembler = CapstoneDisassembler.CreateArmDisassembler(ArmDisassembleMode.Arm);
15+
16+
disassembler.DisassembleSyntax = DisassembleSyntax.Intel;
17+
disassembler.EnableInstructionDetails = true;
18+
var disassembledCode = disassembler.Disassemble(binaryCode);
19+
disassembledCode.Length.Should().Be(1);
20+
21+
var instruction = disassembledCode[0];
22+
instruction.DisassembleArchitecture.Should().Be(DisassembleArchitecture.Arm);
23+
instruction.DisassembleMode.Should().Be(ArmDisassembleMode.Arm);
24+
$"{instruction.Mnemonic} {instruction.Operand}".Should().Be("str lr, [sp, #-4]!");
25+
}
26+
27+
[Fact]
28+
public void DisassembleArm_B() {
29+
var binaryCode = new byte[] { 0xE0, 0x83, 0x22, 0xE5 };
30+
using var disassembler = CapstoneDisassembler.CreateArmDisassembler(ArmDisassembleMode.Arm);
31+
32+
disassembler.DisassembleSyntax = DisassembleSyntax.Intel;
33+
disassembler.EnableInstructionDetails = true;
34+
var disassembledCode = disassembler.Disassemble(binaryCode);
35+
disassembledCode.Length.Should().Be(1);
36+
37+
var instruction = disassembledCode[0];
38+
instruction.DisassembleArchitecture.Should().Be(DisassembleArchitecture.Arm);
39+
instruction.DisassembleMode.Should().Be(ArmDisassembleMode.Arm);
40+
$"{instruction.Mnemonic} {instruction.Operand}".Should().Be("str r8, [r2, #-0x3e0]!");
41+
}
42+
43+
[Fact]
44+
public void DisassembleArmV8_A() {
45+
var binaryCode = new byte[] { 0xE0, 0x3B, 0xB2, 0xEE, 0x42, 0x00, 0x01, 0xE1, 0x51, 0xF0, 0x7F, 0xF5 };
46+
using var disassembler = CapstoneDisassembler.CreateArmDisassembler(ArmDisassembleMode.Arm | ArmDisassembleMode.V8);
47+
48+
disassembler.DisassembleSyntax = DisassembleSyntax.Intel;
49+
disassembler.EnableInstructionDetails = true;
50+
var disassembledCode = disassembler.Disassemble(binaryCode);
51+
disassembledCode.Length.Should().Be(3);
52+
53+
var instruction = disassembledCode[0];
54+
instruction.DisassembleArchitecture.Should().Be(DisassembleArchitecture.Arm);
55+
instruction.DisassembleMode.Should().Be(ArmDisassembleMode.Arm | ArmDisassembleMode.V8);
56+
$"{instruction.Mnemonic} {instruction.Operand}".Should().Be("vcvtt.f64.f16 d3, s1");
57+
58+
instruction = disassembledCode[1];
59+
instruction.DisassembleArchitecture.Should().Be(DisassembleArchitecture.Arm);
60+
instruction.DisassembleMode.Should().Be(ArmDisassembleMode.Arm | ArmDisassembleMode.V8);
61+
$"{instruction.Mnemonic} {instruction.Operand}".Should().Be("crc32b r0, r1, r2");
62+
63+
instruction = disassembledCode[2];
64+
instruction.DisassembleArchitecture.Should().Be(DisassembleArchitecture.Arm);
65+
instruction.DisassembleMode.Should().Be(ArmDisassembleMode.Arm | ArmDisassembleMode.V8);
66+
$"{instruction.Mnemonic} {instruction.Operand}".Should().Be("dmb oshld");
67+
}
68+
69+
[Fact]
70+
public void DisassembleThumbCortexM_A() {
71+
var binaryCode = new byte[] { 0xEF, 0xF3, 0x02, 0x80 };
72+
using var disassembler = CapstoneDisassembler.CreateArmDisassembler(ArmDisassembleMode.Thumb | ArmDisassembleMode.CortexM);
73+
74+
disassembler.DisassembleSyntax = DisassembleSyntax.Intel;
75+
disassembler.EnableInstructionDetails = true;
76+
var disassembledCode = disassembler.Disassemble(binaryCode);
77+
disassembledCode.Length.Should().Be(1);
78+
79+
var instruction = disassembledCode[0];
80+
instruction.DisassembleArchitecture.Should().Be(DisassembleArchitecture.Arm);
81+
instruction.DisassembleMode.Should().Be(ArmDisassembleMode.Thumb | ArmDisassembleMode.CortexM);
82+
$"{instruction.Mnemonic} {instruction.Operand}".Should().Be("mrs r0, eapsr");
83+
}
84+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using FluentAssertions;
2+
using Gee.External.Capstone;
3+
using Gee.External.Capstone.Arm64;
4+
using System.Diagnostics.CodeAnalysis;
5+
using Xunit;
6+
7+
namespace Tests.Gee.External.Capstone.Arm64;
8+
9+
[ExcludeFromCodeCoverage]
10+
public sealed class CapstoneArm64DisassemblerTests {
11+
[Fact]
12+
public void DisassembleArm_A() {
13+
var binaryCode = new byte[] { 0xE1, 0x0B, 0x40, 0xB9 };
14+
using var disassembler = CapstoneDisassembler.CreateArm64Disassembler(Arm64DisassembleMode.Arm);
15+
16+
disassembler.DisassembleSyntax = DisassembleSyntax.Intel;
17+
disassembler.EnableInstructionDetails = true;
18+
var disassembledCode = disassembler.Disassemble(binaryCode);
19+
disassembledCode.Length.Should().Be(1);
20+
21+
var instruction = disassembledCode[0];
22+
instruction.DisassembleArchitecture.Should().Be(DisassembleArchitecture.Arm64);
23+
instruction.DisassembleMode.Should().Be(Arm64DisassembleMode.Arm);
24+
$"{instruction.Mnemonic} {instruction.Operand}".Should().Be("ldr w1, [sp, #8]");
25+
}
26+
27+
[Fact]
28+
public void DisassembleArm_B() {
29+
var binaryCode = new byte[] { 0x20, 0x04, 0x81, 0xDA };
30+
using var disassembler = CapstoneDisassembler.CreateArm64Disassembler(Arm64DisassembleMode.Arm);
31+
32+
disassembler.DisassembleSyntax = DisassembleSyntax.Intel;
33+
disassembler.EnableInstructionDetails = true;
34+
var disassembledCode = disassembler.Disassemble(binaryCode);
35+
disassembledCode.Length.Should().Be(1);
36+
37+
var instruction = disassembledCode[0];
38+
instruction.DisassembleArchitecture.Should().Be(DisassembleArchitecture.Arm64);
39+
instruction.DisassembleMode.Should().Be(Arm64DisassembleMode.Arm);
40+
$"{instruction.Mnemonic} {instruction.Operand}".Should().Be("cneg x0, x1, ne");
41+
}
42+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<IsPackable>false</IsPackable>
4+
<Nullable>enable</Nullable>
5+
<TargetFramework>net6.0</TargetFramework>
6+
</PropertyGroup>
7+
<ItemGroup>
8+
<PackageReference Include="FluentAssertions" Version="6.7.0" />
9+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
10+
<PackageReference Include="xunit" Version="2.4.2" />
11+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
12+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
13+
<PrivateAssets>all</PrivateAssets>
14+
</PackageReference>
15+
<PackageReference Include="coverlet.collector" Version="3.1.2">
16+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
17+
<PrivateAssets>all</PrivateAssets>
18+
</PackageReference>
19+
</ItemGroup>
20+
<ItemGroup>
21+
<ProjectReference Include="..\Gee.External.Capstone\Gee.External.Capstone.csproj" />
22+
<None Include="$(MSBuildProjectDirectory)\..\Gee.External.Capstone\runtimes\linux-x64\native\libcapstone.so">
23+
<Link>libcapstone.so</Link>
24+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
25+
</None>
26+
<None Include="$(MSBuildProjectDirectory)\..\Gee.External.Capstone\runtimes\osx-x64\native\libcapstone.dylib">
27+
<Link>libcapstone.dylib</Link>
28+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
29+
</None>
30+
<None Include="$(MSBuildProjectDirectory)\..\Gee.External.Capstone\runtimes\win-x64\native\capstone.dll">
31+
<Link>capstone.dll</Link>
32+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
33+
</None>
34+
</ItemGroup>
35+
</Project>

0 commit comments

Comments
 (0)