From 6e451522500faa269efa68b6734d831a5902a11c Mon Sep 17 00:00:00 2001 From: "JSD\\13999" <1399945104@qq.com> Date: Wed, 20 May 2026 20:49:29 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B6=E6=9D=9F=20P1=20=E8=B5=84=E6=BA=90?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E9=80=82=E9=85=8D=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AddressablesResourceBackend.cs | 6 +- .../FlowScope.Addressables.asmdef | 3 +- .../Resources/ResourceServiceBackendTests.cs | 130 ++++++++++++++---- My project/Packages/packages-lock.json | 21 +++ 4 files changed, 129 insertions(+), 31 deletions(-) diff --git a/My project/Assets/FlowScope/Addressables/AddressablesResourceBackend.cs b/My project/Assets/FlowScope/Addressables/AddressablesResourceBackend.cs index d887982..8ef9b1b 100644 --- a/My project/Assets/FlowScope/Addressables/AddressablesResourceBackend.cs +++ b/My project/Assets/FlowScope/Addressables/AddressablesResourceBackend.cs @@ -2,7 +2,7 @@ using System; using System.Threading; using System.Threading.Tasks; using FlowScope.Resources; -using UnityEngine.AddressableAssets; +using UnityAddressables = UnityEngine.AddressableAssets.Addressables; namespace FlowScope.Addressables { @@ -13,7 +13,7 @@ namespace FlowScope.Addressables public async Task LoadAsync(string key, CancellationToken cancellationToken) where T : class { - var handle = Addressables.LoadAssetAsync(key); + var handle = UnityAddressables.LoadAssetAsync(key); await WaitWithCancellation(handle.Task, cancellationToken); return handle.Result; } @@ -21,7 +21,7 @@ namespace FlowScope.Addressables public void Release(string key, T asset) where T : class { - Addressables.Release(asset); + UnityAddressables.Release(asset); } private static async Task WaitWithCancellation(Task task, CancellationToken cancellationToken) diff --git a/My project/Assets/FlowScope/Addressables/FlowScope.Addressables.asmdef b/My project/Assets/FlowScope/Addressables/FlowScope.Addressables.asmdef index 7a5e492..ab7704a 100644 --- a/My project/Assets/FlowScope/Addressables/FlowScope.Addressables.asmdef +++ b/My project/Assets/FlowScope/Addressables/FlowScope.Addressables.asmdef @@ -3,7 +3,8 @@ "rootNamespace": "FlowScope.Addressables", "references": [ "FlowScope.Runtime", - "Unity.Addressables" + "Unity.Addressables", + "Unity.ResourceManager" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/My project/Assets/FlowScope/Tests/EditMode/Resources/ResourceServiceBackendTests.cs b/My project/Assets/FlowScope/Tests/EditMode/Resources/ResourceServiceBackendTests.cs index c41a920..034be1b 100644 --- a/My project/Assets/FlowScope/Tests/EditMode/Resources/ResourceServiceBackendTests.cs +++ b/My project/Assets/FlowScope/Tests/EditMode/Resources/ResourceServiceBackendTests.cs @@ -1,15 +1,18 @@ using System; +using System.Collections; +using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; using FlowScope.Resources; using NUnit.Framework; +using UnityEngine.TestTools; namespace FlowScope.Tests.EditMode.Resources { public sealed class ResourceServiceBackendTests { - [Test] - public async Task LoadAsync_WhenSameKeyLoadsConcurrently_UsesOneBackendLoad() + [UnityTest] + public IEnumerator LoadAsync_WhenSameKeyLoadsConcurrently_UsesOneBackendLoad() { var backend = new FakeResourceBackend(); var service = new ResourceService(backend); @@ -18,15 +21,17 @@ namespace FlowScope.Tests.EditMode.Resources var second = service.LoadAsync("shared", CancellationToken.None); backend.Gate.SetResult(new TestAsset()); - using var firstHandle = await first; - using var secondHandle = await second; + yield return Await(first); + yield return Await(second); + using var firstHandle = Result(first); + using var secondHandle = Result(second); Assert.AreEqual(1, backend.LoadCalls); Assert.AreSame(firstHandle.Asset, secondHandle.Asset); } - [Test] - public async Task LoadAsync_WhenCanceled_DoesNotCreateHandle() + [UnityTest] + public IEnumerator LoadAsync_WhenCanceled_DoesNotCreateHandle() { var backend = new FakeResourceBackend(); var service = new ResourceService(backend); @@ -35,13 +40,20 @@ namespace FlowScope.Tests.EditMode.Resources var task = service.LoadAsync("canceled", cts.Token); cts.Cancel(); - await ExpectThrowsAsync(task); - Assert.IsFalse(service.TryLoadCompleted("canceled", out var handle)); - Assert.IsNull(handle); + try + { + yield return AwaitExpected(task); + Assert.IsFalse(service.TryLoadCompleted("canceled", out var handle)); + Assert.IsNull(handle); + } + finally + { + backend.Gate.TrySetResult(new TestAsset()); + } } - [Test] - public async Task DisposeLastHandle_ReleasesBackendAsset() + [UnityTest] + public IEnumerator DisposeLastHandle_ReleasesBackendAsset() { var backend = new FakeResourceBackend(); var service = new ResourceService(backend); @@ -49,8 +61,10 @@ namespace FlowScope.Tests.EditMode.Resources var first = service.LoadAsync("shared", CancellationToken.None); var second = service.LoadAsync("shared", CancellationToken.None); backend.Gate.SetResult(new TestAsset()); - var firstHandle = await first; - var secondHandle = await second; + yield return Await(first); + yield return Await(second); + var firstHandle = Result(first); + var secondHandle = Result(second); firstHandle.Dispose(); Assert.AreEqual(0, backend.ReleaseCalls); @@ -59,15 +73,16 @@ namespace FlowScope.Tests.EditMode.Resources Assert.AreEqual(1, backend.ReleaseCalls); } - [Test] - public async Task DisposeLastHandle_RemovesCompletedCacheEntry() + [UnityTest] + public IEnumerator DisposeLastHandle_RemovesCompletedCacheEntry() { var backend = new FakeResourceBackend(); var service = new ResourceService(backend); var load = service.LoadAsync("cached", CancellationToken.None); backend.Gate.SetResult(new TestAsset()); - var handle = await load; + yield return Await(load); + var handle = Result(load); Assert.IsTrue(service.TryLoadCompleted("cached", out var cached)); cached.Dispose(); @@ -76,8 +91,8 @@ namespace FlowScope.Tests.EditMode.Resources Assert.IsFalse(service.TryLoadCompleted("cached", out _)); } - [Test] - public async Task CreateGroup_DisposesAllHandles() + [UnityTest] + public IEnumerator CreateGroup_DisposesAllHandles() { var backend = new FakeResourceBackend(); var service = new ResourceService(backend); @@ -85,13 +100,15 @@ namespace FlowScope.Tests.EditMode.Resources var first = service.LoadAsync("first", CancellationToken.None); backend.Gate.SetResult(new TestAsset()); - var firstHandle = await first; + yield return Await(first); + var firstHandle = Result(first); group.Add(firstHandle); - backend.Gate = new TaskCompletionSource(); + backend.ResetGate(); var second = service.LoadAsync("second", CancellationToken.None); backend.Gate.SetResult(new TestAsset()); - var secondHandle = await second; + yield return Await(second); + var secondHandle = Result(second); group.Add(secondHandle); group.Dispose(); @@ -106,7 +123,13 @@ namespace FlowScope.Tests.EditMode.Resources public string Name => "Fake"; public int LoadCalls { get; private set; } public int ReleaseCalls { get; private set; } - public TaskCompletionSource Gate { get; set; } = new(); + public TaskCompletionSource Gate { get; private set; } = + new(TaskCreationOptions.RunContinuationsAsynchronously); + + public void ResetGate() + { + Gate = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + } public async Task LoadAsync(string key, CancellationToken cancellationToken) where T : class @@ -126,19 +149,72 @@ namespace FlowScope.Tests.EditMode.Resources { } - private static async Task ExpectThrowsAsync(Task task) + private static IEnumerator Await(Task task) + { + var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(2); + while (!task.IsCompleted) + { + if (DateTime.UtcNow > deadline) + { + Assert.Fail("Async operation did not complete within 2 seconds."); + } + + yield return null; + } + + ThrowIfFailed(task); + } + + private static IEnumerator AwaitExpected(Task task) where TException : Exception { - try + var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(2); + while (!task.IsCompleted) { - await task; + if (DateTime.UtcNow > deadline) + { + Assert.Fail("Async operation did not complete within 2 seconds."); + } + + yield return null; } - catch (TException) + + if (task.IsCanceled && typeof(TException) == typeof(OperationCanceledException)) { - return; + yield break; + } + + var exception = task.Exception?.InnerException; + if (exception is TException) + { + yield break; + } + + if (exception != null) + { + ExceptionDispatchInfo.Capture(exception).Throw(); } Assert.Fail($"Expected {typeof(TException).Name}."); } + + private static T Result(Task task) + { + ThrowIfFailed(task); + return task.Result; + } + + private static void ThrowIfFailed(Task task) + { + if (task.IsCanceled) + { + throw new OperationCanceledException(); + } + + if (task.Exception?.InnerException != null) + { + ExceptionDispatchInfo.Capture(task.Exception.InnerException).Throw(); + } + } } } diff --git a/My project/Packages/packages-lock.json b/My project/Packages/packages-lock.json index fba6248..082e285 100644 --- a/My project/Packages/packages-lock.json +++ b/My project/Packages/packages-lock.json @@ -9,6 +9,20 @@ }, "hash": "329ca7915713417f2e0837b0e0a80b4da074db4a" }, + "com.unity.addressables": { + "version": "1.21.21", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.scriptablebuildpipeline": "1.21.23", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0" + }, + "url": "https://packages.unity.cn" + }, "com.unity.collab-proxy": { "version": "2.12.4", "depth": 0, @@ -76,6 +90,13 @@ "dependencies": {}, "url": "https://packages.unity.cn" }, + "com.unity.scriptablebuildpipeline": { + "version": "1.21.25", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.cn" + }, "com.unity.settings-manager": { "version": "2.1.0", "depth": 2,