Files
Test/Library/PackageCache/com.unity.ugui@eb824e41fbc7/Tests/Runtime/UGUI/RaycastReceiver/RaycastReceiverTests.cs
T
2026-11-01 23:39:55 +02:00

258 lines
9.5 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.TestTools;
using UnityEngine.UI;
using NUnit.Framework;
[TestFixture]
internal class RaycastReceiverTests
{
private Canvas m_canvas;
private GraphicRaycaster m_raycaster;
private EventSystem m_eventSystem;
private RaycastReceiver m_receiver;
[SetUp]
public void Setup()
{
var canvasGO = new GameObject("Canvas", typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster));
m_canvas = canvasGO.GetComponent<Canvas>();
m_raycaster = canvasGO.GetComponent<GraphicRaycaster>();
m_canvas.renderMode = RenderMode.ScreenSpaceOverlay;
m_eventSystem = new GameObject("EventSystem").AddComponent<EventSystem>();
m_receiver = new GameObject("Receiver", typeof(RectTransform)).AddComponent<RaycastReceiver>();
m_receiver.transform.SetParent(m_canvas.transform);
// Ensure it has size so raycasts can hit it
var rt = m_receiver.GetComponent<RectTransform>();
rt.sizeDelta = new Vector2(100, 100);
rt.anchoredPosition = new Vector2(0, 0);
}
[TearDown]
public void TearDown()
{
Object.DestroyImmediate(m_canvas.gameObject);
Object.DestroyImmediate(m_eventSystem.gameObject);
m_canvas = null;
m_raycaster = null;
m_eventSystem = null;
m_receiver = null;
}
private void IsComponentInResults(Component graphic, List<RaycastResult> results, out bool exists)
{
exists = false;
foreach (var result in results)
{
if (result.gameObject == graphic.gameObject)
{
exists = true;
break;
}
}
}
[Test]
[Description("Makes sure that there is no geometry to be drawn by RaycastReceiver")]
public void RaycastReceiver_OnPopulateMesh_ClearsGeometry()
{
//Create a VertexHelper and add fake geometry
var vh = new VertexHelper();
vh.AddVert(new Vector3(0, 0, 0), Color.white, new Vector2(0, 0));
vh.AddVert(new Vector3(10, 0, 0), Color.white, new Vector2(1, 0));
vh.AddVert(new Vector3(10, 10, 0), Color.white, new Vector2(1, 1));
vh.AddTriangle(0, 1, 2);
Assert.AreEqual(3, vh.currentVertCount);
//Invoke OnPopulateMesh via reflection since it is protected
var methodInfo = typeof(RaycastReceiver).GetMethod(
"OnPopulateMesh",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance,
null,
new System.Type[] { typeof(VertexHelper) }, //Needed to avoid ambiguity
null
);
methodInfo.Invoke(m_receiver, new object[] { vh });
//Assert that the mesh was cleared (0 vertices)
Assert.AreEqual(0, vh.currentVertCount, "RaycastReceiver should clear the VertexHelper to remain invisible.");
}
[UnityTest]
public IEnumerator RaycastReceiver_InterceptsRaycast()
{
//Wait a frame to allow the canvas to process renderers
yield return null;
//Create PointerEventData at the center of the screen/canvas
PointerEventData pointerData = new PointerEventData(m_eventSystem)
{
position = new Vector2(Screen.width / 2f, Screen.height / 2f)
};
List<RaycastResult> results = new List<RaycastResult>();
m_raycaster.Raycast(pointerData, results);
//Verify that the RaycastReceiver intercepted the ray
IsComponentInResults(m_receiver, results, out bool exists);
Assert.IsTrue(exists, "RaycastReceiver should intercept raycasts when raycastTarget is true.");
}
[UnityTest]
public IEnumerator RaycastReceiver_IgnoreRaycast_WhenTargetFalse()
{
m_receiver.raycastTarget = false;
//Wait a frame to allow the canvas to process renderers
yield return null;
//Convert world position of receiver to screen point for raycast
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(null, m_receiver.transform.position);
PointerEventData pointerData = new PointerEventData(m_eventSystem) { position = screenPos };
List<RaycastResult> results = new List<RaycastResult>();
m_raycaster.Raycast(pointerData, results);
IsComponentInResults(m_receiver, results, out bool exists);
Assert.IsFalse(exists, "RaycastReceiver should NOT intercept raycasts when raycastTarget is false.");
}
[UnityTest]
public IEnumerator RaycastReceiver_RespectsMasking()
{
//Setup a game object with a Mask
var maskObj = new GameObject("Mask", typeof(RectTransform), typeof(Image), typeof(Mask));
maskObj.transform.SetParent(m_canvas.transform);
//Set mask size to 50x50
var maskRect = maskObj.GetComponent<RectTransform>();
maskRect.sizeDelta = new Vector2(50, 50);
maskRect.anchoredPosition = Vector2.zero;
//Move Receiver inside the mask hierarchy
m_receiver.transform.SetParent(maskObj.transform);
m_receiver.rectTransform.sizeDelta = new Vector2(20, 20);
//Position Receiver OUTSIDE the mask bounds (e.g., at x=100)
m_receiver.rectTransform.anchoredPosition = new Vector2(100, 0);
yield return null;
//Convert world position of receiver to screen point for raycast
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(null, m_receiver.transform.position);
PointerEventData pointerData = new PointerEventData(m_eventSystem) { position = screenPos };
List<RaycastResult> results = new List<RaycastResult>();
m_raycaster.Raycast(pointerData, results);
//Should NOT hit because it is masked out
IsComponentInResults(m_receiver, results, out bool hit);
Assert.IsFalse(hit, "RaycastReceiver should be ignored when outside of a parent Mask.");
//2nd test...
//Move Receiver INSIDE the mask bounds
m_receiver.rectTransform.anchoredPosition = Vector2.zero;
yield return null;
//Update screen position
screenPos = RectTransformUtility.WorldToScreenPoint(null, m_receiver.transform.position);
pointerData.position = screenPos;
results.Clear();
m_raycaster.Raycast(pointerData, results);
//Should HIT now
hit = false;
IsComponentInResults(m_receiver, results, out hit);
Assert.IsTrue(hit, "RaycastReceiver should be hit when inside a parent Mask.");
}
[UnityTest]
public IEnumerator RaycastReceiver_RespectsRectMask2D()
{
//Setup game object with RectMask2D
var maskObj = new GameObject("RectMask", typeof(RectTransform), typeof(RectMask2D));
maskObj.transform.SetParent(m_canvas.transform);
var maskRect = maskObj.GetComponent<RectTransform>();
maskRect.sizeDelta = new Vector2(50, 50);
maskRect.anchoredPosition = Vector2.zero;
//Move Receiver inside the mask hierarchy
m_receiver.transform.SetParent(maskObj.transform);
m_receiver.rectTransform.sizeDelta = new Vector2(20, 20);
//Position Receiver OUTSIDE the mask bounds
m_receiver.rectTransform.anchoredPosition = new Vector2(100, 0);
yield return null;
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(null, m_receiver.transform.position);
PointerEventData pointerData = new PointerEventData(m_eventSystem) { position = screenPos };
List<RaycastResult> results = new List<RaycastResult>();
m_raycaster.Raycast(pointerData, results);
IsComponentInResults(m_receiver, results, out bool hit);
Assert.IsFalse(hit, "RaycastReceiver should be ignored when outside of a parent RectMask2D.");
//2nd test...
//Move Receiver INSIDE the mask bounds
m_receiver.rectTransform.anchoredPosition = Vector2.zero;
yield return null;
//Update screen position
screenPos = RectTransformUtility.WorldToScreenPoint(null, m_receiver.transform.position);
pointerData.position = screenPos;
results.Clear();
m_raycaster.Raycast(pointerData, results);
//Should HIT now
hit = false;
IsComponentInResults(m_receiver, results, out hit);
Assert.IsTrue(hit, "RaycastReceiver should be hit when inside a parent RectMask2D.");
}
[UnityTest]
public IEnumerator RaycastReceiver_RespectsCanvasGroup_BlocksRaycasts()
{
//Add CanvasGroup to the receiver's parent (or the receiver itself)
var group = m_receiver.gameObject.AddComponent<CanvasGroup>();
group.blocksRaycasts = true;
yield return null;
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(null, m_receiver.transform.position);
PointerEventData pointerData = new PointerEventData(m_eventSystem) { position = screenPos };
List<RaycastResult> results = new List<RaycastResult>();
m_raycaster.Raycast(pointerData, results);
IsComponentInResults(m_receiver, results, out bool hit);
Assert.IsTrue(hit, "Should hit when CanvasGroup.blocksRaycasts is true.");
yield return null;
//2nd test...
//Disable blocksRaycasts
group.blocksRaycasts = false;
results.Clear();
m_raycaster.Raycast(pointerData, results);
hit = false;
IsComponentInResults(m_receiver, results, out hit);
Assert.IsFalse(hit, "Should NOT hit when CanvasGroup.blocksRaycasts is false.");
}
}