0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-06-19 16:08:02 +03:00

Fixed TEST instruction handlers and tests. Updated TestImmWithRm8Handler and TestImmWithRm32Handler to properly check opcode in CanHandle and validate reg field in Decode. Improved test cases to use InstructionDecoder directly.

This commit is contained in:
bird_egop
2025-04-12 21:21:03 +03:00
parent bf5fcdd2ff
commit fe0b04f5a1
10 changed files with 330 additions and 74 deletions

View File

@ -0,0 +1 @@
global using Xunit;

View File

@ -52,8 +52,8 @@ public class InstructionDecoderTests
// Assert
Assert.NotNull(instruction);
Assert.Equal("test", instruction.Mnemonic);
// The actual implementation produces "al, cl" as the operands
Assert.Equal("al, cl", instruction.Operands);
// The correct operand order is TEST r/m8, r8 (TEST CL, AL)
Assert.Equal("cl, al", instruction.Operands);
Assert.Equal(2, instruction.RawBytes.Length);
Assert.Equal(0x84, instruction.RawBytes[0]);
Assert.Equal(0xC1, instruction.RawBytes[1]);
@ -76,8 +76,8 @@ public class InstructionDecoderTests
// Assert
Assert.NotNull(instruction);
Assert.Equal("test", instruction.Mnemonic);
// The actual implementation produces "eax, ecx" as the operands
Assert.Equal("eax, ecx", instruction.Operands);
// The correct operand order is TEST r/m32, r32 (TEST ECX, EAX)
Assert.Equal("ecx, eax", instruction.Operands);
Assert.Equal(2, instruction.RawBytes.Length);
Assert.Equal(0x85, instruction.RawBytes[0]);
Assert.Equal(0xC1, instruction.RawBytes[1]);
@ -176,7 +176,6 @@ public class InstructionDecoderTests
// Act - First instruction
var instruction1 = decoder.DecodeInstruction();
Debug.WriteLine($"After first instruction, decoder position: {decoder.GetPosition()}");
// Assert - First instruction
Assert.NotNull(instruction1);
@ -185,12 +184,11 @@ public class InstructionDecoderTests
// Act - Second instruction
var instruction2 = decoder.DecodeInstruction();
Debug.WriteLine($"After second instruction, decoder position: {decoder.GetPosition()}");
// Assert - Second instruction
Assert.NotNull(instruction2);
Assert.Equal("jz", instruction2.Mnemonic);
// The correct target address according to x86 architecture
Assert.Equal("0x00000032", instruction2?.Operands ?? string.Empty);
Assert.Equal("0x00000032", instruction2.Operands);
}
}

View File

