using System.Runtime.InteropServices; using WhiteMagic; namespace WhiteMagicTest; /// /// Tests for . The current implementation uses /// ReadProcessMemory/WriteProcessMemory on a self-handle (per the D1 /// revision — unsafe direct-pointer dereference was rejected because .NET cannot /// catch ). Verifies the shared /// API works for both external and in-process readers. /// public class InProcessReaderTests { private static InProcessReader CreateReader() { return new InProcessReader(); } [Fact] public void ImageBase_is_nonzero() { using var reader = CreateReader(); Assert.NotEqual(IntPtr.Zero, reader.ImageBase); } [Fact] public void Read_int_reads_known_value_from_own_memory() { using var reader = CreateReader(); int expected = 0x12345678; GCHandle pin = GCHandle.Alloc(expected, GCHandleType.Pinned); try { IntPtr addr = pin.AddrOfPinnedObject(); int result = reader.Read(addr); Assert.Equal(expected, result); } finally { pin.Free(); } } [Fact] public void Write_int_writes_and_reads_back() { using var reader = CreateReader(); int slot = 0; GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned); try { IntPtr addr = pin.AddrOfPinnedObject(); Assert.True(reader.Write(addr, unchecked((int)0xCAFEBABE))); Assert.Equal(unchecked((int)0xCAFEBABE), reader.Read(addr)); } finally { pin.Free(); } } [Fact] public void Read_bytes_reads_known_bytes() { using var reader = CreateReader(); byte[] expected = [0x0A, 0x0B, 0x0C, 0x0D]; GCHandle pin = GCHandle.Alloc(expected, GCHandleType.Pinned); try { IntPtr addr = pin.AddrOfPinnedObject(); byte[] result = reader.ReadBytes(addr, 4); Assert.Equal(expected, result); } finally { pin.Free(); } } [Fact] public void Write_bytes_writes_and_reads_back() { using var reader = CreateReader(); byte[] slot = new byte[4]; GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned); try { IntPtr addr = pin.AddrOfPinnedObject(); byte[] expected = [0xDE, 0xAD, 0xBE, 0xEF]; int written = reader.WriteBytes(addr, expected); Assert.Equal(4, written); byte[] result = reader.ReadBytes(addr, 4); Assert.Equal(expected, result); } finally { pin.Free(); } } [Fact] public void Read_struct_via_InProcessReader() { using var reader = CreateReader(); var slot = new TestStruct { X = 10, Y = 20 }; GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned); try { IntPtr addr = pin.AddrOfPinnedObject(); var result = reader.Read(addr); Assert.Equal(10, result.X); Assert.Equal(20, result.Y); } finally { pin.Free(); } } [Fact] public void Write_struct_via_InProcessReader() { using var reader = CreateReader(); var slot = new TestStruct { X = 1, Y = 2 }; GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned); try { IntPtr addr = pin.AddrOfPinnedObject(); Assert.True(reader.Write(addr, new TestStruct { X = 99, Y = 88 })); var result = reader.Read(addr); Assert.Equal(99, result.X); Assert.Equal(88, result.Y); } finally { pin.Free(); } } [Fact] public void Dispose_disposes_handle() { var reader = CreateReader(); Assert.False(reader.Handle.IsClosed); reader.Dispose(); Assert.True(reader.Handle.IsClosed); } }