using System; using System.Reflection; using NUnit.Framework; using UnityEngine; using XGame.VirtualInput; public sealed class VirtualJoystickTests { private GameObject _root; [TearDown] public void TearDown() { if (_root != null) { UnityEngine.Object.DestroyImmediate(_root); _root = null; } } [Test] public void ApplyPointerInsideDeadZone_ReportsInactiveAndZero() { VirtualJoystick joystick = CreateJoystick(out _); ApplyPointer(joystick, new Vector2(106f, 100f)); Assert.That(joystick.IsActive, Is.False); Assert.That(joystick.Value, Is.EqualTo(Vector2.zero)); } [Test] public void ApplyPointerBeyondRadius_ClampsValueAndKnobTravel() { VirtualJoystick joystick = CreateJoystick(out RectTransform knob); ApplyPointer(joystick, new Vector2(300f, 100f)); Assert.That(joystick.IsActive, Is.True); Assert.That(joystick.Value.x, Is.EqualTo(1f).Within(0.001f)); Assert.That(joystick.Value.y, Is.EqualTo(0f).Within(0.001f)); Assert.That(knob.anchoredPosition.x, Is.EqualTo(24f).Within(0.001f)); Assert.That(knob.anchoredPosition.y, Is.EqualTo(0f).Within(0.001f)); } [Test] public void ReleasePointer_ResetsValueAndRaisesEnded() { VirtualJoystick joystick = CreateJoystick(out RectTransform knob); int ended = 0; joystick.Ended += () => ended++; ApplyPointer(joystick, new Vector2(300f, 100f)); ReleasePointer(joystick); Assert.That(joystick.IsActive, Is.False); Assert.That(joystick.Value, Is.EqualTo(Vector2.zero)); Assert.That(knob.anchoredPosition, Is.EqualTo(Vector2.zero)); Assert.That(ended, Is.EqualTo(1)); } [Test] public void IsScreenPositionInAcquireArea_UsesAcquireRadiusMultiplier() { VirtualJoystick joystick = CreateJoystick(out _); Assert.That(joystick.IsScreenPositionInAcquireArea(new Vector2(179f, 100f)), Is.True); Assert.That(joystick.IsScreenPositionInAcquireArea(new Vector2(181f, 100f)), Is.False); } private VirtualJoystick CreateJoystick(out RectTransform knob) { _root = new GameObject("UI_VirtualJoystick", typeof(RectTransform)); RectTransform rootRect = _root.GetComponent(); rootRect.sizeDelta = new Vector2(100f, 100f); GameObject knobObject = new GameObject("Knob", typeof(RectTransform)); knobObject.transform.SetParent(_root.transform, false); knob = knobObject.GetComponent(); knob.sizeDelta = new Vector2(52f, 52f); VirtualJoystick joystick = _root.AddComponent(); SetPrivateField(joystick, "screenCenterOverride", new Vector2(100f, 100f)); SetPrivateField(joystick, "screenRadiusOverride", 50f); InvokePrivate(joystick, "Awake"); return joystick; } private static void ApplyPointer(VirtualJoystick joystick, Vector2 screenPosition) { InvokePrivate(joystick, "ApplyPointer", screenPosition); } private static void ReleasePointer(VirtualJoystick joystick) { InvokePrivate(joystick, "ReleasePointer"); } private static void SetPrivateField(object target, string name, object value) { FieldInfo field = target.GetType().GetField(name, BindingFlags.Instance | BindingFlags.NonPublic); Assert.That(field, Is.Not.Null); field.SetValue(target, value); } private static void InvokePrivate(object target, string name, params object[] args) { MethodInfo method = target.GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic); Assert.That(method, Is.Not.Null); method.Invoke(target, args); } }