feat(render #53): DEBUG cross-check guards against the prior Tier 1 bug class
Adds EntityClassificationCache.DebugCrossCheck(entityId, liveBatches) that asserts cached state matches a live re-classification. Wires a simpler predicate assert into WbDrawDispatcher's cache-hit branch (asserts isAnimated == false on cache hit). Tests #13a and #13b cover the batch-count mismatch and clean-match cases via a custom TraceListener that captures Debug.Assert calls. Zero cost in Release. In DEBUG, the assert fires immediately if a future regression mutates static-entity state outside the audit's known write sites — the same failure mode that bit the prior Tier 1 attempt. Phase 4 complete. Cache + invalidation + safety net all in place. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
489174f21c
commit
f16604b60b
3 changed files with 149 additions and 0 deletions
|
|
@ -193,6 +193,82 @@ public class EntityClassificationCacheTests
|
|||
Assert.Equal(0xCCu, entry.Batches[0].BindlessTextureHandle);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[Fact]
|
||||
public void DebugCrossCheck_BatchCountMismatch_FiresAssert()
|
||||
{
|
||||
var cache = new EntityClassificationCache();
|
||||
cache.Populate(100, 0u, new[]
|
||||
{
|
||||
MakeCachedBatch(1, 0, 6, 0xAA),
|
||||
MakeCachedBatch(1, 6, 6, 0xBB),
|
||||
});
|
||||
|
||||
// Synthetic "live" with fewer batches → should fire Debug.Assert.
|
||||
var liveBatches = new[] { MakeCachedBatch(1, 0, 6, 0xAA) };
|
||||
|
||||
// Capture Debug.Assert via a custom TraceListener.
|
||||
var originalListeners = new System.Diagnostics.TraceListener[System.Diagnostics.Trace.Listeners.Count];
|
||||
System.Diagnostics.Trace.Listeners.CopyTo(originalListeners, 0);
|
||||
System.Diagnostics.Trace.Listeners.Clear();
|
||||
var asserts = new List<string>();
|
||||
System.Diagnostics.Trace.Listeners.Add(new CaptureListener(asserts));
|
||||
|
||||
try
|
||||
{
|
||||
cache.DebugCrossCheck(100, liveBatches);
|
||||
}
|
||||
finally
|
||||
{
|
||||
System.Diagnostics.Trace.Listeners.Clear();
|
||||
foreach (var l in originalListeners) System.Diagnostics.Trace.Listeners.Add(l);
|
||||
}
|
||||
|
||||
Assert.NotEmpty(asserts);
|
||||
string joined = string.Join(" ", asserts);
|
||||
Assert.Contains("batch count mismatch", joined);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DebugCrossCheck_RestPoseMatch_NoAssert()
|
||||
{
|
||||
var cache = new EntityClassificationCache();
|
||||
var batches = new[] { MakeCachedBatch(1, 0, 6, 0xAA) };
|
||||
cache.Populate(100, 0u, batches);
|
||||
|
||||
var originalListeners = new System.Diagnostics.TraceListener[System.Diagnostics.Trace.Listeners.Count];
|
||||
System.Diagnostics.Trace.Listeners.CopyTo(originalListeners, 0);
|
||||
System.Diagnostics.Trace.Listeners.Clear();
|
||||
var asserts = new List<string>();
|
||||
System.Diagnostics.Trace.Listeners.Add(new CaptureListener(asserts));
|
||||
|
||||
try
|
||||
{
|
||||
cache.DebugCrossCheck(100, batches);
|
||||
}
|
||||
finally
|
||||
{
|
||||
System.Diagnostics.Trace.Listeners.Clear();
|
||||
foreach (var l in originalListeners) System.Diagnostics.Trace.Listeners.Add(l);
|
||||
}
|
||||
|
||||
Assert.Empty(asserts);
|
||||
}
|
||||
|
||||
private sealed class CaptureListener : System.Diagnostics.TraceListener
|
||||
{
|
||||
private readonly List<string> _captured;
|
||||
public CaptureListener(List<string> captured) { _captured = captured; }
|
||||
public override void Write(string? message) { if (message != null) _captured.Add(message); }
|
||||
public override void WriteLine(string? message) { if (message != null) _captured.Add(message); }
|
||||
public override void Fail(string? message, string? detailMessage)
|
||||
{
|
||||
_captured.Add($"{message}: {detailMessage}");
|
||||
}
|
||||
public override void Fail(string? message) { if (message != null) _captured.Add(message); }
|
||||
}
|
||||
#endif
|
||||
|
||||
private static CachedBatch MakeCachedBatch(
|
||||
uint ibo, uint firstIndex, int indexCount, ulong texHandle)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue