Initial commit

This commit is contained in:
2026-06-02 18:57:47 -04:00
commit 59d26a915d
268 changed files with 41240 additions and 0 deletions
@@ -0,0 +1,22 @@
{
"name": "BracerLib.Tests",
"rootNamespace": "BracerLib.Tests",
"references": [
"UnityEngine.TestRunner",
"BracerLib"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll",
"Moq.dll"
],
"autoReferenced": true,
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f994df8a4a2196f499e769b079127c12
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,12 @@
using UnityEngine;
using UnityEngine.TestTools;
namespace BracerLib.Tests
{
[ExecuteInEditMode]
[ExcludeFromCoverage]
public class MonoBehaviourTester : MonoBehaviour, IMonoBehaviourTest
{
public virtual bool IsTestFinished { get; set; }
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7e2baafc97e51834e89c53aaa65ddd67
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0ca20ad462434c06ad77f83ad433b8e3
timeCreated: 1778953578
@@ -0,0 +1,130 @@
using System;
using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Assert = UnityEngine.Assertions.Assert;
namespace BracerLib.Tests.Objects
{
public class ObjectLifetimeTests : TestBase
{
private class SomeDisposable : IDisposable
{
public bool IsDisposed { get; private set; }
public void Dispose()
{
if (IsDisposed)
return;
IsDisposed = true;
GC.SuppressFinalize(this);
}
}
private SomeDisposable disposableObject;
private SomeDisposable disposableFuncObject;
private GameObject singleTestLifetimeObject;
private GameObject singleTestLifetimeFuncObject;
private GameObject completeTestLifetimeObject;
private GameObject completeTestLifetimeFuncObject;
private bool singleTestWasCreated;
[UnityTest, Order(1)]
public IEnumerator SetUpOneTimeObjects()
{
completeTestLifetimeObject = new GameObject("full lifetime");
RegisterOneTimeTestObject(completeTestLifetimeObject);
yield return null;
Assert.IsTrue(completeTestLifetimeObject != null);
completeTestLifetimeFuncObject = RegisterOneTimeTestObject(GetNewObject);
yield return null;
Assert.IsTrue(completeTestLifetimeFuncObject != null);
}
/// <summary>
/// Not here to test Unity code, but want to run through a basic shift of the object position.
/// </summary>
[UnityTest, Order(2)]
public IEnumerator TempUnityObjectMovesCorrectly()
{
Assert.IsFalse(singleTestWasCreated);
singleTestLifetimeObject = new GameObject("singleTestLifetime");
RegisterTempTestObject(singleTestLifetimeObject);
singleTestLifetimeFuncObject = RegisterTempTestObject(GetNewObject);
singleTestWasCreated = true;
Assert.IsTrue(singleTestWasCreated);
yield return null;
var testTransform = singleTestLifetimeObject.transform;
var tPos = testTransform.position;
var lastPos = tPos;
tPos = Vector3.one;
testTransform.position = tPos;
Assert.IsTrue(tPos != lastPos);
testTransform.Translate(Vector3.up);
yield return null;
tPos = testTransform.position;
Assert.IsTrue(tPos != lastPos);
}
[UnityTest, Order(3)]
public IEnumerator TempUnityObjectNoLongerExistsAfterPreviousTest()
{
Assert.IsTrue(singleTestWasCreated);
Assert.IsNull(singleTestLifetimeObject);
Assert.IsNull(singleTestLifetimeFuncObject);
yield return null;
}
[UnityTest, Order(4)]
public IEnumerator OneTimeObjectStillExists()
{
Assert.IsTrue(completeTestLifetimeObject != null);
Assert.IsTrue(completeTestLifetimeFuncObject != null);
yield return null;
}
[Test, Order(5)]
public void RegisterDisposableObject()
{
disposableObject = new SomeDisposable();
RegisterDisposableTempTestObject(disposableObject);
Assert.IsNotNull(disposableObject);
Assert.IsFalse(disposableObject.IsDisposed);
disposableFuncObject = RegisterDisposableTempTestObject(() => new SomeDisposable());
Assert.IsNotNull(disposableFuncObject);
Assert.IsFalse(disposableFuncObject.IsDisposed);
}
[Test, Order(6)]
public void CheckIfDisposableObjectHasDisposed()
{
Assert.IsNotNull(disposableObject);
Assert.IsTrue(disposableObject.IsDisposed);
disposableObject = null;
Assert.IsNotNull(disposableFuncObject);
Assert.IsTrue(disposableFuncObject.IsDisposed);
disposableObject = null;
}
private GameObject GetNewObject() => new GameObject();
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 78520c491186453a91097eac4579ed75
timeCreated: 1778931474
@@ -0,0 +1,55 @@
using System.Collections;
using Moq;
using NUnit.Framework;
using UnityEngine;
namespace BracerLib.Tests.Objects
{
public interface ITester
{
void Test();
}
public class Tester : ITester
{
public void Test() {}
}
public class MockComponent : MonoBehaviour
{
private ITester tester;
public void DoTest()
{
tester.Test();
}
}
public class ObjectMockTests : TestBase
{
private MockComponent mockComponent;
private Mock<ITester> testerMock;
protected override IEnumerator UnityOneTimeSetUp()
{
testerMock = new Mock<ITester>();
var go = new GameObject("mock test obj");
mockComponent = go.AddComponent<MockComponent>();
RegisterOneTimeTestObject(go);
SetReflectedValue(mockComponent, "tester", testerMock.Object);
yield return null;
}
[Test]
public void TestMock()
{
testerMock.Setup(x => x.Test());
mockComponent.DoTest();
testerMock.Verify(x => x.Test(), Times.Once);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 45e688432fb9423e8efb7c88cdbd9785
timeCreated: 1779762115
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 82e81a731adf4d6fbab5315db59006d2
timeCreated: 1778983978
@@ -0,0 +1,130 @@
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.TestTools;
namespace BracerLib.Tests.Properties
{
public class PropertyTests : TestBase
{
public class SomeObject : MonoBehaviour
{
public DependencyA dependencyA;
[SerializeField]
private DependencyB dependencyB1;
[SerializeField]
private DependencyB dependencyB2;
[SerializeField]
private DependencyB dependencyB3;
private DependencyC dependencyC;
private DependencyD dependencyD;
private ValueDependency valueDependency;
private int someValue;
public DependencyB DependencyB1 => dependencyB1;
public DependencyB DependencyB2 => dependencyB2;
public DependencyB DependencyB3 => dependencyB3;
public DependencyC DependencyC => dependencyC;
public DependencyD DependencyD => dependencyD;
public ValueDependency ValueDependency => valueDependency;
public int SomeValue => someValue;
}
public class DependencyA : MonoBehaviour
{
public int Value => 1;
}
public class DependencyB : MonoBehaviour
{
public int Value => 2;
}
public class DependencyC : MonoBehaviour
{
public int Value => 3;
}
[Serializable]
public class DependencyD { }
public struct ValueDependency
{
public int Value;
}
private GameObject setupGameObject;
private SomeObject setupSomeObject;
private DependencyA setupDependencyA;
protected override IEnumerator UnityOneTimeSetUp()
{
setupGameObject = new GameObject("setup");
setupSomeObject = setupGameObject.AddComponent<SomeObject>();
setupDependencyA = setupGameObject.AddComponent<DependencyA>();
setupSomeObject.dependencyA = setupDependencyA;
RegisterOneTimeTestObject(setupSomeObject);
yield return null;
}
[UnityTest]
public IEnumerator TestProperties()
{
Assert.IsNotNull(setupSomeObject);
Assert.IsNotNull(setupDependencyA);
// Set Serialized private Mono
var depB = new[] { setupGameObject.AddComponent<DependencyB>(), setupGameObject.AddComponent<DependencyB>(), setupGameObject.AddComponent<DependencyB>() };
SetObjectReference(setupSomeObject, "dependencyB1", depB[0]);
SetObjectReferences(setupSomeObject, ("dependencyB2", depB[1]), ("dependencyB3", depB[2]));
// Set Reflected private Mono
var depC = setupGameObject.AddComponent<DependencyC>();
SetReflectedValue(setupSomeObject, "dependencyC", depC);
// Set Reflected private POCO
// Set Reflected private value
var depD = new DependencyD();
var valueDependency = new ValueDependency { Value = 255 };
SetReflectedValues(setupSomeObject, ("dependencyD", depD), ("valueDependency", valueDependency));
yield return null;
Assert.IsNotNull(depB[0]);
Assert.IsNotNull(setupSomeObject.DependencyB1);
Assert.AreEqual(depB[0], setupSomeObject.DependencyB1);
Assert.IsNotNull(depB[1]);
Assert.IsNotNull(setupSomeObject.DependencyB2);
Assert.AreEqual(depB[1], setupSomeObject.DependencyB2);
Assert.IsNotNull(depB[2]);
Assert.IsNotNull(setupSomeObject.DependencyB3);
Assert.AreEqual(depB[2], setupSomeObject.DependencyB3);
Assert.IsNotNull(depC);
Assert.IsNotNull(setupSomeObject.DependencyC);
Assert.AreEqual(depC, setupSomeObject.DependencyC);
Assert.IsNotNull(depD);
Assert.IsNotNull(setupSomeObject.DependencyD);
Assert.AreEqual(depD, setupSomeObject.DependencyD);
Assert.AreEqual(setupSomeObject.ValueDependency.Value, valueDependency.Value);
}
[UnityTest]
public IEnumerator TestPropertyErrors()
{
yield return null;
SetReflectedValue(setupSomeObject, "someFakeValue", 1);
LogAssert.Expect(LogType.Warning, "There is no property someFakeValue to the target object.");
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ce9835c5996a47e6a286fabb5d421d3e
timeCreated: 1778983994
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f662576f6c6c422d810fcd5290ec107c
timeCreated: 1778977478
+45
View File
@@ -0,0 +1,45 @@
using System.Collections;
using UnityEngine.Assertions;
using UnityEngine.SceneManagement;
using UnityEngine.TestTools;
namespace BracerLib.Tests.Scenes
{
public class SceneTests : TestBase
{
private Scene oneTimeScene;
private Scene testScene;
[UnityTest]
public IEnumerator CloseSceneWithZeroScenesRegistered()
{
var sceneCount = SceneManager.loadedSceneCount;
Assert.IsTrue(sceneCount > 0);
yield return CloseLatestScene();
Assert.IsTrue(SceneManager.loadedSceneCount == sceneCount);
}
[UnityTest]
public IEnumerator CreateScenesWithSpecificLifetimes()
{
yield return OpenScene("Scenes/Tests/Test_Empty", true);
oneTimeScene = SceneManager.GetSceneAt(SceneManager.loadedSceneCount - 1);
Assert.IsTrue(oneTimeScene.isLoaded);
yield return OpenScene("Scenes/Tests/Test_Empty");
testScene = SceneManager.GetSceneAt(SceneManager.loadedSceneCount - 1);
Assert.IsTrue(testScene.isLoaded);
}
[UnityTest]
public IEnumerator TestSceneLifetimes()
{
yield return null;
Assert.IsTrue(oneTimeScene.isLoaded);
Assert.IsFalse(testScene.isLoaded);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6c5d9b3d87fe4f1dab685f84ed847fdf
timeCreated: 1778977483
+413
View File
@@ -0,0 +1,413 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using Moq;
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.TestTools;
using Object = UnityEngine.Object;
namespace BracerLib.Tests
{
[ExcludeFromCodeCoverage, ExcludeFromCoverage]
public class TestBase
{
// private readonly IDictionary<Object, SerializedObject> globalPropertyCache;
private readonly IDictionary<Object, SerializedObject> objectPropertyCache;
private readonly Queue<Object> destroyOnTestEnd;
private readonly Stack<Scene> closeOnTestEnd;
private readonly Queue<IDisposable> disposeOnTestEnd;
private readonly Queue<Object> destroyOnOneTimeEnd;
private readonly Stack<Scene> closeOnOneTimeEnd;
private readonly Queue<IDisposable> disposeOnOneTimeEnd;
[ExcludeFromCoverage]
protected TestBase()
{
// globalPropertyCache = new Dictionary<Object, SerializedObject>();
objectPropertyCache = new Dictionary<Object, SerializedObject>();
destroyOnTestEnd = new Queue<Object>();
closeOnTestEnd = new Stack<Scene>();
disposeOnTestEnd = new Queue<IDisposable>();
destroyOnOneTimeEnd = new Queue<Object>();
closeOnOneTimeEnd = new Stack<Scene>();
disposeOnOneTimeEnd = new Queue<IDisposable>();
}
/// <summary>
/// Called as part of NUnit framework. Override <see cref="OneTimeSetUp"/> instead.
/// </summary>
[OneTimeSetUp, ExcludeFromCoverage]
public void DoOneTimeSetUp()
{
OneTimeSetUp();
}
[UnityOneTimeSetUp, ExcludeFromCoverage]
public IEnumerator DoUnityOneTimeSetUp()
{
yield return UnityOneTimeSetUp();
}
/// <summary>
/// Called as part of NUnit framework. Override <see cref="SetUp"/> instead.
/// </summary>
[SetUp, ExcludeFromCoverage]
public void DoSetUp()
{
SetUp();
}
[UnitySetUp, ExcludeFromCoverage]
public IEnumerator DoUnitySetUp()
{
yield return UnitySetUp();
}
/// <summary>
/// Called as part of NUnit framework. Override <see cref="TearDown"/> instead.
/// </summary>
[TearDown, ExcludeFromCoverage]
public void DoTearDown()
{
TearDown();
objectPropertyCache.Clear();
}
[UnityTearDown, ExcludeFromCoverage]
public IEnumerator DoUnityTearDown()
{
yield return UnityTearDown();
Reset();
while (closeOnTestEnd.Count > 0)
yield return CloseLatestScene();
}
/// <summary>
/// Called as part of NUnit framework. Override <see cref="OneTimeTearDown"/> instead.
/// </summary>
[OneTimeTearDown, ExcludeFromCoverage]
public void DoOneTimeTearDown()
{
OneTimeTearDown();
}
[UnityOneTimeTearDown, ExcludeFromCoverage]
public IEnumerator DoUnityOneTimeTearDown()
{
yield return UnityOneTimeTearDown();
CleanupUnityObjects(destroyOnOneTimeEnd);
CleanupDisposableObjects(disposeOnOneTimeEnd);
while (closeOnOneTimeEnd.Count > 0)
yield return CloseLatestScene(true);
}
/// <summary>
/// Pass a Unity object that will be destroyed at the end of the test.
/// </summary>
protected T RegisterTempTestObject<T>(T obj) where T : Object
{
destroyOnTestEnd.Enqueue(obj);
return obj;
}
/// <summary>
/// Pass a function that generates or returns a Unity object that will be destroyed at the end of the test.
/// </summary>
protected T RegisterTempTestObject<T>(Func<T> generator) where T : Object
{
var obj = generator();
return RegisterTempTestObject(obj);
}
/// <summary>
/// Pass a Unity object that will be destroyed at the end of all the tests in a given suite.
/// </summary>
protected T RegisterOneTimeTestObject<T>(T obj) where T : Object
{
destroyOnOneTimeEnd.Enqueue(obj);
return obj;
}
/// <summary>
/// Pass a function that generates or returns a Unity object that will be destroyed at the end of all the tests in a given suite.
/// </summary>
protected T RegisterOneTimeTestObject<T>(Func<T> generator) where T : Object
{
var obj = generator();
return RegisterOneTimeTestObject(obj);
}
/// <summary>
/// Pass a disposable object that will be cleaned up at the end of the test.
/// </summary>
protected T RegisterDisposableTempTestObject<T>(T obj) where T : IDisposable
{
disposeOnTestEnd.Enqueue(obj);
return obj;
}
/// <summary>
/// Pass a function that generates or returns a disposable object that will be cleaned up at the end of the test.
/// </summary>
/// <param name="generator"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
protected T RegisterDisposableTempTestObject<T>(Func<T> generator) where T : IDisposable
{
var obj = generator();
return RegisterDisposableTempTestObject(obj);
}
/// <summary>
/// Pass a disposable object that will be cleaned up at the end of the test.
/// </summary>
protected T RegisterDisposableOneTimeTestObject<T>(T obj) where T : IDisposable
{
disposeOnOneTimeEnd.Enqueue(obj);
return obj;
}
/// <summary>
/// Pass a function that generates or returns a disposable object that will be cleaned up at the end of the test.
/// </summary>
/// <param name="generator"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
protected T RegisterDisposableOneTimeTestObject<T>(Func<T> generator) where T : IDisposable
{
var obj = generator();
return RegisterDisposableOneTimeTestObject(obj);
}
protected IEnumerator OpenScene(string scenePath, bool isOneTime = false)
{
var asyncOp = SceneManager.LoadSceneAsync(scenePath, LoadSceneMode.Additive);
asyncOp!.completed += SetLoadedSceneActive;
yield return asyncOp;
var loadedScene = SceneManager.GetSceneAt(SceneManager.loadedSceneCount - 1);
if (!isOneTime)
closeOnTestEnd.Push(loadedScene);
else
closeOnOneTimeEnd.Push(loadedScene);
}
protected IEnumerator CloseLatestScene(bool isOneTime = false)
{
var targetStack = !isOneTime ? closeOnTestEnd : closeOnOneTimeEnd;
if (!targetStack.TryPop(out var targetScene))
yield break;
var asyncOp = SceneManager.UnloadSceneAsync(targetScene);
asyncOp!.completed += SetLoadedSceneActive;
yield return asyncOp;
}
protected void SetLoadedSceneActive(AsyncOperation asyncOperation)
{
SceneManager.SetActiveScene(SceneManager.GetSceneAt(SceneManager.loadedSceneCount - 1));
}
[ExcludeFromCoverage]
protected virtual void OneTimeSetUp() { }
[ExcludeFromCoverage]
protected virtual IEnumerator UnityOneTimeSetUp()
{
yield return null;
}
protected virtual void SetUp() { }
protected virtual IEnumerator UnitySetUp()
{
yield return null;
}
protected virtual void TearDown() { }
protected virtual IEnumerator UnityTearDown()
{
yield return null;
}
[ExcludeFromCoverage]
protected virtual void OneTimeTearDown() { }
[ExcludeFromCoverage]
protected virtual IEnumerator UnityOneTimeTearDown()
{
yield return null;
}
/// <summary>
/// Set a private value member of an object via C# reflection.
/// </summary>
/// <example><code>
/// public class SomeObject {
/// private int item;
/// }
///
/// var obj = new SomeObject();
/// SetReflectedValue(obj, "item", 25);
/// </code></example>
private protected void SetReflectedValue(object targetObject, string targetProperty, object targetValue)
{
SetReflectedValue(targetObject, targetObject.GetType(), targetProperty, targetValue);
}
private protected void SetReflectedValues(object targetObject, params ValueTuple<string, object>[] properties)
{
var type = targetObject.GetType();
for (var i = 0; i < properties.Length; i++)
SetReflectedValue(targetObject, type, properties[i].Item1, properties[i].Item2);
}
/// <summary>
/// Set a non-interface reference member of a MonoBehaviour via Unity reflection.
/// Will be applied depending on context of Test setup being used.
/// </summary>
/// <example><code>
/// public class SomeOtherObject { }
///
/// public class SomeObject : MonoBehaviour {
/// private SomeOtherObject item;
/// }
///
/// var gameObj = new GameObject("SomeObj");
/// var c = gameObj.AddComponent(typeof(SomeObject));
/// var someOtherObj = new SomeOtherObj();
///
/// SetObjectReference(c, "item", someOtherObj);
/// </code></example>
private protected void SetObjectReference(Object targetObj, string targetValue, Object value)
{
if (!objectPropertyCache.TryGetValue(targetObj, out var serializedObject))
{
serializedObject = new SerializedObject(targetObj);
objectPropertyCache.Add(targetObj, serializedObject);
}
var property = serializedObject.FindProperty(targetValue);
property.objectReferenceValue = value;
serializedObject.ApplyModifiedProperties();
}
/// <summary>
/// Set a non-interface reference member of a MonoBehaviour via Unity reflection.
/// Will be applied depending on context of Test setup being used.
/// </summary>
/// <example><code>
/// public class SomeObject : MonoBehaviour {
/// private SomeOtherObject item1;
/// private SomeAdditionalObject item2;
/// }
///
/// var gameObj = new GameObject("SomeObj");
/// var c = gameObj.AddComponent(typeof(SomeObject));
///
/// SetObjectReference(c, a);
/// </code></example>
private protected void SetObjectReferences(Object targetObj, params ValueTuple<string, Object>[] properties)
{
for (var i = 0; i < properties.Length; i++)
SetObjectReference(targetObj, properties[i].Item1, properties[i].Item2);
}
private void SetReflectedValue(object targetObject, Type type, string targetProperty, object targetValue)
{
var fieldProperty = type.GetField(targetProperty, BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldProperty == null)
{
Debug.LogWarning($"There is no property {targetProperty} to the target object.");
return;
}
fieldProperty.SetValue(targetObject, targetValue);
}
private void Reset()
{
ResetAllMocks();
CleanupDisposableObjects(disposeOnTestEnd);
CleanupUnityObjects(destroyOnTestEnd);
}
private void CleanupUnityObjects(Queue<Object> unityObjects)
{
if (unityObjects.Count == 0)
return;
while (unityObjects.Count != 0)
{
var temp = unityObjects.Dequeue();
if (temp != null)
Object.DestroyImmediate(temp);
}
}
private void CleanupDisposableObjects(Queue<IDisposable> disposableObjects)
{
if (disposableObjects.Count == 0)
return;
while (disposableObjects.Count != 0)
{
var temp = disposableObjects.Dequeue();
temp?.Dispose();
}
}
[ExcludeFromCoverage]
private void ResetAllMocks()
{
var mocks = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(f => f.FieldType == typeof(Mock)).Select(f => (Mock)f.GetValue(this));
foreach (var m in mocks)
m.Reset();
}
// [ExcludeFromCoverage]
// private void Apply(bool isGlobal = false)
// {
// ApplyPropertyCache(objectPropertyCache);
// }
//
// [ExcludeFromCoverage]
// private void ApplyPropertyCache(IDictionary<Object, SerializedObject> cache)
// {
// if (cache.Count == 0)
// return;
//
// foreach (var pair in cache)
// pair.Value.ApplyModifiedProperties();
// }
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f1863291fabd7fb43837115239feede3
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c3b38a9a1e7f41b8849eb925b8dda6ef
timeCreated: 1686834699
@@ -0,0 +1,63 @@
using System.Collections;
using BracerLib.Utility;
using NUnit.Framework;
using UnityEngine;
namespace BracerLib.Tests.Utility
{
public class MathUtilityTests : TestBase
{
private static IEnumerable BoundValues()
{
yield return new TestCaseData(2, 1, 3, 2).SetName("Value is between bounds");
yield return new TestCaseData(0, 1, 3, 3).SetName("Value is below bounds");
yield return new TestCaseData(4, 1, 3, 1).SetName("Value is above bounds");
}
private static IEnumerable BetweenValuesInt()
{
yield return new TestCaseData(0, -1, 1, BoundsInclusivity.None, true).SetName("Value is between bounds");
yield return new TestCaseData(-2, -1, 1, BoundsInclusivity.None, false).SetName("Value is below bounds");
yield return new TestCaseData(2, -1, 1, BoundsInclusivity.None, false).SetName("Value is above bounds");
yield return new TestCaseData(-1, -1, 1, BoundsInclusivity.Both, true).SetName("Value is at bound, inclusive both");
yield return new TestCaseData(-1, -1, 1, BoundsInclusivity.Left, true).SetName("Value is at bound, inclusive left");
yield return new TestCaseData(1, -1, 1, BoundsInclusivity.Right, true).SetName("Value is at bound, inclusive right");
yield return new TestCaseData(1, -1, 1, BoundsInclusivity.Both, true).SetName("Value is at bound, exclusive");
}
private static IEnumerable BetweenValuesFloat()
{
yield return new TestCaseData(0f, -1f, 1f, BoundsInclusivity.None, true).SetName("Value is between bounds");
yield return new TestCaseData(-2f, -1f, 1f, BoundsInclusivity.None, false).SetName("Value is below bounds");
yield return new TestCaseData(2f, -1f, 1f, BoundsInclusivity.None, false).SetName("Value is above bounds");
yield return new TestCaseData(-1f, -1f, 1f, BoundsInclusivity.Both, true).SetName("Value is at bound, inclusive both");
yield return new TestCaseData(-1f, -1f, 1f, BoundsInclusivity.Left, true).SetName("Value is at bound, inclusive left");
yield return new TestCaseData(1f, -1f, 1f, BoundsInclusivity.Right, true).SetName("Value is at bound, inclusive right");
yield return new TestCaseData(1f, -1f, 1f, BoundsInclusivity.Both, true).SetName("Value is at bound, exclusive");
}
[Test]
[TestCaseSource(nameof(BoundValues))]
public void ValuesAreWithinBounds(int value, int min, int max, int expected)
{
var result = MathUtility.KeepWithinBounds(value, min, max);
Assert.That(result, Is.EqualTo(expected));
}
[Test]
[TestCaseSource(nameof(BetweenValuesInt))]
public void ValuesBetweenBounds(int value, int min, int max, BoundsInclusivity inclusivity, bool expected)
{
var result = MathUtility.IsBetween(value, min, max, inclusivity);
Assert.That(result, Is.EqualTo(expected));
}
[Test]
[TestCaseSource(nameof(BetweenValuesFloat))]
public void ValuesBetweenBoundsFloat(float value, float min, float max, BoundsInclusivity inclusivity, bool expected)
{
var result = MathUtility.IsBetween(value, min, max, inclusivity);
Assert.That(result, Is.EqualTo(expected));
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4fcf35728772424c9c2c84e29290ac5e
timeCreated: 1780244918
@@ -0,0 +1,129 @@
using System;
using System.Collections;
using System.Collections.Generic;
using BracerLib.Utility;
using NUnit.Framework;
using UnityEngine;
namespace BracerLib.Tests.Utility
{
public class TriangulatorTest : TestBase
{
private static IEnumerable AreaValueTests()
{
var points = new List<Vector2>();
yield return new TestCaseData(points.ToArray(), 0f).SetName("No points to calculate");
points.AddRange(new[]
{
Vector2.one,
new Vector2(5f, 7f),
new Vector2(-2f, 8f)
});
yield return new TestCaseData(points.ToArray(), 23f).SetName("Area of a triangle");
points.Add(new Vector2(3f, 5f));
yield return new TestCaseData(points.ToArray(), 10f).SetName("Area of a quad");
}
private static IEnumerable InsideTrianglePointsTest()
{
yield return new TestCaseData(
Vector2.zero,
new Vector2(3f, 3f),
new Vector2(3f, 0f),
new Vector2(2f, 1f),
true
).SetName("Point inside triangle");
yield return new TestCaseData(
Vector2.zero,
new Vector2(3f, 3f),
new Vector2(3f, 0f),
new Vector2(1f, 0f),
true
).SetName("Point on the line");
yield return new TestCaseData(
Vector2.zero,
new Vector2(3f, 3f),
new Vector2(3f, 0f),
new Vector2(3f, 0f),
false
).SetName("Point is one of triangle points");
yield return new TestCaseData(
Vector2.zero,
new Vector2(3f, 3f),
new Vector2(3f, 0f),
new Vector2(-2f, 1f),
false
).SetName("Point outside triangle");
}
private static IEnumerable TriangulatePointsTest()
{
yield return new TestCaseData(
new[]
{
Vector2.zero,
Vector2.right,
Vector2.right + Vector2.up,
Vector2.up,
Vector2.left + Vector2.up,
Vector2.left
},
new[] { 5,3,2,2,0,5,5,4,3,2,1,0 }
).SetName("Positive triangulation");
yield return new TestCaseData(
new[]
{
Vector2.zero,
Vector2.right,
Vector2.right + Vector2.down,
Vector2.down,
Vector2.left + Vector2.down,
Vector2.left
},
new[] { 1,3,4,4,0,1,1,2,3,4,5,0 }
).SetName("Negative triangulation");
yield return new TestCaseData(
new[] { Vector2.zero, Vector2.right },
Array.Empty<int>()
).SetName("Empty triangulation");
}
[Test]
[TestCaseSource(nameof(AreaValueTests))]
public void AreaCalculatesCorrectly(Vector2[] points, float expected)
{
var result = Triangulator.Area(points);
Assert.AreEqual(expected, result);
}
[Test]
[TestCaseSource(nameof(InsideTrianglePointsTest))]
public void PointsInsideTriangleCorrectly(Vector2 a, Vector2 b, Vector2 c, Vector2 p, bool expected)
{
var result = Triangulator.InsideTriangle(a, b, c, p);
Assert.AreEqual(expected, result);
}
[Test]
[TestCaseSource(nameof(TriangulatePointsTest))]
public void TriangulatePoints(Vector2[] points, int[] expected)
{
var result = Triangulator.Triangulate(points);
Assert.AreEqual(expected.Length, result.Length);
for (var i = 0; i < result.Length; i++)
{
Assert.AreEqual(expected[i], result[i]);
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0a7aaa2ed31747e5ae172f296a2808e3
timeCreated: 1686834708