mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Split up test project
Robust.UnitTesting was both ALL tests for RT, and also API surface for content tests. Tests are now split into separate projects as appropriate, and the API side has also been split off.
This commit is contained in:
43
Robust.Shared.Tests/Audio/AudioGainVolume_Test.cs
Normal file
43
Robust.Shared.Tests/Audio/AudioGainVolume_Test.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Shared.Tests.Audio;
|
||||
|
||||
[TestFixture]
|
||||
public sealed class AudioGainVolume_Test
|
||||
{
|
||||
private static float[] _gainValues = new[]
|
||||
{
|
||||
1f,
|
||||
0.5f,
|
||||
0f,
|
||||
};
|
||||
|
||||
private static float[] _volumeValues = new[]
|
||||
{
|
||||
-100f,
|
||||
-3f,
|
||||
0f,
|
||||
1f,
|
||||
100f,
|
||||
};
|
||||
|
||||
[Test, TestCaseSource(nameof(_gainValues))]
|
||||
public void GainCalculationTest(float value)
|
||||
{
|
||||
var volume = SharedAudioSystem.GainToVolume(value);
|
||||
var gain = SharedAudioSystem.VolumeToGain(volume);
|
||||
|
||||
Assert.That(MathHelper.CloseTo(value, gain, 0.01f), $"Expected {value} and found {volume}");
|
||||
}
|
||||
|
||||
[Test, TestCaseSource(nameof(_volumeValues))]
|
||||
public void VolumeCalculationTest(float value)
|
||||
{
|
||||
var gain = SharedAudioSystem.VolumeToGain(value);
|
||||
var volume = SharedAudioSystem.GainToVolume(gain);
|
||||
|
||||
Assert.That(MathHelper.CloseTo(value, volume, 0.01f), $"Expected {value} and found {volume}");
|
||||
}
|
||||
}
|
||||
75
Robust.Shared.Tests/Collections/OverflowDictionary_Test.cs
Normal file
75
Robust.Shared.Tests/Collections/OverflowDictionary_Test.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Collections;
|
||||
|
||||
namespace Robust.Shared.Tests.Collections;
|
||||
|
||||
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
|
||||
[TestFixture, TestOf(typeof(OverflowQueue<>))]
|
||||
internal sealed class OverflowDictionary_Test
|
||||
{
|
||||
private static IEnumerable<(int size, int iterations)> TestParams => new[]
|
||||
{
|
||||
(10, 17),
|
||||
(10, 4)
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void ValueDisposerTest()
|
||||
{
|
||||
var disposedCalled = 0;
|
||||
var dict = new OverflowDictionary<int, int>(1, (_) => disposedCalled++);
|
||||
dict.Add(0,0);
|
||||
dict.Add(1,0);
|
||||
Assert.That(dict.ContainsKey(0), Is.False);
|
||||
Assert.That(dict.ContainsKey(1));
|
||||
Assert.That(disposedCalled, Is.EqualTo(1));
|
||||
Assert.That(dict.Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestQueue([ValueSource(nameof(TestParams))] (int size, int iterations) test)
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
var _ = new OverflowDictionary<int, int>(0);
|
||||
});
|
||||
|
||||
var dict = new OverflowDictionary<int, int>(test.size);
|
||||
|
||||
for (int i = 0; i < test.iterations; i++)
|
||||
{
|
||||
dict.Add(i, i+1);
|
||||
}
|
||||
|
||||
Assert.That(dict.ContainsKey(test.iterations-1));
|
||||
Assert.Throws<InvalidOperationException>(() => dict.Add(test.iterations - 1, 0));
|
||||
|
||||
var overlap = Math.Max(test.iterations - test.size, 0);
|
||||
for (int i = overlap; i < test.iterations; i++)
|
||||
{
|
||||
Assert.That(dict.TryGetValue(i, out var val));
|
||||
Assert.That(val, Is.EqualTo(i+1));
|
||||
}
|
||||
|
||||
if(overlap > 0)
|
||||
{
|
||||
Assert.That(dict.ContainsKey(0), Is.False);
|
||||
Assert.That(dict.Count, Is.EqualTo(test.size));
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(dict.Count, Is.EqualTo(test.iterations));
|
||||
}
|
||||
|
||||
dict.Clear();
|
||||
Assert.That(dict.Count, Is.EqualTo(0));
|
||||
|
||||
//assert that the clear didnt mess up our internal ordering & array. just to make sure we didnt forget to reset something
|
||||
dict.Add(0, 1);
|
||||
Assert.That(dict.TryGetValue(0, out var value));
|
||||
Assert.That(value, Is.EqualTo(1));
|
||||
|
||||
Assert.Throws<NotImplementedException>(() => dict.Remove(0));
|
||||
}
|
||||
|
||||
}
|
||||
54
Robust.Shared.Tests/Collections/OverflowQueue_Test.cs
Normal file
54
Robust.Shared.Tests/Collections/OverflowQueue_Test.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Collections;
|
||||
|
||||
namespace Robust.Shared.Tests.Collections;
|
||||
|
||||
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
|
||||
[TestFixture, TestOf(typeof(OverflowQueue<>))]
|
||||
internal sealed class OverflowQueue_Test
|
||||
{
|
||||
private static IEnumerable<(int size, int iterations)> TestParams => new[]
|
||||
{
|
||||
(10, 17),
|
||||
(10, 4)
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestQueue([ValueSource(nameof(TestParams))] (int size, int iterations) test)
|
||||
{
|
||||
var queue = new OverflowQueue<int>(test.size);
|
||||
|
||||
Assert.That(queue.Contains(0), Is.False);
|
||||
|
||||
for (int i = 0; i < test.iterations; i++)
|
||||
{
|
||||
queue.Enqueue(i);
|
||||
}
|
||||
|
||||
var overlap = Math.Max(test.iterations - test.size, 0);
|
||||
for (int i = overlap; i < test.iterations; i++)
|
||||
{
|
||||
Assert.That(queue.Contains(i));
|
||||
}
|
||||
|
||||
Assert.That(queue.Contains(test.iterations-1));
|
||||
Assert.That(queue.Contains(-1), Is.False);
|
||||
|
||||
Assert.That(queue.Peek(), Is.EqualTo(overlap));
|
||||
var array = queue.ToArray();
|
||||
Assert.That(array.Length, Is.EqualTo(Math.Min(test.size, test.iterations)));
|
||||
for (var i = 0; i < array.Length; i++)
|
||||
{
|
||||
Assert.That(array[i], Is.EqualTo(i + overlap));
|
||||
}
|
||||
|
||||
for (int i = overlap; i < test.iterations; i++)
|
||||
{
|
||||
Assert.That(queue.TryDequeue(out var item));
|
||||
Assert.That(item, Is.EqualTo(i));
|
||||
}
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => queue.Dequeue());
|
||||
Assert.That(queue.TryDequeue(out _), Is.False);
|
||||
}
|
||||
}
|
||||
95
Robust.Shared.Tests/Collections/RingBufferListTest.cs
Normal file
95
Robust.Shared.Tests/Collections/RingBufferListTest.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Collections;
|
||||
|
||||
namespace Robust.Shared.Tests.Collections;
|
||||
|
||||
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
|
||||
[TestFixture, TestOf(typeof(RingBufferList<>))]
|
||||
internal sealed class RingBufferListTest
|
||||
{
|
||||
[Test]
|
||||
public void TestBasicAdd()
|
||||
{
|
||||
var list = new RingBufferList<int>();
|
||||
list.Add(1);
|
||||
list.Add(2);
|
||||
list.Add(3);
|
||||
|
||||
Assert.That(list, Is.EquivalentTo(new[] {1, 2, 3}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBasicAddAfterWrap()
|
||||
{
|
||||
var list = new RingBufferList<int>(6);
|
||||
list.Add(1);
|
||||
list.Add(2);
|
||||
list.Add(3);
|
||||
list.RemoveAt(0);
|
||||
list.Add(4);
|
||||
list.Add(5);
|
||||
list.Add(6);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Ensure wrapping properly happened and we didn't expand.
|
||||
// (one slot is wasted by nature of implementation)
|
||||
Assert.That(list.Capacity, Is.EqualTo(6));
|
||||
Assert.That(list, Is.EquivalentTo(new[] { 2, 3, 4, 5, 6 }));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMiddleRemoveAtScenario1()
|
||||
{
|
||||
var list = new RingBufferList<int>(6);
|
||||
list.Add(-1);
|
||||
list.Add(-1);
|
||||
list.Add(-1);
|
||||
list.Add(-1);
|
||||
list.Add(1);
|
||||
list.RemoveAt(0);
|
||||
list.RemoveAt(0);
|
||||
list.RemoveAt(0);
|
||||
list.RemoveAt(0);
|
||||
list.Add(2);
|
||||
list.Add(3);
|
||||
list.Add(4);
|
||||
list.Add(5);
|
||||
list.Remove(4);
|
||||
|
||||
Assert.That(list, Is.EquivalentTo(new[] {1, 2, 3, 5}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMiddleRemoveAtScenario2()
|
||||
{
|
||||
var list = new RingBufferList<int>(6);
|
||||
list.Add(-1);
|
||||
list.Add(-1);
|
||||
list.Add(1);
|
||||
list.RemoveAt(0);
|
||||
list.RemoveAt(0);
|
||||
list.Add(2);
|
||||
list.Add(3);
|
||||
list.Add(4);
|
||||
list.Add(5);
|
||||
list.Remove(3);
|
||||
|
||||
Assert.That(list, Is.EquivalentTo(new[] {1, 2, 4, 5}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMiddleRemoveAtScenario3()
|
||||
{
|
||||
var list = new RingBufferList<int>(6);
|
||||
list.Add(1);
|
||||
list.Add(2);
|
||||
list.Add(3);
|
||||
list.Add(4);
|
||||
list.Add(5);
|
||||
list.Remove(4);
|
||||
|
||||
Assert.That(list, Is.EquivalentTo(new[] {1, 2, 3, 5}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Reflection.Metadata;
|
||||
using NUnit.Framework;
|
||||
using Pidgin;
|
||||
using static Robust.Shared.ContentPack.AssemblyTypeChecker;
|
||||
|
||||
namespace Robust.Shared.Tests.ContentPack
|
||||
{
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
[TestFixture]
|
||||
internal sealed class AssemblyTypeCheckerParsingTest
|
||||
{
|
||||
[Test]
|
||||
public void TestMethod()
|
||||
{
|
||||
var res = MethodParser.ParseOrThrow(" void foo ( int , string )");
|
||||
|
||||
Assert.That(res.Name, Is.EqualTo("foo"));
|
||||
Assert.That(res.ReturnType, Is.EqualTo(new MTypePrimitive(PrimitiveTypeCode.Void)));
|
||||
Assert.That(res.ParameterTypes,
|
||||
Is.EquivalentTo(new[]
|
||||
{
|
||||
new MTypePrimitive(PrimitiveTypeCode.Int32),
|
||||
new MTypePrimitive(PrimitiveTypeCode.String)
|
||||
}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestParseConstructor()
|
||||
{
|
||||
var res = MethodParser.ParseOrThrow(" void .ctor ( int , string )");
|
||||
|
||||
Assert.That(res.Name, Is.EqualTo(".ctor"));
|
||||
Assert.That(res.ReturnType, Is.EqualTo(new MTypePrimitive(PrimitiveTypeCode.Void)));
|
||||
Assert.That(res.ParameterTypes,
|
||||
Is.EquivalentTo(new[]
|
||||
{
|
||||
new MTypePrimitive(PrimitiveTypeCode.Int32),
|
||||
new MTypePrimitive(PrimitiveTypeCode.String)
|
||||
}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMethodInvalid()
|
||||
{
|
||||
Assert.That(() => MethodParser.ParseOrThrow("foo ( int , string)"), Throws.InstanceOf<ParseException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestField()
|
||||
{
|
||||
var res = FieldParser.ParseOrThrow("string bar");
|
||||
|
||||
Assert.That(res.Name, Is.EqualTo("bar"));
|
||||
Assert.That(res.FieldType, Is.EqualTo(new MTypePrimitive(PrimitiveTypeCode.String)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGenericMethod()
|
||||
{
|
||||
var res = MethodParser.ParseOrThrow("string Concat(System.Collections.Generic.IEnumerable`1<!!0>)");
|
||||
|
||||
Assert.That(res.Name, Is.EqualTo("Concat"));
|
||||
Assert.That(res.ReturnType, Is.EqualTo(new MTypePrimitive(PrimitiveTypeCode.String)));
|
||||
Assert.That(res.ParameterTypes,
|
||||
Is.EquivalentTo(new MType[]
|
||||
{
|
||||
new MTypeGeneric(
|
||||
new MTypeParsed("System.Collections.Generic.IEnumerable`1"),
|
||||
new MType[] {new MTypeGenericMethodPlaceHolder(0)}.ToImmutableArray())
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
111
Robust.Shared.Tests/ContentPack/ResourceManagerTest2.cs
Normal file
111
Robust.Shared.Tests/ContentPack/ResourceManagerTest2.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Tests.ContentPack;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(ResourceManager))]
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
internal sealed class ResourceManagerTest2
|
||||
{
|
||||
[Test]
|
||||
public void TestMemoryRootReadFiles()
|
||||
{
|
||||
var (_, res) = CreateRes();
|
||||
|
||||
var testRoot = new MemoryContentRoot();
|
||||
testRoot.AddOrUpdateFile(new ResPath("/a.txt"), "a"u8.ToArray());
|
||||
testRoot.AddOrUpdateFile(new ResPath("/b.txt"), "b"u8.ToArray());
|
||||
testRoot.AddOrUpdateFile(new ResPath("/c.txt"), "c"u8.ToArray());
|
||||
testRoot.AddOrUpdateFile(new ResPath("/d/foo.txt"), "foo"u8.ToArray());
|
||||
|
||||
res.AddRoot(new ResPath("/"), testRoot);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(res.ContentFileReadAllText("/a.txt"), Is.EqualTo("a"));
|
||||
Assert.That(res.ContentFileReadAllText("/b.txt"), Is.EqualTo("b"));
|
||||
Assert.That(res.ContentFileReadAllText("/c.txt"), Is.EqualTo("c"));
|
||||
Assert.That(res.ContentFileReadAllText("/d/foo.txt"), Is.EqualTo("foo"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMemoryRootGetDirectoryEntries()
|
||||
{
|
||||
var (_, res) = CreateRes();
|
||||
|
||||
var testRoot = new MemoryContentRoot();
|
||||
testRoot.AddOrUpdateFile(new ResPath("/a.txt"), "a"u8.ToArray());
|
||||
testRoot.AddOrUpdateFile(new ResPath("/b.txt"), "b"u8.ToArray());
|
||||
testRoot.AddOrUpdateFile(new ResPath("/c.txt"), "c"u8.ToArray());
|
||||
testRoot.AddOrUpdateFile(new ResPath("/d/foo.txt"), "foo"u8.ToArray());
|
||||
|
||||
res.AddRoot(new ResPath("/"), testRoot);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(res.ContentGetDirectoryEntries(new ResPath("/")), Is.EquivalentTo(new[]
|
||||
{
|
||||
"a.txt",
|
||||
"b.txt",
|
||||
"c.txt",
|
||||
"d/"
|
||||
}));
|
||||
|
||||
// Listing should work both with and without a trailing /
|
||||
Assert.That(res.ContentGetDirectoryEntries(new ResPath("/d")), Is.EquivalentTo(new[]
|
||||
{
|
||||
"foo.txt"
|
||||
}));
|
||||
|
||||
Assert.That(res.ContentGetDirectoryEntries(new ResPath("/d/")), Is.EquivalentTo(new[]
|
||||
{
|
||||
"foo.txt"
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that a mount path is properly shown as a directory entry.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGetDirectoryEntriesTwoMounts()
|
||||
{
|
||||
var (_, res) = CreateRes();
|
||||
|
||||
var testRoot = new MemoryContentRoot();
|
||||
testRoot.AddOrUpdateFile(new ResPath("foo.txt"), Array.Empty<byte>());
|
||||
testRoot.AddOrUpdateFile(new ResPath("bar/foo.txt"), Array.Empty<byte>());
|
||||
|
||||
res.AddRoot(new ResPath("/"), testRoot);
|
||||
res.AddRoot(new ResPath("/second"), testRoot);
|
||||
res.AddRoot(new ResPath("/third/fourth"), testRoot);
|
||||
|
||||
Assert.That(res.ContentGetDirectoryEntries(new ResPath("/")), Is.EquivalentTo(new []
|
||||
{
|
||||
"foo.txt",
|
||||
"bar/",
|
||||
"second/",
|
||||
"third/"
|
||||
}));
|
||||
}
|
||||
|
||||
private static (IDependencyCollection, IResourceManagerInternal) CreateRes()
|
||||
{
|
||||
var deps = new DependencyCollection();
|
||||
deps.Register<IResourceManager, ResourceManager>();
|
||||
deps.Register<IResourceManagerInternal, ResourceManager>();
|
||||
deps.Register<IConfigurationManager, ConfigurationManager>();
|
||||
deps.Register<ILogManager, LogManager>();
|
||||
deps.Register<IGameTiming, GameTiming>();
|
||||
|
||||
deps.BuildGraph();
|
||||
return (deps, deps.Resolve<IResourceManagerInternal>());
|
||||
}
|
||||
}
|
||||
43
Robust.Shared.Tests/IoC/DependencyCollectionTest.cs
Normal file
43
Robust.Shared.Tests/IoC/DependencyCollectionTest.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Robust.Shared.Tests.IoC;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(DependencyCollection))]
|
||||
[Parallelizable]
|
||||
internal sealed class DependencyCollectionTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests that registering two interfaces with the same implementation results in a single instance being shared.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestRegisterSameImplementation()
|
||||
{
|
||||
var deps = new DependencyCollection();
|
||||
deps.Register<IA, C>();
|
||||
deps.Register<IB, C>();
|
||||
|
||||
deps.BuildGraph();
|
||||
|
||||
var a = deps.Resolve<IA>();
|
||||
var b = deps.Resolve<IB>();
|
||||
|
||||
Assert.That(a, Is.EqualTo(b), () => "A & B instances must be reference equal");
|
||||
}
|
||||
|
||||
private interface IA
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private interface IB
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private sealed class C : IA, IB
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
314
Robust.Shared.Tests/IoC/IoCManager_Test.cs
Normal file
314
Robust.Shared.Tests/IoC/IoCManager_Test.cs
Normal file
@@ -0,0 +1,314 @@
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.IoC.Exceptions;
|
||||
|
||||
namespace Robust.Shared.Tests.IoC
|
||||
{
|
||||
/// <remarks>
|
||||
/// This fixture CAN NOT be parallelized, because <see cref="IoCManager"/> is a static singleton.
|
||||
/// </remarks>
|
||||
[TestFixture, TestOf(typeof(IoCManager))]
|
||||
internal sealed class IoCManager_Test
|
||||
{
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
IoCManager.InitThread();
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void TestSetup()
|
||||
{
|
||||
// Because IoCManager is a singleton, it must be cleared every
|
||||
// test so that each test is isolated.
|
||||
IoCManager.Clear();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCTestFieldInjection()
|
||||
{
|
||||
IoCManager.Register<TestFieldInjection, TestFieldInjection>();
|
||||
IoCManager.BuildGraph();
|
||||
var tester = IoCManager.Resolve<TestFieldInjection>();
|
||||
|
||||
tester.Test();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCTestConstructorInjection()
|
||||
{
|
||||
IoCManager.Register<TestFieldInjection, TestFieldInjection>();
|
||||
IoCManager.Register<TestConstructorInjection, TestConstructorInjection>();
|
||||
IoCManager.BuildGraph();
|
||||
|
||||
var tester = IoCManager.Resolve<TestConstructorInjection>();
|
||||
|
||||
Assert.That(tester.FieldInjection, Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCTestBasic()
|
||||
{
|
||||
IoCManager.Register<TestFieldInjection, TestFieldInjection>();
|
||||
IoCManager.BuildGraph();
|
||||
|
||||
Assert.That(IoCManager.Resolve<TestFieldInjection>(), Is.Not.Null);
|
||||
|
||||
Assert.That(IoCManager.ResolveType(typeof(TestFieldInjection)), Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCRegisterFactory()
|
||||
{
|
||||
var newInstance = new TestFieldInjection();
|
||||
IoCManager.Register<TestFieldInjection, TestFieldInjection>(() => newInstance);
|
||||
|
||||
IoCManager.BuildGraph(); // Actually calls the factory
|
||||
|
||||
var result = IoCManager.Resolve<TestFieldInjection>();
|
||||
Assert.That(result, Is.EqualTo(newInstance));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCTestOverwrite()
|
||||
{
|
||||
IoCManager.Register<IIoCTestPriorities, IoCTestPriorities2>();
|
||||
IoCManager.Register<IIoCTestPriorities, IoCTestPriorities1>(true);
|
||||
IoCManager.BuildGraph();
|
||||
|
||||
Assert.That(IoCManager.Resolve<IIoCTestPriorities>(), Is.TypeOf<IoCTestPriorities1>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCTestConstructorException()
|
||||
{
|
||||
IoCManager.Register<IConstructorException, ConstructorException>();
|
||||
Assert.That(() => IoCManager.BuildGraph(), Throws.InstanceOf<ImplementationConstructorException>().And.InnerException.InstanceOf<TestConstructorExceptionException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCTestUnregisteredDirectInject()
|
||||
{
|
||||
Assert.That(()=>IoCManager.InjectDependencies(new TestUnregisteredInjection()), Throws.TypeOf<UnregisteredDependencyException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCTestResolveTypeThrowsWhenGraphUnbuilt()
|
||||
{
|
||||
IoCManager.Register<IIoCFailInterface, TestFailImplementation>();
|
||||
// we *forgot* to call BuildGraph
|
||||
Assert.That(()=>IoCManager.Resolve<IIoCFailInterface>(), Throws.TypeOf<InvalidOperationException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCTestResolveThrowsUnregisteredType()
|
||||
{
|
||||
Assert.That(()=>IoCManager.Resolve<IIoCFailInterface>(), Throws.TypeOf<UnregisteredTypeException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCTestDuplicateResgisterWithoutBuildingGraph()
|
||||
{
|
||||
IoCManager.Register<IIoCFailInterface, TestFailImplementation>();
|
||||
IoCManager.BuildGraph();
|
||||
|
||||
// cannot overwrite an already built implementation.
|
||||
Assert.That(()=> IoCManager.Register<IIoCFailInterface, TestFailImplementation>(true), Throws.TypeOf<InvalidOperationException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCTestDumplicateRegisterThrows()
|
||||
{
|
||||
IoCManager.Register<IIoCFailInterface, TestFailImplementation>();
|
||||
|
||||
// duplicate registerations will throw an exception.
|
||||
Assert.That(() => IoCManager.Register<IIoCFailInterface, TestFailImplementation>(), Throws.TypeOf<InvalidOperationException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCBasicRegisterInstance()
|
||||
{
|
||||
var obj = new Mock<IIoCTestPriorities>().Object;
|
||||
|
||||
IoCManager.RegisterInstance<IIoCTestPriorities>(obj);
|
||||
|
||||
IoCManager.BuildGraph();
|
||||
|
||||
Assert.That(IoCManager.Resolve<IIoCTestPriorities>(), Is.EqualTo(obj));
|
||||
}
|
||||
|
||||
private sealed class DependencyA
|
||||
{
|
||||
[Dependency] public readonly DependencyB _depB = default!;
|
||||
}
|
||||
private sealed class DependencyB
|
||||
{
|
||||
[Dependency] public readonly DependencyA _depA = default!;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCRegInstancesBeforeBuildGraph()
|
||||
{
|
||||
var instanceA = new DependencyA();
|
||||
IoCManager.RegisterInstance<DependencyA>(instanceA);
|
||||
|
||||
var instanceB = new DependencyB();
|
||||
IoCManager.RegisterInstance<DependencyB>(instanceB);
|
||||
|
||||
IoCManager.BuildGraph();
|
||||
|
||||
var resolveA = IoCManager.Resolve<DependencyA>();
|
||||
var resolveB = IoCManager.Resolve<DependencyB>();
|
||||
|
||||
Assert.That(instanceA, Is.EqualTo(resolveA));
|
||||
Assert.That(instanceB, Is.EqualTo(resolveB));
|
||||
Assert.That(resolveA._depB, Is.EqualTo(resolveB));
|
||||
Assert.That(resolveB._depA, Is.EqualTo(resolveA));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCRegInstanceBeforeBuildGraph()
|
||||
{
|
||||
IoCManager.Register<DependencyA, DependencyA>();
|
||||
|
||||
var instanceB = new DependencyB();
|
||||
IoCManager.RegisterInstance<DependencyB>(instanceB);
|
||||
|
||||
IoCManager.BuildGraph();
|
||||
|
||||
var resolveA = IoCManager.Resolve<DependencyA>();
|
||||
var resolveB = IoCManager.Resolve<DependencyB>();
|
||||
|
||||
Assert.That(instanceB, Is.EqualTo(resolveB));
|
||||
Assert.That(resolveA._depB, Is.EqualTo(resolveB));
|
||||
Assert.That(resolveB._depA, Is.EqualTo(resolveA));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IoCRegInstanceDepBeforeBuildGraph()
|
||||
{
|
||||
var instanceB = new DependencyB();
|
||||
IoCManager.RegisterInstance<DependencyB>(instanceB);
|
||||
|
||||
IoCManager.Register<DependencyA, DependencyA>();
|
||||
|
||||
IoCManager.BuildGraph();
|
||||
|
||||
var resolveA = IoCManager.Resolve<DependencyA>();
|
||||
var resolveB = IoCManager.Resolve<DependencyB>();
|
||||
|
||||
Assert.That(instanceB, Is.EqualTo(resolveB));
|
||||
Assert.That(resolveA._depB, Is.EqualTo(resolveB));
|
||||
Assert.That(resolveB._depA, Is.EqualTo(resolveA));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExplicitInjection()
|
||||
{
|
||||
// This will explicitly cause the DynamicMethod code path to be taken.
|
||||
// To ensure that works.
|
||||
var test = new ExplicitInjectionTest();
|
||||
IoCManager.InjectDependencies(test);
|
||||
Assert.That(test.DependencyCollection, Is.Not.Null);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IIoCFailInterface { }
|
||||
|
||||
public interface IIoCTestPriorities { }
|
||||
|
||||
public sealed class IoCTestPriorities1 : IIoCTestPriorities { }
|
||||
public sealed class IoCTestPriorities2 : IIoCTestPriorities { }
|
||||
|
||||
public interface IConstructorException { }
|
||||
|
||||
public sealed class ConstructorException : IConstructorException
|
||||
{
|
||||
public ConstructorException()
|
||||
{
|
||||
throw new TestConstructorExceptionException();
|
||||
}
|
||||
}
|
||||
|
||||
[Virtual]
|
||||
public class TestConstructorExceptionException : Exception
|
||||
{
|
||||
}
|
||||
|
||||
[Virtual]
|
||||
public class TestFieldInjectionParent
|
||||
{
|
||||
[Dependency]
|
||||
#pragma warning disable 649
|
||||
#pragma warning disable RA0032
|
||||
private readonly TestFieldInjection myself = default!;
|
||||
|
||||
[Dependency]
|
||||
public TestFieldInjection myotherself = default!;
|
||||
#pragma warning restore RA0032
|
||||
#pragma warning restore 649
|
||||
|
||||
public virtual void Test()
|
||||
{
|
||||
Assert.That(myself, Is.EqualTo(this));
|
||||
Assert.That(myotherself, Is.EqualTo(this));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TestFieldInjection : TestFieldInjectionParent
|
||||
{
|
||||
#pragma warning disable RA0032 // Duplicate [Dependency] field. I wrote this test 7 years idk if this makes sense.
|
||||
[Dependency]
|
||||
#pragma warning disable 649
|
||||
private readonly TestFieldInjection myuniqueself = default!;
|
||||
|
||||
[Dependency]
|
||||
public TestFieldInjection mydifferentself = default!;
|
||||
#pragma warning restore 649
|
||||
#pragma warning restore RA0032
|
||||
|
||||
public override void Test()
|
||||
{
|
||||
base.Test();
|
||||
Assert.That(myuniqueself, Is.EqualTo(this));
|
||||
Assert.That(mydifferentself, Is.EqualTo(this));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TestConstructorInjection
|
||||
{
|
||||
public TestFieldInjection FieldInjection { get; }
|
||||
|
||||
public TestConstructorInjection(TestFieldInjection fieldInjection)
|
||||
{
|
||||
FieldInjection = fieldInjection;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TestUnregisteredInjection
|
||||
{
|
||||
[Dependency]
|
||||
#pragma warning disable 414
|
||||
private readonly IIoCFailInterface FailInterface = default!;
|
||||
#pragma warning restore 414
|
||||
}
|
||||
|
||||
public sealed class TestFailImplementation : IIoCFailInterface { }
|
||||
|
||||
public interface ITestDisposeExceptionCaught { }
|
||||
|
||||
public sealed class TestDisposeExceptionCaught : ITestDisposeExceptionCaught, IDisposable
|
||||
{
|
||||
public void Dispose()
|
||||
{
|
||||
throw new Exception("UNIT TEST EXCEPTION");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ExplicitInjectionTest
|
||||
{
|
||||
[Dependency] public readonly IDependencyCollection DependencyCollection = default!;
|
||||
}
|
||||
}
|
||||
76
Robust.Shared.Tests/Localization/FormatErrorTest.cs
Normal file
76
Robust.Shared.Tests/Localization/FormatErrorTest.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using Linguini.Syntax.Parser.Error;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Robust.Shared.Tests.Localization;
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable]
|
||||
internal sealed class TestFormatErrors
|
||||
{
|
||||
// Error spans a single line
|
||||
private const string ResSingle = "err1 = $user)";
|
||||
|
||||
private const string ExpectSingle1Wide1 = """
|
||||
1 |err1 = $user)
|
||||
^ Unbalanced closing brace
|
||||
""";
|
||||
|
||||
private const string Expect2Wide1 = """
|
||||
1 |err1 = $user)
|
||||
^ Unbalanced closing brace
|
||||
""";
|
||||
|
||||
private const string Expect1Wide4 = """
|
||||
1 |err1 = $user)
|
||||
^^^^ Expected a message field for "x"
|
||||
""";
|
||||
|
||||
private const string Expect2Wide4 = """
|
||||
1 |err1 = $user)
|
||||
^^^^ Expected a message field for "x"
|
||||
""";
|
||||
|
||||
// Error spans multiple lines
|
||||
private const string ResMulti = """
|
||||
a = b {{
|
||||
err = x
|
||||
""";
|
||||
|
||||
private const string ExpectMulti1Wide1 = """
|
||||
1 |a = b {{
|
||||
2 | err = x
|
||||
^ Unbalanced closing brace
|
||||
""";
|
||||
|
||||
private const string ExpectMulti1Wide3 = """
|
||||
1 |a = b {{
|
||||
2 | err = x
|
||||
^^^ Expected a message field for "x"
|
||||
""";
|
||||
|
||||
[Test]
|
||||
[TestCase(ExpectSingle1Wide1, ResSingle, 7)]
|
||||
[TestCase(Expect2Wide1, ResSingle, 0)]
|
||||
[TestCase(Expect1Wide4, ResSingle, 8, 12)]
|
||||
[TestCase(Expect2Wide4, ResSingle, 0, 4)]
|
||||
[TestCase(ExpectMulti1Wide1, ResMulti, 11)]
|
||||
[TestCase(ExpectMulti1Wide3, ResMulti, 11, 14)]
|
||||
[TestCase(ExpectMulti1Wide1, ResMulti, 11)]
|
||||
[TestCase(ExpectMulti1Wide3, ResMulti, 11, 14)]
|
||||
public void TestSingleLineTestLf(string expected, string resource, int start, int? end = null)
|
||||
{
|
||||
expected = expected.ReplaceLineEndings("\n");
|
||||
resource = resource.ReplaceLineEndings("\n");
|
||||
|
||||
var err = ParseError.UnbalancedClosingBrace(start, 99);
|
||||
if (end != null)
|
||||
{
|
||||
err = ParseError.ExpectedMessageField("x".AsMemory(), start, end.Value, 99);
|
||||
}
|
||||
|
||||
err.Slice = new Range(0, resource.Length);
|
||||
var actual = err.FormatCompileErrors(resource.AsMemory(), "\n");
|
||||
Assert.That(actual, Is.EqualTo(expected));
|
||||
}
|
||||
}
|
||||
24
Robust.Shared.Tests/Map/MapBitmask_Tests.cs
Normal file
24
Robust.Shared.Tests/Map/MapBitmask_Tests.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Shared.Tests.Map;
|
||||
|
||||
[TestFixture]
|
||||
internal sealed class MapBitmask_Tests
|
||||
{
|
||||
private static readonly TestCaseData[] Cases = new[]
|
||||
{
|
||||
new TestCaseData(Vector2i.Zero, SharedMapSystem.ToBitmask(Vector2i.Zero), true),
|
||||
|
||||
new TestCaseData(Vector2i.One * 7, SharedMapSystem.ToBitmask(Vector2i.One * 7), true),
|
||||
|
||||
new TestCaseData(Vector2i.One * 7, SharedMapSystem.ToBitmask(Vector2i.Zero), false),
|
||||
};
|
||||
|
||||
[Test, TestCaseSource(nameof(Cases))]
|
||||
public void TestBitmask(Vector2i index, ulong bitmask, bool result)
|
||||
{
|
||||
Assert.That(SharedMapSystem.FromBitmask(index, bitmask), Is.EqualTo(result));
|
||||
}
|
||||
}
|
||||
113
Robust.Shared.Tests/Networking/NetDisconnectMessageTest.cs
Normal file
113
Robust.Shared.Tests/Networking/NetDisconnectMessageTest.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Robust.Shared.Tests.Networking;
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
[TestOf(typeof(NetDisconnectMessage))]
|
||||
internal sealed class NetDisconnectMessageTest
|
||||
{
|
||||
[Test]
|
||||
[TestCase("Disconnected: bye", "Disconnected: bye", NetDisconnectMessage.DefaultRedialFlag)]
|
||||
[TestCase("Disconnected: {\"reason\": \"bye\"}", "bye", NetDisconnectMessage.DefaultRedialFlag)]
|
||||
[TestCase("Disconnected: {}", NetDisconnectMessage.DefaultReason, NetDisconnectMessage.DefaultRedialFlag)]
|
||||
[TestCase("Disconnected: {\"redial\": true}", NetDisconnectMessage.DefaultReason, true)]
|
||||
[TestCase("Disconnected: {\"redial\": true, \"foobar\": 5}", NetDisconnectMessage.DefaultReason, true)]
|
||||
[TestCase("Disconnected: {\"redial\": true, \"foobar\": 5, \"reason\": \"asdf\"}", "asdf", true)]
|
||||
[TestCase("Disconnected: {", "Disconnected: {", NetDisconnectMessage.DefaultRedialFlag)]
|
||||
[TestCase("Disconnected: {\"a\":[]}", NetDisconnectMessage.DefaultReason, NetDisconnectMessage.DefaultRedialFlag)]
|
||||
[TestCase("{\"redial\": true, \"foobar\": 5, \"reason\": \"asdf\"}", "asdf", true)]
|
||||
public void TestBasicDecode(string encoded, string reasonExpected, bool redialExpected)
|
||||
{
|
||||
var parsed = NetDisconnectMessage.Decode(encoded);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(parsed.Reason, Is.EqualTo(reasonExpected));
|
||||
Assert.That(parsed.RedialFlag, Is.EqualTo(redialExpected));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEncode()
|
||||
{
|
||||
var value = new NetDisconnectMessage("foobar", true)
|
||||
{
|
||||
Values =
|
||||
{
|
||||
["asdf"] = 20.5f
|
||||
}
|
||||
};
|
||||
|
||||
var encoded = value.Encode();
|
||||
TestContext.Out.Write($"Encoded: {encoded}\n");
|
||||
var decodedAgain = NetDisconnectMessage.Decode(encoded);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(decodedAgain.Reason, Is.EqualTo("foobar"));
|
||||
Assert.That(decodedAgain.RedialFlag, Is.EqualTo(true));
|
||||
Assert.That(decodedAgain.SingleOf("asdf"), Is.EqualTo(20.5f));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDefaultConstructor()
|
||||
{
|
||||
var value = new NetDisconnectMessage("foobar");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(value.Reason, Is.EqualTo("foobar"));
|
||||
Assert.That(value.RedialFlag, Is.EqualTo(false));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestValueOfInt()
|
||||
{
|
||||
var parsed = NetDisconnectMessage.Decode("{\"foobar\": 5}");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(parsed.Int32Of("foobar"), Is.EqualTo(5));
|
||||
Assert.That(parsed.Int32Of("asdf"), Is.Null);
|
||||
Assert.That(parsed.Int32Of("asdf", 7), Is.EqualTo(7));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestValueOfFloat()
|
||||
{
|
||||
var parsed = NetDisconnectMessage.Decode("{\"foobar\": 5.5}");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(parsed.SingleOf("foobar"), Is.EqualTo(5.5f));
|
||||
Assert.That(parsed.SingleOf("asdf"), Is.Null);
|
||||
Assert.That(parsed.SingleOf("asdf", 7), Is.EqualTo(7f));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestValueOfFloatInt()
|
||||
{
|
||||
var parsed = NetDisconnectMessage.Decode("{\"foobar\": 5}");
|
||||
|
||||
Assert.That(parsed.SingleOf("foobar"), Is.EqualTo(5f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestValueOfString()
|
||||
{
|
||||
var parsed = NetDisconnectMessage.Decode("{\"foobar\": \"real\"}");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(parsed.StringOf("foobar"), Is.EqualTo("real"));
|
||||
Assert.That(parsed.StringOf("asdf"), Is.Null);
|
||||
Assert.That(parsed.StringOf("asdf", "honk"), Is.EqualTo("honk"));
|
||||
});
|
||||
}
|
||||
}
|
||||
70
Robust.Shared.Tests/Physics/B2DynamicTree_Test.cs
Normal file
70
Robust.Shared.Tests/Physics/B2DynamicTree_Test.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
|
||||
namespace Robust.Shared.Tests.Physics
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(B2DynamicTree<>))]
|
||||
internal sealed class B2DynamicTree_Test
|
||||
{
|
||||
private static Box2[] aabbs1 =
|
||||
{
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
new(-3, 3, -3, 3), // point off to the bottom left
|
||||
new(-3, -3, -3, -3), // point off to the top left
|
||||
new(3, 3, 3, 3), // point off to the bottom right
|
||||
new(3, -3, 3, -3), // point off to the top right
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
((Box2) default).Enlarged(3), //6x6 square
|
||||
new(-3, 3, -3, 3), // point off to the bottom left
|
||||
new(-3, -3, -3, -3), // point off to the top left
|
||||
new(3, 3, 3, 3), // point off to the bottom right
|
||||
new(3, -3, 3, -3), // point off to the top right
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void AddAndQuery()
|
||||
{
|
||||
var dt = new B2DynamicTree<int>();
|
||||
|
||||
for (var i = 0; i < aabbs1.Length; ++i)
|
||||
{
|
||||
dt.CreateProxy(aabbs1[i], uint.MaxValue, i);
|
||||
}
|
||||
|
||||
var point = new Vector2(0, 0);
|
||||
var box2 = Box2.CenteredAround(point, new Vector2(0.1f, 0.1f));
|
||||
|
||||
var results = new HashSet<int>();
|
||||
|
||||
dt.Query(proxy =>
|
||||
{
|
||||
results.Add(dt.GetUserData(proxy));
|
||||
return true;
|
||||
}, box2);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = 0; i < aabbs1.Length; i++)
|
||||
{
|
||||
var aabb = aabbs1[i];
|
||||
|
||||
if (aabb.Intersects(box2))
|
||||
{
|
||||
Assert.That(results, Does.Contain(i));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
232
Robust.Shared.Tests/Physics/DynamicTree_Test.cs
Normal file
232
Robust.Shared.Tests/Physics/DynamicTree_Test.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
|
||||
namespace Robust.Shared.Tests.Physics
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(DynamicTree<>))]
|
||||
internal sealed class DynamicTree_Test
|
||||
{
|
||||
|
||||
private static Box2[] aabbs1 =
|
||||
{
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
new(-3, 3, -3, 3), // point off to the bottom left
|
||||
new(-3, -3, -3, -3), // point off to the top left
|
||||
new(3, 3, 3, 3), // point off to the bottom right
|
||||
new(3, -3, 3, -3), // point off to the top right
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
((Box2) default).Enlarged(3), //6x6 square
|
||||
new(-3, 3, -3, 3), // point off to the bottom left
|
||||
new(-3, -3, -3, -3), // point off to the top left
|
||||
new(3, 3, 3, 3), // point off to the bottom right
|
||||
new(3, -3, 3, -3), // point off to the top right
|
||||
};
|
||||
|
||||
private static Box2[] aabbs2 =
|
||||
{
|
||||
((Box2) default).Enlarged(3), //6x6 square
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
new(-3, 3, -3, 3), // point off to the bottom left
|
||||
new(-3, -3, -3, -3), // point off to the top left
|
||||
new(3, 3, 3, 3), // point off to the bottom right
|
||||
new(3, -3, 3, -3), // point off to the top right
|
||||
new(-3, 3, -3, 3), // point off to the bottom left
|
||||
new(-3, -3, -3, -3), // point off to the top left
|
||||
new(3, 3, 3, 3), // point off to the bottom right
|
||||
new(3, -3, 3, -3), // point off to the top right
|
||||
new(-3, 3, -3, 3), // point off to the bottom left
|
||||
new(-3, -3, -3, -3), // point off to the top left
|
||||
new(3, 3, 3, 3), // point off to the bottom right
|
||||
new(3, -3, 3, -3), // point off to the top right
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
((Box2) default).Enlarged(2), //4x4 square
|
||||
((Box2) default).Enlarged(1), //2x2 square
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void AddAndGrow()
|
||||
{
|
||||
var dt = new DynamicTree<int>((in int x) => aabbs1[x], capacity: 16, growthFunc: x => x += 2);
|
||||
|
||||
var initCap = dt.Capacity;
|
||||
|
||||
Assert.That(initCap, Is.EqualTo(16));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = 0; i < aabbs1.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Add(i), $"Add {i}");
|
||||
}
|
||||
});
|
||||
|
||||
Assert.That(dt.Capacity, Is.AtLeast(initCap));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddDuplicates()
|
||||
{
|
||||
var dt = new DynamicTree<int>((in int x) => aabbs1[x], capacity: 16, growthFunc: x => x += 2);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = 0; i < aabbs1.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Add(i), $"Add {i}");
|
||||
}
|
||||
});
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = 0; i < aabbs1.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Add(i), Is.False, $"Add Dupe {i}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveMissingWhileEmpty()
|
||||
{
|
||||
var dt = new DynamicTree<int>((in int x) => aabbs1[x], capacity: 16, growthFunc: x => x += 2);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = 0; i < aabbs1.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Remove(i), Is.False, $"Remove {i}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateMissingWhileEmpty()
|
||||
{
|
||||
var dt = new DynamicTree<int>((in int x) => aabbs1[x], capacity: 16, growthFunc: x => x += 2);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = 0; i < aabbs1.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Update(i), Is.False, $"Update {i}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveMissingNotEmpty()
|
||||
{
|
||||
var dt = new DynamicTree<int>((in int x) => aabbs1[x], capacity: 16, growthFunc: x => x += 2);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = 0; i < aabbs1.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Add(i), $"Add {i}");
|
||||
}
|
||||
});
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = aabbs1.Length; i < aabbs1.Length + aabbs2.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Remove(i), Is.False, $"Remove {i}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateMissingNotEmpty()
|
||||
{
|
||||
var dt = new DynamicTree<int>((in int x) => aabbs1[x], capacity: 16, growthFunc: x => x += 2);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = 0; i < aabbs1.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Add(i), $"Add {i}");
|
||||
}
|
||||
});
|
||||
|
||||
Assert.Multiple(() => {
|
||||
for (var i = aabbs1.Length; i < aabbs1.Length + aabbs2.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Update(i), Is.False, $"Update {i}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddThenRemove()
|
||||
{
|
||||
var aabbs = aabbs1;
|
||||
var dt = new DynamicTree<int>((in int x) => aabbs[x], capacity: 16, growthFunc: x => x += 2);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = 0; i < aabbs.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Add(i), $"Add {i}");
|
||||
}
|
||||
});
|
||||
aabbs = aabbs2;
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = 0; i < aabbs.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Remove(i), $"Remove {i}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddAndQuery() {
|
||||
var dt = new DynamicTree<int>((in int x) => aabbs1[x], capacity: 16, growthFunc: x => x += 2);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
for (var i = 0; i < aabbs1.Length; ++i)
|
||||
{
|
||||
Assert.That(dt.Add(i), $"Add {i}");
|
||||
}
|
||||
});
|
||||
|
||||
var point = new Vector2(0, 0);
|
||||
|
||||
var containers = Enumerable.Range(0, aabbs1.Length)
|
||||
.Where(x => aabbs1[x].Contains(point))
|
||||
.OrderBy(x => x).ToArray();
|
||||
|
||||
var results = dt.QueryPoint(point)
|
||||
.OrderBy(x => x).ToArray();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(results.Length, Is.EqualTo(containers.Length), "Length");
|
||||
var l = Math.Min(containers.Length, results.Length);
|
||||
for (var i = 0; i < l; ++i)
|
||||
{
|
||||
Assert.That(results[i], Is.EqualTo(containers[i]));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: other Box2, Ray, Point query method tests
|
||||
}
|
||||
|
||||
}
|
||||
124
Robust.Shared.Tests/Physics/Shapes/SlimPolygonTest.cs
Normal file
124
Robust.Shared.Tests/Physics/Shapes/SlimPolygonTest.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Maths.Tests;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Shapes;
|
||||
using Robust.UnitTesting;
|
||||
|
||||
namespace Robust.Shared.Tests.Physics.Shapes;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(SlimPolygon))]
|
||||
public sealed class SlimPolygonTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Check that Slim and normal Polygon are equals
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestSlim()
|
||||
{
|
||||
var slim = new SlimPolygon(Box2.UnitCentered.Translated(Vector2.One));
|
||||
|
||||
var poly = new Polygon(Box2.UnitCentered.Translated(Vector2.One));
|
||||
|
||||
Assert.That(slim.Equals(poly));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAABB()
|
||||
{
|
||||
var shape = new SlimPolygon(Box2.UnitCentered.Translated(Vector2.One));
|
||||
|
||||
Assert.That(shape.ComputeAABB(Transform.Empty, 0), Is.EqualTo(Box2.UnitCentered.Translated(Vector2.One)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBox2()
|
||||
{
|
||||
var shape = new SlimPolygon(Box2.UnitCentered.Translated(Vector2.One));
|
||||
Assert.That(shape._vertices.AsSpan.ToArray(), Is.EqualTo(new Vector2[]
|
||||
{
|
||||
new Vector2(0.5f, 0.5f),
|
||||
new Vector2(1.5f, 0.5f),
|
||||
new Vector2(1.5f, 1.5f),
|
||||
new Vector2(0.5f, 1.5f),
|
||||
}));
|
||||
}
|
||||
|
||||
public static IEnumerable<(Box2 baseBox, Vector2 origin, Angle rotation, Box2 expected)> CalcBoundingBoxData
|
||||
=> Box2Rotated_Test.CalcBoundingBoxData;
|
||||
|
||||
[Test]
|
||||
public void TestBox2Rotated([ValueSource(nameof(CalcBoundingBoxData))] (Box2 baseBox, Vector2 origin, Angle rotation, Box2 expected) dat)
|
||||
{
|
||||
var box = new Box2Rotated(dat.baseBox, dat.rotation, dat.origin);
|
||||
var shape = new SlimPolygon(box);
|
||||
|
||||
Assert.That(shape._vertices._00, Is.Approximately(box.BottomLeft, 0.0001f));
|
||||
Assert.That(shape._vertices._01, Is.Approximately(box.BottomRight, 0.0001f));
|
||||
Assert.That(shape._vertices._02, Is.Approximately(box.TopRight, 0.0001f));
|
||||
Assert.That(shape._vertices._03, Is.Approximately(box.TopLeft, 0.0001f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBox2RotatedBounds([ValueSource(nameof(CalcBoundingBoxData))](Box2 baseBox, Vector2 origin, Angle rotation, Box2 expected) dat)
|
||||
{
|
||||
var box = new Box2Rotated(dat.baseBox, dat.rotation, dat.origin);
|
||||
var shape = new SlimPolygon(box);
|
||||
var aabb = shape.ComputeAABB(Transform.Empty, 0);
|
||||
Assert.That(aabb, Is.Approximately(dat.expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTransformConstructor([ValueSource(nameof(CalcBoundingBoxData))] (Box2 baseBox, Vector2 origin, Angle rotation, Box2 expected) dat)
|
||||
{
|
||||
var box = new Box2Rotated(dat.baseBox, dat.rotation, dat.origin);
|
||||
var shape = new SlimPolygon(box.Box, box.Transform, out var bounds);
|
||||
|
||||
Assert.That(shape._vertices._00, Is.Approximately(box.BottomLeft, 0.0001f));
|
||||
Assert.That(shape._vertices._01, Is.Approximately(box.BottomRight, 0.0001f));
|
||||
Assert.That(shape._vertices._02, Is.Approximately(box.TopRight, 0.0001f));
|
||||
Assert.That(shape._vertices._03, Is.Approximately(box.TopLeft, 0.0001f));
|
||||
Assert.That(box.CalcBoundingBox(), Is.Approximately(bounds, 0.0001f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTransformRotatedConstructor([ValueSource(nameof(CalcBoundingBoxData))](Box2 baseBox, Vector2 origin, Angle rotation, Box2 expected) dat)
|
||||
{
|
||||
var box = new Box2Rotated(dat.baseBox, dat.rotation, dat.origin);
|
||||
Matrix3x2.Invert(box.Transform, out var inverse);
|
||||
var shape = new SlimPolygon(box, inverse, out var bounds);
|
||||
|
||||
Assert.That(shape._vertices._00, Is.Approximately(dat.baseBox.BottomLeft, 0.0001f));
|
||||
Assert.That(shape._vertices._01, Is.Approximately(dat.baseBox.BottomRight, 0.0001f));
|
||||
Assert.That(shape._vertices._02, Is.Approximately(dat.baseBox.TopRight, 0.0001f));
|
||||
Assert.That(shape._vertices._03, Is.Approximately(dat.baseBox.TopLeft, 0.0001f));
|
||||
Assert.That(dat.baseBox, Is.Approximately(bounds, 0.0001f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestComputeAABB()
|
||||
{
|
||||
var box = new Box2Rotated(Box2.UnitCentered, Angle.FromDegrees(45), Vector2.One);
|
||||
var shape = new SlimPolygon(box);
|
||||
Assert.That(shape._vertices._00, Is.Approximately(box.BottomLeft, 0.0001f));
|
||||
Assert.That(shape._vertices._01, Is.Approximately(box.BottomRight, 0.0001f));
|
||||
Assert.That(shape._vertices._02, Is.Approximately(box.TopRight, 0.0001f));
|
||||
Assert.That(shape._vertices._03, Is.Approximately(box.TopLeft, 0.0001f));
|
||||
|
||||
// AABB of a 45 degree rotated unit box will be enlarged by a factor of sqrt(2)
|
||||
var transform = Transform.Empty;
|
||||
var expected = Box2.UnitCentered.Translated(new Vector2(1, 1 - MathF.Sqrt(2))).Scale(Vector2.One * MathF.Sqrt(2));
|
||||
var aabb = shape.ComputeAABB(transform, 0);
|
||||
Assert.That(aabb, Is.Approximately(expected, 0.0001f));
|
||||
Assert.That(aabb.Size, Is.Approximately(Vector2.One * MathF.Sqrt(2), 0.0001f));
|
||||
|
||||
// But if we pass a 45 degree rotation into ComputeAABB, the box will not be enlarged.
|
||||
transform = new Transform(Vector2.Zero, Angle.FromDegrees(45));
|
||||
expected = Box2.UnitCentered.Translated(new Vector2(1, MathF.Sqrt(2) - 1));
|
||||
aabb = shape.ComputeAABB(transform, 0);
|
||||
Assert.That(aabb, Is.Approximately(expected, 0.0001f));
|
||||
Assert.That(aabb.Size, Is.Approximately(Vector2.One, 0.0001f));
|
||||
}
|
||||
}
|
||||
112
Robust.Shared.Tests/Prototypes/MultiRootGraphTest.cs
Normal file
112
Robust.Shared.Tests/Prototypes/MultiRootGraphTest.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Robust.Shared.Tests.Prototypes;
|
||||
|
||||
[TestFixture]
|
||||
internal sealed class MultiRootGraphTest
|
||||
{
|
||||
private const string Id1 = "id1";
|
||||
private const string Id2 = "id2";
|
||||
private const string Id3 = "id3";
|
||||
private const string Id4 = "id4";
|
||||
|
||||
[Test]
|
||||
public void AddAndRemoveRoot()
|
||||
{
|
||||
var graph = new MultiRootInheritanceGraph<string>();
|
||||
graph.Add(Id1);
|
||||
Assert.That(graph.RootNodes.Count, Is.EqualTo(1));
|
||||
Assert.That(graph.RootNodes.Contains(Id1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddAndRemoveRootAndChild()
|
||||
{
|
||||
var graph = new MultiRootInheritanceGraph<string>();
|
||||
graph.Add(Id3, new []{Id1});
|
||||
|
||||
var children = graph.GetChildren(Id1);
|
||||
Assert.That(children, Is.Not.Null);
|
||||
Assert.That(children!.Count, Is.EqualTo(1));
|
||||
Assert.That(children.Contains(Id3));
|
||||
|
||||
var parents = graph.GetParents(Id3);
|
||||
Assert.That(parents, Is.Not.Null);
|
||||
Assert.That(parents!.Count, Is.EqualTo(1));
|
||||
Assert.That(parents.Contains(Id1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddTwoParentsRemoveOne()
|
||||
{
|
||||
var graph = new MultiRootInheritanceGraph<string>();
|
||||
graph.Add(Id3, new []{Id1, Id2});
|
||||
|
||||
var parents = graph.GetParents(Id3);
|
||||
Assert.That(parents, Is.Not.Null);
|
||||
Assert.That(parents!.Count, Is.EqualTo(2));
|
||||
Assert.That(parents.Contains(Id1));
|
||||
Assert.That(parents.Contains(Id2));
|
||||
|
||||
var children = graph.GetChildren(Id1);
|
||||
Assert.That(children, Is.Not.Null);
|
||||
Assert.That(children!.Count, Is.EqualTo(1));
|
||||
Assert.That(children.Contains(Id3));
|
||||
|
||||
children = graph.GetChildren(Id2);
|
||||
Assert.That(children, Is.Not.Null);
|
||||
Assert.That(children!.Count, Is.EqualTo(1));
|
||||
Assert.That(children.Contains(Id3));
|
||||
|
||||
Assert.That(graph.RootNodes.Count, Is.EqualTo(2));
|
||||
Assert.That(graph.RootNodes.Contains(Id1));
|
||||
Assert.That(graph.RootNodes.Contains(Id2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OneParentTwoChildrenRemoveParent()
|
||||
{
|
||||
var graph = new MultiRootInheritanceGraph<string>();
|
||||
graph.Add(Id3, new []{Id1});
|
||||
graph.Add(Id4, new []{Id1});
|
||||
|
||||
var parents = graph.GetParents(Id3);
|
||||
Assert.That(parents, Is.Not.Null);
|
||||
Assert.That(parents!.Count, Is.EqualTo(1));
|
||||
Assert.That(parents.Contains(Id1));
|
||||
|
||||
parents = graph.GetParents(Id4);
|
||||
Assert.That(parents, Is.Not.Null);
|
||||
Assert.That(parents!.Count, Is.EqualTo(1));
|
||||
Assert.That(parents.Contains(Id1));
|
||||
|
||||
var children = graph.GetChildren(Id1);
|
||||
Assert.That(children, Is.Not.Null);
|
||||
Assert.That(children!.Count, Is.EqualTo(2));
|
||||
Assert.That(children.Contains(Id3));
|
||||
Assert.That(children.Contains(Id4));
|
||||
|
||||
Assert.That(graph.RootNodes.Count, Is.EqualTo(1));
|
||||
Assert.That(graph.RootNodes.Contains(Id1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CircleCheckTest()
|
||||
{
|
||||
var graph = new MultiRootInheritanceGraph<string>();
|
||||
graph.Add(Id1, new []{Id2});
|
||||
Assert.Throws<InvalidOperationException>(() => graph.Add(Id2, new []{Id1}));
|
||||
|
||||
graph.Add(Id2, new[] { Id3 });
|
||||
Assert.Throws<InvalidOperationException>(() => graph.Add(Id3, new[] { Id1 }));
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsOwnParentTest()
|
||||
{
|
||||
var graph = new MultiRootInheritanceGraph<string>();
|
||||
Assert.Throws<InvalidOperationException>(() => graph.Add(Id1, new []{ Id1 }));
|
||||
}
|
||||
}
|
||||
279
Robust.Shared.Tests/Random/RandomExtensionsTests.cs
Normal file
279
Robust.Shared.Tests/Random/RandomExtensionsTests.cs
Normal file
@@ -0,0 +1,279 @@
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Robust.Shared.Tests.Random;
|
||||
|
||||
/// <summary> Instantiable tests for <see cref="RandomExtensions.GetItems{T}(IRobustRandom,IList{T},int,bool)"/>. </summary>
|
||||
[TestFixture]
|
||||
internal sealed class RandomExtensionsGetItemsWithListTests : RandomExtensionsTests<IList<string>>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override IList<string> CreateCollection()
|
||||
=> new List<string>(CollectionForTests);
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IReadOnlyCollection<string> Invoke(IList<string> collection, int count, bool allowDuplicates)
|
||||
=> _underlyingRandom.GetItems(collection, count, allowDuplicates);
|
||||
}
|
||||
|
||||
/// <summary> Instantiable tests for <see cref="RandomExtensions.GetItems{T}(IRobustRandom,Span{T},int,bool)"/>. </summary>
|
||||
[TestFixture]
|
||||
internal sealed class RandomExtensionsGetItemsWithSpanTests : RandomExtensionsTests<string[]>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string[] CreateCollection()
|
||||
=> CollectionForTests;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IReadOnlyCollection<string> Invoke(string[] collection, int count, bool allowDuplicates)
|
||||
{
|
||||
var span = new Span<string>(collection);
|
||||
return _underlyingRandom.GetItems(span, count, allowDuplicates)
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Instantiable tests for <see cref="RandomExtensions.GetItems{T}(IRobustRandom,ValueList{T},int,bool)"/>. </summary>
|
||||
[TestFixture]
|
||||
internal sealed class RandomExtensionsGetItemsWithValueListTests : RandomExtensionsTests<ValueList<string>>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override ValueList<string> CreateCollection()
|
||||
=> new ValueList<string>(CollectionForTests);
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IReadOnlyCollection<string> Invoke(ValueList<string> collection, int count, bool allowDuplicates)
|
||||
=> _underlyingRandom.GetItems(collection, count, allowDuplicates)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
internal abstract class RandomExtensionsTests<T>
|
||||
{
|
||||
protected IRobustRandom _underlyingRandom = default!;
|
||||
|
||||
protected readonly string[] CollectionForTests = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
|
||||
|
||||
private T _collection = default!;
|
||||
|
||||
private int Count => CollectionForTests.Length;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_underlyingRandom = Mock.Of<IRobustRandom>();
|
||||
_collection = CreateCollection();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_PickOneFromList_ReturnOfRandomizedIndex()
|
||||
{
|
||||
// Arrange
|
||||
Mock.Get(_underlyingRandom)
|
||||
.Setup(x => x.Next(Count))
|
||||
.Returns(8);
|
||||
|
||||
// Act
|
||||
var result = Invoke(_collection, 1, true);
|
||||
|
||||
// Assert
|
||||
Assert.That(result.Count, Is.EqualTo(1));
|
||||
Assert.That(result.Single(), Is.EqualTo("8"));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void GetItems_PickOneFromListWithoutDuplicates_ReturnOfRandomizedIndex()
|
||||
{
|
||||
// Arrange
|
||||
Mock.Get(_underlyingRandom)
|
||||
.Setup(x => x.Next(Count))
|
||||
.Returns(8);
|
||||
|
||||
// Act
|
||||
var result = Invoke(_collection, 1, allowDuplicates: false);
|
||||
|
||||
// Assert
|
||||
Assert.That(result.Count, Is.EqualTo(1));
|
||||
Assert.That(result.Single(), Is.EqualTo("8"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_PickSomeFromList_ReturnOfRandomizedIndex()
|
||||
{
|
||||
// Arrange
|
||||
Mock.Get(_underlyingRandom)
|
||||
.SetupSequence(x => x.Next(Count))
|
||||
.Returns(8)
|
||||
.Returns(3)
|
||||
.Returns(2);
|
||||
|
||||
// Act
|
||||
var result = Invoke(_collection, 3, true);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new[] { "8", "3", "2" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_PickSomeFromListWhileRollingDuplicates_ReturnWithDuplicates()
|
||||
{
|
||||
// Arrange
|
||||
Mock.Get(_underlyingRandom)
|
||||
.SetupSequence(x => x.Next(Count))
|
||||
.Returns(8)
|
||||
.Returns(2)
|
||||
.Returns(2)
|
||||
.Returns(2);
|
||||
|
||||
// Act
|
||||
var result = Invoke(_collection, 4, allowDuplicates: true);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new[] { "8", "2", "2", "2" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_PickSameAmountAsOriginalCollection_ReturnWithDuplicates()
|
||||
{
|
||||
// Arrange
|
||||
Mock.Get(_underlyingRandom)
|
||||
.SetupSequence(x => x.Next(Count))
|
||||
.Returns(0)
|
||||
.Returns(2)
|
||||
.Returns(2)
|
||||
.Returns(4)
|
||||
.Returns(6)
|
||||
.Returns(5)
|
||||
.Returns(4)
|
||||
.Returns(3)
|
||||
.Returns(2)
|
||||
.Returns(1)
|
||||
.Returns(0);
|
||||
|
||||
// Act
|
||||
var result = Invoke(_collection, 11, allowDuplicates: true);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new[] { "0", "2", "2", "4", "6", "5", "4", "3", "2", "1", "0" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_PickMoreItemsThenOriginalCollectionHave_ReturnWithDuplicates()
|
||||
{
|
||||
// Arrange
|
||||
Mock.Get(_underlyingRandom)
|
||||
.SetupSequence(x => x.Next(Count))
|
||||
.Returns(0)
|
||||
.Returns(2)
|
||||
.Returns(2)
|
||||
.Returns(4)
|
||||
.Returns(6)
|
||||
.Returns(5)
|
||||
.Returns(4)
|
||||
.Returns(3)
|
||||
.Returns(2)
|
||||
.Returns(1)
|
||||
.Returns(9)
|
||||
.Returns(9);
|
||||
|
||||
// Act
|
||||
var result = Invoke(_collection, 12, allowDuplicates: true);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new[] { "0", "2", "2", "4", "6", "5", "4", "3", "2", "1", "9", "9" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_PickSomeItemsWithoutDuplicates_ReturnWithoutDuplicates()
|
||||
{
|
||||
// Arrange
|
||||
var mock = Mock.Get(_underlyingRandom);
|
||||
mock.Setup(x => x.Next(Count)).Returns(1);
|
||||
mock.Setup(x => x.Next(Count - 1)).Returns(1);
|
||||
mock.Setup(x => x.Next(Count - 2)).Returns(6);
|
||||
|
||||
// Act
|
||||
var result = Invoke(_collection, 3, allowDuplicates: false);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new[] { "1", "10", "6" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_PickOneLessItemsThenOriginalCollectionHaveWithoutDuplicates_ReturnWithoutDuplicates()
|
||||
{
|
||||
// Arrange
|
||||
var mock = Mock.Get(_underlyingRandom);
|
||||
mock.Setup(x => x.Next(Count)).Returns(1);
|
||||
mock.Setup(x => x.Next(Count - 1)).Returns(1);
|
||||
mock.Setup(x => x.Next(Count - 2)).Returns(6);
|
||||
mock.Setup(x => x.Next(Count - 3)).Returns(6);
|
||||
mock.Setup(x => x.Next(Count - 4)).Returns(3);
|
||||
mock.Setup(x => x.Next(Count - 5)).Returns(4);
|
||||
mock.Setup(x => x.Next(Count - 6)).Returns(4);
|
||||
mock.Setup(x => x.Next(Count - 7)).Returns(3);
|
||||
mock.Setup(x => x.Next(Count - 8)).Returns(1);
|
||||
mock.Setup(x => x.Next(Count - 9)).Returns(1);
|
||||
|
||||
// Act
|
||||
var result = Invoke(_collection, 10, allowDuplicates: false);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new[] { "1", "10", "6", "8", "3", "4", "5", "7", "9", "2" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_PickAllItemsWithoutDuplicates_ReturnOriginalCollectionShuffledWithoutDuplicates()
|
||||
{
|
||||
// Arrange
|
||||
var shuffled = new[] { "9", "0", "4", "2", "3", "7", "5", "8", "6", "10", "1" };
|
||||
Mock.Get(_underlyingRandom)
|
||||
.Setup(x => x.Shuffle(It.IsAny<IList<string>>()))
|
||||
.Callback<IList<string>>(x =>
|
||||
{
|
||||
for (int i = 0; i < shuffled.Length; i++)
|
||||
{
|
||||
x[i] = shuffled[i];
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = Invoke(_collection, 11, allowDuplicates: false);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(shuffled));
|
||||
Mock.Get(_underlyingRandom).Verify(x => x.Next(It.IsAny<int>()), Times.Never);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_PickMoreItemsThenOriginalHaveWithoutDuplicates_ReturnOriginalShuffledOriginalCollectionWithoutDuplicates()
|
||||
{
|
||||
// Arrange
|
||||
var shuffled = new[] { "9", "0", "4", "2", "3", "7", "5", "8", "6", "10", "1" };
|
||||
Mock.Get(_underlyingRandom)
|
||||
.Setup(x => x.Shuffle(It.IsAny<IList<string>>()))
|
||||
.Callback<IList<string>>(x =>
|
||||
{
|
||||
for (int i = 0; i < shuffled.Length; i++)
|
||||
{
|
||||
x[i] = shuffled[i];
|
||||
}
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = Invoke(_collection, 30, allowDuplicates: false);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(shuffled));
|
||||
Mock.Get(_underlyingRandom).Verify(x => x.Next(It.IsAny<int>()), Times.Never);
|
||||
}
|
||||
|
||||
/// <summary> Create concrete collection for tests. </summary>
|
||||
protected abstract T CreateCollection();
|
||||
|
||||
/// <summary> Invoke method under test. Separate implementation types will have different overrides to be tested. </summary>
|
||||
protected abstract IReadOnlyCollection<string> Invoke(T collection, int count, bool allowDuplicates);
|
||||
}
|
||||
63
Robust.Shared.Tests/Resources/WritableDirProviderTest.cs
Normal file
63
Robust.Shared.Tests/Resources/WritableDirProviderTest.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Tests.Resources
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(WritableDirProvider))]
|
||||
internal sealed class WritableDirProviderTest
|
||||
{
|
||||
private string _testDirPath = default!;
|
||||
private DirectoryInfo _testDir = default!;
|
||||
private WritableDirProvider _dirProvider = default!;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var tmpPath = Path.GetTempPath();
|
||||
var guid = Guid.NewGuid();
|
||||
_testDirPath = Path.Combine(tmpPath, guid.ToString());
|
||||
|
||||
_testDir = Directory.CreateDirectory(_testDirPath);
|
||||
var subDir = Path.Combine(_testDirPath, "writable");
|
||||
|
||||
_dirProvider = new WritableDirProvider(Directory.CreateDirectory(subDir), hideRootDir: false);
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
_testDir.Delete(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoParentAccess()
|
||||
{
|
||||
File.WriteAllText(Path.Combine(_testDirPath, "dummy"), "foobar");
|
||||
|
||||
// No, ../ does not work to read stuff in the parent dir.
|
||||
Assert.That(() => _dirProvider.ReadAllText(new ResPath("/../dummy")),
|
||||
Throws.InstanceOf<FileNotFoundException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNotRooted()
|
||||
{
|
||||
// Path must be rooted.
|
||||
Assert.That(() => _dirProvider.OpenRead(new ResPath("foo.bar")),
|
||||
Throws.InstanceOf<ArgumentException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestParentAccessClamped()
|
||||
{
|
||||
File.WriteAllText(Path.Combine(_testDirPath, "dummy"), "foobar");
|
||||
|
||||
_dirProvider.WriteAllText(new ResPath("/dummy"), "pranked");
|
||||
|
||||
// ../ should get clamped to /.
|
||||
Assert.That(_dirProvider.ReadAllText(new ResPath("/../dummy")), Is.EqualTo("pranked"));
|
||||
}
|
||||
}
|
||||
}
|
||||
54
Robust.Shared.Tests/RichText/FormattedStringTest.cs
Normal file
54
Robust.Shared.Tests/RichText/FormattedStringTest.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.RichText;
|
||||
|
||||
namespace Robust.UnitTesting.Shared.RichText;
|
||||
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
[TestOf(typeof(FormattedString))]
|
||||
[TestFixture]
|
||||
internal sealed class FormattedStringTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Test that permissive parsing properly normalizes & passes through markup, as appropriate.
|
||||
/// </summary>
|
||||
[Test]
|
||||
[TestCase("", ExpectedResult = "")]
|
||||
[TestCase("foobar", ExpectedResult = "foobar")]
|
||||
[TestCase("[whaaaaaa", ExpectedResult = "\\[whaaaaaa")]
|
||||
[TestCase("\\[whaaaaaa", ExpectedResult = "\\[whaaaaaa")]
|
||||
[TestCase("[whaaaaaa]wow[/whaaaaaa]", ExpectedResult = "[whaaaaaa]wow[/whaaaaaa]")]
|
||||
[TestCase("[whaaaaaa]\\[womp[/whaaaaaa]", ExpectedResult = "[whaaaaaa]\\[womp[/whaaaaaa]")]
|
||||
public static string TestPermissiveNormalize(string input)
|
||||
{
|
||||
return FormattedString.FromMarkupPermissive(input).Markup;
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("")]
|
||||
[TestCase("real")]
|
||||
[TestCase("[whaaaaaa]wow[/whaaaaaa]")]
|
||||
public static void TestStrictParse(string input)
|
||||
{
|
||||
var str = FormattedString.FromMarkup(input);
|
||||
|
||||
Assert.That(str.Markup, Is.EqualTo(input));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", ExpectedResult = "")]
|
||||
[TestCase("real", ExpectedResult = "real")]
|
||||
[TestCase("[real", ExpectedResult = "\\[real")]
|
||||
[TestCase("\\", ExpectedResult = @"\\")]
|
||||
public static string TestFromPlainText(string input)
|
||||
{
|
||||
return FormattedString.FromPlainText(input).Markup;
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("[whaaaaaawow")]
|
||||
[TestCase("[whaaaaaawow val=\"]")]
|
||||
public static void TestStrictThrows(string input)
|
||||
{
|
||||
Assert.That(() => FormattedString.FromMarkup(input), Throws.ArgumentException);
|
||||
}
|
||||
}
|
||||
25
Robust.Shared.Tests/Robust.Shared.Tests.csproj
Normal file
25
Robust.Shared.Tests/Robust.Shared.Tests.csproj
Normal file
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\MSBuild\Robust.Engine.props"/>
|
||||
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk"/>
|
||||
<PackageReference Include="Moq" />
|
||||
<PackageReference Include="NUnit"/>
|
||||
<PackageReference Include="NUnit3TestAdapter"/>
|
||||
<PackageReference Include="NUnit.Analyzers"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Robust.Shared.Maths.Tests\Robust.Shared.Maths.Tests.csproj" />
|
||||
<ProjectReference Include="..\Robust.Shared.Maths\Robust.Shared.Maths.csproj"/>
|
||||
<ProjectReference Include="..\Robust.Shared.Maths.Testing\Robust.Shared.Maths.Testing.csproj"/>
|
||||
<ProjectReference Include="..\Robust.Shared\Robust.Shared.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\MSBuild\Robust.Properties.targets"/>
|
||||
</Project>
|
||||
115
Robust.Shared.Tests/Serialization/NetSerializerBitArrayTest.cs
Normal file
115
Robust.Shared.Tests/Serialization/NetSerializerBitArrayTest.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using NetSerializer;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Robust.Shared.Tests.Serialization;
|
||||
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
[TestFixture, TestOf(typeof(NetBitArraySerializer))]
|
||||
internal sealed class NetSerializerBitArrayTest
|
||||
{
|
||||
// Test that BitArray serialization matches the behavior before .NET 10
|
||||
// This test can be removed in future RT versions.
|
||||
|
||||
[Test]
|
||||
[TestCase("little creature, have you ever heard about gay people?",
|
||||
"AgAP2KWjxw7YlYOyDOSVi8YO6smrxgXAoIvmDsqByfcN6oGp5g7KyYOCDcqFk8cMwIST9g3q0YPyDMLlg4IOyr2Dxw3K/QHgBg==")]
|
||||
[TestCase("", "AgABAA==")]
|
||||
public void Test(string testData, string expected)
|
||||
{
|
||||
var bitData = Encoding.UTF8.GetBytes(testData);
|
||||
var bitArray = new BitArray(bitData);
|
||||
|
||||
var serializer = new Serializer([typeof(BitArray)],
|
||||
new Settings
|
||||
{
|
||||
CustomTypeSerializers = [new NetBitArraySerializer()]
|
||||
});
|
||||
|
||||
var stream = new MemoryStream();
|
||||
serializer.Serialize(stream, bitArray);
|
||||
|
||||
var base64 = Convert.ToBase64String(stream.ToArray());
|
||||
|
||||
TestContext.Out.WriteLine(base64);
|
||||
|
||||
Assert.That(base64, Is.EqualTo(expected));
|
||||
|
||||
stream.Position = 0;
|
||||
var newBitArray = (BitArray)serializer.Deserialize(stream);
|
||||
|
||||
Assert.That(newBitArray, Is.EquivalentTo(bitArray));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Unset()
|
||||
{
|
||||
var bitArray = new BitArray(16);
|
||||
|
||||
var serializer = new Serializer([typeof(BitArray)],
|
||||
new Settings
|
||||
{
|
||||
CustomTypeSerializers = [new NetBitArraySerializer()]
|
||||
});
|
||||
|
||||
var stream = new MemoryStream();
|
||||
serializer.Serialize(stream, bitArray);
|
||||
|
||||
var base64 = Convert.ToBase64String(stream.ToArray());
|
||||
|
||||
TestContext.Out.WriteLine(base64);
|
||||
|
||||
Assert.That(base64, Is.EqualTo("AgACACA="));
|
||||
|
||||
stream.Position = 0;
|
||||
var newBitArray = (BitArray)serializer.Deserialize(stream);
|
||||
|
||||
Assert.That(newBitArray, Is.EquivalentTo(bitArray));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClass()
|
||||
{
|
||||
var obj = new FooBar
|
||||
{
|
||||
Real = 0x3005,
|
||||
Heck = "omg",
|
||||
Wawa = new BitArray("I miss my wife"u8.ToArray())
|
||||
};
|
||||
|
||||
var serializer = new Serializer([typeof(BitArray), typeof(FooBar)],
|
||||
new Settings
|
||||
{
|
||||
CustomTypeSerializers = [new NetBitArraySerializer()]
|
||||
});
|
||||
|
||||
var stream = new MemoryStream();
|
||||
serializer.Serialize(stream, obj);
|
||||
|
||||
var base64 = Convert.ToBase64String(stream.ToArray());
|
||||
|
||||
TestContext.Out.WriteLine(base64);
|
||||
|
||||
Assert.That(base64, Is.EqualTo("AgQDb21nisABAwAFkoHplg3mzYPSDfKBuZcNzJUD4AE="));
|
||||
|
||||
stream.Position = 0;
|
||||
var newObject = (FooBar)serializer.Deserialize(stream);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(newObject.Real, Is.EqualTo(obj.Real));
|
||||
Assert.That(newObject.Heck, Is.EqualTo(obj.Heck));
|
||||
Assert.That(newObject.Wawa, Is.EquivalentTo(obj.Wawa));
|
||||
});
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private sealed class FooBar
|
||||
{
|
||||
public required int Real;
|
||||
public required string Heck;
|
||||
public required BitArray Wawa;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using NetSerializer;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.RichText;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Robust.Shared.Tests.Serialization;
|
||||
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
[TestFixture, TestOf(typeof(NetFormattedStringSerializer))]
|
||||
internal sealed class NetSerializerFormattedStringTest
|
||||
{
|
||||
[Test]
|
||||
[TestCase("")]
|
||||
[TestCase("real")]
|
||||
[TestCase("[i]heck[/i]")]
|
||||
public void TestBasic(string markup)
|
||||
{
|
||||
var serializer = MakeSerializer();
|
||||
|
||||
var str = FormattedString.FromMarkup(markup);
|
||||
|
||||
var stream = new MemoryStream();
|
||||
serializer.Serialize(stream, str);
|
||||
stream.Position = 0;
|
||||
|
||||
var deserialized = (FormattedString) serializer.Deserialize(stream);
|
||||
|
||||
Assert.That(deserialized, NUnit.Framework.Is.EqualTo(str));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that the on-wire representation of a <see cref="FormattedString"/> is the same as a regular string.
|
||||
/// This is to ensure <see cref="TestInvalid"/> is a valid test.
|
||||
/// </summary>
|
||||
[Test]
|
||||
[TestCase("")]
|
||||
[TestCase("real")]
|
||||
[TestCase("[i]heck[/i]")]
|
||||
public void TestEqualToString(string markup)
|
||||
{
|
||||
var serializer = MakeSerializer();
|
||||
|
||||
var stream = new MemoryStream();
|
||||
serializer.SerializeDirect(stream, markup);
|
||||
stream.Position = 0;
|
||||
|
||||
serializer.DeserializeDirect(stream, out FormattedString str);
|
||||
|
||||
Assert.That(str.Markup, Is.EqualTo(markup));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that deserialization fails if a malicious client sends broken markup.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestInvalid()
|
||||
{
|
||||
var serializer = MakeSerializer();
|
||||
|
||||
var stream = new MemoryStream();
|
||||
serializer.SerializeDirect(stream, "[wahoooo");
|
||||
stream.Position = 0;
|
||||
|
||||
Assert.That(() => serializer.DeserializeDirect(stream, out FormattedString _), Throws.Exception);
|
||||
}
|
||||
|
||||
private static Serializer MakeSerializer()
|
||||
{
|
||||
return new Serializer([typeof(FormattedString)],
|
||||
new Settings
|
||||
{
|
||||
CustomTypeSerializers = [new NetFormattedStringSerializer()]
|
||||
});
|
||||
}
|
||||
}
|
||||
215
Robust.Shared.Tests/Timing/GameTiming_Test.cs
Normal file
215
Robust.Shared.Tests/Timing/GameTiming_Test.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using System.Reflection;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.Shared.Tests.Timing
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(GameTiming))]
|
||||
internal sealed class GameTiming_Test
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks that IGameTiming.RealTime returns the real(wall) uptime since the stopwatch was started.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is unaffected by pausing, and has nothing to do with the simulation. This should be used for
|
||||
/// out-of-simulation timing, for example sound timing, UI timing, input timing, etc.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void RealTimeTest()
|
||||
{
|
||||
// Arrange
|
||||
var elapsedVal = TimeSpan.FromSeconds(Math.PI);
|
||||
var newStopwatch = new Mock<IStopwatch>();
|
||||
newStopwatch.SetupGet(p => p.Elapsed).Returns(elapsedVal);
|
||||
var gameTiming = GameTimingFactory(newStopwatch.Object);
|
||||
|
||||
// Act
|
||||
gameTiming.StartFrame();
|
||||
var result = gameTiming.RealTime;
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(elapsedVal));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that IGameTiming.RealFrameTime returns the real(wall) delta time between the two most recent calls to
|
||||
/// IGameTiming.StartFrame().
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is unaffected by pausing, and has nothing to do with the simulation. This value is used
|
||||
/// by the profiling functions.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void RealFrameTimeTest()
|
||||
{
|
||||
// Arrange
|
||||
var elapsedVal = TimeSpan.FromSeconds(3);
|
||||
var newStopwatch = new Mock<IStopwatch>();
|
||||
newStopwatch.SetupGet(p => p.Elapsed).Returns(() => elapsedVal);
|
||||
var gameTiming = GameTimingFactory(newStopwatch.Object);
|
||||
gameTiming.StartFrame(); // changes last time from 0 to 3
|
||||
|
||||
// Act
|
||||
elapsedVal = TimeSpan.FromSeconds(5);
|
||||
gameTiming.StartFrame();
|
||||
var result = gameTiming.RealFrameTime;
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(TimeSpan.FromSeconds(2))); // 5 - 3 = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that IGameTiming.CurTime returns the current simulation uptime when inside the simulation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is affected by pausing. This value is derived from CurTick and TickRate, and is unaffected
|
||||
/// by RealTime. All simulation code should be using this value to measure uptime.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void InSimCurTimeTest()
|
||||
{
|
||||
// Arrange
|
||||
var newStopwatch = new Mock<IStopwatch>();
|
||||
var gameTiming = GameTimingFactory(newStopwatch.Object);
|
||||
gameTiming.InSimulation = true;
|
||||
|
||||
//NOTE: TickRate can cause a slight rounding error in TickPeriod reciprocal calculation from repeating decimals depending
|
||||
// on the value chosen.
|
||||
gameTiming.TickRate = 20;
|
||||
gameTiming.CurTick = new GameTick(61); // 1 + 60, because 1 is the first tick
|
||||
|
||||
// Act
|
||||
gameTiming.StartFrame();
|
||||
var result = gameTiming.CurTime;
|
||||
|
||||
// Assert
|
||||
var expected = TimeSpan.FromTicks(TimeSpan.TicksPerSecond * 3);
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that IGameTiming.CurTime returns the current simulation time + fractional tick time when outside the
|
||||
/// simulation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the same thing as in-simulation CurTime, but also adds the fractional tick to the time. This is useful
|
||||
/// for the renderer to be able to transparently cause the simulation to extrapolate between CurTick and CurTick + 1.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void OutSimCurTimeTest()
|
||||
{
|
||||
// Arrange
|
||||
var newStopwatch = new Mock<IStopwatch>();
|
||||
var gameTiming = GameTimingFactory(newStopwatch.Object);
|
||||
gameTiming.InSimulation = false;
|
||||
gameTiming.TickRate = 20;
|
||||
gameTiming.CurTick = new GameTick(61); // 1 + 60, because 1 is the first tick
|
||||
gameTiming.TickRemainder = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 2); // half a second
|
||||
|
||||
// Act
|
||||
gameTiming.StartFrame();
|
||||
var result = gameTiming.CurTime;
|
||||
|
||||
// Assert
|
||||
var expected = TimeSpan.FromSeconds(3.5);
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that IGameTiming.FrameTime returns the simulated delta time between the two most recent calls to IGameTiming.StartFrame().
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is not affected by pausing. This value is derived from TickRate, and is unaffected
|
||||
/// by RealTime. There is no lag or jitter inside the simulation. The FrameTime is always exactly TickPeriod.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void InSimFrameTimeTest()
|
||||
{
|
||||
// Arrange
|
||||
var newStopwatch = new Mock<IStopwatch>();
|
||||
var gameTiming = GameTimingFactory(newStopwatch.Object);
|
||||
gameTiming.InSimulation = true;
|
||||
gameTiming.TickRate = 20;
|
||||
|
||||
// Act
|
||||
gameTiming.StartFrame();
|
||||
gameTiming.CurTick = new GameTick(gameTiming.CurTick.Value + 1);
|
||||
gameTiming.StartFrame();
|
||||
var result = gameTiming.FrameTime;
|
||||
|
||||
// Assert
|
||||
var expected = TimeSpan.FromTicks((long)(TimeSpan.TicksPerSecond * (1/20.0)));
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that IGameTiming.FrameTime returns the real delta time between the two most recent calls to IGameTiming.StartFrame().
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When outside the simulation, FrameTime returns the same value as RealFrameTime. This allows rendering code to also use
|
||||
/// the FrameTime property instead of RealFrameTime.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void OutSimFrameTimeTest()
|
||||
{
|
||||
// Arrange
|
||||
var elapsedVal = TimeSpan.FromSeconds(3);
|
||||
var newStopwatch = new Mock<IStopwatch>();
|
||||
newStopwatch.SetupGet(p => p.Elapsed).Returns(() => elapsedVal);
|
||||
var gameTiming = GameTimingFactory(newStopwatch.Object);
|
||||
gameTiming.InSimulation = false;
|
||||
gameTiming.Paused = false; // paused timing returns 0 frame time.
|
||||
gameTiming.StartFrame(); // changes last time from 0 to 3
|
||||
|
||||
// Act
|
||||
elapsedVal = TimeSpan.FromSeconds(5);
|
||||
gameTiming.StartFrame();
|
||||
var result = gameTiming.FrameTime;
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(TimeSpan.FromSeconds(2))); // 5 - 3 = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that IGameTiming.FrameTime returns zero when outside the simulation, and the simulation is paused.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the simulation is paused, then the update loop should not be ran. When rendering calls code that uses FrameTime
|
||||
/// while paused, time never passed since the last frame, and FrameTime should always return 0.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void OutSimFrameTimePausedTest()
|
||||
{
|
||||
// Arrange
|
||||
var elapsedVal = TimeSpan.FromSeconds(3);
|
||||
var newStopwatch = new Mock<IStopwatch>();
|
||||
newStopwatch.SetupGet(p => p.Elapsed).Returns(() => elapsedVal);
|
||||
var gameTiming = GameTimingFactory(newStopwatch.Object);
|
||||
gameTiming.InSimulation = false;
|
||||
gameTiming.StartFrame(); // changes last time from 0 to 3
|
||||
gameTiming.Paused = true;
|
||||
|
||||
// Act
|
||||
elapsedVal = TimeSpan.FromSeconds(5); // RealTime increases
|
||||
gameTiming.StartFrame();
|
||||
var result = gameTiming.FrameTime;
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(TimeSpan.Zero)); // But simulation time never increases.
|
||||
}
|
||||
|
||||
private static IGameTiming GameTimingFactory(IStopwatch stopwatch)
|
||||
{
|
||||
var timing = new GameTiming();
|
||||
|
||||
var field = typeof(GameTiming).GetField("_realTimer", BindingFlags.NonPublic | BindingFlags.Instance)!;
|
||||
field.SetValue(timing, stopwatch);
|
||||
|
||||
Assert.That(timing.CurTime, Is.EqualTo(TimeSpan.Zero));
|
||||
|
||||
return timing;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Robust.Shared.Tests/Utility/CaseConversionTest.cs
Normal file
23
Robust.Shared.Tests/Utility/CaseConversionTest.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Tests.Utility
|
||||
{
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
[TestFixture]
|
||||
[TestOf(typeof(CaseConversion))]
|
||||
internal sealed class CaseConversionTest
|
||||
{
|
||||
[Test]
|
||||
[TestCase("FooBar", ExpectedResult = "foo-bar")]
|
||||
[TestCase("Foo", ExpectedResult = "foo")]
|
||||
[TestCase("FooBarBaz", ExpectedResult = "foo-bar-baz")]
|
||||
[TestCase("AssistantPDA", ExpectedResult = "assistant-pda")] // incorrect abbreviations
|
||||
[TestCase("AssistantPda", ExpectedResult = "assistant-pda")] // correct abbreviations
|
||||
[TestCase("FileIO", ExpectedResult = "file-io")]
|
||||
public string PascalToKebab(string input)
|
||||
{
|
||||
return CaseConversion.PascalToKebab(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Robust.Shared.Tests/Utility/CollectionExtensions_Test.cs
Normal file
34
Robust.Shared.Tests/Utility/CollectionExtensions_Test.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Tests.Utility
|
||||
{
|
||||
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
|
||||
[TestFixture]
|
||||
internal sealed class CollectionExtensions_Test
|
||||
{
|
||||
[Test]
|
||||
public void RemoveSwapTest()
|
||||
{
|
||||
var list = new List<int> {1, 2, 3};
|
||||
list.RemoveSwap(2);
|
||||
Assert.That(list, Is.EqualTo(new List<int> {1, 2}));
|
||||
|
||||
list = new List<int> {1, 2, 3};
|
||||
list.RemoveSwap(0);
|
||||
Assert.That(list, Is.EqualTo(new List<int> {3, 2}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFirstOrNull()
|
||||
{
|
||||
Assert.That(Enumerable.Empty<int>().FirstOrNull(), Is.Null);
|
||||
Assert.That(new[] {1}.FirstOrNull(), Is.EqualTo(1));
|
||||
Assert.That(new[] {1, 2, 3}.FirstOrNull(), Is.EqualTo(1));
|
||||
|
||||
Assert.That(Enumerable.Empty<int>().FirstOrNull(p => p == 2), Is.Null);
|
||||
Assert.That(new[] {1}.FirstOrNull(p => p == 2), Is.Null);
|
||||
Assert.That(new[] {1, 2, 3}.FirstOrNull(p => p == 2), Is.EqualTo(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Robust.Shared.Tests/Utility/CommandParsing_Test.cs
Normal file
37
Robust.Shared.Tests/Utility/CommandParsing_Test.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Tests.Utility
|
||||
{
|
||||
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
|
||||
[TestFixture]
|
||||
[TestOf(typeof(CommandParsing))]
|
||||
internal sealed class CommandParsing_Test
|
||||
{
|
||||
[TestCase("foo bar", new[] {"foo", "bar"})]
|
||||
[TestCase("foo bar", new[] {"foo", "bar"})]
|
||||
[TestCase("foo \"bar baz\"", new[] {"foo", "bar baz"})]
|
||||
[TestCase("foo \"bar baz\"", new[] {"foo", "bar baz"})]
|
||||
[TestCase("foo bar baz", new[] {"foo", "bar", "baz"})]
|
||||
[TestCase(@"foo \""bar\""", new[] {"foo", "\"bar\""})]
|
||||
[TestCase(@"foo \""b\ar\""", new[] {"foo", "\"bar\""})]
|
||||
[TestCase("", new string[0])]
|
||||
public void TestParse(string command, string[] expected)
|
||||
{
|
||||
var list = new List<string>();
|
||||
CommandParsing.ParseArguments(command, list);
|
||||
|
||||
Assert.That(list, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase("foo", "foo")]
|
||||
[TestCase(@"f\oo", @"f\\oo")]
|
||||
[TestCase(@"f""oo", @"f\""oo")]
|
||||
public void TestEscape(string source, string expected)
|
||||
{
|
||||
var escaped = CommandParsing.Escape(source);
|
||||
|
||||
Assert.That(escaped, Is.EqualTo(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
99
Robust.Shared.Tests/Utility/FormattedMessage_Test.cs
Normal file
99
Robust.Shared.Tests/Utility/FormattedMessage_Test.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Tests.Utility
|
||||
{
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
[TestFixture]
|
||||
[TestOf(typeof(FormattedMessage))]
|
||||
internal sealed class FormattedMessage_Test
|
||||
{
|
||||
[Test]
|
||||
public static void TestParseMarkup()
|
||||
{
|
||||
var msg = FormattedMessage.FromMarkupOrThrow("foo[color=#aabbcc]bar[/color]baz");
|
||||
|
||||
Assert.That(msg.Nodes, NUnit.Framework.Is.EquivalentTo(new MarkupNode[]
|
||||
{
|
||||
new("foo"),
|
||||
new("color", new MarkupParameter(Color.FromHex("#aabbcc")), null),
|
||||
new("bar"),
|
||||
new("color", null, null, true),
|
||||
new("baz")
|
||||
}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestParseMarkupColorName()
|
||||
{
|
||||
var msg = FormattedMessage.FromMarkupOrThrow("foo[color=orange]bar[/color]baz");
|
||||
|
||||
Assert.That(msg.Nodes, NUnit.Framework.Is.EquivalentTo(new MarkupNode[]
|
||||
{
|
||||
new("foo"),
|
||||
new("color", new MarkupParameter(Color.Orange), null),
|
||||
new("bar"),
|
||||
new("color", null, null, true),
|
||||
new("baz")
|
||||
}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("foo[color=#aabbcc bar")]
|
||||
public static void TestParsePermissiveMarkup(string text)
|
||||
{
|
||||
var msg = FormattedMessage.FromMarkupPermissive(text);
|
||||
|
||||
Assert.That(
|
||||
string.Join("", msg.Nodes.Where(p => p.Name == null).Select(p => p.Value.StringValue ?? "")),
|
||||
NUnit.Framework.Is.EqualTo(text));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("Foo", ExpectedResult = "Foo")]
|
||||
[TestCase("[color=red]Foo[/color]", ExpectedResult = "Foo")]
|
||||
[TestCase("[color=red]Foo[/color]bar", ExpectedResult = "Foobar")]
|
||||
public string TestRemoveMarkup(string test)
|
||||
{
|
||||
return FormattedMessage.RemoveMarkupOrThrow(test);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("Foo")]
|
||||
[TestCase("[color=#FF000000]Foo[/color]")]
|
||||
[TestCase("[color=lime]Foo[/color]bar")]
|
||||
public static void TestToMarkup(string text)
|
||||
{
|
||||
var message = FormattedMessage.FromMarkupOrThrow(text);
|
||||
Assert.That(message.ToMarkup(), NUnit.Framework.Is.EqualTo(text));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("Foo")]
|
||||
[TestCase("[color=#FF000000]Foo[/color]")]
|
||||
[TestCase("[color=#00FF00FF]Foo[/color]bar")]
|
||||
[TestCase("honk honk [color=#00FF00FF]Foo[/color]bar")]
|
||||
public static void TestEnumerateRunes(string text)
|
||||
{
|
||||
var message = FormattedMessage.FromMarkupOrThrow(text);
|
||||
|
||||
Assert.That(
|
||||
message.EnumerateRunes(),
|
||||
Is.EquivalentTo(message.ToString().EnumerateRunes()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that the given formatted message string provides equal result when output & parsed again.
|
||||
/// </summary>
|
||||
[Test]
|
||||
[TestCase("\\[whaaaaa")]
|
||||
public static void TestRoundTrip(string markup)
|
||||
{
|
||||
var message = FormattedMessage.FromMarkupOrThrow(markup);
|
||||
var secondMessage = FormattedMessage.FromMarkupOrThrow(message.ToMarkup());
|
||||
|
||||
Assert.That(secondMessage, NUnit.Framework.Is.EqualTo(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Robust.Shared.Tests/Utility/MarkupNodeTest.cs
Normal file
64
Robust.Shared.Tests/Utility/MarkupNodeTest.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Tests.Utility;
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
[TestOf(typeof(MarkupNode))]
|
||||
internal sealed class MarkupNodeTest
|
||||
{
|
||||
[Test]
|
||||
[SuppressMessage("Assertion", "NUnit2009:The same value has been provided as both the actual and the expected argument")]
|
||||
public void TestEquality()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Test name match
|
||||
Assert.That(new MarkupNode("A"), Is.EqualTo(new MarkupNode("A")));
|
||||
Assert.That(new MarkupNode("A").GetHashCode(), Is.EqualTo(new MarkupNode("A").GetHashCode()));
|
||||
Assert.That(new MarkupNode("A"), Is.Not.EqualTo(new MarkupNode("B")));
|
||||
|
||||
// Test closing match
|
||||
Assert.That(new MarkupNode("A", null, null, true), Is.EqualTo(new MarkupNode("A", null, null, true)));
|
||||
Assert.That(new MarkupNode("A", null, null, true).GetHashCode(), Is.EqualTo(new MarkupNode("A", null, null, true).GetHashCode()));
|
||||
Assert.That(new MarkupNode("A", null, null, true), Is.Not.EqualTo(new MarkupNode("A")));
|
||||
|
||||
// Test value match
|
||||
var param = new MarkupParameter("A");
|
||||
Assert.That(new MarkupNode("A", param, null), Is.EqualTo(new MarkupNode("A", param, null)));
|
||||
Assert.That(new MarkupNode("A", param, null).GetHashCode(), Is.EqualTo(new MarkupNode("A", param, null).GetHashCode()));
|
||||
Assert.That(new MarkupNode("A", param, null), Is.Not.EqualTo(new MarkupNode("A")));
|
||||
Assert.That(new MarkupNode("A", param, null), Is.Not.EqualTo(new MarkupNode("A", new MarkupParameter("B"), null)));
|
||||
|
||||
// Test attributes match
|
||||
var attrs = new Dictionary<string, MarkupParameter>
|
||||
{
|
||||
{ "A", new MarkupParameter("A") },
|
||||
{ "B", new MarkupParameter(5) },
|
||||
{ "C", new MarkupParameter(Color.Red) },
|
||||
};
|
||||
var wrongAttrs = new Dictionary<string, MarkupParameter>
|
||||
{
|
||||
{ "A", new MarkupParameter("A") },
|
||||
{ "B", new MarkupParameter(6) },
|
||||
{ "C", new MarkupParameter(Color.Red) },
|
||||
};
|
||||
var wrongAttrsTooLong = new Dictionary<string, MarkupParameter>
|
||||
{
|
||||
{ "A", new MarkupParameter("A") },
|
||||
{ "B", new MarkupParameter(5) },
|
||||
{ "C", new MarkupParameter(Color.Red) },
|
||||
{ "D", new MarkupParameter(Color.Red) },
|
||||
};
|
||||
var attrs2 = attrs.Reverse().ToDictionary();
|
||||
Assert.That(new MarkupNode("A", null, attrs), Is.EqualTo(new MarkupNode("A", null, attrs2)));
|
||||
Assert.That(new MarkupNode("A", null, attrs).GetHashCode(), Is.EqualTo(new MarkupNode("A", null, attrs2).GetHashCode()));
|
||||
Assert.That(new MarkupNode("A", null, attrs), Is.Not.EqualTo(new MarkupNode("A")));
|
||||
Assert.That(new MarkupNode("A", null, attrs), Is.Not.EqualTo(new MarkupNode("A", null, wrongAttrs)));
|
||||
Assert.That(new MarkupNode("A", null, attrs), Is.Not.EqualTo(new MarkupNode("A", null, wrongAttrsTooLong)));
|
||||
});
|
||||
}
|
||||
}
|
||||
325
Robust.Shared.Tests/Utility/MathHelper_Test.cs
Normal file
325
Robust.Shared.Tests/Utility/MathHelper_Test.cs
Normal file
@@ -0,0 +1,325 @@
|
||||
using System.Numerics;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Shared.Tests.Utility
|
||||
{
|
||||
[TestFixture, Parallelizable]
|
||||
[TestOf(typeof(MathHelper))]
|
||||
internal sealed class MathHelper_Test
|
||||
{
|
||||
public static IEnumerable<(long val, long result)> LongNextPowerOfTwoData = new (long, long)[]
|
||||
{
|
||||
(1L, 2L),
|
||||
(2L, 4L),
|
||||
(2147483647L, 2147483648L)
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestLongNextPowerOfTwo([ValueSource(nameof(LongNextPowerOfTwoData))] (long, long) data)
|
||||
{
|
||||
var (val, result) = data;
|
||||
|
||||
Assert.That(MathHelper.NextPowerOfTwo(val), Is.EqualTo(result));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLongNextPowerOfTwoNegativeThrows()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => { MathHelper.NextPowerOfTwo(-10L); });
|
||||
}
|
||||
|
||||
public static IEnumerable<(int val, int result)> IntNextPowerOfTwoData = new (int, int)[]
|
||||
{
|
||||
(1, 2),
|
||||
(2, 4),
|
||||
(3, 4)
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestIntNextPowerOfTwo([ValueSource(nameof(IntNextPowerOfTwoData))] (int, int) data)
|
||||
{
|
||||
var (val, result) = data;
|
||||
|
||||
Assert.That(MathHelper.NextPowerOfTwo(val), Is.EqualTo(result));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestIntNextPowerOfTwoNegativeThrows()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => { MathHelper.NextPowerOfTwo(-10); });
|
||||
}
|
||||
|
||||
public static IEnumerable<(float val, float result)> FloatNextPowerOfTwoData = new (float, float)[]
|
||||
{
|
||||
(0.001f, 1),
|
||||
(0.999f, 1),
|
||||
(1.001f, 2),
|
||||
(2f, 4)
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestFloatNextPowerOfTwo([ValueSource(nameof(FloatNextPowerOfTwoData))] (float, float) data)
|
||||
{
|
||||
var (val, result) = data;
|
||||
|
||||
Assert.That(MathHelper.NextPowerOfTwo(val), Is.EqualTo(result));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFloatNextPowerOfTwoNegativeThrows()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => { MathHelper.NextPowerOfTwo(-10f); });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFloatNextPowerOfTwoNaNThrows()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => { MathHelper.NextPowerOfTwo(float.NaN); });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFloatNextPowerOfTwoInfinityThrows()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => { MathHelper.NextPowerOfTwo(float.PositiveInfinity); });
|
||||
}
|
||||
|
||||
public static IEnumerable<(double val, double result)> DoubleNextPowerOfTwoData = new (double, double)[]
|
||||
{
|
||||
(0.0000001, 1),
|
||||
(0.9999999, 1),
|
||||
(2.0, 4)
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestDoubleNextPowerOfTwo([ValueSource(nameof(DoubleNextPowerOfTwoData))] (double, double) data)
|
||||
{
|
||||
var (val, result) = data;
|
||||
|
||||
Assert.That(MathHelper.NextPowerOfTwo(val), Is.EqualTo(result));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDoubleNextPowerOfTwoNegativeThrows()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => { MathHelper.NextPowerOfTwo(-10.0); });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDoubleNextPowerOfTwoNaNThrows()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => { MathHelper.NextPowerOfTwo(double.NaN); });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDoubleNextPowerOfTwoInfinityThrows()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => { MathHelper.NextPowerOfTwo(double.PositiveInfinity); });
|
||||
}
|
||||
|
||||
public static IEnumerable<(int val, long result)> FactorialData = new (int, long)[]
|
||||
{
|
||||
(0, 1L),
|
||||
(1, 1L),
|
||||
(2, 2L),
|
||||
(3, 6L),
|
||||
(20, 2432902008176640000L)
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestFactorial([ValueSource(nameof(FactorialData))] (int, long) data)
|
||||
{
|
||||
var (val, result) = data;
|
||||
|
||||
Assert.That(MathHelper.Factorial(val), Is.EqualTo(result));
|
||||
}
|
||||
|
||||
public static IEnumerable<(int n, int k, long result)> BinomialCoefficientData = new (int, int, long)[]
|
||||
{
|
||||
(0, 0, 1L),
|
||||
(0, 1, 1L),
|
||||
(1, 0, 1L),
|
||||
(1, 1, 1L),
|
||||
(1, 2, 0L),
|
||||
(2, 1, 2L),
|
||||
(12, 5, 792L),
|
||||
(20, 13, 77520L),
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestBinomialCoefficient([ValueSource(nameof(BinomialCoefficientData))] (int, int, long) data)
|
||||
{
|
||||
var (n, k, result) = data;
|
||||
|
||||
Assert.That(MathHelper.BinomialCoefficient(n, k), Is.EqualTo(result));
|
||||
}
|
||||
|
||||
public static IEnumerable<(double deg, double rad)> DegreesToRadiansData = new (double, double)[] {
|
||||
(0, 0),
|
||||
(1, 0.017453292519943295),
|
||||
(57.295779513082323, 1),
|
||||
(45, 0.78539816339744828),
|
||||
(60, 1.0471975511965976),
|
||||
(90, 1.5707963267948966),
|
||||
(180, 3.1415926535897931),
|
||||
(270, 4.7123889803846897),
|
||||
(360, 6.2831853071795862)
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestDegreesToRadiansFloat([ValueSource(nameof(DegreesToRadiansData))] (double, double) data)
|
||||
{
|
||||
var (deg, rad) = data;
|
||||
|
||||
Assert.That(MathHelper.DegreesToRadians((float)deg), Is.EqualTo((float)rad).Within(0.0001f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRadiansToDegreesFloat([ValueSource(nameof(DegreesToRadiansData))] (double, double) data)
|
||||
{
|
||||
var (deg, rad) = data;
|
||||
|
||||
Assert.That(MathHelper.RadiansToDegrees((float)rad), Is.EqualTo((float)deg).Within(0.0001f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDegreesToRadiansDouble([ValueSource(nameof(DegreesToRadiansData))] (double, double) data)
|
||||
{
|
||||
var (deg, rad) = data;
|
||||
|
||||
Assert.That(MathHelper.DegreesToRadians(deg), Is.EqualTo(rad).Within(0.00000000001));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRadiansToDegreesDouble([ValueSource(nameof(DegreesToRadiansData))] (double, double) data)
|
||||
{
|
||||
var (deg, rad) = data;
|
||||
|
||||
Assert.That(MathHelper.RadiansToDegrees(rad), Is.EqualTo(deg).Within(0.00000000001));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSwapFloat()
|
||||
{
|
||||
const float a_original = MathHelper.Pi;
|
||||
const float b_original = MathHelper.PiOver2;
|
||||
|
||||
float a = a_original;
|
||||
float b = b_original;
|
||||
|
||||
MathHelper.Swap(ref a, ref b);
|
||||
|
||||
Assert.That(b, Is.EqualTo(a_original));
|
||||
Assert.That(a, Is.EqualTo(b_original));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSwapDouble()
|
||||
{
|
||||
const double a_original = MathHelper.Pi;
|
||||
const double b_original = MathHelper.PiOver2;
|
||||
|
||||
double a = a_original;
|
||||
double b = b_original;
|
||||
|
||||
MathHelper.Swap(ref a, ref b);
|
||||
|
||||
Assert.That(b, Is.EqualTo(a_original));
|
||||
Assert.That(a, Is.EqualTo(b_original));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMin()
|
||||
{
|
||||
Assert.That(MathHelper.Min(1f, 1f, 1f, 0f), Is.EqualTo(0f));
|
||||
Assert.That(MathHelper.Min(1f, 1f, 0f, 1f), Is.EqualTo(0f));
|
||||
Assert.That(MathHelper.Min(1f, 0f, 1f, 1f), Is.EqualTo(0f));
|
||||
Assert.That(MathHelper.Min(0f, 1f, 1f, 1f), Is.EqualTo(0f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMax()
|
||||
{
|
||||
Assert.That(MathHelper.Max(0f, 0f, 0f, 1f), Is.EqualTo(1f));
|
||||
Assert.That(MathHelper.Max(0f, 0f, 1f, 0f), Is.EqualTo(1f));
|
||||
Assert.That(MathHelper.Max(0f, 1f, 0f, 0f), Is.EqualTo(1f));
|
||||
Assert.That(MathHelper.Max(1f, 0f, 0f, 0f), Is.EqualTo(1f));
|
||||
}
|
||||
|
||||
public static IEnumerable<(int val, int mod, int result)> IntModData = new (int, int, int)[]
|
||||
{
|
||||
(-5, 5, 0),
|
||||
(-4, 5, 1),
|
||||
(-3, 5, 2),
|
||||
(-2, 5, 3),
|
||||
(-1, 5, 4),
|
||||
(0, 5, 0),
|
||||
(1, 5, 1),
|
||||
(2, 5, 2),
|
||||
(3, 5, 3),
|
||||
(4, 5, 4),
|
||||
(5, 5, 0),
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestIntMod([ValueSource(nameof(IntModData))] (int, int, int) data)
|
||||
{
|
||||
var (val, mod, result) = data;
|
||||
|
||||
Assert.That(MathHelper.Mod(val, mod), Is.EqualTo(result));
|
||||
}
|
||||
|
||||
public static IEnumerable<(double val, double mod, double result)> DoubleModData = new (double, double, double)[]
|
||||
{
|
||||
(-5.1, 5, 4.9),
|
||||
(-4.9, 5, 0.1),
|
||||
(-4.1, 5, 0.9),
|
||||
(-3.9, 5, 1.1),
|
||||
(-3.1, 5, 1.9),
|
||||
(-2.9, 5, 2.1),
|
||||
(-2.1, 5, 2.9),
|
||||
(-1.9, 5, 3.1),
|
||||
(-1.1, 5, 3.9),
|
||||
(-0.9, 5, 4.1),
|
||||
(-0.1, 5, 4.9),
|
||||
(0.0, 5, 0.0),
|
||||
(0.1, 5, 0.1),
|
||||
(0.9, 5, 0.9),
|
||||
(1.1, 5, 1.1),
|
||||
(1.9, 5, 1.9),
|
||||
(2.1, 5, 2.1),
|
||||
(2.9, 5, 2.9),
|
||||
(3.1, 5, 3.1),
|
||||
(3.9, 5, 3.9),
|
||||
(4.1, 5, 4.1),
|
||||
(4.9, 5, 4.9),
|
||||
(5.1, 5, 0.1),
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestDoubleMod([ValueSource(nameof(DoubleModData))] (double, double, double) data)
|
||||
{
|
||||
var (val, mod, result) = data;
|
||||
|
||||
Assert.That(MathHelper.Mod(val, mod), Is.EqualTo(result).Within(0.00000000001));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(4, 4, ExpectedResult = 4)]
|
||||
[TestCase(5, 4, ExpectedResult = 8)]
|
||||
[TestCase(7, 4, ExpectedResult = 8)]
|
||||
[TestCase(8, 4, ExpectedResult = 8)]
|
||||
[TestCase(4U, 4U, ExpectedResult = 4U)]
|
||||
[TestCase(5U, 4U, ExpectedResult = 8U)]
|
||||
[TestCase(7U, 4U, ExpectedResult = 8U)]
|
||||
[TestCase(8U, 4U, ExpectedResult = 8U)]
|
||||
[TestCase(4L, 4L, ExpectedResult = 4L)]
|
||||
[TestCase(5L, 4L, ExpectedResult = 8L)]
|
||||
[TestCase(7L, 4L, ExpectedResult = 8L)]
|
||||
[TestCase(8L, 4L, ExpectedResult = 8L)]
|
||||
public T TestCeilMultipleOfPowerOfTwo<T>(T value, T powerOfTwo) where T : IBinaryInteger<T>
|
||||
{
|
||||
return MathHelper.CeilMultipleOfPowerOfTwo(value, powerOfTwo);
|
||||
}
|
||||
}
|
||||
}
|
||||
86
Robust.Shared.Tests/Utility/NullableHelper_Test.cs
Normal file
86
Robust.Shared.Tests/Utility/NullableHelper_Test.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Tests.Utility
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(NullableHelper))]
|
||||
internal sealed class NullableHelper_Test
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
//initializing logmanager so it wont error out if nullablehelper logs an error
|
||||
var collection = new DependencyCollection();
|
||||
collection.Register<ILogManager, LogManager>();
|
||||
collection.BuildGraph();
|
||||
IoCManager.InitThread(collection, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsNullableTest()
|
||||
{
|
||||
var fields = typeof(NullableTestClass).GetAllFields();
|
||||
foreach (var field in fields)
|
||||
{
|
||||
Assert.That(NullableHelper.IsMarkedAsNullable((SpecificFieldInfo)field), Is.True, $"{field}");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NullableContextTest()
|
||||
{
|
||||
foreach (var field in typeof(NullableTestContextClass).GetAllFields())
|
||||
{
|
||||
Assert.That(NullableHelper.IsMarkedAsNullable((SpecificFieldInfo)field), Is.EqualTo(!field.FieldType.IsValueType), $"{field}");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsNotNullableTest()
|
||||
{
|
||||
var fields = typeof(NotNullableTestClass).GetAllFields();
|
||||
foreach (var field in fields)
|
||||
{
|
||||
Assert.That(!NullableHelper.IsMarkedAsNullable((SpecificFieldInfo)field), Is.True, $"{field}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable 169
|
||||
#pragma warning disable 414
|
||||
public sealed class NullableTestClass
|
||||
{
|
||||
private int? i;
|
||||
private double? d;
|
||||
public object? o;
|
||||
public INullableTestInterface? Itest;
|
||||
public NullableTestClass? nTc;
|
||||
private char? c;
|
||||
}
|
||||
|
||||
//this provokes the nullablecontext optimization
|
||||
public sealed class NullableTestContextClass
|
||||
{
|
||||
public INullableTestInterface? Itest;
|
||||
public NullableTestClass? nTc;
|
||||
public object? o;
|
||||
private int i;
|
||||
}
|
||||
|
||||
public sealed class NotNullableTestClass
|
||||
{
|
||||
private int i;
|
||||
private double d;
|
||||
private object o = null!;
|
||||
private INullableTestInterface Itest = null!;
|
||||
private NullableTestClass nTc = null!;
|
||||
private char c;
|
||||
}
|
||||
#pragma warning restore 414
|
||||
#pragma warning restore 169
|
||||
|
||||
public interface INullableTestInterface{}
|
||||
}
|
||||
31
Robust.Shared.Tests/Utility/PrettyPrint_Test.cs
Normal file
31
Robust.Shared.Tests/Utility/PrettyPrint_Test.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Robust.Shared.TestPrettyPrint;
|
||||
|
||||
public sealed class Foo
|
||||
{
|
||||
override public string ToString() { return "ACustomFooRep"; }
|
||||
}
|
||||
|
||||
public sealed class Bar {}
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable(ParallelScope.Fixtures | ParallelScope.All)]
|
||||
[TestOf(typeof(PrettyPrint))]
|
||||
internal sealed class PrettyPrint_Test
|
||||
{
|
||||
private static IEnumerable<(object val, string expectedRep, string expectedTypeRep)> TestCases { get; } = new (object, string, string)[]
|
||||
{
|
||||
(new Foo(), "ACustomFooRep", "R.Sh.TestPrettyPrint.Foo"),
|
||||
(new Robust.Shared.TestPrettyPrint.Bar(), "R.Sh.TestPrettyPrint.Bar", ""),
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void Test([ValueSource(nameof(TestCases))] (object value, string expectedRep, string expectedTypeRep) data)
|
||||
{
|
||||
Assert.That(PrettyPrint.PrintUserFacingWithType(data.value, out var typeRep), Is.EqualTo(data.expectedRep));
|
||||
Assert.That(typeRep, Is.EqualTo(data.expectedTypeRep));
|
||||
}
|
||||
}
|
||||
247
Robust.Shared.Tests/Utility/ResPathTest.cs
Normal file
247
Robust.Shared.Tests/Utility/ResPathTest.cs
Normal file
@@ -0,0 +1,247 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Tests.Utility;
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable(ParallelScope.Fixtures | ParallelScope.All)]
|
||||
[TestOf(typeof(ResPath))]
|
||||
internal sealed class ResPathTest
|
||||
{
|
||||
[Test]
|
||||
[TestCase("foo", ExpectedResult = "")]
|
||||
[TestCase("foo.png", ExpectedResult = "png")]
|
||||
[TestCase("test/foo.png", ExpectedResult = "png")]
|
||||
[TestCase("..png", ExpectedResult = "png")]
|
||||
[TestCase(".bashrc", ExpectedResult = "")]
|
||||
[TestCase("x.y.z", ExpectedResult = "z")]
|
||||
public string ExtensionTest(string input)
|
||||
{
|
||||
var resPathExt = new ResPath(input).Extension;
|
||||
var resourceExt = new ResPath(input).Extension;
|
||||
Assert.That(resPathExt, Is.EqualTo(resourceExt),
|
||||
message: "Found discrepancy between ResPath and ResourcePath Extension");
|
||||
return resPathExt;
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", ExpectedResult = ".")]
|
||||
[TestCase(".", ExpectedResult = ".")]
|
||||
[TestCase("foo", ExpectedResult = "foo")]
|
||||
[TestCase("foo.png", ExpectedResult = "foo.png")]
|
||||
[TestCase("test/foo.png", ExpectedResult = "foo.png")]
|
||||
[TestCase("derp/.bashrc", ExpectedResult = ".bashrc")]
|
||||
[TestCase("..png", ExpectedResult = "..png")]
|
||||
[TestCase("x/y/z", ExpectedResult = "z")]
|
||||
[TestCase("/bar", ExpectedResult = "bar")]
|
||||
[TestCase("bar/", ExpectedResult = "bar")] // Trailing / gets trimmed.
|
||||
[TestCase("/foo/bar/", ExpectedResult = "bar")]
|
||||
// These next two tests are the current behaviour. I don't know if this is how it should behave, these tests just
|
||||
// ensure that it doesn't change unintentionally
|
||||
[TestCase("/foo/bar//", ExpectedResult = "")]
|
||||
[TestCase("/foo/bar///", ExpectedResult = "")]
|
||||
public string FilenameTest(string input)
|
||||
{
|
||||
var resPathFilename = new ResPath(input).Filename;
|
||||
return resPathFilename;
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(@"", ExpectedResult = @".")]
|
||||
[TestCase(@".", ExpectedResult = @".")]
|
||||
[TestCase(@"foo", ExpectedResult = @"foo")]
|
||||
[TestCase(@"foo.png", ExpectedResult = @"foo")]
|
||||
[TestCase(@"test/foo.png", ExpectedResult = @"foo")]
|
||||
[TestCase(@"derp/.bashrc", ExpectedResult = @".bashrc")]
|
||||
[TestCase(@"..png", ExpectedResult = @".")]
|
||||
[TestCase(@"x.y.z", ExpectedResult = @"x.y")]
|
||||
public string FilenameWithoutExtension(string input)
|
||||
{
|
||||
var resPathFileNoExt = new ResPath(input).FilenameWithoutExtension;
|
||||
return resPathFileNoExt;
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(@"", ExpectedResult = @".")]
|
||||
[TestCase(@".", ExpectedResult = @".")]
|
||||
[TestCase(@"/foo/bar", ExpectedResult = @"/foo")]
|
||||
[TestCase(@"/foo/bar/", ExpectedResult = @"/foo")]
|
||||
[TestCase(@"/foo/bar/x", ExpectedResult = @"/foo/bar")]
|
||||
[TestCase(@"/foo/bar.txt", ExpectedResult = @"/foo")]
|
||||
[TestCase(@"/bar.txt", ExpectedResult = @"/")]
|
||||
// These next three tests are the current behaviour. I don't know if this is how it should behave, these tests just
|
||||
// ensure that it doesn't change unintentionally
|
||||
[TestCase(@"/foo/bar//", ExpectedResult = "/foo/bar")]
|
||||
[TestCase(@"/foo/bar///", ExpectedResult = "/foo/bar/")]
|
||||
[TestCase(@"/foo/bar////", ExpectedResult = "/foo/bar//")]
|
||||
public string DirectoryTest(string path)
|
||||
{
|
||||
var resPathDirectory = new ResPath(path).Directory.ToString();
|
||||
return resPathDirectory;
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(@"a/b/c", "\\", ExpectedResult = @"a\b\c")]
|
||||
[TestCase(@"/a/b/c", "\\", ExpectedResult = @"\a\b\c")]
|
||||
public string ChangeSeparatorTest(string input, string separator)
|
||||
{
|
||||
return new ResPath(input).ChangeSeparator(separator);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(@"a.b.c", ".")]
|
||||
[TestCase("\0a\0b\0c", "\0")]
|
||||
public void ChangeSeparatorTestException(string input, string separator)
|
||||
{
|
||||
Assert.Catch(typeof(ArgumentException), () => {new ResPath(input).ChangeSeparator(separator); });
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("/a/b", "c/d.png", ExpectedResult = "/a/b/c/d.png")]
|
||||
[TestCase("/a/b", "z", ExpectedResult = "/a/b/z")]
|
||||
[TestCase("/a/b", "/z", ExpectedResult = "/z")]
|
||||
[TestCase("/a/b", ".", ExpectedResult = "/a/b")]
|
||||
[TestCase("/", "/a", ExpectedResult = "/a")]
|
||||
[TestCase("/", "a", ExpectedResult = "/a")]
|
||||
public string CombineTest(string left, string right)
|
||||
{
|
||||
var pathDivRes = new ResPath(left) / new ResPath(right);
|
||||
var pathDivStr = new ResPath(left) / right;
|
||||
Assert.That(pathDivRes, Is.EqualTo(pathDivStr));
|
||||
return pathDivRes.ToString();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RootedConversionsTest()
|
||||
{
|
||||
var path = new ResPath("/a/b");
|
||||
Assert.That(path.IsRooted);
|
||||
Assert.That(path.ToRootedPath(), Is.EqualTo(path));
|
||||
|
||||
var relative = path.ToRelativePath();
|
||||
Assert.That(relative, Is.EqualTo( new ResPath("a/b")));
|
||||
Assert.That(relative.IsRelative);
|
||||
|
||||
Assert.That(relative.ToRelativePath(), Is.EqualTo(relative));
|
||||
Assert.That(relative.ToRootedPath(), Is.EqualTo(path));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("/a/b", "/a", ExpectedResult = "b")]
|
||||
[TestCase("/a", "/", ExpectedResult = "a")]
|
||||
[TestCase("/a/b/c", "/", ExpectedResult = "a/b/c")]
|
||||
[TestCase("/a", "/a", ExpectedResult = ".")]
|
||||
[TestCase("a/b", "a", ExpectedResult = "b")]
|
||||
[TestCase("/bar/", "/", ExpectedResult = "bar")]
|
||||
[TestCase("/Textures/Weapons/laser.png", "/Textures/", ExpectedResult = "Weapons/laser.png")]
|
||||
[TestCase("foo.txt", ".", ExpectedResult = "foo.txt")]
|
||||
public string RelativeToTest(string source, string baseDir)
|
||||
{
|
||||
var path = new ResPath(source);
|
||||
var basePath = new ResPath(baseDir);
|
||||
return path.RelativeTo(basePath).ToString();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("/a/b", "/b", false)]
|
||||
[TestCase("/a", "/c/d", false)]
|
||||
[TestCase("/a/b", "/a/d", false)]
|
||||
[TestCase(".", "/", false)]
|
||||
[TestCase("/", ".", false)]
|
||||
public void RelativeToFailTest(string left, string right, bool isRelative)
|
||||
{
|
||||
var path = new ResPath(left);
|
||||
var basePath = new ResPath(right);
|
||||
Assert.That(() => path.RelativeTo(basePath), Throws.ArgumentException);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithNameTest()
|
||||
{
|
||||
var path = new ResPath("/a/b");
|
||||
var modified = path.WithName("foo");
|
||||
Assert.That(modified.Filename, Is.EqualTo("foo"));
|
||||
modified = path.WithName("foo.exe");
|
||||
Assert.That(modified.Filename, Is.EqualTo("foo.exe"));
|
||||
Assert.That(modified.Extension, Is.EqualTo("exe"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WithNameExceptionTest()
|
||||
{
|
||||
ResPath path = new("/a/b");
|
||||
Assert.That(() => path.WithName("/foo"), Throws.ArgumentException);
|
||||
Assert.That(() => path.WithName("."), Throws.ArgumentException);
|
||||
Assert.That(() => path.WithName(""), Throws.ArgumentException);
|
||||
Assert.That(() => path.WithName(null!), Throws.ArgumentException);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("/a/b.txt", "png", "/a/b.png")]
|
||||
[TestCase("/a/b.txt.bak", "png", "/a/b.txt.png")]
|
||||
public void WithExtensionTest(string start, string newExt, string expected)
|
||||
{
|
||||
var startPath = new ResPath(start);
|
||||
Assert.That(startPath.WithExtension(newExt).ToString(), Is.EqualTo(expected));
|
||||
Assert.That(startPath.WithExtension(newExt).ToString(), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("/.gitignore")]
|
||||
[TestCase("")]
|
||||
[TestCase("/")]
|
||||
[TestCase("")]
|
||||
public void WithExtensionExceptionTest(string ext)
|
||||
{
|
||||
var resPath = new ResPath("/a/b");
|
||||
Assert.Catch(typeof(ArgumentException), () => { resPath.WithExtension(ext); });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RootToRelativeTest()
|
||||
{
|
||||
var path = new ResPath("/");
|
||||
|
||||
Assert.That(path.ToRelativePath(), Is.EqualTo(new ResPath(".")));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmptyEdgeCases()
|
||||
{
|
||||
ResPath? empty = ResPath.Empty;
|
||||
Assert.That(empty?.Extension, Is.EqualTo(""));
|
||||
Assert.That(empty?.Filename, Is.EqualTo("."));
|
||||
Assert.That(empty?.FilenameWithoutExtension, Is.EqualTo("."));
|
||||
Assert.That(empty.Equals(null), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("a", "a", ExpectedResult = true)]
|
||||
[TestCase("a", "ab", ExpectedResult = false)]
|
||||
[TestCase("", "", ExpectedResult = true)]
|
||||
[TestCase("", ".", ExpectedResult = false)]
|
||||
[TestCase(".", "", ExpectedResult = false)]
|
||||
[TestCase("/bin", "/usr", ExpectedResult = false)]
|
||||
public bool TestHashAndEquals(string left, string right)
|
||||
{
|
||||
var pathA = new ResPath(left);
|
||||
var pathB = new ResPath(right);
|
||||
Assert.That(pathA.GetHashCode() == pathB.GetHashCode(), Is.EqualTo(pathA == pathB));
|
||||
Assert.That(pathA.GetHashCode() != pathB.GetHashCode(), Is.EqualTo(pathA != pathB));
|
||||
return pathA == pathB;
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(@"\a\b\c", "/a/b/c")]
|
||||
[TestCase(@"\a\c", "/a/c")]
|
||||
[TestCase(@".", ".")]
|
||||
public void TestRelativeSystemPaths(string systemIn, string canonStr)
|
||||
{
|
||||
// Prevents frivolous warning, will lead to test having OS specific fails
|
||||
// ReSharper disable once RedundantArgumentDefaultValue
|
||||
var systemPath = ResPath.FromRelativeSystemPath(systemIn, '\\');
|
||||
var canonPath = new ResPath(canonStr);
|
||||
Assert.That(systemPath, Is.EqualTo(canonPath));
|
||||
Assert.That(systemPath.ToRelativeSystemPath(), Is.EqualTo(canonPath.ToRelativeSystemPath()));
|
||||
}
|
||||
}
|
||||
144
Robust.Shared.Tests/Utility/TextRope_Test.cs
Normal file
144
Robust.Shared.Tests/Utility/TextRope_Test.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Tests.Utility;
|
||||
|
||||
[TestFixture]
|
||||
[TestOf(typeof(Rope))]
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
internal static class TextRope_Test
|
||||
{
|
||||
[Test]
|
||||
public static void TestCalcWeight()
|
||||
{
|
||||
// Just using the example from Wikipedia:
|
||||
// https://commons.wikimedia.org/wiki/File:Vector_Rope_example.svg
|
||||
|
||||
BuildExample(out var tree);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(tree.NodeN.Weight, Is.EqualTo(6));
|
||||
Assert.That(tree.NodeM.Weight, Is.EqualTo(1));
|
||||
Assert.That(tree.NodeK.Weight, Is.EqualTo(4));
|
||||
Assert.That(tree.NodeJ.Weight, Is.EqualTo(2));
|
||||
Assert.That(tree.NodeF.Weight, Is.EqualTo(3));
|
||||
Assert.That(tree.NodeE.Weight, Is.EqualTo(6));
|
||||
|
||||
Assert.That(tree.NodeH.Weight, Is.EqualTo(1));
|
||||
Assert.That(tree.NodeG.Weight, Is.EqualTo(2));
|
||||
|
||||
Assert.That(tree.NodeC.Weight, Is.EqualTo(6));
|
||||
Assert.That(tree.NodeD.Weight, Is.EqualTo(6));
|
||||
|
||||
Assert.That(tree.NodeB.Weight, Is.EqualTo(9));
|
||||
|
||||
Assert.That(tree.NodeA.Weight, Is.EqualTo(22));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestCollect()
|
||||
{
|
||||
var tree = BuildExample(out _);
|
||||
var leaves = Rope.CollectLeaves(tree).Select(x => x.Text).ToArray();
|
||||
|
||||
Assert.That(leaves, Is.EquivalentTo(new[]
|
||||
{
|
||||
"Hello ", "my ", "na", "me i", "s", " Simon"
|
||||
}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestCollectReverse()
|
||||
{
|
||||
var tree = BuildExample(out _);
|
||||
var leaves = Rope.CollectLeavesReverse(tree).Select(x => x.Text).ToArray();
|
||||
|
||||
Assert.That(leaves, Is.EquivalentTo(new[]
|
||||
{
|
||||
"Hello ", "my ", "na", "me i", "s", " Simon"
|
||||
}.Reverse()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestCollapse()
|
||||
{
|
||||
var tree = BuildExample(out _);
|
||||
|
||||
Assert.That(Rope.Collapse(tree), Is.EqualTo("Hello my name is Simon"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestSplit()
|
||||
{
|
||||
var tree = BuildExample(out _);
|
||||
var (left, right) = Rope.Split(tree, 7);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(Rope.Collapse(left), Is.EqualTo("Hello m"));
|
||||
Assert.That(Rope.Collapse(right), Is.EqualTo("y name is Simon"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestDelete()
|
||||
{
|
||||
var tree = BuildExample(out _);
|
||||
|
||||
tree = Rope.Delete(tree, 2, 11);
|
||||
Assert.That(Rope.Collapse(tree), Is.EqualTo("He is Simon"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestEnumerateRunesReverseSub()
|
||||
{
|
||||
var tree = BuildExample(out _);
|
||||
|
||||
var runes = Rope.EnumerateRunesReverse(tree, 10);
|
||||
Assert.That(
|
||||
runes,
|
||||
Is.EquivalentTo("Hello my n".EnumerateRunes().Reverse()));
|
||||
}
|
||||
|
||||
private static Rope.Node BuildExample(out ExampleTree tree)
|
||||
{
|
||||
tree = default;
|
||||
|
||||
tree.NodeN = new Rope.Leaf(" Simon");
|
||||
tree.NodeM = new Rope.Leaf("s");
|
||||
tree.NodeK = new Rope.Leaf("me i");
|
||||
tree.NodeJ = new Rope.Leaf("na");
|
||||
tree.NodeF = new Rope.Leaf("my ");
|
||||
tree.NodeE = new Rope.Leaf("Hello ");
|
||||
|
||||
tree.NodeH = new Rope.Branch(tree.NodeM, tree.NodeN);
|
||||
tree.NodeG = new Rope.Branch(tree.NodeJ, tree.NodeK);
|
||||
|
||||
tree.NodeC = new Rope.Branch(tree.NodeE, tree.NodeF);
|
||||
tree.NodeD = new Rope.Branch(tree.NodeG, tree.NodeH);
|
||||
|
||||
tree.NodeB = new Rope.Branch(tree.NodeC, tree.NodeD);
|
||||
|
||||
tree.NodeA = new Rope.Branch(tree.NodeB, null);
|
||||
|
||||
return tree.NodeA;
|
||||
}
|
||||
|
||||
public struct ExampleTree
|
||||
{
|
||||
public Rope.Node NodeN;
|
||||
public Rope.Node NodeM;
|
||||
public Rope.Node NodeK;
|
||||
public Rope.Node NodeJ;
|
||||
public Rope.Node NodeF;
|
||||
public Rope.Node NodeE;
|
||||
public Rope.Node NodeH;
|
||||
public Rope.Node NodeG;
|
||||
public Rope.Node NodeC;
|
||||
public Rope.Node NodeD;
|
||||
public Rope.Node NodeB;
|
||||
public Rope.Node NodeA;
|
||||
}
|
||||
}
|
||||
46
Robust.Shared.Tests/Utility/TypeAbbreviations_Test.cs
Normal file
46
Robust.Shared.Tests/Utility/TypeAbbreviations_Test.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Robust.Shared.TestTypeAbbreviation;
|
||||
|
||||
public sealed class Foo<T> {}
|
||||
|
||||
public sealed class Bar {}
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable(ParallelScope.Fixtures | ParallelScope.All)]
|
||||
[TestOf(typeof(TypeAbbreviation))]
|
||||
public sealed class TypeAbbreviations_Test
|
||||
{
|
||||
private static IEnumerable<(string name, string expected)> NameTestCases { get; } = new[]
|
||||
{
|
||||
("Robust.Shared.GameObjects.Foo", "R.Sh.GO.Foo"),
|
||||
("Robust.Client.GameObjects.Foo", "R.C.GO.Foo"),
|
||||
("Content.Client.GameObjects.Foo", "C.C.GO.Foo"),
|
||||
("Robust.Shared.Maths.Vector2", "R.Sh.M.Vector2"),
|
||||
("System.Collections.Generic.List", "S.C.G.List"),
|
||||
("System.Math", "S.Math"),
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void Test([ValueSource(nameof(NameTestCases))] (string name, string expected) data)
|
||||
{
|
||||
Assert.That(TypeAbbreviation.Abbreviate(data.name), Is.EqualTo(data.expected));
|
||||
}
|
||||
|
||||
|
||||
private static IEnumerable<(Type type, string expected)> TypeTestCases { get; } = new[]
|
||||
{
|
||||
( typeof(Robust.Shared.TestTypeAbbreviation.Foo<Robust.Shared.TestTypeAbbreviation.Bar>)
|
||||
, "R.Sh.TestTypeAbbreviation.Foo`1[R.Sh.TestTypeAbbreviation.Bar]"
|
||||
),
|
||||
(typeof(Robust.Shared.TestTypeAbbreviation.Bar), "R.Sh.TestTypeAbbreviation.Bar"),
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void Test([ValueSource(nameof(TypeTestCases))] (Type type, string expected) data)
|
||||
{
|
||||
Assert.That(TypeAbbreviation.Abbreviate(data.type), Is.EqualTo(data.expected));
|
||||
}
|
||||
}
|
||||
47
Robust.Shared.Tests/Utility/TypeHelpers_Test.cs
Normal file
47
Robust.Shared.Tests/Utility/TypeHelpers_Test.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Tests.Utility
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(TypeHelpers))]
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
||||
public sealed class TypeHelpers_Test
|
||||
{
|
||||
[Test]
|
||||
public void TestIsBasePropertyDefinition()
|
||||
{
|
||||
// Easy, the definition of the virtual property.
|
||||
Assert.That(typeof(Parent).GetProperty("X")!.IsBasePropertyDefinition(), Is.True);
|
||||
Assert.That(typeof(Child).GetProperty("X")!.IsBasePropertyDefinition(), Is.False);
|
||||
Assert.That(typeof(SealedChild).GetProperty("X")!.IsBasePropertyDefinition(), Is.False);
|
||||
Assert.That(typeof(Hidden).GetProperty("X")!.IsBasePropertyDefinition(), Is.True);
|
||||
}
|
||||
|
||||
[Virtual]
|
||||
private class Parent
|
||||
{
|
||||
public virtual int X => 0;
|
||||
}
|
||||
|
||||
[Virtual]
|
||||
private class Child : Parent
|
||||
{
|
||||
public override int X => 5;
|
||||
}
|
||||
|
||||
[Virtual]
|
||||
private class SealedChild : Parent
|
||||
{
|
||||
public sealed override int X => 6;
|
||||
}
|
||||
|
||||
[Virtual]
|
||||
private class Hidden : Parent
|
||||
{
|
||||
public new int X { get; } = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Robust.Shared.Tests/Utility/YamlHelpers_Test.cs
Normal file
25
Robust.Shared.Tests/Utility/YamlHelpers_Test.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Globalization;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Robust.Shared.Tests.Utility
|
||||
{
|
||||
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
|
||||
[TestFixture]
|
||||
public sealed class YamlHelpers_Test
|
||||
{
|
||||
[Test]
|
||||
[SetCulture("fr-FR")]
|
||||
public void Test_CultureInvariance()
|
||||
{
|
||||
// Make sure that we're on a locale in which the decimals would be messed up.
|
||||
// French is one but I'd rather have false negatives than false positives.
|
||||
Assert.That(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator, Is.EqualTo(","));
|
||||
Assert.That(float.Parse("10,5"), Is.EqualTo(10.5f));
|
||||
Assert.That(() => float.Parse("10.5"), Throws.InstanceOf<FormatException>());
|
||||
|
||||
Assert.That(new YamlScalarNode("10.5").AsFloat(), Is.EqualTo(10.5f));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user