acdream/tests/AcDream.App.Tests/Rendering/WorldRenderDiagnosticsTests.cs
Erik 0c5057c9ff fix #435 (part 1): delete 17 probes that outlived their closed investigations
Each of these was temporary apparatus added to chase one bug, and each was
supposed to be deleted in the commit that fixed it. Fourteen closed issues
later they were still here: #337's support/wire-mesh trio, #171's sticky
timeline, #119's viewer and entity dumps, #113's phantom probe, and a dozen
more. 3,493 lines removed; the client now reads 144 environment variables
instead of 161, and 47 temporary probes remain instead of 64.

This is not only tidying. Every probe leaves a branch on its hot path when
unset, several re-read the environment per call rather than caching, and
the volume buries the diagnostics that are actually load-bearing. It is
also a headless correctness matter: HeadlessStaticStateAudit reflects over
PhysicsDiagnostics' flags to refuse a multi-session host when any is set,
and cannot see probes that live outside that owner.

Four files went entirely — WalkMissDiagnostic.cs, CollisionMeshWireframe.cs
and two test files whose only subject was a deleted probe.
TransitionTypes.SetContactPlane also sheds its CallerMemberName /
CallerLineNumber parameters, which existed solely for #337's cpSrc=
attribution and carried the instruction to strip them with the probe
family; no call site passed them, so no behavior changes. F2's collision
overlay survives and reverts to its proxy-cylinder form, which is what
removing the ACDREAM_WIRE_MESH upgrade means.

LaunchOptionsDocumentationTests earned its keep here: it refused the
deletion until docs/launch-options.md moved the 17 rows into Retired and
the frozen direct-read counts came down (PhysicsEngine.cs to zero,
TransitionTypes.cs 3 to 2). The documentation could not drift during a
cleanup this wide.

The 14 probes that name no owning issue are deliberately NOT deleted.
Nothing records when they became safe to remove, and guessing is how a
future investigation loses apparatus it needed; #435 stays open for their
attribution.

Full hermetic suite 15,321 passed / 0 failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 11:41:20 +02:00

245 lines
8.2 KiB
C#

