first commit

This commit is contained in:
2025-07-06 00:23:46 +02:00
commit 38f50c8819
1788 changed files with 112878 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace NitroxModel.DataStructures;
[TestClass]
public class CircularBufferTest
{
[TestMethod]
public void ShouldLimitSizeToMaxSize()
{
CircularBuffer<string> buffer = new(1);
buffer.Count.Should().Be(0);
buffer.Add("1");
buffer.Count.Should().Be(1);
buffer.Add("2");
buffer.Count.Should().Be(1);
buffer = new CircularBuffer<string>(5);
buffer.Count.Should().Be(0);
buffer.Add("1");
buffer.Count.Should().Be(1);
buffer.Add("2");
buffer.Count.Should().Be(2);
buffer.Add("3");
buffer.Count.Should().Be(3);
buffer.Add("4");
buffer.Count.Should().Be(4);
buffer.Add("5");
buffer.Count.Should().Be(5);
buffer.Add("6");
buffer.Count.Should().Be(5);
}
[TestMethod]
public void ShouldOverwriteOldestItemInBufferWhenCapped()
{
CircularBuffer<string> buffer = new(3);
buffer.Add("1");
buffer[0].Should().Be("1");
buffer.Add("2");
buffer[1].Should().Be("2");
buffer.Add("3");
buffer[2].Should().Be("3");
buffer.Add("4");
buffer[0].Should().Be("4");
buffer.Add("5");
buffer[1].Should().Be("5");
buffer[2].Should().Be("3");
buffer.Add("6");
buffer[2].Should().Be("6");
buffer.Add("7");
buffer.Should().ContainInOrder("7", "5", "6");
}
[TestMethod]
public void ShouldDiscardAddIfCapacityReached()
{
CircularBuffer<string> buffer = new(0);
buffer.Count.Should().Be(0);
buffer.Add("1");
buffer.Count.Should().Be(0);
}
[TestMethod]
public void ShouldBeEmptyWhenCleared()
{
CircularBuffer<string> buffer = new(10);
buffer.Count.Should().Be(0);
buffer.Add("1");
buffer.Add("1");
buffer.Add("1");
buffer.Count.Should().Be(3);
buffer.Clear();
buffer.Count.Should().Be(0);
}
[TestMethod]
public void ShouldGiveLastChanged()
{
CircularBuffer<int> buffer = new(3);
buffer.LastChangedIndex.Should().Be(-1);
buffer.Add(1);
buffer.LastChangedIndex.Should().Be(0);
buffer.Add(2);
buffer.LastChangedIndex.Should().Be(1);
buffer.Add(3);
buffer.LastChangedIndex.Should().Be(2);
buffer.Add(4);
buffer.LastChangedIndex.Should().Be(0);
buffer.Add(5);
buffer.LastChangedIndex.Should().Be(1);
buffer.Add(6);
buffer.LastChangedIndex.Should().Be(2);
buffer.Add(7);
buffer.LastChangedIndex.Should().Be(0);
buffer.Add(8);
buffer.LastChangedIndex.Should().Be(1);
buffer.Clear();
buffer.LastChangedIndex.Should().Be(-1);
}
[TestMethod]
public void ShouldReverseOrderWithNegativeIndex()
{
CircularBuffer<int> buffer = new(6);
buffer.AddRange(1, 2, 3, 4, 5, 6);
buffer[-1].Should().Be(6);
buffer[-2].Should().Be(5);
buffer[-3].Should().Be(4);
buffer[-4].Should().Be(3);
buffer[-5].Should().Be(2);
buffer[-6].Should().Be(1);
buffer[-7].Should().Be(6);
buffer[-8].Should().Be(5);
}
}

View File

