refactor(app): compose interaction and retained UI startup
This commit is contained in:
parent
f663b04a54
commit
aa6ffa5176
15 changed files with 2157 additions and 467 deletions
|
|
@ -0,0 +1,332 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using AcDream.App.Combat;
|
||||
using AcDream.App.Composition;
|
||||
using AcDream.App.Diagnostics;
|
||||
using AcDream.App.Rendering;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.App.World;
|
||||
|
||||
namespace AcDream.App.Tests.Composition;
|
||||
|
||||
public sealed class InteractionRetainedUiCompositionTests
|
||||
{
|
||||
private static readonly InteractionRetainedUiCompositionPoint[] UiPoints =
|
||||
[
|
||||
InteractionRetainedUiCompositionPoint.UiHostAcquired,
|
||||
InteractionRetainedUiCompositionPoint.InputCaptureBound,
|
||||
InteractionRetainedUiCompositionPoint.CursorAssetsCreated,
|
||||
InteractionRetainedUiCompositionPoint.CharacterSheetCreated,
|
||||
InteractionRetainedUiCompositionPoint.MagicRuntimeCreated,
|
||||
InteractionRetainedUiCompositionPoint.MouseInputWired,
|
||||
InteractionRetainedUiCompositionPoint.KeyboardInputWired,
|
||||
InteractionRetainedUiCompositionPoint.UiAssetsCreated,
|
||||
InteractionRetainedUiCompositionPoint.UiProbeCreated,
|
||||
InteractionRetainedUiCompositionPoint.UiRuntimeMounted,
|
||||
InteractionRetainedUiCompositionPoint.InventoryContainerBound,
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void EnabledUiPublishesOneExactResultAfterFrozenConstructionOrder()
|
||||
{
|
||||
var fixture = new Fixture(retailUi: true);
|
||||
|
||||
InteractionRetainedUiResult result = fixture.Compose();
|
||||
|
||||
Assert.Same(result, fixture.Publication.Result);
|
||||
Assert.Equal(
|
||||
[
|
||||
InteractionRetainedUiCompositionPoint.LateBindingsCreated,
|
||||
InteractionRetainedUiCompositionPoint.CombatAttackCreated,
|
||||
InteractionRetainedUiCompositionPoint.CombatTargetCreated,
|
||||
InteractionRetainedUiCompositionPoint.ExternalContainerLifecycleCreated,
|
||||
InteractionRetainedUiCompositionPoint.ItemInteractionCreated,
|
||||
.. UiPoints,
|
||||
InteractionRetainedUiCompositionPoint.ResultPublished,
|
||||
], fixture.Points);
|
||||
Assert.NotNull(result.RetainedUi);
|
||||
Assert.Empty(fixture.Factory.Releases);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisabledUiAcquiresNoRetainedFrontendResource()
|
||||
{
|
||||
var fixture = new Fixture(retailUi: false);
|
||||
|
||||
InteractionRetainedUiResult result = fixture.Compose();
|
||||
|
||||
Assert.Null(result.RetainedUi);
|
||||
Assert.Equal(
|
||||
[
|
||||
InteractionRetainedUiCompositionPoint.LateBindingsCreated,
|
||||
InteractionRetainedUiCompositionPoint.CombatAttackCreated,
|
||||
InteractionRetainedUiCompositionPoint.CombatTargetCreated,
|
||||
InteractionRetainedUiCompositionPoint.ExternalContainerLifecycleCreated,
|
||||
InteractionRetainedUiCompositionPoint.ItemInteractionCreated,
|
||||
InteractionRetainedUiCompositionPoint.RetainedUiDisabled,
|
||||
InteractionRetainedUiCompositionPoint.ResultPublished,
|
||||
], fixture.Points);
|
||||
Assert.Equal(0, fixture.Factory.RetainedUiCalls);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(EnabledFailurePoints))]
|
||||
public void FaultAtEveryEnabledBoundaryStopsSuffixAndRollsBackUnpublishedPrefix(
|
||||
int pointValue)
|
||||
{
|
||||
var point = (InteractionRetainedUiCompositionPoint)pointValue;
|
||||
var fixture = new Fixture(retailUi: true, failurePoint: point);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(fixture.Compose);
|
||||
|
||||
Assert.Equal(point, fixture.Points[^1]);
|
||||
if (point == InteractionRetainedUiCompositionPoint.ResultPublished)
|
||||
{
|
||||
Assert.Empty(fixture.Factory.Releases);
|
||||
Assert.NotNull(fixture.Publication.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Null(fixture.Publication.Result);
|
||||
Assert.Equal(ExpectedRollback(point), fixture.Factory.Releases);
|
||||
}
|
||||
}
|
||||
|
||||
public static TheoryData<int> EnabledFailurePoints()
|
||||
{
|
||||
var data = new TheoryData<int>();
|
||||
foreach (InteractionRetainedUiCompositionPoint point in
|
||||
Enum.GetValues<InteractionRetainedUiCompositionPoint>())
|
||||
{
|
||||
if (point != InteractionRetainedUiCompositionPoint.RetainedUiDisabled)
|
||||
data.Add((int)point);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private static string[] ExpectedRollback(
|
||||
InteractionRetainedUiCompositionPoint point)
|
||||
{
|
||||
var acquired = new List<string> { "late bindings" };
|
||||
if (point >= InteractionRetainedUiCompositionPoint.CombatAttackCreated)
|
||||
acquired.Add("combat attack");
|
||||
if (point >= InteractionRetainedUiCompositionPoint.CombatTargetCreated)
|
||||
acquired.Add("combat target");
|
||||
if (point >= InteractionRetainedUiCompositionPoint.ExternalContainerLifecycleCreated)
|
||||
acquired.Add("external container");
|
||||
if (point >= InteractionRetainedUiCompositionPoint.ItemInteractionCreated)
|
||||
acquired.Add("item interaction");
|
||||
if (point >= InteractionRetainedUiCompositionPoint.UiHostAcquired)
|
||||
acquired.Add("retained UI lease");
|
||||
acquired.Reverse();
|
||||
return acquired.ToArray();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PublicationFailureRollsBackCompleteUnpublishedPrefix()
|
||||
{
|
||||
var fixture = new Fixture(retailUi: true, publicationFailure: true);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(fixture.Compose);
|
||||
|
||||
Assert.Equal(
|
||||
[
|
||||
"retained UI lease",
|
||||
"item interaction",
|
||||
"external container",
|
||||
"combat target",
|
||||
"combat attack",
|
||||
"late bindings",
|
||||
], fixture.Factory.Releases);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GameWindowUsesPhaseAndContainsNoRetainedUiConstructionBody()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"src",
|
||||
"AcDream.App",
|
||||
"Rendering",
|
||||
"GameWindow.cs"));
|
||||
|
||||
Assert.Contains("new InteractionRetainedUiCompositionPhase(", source);
|
||||
Assert.DoesNotContain("new AcDream.App.UI.ItemInteractionController(", source);
|
||||
Assert.DoesNotContain("_retailUiLease.AcquireHost(", source);
|
||||
Assert.DoesNotContain("RetailUiRuntime.CreateUninitialized(", source);
|
||||
Assert.DoesNotContain("private void UseItemByGuid(", source);
|
||||
Assert.DoesNotContain("private uint? PickWorldGuidAtCursor(", source);
|
||||
}
|
||||
|
||||
private sealed class Fixture
|
||||
{
|
||||
private readonly InteractionRetainedUiCompositionPoint? _failurePoint;
|
||||
|
||||
public Fixture(
|
||||
bool retailUi,
|
||||
InteractionRetainedUiCompositionPoint? failurePoint = null,
|
||||
bool publicationFailure = false)
|
||||
{
|
||||
_failurePoint = failurePoint;
|
||||
Factory = new FakeFactory();
|
||||
Publication = new Publication(publicationFailure);
|
||||
RuntimeOptions options = RuntimeOptions.Parse("dat", static _ => null)
|
||||
with { RetailUi = retailUi };
|
||||
Dependencies = new InteractionRetainedUiDependencies(
|
||||
Options: options,
|
||||
Gl: null!,
|
||||
Window: null!,
|
||||
Input: null!,
|
||||
ShadersDirectory: "shaders",
|
||||
Dats: null!,
|
||||
DatLock: new object(),
|
||||
TextureCache: null!,
|
||||
DebugFont: null,
|
||||
HostQuiescence: null!,
|
||||
RetainedInputCapture: null!,
|
||||
InputDispatcher: null,
|
||||
Settings: null!,
|
||||
Combat: null!,
|
||||
CombatAttackOperations: null!,
|
||||
Selection: null!,
|
||||
ExternalContainers: null!,
|
||||
Objects: null!,
|
||||
MagicCatalog: null!,
|
||||
Spellbook: null!,
|
||||
Chat: null!,
|
||||
LocalPlayer: null!,
|
||||
ItemMana: null!,
|
||||
StackSplitQuantity: null!,
|
||||
UiRegistry: null,
|
||||
CombatModeCommands: null!,
|
||||
PlayerIdentity: null!,
|
||||
PlayerController: null!,
|
||||
PlayerMode: null!,
|
||||
CharacterOptions: null!,
|
||||
Shortcuts: null!,
|
||||
SelectionCameraFactory: static _ => Stub<SelectionCameraSource>(),
|
||||
FrameDiagnostics: new DeferredRenderFrameDiagnosticsSource(),
|
||||
ExistingVitals: null,
|
||||
Toast: null,
|
||||
ClientTime: static () => 0d,
|
||||
Log: static _ => { });
|
||||
}
|
||||
|
||||
public InteractionRetainedUiDependencies Dependencies { get; }
|
||||
public FakeFactory Factory { get; }
|
||||
public Publication Publication { get; }
|
||||
public List<InteractionRetainedUiCompositionPoint> Points { get; } = [];
|
||||
|
||||
public InteractionRetainedUiResult Compose() =>
|
||||
new InteractionRetainedUiCompositionPhase(
|
||||
Dependencies,
|
||||
new RetailUiRuntimeLease(),
|
||||
Publication,
|
||||
Factory,
|
||||
point =>
|
||||
{
|
||||
Points.Add(point);
|
||||
if (_failurePoint == point)
|
||||
throw new InvalidOperationException($"fault at {point}");
|
||||
}).Compose();
|
||||
}
|
||||
|
||||
private sealed class FakeFactory : IInteractionRetainedUiCompositionFactory
|
||||
{
|
||||
private readonly Dictionary<object, string> _names =
|
||||
new(ReferenceEqualityComparer.Instance);
|
||||
|
||||
public List<string> Releases { get; } = [];
|
||||
public int RetainedUiCalls { get; private set; }
|
||||
|
||||
public CombatAttackController CreateCombatAttack(
|
||||
InteractionRetainedUiDependencies dependencies) =>
|
||||
Resource<CombatAttackController>("combat attack");
|
||||
|
||||
public CombatTargetController CreateCombatTarget(
|
||||
InteractionRetainedUiDependencies dependencies,
|
||||
DeferredSelectionUiAuthority selection) =>
|
||||
Resource<CombatTargetController>("combat target");
|
||||
|
||||
public ExternalContainerLifecycleController CreateExternalContainerLifecycle(
|
||||
InteractionRetainedUiDependencies dependencies,
|
||||
DeferredLiveSessionUiAuthority session) =>
|
||||
Resource<ExternalContainerLifecycleController>("external container");
|
||||
|
||||
public ItemInteractionController CreateItemInteraction(
|
||||
InteractionRetainedUiDependencies dependencies,
|
||||
InteractionUiLateBindings lateBindings) =>
|
||||
Resource<ItemInteractionController>("item interaction");
|
||||
|
||||
public RetainedUiComposition CreateRetainedUi(
|
||||
InteractionRetainedUiDependencies dependencies,
|
||||
InteractionUiLateBindings lateBindings,
|
||||
RetailUiRuntimeLease lease,
|
||||
CombatAttackController combatAttack,
|
||||
ItemInteractionController itemInteraction,
|
||||
Action<InteractionRetainedUiCompositionPoint> checkpoint)
|
||||
{
|
||||
RetainedUiCalls++;
|
||||
_names.Add(lease, "retained UI lease");
|
||||
foreach (InteractionRetainedUiCompositionPoint point in UiPoints)
|
||||
checkpoint(point);
|
||||
return new RetainedUiComposition(
|
||||
Stub<UiHost>(),
|
||||
Stub<RetailUiRuntime>(),
|
||||
Stub<AcDream.UI.Abstractions.Panels.Vitals.VitalsVM>(),
|
||||
Stub<AcDream.UI.Abstractions.Panels.Chat.ChatVM>(),
|
||||
Stub<CharacterSheetProvider>(),
|
||||
Stub<AcDream.App.Spells.MagicRuntime>(),
|
||||
null);
|
||||
}
|
||||
|
||||
public void Release(IDisposable resource)
|
||||
{
|
||||
string name = _names.TryGetValue(resource, out string? found)
|
||||
? found
|
||||
: resource switch
|
||||
{
|
||||
InteractionUiLateBindings => "late bindings",
|
||||
RetailUiRuntimeLease => "retained UI lease",
|
||||
_ => throw new InvalidOperationException(
|
||||
$"Unknown test resource {resource.GetType().Name}"),
|
||||
};
|
||||
Releases.Add(name);
|
||||
}
|
||||
|
||||
private T Resource<T>(string name) where T : class
|
||||
{
|
||||
T value = Stub<T>();
|
||||
_names.Add(value, name);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class Publication(bool fail)
|
||||
: IGameWindowInteractionRetainedUiPublication
|
||||
{
|
||||
public InteractionRetainedUiResult? Result { get; private set; }
|
||||
|
||||
public void PublishInteractionRetainedUi(InteractionRetainedUiResult result)
|
||||
{
|
||||
if (fail)
|
||||
throw new InvalidOperationException("publication failed");
|
||||
Result = result;
|
||||
}
|
||||
}
|
||||
|
||||
private static T Stub<T>() where T : class =>
|
||||
(T)RuntimeHelpers.GetUninitializedObject(typeof(T));
|
||||
|
||||
private static string FindRepoRoot()
|
||||
{
|
||||
DirectoryInfo? directory = new(AppContext.BaseDirectory);
|
||||
while (directory is not null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(directory.FullName, "AcDream.slnx")))
|
||||
return directory.FullName;
|
||||
directory = directory.Parent;
|
||||
}
|
||||
throw new DirectoryNotFoundException("Could not find AcDream.slnx.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using AcDream.App.Composition;
|
||||
using AcDream.App.Input;
|
||||
using AcDream.App.Interaction;
|
||||
using AcDream.App.Net;
|
||||
using AcDream.App.Rendering;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.Core.Net;
|
||||
using AcDream.Core.World;
|
||||
using AcDream.UI.Abstractions;
|
||||
|
||||
namespace AcDream.App.Tests.Composition;
|
||||
|
||||
public sealed class InteractionUiRuntimeSourcesTests
|
||||
{
|
||||
[Fact]
|
||||
public void SessionAuthorityDefaultsBindUnbindRebindAndDeactivateExactly()
|
||||
{
|
||||
var source = new DeferredLiveSessionUiAuthority();
|
||||
var first = new SessionTarget(true);
|
||||
var second = new SessionTarget(false);
|
||||
|
||||
Assert.False(source.IsInWorld);
|
||||
Assert.Same(NullCommandBus.Instance, source.Commands);
|
||||
|
||||
IDisposable stale = source.Bind(first);
|
||||
Assert.True(source.IsInWorld);
|
||||
Assert.Same(first.Commands, source.Commands);
|
||||
Assert.Throws<InvalidOperationException>(() => source.Bind(second));
|
||||
|
||||
stale.Dispose();
|
||||
IDisposable current = source.Bind(second);
|
||||
stale.Dispose();
|
||||
Assert.False(source.IsInWorld);
|
||||
Assert.Same(second.Commands, source.Commands);
|
||||
|
||||
source.Deactivate();
|
||||
current.Dispose();
|
||||
Assert.Same(NullCommandBus.Instance, source.Commands);
|
||||
Assert.Throws<ObjectDisposedException>(() => source.Bind(first));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectionAuthorityUsesRetailSafeDefaultsAndExactBindingLifetime()
|
||||
{
|
||||
var source = new DeferredSelectionUiAuthority();
|
||||
var query = new SelectionQuery();
|
||||
SelectionInteractionController interactions =
|
||||
Stub<SelectionInteractionController>();
|
||||
|
||||
Assert.True(source.IsWithinExternalContainerUseRange(1u));
|
||||
Assert.False(source.ShouldShowHealth(1u));
|
||||
Assert.Null(source.ResolveVividTargetInfo(1u));
|
||||
|
||||
IDisposable binding = source.Bind(query, interactions);
|
||||
Assert.False(source.IsWithinExternalContainerUseRange(1u));
|
||||
Assert.True(source.ShouldShowHealth(1u));
|
||||
Assert.Equal(3f, source.ResolveVividTargetInfo(1u)?.SelectionSphereRadius);
|
||||
Assert.Throws<InvalidOperationException>(() => source.Bind(query, interactions));
|
||||
|
||||
binding.Dispose();
|
||||
Assert.True(source.IsWithinExternalContainerUseRange(1u));
|
||||
source.Deactivate();
|
||||
Assert.Throws<ObjectDisposedException>(() => source.Bind(query, interactions));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RadarNeverCachesAnUnboundBootstrapSnapshot()
|
||||
{
|
||||
var source = new DeferredRadarSnapshotSource();
|
||||
Assert.Same(UiRadarSnapshot.Empty, source.Snapshot());
|
||||
|
||||
var provider = new RadarSnapshotProvider(
|
||||
new AcDream.Core.Items.ClientObjectTable(),
|
||||
static () => new Dictionary<uint, WorldEntity>(),
|
||||
static () => new Dictionary<uint, WorldSession.EntitySpawn>(),
|
||||
static () => 0u,
|
||||
static () => 0f,
|
||||
static () => 0u,
|
||||
static () => null,
|
||||
static () => false,
|
||||
static () => true);
|
||||
IDisposable binding = source.Bind(provider);
|
||||
|
||||
Assert.True(source.Snapshot().UiLocked);
|
||||
binding.Dispose();
|
||||
Assert.False(source.Snapshot().UiLocked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AutomationProxyIsInertUntilExactRuntimeBinds()
|
||||
{
|
||||
var source = new DeferredWorldLifecycleAutomationRuntime();
|
||||
Assert.False(source.TryWriteCheckpoint("early", out string earlyError));
|
||||
Assert.Contains("not bound", earlyError);
|
||||
|
||||
var target = new AutomationRuntime();
|
||||
IDisposable binding = source.Bind(target);
|
||||
Assert.True(source.IsWorldReady);
|
||||
Assert.True(source.TryWriteCheckpoint("ready", out _));
|
||||
Assert.Equal("ready", target.LastCheckpoint);
|
||||
|
||||
binding.Dispose();
|
||||
Assert.False(source.IsWorldReady);
|
||||
source.Deactivate();
|
||||
Assert.Throws<ObjectDisposedException>(() => source.Bind(target));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExpectedOwnerBindingReleasesOnce()
|
||||
{
|
||||
object target = new();
|
||||
int releases = 0;
|
||||
var binding = new ExpectedOwnerBinding<object>(target, value =>
|
||||
{
|
||||
Assert.Same(target, value);
|
||||
releases++;
|
||||
});
|
||||
|
||||
binding.Dispose();
|
||||
binding.Dispose();
|
||||
|
||||
Assert.Equal(1, releases);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RetainedInputCaptureBindingCannotClearAReplacement()
|
||||
{
|
||||
var slot = new RetainedUiInputCaptureSlot();
|
||||
var first = new UiRoot();
|
||||
var second = new UiRoot();
|
||||
|
||||
IDisposable stale = slot.Bind(first);
|
||||
Assert.Same(first, slot.Root);
|
||||
Assert.Throws<InvalidOperationException>(() => slot.Bind(second));
|
||||
stale.Dispose();
|
||||
IDisposable current = slot.Bind(second);
|
||||
stale.Dispose();
|
||||
Assert.Same(second, slot.Root);
|
||||
current.Dispose();
|
||||
Assert.Null(slot.Root);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LateBindingCleanupRetriesOnlyTheFailedSuffix()
|
||||
{
|
||||
var bindings = new InteractionUiLateBindings();
|
||||
var first = new RetryBinding(failures: 0);
|
||||
var second = new RetryBinding(failures: 1);
|
||||
bindings.AdoptLateOwnerBinding("first", first);
|
||||
bindings.AdoptLateOwnerBinding("second", second);
|
||||
|
||||
Assert.Throws<AggregateException>(bindings.Dispose);
|
||||
Assert.Equal(1, first.Calls);
|
||||
Assert.Equal(1, second.Calls);
|
||||
|
||||
bindings.Dispose();
|
||||
Assert.Equal(1, first.Calls);
|
||||
Assert.Equal(2, second.Calls);
|
||||
Assert.Throws<ObjectDisposedException>(() =>
|
||||
bindings.AdoptLateOwnerBinding("late", new RetryBinding(0)));
|
||||
}
|
||||
|
||||
private sealed class SessionTarget(bool inWorld) : ILiveUiSessionTarget
|
||||
{
|
||||
public bool IsInWorld { get; } = inWorld;
|
||||
public WorldSession? CurrentSession => null;
|
||||
public ICommandBus Commands { get; } = new LiveCommandBus();
|
||||
}
|
||||
|
||||
private sealed class SelectionQuery : IRetainedUiSelectionQuery
|
||||
{
|
||||
public bool ShouldShowHealth(uint serverGuid) => true;
|
||||
public VividTargetInfo? ResolveVividTargetInfo(uint serverGuid) =>
|
||||
new(Vector3.Zero, 3f, 0u, 0u);
|
||||
public bool IsWithinExternalContainerUseRange(uint serverGuid) => false;
|
||||
}
|
||||
|
||||
private sealed class AutomationRuntime
|
||||
: AcDream.App.UI.Testing.IRetailUiAutomationRuntime
|
||||
{
|
||||
public bool IsWorldReady => true;
|
||||
public bool IsWorldViewportVisible => true;
|
||||
public int PortalMaterializationCount => 2;
|
||||
public string? LastCheckpoint { get; private set; }
|
||||
|
||||
public bool TryWriteCheckpoint(string name, out string error)
|
||||
{
|
||||
LastCheckpoint = name;
|
||||
error = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryRequestScreenshot(string name, out string error)
|
||||
{
|
||||
error = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsScreenshotComplete(string name) => true;
|
||||
}
|
||||
|
||||
private sealed class RetryBinding(int failures) : IDisposable
|
||||
{
|
||||
private int _failures = failures;
|
||||
public int Calls { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Calls++;
|
||||
if (_failures > 0)
|
||||
{
|
||||
_failures--;
|
||||
throw new InvalidOperationException("retry");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static T Stub<T>() where T : class =>
|
||||
(T)RuntimeHelpers.GetUninitializedObject(typeof(T));
|
||||
}
|
||||
|
|
@ -58,10 +58,9 @@ public sealed class GameWindowSlice8BoundaryTests
|
|||
"this).Compose(platform, hostInputCamera);",
|
||||
"new SettingsDevToolsCompositionPhase(",
|
||||
"this).Compose(platform, hostInputCamera, contentEffectsAudio);",
|
||||
"_uiHost = _retailUiLease.AcquireHost(",
|
||||
"_uiHost.WireMouse(m)",
|
||||
"_uiHost.WireKeyboard(kb)",
|
||||
"_retailUiRuntime = _retailUiLease.Mount(",
|
||||
"InteractionRetainedUiResult interactionUi =",
|
||||
"new InteractionRetainedUiCompositionPhase(",
|
||||
"this).Compose(",
|
||||
"_liveEntities = new AcDream.App.World.LiveEntityRuntime(",
|
||||
"_selectionInteractions ??= new AcDream.App.Interaction.SelectionInteractionController(",
|
||||
"_retainedUiGameplayBinding =",
|
||||
|
|
@ -220,7 +219,7 @@ public sealed class GameWindowSlice8BoundaryTests
|
|||
"private AcDream.App.Net.LiveSessionHost");
|
||||
string body = MethodBody(
|
||||
"private void OnFramebufferResize(",
|
||||
"private uint? PickWorldGuidAtCursor(");
|
||||
"private (uint Claim, bool Unhydratable)? _spawnClaimRangeMemo;");
|
||||
|
||||
Assert.Contains("=> _framebufferResize.Resize(newSize);", body, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("Viewport(", body, StringComparison.Ordinal);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue