acdream/tests/AcDream.App.Tests/Rendering/CameraDiagnosticsCollection.cs
Erik bf53e2ad6e refactor(rendering): delete superseded visibility probes
Delete the callerless portal-BFS research graph and spent renderer probe families while retaining the production RetailFrameWalk path, terrain diagnostics, membership invariant, and walk transcript.

Mutation evidence (all restored):

1. Restored PortalVisibilityBuilder type -> AppAssembly_ContainsNoSupersededPortalGraphTypes first failed Assert.Empty with AcDream.App.Rendering.PortalVisibilityBuilder.

2. Restored ACDREAM_PROBE_FACILITY_STAIRS -> ProductionSource_ContainsNoDeletedRendererProbe_AndRetainsWalkTranscriptProof first failed Assert.Empty on RenderingDiagnostics.cs.

3. Added a second RetailFrameWalk field -> WalkFrameOwners_AreUnique first failed Assert.Single with _frameWalk and _mutatedSecondFrameWalk.

4. Added OrderBy to OrderedStream -> OrderedWalkStream_HasNoCrossStreamReorder first failed Assert.DoesNotContain on OrderBy(.

5. Added IDatReaderWriter parameter -> FrameTimeWalkOwners_HaveNoRawDatDependency first failed Assert.Empty on RetailFrameWalk.MutatedRawDatParameter.
2026-09-05 05:18:17 +02:00

67 lines
3.4 KiB
C#

using Xunit;
namespace AcDream.App.Tests.Rendering;
/// <summary>
/// Serializes every test class that shares the camera/render family of
/// <b>process-global mutable statics</b>. xUnit runs distinct test classes in
/// PARALLEL by default, and these statics live on the process, not on the test
/// — so two classes running concurrently observe each other's writes.
///
/// <para>
/// The per-class <c>try</c>/<c>finally</c> save/restore blocks are correct
/// <i>within</i> a class and remain necessary — but they are not sufficient.
/// A <c>finally</c> only bounds the mutation in TIME along its own thread; it
/// cannot stop another class from reading the static inside that window. Worse,
/// two overlapping save/restore pairs can interleave so the second restore
/// writes back the FIRST one's temporary value, leaving the global permanently
/// wrong for the rest of the run. Serializing the sharers is what actually makes
/// each class's <c>finally</c> sufficient.
/// </para>
///
/// <para>The shared globals below are covered, and every one of them is an
/// edge between at least two classes in this collection:</para>
/// <list type="bullet">
/// <item><description><c>AcDream.Core.Rendering.CameraDiagnostics</c> —
/// <c>AlignToSlope</c>, <c>CollideCamera</c>, <c>TranslationStiffness</c>,
/// <c>RotationStiffness</c>, <c>UseRetailChaseCamera</c>. Read by
/// <c>RetailChaseCamera.Update</c>, <c>CameraController.Active</c>,
/// <c>CameraFrameController</c>, <c>WorldRenderFrameBuilder</c> and
/// <c>MouseLookController</c>.</description></item>
/// <item><description><c>AcDream.Core.Rendering.RenderingDiagnostics.DumpWalkTranscriptEnabled</c>
/// (Campaign OVERHAUL S3 chunk 1) — written by
/// <c>WalkFrameDriverTests</c>' transcript-emitter tests
/// (<c>WalkFrameDriverTranscriptTests.cs</c>).</description></item>
/// <item><description><c>System.Console.Out</c> — redirected via
/// <c>Console.SetOut</c> by the transcript tests to capture output.
/// Interleaved redirection can restore a DISPOSED <c>StringWriter</c> as the
/// process-wide <c>Console.Out</c>, which then throws in unrelated
/// tests.</description></item>
/// </list>
///
/// <para>
/// Membership is deliberately narrow: only classes that write one of these
/// globals, or that drive production code which READS a knob another member
/// mutates away from its default (<c>RetailChaseCameraTests</c> sets
/// <c>AlignToSlope</c> and <c>CollideCamera</c> to <see langword="false"/>;
/// the <c>UseRetailChaseCamera</c> writers set it to <see langword="false"/>).
/// Classes that merely construct a <c>CameraController</c> without a retail
/// chase camera are NOT members — their reads are insensitive.
/// </para>
///
/// <para>
/// Marker only, no collection fixture: each member still needs its own
/// per-test values (several are <c>[Theory]</c> cases that set different knobs
/// per case), so a fixture cannot own the save/restore without rewriting every
/// member's internals. The existing per-test <c>finally</c> blocks already
/// return the defaults; this attribute supplies the mutual exclusion they were
/// missing. Follows the <c>WorldEnvironmentControllerCollection</c> precedent.
/// </para>
///
/// <para>Evidence + history: <c>docs/ISSUES.md</c> #251.</para>
/// </summary>
[CollectionDefinition(Name)]
public sealed class CameraDiagnosticsCollection
{
public const string Name = "Camera diagnostics globals";
}