@@ -0,0 +1,45 @@
using System;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace NitroxModel.DataStructures;
[TestClass]
public class NitroxIdTest
{
private NitroxId id1;
private NitroxId id2;
[TestMethod]
public void SameGuidEquality()
{
Guid guid = Guid.NewGuid();
id1 = new(guid);
id2 = new(guid);
(id1 == id2).Should().BeTrue();
id1.Equals(id2).Should().BeTrue();
(id1 != id2).Should().BeFalse();
(!id1.Equals(id2)).Should().BeFalse();
}
[TestMethod]
public void NullGuidEquality()
{
id1 = new();
id2 = null;
(id1 == id2).Should().BeFalse();
id1.Equals(id2).Should().BeFalse();
(id1 != id2).Should().BeTrue();
(!id1.Equals(id2)).Should().BeTrue();
}
[TestMethod]
public void BothNullEquality()
{
id1 = id2 = null;
(id1 != id2).Should().BeFalse();
(id1 == id2).Should().BeTrue();
}
}

View File

@@ -0,0 +1,39 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace NitroxModel.DataStructures
{
[TestClass]
public class NitroxInt3Test
{
private NitroxInt3 int3;
[TestInitialize]
public void Setup()
{
int3 = new NitroxInt3(5, 10, 15);
}
[TestMethod]
public void Equals()
{
NitroxInt3 other1 = new NitroxInt3(5, 10, 15);
NitroxInt3 other2 = new NitroxInt3(15, 10, 5);
int3.Equals(other1).Should().BeTrue();
int3.Equals(other2).Should().BeFalse();
}
[TestMethod]
public void Floor()
{
NitroxInt3.Floor(5.1f, 10.4f, 15.5f).Should().Be(int3);
}
[TestMethod]
public void Ceil()
{
NitroxInt3.Ceil(4.1f, 9.4f, 14.5f).Should().Be(int3);
}
}
}

View File

@@ -0,0 +1,29 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace NitroxModel.DataStructures;
[TestClass]
public class NitroxVersionTest
{
[TestMethod]
public void Equals()
{
NitroxVersion a = new(2, 1);
NitroxVersion b = new(1, 15);
NitroxVersion source = new(2, 1);
source.Equals(a).Should().BeTrue();
source.Equals(b).Should().BeFalse();
}
[TestMethod]
public void Compare()
{
NitroxVersion source = new(2, 1);
source.CompareTo(new(2, 1)).Should().Be(0);
source.CompareTo(new(1, 15)).Should().Be(1);
source.CompareTo(new (2, 2)).Should().Be(-1);
source.CompareTo(new (3, 1)).Should().Be(-1);
}
}

View File

@@ -0,0 +1,78 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace NitroxModel.DataStructures
{
using StringPriorityQueue = PriorityQueue<string>;
[TestClass]
public class PriorityQueueTest
{
[TestMethod]
public void SameOrder()
{
StringPriorityQueue queue = new StringPriorityQueue();
queue.Enqueue(0, "First");
queue.Enqueue(0, "Second");
queue.Enqueue(0, "Third");
Assert.AreEqual("First", queue.Dequeue());
Assert.AreEqual("Second", queue.Dequeue());
Assert.AreEqual("Third", queue.Dequeue());
}
[TestMethod]
public void DifferentOrder()
{
StringPriorityQueue queue = new StringPriorityQueue();
queue.Enqueue(3, "First");
queue.Enqueue(2, "Second");
queue.Enqueue(1, "Third");
Assert.AreEqual("First", queue.Dequeue());
Assert.AreEqual("Second", queue.Dequeue());
Assert.AreEqual("Third", queue.Dequeue());
}
[TestMethod]
public void SomeAreSameOrder()
{
StringPriorityQueue queue = new StringPriorityQueue();
queue.Enqueue(2, "First");
queue.Enqueue(2, "Second");
queue.Enqueue(0, "Third");
Assert.AreEqual("First", queue.Dequeue());
Assert.AreEqual("Second", queue.Dequeue());
Assert.AreEqual("Third", queue.Dequeue());
}
[TestMethod]
public void PrioritySanity()
{
StringPriorityQueue queue = new StringPriorityQueue();
queue.Enqueue(2, "Second");
queue.Enqueue(3, "First");
queue.Enqueue(1, "Third");
Assert.AreEqual("First", queue.Dequeue());
Assert.AreEqual("Second", queue.Dequeue());
Assert.AreEqual("Third", queue.Dequeue());
}
[TestMethod]
public void CountSanity()
{
StringPriorityQueue queue = new StringPriorityQueue();
queue.Enqueue(2, "Second");
queue.Enqueue(3, "First");
queue.Enqueue(1, "Third");
Assert.AreEqual(3, queue.Count);
queue.Dequeue();
queue.Dequeue();
Assert.AreEqual(1, queue.Count);
}
}
}

View File

@@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace NitroxModel.DataStructures
{
[TestClass]
public class ThreadSafeListTest
{
private ThreadSafeList<string> list;
[TestInitialize]
public void Setup()
{
list = new ThreadSafeList<string>();
for (int i = 0; i < 10; i++)
{
list.Add($"test {i}");
}
}
[TestMethod]
public void Insert()
{
list.Insert(5, "derp");
list[5].Should().Be("derp");
list[0] = "Hello world!";
list[0].Should().Be("Hello world!");
}
[TestMethod]
public void RemoveAt()
{
list.RemoveAt(5);
foreach (string item in list)
{
item.Should().NotBe("test 5");
}
}
[TestMethod]
public void Remove()
{
list.Remove("test 0");
list[0].Should().Be("test 1");
}
[TestMethod]
public void Find()
{
list.Find(s => s == "test 1").Should().Be("test 1");
list.Find(s => s == "tesT 1").Should().BeNull();
list.Find(s => s == "test 1361").Should().BeNull();
}
[TestMethod]
public void ReadAndWriteSimultaneous()
{
int iterations = 500000;
ThreadSafeList<int> comeGetMe = new(iterations);
List<long> countsRead = new();
long addCount = 0;
Random r = new Random();
DoReaderWriter(() =>
{
countsRead.Add(Interlocked.Read(ref addCount));
},
i =>
{
comeGetMe.Add(r.Next());
Interlocked.Increment(ref addCount);
},
iterations);
addCount.Should().Be(iterations);
countsRead.Count.Should().BeGreaterThan(0);
countsRead.Last().Should().Be(iterations);
comeGetMe.Count.Should().Be(iterations);
}
[TestMethod]
public void IterateAndAddSimultaneous()
{
int iterations = 500000;
ThreadSafeList<int> comeGetMe = new(iterations);
long addCount = 0;
long iterationsReadMany = 0;
Random r = new Random();
DoReaderWriter(() =>
{
foreach (int unused in comeGetMe)
{
Interlocked.Increment(ref iterationsReadMany);
}
},
i =>
{
comeGetMe.Add(r.Next());
Interlocked.Increment(ref addCount);
},
iterations);
addCount.Should().Be(iterations);
iterationsReadMany.Should().BePositive();
}
[TestMethod]
public void IterateAndAdd()
{
ThreadSafeList<int> nums = new()
{
1,2,3,4,5
};
foreach (int num in nums)
{
if (num == 3)
{
nums.Add(10);
}
}
nums.Count.Should().Be(6);
nums.Last().Should().Be(10);
}
private void DoReaderWriter(Action reader, Action<int> writer, int iterators)
{
ManualResetEventSlim barrier = new(false);
Thread readerThread = new(() =>
{
while (!barrier.IsSet)
{
reader();
Thread.Yield();
}
// Read one last time after writer finishes
reader();
});
Thread writerThread = new(() =>
{
for (int i = 0; i < iterators; i++)
{
writer(i);
}
barrier.Set();
});
readerThread.Start();
writerThread.Start();
barrier.Wait();
}
}
}

View File

@@ -0,0 +1,56 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace NitroxModel.DataStructures
{
[TestClass]
public class ThreadSafeQueueTest
{
private ThreadSafeQueue<string> queue;
[TestInitialize]
public void Setup()
{
queue = new ThreadSafeQueue<string>();
for (int i = 0; i < 10; i++)
{
queue.Enqueue($"test {i}");
}
}
[TestMethod]
public void Peek()
{
queue.Peek().Should().Be("test 0");
}
[TestMethod]
public void Enqueue()
{
queue.Enqueue("derp");
queue.Count.Should().Be(11);
}
[TestMethod]
public void Dequeue()
{
queue.Dequeue().Should().Be("test 0");
queue.Count.Should().Be(9);
queue.Should().NotContain("test 0");
}
[TestMethod]
public void Clear()
{
queue.Clear();
queue.Count.Should().Be(0);
}
[TestMethod]
public void Contains()
{
queue.Contains("test 5").Should().BeTrue();
queue.Contains("test 11").Should().BeFalse();
}
}
}

View File

@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace NitroxModel.DataStructures
{
[TestClass]
public class ThreadSafeSetTest
{
private ThreadSafeSet<string> set;
[TestInitialize]
public void Setup()
{
set = new ThreadSafeSet<string>();
for (int i = 0; i < 10; i++)
{
set.Add($"test {i}");
}
}
[TestMethod]
public void Remove()
{
set.Should().Contain("test 0");
set.Remove("test 0");
set.Should().NotContain("test 0");
}
[TestMethod]
public void Contains()
{
set.Contains("test 1").Should().BeTrue();
}
[TestMethod]
public void Except()
{
string[] exclude = { "test 0", "test 5", "test 9" };
set.Should().Contain(exclude);
set.ExceptWith(exclude);
set.Should().NotContain(exclude);
}
[TestMethod]
public void ReadAndWriteSimultaneous()
{
int iterations = 500000;
ThreadSafeSet<string> comeGetMe = new();
List<long> countsRead = new();
long addCount = 0;
Random r = new Random();
DoReaderWriter(() =>
{
countsRead.Add(Interlocked.Read(ref addCount));
},
i =>
{
comeGetMe.Add(new string(Enumerable.Repeat(' ', 10).Select(c => (char)r.Next('A', 'Z')).ToArray()));
Interlocked.Increment(ref addCount);
},
iterations);
addCount.Should().Be(iterations);
countsRead.Count.Should().BeGreaterThan(0);
countsRead.Last().Should().Be(iterations);
comeGetMe.Count.Should().Be(iterations);
}
[TestMethod]
public void IterateAndAddSimultaneous()
{
int iterations = 500000;
ThreadSafeSet<int> comeGetMe = new();
long addCount = 0;
long iterationsReadMany = 0;
Random r = new();
DoReaderWriter(() =>
{
foreach (int item in comeGetMe)
{
Interlocked.Increment(ref iterationsReadMany);
}
},
i =>
{
comeGetMe.Add(r.Next());
Interlocked.Increment(ref addCount);
},
iterations);
addCount.Should().Be(iterations);
iterationsReadMany.Should().BePositive();
}
[TestMethod]
public void IterateAndAdd()
{
ThreadSafeSet<int> nums = new()
{
1,2,3,4,5
};
foreach (int num in nums)
{
if (num == 3)
{
nums.Add(10);
}
}
nums.Count.Should().Be(6);
nums.Last().Should().Be(10);
}
private void DoReaderWriter(Action reader, Action<int> writer, int iterators)
{
ManualResetEventSlim barrier = new(false);
Thread readerThread = new(() =>
{
while (!barrier.IsSet)
{
reader();
Thread.Yield();
}
// Read one last time after writer finishes
reader();
});
Thread writerThread = new(() =>
{
for (int i = 0; i < iterators; i++)
{
writer(i);
}
barrier.Set();
});
readerThread.Start();
writerThread.Start();
barrier.Wait();
}
}
}

View File

@@ -0,0 +1,77 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace NitroxModel.DataStructures.Unity
{
[TestClass]
public class NitroxQuaternionTest
{
private NitroxQuaternion defaultVal;
private const float TOLERANCE = 0.0001f;
[TestInitialize]
public void Init()
{
defaultVal = new NitroxQuaternion(0.5682333f, -0.01828304f, -0.5182831f, 0.6388735f);
}
[TestMethod]
public void TestEquality()
{
NitroxQuaternion other1 = new NitroxQuaternion(0.5682333f, -0.01828304f, -0.5182831f, 0.6388735f);
NitroxQuaternion other2 = new NitroxQuaternion(-0.5682333f, 0.01828304f, 0.5182831f, -0.6388735f);
NitroxQuaternion other3 = new NitroxQuaternion(0.5682343f, -0.01828314f, -0.5182841f, 0.6388745f);
defaultVal.Equals(other1, TOLERANCE).Should().BeTrue();
defaultVal.Equals(other2, TOLERANCE).Should().BeTrue();
defaultVal.Equals(other3, TOLERANCE).Should().BeTrue(); //Tolerance to low to detect the difference
(defaultVal == other1).Should().BeTrue();
(defaultVal == other2).Should().BeTrue();
(defaultVal != other3).Should().BeTrue();
}
[TestMethod]
public void TestMultiplication()
{
NitroxQuaternion result1 = defaultVal * new NitroxQuaternion(-10f, 0.5f, 0.004f, 256.1111f);
NitroxQuaternion result2 = new NitroxQuaternion(-10f, 0.5f, 0.004f, 256.1111f) * defaultVal;
NitroxQuaternion expectedResult1 = new NitroxQuaternion(139.4012f, 0.8175055f, -132.6342f, 169.3162f);
NitroxQuaternion expectedResult2 = new NitroxQuaternion(138.8831f, -9.543612f, -132.8368f, 169.3162f);
result1.Equals(expectedResult1, TOLERANCE).Should().BeTrue($"Expected: {expectedResult1} - Found: {result1}");
result2.Equals(expectedResult2, TOLERANCE).Should().BeTrue($"Expected: {expectedResult2} - Found: {result2}");
}
[TestMethod]
public void TestToEuler()
{
NitroxVector3 euler1 = defaultVal.ToEuler();
NitroxVector3 euler2 = new NitroxQuaternion(0.5f, 0.5f, -0.5f, 0.5f).ToEuler();
NitroxVector3 euler3 = new NitroxQuaternion(-0.5f, 0.5f, -0.5f, -0.5f).ToEuler();
NitroxVector3 expectedResult1 = new NitroxVector3(45f, 300f, 255f);
NitroxVector3 expectedResult1Other = new NitroxVector3(104.5108f, 50.75358f, 316.9205f); //defaultVal can be interpreted as both euler :shrug:
NitroxVector3 expectedResult2 = new NitroxVector3(90f, 90f, 0f);
NitroxVector3 expectedResult3 = new NitroxVector3(90f, 270f, 0f);
(euler1.Equals(expectedResult1, TOLERANCE) || euler1.Equals(expectedResult1Other, TOLERANCE)).Should().BeTrue($"Expected: {expectedResult1} or {expectedResult1Other}- Found: {euler1}");
euler2.Equals(expectedResult2, TOLERANCE).Should().BeTrue($"Expected: {expectedResult2} - Found: {euler2}");
euler3.Equals(expectedResult3, TOLERANCE).Should().BeTrue($"Expected: {expectedResult3} - Found: {euler3}");
}
[TestMethod]
public void TestFromEuler()
{
NitroxQuaternion result1 = NitroxQuaternion.FromEuler(new NitroxVector3(45f, 300f, 255f));
NitroxQuaternion result2 = NitroxQuaternion.FromEuler(new NitroxVector3(45f, -60f, 615f));
NitroxQuaternion result3 = NitroxQuaternion.FromEuler(new NitroxVector3(400f, 10f, -0.07f));
NitroxQuaternion result4 = NitroxQuaternion.FromEuler(new NitroxVector3(360f, 0f, -720));
NitroxQuaternion expectedResult3 = new NitroxQuaternion(-0.3406684f, -0.08210776f, 0.03038081f, -0.9360985f);
result1.Equals(defaultVal, TOLERANCE).Should().BeTrue($"Expected: {defaultVal} - Found: {result1}");
result2.Equals(defaultVal, TOLERANCE).Should().BeTrue($"Expected: {defaultVal} - Found: {result2}");
result3.Equals(expectedResult3, TOLERANCE).Should().BeTrue($"Expected: {expectedResult3} - Found: {result3}");
result4.Equals(NitroxQuaternion.Identity, TOLERANCE).Should().BeTrue($"Expected: {NitroxQuaternion.Identity} - Found: {result4}");
}
}
}

View File

@@ -0,0 +1,95 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace NitroxModel.DataStructures.Unity
{
[TestClass]
public class NitroxTransformTest
{
private const float TOLERANCE = 0.005f;
private static readonly NitroxTransform root = new NitroxTransform(new NitroxVector3(1, 1, 1), NitroxQuaternion.FromEuler(0, 0, 0), new NitroxVector3(1, 1, 1));
private static readonly NitroxTransform child1 = new NitroxTransform(new NitroxVector3(5, 3, -6), NitroxQuaternion.FromEuler(30, 0, 10), new NitroxVector3(2, 2, 2));
private static readonly NitroxTransform child2 = new NitroxTransform(new NitroxVector3(11, 0, -0.5f), NitroxQuaternion.FromEuler(180, 30, 80), new NitroxVector3(0.5f, 0.5f, 0.5f));
private static readonly NitroxTransform grandchild1 = new NitroxTransform(new NitroxVector3(13, 8, 15), NitroxQuaternion.FromEuler(-50, 5, 10), new NitroxVector3(1, 1, 1));
private static readonly NitroxTransform grandchild2 = new NitroxTransform(new NitroxVector3(3, 18, -5), NitroxQuaternion.FromEuler(-5, 15, 1), new NitroxVector3(10, 10, 10));
[ClassInitialize]
public static void Setup(TestContext testContext)
{
child1.SetParent(root, false);
child2.SetParent(root, false);
grandchild1.SetParent(child1, false);
grandchild2.SetParent(child2, false);
}
[TestMethod]
public void PositionTest()
{
NitroxVector3 rootResult = new NitroxVector3(1, 1, 1);
NitroxVector3 child1Result = new NitroxVector3(6, 4, -5);
NitroxVector3 child2Result = new NitroxVector3(12, 1, 0.5f);
NitroxVector3 grandchild1Result = new NitroxVector3(28.82663f, 6.55587f, 31.11665f);
NitroxVector3 grandchild2Result = new NitroxVector3(5.79976f, -2.040047f, 6.966463f);
root.Position.Equals(rootResult, TOLERANCE).Should().BeTrue($"Expected: {rootResult} Found: {root.Position}");
child1.Position.Equals(child1Result, TOLERANCE).Should().BeTrue($"Expected: {child1Result} Found: {child1.Position}");
child2.Position.Equals(child2Result, TOLERANCE).Should().BeTrue($"Expected: {child2Result} Found: {child2.Position}");
grandchild1.Position.Equals(grandchild1Result, TOLERANCE).Should().BeTrue($"Expected: {grandchild1Result} Found: {grandchild1.Position}");
grandchild2.Position.Equals(grandchild2Result, TOLERANCE).Should().BeTrue($"Expected: {grandchild2Result} Found: {grandchild2.Position}");
}
[TestMethod]
public void RotationTest()
{
NitroxQuaternion rootResult = NitroxQuaternion.FromEuler(0, 0, 0);
NitroxQuaternion child1Result = NitroxQuaternion.FromEuler(30, 0, 10);
NitroxQuaternion child2Result = NitroxQuaternion.FromEuler(8.537737e-07f, 210, 260);
NitroxQuaternion grandchild1Result = NitroxQuaternion.FromEuler(340.0263f, 355.2486f, 21.87437f);
NitroxQuaternion grandchild2Result = NitroxQuaternion.FromEuler(15.60783f, 212.4433f, 261.9936f);
root.Rotation.Equals(rootResult, TOLERANCE).Should().BeTrue($"Expected: {rootResult} Found: {root.Rotation}");
child1.Rotation.Equals(child1Result, TOLERANCE).Should().BeTrue($"Expected: {child1Result} Found: {child1.Rotation}");
child2.Rotation.Equals(child2Result, TOLERANCE).Should().BeTrue($"Expected: {child2Result} Found: {child2.Rotation}");
grandchild1.Rotation.Equals(grandchild1Result, TOLERANCE).Should().BeTrue($"Expected: {grandchild1Result} Found: {grandchild1.Rotation}");
grandchild2.Rotation.Equals(grandchild2Result, TOLERANCE).Should().BeTrue($"Expected: {grandchild2Result} Found: {grandchild2.Rotation}");
}
[TestMethod]
public void ChangingTransformTest()
{
NitroxVector3 beforeLocalPosition = new NitroxVector3(15, 2, -7);
NitroxQuaternion beforeRotation = NitroxQuaternion.FromEuler(45, 15, 1);
NitroxVector3 beforeChildLocalPosition = new NitroxVector3(75, -10, 13.333f);
NitroxQuaternion beforeChildRotation = NitroxQuaternion.FromEuler(75, 11, 5);
NitroxVector3 setGlobalPosition = new NitroxVector3(34.62131f, 45.99337f, -10.77733f);
NitroxQuaternion setGlobalRotation = new NitroxQuaternion(0.6743798f, 0.2302919f, 0.02638498f, 0.7010573f);
NitroxVector3 afterLocalPosition = new NitroxVector3(17, 14, -13);
NitroxQuaternion afterLocalRotation = NitroxQuaternion.FromEuler(60, 25, 0);
NitroxVector3 afterChildGlobalPosition = new NitroxVector3(379.541f, 109.6675f, -167.4466f);
NitroxQuaternion afterChildGlobalRotation = NitroxQuaternion.FromEuler(17.81689f, 187.7957f, 151.9425f);
NitroxTransform grandchild3 = new NitroxTransform(beforeLocalPosition, beforeRotation, new NitroxVector3(2.5f, 2.5f, 2.5f));
NitroxTransform grandgrandchild1 = new NitroxTransform(beforeChildLocalPosition, beforeChildRotation, new NitroxVector3(1, 1, 1));
grandgrandchild1.SetParent(grandchild3, false);
grandchild3.SetParent(child1, true);
grandchild3.Position.Equals(beforeLocalPosition, TOLERANCE).Should().BeTrue($"Expected: {beforeLocalPosition} Found: {grandchild3.Position}");
grandchild3.Rotation.Equals(beforeRotation, TOLERANCE).Should().BeTrue($"Expected: {beforeRotation} Found: {grandchild3.Rotation}");
grandchild3.Position = setGlobalPosition;
grandchild3.Rotation = setGlobalRotation;
grandchild3.LocalPosition.Equals(afterLocalPosition, TOLERANCE).Should().BeTrue($"Expected: {afterLocalPosition} Found: {grandchild3.LocalPosition}");
grandchild3.LocalRotation.Equals(afterLocalRotation, TOLERANCE).Should().BeTrue($"Expected: {afterLocalRotation} Found: {grandchild3.LocalRotation}");
grandgrandchild1.Position.Equals(afterChildGlobalPosition, TOLERANCE).Should().BeTrue($"Expected: {afterChildGlobalPosition} Found: {grandgrandchild1.Position}");
grandgrandchild1.Rotation.Equals(afterChildGlobalRotation, TOLERANCE).Should().BeTrue($"Expected: {afterChildGlobalRotation} Found: {grandgrandchild1.Rotation}");
}
}
}

