acdream/tests/AcDream.Core.Net.Tests/Packets/PacketHeaderFlagsConformanceTests.cs
Erik 6119364306 test(net): pin the transport flag word against ACE, all twenty-three bits
The wire-stack audit checked the transport layer by hand and found it clean:
PacketHeader's seven fields match ACE's Pack order exactly, the optional-header
sections are parsed in ACE's order, and PacketHeaderFlags is a twenty-three of
twenty-three value match including the sparse gaps between 0x04 and 0x100 and
between 0x00800000 and 0x01000000.

Clean is worth freezing. These bits are not design choices; each one gates an
optional-header section, so a single wrong value shifts every following
section's offset and takes the packet checksum with it. The failure would not
look like a wrong flag, it would look like a corrupt connection. The enum is
small enough to pin exhaustively, so this transcribes ACE's declaration and
asserts both directions: every ACE flag exists here with ACE's value, and we
declare nothing ACE does not.

Core.Net tests go 630 to 654.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 01:54:56 +02:00

90 lines
3.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using AcDream.Core.Net.Packets;
using Xunit;
namespace AcDream.Core.Net.Tests.Packets;
/// <summary>
/// Value-conformance for the transport flag word against ACE's
/// <c>Source/ACE.Server/Network/PacketHeaderFlags.cs</c>, read 2026-07-29
/// during the wire-stack audit.
///
/// <para>These are wire-format facts, not choices: a flag bit is the gate for
/// an optional-header section, so a single wrong value silently shifts every
/// subsequent section's offset and corrupts the packet checksum. The enum is
/// small enough to pin exhaustively, and doing so makes any future edit a
/// deliberate act rather than a typo.</para>
///
/// <para>The audit found acdream's enum a 23-of-23 match with ACE's, including
/// the sparse gaps (nothing between 0x04 and 0x100, nothing between 0x00800000
/// and 0x01000000). This test freezes that result.</para>
/// </summary>
public class PacketHeaderFlagsConformanceTests
{
/// <summary>
/// Transcribed from ACE's PacketHeaderFlags enum, in declaration order.
/// The trailing comments are ACE's own.
/// </summary>
private static readonly (string Name, uint Value)[] AceFlags =
{
("None", 0x00000000u),
("Retransmission", 0x00000001u),
("EncryptedChecksum", 0x00000002u), // can't be paired with 0x1
("BlobFragments", 0x00000004u),
("ServerSwitch", 0x00000100u),
("LogonServerAddr", 0x00000200u),
("EmptyHeader1", 0x00000400u),
("Referral", 0x00000800u),
("RequestRetransmit", 0x00001000u), // Nak
("RejectRetransmit", 0x00002000u), // Empty Ack
("AckSequence", 0x00004000u), // Pak
("Disconnect", 0x00008000u), // Empty Header 2
("LoginRequest", 0x00010000u),
("WorldLoginRequest", 0x00020000u),
("ConnectRequest", 0x00040000u),
("ConnectResponse", 0x00080000u),
("NetError", 0x00100000u),
("NetErrorDisconnect", 0x00200000u),
("CICMDCommand", 0x00400000u),
("TimeSync", 0x01000000u),
("EchoRequest", 0x02000000u),
("EchoResponse", 0x04000000u),
("Flow", 0x08000000u),
};
public static TheoryData<string, uint> Flags()
{
var data = new TheoryData<string, uint>();
foreach ((string name, uint value) in AceFlags)
data.Add(name, value);
return data;
}
[Theory]
[MemberData(nameof(Flags))]
public void Flag_MatchesAceValue(string name, uint aceValue)
{
Assert.True(
Enum.IsDefined(typeof(PacketHeaderFlags), aceValue) || aceValue == 0,
$"ACE declares {name} = 0x{aceValue:X8}; acdream has no such value.");
object parsed = Enum.Parse(typeof(PacketHeaderFlags), name);
Assert.Equal(aceValue, (uint)(PacketHeaderFlags)parsed);
}
[Fact]
public void EnumHasNoMembersAceDoesNotDeclare()
{
HashSet<string> ace = AceFlags.Select(f => f.Name).ToHashSet(StringComparer.Ordinal);
string[] ours = Enum.GetNames(typeof(PacketHeaderFlags));
string[] extra = ours.Where(n => !ace.Contains(n)).ToArray();
Assert.True(
extra.Length == 0,
$"acdream declares flags ACE does not: {string.Join(", ", extra)}");
Assert.Equal(AceFlags.Length, ours.Length);
}
}