From 4e97724486f7d83ab6083eaa428afcaf3f7f704e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 May 2026 11:55:19 -0700 Subject: [PATCH 1/8] Bump addressable from 2.8.8 to 2.9.0 in /docs (#1120) Bumps [addressable](https://github.com/sporkmonger/addressable) from 2.8.8 to 2.9.0. - [Changelog](https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md) - [Commits](https://github.com/sporkmonger/addressable/compare/addressable-2.8.8...addressable-2.9.0) --- updated-dependencies: - dependency-name: addressable dependency-version: 2.9.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index cb4fc54ab..bfab914b5 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - addressable (2.8.8) + addressable (2.9.0) public_suffix (>= 2.0.2, < 8.0) base64 (0.3.0) bigdecimal (3.3.1) @@ -66,7 +66,7 @@ GEM mercenary (0.4.0) pathutil (0.16.2) forwardable-extended (~> 2.6) - public_suffix (7.0.0) + public_suffix (7.0.5) rake (13.3.1) rb-fsevent (0.11.2) rb-inotify (0.11.1) From c722506d99b26a0bce06bfcf6443fc66731dd581 Mon Sep 17 00:00:00 2001 From: Kurtis <3580640+keveleigh@users.noreply.github.com> Date: Thu, 4 Jun 2026 17:53:46 -0700 Subject: [PATCH 2/8] Add #if UNITY_EDITOR to PackageValidator (#1125) Add #if UNITY_EDITOR --- org.mixedrealitytoolkit.core/CHANGELOG.md | 1 + .../Tests/TestUtilities/PackageValidator.cs | 15 ++++----------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/org.mixedrealitytoolkit.core/CHANGELOG.md b/org.mixedrealitytoolkit.core/CHANGELOG.md index df03116c9..3fa9674d9 100644 --- a/org.mixedrealitytoolkit.core/CHANGELOG.md +++ b/org.mixedrealitytoolkit.core/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Changed * Updated code style in `HandsSubsystemDescriptor`, `MRTKSubsystemDescriptor`, `DictationSubsystemDescriptor`, and `XRSubsystemHelpers`. [PR #1109](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1109) +* Updated `PackageValidator` to only be valid if `UNITY_EDITOR` is true. [PR #1125](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1125) ### Fixed diff --git a/org.mixedrealitytoolkit.core/Tests/TestUtilities/PackageValidator.cs b/org.mixedrealitytoolkit.core/Tests/TestUtilities/PackageValidator.cs index e7f775918..264bfe5be 100644 --- a/org.mixedrealitytoolkit.core/Tests/TestUtilities/PackageValidator.cs +++ b/org.mixedrealitytoolkit.core/Tests/TestUtilities/PackageValidator.cs @@ -1,9 +1,7 @@ // Copyright (c) Mixed Reality Toolkit Contributors // Licensed under the BSD 3-Clause -// Disable "missing XML comment" warning for tests. While nice to have, this documentation is not required. -#pragma warning disable CS1591 -#if HAS_ASSET_STORE_VALIDATION +#if HAS_ASSET_STORE_VALIDATION && UNITY_EDITOR using System; using System.Collections.Generic; @@ -26,12 +24,7 @@ public static class PackageValidator /// public static PackageValidatorResults Validate(string packageName) { - PackageInfo info = UpmPackageInfo(packageName); - if (info == null) - { - throw new ArgumentException($"No package found with name \"{packageName}\""); - } - + PackageInfo info = UpmPackageInfo(packageName) ?? throw new ArgumentException($"No package found with name \"{packageName}\""); string packageId = $"{info.name}@{info.version}"; ValidationSuite.ValidatePackage(packageId, ValidationType.AssetStore); @@ -70,5 +63,5 @@ private static PackageInfo[] UpmListOffline(string packageIdOrName = null) } } } -#endif // HAS_ASSET_STORE_VALIDATION -#pragma warning restore CS1591 + +#endif // HAS_ASSET_STORE_VALIDATION && UNITY_EDITOR From bd016cc11f15123f49ba6703c15eb859ca831cf3 Mon Sep 17 00:00:00 2001 From: Kurtis <3580640+keveleigh@users.noreply.github.com> Date: Thu, 4 Jun 2026 17:57:17 -0700 Subject: [PATCH 3/8] Add check for TouchScreenKeyboard.isSupported to SystemKeyboardExample (#1124) Add check for TouchScreenKeyboard.isSupported --- .../Assets/Scripts/SystemKeyboardExample.cs | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/SystemKeyboardExample.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/SystemKeyboardExample.cs index a5bc39a78..77c0f9218 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/SystemKeyboardExample.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/SystemKeyboardExample.cs @@ -1,10 +1,6 @@ // Copyright (c) Mixed Reality Toolkit Contributors // Licensed under the BSD 3-Clause -// Disable "missing XML comment" warning for samples. While nice to have, this XML documentation is not required for samples. -#pragma warning disable CS1591 - -using MixedReality.Toolkit.Input; using MixedReality.Toolkit.UX; using TMPro; using UnityEngine; @@ -30,10 +26,8 @@ public class SystemKeyboardExample : MonoBehaviour [SerializeField] private TextMeshPro debugMessage = null; -#pragma warning disable 0414 [SerializeField] private KeyboardPreview mixedRealityKeyboardPreview = null; -#pragma warning restore 0414 /// /// Opens a platform specific keyboard. @@ -43,7 +37,10 @@ public void OpenSystemKeyboard() #if WINDOWS_UWP wmrKeyboard.ShowKeyboard(wmrKeyboard.Text, false); #elif UNITY_IOS || UNITY_ANDROID - touchscreenKeyboard = TouchScreenKeyboard.Open(string.Empty, TouchScreenKeyboardType.Default, false, false, false, false); + if (TouchScreenKeyboard.isSupported) + { + touchscreenKeyboard = TouchScreenKeyboard.Open(string.Empty, TouchScreenKeyboardType.Default, false, false, false, false); + } #endif } @@ -51,7 +48,7 @@ public void OpenSystemKeyboard() /// /// A Unity event function that is called on the frame when a script is enabled just before any of the update methods are called the first time. - /// + /// private void Start() { // Initially hide the preview. @@ -91,7 +88,6 @@ private void Start() #endif } - #if WINDOWS_UWP /// /// A Unity event function that is called every frame, if this object is enabled. @@ -149,19 +145,19 @@ private void Update() // touch screen keyboard. if (touchscreenKeyboard != null) { - string KeyboardText = touchscreenKeyboard.text; + string keyboardText = touchscreenKeyboard.text; if (TouchScreenKeyboard.visible) { if (debugMessage != null) { - debugMessage.text = "typing... " + KeyboardText; + debugMessage.text = "typing... " + keyboardText; } } else { if (debugMessage != null) { - debugMessage.text = "typed " + KeyboardText; + debugMessage.text = "typed " + keyboardText; } touchscreenKeyboard = null; @@ -173,4 +169,3 @@ private void Update() #endregion MonoBehaviour Implementation } } -#pragma warning restore CS1591 \ No newline at end of file From 8735060caade1af18f78e4773920dd34353638a5 Mon Sep 17 00:00:00 2001 From: Kurtis <3580640+keveleigh@users.noreply.github.com> Date: Mon, 8 Jun 2026 10:22:32 -0700 Subject: [PATCH 4/8] Add edit mode tests for AssemblyExtensions, SystemType, and SerializableDictionary (#1122) * Add new tests * Update AssemblyExtensions.cs * Update CHANGELOG.md --- org.mixedrealitytoolkit.core/CHANGELOG.md | 5 + .../Tests/Editor/AssemblyExtensionsTests.cs | 37 ++++++ .../Editor/AssemblyExtensionsTests.cs.meta | 11 ++ .../Editor/SerializableDictionaryTests.cs | 87 +++++++++++++ .../SerializableDictionaryTests.cs.meta | 11 ++ .../Tests/Editor/SystemTypeTests.cs | 116 ++++++++++++++++++ .../Tests/Editor/SystemTypeTests.cs.meta | 11 ++ .../Extensions/AssemblyExtensions.cs | 7 +- 8 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 org.mixedrealitytoolkit.core/Tests/Editor/AssemblyExtensionsTests.cs create mode 100644 org.mixedrealitytoolkit.core/Tests/Editor/AssemblyExtensionsTests.cs.meta create mode 100644 org.mixedrealitytoolkit.core/Tests/Editor/SerializableDictionaryTests.cs create mode 100644 org.mixedrealitytoolkit.core/Tests/Editor/SerializableDictionaryTests.cs.meta create mode 100644 org.mixedrealitytoolkit.core/Tests/Editor/SystemTypeTests.cs create mode 100644 org.mixedrealitytoolkit.core/Tests/Editor/SystemTypeTests.cs.meta diff --git a/org.mixedrealitytoolkit.core/CHANGELOG.md b/org.mixedrealitytoolkit.core/CHANGELOG.md index 3fa9674d9..4933cdbd1 100644 --- a/org.mixedrealitytoolkit.core/CHANGELOG.md +++ b/org.mixedrealitytoolkit.core/CHANGELOG.md @@ -8,6 +8,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). * Updated code style in `HandsSubsystemDescriptor`, `MRTKSubsystemDescriptor`, `DictationSubsystemDescriptor`, and `XRSubsystemHelpers`. [PR #1109](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1109) * Updated `PackageValidator` to only be valid if `UNITY_EDITOR` is true. [PR #1125](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1125) +* `AssemblyExtensions.GetLoadableTypes` now throws `ArgumentNullException` when called on a null assembly instead of `NullReferenceException`. [PR #1122](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1122) + +### Added + +* Added edit mode tests for `AssemblyExtensions`, `SystemType`, and `SerializableDictionary`. [PR #1122](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1122) ### Fixed diff --git a/org.mixedrealitytoolkit.core/Tests/Editor/AssemblyExtensionsTests.cs b/org.mixedrealitytoolkit.core/Tests/Editor/AssemblyExtensionsTests.cs new file mode 100644 index 000000000..0ceffcba0 --- /dev/null +++ b/org.mixedrealitytoolkit.core/Tests/Editor/AssemblyExtensionsTests.cs @@ -0,0 +1,37 @@ +// Copyright (c) Mixed Reality Toolkit Contributors +// Licensed under the BSD 3-Clause + +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace MixedReality.Toolkit.Core.Tests.EditMode +{ + /// + /// Unit tests for AssemblyExtensions. + /// These run outside of PlayMode and do not require Unity engine initialization. + /// + public class AssemblyExtensionsTests + { + [Test] + public void GetLoadableTypes_ReturnsTypes_ForValidAssembly() + { + Assembly currentAssembly = Assembly.GetExecutingAssembly(); + + IEnumerable types = currentAssembly.GetLoadableTypes(); + + Assert.IsNotNull(types, "GetLoadableTypes should never return null."); + Assert.Greater(types.Count(), 0, "GetLoadableTypes should return the types within the executing assembly."); + Assert.IsTrue(types.Contains(typeof(AssemblyExtensionsTests)), "GetLoadableTypes failed to return known loadable types."); + } + + [Test] + public void GetLoadableTypes_HandlesNullAssembly_Safely() + { + Assembly nullAssembly = null; + Assert.Throws(() => nullAssembly.GetLoadableTypes()); + } + } +} diff --git a/org.mixedrealitytoolkit.core/Tests/Editor/AssemblyExtensionsTests.cs.meta b/org.mixedrealitytoolkit.core/Tests/Editor/AssemblyExtensionsTests.cs.meta new file mode 100644 index 000000000..46f2addd4 --- /dev/null +++ b/org.mixedrealitytoolkit.core/Tests/Editor/AssemblyExtensionsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32e95d882d3d7c44ca4f53530fed61b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/org.mixedrealitytoolkit.core/Tests/Editor/SerializableDictionaryTests.cs b/org.mixedrealitytoolkit.core/Tests/Editor/SerializableDictionaryTests.cs new file mode 100644 index 000000000..7f99497c5 --- /dev/null +++ b/org.mixedrealitytoolkit.core/Tests/Editor/SerializableDictionaryTests.cs @@ -0,0 +1,87 @@ +// Copyright (c) Mixed Reality Toolkit Contributors +// Licensed under the BSD 3-Clause + +using NUnit.Framework; +using System.Collections.Generic; +using UnityEngine; + +namespace MixedReality.Toolkit.Core.Tests.EditMode +{ + /// + /// Unit tests for SerializableDictionary. + /// These run outside of PlayMode and do not require Unity engine initialization. + /// + public class SerializableDictionaryTests + { + [Test] + public void Serialization_RestoresDictionary_FromInternalEntries() + { + var dict = new SerializableDictionary(); + dict.Add("Key1", 100); + dict.Add("Key2", 200); + + ISerializationCallbackReceiver receiver = dict; + + // Simulate Unity preparing to serialize the object (populates the internal 'entries' list) + receiver.OnBeforeSerialize(); + + // Clear the base dictionary to simulate starting fresh after deserialization + ((Dictionary)dict).Clear(); + Assert.AreEqual(0, dict.Count, "Base dictionary should be empty before deserialization."); + + // Simulate Unity finishing deserialization (repopulates the dictionary from 'entries') + receiver.OnAfterDeserialize(); + + Assert.AreEqual(2, dict.Count, "Dictionary should have restored 2 items."); + Assert.AreEqual(100, dict["Key1"]); + Assert.AreEqual(200, dict["Key2"]); + } + + [Test] + public void EditorOverride_Clear_RemovesAllSerializedEntries() + { + var dict = new SerializableDictionary(); + dict.Add("Key1", 100); + + ISerializationCallbackReceiver receiver = dict; + receiver.OnBeforeSerialize(); // Populate internal list + + // Call the custom overridden Clear() + dict.Clear(); + + // Attempt to deserialize (which would normally restore Key1 if the internal list wasn't cleared) + receiver.OnAfterDeserialize(); + + Assert.AreEqual(0, dict.Count, "Dictionary should remain empty because the internal serialized entries were cleared."); + } + + [Test] + public void EditorOverride_Remove_RemovesSpecificSerializedEntry() + { + var dict = new SerializableDictionary(); + dict.Add("A", 1); + dict.Add("B", 2); + dict.Add("C", 3); + + ISerializationCallbackReceiver receiver = dict; + receiver.OnBeforeSerialize(); + + // Use the overridden remove method which should also remove from the internal list + bool removedB = dict.Remove("B"); + bool removedC = dict.Remove("C", out int valC); + + // Clear the dictionary and restore from the serialized list to verify they are gone + ((Dictionary)dict).Clear(); + receiver.OnAfterDeserialize(); + + Assert.IsTrue(removedB, "Remove(key) should return true for existing key."); + Assert.IsTrue(removedC, "Remove(key, out val) should return true for existing key."); + Assert.AreEqual(3, valC, "Remove(key, out val) should output the correct value."); + + Assert.AreEqual(1, dict.Count, "Only 1 item should remain after deserialization."); + Assert.IsTrue(dict.ContainsKey("A"), "Key 'A' should have been preserved."); + Assert.IsFalse(dict.ContainsKey("B"), "Key 'B' should have been permanently removed."); + Assert.IsFalse(dict.ContainsKey("C"), "Key 'C' should have been permanently removed."); + } + } +} diff --git a/org.mixedrealitytoolkit.core/Tests/Editor/SerializableDictionaryTests.cs.meta b/org.mixedrealitytoolkit.core/Tests/Editor/SerializableDictionaryTests.cs.meta new file mode 100644 index 000000000..77e68063f --- /dev/null +++ b/org.mixedrealitytoolkit.core/Tests/Editor/SerializableDictionaryTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2801ac5575b6e5044ac92e55fe647979 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/org.mixedrealitytoolkit.core/Tests/Editor/SystemTypeTests.cs b/org.mixedrealitytoolkit.core/Tests/Editor/SystemTypeTests.cs new file mode 100644 index 000000000..a1d62be59 --- /dev/null +++ b/org.mixedrealitytoolkit.core/Tests/Editor/SystemTypeTests.cs @@ -0,0 +1,116 @@ +// Copyright (c) Mixed Reality Toolkit Contributors +// Licensed under the BSD 3-Clause + +using NUnit.Framework; +using System; +using UnityEngine; +using UnityEngine.TestTools; + +namespace MixedReality.Toolkit.Core.Tests.EditMode +{ + /// + /// Unit tests for SystemType. + /// These run outside of PlayMode and do not require Unity engine initialization. + /// + public class SystemTypeTests + { + [Test] + public void GetReference_FromType_ReturnsValidString() + { + string reference = SystemType.GetReference(typeof(Vector3)); + + Assert.IsFalse(string.IsNullOrEmpty(reference)); + Assert.IsTrue(reference.Contains("UnityEngine.Vector3")); + Assert.IsTrue(reference.Contains("UnityEngine.CoreModule")); + } + + [Test] + public void GetReference_NullOrEmpty_ReturnsEmptyString() + { + Assert.AreEqual(string.Empty, SystemType.GetReference((Type)null)); + Assert.AreEqual(string.Empty, SystemType.GetReference((string)null)); + Assert.AreEqual(string.Empty, SystemType.GetReference(string.Empty)); + } + + [Test] + public void Constructors_SetPropertiesCorrectly() + { + Type targetType = typeof(int); + + // Initialize from Type + SystemType fromType = new SystemType(targetType); + Assert.AreEqual(targetType, fromType.Type); + Assert.AreEqual(SystemType.GetReference(targetType), (string)fromType); + + // Initialize from AssemblyQualifiedName + SystemType fromString = new SystemType(targetType.AssemblyQualifiedName); + Assert.AreEqual(targetType, fromString.Type); + } + + [Test] + public void Constructor_AbstractType_SetsTypeToNull() + { + // SystemType is intentionally designed to nullify abstract types when initialized via string + SystemType fromString = new SystemType(typeof(Array).AssemblyQualifiedName); + Assert.IsNull(fromString.Type, "SystemType should not allow abstract types when initialized from an assembly string."); + } + + [Test] + public void InvalidTypeAssignment_LogsError_ButSetsType() + { + SystemType sysType = new SystemType(typeof(int)); + + // Enums violate the ValidConstraint. SystemType logs an error but still completes the assignment. + LogAssert.Expect(LogType.Error, $"'{typeof(DayOfWeek).FullName}' is not a valid class or struct type."); + + sysType.Type = typeof(DayOfWeek); + + Assert.AreEqual(typeof(DayOfWeek), sysType.Type); + } + + [Test] + public void ImplicitConversions_WorkCorrectly() + { + Type originalType = typeof(string); + + // Type -> SystemType + SystemType sysType = originalType; + Assert.IsNotNull(sysType); + + // SystemType -> Type + Type convertedType = sysType; + Assert.AreEqual(originalType, convertedType); + + // SystemType -> string + string reference = sysType; + Assert.AreEqual(SystemType.GetReference(originalType), reference); + } + + [Test] + public void Equality_MatchesSameTypes() + { + SystemType type1 = new SystemType(typeof(float)); + SystemType type2 = new SystemType(typeof(float)); + SystemType type3 = new SystemType(typeof(double)); + + Assert.IsTrue(type1.Equals(type2)); + Assert.IsFalse(type1.Equals(type3)); + Assert.IsFalse(type1.Equals(null)); + + // HashCodes should match for identical references + Assert.AreEqual(type1.GetHashCode(), type2.GetHashCode()); + } + + [Test] + public void Serialization_RestoresType() + { + var sysType = new SystemType(typeof(int)); + ISerializationCallbackReceiver receiver = sysType; + + // SystemType uses OnAfterDeserialize to re-establish the `type` mapping from the string `reference` + receiver.OnAfterDeserialize(); + + Assert.AreEqual(typeof(int), sysType.Type); + } + } +} diff --git a/org.mixedrealitytoolkit.core/Tests/Editor/SystemTypeTests.cs.meta b/org.mixedrealitytoolkit.core/Tests/Editor/SystemTypeTests.cs.meta new file mode 100644 index 000000000..f6e786970 --- /dev/null +++ b/org.mixedrealitytoolkit.core/Tests/Editor/SystemTypeTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bff9d511c00e10941baf652aeb49d861 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/org.mixedrealitytoolkit.core/Utilities/Extensions/AssemblyExtensions.cs b/org.mixedrealitytoolkit.core/Utilities/Extensions/AssemblyExtensions.cs index 8eba33c1e..59e4586da 100644 --- a/org.mixedrealitytoolkit.core/Utilities/Extensions/AssemblyExtensions.cs +++ b/org.mixedrealitytoolkit.core/Utilities/Extensions/AssemblyExtensions.cs @@ -14,10 +14,15 @@ namespace MixedReality.Toolkit public static class AssemblyExtensions { /// - /// Assembly.GetTypes() can throw in some cases. This extension will catch that exception and return only the types which were successfully loaded from the assembly. + /// Assembly.GetTypes() can throw in some cases. This extension will catch that exception and return only the types which were successfully loaded from the assembly. /// public static IEnumerable GetLoadableTypes(this Assembly @this) { + if (@this == null) + { + throw new ArgumentNullException(nameof(@this), "Assembly cannot be null."); + } + try { return @this.GetTypes(); From 9fdcb39bdf9fcb20dcf71f5aed8c5766ecdc9ea2 Mon Sep 17 00:00:00 2001 From: Kurtis <3580640+keveleigh@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:34:57 -0700 Subject: [PATCH 5/8] Add AlphaBlend tint mode to TintEffect (#1131) * Add AlphaBlend * Update CHANGELOG.md --- org.mixedrealitytoolkit.uxcore/CHANGELOG.md | 4 ++++ .../StateVisualizer/Effects/TintEffect.cs | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/CHANGELOG.md b/org.mixedrealitytoolkit.uxcore/CHANGELOG.md index 9d6165a29..f5b02e2d5 100644 --- a/org.mixedrealitytoolkit.uxcore/CHANGELOG.md +++ b/org.mixedrealitytoolkit.uxcore/CHANGELOG.md @@ -4,6 +4,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## Unreleased +### Added + +* Added `AlphaBlend` tint mode to `TintEffect`. [PR #1131](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1131) + ### Fixed * Fixed "leaked managed shell" issue in `UGUIInputAdapter`. [PR #1096](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1096) diff --git a/org.mixedrealitytoolkit.uxcore/StateVisualizer/Effects/TintEffect.cs b/org.mixedrealitytoolkit.uxcore/StateVisualizer/Effects/TintEffect.cs index 916fa7c01..511b3de07 100644 --- a/org.mixedrealitytoolkit.uxcore/StateVisualizer/Effects/TintEffect.cs +++ b/org.mixedrealitytoolkit.uxcore/StateVisualizer/Effects/TintEffect.cs @@ -132,7 +132,6 @@ public override void PrepareFrame(Playable playable, FrameData info) { ApplyColor(startColors[i], tintables[i]); } - } /// @@ -162,6 +161,12 @@ public override void ProcessFrame(Playable playable, FrameData info, object play { targetColor = currentColor * TintColor; } + else if (BlendMode == BlendType.AlphaBlend) + { + // Simulate layering a transparent color over the current color + targetColor = Color.Lerp(currentColor, TintColor, TintColor.a); + targetColor.a = currentColor.a; // Preserve the graphic's original overall opacity + } else { targetColor = TintColor; @@ -191,7 +196,12 @@ internal enum BlendType /// /// Multiply the tint color onto the existing color stack. /// - Multiply + Multiply, + + /// + /// Alpha-blends the tint color onto the existing color stack using the tint color's alpha value. + /// + AlphaBlend } [SerializeField] From bb34a674f716e84059b9e97fb0d8ccf92665058b Mon Sep 17 00:00:00 2001 From: Kurtis <3580640+keveleigh@users.noreply.github.com> Date: Wed, 10 Jun 2026 17:25:47 -0700 Subject: [PATCH 6/8] Various test improvements (#1073) * Formatting * Fix test referring to the wrong interactable * Add a few more smoke tests * Update InteractionModeManagerTests.cs * Adding visibility modifier * Docs updates * Restore a commented-out test and Ignore it instead --- org.mixedrealitytoolkit.core/CHANGELOG.md | 3 +- .../Interactables/MRTKBaseInteractable.cs | 36 ++++++------ org.mixedrealitytoolkit.input/CHANGELOG.md | 1 + .../Tests/Runtime/BasicInputTests.cs | 57 ++++++++++--------- .../Runtime/InteractionModeManagerTests.cs | 8 +-- .../Runtime/Utilities/InputTestUtilities.cs | 2 +- .../CHANGELOG.md | 4 ++ .../Tests/Runtime/HandConstraintTests.cs | 2 +- .../Tests/Runtime/ObjectManipulatorTests.cs | 51 +++++++++-------- 9 files changed, 90 insertions(+), 74 deletions(-) diff --git a/org.mixedrealitytoolkit.core/CHANGELOG.md b/org.mixedrealitytoolkit.core/CHANGELOG.md index 4933cdbd1..8e8c3c41d 100644 --- a/org.mixedrealitytoolkit.core/CHANGELOG.md +++ b/org.mixedrealitytoolkit.core/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). * Updated code style in `HandsSubsystemDescriptor`, `MRTKSubsystemDescriptor`, `DictationSubsystemDescriptor`, and `XRSubsystemHelpers`. [PR #1109](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1109) * Updated `PackageValidator` to only be valid if `UNITY_EDITOR` is true. [PR #1125](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1125) * `AssemblyExtensions.GetLoadableTypes` now throws `ArgumentNullException` when called on a null assembly instead of `NullReferenceException`. [PR #1122](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1122) +* Updated `MRTKBaseInteractable` to follow MRTK style. [PR #1073](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1073) ### Added @@ -16,7 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Fixed -* Fixed "The type MixedReality.Toolkit.Core MixedReality.Toolkit.Experimental.BubbleChildHoverEvents/TrickleChildHoverEvents/BubbleChildSelectEvents/TrickleChildSelectEvents is being serialized by `[SerializeReference]`, but is missing the `[Serializable]` attribute." on Unity 6.3. [PR #1107](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1107) +* Fixed "The type `MixedReality.Toolkit.Core MixedReality.Toolkit.Experimental.BubbleChildHoverEvents/TrickleChildHoverEvents/BubbleChildSelectEvents/TrickleChildSelectEvents` is being serialized by `[SerializeReference]`, but is missing the `[Serializable]` attribute." on Unity 6.3. [PR #1107](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1107) ## Deprecated diff --git a/org.mixedrealitytoolkit.core/Interactables/MRTKBaseInteractable.cs b/org.mixedrealitytoolkit.core/Interactables/MRTKBaseInteractable.cs index 4a437a091..73cacb613 100644 --- a/org.mixedrealitytoolkit.core/Interactables/MRTKBaseInteractable.cs +++ b/org.mixedrealitytoolkit.core/Interactables/MRTKBaseInteractable.cs @@ -17,7 +17,7 @@ public class MRTKBaseInteractable : XRBaseInteractable { #region Gaze - readonly List hoveringGazeInteractors = new List(); + private readonly List hoveringGazeInteractors = new List(); /// /// (Read Only) The list of components currently gazing this object. @@ -28,14 +28,14 @@ public class MRTKBaseInteractable : XRBaseInteractable #region GazePinch - readonly List hoveringGazePinchInteractors = new List(); + private readonly List hoveringGazePinchInteractors = new List(); /// /// (Read Only) The list of components currently hovering this object. /// public List HoveringGazePinchInteractors => hoveringGazePinchInteractors; - readonly List selectingGazePinchInteractors = new List(); + private readonly List selectingGazePinchInteractors = new List(); /// /// (Read Only) The list of components currently selecting this object. @@ -46,7 +46,7 @@ public class MRTKBaseInteractable : XRBaseInteractable #region Poke - readonly List hoveringPokeInteractors = new List(); + private readonly List hoveringPokeInteractors = new List(); /// /// (Read Only) The list of components currently hovering this object. @@ -57,14 +57,14 @@ public class MRTKBaseInteractable : XRBaseInteractable #region Grab - readonly List hoveringGrabInteractors = new List(); + private readonly List hoveringGrabInteractors = new List(); /// /// (Read Only) The list of components currently hovering this object. /// ] public List HoveringGrabInteractors => hoveringGrabInteractors; - readonly List selectingGrabInteractors = new List(); + private readonly List selectingGrabInteractors = new List(); /// /// (Read Only) The list of components currently selecting this object. @@ -75,7 +75,7 @@ public class MRTKBaseInteractable : XRBaseInteractable #region Ray - readonly List hoveringRayInteractors = new List(); + private readonly List hoveringRayInteractors = new List(); /// /// (Read Only) The list of components currently hovering this object. @@ -93,7 +93,7 @@ public class MRTKBaseInteractable : XRBaseInteractable /// /// Is this object selected by a gaze-pinch interactor? /// - public TimedFlag IsGazePinchSelected { get => isGazePinchSelected; } + public TimedFlag IsGazePinchSelected => isGazePinchSelected; [SerializeField] [Tooltip("Is this object selected by a non-gaze ray interactor?")] @@ -102,7 +102,7 @@ public class MRTKBaseInteractable : XRBaseInteractable /// /// Is this object selected by a non-gaze ray interactor? /// - public TimedFlag IsRaySelected { get => isRaySelected; } + public TimedFlag IsRaySelected => isRaySelected; [SerializeField] [Tooltip("Is this object selected by a poke interactor?")] @@ -111,7 +111,7 @@ public class MRTKBaseInteractable : XRBaseInteractable /// /// Is this object selected by a poke interactor? /// - public TimedFlag IsPokeSelected { get => isPokeSelected; } + public TimedFlag IsPokeSelected => isPokeSelected; [SerializeField] [Tooltip("Is this object selected by a grab interactor?")] @@ -120,7 +120,7 @@ public class MRTKBaseInteractable : XRBaseInteractable /// /// Is this object selected by a grab interactor? /// - public TimedFlag IsGrabSelected { get => isGrabSelected; } + public TimedFlag IsGrabSelected => isGrabSelected; [SerializeField] [Tooltip("Is this object hovered by any gaze interactor?")] @@ -129,7 +129,7 @@ public class MRTKBaseInteractable : XRBaseInteractable /// /// Is this object hovered by any gaze interactor? /// - public TimedFlag IsGazeHovered { get => isGazeHovered; } + public TimedFlag IsGazeHovered => isGazeHovered; [SerializeField] [Tooltip("Is this object hovered by a gaze-pinch interactor?")] @@ -138,7 +138,7 @@ public class MRTKBaseInteractable : XRBaseInteractable /// /// Is this object hovered by a gaze-pinch interactor? /// - public TimedFlag IsGazePinchHovered { get => isGazePinchHovered; } + public TimedFlag IsGazePinchHovered => isGazePinchHovered; [SerializeField] [Tooltip("Is this object hovered by a non-gaze ray interactor?")] @@ -147,7 +147,7 @@ public class MRTKBaseInteractable : XRBaseInteractable /// /// Is this object hovered by a non-gaze ray interactor? /// - public TimedFlag IsRayHovered { get => isRayHovered; } + public TimedFlag IsRayHovered => isRayHovered; [SerializeField] [Tooltip("Is this object hovered by a grab interactor?")] @@ -156,7 +156,7 @@ public class MRTKBaseInteractable : XRBaseInteractable /// /// Is this object hovered by a grab interactor? /// - public TimedFlag IsGrabHovered { get => isGrabHovered; } + public TimedFlag IsGrabHovered => isGrabHovered; [SerializeField] [Tooltip("Is this object hovered by a near touch/poke interactor?")] @@ -166,12 +166,12 @@ public class MRTKBaseInteractable : XRBaseInteractable /// /// Is this object hovered by a near touch/poke interactor? /// - public TimedFlag IsPokeHovered { get => isPokeHovered; } + public TimedFlag IsPokeHovered => isPokeHovered; /// /// Is this object hovered by any interactor other than passive targeting interactors? /// - public TimedFlag IsActiveHovered { get => isActiveHovered; } + public TimedFlag IsActiveHovered => isActiveHovered; [SerializeField] [Tooltip("Is this object hovered by any interactor other than only passive targeting interactors?")] @@ -199,7 +199,7 @@ public void DisableInteractorType(SystemInterfaceType type) } } /// - /// Removes the specified type to the set of interactors which cannot select this interactable + /// Removes the specified type from the set of interactors which cannot select this interactable /// public void EnableInteractorType(SystemInterfaceType type) { diff --git a/org.mixedrealitytoolkit.input/CHANGELOG.md b/org.mixedrealitytoolkit.input/CHANGELOG.md index 42d19c346..7de0760fb 100644 --- a/org.mixedrealitytoolkit.input/CHANGELOG.md +++ b/org.mixedrealitytoolkit.input/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Changed * Reserialized MRTK XR Rig prefab to remove stale serialized fields. [PR #1110](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1110) +* Updated tests to follow existing MRTK test patterns. [PR #1073](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1073) ### Fixed diff --git a/org.mixedrealitytoolkit.input/Tests/Runtime/BasicInputTests.cs b/org.mixedrealitytoolkit.input/Tests/Runtime/BasicInputTests.cs index a6ae95b3b..8d23a6b03 100644 --- a/org.mixedrealitytoolkit.input/Tests/Runtime/BasicInputTests.cs +++ b/org.mixedrealitytoolkit.input/Tests/Runtime/BasicInputTests.cs @@ -5,19 +5,15 @@ #pragma warning disable CS1591 using MixedReality.Toolkit.Core.Tests; +using MixedReality.Toolkit.Input.Simulation; +using MixedReality.Toolkit.Subsystems; using NUnit.Framework; using System.Collections; -using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.TestTools; using UnityEngine.XR; using UnityEngine.XR.Interaction.Toolkit; -using MixedReality.Toolkit.Input; -using MixedReality.Toolkit.Input.Simulation; -using MixedReality.Toolkit; -using MixedReality.Toolkit.Subsystems; - using HandshapeId = MixedReality.Toolkit.Input.HandshapeTypes.HandshapeId; namespace MixedReality.Toolkit.Input.Tests @@ -31,7 +27,7 @@ public class BasicInputTests : BaseRuntimeInputTests /// Ensure the simulated input devices are registered and present. /// [UnityTest] - public IEnumerator InputDeviceSmoketest() + public IEnumerator InputDeviceSmokeTest() { foreach (var device in InputSystem.devices) { @@ -45,9 +41,10 @@ public IEnumerator InputDeviceSmoketest() /// Ensure the simulated input devices bind to the controllers on the rig. /// [UnityTest] - public IEnumerator InputBindingSmoketest() + public IEnumerator InputBindingSmokeTest() { - var controllers = new[] { + XRBaseController[] controllers = + { CachedLookup.LeftHandController, CachedLookup.RightHandController, CachedLookup.GazeController @@ -69,7 +66,7 @@ public IEnumerator InputBindingSmoketest() /// Ensure the simulated input device actually makes the rig's controllers move/actuate. /// [UnityTest] - public IEnumerator HandMovingSmoketest() + public IEnumerator HandMovingSmokeTest() { var controller = CachedLookup.RightHandController as ActionBasedController; @@ -107,7 +104,7 @@ public IEnumerator GrabAnchorTest() Vector3 cubePos = InputTestUtilities.InFrontOfUser(); cube.transform.position = cubePos; cube.transform.localScale = Vector3.one * 1.0f; - + var testHand = new TestHand(Handedness.Right); InputTestUtilities.SetHandAnchorPoint(Handedness.Right, ControllerAnchorPoint.Grab); @@ -136,32 +133,28 @@ public IEnumerator GrabAnchorTest() public IEnumerator StatefulInteractableSmokeTest() { GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube); - cube.AddComponent(); + StatefulInteractable firstCubeInteractable = cube.AddComponent(); cube.transform.position = InputTestUtilities.InFrontOfUser(new Vector3(0.2f, 0.2f, 0.5f)); cube.transform.localScale = Vector3.one * 0.1f; // For this test, we won't use poke selection. - cube.GetComponent().DisableInteractorType(typeof(PokeInteractor)); + firstCubeInteractable.DisableInteractorType(typeof(PokeInteractor)); GameObject cube2 = GameObject.CreatePrimitive(PrimitiveType.Cube); - cube2.AddComponent(); + StatefulInteractable secondCubeInteractable = cube2.AddComponent(); cube2.transform.position = InputTestUtilities.InFrontOfUser(new Vector3(-0.2f, -0.2f, 0.5f)); cube2.transform.localScale = Vector3.one * 0.1f; // For this test, we won't use poke selection. - cube2.GetComponent().DisableInteractorType(typeof(PokeInteractor)); + secondCubeInteractable.DisableInteractorType(typeof(PokeInteractor)); var rightHand = new TestHand(Handedness.Right); yield return rightHand.Show(InputTestUtilities.InFrontOfUser(0.5f)); - yield return RuntimeTestUtilities.WaitForUpdates(); bool shouldTestToggle = false; - StatefulInteractable firstCubeInteractable = cube.GetComponent(); - StatefulInteractable secondCubeInteractable = cube2.GetComponent(); - for (int i = 0; i < 5; i++) { // Flip this back and forth to test both toggleability and un-toggleability @@ -176,27 +169,33 @@ public IEnumerator StatefulInteractableSmokeTest() firstCubeInteractable.TriggerOnRelease = (i % 2) == 0; Assert.IsFalse(firstCubeInteractable.IsGrabHovered, + "StatefulInteractable was already GrabHovered."); + Assert.IsFalse(firstCubeInteractable.isHovered, "StatefulInteractable was already hovered."); yield return rightHand.MoveTo(cube.transform.position); yield return RuntimeTestUtilities.WaitForUpdates(); Assert.IsTrue(firstCubeInteractable.IsGrabHovered, + "StatefulInteractable did not get GrabHovered."); + Assert.IsTrue(firstCubeInteractable.isHovered, "StatefulInteractable did not get hovered."); yield return rightHand.SetHandshape(HandshapeId.Pinch); yield return RuntimeTestUtilities.WaitForUpdates(); Assert.IsTrue(firstCubeInteractable.IsGrabSelected, "StatefulInteractable did not get GrabSelected."); + Assert.IsTrue(firstCubeInteractable.isSelected, + "StatefulInteractable did not get selected."); if (shouldTestToggle) { - if (secondCubeInteractable.TriggerOnRelease) + if (firstCubeInteractable.TriggerOnRelease) { - Assert.IsFalse(secondCubeInteractable.IsToggled, "StatefulInteractable toggled on press, when it was set to be toggled on release."); + Assert.IsFalse(firstCubeInteractable.IsToggled, "StatefulInteractable toggled on press, when it was set to be toggled on release."); } else { - Assert.IsFalse(secondCubeInteractable.IsToggled, "StatefulInteractable didn't toggled on press, when it was set to be toggled on press."); + Assert.IsFalse(firstCubeInteractable.IsToggled, "StatefulInteractable didn't toggled on press, when it was set to be toggled on press."); } } @@ -225,17 +224,23 @@ public IEnumerator StatefulInteractableSmokeTest() yield return RuntimeTestUtilities.WaitForUpdates(); Assert.IsFalse(secondCubeInteractable.IsGrabHovered, + "StatefulInteractable was already GrabHovered."); + Assert.IsFalse(secondCubeInteractable.isHovered, "StatefulInteractable was already hovered."); yield return rightHand.MoveTo(secondCubeInteractable.transform.position); yield return RuntimeTestUtilities.WaitForUpdates(); Assert.IsTrue(secondCubeInteractable.IsGrabHovered, + "StatefulInteractable did not get GrabHovered."); + Assert.IsTrue(secondCubeInteractable.isHovered, "StatefulInteractable did not get hovered."); yield return rightHand.SetHandshape(HandshapeId.Pinch); yield return RuntimeTestUtilities.WaitForUpdates(); Assert.IsTrue(secondCubeInteractable.IsGrabSelected, "StatefulInteractable did not get GrabSelected."); + Assert.IsTrue(secondCubeInteractable.isSelected, + "StatefulInteractable did not get selected."); if (shouldTestToggle) { @@ -303,7 +308,7 @@ public IEnumerator GazePinchSmokeTest() yield return rightHand.SetHandshape(HandshapeId.Open); yield return RuntimeTestUtilities.WaitForUpdates(); - + Assert.IsFalse(interactable.isSelected); Assert.IsFalse(interactable.IsGazePinchSelected); Assert.IsTrue(interactable.isHovered); @@ -388,7 +393,7 @@ public IEnumerator ToggleHydrationTest() didFireEvent = false; interactable.ForceSetToggled(true, fireEvents: false); - + Assert.IsTrue(interactable.IsToggled, "Interactable didn't get toggled."); Assert.IsFalse(didFireEvent, "ForceSetToggled(true, fireEvents:false) should NOT have fired the event."); @@ -493,7 +498,7 @@ public IEnumerator SpawnInteractableOnHand() // Move hand far away. yield return rightHand.MoveTo(new Vector3(2, 2, 2)); - yield return RuntimeTestUtilities.WaitForUpdates(frameCount:240); + yield return RuntimeTestUtilities.WaitForUpdates(frameCount: 240); Assert.IsFalse(AnyProximityDetectorsTriggered(), "Prox detectors should no longer be triggered."); @@ -608,4 +613,4 @@ private bool AnyProximityDetectorsTriggered() } } } -#pragma warning restore CS1591 \ No newline at end of file +#pragma warning restore CS1591 diff --git a/org.mixedrealitytoolkit.input/Tests/Runtime/InteractionModeManagerTests.cs b/org.mixedrealitytoolkit.input/Tests/Runtime/InteractionModeManagerTests.cs index 06515e3f5..83725205f 100644 --- a/org.mixedrealitytoolkit.input/Tests/Runtime/InteractionModeManagerTests.cs +++ b/org.mixedrealitytoolkit.input/Tests/Runtime/InteractionModeManagerTests.cs @@ -76,7 +76,7 @@ public IEnumerator InteractionDetectorTest() XRBaseController rightHandController = CachedLookup.RightHandController; Assert.IsTrue(rightHandController != null, "No controllers found for right hand."); - // Moving the hand to a position where it's far ray is hovering over the cube + // Moving the hand to a position where its far ray is hovering over the cube yield return rightHand.AimAt(cube.transform.position); yield return RuntimeTestUtilities.WaitForUpdates(); @@ -127,7 +127,7 @@ public IEnumerator ModeMediationTest() InputTestUtilities.SetHandAnchorPoint(Handedness.Right, ControllerAnchorPoint.Grab); yield return RuntimeTestUtilities.WaitForUpdates(); - // Moving the hand to a position where it's far ray is hovering over the cube + // Moving the hand to a position where its far ray is hovering over the cube yield return rightHand.AimAt(cube.transform.position); yield return RuntimeTestUtilities.WaitForUpdates(); InteractionMode farRayMode = rightHandController.GetComponentInChildren().GetComponent().ModeOnHover; @@ -165,7 +165,7 @@ public IEnumerator ModeMediationTest() ValidateInteractionModeActive(rightHandController, nearMode); - // Moving the hand to a position where it's far ray is hovering over the cube + // Moving the hand to a position where its far ray is hovering over the cube yield return rightHand.MoveTo(cube.transform.position + new Vector3(0.02f, -0.1f, -0.8f)); yield return RuntimeTestUtilities.WaitForUpdates(frameCount:120); @@ -180,7 +180,7 @@ public IEnumerator ModeMediationTest() private void ValidateInteractionModeActive(XRBaseController controller, InteractionMode currentMode) { // We construct the list of managed interactor types manually because we don't want to expose the internal controller mapping implementation to even internal use, since - // we don't want any other class to be able to modify those collections without going through the Mode Manager or it's in-editor inspector. + // we don't want any other class to be able to modify those collections without going through the Mode Manager or its in-editor inspector. HashSet managedInteractorTypes = new HashSet(InteractionModeManager.Instance.PrioritizedInteractionModes.SelectMany(x => x.AssociatedTypes)); HashSet activeInteractorTypes = InteractionModeManager.Instance.PrioritizedInteractionModes.Find(x => x.ModeName == currentMode.Name).AssociatedTypes; diff --git a/org.mixedrealitytoolkit.input/Tests/Runtime/Utilities/InputTestUtilities.cs b/org.mixedrealitytoolkit.input/Tests/Runtime/Utilities/InputTestUtilities.cs index 5ca4fe1d3..5ce3c9f8c 100644 --- a/org.mixedrealitytoolkit.input/Tests/Runtime/Utilities/InputTestUtilities.cs +++ b/org.mixedrealitytoolkit.input/Tests/Runtime/Utilities/InputTestUtilities.cs @@ -435,7 +435,7 @@ public static IEnumerator PointHandToTarget(Vector3 target, HandshapeId handshap /// /// /// - /// This smooths the handshape based on the provided/ over the number of + /// This smooths the handshape based on the provided over the number of /// steps provided by . /// /// diff --git a/org.mixedrealitytoolkit.spatialmanipulation/CHANGELOG.md b/org.mixedrealitytoolkit.spatialmanipulation/CHANGELOG.md index c146e22b5..4ff1c061c 100644 --- a/org.mixedrealitytoolkit.spatialmanipulation/CHANGELOG.md +++ b/org.mixedrealitytoolkit.spatialmanipulation/CHANGELOG.md @@ -8,6 +8,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). * Fixed "leaked managed shell" issue in `BoundsCalculator`. [PR #1096](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1096) +### Changed + +* Updated tests to follow existing MRTK test patterns. [PR #1073](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1073) + ## [3.4.0] - 2025-11-12 ### Added diff --git a/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/HandConstraintTests.cs b/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/HandConstraintTests.cs index cfa274fe7..fb2a05341 100644 --- a/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/HandConstraintTests.cs +++ b/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/HandConstraintTests.cs @@ -24,7 +24,7 @@ public class HandConstraintTests : BaseRuntimeInputTests [UnityTest] public IEnumerator HandConstraintEventsOneHanded() { - // Disable gaze interactions for this unit test; + // Disable gaze interactions for this unit test InputTestUtilities.DisableGazeInteractor(); // Set up GameObject with a SolverHandler diff --git a/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/ObjectManipulatorTests.cs b/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/ObjectManipulatorTests.cs index 3f69290b8..9a0ee83cd 100644 --- a/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/ObjectManipulatorTests.cs +++ b/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/ObjectManipulatorTests.cs @@ -4,19 +4,19 @@ // Disable "missing XML comment" warning for tests. While nice to have, this documentation is not required. #pragma warning disable CS1591 -using MixedReality.Toolkit; using MixedReality.Toolkit.Core.Tests; -using MixedReality.Toolkit.Input.Tests; +using MixedReality.Toolkit.Input; using MixedReality.Toolkit.Input.Simulation; +using MixedReality.Toolkit.Input.Tests; using NUnit.Framework; using System; using System.Collections; +using System.Collections.Generic; using UnityEngine; using UnityEngine.TestTools; using UnityEngine.XR.Interaction.Toolkit; using HandshapeId = MixedReality.Toolkit.Input.HandshapeTypes.HandshapeId; using MovementType = UnityEngine.XR.Interaction.Toolkit.XRBaseInteractable.MovementType; -using MixedReality.Toolkit.Input; namespace MixedReality.Toolkit.SpatialManipulation.Runtime.Tests { @@ -537,7 +537,6 @@ public IEnumerator ObjectManipulatorOneHandMoveFar() } } - /// /// This tests that the gaze pointer can be used to directly invoke the manipulation logic via simulated pointer events, used /// for scenarios like voice-driven movement using the gaze pointer. @@ -744,29 +743,27 @@ public IEnumerator TestObjManipTargetChange() Assert.IsTrue(cube1.transform.position.CloseEnoughTo(cube1Pos), "Cube1 moved when it shouldn't have!"); Assert.IsTrue(!cube2.transform.position.CloseEnoughTo(cube2Pos), "Cube2 didn't move when it should have!"); - + // Cube2 should be facing the user. Assert.IsTrue(cube2.transform.forward.CloseEnoughTo(-(cube2.transform.position - Camera.main.transform.position).normalized), "Cube2 didn't stay facing user!"); - } #endregion #region Two Handed Manipulation Tests - // This test is not yet working due to some confusion as to how the centroid math works with the current object manipulator - - /* /// /// Test that the grab centroid is calculated correctly while rotating /// the hands during a two-hand near interaction grab. /// - [UnityTest] + [UnityTest, Ignore("This test is not yet working due to some confusion as to how the centroid math works with the current object manipulator")] public IEnumerator ObjectManipulatorTwoHandedCentroid() { InputTestUtilities.DisableGazeInteractor(); + yield return RuntimeTestUtilities.WaitForUpdates(); InputTestUtilities.InitializeCameraToOriginAndForward(); + yield return RuntimeTestUtilities.WaitForUpdates(); // Set up cube with ObjectManipulator var testObject = GameObject.CreatePrimitive(PrimitiveType.Cube); @@ -780,17 +777,21 @@ public IEnumerator ObjectManipulatorTwoHandedCentroid() objectManipulator.SmoothingFar = false; objectManipulator.SmoothingNear = false; // Configuring for two-handed interaction - objectManipulator.selectMode = UnityEngine.XR.Interaction.Toolkit.InteractableSelectMode.Multiple; + objectManipulator.selectMode = InteractableSelectMode.Multiple; TestHand rightHand = new TestHand(Handedness.Right); TestHand leftHand = new TestHand(Handedness.Left); + yield return RuntimeTestUtilities.WaitForUpdates(); yield return rightHand.Show(Vector3.zero); + yield return RuntimeTestUtilities.WaitForUpdates(); yield return leftHand.Show(Vector3.zero); + yield return RuntimeTestUtilities.WaitForUpdates(); yield return rightHand.MoveTo(new Vector3(0.1f, -0.1f, 0.8f)); + yield return RuntimeTestUtilities.WaitForUpdates(); yield return leftHand.MoveTo(new Vector3(-0.1f, -0.1f, 0.8f)); - yield return null; + yield return RuntimeTestUtilities.WaitForUpdates(); // Only testing move/rotate centroid position objectManipulator.AllowedManipulations = TransformFlags.Move | TransformFlags.Scale; @@ -804,8 +805,10 @@ public IEnumerator ObjectManipulatorTwoHandedCentroid() objectManipulator.selectExited.AddListener((med) => manipulationEndedCount++); // Grab the box. - yield return rightHand.SetGesture(GestureId.Pinch); - yield return leftHand.SetGesture(GestureId.Pinch); + yield return rightHand.SetHandshape(HandshapeId.Pinch); + yield return RuntimeTestUtilities.WaitForUpdates(); + yield return leftHand.SetHandshape(HandshapeId.Pinch); + yield return RuntimeTestUtilities.WaitForUpdates(); // Previously we checked that we didn't move after two pinches, however, due to the hand position shifting slighting on pinch, this is not applicable // TODO, address in the future? @@ -815,14 +818,11 @@ public IEnumerator ObjectManipulatorTwoHandedCentroid() // The ObjectManipulator should recognize that we've begun manipulation. Assert.IsTrue(manipulationStartedCount > 0); - yield return RuntimeTestUtilities.WaitForEnterKey(); - // Move both hands outwards; the object may be scaled but the position should remain the same. yield return rightHand.MoveTo(new Vector3(0.2f, -0.1f, 0.8f)); + yield return RuntimeTestUtilities.WaitForUpdates(); yield return leftHand.MoveTo(new Vector3(-0.2f, -0.1f, 0.8f)); - - - yield return RuntimeTestUtilities.WaitForEnterKey(); + yield return RuntimeTestUtilities.WaitForUpdates(); // Should *still* not have moved! // TestUtilities.AssertAboutEqual(testObject.transform.position, initialObjectPosition, $"Object moved when it shouldn't have! Position: {testObject.transform.position:F5}", 0.00001f); @@ -853,8 +853,10 @@ public IEnumerator ObjectManipulatorTwoHandedCentroid() yield return MoveHandsAndCheckCentroid(testCondition.Item1, testCondition.Item2, leftHand, rightHand, objectManipulator, initialObjectPosition, originalCentroid, testObject.transform); } - yield return rightHand.SetGesture(GestureId.Open); - yield return leftHand.SetGesture(GestureId.Open); + yield return rightHand.SetHandshape(HandshapeId.Open); + yield return RuntimeTestUtilities.WaitForUpdates(); + yield return leftHand.SetHandshape(HandshapeId.Open); + yield return RuntimeTestUtilities.WaitForUpdates(); } /// @@ -870,11 +872,15 @@ private IEnumerator MoveHandsAndCheckCentroid(Vector3 handRotationEuler, Vector3 { // Rotate the hands. yield return rightHand.RotateTo(Quaternion.Euler(handRotationEuler.x, handRotationEuler.y, handRotationEuler.z)); + yield return RuntimeTestUtilities.WaitForUpdates(); yield return leftHand.RotateTo(Quaternion.Euler(handRotationEuler.x, -handRotationEuler.y, -handRotationEuler.z)); + yield return RuntimeTestUtilities.WaitForUpdates(); // Move the hands. yield return rightHand.MoveTo(new Vector3(handPosition.x, handPosition.y, handPosition.z)); + yield return RuntimeTestUtilities.WaitForUpdates(); yield return leftHand.MoveTo(new Vector3(-handPosition.x, handPosition.y, handPosition.z)); + yield return RuntimeTestUtilities.WaitForUpdates(); // Recalculate the new grab centroid. var leftGrabPoint = om.interactorsSelecting[0].transform.position; @@ -888,7 +894,6 @@ private IEnumerator MoveHandsAndCheckCentroid(Vector3 handRotationEuler, Vector3 TestUtilities.AssertAboutEqual(testObject.transform.position, originalObjectPosition + centroidDelta, $"Object moved did not move according to the delta! Actual position: {testObject.transform.position:F5}, should be {originalObjectPosition + centroidDelta}", 0.00001f); } - */ #endregion @@ -1287,4 +1292,4 @@ public IEnumerator ObjectManipulatorFarThrow() */ } } -#pragma warning restore CS1591 \ No newline at end of file +#pragma warning restore CS1591 From d29595ed6252e5340775bc89e41097aa419b28c9 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Wed, 10 Jun 2026 17:51:28 -0700 Subject: [PATCH 7/8] Fixup CHANGELOGs --- org.mixedrealitytoolkit.core/CHANGELOG.md | 14 +++++++------- org.mixedrealitytoolkit.uxcore/CHANGELOG.md | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/org.mixedrealitytoolkit.core/CHANGELOG.md b/org.mixedrealitytoolkit.core/CHANGELOG.md index 49967e9e5..0e5dbcf58 100644 --- a/org.mixedrealitytoolkit.core/CHANGELOG.md +++ b/org.mixedrealitytoolkit.core/CHANGELOG.md @@ -7,6 +7,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Added * Added new `editorDefault` field for debugging the various `DisplayType`s in-editor. [PR #1130](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1130) +* Added edit mode tests for `AssemblyExtensions`, `SystemType`, and `SerializableDictionary`. [PR #1122](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1122) + +### Changed + +* Updated `PackageValidator` to only be valid if `UNITY_EDITOR` is true. [PR #1125](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1125) +* `AssemblyExtensions.GetLoadableTypes` now throws `ArgumentNullException` when called on a null assembly instead of `NullReferenceException`. [PR #1122](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1122) +* Updated `MRTKBaseInteractable` to follow MRTK style. [PR #1073](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1073) ## [4.0.0-pre.3] - 2026-05-20 @@ -18,13 +25,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). * Updated the minimum editor version to 6000.0.66f2 [PR #1112](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1112) * Updated code style in `HandsSubsystemDescriptor`, `MRTKSubsystemDescriptor`, `DictationSubsystemDescriptor`, and `XRSubsystemHelpers`. [PR #1109](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1109) -* Updated `PackageValidator` to only be valid if `UNITY_EDITOR` is true. [PR #1125](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1125) -* `AssemblyExtensions.GetLoadableTypes` now throws `ArgumentNullException` when called on a null assembly instead of `NullReferenceException`. [PR #1122](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1122) -* Updated `MRTKBaseInteractable` to follow MRTK style. [PR #1073](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1073) - -### Added - -* Added edit mode tests for `AssemblyExtensions`, `SystemType`, and `SerializableDictionary`. [PR #1122](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1122) ### Fixed diff --git a/org.mixedrealitytoolkit.uxcore/CHANGELOG.md b/org.mixedrealitytoolkit.uxcore/CHANGELOG.md index f4cba665f..514019778 100644 --- a/org.mixedrealitytoolkit.uxcore/CHANGELOG.md +++ b/org.mixedrealitytoolkit.uxcore/CHANGELOG.md @@ -4,6 +4,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [4.0.0-pre.4] - 2026-06-10 +### Added + +* Added `AlphaBlend` tint mode to `TintEffect`. [PR #1131](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1131) + ### Fixed * Fixed build issue caused by `FontIconSelectorMigrationUtility` not being in an Editor-only assembly. @@ -21,10 +25,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). * Updated the minimum editor version to 6000.0.66f2 [PR #1112](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1112) * Updated `FontIconSelector`, `StateVisualizer`, and `TintEffect` to be themeable. [PR #1119](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1119) -### Added - -* Added `AlphaBlend` tint mode to `TintEffect`. [PR #1131](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1131) - ### Fixed * Fixed "leaked managed shell" issue in `UGUIInputAdapter`. [PR #1096](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1096) From a219db98c6d85ac48144fd5bbf45748856207316 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Wed, 10 Jun 2026 17:54:21 -0700 Subject: [PATCH 8/8] Add missing namespace --- .../Tests/Runtime/ObjectManipulatorTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/ObjectManipulatorTests.cs b/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/ObjectManipulatorTests.cs index 9b10e2825..9ef49ac43 100644 --- a/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/ObjectManipulatorTests.cs +++ b/org.mixedrealitytoolkit.spatialmanipulation/Tests/Runtime/ObjectManipulatorTests.cs @@ -14,6 +14,7 @@ using System.Collections.Generic; using UnityEngine; using UnityEngine.TestTools; +using UnityEngine.XR.Interaction.Toolkit.Interactables; using UnityEngine.XR.Interaction.Toolkit.Interactors; using HandshapeId = MixedReality.Toolkit.Input.HandshapeTypes.HandshapeId;