You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

180 lines
9.8 KiB

using NUnit.Framework;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using UnityEditor;
using UnityEditor.Rendering;
namespace UnityEngine.Rendering.Tests
{
class RemoveComponent
{
#region Components
interface ITest { }
protected class Apple : MonoBehaviour, ITest { }
protected class Banana : MonoBehaviour, ITest { }
[RequireComponent(typeof(Apple))]
protected class AdditionalApple : MonoBehaviour, IAdditionalData, ITest { }
[RequireComponent(typeof(Banana))]
protected class AdditionalBanana : MonoBehaviour, IAdditionalData, ITest { }
[RequireComponent(typeof(Banana))]
protected class AdditionalBananaColor : MonoBehaviour, IAdditionalData, ITest { }
protected class WaterMelon : MonoBehaviour, IAdditionalData, ITest{ }
[RequireComponent(typeof(Apple), typeof(Banana))]
protected class FruitBasket : MonoBehaviour, IAdditionalData, ITest { }
#endregion
#region SetUp & TearDown
protected GameObject m_GameObject;
[SetUp]
public void SetUp()
{
m_GameObject = new("RemoveComponentTestsRoot");
}
[TearDown]
public void TearDown()
{
GameObject.DestroyImmediate(m_GameObject);
}
#endregion
protected Type[] GenericRemoveComponent(
[DisallowNull] int selectionAmount,
[DisallowNull] Type componentToRemove,
[DisallowNull] Type[] componentsToAdd,
[DisallowNull] Action<Component> removeMethod)
{
Assert.IsTrue(selectionAmount > 0, "GenericRemoveComponent should only be called with a non null selection");
//Create object to select
GameObject[] selectedGameObjects = new GameObject[selectionAmount];
for (int i = 0; i < selectionAmount; ++i)
{
(selectedGameObjects[i] = new GameObject($"Selected_{i}", componentsToAdd)).transform.parent = m_GameObject.transform;
}
//update selected objects
Selection.objects = selectedGameObjects;
//Call method to test
removeMethod(Selection.activeGameObject.GetComponent(componentToRemove));
//Assert all selection have same component
var typesOfFirstSelected = selectedGameObjects[0].GetComponents<ITest>().Select(c => c.GetType());
Assert.IsTrue(DoesAllGameObjectHaveSameComponents(selectedGameObjects.Skip(1), typesOfFirstSelected), "Not all the GameObject of the selection have same Components");
//Will assert that remaining components are the desired ones
return typesOfFirstSelected.ToArray();
}
bool DoesAllGameObjectHaveSameComponents([NotNull] System.Collections.Generic.IEnumerable<GameObject> objectsToCheck, System.Collections.Generic.IEnumerable<Type> typesToCheck)
{
var typeAmount = typesToCheck.Count();
foreach(var objectToCheck in objectsToCheck)
{
if (objectToCheck.GetComponents<ITest>().Length != typeAmount)
return false;
foreach (var typeToCheck in typesToCheck)
if (!objectToCheck.TryGetComponent(typeToCheck, out _))
return false;
}
return true;
}
}
[TestOf(typeof(RemoveComponentUtils))]
class RemoveComponentUtilsTests : RemoveComponent
{
//No multiedition test needed as this is not Selection dependant
static TestCaseData[] s_RemoveComponentTestCaseDatas =
{
new TestCaseData(typeof(Banana), new Type[] {typeof(Banana), typeof(AdditionalBanana)})
.SetName("Removal of target component removes it's additional data")
.Returns(Array.Empty<Type>()),
new TestCaseData(typeof(Banana), new Type[] {typeof(Banana), typeof(AdditionalBanana), typeof(AdditionalBananaColor)})
.SetName("Removal of target component removes all it's additional datas")
.Returns(Array.Empty<Type>()),
new TestCaseData(typeof(Apple), new Type[] {typeof(Banana), typeof(AdditionalBanana), typeof(Apple), typeof(AdditionalApple)})
.SetName("Given multiple components, each with additional datas, the removal of the component only removes its additional datas")
.Returns(new Type[] {typeof(Banana), typeof(AdditionalBanana) }),
};
[Test, TestCaseSource(nameof(s_RemoveComponentTestCaseDatas))]
public Type[] RemoveComponentAndPropagateTheDeleteToAdditionalDatas([DisallowNull] Type componentToRemove, [DisallowNull] Type[] componentsToAdd)
{
return GenericRemoveComponent(1, componentToRemove, componentsToAdd, RemoveComponentUtils.RemoveComponent);
}
}
[TestOf(typeof(RemoveAdditionalDataUtils))]
class RemoveAdditionalDataUtilsTests : RemoveComponent
{
//No multiedition test needed as this is not Selection dependant
static TestCaseData[] s_TryGetComponentsToRemoveTestCaseDatas =
{
new TestCaseData(typeof(AdditionalBanana))
.Returns(new string[] {"Banana"})
.SetName("For additional data targeting one component, return the targeted component (most common case)"),
new TestCaseData(typeof(FruitBasket))
.Returns(new string[] { "Apple", "Banana" })
.SetName("For additional data targeting multiple components, return all the targeted components"),
new TestCaseData(typeof(WaterMelon))
.Returns(Array.Empty<string>())
.SetName("For additional data targetting no component, return empty collection."),
};
[Test, TestCaseSource(nameof(s_TryGetComponentsToRemoveTestCaseDatas))]
public string[] TryGetComponentsToRemove([DisallowNull] Type type)
{
string[] result = Array.Empty<string>();
var additionalData = m_GameObject.AddComponent(type) as IAdditionalData;
using (ListPool<Type>.Get(out var componentsToRemove))
{
if (RemoveAdditionalDataUtils.TryGetComponentsToRemove(additionalData, componentsToRemove, out var error))
result = componentsToRemove.Select(t => t.Name).ToArray();
}
return result;
}
//No multiedition RECQUIRED: This is Selection dependent to handle correctly the popup
static TestCaseData[] s_RemoveAdditionalDataComponentTestCaseDatas =
{
new TestCaseData(1, typeof(AdditionalBanana), new Type[] {typeof(Banana), typeof(AdditionalBanana) })
.SetName("For single additional data, when removing it, the target component is deleted")
.Returns(Array.Empty<Type>()),
new TestCaseData(1, typeof(AdditionalBananaColor), new Type[] {typeof(Banana), typeof(AdditionalBanana), typeof(AdditionalBananaColor)})
.SetName("For multiple additional datas, when removing one of them, target component is deleted, and the other additional data")
.Returns(Array.Empty<Type>()),
new TestCaseData(1, typeof(AdditionalBananaColor), new Type[] {typeof(Banana), typeof(Banana), typeof(AdditionalBanana), typeof(AdditionalBananaColor)})
.SetName("For multiple additional component and datas, when removing one of them everything is removed")
.Returns(Array.Empty<Type>()),
new TestCaseData(1, typeof(AdditionalApple), new Type[] {typeof(Banana), typeof(AdditionalBanana), typeof(Apple), typeof(AdditionalApple)})
.SetName("For multiple types of target component, when deleting an additional data, only the target component is being removed")
.Returns(new Type[] {typeof(Banana), typeof(AdditionalBanana)}),
new TestCaseData(3, typeof(AdditionalBanana), new Type[] {typeof(Banana), typeof(AdditionalBanana) })
.SetName("For single additional data, when removing it, the target component is deleted (multiedition case)")
.Returns(Array.Empty<Type>()),
new TestCaseData(3, typeof(AdditionalBananaColor), new Type[] {typeof(Banana), typeof(AdditionalBanana), typeof(AdditionalBananaColor)})
.SetName("For multiple additional datas, when removing one of them, target component is deleted, and the other additional data (multiedition case)")
.Returns(Array.Empty<Type>()),
new TestCaseData(3, typeof(AdditionalBananaColor), new Type[] {typeof(Banana), typeof(Banana), typeof(AdditionalBanana), typeof(AdditionalBananaColor)})
.SetName("For multiple additional component and datas, when removing one of them everything is removed (multiedition case)")
.Returns(Array.Empty<Type>()),
new TestCaseData(3, typeof(AdditionalApple), new Type[] {typeof(Banana), typeof(AdditionalBanana), typeof(Apple), typeof(AdditionalApple)})
.SetName("For multiple types of target component, when deleting an additional data, only the target component is being removed (multiedition case)")
.Returns(new Type[] {typeof(Banana), typeof(AdditionalBanana)})
};
[Test, TestCaseSource(nameof(s_RemoveAdditionalDataComponentTestCaseDatas))]
[NUnit.Framework.Property("FogBugz", "1396805")]
[NUnit.Framework.Property("Jira", "UUM-5452")]
public Type[] RemoveAdditionalDataComponentAndPropagateToComponent(int selectionAmount, [DisallowNull] Type componentToRemove, [DisallowNull] Type[] componentsToAdd)
{
return GenericRemoveComponent(selectionAmount, componentToRemove, componentsToAdd, c => RemoveAdditionalDataUtils.RemoveAdditionalData(new UnityEditor.MenuCommand(c), false));
}
}
}