test: replace streaming source freezes
This commit is contained in:
parent
5a33369074
commit
0ad2ee1cdf
6 changed files with 436 additions and 285 deletions
|
|
@ -1,7 +1,14 @@
|
|||
using System.Reflection;
|
||||
using AcDream.App.Composition;
|
||||
using AcDream.App.Rendering;
|
||||
using AcDream.App.Rendering.Wb;
|
||||
using AcDream.App.Streaming;
|
||||
using AcDream.App.Tests.Architecture;
|
||||
using AcDream.App.World;
|
||||
using AcDream.Core.Terrain;
|
||||
using AcDream.Core.World;
|
||||
using AcDream.Runtime;
|
||||
using AcDream.Runtime.Session;
|
||||
using DatReaderWriter.DBObjs;
|
||||
|
||||
namespace AcDream.App.Tests.Streaming;
|
||||
|
|
@ -252,179 +259,136 @@ public sealed class LandblockBuildOriginTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildFactoryAndRenderPublisher_UseCapturedOriginWithoutGameWindowFacade()
|
||||
public void ProductionCompositionOwnsPublishersWithoutGameWindowFacade()
|
||||
{
|
||||
string root = FindRepoRoot();
|
||||
string gameWindowSource = File.ReadAllText(Path.Combine(
|
||||
root,
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Rendering",
|
||||
"GameWindow.cs"));
|
||||
string livePresentationSource = File.ReadAllText(Path.Combine(
|
||||
root,
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Composition",
|
||||
"LivePresentationComposition.cs"));
|
||||
string buildSource = File.ReadAllText(Path.Combine(
|
||||
root,
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Streaming",
|
||||
"LandblockBuildFactory.cs"));
|
||||
string renderPublisherSource = File.ReadAllText(Path.Combine(
|
||||
root,
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Streaming",
|
||||
"LandblockRenderPublisher.cs"));
|
||||
string recenterSource = File.ReadAllText(Path.Combine(
|
||||
root,
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Streaming",
|
||||
"StreamingOriginRecenterCoordinator.cs"));
|
||||
Assert.Contains("request.Origin", buildSource, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_liveCenterX", buildSource, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_liveCenterY", buildSource, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
MethodInfo[] windowMethods = typeof(GameWindow).GetMethods(
|
||||
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
|
||||
string[] extractedMethodNames =
|
||||
[
|
||||
"BuildLandblockForStreaming",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"BuildSceneryEntitiesForStreaming",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"BuildInteriorEntitiesForStreaming",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"BuildPhysicsDatBundle",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"ApplyLoadedTerrain",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"PublishLandblockStaticLightingBeforeCollision",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
];
|
||||
Assert.DoesNotContain(
|
||||
"_landblockPhysicsPublisher!.RemoveLandblock",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
windowMethods,
|
||||
method => extractedMethodNames.Contains(method.Name, StringComparer.Ordinal));
|
||||
|
||||
FieldInfo[] windowFields = typeof(GameWindow).GetFields(
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
Assert.Single(
|
||||
windowFields,
|
||||
field => field.FieldType == typeof(LandblockPresentationPipeline));
|
||||
Assert.DoesNotContain(
|
||||
"_landblockRenderPublisher",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
windowFields,
|
||||
field => field.FieldType == typeof(LandblockRenderPublisher)
|
||||
|| field.FieldType == typeof(LandblockPhysicsPublisher)
|
||||
|| field.FieldType == typeof(LandblockStaticPresentationPublisher));
|
||||
|
||||
IReadOnlyList<CompiledCall> windowCalls =
|
||||
CompiledCallGraph.ReadDeclared(typeof(GameWindow));
|
||||
Assert.DoesNotContain(
|
||||
"_landblockPhysicsPublisher",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"_landblockStaticPresentationPublisher",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"_landblockPresentationPipeline",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"new LandblockRenderPublisher(",
|
||||
livePresentationSource,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"new LandblockPhysicsPublisher(",
|
||||
livePresentationSource,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"new LandblockStaticPresentationPublisher(",
|
||||
livePresentationSource,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("applyTerrain:", gameWindowSource, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("demoteNearLayer:", gameWindowSource, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("retirementCoordinator:", gameWindowSource, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"_liveWorldOrigin.Recenter(lbX, lbY)",
|
||||
gameWindowSource,
|
||||
StringComparison.Ordinal);
|
||||
int retirementBarrier = recenterSource.IndexOf(
|
||||
"IsOriginRecenterRetirementComplete()",
|
||||
StringComparison.Ordinal);
|
||||
int originCommit = recenterSource.IndexOf(
|
||||
"_origin.Recenter(",
|
||||
StringComparison.Ordinal);
|
||||
int destinationCommit = recenterSource.IndexOf(
|
||||
"_streaming.TryCommitOriginRecenter(",
|
||||
StringComparison.Ordinal);
|
||||
Assert.True(retirementBarrier >= 0);
|
||||
Assert.True(originCommit > retirementBarrier);
|
||||
Assert.True(destinationCommit > originCommit);
|
||||
Assert.Contains("ComputeOrigin(landblockId, build.Origin)", renderPublisherSource, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_liveCenterX", renderPublisherSource, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_liveCenterY", renderPublisherSource, StringComparison.Ordinal);
|
||||
windowCalls,
|
||||
call => call.Target.DeclaringType == typeof(LiveWorldOriginState)
|
||||
&& call.Target.Name == nameof(LiveWorldOriginState.Recenter));
|
||||
|
||||
MethodInfo compose = typeof(LivePresentationCompositionPhase).GetMethod(
|
||||
"CompletePresentation",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic)!;
|
||||
IReadOnlyList<CompiledCall> composeCalls = CompiledCallGraph.Read(compose);
|
||||
int renderPublisher = RequiredCallIndex(
|
||||
composeCalls,
|
||||
typeof(LandblockRenderPublisher),
|
||||
".ctor");
|
||||
int physicsPublisher = RequiredCallIndex(
|
||||
composeCalls,
|
||||
typeof(LandblockPhysicsPublisher),
|
||||
".ctor");
|
||||
int staticPublisher = RequiredCallIndex(
|
||||
composeCalls,
|
||||
typeof(LandblockStaticPresentationPublisher),
|
||||
".ctor");
|
||||
int pipeline = RequiredCallIndex(
|
||||
composeCalls,
|
||||
typeof(LandblockPresentationPipeline),
|
||||
".ctor");
|
||||
Assert.True(renderPublisher < physicsPublisher);
|
||||
Assert.True(physicsPublisher < staticPublisher);
|
||||
Assert.True(staticPublisher < pipeline);
|
||||
|
||||
// Captured-origin flow itself is behavioral: BuildFar exercises the
|
||||
// real LandblockBuildFactory and BeginPublication exercises the real
|
||||
// render publisher. This metadata check protects only production
|
||||
// ownership and composition, which those fixtures cannot observe.
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OriginRecenterWaitsForRetirementBeforeOriginAndDestinationCommits()
|
||||
{
|
||||
MethodInfo advance = typeof(StreamingOriginRecenterCoordinator).GetMethod(
|
||||
nameof(StreamingOriginRecenterCoordinator.Advance))!;
|
||||
IReadOnlyList<CompiledCall> calls = CompiledCallGraph.Read(advance);
|
||||
int retirement = RequiredCallIndex(
|
||||
calls,
|
||||
typeof(StreamingController),
|
||||
"IsOriginRecenterRetirementComplete");
|
||||
int origin = RequiredCallIndex(
|
||||
calls,
|
||||
typeof(LiveWorldOriginState),
|
||||
nameof(LiveWorldOriginState.Recenter));
|
||||
int destination = RequiredCallIndex(
|
||||
calls,
|
||||
typeof(StreamingController),
|
||||
"TryCommitOriginRecenter");
|
||||
|
||||
Assert.True(retirement < origin);
|
||||
Assert.True(origin < destination);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GameWindowShutdownKeepsStreamerAliveUntilSessionResetConverges()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Rendering",
|
||||
"GameWindowLifetime.cs"));
|
||||
int sessionStage = source.IndexOf(
|
||||
"new ResourceShutdownStage(\"host and session barriers\"",
|
||||
StringComparison.Ordinal);
|
||||
Assert.True(sessionStage >= 0);
|
||||
MethodInfo manifest = typeof(GameWindowShutdownManifest).GetMethod(
|
||||
nameof(GameWindowShutdownManifest.Create))!;
|
||||
IReadOnlyList<string> labels = CompiledCallGraph.ReadStringLiterals(manifest);
|
||||
AssertAppearsInOrder(
|
||||
labels,
|
||||
"host and session barriers",
|
||||
"game runtime session",
|
||||
"session dependents",
|
||||
"streamer");
|
||||
|
||||
int sessionOperation = source.IndexOf(
|
||||
"Hard(\"game runtime session\", ingress.Runtime.StopSession)",
|
||||
sessionStage,
|
||||
StringComparison.Ordinal);
|
||||
Assert.True(sessionOperation > sessionStage);
|
||||
|
||||
int dependentStage = source.IndexOf(
|
||||
"new ResourceShutdownStage(\"session dependents\"",
|
||||
sessionOperation,
|
||||
StringComparison.Ordinal);
|
||||
Assert.True(dependentStage > sessionOperation);
|
||||
|
||||
int streamerDispose = source.IndexOf(
|
||||
"Hard(\"streamer\", () => live.Streamer?.Dispose())",
|
||||
dependentStage,
|
||||
StringComparison.Ordinal);
|
||||
Assert.True(streamerDispose > dependentStage);
|
||||
|
||||
string runtime = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"src",
|
||||
"AcDream.Runtime",
|
||||
"GameRuntime.cs"));
|
||||
int helper = runtime.IndexOf(
|
||||
"public void StopSession()",
|
||||
StringComparison.Ordinal);
|
||||
Assert.True(helper >= 0);
|
||||
int sessionDispose = runtime.IndexOf(
|
||||
"Session.Dispose();",
|
||||
helper,
|
||||
StringComparison.Ordinal);
|
||||
Assert.True(sessionDispose > helper);
|
||||
|
||||
int disposalCompletionBarrier = runtime.IndexOf(
|
||||
"if (!Session.IsDisposalComplete)",
|
||||
sessionDispose,
|
||||
StringComparison.Ordinal);
|
||||
Assert.True(disposalCompletionBarrier > sessionDispose);
|
||||
IReadOnlyList<CompiledCall> references =
|
||||
CompiledCallGraph.ReadMethodReferences(manifest);
|
||||
int stopSession = RequiredCallIndex(
|
||||
references,
|
||||
typeof(GameRuntime),
|
||||
nameof(GameRuntime.StopSession));
|
||||
int streamerDispose = Enumerable.Range(stopSession + 1, references.Count - stopSession - 1)
|
||||
.FirstOrDefault(
|
||||
index => Calls(
|
||||
references[index].Target,
|
||||
typeof(LandblockStreamer),
|
||||
nameof(LandblockStreamer.Dispose)),
|
||||
-1);
|
||||
Assert.True(streamerDispose > stopSession, "Missing later streamer-disposal operation.");
|
||||
|
||||
MethodInfo runtimeStop = typeof(GameRuntime).GetMethod(nameof(GameRuntime.StopSession))!;
|
||||
IReadOnlyList<CompiledCall> runtimeCalls = CompiledCallGraph.Read(runtimeStop);
|
||||
int sessionDispose = RequiredCallIndex(
|
||||
runtimeCalls,
|
||||
typeof(LiveSessionController),
|
||||
nameof(LiveSessionController.Dispose));
|
||||
int completionBarrier = RequiredCallIndex(
|
||||
runtimeCalls,
|
||||
typeof(LiveSessionController),
|
||||
"get_IsDisposalComplete");
|
||||
Assert.True(sessionDispose < completionBarrier);
|
||||
Assert.Contains(
|
||||
"The Runtime session shutdown was deferred by a re-entrant callback.",
|
||||
runtime[disposalCompletionBarrier..],
|
||||
StringComparison.Ordinal);
|
||||
CompiledCallGraph.ReadStringLiterals(runtimeStop));
|
||||
}
|
||||
|
||||
private static LandblockBuild EmptyBuild(uint landblockId, LandblockBuildOrigin origin) =>
|
||||
|
|
@ -458,16 +422,37 @@ public sealed class LandblockBuildOriginTests
|
|||
return results;
|
||||
}
|
||||
|
||||
private static string FindRepoRoot()
|
||||
private static int RequiredCallIndex(
|
||||
IReadOnlyList<CompiledCall> calls,
|
||||
Type declaringType,
|
||||
string methodName)
|
||||
{
|
||||
string? dir = AppContext.BaseDirectory;
|
||||
while (dir is not null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(dir, "AcDream.slnx")))
|
||||
return dir;
|
||||
dir = Directory.GetParent(dir)?.FullName;
|
||||
}
|
||||
int index = CompiledCallGraph.IndexOf(calls, declaringType, methodName);
|
||||
Assert.True(index >= 0, $"Missing compiled call: {declaringType.Name}.{methodName}");
|
||||
return index;
|
||||
}
|
||||
|
||||
throw new DirectoryNotFoundException("Could not locate AcDream.slnx.");
|
||||
private static bool Calls(
|
||||
MethodBase method,
|
||||
Type declaringType,
|
||||
string methodName) =>
|
||||
method.GetMethodBody() is not null
|
||||
&& CompiledCallGraph.IndexOf(
|
||||
CompiledCallGraph.Read(method),
|
||||
declaringType,
|
||||
methodName) >= 0;
|
||||
|
||||
private static void AssertAppearsInOrder(
|
||||
IReadOnlyList<string> values,
|
||||
params string[] expected)
|
||||
{
|
||||
int cursor = -1;
|
||||
foreach (string value in expected)
|
||||
{
|
||||
int next = Enumerable.Range(cursor + 1, values.Count - cursor - 1)
|
||||
.FirstOrDefault(index => values[index] == value, -1);
|
||||
Assert.True(next > cursor, $"Missing or out-of-order metadata string: {value}");
|
||||
cursor = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
using System.Collections.Immutable;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using AcDream.App.Rendering;
|
||||
using AcDream.App.Streaming;
|
||||
using AcDream.App.Tests.Architecture;
|
||||
using AcDream.Core.Net;
|
||||
using AcDream.Core.Net.Messages;
|
||||
using AcDream.Core.Physics;
|
||||
|
|
@ -1047,34 +1049,63 @@ public sealed class LandblockPhysicsPublisherTests
|
|||
[Fact]
|
||||
public void GameWindow_HasNoLandblockPhysicsPublicationBodies()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Rendering",
|
||||
"GameWindow.cs"));
|
||||
IReadOnlyList<CompiledCall> windowCalls =
|
||||
CompiledCallGraph.ReadDeclared(typeof(GameWindow));
|
||||
AssertNoCall(windowCalls, typeof(PhysicsDataCache), nameof(PhysicsDataCache.CacheCellStruct));
|
||||
AssertNoCall(windowCalls, typeof(PhysicsDataCache), nameof(PhysicsDataCache.CacheBuilding));
|
||||
AssertNoCall(
|
||||
windowCalls,
|
||||
typeof(ShadowShapeBuilder),
|
||||
nameof(ShadowShapeBuilder.FromLandblockBspParts));
|
||||
AssertNoCall(
|
||||
windowCalls,
|
||||
typeof(ShadowObjectRegistry),
|
||||
nameof(ShadowObjectRegistry.RefloodLandblock));
|
||||
AssertNoCall(
|
||||
windowCalls,
|
||||
typeof(PhysicsEngine),
|
||||
"DemoteLandblockToTerrain");
|
||||
AssertNoCall(windowCalls, typeof(PhysicsEngine), "RemoveLandblock");
|
||||
|
||||
Assert.DoesNotContain("_physicsDataCache.CacheCellStruct", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_physicsDataCache.CacheBuilding", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("ShadowShapeBuilder.FromLandblockBspParts", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("ShadowObjects.RefloodLandblock", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_physicsEngine.DemoteLandblockToTerrain", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_physicsEngine.RemoveLandblock", source, StringComparison.Ordinal);
|
||||
|
||||
string publisherSource = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Streaming",
|
||||
"LandblockPhysicsPublisher.cs"));
|
||||
Assert.DoesNotContain("_physicsDataCache.RemoveCellsForLandblock", publisherSource, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_physicsDataCache.RemoveBuildingsForLandblock", publisherSource, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_physicsEngine.ShadowObjects.Reflood", publisherSource, StringComparison.Ordinal);
|
||||
Assert.Contains("CommitCollisionGeneration(", publisherSource, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"RestartCollisionRetainedOwnerCapture(",
|
||||
publisherSource,
|
||||
StringComparison.Ordinal);
|
||||
IReadOnlyList<CompiledCall> publisherCalls =
|
||||
CompiledCallGraph.ReadDeclared(typeof(LandblockPhysicsPublisher));
|
||||
MethodInfo advance = typeof(LandblockPhysicsPublisher).GetMethod(
|
||||
"AdvanceBeginOne",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic)!;
|
||||
IReadOnlyList<CompiledCall> advanceCalls = CompiledCallGraph.Read(advance);
|
||||
int stagedCache = CompiledCallGraph.IndexOf(
|
||||
advanceCalls,
|
||||
typeof(LandblockPhysicsPublication),
|
||||
"get_StagingCache");
|
||||
int removeCells = CompiledCallGraph.IndexOf(
|
||||
advanceCalls,
|
||||
typeof(PhysicsDataCache),
|
||||
nameof(PhysicsDataCache.RemoveCellsForLandblock));
|
||||
int removeBuildings = CompiledCallGraph.IndexOf(
|
||||
advanceCalls,
|
||||
typeof(PhysicsDataCache),
|
||||
nameof(PhysicsDataCache.RemoveBuildingsForLandblock));
|
||||
int secondStagedCache = CompiledCallGraph.IndexOf(
|
||||
advanceCalls,
|
||||
typeof(LandblockPhysicsPublication),
|
||||
"get_StagingCache",
|
||||
removeCells + 1);
|
||||
Assert.True(stagedCache >= 0);
|
||||
Assert.True(stagedCache < removeCells);
|
||||
Assert.True(removeCells < secondStagedCache);
|
||||
Assert.True(secondStagedCache < removeBuildings);
|
||||
AssertNoCall(
|
||||
publisherCalls,
|
||||
typeof(ShadowObjectRegistry),
|
||||
nameof(ShadowObjectRegistry.RefloodLandblock));
|
||||
Assert.Contains(
|
||||
publisherCalls,
|
||||
call => call.Target.DeclaringType == typeof(RuntimePhysicsState)
|
||||
&& call.Target.Name == "CommitCollisionGeneration");
|
||||
AssertNoCall(
|
||||
publisherCalls,
|
||||
typeof(RuntimePhysicsState),
|
||||
"RestartCollisionRetainedOwnerCapture");
|
||||
}
|
||||
|
||||
private static void Publish(
|
||||
|
|
@ -1500,15 +1531,14 @@ public sealed class LandblockPhysicsPublisherTests
|
|||
Height = new byte[81],
|
||||
};
|
||||
|
||||
private static string FindRepoRoot()
|
||||
private static void AssertNoCall(
|
||||
IReadOnlyList<CompiledCall> calls,
|
||||
Type declaringType,
|
||||
string methodName)
|
||||
{
|
||||
string? directory = AppContext.BaseDirectory;
|
||||
while (directory is not null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(directory, "AcDream.slnx")))
|
||||
return directory;
|
||||
directory = Directory.GetParent(directory)?.FullName;
|
||||
}
|
||||
throw new DirectoryNotFoundException("Could not locate repository root.");
|
||||
Assert.DoesNotContain(
|
||||
calls,
|
||||
call => call.Target.DeclaringType == declaringType
|
||||
&& call.Target.Name == methodName);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using System.Collections.Immutable;
|
|||
using AcDream.App.Rendering;
|
||||
using AcDream.App.Rendering.Wb;
|
||||
using AcDream.App.Streaming;
|
||||
using AcDream.App.Tests.Architecture;
|
||||
using AcDream.Core.Terrain;
|
||||
using AcDream.Core.World;
|
||||
using DatReaderWriter.DBObjs;
|
||||
|
|
@ -306,18 +307,27 @@ public sealed class LandblockRenderPublisherTests
|
|||
[Fact]
|
||||
public void GameWindow_HasNoDirectRenderPublicationBodies()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Rendering",
|
||||
"GameWindow.cs"));
|
||||
IReadOnlyList<CompiledCall> calls =
|
||||
CompiledCallGraph.ReadDeclared(typeof(GameWindow));
|
||||
Assert.DoesNotContain(
|
||||
calls,
|
||||
call => call.Target.DeclaringType == typeof(TerrainModernRenderer)
|
||||
&& call.Target.Name == nameof(TerrainModernRenderer.AddLandblockWithMesh));
|
||||
Assert.DoesNotContain(
|
||||
calls,
|
||||
call => call.Target.DeclaringType == typeof(CellVisibility)
|
||||
&& call.Target.Name == nameof(CellVisibility.CommitLandblock));
|
||||
Assert.DoesNotContain(
|
||||
calls,
|
||||
call => call.Target.DeclaringType == typeof(EnvCellRenderer)
|
||||
&& call.Target.Name == nameof(EnvCellRenderer.CommitLandblock));
|
||||
|
||||
Assert.DoesNotContain("_terrain.AddLandblockWithMesh", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_cellVisibility.CommitLandblock", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_buildingRegistries", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("_envCellRenderer?.CommitLandblock", source, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("EnsureEnvCellMeshesAfterPin", source, StringComparison.Ordinal);
|
||||
Assert.Null(typeof(GameWindow).GetMethod(
|
||||
"EnsureEnvCellMeshesAfterPin",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic));
|
||||
Assert.DoesNotContain(
|
||||
typeof(GameWindow).GetFields(BindingFlags.Instance | BindingFlags.NonPublic),
|
||||
field => field.Name == "_buildingRegistries");
|
||||
}
|
||||
|
||||
private static LandblockRenderPublisher Publisher(
|
||||
|
|
@ -406,18 +416,6 @@ public sealed class LandblockRenderPublisherTests
|
|||
private static LandblockMeshData EmptyMesh() =>
|
||||
new(Array.Empty<TerrainVertex>(), Array.Empty<uint>());
|
||||
|
||||
private static string FindRepoRoot()
|
||||
{
|
||||
string? directory = AppContext.BaseDirectory;
|
||||
while (directory is not null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(directory, "AcDream.slnx")))
|
||||
return directory;
|
||||
directory = Directory.GetParent(directory)?.FullName;
|
||||
}
|
||||
throw new DirectoryNotFoundException("Could not locate repository root.");
|
||||
}
|
||||
|
||||
private sealed class RecordingEnvCellPublisher :
|
||||
IEnvCellLandblockPublisher
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue