using System; using NUnit.Framework; using UnityEngine.Profiling; namespace UnityEngine.Rendering.Tests { class DynamicArrayTests { DynamicArray m_DynamicArray; [SetUp] public void Setup() { m_DynamicArray = new DynamicArray(); } [OneTimeTearDown] public void CleanUp() { m_DynamicArray = null; } [Test] public void TestContainElement() { m_DynamicArray.Add(2); Assert.IsTrue(m_DynamicArray.Contains(2)); Assert.IsFalse(m_DynamicArray.Contains(55)); } [Test] public void TestAddElementCorrectSize() { Assert.AreEqual(0, m_DynamicArray.size); m_DynamicArray.Add(2); Assert.AreEqual(1, m_DynamicArray.size); m_DynamicArray.Add(4); Assert.AreEqual(2, m_DynamicArray.size); } [Test] public void TestAddRangeCorrectElements() { m_DynamicArray.Add(1); m_DynamicArray.Add(2); var otherArray = new DynamicArray(); otherArray.Add(3); otherArray.Add(4); m_DynamicArray.AddRange(otherArray); Assert.AreEqual(1, m_DynamicArray[0]); Assert.AreEqual(2, m_DynamicArray[1]); Assert.AreEqual(3, m_DynamicArray[2]); Assert.AreEqual(4, m_DynamicArray[3]); Assert.AreEqual(4, m_DynamicArray.size); } [Test] public void TestAddRangeOutOfSpaceKeepPreviousElements() { var smallDynamicArray = new DynamicArray(2); smallDynamicArray[0] = 1; smallDynamicArray[1] = 2; var otherArray = new DynamicArray(); otherArray.Add(3); otherArray.Add(4); smallDynamicArray.AddRange(otherArray); Assert.AreEqual(1, smallDynamicArray[0]); Assert.AreEqual(2, smallDynamicArray[1]); Assert.AreEqual(3, smallDynamicArray[2]); Assert.AreEqual(4, smallDynamicArray[3]); Assert.AreEqual(4, smallDynamicArray.size); } [Test] public void TestRemoveElementCorrectSize() { m_DynamicArray.Add(2); m_DynamicArray.Add(4); Assert.AreEqual(2, m_DynamicArray.size); m_DynamicArray.Remove(2); Assert.AreEqual(1, m_DynamicArray.size); m_DynamicArray.Remove(4); Assert.AreEqual(0, m_DynamicArray.size); } [Test] public void TestRemoveAtKeepOrder() { m_DynamicArray.Add(2); m_DynamicArray.Add(4); m_DynamicArray.Add(8); Assert.AreEqual(3, m_DynamicArray.size); m_DynamicArray.RemoveAt(1); Assert.AreEqual(2, m_DynamicArray.size); Assert.AreEqual(2, m_DynamicArray[0]); Assert.AreEqual(8, m_DynamicArray[1]); } [Test] public void TestRemoveInexistantElementReturnFalse() { m_DynamicArray.Add(2); m_DynamicArray.Add(4); Assert.IsFalse(m_DynamicArray.Remove(8)); Assert.AreEqual(2, m_DynamicArray.size); } [Test] public void TestRemoveKeepOrder() { m_DynamicArray.Add(1); m_DynamicArray.Add(2); m_DynamicArray.Add(3); m_DynamicArray.Add(4); Assert.AreEqual(1, m_DynamicArray[0]); Assert.AreEqual(2, m_DynamicArray[1]); Assert.AreEqual(3, m_DynamicArray[2]); Assert.AreEqual(4, m_DynamicArray[3]); Assert.AreEqual(4, m_DynamicArray.size); m_DynamicArray.Remove(2); Assert.IsFalse(m_DynamicArray.Contains(2)); Assert.AreEqual(1, m_DynamicArray[0]); Assert.AreEqual(3, m_DynamicArray[1]); Assert.AreEqual(4, m_DynamicArray[2]); Assert.AreEqual(3, m_DynamicArray.size); } [Test] public void TestRemoveRangeKeepOrder() { m_DynamicArray.Add(1); m_DynamicArray.Add(2); m_DynamicArray.Add(3); m_DynamicArray.Add(4); m_DynamicArray.Add(5); Assert.AreEqual(1, m_DynamicArray[0]); Assert.AreEqual(2, m_DynamicArray[1]); Assert.AreEqual(3, m_DynamicArray[2]); Assert.AreEqual(4, m_DynamicArray[3]); Assert.AreEqual(5, m_DynamicArray[4]); Assert.AreEqual(5, m_DynamicArray.size); m_DynamicArray.RemoveRange(1, 2); Assert.IsFalse(m_DynamicArray.Contains(2)); Assert.IsFalse(m_DynamicArray.Contains(3)); Assert.AreEqual(1, m_DynamicArray[0]); Assert.AreEqual(4, m_DynamicArray[1]); Assert.AreEqual(5, m_DynamicArray[2]); Assert.AreEqual(3, m_DynamicArray.size); } [Test] public void TestInvalidAccessThrows() { m_DynamicArray.Add(1); m_DynamicArray.Add(2); int dummy; Assert.Throws(() => dummy = m_DynamicArray[2]); Assert.Throws(() => dummy = m_DynamicArray[-1]); } [Test] public void TestRemoveAtInvalidAccessThrows() { m_DynamicArray.Add(1); m_DynamicArray.Add(2); Assert.Throws(() => m_DynamicArray.RemoveAt(-1)); Assert.Throws(() => m_DynamicArray.RemoveAt(2)); } [Test] public void TestRemoveRangeInvalidAccessThrows() { m_DynamicArray.Add(1); m_DynamicArray.Add(2); Assert.Throws(() => m_DynamicArray.RemoveRange(1, 2)); } [Test] public void TestRemoveRangeValidAccessDoesNotThrows() { m_DynamicArray.Add(1); m_DynamicArray.Add(2); Assert.DoesNotThrow(() => m_DynamicArray.RemoveRange(1, 1)); } [Test] public void TestFindIndexFailReturnMinusOne() { m_DynamicArray.Add(1); m_DynamicArray.Add(2); Assert.AreEqual(-1, m_DynamicArray.FindIndex(0, m_DynamicArray.size, (x) => x == 4)); } [Test] public void TestFindIndexSuccessReturnRightFirstIndex() { m_DynamicArray.Add(1); m_DynamicArray.Add(2); m_DynamicArray.Add(3); m_DynamicArray.Add(2); Assert.AreEqual(1, m_DynamicArray.FindIndex(0, m_DynamicArray.size, (x) => x == 2)); } [Test] public void TestIndexOfReturnFirstValidIndex() { m_DynamicArray.Add(1); m_DynamicArray.Add(2); m_DynamicArray.Add(3); m_DynamicArray.Add(2); Assert.AreEqual(1, m_DynamicArray.IndexOf(2)); } [Test] public void TestIndexOfRangeRespectCount() { m_DynamicArray.Add(1); m_DynamicArray.Add(2); m_DynamicArray.Add(3); m_DynamicArray.Add(4); Assert.AreEqual(-1, m_DynamicArray.IndexOf(4, 1, 2)); } [Test] public void TestIndexOfRangeReturnFirstValidIndex() { m_DynamicArray.Add(1); m_DynamicArray.Add(4); m_DynamicArray.Add(3); m_DynamicArray.Add(4); m_DynamicArray.Add(5); Assert.AreEqual(1, m_DynamicArray.IndexOf(4, 1, 3)); } [Test] public void TestIndexOfWithStartingIndexFail() { m_DynamicArray.Add(1); m_DynamicArray.Add(4); m_DynamicArray.Add(3); Assert.AreEqual(-1, m_DynamicArray.IndexOf(1, 1, 2)); } [Test] public void TestResizeIncreaseCapacity() { m_DynamicArray.Resize(256); Assert.AreEqual(256, m_DynamicArray.capacity); } [Test] public void TestReserveKeepsSize() { var size = m_DynamicArray.size; m_DynamicArray.Reserve(256); Assert.AreEqual(256, m_DynamicArray.capacity); Assert.AreEqual(size, m_DynamicArray.size); } [Test] public void TestResizeAndClear() { // Uses the capacity only allocator m_DynamicArray = new DynamicArray(64, false); Assert.AreEqual(0, m_DynamicArray.size); Assert.AreEqual(64, m_DynamicArray.capacity); // First resize it to 32 elements m_DynamicArray.Resize(32, false); Assert.AreEqual(32, m_DynamicArray.size); m_DynamicArray[31] = 0xFFFF; // Resize it back to 0 elements m_DynamicArray.Resize(0); Assert.AreEqual(0, m_DynamicArray.size); // Resize it back to 32 elements, the memory should not have been reallocated // it also shouln't have been cleared (for peformance reasons) m_DynamicArray.Resize(32); Assert.AreEqual(32, m_DynamicArray.size); Assert.AreEqual(0xFFFF, m_DynamicArray[31]); // Resize it back to 0 elements m_DynamicArray.Resize(0); Assert.AreEqual(0, m_DynamicArray.size); // Resize it back to 32 elements, the memory should not have been reallocated // the memory should have been cleared, resize and clear was used m_DynamicArray.ResizeAndClear(32); Assert.AreEqual(32, m_DynamicArray.size); Assert.AreEqual(0, m_DynamicArray[31]); } [Test] public void TestDynamicString() { var ds = new DynamicString("Foo"); ds.Append("Bar"); ds.Append(new DynamicString("Baz")); var s = ds.ToString(); Assert.AreEqual("FooBarBaz", s); } [Test] public void TestAppendSelf() { var ds = new DynamicString("Foo"); ds.Append(ds); var s = ds.ToString(); Assert.AreEqual("FooFoo", s); } [Test] public void TestQuickSort() { m_DynamicArray.Add(8); m_DynamicArray.Add(4); m_DynamicArray.Add(3); m_DynamicArray.Add(4); m_DynamicArray.Add(5); m_DynamicArray.Add(1); m_DynamicArray.Add(12); m_DynamicArray.QuickSort(); Assert.AreEqual(1, m_DynamicArray[0]); Assert.AreEqual(3, m_DynamicArray[1]); Assert.AreEqual(4, m_DynamicArray[2]); Assert.AreEqual(4, m_DynamicArray[3]); Assert.AreEqual(5, m_DynamicArray[4]); Assert.AreEqual(8, m_DynamicArray[5]); Assert.AreEqual(12, m_DynamicArray[6]); } [Test] public void TestForEach_FullRange() { m_DynamicArray.Add(8); m_DynamicArray.Add(4); m_DynamicArray.Add(3); m_DynamicArray.Add(6); var sum = 0; foreach (var i in m_DynamicArray) { sum += i; } Assert.AreEqual(21, sum); // now check if we are _not_ iterating on empty array sum = 0; m_DynamicArray.Clear(); foreach (var i in m_DynamicArray) { sum += i; } Assert.AreEqual(0, sum); } [Test] public void TestForEach_SubRange() { m_DynamicArray.Add(8); m_DynamicArray.Add(4); m_DynamicArray.Add(3); m_DynamicArray.Add(6); var sum = 0; foreach (var i in m_DynamicArray.SubRange(1,2)) { sum += i; } Assert.AreEqual(7, sum); //remove item of array and test again m_DynamicArray.RemoveAt(1); sum = 0; foreach (var i in m_DynamicArray.SubRange(1,2)) { sum += i; } Assert.AreEqual(9, sum); } [Test] public void GetEnumerators_ArgumentValidation() { Assert.Throws(() => { var iterator = new DynamicArray.Iterator(null); }); Assert.Throws(() => { var iterator = new DynamicArray.RangeEnumerable.RangeIterator(null, 0,0); }); m_DynamicArray.Add(12); m_DynamicArray.Add(2); Assert.Throws(() => { var iterator = m_DynamicArray.SubRange(-5, 1); }); Assert.Throws(() => { var iterator = m_DynamicArray.SubRange(17, 1); }); Assert.Throws(() => { var iterator = m_DynamicArray.SubRange(0, 12); }); Assert.Throws(() => { var iterator = m_DynamicArray.SubRange(1, 2); }); Assert.DoesNotThrow(() => { var iterator = m_DynamicArray.SubRange(1, 1); }); Assert.Throws(() => { var iterator = m_DynamicArray.SubRange(2, 1); }); } [Test] public void Foreach_TestNoModificationsAllowed() { Assert.Throws(() => { m_DynamicArray.Add(3); m_DynamicArray.Add(3); foreach (var i in m_DynamicArray) { m_DynamicArray.Remove(i); } }); Assert.Throws(() => { m_DynamicArray.Add(3); m_DynamicArray.Add(3); foreach (var i in m_DynamicArray) { m_DynamicArray.Add(1); } }); Assert.Throws(() => { m_DynamicArray.Add(8); m_DynamicArray.Add(3); foreach (var i in m_DynamicArray) { if (i == 3) { m_DynamicArray.Add(1); m_DynamicArray.RemoveAt(0); } } }); Assert.Throws(() => { m_DynamicArray.Add(8); m_DynamicArray.Add(3); m_DynamicArray.Add(7); foreach (var i in m_DynamicArray) { if (i == 3) { m_DynamicArray.QuickSort(); } } }); } static Recorder gcAllocRecorder = Recorder.Get("GC.Alloc"); static int CountGCAllocs(Action action) { gcAllocRecorder.FilterToCurrentThread(); gcAllocRecorder.enabled = false; gcAllocRecorder.enabled = true; action(); gcAllocRecorder.enabled = false; return gcAllocRecorder.sampleBlockCount; } static void ValidateNoGCAllocs(Action action) { // warmup // this will catch static c'tors etc CountGCAllocs(action); // actual test var count = CountGCAllocs(action); if (count != 0) throw new AssertionException($"Expected 0 GC allocations but there were {count}"); } [Test] public void Foreach_NoGC() { m_DynamicArray.Reserve(4); m_DynamicArray.Add(12); m_DynamicArray.Add(4); m_DynamicArray.Add(8); m_DynamicArray.Add(2); var sum = 0; ValidateNoGCAllocs(() => { sum = 0; foreach (var i in m_DynamicArray) { sum += i; } }); Assert.AreEqual(sum, 26); ValidateNoGCAllocs(() => { sum = 0; foreach (var i in m_DynamicArray.SubRange(0, 2)) { sum += i; } }); Assert.AreEqual(sum, 16); } } }