using NUnit.Framework;
using System;
using System.Collections;
using System.Linq;
using UnityEngine;
using UnityEngine.Pool;
namespace UnityEditor.Rendering.Tests
{
class AnalyticsUtilsTests
{
private TestScriptableObject m_SO;
private TestObject m_Current;
[SetUp]
public void SetUp()
{
m_Current = new TestObject();
m_SO = ScriptableObject.CreateInstance(typeof(TestScriptableObject)) as TestScriptableObject;
}
[TearDown]
public void TearDown()
{
ScriptableObject.DestroyImmediate(m_SO);
}
[Serializable]
public class TestObject
{
public int integer;
public float floatNumber;
public double doubleNumber;
public bool boolean;
public string test;
public int[] array;
public enum TestDiffEnum
{
a, b, c
}
public TestDiffEnum diffEnum;
[Serializable]
public struct InnerTestStruct
{
public int myValue;
}
public InnerTestStruct innerStruct;
}
public class TestScriptableObject : ScriptableObject
{
public TestObject myData;
public TestScriptableObject()
{
myData = new TestObject();
}
}
static TestCaseData[] s_TestCaseDatas =
{
new TestCaseData("integer", 1)
.Returns(new string[] { "{\"myData.integer\":\"1\"}" })
.SetName("Given an int field, the nested column is generated correctly"),
new TestCaseData("floatNumber", 1.5f)
.Returns(new string[] { "{\"myData.floatNumber\":\"1.5\"}" })
.SetName("Given a float field, the nested column is generated correctly"),
new TestCaseData("doubleNumber", 1.2)
.Returns(new string[] { "{\"myData.doubleNumber\":\"1.2\"}" })
.SetName("Given a double field, the nested column is generated correctly"),
new TestCaseData("boolean", true)
.Returns(new string[] { "{\"myData.boolean\":\"True\"}" })
.SetName("Given a bool field, the nested column is generated correctly"),
new TestCaseData("test", "Hello World")
.Returns(new string[] { "{\"myData.test\":\"Hello World\"}" })
.SetName("Given a string field, the nested column is generated correctly"),
new TestCaseData("array", new int[] { 1,2,3} )
.Returns(new string[] { "{\"myData.array\":\"[1,2,3]\"}" })
.SetName("Given an array of ints field, the nested column is generated correctly"),
new TestCaseData("diffEnum", TestObject.TestDiffEnum.b)
.Returns(new string[] { "{\"myData.diffEnum\":\"b\"}" })
.SetName("Given an enum field, the nested column is generated correctly"),
new TestCaseData("innerStruct", new TestObject.InnerTestStruct{ myValue = 5 } )
.Returns(new string[] { "{\"myData.innerStruct.myValue\":\"5\"}" })
.SetName("Given an inner struct field, the nested column is generated correctly"),
};
private void SetValue(TestObject current, string fieldName, object value)
{
current.GetType().GetField(fieldName).SetValue(current, value);
}
[Test, TestCaseSource(nameof(s_TestCaseDatas))]
public string[] ToNestedColumnUnityObject(string fieldName, object value)
{
SetValue(m_Current, fieldName, value);
m_SO.myData = m_Current;
return m_SO.ToNestedColumn(true);
}
static TestCaseData[] s_TestCaseDatasWithDefault =
{
new TestCaseData("integer", 1)
.Returns(new string[] { "{\"integer\":\"1\"}" })
.SetName("Given an int field, the nested column is generated correctly"),
new TestCaseData("floatNumber", 1.5f)
.Returns(new string[] { "{\"floatNumber\":\"1.5\"}" })
.SetName("Given a float field, the nested column is generated correctly"),
new TestCaseData("doubleNumber", 1.2)
.Returns(new string[] { "{\"doubleNumber\":\"1.2\"}" })
.SetName("Given a double field, the nested column is generated correctly"),
new TestCaseData("boolean", true)
.Returns(new string[] { "{\"boolean\":\"True\"}" })
.SetName("Given a bool field, the nested column is generated correctly"),
new TestCaseData("test", "Hello World")
.Returns(new string[] { "{\"test\":\"Hello World\"}" })
.SetName("Given a string field, the nested column is generated correctly"),
new TestCaseData("array", new int[] { 1,2,3} )
.Returns(new string[] { "{\"array\":\"[1,2,3]\"}" })
.SetName("Given an array of ints field, the nested column is generated correctly"),
new TestCaseData("diffEnum", TestObject.TestDiffEnum.b)
.Returns(new string[] { "{\"diffEnum\":\"b\"}" })
.SetName("Given an enum field, the nested column is generated correctly"),
new TestCaseData("innerStruct", new TestObject.InnerTestStruct{ myValue = 5 } )
.Returns(new string[] { "{\"innerStruct.myValue\":\"5\"}" })
.SetName("Given an inner struct field, the nested column is generated correctly"),
};
[Test, TestCaseSource(nameof(s_TestCaseDatasWithDefault))]
public string[] ToNestedColumnWithDefault(string fieldName, object value)
{
SetValue(m_Current, fieldName, value);
m_SO.myData = m_Current;
return m_Current.ToNestedColumnWithDefault<TestObject>(new TestObject(), true);
}
[Test]
public void GivenAnObjectWithSerializableFields_WhenAllFieldsAreRequested_AllOfThemAreReturnedCorrectly()
{
using (ListPool<string>.Get(out var tmp))
{
foreach (var testCase in s_TestCaseDatas)
{
SetValue(m_Current, (string)testCase.Arguments[0], testCase.Arguments[1]);
tmp.Add(((string[])testCase.ExpectedResult)[0]);
}
m_SO.myData = m_Current;
Assert.AreEqual(m_SO.ToNestedColumn(false), tmp.ToArray());
}
}
[Test]
public void CheckEditorAnalyticsAreDisabledOnCI()
{
var ci = Environment.GetEnvironmentVariable("CI");
if (!string.IsNullOrWhiteSpace(ci) && bool.TryParse(ci, out var result) && result)
{
Assert.IsFalse(EditorAnalytics.enabled, "Analytics must be only enabled for user projects not on CI");
Debug.Log("Assert for CheckEditorAnalyticsAreDisabledOnCI was executed.");
}
}
[Serializable]
class ClassWithPublicInt
{
public int myPublicInt;
}
[Serializable]
class ClassWithPrivateBool
{
private bool myPrivateBoolNotSerializable;
}
[Serializable]
class ClassWithPrivateIntWithSerializableFieldAttribute
{
[SerializeField]
private int myPrivateIntSerializable;
}
[Serializable]
class ClassWithPublicIntWithNonSerializableFieldAttribute
{
[NonSerialized]
public int myPublicNonSerializedInt;
}
[Serializable]
class ClassWithPublicPropertytWithSerializableFieldAttributeForTheBackingField
{
[field: SerializeField]
public int myProperty { get; private set; }
}
[Serializable]
class ClassWithObsoletePublicField
{
[Obsolete("this is obsolete")]
public int myPublicInt;
}
[Serializable]
class BaseClassWithField
{
public int myPublicInt;
}
[Serializable]
class ChildClass : BaseClassWithField
{
public bool myPublicBool;
}
static TestCaseData[] s_ListTestsCaseDatasSerializableFields =
{
new TestCaseData(typeof(ClassWithPublicInt), false)
.SetName("Given a class with a public field, the field is returned")
.Returns(new string[] { "myPublicInt" }),
new TestCaseData(typeof(ClassWithPrivateBool), false)
.SetName("Given a class with a private field, nothing is returned")
.Returns(new string[] { }),
new TestCaseData(typeof(ClassWithPrivateIntWithSerializableFieldAttribute), false)
.SetName("Given a class with a private field with [SerializeField] attribute, the field is returned")
.Returns(new string[] {"myPrivateIntSerializable" }),
new TestCaseData(typeof(ClassWithPublicIntWithNonSerializableFieldAttribute), false)
.SetName("Given a class with public field with [NonSerialized] attribute, nothing is returned")
.Returns(new string[] { }),
new TestCaseData(typeof(ClassWithPublicPropertytWithSerializableFieldAttributeForTheBackingField), false)
.SetName("Given a class with public property with [field: SerializeField] attribute, the backing field is returned")
.Returns(new string[] {"<myProperty>k__BackingField" }),
new TestCaseData(typeof(ClassWithObsoletePublicField), false)
.SetName("Given a class with public field with [Obsolete] attribute and not removing obsolete fields, the obsolete is returned")
.Returns(new string[] {"myPublicInt" }),
new TestCaseData(typeof(ClassWithObsoletePublicField), true)
.SetName("Given a class with public field with [Obsolete] attribute, nothing is returned when obsolete fields must be removed")
.Returns(new string[] { }),
new TestCaseData(typeof(ChildClass), false)
.SetName("Given a class with inheriting from another with a public field, the parent field is returned")
.Returns(new string[] { "myPublicInt", "myPublicBool" }),
};
[Test, TestCaseSource(nameof(s_ListTestsCaseDatasSerializableFields))]
public string[] GetSerializableFields(Type type, bool removeObsolete)
{
return type
.GetSerializableFields(removeObsolete)
.Select(f => f.Name)
.ToArray();
}
private static IEnumerable ValueComparisonTestsCases
{
get
{
// String test cases
yield return new TestCaseData(typeof(string), "test", "test", true).SetName("StringEqual");
yield return new TestCaseData(typeof(string), "test1", "test2", false).SetName("StringNotEqual");
// Primitive and enum test cases
yield return new TestCaseData(typeof(int), 1, 1, true).SetName("IntEqual");
yield return new TestCaseData(typeof(int), 1, 2, false).SetName("IntNotEqual");
yield return new TestCaseData(typeof(DayOfWeek), DayOfWeek.Monday, DayOfWeek.Monday, true).SetName("EnumEqual");
yield return new TestCaseData(typeof(DayOfWeek), DayOfWeek.Monday, DayOfWeek.Tuesday, false).SetName("EnumNotEqual");
// Array test cases
yield return new TestCaseData(typeof(int[]), new int[] { 1, 2, 3 }, new int[] { 1, 2, 3 }, true).SetName("ArrayEqual");
yield return new TestCaseData(typeof(int[]), new int[] { 1, 2, 3 }, new int[] { 1, 2, 4 }, false).SetName("ArrayNotEqual");
yield return new TestCaseData(typeof(int[]), new int[] { 1, 2, 3 }, new int[] { 1, 2 }, false).SetName("ArrayDifferentLength");
// Null test cases
yield return new TestCaseData(typeof(object), null, null, true).SetName("BothNull");
yield return new TestCaseData(typeof(object), new object(), null, false).SetName("OneNull");
yield return new TestCaseData(typeof(object), null, new object(), false).SetName("OneNullOtherWay");
}
}
[Test, TestCaseSource(nameof(ValueComparisonTestsCases))]
public void TestAreValuesEqual(Type fieldType, object valueCurrent, object valueDefault, bool expected)
{
bool result = AnalyticsUtils.AreValuesEqual(fieldType, valueCurrent, valueDefault);
Assert.AreEqual(expected, result);
}
private class TestClass { }
private static IEnumerable TypeComplexityTestCases
{
get
{
// Primitive types test cases
yield return new TestCaseData(typeof(int), false).SetName("IntIsNotComplex");
yield return new TestCaseData(typeof(double), false).SetName("DoubleIsNotComplex");
// Enum test cases
yield return new TestCaseData(typeof(DayOfWeek), false).SetName("EnumIsNotComplex");
// String test cases
yield return new TestCaseData(typeof(string), false).SetName("StringIsNotComplex");
// Array test cases
yield return new TestCaseData(typeof(int[]), false).SetName("IntArrayIsNotComplex");
yield return new TestCaseData(typeof(string[]), false).SetName("StringArrayIsNotComplex");
// Struct test cases
yield return new TestCaseData(typeof(DateTime), true).SetName("DateTimeIsComplex");
// Class test cases
yield return new TestCaseData(typeof(object), true).SetName("ObjectIsComplex");
yield return new TestCaseData(typeof(TestClass), true).SetName("CustomClassIsComplex");
}
}
[Test, TestCaseSource(nameof(TypeComplexityTestCases))]
public void TestIsComplexType(Type fieldType, bool expected)
{
bool result = AnalyticsUtils.IsComplexType(fieldType);
Assert.AreEqual(expected, result);
}
}
}