上传YomovSDK

This commit is contained in:
Sora丶kong
2026-03-03 03:15:46 +08:00
parent 9096da7e6c
commit eb97f31065
6477 changed files with 1932208 additions and 3 deletions

View File

@@ -0,0 +1,62 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using NUnit.Framework;
using UnityEditor.Build.Reporting;
using UnityEditor.VersionControl;
using UnityEditor.XR.OpenXR.Features;
using UnityEngine;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.Features.Interactions;
using UnityEngine.XR.OpenXR.Features.Mock;
using Assert = UnityEngine.Assertions.Assert;
using UnityEngine.XR.OpenXR.Tests;
using static UnityEditor.XR.OpenXR.Tests.OpenXREditorTestHelpers;
namespace UnityEditor.XR.OpenXR.Tests
{
internal class BootConfigEditorTests : OpenXRLoaderSetup
{
[Test]
public void TestCanCreateBootConfigAndroid()
{
TestBuildTarget(BuildTarget.Android);
}
[Test]
public void TestCanCreateBootConfigWindows()
{
TestBuildTarget(BuildTarget.StandaloneWindows);
TestBuildTarget(BuildTarget.StandaloneWindows64);
}
private void TestBuildTarget(BuildTarget buildTarget)
{
var bootConfig = new BootConfig(buildTarget);
bootConfig.ReadBootConfig();
// Check to see that we do not have the following key in the boot config
Assert.IsFalse(bootConfig.TryGetValue("xr-sample-bootconfig-key01", out string value));
Assert.AreEqual(value, null);
// Check to see that we can store a key and retrieve it.
bootConfig.SetValueForKey("xr-sample-bootconfig-key02", "primary value");
Assert.IsTrue(bootConfig.TryGetValue("xr-sample-bootconfig-key02", out string key02value));
Assert.AreEqual(key02value, "primary value");
Assert.IsTrue(bootConfig.CheckValuePairExists("xr-sample-bootconfig-key02", "primary value"));
// check to see that we can write the keys to the boot config and ensure that we can
// retrieve the stored values
bootConfig.WriteBootConfig();
var cloneBootConfig = new BootConfig(buildTarget);
cloneBootConfig.ReadBootConfig();
Assert.IsTrue(cloneBootConfig.TryGetValue("xr-sample-bootconfig-key02", out key02value));
Assert.AreEqual(key02value, "primary value");
Assert.IsTrue(cloneBootConfig.CheckValuePairExists("xr-sample-bootconfig-key02", "primary value"));
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a1c3182e62fd44cea6ebdbb5b36feec5
timeCreated: 1677640135

View File

@@ -0,0 +1,57 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using NUnit.Framework;
using UnityEditor.Build.Reporting;
using UnityEditor.VersionControl;
using UnityEditor.XR.OpenXR.Features;
using UnityEngine;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.Features.Interactions;
using UnityEngine.XR.OpenXR.Features.Mock;
using Assert = UnityEngine.Assertions.Assert;
using UnityEngine.XR.OpenXR.Tests;
using static UnityEditor.XR.OpenXR.Tests.OpenXREditorTestHelpers;
namespace UnityEditor.XR.OpenXR.Tests
{
internal class FeatureModifyingTests : OpenXRLoaderSetup
{
// Override AfterTest to prevent OpenXRSettings.Instance.features from getting reset.
// This test suite destroys and restores OpenXRSettings.Instance.features manually.
public override void AfterTest()
{
}
[Test]
public void DuplicateSettingAssetTest()
{
// Local OpenXR filepath that contains the test OpenXR Package Settings.asset
string openXRFolder = Path.GetFullPath("Packages/com.unity.xr.openxr");
string settingsFilePath = OpenXRPackageSettings.OpenXRPackageSettingsAssetPath();
string metaFilePath = settingsFilePath + ".meta";
string testAssetName = "OpenXR Package Settings With Duplicates.testasset";
string testAssetPath = Path.Combine(openXRFolder, "Tests", "Editor", testAssetName);
string testMetaAssetPath = testAssetPath + ".meta";
// Copy in the test files (the files with duplicate settings)
File.Delete(settingsFilePath);
File.Delete(metaFilePath);
File.Copy(testAssetPath, settingsFilePath);
File.Copy(testMetaAssetPath, metaFilePath);
// Verify that we detect duplicates in the test file.
Assert.IsFalse(OpenXRProjectValidation.AssetHasNoDuplicates(), "The duplicate settings on the bad asset should be detected.");
// Regenerate the asset (as if the user clicks on the Fix button in the validation window)
OpenXRProjectValidation.RegenerateXRPackageSettingsAsset();
// Verify that there are no duplicates in the settings file now.
Assert.IsTrue(OpenXRProjectValidation.AssetHasNoDuplicates(), "After regenerating the asset, the duplicate settings should be removed.");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2755597eb30ac124c861b2694debd290
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,408 @@
using System;
using System.Linq;
using NUnit.Framework;
using UnityEditor.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.Features.Interactions;
using UnityEngine.XR.OpenXR.Features;
using Assert = UnityEngine.Assertions.Assert;
using static UnityEditor.XR.OpenXR.Features.OpenXRFeatureSetManager;
using static UnityEditor.XR.OpenXR.Tests.OpenXREditorTestHelpers;
using UnityEngine.XR.OpenXR.Tests;
namespace UnityEditor.XR.OpenXR.Tests
{
internal class FeatureSetTests : OpenXRLoaderSetup
{
const string k_KnownFeatureSetName = "Known Test";
const string k_TestFeatureSetName = "Test Feature Set";
const string k_TestFeatureSetNameHandAndEye = "Test Feature Set Hand and Eye Tracking";
const string k_TestFeatureSetNameHand = "Test Feature Set Hand Tracking";
const string k_TestFeatureSetDescription = "Test feature set";
const string k_TestFeatureSetId = "com.unity.xr.test.featureset";
const string k_TestFeatureSetIdTwo = "com.unity.xr.test.featureset2";
const string k_TestFeatureSetIdThree = "com.unity.xr.test.featureset3";
const string k_TestFeatureSetIdFour = "com.unity.xr.test.featureset4";
[OpenXRFeatureSet(
FeatureIds = new string[]
{
MicrosoftHandInteraction.featureId
},
UiName = k_TestFeatureSetName,
Description = k_TestFeatureSetDescription,
FeatureSetId = k_TestFeatureSetId,
SupportedBuildTargets = new BuildTargetGroup[] { BuildTargetGroup.Standalone },
RequiredFeatureIds = new string[]
{
MicrosoftHandInteraction.featureId
}
)]
[OpenXRFeatureSet(
FeatureIds = new string[]
{
MicrosoftHandInteraction.featureId,
EyeGazeInteraction.featureId,
},
UiName = k_TestFeatureSetNameHandAndEye,
Description = k_TestFeatureSetDescription,
FeatureSetId = k_TestFeatureSetIdTwo,
SupportedBuildTargets = new BuildTargetGroup[] { BuildTargetGroup.WSA },
RequiredFeatureIds = new string[]
{
MicrosoftHandInteraction.featureId,
EyeGazeInteraction.featureId,
}
)]
[OpenXRFeatureSet(
FeatureIds = new string[]
{
MicrosoftHandInteraction.featureId,
},
UiName = k_TestFeatureSetNameHand,
Description = k_TestFeatureSetDescription,
FeatureSetId = k_TestFeatureSetIdThree,
SupportedBuildTargets = new BuildTargetGroup[] { BuildTargetGroup.WSA },
RequiredFeatureIds = new string[]
{
MicrosoftHandInteraction.featureId,
}
)]
[OpenXRFeatureSet(
FeatureIds = new string[]
{
MicrosoftHandInteraction.featureId,
EyeGazeInteraction.featureId,
},
UiName = k_TestFeatureSetName,
Description = k_TestFeatureSetDescription,
FeatureSetId = k_TestFeatureSetId,
SupportedBuildTargets = new BuildTargetGroup[] { BuildTargetGroup.Android },
RequiredFeatureIds = new string[]
{
MicrosoftHandInteraction.featureId,
EyeGazeInteraction.featureId,
}
)]
[OpenXRFeatureSet(
FeatureIds = new string[]
{
MicrosoftHandInteraction.featureId,
EyeGazeInteraction.featureId,
HTCViveControllerProfile.featureId,
OculusTouchControllerProfile.featureId,
},
UiName = k_TestFeatureSetName,
Description = k_TestFeatureSetDescription,
FeatureSetId = k_TestFeatureSetIdFour,
SupportedBuildTargets = new BuildTargetGroup[] { BuildTargetGroup.Standalone },
RequiredFeatureIds = new string[]
{
MicrosoftHandInteraction.featureId,
EyeGazeInteraction.featureId,
},
DefaultFeatureIds = new string[]
{
HTCViveControllerProfile.featureId,
}
)]
sealed class TestFeatureSet { }
public override void BeforeTest()
{
base.BeforeTest();
OpenXRFeature.canSetFeatureDisabled = null;
InitializeFeatureSets(true);
}
/// <summary>
/// Initialize the feature sets by disabling all features sets and all features
/// </summary>
/// <param name="addTestFeatures">True to include test features</param>
private void InitializeFeatureSets(bool addTestFeatures)
{
// Initialize first with test feature sets so we can make sure all feature sets are disabled
OpenXRFeatureSetManager.InitializeFeatureSets(true);
foreach (var buildTargetGroup in GetBuildTargetGroups())
{
// Disable all feature sets for this build target
foreach (var featureSetInfo in FeatureSetInfosForBuildTarget(buildTargetGroup))
{
featureSetInfo.isEnabled = false;
featureSetInfo.wasEnabled = false;
OpenXREditorSettings.Instance.SetFeatureSetSelected(buildTargetGroup, featureSetInfo.featureSetId, false);
}
// Disable all features for this build target
var extInfo = FeatureHelpersInternal.GetAllFeatureInfo(buildTargetGroup);
foreach (var ext in extInfo.Features)
{
ext.Feature.enabled = false;
}
}
// If requested with no feature sets then reinitialize
if (!addTestFeatures)
OpenXRFeatureSetManager.InitializeFeatureSets(false);
foreach (var buildTargetGroup in GetBuildTargetGroups())
{
// No feature sets should be enabled for any build target
Assert.IsFalse(FeatureSetInfosForBuildTarget(buildTargetGroup).Any(f => f.isEnabled));
// No features should be enabled
AssertAllFeatures(buildTargetGroup, FeatureDisabled);
}
}
public override void AfterTest()
{
base.AfterTest();
OpenXRFeature.canSetFeatureDisabled = OpenXRFeatureSetManager.CanFeatureBeDisabled;
}
[Test]
public void NoFeatureSetsReturnsEmptyList()
{
var featureSets = FeatureSetsForBuildTarget(BuildTargetGroup.iOS);
Assert.AreEqual(0, featureSets.Count);
}
[Test]
public void FoundExpectedFeatureSets()
{
InitializeFeatureSets(false);
string[] expectedFeatureSets = new string[]
{
KnownFeatureSetsContent.s_MicrosoftHoloLensFeatureSetId
};
var featureSets = FeatureSetsForBuildTarget(BuildTargetGroup.WSA);
Assert.IsNotNull(featureSets);
Assert.AreEqual(expectedFeatureSets.Length, featureSets.Count);
foreach (var featureSet in featureSets)
{
if (Array.IndexOf(expectedFeatureSets, featureSet.featureSetId) == -1)
Assert.IsTrue(false, $"Found unexpected feature set id {featureSet.featureSetId}!");
}
}
[Test]
public void UnknownFeatureSetRerturnNull()
{
// For this test we do not want the test features enabled so rerun the initilization with
InitializeFeatureSets(false);
var foundFeatureSet = GetFeatureSetWithId(BuildTargetGroup.iOS, k_TestFeatureSetId);
Assert.IsNull(foundFeatureSet);
foundFeatureSet = GetFeatureSetWithId(BuildTargetGroup.Standalone, "BAD FEATURE SET ID");
Assert.IsNull(foundFeatureSet);
}
[Test]
public void OverrideKnownTestFeatureSet()
{
var foundFeatureSet = GetFeatureSetWithId(BuildTargetGroup.Standalone, k_TestFeatureSetId);
Assert.IsNotNull(foundFeatureSet);
Assert.AreEqual(0, String.Compare(foundFeatureSet.name, k_TestFeatureSetName, true));
}
[Test]
public void NonoverrideKnownTestFeatureSet()
{
var foundFeatureSet = GetFeatureSetWithId(BuildTargetGroup.WSA, k_TestFeatureSetId);
Assert.IsNotNull(foundFeatureSet);
Assert.AreEqual(0, String.Compare(foundFeatureSet.name, k_KnownFeatureSetName, true));
}
[Test]
public void EnableFeatureSetEnablesFeatures()
{
EnableFeatureSet(BuildTargetGroup.Standalone, k_TestFeatureSetId, enabled: true);
AssertOnlyFeatures(BuildTargetGroup.Standalone, new string[] { MicrosoftHandInteraction.featureId }, FeatureEnabled);
}
[Test]
public void DisableFeatureSetDisabledFeatures()
{
// Enable the feature set and make sure only its features are enabled
EnableFeatureSet(BuildTargetGroup.Standalone, k_TestFeatureSetId, true);
AssertOnlyFeatures(BuildTargetGroup.Standalone, new string[] { MicrosoftHandInteraction.featureId }, FeatureEnabled);
// Disable the feature set an make sure its features are disabled
EnableFeatureSet(BuildTargetGroup.Standalone, k_TestFeatureSetId, false);
AssertAllFeatures(BuildTargetGroup.Standalone, FeatureDisabled);
}
[Test]
public void DisableSharedFeaturesLeaveSharedFeaturesEnabled()
{
// Ensable all WSA feature sets and make sure only the WSA feature set features are enabled
EnableFeatureSets(BuildTargetGroup.WSA, enabled: true);
AssertOnlyFeatures(BuildTargetGroup.WSA, new string[]
{
MicrosoftHandInteraction.featureId,
EyeGazeInteraction.featureId,
}, FeatureEnabled);
// Disable the feature seth with both features set as required
EnableFeatureSet(BuildTargetGroup.WSA, k_TestFeatureSetIdTwo, enabled: false);
AssertOnlyFeatures(BuildTargetGroup.WSA, new string[]
{
MicrosoftHandInteraction.featureId,
}, FeatureEnabled);
// Disable all WSA feature sets and make sure all features are disabled
EnableFeatureSets(BuildTargetGroup.WSA, enabled: false);
AssertAllFeatures(BuildTargetGroup.WSA, FeatureDisabled);
}
[Test]
public void DisableSharedFeaturesLeaveOthersFeaturesEnabled()
{
string[] allFeatureIds = new string[]
{
MicrosoftHandInteraction.featureId,
EyeGazeInteraction.featureId,
MicrosoftMotionControllerProfile.featureId,
};
string[] otherFeatureIds = new string[]
{
MicrosoftMotionControllerProfile.featureId,
};
EnableFeatureInfos(BuildTargetGroup.WSA, otherFeatureIds, true);
// Enable the second feature set and ensure that only features in the `all` list are enabled
var featureSetToEnable = GetFeatureSetInfoWithId(BuildTargetGroup.WSA, k_TestFeatureSetIdTwo);
EnableFeatureSet(BuildTargetGroup.WSA, featureSetToEnable.featureSetId, true);
AssertOnlyFeatures(BuildTargetGroup.WSA, allFeatureIds, FeatureEnabled);
// Disable the second feature set and ensure only features in the `others` list are enabled
var featureSetToDisable = GetFeatureSetInfoWithId(BuildTargetGroup.WSA, k_TestFeatureSetIdTwo);
Assert.IsNotNull(featureSetToDisable);
EnableFeatureSet(BuildTargetGroup.WSA, featureSetToDisable.featureSetId, enabled: false);
AssertOnlyFeatures(BuildTargetGroup.WSA, otherFeatureIds, FeatureEnabled);
}
[Test]
public void EnablingFeatureSetEnabledDefaultFeatures()
{
var foundFeatureSet = GetFeatureSetInfoWithId(BuildTargetGroup.Standalone, k_TestFeatureSetIdFour);
Assert.IsNotNull(foundFeatureSet);
EnableFeatureSet(BuildTargetGroup.Standalone, foundFeatureSet.featureSetId, true);
// Ensure that only the non-optional features are enabled
AssertOnlyFeatures(BuildTargetGroup.Standalone, foundFeatureSet.featureIds, (f) => f.Feature.enabled == !FeatureIsOptional(foundFeatureSet, f));
}
[Test]
public void EnablingFeatureSetLeavesOptionFeaturesEnabled()
{
// Enable the feature set
var foundFeatureSet = GetFeatureSetInfoWithId(BuildTargetGroup.Standalone, k_TestFeatureSetIdFour);
Assert.IsNotNull(foundFeatureSet);
EnableFeatureSet(BuildTargetGroup.Standalone, foundFeatureSet.featureSetId, true);
// Ensure the Optional features are all disabled
AssertAllFeatures(BuildTargetGroup.Standalone, (f) => !FeatureIsOptional(foundFeatureSet, f) || !f.Feature.enabled);
// Disable the feature set and ensure the optional features are disabled
EnableFeatureSet(BuildTargetGroup.Standalone, foundFeatureSet.featureSetId, false);
AssertAllFeatures(BuildTargetGroup.Standalone, (f) => !FeatureIsOptional(foundFeatureSet, f) || !f.Feature.enabled);
// Enable the optional features and the feature set and ensure the optional features are still enabled
EnableFeatureInfos(BuildTargetGroup.Standalone, true, (f) => FeatureIsOptional(foundFeatureSet, f));
EnableFeatureSet(BuildTargetGroup.Standalone, foundFeatureSet.featureSetId, enabled: true);
AssertAllFeatures(BuildTargetGroup.Standalone, (f) => !FeatureIsOptional(foundFeatureSet, f) || f.Feature.enabled);
// Enable the feature set again and make sure the optional features are still enabled
EnableFeatureSet(BuildTargetGroup.Standalone, foundFeatureSet.featureSetId, enabled: true);
AssertAllFeatures(BuildTargetGroup.Standalone, (f) => !FeatureIsOptional(foundFeatureSet, f) || f.Feature.enabled);
}
[Test]
public void DisablingFeatureSetLeavesDefaultFeaturesEnabled()
{
var foundFeatureSet = GetFeatureSetInfoWithId(BuildTargetGroup.Standalone, k_TestFeatureSetIdFour);
Assert.IsNotNull(foundFeatureSet);
EnableFeatureSet(BuildTargetGroup.Standalone, foundFeatureSet.featureSetId, true);
// Ensure that the only enabled features are the non optional features
AssertAllFeatures(BuildTargetGroup.Standalone, foundFeatureSet.featureIds, (f) => f.Feature.enabled == !FeatureIsOptional(foundFeatureSet, f));
// Disabling the feature set should disable the required components but not the default ones
EnableFeatureSet(BuildTargetGroup.Standalone, foundFeatureSet.featureSetId, enabled: false);
AssertAllFeatures(BuildTargetGroup.Standalone, foundFeatureSet.requiredFeatureIds, FeatureDisabled);
AssertAllFeatures(BuildTargetGroup.Standalone, foundFeatureSet.defaultFeatureIds, FeatureEnabled);
}
[Test]
public void DisablingFeatureSetLeavesDisabledDefaultFeaturesDisabled()
{
var buildTargetGroup = BuildTargetGroup.Standalone;
var foundFeatureSet = GetFeatureSetInfoWithId(buildTargetGroup, k_TestFeatureSetIdFour);
Assert.IsNotNull(foundFeatureSet);
EnableFeatureSet(buildTargetGroup, foundFeatureSet.featureSetId, enabled: true);
// Ensure that only the non optional features are enabled
AssertOnlyFeatures(buildTargetGroup, foundFeatureSet.featureIds, (f) => f.Feature.enabled == !FeatureIsOptional(foundFeatureSet, f));
// Disable all features in the default feature list
EnableFeatureInfos(buildTargetGroup, foundFeatureSet.defaultFeatureIds, enable: false);
AssertAllFeatures(buildTargetGroup, foundFeatureSet.defaultFeatureIds, FeatureDisabled);
// Ensure that all features in the required list are enabled and that all features in the default features list are disabled
AssertAllFeatures(buildTargetGroup, foundFeatureSet.requiredFeatureIds, FeatureEnabled);
}
[Test]
public void CanNotChangeEnabledStateOfRequiredFeature()
{
OpenXRFeatureSetManager.activeBuildTarget = BuildTargetGroup.Standalone;
var foundFeatureSet = GetFeatureSetInfoWithId(BuildTargetGroup.Standalone, k_TestFeatureSetIdFour);
Assert.IsNotNull(foundFeatureSet);
var featureInfos = GetFeatureInfos(BuildTargetGroup.Standalone, foundFeatureSet.requiredFeatureIds);
foreach (var featureInfo in featureInfos)
{
AssertFeatureEnabled(featureInfo, false);
featureInfo.Feature.enabled = true;
AssertFeatureEnabled(featureInfo, true);
featureInfo.Feature.enabled = false;
AssertFeatureEnabled(featureInfo, false);
}
EnableFeatureSet(BuildTargetGroup.Standalone, foundFeatureSet.featureSetId, enabled: true);
OpenXRFeature.canSetFeatureDisabled = OpenXRFeatureSetManager.CanFeatureBeDisabled;
foreach (var featureInfo in featureInfos)
{
AssertFeatureEnabled(featureInfo, true);
featureInfo.Feature.enabled = false;
AssertFeatureEnabled(featureInfo, true);
}
EnableFeatureSet(BuildTargetGroup.Standalone, foundFeatureSet.featureSetId, enabled: false);
foreach (var featureInfo in featureInfos)
{
AssertFeatureEnabled(featureInfo, false);
featureInfo.Feature.enabled = true;
AssertFeatureEnabled(featureInfo, true);
featureInfo.Feature.enabled = false;
AssertFeatureEnabled(featureInfo, false);
}
OpenXRFeatureSetManager.activeBuildTarget = BuildTargetGroup.Unknown;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 328562bda27130c4a853afe94025c8a6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,122 @@
using System;
using System.Linq;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEditor.Build.Reporting;
using UnityEditor.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.Features.Interactions;
using UnityEngine.XR.OpenXR.Features.Mock;
using Assert = UnityEngine.Assertions.Assert;
using UnityEngine.XR.OpenXR.Tests;
using static UnityEditor.XR.OpenXR.Tests.OpenXREditorTestHelpers;
namespace UnityEditor.XR.OpenXR.Tests
{
internal class FeatureTests : OpenXRLoaderSetup
{
[Test]
public void EnableFeatures()
{
var featureInfos = GetFeatureInfos(BuildTargetGroup.Standalone);
featureInfos.SingleOrDefault(ext => ext.Attribute.UiName == "Mock Runtime").Feature.enabled = true;
Assert.IsTrue(MockRuntime.Instance.enabled);
featureInfos.SingleOrDefault(ext => ext.Attribute.UiName == "Mock Runtime").Feature.enabled = false;
Assert.IsFalse(MockRuntime.Instance.enabled);
}
[Test]
public void CheckDefaultValues()
{
var featureInfos = GetFeatureInfos(BuildTargetGroup.Standalone);
var mockExtInfo = featureInfos.SingleOrDefault(ext => ext.Attribute.UiName == "Mock Runtime");
Assert.AreEqual(mockExtInfo.Attribute.UiName, mockExtInfo.Feature.nameUi);
Assert.AreEqual(mockExtInfo.Attribute.Version, mockExtInfo.Feature.version);
Assert.AreEqual(mockExtInfo.Attribute.OpenxrExtensionStrings, mockExtInfo.Feature.openxrExtensionStrings);
}
[Test]
public void ValidationError()
{
bool errorFixed = false;
// Set up a validation check ...
MockRuntime.Instance.TestCallback = (s, o) =>
{
if (s == "GetValidationChecks")
{
var validationChecks = o as List<OpenXRFeature.ValidationRule>;
validationChecks?.Add(new OpenXRFeature.ValidationRule
{
message = "Mock Validation Fail",
checkPredicate = () => errorFixed,
fixIt = () => errorFixed = true,
error = true
});
}
return true;
};
// Try to build the player ...
var report = zBuildHookTests.BuildMockPlayer();
// It will fail because of the above validation issue ...
Assert.AreEqual(BuildResult.Failed, report.summary.result);
// There's one validation issue ...
var validationIssues = new List<OpenXRFeature.ValidationRule>();
OpenXRProjectValidation.GetCurrentValidationIssues(validationIssues, BuildTargetGroup.Standalone);
Assert.AreEqual(1, validationIssues.Count);
// Fix it ...
Assert.IsFalse(errorFixed);
validationIssues[0].fixIt.Invoke();
Assert.IsTrue(errorFixed);
// Now there's zero validation issues ...
OpenXRProjectValidation.GetCurrentValidationIssues(validationIssues, BuildTargetGroup.Standalone);
Assert.AreEqual(0, validationIssues.Count);
// Close the validation window ...
OpenXRProjectValidationRulesSetup.CloseWindow();
}
[Test]
public void GetFeatureByFeatureId()
{
var feature = FeatureHelpers.GetFeatureWithIdForActiveBuildTarget(MockRuntime.featureId);
Assert.IsNotNull(feature);
}
[Test]
public void GetFeatureByUnknownFeatureIdReturnsNull()
{
var feature = FeatureHelpers.GetFeatureWithIdForActiveBuildTarget("some.unknown.feature.id");
Assert.IsNull(feature);
feature = FeatureHelpers.GetFeatureWithIdForActiveBuildTarget("");
Assert.IsNull(feature);
feature = FeatureHelpers.GetFeatureWithIdForActiveBuildTarget(null);
Assert.IsNull(feature);
}
[Test]
public void GetFeaturesWithIdsReturnsFeatures()
{
var featureIds = new string[] { MockRuntime.featureId, EyeGazeInteraction.featureId };
var features = FeatureHelpers.GetFeaturesWithIdsForActiveBuildTarget(featureIds);
Assert.IsNotNull(features);
Assert.IsTrue(features.Length == 2);
var expectedTypes = new Type[] { typeof(MockRuntime), typeof(EyeGazeInteraction) };
foreach (var feature in features)
{
Assert.IsTrue(Array.IndexOf(expectedTypes, feature.GetType()) > -1);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7a788d71a20869d4db1291a18e647426
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2bcf50ca7a335ea40b37e3bcf05eea52
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,51 @@
using NUnit.Framework;
using UnityEngine.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.Features.Mock;
using UnityEngine.XR.OpenXR.Tests;
using Assert = UnityEngine.Assertions.Assert;
namespace UnityEditor.XR.OpenXR.Tests
{
internal class OpenXRCallbackTests : OpenXRLoaderSetup
{
[Test]
public void InstanceCreated()
{
bool instanceCreated = false;
MockRuntime.Instance.TestCallback = (methodName, param) =>
{
if (methodName == nameof(OpenXRFeature.OnInstanceCreate))
{
instanceCreated = true;
Assert.AreEqual(10, (ulong)param);
}
return true;
};
AddExtension(MockRuntime.XR_UNITY_mock_test);
base.InitializeAndStart();
Assert.IsTrue(instanceCreated);
}
[Test]
public void SessionCreated()
{
bool sessionCreated = false;
MockRuntime.Instance.TestCallback = (methodName, param) =>
{
if (methodName == nameof(OpenXRFeature.OnSessionCreate))
{
sessionCreated = true;
Assert.AreEqual(3, (ulong)param);
}
return true;
};
base.InitializeAndStart();
Assert.IsTrue(sessionCreated);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8dc9dc15a0724a46ba08d4aecabca976
timeCreated: 1586986782

View File

@@ -0,0 +1,62 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Tests;
using UnityEditor;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.TestTools;
using UnityEngine.Scripting;
using Assert = UnityEngine.Assertions.Assert;
namespace UnityEditor.XR.OpenXR.Tests
{
#if false // Tests are temporarily disabled due to an issue with [BeforeTest] being called twice during a domain reload
/// <summary>
/// Tests domain reloads within OpenXR. Note that his class was named with two z's in front
/// because the domain reloads during this test were causing other tests to fail that ran after it.
/// </summary>
internal class zzOpenXRDomainReloadTests : OpenXRLoaderSetup
{
[UnityTest]
public IEnumerator AfterInitialize()
{
MockRuntimeFeature.Instance.TestCallback = (methodName, param) => true;
Assert.IsNull(OpenXRLoaderBase.Instance);
base.InitializeAndStart();
// Perform a domain reload and wait for it to complete
EditorUtility.RequestScriptReload();
yield return new WaitForDomainReload();
Assert.IsNotNull(OpenXRLoaderBase.Instance);
base.StopAndShutdown();
Assert.IsNull(OpenXRLoaderBase.Instance);
yield return null;
}
[UnityTest]
public IEnumerator BeforeInitialize()
{
MockRuntimeFeature.Instance.TestCallback = (methodName, param) => true;
// Perform a domain reload and wait for it to complete
EditorUtility.RequestScriptReload();
yield return new WaitForDomainReload();
base.InitializeAndStart();
base.StopAndShutdown();
yield return null;
}
}
#endif
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 742a28a82ea69ef4fba68040fee09aac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,230 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.XR.OpenXR.Features;
using static UnityEditor.XR.OpenXR.Features.OpenXRFeatureSetManager;
namespace UnityEditor.XR.OpenXR.Tests
{
internal static class OpenXREditorTestHelpers
{
public delegate bool FeatureInfoPredicate(FeatureHelpersInternal.FeatureInfo featureInfo);
public static bool FeatureEnabled(FeatureHelpersInternal.FeatureInfo featureInfo) => featureInfo.Feature.enabled;
public static bool FeatureDisabled(FeatureHelpersInternal.FeatureInfo featureInfo) => !featureInfo.Feature.enabled;
private static Dictionary<BuildTargetGroup, FeatureHelpersInternal.FeatureInfo[]> s_FeatureInfos;
private static BuildTargetGroup[] s_BuildTargetGroups =
((BuildTargetGroup[])Enum.GetValues(typeof(BuildTargetGroup))).Distinct().ToArray();
/// <summary>
/// Return the distinct list of build target groups to test
/// </summary>
public static BuildTargetGroup[] GetBuildTargetGroups() => s_BuildTargetGroups;
/// <summary>
/// Clear the FeatureInfo cache
/// </summary>
public static void ClearFeatureInfos()
{
s_FeatureInfos = null;
}
/// <summary>
/// Helper function to retrieve the cached FeatureInfos for a given build target group
/// </summary>
/// <param name="buildTargetGroup">Build target group</param>
/// <returns>Array of FeatureInfos for the build target group</returns>
public static FeatureHelpersInternal.FeatureInfo[] GetFeatureInfos(BuildTargetGroup buildTargetGroup)
{
if (null == s_FeatureInfos)
s_FeatureInfos = new Dictionary<BuildTargetGroup, FeatureHelpersInternal.FeatureInfo[]>();
if (!s_FeatureInfos.TryGetValue(buildTargetGroup, out var featureInfos))
{
featureInfos = FeatureHelpersInternal.GetAllFeatureInfo(buildTargetGroup).Features.ToArray();
s_FeatureInfos[buildTargetGroup] = featureInfos;
}
return featureInfos;
}
/// <summary>
/// Helper function to retrieve a subset of FeatureInfos in <paramref name="buildTargetGroup"/>.
/// </summary>
/// <param name="buildTargetGroup">Build target group</param>
/// <param name="featureIds">Specific feature identifiers to retrieve</param>
/// <returns>Array of FeatureInfos matching request</returns>
public static FeatureHelpersInternal.FeatureInfo[] GetFeatureInfos(BuildTargetGroup buildTargetGroup, string[] featureIds)
{
return GetFeatureInfos(buildTargetGroup).Where(f => featureIds.Contains(f.Attribute.FeatureId)).ToArray();
}
/// <summary>
/// Enable or Disable a feature set
/// </summary>
/// <param name="buildTargetGroup">Build target group containing feature set</param>
/// <param name="featureSetId">Identifier of feature</param>
/// <param name="enabled">True to enable, false to disable</param>
/// <param name="changed">True if the FeatureSet enabled state should be considered changed</param>
/// <param name="commit">True if the FeatureSet enabled state should be automatically commmitted with `SetFeaturesFromEnabledFeatureSets`</param>
public static void EnableFeatureSet(BuildTargetGroup buildTargetGroup, string featureSetId, bool enabled = true, bool changed = true, bool commit = true)
{
var featureSetInfo = GetFeatureSetInfoWithId(buildTargetGroup, featureSetId);
Assert.IsNotNull(featureSetInfo, $"FeatureSetInfo '{featureSetId}' not found ");
featureSetInfo.isEnabled = enabled;
featureSetInfo.wasEnabled = changed ? !enabled : enabled;
if (commit)
SetFeaturesFromEnabledFeatureSets(buildTargetGroup);
}
/// <summary>
/// Enable/Disable all feature sets for <paramref name="buildTargetGroup"/>
/// </summary>
/// <param name="buildTargetGroup">Build Target Group</param>
/// <param name="enabled">Enabled state</param>
/// <param name="changed">True if the feature set should be marked as changed, false if not</param>
public static void EnableFeatureSets(BuildTargetGroup buildTargetGroup, bool enabled, bool changed = true, bool commit = true)
{
foreach (var featureSetInfo in FeatureSetInfosForBuildTarget(buildTargetGroup))
{
featureSetInfo.isEnabled = enabled;
featureSetInfo.wasEnabled = changed ? !enabled : enabled;
}
if (commit)
SetFeaturesFromEnabledFeatureSets(buildTargetGroup);
}
public static void EnableFeatureInfos(BuildTargetGroup buildTargetGroup, string[] featureIds, bool enable, FeatureInfoPredicate predicate = null)
{
foreach (var featureInfo in GetFeatureInfos(buildTargetGroup, featureIds))
{
if (null == predicate || predicate(featureInfo))
featureInfo.Feature.enabled = enable;
}
}
public static void EnableFeatureInfos(BuildTargetGroup buildTargetGroup, bool enable, FeatureInfoPredicate predicate = null)
{
foreach (var featureInfo in GetFeatureInfos(buildTargetGroup))
{
if (null == predicate || predicate(featureInfo))
featureInfo.Feature.enabled = enable;
}
}
/// <summary>
/// Builds a comma separated list of features that pass the <paramref name="check"/> within <paramref name="featureInfos"/>
/// </summary>
/// <param name="featureInfos">Feature infos</param>
/// <param name="check">Delegate used to check status</param>
/// <param name="exclude">Optional list of feature identifiers exclude</param>
/// <returns>Comma separated list of features</returns>
public static string FeaturesToString(FeatureHelpersInternal.FeatureInfo[] featureInfos, FeatureInfoPredicate check, string[] exclude = null)
{
return string.Join(",", featureInfos
.Where(f => (exclude == null || !exclude.Contains(f.Attribute.FeatureId)) && check(f))
.Select(f => f.Attribute.FeatureId));
}
/// <summary>
/// Builds a comma separated list of features from <paramref name="featureIds"/> in <paramref name="buildTargetGroup"/> that pass the <paramref name="check"/>
/// </summary>
/// <param name="buildTargetGroup">Build Target Group</param>
/// <param name="featureIds">Feature ids to include</param>
/// <param name="check">Delegate used to check status</param>
/// <returns>Comma separated list of features</returns>
public static string FeaturesToString(BuildTargetGroup buildTargetGroup, string[] featureIds, FeatureInfoPredicate check)
{
return FeaturesToString(GetFeatureInfos(buildTargetGroup).Where(f => featureIds.Contains(f.Attribute.FeatureId)).ToArray(), check);
}
/// <summary>
/// Builds a comma separated list of features identifier that pass the <paramref name="check"/> within <paramref name="buildTargetGroup"/>
/// </summary>
/// <param name="buildTargetGroup">Build Target Group</param>
/// <param name="check">Delegate used to check status</param>
/// <param name="exclude">Optional list of feature identifiers to exclude from the list</param>
/// <returns>Comma separated list of features</returns>
public static string FeaturesToString(BuildTargetGroup buildTargetGroup, FeatureInfoPredicate check, string[] exclude = null)
{
return FeaturesToString(GetFeatureInfos(buildTargetGroup), check, exclude: exclude);
}
/// <summary>
/// Checks if all features for the <paramref name="buildTargetGroup"/> pass the <paramref name="check"/>.
/// </summary>
/// <param name="buildTargetGroup">Build Target Group</param>
/// <param name="check">Delegate used to check status</param>
/// <returns>True if the check passes, false if not</returns>
public static bool CheckAllFeatures(BuildTargetGroup buildTargetGroup, FeatureInfoPredicate check)
{
return GetFeatureInfos(buildTargetGroup).All(f => check(f));
}
/// <summary>
/// Check that all features in <paramref name="featureIds"/> in <paramref name="buildTargetGroup"/> match the pass the <paramref name="check"/>.
/// </summary>
/// <param name="buildTargetGroup">Build target group</param>
/// <param name="featureIds">Features to check</param>
/// <param name="check">Delegate used to check status</param>
/// <returns>True if the check passes, false if not</returns>
public static bool CheckAllFeatures(BuildTargetGroup buildTargetGroup, string[] featureIds, FeatureInfoPredicate check)
{
return GetFeatureInfos(buildTargetGroup).All(f => !featureIds.Contains(f.Attribute.FeatureId) || check(f));
}
/// <summary>
/// Check that only features in <paramref name="featureIds"/> for <paramref name="buildTargetGroup"/> pass the <paramref name="check"/>.
/// </summary>
/// <param name="buildTargetGroup">Build target group</param>
/// <param name="featureIds">Features to check</param>
/// <param name="check">Delegate used to check a FeatureInfo</param>
/// <returns>True if the check passes, false if not</returns>
public static bool CheckOnlyFeatures(BuildTargetGroup buildTargetGroup, string[] featureIds, FeatureInfoPredicate check)
{
return GetFeatureInfos(buildTargetGroup).All(f => featureIds.Contains(f.Attribute.FeatureId) == check(f));
}
private static string AssertFeaturesMessage(string features) =>
$"The following features failed the check: {features}";
public static void AssertOnlyFeatures(BuildTargetGroup buildTargetGroup, string[] featureIds, FeatureInfoPredicate check)
{
Assert.IsTrue(
CheckOnlyFeatures(buildTargetGroup, featureIds, check),
AssertFeaturesMessage(FeaturesToString(buildTargetGroup, featureIds, (f) => !check(f))));
}
public static void AssertAllFeatures(BuildTargetGroup buildTargetGroup, string[] featureIds, FeatureInfoPredicate check)
{
Assert.IsTrue(
CheckAllFeatures(buildTargetGroup, featureIds, check),
AssertFeaturesMessage(FeaturesToString(buildTargetGroup, featureIds, (f) => !check(f))));
}
public static void AssertAllFeatures(BuildTargetGroup buildTargetGroup, FeatureInfoPredicate check)
{
Assert.IsTrue(
CheckAllFeatures(buildTargetGroup, check),
AssertFeaturesMessage(FeaturesToString(buildTargetGroup, (f) => !check(f))));
}
public static void AssertFeatureEnabled(FeatureHelpersInternal.FeatureInfo featureInfo, bool enabled = true)
{
Assert.IsTrue(featureInfo.Feature.enabled == enabled, $"{featureInfo.Attribute.FeatureId} should be {(enabled ? "enabled" : "disabled")}");
}
public static bool FeatureIsOptional(FeatureSetInfo featureSet, FeatureHelpersInternal.FeatureInfo feature)
{
return Array.IndexOf(featureSet.featureIds, feature.Attribute.FeatureId) > -1 &&
(featureSet.requiredFeatureIds == null || Array.IndexOf(featureSet.requiredFeatureIds, feature.Attribute.FeatureId) == -1) &&
(featureSet.defaultFeatureIds == null || Array.IndexOf(featureSet.defaultFeatureIds, feature.Attribute.FeatureId) == -1);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f87eee2b71c3bf24aa0e63794ac22ae5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
using System;
using NUnit.Framework;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.Features.Interactions;
using UnityEngine.XR.OpenXR;
namespace UnityEditor.XR.OpenXR.Tests
{
internal class OpenXREditorTests
{
[Test]
public void DocumentationVersion()
{
var version = PackageManager.PackageInfo.FindForAssembly(typeof(OpenXREditorTests).Assembly)?.version;
var majorminor = "@" + OpenXRFeatureAttribute.k_PackageVersionRegex.Match(version).Groups[1].Value + "/";
UnityEngine.Debug.Log(typeof(KHRSimpleControllerProfile).GetCustomAttribute<OpenXRFeatureAttribute>().InternalDocumentationLink);
Assert.IsTrue(typeof(KHRSimpleControllerProfile).GetCustomAttribute<OpenXRFeatureAttribute>().InternalDocumentationLink.Contains(majorminor));
}
[Test]
public void PluginVersion()
{
var version = PackageManager.PackageInfo.FindForAssembly(typeof(OpenXREditorTests).Assembly)?.version;
System.Text.RegularExpressions.Regex ReleaseVersion = new System.Text.RegularExpressions.Regex(@"^(\d+\.\d+\.\d+)$");
//check for release build provider version number matches package version
if (ReleaseVersion.IsMatch(version))
{
var tag = OpenXRRuntime.pluginVersion;
Assert.AreEqual(0, String.Compare(version, tag), "Tag in github must match the package version number.");
return;
}
//check for non-release build package version number supposed to be x.x.x-pre.x(pre-release) or x.x.x-exp.x(experimental)
System.Text.RegularExpressions.Regex PreviewVersion = new System.Text.RegularExpressions.Regex(@"^(\d+\.\d+\.\d+\-\w+\.\d+)$");
Assert.IsTrue(PreviewVersion.IsMatch(version), "Wrong package version format! Non-release branch should follow x.x.x-pre.x(pre-release) or x.x.x-exp.x(experimental)");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2c99482b3559f1f47babd8d8fec8a820
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,81 @@
using System;
using System.Collections;
using System.Linq;
using NUnit.Framework;
using UnityEngine.InputSystem;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features.Interactions;
using UnityEngine.XR.OpenXR.Tests;
using Assert = UnityEngine.Assertions.Assert;
namespace UnityEditor.XR.OpenXR.Tests
{
internal class OpenXRInputEditorTests : OpenXRInputTestsBase
{
/// <summary>
/// Tests whether or not the device layout for an interaction feature is registered/unregistered
/// when the feature is enabled/disabled
/// </summary>
#if !INPUT_SYSTEM_BINDING_VALIDATOR
[Test]
public void DeviceLayoutRegistration([ValueSource(nameof(s_InteractionFeatureLayouts))] (Type featureType, Type layoutType, string layoutNameOverride) interactionFeature)
{
var layoutName = interactionFeature.layoutNameOverride ?? interactionFeature.layoutType.Name;
// Make sure the layout is not registered as it would give the test a false positive
InputSystem.RemoveLayout(layoutName);
Assert.IsFalse(IsLayoutRegistered(layoutName), "Layout is still registered, test will give a false positive");
// Enabling the feature should register the layout
EnableFeature(interactionFeature.featureType);
Assert.IsTrue(IsLayoutRegistered(layoutName), "Layout was not registered by enabling the feature");
// When an interaction feature is disabled its layout should be disable as well
EnableFeature(interactionFeature.featureType, false);
Assert.IsFalse(IsLayoutRegistered(layoutName), "Layout was not unregistered by the interaction feature");
}
/// <summary>
/// Tests that interaction features enabled in multiple build targets properly registers and unregisters
/// the device layout depending on whether the feature is enabled in at least one build target.
/// </summary>
[Test]
public void InteractionFeatureLayoutRegistration()
{
var packageSettings = OpenXRSettings.GetPackageSettings();
Assert.IsNotNull(packageSettings);
// Ignore the test if there is not more than 1 build target.
var features = packageSettings.GetFeatures<OculusTouchControllerProfile>().Select(f => f.feature).ToArray();
if (features.Length < 2)
return;
// Disable all of the oculus interaction features
foreach (var feature in features)
{
feature.enabled = false;
}
// Make sure the oculus device layout is not registered
NUnit.Framework.Assert.Throws(typeof(ArgumentException), () => UnityEngine.InputSystem.InputSystem.LoadLayout<OculusTouchControllerProfile.OculusTouchController>());
// Enable one of the features and make sure the layout is registered
features[0].enabled = true;
NUnit.Framework.Assert.DoesNotThrow(() => UnityEngine.InputSystem.InputSystem.LoadLayout<OculusTouchControllerProfile.OculusTouchController>());
NUnit.Framework.Assert.DoesNotThrow(() => UnityEngine.InputSystem.InputSystem.LoadLayout<OculusTouchControllerProfile.OculusTouchController>());
// Enable a second feature and make sure the layout is still enabled
features[1].enabled = true;
NUnit.Framework.Assert.DoesNotThrow(() => UnityEngine.InputSystem.InputSystem.LoadLayout<OculusTouchControllerProfile.OculusTouchController>());
// Disable the first feature and make sure the layout is still enabled
features[0].enabled = false;
NUnit.Framework.Assert.DoesNotThrow(() => UnityEngine.InputSystem.InputSystem.LoadLayout<OculusTouchControllerProfile.OculusTouchController>());
// Disable the second feature and make sure the layout is no longer
features[1].enabled = false;
NUnit.Framework.Assert.Throws(typeof(ArgumentException), () => UnityEngine.InputSystem.InputSystem.LoadLayout<OculusTouchControllerProfile.OculusTouchController>());
}
#endif
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ee1a4eb1841c4a40a7e4a76be579ca3e
timeCreated: 1622132012

View File

@@ -0,0 +1,142 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features.Interactions;
using UnityEngine.XR.OpenXR.Tests;
using Assert = UnityEngine.Assertions.Assert;
namespace UnityEditor.XR.OpenXR.Tests
{
internal class OpenXRRuntimeSelectorTests : OpenXRInputTestsBase
{
[Test]
public void NoAvailableRuntimesTest()
{
List<OpenXRRuntimeSelector.RuntimeDetector> detectorList = OpenXRRuntimeSelector.GenerateRuntimeDetectorList();
Assert.IsTrue(detectorList.Count > 0);
Assert.IsTrue(detectorList[0] is OpenXRRuntimeSelector.SystemDefault, "First choice should always be SystemDefault");
Assert.IsTrue(detectorList[detectorList.Count - 1] is OpenXRRuntimeSelector.OtherRuntime, "Last choice should always be Other");
}
[Test]
public void BuiltInRuntimesAsAvailableRuntimesTest()
{
// Simulate what happens if the AvailableRuntimes registry key is empty.
// WindowsMR, SteamVR, and Oculus should all be added to the list.
Dictionary<string, int> runtimePathToValue = new Dictionary<string, int>();
List<OpenXRRuntimeSelector.RuntimeDetector> detectorList = OpenXRRuntimeSelector.GenerateRuntimeDetectorList(runtimePathToValue);
Assert.IsTrue(detectorList.Count > 0);
Assert.IsTrue(detectorList[0] is OpenXRRuntimeSelector.SystemDefault);
Assert.IsTrue(detectorList[detectorList.Count - 1] is OpenXRRuntimeSelector.OtherRuntime);
bool foundWindowsMRDetector = false;
bool foundSteamVRDetector = false;
bool foundOculusDetector = false;
foreach (var detector in detectorList)
{
foundWindowsMRDetector |= detector is OpenXRRuntimeSelector.WindowsMRDetector;
foundSteamVRDetector |= detector is OpenXRRuntimeSelector.SteamVRDetector;
foundOculusDetector |= detector is OpenXRRuntimeSelector.OculusDetector;
}
Assert.IsTrue(foundWindowsMRDetector);
Assert.IsTrue(foundSteamVRDetector);
Assert.IsTrue(foundOculusDetector);
}
[Test]
public void DiscoveredAvailableRuntimesTest()
{
OpenXRRuntimeSelector.WindowsMRDetector windowsMRDetector = new OpenXRRuntimeSelector.WindowsMRDetector();
OpenXRRuntimeSelector.SteamVRDetector steamVRDetector = new OpenXRRuntimeSelector.SteamVRDetector();
OpenXRRuntimeSelector.OculusDetector oculusDetector = new OpenXRRuntimeSelector.OculusDetector();
string enabledRuntime = "enabledRuntime";
string disabledRuntime = "disabledRuntime";
Dictionary<string, int> runtimePathToValue = new Dictionary<string, int>()
{
{ windowsMRDetector.jsonPath, 0},
{ steamVRDetector.jsonPath, 1},
{ enabledRuntime, 0 },
{ disabledRuntime, 1 }
};
List<OpenXRRuntimeSelector.RuntimeDetector> detectorList = OpenXRRuntimeSelector.GenerateRuntimeDetectorList(runtimePathToValue);
Assert.IsTrue(detectorList.Count > 0);
Assert.IsTrue(detectorList[0] is OpenXRRuntimeSelector.SystemDefault);
Assert.IsTrue(detectorList[detectorList.Count - 1] is OpenXRRuntimeSelector.OtherRuntime);
HashSet<string> detectedJsons = new HashSet<string>();
foreach (var detector in detectorList)
{
detectedJsons.Add(detector.jsonPath);
}
Assert.IsTrue(detectedJsons.Contains(windowsMRDetector.jsonPath));
Assert.IsFalse(detectedJsons.Contains(steamVRDetector.jsonPath));
Assert.IsTrue(detectedJsons.Contains(oculusDetector.jsonPath));
Assert.IsTrue(detectedJsons.Contains(enabledRuntime));
Assert.IsFalse(detectedJsons.Contains(disabledRuntime));
}
[Test]
public void TestSelectOtherRuntime()
{
// Get the OtherRuntime choice (verify that it's the last detector)
var runtimeDetector = OpenXRRuntimeSelector.RuntimeDetectors[OpenXRRuntimeSelector.RuntimeDetectors.Count - 1];
OpenXRRuntimeSelector.OtherRuntime otherRuntime = runtimeDetector as OpenXRRuntimeSelector.OtherRuntime;
Assert.IsTrue(otherRuntime != null);
// Save data that this test will modify to restore state after the test finishes.
string previousOtherJsonPath = otherRuntime.jsonPath;
string previousActiveRuntime = Environment.GetEnvironmentVariable(OpenXRRuntimeSelector.RuntimeDetector.k_RuntimeEnvKey);
string previousSelectedRuntime = Environment.GetEnvironmentVariable(OpenXRRuntimeSelector.k_SelectedRuntimeEnvKey);
try
{
// Set the other runtime value and set this as the selected runtime.
string jsonPath = "testJsonPath";
otherRuntime.SetOtherRuntimeJsonPath(jsonPath);
OpenXRRuntimeSelector.SetSelectedRuntime(jsonPath);
// Exit Edit Mode. Active runtime and Selected runtime should have the json path.
OpenXRRuntimeSelector.ActivateOrDeactivateRuntime(PlayModeStateChange.ExitingEditMode);
string activeRuntime = Environment.GetEnvironmentVariable(OpenXRRuntimeSelector.RuntimeDetector.k_RuntimeEnvKey);
string selectedRuntime = Environment.GetEnvironmentVariable(OpenXRRuntimeSelector.k_SelectedRuntimeEnvKey);
Assert.AreEqual(activeRuntime, jsonPath);
Assert.AreEqual(selectedRuntime, jsonPath);
// Simulate a refresh of the runtime detectors when entering play mode.
// The OtherRuntime should still have the jsonPath from before.
OpenXRRuntimeSelector.RefreshRuntimeDetectorList();
runtimeDetector = OpenXRRuntimeSelector.RuntimeDetectors[OpenXRRuntimeSelector.RuntimeDetectors.Count - 1];
otherRuntime = runtimeDetector as OpenXRRuntimeSelector.OtherRuntime;
Assert.AreEqual(otherRuntime.jsonPath, jsonPath);
// Enter Edit Mode. Active runtime should be cleared, selected runtime should still have the json path.
OpenXRRuntimeSelector.ActivateOrDeactivateRuntime(PlayModeStateChange.EnteredEditMode);
activeRuntime = Environment.GetEnvironmentVariable(OpenXRRuntimeSelector.RuntimeDetector.k_RuntimeEnvKey);
selectedRuntime = Environment.GetEnvironmentVariable(OpenXRRuntimeSelector.k_SelectedRuntimeEnvKey);
Assert.AreNotEqual(activeRuntime, jsonPath);
Assert.AreEqual(selectedRuntime, jsonPath);
// Refresh again. OtherRuntime and selected runtime should still have the json path.
OpenXRRuntimeSelector.RefreshRuntimeDetectorList();
runtimeDetector = OpenXRRuntimeSelector.RuntimeDetectors[OpenXRRuntimeSelector.RuntimeDetectors.Count - 1];
otherRuntime = runtimeDetector as OpenXRRuntimeSelector.OtherRuntime;
Assert.AreEqual(otherRuntime.jsonPath, jsonPath);
}
finally
{
otherRuntime.SetOtherRuntimeJsonPath(previousOtherJsonPath);
Environment.SetEnvironmentVariable(OpenXRRuntimeSelector.RuntimeDetector.k_RuntimeEnvKey, previousActiveRuntime);
Environment.SetEnvironmentVariable(OpenXRRuntimeSelector.k_SelectedRuntimeEnvKey, previousSelectedRuntime);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 14582cceaceaa6949852ce064e85a84a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,75 @@
using System;
using NUnit.Framework;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.Features.Interactions;
using UnityEngine.XR.OpenXR;
using Unity.XR.CoreUtils.Editor;
namespace UnityEditor.XR.OpenXR.Tests
{
internal class OpenXRValidationTests
{
internal class FakeFeature : OpenXRFeature
{
}
/// <summary>
/// Test that IsRuleEnabled will be true at the correct time for a BuildValidationRule.
/// </summary>
[Test]
public void IsRuleEnabledTest()
{
// Create a validation rule that is enabled when FakeFeature is active
OpenXRFeature.ValidationRule testRule = new OpenXRFeature.ValidationRule(ScriptableObject.CreateInstance<FakeFeature>())
{
message = "Fake feature message.",
checkPredicate = () => true,
fixIt = () => { },
error = false,
errorEnteringPlaymode = false
};
// Create the build validation rule for Standalone (arbitrarily picked)
BuildValidationRule buildValidationRule = OpenXRProjectValidationRulesSetup.ConvertRuleToBuildValidationRule(testRule, BuildTargetGroup.Standalone);
// Since the feature isn't in the active Standalone settings, the rule should not be enabled.
Assert.IsFalse(buildValidationRule.IsRuleEnabled());
// Temporarily add an enabled FakeFeature to the Standalone settings, and then restore the settings when the test is done.
// The build validation rule should be enabled when we add the feature to the Standalone settings.
OpenXRSettings standaloneSettings = OpenXRSettings.GetSettingsForBuildTargetGroup(BuildTargetGroup.Standalone);
OpenXRFeature firstStandaloneSetting = standaloneSettings.features[0];
try
{
FakeFeature fakeFeature = ScriptableObject.CreateInstance<FakeFeature>();
fakeFeature.enabled = true;
standaloneSettings.features[0] = fakeFeature;
Assert.IsTrue(buildValidationRule.IsRuleEnabled());
}
finally
{
standaloneSettings.features[0] = firstStandaloneSetting;
}
// Create another build validation rule for something else other than Standalone.
// The build validation rule should not be enabled when we add the feature to the Standalone group.
buildValidationRule = OpenXRProjectValidationRulesSetup.ConvertRuleToBuildValidationRule(testRule, BuildTargetGroup.WSA);
standaloneSettings = OpenXRSettings.GetSettingsForBuildTargetGroup(BuildTargetGroup.Standalone);
firstStandaloneSetting = standaloneSettings.features[0];
try
{
FakeFeature fakeFeature = ScriptableObject.CreateInstance<FakeFeature>();
fakeFeature.enabled = true;
standaloneSettings.features[0] = fakeFeature;
Assert.IsFalse(buildValidationRule.IsRuleEnabled());
}
finally
{
standaloneSettings.features[0] = firstStandaloneSetting;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8329db5b1413bf24f849af3e63602cd9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,36 @@
{
"name": "Unity.XR.OpenXR.Tests.Editor",
"rootNamespace": "",
"references": [
"GUID:27619889b8ba8c24980f49ee34dbb44a",
"GUID:0acc523941302664db1f4e527237feb3",
"GUID:4847341ff46394e83bb78fbd0652937e",
"GUID:96aa6ba065960476598f8f643e7252b6",
"GUID:e40ba710768534012815d3193fa296cb",
"GUID:2023fa18bf9504e98b11fe2174802802",
"GUID:6150739e4dc7bff4d833306fd9d5a4f0",
"GUID:75469ad4d38634e559750d17036d5f7c",
"GUID:4ddd23ea56a3a40f0aa0036d1624a53e"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
],
"versionDefines": [
{
"name": "com.unity.inputsystem",
"expression": "1.6.3",
"define": "INPUT_SYSTEM_BINDING_VALIDATOR"
}
],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 666653aa92bac494b9db60410f5b51f0
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,158 @@
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.Features.Mock;
using UnityEngine.XR.OpenXR.Tests;
using Assert = UnityEngine.Assertions.Assert;
[assembly: UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor)]
namespace UnityEditor.XR.OpenXR.Tests
{
internal class XRLoaderLifecycleTests : OpenXRLoaderSetup
{
[Test]
public void FullLifecycleOrder()
{
bool subsystemCreate = false;
bool subsystemStart = false;
bool hookInstanceProc = false;
MockRuntime.Instance.TestCallback = (methodName, param) =>
{
switch (methodName)
{
case nameof(OpenXRFeature.HookGetInstanceProcAddr):
Assert.IsFalse(subsystemCreate);
Assert.IsFalse(subsystemStart);
hookInstanceProc = true;
break;
case nameof(OpenXRFeature.OnSubsystemCreate):
Assert.IsTrue(hookInstanceProc);
Assert.IsFalse(subsystemStart);
subsystemCreate = true;
break;
case nameof(OpenXRFeature.OnSubsystemStart):
Assert.IsTrue(hookInstanceProc);
Assert.IsTrue(subsystemCreate);
subsystemStart = true;
break;
}
return true;
};
base.InitializeAndStart();
ProcessOpenXRMessageLoop();
Assert.IsTrue(hookInstanceProc);
Assert.IsTrue(subsystemCreate);
Assert.IsTrue(subsystemStart);
bool subsystemStop = false;
bool subsystemDestroy = false;
MockRuntime.Instance.TestCallback = (methodName, param) =>
{
switch (methodName)
{
case nameof(OpenXRFeature.OnSubsystemStop):
Assert.IsFalse(subsystemDestroy);
subsystemStop = true;
break;
case nameof(OpenXRFeature.OnSubsystemDestroy):
Assert.IsTrue(subsystemStop);
subsystemDestroy = true;
break;
}
return true;
};
base.StopAndShutdown();
Assert.IsTrue(subsystemStop);
Assert.IsTrue(subsystemDestroy);
}
[Test]
public void InstanceCreate() => TestInstanceCreate(true, false);
[Test]
public void InstanceCreateFail() => TestInstanceCreate(false, false);
[Test]
public void InstanceCreateRequired() => TestInstanceCreate(true, true);
[Test]
public void InstanceCreateFailRequired() => TestInstanceCreate(false, true);
public void TestInstanceCreate(bool result, bool required)
{
Loader.DisableValidationChecksOnEnteringPlaymode = true;
bool instanceCreated = false;
bool hookInstanceProcAddr = false;
bool other = false;
MockRuntime.Instance.TestCallback = (methodName, param) =>
{
switch (methodName)
{
case nameof(OpenXRFeature.OnInstanceCreate):
instanceCreated = true;
return result;
case nameof(OpenXRFeature.HookGetInstanceProcAddr):
hookInstanceProcAddr = true;
break;
default:
other = true;
break;
}
return true;
};
MockRuntime.Instance.required = required;
base.InitializeAndStart();
Assert.IsTrue(instanceCreated);
Assert.IsTrue(hookInstanceProcAddr);
if (required && !result)
Assert.IsNull(OpenXRLoaderBase.Instance);
else
Assert.IsNotNull(OpenXRLoaderBase.Instance);
// A feature that fails that is not required should be disabled
if (!result && !required)
Assert.IsFalse(MockRuntime.Instance.enabled);
base.StopAndShutdown();
if (result)
Assert.IsTrue(other);
else
// A feature that fails initialize should have no further callbacks
Assert.IsFalse(other);
}
[Test]
public void DeinitWithoutInit()
{
bool callback = false;
MockRuntime.Instance.TestCallback = (methodName, param) =>
{
callback = true;
return true;
};
base.StopAndShutdown();
Assert.IsFalse(callback);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dd9093c836e64270bb8a8c79d98e0055
timeCreated: 1586981136

View File

@@ -0,0 +1,45 @@
using System.IO;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using UnityEditor.SceneManagement;
[assembly: UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor)]
namespace UnityEditor.XR.OpenXR.Tests
{
internal class aAssetBundleTests
{
[Test]
public void BuildAssetBundle()
{
#if UNITY_EDITOR_WIN
var target = BuildTarget.StandaloneWindows64;
#elif UNITY_EDITOR_OSX
var target = BuildTarget.StandaloneOSX;
#else
var target = BuildTarget.NoTarget;
#endif
// Test is only valid if we have a valid build target and that build target is available
if (target == BuildTarget.NoTarget || !BuildPipeline.IsBuildTargetSupported(BuildPipeline.GetBuildTargetGroup(target), target))
return;
// Create an asset and add it to an asset bundle
var scene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects);
EditorSceneManager.SaveScene(scene, "Assets/abtest.unity");
AssetDatabase.Refresh();
var importer = AssetImporter.GetAtPath("Assets/abtest.unity");
importer.assetBundleName = "mocktest";
if (!Directory.Exists("mocktest/ab"))
Directory.CreateDirectory("mocktest/ab");
// Build the asset bundle
BuildPipeline.BuildAssetBundles("mocktest/ab", BuildAssetBundleOptions.ForceRebuildAssetBundle, target);
// Cleanup
AssetDatabase.DeleteAsset("Assets/abtest.unity");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3bfe33a5f8e944b0be093f643d913262
timeCreated: 1625861611

View File

@@ -0,0 +1,310 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
using UnityEditor.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.Features.Mock;
using UnityEditor.Build.Reporting;
using UnityEngine;
using UnityEngine.XR.Management;
using UnityEngine.XR.OpenXR.Tests;
using Assert = UnityEngine.Assertions.Assert;
namespace UnityEditor.XR.OpenXR.Tests
{
// If you change this file, be sure to run the "no players" tests on yamato.
// APV jobs don't include "players" such as standalone, so `BuildMockPlayer()`
// will fail during APV. The "no players" job on yamato will catch this.
internal class zBuildHookTests : OpenXRLoaderSetup
{
internal static BuildReport BuildMockPlayer()
{
BuildPlayerOptions opts = new BuildPlayerOptions();
#if UNITY_EDITOR_WIN
opts.target = BuildTarget.StandaloneWindows64;
#elif UNITY_EDITOR_OSX
opts.target = BuildTarget.StandaloneOSX;
#endif
if (File.Exists("Assets/main.unity"))
opts.scenes = new string[] { "Assets/main.unity" };
opts.targetGroup = BuildTargetGroup.Standalone;
opts.locationPathName = "mocktest/mocktest.exe";
UnityEngine.TestTools.LogAssert.ignoreFailingMessages = true;
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone, opts.target);
var report = BuildPipeline.BuildPlayer(opts);
UnityEngine.TestTools.LogAssert.ignoreFailingMessages = false;
return report;
}
[Test]
public void PrePostCallbacksAreReceived()
{
bool preprocessCalled = false;
bool postprocessCalled = false;
BuildCallbacks.TestCallback = (methodName, param) =>
{
if (methodName == "OnPreprocessBuildExt")
{
preprocessCalled = true;
}
if (methodName == "OnPostprocessBuildExt")
{
postprocessCalled = true;
}
return true;
};
var result = BuildMockPlayer();
if (Environment.GetEnvironmentVariable("UNITY_OPENXR_YAMATO") == "1")
Assert.IsTrue(result.summary.result == BuildResult.Succeeded);
else if (result.summary.result != BuildResult.Succeeded)
return;
Assert.IsTrue(preprocessCalled);
Assert.IsTrue(postprocessCalled);
}
[Test]
public void NoBuildCallbacksFeatureDisabled()
{
bool preprocessCalled = false;
bool postprocessCalled = false;
BuildCallbacks.TestCallback = (methodName, param) =>
{
if (methodName == "OnPreprocessBuildExt")
{
preprocessCalled = true;
}
if (methodName == "OnPostprocessBuildExt")
{
postprocessCalled = true;
}
return true;
};
// Disable mock runtime, no callbacks should occur during build
EnableFeature<MockRuntime>(false);
BuildMockPlayer();
Assert.IsFalse(preprocessCalled);
Assert.IsFalse(postprocessCalled);
}
[Test]
public void NoBuildCallbacksOpenXRDisabled()
{
bool preprocessCalled = false;
bool postprocessCalled = false;
BuildCallbacks.TestCallback = (methodName, param) =>
{
if (methodName == "OnPreprocessBuildExt")
{
preprocessCalled = true;
}
if (methodName == "OnPostprocessBuildExt")
{
postprocessCalled = true;
}
return true;
};
// Remove OpenXR Loader, no callbacks should occur during build
var loaders = XRGeneralSettings.Instance.Manager.activeLoaders;
XRGeneralSettings.Instance.Manager.TrySetLoaders(new List<XRLoader>());
BuildMockPlayer();
XRGeneralSettings.Instance.Manager.TrySetLoaders(new List<XRLoader>(loaders));
Assert.IsFalse(preprocessCalled);
Assert.IsFalse(postprocessCalled);
}
[Test]
public void VerifyBootConfigWrite()
{
bool preprocessCalled = false;
bool postprocessCalled = false;
BootConfigTests.TestCallback = (methodName, param) =>
{
if (methodName == "OnPreprocessBuildExt")
{
preprocessCalled = true;
}
if (methodName == "OnPostprocessBuildExt")
{
postprocessCalled = true;
}
return true;
};
var result = BuildMockPlayer();
BuildMockPlayer();
Assert.IsFalse(preprocessCalled);
Assert.IsFalse(postprocessCalled);
BootConfigTests.EnsureCleanupFromLastRun();
}
private bool HasOpenXRLibraries(BuildReport report)
{
var path = Path.GetDirectoryName(report.summary.outputPath);
var dir = new DirectoryInfo(path);
var ext = "dll";
if (Application.platform == RuntimePlatform.OSXEditor)
ext = "dylib";
var dlls = dir.EnumerateFiles($"*.{ext}", SearchOption.AllDirectories).Select(s => s.Name).ToList();
return dlls.Contains($"openxr_loader.{ext}") || dlls.Contains($"UnityOpenXR.{ext}");
}
[Test]
public void VerifyBuildOutputLibraries()
{
var resultWithOpenXR = BuildMockPlayer();
// Disable this test if we're not running our openxr yamato infrastructure
if (resultWithOpenXR.summary.result != BuildResult.Succeeded && Environment.GetEnvironmentVariable("UNITY_OPENXR_YAMATO") != "1")
return;
Assert.IsTrue(HasOpenXRLibraries(resultWithOpenXR));
// Remove OpenXR Loader
XRGeneralSettings.Instance.Manager.TrySetLoaders(new List<XRLoader>());
var resultWithoutOpenXR = BuildMockPlayer();
Assert.IsFalse(HasOpenXRLibraries(resultWithoutOpenXR));
}
[Test]
public void VerifyBuildWithoutAnalytics()
{
var packageName = "com.unity.analytics";
UnityEditor.PackageManager.Client.Remove(packageName);
var result = BuildMockPlayer();
if (Environment.GetEnvironmentVariable("UNITY_OPENXR_YAMATO") == "1")
Assert.IsTrue(result.summary.result == BuildResult.Succeeded);
else if (result.summary.result != BuildResult.Succeeded)
return;
}
internal class BuildCallbacks : OpenXRFeatureBuildHooks
{
[NonSerialized] internal static Func<string, object, bool> TestCallback = (methodName, param) => true;
public override int callbackOrder => 1;
public override Type featureType => typeof(MockRuntime);
protected override void OnPreprocessBuildExt(BuildReport report)
{
TestCallback(MethodBase.GetCurrentMethod().Name, report);
}
protected override void OnPostGenerateGradleAndroidProjectExt(string path)
{
TestCallback(MethodBase.GetCurrentMethod().Name, path);
}
protected override void OnPostprocessBuildExt(BuildReport report)
{
TestCallback(MethodBase.GetCurrentMethod().Name, report);
}
protected override void OnProcessBootConfigExt(BuildReport report, BootConfigBuilder builder)
{
TestCallback(MethodBase.GetCurrentMethod().Name, report);
}
}
internal class BootConfigTests : OpenXRFeatureBuildHooks
{
[NonSerialized] internal static Func<string, object, bool> TestCallback = (methodName, param) => true;
public override int callbackOrder => 1;
public override Type featureType => typeof(MockRuntime);
// For this test, we want to ensure that the last run actually cleans up any settings that we've
// stored into the boot settings of the EditorUserBuildSettings. We need the last run BuildReport
// in order to check the EditorUserBuildSettings.
private static BuildReport s_lastRunBuildReport;
protected override void OnPreprocessBuildExt(BuildReport report)
{
}
protected override void OnPostGenerateGradleAndroidProjectExt(string path)
{
}
protected override void OnPostprocessBuildExt(BuildReport report)
{
// check to see if we've got the boot config written into the UserSettings
var bootConfig = new BootConfig(report);
bootConfig.ReadBootConfig();
Assert.IsTrue(bootConfig.TryGetValue("key-01", out var key01Value));
Assert.AreEqual(key01Value, "primary test value");
Assert.IsTrue(bootConfig.TryGetValue("key-02", out var key02Value));
Assert.AreEqual(key02Value, "secondary test value");
Assert.IsTrue(bootConfig.TryGetValue("key-03", out var key03Value));
Assert.AreEqual(key03Value, "1");
Assert.IsTrue(bootConfig.TryGetValue("key-04", out var key04Value));
Assert.AreEqual(key04Value, "0");
s_lastRunBuildReport = report;
}
protected override void OnProcessBootConfigExt(BuildReport report, BootConfigBuilder builder)
{
// Now we set some boot config values and check to make sure they're there.
builder.SetBootConfigValue("key-01", "primary test value");
builder.SetBootConfigValue("key-02", "secondary test value");
builder.SetBootConfigBoolean("key-03", true);
builder.SetBootConfigBoolean("key-04", false);
Assert.IsTrue(builder.TryGetBootConfigValue("key-01", out var result01));
Assert.AreEqual(result01, "primary test value");
Assert.IsTrue(builder.TryGetBootConfigValue("key-02", out var result02));
Assert.AreEqual(result02, "secondary test value");
Assert.IsTrue(builder.TryGetBootConfigBoolean("key-03", out var result03));
Assert.IsTrue(result03);
Assert.IsTrue(builder.TryGetBootConfigBoolean("key-04", out var result04));
Assert.IsFalse(result04);
builder.SetBootConfigValue("key-05", "remove-me");
Assert.IsTrue(builder.TryRemoveBootConfigEntry("key-05"));
Assert.IsFalse(builder.TryGetBootConfigValue("key-05", out var result05));
Assert.IsFalse(builder.TryGetBootConfigBoolean("key-999", out var result06));
Assert.IsFalse(result06);
}
public static void EnsureCleanupFromLastRun()
{
// make sure that the UserSettings doesn't hold any additional configs we've previously written
if (s_lastRunBuildReport == null)
return;
var bootConfig = new BootConfig(s_lastRunBuildReport);
bootConfig.ReadBootConfig();
Assert.IsFalse(bootConfig.TryGetValue("key-01", out var key01Value));
Assert.IsFalse(bootConfig.TryGetValue("key-02", out var key02Value));
Assert.IsFalse(bootConfig.TryGetValue("key-03", out var key03Value));
Assert.IsFalse(bootConfig.TryGetValue("key-04", out var key04Value));
Assert.IsFalse(bootConfig.TryGetValue("key-05", out var key05Value));
s_lastRunBuildReport = null;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4a0dc36717c904db4ab68f42baa559da
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,372 @@
using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor.XR.OpenXR.Features;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Rendering;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.Features.Interactions;
class zBuildSamplesYamatoOnly
{
struct SampleBuildTargetSetup
{
public BuildTarget buildTarget;
public BuildTargetGroup targetGroup;
public Action<string, string> setupPlayerSettings;
public string outputPostfix;
public Regex sampleRegex;
}
static void WriteAndroidInstallerScripts(string outputFile, string identifier)
{
var dir = Path.GetDirectoryName(outputFile);
if (dir == null) return;
Directory.CreateDirectory(dir);
var scripts = new string[] { "install.command", "install.bat" };
foreach (var script in scripts)
{
var scriptPath = Path.Combine(dir, script);
var scriptContents = $"adb uninstall {identifier}\n" +
$"adb install \"{Path.GetFileName(outputFile)}\"\n\n";
File.AppendAllText(scriptPath, scriptContents);
}
}
static void EnableQuestFeature()
{
foreach (var feature in OpenXRSettings.ActiveBuildTargetInstance.features)
{
if (String.Compare(feature.featureIdInternal, "com.unity.openxr.feature.metaquest", true) == 0)
{
Console.WriteLine($"Enable: {feature.nameUi}");
feature.enabled = true;
return;
}
}
Assert.IsTrue(false, "Could not enable meta quest extension - if you're not on build machine you must copy dir MetaQuest to your project.");
}
static void EnableMSFTObserverFeature()
{
foreach (var feature in OpenXRSettings.ActiveBuildTargetInstance.features)
{
if (String.Compare(feature.featureIdInternal, "com.unity.openxr.feature.example.msftobserver", true) == 0)
{
Console.WriteLine($"Enable: {feature.nameUi}");
feature.enabled = true;
return;
}
}
}
static void EnableFeature<TFeatureType>() where TFeatureType : OpenXRFeature
{
foreach (var feature in OpenXRSettings.ActiveBuildTargetInstance.features)
{
if (feature is TFeatureType)
{
Console.WriteLine($"Enable: {feature.nameUi}");
feature.enabled = true;
break;
}
}
}
static void EnableSampleFeatures()
{
foreach (var feature in OpenXRSettings.ActiveBuildTargetInstance.features)
{
if (feature.GetType().Namespace == null)
{
throw new Exception("All code in the OpenXR Package must be in a namespace.");
}
if (feature.GetType().Namespace.StartsWith("UnityEngine.XR.OpenXR.Samples"))
{
Console.WriteLine($"Enable: {feature.nameUi}");
feature.enabled = true;
}
}
}
static void EnableStandaloneProfiles()
{
EnableFeature<MicrosoftHandInteraction>();
EnableFeature<MicrosoftMotionControllerProfile>();
EnableFeature<HTCViveControllerProfile>();
EnableFeature<ValveIndexControllerProfile>();
EnableFeature<OculusTouchControllerProfile>();
EnableFeature<MetaQuestTouchProControllerProfile>();
EnableFeature<HandInteractionProfile>();
EnableFeature<PalmPoseInteraction>();
EnableFeature<DPadInteraction>();
EnableFeature<HandCommonPosesInteraction>();
}
static void EnableWSAProfiles()
{
EnableFeature<MicrosoftHandInteraction>();
EnableFeature<EyeGazeInteraction>();
EnableFeature<MicrosoftMotionControllerProfile>();
EnableFeature<HandInteractionProfile>();
EnableFeature<PalmPoseInteraction>();
EnableFeature<HandCommonPosesInteraction>();
}
static void EnableAndroidProfiles()
{
EnableFeature<OculusTouchControllerProfile>();
EnableFeature<MetaQuestTouchProControllerProfile>();
}
static SampleBuildTargetSetup[] buildTargetSetup =
{
#if UNITY_EDITOR_WIN
new SampleBuildTargetSetup
{
buildTarget = BuildTarget.StandaloneWindows64,
targetGroup = BuildTargetGroup.Standalone,
setupPlayerSettings = (outputFile, identifier) =>
{
EnableSampleFeatures();
EnableStandaloneProfiles();
PlayerSettings.SetGraphicsAPIs(BuildTarget.StandaloneWindows64, new[] { GraphicsDeviceType.Direct3D11, GraphicsDeviceType.Vulkan });
OpenXRSettings.ActiveBuildTargetInstance.depthSubmissionMode = OpenXRSettings.DepthSubmissionMode.Depth24Bit;
},
outputPostfix = "dx11",
},
new SampleBuildTargetSetup
{
sampleRegex = new Regex(".*Render.*"), // Only build dx12 variant for Render Samples
buildTarget = BuildTarget.StandaloneWindows64,
targetGroup = BuildTargetGroup.Standalone,
setupPlayerSettings = (outputFile, identifier) =>
{
EnableSampleFeatures();
PlayerSettings.SetGraphicsAPIs(BuildTarget.StandaloneWindows64, new[] { GraphicsDeviceType.Direct3D12, GraphicsDeviceType.Direct3D11 });
QualitySettings.SetQualityLevel(5);
QualitySettings.antiAliasing = 4;
},
outputPostfix = "dx12",
},
new SampleBuildTargetSetup
{
sampleRegex = new Regex(".*Render.*"), // Only build vulkan variant for Render Samples
buildTarget = BuildTarget.StandaloneWindows64,
targetGroup = BuildTargetGroup.Standalone,
setupPlayerSettings = (outputFile, identifier) =>
{
EnableSampleFeatures();
PlayerSettings.SetGraphicsAPIs(BuildTarget.StandaloneWindows64, new[] { GraphicsDeviceType.Vulkan, GraphicsDeviceType.Direct3D11 });
OpenXRSettings.ActiveBuildTargetInstance.depthSubmissionMode = OpenXRSettings.DepthSubmissionMode.Depth24Bit;
},
outputPostfix = "vk",
},
new SampleBuildTargetSetup
{
buildTarget = BuildTarget.WSAPlayer,
targetGroup = BuildTargetGroup.WSA,
setupPlayerSettings = (outputFile, identifier) =>
{
EnableSampleFeatures();
EnableMSFTObserverFeature();
EnableFeature<EyeGazeInteraction>();
EnableFeature<MicrosoftHandInteraction>();
EnableWSAProfiles();
PlayerSettings.SetGraphicsAPIs(BuildTarget.WSAPlayer, new[] { GraphicsDeviceType.Direct3D11 });
PlayerSettings.WSA.SetCapability(PlayerSettings.WSACapability.GazeInput, true);
#if UNITY_2021_3_OR_NEWER
PlayerSettings.WSA.packageName = PlayerSettings.GetApplicationIdentifier(NamedBuildTarget.WindowsStoreApps);
#else
PlayerSettings.WSA.packageName = PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.WSA);
#endif
OpenXRSettings.ActiveBuildTargetInstance.renderMode = OpenXRSettings.RenderMode.SinglePassInstanced;
OpenXRSettings.ActiveBuildTargetInstance.depthSubmissionMode = OpenXRSettings.DepthSubmissionMode.Depth16Bit;
},
outputPostfix = "dx11",
},
new SampleBuildTargetSetup
{
sampleRegex = new Regex(".*Render.*"), // Only build dx12 variant for Render Samples
buildTarget = BuildTarget.WSAPlayer,
targetGroup = BuildTargetGroup.WSA,
setupPlayerSettings = (outputFile, identifier) =>
{
EnableSampleFeatures();
EnableMSFTObserverFeature();
EnableFeature<EyeGazeInteraction>();
EnableFeature<MicrosoftHandInteraction>();
PlayerSettings.SetGraphicsAPIs(BuildTarget.WSAPlayer, new[] { GraphicsDeviceType.Direct3D12 });
QualitySettings.SetQualityLevel(5);
QualitySettings.antiAliasing = 4;
#if UNITY_2021_3_OR_NEWER
PlayerSettings.WSA.packageName = PlayerSettings.GetApplicationIdentifier(NamedBuildTarget.WindowsStoreApps);
#else
PlayerSettings.WSA.packageName = PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.WSA);
#endif
PlayerSettings.WSA.SetCapability(PlayerSettings.WSACapability.GazeInput, true);
},
outputPostfix = "dx12",
},
#endif
new SampleBuildTargetSetup
{
sampleRegex = new Regex(".*Render.*|.*MetaSample.*"), // Only build vulkan variant for Render Samples
buildTarget = BuildTarget.Android,
targetGroup = BuildTargetGroup.Android,
setupPlayerSettings = (outputFile, identifier) =>
{
EnableSampleFeatures();
EnableQuestFeature();
EnableAndroidProfiles();
PlayerSettings.SetGraphicsAPIs(BuildTarget.Android, new[] { GraphicsDeviceType.Vulkan, GraphicsDeviceType.OpenGLES3 });
PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel25;
PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64;
#if UNITY_2021_3_OR_NEWER
PlayerSettings.SetScriptingBackend(NamedBuildTarget.Android, ScriptingImplementation.IL2CPP);
#else
PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, ScriptingImplementation.IL2CPP);
#endif
WriteAndroidInstallerScripts(outputFile, identifier);
OpenXRSettings.ActiveBuildTargetInstance.depthSubmissionMode = OpenXRSettings.DepthSubmissionMode.Depth16Bit;
},
outputPostfix = "arm64_vk",
},
new SampleBuildTargetSetup
{
sampleRegex = new Regex("^(?!.*MetaSample).*$"), // Don't build the Meta Sample for GLES
buildTarget = BuildTarget.Android,
targetGroup = BuildTargetGroup.Android,
setupPlayerSettings = (outputFile, identifier) =>
{
EnableSampleFeatures();
EnableQuestFeature();
EnableAndroidProfiles();
PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.Android, false);
PlayerSettings.SetGraphicsAPIs(BuildTarget.Android, new[] { GraphicsDeviceType.OpenGLES3, GraphicsDeviceType.Vulkan });
PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel25;
PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64;
#if UNITY_2021_3_OR_NEWER
PlayerSettings.SetScriptingBackend(NamedBuildTarget.Android, ScriptingImplementation.IL2CPP);
#else
PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, ScriptingImplementation.IL2CPP);
#endif
WriteAndroidInstallerScripts(outputFile, identifier);
OpenXRSettings.ActiveBuildTargetInstance.depthSubmissionMode = OpenXRSettings.DepthSubmissionMode.Depth16Bit;
},
outputPostfix = "arm64_gles3",
},
};
static string GetBuildFileExt(BuildTarget target)
{
switch (target)
{
case BuildTarget.Android:
return ".apk";
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
return ".exe";
default:
return "";
}
}
static string GetResultDir()
{
bool next = false;
foreach (var arg in System.Environment.GetCommandLineArgs())
{
if (next)
return arg;
if (arg == "-resultDir")
next = true;
}
return "OpenXR Samples";
}
static void BuildSamples()
{
string resultDir = GetResultDir();
Console.WriteLine("Result Dir: " + resultDir);
var sampleName = "Unknown Sample";
var projSamplesDir = new DirectoryInfo("Assets/Sample");
if (projSamplesDir.Exists)
{
// Use the directory name in the samples directory, if it exists
sampleName = projSamplesDir.GetDirectories()[0].Name;
}
else
{
// Otherwise use the current folder as the project name
projSamplesDir = new DirectoryInfo("Assets");
sampleName = new DirectoryInfo(".").Name;
}
PlayerSettings.colorSpace = ColorSpace.Linear;
FeatureHelpers.RefreshFeatures(EditorUserBuildSettings.selectedBuildTargetGroup);
foreach (var setup in buildTargetSetup)
{
if (setup.sampleRegex != null && !setup.sampleRegex.Match(sampleName).Success)
continue;
if (EditorUserBuildSettings.activeBuildTarget != setup.buildTarget)
continue;
string outputDir = Path.Combine(resultDir, setup.buildTarget.ToString());
string identifier = "com.openxr." + sampleName + "." + setup.outputPostfix;
#if UNITY_2021_3_OR_NEWER
PlayerSettings.SetApplicationIdentifier(NamedBuildTarget.FromBuildTargetGroup(setup.targetGroup), identifier);
#else
PlayerSettings.SetApplicationIdentifier(setup.targetGroup, identifier);
#endif
PlayerSettings.productName = "OpenXR " + sampleName + " " + setup.outputPostfix;
Console.WriteLine("=========== Setting up player settings (changing graphics apis)");
string outputFile = Path.Combine(outputDir,
PlayerSettings.productName + GetBuildFileExt(setup.buildTarget));
setup.setupPlayerSettings(outputFile, identifier);
// Get the list of scenes set in build settings in the project
var scenes = EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray();
// If there aren't any, just build all of the scenes found in the sample
if (scenes.Length == 0)
{
scenes = Directory.GetFiles(projSamplesDir.FullName, "*.unity", SearchOption.AllDirectories);
}
BuildPlayerOptions buildOptions = new BuildPlayerOptions
{
scenes = scenes,
target = setup.buildTarget,
targetGroup = setup.targetGroup,
locationPathName = outputFile,
};
Console.WriteLine($"=========== Building {sampleName} {setup.buildTarget}_{setup.outputPostfix}");
var report = BuildPipeline.BuildPlayer(buildOptions);
Console.WriteLine($"=========== Build Result {sampleName} {setup.buildTarget}_{setup.outputPostfix} {report.summary.result}");
if (report.summary.result == BuildResult.Failed)
{
EditorApplication.Exit(1);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b539520d5a342436b8ee4abb353fd33b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: