ModernUO/Projects/Server.Tests/Tests/Serialization/FileBufferWriterTests.cs
2026-07-16 22:38:47 -07:00

141 lines
3.8 KiB
C#

using System;
using System.IO;
using System.Text;
using Xunit;
namespace Server.Tests;
public class FileBufferWriterTests
{
private static string TempFile() =>
Path.Combine(Path.GetTempPath(), $"muo-fbw-{Guid.NewGuid():N}.bin");
[Fact]
public void DrainsAcrossStagingBoundariesAndPatchesBackwards()
{
var path = TempFile();
try
{
// Tiny staging block so every few records cross a drain; mirrors the idx
// pattern: version, count placeholder, records, backwards count patch.
using (var writer = new FileBufferWriter(path, expectedSize: 64))
{
writer.Write(3); // version
var countPosition = writer.Position;
writer.Write(0);
const int records = 1000;
for (var i = 0; i < records; i++)
{
writer.Write((ulong)i * 0x9E3779B97F4A7C15);
writer.Write(i);
}
var end = writer.Position;
writer.Seek(countPosition, SeekOrigin.Begin);
writer.Write(records);
writer.Seek(0, SeekOrigin.End);
Assert.Equal(end, writer.Position);
}
var bytes = File.ReadAllBytes(path);
Assert.Equal(4 + 4 + 1000 * 12, bytes.Length);
IGenericReader reader = new BufferReader(bytes);
Assert.Equal(3, reader.ReadInt());
Assert.Equal(1000, reader.ReadInt());
for (var i = 0; i < 1000; i++)
{
Assert.Equal((ulong)i * 0x9E3779B97F4A7C15, reader.ReadULong());
Assert.Equal(i, reader.ReadInt());
}
}
finally
{
File.Delete(path);
}
}
[Fact]
public void OversizedSingleItemGrowsTheStagingBlock()
{
var path = TempFile();
try
{
// A string whose worst-case reservation exceeds the staging block must grow
// the block instead of deadlocking the drain loop.
var value = new string('二', 500); // 1500 bytes utf8, staging 64
using (var writer = new FileBufferWriter(path, expectedSize: 64))
{
writer.Write(value);
writer.Write(0xC0FFEE);
}
IGenericReader reader = new BufferReader(File.ReadAllBytes(path));
Assert.Equal(value, reader.ReadString());
Assert.Equal(0xC0FFEE, reader.ReadInt());
}
finally
{
File.Delete(path);
}
}
[Fact]
public void SpanWritesCrossDrains()
{
var path = TempFile();
try
{
var payload = new byte[777];
new System.Random(0x5EED).NextBytes(payload);
using (var writer = new FileBufferWriter(path, expectedSize: 64))
{
writer.Write((ReadOnlySpan<byte>)payload);
}
Assert.Equal(payload, File.ReadAllBytes(path));
}
finally
{
File.Delete(path);
}
}
[Fact]
public void TypeWritesRegisterIntoTheTypeSet()
{
var path = TempFile();
try
{
var typeSet = new System.Collections.Generic.HashSet<Type>();
using (var writer = new FileBufferWriter(path, typeSet))
{
writer.Write(typeof(string));
writer.Write((Type)null);
}
Assert.Contains(typeof(string), typeSet);
Assert.Single(typeSet);
var bytes = File.ReadAllBytes(path);
Assert.Equal(1 + 8 + 1, bytes.Length); // flag + hash + null flag
Assert.Equal(2, bytes[0]);
Assert.Equal(0, bytes[^1]);
}
finally
{
File.Delete(path);
}
}
}