@ -0,0 +1,183 @@
namespace X86DisassemblerTests;
using System;
using Xunit;
using X86Disassembler.X86;
using X86Disassembler.X86.Handlers;
using X86Disassembler.X86.Handlers.Group3;
/// <summary>
/// Tests for TEST instruction handlers
/// </summary>
public class TestInstructionHandlerTests
{
/// <summary>
/// Tests the TestRegMemHandler for decoding TEST r/m32, r32 instructions
/// </summary>
[Fact]
public void TestRegMemHandler_DecodesTestR32R32_Correctly()
{
// Arrange
// TEST ECX, EAX (85 C1) - ModR/M byte C1 = 11 000 001 (mod=3, reg=0, rm=1)
// mod=3 means direct register addressing, reg=0 is EAX, rm=1 is ECX
byte[] codeBuffer = new byte[] { 0x85, 0xC1 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("test", instruction.Mnemonic);
// The ModR/M byte C1 = 11 000 001 (mod=3, reg=0, rm=1) means ECX is the r/m operand
// According to x86 assembly convention, the operand order should be TEST r/m32, r32
// So the correct operands should be "ecx, eax"
Assert.Equal("ecx, eax", instruction.Operands);
}
/// <summary>
/// Tests the TestRegMem8Handler for decoding TEST r/m8, r8 instructions
/// </summary>
[Fact]
public void TestRegMem8Handler_DecodesTestR8R8_Correctly()
{
// Arrange
// TEST CL, AL (84 C1) - ModR/M byte C1 = 11 000 001 (mod=3, reg=0, rm=1)
// mod=3 means direct register addressing, reg=0 is AL, rm=1 is CL
byte[] codeBuffer = new byte[] { 0x84, 0xC1 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("test", instruction.Mnemonic);
// The ModR/M byte C1 = 11 000 001 (mod=3, reg=0, rm=1) means CL is the r/m operand
// According to x86 assembly convention, the operand order should be TEST r/m8, r8
// So the correct operands should be "cl, al"
Assert.Equal("cl, al", instruction.Operands);
}
/// <summary>
/// Tests the TestAlImmHandler for decoding TEST AL, imm8 instructions
/// </summary>
[Fact]
public void TestAlImmHandler_DecodesTestAlImm8_Correctly()
{
// Arrange
// TEST AL, 0x42 (A8 42)
byte[] codeBuffer = new byte[] { 0xA8, 0x42 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("test", instruction.Mnemonic);
// The handler should produce "al, 0xXX" as the operands
Assert.Equal("al, 0x42", instruction.Operands);
}
/// <summary>
/// Tests the TestEaxImmHandler for decoding TEST EAX, imm32 instructions
/// </summary>
[Fact]
public void TestEaxImmHandler_DecodesTestEaxImm32_Correctly()
{
// Arrange
// TEST EAX, 0x12345678 (A9 78 56 34 12)
byte[] codeBuffer = new byte[] { 0xA9, 0x78, 0x56, 0x34, 0x12 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("test", instruction.Mnemonic);
// The handler should produce "eax, 0xXXXXXXXX" as the operands
Assert.Equal("eax, 0x12345678", instruction.Operands);
}
/// <summary>
/// Tests that the TestImmWithRm8Handler can handle the correct opcode
/// </summary>
[Fact]
public void TestImmWithRm8Handler_CanHandle_ReturnsTrueForCorrectOpcode()
{
// Arrange
byte[] codeBuffer = new byte[] { 0xF6, 0xC0 }; // ModR/M byte C0 = 11 000 000 (mod=3, reg=0, rm=0)
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
var handler = new TestImmWithRm8Handler(codeBuffer, decoder, codeBuffer.Length);
// Act
bool result = handler.CanHandle(0xF6);
// Assert
Assert.True(result);
}
/// <summary>
/// Tests that the TestImmWithRm8Handler cannot handle an incorrect opcode
/// </summary>
[Fact]
public void TestImmWithRm8Handler_CanHandle_ReturnsFalseForIncorrectOpcode()
{
// Arrange
byte[] codeBuffer = new byte[] { 0xF7 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
var handler = new TestImmWithRm8Handler(codeBuffer, decoder, codeBuffer.Length);
// Act
bool result = handler.CanHandle(0xF7);
// Assert
Assert.False(result);
}
/// <summary>
/// Tests the TestImmWithRm8Handler for decoding TEST r/m8, imm8 instructions
/// </summary>
[Fact]
public void TestImmWithRm8Handler_DecodesTestRm8Imm8_Correctly()
{
// Arrange
// TEST AH, 0x01 (F6 C4 01) - ModR/M byte C4 = 11 000 100 (mod=3, reg=0, rm=4)
// mod=3 means direct register addressing, reg=0 indicates TEST operation, rm=4 is AH
byte[] codeBuffer = new byte[] { 0xF6, 0xC4, 0x01 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("test", instruction.Mnemonic);
// The handler should produce "ah, 0xXX" as the operands
Assert.Equal("ah, 0x01", instruction.Operands);
}
/// <summary>
/// Tests the TestImmWithRm32Handler for decoding TEST r/m32, imm32 instructions
/// </summary>
[Fact]
public void TestImmWithRm32Handler_DecodesTestRm32Imm32_Correctly()
{
// Arrange
// TEST EDI, 0x12345678 (F7 C7 78 56 34 12) - ModR/M byte C7 = 11 000 111 (mod=3, reg=0, rm=7)
// mod=3 means direct register addressing, reg=0 indicates TEST operation, rm=7 is EDI
byte[] codeBuffer = new byte[] { 0xF7, 0xC7, 0x78, 0x56, 0x34, 0x12 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("test", instruction.Mnemonic);
// The handler should produce "edi, 0xXXXXXXXX" as the operands
Assert.Equal("edi, 0x12345678", instruction.Operands);
}
}

View File

@ -0,0 +1,10 @@
namespace X86DisassemblerTests;
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}

View File

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\X86Disassembler\X86Disassembler.csproj" />
</ItemGroup>
</Project>