using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; namespace UnityEngine.Rendering.Tests { class VolumeCollectionTests { const int k_Iterations = 100; private static readonly LayerMask s_Default = 1 << 0; private static readonly LayerMask s_First = 1 << 1; private static readonly LayerMask s_Fifth = 1 << 5; private static readonly LayerMask s_Everything = ~0; private VolumeCollection m_VolumeCollection; private List<Volume> m_Volumes = new(); [SetUp] public void Setup() { m_VolumeCollection = new VolumeCollection(); } [TearDown] public void Teardown() { foreach (var volume in m_Volumes) { Object.DestroyImmediate(volume.gameObject); } m_Volumes.Clear(); } private Volume CreateVolume() { string name = $"Volume Collection Test ({m_Volumes.Count})"; var go = new GameObject(name); var v = go.AddComponent<Volume>(); m_Volumes.Add(v); return v; } [Test] public void IsRegistered() { var volume = CreateVolume(); Assert.IsTrue(m_VolumeCollection.Register(volume, volume.gameObject.layer)); Assert.IsFalse(m_VolumeCollection.Register(volume, volume.gameObject.layer)); Assert.AreEqual(1, m_VolumeCollection.count); Assert.IsTrue(m_VolumeCollection.Unregister(volume, volume.gameObject.layer)); Assert.AreEqual(0, m_VolumeCollection.count); } [Test] public void GrabVolumesLayerAndEverything() { var volume = CreateVolume(); volume.gameObject.layer = 5; Assert.IsTrue(m_VolumeCollection.Register(volume, 5)); var volumes = m_VolumeCollection.GrabVolumes(s_Default); Assert.AreEqual(0, volumes.Count); volumes = m_VolumeCollection.GrabVolumes(s_Fifth); Assert.AreEqual(1, volumes.Count); volumes = m_VolumeCollection.GrabVolumes(s_Everything); Assert.AreEqual(1, volumes.Count); } [Test] public void GrabVolumesFromMultipleLayers() { var volume = CreateVolume(); volume.gameObject.layer = 5; Assert.IsTrue(m_VolumeCollection.Register(volume,5)); var volume2 = CreateVolume(); volume2.gameObject.layer = 1; Assert.IsTrue(m_VolumeCollection.Register(volume2, 1)); CollectionAssert.AreEqual(m_VolumeCollection.GrabVolumes(s_First | s_Fifth), m_VolumeCollection.GrabVolumes(s_Everything)); Assert.AreEqual(volume, m_VolumeCollection.GrabVolumes(s_Fifth).FirstOrDefault()); Assert.AreEqual(volume2, m_VolumeCollection.GrabVolumes(s_First).FirstOrDefault()); } public static IEnumerable<TestCaseData> VolumeTestCases() { yield return new TestCaseData((Action<Volume, int>)((Volume v, int i) => v.priority = 5.0f)).SetName("All Same Priority"); yield return new TestCaseData((Action<Volume, int>)((Volume v, int i) => v.priority = (float)(i))).SetName("Ascending Order"); yield return new TestCaseData((Action<Volume, int>)((Volume v, int i) => v.priority = (float)(k_Iterations - 1 - i))).SetName("Descending Order"); yield return new TestCaseData((Action<Volume, int>)((Volume v, int i) => v.priority = (float)(i % 5))).SetName("Mod 5"); yield return new TestCaseData((Action<Volume, int>)((Volume v, int i) => v.priority = (float)(i % 2))).SetName("Mod 2"); yield return new TestCaseData((Action<Volume, int>)((Volume v, int i) => v.priority = (float)(i % 3))).SetName("Mod 3"); yield return new TestCaseData((Action<Volume, int>)((Volume v, int i) => v.priority = (float)(i - 5))).SetName("Negative Priorities"); yield return new TestCaseData((Action<Volume, int>)((Volume v, int i) => v.priority = (float)(i / 3.0))).SetName("Floating Point Precision"); yield return new TestCaseData((Action<Volume, int>)((Volume v, int i) => v.priority = (float)(i * 1000))).SetName("Large Range of Priorities"); } [Test, TestCaseSource(nameof(VolumeTestCases))] public void VolumesAreSortedByPriority(Action<Volume, int> action) { var expectedOrder = new List<Volume>(); for (int i = 0; i < k_Iterations; i++) { var volume = CreateVolume(); action(volume, i); Assert.IsTrue(m_VolumeCollection.Register(volume, volume.gameObject.layer)); expectedOrder.Add(volume); } Assert.IsTrue(IsSortedByPriority(m_VolumeCollection.GrabVolumes(s_Default))); } [Test, TestCaseSource(nameof(VolumeTestCases))] public void VolumesAreSortedByPriorityChanges(Action<Volume, int> action) { var expectedOrder = new List<Volume>(); for (int i = 0; i < k_Iterations; i++) { var volume = CreateVolume(); action(volume, i); m_VolumeCollection.SetLayerIndexDirty(1 << volume.gameObject.layer); Assert.IsTrue(m_VolumeCollection.Register(volume, volume.gameObject.layer)); expectedOrder.Add(volume); } // Swap priorities after they are added into the collection (expectedOrder[1].priority, expectedOrder[8].priority) = (expectedOrder[8].priority, expectedOrder[1].priority); // Notify the collection that the layer is dirty m_VolumeCollection.SetLayerIndexDirty(1 << 0); Assert.IsTrue(IsSortedByPriority(m_VolumeCollection.GrabVolumes(s_Default))); } private bool IsSortedByPriority(List<Volume> volumes) { for (int i = 0; i < volumes.Count - 1; ++i) { if (volumes[i].priority > volumes[i + 1].priority) return false; } return true; } [Test] public void UpdateLayer() { var volume = CreateVolume(); volume.gameObject.layer = 0; Assert.IsTrue(m_VolumeCollection.Register(volume, 0)); for (int i = 0; i < VolumeCollection.k_MaxLayerCount; ++i) { var previousLayer = volume.gameObject.layer; volume.gameObject.layer = i; m_VolumeCollection.ChangeLayer(volume, previousLayer, i); for (int j = 0; j < VolumeCollection.k_MaxLayerCount; ++j) { var volumes = m_VolumeCollection.GrabVolumes(1 << j); if (i != j) Assert.IsEmpty(volumes); else Assert.AreEqual(1, volumes.Count); } var volumesEverything = m_VolumeCollection.GrabVolumes(s_Everything); Assert.AreEqual(1, volumesEverything.Count); } } [Test] public void UpdateLayerMultipleVolumes() { for (int i = 0; i < k_Iterations; i++) { var volume = CreateVolume(); volume.priority = (float)(i % 2); if (i < k_Iterations / 2) { volume.gameObject.layer = 0; } else { volume.gameObject.layer = 1; } Assert.IsTrue(m_VolumeCollection.Register(volume, volume.gameObject.layer)); } var arrayVolumes = m_VolumeCollection.GrabVolumes(s_Everything).ToArray(); foreach (var volume in arrayVolumes) { var previousLayerIndex = volume.gameObject.layer; volume.gameObject.layer = 5; m_VolumeCollection.ChangeLayer(volume, previousLayerIndex, volume.gameObject.layer); } Assert.IsEmpty(m_VolumeCollection.GrabVolumes(s_Default)); Assert.IsEmpty(m_VolumeCollection.GrabVolumes(s_First)); Assert.IsTrue(IsSortedByPriority(m_VolumeCollection.GrabVolumes(s_Fifth))); } [Test] public void VolumeOnMultipleLayers() { var volumesExpected = new List<Volume>(); for (int i = 0; i < VolumeCollection.k_MaxLayerCount; i++) { var volume = CreateVolume(); volume.gameObject.layer = i; volumesExpected.Add(volume); Assert.IsTrue(m_VolumeCollection.Register(volume, i)); } for (int i = 0; i < VolumeCollection.k_MaxLayerCount; i++) { LayerMask mask = (1 << i); var volumes = m_VolumeCollection.GrabVolumes(mask); Assert.AreEqual(1, volumes.Count); Assert.AreEqual(volumesExpected[i], volumes[0]); } CollectionAssert.AreEqual(volumesExpected, m_VolumeCollection.GrabVolumes(s_Everything)); } [Test] public void VolumeOnMultipleLayersGrabMultiple() { var volumesExpected = new List<Volume>(); for (int i = 0; i < VolumeCollection.k_MaxLayerCount; i++) { var volume = CreateVolume(); volume.gameObject.layer = i; volumesExpected.Add(volume); Assert.IsTrue(m_VolumeCollection.Register(volume, i)); } for (int i = 0; i < VolumeCollection.k_MaxLayerCount - 1; i++) { LayerMask mask = 1 << i | 1 << i + 1; var volumes = m_VolumeCollection.GrabVolumes(mask); Assert.AreEqual(2, volumes.Count); Assert.AreEqual(volumesExpected[i], volumes[0]); Assert.AreEqual(volumesExpected[i + 1], volumes[1]); } CollectionAssert.AreEqual(volumesExpected, m_VolumeCollection.GrabVolumes(s_Everything)); } } }