Add reagent dispenser BUI test (#15443)

This commit is contained in:
Leon Friedrich
2023-04-17 04:34:36 +12:00
committed by GitHub
parent 6e0022d30f
commit a1f103d1e7
4 changed files with 181 additions and 20 deletions

View File

@@ -0,0 +1,35 @@
using System.Threading.Tasks;
using Content.IntegrationTests.Tests.Interaction;
using Content.Shared.Chemistry;
using Content.Shared.Containers.ItemSlots;
using NUnit.Framework;
namespace Content.IntegrationTests.Tests.Chemistry;
public sealed class DispenserTest : InteractionTest
{
/// <summary>
/// Basic test that checks that a beaker can be inserted and ejected from a dispenser.
/// </summary>
[Test]
public async Task InsertEjectBuiTest()
{
await SpawnTarget("chem_dispenser");
ToggleNeedPower();
// Insert beaker
await Interact("Beaker");
Assert.IsNull(Hands.ActiveHandEntity);
// Open BUI
await Interact("");
// Eject beaker via BUI.
var ev = new ItemSlotButtonPressedEvent(SharedChemMaster.InputSlotName);
await SendBui(ReagentDispenserUiKey.Key, ev);
// Beaker is back in the player's hands
Assert.IsNotNull(Hands.ActiveHandEntity);
AssertPrototype("Beaker", Hands.ActiveHandEntity);
}
}

View File

@@ -62,6 +62,10 @@ public abstract partial class InteractionTest
return; return;
Converted = true; Converted = true;
if (string.IsNullOrWhiteSpace(Prototype))
return;
if (protoMan.HasIndex<StackPrototype>(Prototype)) if (protoMan.HasIndex<StackPrototype>(Prototype))
return; return;
@@ -121,6 +125,6 @@ public abstract partial class InteractionTest
var meta = SEntMan.GetComponent<MetaDataComponent>(uid); var meta = SEntMan.GetComponent<MetaDataComponent>(uid);
Assert.NotNull(meta.EntityPrototype); Assert.NotNull(meta.EntityPrototype);
return new (meta.EntityPrototype.ID, 1) { Converted = true }; return new (meta.EntityPrototype!.ID, 1) { Converted = true };
} }
} }

View File

