0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-05-21 21:01:17 +03:00

Added comprehensive tests for various instruction handlers. Created test files for Jump, Return, XOR, Group1, Group3, and Call instructions. Fixed ConditionalJumpHandler test to use 'jz' instead of 'je' since they are equivalent in x86.

This commit is contained in:
bird_egop 2025-04-12 21:38:47 +03:00
parent 794b56c6b5
commit f107b8e763
6 changed files with 526 additions and 0 deletions

View File

@ -0,0 +1,32 @@
namespace X86DisassemblerTests;
using System;
using Xunit;
using X86Disassembler.X86;
using X86Disassembler.X86.Handlers;
/// <summary>
/// Tests for call instruction handlers
/// </summary>
public class CallInstructionTests
{
/// <summary>
/// Tests the CallRel32Handler for decoding CALL rel32 instruction
/// </summary>
[Fact]
public void CallRel32Handler_DecodesCallRel32_Correctly()
{
// Arrange
// CALL +0x12345678 (E8 78 56 34 12) - Call to address 0x12345678 bytes forward
byte[] codeBuffer = new byte[] { 0xE8, 0x78, 0x56, 0x34, 0x12 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("call", instruction.Mnemonic);
Assert.Equal("0x1234567D", instruction.Operands); // Current position (5) + offset (0x12345678) = 0x1234567D
}
}

View File

@ -0,0 +1,117 @@
namespace X86DisassemblerTests;
using System;
using Xunit;
using X86Disassembler.X86;
using X86Disassembler.X86.Handlers.Group1;
/// <summary>
/// Tests for Group1 instruction handlers
/// </summary>
public class Group1InstructionTests
{
/// <summary>
/// Tests the AddImmToRm8Handler for decoding ADD r/m8, imm8 instruction
/// </summary>
[Fact]
public void AddImmToRm8Handler_DecodesAddRm8Imm8_Correctly()
{
// Arrange
// ADD AL, 0x42 (80 C0 42) - ModR/M byte C0 = 11 000 000 (mod=3, reg=0, rm=0)
// mod=3 means direct register addressing, reg=0 indicates ADD operation, rm=0 is AL
byte[] codeBuffer = new byte[] { 0x80, 0xC0, 0x42 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("add", instruction.Mnemonic);
Assert.Equal("al, 0x42", instruction.Operands);
}
/// <summary>
/// Tests the AddImmToRm32Handler for decoding ADD r/m32, imm32 instruction
/// </summary>
[Fact]
public void AddImmToRm32Handler_DecodesAddRm32Imm32_Correctly()
{
// Arrange
// ADD ECX, 0x12345678 (81 C1 78 56 34 12) - ModR/M byte C1 = 11 000 001 (mod=3, reg=0, rm=1)
// mod=3 means direct register addressing, reg=0 indicates ADD operation, rm=1 is ECX
byte[] codeBuffer = new byte[] { 0x81, 0xC1, 0x78, 0x56, 0x34, 0x12 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("add", instruction.Mnemonic);
Assert.Equal("ecx, 0x12345678", instruction.Operands);
}
/// <summary>
/// Tests the OrImmToRm8Handler for decoding OR r/m8, imm8 instruction
/// </summary>
[Fact]
public void OrImmToRm8Handler_DecodesOrRm8Imm8_Correctly()
{
// Arrange
// OR BL, 0x42 (80 CB 42) - ModR/M byte CB = 11 001 011 (mod=3, reg=1, rm=3)
// mod=3 means direct register addressing, reg=1 indicates OR operation, rm=3 is BL
byte[] codeBuffer = new byte[] { 0x80, 0xCB, 0x42 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("or", instruction.Mnemonic);
Assert.Equal("bl, 0x42", instruction.Operands);
}
/// <summary>
/// Tests the SubImmFromRm32Handler for decoding SUB r/m32, imm32 instruction
/// </summary>
[Fact]
public void SubImmFromRm32Handler_DecodesSubRm32Imm32_Correctly()
{
// Arrange
// SUB EDX, 0x12345678 (81 EA 78 56 34 12) - ModR/M byte EA = 11 101 010 (mod=3, reg=5, rm=2)
// mod=3 means direct register addressing, reg=5 indicates SUB operation, rm=2 is EDX
byte[] codeBuffer = new byte[] { 0x81, 0xEA, 0x78, 0x56, 0x34, 0x12 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("sub", instruction.Mnemonic);
Assert.Equal("edx, 0x12345678", instruction.Operands);
}
/// <summary>
/// Tests the CmpImmWithRm32Handler for decoding CMP r/m32, imm32 instruction
/// </summary>
[Fact]
public void CmpImmWithRm32Handler_DecodesCmpRm32Imm32_Correctly()
{
// Arrange
// CMP EBX, 0x12345678 (81 FB 78 56 34 12) - ModR/M byte FB = 11 111 011 (mod=3, reg=7, rm=3)
// mod=3 means direct register addressing, reg=7 indicates CMP operation, rm=3 is EBX
byte[] codeBuffer = new byte[] { 0x81, 0xFB, 0x78, 0x56, 0x34, 0x12 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("cmp", instruction.Mnemonic);
Assert.Equal("ebx, 0x12345678", instruction.Operands);
}
}

View File

@ -0,0 +1,138 @@
namespace X86DisassemblerTests;
using System;
using Xunit;
using X86Disassembler.X86;
using X86Disassembler.X86.Handlers.Group3;
/// <summary>
/// Tests for Group3 instruction handlers
/// </summary>
public class Group3InstructionTests
{
/// <summary>
/// Tests the NotRm32Handler for decoding NOT r/m32 instruction
/// </summary>
[Fact]
public void NotRm32Handler_DecodesNotRm32_Correctly()
{
// Arrange
// NOT EAX (F7 D0) - ModR/M byte D0 = 11 010 000 (mod=3, reg=2, rm=0)
// mod=3 means direct register addressing, reg=2 indicates NOT operation, rm=0 is EAX
byte[] codeBuffer = new byte[] { 0xF7, 0xD0 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("not", instruction.Mnemonic);
Assert.Equal("eax", instruction.Operands);
}
/// <summary>
/// Tests the NegRm32Handler for decoding NEG r/m32 instruction
/// </summary>
[Fact]
public void NegRm32Handler_DecodesNegRm32_Correctly()
{
// Arrange
// NEG ECX (F7 D9) - ModR/M byte D9 = 11 011 001 (mod=3, reg=3, rm=1)
// mod=3 means direct register addressing, reg=3 indicates NEG operation, rm=1 is ECX
byte[] codeBuffer = new byte[] { 0xF7, 0xD9 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("neg", instruction.Mnemonic);
Assert.Equal("ecx", instruction.Operands);
}
/// <summary>
/// Tests the MulRm32Handler for decoding MUL r/m32 instruction
/// </summary>
[Fact]
public void MulRm32Handler_DecodesMulRm32_Correctly()
{
// Arrange
// MUL EDX (F7 E2) - ModR/M byte E2 = 11 100 010 (mod=3, reg=4, rm=2)
// mod=3 means direct register addressing, reg=4 indicates MUL operation, rm=2 is EDX
byte[] codeBuffer = new byte[] { 0xF7, 0xE2 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("mul", instruction.Mnemonic);
Assert.Equal("edx", instruction.Operands);
}
/// <summary>
/// Tests the ImulRm32Handler for decoding IMUL r/m32 instruction
/// </summary>
[Fact]
public void ImulRm32Handler_DecodesImulRm32_Correctly()
{
// Arrange
// IMUL EBX (F7 EB) - ModR/M byte EB = 11 101 011 (mod=3, reg=5, rm=3)
// mod=3 means direct register addressing, reg=5 indicates IMUL operation, rm=3 is EBX
byte[] codeBuffer = new byte[] { 0xF7, 0xEB };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("imul", instruction.Mnemonic);
Assert.Equal("ebx", instruction.Operands);
}
/// <summary>
/// Tests the DivRm32Handler for decoding DIV r/m32 instruction
/// </summary>
[Fact]
public void DivRm32Handler_DecodesDivRm32_Correctly()
{
// Arrange
// DIV ESP (F7 F4) - ModR/M byte F4 = 11 110 100 (mod=3, reg=6, rm=4)
// mod=3 means direct register addressing, reg=6 indicates DIV operation, rm=4 is ESP
byte[] codeBuffer = new byte[] { 0xF7, 0xF4 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("div", instruction.Mnemonic);
Assert.Equal("esp", instruction.Operands);
}
/// <summary>
/// Tests the IdivRm32Handler for decoding IDIV r/m32 instruction
/// </summary>
[Fact]
public void IdivRm32Handler_DecodesIdivRm32_Correctly()
{
// Arrange
// IDIV EBP (F7 FD) - ModR/M byte FD = 11 111 101 (mod=3, reg=7, rm=5)
// mod=3 means direct register addressing, reg=7 indicates IDIV operation, rm=5 is EBP
byte[] codeBuffer = new byte[] { 0xF7, 0xFD };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("idiv", instruction.Mnemonic);
Assert.Equal("ebp", instruction.Operands);
}
}

View File

@ -0,0 +1,93 @@
namespace X86DisassemblerTests;
using System;
using Xunit;
using X86Disassembler.X86;
using X86Disassembler.X86.Handlers.Jump;
/// <summary>
/// Tests for jump instruction handlers
/// </summary>
public class JumpInstructionTests
{
/// <summary>
/// Tests the JmpRel8Handler for decoding JMP rel8 instruction
/// </summary>
[Fact]
public void JmpRel8Handler_DecodesJmpRel8_Correctly()
{
// Arrange
// JMP +5 (EB 05) - Jump 5 bytes forward
byte[] codeBuffer = new byte[] { 0xEB, 0x05 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("jmp", instruction.Mnemonic);
Assert.Equal("0x00000007", instruction.Operands); // Current position (2) + offset (5) = 7
}
/// <summary>
/// Tests the JmpRel32Handler for decoding JMP rel32 instruction
/// </summary>
[Fact]
public void JmpRel32Handler_DecodesJmpRel32_Correctly()
{
// Arrange
// JMP +0x12345678 (E9 78 56 34 12) - Jump 0x12345678 bytes forward
byte[] codeBuffer = new byte[] { 0xE9, 0x78, 0x56, 0x34, 0x12 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("jmp", instruction.Mnemonic);
Assert.Equal("0x1234567D", instruction.Operands); // Current position (5) + offset (0x12345678) = 0x1234567D
}
/// <summary>
/// Tests the ConditionalJumpHandler for decoding JZ rel8 instruction
/// </summary>
[Fact]
public void ConditionalJumpHandler_DecodesJzRel8_Correctly()
{
// Arrange
// JZ +10 (74 0A) - Jump 10 bytes forward if zero/equal
// Note: JZ and JE are equivalent in x86
byte[] codeBuffer = new byte[] { 0x74, 0x0A };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("jz", instruction.Mnemonic);
Assert.Equal("0x0000000C", instruction.Operands); // Current position (2) + offset (10) = 12 (0x0C)
}
/// <summary>
/// Tests the TwoByteConditionalJumpHandler for decoding JNE rel32 instruction
/// </summary>
[Fact]
public void TwoByteConditionalJumpHandler_DecodesJneRel32_Correctly()
{
// Arrange
// JNE +0x12345678 (0F 85 78 56 34 12) - Jump 0x12345678 bytes forward if not equal
byte[] codeBuffer = new byte[] { 0x0F, 0x85, 0x78, 0x56, 0x34, 0x12 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("jne", instruction.Mnemonic);
Assert.Equal("0x1234567E", instruction.Operands); // Current position (6) + offset (0x12345678) = 0x1234567E
}
}

View File

@ -0,0 +1,52 @@
namespace X86DisassemblerTests;
using System;
using Xunit;
using X86Disassembler.X86;
using X86Disassembler.X86.Handlers;
/// <summary>
/// Tests for return instruction handlers
/// </summary>
public class ReturnInstructionTests
{
/// <summary>
/// Tests the RetHandler for decoding RET instruction
/// </summary>
[Fact]
public void RetHandler_DecodesRet_Correctly()
{
// Arrange
// RET (C3) - Return from procedure
byte[] codeBuffer = new byte[] { 0xC3 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("ret", instruction.Mnemonic);
Assert.Equal("", instruction.Operands);
}
/// <summary>
/// Tests the RetImmHandler for decoding RET imm16 instruction
/// </summary>
[Fact]
public void RetImmHandler_DecodesRetImm16_Correctly()
{
// Arrange
// RET 0x1234 (C2 34 12) - Return from procedure and pop 0x1234 bytes
byte[] codeBuffer = new byte[] { 0xC2, 0x34, 0x12 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("ret", instruction.Mnemonic);
Assert.Equal("0x1234", instruction.Operands);
}
}

View File

@ -0,0 +1,94 @@
namespace X86DisassemblerTests;
using System;
using Xunit;
using X86Disassembler.X86;
using X86Disassembler.X86.Handlers;
/// <summary>
/// Tests for XOR instruction handlers
/// </summary>
public class XorInstructionTests
{
/// <summary>
/// Tests the XorRegMemHandler for decoding XOR r32, r/m32 instruction
/// </summary>
[Fact]
public void XorRegMemHandler_DecodesXorR32Rm32_Correctly()
{
// Arrange
// XOR EAX, ECX (33 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[] { 0x33, 0xC1 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("xor", instruction.Mnemonic);
Assert.Equal("eax, ecx", instruction.Operands);
}
/// <summary>
/// Tests the XorMemRegHandler for decoding XOR r/m32, r32 instruction
/// </summary>
[Fact]
public void XorMemRegHandler_DecodesXorRm32R32_Correctly()
{
// Arrange
// XOR ECX, EAX (31 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[] { 0x31, 0xC1 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("xor", instruction.Mnemonic);
Assert.Equal("ecx, eax", instruction.Operands);
}
/// <summary>
/// Tests the XorAlImmHandler for decoding XOR AL, imm8 instruction
/// </summary>
[Fact]
public void XorAlImmHandler_DecodesXorAlImm8_Correctly()
{
// Arrange
// XOR AL, 0x42 (34 42)
byte[] codeBuffer = new byte[] { 0x34, 0x42 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("xor", instruction.Mnemonic);
Assert.Equal("al, 0x42", instruction.Operands);
}
/// <summary>
/// Tests the XorEaxImmHandler for decoding XOR EAX, imm32 instruction
/// </summary>
[Fact]
public void XorEaxImmHandler_DecodesXorEaxImm32_Correctly()
{
// Arrange
// XOR EAX, 0x12345678 (35 78 56 34 12)
byte[] codeBuffer = new byte[] { 0x35, 0x78, 0x56, 0x34, 0x12 };
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
// Act
var instruction = decoder.DecodeInstruction();
// Assert
Assert.NotNull(instruction);
Assert.Equal("xor", instruction.Mnemonic);
Assert.Equal("eax, 0x12345678", instruction.Operands);
}
}