Files
whitemagic/WhiteMagicTest/StringReadWriteTests.cs
T
2026-07-21 22:30:10 +02:00

184 lines
5.3 KiB
C#

using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using WhiteMagic;
using WhiteMagic.Native;
namespace WhiteMagicTest;
/// <summary>
/// Tests for <see cref="MemoryBase.ReadString"/> and <see cref="MemoryBase.WriteString"/>
/// with encoding, null-terminator stop, and max-length behavior.
/// </summary>
public class StringReadWriteTests
{
private static ExternalReader OpenSelf()
{
return new ExternalReader(
Process.GetCurrentProcess(),
ProcessAccess.VmRead | ProcessAccess.VmWrite | ProcessAccess.VmOperation | ProcessAccess.QueryInformation);
}
[Fact]
public void WriteString_ascii_then_ReadString_round_trips()
{
using var reader = OpenSelf();
byte[] slot = new byte[64];
GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned);
try
{
IntPtr addr = pin.AddrOfPinnedObject();
Assert.True(reader.WriteString(addr, "hello", Encoding.ASCII));
string result = reader.ReadString(addr, Encoding.ASCII);
Assert.Equal("hello", result);
}
finally
{
pin.Free();
}
}
[Fact]
public void WriteString_utf8_then_ReadString_round_trips()
{
using var reader = OpenSelf();
byte[] slot = new byte[64];
GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned);
try
{
IntPtr addr = pin.AddrOfPinnedObject();
Assert.True(reader.WriteString(addr, "héllo wörld", Encoding.UTF8));
string result = reader.ReadString(addr, Encoding.UTF8);
Assert.Equal("héllo wörld", result);
}
finally
{
pin.Free();
}
}
[Fact]
public void WriteString_unicode_then_ReadString_round_trips()
{
using var reader = OpenSelf();
byte[] slot = new byte[128];
GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned);
try
{
IntPtr addr = pin.AddrOfPinnedObject();
Assert.True(reader.WriteString(addr, "Hello\u00A9\u00AE\u20AC", Encoding.Unicode));
string result = reader.ReadString(addr, Encoding.Unicode);
Assert.Equal("Hello\u00A9\u00AE\u20AC", result);
}
finally
{
pin.Free();
}
}
[Fact]
public void ReadString_stops_at_null_terminator()
{
using var reader = OpenSelf();
byte[] slot = Encoding.ASCII.GetBytes("hello\0world");
GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned);
try
{
IntPtr addr = pin.AddrOfPinnedObject();
string result = reader.ReadString(addr, Encoding.ASCII, maxLength: 64);
Assert.Equal("hello", result);
}
finally
{
pin.Free();
}
}
[Fact]
public void ReadString_respects_max_length()
{
using var reader = OpenSelf();
byte[] slot = Encoding.ASCII.GetBytes("hello world this is a test");
GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned);
try
{
IntPtr addr = pin.AddrOfPinnedObject();
string result = reader.ReadString(addr, Encoding.ASCII, maxLength: 5);
Assert.Equal("hello", result);
}
finally
{
pin.Free();
}
}
[Fact]
public void WriteString_appends_null_terminator_automatically()
{
using var reader = OpenSelf();
byte[] slot = new byte[32];
GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned);
try
{
IntPtr addr = pin.AddrOfPinnedObject();
// Write without terminator
Assert.True(reader.WriteString(addr, "test", Encoding.ASCII));
// The written bytes should end with \0
byte[] read = reader.ReadBytes(addr, 8);
Assert.Equal((byte)'t', read[0]);
Assert.Equal((byte)'e', read[1]);
Assert.Equal((byte)'s', read[2]);
Assert.Equal((byte)'t', read[3]);
Assert.Equal(0, read[4]); // null terminator
}
finally
{
pin.Free();
}
}
[Fact]
public void ReadString_empty_buffer_returns_empty_string()
{
using var reader = OpenSelf();
byte[] slot = new byte[1] { 0 };
GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned);
try
{
IntPtr addr = pin.AddrOfPinnedObject();
string result = reader.ReadString(addr, Encoding.ASCII, maxLength: 1);
Assert.Equal("", result);
}
finally
{
pin.Free();
}
}
[Fact]
public void WriteString_empty_string_writes_only_null()
{
using var reader = OpenSelf();
byte[] slot = new byte[8];
GCHandle pin = GCHandle.Alloc(slot, GCHandleType.Pinned);
try
{
IntPtr addr = pin.AddrOfPinnedObject();
// Write a marker first
reader.WriteBytes(addr, [0xAB, 0xCD, 0xEF, 0x00]);
// Now overwrite with empty string
Assert.True(reader.WriteString(addr, "", Encoding.ASCII));
byte[] read = reader.ReadBytes(addr, 4);
Assert.Equal(0, read[0]); // null
}
finally
{
pin.Free();
}
}
}