VR4Medical/ICI/Library/PackageCache/com.unity.xr.openxr@3903c1059bcf/Tests/Runtime/OpenXRLoaderSetup.cs
2025-07-29 13:45:50 +03:00

287 lines
12 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using NUnit.Framework;
using UnityEditor;
#if UNITY_EDITOR
using UnityEditor.XR.OpenXR.Features;
#endif
using UnityEngine;
using UnityEngine.TestTools;
using UnityEngine.XR.Management;
using UnityEngine.XR.OpenXR.Features;
using UnityEngine.XR.TestTooling;
using UnityEngine.XR.OpenXR.Features.Mock;
using UnityEngine.XR.OpenXR.NativeTypes;
using Assert = UnityEngine.Assertions.Assert;
[assembly: InternalsVisibleTo("Unity.XR.OpenXR.Tests.Editor")]
[assembly: UnityPlatform(RuntimePlatform.WindowsPlayer, RuntimePlatform.WindowsEditor, RuntimePlatform.Android, RuntimePlatform.OSXEditor, RuntimePlatform.OSXPlayer)]
namespace UnityEngine.XR.OpenXR.Tests
{
internal class OpenXRLoaderSetup : LoaderTestSetup<OpenXRLoader, OpenXRSettings>
{
protected override string settingsKey => "OpenXRTestSettings";
private OpenXRFeature[] savedFeatures = null;
/// <summary>
/// Save the previous value of OpenXRRestarter.DisableApplicationQuit.
/// We want to set it to true when running the test, and then restore the value after the test.
/// </summary>
private bool oldDisableApplicationQuit = false;
/// <summary>
/// Helper method to return a feature of the given type
/// </summary>
/// <param name="featureType">Feature type</param>
/// <returns>Reference to the requested feature or null if not found</returns>
protected OpenXRFeature GetFeature(Type featureType) =>
OpenXRSettings.ActiveBuildTargetInstance.GetFeature(featureType);
/// <summary>
/// Helper method to return a feature of the given type
/// </summary>
/// <typeparam name="T">Feature Type</typeparam>
/// <returns>Reference to the requested feature or null if not found</returns>
protected T GetFeature<T>() where T : OpenXRFeature => GetFeature(typeof(T)) as T;
/// <summary>
/// Enables a required feature of a given type.
/// </summary>
/// <param name="featureType">Type of feature to enable</param>
/// <returns>Feature that was enabled or null</returns>
protected OpenXRFeature EnableFeature(Type featureType, bool enable = true)
{
var feature = GetFeature(featureType);
Assert.IsNotNull(feature);
feature.enabled = enable;
return feature;
}
/// <summary>
/// Enables a required feature of a given type.
/// </summary>
/// <typeparam name="T">Type of feature to enable</typeparam>
/// <returns>Feature that was enabled or null</returns>
protected T EnableFeature<T>(bool enable = true) where T : OpenXRFeature => EnableFeature(typeof(T), enable) as T;
protected bool EnableMockRuntime(bool enable = true)
{
var feature = MockRuntime.Instance;
if (null == feature)
return false;
if (feature.enabled == enable)
return true;
feature.enabled = enable;
feature.openxrExtensionStrings = MockRuntime.XR_UNITY_null_gfx + " " + MockRuntime.XR_UNITY_android_present;
feature.priority = 0;
feature.required = false;
feature.ignoreValidationErrors = true;
return true;
}
protected void AddExtension(string extensionName)
{
MockRuntime.Instance.openxrExtensionStrings += $" {extensionName}";
}
private void DisableAllFeatures()
{
foreach (var ext in OpenXRSettings.ActiveBuildTargetInstance.features)
{
ext.enabled = false;
}
}
#pragma warning disable CS0618
public OpenXRLoader Loader => XRGeneralSettings.Instance?.Manager?.loaders[0] as OpenXRLoader;
#pragma warning restore CS0618
public override void SetupTest()
{
base.SetupTest();
#if UNITY_EDITOR
UnityEditor.XR.OpenXR.Features.FeatureHelpers.RefreshFeatures(BuildTargetGroup.Standalone);
UnityEditor.XR.OpenXR.Features.FeatureHelpers.RefreshFeatures(BuildPipeline.GetBuildTargetGroup(UnityEditor.EditorUserBuildSettings.activeBuildTarget));
#endif
// Enable all build features
var featureTypes = new List<Type>();
QueryBuildFeatures(featureTypes);
featureTypes.Add(typeof(MockRuntime));
foreach (var feature in featureTypes.Select(featureType => OpenXRSettings.ActiveBuildTargetInstance.GetFeature(featureType)).Where(feature => null != feature))
{
feature.enabled = true;
}
}
/// <summary>
/// Override to return a list of feature types that should be enabled in the build
/// </summary>
protected virtual void QueryBuildFeatures(List<Type> featureTypes)
{
}
// NOTE: If you override this function, do NOT add the SetUp test attribute.
// If you do the overriden function and this function will be called separately
// and will most likely invalidate your test or even crash Unity.
[SetUp]
public virtual void BeforeTest()
{
// Make sure we are not running
if (OpenXRLoaderBase.Instance != null)
StopAndShutdown();
// Disable quitting the application functionality for all tests (since we don't want to exit play mode during the test)
oldDisableApplicationQuit = OpenXRRestarter.DisableApplicationQuit;
OpenXRRestarter.DisableApplicationQuit = true;
// Cache off the features before we start
savedFeatures = (OpenXRFeature[])OpenXRSettings.ActiveBuildTargetInstance.features.Clone();
// Disable all features to make sure the feature list is clean before tests start.
DisableAllFeatures();
// Enable the mock runtime and reset it back to default state
Assert.IsTrue(EnableMockRuntime());
MockRuntime.ResetDefaults();
OpenXRRuntime.ClearEvents();
OpenXRRestarter.Instance.ResetCallbacks();
#pragma warning disable CS0618
loader = XRGeneralSettings.Instance?.Manager?.loaders[0] as OpenXRLoader;
#pragma warning restore CS0618
#if UNITY_EDITOR && OPENXR_USE_KHRONOS_LOADER
var features = FeatureHelpersInternal.GetAllFeatureInfo(BuildTargetGroup.Standalone);
foreach (var f in features.Features)
{
if (f.Feature.nameUi == "Mock Runtime")
{
var path = Path.GetFullPath(f.PluginPath + "/unity-mock-runtime.json");
Environment.SetEnvironmentVariable("XR_RUNTIME_JSON", path);
}
}
#endif
}
[UnityTearDown]
public IEnumerator TearDown()
{
AfterTest();
yield return null;
}
// NOTE: If you override this function, do NOT add the SetUp test attribute.
// If you do the overriden function and this function will be called separately
// and will most likely invalidate your test or even crash Unity.
public virtual void AfterTest()
{
#pragma warning disable CS0618
var curLoader = XRGeneralSettings.Instance?.Manager?.activeLoader;
// Restore the original loader if it got removed during the test
if (curLoader == null)
XRGeneralSettings.Instance?.Manager?.TryAddLoader(loader);
#pragma warning restore CS0618
OpenXRRestarter.Instance.ResetCallbacks();
StopAndShutdown();
EnableMockRuntime(false);
MockRuntime.Instance.TestCallback = (methodName, param) => true;
MockRuntime.KeepFunctionCallbacks = false;
MockRuntime.ClearFunctionCallbacks();
// Replace the features with the saved features
OpenXRSettings.ActiveBuildTargetInstance.features = savedFeatures;
// Wait for all shutdowns and restart requests to finish
// and then restore the value of OpenXRRestarter.DisableApplicationQuit
WaitForRestarterToFinish();
}
private IEnumerable WaitForRestarterToFinish()
{
// It is possible that a test may have done something to initiate the OpenXRRestarter. To ensure
// that the restarter does not impact other tests we must make sure it finishes before continuing.
yield return new WaitForRestarter();
// Restore the value of DisableApplicationQuit.
OpenXRRestarter.DisableApplicationQuit = oldDisableApplicationQuit;
}
public override void Setup()
{
SetupTest();
EnableMockRuntime();
base.Setup();
}
public override void Cleanup()
{
base.Cleanup();
TearDownTest();
EnableMockRuntime(false);
}
static Dictionary<XrSessionState, HashSet<XrSessionState>> s_AllowedStateTransitions = new Dictionary<XrSessionState, HashSet<XrSessionState>>()
{
{XrSessionState.Unknown, new HashSet<XrSessionState>() {XrSessionState.Unknown}},
{XrSessionState.Idle, new HashSet<XrSessionState>() {XrSessionState.Unknown, XrSessionState.Unknown, XrSessionState.Exiting, XrSessionState.LossPending, XrSessionState.Stopping}},
{XrSessionState.Ready, new HashSet<XrSessionState>() {XrSessionState.Idle}},
{XrSessionState.Synchronized, new HashSet<XrSessionState>() {XrSessionState.Ready, XrSessionState.Visible}},
{XrSessionState.Visible, new HashSet<XrSessionState>() {XrSessionState.Synchronized, XrSessionState.Focused}},
{XrSessionState.Focused, new HashSet<XrSessionState>() {XrSessionState.Visible}},
{XrSessionState.Stopping, new HashSet<XrSessionState>() {XrSessionState.Synchronized}},
{XrSessionState.LossPending, new HashSet<XrSessionState>() {XrSessionState.Unknown, XrSessionState.Idle, XrSessionState.Ready, XrSessionState.Synchronized, XrSessionState.Visible, XrSessionState.Focused, XrSessionState.Stopping, XrSessionState.Exiting, XrSessionState.LossPending}},
{XrSessionState.Exiting, new HashSet<XrSessionState>() {XrSessionState.Idle}},
};
public void CheckValidStateTransition(XrSessionState oldState, XrSessionState newState)
{
bool hasNewState = s_AllowedStateTransitions.ContainsKey(newState);
bool canTransitionTo = s_AllowedStateTransitions[newState].Contains(oldState);
Debug.LogWarning($"Attempting to transition from {oldState} to {newState}");
if (!hasNewState)
Debug.LogError($"Has {newState} : {hasNewState}");
if (!canTransitionTo)
Debug.LogError($"Can transition from {oldState} to {newState} : {canTransitionTo}");
NUnit.Framework.Assert.IsTrue(hasNewState);
NUnit.Framework.Assert.IsTrue(canTransitionTo);
}
/// <summary>
/// Return true if the diagnostic report contains text that matches the given regex
/// </summary>
/// <param name="match">Regex to match</param>
/// <returns>True if the report matches the regex</returns>
protected bool DoesDiagnosticReportContain(Regex match) =>
match.IsMatch(DiagnosticReport.GenerateReport());
/// <summary>
/// Return true if the diagnostic report contains the given text
/// </summary>
/// <param name="match">String to search for</param>
/// <returns>True if the report contains the given text</returns>
protected bool DoesDiagnosticReportContain(string match) =>
DiagnosticReport.GenerateReport().Contains(match);
protected void ProcessOpenXRMessageLoop() => loader.ProcessOpenXRMessageLoop();
}
}