From ae0ed3584cafa5afaa024c2fe6ba3cbb4a21a4f4 Mon Sep 17 00:00:00 2001 From: Eli Pinkerton Date: Sun, 18 Oct 2026 20:31:01 +0000 Subject: [PATCH] Fix tests in populated Unity projects Project-wide discovery includes host assets, and initial loads replace stale selections through legitimate fallback selection. Assert fixture membership after complete loading and isolate normalization from automatic selection. Cover a replacement selection during the busy window. Reproduced five failures on main with eleven existing TestDataObject assets. All 394 EditMode and 15 PlayMode tests now pass on Unity 6000.5.2f1 Windows. The 13-step local gate and npm pack preview pass; package payload stays at 181 files. No production code changes. Fixes #293. --- Tests/Editor/PlayModeMutationGateTests.cs | 15 ++++++--- Tests/Editor/PlayModeSuspensionTests.cs | 1 - .../SavedSelectionNormalizationTests.cs | 31 +++++++++++++++---- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/Tests/Editor/PlayModeMutationGateTests.cs b/Tests/Editor/PlayModeMutationGateTests.cs index 8028b7e9..915805c2 100644 --- a/Tests/Editor/PlayModeMutationGateTests.cs +++ b/Tests/Editor/PlayModeMutationGateTests.cs @@ -309,7 +309,7 @@ public void ShouldGateManualTypeLoadWhileSuspendedForPlayMode() DataVisualizerWindow window = ScriptableObject.CreateInstance(); cleanup.Defer(() => UnityEngine.Object.DestroyImmediate(window)); - CreateFixtureAsset(folder, "First.asset"); + ScriptableObject fixtureAsset = CreateFixtureAsset(folder, "First.asset"); SuspendForPlayMode(window); InvokePrivate(window, "LoadObjectTypesAsync", typeof(TestDataObject), false); @@ -319,10 +319,15 @@ public void ShouldGateManualTypeLoadWhileSuspendedForPlayMode() ResumeFromPlayMode(window); InvokePrivate(window, "LoadObjectTypesAsync", typeof(TestDataObject), false); - Assert.AreEqual( - 1, - ReadPrivateField>(window, "_selectedObjects").Count, - "the same manual type load after resume must load the type's objects" + while (ReadPrivateField(window, "_isLoadingObjectsAsync")) + { + InvokePrivate(window, "ContinueLoadingObjects", typeof(TestDataObject), ReadPrivateField(window, "_asyncLoadGeneration")); + } + + CollectionAssert.Contains( + ReadPrivateField>(window, "_selectedObjects"), + fixtureAsset, + "the same manual type load after resume must load the fixture even when other assets exist" ); } } diff --git a/Tests/Editor/PlayModeSuspensionTests.cs b/Tests/Editor/PlayModeSuspensionTests.cs index ccbdc953..bc5ee9bb 100644 --- a/Tests/Editor/PlayModeSuspensionTests.cs +++ b/Tests/Editor/PlayModeSuspensionTests.cs @@ -112,7 +112,6 @@ public void ShouldStopPumpingWhileSuspendedAndCompleteOnResume() Assert.IsTrue(index.IsComplete); string[] guids = index.GetKnownGuids(typeof(TestDataObject)); - Assert.AreEqual(3, guids.Length); CollectionAssert.Contains(guids, firstGuid); CollectionAssert.Contains(guids, secondGuid); CollectionAssert.Contains(guids, thirdGuid); diff --git a/Tests/Editor/SavedSelectionNormalizationTests.cs b/Tests/Editor/SavedSelectionNormalizationTests.cs index e4d089f1..d563744e 100644 --- a/Tests/Editor/SavedSelectionNormalizationTests.cs +++ b/Tests/Editor/SavedSelectionNormalizationTests.cs @@ -93,6 +93,15 @@ private static DataVisualizerWindow CreateWindow(TestCleanupScope cleanup, out D return window; } + private static void LoadWithoutAutoSelection(DataVisualizerWindow window) + { + /* + Continue a load so automatic first-object selection cannot replace the stale + GUID before the normalization pump is tested in a populated host. + */ + InvokePrivate(window, "LoadObjectTypesAsync", typeof(TestDataObject), true); + } + private static string ReadSavedSelection(DataVisualizerWindow window, string typeFullName) { return (string)InvokePrivate(window, "GetLastSelectedObjectGuidForType", typeFullName); @@ -134,7 +143,7 @@ public void ShouldKeepSavedSelectionWhenLoadRunsWhileAssetDatabaseIsBusy() string typeFullName = typeof(TestDataObject).FullName; WriteSavedSelection(window, typeFullName, "stale-saved-guid"); - InvokePrivate(window, "LoadObjectTypesAsync", typeof(TestDataObject), false); + LoadWithoutAutoSelection(window); Assert.AreEqual("stale-saved-guid", ReadSavedSelection(window, typeFullName), "a busy-window load must keep the persisted saved selection"); CollectionAssert.Contains(ReadPrivateField>(window, "_pendingSavedSelectionNormalizationTypes"), typeof(TestDataObject)); @@ -142,8 +151,9 @@ public void ShouldKeepSavedSelectionWhenLoadRunsWhileAssetDatabaseIsBusy() } } - [Test] - public void ShouldClearInvalidSavedSelectionAfterAssetDatabaseSettles() + [TestCase(false)] + [TestCase(true)] + public void ShouldNormalizeLatestSavedSelectionAfterAssetDatabaseSettles(bool replaceSelection) { string folder = CreateFixtureFolder(); object previousInstance = ReadSharedInstance(); @@ -164,13 +174,22 @@ public void ShouldClearInvalidSavedSelectionAfterAssetDatabaseSettles() bool isBusy = true; AssetGuidDiscovery.AssetDatabaseBusyOverride = () => isBusy; - InvokePrivate(window, "LoadObjectTypesAsync", typeof(TestDataObject), false); + LoadWithoutAutoSelection(window); Assert.AreEqual("stale-saved-guid", ReadSavedSelection(window, typeFullName), "a busy-window load must keep the persisted saved selection"); + string assetPath = folder + "/Replacement.asset"; + AssetDatabase.CreateAsset(ScriptableObject.CreateInstance(), assetPath); + AssetDatabase.SaveAssets(); + string replacementGuid = AssetDatabase.AssetPathToGUID(assetPath); + if (replaceSelection) + { + WriteSavedSelection(window, typeFullName, replacementGuid); + } + isBusy = false; InvokePrivate(window, "ProcessSavedSelectionNormalizations"); - Assert.That(ReadSavedSelection(window, typeFullName) == null, "an invalid saved selection must be cleared once the AssetDatabase settles"); + Assert.AreEqual(replaceSelection ? replacementGuid : null, ReadSavedSelection(window, typeFullName), "normalize the latest selection, not the deferred snapshot"); Assert.IsEmpty(ReadPrivateField>(window, "_pendingSavedSelectionNormalizationTypes")); } } @@ -236,7 +255,7 @@ public void ShouldResumeSavedSelectionNormalizationAfterPlayMode() bool isBusy = true; AssetGuidDiscovery.AssetDatabaseBusyOverride = () => isBusy; - InvokePrivate(window, "LoadObjectTypesAsync", typeof(TestDataObject), false); + LoadWithoutAutoSelection(window); SuspendForPlayMode(window); Assert.That(ReadPrivateField(window, "_savedSelectionNormalizationTask") == null, "suspending for play mode must stop the pump");