using System.Numerics;
using System.Reflection;
using AcDream.App.Rendering;
using AcDream.Core.Vfx;
namespace AcDream.App.Tests.Rendering;
public sealed class WorldRenderDiagnosticsTests
{
[Fact]
public void GlTripwire_DisabledPerformsNoGlRead()
{
var gl = new RecordingGlStateReader();
var log = new RecordingLog();
var diagnostics = new WorldRenderDiagnostics(gl, log);
diagnostics.EmitGlStateTripwireIfChanged(enabled: false);
Assert.Equal(0, gl.StateCaptureCount);
Assert.Empty(log.Messages);
}
[Fact]
public void GlTripwire_LogsOnlyChangesAndReportsStableFrameCount()
{
var gl = new RecordingGlStateReader
{
State = State(depthFunction: 0x201),
};
var log = new RecordingLog();
var diagnostics = new WorldRenderDiagnostics(gl, log);
diagnostics.EmitGlStateTripwireIfChanged(enabled: true);
diagnostics.EmitGlStateTripwireIfChanged(enabled: true);
gl.State = State(depthFunction: 0x203);
diagnostics.EmitGlStateTripwireIfChanged(enabled: true);
Assert.Equal(3, gl.StateCaptureCount);
Assert.Collection(
log.Messages,
first =>
{
Assert.StartsWith("[gl-state] frame=1 stable=0", first);
Assert.Contains("dfunc=0x201", first);
},
changed =>
{
Assert.StartsWith("[gl-state] frame=3 stable=1", changed);
Assert.Contains("dfunc=0x203", changed);
});
}
[Fact]
public void ScissorProbe_SequenceAdvancesAcrossSuppressedDuplicates()
{
var gl = new RecordingGlStateReader
{
Scissor = new RenderGlScissorSnapshot(
true,
new IntRenderRectangle(1, 2, 3, 4)),
};
var log = new RecordingLog();
var diagnostics = new WorldRenderDiagnostics(gl, log);
diagnostics.EmitClipRouteScissorProbe(true, true, new Vector4(-1, -1, 1, 1));
diagnostics.EmitClipRouteScissorProbe(true, true, new Vector4(-1, -1, 1, 1));
gl.Scissor = new RenderGlScissorSnapshot(
true,
new IntRenderRectangle(5, 6, 7, 8));
diagnostics.EmitClipRouteScissorProbe(true, true, new Vector4(-1, -1, 1, 1));
Assert.Equal(3, gl.ScissorCaptureCount);
Assert.Collection(
log.Messages,
first => Assert.StartsWith("[clip-route-scis] n=1", first),
changed => Assert.StartsWith("[clip-route-scis] n=3", changed));
}
[Fact]
public void Owner_RetainsNoBorrowedFrameProductsOrBroadRuntimeOwners()
{
FieldInfo[] fields = typeof(WorldRenderDiagnostics).GetFields(
BindingFlags.Instance | BindingFlags.NonPublic);
Type[] forbidden =
[
typeof(GameWindow),
typeof(PortalVisibilityFrame),
typeof(ClipFrameAssembly),
typeof(InteriorEntityPartition.Result),
typeof(AcDream.Core.Physics.PhysicsEngine),
typeof(CameraController),
typeof(CellVisibility),
];
foreach (Type type in forbidden)
Assert.DoesNotContain(fields, field => field.FieldType == type);
Assert.DoesNotContain(
fields,
field => typeof(Delegate).IsAssignableFrom(field.FieldType));
}
// Campaign V slice V11 deleted SilkRenderGlStateReader, the raw-GL
// IRenderGlStateReader implementation this test pinned (it was never
// constructed in production — NullRenderGlStateReader.Instance is the
// sole surviving implementer), so the "consume the entering GL error
// before other state reads" source-order tripwire it protected has
// nothing left to pin.
[Fact]
public void TerrainDiagnostics_RetryFailedPublicationWithoutLosingSamples()
{
var log = new ThrowOnceLog();
var diagnostics = new WorldRenderDiagnostics(new RecordingGlStateReader(), log);
var facts = new TerrainRenderDiagnosticFacts(3, 5, 8);
diagnostics.BeginTerrainDraw();
diagnostics.EndTerrainDraw();
Assert.Throws<InvalidOperationException>(() =>
diagnostics.PublishTerrainDiagnostics(facts));
diagnostics.BeginTerrainDraw();
diagnostics.EndTerrainDraw();
diagnostics.PublishTerrainDiagnostics(facts);
Assert.Single(log.Messages);
Assert.Contains("draws=3/frame", log.Messages[0]);
Assert.Contains("visible=3", log.Messages[0]);
Assert.Contains("loaded=5", log.Messages[0]);
Assert.Contains("capacity=8", log.Messages[0]);
}
[Fact]
public void RenderSignature_LogsOnlyChangesAndCarriesStableCount()
{
var log = new RecordingLog();
var diagnostics = new WorldRenderDiagnostics(new RecordingGlStateReader(), log);
EmitMinimalSignature(diagnostics, "flat");
EmitMinimalSignature(diagnostics, "flat");
EmitMinimalSignature(diagnostics, "pview");
Assert.Collection(
log.Messages,
first => Assert.StartsWith("[render-sig] frame=1 stable=0 branch=flat", first),
changed => Assert.StartsWith("[render-sig] frame=3 stable=1 branch=pview", changed));
}
private static RenderGlStateSnapshot State(int depthFunction) => new(
DepthTest: true,
DepthWrite: true,
DepthFunction: depthFunction,
Blend: false,
BlendSource: 1,
BlendDestination: 0,
CullFace: true,
CullMode: 0x405,
FrontFace: 0x900,
Scissor: false,
ScissorBox: new IntRenderRectangle(0, 0, 1280, 720),
Viewport: new IntRenderRectangle(0, 0, 1280, 720),
DrawFramebuffer: 0,
AlphaToCoverage: false,
Stencil: false,
ClipBits: 0,
Error: 0);
private sealed class RecordingGlStateReader : IRenderGlStateReader
{
public RenderGlStateSnapshot State { get; set; } = WorldRenderDiagnosticsTests.State(0x201);
public RenderGlScissorSnapshot Scissor { get; set; }
public int StateCaptureCount { get; private set; }
public int ScissorCaptureCount { get; private set; }
public RenderGlStateSnapshot CaptureState()
{
StateCaptureCount++;
return State;
}
public RenderGlScissorSnapshot CaptureScissor()
{
ScissorCaptureCount++;
return Scissor;
}
}
private sealed class RecordingLog : IRenderFrameDiagnosticLog
{
public List<string> Messages { get; } = [];
public void WriteLine(string message) => Messages.Add(message);
}
private sealed class ThrowOnceLog : IRenderFrameDiagnosticLog
{
private bool _throw = true;
public List<string> Messages { get; } = [];
public void WriteLine(string message)
{
if (_throw)
{
_throw = false;
throw new InvalidOperationException("diagnostic sink failed");
}
Messages.Add(message);
}
}
private static void EmitMinimalSignature(
WorldRenderDiagnostics diagnostics,
string branch) =>
diagnostics.EmitRenderSignatureIfChanged(
enabled: true,
branch: branch,
clipRoot: null,
viewerRoot: null,
playerRoot: null,
viewerCellId: 0,
playerCellId: 0,
playerIndoorGate: false,
cameraInsideCell: false,
renderSkyGate: false,
drawSkyThisFrame: false,
terrainDrawn: false,
terrainClipMode: TerrainClipMode.Skip,
skyDrawn: false,
depthClear: false,
outdoorSceneryDrawn: false,
outdoorPortalDrawn: false,
outdoorRootObjectCount: 0,
liveDynamicDrawnCount: 0,
sceneParticles: "none",
portalFrame: null,
clipAssembly: null,
drawableCells: null,
partition: null,
exteriorPortalFrame: null,
exteriorClipAssembly: null,
exteriorDrawableCells: null,
exteriorPartition: null,
cameraPosition: Vector3.Zero,
playerPosition: Vector3.Zero);
}