using System;
using System.Collections.Generic;
using System.Linq;
using AcDream.Core.Net.Packets;
using Xunit;
namespace AcDream.Core.Net.Tests.Packets;
///
/// Value-conformance for the transport flag word against ACE's
/// Source/ACE.Server/Network/PacketHeaderFlags.cs, read 2026-07-29
/// during the wire-stack audit.
///
/// 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.
///
/// 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.
///
public class PacketHeaderFlagsConformanceTests
{
///
/// Transcribed from ACE's PacketHeaderFlags enum, in declaration order.
/// The trailing comments are ACE's own.
///
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 Flags()
{
var data = new TheoryData();
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 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);
}
}