using System.Collections.Generic; using System.Numerics; using AcDream.Core.Physics; using Xunit; namespace AcDream.Core.Tests.Physics; public class CellTransitCheckBuildingTransitTests { [Fact] public void BuildingPortalWithUnloadedCellBSP_NoCandidateAdded() { // Verifies the null-CellBSP guard: when the destination interior cell // is cached but its CellBSP isn't yet loaded (or is structurally absent), // CheckBuildingTransit must NOT add the cell to candidates — even though // PointInsideCellBsp(null, _) returns true. // // Happy-path (CellBSP present, sphere inside) requires a synthetic // CellBSPTree which is non-trivial to construct from DatReaderWriter // types. Deferred to visual verification. // Building at world origin. One portal to interior cell 0xA9B40100. var building = new BuildingPhysics { WorldTransform = Matrix4x4.Identity, InverseWorldTransform = Matrix4x4.Identity, Portals = new[] { new BldPortalInfo( otherCellId: 0xA9B40100u, otherPortalId: 0, flags: 0), }, }; // Interior cell with null CellBSP — PointInsideCellBsp(null, _) returns true, // but CheckBuildingTransit guards on CellBSP?.Root being non-null, so this // cell is skipped. var interiorCell = new CellPhysics { WorldTransform = Matrix4x4.Identity, InverseWorldTransform = Matrix4x4.Identity, Resolved = new Dictionary(), }; var cache = new PhysicsDataCache(); cache.RegisterCellStructForTest(0xA9B40100u, interiorCell); var candidates = new HashSet(); CellTransit.CheckBuildingTransit( cache, building, worldSphereCenter: new Vector3(0, 0, 0), sphereRadius: 0.5f, candidates); // CellBSP is null → containment guard (otherCell?.CellBSP?.Root is null) // skips this cell. No candidate added. Assert.Empty(candidates); } // A second test that uses a synthetic CellBSP whose Root.Type == BSPNodeType.Leaf // (which PointInsideCellBsp short-circuits as "inside") would verify the // happy path. Constructing a CellBSPTree by hand from DatReaderWriter // types is awkward; deferred to integration testing at visual-verify time. }