using AcDream.Core.Physics;
using DatReaderWriter;
using DatReaderWriter.DBObjs;
using DatReaderWriter.Options;
namespace AcDream.Content.Tests;
///
/// AP-22 reachability proof. The deleted Setup-radius collision fallback fired
/// only for a Setup with no CylSphere, no Sphere, and a nonzero summary
/// Radius. This sweeps every Setup in the installed client_portal.dat and
/// asserts no such Setup exists, so the deletion cannot remove collision from
/// any real object.
///
public sealed class InstalledSetupCollisionReachabilityTests
{
// Positive controls. These are EXTERNAL constants, measured on 2026-08-06
// by an independent raw client_portal.dat parse (B-tree directory walk +
// Setup record decode) that validated itself by byte accounting: all
// 5,935 records consumed with an exact residual tail of
// 20 + 48 * numLights and zero unexplained bytes.
//
// They are deliberately NOT derived from FlatCollisionAssetBuilder. A
// broken enumeration, a wrong dat path, or a silently-empty flatten all
// satisfy the negative claim vacuously and are caught only here.
private const int ExpectedSetups = 5935;
private const int ExpectedWithCylinder = 678;
private const int ExpectedSphereOnlyNoCylinder = 3605;
private const int ExpectedWithoutAnyPrimitive = 1652;
private const int ExpectedWithSummaryRadius = 4282;
[Fact]
public void InstalledSetups_NeverReachTheDeletedRadiusFallback()
{
string? datDir = ContentConformanceDats.ResolveDatDir();
if (datDir is null)
return;
using var dats = new DatCollection(datDir, DatAccessType.Read);
int total = 0;
int withCylinder = 0;
int sphereOnly = 0;
int withoutPrimitive = 0;
int withRadius = 0;
var fallbackReachable = new List();
var fallbackReachableWideGuard = new List();
foreach (uint id in dats.GetAllIdsOfType())
{
if (!dats.Portal.TryGet(id, out Setup? setup)
|| setup is null)
{
continue;
}
FlatSetupCollision flat =
FlatCollisionAssetBuilder.FlattenSetup(setup);
total++;
bool hasCylinder = flat.Cylinders.Length > 0;
bool hasSphere = flat.Spheres.Length > 0;
if (hasCylinder)
withCylinder++;
else if (hasSphere)
sphereOnly++;
else
withoutPrimitive++;
if (flat.Radius > 0.0001f)
withRadius++;
// BOTH guard variants the deleted copies used — they are not the
// same predicate. Site 1 (LiveEntityCollisionBuilder) tested
// `Radius > 0.0001f`; sites 2 and 3 (LandblockPhysicsPublisher,
// LandblockPhysicsContentBuilder — the headless-reachable one)
// tested the strictly wider `Radius > 0f`. Corrected 2026-08-06 at
// the AP-22 architecture review, which measured that the two
// genuinely differ over the installed DAT by exactly one Setup:
// 0x02001657, whose radius is the denormal 1.3e-39. Asserting only
// the narrow guard would have claimed coverage of two deletions it
// never evaluated.
if (!hasCylinder && !hasSphere && flat.Radius > 0.0001f)
fallbackReachable.Add(id);
if (!hasCylinder && !hasSphere && flat.Radius > 0f)
fallbackReachableWideGuard.Add(id);
}
// (b) Positive controls first: if the enumeration is broken, fail here
// rather than passing (a) for the wrong reason.
Assert.Equal(ExpectedSetups, total);
Assert.Equal(ExpectedWithCylinder, withCylinder);
Assert.Equal(ExpectedSphereOnlyNoCylinder, sphereOnly);
Assert.Equal(ExpectedWithoutAnyPrimitive, withoutPrimitive);
Assert.Equal(ExpectedWithSummaryRadius, withRadius);
// (a) The negative claim the deletion rests on.
Assert.Empty(fallbackReachable);
// The wider guard sites 2 and 3 actually used. Zero here is what makes
// the headless-reachable deletion safe; the narrow guard above does
// not evaluate it.
Assert.Empty(fallbackReachableWideGuard);
}
}