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>
This commit is contained in:
parent
7e95c45ece
commit
6119364306
1 changed files with 90 additions and 0 deletions
|
|
@ -0,0 +1,90 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue