mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Split up test project
Robust.UnitTesting was both ALL tests for RT, and also API surface for content tests. Tests are now split into separate projects as appropriate, and the API side has also been split off.
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.UnitTesting.Server;
|
||||
|
||||
namespace Robust.UnitTesting.Client.GameObjects.Components
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(TransformComponent))]
|
||||
public sealed class TransformComponentTests
|
||||
{
|
||||
private static (ISimulation, EntityUid gridA, EntityUid gridB) SimulationFactory()
|
||||
{
|
||||
var sim = RobustServerSimulation
|
||||
.NewSimulation()
|
||||
.InitializeInstance();
|
||||
|
||||
var mapId = sim.Resolve<IEntityManager>().System<SharedMapSystem>().CreateMap();
|
||||
var mapManager = sim.Resolve<IMapManager>();
|
||||
|
||||
// Adds two grids to use in tests.
|
||||
var gridA = mapManager.CreateGridEntity(mapId);
|
||||
var gridB = mapManager.CreateGridEntity(mapId);
|
||||
|
||||
return (sim, gridA, gridB);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make sure that component state locations are RELATIVE.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ComponentStatePositionTest()
|
||||
{
|
||||
var (sim, gridIdA, gridIdB) = SimulationFactory();
|
||||
var entMan = sim.Resolve<IEntityManager>();
|
||||
var xformSystem = entMan.System<SharedTransformSystem>();
|
||||
var gridSystem = entMan.System<SharedGridTraversalSystem>();
|
||||
gridSystem.Enabled = false;
|
||||
|
||||
// Arrange
|
||||
var initialPos = new EntityCoordinates(gridIdA, new Vector2(0, 0));
|
||||
var parent = entMan.SpawnEntity(null, initialPos);
|
||||
var child = entMan.SpawnEntity(null, initialPos);
|
||||
var parentTrans = entMan.GetComponent<TransformComponent>(parent);
|
||||
var childTrans = entMan.GetComponent<TransformComponent>(child);
|
||||
ComponentHandleState handleState;
|
||||
|
||||
var compState = new TransformComponentState(new Vector2(5, 5), new Angle(0), entMan.GetNetEntity(gridIdB), false, false);
|
||||
handleState = new ComponentHandleState(compState, null);
|
||||
xformSystem.OnHandleState(parent, parentTrans, ref handleState);
|
||||
|
||||
compState = new TransformComponentState(new Vector2(6, 6), new Angle(0), entMan.GetNetEntity(gridIdB), false, false);
|
||||
handleState = new ComponentHandleState(compState, null);
|
||||
xformSystem.OnHandleState(child, childTrans, ref handleState);
|
||||
// World pos should be 6, 6 now.
|
||||
|
||||
// Act
|
||||
var oldWpos = xformSystem.GetWorldPosition(childTrans);
|
||||
compState = new TransformComponentState(new Vector2(1, 1), new Angle(0), entMan.GetNetEntity(parent), false, false);
|
||||
handleState = new ComponentHandleState(compState, null);
|
||||
xformSystem.OnHandleState(child, childTrans, ref handleState);
|
||||
var newWpos = xformSystem.GetWorldPosition(childTrans);
|
||||
|
||||
gridSystem.Enabled = true;
|
||||
|
||||
// Assert
|
||||
Assert.That(newWpos, Is.EqualTo(oldWpos));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests that world rotation is built properly
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void WorldRotationTest()
|
||||
{
|
||||
var (sim, gridIdA, gridIdB) = SimulationFactory();
|
||||
var entMan = sim.Resolve<IEntityManager>();
|
||||
var xformSystem = entMan.System<SharedTransformSystem>();
|
||||
var metaSystem = entMan.System<MetaDataSystem>();
|
||||
var gridSystem = entMan.System<SharedGridTraversalSystem>();
|
||||
gridSystem.Enabled = false;
|
||||
|
||||
// Arrange
|
||||
var initalPos = new EntityCoordinates(gridIdA, new Vector2(0, 0));
|
||||
var node1 = entMan.SpawnEntity(null, initalPos);
|
||||
var node2 = entMan.SpawnEntity(null, initalPos);
|
||||
var node3 = entMan.SpawnEntity(null, initalPos);
|
||||
|
||||
metaSystem.SetEntityName(node1, "node1_dummy");
|
||||
metaSystem.SetEntityName(node2, "node2_dummy");
|
||||
metaSystem.SetEntityName(node3, "node3_dummy");
|
||||
|
||||
var node1Trans = entMan.GetComponent<TransformComponent>(node1);
|
||||
var node2Trans = entMan.GetComponent<TransformComponent>(node2);
|
||||
var node3Trans = entMan.GetComponent<TransformComponent>(node3);
|
||||
|
||||
var compState = new TransformComponentState(new Vector2(6, 6), Angle.FromDegrees(135), entMan.GetNetEntity(gridIdB), false, false);
|
||||
var handleState = new ComponentHandleState(compState, null);
|
||||
xformSystem.OnHandleState(node1, node1Trans, ref handleState);
|
||||
|
||||
compState = new TransformComponentState(new Vector2(1, 1), Angle.FromDegrees(45), entMan.GetNetEntity(node1), false, false);
|
||||
handleState = new ComponentHandleState(compState, null);
|
||||
xformSystem.OnHandleState(node2, node2Trans, ref handleState);
|
||||
|
||||
compState = new TransformComponentState(new Vector2(0, 0), Angle.FromDegrees(45), entMan.GetNetEntity(node2), false, false);
|
||||
handleState = new ComponentHandleState(compState, null);
|
||||
xformSystem.OnHandleState(node3, node3Trans, ref handleState);
|
||||
|
||||
// Act
|
||||
var result = xformSystem.GetWorldRotation(node3Trans);
|
||||
|
||||
gridSystem.Enabled = true;
|
||||
|
||||
// Assert (135 + 45 + 45 = 225)
|
||||
Assert.That(result, new ApproxEqualityConstraint(Angle.FromDegrees(225)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.GameStates;
|
||||
using Robust.Client.Timing;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.UnitTesting.Client.GameStates
|
||||
{
|
||||
[TestFixture, Parallelizable, TestOf(typeof(GameStateProcessor))]
|
||||
sealed class GameStateProcessor_Tests
|
||||
{
|
||||
[Test]
|
||||
public void FillBufferBlocksProcessing()
|
||||
{
|
||||
var timingMock = new Mock<IClientGameTiming>();
|
||||
timingMock.SetupProperty(p => p.CurTick);
|
||||
|
||||
var timing = timingMock.Object;
|
||||
var managerMock = new Mock<IClientGameStateManager>();
|
||||
var logMock = new Mock<ISawmill>();
|
||||
var processor = new GameStateProcessor(managerMock.Object, timing, logMock.Object);
|
||||
processor.Interpolation = true;
|
||||
|
||||
processor.AddNewState(GameStateFactory(0, 1));
|
||||
processor.AddNewState(GameStateFactory(1, 2)); // buffer is at 2/3, so processing should be blocked
|
||||
|
||||
// calculate states for first tick
|
||||
timing.LastProcessedTick = new GameTick(0);
|
||||
var result = processor.TryGetServerState(out _, out _);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FillBufferAndCalculateFirstState()
|
||||
{
|
||||
var timingMock = new Mock<IClientGameTiming>();
|
||||
timingMock.SetupProperty(p => p.CurTick);
|
||||
|
||||
var timing = timingMock.Object;
|
||||
var managerMock = new Mock<IClientGameStateManager>();
|
||||
var logMock = new Mock<ISawmill>();
|
||||
var processor = new GameStateProcessor(managerMock.Object, timing, logMock.Object);
|
||||
|
||||
processor.AddNewState(GameStateFactory(0, 1));
|
||||
processor.AddNewState(GameStateFactory(1, 2));
|
||||
processor.AddNewState(GameStateFactory(2, 3)); // buffer is now full, otherwise cannot calculate states.
|
||||
|
||||
// calculate states for first tick
|
||||
timing.LastProcessedTick = new GameTick(0);
|
||||
var result = processor.TryGetServerState(out var curState, out var nextState);
|
||||
|
||||
Assert.That(result, Is.True);
|
||||
Assert.That(curState, Is.Not.Null);
|
||||
Assert.That(curState!.ToSequence.Value, Is.EqualTo(1));
|
||||
Assert.That(nextState, Is.Null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When a full state is in the queue (fromSequence = 0), it will modify CurTick to the states' toSequence,
|
||||
/// then return the state as curState.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void FullStateResyncsCurTick()
|
||||
{
|
||||
var timingMock = new Mock<IClientGameTiming>();
|
||||
timingMock.SetupProperty(p => p.CurTick);
|
||||
|
||||
var timing = timingMock.Object;
|
||||
var managerMock = new Mock<IClientGameStateManager>();
|
||||
var logMock = new Mock<ISawmill>();
|
||||
var processor = new GameStateProcessor(managerMock.Object, timing, logMock.Object);
|
||||
|
||||
processor.AddNewState(GameStateFactory(0, 1));
|
||||
processor.AddNewState(GameStateFactory(1, 2));
|
||||
processor.AddNewState(GameStateFactory(2, 3)); // buffer is now full, otherwise cannot calculate states.
|
||||
|
||||
// calculate states for first tick
|
||||
timing.LastProcessedTick = new GameTick(2);
|
||||
processor.TryGetServerState(out var state, out _);
|
||||
|
||||
Assert.That(state, Is.Not.Null);
|
||||
Assert.That(state!.ToSequence.Value, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StatesReceivedPastCurTickAreDropped()
|
||||
{
|
||||
var (timing, processor) = SetupProcessorFactory();
|
||||
|
||||
// a few moments later...
|
||||
timing.LastProcessedTick = new GameTick(4); // current clock is ahead of server
|
||||
processor.AddNewState(GameStateFactory(3, 4)); // received a late state
|
||||
var result = processor.TryGetServerState(out _, out _);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The server fell behind the client, so the client clock is now ahead of the incoming states.
|
||||
/// Without extrapolation, processing blocks.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ServerLagsWithoutExtrapolation()
|
||||
{
|
||||
var (timing, processor) = SetupProcessorFactory();
|
||||
|
||||
// a few moments later...
|
||||
timing.LastProcessedTick = new GameTick(4); // current clock is ahead of server
|
||||
var result = processor.TryGetServerState(out _, out _);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// There is a hole in the state buffer, we have a future state but their FromSequence is too high!
|
||||
/// In this case we stop and wait for the server to get us the missing link.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Hole()
|
||||
{
|
||||
var (timing, processor) = SetupProcessorFactory();
|
||||
|
||||
processor.AddNewState(GameStateFactory(4, 5));
|
||||
timing.LastRealTick = new GameTick(3);
|
||||
timing.LastProcessedTick = new GameTick(3);
|
||||
|
||||
var result = processor.TryGetServerState(out _, out _);
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that the game state manager goes into extrapolation mode *temporarily*,
|
||||
/// if we are missing the curState, but we have a future state that we can apply to skip it.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ExtrapolateAdvanceWithFutureState()
|
||||
{
|
||||
var (timing, processor) = SetupProcessorFactory();
|
||||
|
||||
processor.Interpolation = true;
|
||||
|
||||
timing.LastProcessedTick = new GameTick(3);
|
||||
|
||||
timing.LastRealTick = new GameTick(3);
|
||||
processor.AddNewState(GameStateFactory(3, 5));
|
||||
|
||||
// We're missing the state for this tick so go into extrap.
|
||||
var result = processor.TryGetServerState(out var curState, out _);
|
||||
|
||||
Assert.That(result, Is.True);
|
||||
Assert.That(curState, Is.Null);
|
||||
|
||||
timing.LastProcessedTick = new GameTick(4);
|
||||
|
||||
// But we DO have the state for the tick after so apply away!
|
||||
result = processor.TryGetServerState(out curState, out _);
|
||||
|
||||
Assert.That(result, Is.True);
|
||||
Assert.That(curState, Is.Not.Null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty GameState with the given to and from properties.
|
||||
/// </summary>
|
||||
private static GameState GameStateFactory(uint from, uint to)
|
||||
{
|
||||
return new(new GameTick(@from), new GameTick(to), 0, default, default, default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GameTiming and GameStateProcessor, fills the processor with enough states, and calculate the first tick.
|
||||
/// CurTick = 1, states 1 - 3 are in the buffer.
|
||||
/// </summary>
|
||||
private static (IClientGameTiming timing, GameStateProcessor processor) SetupProcessorFactory()
|
||||
{
|
||||
var timingMock = new Mock<IClientGameTiming>();
|
||||
timingMock.SetupProperty(p => p.CurTick);
|
||||
timingMock.SetupProperty(p => p.LastProcessedTick);
|
||||
timingMock.SetupProperty(p => p.LastRealTick);
|
||||
timingMock.SetupProperty(p => p.TickTimingAdjustment);
|
||||
|
||||
var timing = timingMock.Object;
|
||||
var managerMock = new Mock<IClientGameStateManager>();
|
||||
var logMock = new Mock<ISawmill>();
|
||||
var processor = new GameStateProcessor(managerMock.Object, timing, logMock.Object);
|
||||
|
||||
processor.AddNewState(GameStateFactory(0, 1));
|
||||
processor.AddNewState(GameStateFactory(1, 2));
|
||||
processor.AddNewState(GameStateFactory(2, 3)); // buffer is now full, otherwise cannot calculate states.
|
||||
|
||||
processor.OnFullStateReceived();
|
||||
timing.LastProcessedTick = timing.LastRealTick = new GameTick(1);
|
||||
|
||||
return (timing, processor);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Robust.Client.IntegrationTests/Graphics/EyeManagerTest.cs
Normal file
47
Robust.Client.IntegrationTests/Graphics/EyeManagerTest.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.UnitTesting.Client.Graphics
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(IEyeManager))]
|
||||
public sealed class EyeManagerTest : RobustIntegrationTest
|
||||
{
|
||||
[Test]
|
||||
public async Task TestViewportRotation()
|
||||
{
|
||||
// At cardinal rotations with a square viewport these should all be the same.
|
||||
var client = StartClient();
|
||||
await client.WaitIdleAsync();
|
||||
|
||||
var eyeManager = client.ResolveDependency<IEyeManager>();
|
||||
|
||||
await client.WaitAssertion(() =>
|
||||
{
|
||||
// At this stage integration tests aren't pooled so no way I'm making each of these a new test for now.
|
||||
foreach (var angle in new[]
|
||||
{
|
||||
Angle.Zero,
|
||||
new Angle(Math.PI / 4),
|
||||
new Angle(Math.PI / 2),
|
||||
new Angle(Math.PI),
|
||||
new Angle(-Math.PI / 4),
|
||||
new Angle(-Math.PI / 2),
|
||||
new Angle(-Math.PI)
|
||||
})
|
||||
{
|
||||
|
||||
eyeManager.CurrentEye.Rotation = angle;
|
||||
|
||||
var worldAABB = eyeManager.GetWorldViewport();
|
||||
var worldPort = eyeManager.GetWorldViewbounds();
|
||||
Assert.That(worldAABB.EqualsApprox(worldPort.CalcBoundingBox()),
|
||||
$"Invalid EyeRotation bounds found for {angle}: Expected {worldAABB} and received {worldPort.CalcBoundingBox()}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\MSBuild\Robust.Engine.props"/>
|
||||
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<OutputPath>../bin/Client.IntegrationTests</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk"/>
|
||||
<PackageReference Include="Moq" />
|
||||
<PackageReference Include="NUnit"/>
|
||||
<PackageReference Include="NUnit3TestAdapter"/>
|
||||
<PackageReference Include="NUnit.Analyzers"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Robust.Client\Robust.Client.csproj" />
|
||||
<ProjectReference Include="..\Robust.Server.Testing\Robust.Server.Testing.csproj" />
|
||||
<ProjectReference Include="..\Robust.Server\Robust.Server.csproj" />
|
||||
<ProjectReference Include="..\Robust.Shared.Maths\Robust.Shared.Maths.csproj"/>
|
||||
<ProjectReference Include="..\Robust.Shared.Maths.Testing\Robust.Shared.Maths.Testing.csproj"/>
|
||||
<ProjectReference Include="..\Robust.Shared\Robust.Shared.csproj"/>
|
||||
<ProjectReference Include="..\Robust.UnitTesting\Robust.UnitTesting.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\MSBuild\Robust.Properties.targets"/>
|
||||
</Project>
|
||||
132
Robust.Client.IntegrationTests/Sprite/SpriteBoundsTest.cs
Normal file
132
Robust.Client.IntegrationTests/Sprite/SpriteBoundsTest.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.UnitTesting.Client.Sprite;
|
||||
|
||||
public sealed class SpriteBoundsTest : RobustIntegrationTest
|
||||
{
|
||||
private static readonly string Prototypes = @"
|
||||
- type: entity
|
||||
id: spriteBoundsTest1
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: debugRotation.rsi
|
||||
layers:
|
||||
- state: direction1
|
||||
|
||||
- type: entity
|
||||
id: spriteBoundsTest2
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: debugRotation.rsi
|
||||
layers:
|
||||
- state: direction1
|
||||
- state: direction1
|
||||
rotation: 0.1
|
||||
|
||||
- type: entity
|
||||
id: spriteBoundsTest3
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: debugRotation.rsi
|
||||
layers:
|
||||
- state: direction1
|
||||
- state: direction1
|
||||
rotation: 0.1
|
||||
visible: false
|
||||
";
|
||||
|
||||
[Test]
|
||||
public async Task TestSpriteBounds()
|
||||
{
|
||||
var client = StartClient(new ClientIntegrationOptions {ExtraPrototypes = Prototypes});
|
||||
await client.WaitIdleAsync();
|
||||
var baseClient = client.Resolve<IBaseClient>();
|
||||
|
||||
await client.WaitPost(() => baseClient.StartSinglePlayer());
|
||||
await client.WaitIdleAsync();
|
||||
|
||||
var entMan = client.EntMan;
|
||||
var sys = client.System<SpriteSystem>();
|
||||
|
||||
EntityUid uid1 = default;
|
||||
EntityUid uid2 = default;
|
||||
EntityUid uid3 = default;
|
||||
|
||||
await client.WaitPost(() =>
|
||||
{
|
||||
uid1 = entMan.Spawn("spriteBoundsTest1");
|
||||
uid2 = entMan.Spawn("spriteBoundsTest2");
|
||||
uid3 = entMan.Spawn("spriteBoundsTest3");
|
||||
});
|
||||
|
||||
var ent1 = new Entity<SpriteComponent>(uid1, entMan.GetComponent<SpriteComponent>(uid1));
|
||||
var ent2 = new Entity<SpriteComponent>(uid2, entMan.GetComponent<SpriteComponent>(uid2));
|
||||
var ent3 = new Entity<SpriteComponent>(uid3, entMan.GetComponent<SpriteComponent>(uid3));
|
||||
|
||||
// None of the entities have empty bounding boxes
|
||||
var box1 = sys.GetLocalBounds(ent1);
|
||||
var box2 = sys.GetLocalBounds(ent2);
|
||||
var box3 = sys.GetLocalBounds(ent3);
|
||||
Assert.That(!box1.EqualsApprox(Box2.Empty));
|
||||
Assert.That(!box2.EqualsApprox(Box2.Empty));
|
||||
Assert.That(!box3.EqualsApprox(Box2.Empty));
|
||||
|
||||
// ent2 should have a larger bb than ent1 as it has a visible rotated layer
|
||||
// ents 1 & 3 should have the same bounds, as the rotated layer is invisible in ent3
|
||||
Assert.That(box1.EqualsApprox(box3));
|
||||
Assert.That(!box1.EqualsApprox(box2));
|
||||
Assert.That(box2.EqualsApprox(ent2.Comp.Layers[1].Bounds));
|
||||
Assert.That(box2.Size.X, Is.GreaterThan(box1.Size.X));
|
||||
Assert.That(box2.Size.Y, Is.GreaterThan(box1.Size.Y));
|
||||
|
||||
// Toggling layer visibility updates the bounds
|
||||
sys.LayerSetVisible(ent2!, 1, false);
|
||||
sys.LayerSetVisible(ent3!, 1, true);
|
||||
|
||||
var newBox2 = sys.GetLocalBounds(ent2);
|
||||
var newBox3 = sys.GetLocalBounds(ent3);
|
||||
Assert.That(!newBox2.EqualsApprox(Box2.Empty));
|
||||
Assert.That(!newBox3.EqualsApprox(Box2.Empty));
|
||||
|
||||
Assert.That(box1.EqualsApprox(newBox2));
|
||||
Assert.That(!box1.EqualsApprox(newBox3));
|
||||
Assert.That(newBox3.EqualsApprox(ent3.Comp.Layers[1].Bounds));
|
||||
Assert.That(newBox3.Size.X, Is.GreaterThan(box1.Size.X));
|
||||
Assert.That(newBox3.Size.Y, Is.GreaterThan(box1.Size.Y));
|
||||
|
||||
// Changing the rotation, offset, scale, all trigger a bounds updatge
|
||||
sys.LayerSetRotation(ent3!, 1, Angle.Zero);
|
||||
var box = sys.GetLocalBounds(ent3);
|
||||
Assert.That(box1.EqualsApprox(box));
|
||||
|
||||
// scale
|
||||
sys.LayerSetScale(ent3!, 1, Vector2.One * 2);
|
||||
box = sys.GetLocalBounds(ent3);
|
||||
Assert.That(box1.EqualsApprox(box.Scale(0.5f)));
|
||||
sys.LayerSetScale(ent3!, 1, Vector2.One);
|
||||
box = sys.GetLocalBounds(ent3);
|
||||
Assert.That(box1.EqualsApprox(box));
|
||||
|
||||
// offset
|
||||
Assert.That(box.Center, Is.Approximately(Vector2.Zero));
|
||||
sys.LayerSetOffset(ent3!, 1, Vector2.One);
|
||||
box = sys.GetLocalBounds(ent3);
|
||||
Assert.That(box.Size.X, Is.GreaterThan(box1.Size.X));
|
||||
Assert.That(box.Size.Y, Is.GreaterThan(box1.Size.Y));
|
||||
Assert.That(box.Center.X, Is.GreaterThan(0));
|
||||
Assert.That(box.Center.Y, Is.GreaterThan(0));
|
||||
|
||||
await client.WaitPost(() =>
|
||||
{
|
||||
entMan.DeleteEntity(uid1);
|
||||
entMan.DeleteEntity(uid2);
|
||||
entMan.DeleteEntity(uid3);
|
||||
});
|
||||
}
|
||||
}
|
||||
199
Robust.Client.IntegrationTests/UserInterface/ControlTest.cs
Normal file
199
Robust.Client.IntegrationTests/UserInterface/ControlTest.cs
Normal file
@@ -0,0 +1,199 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(Control))]
|
||||
public sealed class ControlTest : RobustUnitTest
|
||||
{
|
||||
private static readonly AttachedProperty _refTypeAttachedProperty
|
||||
= AttachedProperty.Create("_refType", typeof(ControlTest), typeof(string), "foo", v => (string?) v != "bar");
|
||||
|
||||
private static readonly AttachedProperty _valueTypeAttachedProperty
|
||||
= AttachedProperty.Create("_valueType", typeof(ControlTest), typeof(float));
|
||||
|
||||
private static readonly AttachedProperty _nullableAttachedProperty
|
||||
= AttachedProperty.Create("_nullable", typeof(ControlTest), typeof(float?));
|
||||
|
||||
private static readonly AttachedProperty<int> _genericProperty =
|
||||
AttachedProperty<int>.Create("generic", typeof(ControlTest), 5, i => i % 2 == 1);
|
||||
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void Setup()
|
||||
{
|
||||
IoCManager.Resolve<IUserInterfaceManagerInternal>().InitializeTesting();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that you can't parent a control to its (grand)child.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestNoRecursion()
|
||||
{
|
||||
var control1 = new Control();
|
||||
var control2 = new Control();
|
||||
var control3 = new Control();
|
||||
|
||||
control1.AddChild(control2);
|
||||
// Test direct parent/child.
|
||||
Assert.That(() => control2.AddChild(control1), Throws.ArgumentException);
|
||||
|
||||
control2.AddChild(control3);
|
||||
// Test grand child.
|
||||
Assert.That(() => control3.AddChild(control1), Throws.ArgumentException);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVisibleInTree()
|
||||
{
|
||||
var control1 = new Control();
|
||||
|
||||
// Not visible because not parented to root control.
|
||||
Assert.That(control1.Visible, Is.True);
|
||||
Assert.That(control1.VisibleInTree, Is.False);
|
||||
|
||||
control1.UserInterfaceManager.RootControl.AddChild(control1);
|
||||
Assert.That(control1.Visible, Is.True);
|
||||
Assert.That(control1.VisibleInTree, Is.True);
|
||||
|
||||
control1.Visible = false;
|
||||
Assert.That(control1.Visible, Is.False);
|
||||
Assert.That(control1.VisibleInTree, Is.False);
|
||||
control1.Visible = true;
|
||||
|
||||
var control2 = new Control();
|
||||
Assert.That(control2.VisibleInTree, Is.False);
|
||||
|
||||
control1.AddChild(control2);
|
||||
Assert.That(control2.VisibleInTree, Is.True);
|
||||
|
||||
control1.Visible = false;
|
||||
Assert.That(control2.VisibleInTree, Is.False);
|
||||
|
||||
control2.Visible = false;
|
||||
Assert.That(control2.VisibleInTree, Is.False);
|
||||
|
||||
control1.Visible = true;
|
||||
Assert.That(control2.VisibleInTree, Is.False);
|
||||
|
||||
control1.Orphan();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAttachedPropertiesBasic()
|
||||
{
|
||||
var control = new Control();
|
||||
|
||||
control.SetValue(_refTypeAttachedProperty, "honk");
|
||||
|
||||
Assert.That(control.GetValue(_refTypeAttachedProperty), Is.EqualTo("honk"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAttachedPropertiesValidate()
|
||||
{
|
||||
var control = new Control();
|
||||
|
||||
Assert.Throws<ArgumentException>(() => control.SetValue(_refTypeAttachedProperty, "bar"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAttachedPropertiesInvalidType()
|
||||
{
|
||||
var control = new Control();
|
||||
|
||||
Assert.Throws<ArgumentException>(() => control.SetValue(_refTypeAttachedProperty, new object()));
|
||||
Assert.Throws<ArgumentException>(() => control.SetValue(_valueTypeAttachedProperty, new object()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAttachedPropertiesInvalidNull()
|
||||
{
|
||||
var control = new Control();
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => control.SetValue(_valueTypeAttachedProperty, null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAttachedPropertiesValidNull()
|
||||
{
|
||||
var control = new Control();
|
||||
|
||||
control.SetValue(_nullableAttachedProperty, null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAttachedPropertiesGeneric()
|
||||
{
|
||||
var control = new Control();
|
||||
|
||||
Assert.That(control.GetValue(_genericProperty), Is.EqualTo(5));
|
||||
|
||||
control.SetValue(_genericProperty, 11);
|
||||
|
||||
Assert.That(control.GetValue(_genericProperty), Is.EqualTo(11));
|
||||
|
||||
Assert.That(() => control.SetValue(_genericProperty, 10), Throws.ArgumentException);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAnimations()
|
||||
{
|
||||
var control = new TestControl();
|
||||
var animation = new Animation
|
||||
{
|
||||
Length = TimeSpan.FromSeconds(3),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackControlProperty
|
||||
{
|
||||
Property = nameof(TestControl.Foo),
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(1f, 1f),
|
||||
new AnimationTrackProperty.KeyFrame(3f, 2f)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
control.PlayAnimation(animation, "foo");
|
||||
control.DoFrameUpdateRecursive(new FrameEventArgs(0.5f));
|
||||
|
||||
Assert.That(control.Foo, new ApproxEqualityConstraint(0f)); // Should still be 0.
|
||||
|
||||
control.DoFrameUpdateRecursive(new FrameEventArgs(0.5001f));
|
||||
|
||||
Assert.That(control.Foo, new ApproxEqualityConstraint(1f, 0.01)); // Should now be 1.
|
||||
|
||||
control.DoFrameUpdateRecursive(new FrameEventArgs(0.5f));
|
||||
|
||||
Assert.That(control.Foo, new ApproxEqualityConstraint(1.5f, 0.01)); // Should now be 1.5.
|
||||
|
||||
control.DoFrameUpdateRecursive(new FrameEventArgs(1.0f));
|
||||
|
||||
Assert.That(control.Foo, new ApproxEqualityConstraint(2.5f, 0.01)); // Should now be 2.5.
|
||||
|
||||
control.DoFrameUpdateRecursive(new FrameEventArgs(0.5f));
|
||||
|
||||
Assert.That(control.Foo, new ApproxEqualityConstraint(3f, 0.01)); // Should now be 3.
|
||||
|
||||
control.DoFrameUpdateRecursive(new FrameEventArgs(0.5f));
|
||||
|
||||
Assert.That(control.Foo, new ApproxEqualityConstraint(3f, 0.01)); // Should STILL be 3.
|
||||
}
|
||||
|
||||
private sealed class TestControl : Control
|
||||
{
|
||||
[Animatable] public float Foo { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface.Controls;
|
||||
|
||||
[TestFixture]
|
||||
public sealed class BaseButtonTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
private string UIRightClick = "UIRightClick";
|
||||
private string OpenContextMenu = "UseSecondary";
|
||||
|
||||
private sealed class TestButton : BaseButton { }
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void Setup()
|
||||
{
|
||||
IoCManager.Resolve<IUserInterfaceManagerInternal>().InitializeTesting();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestToggleButtonToggle()
|
||||
{
|
||||
var button = new TestButton
|
||||
{
|
||||
ToggleMode = true
|
||||
};
|
||||
var toggled = false;
|
||||
|
||||
button.OnToggled += _ =>
|
||||
{
|
||||
toggled = true;
|
||||
};
|
||||
|
||||
var click = new GUIBoundKeyEventArgs(EngineKeyFunctions.UIClick, BoundKeyState.Down, new ScreenCoordinates(), true, Vector2.Zero, Vector2.Zero);
|
||||
button.KeyBindDown(click);
|
||||
button.KeyBindUp(click);
|
||||
Assert.That(button.Pressed, Is.EqualTo(true));
|
||||
Assert.That(toggled, Is.EqualTo(true));
|
||||
|
||||
toggled = false;
|
||||
button.KeyBindDown(click);
|
||||
button.KeyBindUp(click);
|
||||
Assert.That(button.Pressed, Is.EqualTo(false));
|
||||
Assert.That(toggled, Is.EqualTo(true));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestToggleButtonAllKeybinds()
|
||||
{
|
||||
var button = new TestButton
|
||||
{
|
||||
EnableAllKeybinds = true,
|
||||
ToggleMode = true
|
||||
};
|
||||
|
||||
var uiRightClickPressed = false;
|
||||
var openContextMenuPressed = false;
|
||||
var toggled = false;
|
||||
button.OnPressed += args =>
|
||||
{
|
||||
if (args.Event.Function == UIRightClick)
|
||||
uiRightClickPressed = true;
|
||||
else if (args.Event.Function == OpenContextMenu)
|
||||
openContextMenuPressed = true;
|
||||
};
|
||||
button.OnToggled += _ =>
|
||||
{
|
||||
toggled = true;
|
||||
};
|
||||
|
||||
var uiRightClick = new GUIBoundKeyEventArgs(UIRightClick, BoundKeyState.Down, new ScreenCoordinates(), true, Vector2.Zero, Vector2.Zero);
|
||||
var openContextMenu = new GUIBoundKeyEventArgs(OpenContextMenu, BoundKeyState.Down, new ScreenCoordinates(), true, Vector2.Zero, Vector2.Zero);
|
||||
button.KeyBindDown(uiRightClick);
|
||||
button.KeyBindDown(openContextMenu);
|
||||
|
||||
Assert.That(button.Pressed, Is.EqualTo(false));
|
||||
Assert.That(toggled, Is.EqualTo(false));
|
||||
button.KeyBindUp(uiRightClick);
|
||||
Assert.That(button.Pressed, Is.EqualTo(false));
|
||||
Assert.That(toggled, Is.EqualTo(false));
|
||||
button.KeyBindUp(openContextMenu);
|
||||
|
||||
Assert.That(uiRightClickPressed, Is.EqualTo(true));
|
||||
Assert.That(openContextMenuPressed, Is.EqualTo(true));
|
||||
Assert.That(button.Pressed, Is.EqualTo(false));
|
||||
Assert.That(toggled, Is.EqualTo(false));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(BoxContainer))]
|
||||
public sealed class BoxContainerTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[Test]
|
||||
public void TestLayoutBasic()
|
||||
{
|
||||
var root = new LayoutContainer();
|
||||
var boxContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
MinSize = new Vector2(50, 60)
|
||||
};
|
||||
var control1 = new Control {MinSize = new Vector2(20, 20)};
|
||||
var control2 = new Control {MinSize = new Vector2(30, 30)};
|
||||
|
||||
root.AddChild(boxContainer);
|
||||
|
||||
boxContainer.AddChild(control1);
|
||||
boxContainer.AddChild(control2);
|
||||
|
||||
root.Arrange(new UIBox2(0, 0, 50, 60));
|
||||
|
||||
Assert.That(control1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(control1.Size, Is.EqualTo(new Vector2(50, 20)));
|
||||
Assert.That(control2.Position, Is.EqualTo(new Vector2(0, 20)));
|
||||
Assert.That(control2.Size, Is.EqualTo(new Vector2(50, 30)));
|
||||
Assert.That(boxContainer.DesiredSize, Is.EqualTo(new Vector2(50, 60)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLayoutExpand()
|
||||
{
|
||||
var root = new LayoutContainer();
|
||||
var boxContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
MinSize = new Vector2(50, 60)
|
||||
};
|
||||
var control1 = new Control
|
||||
{
|
||||
VerticalExpand = true
|
||||
};
|
||||
var control2 = new Control {MinSize = new Vector2(30, 30)};
|
||||
|
||||
boxContainer.AddChild(control1);
|
||||
boxContainer.AddChild(control2);
|
||||
|
||||
root.AddChild(boxContainer);
|
||||
|
||||
root.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(control1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(control1.Size, Is.EqualTo(new Vector2(50, 30)));
|
||||
Assert.That(control2.Position, Is.EqualTo(new Vector2(0, 30)));
|
||||
Assert.That(control2.Size, Is.EqualTo(new Vector2(50, 30)));
|
||||
Assert.That(boxContainer.DesiredSize, Is.EqualTo(new Vector2(50, 60)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCalcMinSize()
|
||||
{
|
||||
var boxContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical
|
||||
};
|
||||
var control1 = new Control
|
||||
{
|
||||
MinSize = new Vector2(50, 30)
|
||||
};
|
||||
var control2 = new Control {MinSize = new Vector2(30, 50)};
|
||||
|
||||
boxContainer.AddChild(control1);
|
||||
boxContainer.AddChild(control2);
|
||||
|
||||
boxContainer.Measure(new Vector2(100, 100));
|
||||
|
||||
Assert.That(boxContainer.DesiredSize, Is.EqualTo(new Vector2(50, 80)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTwoExpand()
|
||||
{
|
||||
var root = new LayoutContainer();
|
||||
var boxContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
MinSize = new Vector2(30, 80)
|
||||
};
|
||||
var control1 = new Control
|
||||
{
|
||||
VerticalExpand = true,
|
||||
};
|
||||
var control2 = new Control
|
||||
{
|
||||
VerticalExpand = true,
|
||||
};
|
||||
var control3 = new Control {MinSize = new Vector2(0, 50)};
|
||||
|
||||
root.AddChild(boxContainer);
|
||||
|
||||
boxContainer.AddChild(control1);
|
||||
boxContainer.AddChild(control3);
|
||||
boxContainer.AddChild(control2);
|
||||
|
||||
root.Arrange(new UIBox2(0, 0, 250, 250));
|
||||
|
||||
Assert.That(control1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(control1.Size, Is.EqualTo(new Vector2(30, 15)));
|
||||
Assert.That(control3.Position, Is.EqualTo(new Vector2(0, 15)));
|
||||
Assert.That(control3.Size, Is.EqualTo(new Vector2(30, 50)));
|
||||
Assert.That(control2.Position, Is.EqualTo(new Vector2(0, 65)));
|
||||
Assert.That(control2.Size, Is.EqualTo(new Vector2(30, 15)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTwoExpandRatio()
|
||||
{
|
||||
var boxContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
SetSize = new Vector2(100, 10),
|
||||
Children =
|
||||
{
|
||||
new Control
|
||||
{
|
||||
MinWidth = 10,
|
||||
HorizontalExpand = true,
|
||||
SizeFlagsStretchRatio = 20,
|
||||
},
|
||||
new Control
|
||||
{
|
||||
MinWidth = 10,
|
||||
HorizontalExpand = true,
|
||||
SizeFlagsStretchRatio = 80
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
boxContainer.Arrange(UIBox2.FromDimensions(Vector2.Zero, boxContainer.SetSize));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(boxContainer.GetChild(0).Width, Is.EqualTo(20));
|
||||
Assert.That(boxContainer.GetChild(1).Width, Is.EqualTo(80));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTwoExpandOneSmall()
|
||||
{
|
||||
var boxContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
SetSize = new Vector2(100, 10),
|
||||
Children =
|
||||
{
|
||||
new Control
|
||||
{
|
||||
MinWidth = 30,
|
||||
HorizontalExpand = true,
|
||||
SizeFlagsStretchRatio = 20,
|
||||
},
|
||||
new Control
|
||||
{
|
||||
MinWidth = 30,
|
||||
HorizontalExpand = true,
|
||||
SizeFlagsStretchRatio = 80
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
boxContainer.Arrange(UIBox2.FromDimensions(Vector2.Zero, boxContainer.SetSize));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(boxContainer.GetChild(0).Width, Is.EqualTo(30));
|
||||
Assert.That(boxContainer.GetChild(1).Width, Is.EqualTo(70));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(CenterContainer))]
|
||||
public sealed class CenterContainerTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[Test]
|
||||
public void Test()
|
||||
{
|
||||
var container = new CenterContainer();
|
||||
var child = new Control {MinSize = new Vector2(50, 50)};
|
||||
|
||||
container.AddChild(child);
|
||||
|
||||
container.Arrange(UIBox2.FromDimensions(0, 0, 100, 100));
|
||||
|
||||
Assert.That(container.DesiredSize, Is.EqualTo(new Vector2(50, 50)));
|
||||
Assert.That(child.Position, Is.EqualTo(new Vector2(25, 25)));
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(50, 50)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(GridContainer))]
|
||||
public sealed class GridContainerTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBasic(bool limitByCount)
|
||||
{
|
||||
var grid = limitByCount ? new GridContainer {Columns = 2} : new GridContainer {MaxGridWidth = 125};
|
||||
var child1 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child2 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child3 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child4 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child5 = new Control {MinSize = new Vector2(50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.Arrange(new UIBox2(0, 0, 250, 250));
|
||||
|
||||
Assert.That(grid.DesiredSize, Is.EqualTo(new Vector2(104, 158)));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(54, 0)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(0, 54)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 54)));
|
||||
Assert.That(child5.Position, Is.EqualTo(new Vector2(0, 108)));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBasicRows(bool limitByCount)
|
||||
{
|
||||
var grid = limitByCount
|
||||
? new GridContainer {Rows = 2}
|
||||
: new GridContainer {MaxGridHeight = 125};
|
||||
var child1 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child2 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child3 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child4 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child5 = new Control {MinSize = new Vector2(50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.Arrange(new UIBox2(0, 0, 250, 250));
|
||||
|
||||
Assert.That(grid.DesiredSize, Is.EqualTo(new Vector2(158, 104)));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(0, 54)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(54, 0)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 54)));
|
||||
Assert.That(child5.Position, Is.EqualTo(new Vector2(108, 0)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnevenLimitSize()
|
||||
{
|
||||
// when uneven sizes are used and limiting by size, they should all be treated as equal size cells based on the
|
||||
// max minwidth / minheight among them.
|
||||
// Note that when limiting by count, the behavior is different - rows and columns are individually
|
||||
// expanded based on the max size of their elements
|
||||
var grid = new GridContainer {MaxGridWidth = 125};
|
||||
var child1 = new Control {MinSize = new Vector2(12, 24)};
|
||||
var child2 = new Control {MinSize = new Vector2(30, 50)};
|
||||
var child3 = new Control {MinSize = new Vector2(40, 20)};
|
||||
var child4 = new Control {MinSize = new Vector2(20, 12)};
|
||||
var child5 = new Control {MinSize = new Vector2(50, 10)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.Arrange(new UIBox2(0, 0, 250, 250));
|
||||
|
||||
Assert.That(grid.DesiredSize, Is.EqualTo(new Vector2(104, 158)));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(54, 0)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(0, 54)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 54)));
|
||||
Assert.That(child5.Position, Is.EqualTo(new Vector2(0, 108)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnevenLimitSizeRows()
|
||||
{
|
||||
var grid = new GridContainer {MaxGridHeight = 125};
|
||||
var child1 = new Control {MinSize = new Vector2(12, 2)};
|
||||
var child2 = new Control {MinSize = new Vector2(5, 23)};
|
||||
var child3 = new Control {MinSize = new Vector2(42, 4)};
|
||||
var child4 = new Control {MinSize = new Vector2(2, 50)};
|
||||
var child5 = new Control {MinSize = new Vector2(50, 34)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.Arrange(new UIBox2(0, 0, 250, 250));
|
||||
|
||||
Assert.That(grid.DesiredSize, Is.EqualTo(new Vector2(158, 104)));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(0, 54)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(54, 0)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 54)));
|
||||
Assert.That(child5.Position, Is.EqualTo(new Vector2(108, 0)));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBasicBackwards(bool limitByCount)
|
||||
{
|
||||
var grid = limitByCount
|
||||
? new GridContainer {Columns = 2, ExpandBackwards = true}
|
||||
: new GridContainer {MaxGridWidth = 125, ExpandBackwards = true};
|
||||
var child1 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child2 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child3 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child4 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child5 = new Control {MinSize = new Vector2(50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.Arrange(new UIBox2(0, 0, 250, 250));
|
||||
|
||||
Assert.That(grid.DesiredSize, Is.EqualTo(new Vector2(104, 158)));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(new Vector2(0, 108)));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(54, 108)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(0, 54)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 54)));
|
||||
Assert.That(child5.Position, Is.EqualTo(Vector2.Zero));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestBasicRowsBackwards(bool limitByCount)
|
||||
{
|
||||
var grid = limitByCount
|
||||
? new GridContainer {Rows = 2, ExpandBackwards = true}
|
||||
: new GridContainer {MaxGridHeight = 125, ExpandBackwards = true};
|
||||
var child1 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child2 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child3 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child4 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child5 = new Control {MinSize = new Vector2(50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.Arrange(new UIBox2(0, 0, 250, 250));
|
||||
|
||||
Assert.That(grid.DesiredSize, Is.EqualTo(new Vector2(158, 104)));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(new Vector2(108, 0)));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(108, 54)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(54, 0)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 54)));
|
||||
Assert.That(child5.Position, Is.EqualTo(Vector2.Zero));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestExpand(bool limitByCount)
|
||||
{
|
||||
// in the presence of a MaxWidth with expanding elements, the
|
||||
// pre-expanded size should be used to determine the size of each "cell", and then expansion
|
||||
// happens within the defined control size
|
||||
var grid = limitByCount
|
||||
? new GridContainer {Columns = 2, SetSize = new Vector2(200, 200)}
|
||||
: new GridContainer {MaxGridWidth = 125, SetSize = new Vector2(200, 200)};
|
||||
var child1 = new Control {MinSize = new Vector2(50, 50), HorizontalExpand = true};
|
||||
var child2 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child3 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child4 = new Control {MinSize = new Vector2(50, 50), VerticalExpand = true};
|
||||
var child5 = new Control {MinSize = new Vector2(50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.Arrange(new UIBox2(0, 0, 250, 250));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(child1.Size, Is.EqualTo(new Vector2(146, 50)));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(150, 0)));
|
||||
Assert.That(child2.Size, Is.EqualTo(new Vector2(50, 50)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(0, 54)));
|
||||
Assert.That(child3.Size, Is.EqualTo(new Vector2(146, 92)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(150, 54)));
|
||||
Assert.That(child4.Size, Is.EqualTo(new Vector2(50, 92)));
|
||||
Assert.That(child5.Position, Is.EqualTo(new Vector2(0, 150)));
|
||||
Assert.That(child5.Size, Is.EqualTo(new Vector2(146, 50)));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestExpandRows(bool limitByCount)
|
||||
{
|
||||
var grid = limitByCount
|
||||
? new GridContainer {Rows = 2, SetSize = new Vector2(200, 200)}
|
||||
: new GridContainer {MaxGridHeight = 125, SetSize = new Vector2(200, 200)};
|
||||
var child1 = new Control {MinSize = new Vector2(50, 50), VerticalExpand = true};
|
||||
var child2 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child3 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child4 = new Control {MinSize = new Vector2(50, 50), HorizontalExpand = true};
|
||||
var child5 = new Control {MinSize = new Vector2(50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.Arrange(new UIBox2(0, 0, 250, 250));
|
||||
|
||||
Assert.That(child1.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(child1.Size, Is.EqualTo(new Vector2(50, 146)));
|
||||
Assert.That(child2.Position, Is.EqualTo(new Vector2(0, 150)));
|
||||
Assert.That(child2.Size, Is.EqualTo(new Vector2(50, 50)));
|
||||
Assert.That(child3.Position, Is.EqualTo(new Vector2(54, 0)));
|
||||
Assert.That(child3.Size, Is.EqualTo(new Vector2(92, 146)));
|
||||
Assert.That(child4.Position, Is.EqualTo(new Vector2(54, 150)));
|
||||
Assert.That(child4.Size, Is.EqualTo(new Vector2(92, 50)));
|
||||
Assert.That(child5.Position, Is.EqualTo(new Vector2(150, 0)));
|
||||
Assert.That(child5.Size, Is.EqualTo(new Vector2(50, 146)));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestRowCount(bool limitByCount)
|
||||
{
|
||||
var grid = limitByCount
|
||||
? new GridContainer {Columns = 2}
|
||||
: new GridContainer {MaxGridWidth = 125};
|
||||
var child1 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child2 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child3 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child4 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child5 = new Control {MinSize = new Vector2(50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.Measure(new Vector2(250, 250));
|
||||
|
||||
Assert.That(grid.Rows, Is.EqualTo(3));
|
||||
|
||||
grid.RemoveChild(child5);
|
||||
|
||||
Assert.That(grid.Rows, Is.EqualTo(2));
|
||||
|
||||
grid.DisposeAllChildren();
|
||||
|
||||
Assert.That(grid.Rows, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestColumnCountRows(bool limitByCount)
|
||||
{
|
||||
var grid = limitByCount
|
||||
? new GridContainer {Rows = 2}
|
||||
: new GridContainer {MaxGridHeight = 125};
|
||||
var child1 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child2 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child3 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child4 = new Control {MinSize = new Vector2(50, 50)};
|
||||
var child5 = new Control {MinSize = new Vector2(50, 50)};
|
||||
|
||||
grid.AddChild(child1);
|
||||
grid.AddChild(child2);
|
||||
grid.AddChild(child3);
|
||||
grid.AddChild(child4);
|
||||
grid.AddChild(child5);
|
||||
|
||||
grid.Measure(new Vector2(250, 250));
|
||||
|
||||
Assert.That(grid.Columns, Is.EqualTo(3));
|
||||
|
||||
grid.RemoveChild(child5);
|
||||
|
||||
Assert.That(grid.Columns, Is.EqualTo(2));
|
||||
|
||||
grid.DisposeAllChildren();
|
||||
|
||||
Assert.That(grid.Columns, Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(LayoutContainer))]
|
||||
public sealed class LayoutContainerTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[Test]
|
||||
public void TestMarginLayoutBasic()
|
||||
{
|
||||
var control = new LayoutContainer {Size = new Vector2(100, 100)};
|
||||
var child = new Control();
|
||||
|
||||
LayoutContainer.SetMarginRight(child, 5);
|
||||
LayoutContainer.SetMarginBottom(child, 5);
|
||||
control.AddChild(child);
|
||||
|
||||
control.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(5, 5)));
|
||||
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
|
||||
|
||||
LayoutContainer.SetMarginTop(child, 3);
|
||||
LayoutContainer.SetMarginLeft(child, 3);
|
||||
|
||||
control.InvalidateArrange();
|
||||
control.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(2, 2)));
|
||||
Assert.That(child.Position, Is.EqualTo(new Vector2(3, 3)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAnchorLayoutBasic()
|
||||
{
|
||||
var control = new LayoutContainer {Size = new Vector2(100, 100)};
|
||||
var child = new Control();
|
||||
LayoutContainer.SetAnchorRight(child, 1);
|
||||
LayoutContainer.SetAnchorBottom(child, 1);
|
||||
control.AddChild(child);
|
||||
|
||||
control.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(100, 100)));
|
||||
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
|
||||
|
||||
LayoutContainer.SetAnchorLeft(child, 0.5f);
|
||||
control.InvalidateArrange();
|
||||
control.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
Assert.That(child.Position, Is.EqualTo(new Vector2(50, 0)));
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(50, 100)));
|
||||
LayoutContainer.SetAnchorTop(child, 0.5f);
|
||||
control.InvalidateArrange();
|
||||
control.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(child.Position, Is.EqualTo(new Vector2(50, 50)));
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(50, 50)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarginLayoutMinimumSize()
|
||||
{
|
||||
var control = new LayoutContainer {Size = new Vector2(100, 100)};
|
||||
var child = new Control
|
||||
{
|
||||
MinSize = new Vector2(50, 50),
|
||||
};
|
||||
|
||||
LayoutContainer.SetMarginRight(child, 20);
|
||||
LayoutContainer.SetMarginBottom(child, 20);
|
||||
|
||||
control.AddChild(child);
|
||||
control.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(50, 50)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarginAnchorLayout()
|
||||
{
|
||||
var control = new LayoutContainer {Size = new Vector2(100, 100)};
|
||||
var child = new Control();
|
||||
|
||||
LayoutContainer.SetMarginRight(child, -10);
|
||||
LayoutContainer.SetMarginBottom(child, -10);
|
||||
LayoutContainer.SetMarginTop(child, 10);
|
||||
LayoutContainer.SetMarginLeft(child, 10);
|
||||
LayoutContainer.SetAnchorRight(child, 1);
|
||||
LayoutContainer.SetAnchorBottom(child, 1);
|
||||
|
||||
control.AddChild(child);
|
||||
control.InvalidateArrange();
|
||||
control.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(child.Position, Is.EqualTo(new Vector2(10, 10)));
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(80, 80)));
|
||||
}
|
||||
|
||||
// Test that a control grows its size instead of position by default. (GrowDirection.End)
|
||||
[Test]
|
||||
public void TestGrowEnd()
|
||||
{
|
||||
var parent = new LayoutContainer();
|
||||
var child = new Control {SetSize = new Vector2(100, 100)};
|
||||
|
||||
LayoutContainer.SetAnchorRight(child, 1);
|
||||
|
||||
parent.AddChild(child);
|
||||
parent.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
// Child should be at 0,0.
|
||||
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
|
||||
|
||||
// Right margin should make the child not have enough space and grow left.
|
||||
LayoutContainer.SetMarginRight(child, -100);
|
||||
parent.InvalidateArrange();
|
||||
parent.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(100, 100)));
|
||||
}
|
||||
|
||||
// Test GrowDirection.Begin
|
||||
[Test]
|
||||
public void TestGrowBegin()
|
||||
{
|
||||
var parent = new LayoutContainer();
|
||||
var child = new Control {SetSize = new Vector2(100, 100)};
|
||||
|
||||
LayoutContainer.SetGrowHorizontal(child, LayoutContainer.GrowDirection.Begin);
|
||||
LayoutContainer.SetAnchorRight(child, 1);
|
||||
|
||||
parent.AddChild(child);
|
||||
parent.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
// Child should be at 0,0.
|
||||
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
|
||||
|
||||
// Right margin should make the child not have enough space and grow left.
|
||||
LayoutContainer.SetMarginRight(child, -100);
|
||||
parent.InvalidateArrange();
|
||||
parent.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(child.Position, Is.EqualTo(new Vector2(-100, 0)));
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(100, 100)));
|
||||
}
|
||||
|
||||
// Test GrowDirection.Both
|
||||
[Test]
|
||||
public void TestGrowBoth()
|
||||
{
|
||||
var parent = new LayoutContainer {MinSize = new Vector2(100, 100)};
|
||||
var child = new Control {SetSize = new Vector2(100, 100)};
|
||||
|
||||
LayoutContainer.SetGrowHorizontal(child, LayoutContainer.GrowDirection.Both);
|
||||
LayoutContainer.SetAnchorRight(child, 1);
|
||||
|
||||
parent.AddChild(child);
|
||||
parent.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
// Child should be at 0,0.
|
||||
Assert.That(child.Position, Is.EqualTo(Vector2.Zero));
|
||||
|
||||
// Right margin should make the child not have enough space and grow left.
|
||||
LayoutContainer.SetMarginRight(child, -100);
|
||||
parent.InvalidateArrange();
|
||||
parent.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(child.Position, Is.EqualTo(new Vector2(-50, 0)));
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(100, 100)));
|
||||
}
|
||||
|
||||
// Test that changing a grow direction updates the position correctly.
|
||||
[Test]
|
||||
public void TestGrowDirectionChange()
|
||||
{
|
||||
var parent = new LayoutContainer {MinSize = new Vector2(100, 100)};
|
||||
var child = new Control();
|
||||
parent.AddChild(child);
|
||||
parent.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
// Child should be at -100,0.
|
||||
Assert.That(child.Position, Is.EqualTo(new Vector2(0, 0)));
|
||||
|
||||
child.MinSize = new Vector2(100, 100);
|
||||
parent.InvalidateMeasure();
|
||||
parent.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(child.Position, Is.EqualTo(new Vector2(0, 0)));
|
||||
Assert.That(child.Size, Is.EqualTo(new Vector2(100, 100)));
|
||||
|
||||
LayoutContainer.SetGrowHorizontal(child, LayoutContainer.GrowDirection.Begin);
|
||||
parent.InvalidateArrange();
|
||||
parent.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(child.Position, Is.EqualTo(new Vector2(-100, 0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(LineEdit))]
|
||||
public sealed class LineEditTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[Test]
|
||||
public void TestRuneBackspace()
|
||||
{
|
||||
var lineEdit = new TestLineEdit();
|
||||
|
||||
lineEdit.Text = "Foo👏";
|
||||
lineEdit.CursorPosition = lineEdit.Text.Length;
|
||||
|
||||
var eventArgs = new GUIBoundKeyEventArgs(
|
||||
EngineKeyFunctions.TextBackspace,
|
||||
BoundKeyState.Down,
|
||||
default, false, default, default);
|
||||
lineEdit.KeyBindDown(eventArgs);
|
||||
|
||||
Assert.That(lineEdit.Text, Is.EqualTo("Foo"));
|
||||
Assert.That(lineEdit.CursorPosition, Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRuneDelete()
|
||||
{
|
||||
var lineEdit = new TestLineEdit();
|
||||
|
||||
lineEdit.Text = "Foo👏";
|
||||
lineEdit.CursorPosition = 3;
|
||||
|
||||
var eventArgs = new GUIBoundKeyEventArgs(
|
||||
EngineKeyFunctions.TextDelete,
|
||||
BoundKeyState.Down,
|
||||
default, false, default, default);
|
||||
lineEdit.KeyBindDown(eventArgs);
|
||||
|
||||
Assert.That(lineEdit.Text, Is.EqualTo("Foo"));
|
||||
Assert.That(lineEdit.CursorPosition, Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMoveLeft()
|
||||
{
|
||||
var lineEdit = new TestLineEdit();
|
||||
|
||||
lineEdit.Text = "Foo👏";
|
||||
lineEdit.CursorPosition = lineEdit.Text.Length;
|
||||
|
||||
var eventArgs = new GUIBoundKeyEventArgs(
|
||||
EngineKeyFunctions.TextCursorLeft,
|
||||
BoundKeyState.Down,
|
||||
default, false, default, default);
|
||||
lineEdit.KeyBindDown(eventArgs);
|
||||
|
||||
Assert.That(lineEdit.Text, Is.EqualTo("Foo👏"));
|
||||
Assert.That(lineEdit.CursorPosition, Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMoveRight()
|
||||
{
|
||||
var lineEdit = new TestLineEdit();
|
||||
|
||||
lineEdit.Text = "Foo👏";
|
||||
lineEdit.CursorPosition = 3;
|
||||
|
||||
var eventArgs = new GUIBoundKeyEventArgs(
|
||||
EngineKeyFunctions.TextCursorRight,
|
||||
BoundKeyState.Down,
|
||||
default, false, default, default);
|
||||
lineEdit.KeyBindDown(eventArgs);
|
||||
|
||||
Assert.That(lineEdit.Text, Is.EqualTo("Foo👏"));
|
||||
Assert.That(lineEdit.CursorPosition, Is.EqualTo(5));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMoveSelectLeft()
|
||||
{
|
||||
var lineEdit = new TestLineEdit();
|
||||
|
||||
lineEdit.Text = "Foo👏";
|
||||
lineEdit.CursorPosition = lineEdit.Text.Length;
|
||||
|
||||
var eventArgs = new GUIBoundKeyEventArgs(
|
||||
EngineKeyFunctions.TextCursorSelectLeft,
|
||||
BoundKeyState.Down,
|
||||
default, false, default, default);
|
||||
lineEdit.KeyBindDown(eventArgs);
|
||||
|
||||
Assert.That(lineEdit.Text, Is.EqualTo("Foo👏"));
|
||||
Assert.That(lineEdit.SelectionStart, Is.EqualTo(5));
|
||||
Assert.That(lineEdit.CursorPosition, Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMoveSelectRight()
|
||||
{
|
||||
var lineEdit = new TestLineEdit();
|
||||
|
||||
lineEdit.Text = "Foo👏";
|
||||
lineEdit.CursorPosition = 3;
|
||||
|
||||
var eventArgs = new GUIBoundKeyEventArgs(
|
||||
EngineKeyFunctions.TextCursorSelectRight,
|
||||
BoundKeyState.Down,
|
||||
default, false, default, default);
|
||||
lineEdit.KeyBindDown(eventArgs);
|
||||
|
||||
Assert.That(lineEdit.Text, Is.EqualTo("Foo👏"));
|
||||
Assert.That(lineEdit.SelectionStart, Is.EqualTo(3));
|
||||
Assert.That(lineEdit.CursorPosition, Is.EqualTo(5));
|
||||
}
|
||||
|
||||
[Test]
|
||||
// RIGHT
|
||||
[TestCase("Foo Bar Baz", false, 0, ExpectedResult = 3)]
|
||||
[TestCase("Foo Bar Baz", false, 8, ExpectedResult = 11)]
|
||||
[TestCase("Foo[Bar[Baz", false, 0, ExpectedResult = 3)]
|
||||
[TestCase("Foo[Bar[Baz", false, 3, ExpectedResult = 4)]
|
||||
[TestCase("Foo^Bar^Baz", false, 0, ExpectedResult = 3)]
|
||||
[TestCase("Foo^Bar^Baz", false, 3, ExpectedResult = 5)]
|
||||
[TestCase("Foo^^^Bar^Baz", false, 3, ExpectedResult = 9)]
|
||||
[TestCase("^^^ ^^^", false, 0, ExpectedResult = 6)]
|
||||
[TestCase("^^^ ^^^", false, 7, ExpectedResult = 13)]
|
||||
// LEFT
|
||||
[TestCase("Foo Bar Baz", true, 4, ExpectedResult = 0)]
|
||||
[TestCase("Foo Bar Baz", true, 11, ExpectedResult = 8)]
|
||||
[TestCase("Foo[Bar[Baz", true, 3, ExpectedResult = 0)]
|
||||
[TestCase("Foo[Bar[Baz", true, 4, ExpectedResult = 3)]
|
||||
[TestCase("Foo^Bar^Baz", true, 3, ExpectedResult = 0)]
|
||||
[TestCase("Foo^Bar^Baz", true, 5, ExpectedResult = 3)]
|
||||
[TestCase("Foo^^^Bar^Baz", true, 9, ExpectedResult = 3)]
|
||||
[TestCase("^^^ ^^^", true, 7, ExpectedResult = 0)]
|
||||
[TestCase("^^^ ^^^", true, 13, ExpectedResult = 7)]
|
||||
public int TestMoveWord(string text, bool left, int initCursorPos)
|
||||
{
|
||||
// ^ is replaced by 👏 because Rider refuses to run the tests otherwise.
|
||||
text = text.Replace("^", "👏");
|
||||
|
||||
var lineEdit = new TestLineEdit();
|
||||
|
||||
lineEdit.Text = text;
|
||||
lineEdit.CursorPosition = initCursorPos;
|
||||
|
||||
var eventArgs = new GUIBoundKeyEventArgs(
|
||||
left ? EngineKeyFunctions.TextCursorWordLeft : EngineKeyFunctions.TextCursorWordRight,
|
||||
BoundKeyState.Down,
|
||||
default, false, default, default);
|
||||
lineEdit.KeyBindDown(eventArgs);
|
||||
|
||||
return lineEdit.CursorPosition;
|
||||
}
|
||||
|
||||
|
||||
private sealed class TestLineEdit : LineEdit
|
||||
{
|
||||
public override bool HasKeyboardFocus()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(MultiselectOptionButton<>))]
|
||||
public sealed class MultiselectOptionButtonTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[Test]
|
||||
public void TestAddRemoveItem()
|
||||
{
|
||||
var uiManager = IoCManager.Resolve<IUserInterfaceManagerInternal>();
|
||||
uiManager.InitializeTesting();
|
||||
var optionButton = new MultiselectOptionButton<string>();
|
||||
optionButton.AddItem("Label1", "Key1");
|
||||
optionButton.AddItem("Label2", "Key2");
|
||||
optionButton.AddItem("Label3", "Key3");
|
||||
|
||||
Assert.That(optionButton.GetIdx("Key1"), Is.EqualTo(0));
|
||||
Assert.That(optionButton.GetIdx("Key2"), Is.EqualTo(1));
|
||||
Assert.That(optionButton.GetIdx("Key3"), Is.EqualTo(2));
|
||||
Assert.That(optionButton.GetItemKey(0), Is.EqualTo("Key1"));
|
||||
Assert.That(optionButton.GetItemKey(1), Is.EqualTo("Key2"));
|
||||
Assert.That(optionButton.GetItemKey(2), Is.EqualTo("Key3"));
|
||||
|
||||
optionButton.RemoveItem(1);
|
||||
|
||||
Assert.That(optionButton.GetIdx("Key1"), Is.EqualTo(0));
|
||||
Assert.That(optionButton.GetIdx("Key3"), Is.EqualTo(1));
|
||||
Assert.That(optionButton.GetItemKey(0), Is.EqualTo("Key1"));
|
||||
Assert.That(optionButton.GetItemKey(1), Is.EqualTo("Key3"));
|
||||
|
||||
optionButton.RemoveItem(0);
|
||||
|
||||
Assert.That(optionButton.GetIdx("Key3"), Is.EqualTo(0));
|
||||
Assert.That(optionButton.GetItemKey(0), Is.EqualTo("Key3"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(PopupContainer))]
|
||||
public sealed class PopupContainerTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[Test]
|
||||
public void Test()
|
||||
{
|
||||
var container = new PopupContainer {MinSize = new Vector2(100, 100)};
|
||||
|
||||
container.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
var popup = new Control {MinSize = new Vector2(50, 50)};
|
||||
|
||||
container.AddChild(popup);
|
||||
|
||||
PopupContainer.SetPopupOrigin(popup, new Vector2(25, 25));
|
||||
|
||||
container.InvalidateArrange();
|
||||
container.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(popup.Position, Is.EqualTo(new Vector2(25, 25)));
|
||||
Assert.That(popup.Size, Is.EqualTo(new Vector2(50, 50)));
|
||||
|
||||
// Test that pos gets pushed back to the top left if the size + offset is too large to fit.
|
||||
PopupContainer.SetPopupOrigin(popup, new Vector2(75, 75));
|
||||
|
||||
container.InvalidateArrange();
|
||||
container.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(popup.Position, Is.EqualTo(new Vector2(50, 50)));
|
||||
Assert.That(popup.Size, Is.EqualTo(new Vector2(50, 50)));
|
||||
|
||||
// Test that pos = 0 if the popup is too large to fit.
|
||||
popup.MinSize = new Vector2(150, 150);
|
||||
|
||||
container.InvalidateArrange();
|
||||
container.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(popup.Position, Is.EqualTo(new Vector2(0, 0)));
|
||||
Assert.That(popup.Size, Is.EqualTo(new Vector2(150, 150)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAltPos()
|
||||
{
|
||||
var container = new PopupContainer {MinSize = new Vector2(100, 100)};
|
||||
|
||||
container.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
var popup = new Control {MinSize = new Vector2(50, 50)};
|
||||
|
||||
container.AddChild(popup);
|
||||
|
||||
PopupContainer.SetPopupOrigin(popup, new Vector2(75, 75));
|
||||
PopupContainer.SetAltOrigin(popup, new Vector2(65, 25));
|
||||
|
||||
container.InvalidateArrange();
|
||||
container.Arrange(new UIBox2(0, 0, 100, 100));
|
||||
|
||||
Assert.That(popup.Position, Is.EqualTo(new Vector2(15, 25)));
|
||||
Assert.That(popup.Size, Is.EqualTo(new Vector2(50, 50)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface.Controls
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(RadioOptions<int>))]
|
||||
public sealed class RadioOptionsTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[Test]
|
||||
public void TestDefaultInvoke()
|
||||
{
|
||||
//Arrange
|
||||
RadioOptions<int> _optionButton = new RadioOptions<int>(RadioOptionsLayout.Horizontal);
|
||||
|
||||
int itemId = _optionButton.AddItem("High", 1);
|
||||
|
||||
int countSelected = 0;
|
||||
_optionButton.OnItemSelected += args =>
|
||||
{
|
||||
countSelected++;
|
||||
};
|
||||
|
||||
//Act
|
||||
_optionButton.InvokeItemSelected(new RadioOptionItemSelectedEventArgs<int>(itemId, _optionButton));
|
||||
|
||||
//Assert
|
||||
Assert.That(countSelected, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOverrideInvoke()
|
||||
{
|
||||
//Arrange
|
||||
RadioOptions<int> _optionButton = new RadioOptions<int>(RadioOptionsLayout.Horizontal);
|
||||
|
||||
int countSelected = 0;
|
||||
|
||||
int itemId = _optionButton.AddItem("High", 1, args => { countSelected--; });
|
||||
int itemId2 = _optionButton.AddItem("High", 2);
|
||||
|
||||
_optionButton.OnItemSelected += args =>
|
||||
{
|
||||
countSelected++;
|
||||
};
|
||||
|
||||
//Act
|
||||
_optionButton.InvokeItemSelected(new RadioOptionItemSelectedEventArgs<int>(itemId, _optionButton));
|
||||
|
||||
//Assert
|
||||
Assert.That(countSelected, Is.EqualTo(-1));
|
||||
|
||||
//Act
|
||||
_optionButton.InvokeItemSelected(new RadioOptionItemSelectedEventArgs<int>(itemId2, _optionButton));
|
||||
_optionButton.InvokeItemSelected(new RadioOptionItemSelectedEventArgs<int>(itemId2, _optionButton));
|
||||
|
||||
//Assert
|
||||
Assert.That(countSelected, Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface.Controls;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(TextEditShared))]
|
||||
[Parallelizable]
|
||||
internal sealed class TextEditSharedTest
|
||||
{
|
||||
// @formatter:off
|
||||
[Test]
|
||||
[TestCase("foo bar baz", 0, ExpectedResult = 0)]
|
||||
[TestCase("foo bar baz", 1, ExpectedResult = 0)]
|
||||
[TestCase("foo bar baz", 4, ExpectedResult = 0)]
|
||||
[TestCase("foo bar baz", 5, ExpectedResult = 4)]
|
||||
[TestCase("foo bar baz", 8, ExpectedResult = 4)]
|
||||
[TestCase("foo bar baz", 9, ExpectedResult = 8)]
|
||||
[TestCase("foo +bar baz", 5, ExpectedResult = 4)]
|
||||
[TestCase("foo +bar baz", 4, ExpectedResult = 0)]
|
||||
[TestCase("foo +bar baz", 6, ExpectedResult = 5)]
|
||||
[TestCase("foo +bar baz", 7, ExpectedResult = 5)]
|
||||
[TestCase("Foo Bar Baz", 4, ExpectedResult = 0)]
|
||||
[TestCase("Foo Bar Baz", 11, ExpectedResult = 8)]
|
||||
[TestCase("Foo[Bar[Baz", 3, ExpectedResult = 0)]
|
||||
[TestCase("Foo[Bar[Baz", 4, ExpectedResult = 3)]
|
||||
[TestCase("Foo^Bar^Baz", 3, ExpectedResult = 0)]
|
||||
[TestCase("Foo^Bar^Baz", 5, ExpectedResult = 3)]
|
||||
[TestCase("Foo^^^Bar^Baz", 9, ExpectedResult = 3)]
|
||||
[TestCase("^^^ ^^^", 7, ExpectedResult = 0)]
|
||||
[TestCase("^^^ ^^^", 13, ExpectedResult = 7)]
|
||||
// @formatter:on
|
||||
public int TestPrevWordPosition(string str, int cursor)
|
||||
{
|
||||
// For my sanity.
|
||||
str = str.Replace("^", "👏");
|
||||
|
||||
return TextEditShared.PrevWordPosition(str, cursor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
// @formatter:off
|
||||
[TestCase("foo bar baz", 11, ExpectedResult = 11)]
|
||||
[TestCase("foo bar baz", 0, ExpectedResult = 3 )]
|
||||
[TestCase("foo bar baz", 1, ExpectedResult = 3 )]
|
||||
[TestCase("foo bar baz", 3, ExpectedResult = 7 )]
|
||||
[TestCase("foo bar baz", 4, ExpectedResult = 7 )]
|
||||
[TestCase("foo bar baz", 5, ExpectedResult = 7 )]
|
||||
[TestCase("Foo Bar Baz", 0, ExpectedResult = 3 )]
|
||||
[TestCase("Foo Bar Baz", 8, ExpectedResult = 11)]
|
||||
[TestCase("foo +bar baz", 0, ExpectedResult = 3 )]
|
||||
[TestCase("foo +bar baz", 4, ExpectedResult = 5 )]
|
||||
[TestCase("Foo[Bar[Baz", 0, ExpectedResult = 3 )]
|
||||
[TestCase("Foo[Bar[Baz", 3, ExpectedResult = 4 )]
|
||||
[TestCase("Foo^Bar^Baz", 0, ExpectedResult = 3 )]
|
||||
[TestCase("Foo^Bar^Baz", 3, ExpectedResult = 5 )]
|
||||
[TestCase("Foo^^^Bar^Baz", 3, ExpectedResult = 9 )]
|
||||
[TestCase("^^^ ^^^", 0, ExpectedResult = 6 )]
|
||||
[TestCase("^^^ ^^^", 7, ExpectedResult = 13)]
|
||||
// @formatter:on
|
||||
public int TestEndWordPosition(string str, int cursor)
|
||||
{
|
||||
// For my sanity.
|
||||
str = str.Replace("^", "👏");
|
||||
|
||||
return TextEditShared.EndWordPosition(str, cursor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface.Controls;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(TextEdit))]
|
||||
public sealed class TextEditTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void Setup()
|
||||
{
|
||||
IoCManager.Resolve<IUserInterfaceManagerInternal>().InitializeTesting();
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/space-wizards/RobustToolbox/issues/4953
|
||||
// It was possible to move the cursor up/down if there was multi-line placeholder text.
|
||||
[Test]
|
||||
public void TestInvalidMoveInPlaceholder()
|
||||
{
|
||||
var textEdit = new TextEdit { Placeholder = new Rope.Leaf("Foo\nBar") };
|
||||
textEdit.Arrange(new UIBox2(0, 0, 200, 200));
|
||||
|
||||
var click = new GUIBoundKeyEventArgs(EngineKeyFunctions.TextCursorDown, BoundKeyState.Down, new ScreenCoordinates(), true, Vector2.Zero, Vector2.Zero);
|
||||
textEdit.KeyBindDown(click);
|
||||
textEdit.KeyBindUp(click);
|
||||
|
||||
Assert.That(textEdit.CursorPosition.Index, Is.Zero);
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/space-wizards/RobustToolbox/issues/4957
|
||||
// Moving left (with the arrow keys) in an empty TextEdit would cause an exception.
|
||||
[Test]
|
||||
public void TestEmptyMoveLeft()
|
||||
{
|
||||
var textEdit = new TextEdit();
|
||||
textEdit.Arrange(new UIBox2(0, 0, 200, 200));
|
||||
|
||||
var click = new GUIBoundKeyEventArgs(EngineKeyFunctions.TextCursorLeft, BoundKeyState.Down, new ScreenCoordinates(), true, Vector2.Zero, Vector2.Zero);
|
||||
textEdit.KeyBindDown(click);
|
||||
textEdit.KeyBindUp(click);
|
||||
}
|
||||
}
|
||||
137
Robust.Client.IntegrationTests/UserInterface/StylesheetTest.cs
Normal file
137
Robust.Client.IntegrationTests/UserInterface/StylesheetTest.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class StylesheetTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void Setup()
|
||||
{
|
||||
IoCManager.Resolve<IUserInterfaceManagerInternal>().InitializeTesting();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSelectors()
|
||||
{
|
||||
var selectorElementLabel = new SelectorElement(typeof(Label), null, null, null);
|
||||
|
||||
var label = new Label();
|
||||
var panel = new PanelContainer {StyleIdentifier = "bar"};
|
||||
Assert.That(selectorElementLabel.Matches(label), Is.True);
|
||||
Assert.That(selectorElementLabel.Matches(panel), Is.False);
|
||||
|
||||
selectorElementLabel = new SelectorElement(typeof(Label), new[] {"foo"}, null, null);
|
||||
Assert.That(selectorElementLabel.Matches(label), Is.False);
|
||||
Assert.That(selectorElementLabel.Matches(panel), Is.False);
|
||||
|
||||
Assert.That(label.HasStyleClass("foo"), Is.False);
|
||||
label.AddStyleClass("foo");
|
||||
Assert.That(selectorElementLabel.Matches(label), Is.True);
|
||||
Assert.That(label.HasStyleClass("foo"));
|
||||
// Make sure it doesn't throw.
|
||||
label.AddStyleClass("foo");
|
||||
label.RemoveStyleClass("foo");
|
||||
Assert.That(selectorElementLabel.Matches(label), Is.False);
|
||||
Assert.That(label.HasStyleClass("foo"), Is.False);
|
||||
// Make sure it doesn't throw.
|
||||
label.RemoveStyleClass("foo");
|
||||
|
||||
selectorElementLabel = new SelectorElement(null, null, "bar", null);
|
||||
Assert.That(selectorElementLabel.Matches(label), Is.False);
|
||||
Assert.That(selectorElementLabel.Matches(panel), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStyleProperties()
|
||||
{
|
||||
var sheet = new Stylesheet(new[]
|
||||
{
|
||||
new StyleRule(new SelectorElement(typeof(Label), null, "baz", null), new[]
|
||||
{
|
||||
new StyleProperty("foo", "honk"),
|
||||
}),
|
||||
new StyleRule(new SelectorElement(typeof(Label), null, null, null), new[]
|
||||
{
|
||||
new StyleProperty("foo", "heh"),
|
||||
}),
|
||||
new StyleRule(new SelectorElement(typeof(Label), null, null, null), new[]
|
||||
{
|
||||
new StyleProperty("foo", "bar"),
|
||||
}),
|
||||
});
|
||||
|
||||
var uiMgr = IoCManager.Resolve<IUserInterfaceManager>();
|
||||
uiMgr.Stylesheet = sheet;
|
||||
|
||||
var control = new Label();
|
||||
|
||||
uiMgr.StateRoot.AddChild(control);
|
||||
control.ForceRunStyleUpdate();
|
||||
|
||||
control.TryGetStyleProperty("foo", out string? value);
|
||||
Assert.That(value, Is.EqualTo("bar"));
|
||||
|
||||
control.StyleIdentifier = "baz";
|
||||
control.ForceRunStyleUpdate();
|
||||
|
||||
control.TryGetStyleProperty("foo", out value);
|
||||
Assert.That(value, Is.EqualTo("honk"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStylesheetOverride()
|
||||
{
|
||||
var sheetA = new Stylesheet(new[]
|
||||
{
|
||||
new StyleRule(SelectorElement.Class("A"), new[] {new StyleProperty("foo", "bar")}),
|
||||
});
|
||||
|
||||
var sheetB = new Stylesheet(new[]
|
||||
{
|
||||
new StyleRule(SelectorElement.Class("A"), new[] {new StyleProperty("foo", "honk!")})
|
||||
});
|
||||
|
||||
// Set style sheet to null, property shouldn't exist.
|
||||
|
||||
var uiMgr = IoCManager.Resolve<IUserInterfaceManager>();
|
||||
uiMgr.Stylesheet = null;
|
||||
|
||||
var baseControl = new Control();
|
||||
baseControl.AddStyleClass("A");
|
||||
var childA = new Control();
|
||||
childA.AddStyleClass("A");
|
||||
var childB = new Control();
|
||||
childB.AddStyleClass("A");
|
||||
|
||||
uiMgr.StateRoot.AddChild(baseControl);
|
||||
|
||||
baseControl.AddChild(childA);
|
||||
childA.AddChild(childB);
|
||||
|
||||
baseControl.ForceRunStyleUpdate();
|
||||
|
||||
Assert.That(baseControl.TryGetStyleProperty("foo", out object? _), Is.False);
|
||||
|
||||
uiMgr.RootControl.Stylesheet = sheetA;
|
||||
childA.Stylesheet = sheetB;
|
||||
|
||||
// Assign sheets.
|
||||
baseControl.ForceRunStyleUpdate();
|
||||
|
||||
baseControl.TryGetStyleProperty("foo", out object? value);
|
||||
Assert.That(value, Is.EqualTo("bar"));
|
||||
|
||||
childA.TryGetStyleProperty("foo", out value);
|
||||
Assert.That(value, Is.EqualTo("honk!"));
|
||||
|
||||
childB.TryGetStyleProperty("foo", out value);
|
||||
Assert.That(value, Is.EqualTo("honk!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.UnitTesting.Client.UserInterface
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class UserInterfaceManagerTest : RobustUnitTest
|
||||
{
|
||||
public override UnitTestProject Project => UnitTestProject.Client;
|
||||
|
||||
private IUserInterfaceManagerInternal _userInterfaceManager = default!;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_userInterfaceManager = IoCManager.Resolve<IUserInterfaceManagerInternal>();
|
||||
_userInterfaceManager.InitializeTesting();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[SuppressMessage("ReSharper", "AccessToModifiedClosure")]
|
||||
public void TestMouseDown()
|
||||
{
|
||||
// We create 4 controls.
|
||||
// Control 2 is set to stop mouse events,
|
||||
// Control 3 pass,
|
||||
// Control 4 ignore.
|
||||
// We check that 4 and 1 do not receive events, that 3 receives before 2, and that positions are correct.
|
||||
var control1 = new LayoutContainer
|
||||
{
|
||||
MinSize = new Vector2(50, 50)
|
||||
};
|
||||
var control2 = new LayoutContainer
|
||||
{
|
||||
MinSize = new Vector2(50, 50),
|
||||
MouseFilter = Control.MouseFilterMode.Stop
|
||||
};
|
||||
var control3 = new LayoutContainer
|
||||
{
|
||||
MinSize = new Vector2(50, 50),
|
||||
MouseFilter = Control.MouseFilterMode.Pass
|
||||
};
|
||||
var control4 = new LayoutContainer
|
||||
{
|
||||
MinSize = new Vector2(50, 50),
|
||||
MouseFilter = Control.MouseFilterMode.Ignore
|
||||
};
|
||||
|
||||
_userInterfaceManager.RootControl.AddChild(control1);
|
||||
control1.AddChild(control2);
|
||||
// Offsets to test relative positioning on the events.
|
||||
LayoutContainer.SetPosition(control2, new Vector2(5, 5));
|
||||
control2.AddChild(control3);
|
||||
LayoutContainer.SetPosition(control3, new Vector2(5, 5));
|
||||
control3.AddChild(control4);
|
||||
LayoutContainer.SetPosition(control4, new Vector2(5, 5));
|
||||
|
||||
control1.Arrange(new UIBox2(0, 0, 50, 50));
|
||||
|
||||
var mouseEvent = new BoundKeyEventArgs(EngineKeyFunctions.Use, BoundKeyState.Down,
|
||||
new ScreenCoordinates(30, 30, WindowId.Main), true);
|
||||
|
||||
var control2Fired = false;
|
||||
var control3Fired = false;
|
||||
|
||||
control1.OnKeyBindDown += _ => Assert.Fail("Control 1 should not get a mouse event.");
|
||||
|
||||
void Control2MouseDown(GUIBoundKeyEventArgs ev)
|
||||
{
|
||||
Assert.That(control2Fired, NUnit.Framework.Is.False);
|
||||
Assert.That(control3Fired, NUnit.Framework.Is.True);
|
||||
|
||||
Assert.That(ev.RelativePosition, NUnit.Framework.Is.EqualTo(new Vector2(25, 25)));
|
||||
|
||||
control2Fired = true;
|
||||
}
|
||||
|
||||
control2.OnKeyBindDown += Control2MouseDown;
|
||||
|
||||
control3.OnKeyBindDown += ev =>
|
||||
{
|
||||
Assert.That(control2Fired, NUnit.Framework.Is.False);
|
||||
Assert.That(control3Fired, NUnit.Framework.Is.False);
|
||||
|
||||
Assert.That(ev.RelativePosition, NUnit.Framework.Is.EqualTo(new Vector2(20, 20)));
|
||||
|
||||
control3Fired = true;
|
||||
};
|
||||
|
||||
control4.OnKeyBindDown += _ => Assert.Fail("Control 4 should not get a mouse event.");
|
||||
|
||||
_userInterfaceManager.KeyBindDown(mouseEvent);
|
||||
_userInterfaceManager.KeyBindUp(mouseEvent);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(control2Fired, NUnit.Framework.Is.True);
|
||||
Assert.That(control3Fired, NUnit.Framework.Is.True);
|
||||
});
|
||||
|
||||
// Step two: instead of relying on stop for control2 to prevent the event reaching control1,
|
||||
// handle the event in control2.
|
||||
|
||||
control2Fired = false;
|
||||
control3Fired = false;
|
||||
|
||||
control2.OnKeyBindDown -= Control2MouseDown;
|
||||
control2.OnKeyBindDown += ev =>
|
||||
{
|
||||
Assert.That(control2Fired, NUnit.Framework.Is.False);
|
||||
Assert.That(control3Fired, NUnit.Framework.Is.True);
|
||||
|
||||
Assert.That(ev.RelativePosition, NUnit.Framework.Is.EqualTo(new Vector2(25, 25)));
|
||||
|
||||
control2Fired = true;
|
||||
ev.Handle();
|
||||
};
|
||||
control2.MouseFilter = Control.MouseFilterMode.Pass;
|
||||
|
||||
_userInterfaceManager.KeyBindDown(mouseEvent);
|
||||
_userInterfaceManager.KeyBindUp(mouseEvent);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(control2Fired, NUnit.Framework.Is.True);
|
||||
Assert.That(control3Fired, NUnit.Framework.Is.True);
|
||||
});
|
||||
|
||||
control1.Orphan();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGrabKeyboardFocus()
|
||||
{
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.Null);
|
||||
var control1 = new Control {CanKeyboardFocus = true};
|
||||
|
||||
control1.GrabKeyboardFocus();
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.EqualTo(control1));
|
||||
Assert.That(control1.HasKeyboardFocus(), NUnit.Framework.Is.EqualTo(true));
|
||||
|
||||
control1.ReleaseKeyboardFocus();
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGrabKeyboardFocusSteal()
|
||||
{
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.Null);
|
||||
var control1 = new Control {CanKeyboardFocus = true};
|
||||
var control2 = new Control {CanKeyboardFocus = true};
|
||||
|
||||
control1.GrabKeyboardFocus();
|
||||
control2.GrabKeyboardFocus();
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.EqualTo(control2));
|
||||
control2.ReleaseKeyboardFocus();
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGrabKeyboardFocusOtherRelease()
|
||||
{
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.Null);
|
||||
var control1 = new Control {CanKeyboardFocus = true};
|
||||
var control2 = new Control {CanKeyboardFocus = true};
|
||||
|
||||
control1.GrabKeyboardFocus();
|
||||
control2.ReleaseKeyboardFocus();
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.EqualTo(control1));
|
||||
_userInterfaceManager.ReleaseKeyboardFocus();
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGrabKeyboardFocusNull()
|
||||
{
|
||||
Assert.That(() => _userInterfaceManager.GrabKeyboardFocus(null!), Throws.ArgumentNullException);
|
||||
Assert.That(() => _userInterfaceManager.ReleaseKeyboardFocus(null!), Throws.ArgumentNullException);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGrabKeyboardFocusBlocked()
|
||||
{
|
||||
var control = new Control();
|
||||
Assert.That(() => _userInterfaceManager.GrabKeyboardFocus(control), Throws.ArgumentException);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGrabKeyboardFocusOnClick()
|
||||
{
|
||||
var control = new Control
|
||||
{
|
||||
CanKeyboardFocus = true,
|
||||
KeyboardFocusOnClick = true,
|
||||
MinSize = new Vector2(50, 50),
|
||||
MouseFilter = Control.MouseFilterMode.Stop
|
||||
};
|
||||
|
||||
_userInterfaceManager.RootControl.AddChild(control);
|
||||
|
||||
_userInterfaceManager.RootControl.Arrange(new UIBox2(0, 0, 50, 50));
|
||||
|
||||
_userInterfaceManager.HandleCanFocusDown(new ScreenCoordinates(30, 30, WindowId.Main), out _);
|
||||
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.EqualTo(control));
|
||||
_userInterfaceManager.ReleaseKeyboardFocus();
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.Null);
|
||||
|
||||
control.Orphan();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assert that indeed nothing happens when the control has focus modes off.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestNotGrabKeyboardFocusOnClick()
|
||||
{
|
||||
var control = new Control
|
||||
{
|
||||
MinSize = new Vector2(50, 50),
|
||||
MouseFilter = Control.MouseFilterMode.Stop
|
||||
};
|
||||
|
||||
_userInterfaceManager.RootControl.AddChild(control);
|
||||
|
||||
var pos = new ScreenCoordinates(30, 30, WindowId.Main);
|
||||
|
||||
var mouseEvent = new GUIBoundKeyEventArgs(EngineKeyFunctions.Use, BoundKeyState.Down,
|
||||
pos, true, pos.Position / 1 - control.GlobalPosition, pos.Position - control.GlobalPixelPosition);
|
||||
|
||||
_userInterfaceManager.KeyBindDown(mouseEvent);
|
||||
_userInterfaceManager.KeyBindUp(mouseEvent);
|
||||
|
||||
Assert.That(_userInterfaceManager.KeyboardFocused, NUnit.Framework.Is.Null);
|
||||
|
||||
control.Orphan();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user