View File

@@ -0,0 +1,140 @@
namespace NitroxModel.DataStructures.Util;
[TestClass]
public class OptionalTest
{
/// <summary>
/// These optional additions should be in <see cref="OptionalHasValueDynamicChecks"/> test method but MSTest
/// reuses instances which causes <see cref="Optional{T}.HasValue">Optional{T}.HasValue</see> to be called before the new conditions are added.
/// </summary>
[ClassInitialize]
public static void Init(TestContext _)
{
Optional.ApplyHasValueCondition<Base>(v => v.GetType() == typeof(A) || v.Threshold > 200); // Cheat: allow check if type A to do more complex tests on Optional<T>.HasValue
Optional.ApplyHasValueCondition<A>(v => v.Threshold <= 200);
}
[TestMethod]
public void OptionalGet()
{
Optional<string> op = Optional.Of("test");
op.Value.Should().Be("test");
}
[TestMethod]
public void OptionalIsPresent()
{
Optional<string> op = Optional.Of("test");
op.HasValue.Should().BeTrue();
}
[TestMethod]
public void OptionalIsNotPresent()
{
Optional<string> op = Optional.Empty;
op.HasValue.Should().BeFalse();
}
[TestMethod]
public void OptionalOrElseValidValue()
{
Optional<string> op = Optional.Of("test");
op.OrElse("test2").Should().Be("test");
}
[TestMethod]
public void OptionalOrElseNoValue()
{
Optional<string> op = Optional.Empty;
op.OrElse("test").Should().Be("test");
}
[TestMethod]
public void OptionalEmpty()
{
Optional<string> op = Optional.Empty;
op.HasValue.Should().BeFalse();
}
[TestMethod]
public void OptionalSetValueNull()
{
Optional<Random> op = Optional.Of(new Random());
Assert.IsTrue(op.HasValue);
Assert.ThrowsException<ArgumentNullException>(() => { op = null; }, "Setting optional to null should not be allowed.");
op = Optional.Empty;
Assert.IsFalse(op.HasValue);
}
[TestMethod]
public void OptionalHasValueDynamicChecks()
{
Optional<Base> opBase = Optional.Of(new Base());
opBase.HasValue.Should().BeTrue();
opBase.Value.Threshold.Should().Be(202);
Optional<A> a = Optional.Of(new A());
a.HasValue.Should().BeTrue();
Optional<A> actuallyB = Optional.Of<A>(new B());
actuallyB.HasValue.Should().BeFalse();
Optional<B> b = Optional.Of(new B());
b.HasValue.Should().BeFalse();
// A check should still happen on Base because Optional<Base> includes more-specific-than-itself checks.
Optional<Base> aAsBase = Optional<Base>.Of((Base)a);
aAsBase.HasValue.Should().BeTrue();
aAsBase.Value.Threshold.Should().Be(200);
// Optional<object> should always do all checks because anything can be in it.
// Note: This test can fail if Optional.ApplyHasValueCondition isn't called early enough. Run this test method directly and it should work.
Optional<object> bAsObj = Optional<object>.Of(new B());
bAsObj.HasValue.Should().BeFalse();
// Type C inheritance doesn't allow for type A. But Optional<object> has the check on A. It should skip the A check on C because inheritance doesn't match up.
Optional<object> cAsObj = Optional<object>.Of(new C());
cAsObj.HasValue.Should().BeTrue();
((C)cAsObj.Value).Threshold.Should().Be(203);
}
[TestMethod]
public void OptionalEqualsCheck()
{
Optional<string> op = Optional.OfNullable<string>(null);
Optional<string> op1 = Optional.OfNullable<string>(null);
Optional<string> op2 = Optional.Of("Test");
Optional<string> op3 = Optional.Of("Test2");
Optional<string> op4 = Optional.Of("Test");
Assert.IsFalse(op.Equals(op2));
Assert.IsFalse(op.Equals(op3));
Assert.IsFalse(op2.Equals(op3));
Assert.IsTrue(op.Equals(op1));
Assert.IsTrue(op2.Equals(op4));
Assert.IsTrue(op != op2);
Assert.IsTrue(op2 == op4);
}
private class Base
{
public virtual int Threshold => 202;
}
private class A : Base
{
public override int Threshold => 200;
}
private class B : A
{
public override int Threshold => 201;
}
private class C : Base
{
public override int Threshold => 203;
}
}