ModernUO/Projects/Server.Tests/Tests/Buffers/RawInterpolatedStringHandlerTests.cs
Kamron Batman 72c568fc8b test(buffers): run RawInterpolatedStringHandlerTests in the sequential collection
It uses the shared, deliberately lock-free STArrayPool<char> (via
RawInterpolatedStringHandler.Clear) but — unlike its siblings STArrayPoolTests and
ValueStringBuilderTests — was not in the [Collection("Sequential Server Tests")]
(DisableParallelization) group. Running in parallel with another pool test races
STArrayPool's single-threaded state and trips its InitializeBuckets Debug.Assert
("Non-null _cacheBuckets"), an intermittent CI failure. Pre-existing; unrelated to the
rest of this branch. Server.Tests 790/790 across repeated runs.
2026-07-21 07:41:33 -07:00

99 lines
3.6 KiB
C#

using System;
using Server.Buffers;
using Xunit;
namespace Server.Tests.Buffers;
// Uses the shared, deliberately lock-free STArrayPool<char> (via RawInterpolatedStringHandler.Clear),
// so it must run in the non-parallel collection like STArrayPoolTests/ValueStringBuilderTests — otherwise
// it races another pool test and trips STArrayPool's single-threaded Debug.Assert.
[Collection("Sequential Server Tests")]
public class RawInterpolatedStringHandlerTests
{
[Fact]
public void TestLowercaseFormatString()
{
var name = "Hello WORLD";
var handler = new RawInterpolatedStringHandler(0, 1);
handler.AppendFormatted(name, format: "L");
Assert.Equal("hello world", handler.Text.ToString());
handler.Clear();
}
[Fact]
public void TestLowercaseFormatEnum()
{
var handler = new RawInterpolatedStringHandler(0, 1);
handler.AppendFormatted(DayOfWeek.Wednesday, format: "L");
Assert.Equal("wednesday", handler.Text.ToString());
handler.Clear();
}
[Fact]
public void TestLowercaseFormatInt()
{
// Numerics have no uppercase chars; :L should be a no-op
var handler = new RawInterpolatedStringHandler(0, 1);
handler.AppendFormatted(42, format: "L");
Assert.Equal("42", handler.Text.ToString());
handler.Clear();
}
[Fact]
public void TestLowercaseFormatSpan()
{
var span = "MIXED Case TEXT".AsSpan();
var handler = new RawInterpolatedStringHandler(0, 1);
handler.AppendFormatted(span, alignment: 0, format: "L");
Assert.Equal("mixed case text", handler.Text.ToString());
handler.Clear();
}
[Fact]
public void TestLowercaseFormatWithAlignment()
{
// Right-aligned: "Gold" in width 8 with :L -> " gold"
var handler = new RawInterpolatedStringHandler(0, 1);
handler.AppendFormatted("Gold", alignment: 8, format: "L");
Assert.Equal(" gold", handler.Text.ToString());
handler.Clear();
}
[Fact]
public void TestNoFormatPreservesCase()
{
var handler = new RawInterpolatedStringHandler(0, 1);
handler.AppendFormatted("Hello WORLD");
Assert.Equal("Hello WORLD", handler.Text.ToString());
handler.Clear();
}
[Fact]
public void TestUnicodeLowercase()
{
// ToLowerInvariant on Greek letter
var handler = new RawInterpolatedStringHandler(0, 1);
handler.AppendFormatted("ΑΒΓ", format: "L");
Assert.Equal("αβγ", handler.Text.ToString());
handler.Clear();
}
[Fact]
public void TestLowercaseFormatSurrogatePairAtChunkBoundary()
{
// The chunked lowercase path uses a 256-char stackalloc temp buffer. Place a
// supplementary-plane code point (U+10400 DESERET CAPITAL LONG I, encoded as
// surrogate pair "𐐀") so its high half lands at offset 255 and its
// low half at offset 256 — straddling the chunk boundary. Without the
// surrogate-aware boundary trim, ToLowerInvariant would see two lone surrogates
// and pass them through unchanged, leaving the capital code point intact.
// With the trim, the chunk shrinks to 255 chars and the pair stays together
// in the next chunk, lowercasing correctly to U+10428 ("𐐨").
var input = new string('a', 255) + "𐐀" + new string('b', 10);
var handler = new RawInterpolatedStringHandler(0, 1);
handler.AppendFormatted(input, format: "L");
var expected = new string('a', 255) + "𐐨" + new string('b', 10);
Assert.Equal(expected, handler.Text.ToString());
handler.Clear();
}
}