@@ -1,14 +1,17 @@
#nullable enable #nullable enable
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Client.Construction; using Content.Client.Construction;
using Content.Server.Construction.Components; using Content.Server.Construction.Components;
using Content.Server.Power.Components;
using Content.Server.Tools.Components; using Content.Server.Tools.Components;
using Content.Shared.Construction.Prototypes; using Content.Shared.Construction.Prototypes;
using Content.Shared.Item; using Content.Shared.Item;
using NUnit.Framework; using NUnit.Framework;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Log; using Robust.Shared.Log;
using Robust.Shared.Map; using Robust.Shared.Map;
@@ -139,7 +142,7 @@ public abstract partial class InteractionTest
await DeleteHeldEntity(); await DeleteHeldEntity();
if (entity == null) if (entity == null || string.IsNullOrWhiteSpace(entity.Prototype))
{ {
await RunTicks(1); await RunTicks(1);
Assert.That(Hands.ActiveHandEntity == null); Assert.That(Hands.ActiveHandEntity == null);
@@ -238,13 +241,19 @@ public abstract partial class InteractionTest
/// <summary> /// <summary>
/// Place an entity prototype into the players hand and interact with the given entity (or target position) /// Place an entity prototype into the players hand and interact with the given entity (or target position)
/// </summary> /// </summary>
protected async Task Interact(string? id, int quantity = 1, bool shouldSucceed = true, bool awaitDoAfters = true) /// <remarks>
=> await Interact(id == null ? null : (id, quantity), shouldSucceed, awaitDoAfters); /// Empty strings imply empty hands.
/// </remarks>
protected async Task Interact(string id, int quantity = 1, bool shouldSucceed = true, bool awaitDoAfters = true)
=> await Interact((id, quantity), shouldSucceed, awaitDoAfters);
/// <summary> /// <summary>
/// Place an entity prototype into the players hand and interact with the given entity (or target position) /// Place an entity prototype into the players hand and interact with the given entity (or target position)
/// </summary> /// </summary>
protected async Task Interact(EntitySpecifier? entity, bool shouldSucceed = true, bool awaitDoAfters = true) /// <remarks>
/// Empty strings imply empty hands.
/// </remarks>
protected async Task Interact(EntitySpecifier entity, bool shouldSucceed = true, bool awaitDoAfters = true)
{ {
// For every interaction, we will also examine the entity, just in case this breaks something, somehow. // For every interaction, we will also examine the entity, just in case this breaks something, somehow.
// (e.g., servers attempt to assemble construction examine hints). // (e.g., servers attempt to assemble construction examine hints).
@@ -376,7 +385,10 @@ public abstract partial class InteractionTest
/// <summary> /// <summary>
/// Variant of <see cref="InteractUsing"/> that performs several interactions using different entities. /// Variant of <see cref="InteractUsing"/> that performs several interactions using different entities.
/// </summary> /// </summary>
protected async Task Interact(params EntitySpecifier?[] specifiers) /// <remarks>
/// Empty strings imply empty hands.
/// </remarks>
protected async Task Interact(params EntitySpecifier[] specifiers)
{ {
foreach (var spec in specifiers) foreach (var spec in specifiers)
{ {
@@ -386,32 +398,60 @@ public abstract partial class InteractionTest
#region Asserts #region Asserts
protected void AssertPrototype(string? prototype) protected void AssertPrototype(string? prototype, EntityUid? target = null)
{ {
var meta = Comp<MetaDataComponent>(); target ??= Target;
if (target == null)
{
Assert.Fail("No target specified");
return;
}
var meta = SEntMan.GetComponent<MetaDataComponent>(target.Value);
Assert.That(meta.EntityPrototype?.ID, Is.EqualTo(prototype)); Assert.That(meta.EntityPrototype?.ID, Is.EqualTo(prototype));
} }
protected void AssertAnchored(bool anchored = true) protected void AssertAnchored(bool anchored = true, EntityUid? target = null)
{ {
var sXform = SEntMan.GetComponent<TransformComponent>(Target!.Value); target ??= Target;
var cXform = CEntMan.GetComponent<TransformComponent>(Target.Value); if (target == null)
{
Assert.Fail("No target specified");
return;
}
var sXform = SEntMan.GetComponent<TransformComponent>(target.Value);
var cXform = CEntMan.GetComponent<TransformComponent>(target.Value);
Assert.That(sXform.Anchored, Is.EqualTo(anchored)); Assert.That(sXform.Anchored, Is.EqualTo(anchored));
Assert.That(cXform.Anchored, Is.EqualTo(anchored)); Assert.That(cXform.Anchored, Is.EqualTo(anchored));
} }
protected void AssertDeleted(bool deleted = true) protected void AssertDeleted(bool deleted = true, EntityUid? target = null)
{ {
Assert.That(SEntMan.Deleted(Target), Is.EqualTo(deleted)); target ??= Target;
Assert.That(CEntMan.Deleted(Target), Is.EqualTo(deleted)); if (target == null)
{
Assert.Fail("No target specified");
return;
}
Assert.That(SEntMan.Deleted(target), Is.EqualTo(deleted));
Assert.That(CEntMan.Deleted(target), Is.EqualTo(deleted));
} }
/// <summary> /// <summary>
/// Assert whether or not the target has the given component. /// Assert whether or not the target has the given component.
/// </summary> /// </summary>
protected void AssertComp<T>(bool hasComp = true) protected void AssertComp<T>(bool hasComp = true, EntityUid? target = null)
{ {
Assert.That(SEntMan.HasComponent<T>(Target), Is.EqualTo(hasComp)); target ??= Target;
if (target == null)
{
Assert.Fail("No target specified");
return;
}
Assert.That(SEntMan.HasComponent<T>(target), Is.EqualTo(hasComp));
} }
/// <summary> /// <summary>
@@ -553,7 +593,6 @@ public abstract partial class InteractionTest
#endregion #endregion
/// <summary> /// <summary>
/// List of currently active DoAfters on the player. /// List of currently active DoAfters on the player.
/// </summary> /// </summary>
@@ -563,7 +602,14 @@ public abstract partial class InteractionTest
/// <summary> /// <summary>
/// Convenience method to get components on the target. Returns SERVER-SIDE components. /// Convenience method to get components on the target. Returns SERVER-SIDE components.
/// </summary> /// </summary>
protected T Comp<T>() => SEntMan.GetComponent<T>(Target!.Value); protected T Comp<T>(EntityUid? target = null)
{
target ??= Target;
if (target == null)
Assert.Fail("No target specified");
return SEntMan.GetComponent<T>(target!.Value);
}
/// <summary> /// <summary>
/// Set the tile at the target position to some prototype. /// Set the tile at the target position to some prototype.
@@ -611,4 +657,77 @@ public abstract partial class InteractionTest
protected async Task RunSeconds(float seconds) protected async Task RunSeconds(float seconds)
=> await RunTicks((int) Math.Ceiling(seconds / TickPeriod)); => await RunTicks((int) Math.Ceiling(seconds / TickPeriod));
#region BUI
/// <summary>
/// Sends a bui message using the given bui key.
/// </summary>
protected async Task SendBui(Enum key, BoundUserInterfaceMessage msg, EntityUid? target = null)
{
if (!TryGetBui(key, out var bui))
return;
await Client.WaitPost(() => bui.SendMessage(msg));
// allow for client -> server and server -> client messages to be sent.
await RunTicks(15);
}
/// <summary>
/// Sends a bui message using the given bui key.
/// </summary>
protected async Task CloseBui(Enum key, EntityUid? target = null)
{
if (!TryGetBui(key, out var bui))
return;
await Client.WaitPost(() => bui.Close());
// allow for client -> server and server -> client messages to be sent.
await RunTicks(15);
}
protected bool TryGetBui(Enum key, [NotNullWhen(true)] out BoundUserInterface? bui, EntityUid? target = null, bool shouldSucceed = true)
{
bui = null;
target ??= Target;
if (target == null)
{
Assert.Fail("No target specified");
return false;
}
if (!CEntMan.TryGetComponent(target, out ClientUserInterfaceComponent? ui))
{
if (shouldSucceed)
Assert.Fail($"Entity {SEntMan.ToPrettyString(target.Value)} does not have a bui component");
return false;
}
var first = ui.Interfaces.First();
bui = ui.Interfaces.FirstOrDefault(x => x.UiKey.Equals(key));
if (bui == null)
{
if (shouldSucceed)
Assert.Fail($"Entity {SEntMan.ToPrettyString(target.Value)} does not have an open bui with key {key.GetType()}.{key}.");
return false;
}
Assert.That(shouldSucceed, Is.True);
return true;
}
#endregion
#region Power
protected void ToggleNeedPower(EntityUid? target = null)
{
var comp = Comp<ApcPowerReceiverComponent>(target);
comp.NeedsPower = !comp.NeedsPower;
}
#endregion
} }

View File

@@ -13,6 +13,7 @@ using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems; using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using NUnit.Framework; using NUnit.Framework;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -97,11 +98,12 @@ public abstract partial class InteractionTest
// player components // player components
protected HandsComponent Hands = default!; protected HandsComponent Hands = default!;
protected DoAfterComponent DoAfters = default!; protected DoAfterComponent DoAfters = default!;
protected UserInterfaceSystem CUISystem = default!;
public float TickPeriod => (float)Timing.TickPeriod.TotalSeconds; public float TickPeriod => (float)Timing.TickPeriod.TotalSeconds;
[SetUp] [SetUp]
public async Task Setup() public virtual async Task Setup()
{ {
PairTracker = await PoolManager.GetServerClient(new PoolSettings()); PairTracker = await PoolManager.GetServerClient(new PoolSettings());
@@ -126,6 +128,7 @@ public abstract partial class InteractionTest
CTestSystem = CEntMan.System<InteractionTestSystem>(); CTestSystem = CEntMan.System<InteractionTestSystem>();
CConSys = CEntMan.System<ConstructionSystem>(); CConSys = CEntMan.System<ConstructionSystem>();
ExamineSys = CEntMan.System<ExamineSystem>(); ExamineSys = CEntMan.System<ExamineSystem>();
CUISystem = CEntMan.System<UserInterfaceSystem>();
// Setup map. // Setup map.
MapData = await PoolManager.CreateTestMap(PairTracker); MapData = await PoolManager.CreateTestMap(PairTracker);
@@ -189,7 +192,7 @@ public abstract partial class InteractionTest
} }
[TearDown] [TearDown]
public async Task Cleanup() public virtual async Task Cleanup()
{ {
await Server.WaitPost(() => MapMan.DeleteMap(MapId)); await Server.WaitPost(() => MapMan.DeleteMap(MapId));
await PairTracker.CleanReturnAsync(); await PairTracker.CleanReturnAsync();