Initial commit: OpenRA game engine
Fork from OpenRA/OpenRA with one-click launch script (start-ra.cmd) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
43
OpenRA.Test/OpenRA.Game/ActionQueueTest.cs
Normal file
43
OpenRA.Test/OpenRA.Game/ActionQueueTest.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class ActionQueueTest
|
||||
{
|
||||
[TestCase(TestName = "ActionQueue performs actions in order of time, then insertion order.")]
|
||||
public void ActionsArePerformedOrderedByTimeThenByInsertionOrder()
|
||||
{
|
||||
var list = new List<int>();
|
||||
var queue = new ActionQueue();
|
||||
queue.Add(() => list.Add(1), 0);
|
||||
queue.Add(() => list.Add(7), 2);
|
||||
queue.Add(() => list.Add(8), 2);
|
||||
queue.Add(() => list.Add(4), 1);
|
||||
queue.Add(() => list.Add(2), 0);
|
||||
queue.Add(() => list.Add(3), 0);
|
||||
queue.Add(() => list.Add(9), 2);
|
||||
queue.Add(() => list.Add(5), 1);
|
||||
queue.Add(() => list.Add(6), 1);
|
||||
queue.PerformActions(1);
|
||||
queue.PerformActions(2);
|
||||
queue.PerformActions(3);
|
||||
if (!list.SequenceEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]))
|
||||
Assert.Fail("Actions were not performed in the correct order. Actual order was: " + string.Join(", ", list));
|
||||
}
|
||||
}
|
||||
}
|
||||
123
OpenRA.Test/OpenRA.Game/ActorInfoTest.cs
Normal file
123
OpenRA.Test/OpenRA.Game/ActorInfoTest.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
interface IMock : ITraitInfoInterface { }
|
||||
class MockTraitInfo : TraitInfo { public override object Create(ActorInitializer init) { return null; } }
|
||||
class MockInheritInfo : MockTraitInfo { }
|
||||
|
||||
sealed class MockAInfo : MockInheritInfo, IMock { }
|
||||
sealed class MockBInfo : MockTraitInfo, Requires<IMock>, Requires<MockInheritInfo> { }
|
||||
sealed class MockCInfo : MockTraitInfo, Requires<MockBInfo> { }
|
||||
|
||||
sealed class MockDInfo : MockTraitInfo, Requires<MockEInfo> { }
|
||||
sealed class MockEInfo : MockTraitInfo, Requires<MockFInfo> { }
|
||||
sealed class MockFInfo : MockTraitInfo, Requires<MockDInfo> { }
|
||||
|
||||
sealed class MockGInfo : MockInheritInfo, IMock, NotBefore<MockAInfo> { }
|
||||
sealed class MockHInfo : MockTraitInfo, NotBefore<IMock>, NotBefore<MockInheritInfo>, NotBefore<MockBInfo> { }
|
||||
sealed class MockIInfo : MockTraitInfo, NotBefore<MockHInfo>, NotBefore<MockCInfo> { }
|
||||
|
||||
sealed class MockJInfo : MockTraitInfo, NotBefore<MockKInfo> { }
|
||||
sealed class MockKInfo : MockTraitInfo, NotBefore<MockLInfo> { }
|
||||
sealed class MockLInfo : MockTraitInfo, NotBefore<MockJInfo> { }
|
||||
|
||||
[TestFixture]
|
||||
sealed class ActorInfoTest
|
||||
{
|
||||
[TestCase(TestName = "Trait ordering sorts in dependency order correctly")]
|
||||
public void TraitOrderingSortsCorrectly()
|
||||
{
|
||||
var unorderedTraits = new TraitInfo[] { new MockBInfo(), new MockCInfo(), new MockAInfo(), new MockBInfo() };
|
||||
var actorInfo = new ActorInfo("test", unorderedTraits);
|
||||
var orderedTraits = actorInfo.TraitsInConstructOrder().ToArray();
|
||||
|
||||
Assert.That(unorderedTraits, Is.EquivalentTo(orderedTraits));
|
||||
|
||||
for (var i = 0; i < orderedTraits.Length; i++)
|
||||
{
|
||||
var traitTypesThatMustOccurBeforeThisTrait =
|
||||
ActorInfo.PrerequisitesOf(orderedTraits[i]).Concat(ActorInfo.OptionalPrerequisitesOf(orderedTraits[i]));
|
||||
var traitTypesThatOccurAfterThisTrait = orderedTraits.Skip(i + 1).Select(ti => ti.GetType());
|
||||
var traitTypesThatShouldOccurEarlier = traitTypesThatOccurAfterThisTrait.Intersect(traitTypesThatMustOccurBeforeThisTrait);
|
||||
Assert.That(traitTypesThatShouldOccurEarlier, Is.Empty, "Dependency order has not been satisfied.");
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Trait ordering sorts in optional dependency order correctly")]
|
||||
public void OptionalTraitOrderingSortsCorrectly()
|
||||
{
|
||||
var unorderedTraits = new TraitInfo[] { new MockHInfo(), new MockIInfo(), new MockGInfo(), new MockHInfo() };
|
||||
var actorInfo = new ActorInfo("test", unorderedTraits);
|
||||
var orderedTraits = actorInfo.TraitsInConstructOrder().ToArray();
|
||||
|
||||
Assert.That(unorderedTraits, Is.EquivalentTo(orderedTraits));
|
||||
|
||||
for (var i = 0; i < orderedTraits.Length; i++)
|
||||
{
|
||||
var traitTypesThatMustOccurBeforeThisTrait =
|
||||
ActorInfo.PrerequisitesOf(orderedTraits[i]).Concat(ActorInfo.OptionalPrerequisitesOf(orderedTraits[i]));
|
||||
var traitTypesThatOccurAfterThisTrait = orderedTraits.Skip(i + 1).Select(ti => ti.GetType());
|
||||
var traitTypesThatShouldOccurEarlier = traitTypesThatOccurAfterThisTrait.Intersect(traitTypesThatMustOccurBeforeThisTrait);
|
||||
Assert.That(traitTypesThatShouldOccurEarlier, Is.Empty, "Dependency order has not been satisfied.");
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Trait ordering exception reports missing dependencies")]
|
||||
public void TraitOrderingReportsMissingDependencies()
|
||||
{
|
||||
var actorInfo = new ActorInfo("test", new MockBInfo(), new MockCInfo());
|
||||
var ex = Assert.Throws<YamlException>(() => actorInfo.TraitsInConstructOrder());
|
||||
|
||||
Assert.That(ex.Message, Does.Contain(nameof(MockBInfo)), "Exception message did not report a missing dependency.");
|
||||
Assert.That(ex.Message, Does.Contain(nameof(MockCInfo)), "Exception message did not report a missing dependency.");
|
||||
Assert.That(ex.Message, Does.Contain(nameof(MockInheritInfo)), "Exception message did not report a missing dependency (from a base class).");
|
||||
Assert.That(ex.Message, Does.Contain(nameof(IMock)), "Exception message did not report a missing dependency (from an interface).");
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Trait ordering allows optional dependencies to be missing")]
|
||||
public void TraitOrderingAllowsMissingOptionalDependencies()
|
||||
{
|
||||
var unorderedTraits = new TraitInfo[] { new MockHInfo(), new MockIInfo() };
|
||||
var actorInfo = new ActorInfo("test", unorderedTraits);
|
||||
var orderedTraits = actorInfo.TraitsInConstructOrder().ToArray();
|
||||
|
||||
Assert.That(unorderedTraits, Is.EquivalentTo(orderedTraits));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Trait ordering exception reports cyclic dependencies")]
|
||||
public void TraitOrderingReportsCyclicDependencies()
|
||||
{
|
||||
var actorInfo = new ActorInfo("test", new MockDInfo(), new MockEInfo(), new MockFInfo());
|
||||
var ex = Assert.Throws<YamlException>(() => actorInfo.TraitsInConstructOrder());
|
||||
|
||||
Assert.That(ex.Message, Does.Contain(nameof(MockDInfo)), "Exception message should report all cyclic dependencies.");
|
||||
Assert.That(ex.Message, Does.Contain(nameof(MockEInfo)), "Exception message should report all cyclic dependencies.");
|
||||
Assert.That(ex.Message, Does.Contain(nameof(MockFInfo)), "Exception message should report all cyclic dependencies.");
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Trait ordering exception reports cyclic optional dependencies")]
|
||||
public void TraitOrderingReportsCyclicOptionalDependencies()
|
||||
{
|
||||
var actorInfo = new ActorInfo("test", new MockJInfo(), new MockKInfo(), new MockLInfo());
|
||||
var ex = Assert.Throws<YamlException>(() => actorInfo.TraitsInConstructOrder());
|
||||
|
||||
Assert.That(ex.Message, Does.Contain(nameof(MockJInfo)), "Exception message should report all cyclic dependencies.");
|
||||
Assert.That(ex.Message, Does.Contain(nameof(MockKInfo)), "Exception message should report all cyclic dependencies.");
|
||||
Assert.That(ex.Message, Does.Contain(nameof(MockLInfo)), "Exception message should report all cyclic dependencies.");
|
||||
}
|
||||
}
|
||||
}
|
||||
41
OpenRA.Test/OpenRA.Game/CPosTest.cs
Normal file
41
OpenRA.Test/OpenRA.Game/CPosTest.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class CPosTest
|
||||
{
|
||||
[TestCase(TestName = "Packing x,y and layer into int")]
|
||||
public void PackUnpackBits()
|
||||
{
|
||||
var values = new int[] { -2048, -1024, 0, 1024, 2047 };
|
||||
var layerValues = new byte[] { 0, 128, 255 };
|
||||
|
||||
foreach (var x in values)
|
||||
{
|
||||
foreach (var y in values)
|
||||
{
|
||||
foreach (var layer in layerValues)
|
||||
{
|
||||
var cell = new CPos(x, y, layer);
|
||||
|
||||
Assert.That(x, Is.EqualTo(cell.X));
|
||||
Assert.That(y, Is.EqualTo(cell.Y));
|
||||
Assert.That(layer, Is.EqualTo(cell.Layer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
91
OpenRA.Test/OpenRA.Game/CoordinateTest.cs
Normal file
91
OpenRA.Test/OpenRA.Game/CoordinateTest.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class CoordinateTest
|
||||
{
|
||||
[TestCase(TestName = "Test CPos to MPos conversion and back again.")]
|
||||
public void CPosConversionRoundtrip()
|
||||
{
|
||||
foreach (var gridType in Enum.GetValues<MapGridType>())
|
||||
{
|
||||
var expected = new CellCoordsRegion(new CPos(-12, -12), new CPos(12, 12));
|
||||
var actual = expected.Select(pos => pos.ToMPos(gridType).ToCPos(gridType)).ToArray();
|
||||
|
||||
Assert.That(expected, Is.EqualTo(actual));
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Test MPos to CPos conversion and back again.")]
|
||||
public void MPosConversionRoundtrip()
|
||||
{
|
||||
foreach (var gridType in Enum.GetValues<MapGridType>())
|
||||
{
|
||||
var expected = new MapCoordsRegion(new MPos(-12, -12), new MPos(12, 12));
|
||||
var actual = expected.Select(pos => pos.ToCPos(gridType).ToMPos(gridType)).ToArray();
|
||||
|
||||
Assert.That(expected, Is.EqualTo(actual));
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Test directional movement of ToCPos.")]
|
||||
public void TestIsometricCPosConversion()
|
||||
{
|
||||
const MapGridType Isometric = MapGridType.RectangularIsometric;
|
||||
Assert.That(new CPos(0, 0), Is.EqualTo(new MPos(0, 0).ToCPos(Isometric)));
|
||||
|
||||
Assert.That(new CPos(1, 1), Is.EqualTo(new MPos(0, 2).ToCPos(Isometric)));
|
||||
Assert.That(new CPos(2, 2), Is.EqualTo(new MPos(0, 4).ToCPos(Isometric)));
|
||||
Assert.That(new CPos(3, 3), Is.EqualTo(new MPos(0, 6).ToCPos(Isometric)));
|
||||
|
||||
Assert.That(new CPos(1, 0), Is.EqualTo(new MPos(0, 1).ToCPos(Isometric)));
|
||||
Assert.That(new CPos(2, 0), Is.EqualTo(new MPos(1, 2).ToCPos(Isometric)));
|
||||
Assert.That(new CPos(3, 0), Is.EqualTo(new MPos(1, 3).ToCPos(Isometric)));
|
||||
|
||||
Assert.That(new CPos(0, 1), Is.EqualTo(new MPos(-1, 1).ToCPos(Isometric)));
|
||||
Assert.That(new CPos(0, 2), Is.EqualTo(new MPos(-1, 2).ToCPos(Isometric)));
|
||||
Assert.That(new CPos(0, 3), Is.EqualTo(new MPos(-2, 3).ToCPos(Isometric)));
|
||||
|
||||
Assert.That(new CPos(1, -1), Is.EqualTo(new MPos(1, 0).ToCPos(Isometric)));
|
||||
Assert.That(new CPos(2, -2), Is.EqualTo(new MPos(2, 0).ToCPos(Isometric)));
|
||||
Assert.That(new CPos(3, -3), Is.EqualTo(new MPos(3, 0).ToCPos(Isometric)));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Test directional movement of ToMPos.")]
|
||||
public void TestIsometricMPosConversion()
|
||||
{
|
||||
const MapGridType Isometric = MapGridType.RectangularIsometric;
|
||||
Assert.That(new MPos(0, 0), Is.EqualTo(new CPos(0, 0).ToMPos(Isometric)));
|
||||
|
||||
Assert.That(new MPos(0, 2), Is.EqualTo(new CPos(1, 1).ToMPos(Isometric)));
|
||||
Assert.That(new MPos(0, 4), Is.EqualTo(new CPos(2, 2).ToMPos(Isometric)));
|
||||
Assert.That(new MPos(0, 6), Is.EqualTo(new CPos(3, 3).ToMPos(Isometric)));
|
||||
|
||||
Assert.That(new MPos(0, 1), Is.EqualTo(new CPos(1, 0).ToMPos(Isometric)));
|
||||
Assert.That(new MPos(1, 2), Is.EqualTo(new CPos(2, 0).ToMPos(Isometric)));
|
||||
Assert.That(new MPos(1, 3), Is.EqualTo(new CPos(3, 0).ToMPos(Isometric)));
|
||||
|
||||
Assert.That(new MPos(-1, 1), Is.EqualTo(new CPos(0, 1).ToMPos(Isometric)));
|
||||
Assert.That(new MPos(-1, 2), Is.EqualTo(new CPos(0, 2).ToMPos(Isometric)));
|
||||
Assert.That(new MPos(-2, 3), Is.EqualTo(new CPos(0, 3).ToMPos(Isometric)));
|
||||
|
||||
Assert.That(new MPos(1, 0), Is.EqualTo(new CPos(1, -1).ToMPos(Isometric)));
|
||||
Assert.That(new MPos(2, 0), Is.EqualTo(new CPos(2, -2).ToMPos(Isometric)));
|
||||
Assert.That(new MPos(3, 0), Is.EqualTo(new CPos(3, -3).ToMPos(Isometric)));
|
||||
}
|
||||
}
|
||||
}
|
||||
833
OpenRA.Test/OpenRA.Game/FieldLoaderTest.cs
Normal file
833
OpenRA.Test/OpenRA.Game/FieldLoaderTest.cs
Normal file
@@ -0,0 +1,833 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Internal;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class FieldLoaderTest
|
||||
{
|
||||
sealed class TypeInfo
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CA1823 // Avoid unused private fields
|
||||
#pragma warning disable IDE0044 // Add readonly modifier
|
||||
#pragma warning disable IDE0051 // Remove unused private members
|
||||
#pragma warning disable RCS1170 // Use read-only auto-implemented property
|
||||
int privateField;
|
||||
public int PublicField;
|
||||
|
||||
[FieldLoader.Ignore]
|
||||
int privateIgnoreField;
|
||||
[FieldLoader.Ignore]
|
||||
public int PublicIgnoreField;
|
||||
|
||||
[FieldLoader.Require]
|
||||
int privateRequiredField;
|
||||
[FieldLoader.Require]
|
||||
public int PublicRequiredField;
|
||||
|
||||
[FieldLoader.LoadUsing(nameof(LoadInt32))]
|
||||
int privateLoadUsingField;
|
||||
[FieldLoader.LoadUsing(nameof(LoadInt32))]
|
||||
public int PublicLoadUsingField;
|
||||
|
||||
int PrivateProperty { get; set; }
|
||||
public int PublicProperty { get; set; }
|
||||
|
||||
static int privateStaticField;
|
||||
public static int PublicStaticField;
|
||||
|
||||
static object LoadInt32(MiniYaml _) => 123;
|
||||
#pragma warning restore RCS1170 // Use read-only auto-implemented property
|
||||
#pragma warning restore IDE0051 // Remove unused private members
|
||||
#pragma warning restore IDE0044 // Add readonly modifier
|
||||
#pragma warning restore CA1823 // Avoid unused private fields
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning restore CS0169
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetTypeLoadInfo()
|
||||
{
|
||||
var infos = FieldLoader.GetTypeLoadInfo(typeof(TypeInfo)).ToList();
|
||||
|
||||
Assert.That(infos, Has.Count.EqualTo(5));
|
||||
|
||||
Assert.That(infos[0].Field, Is.EqualTo(typeof(TypeInfo).GetField(nameof(TypeInfo.PublicField))));
|
||||
Assert.That(infos[0].Attribute, Is.EqualTo(FieldLoader.SerializeAttribute.Default));
|
||||
Assert.That(infos[0].YamlName, Is.EqualTo(nameof(TypeInfo.PublicField)));
|
||||
Assert.That(infos[0].Loader, Is.Null);
|
||||
|
||||
Assert.That(infos[1].Field, Is.EqualTo(typeof(TypeInfo).GetField("privateRequiredField", BindingFlags.NonPublic | BindingFlags.Instance)));
|
||||
Assert.That(infos[1].Attribute, Is.EqualTo(new FieldLoader.RequireAttribute()));
|
||||
Assert.That(infos[1].YamlName, Is.EqualTo("privateRequiredField"));
|
||||
Assert.That(infos[1].Loader, Is.Null);
|
||||
|
||||
Assert.That(infos[2].Field, Is.EqualTo(typeof(TypeInfo).GetField(nameof(TypeInfo.PublicRequiredField))));
|
||||
Assert.That(infos[2].Attribute, Is.EqualTo(new FieldLoader.RequireAttribute()));
|
||||
Assert.That(infos[2].YamlName, Is.EqualTo(nameof(TypeInfo.PublicRequiredField)));
|
||||
Assert.That(infos[2].Loader, Is.Null);
|
||||
|
||||
Assert.That(infos[3].Field, Is.EqualTo(typeof(TypeInfo).GetField("privateLoadUsingField", BindingFlags.NonPublic | BindingFlags.Instance)));
|
||||
Assert.That(infos[3].Attribute, Is.EqualTo(new FieldLoader.LoadUsingAttribute("LoadInt32")));
|
||||
Assert.That(infos[3].YamlName, Is.EqualTo("privateLoadUsingField"));
|
||||
Assert.That(infos[3].Loader(new MiniYaml(null)), Is.EqualTo(123));
|
||||
|
||||
Assert.That(infos[4].Field, Is.EqualTo(typeof(TypeInfo).GetField(nameof(TypeInfo.PublicLoadUsingField))));
|
||||
Assert.That(infos[4].Attribute, Is.EqualTo(new FieldLoader.LoadUsingAttribute("LoadInt32")));
|
||||
Assert.That(infos[4].YamlName, Is.EqualTo(nameof(TypeInfo.PublicLoadUsingField)));
|
||||
Assert.That(infos[4].Loader(new MiniYaml(null)), Is.EqualTo(123));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_UnknownField()
|
||||
{
|
||||
static void Act() => FieldLoader.GetValue<object>("field", "test");
|
||||
|
||||
Assert.That(Act, Throws.TypeOf<NotImplementedException>().And.Message.EqualTo("FieldLoader: Missing field `[Type] test` on `Object`"));
|
||||
}
|
||||
|
||||
static IEnumerable<TestCaseData> GetValue_InvalidValue_TestCases()
|
||||
{
|
||||
return
|
||||
[
|
||||
new TestCaseData(null) { TypeArgs = [typeof(int)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(int)] },
|
||||
new TestCaseData("1.2") { TypeArgs = [typeof(int)] },
|
||||
new TestCaseData((int.MaxValue + 1L).ToString(CultureInfo.InvariantCulture)) { TypeArgs = [typeof(int)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(ushort)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(ushort)] },
|
||||
new TestCaseData("1.2") { TypeArgs = [typeof(ushort)] },
|
||||
new TestCaseData((ushort.MaxValue + 1L).ToString(CultureInfo.InvariantCulture)) { TypeArgs = [typeof(ushort)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(long)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(long)] },
|
||||
new TestCaseData("1.2") { TypeArgs = [typeof(long)] },
|
||||
new TestCaseData((long.MaxValue + 1UL).ToString(CultureInfo.InvariantCulture)) { TypeArgs = [typeof(long)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(float)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(float)] },
|
||||
new TestCaseData("1,2") { TypeArgs = [typeof(float)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(decimal)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(decimal)] },
|
||||
new TestCaseData("1,2") { TypeArgs = [typeof(decimal)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(Color)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(Color)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(Hotkey)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(Hotkey)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(WDist)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(WDist)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(WVec)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(WVec)] },
|
||||
new TestCaseData("1,2") { TypeArgs = [typeof(WVec)] },
|
||||
new TestCaseData("1,test,3") { TypeArgs = [typeof(WVec)] },
|
||||
new TestCaseData("1,2,3,4") { TypeArgs = [typeof(WVec)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(WVec[])] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(WVec[])] },
|
||||
new TestCaseData("1,2") { TypeArgs = [typeof(WVec[])] },
|
||||
new TestCaseData("1,test,3") { TypeArgs = [typeof(WVec[])] },
|
||||
new TestCaseData("1,2,3,4") { TypeArgs = [typeof(WVec[])] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(WPos)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(WPos)] },
|
||||
new TestCaseData("1,2") { TypeArgs = [typeof(WPos)] },
|
||||
new TestCaseData("1,test,3") { TypeArgs = [typeof(WPos)] },
|
||||
new TestCaseData("1,2,3,4") { TypeArgs = [typeof(WPos)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(WAngle)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(WAngle)] },
|
||||
new TestCaseData("1,2") { TypeArgs = [typeof(WAngle)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(WRot)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(WRot)] },
|
||||
new TestCaseData("1,2") { TypeArgs = [typeof(WRot)] },
|
||||
new TestCaseData("1,test,3") { TypeArgs = [typeof(WRot)] },
|
||||
new TestCaseData("1,2,3,4") { TypeArgs = [typeof(WRot)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(CPos)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(CPos)] },
|
||||
new TestCaseData("1") { TypeArgs = [typeof(CPos)] },
|
||||
new TestCaseData("1,test,3") { TypeArgs = [typeof(CPos)] },
|
||||
new TestCaseData("1,2,3,4") { TypeArgs = [typeof(CPos)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(CPos[])] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(CPos[])] },
|
||||
new TestCaseData("1") { TypeArgs = [typeof(CPos[])] },
|
||||
new TestCaseData("1,test") { TypeArgs = [typeof(CPos[])] },
|
||||
new TestCaseData("1,2,3") { TypeArgs = [typeof(CPos[])] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(CVec)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(CVec)] },
|
||||
new TestCaseData("1") { TypeArgs = [typeof(CVec)] },
|
||||
new TestCaseData("1,test") { TypeArgs = [typeof(CVec)] },
|
||||
new TestCaseData("1,2,3") { TypeArgs = [typeof(CVec)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(CVec[])] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(CVec[])] },
|
||||
new TestCaseData("1") { TypeArgs = [typeof(CVec[])] },
|
||||
new TestCaseData("1,test") { TypeArgs = [typeof(CVec[])] },
|
||||
new TestCaseData("1,2,3") { TypeArgs = [typeof(CVec[])] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(BooleanExpression)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(IntegerExpression)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(MapGridType)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(bool)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(bool)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(int2[])] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(int2[])] },
|
||||
new TestCaseData("1") { TypeArgs = [typeof(int2[])] },
|
||||
new TestCaseData("1,test") { TypeArgs = [typeof(int2[])] },
|
||||
new TestCaseData("1,2,3") { TypeArgs = [typeof(int2[])] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(Size)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(Size)] },
|
||||
new TestCaseData("1") { TypeArgs = [typeof(Size)] },
|
||||
new TestCaseData("1,test") { TypeArgs = [typeof(Size)] },
|
||||
new TestCaseData("1,2,3") { TypeArgs = [typeof(Size)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(int2)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(int2)] },
|
||||
new TestCaseData("1") { TypeArgs = [typeof(int2)] },
|
||||
new TestCaseData("1,test") { TypeArgs = [typeof(int2)] },
|
||||
new TestCaseData("1,2,3") { TypeArgs = [typeof(int2)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(float2)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(float2)] },
|
||||
new TestCaseData("1") { TypeArgs = [typeof(float2)] },
|
||||
new TestCaseData("1,test") { TypeArgs = [typeof(float2)] },
|
||||
new TestCaseData("1,2,3") { TypeArgs = [typeof(float2)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(float3)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(float3)] },
|
||||
new TestCaseData("1") { TypeArgs = [typeof(float3)] },
|
||||
new TestCaseData("1,test") { TypeArgs = [typeof(float3)] },
|
||||
new TestCaseData("1,2,3,4") { TypeArgs = [typeof(float3)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(Rectangle)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(Rectangle)] },
|
||||
new TestCaseData("1,2,3") { TypeArgs = [typeof(Rectangle)] },
|
||||
new TestCaseData("1,test,3,4") { TypeArgs = [typeof(Rectangle)] },
|
||||
new TestCaseData("1,2,3,4,5") { TypeArgs = [typeof(Rectangle)] },
|
||||
new TestCaseData(null) { TypeArgs = [typeof(DateTime)] },
|
||||
new TestCaseData("test") { TypeArgs = [typeof(DateTime)] },
|
||||
new TestCaseData("2000-01-01") { TypeArgs = [typeof(DateTime)] },
|
||||
];
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(GetValue_InvalidValue_TestCases))]
|
||||
public void GetValue_InvalidValue<T>(string input)
|
||||
{
|
||||
void Act() => FieldLoader.GetValue<T>("field", input);
|
||||
|
||||
Assert.That(Act, Throws.TypeOf<YamlException>().And.Message.EqualTo($"FieldLoader: Cannot parse `{input}` into `field.{typeof(T).FullName}`"));
|
||||
}
|
||||
|
||||
[TestCase(TypeArgs = [typeof(BooleanExpression)])]
|
||||
[TestCase(TypeArgs = [typeof(IntegerExpression)])]
|
||||
public void GetValue_InvalidValue<T>()
|
||||
{
|
||||
static void Act() => FieldLoader.GetValue<T>("field", "");
|
||||
|
||||
Assert.That(Act, Throws.TypeOf<YamlException>().And.Message.EqualTo($"FieldLoader: Cannot parse `` into `field.{typeof(T).FullName}`: Empty expression"));
|
||||
}
|
||||
|
||||
static IEnumerable<TestCaseData> GetValue_Primitive_TestCases()
|
||||
{
|
||||
return
|
||||
[
|
||||
new TestCaseData(123),
|
||||
new TestCaseData((ushort)123),
|
||||
new TestCaseData(123L),
|
||||
new TestCaseData(123.4f),
|
||||
new TestCaseData(123m),
|
||||
new TestCaseData("test"),
|
||||
new TestCaseData(Color.CornflowerBlue),
|
||||
new TestCaseData(new Hotkey(Keycode.A, Modifiers.Shift)),
|
||||
new TestCaseData(new WDist(123)),
|
||||
new TestCaseData(new WVec(123, 456, 789)),
|
||||
new TestCaseData(new WPos(123, 456, 789)),
|
||||
new TestCaseData(new WAngle(123)),
|
||||
new TestCaseData(new WRot(new WAngle(123), new WAngle(456), new WAngle(789))),
|
||||
new TestCaseData(new CPos(123, 456)),
|
||||
new TestCaseData(new CPos(123, 456, 78)),
|
||||
new TestCaseData(new CVec(123, 456)),
|
||||
new TestCaseData(MapGridType.RectangularIsometric),
|
||||
new TestCaseData((MapGridType)byte.MaxValue),
|
||||
new TestCaseData(SystemActors.World | SystemActors.EditorWorld),
|
||||
new TestCaseData(true),
|
||||
new TestCaseData(new Size(123, 456)),
|
||||
new TestCaseData(new int2(123, 456)),
|
||||
new TestCaseData(new float2(123, 456)),
|
||||
new TestCaseData(new float3(123, 456, 789)),
|
||||
new TestCaseData(new Rectangle(123, 456, 789, 123)),
|
||||
];
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(GetValue_Primitive_TestCases))]
|
||||
public void GetValue_Primitive<T>(T expected)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<T>("field", $" {expected} ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_NullString()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<string>("field", null);
|
||||
|
||||
Assert.That(actual, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_BooleanExpression()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<BooleanExpression>("field", " true ");
|
||||
|
||||
Assert.That(actual.Expression, Is.EqualTo("true"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_IntegerExpression()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<IntegerExpression>("field", " 1 + 2 ");
|
||||
|
||||
Assert.That(actual.Expression, Is.EqualTo("1 + 2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_DateTime()
|
||||
{
|
||||
var expected = new DateTime(2000, 1, 1);
|
||||
var input = expected.ToString("yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture);
|
||||
|
||||
var actual = FieldLoader.GetValue<DateTime>("field", $" {input} ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase("123%", 1.23f)]
|
||||
[TestCase("%123", 1.23f)]
|
||||
[TestCase("123.456%", 1.23456f)]
|
||||
[TestCase("%123.456", 1.23456f)]
|
||||
public void GetValue_FloatPercentage(string input, float expected)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<float>("field", $" {input} ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
static IEnumerable<TestCaseData> GetValue_DecimalPercentage_TestCases()
|
||||
{
|
||||
return
|
||||
[
|
||||
new TestCaseData("123%", 1.23m),
|
||||
new TestCaseData("%123", 1.23m),
|
||||
new TestCaseData("123.456%", 1.23456m),
|
||||
new TestCaseData("%123.456", 1.23456m),
|
||||
];
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(GetValue_DecimalPercentage_TestCases))]
|
||||
public void GetValue_DecimalPercentage(string input, decimal expected)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<decimal>("field", $" {input} ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_float3_TwoElements()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<float3>("field", "123,456");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(new float3(123, 456, 0)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_WVecArray()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<WVec[]>("field", " 1 , 2 , 3 , 4 , 5 , 6 , , ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(new WVec[] { new(1, 2, 3), new(4, 5, 6) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_CPosArray()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<CPos[]>("field", " 1 , 2 , 3 , 4 , 5 , 6 , , ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(new CPos[] { new(1, 2), new(3, 4), new(5, 6) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_CVecArray()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<CVec[]>("field", " 1 , 2 , 3 , 4 , 5 , 6 , , ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(new CVec[] { new(1, 2), new(3, 4), new(5, 6) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_int2Array()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<int2[]>("field", " 1 , 2 , 3 , 4 , 5 , 6 , , ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(new int2[] { new(1, 2), new(3, 4), new(5, 6) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_WVecImmutableArray()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<ImmutableArray<WVec>>("field", " 1 , 2 , 3 , 4 , 5 , 6 , , ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(new WVec[] { new(1, 2, 3), new(4, 5, 6) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_CPosImmutableArray()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<ImmutableArray<CPos>>("field", " 1 , 2 , 3 , 4 , 5 , 6 , , ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(new CPos[] { new(1, 2), new(3, 4), new(5, 6) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_CVecImmutableArray()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<ImmutableArray<CVec>>("field", " 1 , 2 , 3 , 4 , 5 , 6 , , ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(new CVec[] { new(1, 2), new(3, 4), new(5, 6) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_int2ImmutableArray()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<ImmutableArray<int2>>("field", " 1 , 2 , 3 , 4 , 5 , 6 , , ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(new int2[] { new(1, 2), new(3, 4), new(5, 6) }));
|
||||
}
|
||||
|
||||
[TestCase(null, null)]
|
||||
[TestCase("", null)]
|
||||
[TestCase("123", 123)]
|
||||
public void GetValue_Nullable(string input, int? expected)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<int?>("field", $" {input} ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase(null, new int[] { })]
|
||||
[TestCase("", new int[] { })]
|
||||
[TestCase("1", new int[] { 1 })]
|
||||
[TestCase("1,2,3", new int[] { 1, 2, 3 })]
|
||||
[TestCase("1,,3", new int[] { 1, 3 })]
|
||||
[TestCase(" 1 , 2 , 3 ", new int[] { 1, 2, 3 })]
|
||||
[TestCase(" 1 , , 3 ", new int[] { 1, 3 })]
|
||||
[TestCase("1,1,2,2,3", new int[] { 1, 1, 2, 2, 3 })]
|
||||
[TestCase("1,1,1,1", new int[] { 1, 1, 1, 1 })]
|
||||
public void GetValue_Array(string input, int[] expected)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<int[]>("field", input);
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase(null, new int[] { })]
|
||||
[TestCase("", new int[] { })]
|
||||
[TestCase("1", new int[] { 1 })]
|
||||
[TestCase("1,2,3", new int[] { 1, 2, 3 })]
|
||||
[TestCase("1,,3", new int[] { 1, 3 })]
|
||||
[TestCase(" 1 , 2 , 3 ", new int[] { 1, 2, 3 })]
|
||||
[TestCase(" 1 , , 3 ", new int[] { 1, 3 })]
|
||||
[TestCase("1,1,2,2,3", new int[] { 1, 1, 2, 2, 3 })]
|
||||
[TestCase("1,1,1,1", new int[] { 1, 1, 1, 1 })]
|
||||
public void GetValue_List(string input, int[] expected)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<List<int>>("field", input);
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase(null, new int[] { })]
|
||||
[TestCase("", new int[] { })]
|
||||
[TestCase("1", new int[] { 1 })]
|
||||
[TestCase("1,2,3", new int[] { 1, 2, 3 })]
|
||||
[TestCase("1,,3", new int[] { 1, 3 })]
|
||||
[TestCase(" 1 , 2 , 3 ", new int[] { 1, 2, 3 })]
|
||||
[TestCase(" 1 , , 3 ", new int[] { 1, 3 })]
|
||||
[TestCase("1,1,2,2,3", new int[] { 1, 2, 3 })]
|
||||
[TestCase("1,1,1,1", new int[] { 1 })]
|
||||
public void GetValue_HashSet(string input, int[] expected)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<HashSet<int>>("field", input);
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase(null)]
|
||||
[TestCase("")]
|
||||
[TestCase("1")]
|
||||
[TestCase("1,2,3")]
|
||||
[TestCase("1,,3")]
|
||||
[TestCase(" 1 , 2 , 3 ")]
|
||||
[TestCase(" 1 , , 3 ")]
|
||||
[TestCase("1,1,2,2,3")]
|
||||
[TestCase("1,1,1,1")]
|
||||
public void GetValue_BitSet(string input)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<BitSet<FieldLoaderTest>>("field", input);
|
||||
var expected = input == null
|
||||
? new BitSet<FieldLoaderTest>([])
|
||||
: new BitSet<FieldLoaderTest>(input.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase(null)]
|
||||
[TestCase("")]
|
||||
[TestCase("1")]
|
||||
[TestCase("1,2")]
|
||||
public void GetValue_Dictionary(string input)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<Dictionary<int, int>>("field", input);
|
||||
|
||||
Assert.That(actual, Is.Empty);
|
||||
}
|
||||
|
||||
[TestCase(null, new int[] { })]
|
||||
[TestCase("", new int[] { })]
|
||||
[TestCase("1", new int[] { 1 })]
|
||||
[TestCase("1,2,3", new int[] { 1, 2, 3 })]
|
||||
[TestCase("1,,3", new int[] { 1, 3 })]
|
||||
[TestCase(" 1 , 2 , 3 ", new int[] { 1, 2, 3 })]
|
||||
[TestCase(" 1 , , 3 ", new int[] { 1, 3 })]
|
||||
[TestCase("1,1,2,2,3", new int[] { 1, 1, 2, 2, 3 })]
|
||||
[TestCase("1,1,1,1", new int[] { 1, 1, 1, 1 })]
|
||||
public void GetValue_ImmutableArray(string input, int[] expected)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<ImmutableArray<int>>("field", input);
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase(null, new int[] { })]
|
||||
[TestCase("", new int[] { })]
|
||||
[TestCase("1", new int[] { 1 })]
|
||||
[TestCase("1,2,3", new int[] { 1, 2, 3 })]
|
||||
[TestCase("1,,3", new int[] { 1, 3 })]
|
||||
[TestCase(" 1 , 2 , 3 ", new int[] { 1, 2, 3 })]
|
||||
[TestCase(" 1 , , 3 ", new int[] { 1, 3 })]
|
||||
[TestCase("1,1,2,2,3", new int[] { 1, 2, 3 })]
|
||||
[TestCase("1,1,1,1", new int[] { 1 })]
|
||||
public void GetValue_FrozenSet(string input, int[] expected)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<FrozenSet<int>>("field", input);
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase(null)]
|
||||
[TestCase("")]
|
||||
[TestCase("1")]
|
||||
[TestCase("1,2")]
|
||||
public void GetValue_FrozenDictionary(string input)
|
||||
{
|
||||
var actual = FieldLoader.GetValue<FrozenDictionary<int, int>>("field", input);
|
||||
|
||||
Assert.That(actual, Is.Empty);
|
||||
}
|
||||
|
||||
[TestCase(TypeArgs = [typeof(int[][])])]
|
||||
[TestCase(TypeArgs = [typeof(List<List<int>>)])]
|
||||
[TestCase(TypeArgs = [typeof(HashSet<HashSet<int>>)])]
|
||||
[TestCase(TypeArgs = [typeof(ImmutableArray<ImmutableArray<int>>)])]
|
||||
[TestCase(TypeArgs = [typeof(FrozenSet<FrozenSet<int>>)])]
|
||||
public void GetValue_NestedCollections<T>()
|
||||
{
|
||||
var actual = FieldLoader.GetValue<T>("field", "1,2,3");
|
||||
|
||||
Assert.That(actual, Is.EquivalentTo(new int[][] { [1], [2], [3] }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_TypeConverter()
|
||||
{
|
||||
// We don't have hardcoded handling for sbyte, but a TypeConverter for it does exist.
|
||||
var actual = FieldLoader.GetValue<sbyte>("field", " 123 ");
|
||||
|
||||
Assert.That(actual, Is.EqualTo(123));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValue_TypeConverter_Invalid()
|
||||
{
|
||||
static void Act() => FieldLoader.GetValue<sbyte>("field", " test ");
|
||||
|
||||
Assert.That(Act, Throws.TypeOf<YamlException>().And.Message.EqualTo($"FieldLoader: Cannot parse `test` into `field.{typeof(sbyte).FullName}`"));
|
||||
}
|
||||
|
||||
sealed class LoadFieldOrPropertyTarget
|
||||
{
|
||||
#pragma warning disable IDE0044 // Add readonly modifier
|
||||
#pragma warning disable RCS1170 // Use read-only auto-implemented property
|
||||
int privateIntField;
|
||||
int PrivateIntProp { get; set; }
|
||||
|
||||
public int PublicIntField;
|
||||
public int PublicIntProp { get; set; }
|
||||
|
||||
public int GetPrivateIntField() => privateIntField;
|
||||
public int GetPrivateIntProp() => PrivateIntProp;
|
||||
#pragma warning restore IDE0044 // Add readonly modifier
|
||||
#pragma warning restore RCS1170 // Use read-only auto-implemented property
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoadFieldOrProperty()
|
||||
{
|
||||
var target = new LoadFieldOrPropertyTarget();
|
||||
FieldLoader.LoadFieldOrProperty(target, $" {nameof(LoadFieldOrPropertyTarget.PublicIntField)} ", "12");
|
||||
FieldLoader.LoadFieldOrProperty(target, $" {nameof(LoadFieldOrPropertyTarget.PublicIntProp)} ", "34");
|
||||
FieldLoader.LoadFieldOrProperty(target, " privateIntField ", "56");
|
||||
FieldLoader.LoadFieldOrProperty(target, " PrivateIntProp ", "78");
|
||||
void Act() => FieldLoader.LoadFieldOrProperty(target, "unknown", "");
|
||||
|
||||
Assert.That(target.PublicIntField, Is.EqualTo(12));
|
||||
Assert.That(target.PublicIntProp, Is.EqualTo(34));
|
||||
Assert.That(target.GetPrivateIntField(), Is.EqualTo(56));
|
||||
Assert.That(target.GetPrivateIntProp(), Is.EqualTo(78));
|
||||
Assert.That(Act, Throws.TypeOf<NotImplementedException>().And.Message.EqualTo("FieldLoader: Missing field `unknown` on `LoadFieldOrPropertyTarget`"));
|
||||
}
|
||||
|
||||
sealed class LoadTarget
|
||||
{
|
||||
public int Int;
|
||||
public string String;
|
||||
public string Unset;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Load()
|
||||
{
|
||||
var target = new LoadTarget() { Unset = "unset" };
|
||||
var yaml = new MiniYaml(
|
||||
null,
|
||||
[
|
||||
new MiniYamlNode(nameof(LoadTarget.Int), "123"),
|
||||
new MiniYamlNode(nameof(LoadTarget.String), "test"),
|
||||
]);
|
||||
|
||||
FieldLoader.Load(target, yaml);
|
||||
|
||||
Assert.That(target.Int, Is.EqualTo(123));
|
||||
Assert.That(target.String, Is.EqualTo("test"));
|
||||
Assert.That(target.Unset, Is.EqualTo("unset"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Load_Generic()
|
||||
{
|
||||
var expected = new LoadTarget();
|
||||
var yaml = new MiniYaml(
|
||||
null,
|
||||
[
|
||||
new MiniYamlNode(nameof(LoadTarget.Int), "123"),
|
||||
new MiniYamlNode(nameof(LoadTarget.String), "test"),
|
||||
]);
|
||||
FieldLoader.Load(expected, yaml);
|
||||
|
||||
var actual = FieldLoader.Load<LoadTarget>(yaml);
|
||||
|
||||
Assert.That(actual.Int, Is.EqualTo(expected.Int));
|
||||
Assert.That(actual.String, Is.EqualTo(expected.String));
|
||||
Assert.That(actual.Unset, Is.EqualTo(expected.Unset));
|
||||
}
|
||||
|
||||
sealed class LoadDictionaryTarget
|
||||
{
|
||||
public Dictionary<int, int> Dictionary;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Load_Dictionary()
|
||||
{
|
||||
var target = new LoadDictionaryTarget();
|
||||
var yaml = new MiniYaml(
|
||||
null,
|
||||
[
|
||||
new MiniYamlNode(
|
||||
nameof(LoadDictionaryTarget.Dictionary),
|
||||
new MiniYaml(
|
||||
null,
|
||||
[
|
||||
new MiniYamlNode("12", "34"),
|
||||
new MiniYamlNode("56", "78")
|
||||
]))
|
||||
]);
|
||||
|
||||
FieldLoader.Load(target, yaml);
|
||||
|
||||
Assert.That(target.Dictionary, Is.EquivalentTo(new Dictionary<int, int> { { 12, 34 }, { 56, 78 } }));
|
||||
}
|
||||
|
||||
sealed class LoadFrozenDictionaryTarget
|
||||
{
|
||||
public FrozenDictionary<int, int> Dictionary;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Load_FrozenDictionary()
|
||||
{
|
||||
var target = new LoadFrozenDictionaryTarget();
|
||||
var yaml = new MiniYaml(
|
||||
null,
|
||||
[
|
||||
new MiniYamlNode(
|
||||
nameof(LoadFrozenDictionaryTarget.Dictionary),
|
||||
new MiniYaml(
|
||||
null,
|
||||
[
|
||||
new MiniYamlNode("12", "34"),
|
||||
new MiniYamlNode("56", "78")
|
||||
]))
|
||||
]);
|
||||
|
||||
FieldLoader.Load(target, yaml);
|
||||
|
||||
Assert.That(target.Dictionary, Is.EquivalentTo(new Dictionary<int, int> { { 12, 34 }, { 56, 78 } }));
|
||||
}
|
||||
|
||||
sealed class LoadRequiredTarget
|
||||
{
|
||||
[FieldLoader.Require]
|
||||
public int Int1 = 1;
|
||||
[FieldLoader.Require]
|
||||
public int Int2 = 2;
|
||||
[FieldLoader.Require]
|
||||
public int Int3 = 3;
|
||||
|
||||
public int Int4 = 4;
|
||||
public int Int5 = 5;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Load_Required()
|
||||
{
|
||||
var target = new LoadRequiredTarget();
|
||||
var yaml = new MiniYaml(
|
||||
null,
|
||||
[
|
||||
new MiniYamlNode(nameof(LoadRequiredTarget.Int1), "123"),
|
||||
new MiniYamlNode(nameof(LoadRequiredTarget.Int4), "456"),
|
||||
]);
|
||||
|
||||
void Act() => FieldLoader.Load(target, yaml);
|
||||
|
||||
Assert.That(Act,
|
||||
Throws.TypeOf<FieldLoader.MissingFieldsException>().And
|
||||
.Message.EqualTo($"{nameof(LoadRequiredTarget.Int2)}, {nameof(LoadRequiredTarget.Int3)}"));
|
||||
Assert.That(target.Int1, Is.EqualTo(123));
|
||||
Assert.That(target.Int2, Is.EqualTo(2));
|
||||
Assert.That(target.Int3, Is.EqualTo(3));
|
||||
Assert.That(target.Int4, Is.EqualTo(456));
|
||||
Assert.That(target.Int5, Is.EqualTo(5));
|
||||
}
|
||||
|
||||
sealed class LoadIgnoreTarget
|
||||
{
|
||||
[FieldLoader.Ignore]
|
||||
public int Int1 = 1;
|
||||
[FieldLoader.Ignore]
|
||||
public int Int2 = 2;
|
||||
|
||||
public int Int3 = 3;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Load_Ignore()
|
||||
{
|
||||
var target = new LoadIgnoreTarget();
|
||||
var yaml = new MiniYaml(
|
||||
null,
|
||||
[
|
||||
new MiniYamlNode(nameof(LoadIgnoreTarget.Int1), "123"),
|
||||
new MiniYamlNode(nameof(LoadIgnoreTarget.Int3), "456"),
|
||||
]);
|
||||
|
||||
FieldLoader.Load(target, yaml);
|
||||
|
||||
Assert.That(target.Int1, Is.EqualTo(1));
|
||||
Assert.That(target.Int2, Is.EqualTo(2));
|
||||
Assert.That(target.Int3, Is.EqualTo(456));
|
||||
}
|
||||
|
||||
sealed class LoadUsingTarget
|
||||
{
|
||||
[FieldLoader.LoadUsing(nameof(LoadInt))]
|
||||
public int Int1 = 1;
|
||||
[FieldLoader.LoadUsing(nameof(LoadInt), true)]
|
||||
public int Int2 = 2;
|
||||
|
||||
[FieldLoader.LoadUsing(nameof(LoadInt))]
|
||||
public int Int3 = 3;
|
||||
[FieldLoader.LoadUsing(nameof(LoadInt), true)]
|
||||
public int Int4 = 4;
|
||||
|
||||
public int Int5 = 5;
|
||||
|
||||
static object LoadInt(MiniYaml yaml) => Exts.ParseInt32Invariant(yaml.NodeWithKey("ForLoadUsing").Value.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Load_Using()
|
||||
{
|
||||
var target = new LoadUsingTarget();
|
||||
var yaml = new MiniYaml(
|
||||
null,
|
||||
[
|
||||
new MiniYamlNode("ForLoadUsing", "100"),
|
||||
new MiniYamlNode(nameof(LoadUsingTarget.Int1), "12"),
|
||||
new MiniYamlNode(nameof(LoadUsingTarget.Int2), "34"),
|
||||
new MiniYamlNode(nameof(LoadUsingTarget.Int5), "56"),
|
||||
]);
|
||||
|
||||
void Act() => FieldLoader.Load(target, yaml);
|
||||
|
||||
Assert.That(Act,
|
||||
Throws.TypeOf<FieldLoader.MissingFieldsException>().And
|
||||
.Message.EqualTo(nameof(LoadRequiredTarget.Int4)));
|
||||
Assert.That(target.Int1, Is.EqualTo(100));
|
||||
Assert.That(target.Int2, Is.EqualTo(100));
|
||||
Assert.That(target.Int3, Is.EqualTo(100));
|
||||
Assert.That(target.Int4, Is.EqualTo(4));
|
||||
Assert.That(target.Int5, Is.EqualTo(56));
|
||||
}
|
||||
|
||||
sealed class LoadUsingMissingTarget
|
||||
{
|
||||
[FieldLoader.LoadUsing("unknown")]
|
||||
public int Int = 1;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Load_UsingMissing()
|
||||
{
|
||||
var target = new LoadUsingMissingTarget();
|
||||
var yaml = new MiniYaml(null);
|
||||
|
||||
void Act() => FieldLoader.Load(target, yaml);
|
||||
|
||||
Assert.That(Act,
|
||||
Throws.TypeOf<InvalidOperationException>().And
|
||||
.Message.EqualTo("LoadUsingMissingTarget does not specify a loader function 'unknown'"));
|
||||
Assert.That(target.Int, Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
343
OpenRA.Test/OpenRA.Game/FieldSaverTest.cs
Normal file
343
OpenRA.Test/OpenRA.Game/FieldSaverTest.cs
Normal file
@@ -0,0 +1,343 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class FieldSaverTest
|
||||
{
|
||||
static IEnumerable<TestCaseData> FormatValue_Primitive_TestCases()
|
||||
{
|
||||
return
|
||||
[
|
||||
new TestCaseData(123),
|
||||
new TestCaseData((ushort)123),
|
||||
new TestCaseData(123L),
|
||||
new TestCaseData(123.4f),
|
||||
new TestCaseData(123m),
|
||||
new TestCaseData("test"),
|
||||
new TestCaseData(Color.CornflowerBlue),
|
||||
new TestCaseData(new Hotkey(Keycode.A, Modifiers.Shift)),
|
||||
new TestCaseData(new WDist(123)),
|
||||
new TestCaseData(new WVec(123, 456, 789)),
|
||||
new TestCaseData(new WPos(123, 456, 789)),
|
||||
new TestCaseData(new WAngle(123)),
|
||||
new TestCaseData(new WRot(new WAngle(123), new WAngle(456), new WAngle(789))),
|
||||
new TestCaseData(new CPos(123, 456)),
|
||||
new TestCaseData(new CPos(123, 456, 78)),
|
||||
new TestCaseData(new CVec(123, 456)),
|
||||
new TestCaseData(new BooleanExpression("true")),
|
||||
new TestCaseData(new IntegerExpression("1 + 2")),
|
||||
new TestCaseData(MapGridType.RectangularIsometric),
|
||||
new TestCaseData(SystemActors.World | SystemActors.EditorWorld),
|
||||
new TestCaseData(true),
|
||||
new TestCaseData(new Size(123, 456)),
|
||||
new TestCaseData(new int2(123, 456)),
|
||||
new TestCaseData(new float2(123, 456)),
|
||||
new TestCaseData(new float3(123, 456, 789)),
|
||||
new TestCaseData(new Rectangle(123, 456, 789, 123)),
|
||||
];
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(FormatValue_Primitive_TestCases))]
|
||||
public void FormatVaue_Primitive<T>(T expected)
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(expected);
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected.ToString()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_Null()
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(null);
|
||||
|
||||
Assert.That(actual, Is.EqualTo(""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_DateTime()
|
||||
{
|
||||
var input = new DateTime(2000, 1, 1);
|
||||
|
||||
var actual = FieldSaver.FormatValue(input);
|
||||
|
||||
Assert.That(actual, Is.EqualTo(input.ToString("yyyy-MM-dd HH-mm-ss", CultureInfo.InvariantCulture)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_WVecArray()
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(new WVec[] { new(1, 2, 3), new(4, 5, 6) });
|
||||
|
||||
Assert.That(actual, Is.EqualTo("1,2,3, 4,5,6"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_CPosArray()
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(new CPos[] { new(1, 2), new(3, 4), new(5, 6) });
|
||||
|
||||
Assert.That(actual, Is.EqualTo("1,2, 3,4, 5,6"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_CVecArray()
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(new CVec[] { new(1, 2), new(3, 4), new(5, 6) });
|
||||
|
||||
Assert.That(actual, Is.EqualTo("1,2, 3,4, 5,6"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_int2Array()
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(new int2[] { new(1, 2), new(3, 4), new(5, 6) });
|
||||
|
||||
Assert.That(actual, Is.EqualTo("1,2, 3,4, 5,6"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_WVecImmutableArray()
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(new WVec[] { new(1, 2, 3), new(4, 5, 6) }.ToImmutableArray());
|
||||
|
||||
Assert.That(actual, Is.EqualTo("1,2,3, 4,5,6"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_CPosImmutableArray()
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(new CPos[] { new(1, 2), new(3, 4), new(5, 6) }.ToImmutableArray());
|
||||
|
||||
Assert.That(actual, Is.EqualTo("1,2, 3,4, 5,6"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_CVecImmutableArray()
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(new CVec[] { new(1, 2), new(3, 4), new(5, 6) }.ToImmutableArray());
|
||||
|
||||
Assert.That(actual, Is.EqualTo("1,2, 3,4, 5,6"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_int2ImmutableArray()
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(new int2[] { new(1, 2), new(3, 4), new(5, 6) }.ToImmutableArray());
|
||||
|
||||
Assert.That(actual, Is.EqualTo("1,2, 3,4, 5,6"));
|
||||
}
|
||||
|
||||
[TestCase(null, "")]
|
||||
[TestCase(123, "123")]
|
||||
public void FormatValue_Nullable(int? input, string expected)
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(input);
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase(null, "")]
|
||||
[TestCase(new int[] { }, "")]
|
||||
[TestCase(new int[] { 1 }, "1")]
|
||||
[TestCase(new int[] { 1, 2, 3 }, "1, 2, 3")]
|
||||
[TestCase(new int[] { 1, 1, 2, 2, 3 }, "1, 1, 2, 2, 3")]
|
||||
[TestCase(new int[] { 1, 1, 1, 1 }, "1, 1, 1, 1")]
|
||||
public void FormatValue_Array(int[] input, string expected)
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(input);
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase(null, "")]
|
||||
[TestCase(new int[] { }, "")]
|
||||
[TestCase(new int[] { 1 }, "1")]
|
||||
[TestCase(new int[] { 1, 2, 3 }, "1, 2, 3")]
|
||||
[TestCase(new int[] { 1, 1, 2, 2, 3 }, "1, 1, 2, 2, 3")]
|
||||
[TestCase(new int[] { 1, 1, 1, 1 }, "1, 1, 1, 1")]
|
||||
public void FormatValue_List(int[] input, string expected)
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(input?.ToList());
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase(null, "")]
|
||||
[TestCase(new int[] { }, "")]
|
||||
[TestCase(new int[] { 1 }, "1")]
|
||||
[TestCase(new int[] { 1, 2, 3 }, "1, 2, 3")]
|
||||
[TestCase(new int[] { 1, 1, 2, 2, 3 }, "1, 2, 3")]
|
||||
[TestCase(new int[] { 1, 1, 1, 1 }, "1")]
|
||||
public void FormatValue_HashSet(int[] input, string expected)
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(input?.ToHashSet());
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase("")]
|
||||
[TestCase("1")]
|
||||
[TestCase("1,2,3")]
|
||||
[TestCase("1,1,2,2,3")]
|
||||
[TestCase("1,1,1,1")]
|
||||
public void FormatValue_BitSet(string input)
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(new BitSet<FieldSaverTest>(input));
|
||||
|
||||
Assert.That(actual, Is.EqualTo(input));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_Dictionary()
|
||||
{
|
||||
var input = new Dictionary<int, int> { { 12, 34 }, { 56, 78 } };
|
||||
|
||||
var actual = FieldSaver.FormatValue(input);
|
||||
|
||||
Assert.That(actual, Is.EqualTo($"12: 34{Environment.NewLine}56: 78{Environment.NewLine}"));
|
||||
}
|
||||
|
||||
[TestCase(null, "")]
|
||||
[TestCase(new int[] { }, "")]
|
||||
[TestCase(new int[] { 1 }, "1")]
|
||||
[TestCase(new int[] { 1, 2, 3 }, "1, 2, 3")]
|
||||
[TestCase(new int[] { 1, 1, 2, 2, 3 }, "1, 1, 2, 2, 3")]
|
||||
[TestCase(new int[] { 1, 1, 1, 1 }, "1, 1, 1, 1")]
|
||||
public void FormatValue_ImmutableArray(int[] input, string expected)
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(input?.ToImmutableArray());
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_ImmutableArray_Default()
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(default(ImmutableArray<int>));
|
||||
|
||||
Assert.That(actual, Is.Empty);
|
||||
}
|
||||
|
||||
[TestCase(null, "")]
|
||||
[TestCase(new int[] { }, "")]
|
||||
[TestCase(new int[] { 1 }, "1")]
|
||||
[TestCase(new int[] { 1, 2, 3 }, "1, 2, 3")]
|
||||
[TestCase(new int[] { 1, 1, 2, 2, 3 }, "1, 2, 3")]
|
||||
[TestCase(new int[] { 1, 1, 1, 1 }, "1")]
|
||||
public void FormatValue_FrozenSet(int[] input, string expected)
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(input?.ToFrozenSet());
|
||||
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_FrozenDictionary()
|
||||
{
|
||||
var input = new Dictionary<int, int> { { 12, 34 }, { 56, 78 } }.ToFrozenDictionary();
|
||||
|
||||
var actual = FieldSaver.FormatValue(input);
|
||||
|
||||
Assert.That(actual, Is.EqualTo($"12: 34{Environment.NewLine}56: 78{Environment.NewLine}"));
|
||||
}
|
||||
|
||||
sealed class FieldTarget
|
||||
{
|
||||
public int Int = 123;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatValue_Field()
|
||||
{
|
||||
var actual = FieldSaver.FormatValue(new FieldTarget(), typeof(FieldTarget).GetField(nameof(FieldTarget.Int)));
|
||||
|
||||
Assert.That(actual, Is.EqualTo("123"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SaveField()
|
||||
{
|
||||
var actual = FieldSaver.SaveField(new FieldTarget(), nameof(FieldTarget.Int));
|
||||
|
||||
var actualString = MiniYamlExts.WriteToString([actual]);
|
||||
var expectedString = MiniYamlExts.WriteToString([new MiniYamlNode(nameof(FieldTarget.Int), "123")]);
|
||||
Assert.That(actualString, Is.EqualTo(expectedString));
|
||||
}
|
||||
|
||||
sealed class SaveTarget
|
||||
{
|
||||
public int Int = 123;
|
||||
public string String = "test";
|
||||
public int[] IntArray = [1, 2, 3];
|
||||
public Dictionary<string, string> StringDictionary = new() { { "a", "b" }, { "c", "d" } };
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Save()
|
||||
{
|
||||
var expected = new MiniYaml(
|
||||
null,
|
||||
[
|
||||
new MiniYamlNode(nameof(SaveTarget.Int), "123"),
|
||||
new MiniYamlNode(nameof(SaveTarget.String), "test"),
|
||||
new MiniYamlNode(nameof(SaveTarget.IntArray), "1, 2, 3"),
|
||||
new MiniYamlNode(
|
||||
nameof(SaveTarget.StringDictionary),
|
||||
new MiniYaml(null, [new MiniYamlNode("a", "b"), new MiniYamlNode("c", "d")])),
|
||||
]);
|
||||
|
||||
var actual = FieldSaver.Save(new SaveTarget());
|
||||
|
||||
var actualString = MiniYamlExts.WriteToString(actual.Nodes);
|
||||
var expectedString = MiniYamlExts.WriteToString(expected.Nodes);
|
||||
Assert.That(actual.Value, Is.EqualTo(expected.Value));
|
||||
Assert.That(actualString, Is.EqualTo(expectedString));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SaveDifferences()
|
||||
{
|
||||
var expected = new MiniYaml(
|
||||
null,
|
||||
[
|
||||
new MiniYamlNode(nameof(SaveTarget.String), ""),
|
||||
new MiniYamlNode(nameof(SaveTarget.IntArray), "1, 2, 4"),
|
||||
]);
|
||||
|
||||
var actual = FieldSaver.SaveDifferences(new SaveTarget { IntArray = [1, 2, 4], String = null }, new SaveTarget());
|
||||
|
||||
var actualString = MiniYamlExts.WriteToString(actual.Nodes);
|
||||
var expectedString = MiniYamlExts.WriteToString(expected.Nodes);
|
||||
Assert.That(actual.Value, Is.EqualTo(expected.Value));
|
||||
Assert.That(actualString, Is.EqualTo(expectedString));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SaveDifferences_DifferentTypes()
|
||||
{
|
||||
static void Act() => FieldSaver.SaveDifferences(new object(), new SaveTarget());
|
||||
|
||||
Assert.That(Act, Throws.TypeOf<InvalidOperationException>().And.Message.EqualTo("FieldSaver: can't diff objects of different types"));
|
||||
}
|
||||
}
|
||||
}
|
||||
37
OpenRA.Test/OpenRA.Game/FluentTest.cs
Normal file
37
OpenRA.Test/OpenRA.Game/FluentTest.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class FluentTest
|
||||
{
|
||||
readonly string pluralForms = @"
|
||||
label-players = {$player ->
|
||||
[one] One player
|
||||
*[other] {$player} players
|
||||
}
|
||||
";
|
||||
|
||||
[TestCase(TestName = "Fluent Plural Terms")]
|
||||
public void TestOne()
|
||||
{
|
||||
var bundle = new FluentBundle("en", pluralForms, e => Console.WriteLine(e.Message));
|
||||
var label = bundle.GetMessage("label-players", ["player", 1]);
|
||||
Assert.That("One player", Is.EqualTo(label));
|
||||
label = bundle.GetMessage("label-players", ["player", 2]);
|
||||
Assert.That("2 players", Is.EqualTo(label));
|
||||
}
|
||||
}
|
||||
}
|
||||
44
OpenRA.Test/OpenRA.Game/MediatorTest.cs
Normal file
44
OpenRA.Test/OpenRA.Game/MediatorTest.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using NUnit.Framework;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class MediatorTest
|
||||
{
|
||||
[TestCase(TestName = "Mediator test")]
|
||||
public void Test()
|
||||
{
|
||||
var mediator = new Mediator();
|
||||
var testHandler = new TestHandler();
|
||||
mediator.Subscribe(testHandler);
|
||||
|
||||
mediator.Send(new TestNotificaton());
|
||||
|
||||
Assert.That(testHandler.WasNotified, Is.True);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class TestHandler : INotificationHandler<TestNotificaton>
|
||||
{
|
||||
public bool WasNotified { get; set; }
|
||||
|
||||
public void Handle(TestNotificaton notification)
|
||||
{
|
||||
WasNotified = true;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class TestNotificaton { }
|
||||
}
|
||||
1142
OpenRA.Test/OpenRA.Game/MiniYamlTest.cs
Normal file
1142
OpenRA.Test/OpenRA.Game/MiniYamlTest.cs
Normal file
File diff suppressed because it is too large
Load Diff
74
OpenRA.Test/OpenRA.Game/OrderTest.cs
Normal file
74
OpenRA.Test/OpenRA.Game/OrderTest.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class OrderTest
|
||||
{
|
||||
static byte[] RoundTripOrder(byte[] bytes)
|
||||
{
|
||||
return Order.Deserialize(null, new BinaryReader(new MemoryStream(bytes))).Serialize();
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Order data persists over serialization (empty)")]
|
||||
public void SerializeEmpty()
|
||||
{
|
||||
var o = new Order().Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Order data persists over serialization (unqueued)")]
|
||||
public void SerializeUnqueued()
|
||||
{
|
||||
var o = new Order("Test", null, false).Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Order data persists over serialization (queued)")]
|
||||
public void SerializeQueued()
|
||||
{
|
||||
var o = new Order("Test", null, true).Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Order data persists over serialization (pos target)")]
|
||||
public void SerializePos()
|
||||
{
|
||||
var o = new Order("Test", null, Target.FromPos(new WPos(int.MinValue, 0, int.MaxValue)), false).Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Order data persists over serialization (invalid target)")]
|
||||
public void SerializeInvalid()
|
||||
{
|
||||
var o = new Order("Test", null, Target.Invalid, false).Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Order data persists over serialization (extra fields)")]
|
||||
public void SerializeExtra()
|
||||
{
|
||||
var o = new Order("Test", null, Target.Invalid, true)
|
||||
{
|
||||
TargetString = "TargetString",
|
||||
ExtraLocation = new CPos(2047, 2047, 128),
|
||||
ExtraData = uint.MaxValue,
|
||||
IsImmediate = true,
|
||||
}.Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
}
|
||||
}
|
||||
43
OpenRA.Test/OpenRA.Game/PlatformTest.cs
Normal file
43
OpenRA.Test/OpenRA.Game/PlatformTest.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class PlatformTest
|
||||
{
|
||||
string supportDir;
|
||||
string engineDir;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
supportDir = Platform.SupportDir;
|
||||
engineDir = Platform.EngineDir;
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Returns literal paths")]
|
||||
public void ResolvePath()
|
||||
{
|
||||
Assert.That(Platform.ResolvePath("^SupportDir|testpath"),
|
||||
Is.EqualTo(Path.Combine(supportDir, "testpath")));
|
||||
|
||||
Assert.That(Platform.ResolvePath("^EngineDir|Foo.dll"),
|
||||
Is.EqualTo(Path.Combine(engineDir, "Foo.dll")));
|
||||
|
||||
Assert.That(Platform.ResolvePath("testpath"),
|
||||
Is.EqualTo("testpath"));
|
||||
}
|
||||
}
|
||||
}
|
||||
164
OpenRA.Test/OpenRA.Game/PngTest.cs
Normal file
164
OpenRA.Test/OpenRA.Game/PngTest.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class PngTests
|
||||
{
|
||||
[Test]
|
||||
public void Save_ShouldProduceValidPngFile()
|
||||
{
|
||||
// Arrange
|
||||
var colors = Enumerable.Range(0, 256).Select(i => Color.FromArgb(i, i, i)).ToArray();
|
||||
var png = new Png(new byte[10 * 20], SpriteFrameType.Indexed8, 10, 20, colors);
|
||||
|
||||
// Act
|
||||
var result = png.Save();
|
||||
|
||||
// Assert
|
||||
Assert.That(Png.Verify(new MemoryStream(result)), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Save_Method_Should_Write_Indexed8_Palette_If_256_Colors_Or_Less()
|
||||
{
|
||||
// Arrange
|
||||
var colors = Enumerable.Range(0, 256).Select(i => Color.FromArgb(i, i, i)).ToArray();
|
||||
var png = new Png(new byte[10 * 20], SpriteFrameType.Indexed8, 10, 20, colors);
|
||||
|
||||
// Act
|
||||
var result = png.Save();
|
||||
|
||||
// Assert
|
||||
// Byte at index 25 contains color type information
|
||||
// 0x03 represents Indexed8 with a palette
|
||||
var colorTypeByte = result[25];
|
||||
Assert.That(colorTypeByte, Is.EqualTo(0x03));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Save_Method_Should_Write_Rgba32_If_Alpha_Channel_Required()
|
||||
{
|
||||
// Arrange
|
||||
var png = new Png(new byte[10 * 20 * 4], SpriteFrameType.Rgba32, 10, 20);
|
||||
|
||||
// Act
|
||||
var result = png.Save();
|
||||
|
||||
// Assert
|
||||
// Byte at index 25 contains color type information
|
||||
// 0x06 represents RGBA32 with alpha
|
||||
var colorTypeByte = result[25];
|
||||
Assert.That(colorTypeByte, Is.EqualTo(0x06));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Save_ShouldThrowException_WhenDataLenghtNotEqualExpectedLenght()
|
||||
{
|
||||
// Arrange
|
||||
var colors = Enumerable.Range(0, 256).Select(i => Color.FromArgb(i, i, i)).ToArray();
|
||||
|
||||
// Act
|
||||
void TestDelegate() => new Png(new byte[10 * 20], SpriteFrameType.Indexed8, 100, 20, colors);
|
||||
|
||||
// Assert
|
||||
var ex = Assert.Throws<InvalidDataException>(TestDelegate);
|
||||
Assert.That(ex.Message, Is.EqualTo("Input data does not match expected length"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PngConstructor_InvalidSignature_ThrowsInvalidDataException()
|
||||
{
|
||||
// Arrange
|
||||
byte[] invalidSignature = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<InvalidDataException>(() => new Png(new MemoryStream(invalidSignature)));
|
||||
Assert.That("PNG Signature is bogus", Does.Contain(exception.Message));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PngConstructor_HeaderNotFirst_ThrowsInvalidDataException()
|
||||
{
|
||||
// Arrange
|
||||
var invalidPngData = new byte[]
|
||||
{
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
|
||||
0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<InvalidDataException>(() => new Png(new MemoryStream(invalidPngData)));
|
||||
Assert.That("Invalid PNG file - header does not appear first.", Does.Contain(exception.Message));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PngConstructor_DuplicateIhdrHeader_ThrowsInvalidDataException()
|
||||
{
|
||||
// Arrange
|
||||
var invalidPngData = new byte[]
|
||||
{
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
|
||||
0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
using (var stream = new MemoryStream(invalidPngData))
|
||||
{
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<EndOfStreamException>(() => new Png(stream));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("Failing test should be fixed")]
|
||||
public void PngConstructor_CompressionMethodNotSupported_ThrowsInvalidDataException()
|
||||
{
|
||||
// Arrange
|
||||
var invalidPngData = new byte[]
|
||||
{
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
|
||||
0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00,
|
||||
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
using (var stream = new MemoryStream(invalidPngData))
|
||||
{
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<InvalidDataException>(() => new Png(stream));
|
||||
Assert.That("Compression method not supported", Is.EqualTo(exception.Message));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Constructor_ThrowsExceptionForNullPaletteIfTypeIsIndexed8()
|
||||
{
|
||||
// Arrange
|
||||
const int Width = 100;
|
||||
const int Height = 100;
|
||||
const SpriteFrameType Type = SpriteFrameType.Indexed8;
|
||||
|
||||
// Act and Assert
|
||||
Assert.Throws<InvalidDataException>(() => new Png(new byte[Width * Height], Type, Width, Height, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
66
OpenRA.Test/OpenRA.Game/PriorityArrayTest.cs
Normal file
66
OpenRA.Test/OpenRA.Game/PriorityArrayTest.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class PriorityArrayTest
|
||||
{
|
||||
[TestCase(0)]
|
||||
[TestCase(5)]
|
||||
[TestCase(int.MinValue)]
|
||||
[TestCase(int.MaxValue)]
|
||||
public void PriorityArraySequentialTest(int initialValue)
|
||||
{
|
||||
var input = new KeyValuePair<int, int>[]
|
||||
{
|
||||
new(0, 1),
|
||||
new(1, 5),
|
||||
new(2, 3),
|
||||
new(3, 2),
|
||||
new(4, 8),
|
||||
new(5, 7),
|
||||
new(6, 4),
|
||||
new(7, 6)
|
||||
};
|
||||
var expected = new KeyValuePair<int, int>[]
|
||||
{
|
||||
new(0, 1),
|
||||
new(3, 2),
|
||||
new(2, 3),
|
||||
new(6, 4),
|
||||
new(1, 5),
|
||||
new(7, 6),
|
||||
new(5, 7),
|
||||
new(4, 8)
|
||||
};
|
||||
|
||||
var pa = new PriorityArray<int>(8, initialValue);
|
||||
|
||||
foreach (var kv in input)
|
||||
pa[kv.Key] = kv.Value;
|
||||
|
||||
var readback = new KeyValuePair<int, int>[8];
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
var index = pa.GetMinIndex();
|
||||
readback[i] = new KeyValuePair<int, int>(index, pa[index]);
|
||||
pa[index] = int.MaxValue;
|
||||
}
|
||||
|
||||
Assert.That(readback, Is.EquivalentTo(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
156
OpenRA.Test/OpenRA.Game/PriorityQueueTest.cs
Normal file
156
OpenRA.Test/OpenRA.Game/PriorityQueueTest.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using OpenRA.Mods.Common;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class PriorityQueueTest
|
||||
{
|
||||
readonly struct Int32Comparer : IComparer<int>
|
||||
{
|
||||
public int Compare(int x, int y) => x.CompareTo(y);
|
||||
}
|
||||
|
||||
[TestCase(1, 123)]
|
||||
[TestCase(1, 1234)]
|
||||
[TestCase(1, 12345)]
|
||||
[TestCase(2, 123)]
|
||||
[TestCase(2, 1234)]
|
||||
[TestCase(2, 12345)]
|
||||
[TestCase(10, 123)]
|
||||
[TestCase(10, 1234)]
|
||||
[TestCase(10, 12345)]
|
||||
[TestCase(15, 123)]
|
||||
[TestCase(15, 1234)]
|
||||
[TestCase(15, 12345)]
|
||||
[TestCase(16, 123)]
|
||||
[TestCase(16, 1234)]
|
||||
[TestCase(16, 12345)]
|
||||
[TestCase(17, 123)]
|
||||
[TestCase(17, 1234)]
|
||||
[TestCase(17, 12345)]
|
||||
[TestCase(100, 123)]
|
||||
[TestCase(100, 1234)]
|
||||
[TestCase(100, 12345)]
|
||||
[TestCase(1000, 123)]
|
||||
[TestCase(1000, 1234)]
|
||||
[TestCase(1000, 12345)]
|
||||
public void PriorityQueueAddThenRemoveTest(int count, int seed)
|
||||
{
|
||||
var mt = new MersenneTwister(seed);
|
||||
var values = Enumerable.Range(0, count).ToList();
|
||||
var shuffledValues = values.Shuffle(mt).ToArray();
|
||||
|
||||
var queue = new Primitives.PriorityQueue<int, Int32Comparer>(default);
|
||||
|
||||
Assert.That(queue.Empty, Is.True, "New queue should start out empty.");
|
||||
Assert.Throws<InvalidOperationException>(() => queue.Peek(), "Peeking at an empty queue should throw.");
|
||||
Assert.Throws<InvalidOperationException>(() => queue.Pop(), "Popping an empty queue should throw.");
|
||||
|
||||
foreach (var value in shuffledValues)
|
||||
{
|
||||
queue.Add(value);
|
||||
Assert.That(queue.Empty, Is.False, "Queue should not be empty - items have been added.");
|
||||
}
|
||||
|
||||
foreach (var value in values)
|
||||
{
|
||||
Assert.That(value, Is.EqualTo(queue.Peek()), "Peek returned the wrong item - should be in order.");
|
||||
Assert.That(queue.Empty, Is.False, "Queue should not be empty yet.");
|
||||
Assert.That(value, Is.EqualTo(queue.Pop()), "Pop returned the wrong item - should be in order.");
|
||||
}
|
||||
|
||||
Assert.That(queue.Empty, Is.True, "Queue should now be empty.");
|
||||
Assert.Throws<InvalidOperationException>(() => queue.Peek(), "Peeking at an empty queue should throw.");
|
||||
Assert.Throws<InvalidOperationException>(() => queue.Pop(), "Popping an empty queue should throw.");
|
||||
}
|
||||
|
||||
[TestCase(15, 123)]
|
||||
[TestCase(15, 1234)]
|
||||
[TestCase(15, 12345)]
|
||||
[TestCase(16, 123)]
|
||||
[TestCase(16, 1234)]
|
||||
[TestCase(16, 12345)]
|
||||
[TestCase(17, 123)]
|
||||
[TestCase(17, 1234)]
|
||||
[TestCase(17, 12345)]
|
||||
[TestCase(100, 123)]
|
||||
[TestCase(100, 1234)]
|
||||
[TestCase(100, 12345)]
|
||||
[TestCase(1000, 123)]
|
||||
[TestCase(1000, 1234)]
|
||||
[TestCase(1000, 12345)]
|
||||
public void PriorityQueueAddAndRemoveInterleavedTest(int count, int seed)
|
||||
{
|
||||
var mt = new MersenneTwister(seed);
|
||||
var shuffledValues = Enumerable.Range(0, count).Shuffle(mt).ToArray();
|
||||
|
||||
var queue = new Primitives.PriorityQueue<int, Int32Comparer>(default);
|
||||
|
||||
Assert.That(queue.Empty, Is.True, "New queue should start out empty.");
|
||||
Assert.Throws<InvalidOperationException>(() => queue.Peek(), "Peeking at an empty queue should throw.");
|
||||
Assert.Throws<InvalidOperationException>(() => queue.Pop(), "Popping an empty queue should throw.");
|
||||
|
||||
foreach (var value in shuffledValues.Take(10))
|
||||
{
|
||||
queue.Add(value);
|
||||
Assert.That(queue.Empty, Is.False, "Queue should not be empty - items have been added.");
|
||||
}
|
||||
|
||||
foreach (var value in shuffledValues.Take(10).Order().Take(5))
|
||||
{
|
||||
Assert.That(value, Is.EqualTo(queue.Peek()), "Peek returned the wrong item - should be in order.");
|
||||
Assert.That(queue.Empty, Is.False, "Queue should not be empty yet.");
|
||||
Assert.That(value, Is.EqualTo(queue.Pop()), "Pop returned the wrong item - should be in order.");
|
||||
}
|
||||
|
||||
foreach (var value in shuffledValues.Skip(10).Take(5))
|
||||
{
|
||||
queue.Add(value);
|
||||
Assert.That(queue.Empty, Is.False, "Queue should not be empty - items have been added.");
|
||||
}
|
||||
|
||||
foreach (var value in shuffledValues.Take(10).Order().Skip(5)
|
||||
.Concat(shuffledValues.Skip(10).Take(5)).Order().Take(5))
|
||||
{
|
||||
Assert.That(value, Is.EqualTo(queue.Peek()), "Peek returned the wrong item - should be in order.");
|
||||
Assert.That(queue.Empty, Is.False, "Queue should not be empty yet.");
|
||||
Assert.That(value, Is.EqualTo(queue.Pop()), "Pop returned the wrong item - should be in order.");
|
||||
}
|
||||
|
||||
foreach (var value in shuffledValues.Skip(15))
|
||||
{
|
||||
queue.Add(value);
|
||||
Assert.That(queue.Empty, Is.False, "Queue should not be empty - items have been added.");
|
||||
}
|
||||
|
||||
foreach (var value in shuffledValues.Take(10).Order().Skip(5)
|
||||
.Concat(shuffledValues.Skip(10).Take(5)).Order().Skip(5)
|
||||
.Concat(shuffledValues.Skip(15)).Order())
|
||||
{
|
||||
Assert.That(value, Is.EqualTo(queue.Peek()), "Peek returned the wrong item - should be in order.");
|
||||
Assert.That(queue.Empty, Is.False, "Queue should not be empty yet.");
|
||||
Assert.That(value, Is.EqualTo(queue.Pop()), "Pop returned the wrong item - should be in order.");
|
||||
}
|
||||
|
||||
Assert.That(queue.Empty, Is.True, "Queue should now be empty.");
|
||||
Assert.Throws<InvalidOperationException>(() => queue.Peek(), "Peeking at an empty queue should throw.");
|
||||
Assert.Throws<InvalidOperationException>(() => queue.Pop(), "Popping an empty queue should throw.");
|
||||
}
|
||||
}
|
||||
}
|
||||
35
OpenRA.Test/OpenRA.Game/Sha1Tests.cs
Normal file
35
OpenRA.Test/OpenRA.Game/Sha1Tests.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using NUnit.Framework;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class Sha1Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// https://en.wikipedia.org/wiki/SHA-1#Examples_and_pseudocode.
|
||||
/// </summary>
|
||||
/// <param name="input">The input string.</param>
|
||||
/// <param name="expected">The expected hex string of the SHA1.</param>
|
||||
[TestCase("The quick brown fox jumps over the lazy dog", "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12")]
|
||||
[TestCase("The quick brown fox jumps over the lazy cog", "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3")]
|
||||
[TestCase("", "da39a3ee5e6b4b0d3255bfef95601890afd80709")]
|
||||
public void Sha1HexConvert(string input, string expected)
|
||||
{
|
||||
var actual = CryptoUtil.SHA1Hash(input);
|
||||
|
||||
Assert.That(expected, Is.EqualTo(actual));
|
||||
}
|
||||
|
||||
[TestCase(0xFF0000FF, "0000FF")]
|
||||
[TestCase(0xFF00FFFF, "00FFFF")]
|
||||
[TestCase(0xFFFF00FF, "FF00FF")]
|
||||
[TestCase(0xAAFF00FF, "FF00FFAA")]
|
||||
public void ColorsToHex(uint value, string expected)
|
||||
{
|
||||
var color = Color.FromArgb(value);
|
||||
var actual = color.ToString();
|
||||
Assert.That(expected, Is.EqualTo(actual));
|
||||
}
|
||||
}
|
||||
}
|
||||
92
OpenRA.Test/OpenRA.Game/SpatiallyPartitionedTest.cs
Normal file
92
OpenRA.Test/OpenRA.Game/SpatiallyPartitionedTest.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using NUnit.Framework;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class SpatiallyPartitionedTest
|
||||
{
|
||||
[TestCase(TestName = "SpatiallyPartitioned.At works")]
|
||||
public void SpatiallyPartitionedAtTest()
|
||||
{
|
||||
var partition = new SpatiallyPartitioned<object>(5, 5, 2);
|
||||
|
||||
var a = new object();
|
||||
partition.Add(a, new Rectangle(0, 0, 1, 1));
|
||||
Assert.That(partition.At(new int2(0, 0)), Does.Contain(a), "a is not present after add");
|
||||
Assert.That(partition.At(new int2(0, 1)), Does.Not.Contain(a), "a is present in the wrong location");
|
||||
Assert.That(partition.At(new int2(1, 0)), Does.Not.Contain(a), "a is present in the wrong location");
|
||||
|
||||
var b = new object();
|
||||
partition.Add(b, new Rectangle(1, 1, 2, 2));
|
||||
Assert.That(partition.At(new int2(0, 1)), Does.Not.Contain(b), "b is present in the wrong location");
|
||||
Assert.That(partition.At(new int2(1, 0)), Does.Not.Contain(b), "b is present in the wrong location");
|
||||
Assert.That(partition.At(new int2(1, 1)), Does.Contain(b), "b is not present after add");
|
||||
Assert.That(partition.At(new int2(2, 2)), Does.Contain(b), "b is not present after add");
|
||||
Assert.That(partition.At(new int2(2, 3)), Does.Not.Contain(b), "b is present in the wrong location");
|
||||
Assert.That(partition.At(new int2(3, 2)), Does.Not.Contain(b), "b is present in the wrong location");
|
||||
Assert.That(partition.At(new int2(3, 3)), Does.Not.Contain(b), "b is present in the wrong location");
|
||||
|
||||
partition[b] = new Rectangle(4, 4, 1, 1);
|
||||
Assert.That(partition.At(new int2(0, 0)), Does.Contain(a), "a wrongly changed location when b was updated");
|
||||
Assert.That(partition.At(new int2(4, 4)), Does.Contain(b), "b is not present at the new location in the extreme corner of the partition");
|
||||
Assert.That(partition.At(new int2(1, 1)), Does.Not.Contain(b), "b is still present at the old location after update");
|
||||
|
||||
partition.Remove(a);
|
||||
Assert.That(partition.At(new int2(0, 0)), Does.Not.Contain(b), "a is still present after removal");
|
||||
Assert.That(partition.At(new int2(4, 4)), Does.Contain(b), "b wrongly changed location when a was removed");
|
||||
}
|
||||
|
||||
[TestCase(TestName = "SpatiallyPartitioned.InBox works")]
|
||||
public void SpatiallyPartitionedInBoxTest()
|
||||
{
|
||||
var partition = new SpatiallyPartitioned<object>(5, 5, 2);
|
||||
|
||||
var a = new object();
|
||||
partition.Add(a, new Rectangle(0, 0, 1, 1));
|
||||
Assert.That(partition.InBox(new Rectangle(0, 0, 0, 0)), Does.Not.Contain(a), "Searching an empty area should not return a");
|
||||
Assert.That(partition.InBox(new Rectangle(0, 0, 1, 1)), Does.Contain(a), "a is not present after add");
|
||||
Assert.That(partition.InBox(new Rectangle(0, 1, 1, 1)), Does.Not.Contain(a), "a is present in the wrong location");
|
||||
Assert.That(partition.InBox(new Rectangle(1, 0, 1, 1)), Does.Not.Contain(a), "a is present in the wrong location");
|
||||
|
||||
var b = new object();
|
||||
partition.Add(b, new Rectangle(1, 1, 2, 2));
|
||||
Assert.That(partition.InBox(new Rectangle(0, 1, 1, 1)), Does.Not.Contain(b), "b is present in the wrong location");
|
||||
Assert.That(partition.InBox(new Rectangle(1, 0, 1, 1)), Does.Not.Contain(b), "b is present in the wrong location");
|
||||
Assert.That(partition.InBox(new Rectangle(1, 1, 1, 1)), Does.Contain(b), "b is not present after add");
|
||||
Assert.That(partition.InBox(new Rectangle(2, 2, 1, 1)), Does.Contain(b), "b is not present after add");
|
||||
Assert.That(partition.InBox(new Rectangle(2, 3, 1, 1)), Does.Not.Contain(b), "b is present in the wrong location");
|
||||
Assert.That(partition.InBox(new Rectangle(3, 2, 1, 1)), Does.Not.Contain(b), "b is present in the wrong location");
|
||||
Assert.That(partition.InBox(new Rectangle(3, 3, 1, 1)), Does.Not.Contain(b), "b is present in the wrong location");
|
||||
|
||||
Assert.That(new[] { b }, Is.EquivalentTo(partition.InBox(new Rectangle(1, 1, 1, 1))),
|
||||
"Searching within a single partition bin did not return the correct result");
|
||||
Assert.That(partition.InBox(new Rectangle(0, 0, 5, 5)), Is.Unique,
|
||||
"Searching the whole partition returned duplicates of some items");
|
||||
Assert.That(new[] { a, b }, Is.EquivalentTo(partition.InBox(new Rectangle(0, 0, 5, 5))),
|
||||
"Searching the whole partition did not return all items");
|
||||
Assert.That(new[] { a, b }, Is.EquivalentTo(partition.InBox(new Rectangle(-10, -10, 25, 25))),
|
||||
"Searching an area larger than the partition did not return all items");
|
||||
|
||||
partition[b] = new Rectangle(4, 4, 1, 1);
|
||||
Assert.That(partition.InBox(new Rectangle(0, 0, 1, 1)), Does.Contain(a), "a wrongly changed location when b was updated");
|
||||
Assert.That(partition.InBox(new Rectangle(4, 4, 1, 1)), Does.Contain(b), "b is not present at the new location in the extreme corner of the partition");
|
||||
Assert.That(partition.InBox(new Rectangle(1, 1, 1, 1)), Does.Not.Contain(b), "b is still present at the old location after update");
|
||||
|
||||
partition.Remove(a);
|
||||
Assert.That(partition.InBox(new Rectangle(0, 0, 1, 1)), Does.Not.Contain(a), "a is still present after removal");
|
||||
Assert.That(partition.InBox(new Rectangle(4, 4, 1, 1)), Does.Contain(b), "b wrongly changed location when a was removed");
|
||||
}
|
||||
}
|
||||
}
|
||||
73
OpenRA.Test/OpenRA.Game/StreamExtsTests.cs
Normal file
73
OpenRA.Test/OpenRA.Game/StreamExtsTests.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class StreamExtsTests
|
||||
{
|
||||
[TestCase(TestName = "ReadAllLines is equivalent to ReadAllLinesAsMemory")]
|
||||
public void ReadAllLines()
|
||||
{
|
||||
foreach (var source in new[]
|
||||
{
|
||||
"abc",
|
||||
"abc\n",
|
||||
"abc\r\n",
|
||||
"abc\ndef",
|
||||
"abc\r\ndef",
|
||||
"abc\n\n\n",
|
||||
"abc\r\n\r\n\r\n",
|
||||
"abc\n\n\ndef",
|
||||
"abc\r\n\r\n\r\ndef",
|
||||
"abc\ndef\nghi\n",
|
||||
"abc\r\ndef\r\nghi\r\n",
|
||||
"abc\ndef\nghi\njkl",
|
||||
"abc\r\ndef\r\nghi\r\njkl",
|
||||
new string('a', 126),
|
||||
new string('a', 126) + '\n',
|
||||
new string('a', 126) + "\r\n",
|
||||
new string('a', 126) + "b",
|
||||
new string('a', 126) + "\nb",
|
||||
new string('a', 126) + "\r\nb",
|
||||
new string('a', 127),
|
||||
new string('a', 127) + '\n',
|
||||
new string('a', 127) + "\r\n",
|
||||
new string('a', 127) + "b",
|
||||
new string('a', 127) + "\nb",
|
||||
new string('a', 127) + "\r\nb",
|
||||
new string('a', 128),
|
||||
new string('a', 128) + '\n',
|
||||
new string('a', 128) + "\r\n",
|
||||
new string('a', 128) + "b",
|
||||
new string('a', 128) + "\nb",
|
||||
new string('a', 128) + "\r\nb",
|
||||
new string('a', 129),
|
||||
new string('a', 129) + '\n',
|
||||
new string('a', 129) + "\r\n",
|
||||
new string('a', 129) + "b",
|
||||
new string('a', 129) + "\nb",
|
||||
new string('a', 129) + "\r\nb",
|
||||
})
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(source);
|
||||
var lines = new MemoryStream(bytes).ReadAllLines().ToArray();
|
||||
var linesAsMemory = new MemoryStream(bytes).ReadAllLinesAsMemory().Select(l => l.ToString()).ToArray();
|
||||
Assert.That(linesAsMemory, Is.EquivalentTo(lines));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
464
OpenRA.Test/OpenRA.Game/VariableExpressionTest.cs
Normal file
464
OpenRA.Test/OpenRA.Game/VariableExpressionTest.cs
Normal file
@@ -0,0 +1,464 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Test
|
||||
{
|
||||
[TestFixture]
|
||||
sealed class VariableExpressionTest
|
||||
{
|
||||
readonly IReadOnlyDictionary<string, int> testValues = new Dictionary<string, int>
|
||||
{
|
||||
{ "t", 5 },
|
||||
{ "t-1", 7 },
|
||||
{ "one", 1 },
|
||||
{ "five", 5 }
|
||||
};
|
||||
|
||||
void AssertFalse(string expression)
|
||||
{
|
||||
Assert.That(new BooleanExpression(expression).Evaluate(testValues), Is.False, expression);
|
||||
}
|
||||
|
||||
void AssertTrue(string expression)
|
||||
{
|
||||
Assert.That(new BooleanExpression(expression).Evaluate(testValues), Is.True, expression);
|
||||
}
|
||||
|
||||
void AssertValue(string expression, int value)
|
||||
{
|
||||
Assert.That(value, Is.EqualTo(new IntegerExpression(expression).Evaluate(testValues)), expression);
|
||||
}
|
||||
|
||||
void AssertParseFailure(string expression, string errorMessage)
|
||||
{
|
||||
var actualErrorMessage = Assert.Throws<InvalidDataException>(
|
||||
() => new IntegerExpression(expression).Evaluate(testValues), expression).Message;
|
||||
Assert.That(errorMessage, Is.EqualTo(actualErrorMessage), expression + " ===> " + actualErrorMessage);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Numbers")]
|
||||
public void TestNumbers()
|
||||
{
|
||||
AssertParseFailure("1a", "Number 1 and variable merged at index 0");
|
||||
AssertValue("0", 0);
|
||||
AssertValue("1", 1);
|
||||
AssertValue("12", 12);
|
||||
AssertValue("-1", -1);
|
||||
AssertValue("-12", -12);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Variables")]
|
||||
public void TestVariables()
|
||||
{
|
||||
AssertValue("one", 1);
|
||||
AssertValue("five", 5);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Boolean Constants")]
|
||||
public void TestBoolConsts()
|
||||
{
|
||||
AssertValue(" true", 1);
|
||||
AssertValue(" true ", 1);
|
||||
AssertValue("true", 1);
|
||||
AssertValue("false", 0);
|
||||
AssertValue("tru", 0);
|
||||
AssertValue("fals", 0);
|
||||
AssertValue("tr", 0);
|
||||
AssertValue("fal", 0);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Booleans")]
|
||||
public void TestBooleans()
|
||||
{
|
||||
AssertValue("false", 0);
|
||||
AssertValue("true", 1);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "AND operation")]
|
||||
public void TestAnd()
|
||||
{
|
||||
AssertTrue("true && true");
|
||||
AssertFalse("false && false");
|
||||
AssertFalse("true && false");
|
||||
AssertFalse("false && true");
|
||||
AssertValue("2 && false", 0);
|
||||
AssertValue("false && 2", 0);
|
||||
AssertValue("3 && 2", 1);
|
||||
AssertValue("2 && 3", 1);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "OR operation")]
|
||||
public void TestOR()
|
||||
{
|
||||
AssertTrue("true || true");
|
||||
AssertFalse("false || false");
|
||||
AssertTrue("true || false");
|
||||
AssertTrue("false || true");
|
||||
AssertValue("2 || false", 1);
|
||||
AssertValue("false || 2", 1);
|
||||
AssertValue("3 || 2", 1);
|
||||
AssertValue("2 || 3", 1);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Equals operation")]
|
||||
public void TestEquals()
|
||||
{
|
||||
AssertTrue("true == true");
|
||||
AssertTrue("false == false");
|
||||
AssertFalse("true == false");
|
||||
AssertFalse("false == true");
|
||||
AssertTrue("1 == 1");
|
||||
AssertTrue("0 == 0");
|
||||
AssertFalse("1 == 0");
|
||||
AssertTrue("1 == true");
|
||||
AssertFalse("1 == false");
|
||||
AssertTrue("0 == false");
|
||||
AssertFalse("0 == true");
|
||||
AssertValue("12 == 12", 1);
|
||||
AssertValue("1 == 12", 0);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Not-equals operation")]
|
||||
public void TestNotEquals()
|
||||
{
|
||||
AssertFalse("true != true");
|
||||
AssertFalse("false != false");
|
||||
AssertTrue("true != false");
|
||||
AssertTrue("false != true");
|
||||
AssertValue("1 != 2", 1);
|
||||
AssertValue("1 != 1", 0);
|
||||
AssertFalse("1 != true");
|
||||
AssertFalse("0 != false");
|
||||
AssertTrue("1 != false");
|
||||
AssertTrue("0 != true");
|
||||
}
|
||||
|
||||
[TestCase(TestName = "NOT operation")]
|
||||
public void TestNOT()
|
||||
{
|
||||
AssertValue("!true", 0);
|
||||
AssertValue("!false", 1);
|
||||
AssertValue("!!true", 1);
|
||||
AssertValue("!!false", 0);
|
||||
AssertValue("!0", 1);
|
||||
AssertValue("!1", 0);
|
||||
AssertValue("!5", 0);
|
||||
AssertValue("!!5", 1);
|
||||
AssertValue("!-5", 0);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Relation operations")]
|
||||
public void TestRelations()
|
||||
{
|
||||
AssertValue("2 < 5", 1);
|
||||
AssertValue("0 < 5", 1);
|
||||
AssertValue("5 < 2", 0);
|
||||
AssertValue("5 < 5", 0);
|
||||
AssertValue("-5 < 0", 1);
|
||||
AssertValue("-2 < -5", 0);
|
||||
AssertValue("-5 < -2", 1);
|
||||
AssertValue("-5 < -5", 0);
|
||||
AssertValue("-7 < 5", 1);
|
||||
AssertValue("0 <= 5", 1);
|
||||
AssertValue("2 <= 5", 1);
|
||||
AssertValue("5 <= 2", 0);
|
||||
AssertValue("5 <= 5", 1);
|
||||
AssertValue("5 <= 0", 0);
|
||||
AssertValue("-2 <= -5", 0);
|
||||
AssertValue("-5 <= -2", 1);
|
||||
AssertValue("-5 <= -5", 1);
|
||||
AssertValue("-7 <= 5", 1);
|
||||
AssertValue("0 <= -5", 0);
|
||||
AssertValue("-5 <= 0", 1);
|
||||
AssertValue("5 > 2", 1);
|
||||
AssertValue("0 > 5", 0);
|
||||
AssertValue("2 > 5", 0);
|
||||
AssertValue("5 > 5", 0);
|
||||
AssertValue("5 > 0", 1);
|
||||
AssertValue("-2 > -5", 1);
|
||||
AssertValue("-7 > -5", 0);
|
||||
AssertValue("-5 > -5", 0);
|
||||
AssertValue("-4 > -5", 1);
|
||||
AssertValue("5 >= 0", 1);
|
||||
AssertValue("0 >= 5", 0);
|
||||
AssertValue("5 >= 2", 1);
|
||||
AssertValue("2 >= 5", 0);
|
||||
AssertValue("5 >= 5", 1);
|
||||
AssertValue("-5 >= 0", 0);
|
||||
AssertValue("0 >= -5", 1);
|
||||
AssertValue("-7 >= 5", 0);
|
||||
AssertValue("-5 >= -5", 1);
|
||||
AssertValue("-4 >= -5", 1);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Relation Mixed Precedence")]
|
||||
public void TestRelationMixedPrecedence()
|
||||
{
|
||||
AssertValue("5 <= 5 && 2 > 1", 1);
|
||||
AssertValue("5 > 5 || 2 > 1", 1);
|
||||
AssertValue("5 > 5 || 1 > 1", 0);
|
||||
AssertValue("5 <= 5 == 2 > 1", 1);
|
||||
AssertValue("5 > 5 == 2 > 1", 0);
|
||||
AssertValue("5 > 5 == 1 > 1", 1);
|
||||
AssertValue("5 <= 5 != 2 > 1", 0);
|
||||
AssertValue("5 > 5 != 2 > 1", 1);
|
||||
AssertValue("5 > 5 != 1 > 1", 0);
|
||||
AssertValue("5 > 5 != 1 >= 1", 1);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "AND-OR Precedence")]
|
||||
public void TestAndOrPrecedence()
|
||||
{
|
||||
AssertTrue("true && false || true");
|
||||
AssertFalse("false || false && true");
|
||||
AssertTrue("true && !true || !false");
|
||||
AssertFalse("false || !true && !false");
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Parenthesis")]
|
||||
public void TestParens()
|
||||
{
|
||||
AssertTrue("(true)");
|
||||
AssertTrue("((true))");
|
||||
AssertFalse("(false)");
|
||||
AssertFalse("((false))");
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Arithmetic")]
|
||||
public void TestArithmetic()
|
||||
{
|
||||
AssertValue("~0", ~0);
|
||||
AssertValue("-0", 0);
|
||||
AssertValue("-a", 0);
|
||||
AssertValue("-true", -1);
|
||||
AssertValue("~-0", -1);
|
||||
AssertValue("2 + 3", 5);
|
||||
AssertValue("2 + 0", 2);
|
||||
AssertValue("2 + 3", 5);
|
||||
AssertValue("5 - 3", 2);
|
||||
AssertValue("5 - -3", 8);
|
||||
AssertValue("5 - 0", 5);
|
||||
AssertValue("2 * 3", 6);
|
||||
AssertValue("2 * 0", 0);
|
||||
AssertValue("2 * -3", -6);
|
||||
AssertValue("-2 * 3", -6);
|
||||
AssertValue("-2 * -3", 6);
|
||||
AssertValue("6 / 3", 2);
|
||||
AssertValue("7 / 3", 2);
|
||||
AssertValue("-6 / 3", -2);
|
||||
AssertValue("6 / -3", -2);
|
||||
AssertValue("-6 / -3", 2);
|
||||
AssertValue("8 / 3", 2);
|
||||
AssertValue("6 % 3", 0);
|
||||
AssertValue("7 % 3", 1);
|
||||
AssertValue("8 % 3", 2);
|
||||
AssertValue("7 % 0", 0);
|
||||
AssertValue("-7 % 3", -1);
|
||||
AssertValue("7 % -3", 1);
|
||||
AssertValue("-7 % -3", -1);
|
||||
AssertValue("8 / 0", 0);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Arithmetic Mixed")]
|
||||
public void TestArithmeticMixed()
|
||||
{
|
||||
AssertValue("~~0", 0);
|
||||
AssertValue("-~0", 1);
|
||||
AssertValue("~- 0", -1);
|
||||
AssertValue("2 * 3 + 4", 10);
|
||||
AssertValue("2 * 3 - 4", 2);
|
||||
AssertValue("2 + 3 * 4", 14);
|
||||
AssertValue("2 + 3 % 4", 5);
|
||||
AssertValue("2 + 3 / 4", 2);
|
||||
AssertValue("2 * 3 / 4", 1);
|
||||
AssertValue("8 / 2 == 4", 1);
|
||||
AssertValue("~2 + ~3", -7);
|
||||
AssertValue("~(~2 + ~3)", 6);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Hyphen")]
|
||||
public void TestHyphen()
|
||||
{
|
||||
AssertValue("t-1", 7);
|
||||
AssertValue("-t-1", -7);
|
||||
AssertValue("t - 1", 4);
|
||||
AssertValue("-1", -1);
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Parenthesis and mixed operations")]
|
||||
public void TestMixedParens()
|
||||
{
|
||||
AssertTrue("(!false)");
|
||||
AssertTrue("!(false)");
|
||||
AssertFalse("!(!false)");
|
||||
AssertTrue("(true) || (false)");
|
||||
AssertTrue("true && (false || true)");
|
||||
AssertTrue("(true && false) || true");
|
||||
AssertTrue("!(true && false) || false");
|
||||
AssertTrue("((true != true) == false) && true");
|
||||
AssertFalse("(true != false) == false && true");
|
||||
AssertTrue("true || ((true != false) != !(false && true))");
|
||||
AssertFalse("((true != false) != !(false && true))");
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Test parser errors")]
|
||||
public void TestParseErrors()
|
||||
{
|
||||
AssertParseFailure("()", "Empty parenthesis at index 0");
|
||||
AssertParseFailure("! && true", "Missing value or sub-expression or there is an extra operator `!` at index 0 or `&&` at index 2");
|
||||
AssertParseFailure("(true", "Unclosed opening parenthesis at index 0");
|
||||
AssertParseFailure(")true", "Unmatched closing parenthesis at index 0");
|
||||
AssertParseFailure("false)", "Unmatched closing parenthesis at index 5");
|
||||
AssertParseFailure("false(", "Missing binary operation before `(` at index 5");
|
||||
AssertParseFailure("(", "Missing value or sub-expression at end for `(` operator");
|
||||
AssertParseFailure(")", "Unmatched closing parenthesis at index 0");
|
||||
AssertParseFailure("false!", "Missing binary operation before `!` at index 5");
|
||||
AssertParseFailure("true false", "Missing binary operation before `false` at index 5");
|
||||
AssertParseFailure("true & false", "Unexpected character '&' at index 5 - should it be `&&`?");
|
||||
AssertParseFailure("true | false", "Unexpected character '|' at index 5 - should it be `||`?");
|
||||
AssertParseFailure("true : false", "Invalid character ':' at index 5");
|
||||
AssertParseFailure("true & false && !", "Unexpected character '&' at index 5 - should it be `&&`?");
|
||||
AssertParseFailure("(true && !)", "Missing value or sub-expression or there is an extra operator `!` at index 9 or `)` at index 10");
|
||||
AssertParseFailure("&& false", "Missing value or sub-expression at beginning for `&&` operator");
|
||||
AssertParseFailure("false ||", "Missing value or sub-expression at end for `||` operator");
|
||||
AssertParseFailure("1 <", "Missing value or sub-expression at end for `<` operator");
|
||||
AssertParseFailure("-1a", "Number -1 and variable merged at index 0");
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Test hyphen parser errors")]
|
||||
public void TestParseHyphenErrors()
|
||||
{
|
||||
AssertParseFailure("-", "Missing value or sub-expression at end for `-` operator");
|
||||
AssertParseFailure("-1-1", "Missing binary operation before `-1` at index 2");
|
||||
AssertParseFailure("5-1", "Missing binary operation before `-1` at index 1");
|
||||
AssertParseFailure("6 -1", "Missing binary operation before `-1` at index 2");
|
||||
AssertParseFailure("t -1", "Missing binary operation before `-1` at index 2");
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Test mixed characters at end of identifier parser errors")]
|
||||
public void TestParseMixedEndErrors()
|
||||
{
|
||||
AssertParseFailure("t- 1", "Invalid identifier end character at index 1 for `t-`");
|
||||
AssertParseFailure("t-", "Invalid identifier end character at index 1 for `t-`");
|
||||
AssertParseFailure("t. 1", "Invalid identifier end character at index 1 for `t.`");
|
||||
AssertParseFailure("t.", "Invalid identifier end character at index 1 for `t.`");
|
||||
AssertParseFailure("t@ 1", "Invalid identifier end character at index 1 for `t@`");
|
||||
AssertParseFailure("t@", "Invalid identifier end character at index 1 for `t@`");
|
||||
AssertParseFailure("t$ 1", "Invalid identifier end character at index 1 for `t$`");
|
||||
AssertParseFailure("t$", "Invalid identifier end character at index 1 for `t$`");
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Test binary operator whitespace parser errors")]
|
||||
public void TestParseSpacedBinaryOperatorErrors()
|
||||
{
|
||||
// `t-1` is valid variable name and `t- 1` starts with an invalid variable name.
|
||||
// `6 -1`, `6-1`, `t -1` contain `-1` and are missing a binary operator.
|
||||
AssertParseFailure("6- 1", "Missing whitespace at index 2, before `-` operator.");
|
||||
|
||||
AssertParseFailure("6+ 1", "Missing whitespace at index 2, before `+` operator.");
|
||||
AssertParseFailure("t+ 1", "Missing whitespace at index 2, before `+` operator.");
|
||||
AssertParseFailure("6 +1", "Missing whitespace at index 3, after `+` operator.");
|
||||
AssertParseFailure("t +1", "Missing whitespace at index 3, after `+` operator.");
|
||||
AssertParseFailure("6+1", "Missing whitespace at index 2, before `+` operator.");
|
||||
AssertParseFailure("t+1", "Missing whitespace at index 2, before `+` operator.");
|
||||
|
||||
AssertParseFailure("6* 1", "Missing whitespace at index 2, before `*` operator.");
|
||||
AssertParseFailure("t* 1", "Missing whitespace at index 2, before `*` operator.");
|
||||
AssertParseFailure("6 *1", "Missing whitespace at index 3, after `*` operator.");
|
||||
AssertParseFailure("t *1", "Missing whitespace at index 3, after `*` operator.");
|
||||
AssertParseFailure("6*1", "Missing whitespace at index 2, before `*` operator.");
|
||||
AssertParseFailure("t*1", "Missing whitespace at index 2, before `*` operator.");
|
||||
|
||||
AssertParseFailure("6/ 1", "Missing whitespace at index 2, before `/` operator.");
|
||||
AssertParseFailure("t/ 1", "Missing whitespace at index 2, before `/` operator.");
|
||||
AssertParseFailure("6 /1", "Missing whitespace at index 3, after `/` operator.");
|
||||
AssertParseFailure("t /1", "Missing whitespace at index 3, after `/` operator.");
|
||||
AssertParseFailure("6/1", "Missing whitespace at index 2, before `/` operator.");
|
||||
AssertParseFailure("t/1", "Missing whitespace at index 2, before `/` operator.");
|
||||
|
||||
AssertParseFailure("6% 1", "Missing whitespace at index 2, before `%` operator.");
|
||||
AssertParseFailure("t% 1", "Missing whitespace at index 2, before `%` operator.");
|
||||
AssertParseFailure("6 %1", "Missing whitespace at index 3, after `%` operator.");
|
||||
AssertParseFailure("t %1", "Missing whitespace at index 3, after `%` operator.");
|
||||
AssertParseFailure("6%1", "Missing whitespace at index 2, before `%` operator.");
|
||||
AssertParseFailure("t%1", "Missing whitespace at index 2, before `%` operator.");
|
||||
|
||||
AssertParseFailure("6< 1", "Missing whitespace at index 2, before `<` operator.");
|
||||
AssertParseFailure("t< 1", "Missing whitespace at index 2, before `<` operator.");
|
||||
AssertParseFailure("6 <1", "Missing whitespace at index 3, after `<` operator.");
|
||||
AssertParseFailure("t <1", "Missing whitespace at index 3, after `<` operator.");
|
||||
AssertParseFailure("6<1", "Missing whitespace at index 2, before `<` operator.");
|
||||
AssertParseFailure("t<1", "Missing whitespace at index 2, before `<` operator.");
|
||||
|
||||
AssertParseFailure("6> 1", "Missing whitespace at index 2, before `>` operator.");
|
||||
AssertParseFailure("t> 1", "Missing whitespace at index 2, before `>` operator.");
|
||||
AssertParseFailure("6 >1", "Missing whitespace at index 3, after `>` operator.");
|
||||
AssertParseFailure("t >1", "Missing whitespace at index 3, after `>` operator.");
|
||||
AssertParseFailure("6>1", "Missing whitespace at index 2, before `>` operator.");
|
||||
AssertParseFailure("t>1", "Missing whitespace at index 2, before `>` operator.");
|
||||
|
||||
AssertParseFailure("6&& 1", "Missing whitespace at index 3, before `&&` operator.");
|
||||
AssertParseFailure("t&& 1", "Missing whitespace at index 3, before `&&` operator.");
|
||||
AssertParseFailure("6 &&1", "Missing whitespace at index 4, after `&&` operator.");
|
||||
AssertParseFailure("t &&1", "Missing whitespace at index 4, after `&&` operator.");
|
||||
AssertParseFailure("6&&1", "Missing whitespace at index 3, before `&&` operator.");
|
||||
AssertParseFailure("t&&1", "Missing whitespace at index 3, before `&&` operator.");
|
||||
|
||||
AssertParseFailure("6|| 1", "Missing whitespace at index 3, before `||` operator.");
|
||||
AssertParseFailure("t|| 1", "Missing whitespace at index 3, before `||` operator.");
|
||||
AssertParseFailure("6 ||1", "Missing whitespace at index 4, after `||` operator.");
|
||||
AssertParseFailure("t ||1", "Missing whitespace at index 4, after `||` operator.");
|
||||
AssertParseFailure("6||1", "Missing whitespace at index 3, before `||` operator.");
|
||||
AssertParseFailure("t||1", "Missing whitespace at index 3, before `||` operator.");
|
||||
|
||||
AssertParseFailure("6== 1", "Missing whitespace at index 3, before `==` operator.");
|
||||
AssertParseFailure("t== 1", "Missing whitespace at index 3, before `==` operator.");
|
||||
AssertParseFailure("6 ==1", "Missing whitespace at index 4, after `==` operator.");
|
||||
AssertParseFailure("t ==1", "Missing whitespace at index 4, after `==` operator.");
|
||||
AssertParseFailure("6==1", "Missing whitespace at index 3, before `==` operator.");
|
||||
AssertParseFailure("t==1", "Missing whitespace at index 3, before `==` operator.");
|
||||
|
||||
AssertParseFailure("6!= 1", "Missing whitespace at index 3, before `!=` operator.");
|
||||
AssertParseFailure("t!= 1", "Missing whitespace at index 3, before `!=` operator.");
|
||||
AssertParseFailure("6 !=1", "Missing whitespace at index 4, after `!=` operator.");
|
||||
AssertParseFailure("t !=1", "Missing whitespace at index 4, after `!=` operator.");
|
||||
AssertParseFailure("6!=1", "Missing whitespace at index 3, before `!=` operator.");
|
||||
AssertParseFailure("t!=1", "Missing whitespace at index 3, before `!=` operator.");
|
||||
|
||||
AssertParseFailure("6<= 1", "Missing whitespace at index 3, before `<=` operator.");
|
||||
AssertParseFailure("t<= 1", "Missing whitespace at index 3, before `<=` operator.");
|
||||
AssertParseFailure("6 <=1", "Missing whitespace at index 4, after `<=` operator.");
|
||||
AssertParseFailure("t <=1", "Missing whitespace at index 4, after `<=` operator.");
|
||||
AssertParseFailure("6<=1", "Missing whitespace at index 3, before `<=` operator.");
|
||||
AssertParseFailure("t<=1", "Missing whitespace at index 3, before `<=` operator.");
|
||||
|
||||
AssertParseFailure("6>= 1", "Missing whitespace at index 3, before `>=` operator.");
|
||||
AssertParseFailure("t>= 1", "Missing whitespace at index 3, before `>=` operator.");
|
||||
AssertParseFailure("6 >=1", "Missing whitespace at index 4, after `>=` operator.");
|
||||
AssertParseFailure("t >=1", "Missing whitespace at index 4, after `>=` operator.");
|
||||
AssertParseFailure("6>=1", "Missing whitespace at index 3, before `>=` operator.");
|
||||
AssertParseFailure("t>=1", "Missing whitespace at index 3, before `>=` operator.");
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Undefined symbols are treated as `false` (0) values")]
|
||||
public void TestUndefinedSymbols()
|
||||
{
|
||||
AssertFalse("undef1 || undef2");
|
||||
AssertValue("undef1", 0);
|
||||
AssertValue("undef1 + undef2", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user