using System.Collections; using System.Collections.Generic; using NUnit.Framework; using UnityEngine.XR.OpenXR.Features; using UnityEngine.XR.OpenXR.Features.Mock; using UnityEngine.TestTools; using UnityEngine.TestTools.Utils; using UnityEngine.XR.OpenXR.NativeTypes; namespace UnityEngine.XR.OpenXR.Tests { /// /// Defines tests that validate the MockRuntime itself. /// internal class MockRuntimeTests : OpenXRLoaderSetup { [UnityTest] public IEnumerator TransitionToState() { InitializeAndStart(); yield return new WaitForXrFrame(); Assert.AreEqual(MockRuntime.sessionState, XrSessionState.Focused, "MockRuntime must be in focused state for this test to work correctly"); Assert.IsTrue(MockRuntime.TransitionToState(XrSessionState.Visible, false), "Failed to transition to visible state"); Assert.AreEqual(MockRuntime.sessionState, XrSessionState.Visible); } [UnityTest] public IEnumerator TransitionToStateForced() { InitializeAndStart(); yield return new WaitForXrFrame(); Assert.IsFalse(MockRuntime.TransitionToState(XrSessionState.Synchronized, false), "Synchronized state must be an invalid transition for this test to be valid"); Assert.IsTrue(MockRuntime.TransitionToState(XrSessionState.Synchronized, true), "Force state transition should not return false"); yield return new WaitForXrFrame(); Assert.IsTrue(MockRuntime.sessionState == XrSessionState.Synchronized); } [UnityTest] public IEnumerator CreateSessionFailure() { bool sawCreateSession = false; MockRuntime.Instance.TestCallback = (methodName, param) => { if (methodName == nameof(OpenXRFeature.OnSessionCreate)) { sawCreateSession = true; } return true; }; MockRuntime.SetFunctionCallback("xrCreateSession", (name) => XrResult.RuntimeFailure); base.InitializeAndStart(); yield return null; Assert.IsFalse(sawCreateSession); } static XrResult[] beginSessionSuccessResults = new XrResult[] { XrResult.Success, XrResult.LossPending }; [UnityTest] public IEnumerator BeginSessionSuccessWithValues([ValueSource("beginSessionSuccessResults")] XrResult successResult) { var states = new List(); MockRuntime.Instance.TestCallback = (methodName, param) => { if (methodName == nameof(OpenXRFeature.OnSessionStateChange)) { var newState = (XrSessionState)((MockRuntime.XrSessionStateChangedParams)param).NewState; states.Add(newState); } return true; }; MockRuntime.SetFunctionCallback("xrBeginSession", (name) => successResult); base.InitializeAndStart(); yield return null; Assert.IsTrue(base.IsRunning()); switch (successResult) { case XrResult.Success: Assert.IsTrue(states.Contains(XrSessionState.Ready)); Assert.IsTrue(states.Contains(XrSessionState.Synchronized)); Assert.IsTrue(states.Contains(XrSessionState.Visible)); Assert.IsTrue(states.Contains(XrSessionState.Focused)); break; case XrResult.LossPending: Assert.IsTrue(states.Contains(XrSessionState.Ready)); Assert.IsFalse(states.Contains(XrSessionState.Synchronized)); Assert.IsFalse(states.Contains(XrSessionState.Visible)); Assert.IsFalse(states.Contains(XrSessionState.Focused)); break; } } [UnityTest] public IEnumerator BeginSessionFailure() { var states = new List(); MockRuntime.Instance.TestCallback = (methodName, param) => { if (methodName == nameof(OpenXRFeature.OnSessionStateChange)) { var newState = (XrSessionState)((MockRuntime.XrSessionStateChangedParams)param).NewState; states.Add(newState); } return true; }; MockRuntime.SetFunctionCallback("xrBeginSession", (name) => XrResult.RuntimeFailure); InitializeAndStart(); yield return null; Assert.IsTrue(base.IsRunning()); Assert.IsTrue(states.Contains(XrSessionState.Ready)); Assert.IsFalse(states.Contains(XrSessionState.Synchronized)); Assert.IsFalse(states.Contains(XrSessionState.Visible)); Assert.IsFalse(states.Contains(XrSessionState.Focused)); } #if false // TEST WAS UNSTABLE, DISABLING FOR RELEASE ONLY [UnityTest] public IEnumerator TestRequestExitShutsdownSubsystems() { bool sawSessionDestroy = false; MockRuntime.Instance.TestCallback = (methodName, param) => { if (methodName == nameof(OpenXRFeature.OnSessionDestroy)) { sawSessionDestroy = true; } return true; }; AddExtension(MockRuntime.XR_UNITY_mock_test); base.InitializeAndStart(); yield return null; Assert.IsTrue(base.IsRunning()); var wait = new WaitForLoaderShutdown(Loader); MockDriver.RequestExitSession(MockRuntime.Instance.XrSession); yield return wait; Assert.IsTrue(sawSessionDestroy); } #endif [UnityTest] public IEnumerator RequestExitSession() { InitializeAndStart(); // Wait for a single XrFrame to make sure OpenXR is up and running yield return new WaitForXrFrame(); // Request the session exit which should shutdown OpenXR MockRuntime.RequestExitSession(); // Wait for OpenXR to shutdown yield return new WaitForLoaderShutdown(); } [UnityTest] public IEnumerator CauseInstanceLoss() { bool instanceLost = false; MockRuntime.Instance.TestCallback = (methodName, param) => { if (methodName == nameof(OpenXRFeature.OnInstanceLossPending)) { instanceLost = true; } return true; }; InitializeAndStart(); yield return null; MockRuntime.CauseInstanceLoss(); yield return new WaitForLoaderShutdown(); Assert.IsTrue(instanceLost); } [UnityTest] public IEnumerator DisplayTransparent() { AddExtension(MockRuntime.XR_UNITY_mock_test); MockRuntime.Instance.TestCallback = (methodName, param) => { if (methodName == nameof(OpenXRFeature.OnInstanceCreate)) { MockRuntime.ChooseEnvironmentBlendMode(XrEnvironmentBlendMode.Additive); } return true; }; base.InitializeAndStart(); yield return null; var displays = new List(); SubsystemManager.GetSubsystems(displays); Assert.AreEqual(false, displays[0].displayOpaque); } [UnityTest] public IEnumerator DisplayOpaque() { base.InitializeAndStart(); yield return null; var displays = new List(); SubsystemManager.GetSubsystems(displays); Assert.AreEqual(true, displays[0].displayOpaque); } [UnityTest] public IEnumerator MultipleEnvironmentBlendModes() { //Mock available environmentBlendModes are Opaque and Additive in mock_runtime.cpp EnumerateEnvironmentBlendModes. AddExtension(MockRuntime.XR_UNITY_mock_test); base.InitializeAndStart(); yield return null; //check default mode is Opaque. Assert.AreEqual(XrEnvironmentBlendMode.Opaque, MockRuntime.GetXrEnvironmentBlendMode()); //Switch to another supported mode - Additive. MockRuntime.ChooseEnvironmentBlendMode(XrEnvironmentBlendMode.Additive); yield return new WaitForXrFrame(2); Assert.AreEqual(XrEnvironmentBlendMode.Additive, MockRuntime.GetXrEnvironmentBlendMode()); //Set to unsupported mode - Alpha_blend MockRuntime.ChooseEnvironmentBlendMode(XrEnvironmentBlendMode.AlphaBlend); yield return new WaitForXrFrame(2); Assert.AreNotEqual(XrEnvironmentBlendMode.AlphaBlend, MockRuntime.GetXrEnvironmentBlendMode()); } [UnityTest] public IEnumerator BoundaryPoints() { AddExtension(MockRuntime.XR_UNITY_mock_test); base.InitializeAndStart(); yield return null; Assert.IsTrue(base.IsRunning(), "Input subsystem failed to properly start!"); MockRuntime.SetReferenceSpaceBounds(XrReferenceSpaceType.Stage, new Vector2 { x = 1.0f, y = 3.0f }); yield return null; var input = Loader.GetLoadedSubsystem(); Assert.That(() => input, Is.Not.Null); input.TrySetTrackingOriginMode(TrackingOriginModeFlags.Floor); yield return null; var points = new List(); Assert.IsTrue(input.TryGetBoundaryPoints(points), "Failed to get boundary points!"); Assert.That(() => points.Count, Is.EqualTo(4), "Incorrect number of boundary points received!"); var comparer = new Vector3EqualityComparer(10e-6f); Assert.That(points[0], Is.EqualTo(new Vector3 { x = -0.5f, y = 0.0f, z = -1.5f }).Using(comparer)); Assert.That(points[1], Is.EqualTo(new Vector3 { x = -0.5f, y = 0.0f, z = 1.5f }).Using(comparer)); Assert.That(points[2], Is.EqualTo(new Vector3 { x = 0.5f, y = 0.0f, z = 1.5f }).Using(comparer)); Assert.That(points[3], Is.EqualTo(new Vector3 { x = 0.5f, y = 0.0f, z = -1.5f }).Using(comparer)); } [UnityTest] public IEnumerator NoBoundaryPoints() { AddExtension(MockRuntime.XR_UNITY_mock_test); base.InitializeAndStart(); yield return null; Assert.IsTrue(base.IsRunning(), "Input subsystem failed to properly start!"); var input = Loader.GetLoadedSubsystem(); Assert.That(() => input, Is.Not.Null); input.TrySetTrackingOriginMode(TrackingOriginModeFlags.Floor); yield return null; var points = new List(); input.TryGetBoundaryPoints(points); Assert.That(() => points.Count, Is.EqualTo(0), "Incorrect number of boundary points received!"); } [UnityTest] public IEnumerator BoundryPointsForTrackingOrigin() { AddExtension(MockRuntime.XR_UNITY_mock_test); base.InitializeAndStart(); yield return null; Assert.IsTrue(base.IsRunning(), "Input subsystem failed to properly start!"); MockRuntime.SetReferenceSpaceBounds(XrReferenceSpaceType.Stage, new Vector2 { x = 1.0f, y = 3.0f }); yield return null; var input = Loader.GetLoadedSubsystem(); Assert.That(() => input, Is.Not.Null); input.TrySetTrackingOriginMode(TrackingOriginModeFlags.Floor); yield return null; var points = new List(); Assert.IsTrue(input.TryGetBoundaryPoints(points), "Failed to get boundary points!"); Assert.That(() => points.Count, Is.EqualTo(4), "Incorrect number of boundary points received!"); input.TrySetTrackingOriginMode(TrackingOriginModeFlags.Device); yield return null; points.Clear(); input.TryGetBoundaryPoints(points); Assert.That(() => points.Count, Is.EqualTo(0), "Incorrect number of boundary points received!"); } [UnityTest] public IEnumerator BeforeFunctionCallbackSuccess() { var createInstanceCalled = false; MockRuntime.SetFunctionCallback("xrCreateInstance", (name) => { createInstanceCalled = true; return XrResult.Success; }); InitializeAndStart(); yield return new WaitForXrFrame(1); Assert.IsTrue(createInstanceCalled, "xrCreateInstance callback was not called"); } [Test] public void BeforeFunctionCallbackError() { var createInstanceCalled = false; MockRuntime.SetFunctionCallback("xrCreateInstance", (name) => { createInstanceCalled = true; return XrResult.RuntimeFailure; }); LogAssert.ignoreFailingMessages = true; InitializeAndStart(); LogAssert.ignoreFailingMessages = false; Assert.IsTrue(OpenXRLoaderBase.Instance == null, "OpenXR instance should have failed to initialize"); Assert.IsTrue(createInstanceCalled, "xrCreateInstance callback was not called"); } [UnityTest] public IEnumerator AfterFunctionCallback() { var createInstanceCalled = false; var createInstanceSuccess = false; MockRuntime.SetFunctionCallback("xrCreateInstance", (name, result) => { createInstanceCalled = true; createInstanceSuccess = result == XrResult.Success; }); InitializeAndStart(); yield return new WaitForXrFrame(1); Assert.IsTrue(createInstanceCalled, "xrCreateInstance callback was not called"); Assert.IsTrue(createInstanceSuccess, "xrCreateInstance result was not XR_SUCCESS"); } [UnityTest] public IEnumerator CallbacksClearedOnLoaderShutdown() { MockRuntime.SetFunctionCallback("xrBeginSession", (func) => XrResult.Success); InitializeAndStart(); yield return new WaitForXrFrame(1); StopAndShutdown(); Assert.IsTrue(OpenXRLoader.Instance == null, "OpenXR should not be running"); Assert.IsNull(MockRuntime.GetBeforeFunctionCallback("xrBeginSession"), "Callback should have been cleared when loader shut down"); } } }