refactor(net): converge live session state reset
This commit is contained in:
parent
78a9223b65
commit
4f31a5085f
35 changed files with 1460 additions and 83 deletions
|
|
@ -55,4 +55,25 @@ public sealed class GameplayConfirmationControllerTests
|
|||
Assert.Equal([(7u, 99u, false)], responses);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FactoryReset_CompletesResponseBeforeSessionTupleIsForgotten()
|
||||
{
|
||||
var root = new UiRoot { Width = 800f, Height = 600f };
|
||||
var factory = new RetailDialogFactory(root, _ =>
|
||||
FixtureLoader.LoadConfirmationDialog());
|
||||
var responses = new List<(uint Type, uint Context, bool Accepted)>();
|
||||
using var controller = new GameplayConfirmationController(
|
||||
factory,
|
||||
(type, context, accepted) => responses.Add((type, context, accepted)));
|
||||
controller.HandleRequest(
|
||||
new GameEvents.CharacterConfirmationRequest(7u, 99u, "Proceed?"));
|
||||
|
||||
factory.Reset();
|
||||
controller.ResetSession();
|
||||
|
||||
Assert.Equal(0u, controller.ActiveDialogContext);
|
||||
Assert.Equal([(7u, 99u, false)], responses);
|
||||
Assert.False(factory.IsOpen);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,4 +29,31 @@ public sealed class InteractionStateTests
|
|||
Assert.Throws<ArgumentOutOfRangeException>(() => state.EnterUseItemOnTarget(0));
|
||||
Assert.Equal(InteractionMode.None, state.Current);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResetSession_RetryRepublishesAndOneObserverCannotStarveAnother()
|
||||
{
|
||||
var state = new InteractionState();
|
||||
state.EnterExamine();
|
||||
bool fail = true;
|
||||
int delivered = 0;
|
||||
state.Changed += _ =>
|
||||
{
|
||||
if (fail)
|
||||
{
|
||||
fail = false;
|
||||
throw new InvalidOperationException("transient");
|
||||
}
|
||||
};
|
||||
state.Changed += transition =>
|
||||
{
|
||||
Assert.Equal(InteractionMode.None, transition.Current);
|
||||
delivered++;
|
||||
};
|
||||
|
||||
Assert.Throws<AggregateException>(state.ResetSession);
|
||||
Assert.Equal(1, delivered);
|
||||
state.ResetSession();
|
||||
Assert.Equal(2, delivered);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,33 @@ public sealed class ItemInteractionControllerTests
|
|||
Assert.Empty(h.UseWithTarget);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResetSession_RetryNotifiesEveryStateObserver()
|
||||
{
|
||||
var h = new Harness();
|
||||
h.Controller.InteractionState.EnterExamine();
|
||||
h.Controller.IncrementBusyCount();
|
||||
bool fail = true;
|
||||
int delivered = 0;
|
||||
h.Controller.StateChanged += () =>
|
||||
{
|
||||
if (fail)
|
||||
{
|
||||
fail = false;
|
||||
throw new InvalidOperationException("transient");
|
||||
}
|
||||
};
|
||||
h.Controller.StateChanged += () => delivered++;
|
||||
|
||||
Assert.Throws<AggregateException>(h.Controller.ResetSession);
|
||||
Assert.Equal(1, delivered);
|
||||
Assert.Equal(0, h.Controller.BusyCount);
|
||||
Assert.Equal(InteractionMode.None, h.Controller.InteractionState.Current);
|
||||
|
||||
h.Controller.ResetSession();
|
||||
Assert.Equal(2, delivered);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExternalContainerUse_RequestsGroundObjectAndSendsUse()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -187,6 +187,74 @@ public sealed class RetailDialogFactoryTests
|
|||
Assert.Null(root.Modal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Reset_CompletesEveryDialogAndKeepsContextSequenceMonotonic()
|
||||
{
|
||||
var root = new UiRoot { Width = 800f, Height = 600f };
|
||||
var layouts = new List<ImportedLayout>();
|
||||
var factory = CreateFactory(root, layouts);
|
||||
int callbacks = 0;
|
||||
int notices = 0;
|
||||
factory.DialogClosed += (_, _) => notices++;
|
||||
|
||||
uint first = factory.MakeConfirmation("active", _ => callbacks++);
|
||||
factory.MakeConfirmation("pending", _ => callbacks++);
|
||||
factory.Reset();
|
||||
|
||||
Assert.Equal(1u, first);
|
||||
Assert.Equal(2, callbacks);
|
||||
Assert.Equal(2, notices);
|
||||
Assert.False(factory.IsOpen);
|
||||
Assert.Equal(0, factory.PendingCount);
|
||||
Assert.Null(root.Modal);
|
||||
Assert.Empty(root.Children);
|
||||
Assert.Equal(3u, factory.MakeConfirmation("new session"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Reset_AttemptsEveryDialogWhenOneCallbackThrows()
|
||||
{
|
||||
var root = new UiRoot { Width = 800f, Height = 600f };
|
||||
var layouts = new List<ImportedLayout>();
|
||||
var factory = CreateFactory(root, layouts);
|
||||
int completed = 0;
|
||||
|
||||
factory.MakeConfirmation("active", _ => throw new InvalidOperationException("boom"));
|
||||
factory.MakeConfirmation("pending", _ => completed++);
|
||||
|
||||
AggregateException error = Assert.Throws<AggregateException>(factory.Reset);
|
||||
|
||||
Assert.Contains("boom", error.ToString());
|
||||
Assert.Equal(1, completed);
|
||||
Assert.False(factory.IsOpen);
|
||||
Assert.Equal(0, factory.PendingCount);
|
||||
Assert.Null(root.Modal);
|
||||
Assert.Empty(root.Children);
|
||||
factory.Reset();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Reset_DrainsDialogCreatedReentrantlyByCompletionCallback()
|
||||
{
|
||||
var root = new UiRoot { Width = 800f, Height = 600f };
|
||||
var layouts = new List<ImportedLayout>();
|
||||
var factory = CreateFactory(root, layouts);
|
||||
int completed = 0;
|
||||
factory.MakeConfirmation("first", _ =>
|
||||
{
|
||||
completed++;
|
||||
factory.MakeConfirmation("reentrant", _ => completed++);
|
||||
});
|
||||
|
||||
factory.Reset();
|
||||
|
||||
Assert.Equal(2, completed);
|
||||
Assert.False(factory.IsOpen);
|
||||
Assert.Equal(0, factory.PendingCount);
|
||||
Assert.Null(root.Modal);
|
||||
Assert.Empty(root.Children);
|
||||
}
|
||||
|
||||
private static RetailDialogFactory CreateFactory(
|
||||
UiRoot root,
|
||||
List<ImportedLayout> layouts)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue