From 46505e7b5e43fa1bc5d00f9f0b67d5f248a29737 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 27 Feb 2025 19:51:59 -0800 Subject: [PATCH 01/33] Update TestUtils.cs --- Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.cs b/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.cs index c1eb451..8d10434 100644 --- a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.cs +++ b/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.cs @@ -49,5 +49,10 @@ public static IEnumerator RunNoLogs(Func test) ImageLoader.settings.debugLevel = DebugLevel.Error; yield return test(); } + public static void RunNoLogs(Action test) + { + ImageLoader.settings.debugLevel = DebugLevel.Error; + test(); + } } } \ No newline at end of file From 4742c60d63bda6ccd358a8ce4e35da29a81811c1 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 27 Feb 2025 19:52:02 -0800 Subject: [PATCH 02/33] Update Future.Placeholder.cs --- .../Runtime/Future/Future.Placeholder.cs | 81 ++++++++++++------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs index 17a6e8a..4b072d8 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using UnityEngine; @@ -7,40 +8,60 @@ namespace Extensions.Unity.ImageLoader { public partial class Future { + protected Mutex placeholderMutex = new Mutex(); + protected Dictionary placeholders; + /// - /// Create and return empty Future instance with loading status + /// /// - // public Future SetPlaceholder(Texture placeholder, params FutureLoadingFrom[] from) - // { - // if (cleared || IsCancelled) - // { - // if (LogLevel.IsActive(DebugLevel.Error)) - // Debug.Log($"[ImageLoader] Future[id={Id}] SetPlaceholder: is impossible because the future is cleared or canceled\n{Url}"); - // return this; - // } - // if (IsInProgress) - // { - // // TODO: set placeholder + public IFuture SetPlaceholder(T placeholder, params FutureLoadingFrom[] from) + { + lock (placeholderMutex) + { + if (placeholders == null) + placeholders = new Dictionary(); + + foreach (var f in from) + { + if (placeholders.ContainsKey(f)) + { + if (LogLevel.IsActive(DebugLevel.Warning)) + Debug.Log($"[ImageLoader] Future[id={Id}] Placeholder for loading from {f} is already set. Replacing it with new value\n{Url}"); + } + if (LogLevel.IsActive(DebugLevel.Trace)) + Debug.Log($"[ImageLoader] Future[id={Id}] Set placeholder for loading from {f}\n{Url}"); + placeholders[f] = placeholder; + } + } + if (cleared || IsCancelled) + { + if (LogLevel.IsActive(DebugLevel.Error)) + Debug.Log($"[ImageLoader] Future[id={Id}] SetPlaceholder: is impossible because the future is cleared or canceled\n{Url}"); + return this; + } + if (IsInProgress) + { + // TODO: set placeholder - // return this; - // } + return this; + } - // if (from.Any(x => x == FutureLoadingFrom.DiskCache)) - // { - // LoadingFromDiskCache(() => - // { - // // TODO: set placeholder - // }); - // } - // if (from.Any(x => x == FutureLoadingFrom.Source)) - // { - // LoadingFromSource(() => - // { - // // TODO: set placeholder - // }); - // } + if (from.Any(x => x == FutureLoadingFrom.DiskCache)) + { + LoadingFromDiskCache(() => + { + // TODO: set placeholder + }); + } + if (from.Any(x => x == FutureLoadingFrom.Source)) + { + LoadingFromSource(() => + { + // TODO: set placeholder + }); + } - // return this; - // } + return this; + } } } From 5ad46ceb708e29257419d57cc0d8a7136938079c Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Tue, 4 Mar 2025 23:37:07 -0800 Subject: [PATCH 03/33] Added Player tests --- Assets/_PackageRoot/Tests/Base.meta | 8 + ...Extensions.Unity.ImageLoader.Tests.asmdef} | 7 +- ...nsions.Unity.ImageLoader.Tests.asmdef.meta | 7 + .../Tests/{Editor => Base}/Utils.meta | 0 .../Tests/{Editor => Base}/Utils/EventData.cs | 0 .../{Editor => Base}/Utils/EventData.cs.meta | 0 .../Tests/{Editor => Base}/Utils/EventName.cs | 0 .../{Editor => Base}/Utils/EventName.cs.meta | 0 .../{Editor => Base}/Utils/FakeConsumer.cs | 0 .../Utils/FakeConsumer.cs.meta | 0 .../FakeFuture.Implementation.IFuture.cs | 0 .../FakeFuture.Implementation.IFuture.cs.meta | 0 ...keFuture.Implementation.IFutureInternal.cs | 0 ...ure.Implementation.IFutureInternal.cs.meta | 0 .../Utils/FakeFuture.Subscription.cs | 0 .../Utils/FakeFuture.Subscription.cs.meta | 0 .../{Editor => Base}/Utils/FakeFuture.cs | 0 .../{Editor => Base}/Utils/FakeFuture.cs.meta | 0 .../Tests/{Editor => Base}/Utils/FutureEx.cs | 0 .../{Editor => Base}/Utils/FutureEx.cs.meta | 0 .../Utils/FutureListener.Assert.cs | 0 .../Utils/FutureListener.Assert.cs.meta | 0 .../{Editor => Base}/Utils/FutureListener.cs | 0 .../Utils/FutureListener.cs.meta | 0 .../{Editor => Base}/Utils/TestUtils.Async.cs | 2 +- .../Utils/TestUtils.Async.cs.meta | 0 .../{Editor => Base}/Utils/TestUtils.Load.cs | 2 +- .../Utils/TestUtils.Load.cs.meta | 0 .../Utils/TestUtils.LoadFail.cs | 2 +- .../Utils/TestUtils.LoadFail.cs.meta | 0 .../Tests/{Editor => Base}/Utils/TestUtils.cs | 2 +- .../{Editor => Base}/Utils/TestUtils.cs.meta | 0 ...ions.Unity.ImageLoader.Tests.Editor.asmdef | 23 + ...nity.ImageLoader.Tests.Editor.asmdef.meta} | 0 ...ons.Unity.ImageLoader.Tests.Runtime.asmdef | 20 + ...nity.ImageLoader.Tests.Runtime.asmdef.meta | 7 + Assets/_PackageRoot/Tests/Runtime/Test.cs | 21 + .../_PackageRoot/Tests/Runtime/Test.cs.meta | 11 + .../_PackageRoot/Tests/Runtime/TestCache.cs | 146 ++++++ .../Tests/Runtime/TestCache.cs.meta | 11 + .../Tests/Runtime/TestConcurrency.cs | 121 +++++ .../Tests/Runtime/TestConcurrency.cs.meta | 11 + .../Runtime/TestFuture.Load.AndCancel.cs | 53 +++ .../Runtime/TestFuture.Load.AndCancel.cs.meta | 11 + .../Runtime/TestFuture.Load.ThenCancel.cs | 73 +++ .../TestFuture.Load.ThenCancel.cs.meta | 11 + .../Tests/Runtime/TestFuture.Load.cs | 54 +++ .../Tests/Runtime/TestFuture.Load.cs.meta | 11 + .../Tests/Runtime/TestFuture.LoadFail.cs | 28 ++ .../Tests/Runtime/TestFuture.LoadFail.cs.meta | 11 + .../_PackageRoot/Tests/Runtime/TestFuture.cs | 301 +++++++++++++ .../Tests/Runtime/TestFuture.cs.meta | 11 + .../Tests/Runtime/TestFutureOrder.cs | 94 ++++ .../Tests/Runtime/TestFutureOrder.cs.meta | 11 + ...tureWaitingAnotherFuture.Load.AndCancel.cs | 62 +++ ...aitingAnotherFuture.Load.AndCancel.cs.meta | 11 + ...ureWaitingAnotherFuture.Load.ThenCancel.cs | 80 ++++ ...itingAnotherFuture.Load.ThenCancel.cs.meta | 11 + .../TestFutureWaitingAnotherFuture.Load.cs | 59 +++ ...estFutureWaitingAnotherFuture.Load.cs.meta | 11 + ...TestFutureWaitingAnotherFuture.LoadFail.cs | 32 ++ ...utureWaitingAnotherFuture.LoadFail.cs.meta | 11 + .../Runtime/TestFutureWaitingAnotherFuture.cs | 11 + .../TestFutureWaitingAnotherFuture.cs.meta | 11 + .../Tests/Runtime/TestLoading.Sprite.cs | 55 +++ .../Tests/Runtime/TestLoading.Sprite.cs.meta | 11 + .../Tests/Runtime/TestLoading.Texture.cs | 55 +++ .../Tests/Runtime/TestLoading.Texture.cs.meta | 11 + .../_PackageRoot/Tests/Runtime/TestLoading.cs | 11 + .../Tests/Runtime/TestLoading.cs.meta | 11 + .../Tests/Runtime/TestReference.cs | 415 ++++++++++++++++++ .../Tests/Runtime/TestReference.cs.meta | 11 + 72 files changed, 1941 insertions(+), 8 deletions(-) create mode 100644 Assets/_PackageRoot/Tests/Base.meta rename Assets/_PackageRoot/Tests/{Editor/Extensions.Unity.ImageLoader.Editor.Tests.asmdef => Base/Extensions.Unity.ImageLoader.Tests.asmdef} (76%) create mode 100644 Assets/_PackageRoot/Tests/Base/Extensions.Unity.ImageLoader.Tests.asmdef.meta rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/EventData.cs (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/EventData.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/EventName.cs (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/EventName.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FakeConsumer.cs (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FakeConsumer.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FakeFuture.Implementation.IFuture.cs (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FakeFuture.Implementation.IFuture.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FakeFuture.Implementation.IFutureInternal.cs (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FakeFuture.Implementation.IFutureInternal.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FakeFuture.Subscription.cs (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FakeFuture.Subscription.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FakeFuture.cs (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FakeFuture.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FutureEx.cs (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FutureEx.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FutureListener.Assert.cs (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FutureListener.Assert.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FutureListener.cs (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/FutureListener.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/TestUtils.Async.cs (97%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/TestUtils.Async.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/TestUtils.Load.cs (99%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/TestUtils.Load.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/TestUtils.LoadFail.cs (98%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/TestUtils.LoadFail.cs.meta (100%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/TestUtils.cs (98%) rename Assets/_PackageRoot/Tests/{Editor => Base}/Utils/TestUtils.cs.meta (100%) create mode 100644 Assets/_PackageRoot/Tests/Editor/Extensions.Unity.ImageLoader.Tests.Editor.asmdef rename Assets/_PackageRoot/Tests/Editor/{Extensions.Unity.ImageLoader.Editor.Tests.asmdef.meta => Extensions.Unity.ImageLoader.Tests.Editor.asmdef.meta} (100%) create mode 100644 Assets/_PackageRoot/Tests/Runtime/Extensions.Unity.ImageLoader.Tests.Runtime.asmdef create mode 100644 Assets/_PackageRoot/Tests/Runtime/Extensions.Unity.ImageLoader.Tests.Runtime.asmdef.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/Test.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/Test.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestCache.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestCache.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestConcurrency.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestConcurrency.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.AndCancel.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.AndCancel.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.ThenCancel.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.ThenCancel.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.LoadFail.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.LoadFail.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestLoading.Sprite.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestLoading.Sprite.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestLoading.Texture.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestLoading.Texture.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestLoading.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestLoading.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestReference.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestReference.cs.meta diff --git a/Assets/_PackageRoot/Tests/Base.meta b/Assets/_PackageRoot/Tests/Base.meta new file mode 100644 index 0000000..879d123 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Base.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a659c4cee9358f0459cc7b10e413a932 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Editor/Extensions.Unity.ImageLoader.Editor.Tests.asmdef b/Assets/_PackageRoot/Tests/Base/Extensions.Unity.ImageLoader.Tests.asmdef similarity index 76% rename from Assets/_PackageRoot/Tests/Editor/Extensions.Unity.ImageLoader.Editor.Tests.asmdef rename to Assets/_PackageRoot/Tests/Base/Extensions.Unity.ImageLoader.Tests.asmdef index 7e425cc..dcaeb90 100644 --- a/Assets/_PackageRoot/Tests/Editor/Extensions.Unity.ImageLoader.Editor.Tests.asmdef +++ b/Assets/_PackageRoot/Tests/Base/Extensions.Unity.ImageLoader.Tests.asmdef @@ -1,12 +1,11 @@ { - "name": "Extensions.Unity.ImageLoader.Editor.Tests", + "name": "Extensions.Unity.ImageLoader.Tests", "references": [ "Extensions.Unity.ImageLoader", + "UnityEngine.TestRunner", "UniTask" ], - "includePlatforms": [ - "Editor" - ], + "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, diff --git a/Assets/_PackageRoot/Tests/Base/Extensions.Unity.ImageLoader.Tests.asmdef.meta b/Assets/_PackageRoot/Tests/Base/Extensions.Unity.ImageLoader.Tests.asmdef.meta new file mode 100644 index 0000000..51db954 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Base/Extensions.Unity.ImageLoader.Tests.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 46caf33cc8e42f348839004db69bcbee +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Editor/Utils.meta b/Assets/_PackageRoot/Tests/Base/Utils.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils.meta rename to Assets/_PackageRoot/Tests/Base/Utils.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/EventData.cs b/Assets/_PackageRoot/Tests/Base/Utils/EventData.cs similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/EventData.cs rename to Assets/_PackageRoot/Tests/Base/Utils/EventData.cs diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/EventData.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/EventData.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/EventData.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/EventData.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/EventName.cs b/Assets/_PackageRoot/Tests/Base/Utils/EventName.cs similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/EventName.cs rename to Assets/_PackageRoot/Tests/Base/Utils/EventName.cs diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/EventName.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/EventName.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/EventName.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/EventName.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FakeConsumer.cs b/Assets/_PackageRoot/Tests/Base/Utils/FakeConsumer.cs similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FakeConsumer.cs rename to Assets/_PackageRoot/Tests/Base/Utils/FakeConsumer.cs diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FakeConsumer.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/FakeConsumer.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FakeConsumer.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/FakeConsumer.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Implementation.IFuture.cs b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Implementation.IFuture.cs rename to Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Implementation.IFuture.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Implementation.IFuture.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Implementation.IFutureInternal.cs b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFutureInternal.cs similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Implementation.IFutureInternal.cs rename to Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFutureInternal.cs diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Implementation.IFutureInternal.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFutureInternal.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Implementation.IFutureInternal.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFutureInternal.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Subscription.cs b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Subscription.cs similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Subscription.cs rename to Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Subscription.cs diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Subscription.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Subscription.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.Subscription.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Subscription.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.cs b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.cs similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.cs rename to Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.cs diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FakeFuture.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FutureEx.cs b/Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FutureEx.cs rename to Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FutureEx.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FutureEx.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.Assert.cs b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.Assert.cs similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.Assert.cs rename to Assets/_PackageRoot/Tests/Base/Utils/FutureListener.Assert.cs diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.Assert.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.Assert.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.Assert.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/FutureListener.Assert.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.cs b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.cs rename to Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Async.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Async.cs similarity index 97% rename from Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Async.cs rename to Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Async.cs index 0852525..00f2cc1 100644 --- a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Async.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Async.cs @@ -6,7 +6,7 @@ namespace Extensions.Unity.ImageLoader.Tests.Utils { - internal static partial class TestUtils + public static partial class TestUtils { public static IEnumerator WaitTicks(int ticks = 1) { diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Async.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Async.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Async.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Async.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Load.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs similarity index 99% rename from Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Load.cs rename to Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs index c2c6a63..4e373ac 100644 --- a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Load.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs @@ -6,7 +6,7 @@ namespace Extensions.Unity.ImageLoader.Tests.Utils { - internal static partial class TestUtils + public static partial class TestUtils { public static IEnumerator LoadFromMemoryCache(string url) => Load(url, null, FutureLoadedFrom.MemoryCache); public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFrom, FutureLoadedFrom expectedLoadedFrom) diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Load.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Load.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.LoadFail.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs similarity index 98% rename from Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.LoadFail.cs rename to Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs index 0173d7c..3141aec 100644 --- a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.LoadFail.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs @@ -7,7 +7,7 @@ namespace Extensions.Unity.ImageLoader.Tests.Utils { - internal static partial class TestUtils + public static partial class TestUtils { public static IEnumerator LoadFailFromMemoryCache(string url) => LoadFail(url, null); public static IEnumerator LoadFail(string url, FutureLoadingFrom? expectedLoadingFrom) diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.LoadFail.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.LoadFail.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs similarity index 98% rename from Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.cs rename to Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs index 8d10434..9bc4988 100644 --- a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs @@ -8,7 +8,7 @@ namespace Extensions.Unity.ImageLoader.Tests.Utils { - internal static partial class TestUtils + public static partial class TestUtils { public static readonly string[] ImageURLs = { diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.cs.meta rename to Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs.meta diff --git a/Assets/_PackageRoot/Tests/Editor/Extensions.Unity.ImageLoader.Tests.Editor.asmdef b/Assets/_PackageRoot/Tests/Editor/Extensions.Unity.ImageLoader.Tests.Editor.asmdef new file mode 100644 index 0000000..0cb286a --- /dev/null +++ b/Assets/_PackageRoot/Tests/Editor/Extensions.Unity.ImageLoader.Tests.Editor.asmdef @@ -0,0 +1,23 @@ +{ + "name": "Extensions.Unity.ImageLoader.Tests.Editor", + "references": [ + "Extensions.Unity.ImageLoader.Tests", + "Extensions.Unity.ImageLoader", + "UnityEngine.TestRunner", + "UnityEditor.TestRunner", + "UniTask" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [ + "NSubstitute.dll" + ], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Editor/Extensions.Unity.ImageLoader.Editor.Tests.asmdef.meta b/Assets/_PackageRoot/Tests/Editor/Extensions.Unity.ImageLoader.Tests.Editor.asmdef.meta similarity index 100% rename from Assets/_PackageRoot/Tests/Editor/Extensions.Unity.ImageLoader.Editor.Tests.asmdef.meta rename to Assets/_PackageRoot/Tests/Editor/Extensions.Unity.ImageLoader.Tests.Editor.asmdef.meta diff --git a/Assets/_PackageRoot/Tests/Runtime/Extensions.Unity.ImageLoader.Tests.Runtime.asmdef b/Assets/_PackageRoot/Tests/Runtime/Extensions.Unity.ImageLoader.Tests.Runtime.asmdef new file mode 100644 index 0000000..91b1c32 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/Extensions.Unity.ImageLoader.Tests.Runtime.asmdef @@ -0,0 +1,20 @@ +{ + "name": "Extensions.Unity.ImageLoader.Tests.Runtime", + "references": [ + "Extensions.Unity.ImageLoader.Tests", + "Extensions.Unity.ImageLoader", + "UnityEngine.TestRunner", + "UniTask" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [ + "NSubstitute.dll" + ], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/Extensions.Unity.ImageLoader.Tests.Runtime.asmdef.meta b/Assets/_PackageRoot/Tests/Runtime/Extensions.Unity.ImageLoader.Tests.Runtime.asmdef.meta new file mode 100644 index 0000000..e396ffc --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/Extensions.Unity.ImageLoader.Tests.Runtime.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b61a7e38a135d044baa1959a8002e39d +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/Test.cs b/Assets/_PackageRoot/Tests/Runtime/Test.cs new file mode 100644 index 0000000..6d6270a --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/Test.cs @@ -0,0 +1,21 @@ +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; +using System; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public class Test + { + public virtual IEnumerator SetUp() + { + yield return TestUtils.ClearEverything("Test Start "); + ImageLoader.settings.debugLevel = DebugLevel.Trace; + } + public virtual IEnumerator TearDown() + { + yield return TestUtils.WaitWhile(() => ImageLoader.GetLoadingSpriteFutures().Count > 0, TimeSpan.FromSeconds(10)); + yield return TestUtils.WaitWhile(() => ImageLoader.GetLoadingTextureFutures().Count > 0, TimeSpan.FromSeconds(10)); + yield return TestUtils.ClearEverything("Test End "); + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/Test.cs.meta b/Assets/_PackageRoot/Tests/Runtime/Test.cs.meta new file mode 100644 index 0000000..6678538 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/Test.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 12ce6cb65d862ce4ca4c64675c18c481 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestCache.cs b/Assets/_PackageRoot/Tests/Runtime/TestCache.cs new file mode 100644 index 0000000..8caa41d --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestCache.cs @@ -0,0 +1,146 @@ +using NUnit.Framework; +using Cysharp.Threading.Tasks; +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; +using System; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public class TestCache : Test + { + [UnitySetUp] public override IEnumerator SetUp() => base.SetUp(); + [UnityTearDown] public override IEnumerator TearDown() => base.TearDown(); + + public async UniTask LoadSprite(string url) + { + var sprite = await ImageLoader.LoadSprite(url); + Assert.IsNotNull(sprite); + } + + [UnityTest] public IEnumerator LoadingFromMemoryCache_NoLogs() => TestUtils.RunNoLogs(LoadingFromMemoryCache); + [UnityTest] public IEnumerator LoadingFromMemoryCache() + { + ImageLoader.settings.useMemoryCache = true; + ImageLoader.settings.useDiskCache = false; + + foreach (var imageURL in TestUtils.ImageURLs) + { + Assert.IsFalse(ImageLoader.MemoryCacheContains(imageURL)); + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.IsTrue(ImageLoader.MemoryCacheContains(imageURL)); + } + } + [UnityTest] public IEnumerator LoadingFromDiskCache_NoLogs() => TestUtils.RunNoLogs(LoadingFromDiskCache); + [UnityTest] public IEnumerator LoadingFromDiskCache() + { + ImageLoader.settings.useMemoryCache = false; + ImageLoader.settings.useDiskCache = true; + + foreach (var imageURL in TestUtils.ImageURLs) + { + Assert.IsFalse(ImageLoader.DiskCacheContains(imageURL)); + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.IsTrue(ImageLoader.DiskCacheContains(imageURL)); + } + } + [UnityTest] public IEnumerator DiskCacheEnable_NoLogs() => TestUtils.RunNoLogs(DiskCacheEnable); + [UnityTest] public IEnumerator DiskCacheEnable() + { + ImageLoader.settings.useDiskCache = true; + + foreach (var imageURL in TestUtils.ImageURLs) + { + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.IsTrue(ImageLoader.DiskCacheContains(imageURL)); + } + } + [UnityTest] public IEnumerator DiskCacheDisable_NoLogs() => TestUtils.RunNoLogs(DiskCacheDisable); + [UnityTest] public IEnumerator DiskCacheDisable() + { + ImageLoader.settings.useDiskCache = false; + + foreach (var imageURL in TestUtils.ImageURLs) + { + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.IsFalse(ImageLoader.DiskCacheContains(imageURL)); + } + } + [UnityTest] public IEnumerator MemoryCacheEnabled_NoLogs() => TestUtils.RunNoLogs(MemoryCacheEnabled); + [UnityTest] public IEnumerator MemoryCacheEnabled() + { + ImageLoader.settings.useMemoryCache = true; + + foreach (var imageURL in TestUtils.ImageURLs) + { + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.IsTrue(ImageLoader.MemoryCacheContains(imageURL)); + } + } + [UnityTest] public IEnumerator MemoryCacheDisabled_NoLogs() => TestUtils.RunNoLogs(MemoryCacheDisabled); + [UnityTest] public IEnumerator MemoryCacheDisabled() + { + ImageLoader.settings.useMemoryCache = false; + + foreach (var imageURL in TestUtils.ImageURLs) + { + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.IsFalse(ImageLoader.MemoryCacheContains(imageURL)); + } + } + [UnityTest] public IEnumerator ClearDiskCache_NoLogs() => TestUtils.RunNoLogs(ClearDiskCache); + [UnityTest] public IEnumerator ClearDiskCache() + { + ImageLoader.settings.useDiskCache = true; + + foreach (var imageURL in TestUtils.ImageURLs) + { + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.IsTrue(ImageLoader.DiskCacheContains(imageURL)); + yield return ImageLoader.ClearDiskCacheAll().TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.IsFalse(ImageLoader.DiskCacheContains(imageURL)); + } + } + [UnityTest] public IEnumerator ClearMemoryCache_NoLogs() => TestUtils.RunNoLogs(ClearMemoryCache); + [UnityTest] public IEnumerator ClearMemoryCache() + { + ImageLoader.settings.useMemoryCache = true; + + foreach (var imageURL in TestUtils.ImageURLs) + { + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.IsTrue(ImageLoader.MemoryCacheContains(imageURL)); + ImageLoader.ClearMemoryCache(imageURL); + Assert.IsFalse(ImageLoader.MemoryCacheContains(imageURL)); + } + } + [UnityTest] public IEnumerator ClearDiskCacheAll_NoLogs() => TestUtils.RunNoLogs(ClearDiskCacheAll); + [UnityTest] public IEnumerator ClearDiskCacheAll() + { + ImageLoader.settings.useDiskCache = true; + + foreach (var imageURL in TestUtils.ImageURLs) + { + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.IsTrue(ImageLoader.DiskCacheContains(imageURL)); + } + yield return ImageLoader.ClearDiskCacheAll().TimeoutCoroutine(TimeSpan.FromSeconds(10)); + foreach (var imageURL in TestUtils.ImageURLs) + Assert.IsFalse(ImageLoader.DiskCacheContains(imageURL)); + } + [UnityTest] public IEnumerator ClearMemoryCacheAll_NoLogs() => TestUtils.RunNoLogs(ClearMemoryCacheAll); + [UnityTest] public IEnumerator ClearMemoryCacheAll() + { + ImageLoader.settings.useMemoryCache = true; + + foreach (var imageURL in TestUtils.ImageURLs) + { + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.IsTrue(ImageLoader.MemoryCacheContains(imageURL)); + } + ImageLoader.ClearMemoryCacheAll(); + foreach (var imageURL in TestUtils.ImageURLs) + Assert.IsFalse(ImageLoader.MemoryCacheContains(imageURL)); + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestCache.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestCache.cs.meta new file mode 100644 index 0000000..8986a3d --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestCache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b5110b05db07284291eda199b280ab6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestConcurrency.cs b/Assets/_PackageRoot/Tests/Runtime/TestConcurrency.cs new file mode 100644 index 0000000..546d16a --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestConcurrency.cs @@ -0,0 +1,121 @@ +using System; +using System.Linq; +using System.Collections; +using NUnit.Framework; +using Cysharp.Threading.Tasks; +using UnityEngine.TestTools; +using UnityEngine; +using System.Threading.Tasks; +using Extensions.Unity.ImageLoader.Tests.Utils; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public class TestConcurrency : Test + { + [UnitySetUp] public override IEnumerator SetUp() => base.SetUp(); + [UnityTearDown] public override IEnumerator TearDown() => base.TearDown(); + + [UnityTest] public IEnumerator Load____1_ReferencesInParallelLateDispose_NoLogs() => TestUtils.RunNoLogs(Load____1_ReferencesInParallelLateDispose); + [UnityTest] public IEnumerator Load____1_ReferencesInParallelLateDispose() + { + yield return Load_X_ReferencesInParallelLateDispose(1); + } + [UnityTest] public IEnumerator Load____2_ReferencesInParallelLateDispose_NoLogs() => TestUtils.RunNoLogs(Load____2_ReferencesInParallelLateDispose); + [UnityTest] public IEnumerator Load____2_ReferencesInParallelLateDispose() + { + yield return Load_X_ReferencesInParallelLateDispose(2); + } + [UnityTest] public IEnumerator Load____5_ReferencesInParallelLateDispose_NoLogs() => TestUtils.RunNoLogs(Load____5_ReferencesInParallelLateDispose); + [UnityTest] public IEnumerator Load____5_ReferencesInParallelLateDispose() + { + yield return Load_X_ReferencesInParallelLateDispose(5); + } + [UnityTest] public IEnumerator Load_1000_ReferencesInParallelLateDispose_NoLogs() => TestUtils.RunNoLogs(Load_1000_ReferencesInParallelLateDispose); + [UnityTest] public IEnumerator Load_1000_ReferencesInParallelLateDispose() + { + yield return Load_X_ReferencesInParallelLateDispose(1000); + } + public IEnumerator Load_X_ReferencesInParallelLateDispose(int count, bool futureDispose = false) + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var cts = new System.Threading.CancellationTokenSource(); + cts.CancelAfterSlim(TimeSpan.FromSeconds(25) + TimeSpan.FromMilliseconds(5 * count)); + + var tasks = Enumerable.Range(0, count) + .Select(i => Task.Run(async () => + { + var futureRef = ImageLoader.LoadSpriteRef(url); + Assert.NotNull(futureRef); + var result = await futureRef; + if (futureDispose) + futureRef.Dispose(); + return result; + })) + .ToArray(); + + var waitTask = Task.WhenAll(tasks); + + while (!waitTask.IsCompleted && !cts.Token.IsCancellationRequested) + yield return UniTask.Yield(); + + Assert.False(cts.Token.IsCancellationRequested, "Timeout"); + Assert.AreEqual(count, Reference.Counter(url)); + + foreach (var reference in tasks.Select(task => task.Result)) + reference.Dispose(); + Assert.AreEqual(0, Reference.Counter(url)); + } + + [UnityTest] public IEnumerator LoadOneMake____5_ReferencesInParallelLateDispose_NoLogs() => TestUtils.RunNoLogs(LoadOneMake____5_ReferencesInParallelLateDispose); + [UnityTest] public IEnumerator LoadOneMake____5_ReferencesInParallelLateDispose() + { + yield return LoadOneMake_X_ReferencesInParallelLateDispose(5); + } + [UnityTest] public IEnumerator LoadOneMake_1000_ReferencesInParallelLateDispose_NoLogs() => TestUtils.RunNoLogs(LoadOneMake_1000_ReferencesInParallelLateDispose); + [UnityTest] public IEnumerator LoadOneMake_1000_ReferencesInParallelLateDispose() + { + yield return LoadOneMake_X_ReferencesInParallelLateDispose(1000); + } + public IEnumerator LoadOneMake_X_ReferencesInParallelLateDispose(int count) + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var future = ImageLoader.LoadSpriteRef(url); + var task1 = future.AsTask(); + + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + Assert.AreEqual(1, Reference.Counter(url)); + + var ref1 = task1.Result; + Assert.NotNull(ref1); + + var references = new Reference[count]; + var tasks = Enumerable.Range(0, count) + .Select(i => Task.Run(() => + { + var ref0 = ImageLoader.LoadSpriteRefFromMemoryCache(url); + Assert.NotNull(ref0); + return ref0; + })) + .ToArray(); + + yield return Task.WhenAll(tasks).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.AreEqual(count + 1, Reference.Counter(url)); + + foreach (var reference in tasks.Select(task => task.Result)) + reference.Dispose(); + Assert.AreEqual(1, Reference.Counter(url)); + + ref1.Dispose(); + Assert.AreEqual(0, Reference.Counter(url)); + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestConcurrency.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestConcurrency.cs.meta new file mode 100644 index 0000000..79436cd --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestConcurrency.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 77b7564380bed854d9016c956c23fc38 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs new file mode 100644 index 0000000..e34fdba --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs @@ -0,0 +1,53 @@ +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFuture + { + [UnityTest] public IEnumerator LoadFrom_Source_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source_AndCancel); + [UnityTest] public IEnumerator LoadFrom_Source_AndCancel() + { + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: true); + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: false); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: true); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: false); + } + IEnumerator LoadFrom_Source_AndCancel(bool useDiskCache, bool useMemoryCache) + { + ImageLoader.settings.useDiskCache = useDiskCache; + ImageLoader.settings.useMemoryCache = useMemoryCache; + + foreach (var url in TestUtils.ImageURLs) + yield return TestUtils.LoadAndCancel(url, FutureLoadingFrom.Source); + + yield return TestUtils.ClearEverything(message: null); + } + [UnityTest] public IEnumerator LoadFrom_MemoryCache_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache_AndCancel); + [UnityTest] public IEnumerator LoadFrom_MemoryCache_AndCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadFromMemoryCacheAndCancel(url); + } + } + + [UnityTest] public IEnumerator LoadFrom_DiskCache_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache_AndCancel); + [UnityTest] public IEnumerator LoadFrom_DiskCache_AndCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = false; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadAndCancel(url, FutureLoadingFrom.DiskCache); + } + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs.meta new file mode 100644 index 0000000..cf5f315 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 04ab48db728d9c545b09c12b0858767d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs new file mode 100644 index 0000000..f48868b --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs @@ -0,0 +1,73 @@ +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFuture + { + [UnityTest] public IEnumerator LoadFrom_Source_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source_ThenCancel); + [UnityTest] public IEnumerator LoadFrom_Source_ThenCancel() + { + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: true); + + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: false); + } + IEnumerator LoadFrom_Source_ThenCancel(bool useDiskCache, bool useMemoryCache, bool useGC) + { + ImageLoader.settings.useDiskCache = useDiskCache; + ImageLoader.settings.useMemoryCache = useMemoryCache; + + foreach (var url in TestUtils.ImageURLs) + yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source, useGC); + + yield return TestUtils.ClearEverything(message: null); + } + + [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache_ThenCancel); + [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadFromMemoryCacheThenCancel(url, useGC: true); + } + // TODO: remove code duplicate + yield return TestUtils.ClearEverything(message: null); + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadFromMemoryCacheThenCancel(url, useGC: false); + } + } + + [UnityTest] public IEnumerator LoadFrom_DiskCache_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache_ThenCancel); + [UnityTest] public IEnumerator LoadFrom_DiskCache_ThenCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = false; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, useGC: true); + } + // TODO: remove code duplicate + yield return TestUtils.ClearEverything(message: null); + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, useGC: false); + } + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs.meta new file mode 100644 index 0000000..acd9c4a --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 68dc40a8db6573f4a9f13deddbd391fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs new file mode 100644 index 0000000..e7b11dd --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs @@ -0,0 +1,54 @@ +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFuture + { + [UnityTest] public IEnumerator LoadFrom_Source_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source); + [UnityTest] public IEnumerator LoadFrom_Source() + { + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: true); + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: false); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: true); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: false); + } + IEnumerator LoadFrom_Source(bool useDiskCache, bool useMemoryCache) + { + ImageLoader.settings.useDiskCache = useDiskCache; + ImageLoader.settings.useMemoryCache = useMemoryCache; + + foreach (var url in TestUtils.ImageURLs) + yield return TestUtils.Load(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source); + + yield return TestUtils.ClearEverything(message: null); + } + + [UnityTest] public IEnumerator LoadFrom_DiskCache_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache); + [UnityTest] public IEnumerator LoadFrom_DiskCache() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = false; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.Load(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache); + } + } + + [UnityTest] public IEnumerator LoadFrom_MemoryCache_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache); + [UnityTest] public IEnumerator LoadFrom_MemoryCache() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadFromMemoryCache(url); + } + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs.meta new file mode 100644 index 0000000..2d51398 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0946b807bf14d1e40a33bc952b23ef90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs b/Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs new file mode 100644 index 0000000..a37b605 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs @@ -0,0 +1,28 @@ +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFuture + { + [UnityTest] public IEnumerator LoadFailFrom_Source_NoLogs() => TestUtils.RunNoLogs(LoadFailFrom_Source); + [UnityTest] public IEnumerator LoadFailFrom_Source() + { + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: true); + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: false); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: true); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: false); + } + IEnumerator LoadFailFrom_Source(bool useDiskCache, bool useMemoryCache) + { + ImageLoader.settings.useDiskCache = useDiskCache; + ImageLoader.settings.useMemoryCache = useMemoryCache; + + foreach (var url in TestUtils.IncorrectImageURLs()) + yield return TestUtils.LoadFail(url, FutureLoadingFrom.Source); + + yield return TestUtils.ClearEverything(message: null); + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs.meta new file mode 100644 index 0000000..cc6c5d7 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0bb6788ffce20d5479763082e87a724d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.cs b/Assets/_PackageRoot/Tests/Runtime/TestFuture.cs new file mode 100644 index 0000000..16b0c53 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.cs @@ -0,0 +1,301 @@ +using NUnit.Framework; +using Cysharp.Threading.Tasks; +using UnityEngine.TestTools; +using System.Collections; +using UnityEngine; +using System; +using Extensions.Unity.ImageLoader.Tests.Utils; +using System.Threading.Tasks; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFuture : Test + { + [UnitySetUp] public override IEnumerator SetUp() => base.SetUp(); + [UnityTearDown] public override IEnumerator TearDown() => base.TearDown(); + + [UnityTest] public IEnumerator GetAllLoadingFutures_NoLogs() => TestUtils.RunNoLogs(GetAllLoadingFutures); + [UnityTest] public IEnumerator GetAllLoadingFutures() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var loadingSpriteFutures = ImageLoader.GetLoadingSpriteFutures(); + Assert.NotNull(loadingSpriteFutures); + Debug.Log($"Loading Future count={loadingSpriteFutures.Count}"); + foreach (var loadingFuture in loadingSpriteFutures) + { + Debug.Log($"Loading Future: {loadingFuture.Url}, Status={loadingFuture.Status}"); + } + Assert.Zero(loadingSpriteFutures.Count); + yield return UniTask.Yield(); + + var loadingTextureFutures = ImageLoader.GetLoadingTextureFutures(); + Assert.NotNull(loadingTextureFutures); + Debug.Log($"Loading Future count={loadingTextureFutures.Count}"); + foreach (var loadingFuture in loadingTextureFutures) + { + Debug.Log($"Loading Future: {loadingFuture.Url}, Status={loadingFuture.Status}"); + } + Assert.Zero(loadingTextureFutures.Count); + } + [UnityTest] public IEnumerator LoadingRefAndWaiting_NoLogs() => TestUtils.RunNoLogs(LoadingRefAndWaiting); + [UnityTest] public IEnumerator LoadingRefAndWaiting() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var task1 = ImageLoader.LoadSpriteRef(url).AsTask(); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var ref0 = task1.Result; + Assert.IsNotNull(ref0); + Assert.AreEqual(1, Reference.Counter(url)); + + Assert.Throws(() => ImageLoader.ClearMemoryCache(url)); + + ref0.Dispose(); + Assert.IsNull(ref0.Value); + Assert.AreEqual(0, Reference.Counter(url)); + } + [UnityTest] public IEnumerator Loading2RefAndCancelFirst_NoLogs() => TestUtils.RunNoLogs(Loading2RefAndCancelFirst); + [UnityTest] public IEnumerator Loading2RefAndCancelFirst() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var future1 = ImageLoader.LoadSpriteRef(url); + var future2 = ImageLoader.LoadSpriteRef(url); + + future1.Cancel(); + + var task1 = future2.AsTask(); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var ref2 = task1.Result; + Assert.IsNotNull(ref2); + Assert.IsNotNull(ref2.Value); + Assert.AreEqual(1, Reference.Counter(url)); + future1.Dispose(); + future2.Dispose(); + ref2.Dispose(); + } + [UnityTest] public IEnumerator Loading2RefAndWait_NoLogs() => TestUtils.RunNoLogs(Loading2RefAndWait); + [UnityTest] public IEnumerator Loading2RefAndWait() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var task1 = ImageLoader.LoadSpriteRef(url).AsTask(); + var task2 = ImageLoader.LoadSpriteRef(url).AsTask(); + + yield return Task.WhenAll(task1, task2).TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var ref0 = task1.Result; + Assert.IsNotNull(ref0); + var ref1 = task2.Result; + Assert.IsNotNull(ref1); + Assert.AreEqual(2, Reference.Counter(url)); + + Assert.Throws(() => ImageLoader.ClearMemoryCache(url)); + + ref0.Dispose(); + Assert.IsNull(ref0.Value); + Assert.AreEqual(1, Reference.Counter(url)); + ref1.Dispose(); + Assert.IsNull(ref1.Value); + Assert.AreEqual(0, Reference.Counter(url)); + + var sprite = ImageLoader.LoadSpriteFromMemoryCache(url); + Assert.IsNull(sprite); + + ImageLoader.ClearMemoryCache(url); + Assert.AreEqual(0, Reference.Counter(url)); + } + [UnityTest] public IEnumerator Loading2RefAndDisposeAll_NoLogs() => TestUtils.RunNoLogs(Loading2RefAndDisposeAll); + [UnityTest] public IEnumerator Loading2RefAndDisposeAll() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var future1 = ImageLoader.LoadSpriteRef(url); + Assert.IsNotNull(future1); + var future2 = ImageLoader.LoadSpriteRef(url); + Assert.IsNotNull(future2); + + Assert.AreEqual(0, Reference.Counter(url)); + + future1.Cancel(); + future2.Cancel(); + + future1.Dispose(); + future2.Dispose(); + + Assert.AreEqual(0, Reference.Counter(url)); + yield return TestUtils.Wait(TimeSpan.FromSeconds(1)); + Assert.AreEqual(0, Reference.Counter(url)); + } + [UnityTest] public IEnumerator DisposeOnOutDisposingBlock_NoLogs() => TestUtils.RunNoLogs(DisposeOnOutDisposingBlock); + [UnityTest] public IEnumerator DisposeOnOutDisposingBlock() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + var future1 = ImageLoader.LoadSpriteRef(url); + var task1 = future1.AsTask(); + Assert.AreEqual(0, Reference.Counter(url)); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + using (var ref1 = task1.Result) + { + Assert.AreEqual(1, Reference.Counter(url)); + } + Assert.AreEqual(0, Reference.Counter(url)); + } + foreach (var url in TestUtils.ImageURLs) + { + Assert.AreEqual(0, Reference.Counter(url), $"Should be zero references to URL={url}"); + } + } + [UnityTest] public IEnumerator DisposeOnOutDisposingBlock2_NoLogs() => TestUtils.RunNoLogs(DisposeOnOutDisposingBlock2); + [UnityTest] public IEnumerator DisposeOnOutDisposingBlock2() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + var future1 = ImageLoader.LoadSpriteRef(url); + var task1 = future1.AsTask(); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + Assert.AreEqual(1, Reference.Counter(url)); + + var ref1 = future1.Value; + ref1.Dispose(); + Assert.AreEqual(0, Reference.Counter(url)); + } + foreach (var url in TestUtils.ImageURLs) + { + Assert.AreEqual(0, Reference.Counter(url), $"Should be zero references to URL={url}"); + } + } + [UnityTest] public IEnumerator DisposeOnOutDisposingBlock3_NoLogs() => TestUtils.RunNoLogs(DisposeOnOutDisposingBlock3); + [UnityTest] public IEnumerator DisposeOnOutDisposingBlock3() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + var future1 = ImageLoader.LoadSpriteRef(url); + var task1 = future1.AsTask(); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + Assert.AreEqual(1, Reference.Counter(url)); + + future1.Value.Dispose(); + Assert.AreEqual(0, Reference.Counter(url)); + + var future2 = ImageLoader.LoadSpriteRef(url); + var task2 = future2.AsTask(); + yield return task2.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + using (var ref2 = task2.Result) + { + Assert.AreEqual(1, Reference.Counter(url)); + } + Assert.AreEqual(0, Reference.Counter(url)); + } + foreach (var url in TestUtils.ImageURLs) + { + Assert.AreEqual(0, Reference.Counter(url), $"Should be zero references to URL={url}"); + } + } + + [UnityTest] public IEnumerator EventFailedWithIncorrectUrlAndTimeout_NoLogs() => TestUtils.RunNoLogs(EventFailedWithIncorrectUrlAndTimeout); + [UnityTest] public IEnumerator EventFailedWithIncorrectUrlAndTimeout() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.IncorrectImageURL; + var exception = default(Exception); + var startTime = DateTime.Now; + var future1 = ImageLoader.LoadSprite(url) + .Timeout(TimeSpan.FromSeconds(0.1f)) + .Failed(e => exception = e); + + Assert.IsNull(exception); + + LogAssert.ignoreFailingMessages = true; + yield return TestUtils.Wait(TimeSpan.FromSeconds(2)); + var task1 = future1.AsTask(); + Assert.IsTrue(task1.IsCompleted); + Assert.IsNotNull(exception); + + future1.Cancel(); // expected warning + LogAssert.ignoreFailingMessages = false; + yield return TestUtils.Wait(TimeSpan.FromSeconds(2)); + future1.Dispose(); + } + [UnityTest] public IEnumerator EventFailedWithIncorrectUrlNotCalledBecauseOfCancel_NoLogs() => TestUtils.RunNoLogs(EventFailedWithIncorrectUrlNotCalledBecauseOfCancel); + [UnityTest] public IEnumerator EventFailedWithIncorrectUrlNotCalledBecauseOfCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.IncorrectImageURL; + var exception = default(Exception); + var startTime = DateTime.Now; + var future1 = ImageLoader.LoadSprite(url) + .Failed(e => exception = e); + + Assert.IsNull(exception); + + var task1 = future1.AsTask(); + future1.Cancel(); + + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + yield return TestUtils.Wait(TimeSpan.FromSeconds(1)); + Assert.IsNull(exception); + future1.Dispose(); + } + [UnityTest] public IEnumerator AsyncOperationCompletion_NoLogs() => TestUtils.RunNoLogs(AsyncOperationCompletion); + [UnityTest] public IEnumerator AsyncOperationCompletion() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + var completed = false; + yield return ImageLoader.LoadSprite(url) + .Completed(success => completed = true) + .TimeoutCoroutine(TimeSpan.FromSeconds(10)); + + Assert.IsTrue(completed); + } + yield return TestUtils.Wait(TimeSpan.FromSeconds(1)); + } + [UnityTest] public IEnumerator AsyncOperationCompletionAfterCancel_NoLogs() => TestUtils.RunNoLogs(AsyncOperationCompletionAfterCancel); + [UnityTest] public IEnumerator AsyncOperationCompletionAfterCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + yield return TestUtils.LoadAndCancel(url, FutureLoadingFrom.Source); + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFuture.cs.meta new file mode 100644 index 0000000..85b73f4 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 894b315b837b07e498ee88f02ff15a86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs b/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs new file mode 100644 index 0000000..356230a --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs @@ -0,0 +1,94 @@ +using NUnit.Framework; +using Cysharp.Threading.Tasks; +using UnityEngine.TestTools; +using System.Collections; +using UnityEngine; +using System; +using Extensions.Unity.ImageLoader.Tests.Utils; +using System.Collections.Generic; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public class TestFutureOrder : Test + { + [UnitySetUp] public override IEnumerator SetUp() => base.SetUp(); + [UnityTearDown] public override IEnumerator TearDown() => base.TearDown(); + + [UnityTest] public IEnumerator EventsLoadedWhenClear_NoLogs() => TestUtils.RunNoLogs(EventsLoadedWhenClear); + [UnityTest] public IEnumerator EventsLoadedWhenClear() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + var startTime = DateTime.Now; + + var future = new FutureSprite(url); + var futureListener = new FutureListener(future); + var task = future.StartLoading().AsTask(); + yield return task.TimeoutCoroutine(TimeSpan.FromSeconds(10)); + + futureListener.Assert_Events_Equals(new List + { + EventName.LoadingFromSource, + EventName.LoadedFromSource, + EventName.Then, + EventName.Completed + }); + futureListener.Assert_Events_Value(EventName.LoadedFromSource, sprite => sprite != null); + futureListener.Assert_Events_Value(EventName.Then, sprite => sprite != null); + futureListener.Assert_Events_Value(EventName.Completed, success => ((bool)success) == true); + futureListener.Assert_Events_NotContains(EventName.Canceled); + + var task1 = future.AsTask(); + Assert.True(task1.IsCompleted); + Assert.AreEqual(FutureStatus.LoadedFromSource, future.Status); + + future.Cancel(); + Assert.AreEqual(FutureStatus.LoadedFromSource, future.Status); + + Assert.True(future.AsTask().IsCompleted); + Assert.AreEqual(FutureStatus.LoadedFromSource, future.Status); + + future.Dispose(); + } + [UnityTest] public IEnumerator EventsFailedWhenClear_NoLogs() => TestUtils.RunNoLogs(EventsFailedWhenClear); + [UnityTest] public IEnumerator EventsFailedWhenClear() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.IncorrectImageURL; + var startTime = DateTime.Now; + + var future = new FutureSprite(url); + var futureListener = new FutureListener(future); + future.Timeout(TimeSpan.FromMilliseconds(100)); + + LogAssert.ignoreFailingMessages = true; + yield return future.StartLoading().TimeoutCoroutine(TimeSpan.FromSeconds(10)); + LogAssert.ignoreFailingMessages = false; + + futureListener.Assert_Events_Equals(new List + { + EventName.LoadingFromSource, + EventName.Failed, + EventName.Completed + }); + futureListener.Assert_Events_Value(EventName.Completed, success => ((bool)success) == false); + futureListener.Assert_Events_NotContains(EventName.Canceled); + + var task1 = future.AsTask(); + Assert.True(task1.IsCompleted); + Assert.AreEqual(FutureStatus.FailedToLoad, future.Status); + + future.Cancel(); + Assert.AreEqual(FutureStatus.FailedToLoad, future.Status); + + Assert.True(future.AsTask().IsCompleted); + Assert.AreEqual(FutureStatus.FailedToLoad, future.Status); + + future.Dispose(); + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs.meta new file mode 100644 index 0000000..e51d0e8 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af3b53b3d23b9694bb437e1678c8aa52 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.AndCancel.cs b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.AndCancel.cs new file mode 100644 index 0000000..e3b9a6a --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.AndCancel.cs @@ -0,0 +1,62 @@ +using System.Linq; +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; +using UnityEngine; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFutureWaitingAnotherFuture + { + [UnityTest] public IEnumerator LoadFrom_Source_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source_AndCancel); + [UnityTest] public IEnumerator LoadFrom_Source_AndCancel() + { + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: true); + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: false); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: true); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: false); + } + IEnumerator LoadFrom_Source_AndCancel(bool useDiskCache, bool useMemoryCache) + { + ImageLoader.settings.useDiskCache = useDiskCache; + ImageLoader.settings.useMemoryCache = useMemoryCache; + + foreach (var url in TestUtils.ImageURLs) + { + var future = ImageLoader.LoadSprite(url); + yield return TestUtils.LoadAndCancel(url, FutureLoadingFrom.Source); + future.Dispose(); + } + + yield return TestUtils.ClearEverything(message: null); + } + [UnityTest] public IEnumerator LoadFrom_MemoryCache_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache_AndCancel); + [UnityTest] public IEnumerator LoadFrom_MemoryCache_AndCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + ImageLoader.LoadSprite(url); + yield return TestUtils.LoadFromMemoryCacheAndCancel(url); + } + } + + [UnityTest] public IEnumerator LoadFrom_DiskCache_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache_AndCancel); + [UnityTest] public IEnumerator LoadFrom_DiskCache_AndCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = false; + + // foreach (var url in TestUtils.ImageURLs.SelectMany(x => Enumerable.Repeat(x, 100)).OrderBy(x => Random.value)) + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + ImageLoader.LoadSprite(url); + yield return TestUtils.LoadAndCancel(url, FutureLoadingFrom.DiskCache); + } + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.AndCancel.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.AndCancel.cs.meta new file mode 100644 index 0000000..f5d6929 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.AndCancel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ee81f6ced8d94e45aa31cc3a94be220 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.ThenCancel.cs b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.ThenCancel.cs new file mode 100644 index 0000000..45ceefc --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.ThenCancel.cs @@ -0,0 +1,80 @@ +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFutureWaitingAnotherFuture + { + [UnityTest] public IEnumerator LoadFrom_Source_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source_ThenCancel); + [UnityTest] public IEnumerator LoadFrom_Source_ThenCancel() + { + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: true); + + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: false); + } + IEnumerator LoadFrom_Source_ThenCancel(bool useDiskCache, bool useMemoryCache, bool useGC) + { + ImageLoader.settings.useDiskCache = useDiskCache; + ImageLoader.settings.useMemoryCache = useMemoryCache; + + foreach (var url in TestUtils.ImageURLs) + { + ImageLoader.LoadSprite(url); + yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source, useGC); + } + + yield return TestUtils.ClearEverything(message: null); + } + + [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache_ThenCancel); + [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + ImageLoader.LoadSprite(url); + yield return TestUtils.LoadFromMemoryCacheThenCancel(url, useGC: true); + } + // TODO: remove code duplicate + yield return TestUtils.ClearEverything(message: null); + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + ImageLoader.LoadSprite(url); + yield return TestUtils.LoadFromMemoryCacheThenCancel(url, useGC: false); + } + } + + [UnityTest] public IEnumerator LoadFrom_DiskCache_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache_ThenCancel); + [UnityTest] public IEnumerator LoadFrom_DiskCache_ThenCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = false; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + ImageLoader.LoadSprite(url); + yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, useGC: true); + } + // TODO: remove code duplicate + yield return TestUtils.ClearEverything(message: null); + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + ImageLoader.LoadSprite(url); + yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, useGC: false); + } + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.ThenCancel.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.ThenCancel.cs.meta new file mode 100644 index 0000000..61ffb12 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.ThenCancel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d7867e9e8d17bdd449365c699ed09690 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.cs b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.cs new file mode 100644 index 0000000..d2a112a --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.cs @@ -0,0 +1,59 @@ +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFutureWaitingAnotherFuture + { + [UnityTest] public IEnumerator LoadFrom_Source_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source); + [UnityTest] public IEnumerator LoadFrom_Source() + { + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: true); + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: false); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: true); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: false); + } + IEnumerator LoadFrom_Source(bool useDiskCache, bool useMemoryCache) + { + ImageLoader.settings.useDiskCache = useDiskCache; + ImageLoader.settings.useMemoryCache = useMemoryCache; + + foreach (var url in TestUtils.ImageURLs) + { + ImageLoader.LoadSprite(url); + yield return TestUtils.Load(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source); + } + + yield return TestUtils.ClearEverything(message: null); + } + + [UnityTest] public IEnumerator LoadFrom_DiskCache_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache); + [UnityTest] public IEnumerator LoadFrom_DiskCache() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = false; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + ImageLoader.LoadSprite(url); + yield return TestUtils.Load(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache); + } + } + + [UnityTest] public IEnumerator LoadFrom_MemoryCache_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache); + [UnityTest] public IEnumerator LoadFrom_MemoryCache() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + ImageLoader.LoadSprite(url); + yield return TestUtils.LoadFromMemoryCache(url); + } + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.cs.meta new file mode 100644 index 0000000..6287b94 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.Load.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7351803d1c78dc94aaa73c57093f3ff3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.LoadFail.cs b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.LoadFail.cs new file mode 100644 index 0000000..3c7fa84 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.LoadFail.cs @@ -0,0 +1,32 @@ +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFutureWaitingAnotherFuture + { + [UnityTest] public IEnumerator LoadFailFrom_Source_NoLogs() => TestUtils.RunNoLogs(LoadFailFrom_Source); + [UnityTest] public IEnumerator LoadFailFrom_Source() + { + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: true); + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: false); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: true); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: false); + } + IEnumerator LoadFailFrom_Source(bool useDiskCache, bool useMemoryCache) + { + ImageLoader.settings.useDiskCache = useDiskCache; + ImageLoader.settings.useMemoryCache = useMemoryCache; + + foreach (var url in TestUtils.IncorrectImageURLs()) + { + var future = ImageLoader.LoadSprite(url); + yield return TestUtils.LoadFail(url, FutureLoadingFrom.Source); + future.Dispose(); + } + + yield return TestUtils.ClearEverything(message: null); + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.LoadFail.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.LoadFail.cs.meta new file mode 100644 index 0000000..98e3e98 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.LoadFail.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0696139d5fea42b4c92741767da1d855 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.cs b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.cs new file mode 100644 index 0000000..f5117cc --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.cs @@ -0,0 +1,11 @@ +using UnityEngine.TestTools; +using System.Collections; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFutureWaitingAnotherFuture : Test + { + [UnitySetUp] public override IEnumerator SetUp() => base.SetUp(); + [UnityTearDown] public override IEnumerator TearDown() => base.TearDown(); + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.cs.meta new file mode 100644 index 0000000..7bc434d --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureWaitingAnotherFuture.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0415ebd124cd7e34b9530d71fa9b0f1c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestLoading.Sprite.cs b/Assets/_PackageRoot/Tests/Runtime/TestLoading.Sprite.cs new file mode 100644 index 0000000..6b5a8d7 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestLoading.Sprite.cs @@ -0,0 +1,55 @@ +using NUnit.Framework; +using Cysharp.Threading.Tasks; +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; +using System; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestLoading : Test + { + public async UniTask LoadSprite(string url) + { + var sprite = await ImageLoader.LoadSprite(url); + Assert.IsNotNull(sprite); + } + + [UnityTest] public IEnumerator LoadSpritesCacheMemoryDisk_NoLogs() => TestUtils.RunNoLogs(LoadSpritesCacheMemoryDisk); + [UnityTest] public IEnumerator LoadSpritesCacheMemoryDisk() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var imageURL in TestUtils.ImageURLs) + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + } + [UnityTest] public IEnumerator LoadSpritesCacheMemory_NoLogs() => TestUtils.RunNoLogs(LoadSpritesCacheMemory); + [UnityTest] public IEnumerator LoadSpritesCacheMemory() + { + ImageLoader.settings.useDiskCache = false; + ImageLoader.settings.useMemoryCache = true; + + foreach (var imageURL in TestUtils.ImageURLs) + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + } + [UnityTest] public IEnumerator LoadSpritesCacheDisk_NoLogs() => TestUtils.RunNoLogs(LoadSpritesCacheDisk); + [UnityTest] public IEnumerator LoadSpritesCacheDisk() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = false; + + foreach (var imageURL in TestUtils.ImageURLs) + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + } + [UnityTest] public IEnumerator LoadSpritesNoCache_NoLogs() => TestUtils.RunNoLogs(LoadSpritesNoCache); + [UnityTest] public IEnumerator LoadSpritesNoCache() + { + ImageLoader.settings.useDiskCache = false; + ImageLoader.settings.useMemoryCache = false; + + foreach (var imageURL in TestUtils.ImageURLs) + yield return LoadSprite(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestLoading.Sprite.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestLoading.Sprite.cs.meta new file mode 100644 index 0000000..5eaa24b --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestLoading.Sprite.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd1a54ed7db82824b9370ddebfc18c01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestLoading.Texture.cs b/Assets/_PackageRoot/Tests/Runtime/TestLoading.Texture.cs new file mode 100644 index 0000000..0031930 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestLoading.Texture.cs @@ -0,0 +1,55 @@ +using NUnit.Framework; +using Cysharp.Threading.Tasks; +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; +using System; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestLoading : Test + { + public async UniTask LoadTextureTexture(string url) + { + var texture = await ImageLoader.LoadTexture(url); + Assert.IsNotNull(texture); + } + + [UnityTest] public IEnumerator LoadTextureTexturesCacheMemoryDisk_NoLogs() => TestUtils.RunNoLogs(LoadTextureTexturesCacheMemoryDisk); + [UnityTest] public IEnumerator LoadTextureTexturesCacheMemoryDisk() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var imageURL in TestUtils.ImageURLs) + yield return LoadTextureTexture(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + } + [UnityTest] public IEnumerator LoadTextureTexturesCacheMemory_NoLogs() => TestUtils.RunNoLogs(LoadTextureTexturesCacheMemory); + [UnityTest] public IEnumerator LoadTextureTexturesCacheMemory() + { + ImageLoader.settings.useDiskCache = false; + ImageLoader.settings.useMemoryCache = true; + + foreach (var imageURL in TestUtils.ImageURLs) + yield return LoadTextureTexture(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + } + [UnityTest] public IEnumerator LoadTextureTexturesCacheDisk_NoLogs() => TestUtils.RunNoLogs(LoadTextureTexturesCacheDisk); + [UnityTest] public IEnumerator LoadTextureTexturesCacheDisk() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = false; + + foreach (var imageURL in TestUtils.ImageURLs) + yield return LoadTextureTexture(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + } + [UnityTest] public IEnumerator LoadTextureTexturesNoCache_NoLogs() => TestUtils.RunNoLogs(LoadTextureTexturesNoCache); + [UnityTest] public IEnumerator LoadTextureTexturesNoCache() + { + ImageLoader.settings.useDiskCache = false; + ImageLoader.settings.useMemoryCache = false; + + foreach (var imageURL in TestUtils.ImageURLs) + yield return LoadTextureTexture(imageURL).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestLoading.Texture.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestLoading.Texture.cs.meta new file mode 100644 index 0000000..69e4b93 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestLoading.Texture.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 431d370810c79d1488e0f1cb51a5e40a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestLoading.cs b/Assets/_PackageRoot/Tests/Runtime/TestLoading.cs new file mode 100644 index 0000000..d33926a --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestLoading.cs @@ -0,0 +1,11 @@ +using UnityEngine.TestTools; +using System.Collections; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestLoading : Test + { + [UnitySetUp] public override IEnumerator SetUp() => base.SetUp(); + [UnityTearDown] public override IEnumerator TearDown() => base.TearDown(); + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestLoading.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestLoading.cs.meta new file mode 100644 index 0000000..f9e74a2 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestLoading.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8480b3de3fda094087dcd71048c609f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestReference.cs b/Assets/_PackageRoot/Tests/Runtime/TestReference.cs new file mode 100644 index 0000000..07e8a54 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestReference.cs @@ -0,0 +1,415 @@ +using System; +using System.Linq; +using System.Collections; +using NUnit.Framework; +using Cysharp.Threading.Tasks; +using UnityEngine.TestTools; +using UnityEngine; +using System.Threading.Tasks; +using Extensions.Unity.ImageLoader.Tests.Utils; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public class TestReference : Test + { + [UnitySetUp] public override IEnumerator SetUp() => base.SetUp(); + [UnityTearDown] public override IEnumerator TearDown() => base.TearDown(); + + [UnityTest] public IEnumerator CleanMemoryCache_NoLogs() => TestUtils.RunNoLogs(CleanMemoryCache); + [UnityTest] public IEnumerator CleanMemoryCache() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var task1 = ImageLoader.LoadSpriteRef(url).AsTask(); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var ref0 = task1.Result; + Assert.AreEqual(1, Reference.Counter(url)); + + Assert.Throws(() => ImageLoader.ClearMemoryCache(url)); + Assert.IsNotNull(ref0.Value); + Assert.AreEqual(1, Reference.Counter(url)); + + ref0.Dispose(); + Assert.IsNull(ref0.Value); + Assert.AreEqual(0, Reference.Counter(url)); + } + + [UnityTest] public IEnumerator DisposeOnOutOfScope_NoLogs() => TestUtils.RunNoLogs(DisposeOnOutOfScope); + [UnityTest] public IEnumerator DisposeOnOutOfScope() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + { // scope + var task = ImageLoader.LoadSpriteRef(url).AsTask(); + yield return task.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var reference = task.Result; + Assert.NotNull(reference); + Assert.AreEqual(1, Reference.Counter(url)); + } // end of scope + + yield return TestUtils.WaitForGC(); + yield return TestUtils.WaitForGC(); + yield return TestUtils.WaitForGC(); + Assert.AreEqual(0, Reference.Counter(url)); + } + + [UnityTest] public IEnumerator DisposeOnOutOfScope2() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var futureRef = ImageLoader.LoadSpriteRef(url); + while (futureRef.IsInProgress) + yield return UniTask.Yield(); + + var reference = futureRef.Value; + Assert.NotNull(reference); + Assert.AreEqual(1, Reference.Counter(url)); + + futureRef = null; + reference = null; + + yield return TestUtils.WaitForGC(); + yield return TestUtils.WaitForGC(); + yield return TestUtils.WaitForGC(); + Assert.AreEqual(0, Reference.Counter(url)); + } + + [UnityTest] public IEnumerator DisposeOnOutOfScopeAll_NoLogs() => TestUtils.RunNoLogs(DisposeOnOutOfScopeAll); + [UnityTest] public IEnumerator DisposeOnOutOfScopeAll() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + var future = ImageLoader.LoadSpriteRef(url); + yield return future.TimeoutCoroutine(TimeSpan.FromSeconds(10)); + + Assert.True(future.IsLoaded); + Assert.True(future.IsCompleted); + var reference = future.Value; + Assert.NotNull(reference); + Assert.NotNull(reference.Value); + Assert.AreEqual(1, Reference.Counter(url)); + } + + yield return TestUtils.WaitForGC(); + yield return TestUtils.WaitForGC(); + yield return TestUtils.WaitForGC(); + + foreach (var url in TestUtils.ImageURLs) + Assert.AreEqual(0, Reference.Counter(url)); + } + [UnityTest] public IEnumerator DisposeOnOutDisposingBlock_NoLogs() => TestUtils.RunNoLogs(DisposeOnOutDisposingBlock); + [UnityTest] public IEnumerator DisposeOnOutDisposingBlock() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + var future = ImageLoader.LoadSpriteRef(url); + yield return future.TimeoutCoroutine(TimeSpan.FromSeconds(10)); + + using (var reference = future.Value) + { + Assert.AreEqual(1, Reference.Counter(url)); + } + Assert.AreEqual(0, Reference.Counter(url)); + } + foreach (var url in TestUtils.ImageURLs) + { + Assert.AreEqual(0, Reference.Counter(url)); + } + } + + [UnityTest] public IEnumerator CleanMemoryCacheAll_NoLogs() => TestUtils.RunNoLogs(CleanMemoryCacheAll); + [UnityTest] public IEnumerator CleanMemoryCacheAll() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var future = ImageLoader.LoadSpriteRef(url); + yield return future.TimeoutCoroutine(TimeSpan.FromSeconds(10)); + + var ref0 = future.Value; + Assert.AreEqual(1, Reference.Counter(url)); + + LogAssert.Expect(LogType.Error, $"[ImageLoader] There are 1 references to the object, clear them first. URL={url}"); + ImageLoader.ClearMemoryCacheAll(); + + Assert.IsNotNull(ref0.Value); + Assert.AreEqual(1, Reference.Counter(url)); + + ref0.Dispose(); + Assert.IsNull(ref0.Value); + Assert.AreEqual(0, Reference.Counter(url)); + } + + [UnityTest] public IEnumerator LoadOneMake1000ReferencesLaterDispose_NoLogs() => TestUtils.RunNoLogs(LoadOneMake1000ReferencesLaterDispose); + [UnityTest] public IEnumerator LoadOneMake1000ReferencesLaterDispose() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var task1 = ImageLoader.LoadSpriteRef(url).AsTask(); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var ref1_1 = task1.Result; + Assert.NotNull(ref1_1); + Assert.AreEqual(1, Reference.Counter(url)); + + var count = 1000; + var references = new Reference[count]; + for (var i = 0; i < count; i++) + { + var reference = ImageLoader.LoadSpriteRefFromMemoryCache(url); + Assert.NotNull(reference); + Assert.AreEqual(i + 2, Reference.Counter(url)); + references[i] = reference; + } + + ref1_1.Dispose(); + Assert.AreEqual(count, Reference.Counter(url)); + + for (var i = 0; i < count; i++) + { + references[i].Dispose(); + Assert.AreEqual(count - i - 1, Reference.Counter(url)); + } + } + + [UnityTest] public IEnumerator KeepReferenceButDisposeFuture_NoLogs() => TestUtils.RunNoLogs(KeepReferenceButDisposeFuture); + [UnityTest] public IEnumerator KeepReferenceButDisposeFuture() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var future = ImageLoader.LoadSpriteRef(url); + var task1 = future.AsTask(); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + Assert.AreEqual(1, Reference.Counter(url)); + + var ref1 = task1.Result; + Assert.NotNull(ref1); + Assert.AreEqual(1, Reference.Counter(url)); + + future.Dispose(); + Assert.AreEqual(1, Reference.Counter(url)); + + ref1.Dispose(); + Assert.AreEqual(0, Reference.Counter(url)); + } + + [UnityTest] public IEnumerator LoadOneMake1000ReferencesImmediateDispose_NoLogs() => TestUtils.RunNoLogs(LoadOneMake1000ReferencesImmediateDispose); + [UnityTest] public IEnumerator LoadOneMake1000ReferencesImmediateDispose() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var future = ImageLoader.LoadSpriteRef(url); + var task1 = future.AsTask(); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var ref1_1 = task1.Result; + Assert.NotNull(ref1_1); + Assert.AreEqual(1, Reference.Counter(url)); + + var count = 1000; + for (var i = 0; i < count; i++) + { + Assert.AreEqual(1, Reference.Counter(url), $"ref[{i}] going to create."); + + var reference = ImageLoader.LoadSpriteRefFromMemoryCache(url); + Assert.NotNull(reference); + Assert.AreEqual(2, Reference.Counter(url), $"ref[{i}] is created, but reference counter is wrong."); + + reference.Dispose(); + Assert.AreEqual(1, Reference.Counter(url), $"ref[{i}] is disposed, but it should be still in memory cache because of another ref."); + } + Assert.AreEqual(1, Reference.Counter(url)); + + future.Dispose(); + Assert.AreEqual(1, Reference.Counter(url)); + + ref1_1.Dispose(); + Assert.AreEqual(0, Reference.Counter(url)); + } + + [UnityTest] public IEnumerator LoadOneMake1000ReferencesInParallelLateDispose_NoLogs() => TestUtils.RunNoLogs(LoadOneMake1000ReferencesInParallelLateDispose); + [UnityTest] public IEnumerator LoadOneMake1000ReferencesInParallelLateDispose() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var task1 = ImageLoader.LoadSpriteRef(url).AsTask(); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var ref1_1 = task1.Result; + Assert.NotNull(ref1_1); + Assert.AreEqual(1, Reference.Counter(url)); + + var count = 1000; + var references = new Reference[count]; + var tasks = Enumerable.Range(0, count) + .Select(i => Task.Run(() => + { + var reference = ImageLoader.LoadSpriteRefFromMemoryCache(url); + Assert.NotNull(reference); + references[i] = reference; + return reference; + })) + .ToArray(); + + yield return Task.WhenAll(tasks).TimeoutCoroutine(TimeSpan.FromSeconds(10)); + Assert.AreEqual(count + 1, Reference.Counter(url)); + + foreach (var reference in references) + reference.Dispose(); + Assert.AreEqual(1, Reference.Counter(url)); + + ref1_1.Dispose(); + Assert.AreEqual(0, Reference.Counter(url)); + } + + [UnityTest] public IEnumerator Load1Sprite2TimesAnd2TimesFromCache_NoLogs() => TestUtils.RunNoLogs(Load1Sprite2TimesAnd2TimesFromCache); + [UnityTest] public IEnumerator Load1Sprite2TimesAnd2TimesFromCache() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + + var task1 = ImageLoader.LoadSpriteRef(url).AsTask(); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var ref0 = task1.Result; + Assert.AreEqual(1, Reference.Counter(url)); + + var task2 = ImageLoader.LoadSpriteRef(url).AsTask(); + yield return task2.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var ref1 = task2.Result; + Assert.AreEqual(2, Reference.Counter(url)); + + var ref2 = ImageLoader.LoadSpriteRefFromMemoryCache(url); + Assert.AreEqual(3, Reference.Counter(url)); + + var ref3 = ImageLoader.LoadSpriteRefFromMemoryCache(url); + Assert.AreEqual(4, Reference.Counter(url)); + + ref0.Dispose(); + Assert.AreEqual(3, Reference.Counter(url)); + Assert.IsNull(ref0.Value); + Assert.IsNotNull(ref1.Value); + Assert.IsNotNull(ref2.Value); + Assert.IsNotNull(ref3.Value); + + ref1.Dispose(); + Assert.AreEqual(2, Reference.Counter(url)); + Assert.IsNull(ref0.Value); + Assert.IsNull(ref1.Value); + Assert.IsNotNull(ref2.Value); + Assert.IsNotNull(ref3.Value); + + ref2.Dispose(); + Assert.AreEqual(1, Reference.Counter(url)); + Assert.IsNull(ref0.Value); + Assert.IsNull(ref1.Value); + Assert.IsNull(ref2.Value); + Assert.IsNotNull(ref3.Value); + + ref3.Dispose(); + Assert.AreEqual(0, Reference.Counter(url)); + Assert.IsNull(ref0.Value); + Assert.IsNull(ref1.Value); + Assert.IsNull(ref2.Value); + Assert.IsNull(ref3.Value); + } + + [UnityTest] public IEnumerator Load2SpritesTimesAnd2TimesFromCache_NoLogs() => TestUtils.RunNoLogs(Load2SpritesTimesAnd2TimesFromCache); + [UnityTest] public IEnumerator Load2SpritesTimesAnd2TimesFromCache() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + var url = TestUtils.ImageURLs[0]; + var url2 = TestUtils.ImageURLs[1]; + + var task1 = ImageLoader.LoadSpriteRef(url).AsTask(); + yield return task1.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var ref1_1 = task1.Result; + Assert.NotNull(ref1_1); + Assert.AreEqual(1, Reference.Counter(url)); + + var task2 = ImageLoader.LoadSpriteRef(url2).AsTask(); + yield return task2.TimeoutCoroutine(TimeSpan.FromSeconds(25)); + + var ref2_1 = task2.Result; + Assert.NotNull(ref2_1); + Assert.AreEqual(1, Reference.Counter(url2)); + + var ref1_2 = ImageLoader.LoadSpriteRefFromMemoryCache(url); + Assert.NotNull(ref1_2); + Assert.AreEqual(2, Reference.Counter(url)); + + var ref2_2 = ImageLoader.LoadSpriteRefFromMemoryCache(url2); + Assert.NotNull(ref2_2); + Assert.AreEqual(2, Reference.Counter(url2)); + + ref1_1.Dispose(); + Assert.AreEqual(1, Reference.Counter(url)); + Assert.AreEqual(2, Reference.Counter(url2)); + Assert.IsNull(ref1_1.Value); + Assert.IsNotNull(ref2_1.Value); + Assert.IsNotNull(ref1_2.Value); + Assert.IsNotNull(ref2_2.Value); + + ref2_1.Dispose(); + Assert.AreEqual(1, Reference.Counter(url)); + Assert.AreEqual(1, Reference.Counter(url2)); + Assert.IsNull(ref1_1.Value); + Assert.IsNull(ref2_1.Value); + Assert.IsNotNull(ref1_2.Value); + Assert.IsNotNull(ref2_2.Value); + + ref1_2.Dispose(); + Assert.AreEqual(0, Reference.Counter(url)); + Assert.AreEqual(1, Reference.Counter(url2)); + Assert.IsNull(ref1_1.Value); + Assert.IsNull(ref2_1.Value); + Assert.IsNull(ref1_2.Value); + Assert.IsNotNull(ref2_2.Value); + + ref2_2.Dispose(); + Assert.AreEqual(0, Reference.Counter(url)); + Assert.AreEqual(0, Reference.Counter(url2)); + Assert.IsNull(ref1_1.Value); + Assert.IsNull(ref2_1.Value); + Assert.IsNull(ref1_2.Value); + Assert.IsNull(ref2_2.Value); + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestReference.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestReference.cs.meta new file mode 100644 index 0000000..2163208 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2395d12b483238641b2509bfc17f9bdd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From adba117973aa8f6ca73d140d7bc8c253e6827c1e Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Tue, 4 Mar 2025 23:53:17 -0800 Subject: [PATCH 04/33] Added Player and Build tests --- .github/workflows/2019.4.40f1_build.yml | 18 ++++++++++++++++++ .github/workflows/2019.4.40f1_player.yml | 18 ++++++++++++++++++ .github/workflows/2020.3.40f1_build.yml | 18 ++++++++++++++++++ .github/workflows/2020.3.40f1_player.yml | 18 ++++++++++++++++++ .github/workflows/2021.3.45f1_build.yml | 18 ++++++++++++++++++ .github/workflows/2021.3.45f1_player.yml | 18 ++++++++++++++++++ .github/workflows/2022.3.57f1_build.yml | 18 ++++++++++++++++++ .github/workflows/2022.3.57f1_player.yml | 18 ++++++++++++++++++ .github/workflows/2023.1.20f1_build.yml | 18 ++++++++++++++++++ .github/workflows/2023.1.20f1_player.yml | 18 ++++++++++++++++++ .github/workflows/2023.2.20f1_build.yml | 18 ++++++++++++++++++ .github/workflows/2023.2.20f1_player.yml | 18 ++++++++++++++++++ .github/workflows/6000.0.37f1_build.yml | 18 ++++++++++++++++++ .github/workflows/6000.0.37f1_player.yml | 18 ++++++++++++++++++ .vscode/settings.json | 1 + Assets/_PackageRoot/Documentation~/README.md | 10 +++++++++- Assets/_PackageRoot/README.md | 10 +++++++++- README.md | 10 +++++++++- 18 files changed, 280 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/2019.4.40f1_build.yml create mode 100644 .github/workflows/2019.4.40f1_player.yml create mode 100644 .github/workflows/2020.3.40f1_build.yml create mode 100644 .github/workflows/2020.3.40f1_player.yml create mode 100644 .github/workflows/2021.3.45f1_build.yml create mode 100644 .github/workflows/2021.3.45f1_player.yml create mode 100644 .github/workflows/2022.3.57f1_build.yml create mode 100644 .github/workflows/2022.3.57f1_player.yml create mode 100644 .github/workflows/2023.1.20f1_build.yml create mode 100644 .github/workflows/2023.1.20f1_player.yml create mode 100644 .github/workflows/2023.2.20f1_build.yml create mode 100644 .github/workflows/2023.2.20f1_player.yml create mode 100644 .github/workflows/6000.0.37f1_build.yml create mode 100644 .github/workflows/6000.0.37f1_player.yml diff --git a/.github/workflows/2019.4.40f1_build.yml b/.github/workflows/2019.4.40f1_build.yml new file mode 100644 index 0000000..9b6ed50 --- /dev/null +++ b/.github/workflows/2019.4.40f1_build.yml @@ -0,0 +1,18 @@ +name: 2019.4.40f1-Build + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2019.4.40f1' + testMode: 'standalone' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/2019.4.40f1_player.yml b/.github/workflows/2019.4.40f1_player.yml new file mode 100644 index 0000000..6c6cdc0 --- /dev/null +++ b/.github/workflows/2019.4.40f1_player.yml @@ -0,0 +1,18 @@ +name: 2019.4.40f1-Player + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2019.4.40f1' + testMode: 'playmode' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/2020.3.40f1_build.yml b/.github/workflows/2020.3.40f1_build.yml new file mode 100644 index 0000000..ca61cae --- /dev/null +++ b/.github/workflows/2020.3.40f1_build.yml @@ -0,0 +1,18 @@ +name: 2020.3.40f1-Build + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2020.3.40f1' + testMode: 'standalone' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/2020.3.40f1_player.yml b/.github/workflows/2020.3.40f1_player.yml new file mode 100644 index 0000000..39507ec --- /dev/null +++ b/.github/workflows/2020.3.40f1_player.yml @@ -0,0 +1,18 @@ +name: 2020.3.40f1-Player + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2020.3.40f1' + testMode: 'playmode' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/2021.3.45f1_build.yml b/.github/workflows/2021.3.45f1_build.yml new file mode 100644 index 0000000..518a2c5 --- /dev/null +++ b/.github/workflows/2021.3.45f1_build.yml @@ -0,0 +1,18 @@ +name: 2021.3.45f1-Build + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2021.3.45f1' + testMode: 'standalone' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/2021.3.45f1_player.yml b/.github/workflows/2021.3.45f1_player.yml new file mode 100644 index 0000000..06ece99 --- /dev/null +++ b/.github/workflows/2021.3.45f1_player.yml @@ -0,0 +1,18 @@ +name: 2021.3.45f1-Player + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2021.3.45f1' + testMode: 'playmode' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/2022.3.57f1_build.yml b/.github/workflows/2022.3.57f1_build.yml new file mode 100644 index 0000000..f2bd778 --- /dev/null +++ b/.github/workflows/2022.3.57f1_build.yml @@ -0,0 +1,18 @@ +name: 2022.3.57f1-Build + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2022.3.57f1' + testMode: 'standalone' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/2022.3.57f1_player.yml b/.github/workflows/2022.3.57f1_player.yml new file mode 100644 index 0000000..33e85bb --- /dev/null +++ b/.github/workflows/2022.3.57f1_player.yml @@ -0,0 +1,18 @@ +name: 2022.3.57f1-Player + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2022.3.57f1' + testMode: 'playmode' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/2023.1.20f1_build.yml b/.github/workflows/2023.1.20f1_build.yml new file mode 100644 index 0000000..acc950d --- /dev/null +++ b/.github/workflows/2023.1.20f1_build.yml @@ -0,0 +1,18 @@ +name: 2023.1.20f1-Build + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2023.1.20f1' + testMode: 'standalone' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/2023.1.20f1_player.yml b/.github/workflows/2023.1.20f1_player.yml new file mode 100644 index 0000000..430b324 --- /dev/null +++ b/.github/workflows/2023.1.20f1_player.yml @@ -0,0 +1,18 @@ +name: 2023.1.20f1-Player + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2023.1.20f1' + testMode: 'playmode' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/2023.2.20f1_build.yml b/.github/workflows/2023.2.20f1_build.yml new file mode 100644 index 0000000..9aa513e --- /dev/null +++ b/.github/workflows/2023.2.20f1_build.yml @@ -0,0 +1,18 @@ +name: 2023.2.20f1-Build + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2023.2.20f1' + testMode: 'standalone' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/2023.2.20f1_player.yml b/.github/workflows/2023.2.20f1_player.yml new file mode 100644 index 0000000..43d7a3d --- /dev/null +++ b/.github/workflows/2023.2.20f1_player.yml @@ -0,0 +1,18 @@ +name: 2023.2.20f1-Player + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '2023.2.20f1' + testMode: 'playmode' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/6000.0.37f1_build.yml b/.github/workflows/6000.0.37f1_build.yml new file mode 100644 index 0000000..194e002 --- /dev/null +++ b/.github/workflows/6000.0.37f1_build.yml @@ -0,0 +1,18 @@ +name: 6000.0.37f1-Build + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '6000.0.37f1' + testMode: 'standalone' + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/6000.0.37f1_player.yml b/.github/workflows/6000.0.37f1_player.yml new file mode 100644 index 0000000..5573d53 --- /dev/null +++ b/.github/workflows/6000.0.37f1_player.yml @@ -0,0 +1,18 @@ +name: 6000.0.37f1-Player + +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + editor-tests: + uses: ./.github/workflows/main.yml + with: + projectPath: './' + unityVersion: '6000.0.37f1' + testMode: 'playmode' + secrets: inherit \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 3890346..2c7bb13 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -60,6 +60,7 @@ "imageloader", "Murzak", "openupm", + "playmode", "ugui", "unitask", "WEBGL" diff --git a/Assets/_PackageRoot/Documentation~/README.md b/Assets/_PackageRoot/Documentation~/README.md index 0bf57d3..d76caee 100644 --- a/Assets/_PackageRoot/Documentation~/README.md +++ b/Assets/_PackageRoot/Documentation~/README.md @@ -2,7 +2,15 @@ ![npm](https://img.shields.io/npm/v/extensions.unity.imageloader) [![openupm](https://img.shields.io/npm/v/extensions.unity.imageloader?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/extensions.unity.imageloader/) ![License](https://img.shields.io/github/license/IvanMurzak/Unity-ImageLoader) [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) -![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) +| Unity Version | Editor test | Player test | Build test | +|---------------|-------------|-------------|------------| +| 2019.4.40f1 | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_player.yml?label=2019.4.40f1-Player) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_build.yml?label=2019.4.40f1-Build) | +| 2020.3.40f1 | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_player.yml?label=2020.3.40f1-Player) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_build.yml?label=2020.3.40f1-Build) | +| 2021.3.45f1 | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_player.yml?label=2021.3.45f1-Player) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_build.yml?label=2021.3.45f1-Build) | +| 2022.3.57f1 | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_player.yml?label=2022.3.57f1-Player) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_build.yml?label=2022.3.57f1-Build) | +| 2023.1.20f1 | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_player.yml?label=2023.1.20f1-Player) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_build.yml?label=2023.1.20f1-Build) | +| 2023.2.20f1 | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_player.yml?label=2023.2.20f1-Player) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_build.yml?label=2023.2.20f1-Build) | +| 6000.0.37f1 | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_player.yml?label=6000.0.37f1-Player) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_build.yml?label=6000.0.37f1-Build) | Async image loader with two caching layers for Unity. It supports loading images from web or local paths and provides memory and disk caching to optimize performance. The package includes features for automatic image setting, cancellation handling, error handling, and lifecycle management. diff --git a/Assets/_PackageRoot/README.md b/Assets/_PackageRoot/README.md index 0bf57d3..d76caee 100644 --- a/Assets/_PackageRoot/README.md +++ b/Assets/_PackageRoot/README.md @@ -2,7 +2,15 @@ ![npm](https://img.shields.io/npm/v/extensions.unity.imageloader) [![openupm](https://img.shields.io/npm/v/extensions.unity.imageloader?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/extensions.unity.imageloader/) ![License](https://img.shields.io/github/license/IvanMurzak/Unity-ImageLoader) [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) -![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) +| Unity Version | Editor test | Player test | Build test | +|---------------|-------------|-------------|------------| +| 2019.4.40f1 | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_player.yml?label=2019.4.40f1-Player) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_build.yml?label=2019.4.40f1-Build) | +| 2020.3.40f1 | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_player.yml?label=2020.3.40f1-Player) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_build.yml?label=2020.3.40f1-Build) | +| 2021.3.45f1 | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_player.yml?label=2021.3.45f1-Player) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_build.yml?label=2021.3.45f1-Build) | +| 2022.3.57f1 | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_player.yml?label=2022.3.57f1-Player) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_build.yml?label=2022.3.57f1-Build) | +| 2023.1.20f1 | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_player.yml?label=2023.1.20f1-Player) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_build.yml?label=2023.1.20f1-Build) | +| 2023.2.20f1 | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_player.yml?label=2023.2.20f1-Player) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_build.yml?label=2023.2.20f1-Build) | +| 6000.0.37f1 | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_player.yml?label=6000.0.37f1-Player) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_build.yml?label=6000.0.37f1-Build) | Async image loader with two caching layers for Unity. It supports loading images from web or local paths and provides memory and disk caching to optimize performance. The package includes features for automatic image setting, cancellation handling, error handling, and lifecycle management. diff --git a/README.md b/README.md index 0bf57d3..d76caee 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,15 @@ ![npm](https://img.shields.io/npm/v/extensions.unity.imageloader) [![openupm](https://img.shields.io/npm/v/extensions.unity.imageloader?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/extensions.unity.imageloader/) ![License](https://img.shields.io/github/license/IvanMurzak/Unity-ImageLoader) [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) -![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) +| Unity Version | Editor test | Player test | Build test | +|---------------|-------------|-------------|------------| +| 2019.4.40f1 | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_player.yml?label=2019.4.40f1-Player) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_build.yml?label=2019.4.40f1-Build) | +| 2020.3.40f1 | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_player.yml?label=2020.3.40f1-Player) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_build.yml?label=2020.3.40f1-Build) | +| 2021.3.45f1 | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_player.yml?label=2021.3.45f1-Player) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_build.yml?label=2021.3.45f1-Build) | +| 2022.3.57f1 | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_player.yml?label=2022.3.57f1-Player) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_build.yml?label=2022.3.57f1-Build) | +| 2023.1.20f1 | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_player.yml?label=2023.1.20f1-Player) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_build.yml?label=2023.1.20f1-Build) | +| 2023.2.20f1 | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_player.yml?label=2023.2.20f1-Player) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_build.yml?label=2023.2.20f1-Build) | +| 6000.0.37f1 | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_player.yml?label=6000.0.37f1-Player) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_build.yml?label=6000.0.37f1-Build) | Async image loader with two caching layers for Unity. It supports loading images from web or local paths and provides memory and disk caching to optimize performance. The package includes features for automatic image setting, cancellation handling, error handling, and lifecycle management. From a8e8aaa580aa28aec8f20132991381ebde2608b9 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Tue, 4 Mar 2025 23:59:36 -0800 Subject: [PATCH 05/33] Fixed branch name in workflows --- .github/workflows/2019.4.40f1_build.yml | 4 ++-- .github/workflows/2019.4.40f1_player.yml | 4 ++-- .github/workflows/2020.3.40f1_build.yml | 4 ++-- .github/workflows/2020.3.40f1_player.yml | 4 ++-- .github/workflows/2021.3.45f1_build.yml | 4 ++-- .github/workflows/2021.3.45f1_player.yml | 4 ++-- .github/workflows/2022.3.57f1_build.yml | 4 ++-- .github/workflows/2022.3.57f1_player.yml | 4 ++-- .github/workflows/2023.1.20f1_build.yml | 4 ++-- .github/workflows/2023.1.20f1_player.yml | 4 ++-- .github/workflows/2023.2.20f1_build.yml | 4 ++-- .github/workflows/2023.2.20f1_player.yml | 4 ++-- .github/workflows/6000.0.37f1_build.yml | 4 ++-- .github/workflows/6000.0.37f1_player.yml | 4 ++-- 14 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.github/workflows/2019.4.40f1_build.yml b/.github/workflows/2019.4.40f1_build.yml index 9b6ed50..8d209c7 100644 --- a/.github/workflows/2019.4.40f1_build.yml +++ b/.github/workflows/2019.4.40f1_build.yml @@ -3,10 +3,10 @@ name: 2019.4.40f1-Build on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/2019.4.40f1_player.yml b/.github/workflows/2019.4.40f1_player.yml index 6c6cdc0..7171c53 100644 --- a/.github/workflows/2019.4.40f1_player.yml +++ b/.github/workflows/2019.4.40f1_player.yml @@ -3,10 +3,10 @@ name: 2019.4.40f1-Player on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/2020.3.40f1_build.yml b/.github/workflows/2020.3.40f1_build.yml index ca61cae..a376b6e 100644 --- a/.github/workflows/2020.3.40f1_build.yml +++ b/.github/workflows/2020.3.40f1_build.yml @@ -3,10 +3,10 @@ name: 2020.3.40f1-Build on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/2020.3.40f1_player.yml b/.github/workflows/2020.3.40f1_player.yml index 39507ec..cd86b5a 100644 --- a/.github/workflows/2020.3.40f1_player.yml +++ b/.github/workflows/2020.3.40f1_player.yml @@ -3,10 +3,10 @@ name: 2020.3.40f1-Player on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/2021.3.45f1_build.yml b/.github/workflows/2021.3.45f1_build.yml index 518a2c5..ee5c55f 100644 --- a/.github/workflows/2021.3.45f1_build.yml +++ b/.github/workflows/2021.3.45f1_build.yml @@ -3,10 +3,10 @@ name: 2021.3.45f1-Build on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/2021.3.45f1_player.yml b/.github/workflows/2021.3.45f1_player.yml index 06ece99..77b22c7 100644 --- a/.github/workflows/2021.3.45f1_player.yml +++ b/.github/workflows/2021.3.45f1_player.yml @@ -3,10 +3,10 @@ name: 2021.3.45f1-Player on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/2022.3.57f1_build.yml b/.github/workflows/2022.3.57f1_build.yml index f2bd778..a506a05 100644 --- a/.github/workflows/2022.3.57f1_build.yml +++ b/.github/workflows/2022.3.57f1_build.yml @@ -3,10 +3,10 @@ name: 2022.3.57f1-Build on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/2022.3.57f1_player.yml b/.github/workflows/2022.3.57f1_player.yml index 33e85bb..9cd081d 100644 --- a/.github/workflows/2022.3.57f1_player.yml +++ b/.github/workflows/2022.3.57f1_player.yml @@ -3,10 +3,10 @@ name: 2022.3.57f1-Player on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/2023.1.20f1_build.yml b/.github/workflows/2023.1.20f1_build.yml index acc950d..c9b48b4 100644 --- a/.github/workflows/2023.1.20f1_build.yml +++ b/.github/workflows/2023.1.20f1_build.yml @@ -3,10 +3,10 @@ name: 2023.1.20f1-Build on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/2023.1.20f1_player.yml b/.github/workflows/2023.1.20f1_player.yml index 430b324..87cd37c 100644 --- a/.github/workflows/2023.1.20f1_player.yml +++ b/.github/workflows/2023.1.20f1_player.yml @@ -3,10 +3,10 @@ name: 2023.1.20f1-Player on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/2023.2.20f1_build.yml b/.github/workflows/2023.2.20f1_build.yml index 9aa513e..e305a3f 100644 --- a/.github/workflows/2023.2.20f1_build.yml +++ b/.github/workflows/2023.2.20f1_build.yml @@ -3,10 +3,10 @@ name: 2023.2.20f1-Build on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/2023.2.20f1_player.yml b/.github/workflows/2023.2.20f1_player.yml index 43d7a3d..dd14f5c 100644 --- a/.github/workflows/2023.2.20f1_player.yml +++ b/.github/workflows/2023.2.20f1_player.yml @@ -3,10 +3,10 @@ name: 2023.2.20f1-Player on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/6000.0.37f1_build.yml b/.github/workflows/6000.0.37f1_build.yml index 194e002..d7d116a 100644 --- a/.github/workflows/6000.0.37f1_build.yml +++ b/.github/workflows/6000.0.37f1_build.yml @@ -3,10 +3,10 @@ name: 6000.0.37f1-Build on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: diff --git a/.github/workflows/6000.0.37f1_player.yml b/.github/workflows/6000.0.37f1_player.yml index 5573d53..ce84e79 100644 --- a/.github/workflows/6000.0.37f1_player.yml +++ b/.github/workflows/6000.0.37f1_player.yml @@ -3,10 +3,10 @@ name: 6000.0.37f1-Player on: pull_request: branches: - - main + - master push: branches: - - main + - master jobs: editor-tests: From b2cd7a9eeffc6ccff0a1432161254bd287cb1973 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Wed, 5 Mar 2025 03:18:53 -0800 Subject: [PATCH 06/33] Added API for setting Placeholder --- .../Runtime/Future/Future.Placeholder.cs | 80 +++++++++---------- Assets/_PackageRoot/Runtime/Future/Future.cs | 32 +------- .../Runtime/Future/FutureEnums.cs | 33 +++++--- .../Runtime/Future/FutureEnumsEx.cs | 38 +++++++++ .../Runtime/Future/FutureEnumsEx.cs.meta | 11 +++ .../Tests/Editor/TestFuture.Placeholder.cs | 54 +++++++++++++ .../Editor/TestFuture.Placeholder.cs.meta | 11 +++ .../Editor/Utils/TestUtils.Placeholder.cs | 58 ++++++++++++++ .../Utils/TestUtils.Placeholder.cs.meta | 11 +++ 9 files changed, 245 insertions(+), 83 deletions(-) create mode 100644 Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs create mode 100644 Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs create mode 100644 Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs.meta create mode 100644 Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Placeholder.cs create mode 100644 Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Placeholder.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs index 4b072d8..726bbb5 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs @@ -1,64 +1,60 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using UnityEngine; +using UnityEngine; namespace Extensions.Unity.ImageLoader { public partial class Future { - protected Mutex placeholderMutex = new Mutex(); - protected Dictionary placeholders; - /// /// /// - public IFuture SetPlaceholder(T placeholder, params FutureLoadingFrom[] from) + public IFuture SetPlaceholder(T placeholder, params FuturePlaceholderTrigger[] triggers) { - lock (placeholderMutex) - { - if (placeholders == null) - placeholders = new Dictionary(); - - foreach (var f in from) - { - if (placeholders.ContainsKey(f)) - { - if (LogLevel.IsActive(DebugLevel.Warning)) - Debug.Log($"[ImageLoader] Future[id={Id}] Placeholder for loading from {f} is already set. Replacing it with new value\n{Url}"); - } - if (LogLevel.IsActive(DebugLevel.Trace)) - Debug.Log($"[ImageLoader] Future[id={Id}] Set placeholder for loading from {f}\n{Url}"); - placeholders[f] = placeholder; - } - } if (cleared || IsCancelled) { if (LogLevel.IsActive(DebugLevel.Error)) Debug.Log($"[ImageLoader] Future[id={Id}] SetPlaceholder: is impossible because the future is cleared or canceled\n{Url}"); return this; } - if (IsInProgress) - { - // TODO: set placeholder - - return this; - } - if (from.Any(x => x == FutureLoadingFrom.DiskCache)) + foreach (var trigger in triggers) { - LoadingFromDiskCache(() => + if (trigger.IsEqual(Status)) { - // TODO: set placeholder - }); - } - if (from.Any(x => x == FutureLoadingFrom.Source)) - { - LoadingFromSource(() => + foreach (var setter in setters) + Safe.Run(setter, placeholder, LogLevel); + continue; + } + switch (trigger) { - // TODO: set placeholder - }); + case FuturePlaceholderTrigger.LoadingFromDiskCache: + LoadingFromDiskCache(() => + { + foreach (var setter in setters) + Safe.Run(setter, placeholder, LogLevel); + }); + break; + case FuturePlaceholderTrigger.LoadingFromSource: + LoadingFromDiskCache(() => + { + foreach (var setter in setters) + Safe.Run(setter, placeholder, LogLevel); + }); + break; + case FuturePlaceholderTrigger.FailedToLoad: + Failed(exception => + { + foreach (var setter in setters) + Safe.Run(setter, placeholder, LogLevel); + }); + break; + case FuturePlaceholderTrigger.Canceled: + Canceled(() => + { + foreach (var setter in setters) + Safe.Run(setter, placeholder, LogLevel); + }); + break; + } } return this; diff --git a/Assets/_PackageRoot/Runtime/Future/Future.cs b/Assets/_PackageRoot/Runtime/Future/Future.cs index 20b3c35..dd3b1d5 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.cs @@ -35,8 +35,8 @@ public partial class Future : IFuture, IFuture, IFutureInternal, IDispo public uint Id { get; } = FutureMetadata.idCounter++; + protected readonly List> setters = new List>(); protected TimeSpan timeout; - protected List> setters = new List>(); protected bool cleared = false; protected bool disposeValue = false; protected T value = default; @@ -135,35 +135,6 @@ public IFuture PassEvents(IFutureInternal to, Func convert, bo return this; } - internal void Placeholder(Sprite placeholder) - { - if (cleared || IsCancelled) return; - - if (LogLevel.IsActive(DebugLevel.Log)) - Debug.Log($"[ImageLoader] Future[id={Id}] Placeholder\n{Url}"); - - // UniTask.ReturnToMainThread() - // if (UnityMainThreadDispatcher.IsMainThread) - // { - // OnLoadedFromMemoryCache?.Invoke(placeholder); - // OnLoadedFromDiskCache?.Invoke(placeholder); - // OnLoadedFromSource?.Invoke(placeholder); - // OnLoaded?.Invoke(placeholder); - // OnCompleted?.Invoke(true); - // Clear(); - // } - // else - // { - // UniTask.SwitchToMainThread(); - // Placeholder(placeholder); - // } - - OnLoadedFromMemoryCache += (v) => { }; - OnLoadingFromDiskCache += ( ) => { }; - OnLoadedFromDiskCache += (v) => { }; - OnLoadingFromSource += ( ) => { }; - OnLoadedFromSource += (v) => { }; - } void IFutureInternal.Loading(FutureLoadingFrom loadingFrom) { if (cleared || IsCancelled) return; @@ -244,6 +215,7 @@ protected virtual void Clear() Debug.Log($"[ImageLoader] Future[id={Id}] Cleared\n{Url}"); cleared = true; + setters.Clear(); OnLoadedFromMemoryCache = null; OnLoadingFromDiskCache = null; OnLoadedFromDiskCache = null; diff --git a/Assets/_PackageRoot/Runtime/Future/FutureEnums.cs b/Assets/_PackageRoot/Runtime/Future/FutureEnums.cs index bcdc55a..00d2ff4 100644 --- a/Assets/_PackageRoot/Runtime/Future/FutureEnums.cs +++ b/Assets/_PackageRoot/Runtime/Future/FutureEnums.cs @@ -2,22 +2,33 @@ { public enum FutureStatus { - Initialized, - LoadedFromMemoryCache, - LoadingFromDiskCache, - LoadedFromDiskCache, - LoadingFromSource, - LoadedFromSource, - FailedToLoad, - Canceled, - Disposed + Initialized = 0, + LoadedFromMemoryCache = 1, + LoadingFromDiskCache = 2, + LoadedFromDiskCache = 3, + LoadingFromSource = 4, + LoadedFromSource = 5, + FailedToLoad = 6, + Canceled = 7, + Disposed = 8 } public enum FutureLoadedFrom { - MemoryCache, DiskCache, Source, FailedToLoad + MemoryCache = 1, + DiskCache = 3, + Source = 5, + FailedToLoad = 6 } public enum FutureLoadingFrom { - DiskCache, Source + DiskCache = 2, + Source = 4 + } + public enum FuturePlaceholderTrigger + { + LoadingFromDiskCache = 2, + LoadingFromSource = 4, + FailedToLoad = 6, + Canceled = 7, } } diff --git a/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs b/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs new file mode 100644 index 0000000..da7f69b --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs @@ -0,0 +1,38 @@ +namespace Extensions.Unity.ImageLoader +{ + public static class FutureEnumEx + { + public static FutureStatus AsFutureStatus(this FutureLoadedFrom value) => (FutureStatus)value; + public static FutureStatus AsFutureStatus(this FutureLoadingFrom value) => (FutureStatus)value; + public static FutureStatus AsFutureStatus(this FuturePlaceholderTrigger value) => (FutureStatus)value; + + public static FutureLoadedFrom AsFutureLoadedFrom(this FutureStatus value) => (FutureLoadedFrom)value; + public static FutureLoadedFrom AsFutureLoadedFrom(this FutureLoadingFrom value) => (FutureLoadedFrom)value; + public static FutureLoadedFrom AsFutureLoadedFrom(this FuturePlaceholderTrigger value) => (FutureLoadedFrom)value; + + public static FutureLoadingFrom AsFutureLoadingFrom(this FutureStatus value) => (FutureLoadingFrom)value; + public static FutureLoadingFrom AsFutureLoadingFrom(this FutureLoadedFrom value) => (FutureLoadingFrom)value; + public static FutureLoadingFrom AsFutureLoadingFrom(this FuturePlaceholderTrigger value) => (FutureLoadingFrom)value; + + public static FuturePlaceholderTrigger AsFuturePlaceholderTrigger(this FutureStatus value) => (FuturePlaceholderTrigger)value; + public static FuturePlaceholderTrigger AsFuturePlaceholderTrigger(this FutureLoadedFrom value) => (FuturePlaceholderTrigger)value; + public static FuturePlaceholderTrigger AsFuturePlaceholderTrigger(this FutureLoadingFrom value) => (FuturePlaceholderTrigger)value; + + + public static bool IsEqual(this FutureStatus value1, FutureLoadedFrom value2) => (int)value1 == (int)value2; + public static bool IsEqual(this FutureStatus value1, FutureLoadingFrom value2) => (int)value1 == (int)value2; + public static bool IsEqual(this FutureStatus value1, FuturePlaceholderTrigger value2) => (int)value1 == (int)value2; + + public static bool IsEqual(this FutureLoadedFrom value1, FutureStatus value2) => (int)value1 == (int)value2; + public static bool IsEqual(this FutureLoadedFrom value1, FutureLoadingFrom value2) => (int)value1 == (int)value2; + public static bool IsEqual(this FutureLoadedFrom value1, FuturePlaceholderTrigger value2) => (int)value1 == (int)value2; + + public static bool IsEqual(this FutureLoadingFrom value1, FutureStatus value2) => (int)value1 == (int)value2; + public static bool IsEqual(this FutureLoadingFrom value1, FutureLoadedFrom value2) => (int)value1 == (int)value2; + public static bool IsEqual(this FutureLoadingFrom value1, FuturePlaceholderTrigger value2) => (int)value1 == (int)value2; + + public static bool IsEqual(this FuturePlaceholderTrigger value1, FutureStatus value2) => (int)value1 == (int)value2; + public static bool IsEqual(this FuturePlaceholderTrigger value1, FutureLoadedFrom value2) => (int)value1 == (int)value2; + public static bool IsEqual(this FuturePlaceholderTrigger value1, FutureLoadingFrom value2) => (int)value1 == (int)value2; + } +} diff --git a/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs.meta b/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs.meta new file mode 100644 index 0000000..93e496f --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 64fc0c3e418e4d14b9b9d5ee7a06d30a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs b/Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs new file mode 100644 index 0000000..7f9519e --- /dev/null +++ b/Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs @@ -0,0 +1,54 @@ +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFuture + { + [UnityTest] public IEnumerator Placeholder_Source_NoLogs() => TestUtils.RunNoLogs(Placeholder_Source); + [UnityTest] public IEnumerator Placeholder_Source() + { + yield return Placeholder_Source(useDiskCache: true, useMemoryCache: true); + yield return Placeholder_Source(useDiskCache: true, useMemoryCache: false); + yield return Placeholder_Source(useDiskCache: false, useMemoryCache: true); + yield return Placeholder_Source(useDiskCache: false, useMemoryCache: false); + } + IEnumerator Placeholder_Source(bool useDiskCache, bool useMemoryCache) + { + ImageLoader.settings.useDiskCache = useDiskCache; + ImageLoader.settings.useMemoryCache = useMemoryCache; + + foreach (var url in TestUtils.ImageURLs) + yield return TestUtils.Placeholder(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source); + + yield return TestUtils.ClearEverything(message: null); + } + + [UnityTest] public IEnumerator Placeholder_DiskCache_NoLogs() => TestUtils.RunNoLogs(Placeholder_DiskCache); + [UnityTest] public IEnumerator Placeholder_DiskCache() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = false; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.Placeholder(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache); + } + } + + [UnityTest] public IEnumerator Placeholder_MemoryCache_NoLogs() => TestUtils.RunNoLogs(Placeholder_MemoryCache); + [UnityTest] public IEnumerator Placeholder_MemoryCache() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadFromMemoryCache(url); + } + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs.meta b/Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs.meta new file mode 100644 index 0000000..e73f8fb --- /dev/null +++ b/Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65c503c3992353b40ae71d1c7c675a03 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Placeholder.cs b/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Placeholder.cs new file mode 100644 index 0000000..3312913 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Placeholder.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections; +using System.Linq; +using Cysharp.Threading.Tasks; +using NUnit.Framework; + +namespace Extensions.Unity.ImageLoader.Tests.Utils +{ + internal static partial class TestUtils + { + public static IEnumerator PlaceholderFromMemoryCache(string url) => Placeholder(url, null, FutureLoadedFrom.MemoryCache); + public static IEnumerator Placeholder(string url, FutureLoadingFrom? expectedLoadingFrom, FutureLoadedFrom expectedLoadedFrom) + { + var future = ImageLoader.LoadSprite(url); + var futureListener = future.ToFutureListener(); + + if (expectedLoadingFrom.HasValue) + futureListener.Assert_Events_Contains(expectedLoadingFrom.Value.ToEventName()); + + var task1 = future.AsTask(); + yield return future.TimeoutCoroutine(TimeSpan.FromSeconds(10)); + var task2 = future.AsTask(); + + futureListener.Assert_Events_NotContains(EventName.Canceled); + + if (expectedLoadingFrom.HasValue) + futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + else + futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + + futureListener.Assert_Events_Value(EventName.Completed, success => success == true); + + Assert.IsTrue(task1.IsCompleted, "Task was not cancelled but Future was cancelled"); + Assert.IsTrue(task2.IsCompleted, "Task was not cancelled but Future was cancelled"); + + yield return UniTask.Yield(); + + if (expectedLoadingFrom.HasValue) + futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + else + futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + + futureListener.Assert_Events_Value(EventName.Completed, success => success == true); + + future.ToFutureListener(ignoreLoadingWhenLoaded: true) + .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) + .Assert_Events_Value(EventName.Completed, success => success == true); + + if (expectedLoadingFrom.HasValue) + future.ToFutureListener() + .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) + .Assert_Events_Value(EventName.Completed, success => success == true); + + future.Dispose(); + yield return UniTask.Yield(); + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Placeholder.cs.meta b/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Placeholder.cs.meta new file mode 100644 index 0000000..a01779c --- /dev/null +++ b/Assets/_PackageRoot/Tests/Editor/Utils/TestUtils.Placeholder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20380b73375185a4f98b40d3e7c41a3e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From dfefa9fd4b83815d706821f531b568fc8d8ae386 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Wed, 5 Mar 2025 20:45:44 -0800 Subject: [PATCH 07/33] Handling placeholders --- Assets/_PackageRoot/Runtime/Consumer.meta | 8 ++ .../_PackageRoot/Runtime/Consumer/Binder.cs | 14 ++++ .../Runtime/Consumer/Binder.cs.meta | 11 +++ .../_PackageRoot/Runtime/Consumer/IBinder.cs | 9 ++ .../Runtime/Consumer/IBinder.cs.meta | 11 +++ .../Runtime/Future/Future.API.Set.cs | 38 +++++++++ .../_PackageRoot/Runtime/Future/Future.API.cs | 5 +- .../Runtime/Future/Future.Placeholder.cs | 82 +++++++++++-------- Assets/_PackageRoot/Runtime/Future/Future.cs | 15 +++- 9 files changed, 157 insertions(+), 36 deletions(-) create mode 100644 Assets/_PackageRoot/Runtime/Consumer.meta create mode 100644 Assets/_PackageRoot/Runtime/Consumer/Binder.cs create mode 100644 Assets/_PackageRoot/Runtime/Consumer/Binder.cs.meta create mode 100644 Assets/_PackageRoot/Runtime/Consumer/IBinder.cs create mode 100644 Assets/_PackageRoot/Runtime/Consumer/IBinder.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Consumer.meta b/Assets/_PackageRoot/Runtime/Consumer.meta new file mode 100644 index 0000000..524525a --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Consumer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9193d8985e89b4c4fa550de4409f0362 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Runtime/Consumer/Binder.cs b/Assets/_PackageRoot/Runtime/Consumer/Binder.cs new file mode 100644 index 0000000..142ec4e --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Consumer/Binder.cs @@ -0,0 +1,14 @@ +using System; + +namespace Extensions.Unity.ImageLoader +{ + public class Binder : IBinder, IDisposable + { + protected Action setter; + + public Binder(Action setter) => this.setter = setter; + + public void Set(Target target, Value value, DebugLevel logLevel = DebugLevel.Error) => Safe.Run(setter, target, value, logLevel); + public void Dispose() => setter = null; + } +} diff --git a/Assets/_PackageRoot/Runtime/Consumer/Binder.cs.meta b/Assets/_PackageRoot/Runtime/Consumer/Binder.cs.meta new file mode 100644 index 0000000..4f44587 --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Consumer/Binder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd9b0b98f870c994a81f826d6abded0f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs b/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs new file mode 100644 index 0000000..bf59c7e --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs @@ -0,0 +1,9 @@ +using System; + +namespace Extensions.Unity.ImageLoader +{ + public interface IBinder : IDisposable + { + void Set(Target target, Value value, DebugLevel logLevel = DebugLevel.Error); + } +} diff --git a/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs.meta b/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs.meta new file mode 100644 index 0000000..69910a1 --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c19a8fd03b7c4ea4bb9c0b0808ae7655 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs b/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs index 41f4cf9..4dc5818 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs @@ -36,5 +36,43 @@ public IFuture SetLogLevel(DebugLevel value) LogLevel = value; return this; } + + /// + /// Set the setter function + /// + /// Setter function + /// Returns the Future instance + public IFuture Set(Action setter) + { + lock (setters) + { + setters.Clear(); + setters.Add(setter); + } + + if (IsLoaded) + { + Safe.Run(setter, value, LogLevel); + return this; + } + return this; + } + /// + /// Set or add the setter function + /// + /// Setter function + /// Returns the Future instance + public IFuture SetOrAdd(Action setter) + { + lock (setters) + setters.Add(setter); + + if (IsLoaded) + { + Safe.Run(setter, value, LogLevel); + return this; + } + return this; + } } } diff --git a/Assets/_PackageRoot/Runtime/Future/Future.API.cs b/Assets/_PackageRoot/Runtime/Future/Future.API.cs index 6c4eb11..7c0d3c6 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.API.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.API.cs @@ -17,7 +17,7 @@ public IFuture Then(Action action) { if (IsLoaded) { - action(value); + Safe.Run(action, value, LogLevel); return this; } OnLoaded += action; @@ -33,7 +33,7 @@ public IFuture Failed(Action action) { if (Status == FutureStatus.FailedToLoad) { - action(exception); + Safe.Run(action, exception, LogLevel); return this; } OnFailedToLoad += action; @@ -207,6 +207,7 @@ public virtual void Cancel() if (Safe.RunCancel(cts, LogLevel)) { Safe.Run(OnCanceled, LogLevel); + ActivatePlaceholder(Status); Safe.Run(OnCompleted, IsLoaded, LogLevel); } Clear(); diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs index 726bbb5..4121629 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs @@ -20,41 +20,57 @@ public IFuture SetPlaceholder(T placeholder, params FuturePlaceholderTrigger[ { if (trigger.IsEqual(Status)) { - foreach (var setter in setters) - Safe.Run(setter, placeholder, LogLevel); + lock (setters) + { + foreach (var setter in setters) + Safe.Run(setter, placeholder, LogLevel); + } continue; } - switch (trigger) - { - case FuturePlaceholderTrigger.LoadingFromDiskCache: - LoadingFromDiskCache(() => - { - foreach (var setter in setters) - Safe.Run(setter, placeholder, LogLevel); - }); - break; - case FuturePlaceholderTrigger.LoadingFromSource: - LoadingFromDiskCache(() => - { - foreach (var setter in setters) - Safe.Run(setter, placeholder, LogLevel); - }); - break; - case FuturePlaceholderTrigger.FailedToLoad: - Failed(exception => - { - foreach (var setter in setters) - Safe.Run(setter, placeholder, LogLevel); - }); - break; - case FuturePlaceholderTrigger.Canceled: - Canceled(() => - { - foreach (var setter in setters) - Safe.Run(setter, placeholder, LogLevel); - }); - break; - } + placeholders[trigger.AsFutureStatus()] = placeholder; + // switch (trigger) + // { + // case FuturePlaceholderTrigger.LoadingFromDiskCache: + // LoadingFromDiskCache(() => + // { + // lock (settersAll) + // { + // foreach (var setter in settersAll) + // Safe.Run(setter, placeholder, LogLevel); + // } + // }); + // break; + // case FuturePlaceholderTrigger.LoadingFromSource: + // LoadingFromDiskCache(() => + // { + // lock (settersAll) + // { + // foreach (var setter in settersAll) + // Safe.Run(setter, placeholder, LogLevel); + // } + // }); + // break; + // case FuturePlaceholderTrigger.FailedToLoad: + // Failed(exception => + // { + // lock (settersAll) + // { + // foreach (var setter in settersAll) + // Safe.Run(setter, placeholder, LogLevel); + // } + // }); + // break; + // case FuturePlaceholderTrigger.Canceled: + // Canceled(() => + // { + // lock (settersAll) + // { + // foreach (var setter in settersAll) + // Safe.Run(setter, placeholder, LogLevel); + // } + // }); + // break; + //} } return this; diff --git a/Assets/_PackageRoot/Runtime/Future/Future.cs b/Assets/_PackageRoot/Runtime/Future/Future.cs index dd3b1d5..9ff643d 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.cs @@ -36,6 +36,7 @@ public partial class Future : IFuture, IFuture, IFutureInternal, IDispo public uint Id { get; } = FutureMetadata.idCounter++; protected readonly List> setters = new List>(); + protected readonly Dictionary placeholders = new Dictionary(); protected TimeSpan timeout; protected bool cleared = false; protected bool disposeValue = false; @@ -159,6 +160,7 @@ void IFutureInternal.Loading(FutureLoadingFrom loadingFrom) this.loadingFrom = loadingFrom; Safe.Run(onLoadingEvent, LogLevel); + ActivatePlaceholder(Status); } void IFutureInternal.Loaded(T value, FutureLoadedFrom loadedFrom) { @@ -190,6 +192,7 @@ void IFutureInternal.Loaded(T value, FutureLoadedFrom loadedFrom) Safe.Run(onLoadedEvent, this.value, LogLevel); Safe.Run(OnLoaded, this.value, LogLevel); + ActivatePlaceholder(Status); Safe.Run(OnCompleted, true, LogLevel); Clear(); } @@ -204,10 +207,19 @@ void IFutureInternal.FailToLoad(Exception exception) Debug.LogError(exception.Message); Safe.Run(OnFailedToLoad, exception, LogLevel); + ActivatePlaceholder(Status); Safe.Run(OnCompleted, false, LogLevel); Clear(); } void IFutureInternal.SetTimeout(TimeSpan duration) => timeout = duration; + void ActivatePlaceholder(FutureStatus status) + { + if (placeholders.TryGetValue(status, out var placeholder)) + { + foreach (var setter in setters) + Safe.Run(setter, placeholder, LogLevel); + } + } protected virtual void Clear() { @@ -215,7 +227,8 @@ protected virtual void Clear() Debug.Log($"[ImageLoader] Future[id={Id}] Cleared\n{Url}"); cleared = true; - setters.Clear(); + lock (placeholders) + placeholders.Clear(); OnLoadedFromMemoryCache = null; OnLoadingFromDiskCache = null; OnLoadedFromDiskCache = null; From baeae72f2d0d60cb2e2310ff2021b54351862e2f Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Wed, 5 Mar 2025 20:46:30 -0800 Subject: [PATCH 08/33] Deleted unused binder class --- Assets/_PackageRoot/Runtime/Consumer.meta | 8 -------- Assets/_PackageRoot/Runtime/Consumer/Binder.cs | 14 -------------- .../_PackageRoot/Runtime/Consumer/Binder.cs.meta | 11 ----------- Assets/_PackageRoot/Runtime/Consumer/IBinder.cs | 9 --------- .../_PackageRoot/Runtime/Consumer/IBinder.cs.meta | 11 ----------- 5 files changed, 53 deletions(-) delete mode 100644 Assets/_PackageRoot/Runtime/Consumer.meta delete mode 100644 Assets/_PackageRoot/Runtime/Consumer/Binder.cs delete mode 100644 Assets/_PackageRoot/Runtime/Consumer/Binder.cs.meta delete mode 100644 Assets/_PackageRoot/Runtime/Consumer/IBinder.cs delete mode 100644 Assets/_PackageRoot/Runtime/Consumer/IBinder.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Consumer.meta b/Assets/_PackageRoot/Runtime/Consumer.meta deleted file mode 100644 index 524525a..0000000 --- a/Assets/_PackageRoot/Runtime/Consumer.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 9193d8985e89b4c4fa550de4409f0362 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_PackageRoot/Runtime/Consumer/Binder.cs b/Assets/_PackageRoot/Runtime/Consumer/Binder.cs deleted file mode 100644 index 142ec4e..0000000 --- a/Assets/_PackageRoot/Runtime/Consumer/Binder.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Extensions.Unity.ImageLoader -{ - public class Binder : IBinder, IDisposable - { - protected Action setter; - - public Binder(Action setter) => this.setter = setter; - - public void Set(Target target, Value value, DebugLevel logLevel = DebugLevel.Error) => Safe.Run(setter, target, value, logLevel); - public void Dispose() => setter = null; - } -} diff --git a/Assets/_PackageRoot/Runtime/Consumer/Binder.cs.meta b/Assets/_PackageRoot/Runtime/Consumer/Binder.cs.meta deleted file mode 100644 index 4f44587..0000000 --- a/Assets/_PackageRoot/Runtime/Consumer/Binder.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dd9b0b98f870c994a81f826d6abded0f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs b/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs deleted file mode 100644 index bf59c7e..0000000 --- a/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Extensions.Unity.ImageLoader -{ - public interface IBinder : IDisposable - { - void Set(Target target, Value value, DebugLevel logLevel = DebugLevel.Error); - } -} diff --git a/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs.meta b/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs.meta deleted file mode 100644 index 69910a1..0000000 --- a/Assets/_PackageRoot/Runtime/Consumer/IBinder.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c19a8fd03b7c4ea4bb9c0b0808ae7655 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From f48d5aabc8d72562bd62ff516d639b6cfb1b59a4 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Wed, 5 Mar 2025 21:08:55 -0800 Subject: [PATCH 09/33] Improved concurrency handling for Future --- .../Runtime/Future/Future.API.Set.cs | 30 +++-------- .../Runtime/Future/Future.Placeholder.cs | 50 ++----------------- Assets/_PackageRoot/Runtime/Future/Future.cs | 14 ++++-- Assets/_PackageRoot/Runtime/Future/IFuture.cs | 3 ++ 4 files changed, 24 insertions(+), 73 deletions(-) diff --git a/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs b/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs index 4dc5818..4016428 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs @@ -40,36 +40,20 @@ public IFuture SetLogLevel(DebugLevel value) /// /// Set the setter function /// - /// Setter function + /// Setter function /// Returns the Future instance - public IFuture Set(Action setter) + public IFuture Consume(Action consumer, bool replace = false) { - lock (setters) + lock (consumers) { - setters.Clear(); - setters.Add(setter); + if (replace) + consumers.Clear(); + consumers.Add(consumer); } if (IsLoaded) { - Safe.Run(setter, value, LogLevel); - return this; - } - return this; - } - /// - /// Set or add the setter function - /// - /// Setter function - /// Returns the Future instance - public IFuture SetOrAdd(Action setter) - { - lock (setters) - setters.Add(setter); - - if (IsLoaded) - { - Safe.Run(setter, value, LogLevel); + Safe.Run(consumer, value, LogLevel); return this; } return this; diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs index 4121629..56bffe2 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs @@ -20,57 +20,15 @@ public IFuture SetPlaceholder(T placeholder, params FuturePlaceholderTrigger[ { if (trigger.IsEqual(Status)) { - lock (setters) + lock (consumers) { - foreach (var setter in setters) + foreach (var setter in consumers) Safe.Run(setter, placeholder, LogLevel); } continue; } - placeholders[trigger.AsFutureStatus()] = placeholder; - // switch (trigger) - // { - // case FuturePlaceholderTrigger.LoadingFromDiskCache: - // LoadingFromDiskCache(() => - // { - // lock (settersAll) - // { - // foreach (var setter in settersAll) - // Safe.Run(setter, placeholder, LogLevel); - // } - // }); - // break; - // case FuturePlaceholderTrigger.LoadingFromSource: - // LoadingFromDiskCache(() => - // { - // lock (settersAll) - // { - // foreach (var setter in settersAll) - // Safe.Run(setter, placeholder, LogLevel); - // } - // }); - // break; - // case FuturePlaceholderTrigger.FailedToLoad: - // Failed(exception => - // { - // lock (settersAll) - // { - // foreach (var setter in settersAll) - // Safe.Run(setter, placeholder, LogLevel); - // } - // }); - // break; - // case FuturePlaceholderTrigger.Canceled: - // Canceled(() => - // { - // lock (settersAll) - // { - // foreach (var setter in settersAll) - // Safe.Run(setter, placeholder, LogLevel); - // } - // }); - // break; - //} + lock (placeholders) + placeholders[trigger.AsFutureStatus()] = placeholder; } return this; diff --git a/Assets/_PackageRoot/Runtime/Future/Future.cs b/Assets/_PackageRoot/Runtime/Future/Future.cs index 9ff643d..6238d5a 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.cs @@ -35,7 +35,7 @@ public partial class Future : IFuture, IFuture, IFutureInternal, IDispo public uint Id { get; } = FutureMetadata.idCounter++; - protected readonly List> setters = new List>(); + protected readonly List> consumers = new List>(); protected readonly Dictionary placeholders = new Dictionary(); protected TimeSpan timeout; protected bool cleared = false; @@ -214,10 +214,16 @@ void IFutureInternal.FailToLoad(Exception exception) void IFutureInternal.SetTimeout(TimeSpan duration) => timeout = duration; void ActivatePlaceholder(FutureStatus status) { - if (placeholders.TryGetValue(status, out var placeholder)) + lock (placeholders) { - foreach (var setter in setters) - Safe.Run(setter, placeholder, LogLevel); + if (placeholders.TryGetValue(status, out var placeholder)) + { + lock (consumers) + { + foreach (var setter in consumers) + Safe.Run(setter, placeholder, LogLevel); + } + } } } diff --git a/Assets/_PackageRoot/Runtime/Future/IFuture.cs b/Assets/_PackageRoot/Runtime/Future/IFuture.cs index a5b60ab..a3ed882 100644 --- a/Assets/_PackageRoot/Runtime/Future/IFuture.cs +++ b/Assets/_PackageRoot/Runtime/Future/IFuture.cs @@ -33,6 +33,9 @@ public partial interface IFuture : IFuture, IDisposable IFuture LoadedFromDiskCache(Action action); IFuture LoadingFromSource(Action action, bool ignoreWhenLoaded = false); IFuture LoadedFromSource(Action action); + + IFuture Consume(Action setter, bool replace = false); + IFuture Canceled(Action action); IFuture SetUseDiskCache(bool value = true); From bcb48e3e1a105d63d915027035c9330b11e5f606 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Wed, 5 Mar 2025 21:09:27 -0800 Subject: [PATCH 10/33] Added Consumer event for FutureListener --- Assets/_PackageRoot/Tests/Editor/Utils/EventName.cs | 3 ++- Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.cs | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/EventName.cs b/Assets/_PackageRoot/Tests/Editor/Utils/EventName.cs index 97ffd36..014fb5e 100644 --- a/Assets/_PackageRoot/Tests/Editor/Utils/EventName.cs +++ b/Assets/_PackageRoot/Tests/Editor/Utils/EventName.cs @@ -13,7 +13,8 @@ public enum EventName Then, Failed, Completed, - Canceled + Canceled, + Consume } public static class EventNameEx diff --git a/Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.cs b/Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.cs index e6ef717..1063d1d 100644 --- a/Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.cs +++ b/Assets/_PackageRoot/Tests/Editor/Utils/FutureListener.cs @@ -90,6 +90,13 @@ public FutureListener(IFuture future, bool ignoreLoadingWhenLoaded = false, D lock (events) events.Add(new EventData { name = EventName.Completed, value = value }); }); + future.Consume(value => + { + if (logLevel.Value.IsActive(DebugLevel.Trace)) + Debug.Log($"[FutureListener] Future[id={future.Id}] Consume: {value}"); + lock (events) + events.Add(new EventData { name = EventName.Consume, value = value }); + }); } } } \ No newline at end of file From 96992ba2be14192c484545b30981aa09dbb07818 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Wed, 5 Mar 2025 21:20:19 -0800 Subject: [PATCH 11/33] Fixed merge issues --- .../Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs | 1 + Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs index f03d6e2..8cdec16 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs @@ -51,6 +51,7 @@ public void Cancel() public IFuture LoadedFromSource(Action action) => throw new NotImplementedException(); public IFuture LoadingFromDiskCache(Action action, bool ignoreLoaded = false) => throw new NotImplementedException(); public IFuture LoadingFromSource(Action action, bool ignoreLoaded = false) => throw new NotImplementedException(); + public IFuture Consume(Action setter, bool replace = false) => throw new NotImplementedException(); public IFuture PassEvents(IFutureInternal to, bool passCancelled = true) => throw new NotImplementedException(); public IFuture PassEvents(IFutureInternal to, Func convert, bool passCancelled = true) => throw new NotImplementedException(); public IFuture SetLogLevel(DebugLevel value) => throw new NotImplementedException(); diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs index 3312913..46109e0 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs @@ -6,7 +6,7 @@ namespace Extensions.Unity.ImageLoader.Tests.Utils { - internal static partial class TestUtils + public static partial class TestUtils { public static IEnumerator PlaceholderFromMemoryCache(string url) => Placeholder(url, null, FutureLoadedFrom.MemoryCache); public static IEnumerator Placeholder(string url, FutureLoadingFrom? expectedLoadingFrom, FutureLoadedFrom expectedLoadedFrom) From 1c18e61b1d42ff3fa6c0dc4530d17805adc9e266 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Wed, 5 Mar 2025 23:59:29 -0800 Subject: [PATCH 12/33] Refactored API around Consume function --- .../Runtime/Future/Future.API.Set.cs | 22 ------ .../_PackageRoot/Runtime/Future/Future.API.cs | 36 +++++++-- .../{Future.ThenSet.cs => Future.Consume.cs} | 49 +++++------- ...ThenSet.cs.meta => Future.Consume.cs.meta} | 0 ...ure.ThenSetRef.cs => Future.ConsumeRef.cs} | 47 +++++------- ...tRef.cs.meta => Future.ConsumeRef.cs.meta} | 0 .../Runtime/Future/Future.Empty.cs | 2 +- .../Runtime/Future/Future.Loading.cs | 6 +- Assets/_PackageRoot/Runtime/Future/Future.cs | 32 ++++---- Assets/_PackageRoot/Runtime/Future/IFuture.cs | 4 +- .../Samples/SampleAwaitAndForget.cs | 4 +- .../Samples/SampleCancellation.cs | 18 ++--- .../_PackageRoot/Samples/SampleErrorHandle.cs | 6 +- .../_PackageRoot/Samples/SampleLifecycle.cs | 18 +++-- .../Samples/SampleLoadSpriteThenSetImage.cs | 2 +- ...mpleLoadSpriteThenSetIntoMultipleImages.cs | 2 +- .../SampleLoadTextureThenSetMaterial.cs | 2 +- .../_PackageRoot/Samples/SampleReferences.cs | 6 +- Assets/_PackageRoot/Samples/SampleTimeout.cs | 2 +- .../FakeFuture.Implementation.IFuture.cs | 2 +- ...keFuture.Implementation.IFutureInternal.cs | 2 +- .../_PackageRoot/Tests/Base/Utils/FutureEx.cs | 4 +- .../Tests/Base/Utils/FutureListener.cs | 21 ++--- .../Tests/Base/Utils/TestUtils.Load.cs | 18 +++-- .../Tests/Base/Utils/TestUtils.Placeholder.cs | 66 +++++++++------- .../Tests/Base/Utils/TestUtils.cs | 8 ++ .../Tests/Editor/TestFuture.Placeholder.cs | 76 +++++++++---------- .../Tests/Runtime/TestFutureOrder.cs | 2 +- 28 files changed, 233 insertions(+), 224 deletions(-) rename Assets/_PackageRoot/Runtime/Future/{Future.ThenSet.cs => Future.Consume.cs} (66%) rename Assets/_PackageRoot/Runtime/Future/{Future.ThenSet.cs.meta => Future.Consume.cs.meta} (100%) rename Assets/_PackageRoot/Runtime/Future/{Future.ThenSetRef.cs => Future.ConsumeRef.cs} (74%) rename Assets/_PackageRoot/Runtime/Future/{Future.ThenSetRef.cs.meta => Future.ConsumeRef.cs.meta} (100%) diff --git a/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs b/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs index 4016428..41f4cf9 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.API.Set.cs @@ -36,27 +36,5 @@ public IFuture SetLogLevel(DebugLevel value) LogLevel = value; return this; } - - /// - /// Set the setter function - /// - /// Setter function - /// Returns the Future instance - public IFuture Consume(Action consumer, bool replace = false) - { - lock (consumers) - { - if (replace) - consumers.Clear(); - consumers.Add(consumer); - } - - if (IsLoaded) - { - Safe.Run(consumer, value, LogLevel); - return this; - } - return this; - } } } diff --git a/Assets/_PackageRoot/Runtime/Future/Future.API.cs b/Assets/_PackageRoot/Runtime/Future/Future.API.cs index 7c0d3c6..486d282 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.API.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.API.cs @@ -9,11 +9,33 @@ namespace Extensions.Unity.ImageLoader public partial class Future : IDisposable { /// - /// When the image is loaded successfully from any source + /// When the it is time to set data into any consumer. Such as setting placeholder or final loaded subject + /// + /// Consumer (setter) function + /// If true, clear all existed consumer and replace them with this new one + /// Returns the Future instance + public IFuture Consume(Action consumer, bool replace = false) + { + if (IsLoaded) + { + Safe.Run(consumer, value, LogLevel); + return this; + } + lock (consumers) + { + if (replace) + consumers.Clear(); + consumers.Add(consumer); + } + return this; + } + + /// + /// When is loaded successfully from any source /// /// action to execute on the event /// Returns the Future instance - public IFuture Then(Action action) + public IFuture Loaded(Action action) { if (IsLoaded) { @@ -226,7 +248,7 @@ public IFuture> AsReference(DebugLevel logLevel = DebugLevel.Trace) LoadedFromMemoryCache(obj => { if (weakReference.TryGetTarget(out var future)) - future.Loaded(new Reference(url, obj), FutureLoadedFrom.MemoryCache); + future.SetLoaded(new Reference(url, obj), FutureLoadedFrom.MemoryCache); }); LoadingFromDiskCache(() => { @@ -236,7 +258,7 @@ public IFuture> AsReference(DebugLevel logLevel = DebugLevel.Trace) LoadedFromDiskCache(obj => { if (weakReference.TryGetTarget(out var future)) - future.Loaded(new Reference(url, obj), FutureLoadedFrom.DiskCache); + future.SetLoaded(new Reference(url, obj), FutureLoadedFrom.DiskCache); }); LoadingFromSource(() => { @@ -246,7 +268,7 @@ public IFuture> AsReference(DebugLevel logLevel = DebugLevel.Trace) LoadedFromSource(obj => { if (weakReference.TryGetTarget(out var future)) - future.Loaded(new Reference(url, obj), FutureLoadedFrom.Source); + future.SetLoaded(new Reference(url, obj), FutureLoadedFrom.Source); }); Failed(e => { @@ -368,7 +390,7 @@ public UniTask AsUniTask() var taskCompletionSource = new UniTaskCompletionSource(); - Then(value => taskCompletionSource.TrySetResult(value)); + Loaded(value => taskCompletionSource.TrySetResult(value)); Failed(exception => taskCompletionSource.TrySetException(exception)); Canceled(() => taskCompletionSource.TrySetCanceled()); @@ -381,7 +403,7 @@ public Task AsTask() var taskCompletionSource = new TaskCompletionSource(); - Then(taskCompletionSource.SetResult); + Loaded(taskCompletionSource.SetResult); Failed(taskCompletionSource.SetException); Canceled(taskCompletionSource.SetCanceled); diff --git a/Assets/_PackageRoot/Runtime/Future/Future.ThenSet.cs b/Assets/_PackageRoot/Runtime/Future/Future.Consume.cs similarity index 66% rename from Assets/_PackageRoot/Runtime/Future/Future.ThenSet.cs rename to Assets/_PackageRoot/Runtime/Future/Future.Consume.cs index 7baa3c8..677dde0 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.ThenSet.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.Consume.cs @@ -13,28 +13,19 @@ public static partial class FutureEx /// Setter function that gets Consumer and loaded object, it should set the object into Consumer /// Array of consumers for injecting /// Returns async Future - public static IFuture ThenSet(this IFuture future, Action setter, params C[] consumers) => future.Then(obj => + public static IFuture Consume(this IFuture future, Action setter, params C[] consumers) => future.Consume(obj => { UniTask.Post(() => // using only MainThread to set any images to any targets { - foreach (var target in consumers) + foreach (var consumer in consumers) { - if (target == null) + if (ReferenceEquals(consumer, null) || consumer == null) { if (future.LogLevel.IsActive(DebugLevel.Warning)) Debug.LogWarning($"[ImageLoader] Future[id={future.Id}] The target is null. Can't set image into it. Skipping."); continue; } - if (target is UnityEngine.Object unityObject) - { - if (unityObject.IsNull()) - { - if (future.LogLevel.IsActive(DebugLevel.Warning)) - Debug.LogWarning($"The target ({typeof(T).Name}) is destroyed. Can't set image into it. Skipping."); - continue; - } - } - setter?.Invoke(target, obj); + Safe.Run(setter, consumer, obj, future.LogLevel); } }); }); @@ -44,40 +35,40 @@ public static IFuture ThenSet(this IFuture future, Action sett /// /// Array of Images /// Returns async Future - public static IFuture ThenSet(this IFuture future, params Image[] images) - => future.ThenSet((consumer, sprite) => consumer.sprite = sprite, images); + public static IFuture Consume(this IFuture future, params Image[] images) + => future.Consume((consumer, sprite) => consumer.sprite = sprite, images); /// /// Set image into array of RawImages /// /// Array of RawImages /// Returns async Future - public static IFuture ThenSet(this IFuture future, params RawImage[] rawImages) - => future.ThenSet((consumer, sprite) => consumer.texture = sprite?.texture, rawImages); + public static IFuture Consume(this IFuture future, params RawImage[] rawImages) + => future.Consume((consumer, sprite) => consumer.texture = sprite?.texture, rawImages); /// /// Set image into array of RawImages /// /// Array of RawImages /// Returns async Future - public static IFuture ThenSet(this IFuture future, params RawImage[] rawImages) - => future.ThenSet((consumer, texture) => consumer.texture = texture, rawImages); + public static IFuture Consume(this IFuture future, params RawImage[] rawImages) + => future.Consume((consumer, texture) => consumer.texture = texture, rawImages); /// /// Set image into array of SpriteRenderers /// /// Array of SpriteRenderers /// Returns async Future - public static IFuture ThenSet(this IFuture future, params SpriteRenderer[] spriteRenderers) - => future.ThenSet((consumer, sprite) => consumer.sprite = sprite, spriteRenderers); + public static IFuture Consume(this IFuture future, params SpriteRenderer[] spriteRenderers) + => future.Consume((consumer, sprite) => consumer.sprite = sprite, spriteRenderers); /// /// Set image into array of Materials /// /// Array of Materials /// Returns async Future - public static IFuture ThenSet(this IFuture future, params Material[] materials) - => future.ThenSet("_MainTex", materials); + public static IFuture Consume(this IFuture future, params Material[] materials) + => future.Consume("_MainTex", materials); /// /// Set image into array of Materials @@ -85,16 +76,16 @@ public static IFuture ThenSet(this IFuture future, params Materi /// Property name to set the texture /// Array of Materials /// Returns async Future - public static IFuture ThenSet(this IFuture future, string propertyName = "_MainTex", params Material[] materials) - => future.ThenSet((consumer, sprite) => consumer.SetTexture(propertyName, sprite?.texture), materials); + public static IFuture Consume(this IFuture future, string propertyName = "_MainTex", params Material[] materials) + => future.Consume((consumer, sprite) => consumer.SetTexture(propertyName, sprite?.texture), materials); /// /// Set image into array of Materials /// /// Array of Materials /// Returns async Future - public static IFuture ThenSet(this IFuture future, params Material[] materials) - => future.ThenSet("_MainTex", materials); + public static IFuture Consume(this IFuture future, params Material[] materials) + => future.Consume("_MainTex", materials); /// /// Set image into array of Materials @@ -102,7 +93,7 @@ public static IFuture ThenSet(this IFuture future, params /// Property name to set the texture /// Array of Materials /// Returns async Future - public static IFuture ThenSet(this IFuture future, string propertyName = "_MainTex", params Material[] materials) - => future.ThenSet((consumer, texture) => consumer.SetTexture(propertyName, texture), materials); + public static IFuture Consume(this IFuture future, string propertyName = "_MainTex", params Material[] materials) + => future.Consume((consumer, texture) => consumer.SetTexture(propertyName, texture), materials); } } diff --git a/Assets/_PackageRoot/Runtime/Future/Future.ThenSet.cs.meta b/Assets/_PackageRoot/Runtime/Future/Future.Consume.cs.meta similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.ThenSet.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Future.Consume.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/Future.ThenSetRef.cs b/Assets/_PackageRoot/Runtime/Future/Future.ConsumeRef.cs similarity index 74% rename from Assets/_PackageRoot/Runtime/Future/Future.ThenSetRef.cs rename to Assets/_PackageRoot/Runtime/Future/Future.ConsumeRef.cs index 231d3e4..02a011a 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.ThenSetRef.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.ConsumeRef.cs @@ -13,29 +13,20 @@ public static partial class FutureEx /// Setter function that gets Consumer and loaded object, it should set the object into Consumer /// Array of consumers for injecting /// Returns async Future - public static IFuture> ThenSet(this IFuture> future, Action> setter, params C[] consumers) => future.Then(reference => + public static IFuture> Consume(this IFuture> future, Action> setter, params C[] consumers) => future.Consume(reference => { UniTask.Post(() => // using only MainThread to set any images to any targets { foreach (var consumer in consumers) { - if (consumer == null) + if (ReferenceEquals(consumer, null) || consumer == null) { if (future.LogLevel.IsActive(DebugLevel.Warning)) Debug.LogWarning($"[ImageLoader] Future[id={future.Id}] The target is null. Can't set image into it. Skipping."); continue; } - if (consumer is UnityEngine.Object unityObject) - { - if (unityObject.IsNull()) - { - if (future.LogLevel.IsActive(DebugLevel.Warning)) - Debug.LogWarning($"The target ({typeof(T).Name}) is destroyed. Can't set image into it. Skipping."); - continue; - } - } - setter?.Invoke(consumer, reference); + Safe.Run(setter, consumer, reference, future.LogLevel); // ┌────────────────────────┬─────────────────────────────────────────────────────┐ // │ Memory leak protection │ Connection Reference to the Component │ @@ -53,40 +44,40 @@ public static IFuture> ThenSet(this IFuture> fut /// /// Array of Images /// Returns async Future - public static IFuture> ThenSet(this IFuture> future, params Image[] images) - => future.ThenSet((consumer, reference) => consumer.sprite = reference?.Value, images); + public static IFuture> Consume(this IFuture> future, params Image[] images) + => future.Consume((consumer, reference) => consumer.sprite = reference?.Value, images); /// /// Set image into array of RawImages /// /// Array of RawImages /// Returns async Future - public static IFuture> ThenSet(this IFuture> future, params RawImage[] rawImages) - => future.ThenSet((consumer, reference) => consumer.texture = reference?.Value?.texture, rawImages); + public static IFuture> Consume(this IFuture> future, params RawImage[] rawImages) + => future.Consume((consumer, reference) => consumer.texture = reference?.Value?.texture, rawImages); /// /// Set image into array of RawImages /// /// Array of RawImages /// Returns async Future - public static IFuture> ThenSet(this IFuture> future, params RawImage[] rawImages) - => future.ThenSet((consumer, reference) => consumer.texture = reference?.Value, rawImages); + public static IFuture> Consume(this IFuture> future, params RawImage[] rawImages) + => future.Consume((consumer, reference) => consumer.texture = reference?.Value, rawImages); /// /// Set image into array of SpriteRenderers /// /// Array of SpriteRenderers /// Returns async Future - public static IFuture> ThenSet(this IFuture> future, params SpriteRenderer[] spriteRenderers) - => future.ThenSet((consumer, reference) => consumer.sprite = reference?.Value, spriteRenderers); + public static IFuture> Consume(this IFuture> future, params SpriteRenderer[] spriteRenderers) + => future.Consume((consumer, reference) => consumer.sprite = reference?.Value, spriteRenderers); /// /// Set image into array of Materials /// /// Array of Materials /// Returns async Future - public static IFuture> ThenSet(this IFuture> future, params Material[] materials) - => future.ThenSet("_MainTex", materials); + public static IFuture> Consume(this IFuture> future, params Material[] materials) + => future.Consume("_MainTex", materials); /// /// Set image into array of Materials @@ -94,16 +85,16 @@ public static IFuture> ThenSet(this IFuture> /// Property name to set the texture /// Array of Materials /// Returns async Future - public static IFuture> ThenSet(this IFuture> future, string propertyName = "_MainTex", params Material[] materials) - => future.ThenSet((consumer, reference) => consumer.SetTexture(propertyName, reference?.Value?.texture), materials); + public static IFuture> Consume(this IFuture> future, string propertyName = "_MainTex", params Material[] materials) + => future.Consume((consumer, reference) => consumer.SetTexture(propertyName, reference?.Value?.texture), materials); /// /// Set image into array of Materials /// /// Array of Materials /// Returns async Future - public static IFuture> ThenSet(this IFuture> future, params Material[] materials) - => future.ThenSet("_MainTex", materials); + public static IFuture> Consume(this IFuture> future, params Material[] materials) + => future.Consume("_MainTex", materials); /// /// Set image into array of Materials @@ -111,7 +102,7 @@ public static IFuture> ThenSet(this IFutureProperty name to set the texture /// Array of Materials /// Returns async Future - public static IFuture> ThenSet(this IFuture> future, string propertyName = "_MainTex", params Material[] materials) - => future.ThenSet((consumer, reference) => consumer.SetTexture(propertyName, reference?.Value), materials); + public static IFuture> Consume(this IFuture> future, string propertyName = "_MainTex", params Material[] materials) + => future.Consume((consumer, reference) => consumer.SetTexture(propertyName, reference?.Value), materials); } } diff --git a/Assets/_PackageRoot/Runtime/Future/Future.ThenSetRef.cs.meta b/Assets/_PackageRoot/Runtime/Future/Future.ConsumeRef.cs.meta similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.ThenSetRef.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Future.ConsumeRef.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Empty.cs b/Assets/_PackageRoot/Runtime/Future/Future.Empty.cs index 1337181..1ff5104 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.Empty.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.Empty.cs @@ -20,7 +20,7 @@ public static IFuture EmptyLoading(string url = null, FutureLoadingFrom from public static IFuture EmptyLoaded(string url = null, FutureLoadedFrom from = FutureLoadedFrom.Source, T value = default) { var future = new FutureEmpty(url).SetLogLevel(DebugLevel.None); - ((IFutureInternal)future).Loaded(value, from); + ((IFutureInternal)future).SetLoaded(value, from); return future; } diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Loading.cs b/Assets/_PackageRoot/Runtime/Future/Future.Loading.cs index a9ebb88..25a3b44 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.Loading.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.Loading.cs @@ -35,7 +35,7 @@ internal async UniTask InternalLoading(bool ignoreImageNotFoundError = false) var cachedObj = LoadFromMemoryCache(Url); if (cachedObj != null) { - ((IFutureInternal)this).Loaded(cachedObj, FutureLoadedFrom.MemoryCache); + ((IFutureInternal)this).SetLoaded(cachedObj, FutureLoadedFrom.MemoryCache); return; } } @@ -89,7 +89,7 @@ internal async UniTask InternalLoading(bool ignoreImageNotFoundError = false) RemoveLoading(); // LOADING REMOVED if (IsCancelled || Status == FutureStatus.FailedToLoad) return; - ((IFutureInternal)this).Loaded(loadedObj, FutureLoadedFrom.DiskCache); + ((IFutureInternal)this).SetLoaded(loadedObj, FutureLoadedFrom.DiskCache); return; } } @@ -214,7 +214,7 @@ internal async UniTask InternalLoading(bool ignoreImageNotFoundError = false) SaveToMemoryCache(downloadedObj, replace: true); RemoveLoading(); // LOADING REMOVED - ((IFutureInternal)this).Loaded(downloadedObj, FutureLoadedFrom.Source); + ((IFutureInternal)this).SetLoaded(downloadedObj, FutureLoadedFrom.Source); } protected virtual bool RegisterLoading(out Future anotherLoadingFuture) diff --git a/Assets/_PackageRoot/Runtime/Future/Future.cs b/Assets/_PackageRoot/Runtime/Future/Future.cs index 6238d5a..a5a1dc2 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.cs @@ -101,11 +101,11 @@ public IFuture PassEvents(IFutureInternal to, bool passCancelled = true) if (LogLevel.IsActive(DebugLevel.Trace)) Debug.Log($"[ImageLoader] Future[id={Id}] -> Future[id={to.Id}] Subscribe on events\n{Url}"); - LoadedFromMemoryCache((v) => to.Loaded(v, FutureLoadedFrom.MemoryCache)); + LoadedFromMemoryCache((v) => to.SetLoaded(v, FutureLoadedFrom.MemoryCache)); LoadingFromDiskCache(( ) => to.Loading(FutureLoadingFrom.DiskCache)); - LoadedFromDiskCache((v) => to.Loaded(v, FutureLoadedFrom.DiskCache)); + LoadedFromDiskCache((v) => to.SetLoaded(v, FutureLoadedFrom.DiskCache)); LoadingFromSource(( ) => to.Loading(FutureLoadingFrom.Source)); - LoadedFromSource((v) => to.Loaded(v, FutureLoadedFrom.Source)); + LoadedFromSource((v) => to.SetLoaded(v, FutureLoadedFrom.Source)); Failed(to.FailToLoad); if (passCancelled) @@ -121,11 +121,11 @@ public IFuture PassEvents(IFutureInternal to, Func convert, bo if (LogLevel.IsActive(DebugLevel.Log)) Debug.Log($"[ImageLoader] Future[id={Id}] -> Future[id={to.Id}] Subscribe on events (${typeof(T).Name} -> ${typeof(T2).Name})\n{Url}"); - LoadedFromMemoryCache((v) => to.Loaded(convert(v), FutureLoadedFrom.MemoryCache)); + LoadedFromMemoryCache((v) => to.SetLoaded(convert(v), FutureLoadedFrom.MemoryCache)); LoadingFromDiskCache(( ) => to.Loading(FutureLoadingFrom.DiskCache)); - LoadedFromDiskCache((v) => to.Loaded(convert(v), FutureLoadedFrom.DiskCache)); + LoadedFromDiskCache((v) => to.SetLoaded(convert(v), FutureLoadedFrom.DiskCache)); LoadingFromSource(( ) => to.Loading(FutureLoadingFrom.Source)); - LoadedFromSource((v) => to.Loaded(convert(v), FutureLoadedFrom.Source)); + LoadedFromSource((v) => to.SetLoaded(convert(v), FutureLoadedFrom.Source)); Failed(to.FailToLoad); if (passCancelled) @@ -162,7 +162,7 @@ void IFutureInternal.Loading(FutureLoadingFrom loadingFrom) Safe.Run(onLoadingEvent, LogLevel); ActivatePlaceholder(Status); } - void IFutureInternal.Loaded(T value, FutureLoadedFrom loadedFrom) + void IFutureInternal.SetLoaded(T value, FutureLoadedFrom loadedFrom) { if (cleared || IsCancelled) return; @@ -192,7 +192,7 @@ void IFutureInternal.Loaded(T value, FutureLoadedFrom loadedFrom) Safe.Run(onLoadedEvent, this.value, LogLevel); Safe.Run(OnLoaded, this.value, LogLevel); - ActivatePlaceholder(Status); + FeedConsumers(this.value); Safe.Run(OnCompleted, true, LogLevel); Clear(); } @@ -217,13 +217,15 @@ void ActivatePlaceholder(FutureStatus status) lock (placeholders) { if (placeholders.TryGetValue(status, out var placeholder)) - { - lock (consumers) - { - foreach (var setter in consumers) - Safe.Run(setter, placeholder, LogLevel); - } - } + FeedConsumers(placeholder); + } + } + void FeedConsumers(T value) + { + lock (consumers) + { + foreach (var setter in consumers) + Safe.Run(setter, value, LogLevel); } } diff --git a/Assets/_PackageRoot/Runtime/Future/IFuture.cs b/Assets/_PackageRoot/Runtime/Future/IFuture.cs index a3ed882..2ba84e7 100644 --- a/Assets/_PackageRoot/Runtime/Future/IFuture.cs +++ b/Assets/_PackageRoot/Runtime/Future/IFuture.cs @@ -25,7 +25,7 @@ public partial interface IFuture : IFuture, IDisposable T Value { get; } DebugLevel LogLevel { get; } UniTask StartLoading(bool ignoreImageNotFoundError = false); - IFuture Then(Action onCompleted); + IFuture Loaded(Action onCompleted); IFuture Failed(Action action); IFuture Completed(Action action); IFuture LoadedFromMemoryCache(Action action); @@ -58,7 +58,7 @@ public interface IFutureInternal : IFuture UnityWebRequest WebRequest { get; } void FailToLoad(Exception exception); void Loading(FutureLoadingFrom loadingFrom); - void Loaded(T value, FutureLoadedFrom loadedFrom); + void SetLoaded(T value, FutureLoadedFrom loadedFrom); void SetTimeout(TimeSpan duration); } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Samples/SampleAwaitAndForget.cs b/Assets/_PackageRoot/Samples/SampleAwaitAndForget.cs index 774f8b1..af18d01 100644 --- a/Assets/_PackageRoot/Samples/SampleAwaitAndForget.cs +++ b/Assets/_PackageRoot/Samples/SampleAwaitAndForget.cs @@ -13,11 +13,11 @@ async void Start() await ImageLoader.LoadSprite(imageURL); // Load image, set image and wait - await ImageLoader.LoadSprite(imageURL).ThenSet(image); + await ImageLoader.LoadSprite(imageURL).Consume(image); // Skip waiting for completion. // To do that we can simply remove 'await' from the start. // To avoid compilation warning need to add '.Forget()'. - ImageLoader.LoadSprite(imageURL).ThenSet(image).Forget(); + ImageLoader.LoadSprite(imageURL).Consume(image).Forget(); } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Samples/SampleCancellation.cs b/Assets/_PackageRoot/Samples/SampleCancellation.cs index eb8ff0b..78e245b 100644 --- a/Assets/_PackageRoot/Samples/SampleCancellation.cs +++ b/Assets/_PackageRoot/Samples/SampleCancellation.cs @@ -12,19 +12,19 @@ public class SampleCancellation : MonoBehaviour void Start() { ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .CancelOnDestroy(this) // cancel OnDestroy event of current gameObject .Forget(); ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .Failed(exception => Debug.LogException(exception)) // if fail print exception .CancelOnDestroy(this) // cancel OnDestroy event of current gameObject .Forget(); ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image - .Then(sprite => image.gameObject.SetActive(true)) // if success activate gameObject + .Consume(image) // if success set sprite into image + .Loaded(sprite => image.gameObject.SetActive(true)) // if success activate gameObject .Failed(exception => image.gameObject.SetActive(false)) // if fail deactivate gameObject .Canceled(() => Debug.Log("ImageLoading canceled")) // if cancelled .CancelOnDisable(this) // cancel OnDisable event of current gameObject @@ -34,7 +34,7 @@ void Start() void DestroyWithMonoBehaviour() { ImageLoader.LoadSprite(imageURL) - .ThenSet(image) + .Consume(image) .CancelOnEnable(this) // cancel on OnEnable event of current MonoBehaviour .CancelOnDisable(this) // cancel on OnDisable event of current MonoBehaviour .CancelOnDestroy(this); // cancel on OnDestroy event of current MonoBehaviour @@ -42,7 +42,7 @@ void DestroyWithMonoBehaviour() void SimpleCancellation() { - var future = ImageLoader.LoadSprite(imageURL).ThenSet(image); + var future = ImageLoader.LoadSprite(imageURL).Consume(image); future.Cancel(); } @@ -52,7 +52,7 @@ void CancellationTokenSample1() // loading with attached cancellation token ImageLoader.LoadSprite(imageURL, cancellationToken: cancellationTokenSource.Token) - .ThenSet(image) + .Consume(image) .Forget(); cancellationTokenSource.Cancel(); // canceling @@ -63,7 +63,7 @@ void CancellationTokenSample2() var cancellationTokenSource = new CancellationTokenSource(); ImageLoader.LoadSprite(imageURL) - .ThenSet(image) + .Consume(image) .Register(cancellationTokenSource.Token) // registering cancellation token .Forget(); @@ -72,7 +72,7 @@ void CancellationTokenSample2() void DisposeSample() { - using (var future = ImageLoader.LoadSprite(imageURL).ThenSet(image)) + using (var future = ImageLoader.LoadSprite(imageURL).Consume(image)) { // future would be canceled and disposed outside of the brackets } diff --git a/Assets/_PackageRoot/Samples/SampleErrorHandle.cs b/Assets/_PackageRoot/Samples/SampleErrorHandle.cs index e759f5a..3aaac28 100644 --- a/Assets/_PackageRoot/Samples/SampleErrorHandle.cs +++ b/Assets/_PackageRoot/Samples/SampleErrorHandle.cs @@ -10,13 +10,13 @@ public class SampleErrorHandle : MonoBehaviour void Start() { ImageLoader.LoadSprite(imageURL) // Attempt to load a sprite - .ThenSet(image) // If successful, set the sprite to the Image component + .Consume(image) // If successful, set the sprite to the Image component .Failed(exception => Debug.LogException(exception)) // If an error occurs, log the exception .Forget(); // Forget the task to avoid compilation warning ImageLoader.LoadSprite(imageURL) // Attempt to load a sprite - .ThenSet(image) // If successful, set the sprite to the Image component - .Then(sprite => image.gameObject.SetActive(true)) // If successful, activate the GameObject + .Consume(image) // If successful, set the sprite to the Image component + .Loaded(sprite => image.gameObject.SetActive(true)) // If successful, activate the GameObject .Failed(exception => image.gameObject.SetActive(false)) // If an error occurs, deactivate the GameObject .Forget(); // Forget the task to avoid compilation warning } diff --git a/Assets/_PackageRoot/Samples/SampleLifecycle.cs b/Assets/_PackageRoot/Samples/SampleLifecycle.cs index 18a6adc..c31b4c2 100644 --- a/Assets/_PackageRoot/Samples/SampleLifecycle.cs +++ b/Assets/_PackageRoot/Samples/SampleLifecycle.cs @@ -20,6 +20,17 @@ void Start() .LoadedFromSource (sprite => Debug.Log("Loaded from source")) // on loaded from source │ // ────────────────────────────────────────────────────────────────────────────────────────────────────┘ + // ┌──────────────────────────┬───────────────────────────────────────────┐ + // │ Success lifecycle events │ │ + // └──────────────────────────┘ │ + .Loaded(sprite => Debug.Log("Loaded")) // on successfully loaded │ + // ┌────────────────────────────────────────────────────────┤ + // │ Set/Consume sprite [placeholder, successfully loaded] │ + // └────────────────────────────────────────────────────────┤ + .Consume(sprite => Debug.Log("Consumed")) // │ + .Consume(image) // │ + // ───────────────────────────────────────────────────────────────────────┘ + // ┌───────────────────────────┬──────────────────────────────────────────┐ // │ Negative lifecycle events │ │ // └───────────────────────────┘ │ @@ -27,13 +38,6 @@ void Start() .Failed(exception => Debug.LogException(exception)) // on failed to load │ // ───────────────────────────────────────────────────────────────────────┘ - // ┌──────────────────────────────────────┬──────────────────────────────┐ - // │ Successfully loaded lifecycle events │ │ - // └──────────────────────────────────────┘ │ - .Then(sprite => Debug.Log("Loaded")) // on loaded │ - .ThenSet(image) // on loaded set sprite into image │ - // ──────────────────────────────────────────────────────────────────────┘ - // ┌──────────────────────┬──────────────────────────────────────────────────────────────────────────┐ // │ The end of lifecycle │ │ // └──────────────────────┘ │ diff --git a/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetImage.cs b/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetImage.cs index 96c4346..065b89e 100644 --- a/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetImage.cs +++ b/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetImage.cs @@ -13,6 +13,6 @@ async void Start() image.sprite = await ImageLoader.LoadSprite(imageURL); // Load a sprite from the web and set it directly to the Image component - await ImageLoader.LoadSprite(imageURL).ThenSet(image); + await ImageLoader.LoadSprite(imageURL).Consume(image); } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetIntoMultipleImages.cs b/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetIntoMultipleImages.cs index a27a7ec..74888ce 100644 --- a/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetIntoMultipleImages.cs +++ b/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetIntoMultipleImages.cs @@ -11,6 +11,6 @@ public class SampleLoadSpriteThenSetIntoMultipleImages : MonoBehaviour void Start() { // Loading with auto set to multiple images - ImageLoader.LoadSprite(imageURL).ThenSet(image1, image2).Forget(); + ImageLoader.LoadSprite(imageURL).Consume(image1, image2).Forget(); } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Samples/SampleLoadTextureThenSetMaterial.cs b/Assets/_PackageRoot/Samples/SampleLoadTextureThenSetMaterial.cs index 9bcbe80..f62e9d8 100644 --- a/Assets/_PackageRoot/Samples/SampleLoadTextureThenSetMaterial.cs +++ b/Assets/_PackageRoot/Samples/SampleLoadTextureThenSetMaterial.cs @@ -12,6 +12,6 @@ async void Start() material.mainTexture = await ImageLoader.LoadTexture(imageURL); // Load a Texture2D from the web and set it directly to the Material - await ImageLoader.LoadTexture(imageURL).ThenSet(material); + await ImageLoader.LoadTexture(imageURL).Consume(material); } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Samples/SampleReferences.cs b/Assets/_PackageRoot/Samples/SampleReferences.cs index c40a902..d62af51 100644 --- a/Assets/_PackageRoot/Samples/SampleReferences.cs +++ b/Assets/_PackageRoot/Samples/SampleReferences.cs @@ -10,12 +10,12 @@ public class SampleReferences : MonoBehaviour void Start() { ImageLoader.LoadSpriteRef(imageURL) // load sprite using Reference - .ThenSet(image) // if success set sprite into image, also creates binding to `image` + .Consume(image) // if success set sprite into image, also creates binding to `image` .Forget(); ImageLoader.LoadSpriteRef(imageURL) // load sprite using Reference - .Then(reference => reference.DisposeOnDestroy(this)) - .Then(reference => + .Loaded(reference => reference.DisposeOnDestroy(this)) + .Loaded(reference => { var sprite = reference.Value; // use sprite diff --git a/Assets/_PackageRoot/Samples/SampleTimeout.cs b/Assets/_PackageRoot/Samples/SampleTimeout.cs index 353dd68..b1d54cf 100644 --- a/Assets/_PackageRoot/Samples/SampleTimeout.cs +++ b/Assets/_PackageRoot/Samples/SampleTimeout.cs @@ -11,7 +11,7 @@ public class SampleTimeout : MonoBehaviour void Start() { ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .Timeout(TimeSpan.FromSeconds(10)) // set timeout duration 10 seconds .Forget(); } diff --git a/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs index 8cdec16..4ebf13a 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs @@ -58,6 +58,6 @@ public void Cancel() public IFuture SetUseDiskCache(bool value = true) => throw new NotImplementedException(); public IFuture SetUseMemoryCache(bool value = true) => throw new NotImplementedException(); public UniTask StartLoading(bool ignoreImageNotFoundError = false) => throw new NotImplementedException(); - public IFuture Then(Action onCompleted) => throw new NotImplementedException(); + public IFuture Loaded(Action onCompleted) => throw new NotImplementedException(); } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFutureInternal.cs b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFutureInternal.cs index 7cdcf8c..27836c7 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFutureInternal.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFutureInternal.cs @@ -17,7 +17,7 @@ public void Loading(FutureLoadingFrom loadingFrom) events.Add(new EventData { name = eventName }); } - public void Loaded(T value, FutureLoadedFrom loadedFrom) + public void SetLoaded(T value, FutureLoadedFrom loadedFrom) { if (LogLevel.IsActive(DebugLevel.Trace)) UnityEngine.Debug.Log($"FakeFuture[id={Id}] Loaded from {loadedFrom}"); diff --git a/Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs b/Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs index 5e6223c..d29cfe8 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs @@ -2,7 +2,7 @@ namespace Extensions.Unity.ImageLoader.Tests.Utils { public static class FutureEx { - public static FutureListener ToFutureListener(this IFuture future, bool ignoreLoadingWhenLoaded = false) - => new FutureListener(future, ignoreLoadingWhenLoaded: ignoreLoadingWhenLoaded); + public static FutureListener ToFutureListener(this IFuture future, bool ignoreLoadingWhenLoaded = false, bool ignorePlaceholder = false) + => new FutureListener(future, ignoreLoadingWhenLoaded: ignoreLoadingWhenLoaded, ignorePlaceholder: ignorePlaceholder); } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs index 1063d1d..9aa38b4 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs @@ -17,7 +17,7 @@ public IReadOnlyList Events } } - public FutureListener(IFuture future, bool ignoreLoadingWhenLoaded = false, DebugLevel? logLevel = null) + public FutureListener(IFuture future, bool ignoreLoadingWhenLoaded = false, bool ignorePlaceholder = false, DebugLevel? logLevel = null) { if (logLevel == null) logLevel = ImageLoader.settings.debugLevel; @@ -59,13 +59,23 @@ public FutureListener(IFuture future, bool ignoreLoadingWhenLoaded = false, D lock (events) events.Add(new EventData { name = EventName.LoadedFromSource, value = value }); }); - future.Then(value => + future.Loaded(value => { if (logLevel.Value.IsActive(DebugLevel.Trace)) Debug.Log($"[FutureListener] Future[id={future.Id}] Then: {value}"); lock (events) events.Add(new EventData { name = EventName.Then, value = value }); }); + if (ignorePlaceholder) + { + future.Consume(value => + { + if (logLevel.Value.IsActive(DebugLevel.Trace)) + Debug.Log($"[FutureListener] Future[id={future.Id}] Consume: {value}"); + lock (events) + events.Add(new EventData { name = EventName.Consume, value = value }); + }); + } future.Failed(exception => { if (logLevel.Value.IsActive(DebugLevel.Trace)) @@ -90,13 +100,6 @@ public FutureListener(IFuture future, bool ignoreLoadingWhenLoaded = false, D lock (events) events.Add(new EventData { name = EventName.Completed, value = value }); }); - future.Consume(value => - { - if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] Consume: {value}"); - lock (events) - events.Add(new EventData { name = EventName.Consume, value = value }); - }); } } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs index 4e373ac..4732c1b 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs @@ -9,10 +9,18 @@ namespace Extensions.Unity.ImageLoader.Tests.Utils public static partial class TestUtils { public static IEnumerator LoadFromMemoryCache(string url) => Load(url, null, FutureLoadedFrom.MemoryCache); - public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFrom, FutureLoadedFrom expectedLoadedFrom) + public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFrom, FutureLoadedFrom expectedLoadedFrom, bool usePlaceholder = false) { var future = ImageLoader.LoadSprite(url); - var futureListener = future.ToFutureListener(); + var futureListener = future.ToFutureListener(ignorePlaceholder: !usePlaceholder); + + if (usePlaceholder) + { + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromDiskCache], FuturePlaceholderTrigger.LoadingFromDiskCache); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromSource], FuturePlaceholderTrigger.LoadingFromSource); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.FailedToLoad], FuturePlaceholderTrigger.FailedToLoad); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.Canceled], FuturePlaceholderTrigger.Canceled); + } if (expectedLoadingFrom.HasValue) futureListener.Assert_Events_Contains(expectedLoadingFrom.Value.ToEventName()); @@ -55,12 +63,6 @@ public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFro yield return UniTask.Yield(); } public static IEnumerator LoadFromMemoryCacheThenCancel(string url, bool useGC) => LoadThenCancel(url, null, FutureLoadedFrom.MemoryCache, useGC); - - // public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expectedLoadingFrom, FutureLoadedFrom expectedLoadedFrom) - // { - // yield return LoadThenCancel(url, expectedLoadingFrom, expectedLoadedFrom, useGC: true); - // yield return LoadThenCancel(url, expectedLoadingFrom, expectedLoadedFrom, useGC: false); - // } public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expectedLoadingFrom, FutureLoadedFrom expectedLoadedFrom, bool useGC) { var future = ImageLoader.LoadSprite(url); diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs index 46109e0..5f3fb9d 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs @@ -3,55 +3,63 @@ using System.Linq; using Cysharp.Threading.Tasks; using NUnit.Framework; +using UnityEngine; +using UnityEngine.UI; namespace Extensions.Unity.ImageLoader.Tests.Utils { public static partial class TestUtils { - public static IEnumerator PlaceholderFromMemoryCache(string url) => Placeholder(url, null, FutureLoadedFrom.MemoryCache); - public static IEnumerator Placeholder(string url, FutureLoadingFrom? expectedLoadingFrom, FutureLoadedFrom expectedLoadedFrom) + // public static IEnumerator PlaceholderFromMemoryCache(string url) => Placeholder(url, null, FutureLoadedFrom.MemoryCache); + public static IEnumerator Placeholder(string url, params FuturePlaceholderTrigger[] triggers) { var future = ImageLoader.LoadSprite(url); var futureListener = future.ToFutureListener(); - if (expectedLoadingFrom.HasValue) - futureListener.Assert_Events_Contains(expectedLoadingFrom.Value.ToEventName()); + var spritePlaceholder = Texture2D.whiteTexture.ToSprite(); - var task1 = future.AsTask(); - yield return future.TimeoutCoroutine(TimeSpan.FromSeconds(10)); - var task2 = future.AsTask(); + future.SetPlaceholder(spritePlaceholder, triggers); - futureListener.Assert_Events_NotContains(EventName.Canceled); - if (expectedLoadingFrom.HasValue) - futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); - else - futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + // var loadedFromMemoryCache = triggers.Contains(FuturePlaceholderTrigger.LoadedFromMemoryCache); + // if (triggers.Any.HasValue) + // futureListener.Assert_Events_Contains(expectedLoadingFrom.Value.ToEventName()); - futureListener.Assert_Events_Value(EventName.Completed, success => success == true); + // var task1 = future.AsTask(); + // yield return future.TimeoutCoroutine(TimeSpan.FromSeconds(10)); + // var task2 = future.AsTask(); - Assert.IsTrue(task1.IsCompleted, "Task was not cancelled but Future was cancelled"); - Assert.IsTrue(task2.IsCompleted, "Task was not cancelled but Future was cancelled"); + // futureListener.Assert_Events_NotContains(EventName.Canceled); - yield return UniTask.Yield(); + // if (expectedLoadingFrom.HasValue) + // futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + // else + // futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + + // futureListener.Assert_Events_Value(EventName.Completed, success => success == true); + + // Assert.IsTrue(task1.IsCompleted, "Task was not cancelled but Future was cancelled"); + // Assert.IsTrue(task2.IsCompleted, "Task was not cancelled but Future was cancelled"); + + // yield return UniTask.Yield(); - if (expectedLoadingFrom.HasValue) - futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); - else - futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + // if (expectedLoadingFrom.HasValue) + // futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + // else + // futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); - futureListener.Assert_Events_Value(EventName.Completed, success => success == true); + // futureListener.Assert_Events_Value(EventName.Completed, success => success == true); - future.ToFutureListener(ignoreLoadingWhenLoaded: true) - .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) - .Assert_Events_Value(EventName.Completed, success => success == true); + // future.ToFutureListener(ignoreLoadingWhenLoaded: true) + // .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) + // .Assert_Events_Value(EventName.Completed, success => success == true); - if (expectedLoadingFrom.HasValue) - future.ToFutureListener() - .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) - .Assert_Events_Value(EventName.Completed, success => success == true); + // if (expectedLoadingFrom.HasValue) + // future.ToFutureListener() + // .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) + // .Assert_Events_Value(EventName.Completed, success => success == true); - future.Dispose(); + // future.Dispose(); yield return UniTask.Yield(); } } diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs index 9bc4988..418834a 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs @@ -20,6 +20,14 @@ public static partial class TestUtils public static IEnumerable IncorrectImageURLs(int count = 3) => Enumerable.Range(0, count).Select(_ => IncorrectImageURL); public static readonly byte[] CorruptedTextureBytes = new byte[] { 0 }; + public static readonly Dictionary placeholderSprites = new Dictionary + { + { FuturePlaceholderTrigger.LoadingFromDiskCache, Texture2D.whiteTexture.ToSprite() }, + { FuturePlaceholderTrigger.LoadingFromSource, Texture2D.blackTexture.ToSprite() }, + { FuturePlaceholderTrigger.FailedToLoad, Texture2D.redTexture.ToSprite() }, + { FuturePlaceholderTrigger.Canceled, Texture2D.grayTexture.ToSprite() } + }; + public static IEnumerator ClearEverything(string message) { if (message != null) diff --git a/Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs b/Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs index 7f9519e..151e016 100644 --- a/Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs +++ b/Assets/_PackageRoot/Tests/Editor/TestFuture.Placeholder.cs @@ -6,49 +6,49 @@ namespace Extensions.Unity.ImageLoader.Tests { public partial class TestFuture { - [UnityTest] public IEnumerator Placeholder_Source_NoLogs() => TestUtils.RunNoLogs(Placeholder_Source); - [UnityTest] public IEnumerator Placeholder_Source() - { - yield return Placeholder_Source(useDiskCache: true, useMemoryCache: true); - yield return Placeholder_Source(useDiskCache: true, useMemoryCache: false); - yield return Placeholder_Source(useDiskCache: false, useMemoryCache: true); - yield return Placeholder_Source(useDiskCache: false, useMemoryCache: false); - } - IEnumerator Placeholder_Source(bool useDiskCache, bool useMemoryCache) - { - ImageLoader.settings.useDiskCache = useDiskCache; - ImageLoader.settings.useMemoryCache = useMemoryCache; + // [UnityTest] public IEnumerator Placeholder_Source_NoLogs() => TestUtils.RunNoLogs(Placeholder_Source); + // [UnityTest] public IEnumerator Placeholder_Source() + // { + // yield return Placeholder_Source(useDiskCache: true, useMemoryCache: true); + // yield return Placeholder_Source(useDiskCache: true, useMemoryCache: false); + // yield return Placeholder_Source(useDiskCache: false, useMemoryCache: true); + // yield return Placeholder_Source(useDiskCache: false, useMemoryCache: false); + // } + // IEnumerator Placeholder_Source(bool useDiskCache, bool useMemoryCache) + // { + // ImageLoader.settings.useDiskCache = useDiskCache; + // ImageLoader.settings.useMemoryCache = useMemoryCache; - foreach (var url in TestUtils.ImageURLs) - yield return TestUtils.Placeholder(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source); + // foreach (var url in TestUtils.ImageURLs) + // yield return TestUtils.Placeholder(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source); - yield return TestUtils.ClearEverything(message: null); - } + // yield return TestUtils.ClearEverything(message: null); + // } - [UnityTest] public IEnumerator Placeholder_DiskCache_NoLogs() => TestUtils.RunNoLogs(Placeholder_DiskCache); - [UnityTest] public IEnumerator Placeholder_DiskCache() - { - ImageLoader.settings.useDiskCache = true; - ImageLoader.settings.useMemoryCache = false; + // [UnityTest] public IEnumerator Placeholder_DiskCache_NoLogs() => TestUtils.RunNoLogs(Placeholder_DiskCache); + // [UnityTest] public IEnumerator Placeholder_DiskCache() + // { + // ImageLoader.settings.useDiskCache = true; + // ImageLoader.settings.useMemoryCache = false; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.Placeholder(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache); - } - } + // foreach (var url in TestUtils.ImageURLs) + // { + // yield return ImageLoader.LoadSprite(url).AsCoroutine(); + // yield return TestUtils.Placeholder(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache); + // } + // } - [UnityTest] public IEnumerator Placeholder_MemoryCache_NoLogs() => TestUtils.RunNoLogs(Placeholder_MemoryCache); - [UnityTest] public IEnumerator Placeholder_MemoryCache() - { - ImageLoader.settings.useDiskCache = true; - ImageLoader.settings.useMemoryCache = true; + // [UnityTest] public IEnumerator Placeholder_MemoryCache_NoLogs() => TestUtils.RunNoLogs(Placeholder_MemoryCache); + // [UnityTest] public IEnumerator Placeholder_MemoryCache() + // { + // ImageLoader.settings.useDiskCache = true; + // ImageLoader.settings.useMemoryCache = true; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadFromMemoryCache(url); - } - } + // foreach (var url in TestUtils.ImageURLs) + // { + // yield return ImageLoader.LoadSprite(url).AsCoroutine(); + // yield return TestUtils.LoadFromMemoryCache(url); + // } + // } } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs b/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs index 356230a..e829653 100644 --- a/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs @@ -24,7 +24,7 @@ [UnityTest] public IEnumerator EventsLoadedWhenClear() var startTime = DateTime.Now; var future = new FutureSprite(url); - var futureListener = new FutureListener(future); + var futureListener = new FutureListener(future, ignorePlaceholder: true); var task = future.StartLoading().AsTask(); yield return task.TimeoutCoroutine(TimeSpan.FromSeconds(10)); From 86bc72cbc1431b94251a2936204d853fb87b5976 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 6 Mar 2025 00:21:28 -0800 Subject: [PATCH 13/33] Renamed EventName.Then -> EventName.Loaded --- .../Tests/Base/Utils/EventName.cs | 6 ++--- .../Tests/Base/Utils/FutureListener.cs | 6 ++--- .../Tests/Base/Utils/TestUtils.Load.cs | 26 +++++++++---------- .../Tests/Editor/TestFutureOrder.cs | 4 +-- .../Tests/Runtime/TestFutureOrder.cs | 4 +-- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Assets/_PackageRoot/Tests/Base/Utils/EventName.cs b/Assets/_PackageRoot/Tests/Base/Utils/EventName.cs index 014fb5e..7483e8d 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/EventName.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/EventName.cs @@ -10,11 +10,11 @@ public enum EventName LoadedFromDiskCache, LoadingFromSource, LoadedFromSource, - Then, + Loaded, + Consumed, Failed, Completed, - Canceled, - Consume + Canceled } public static class EventNameEx diff --git a/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs index 9aa38b4..23ba354 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs @@ -64,16 +64,16 @@ public FutureListener(IFuture future, bool ignoreLoadingWhenLoaded = false, b if (logLevel.Value.IsActive(DebugLevel.Trace)) Debug.Log($"[FutureListener] Future[id={future.Id}] Then: {value}"); lock (events) - events.Add(new EventData { name = EventName.Then, value = value }); + events.Add(new EventData { name = EventName.Loaded, value = value }); }); - if (ignorePlaceholder) + if (!ignorePlaceholder) { future.Consume(value => { if (logLevel.Value.IsActive(DebugLevel.Trace)) Debug.Log($"[FutureListener] Future[id={future.Id}] Consume: {value}"); lock (events) - events.Add(new EventData { name = EventName.Consume, value = value }); + events.Add(new EventData { name = EventName.Consumed, value = value }); }); } future.Failed(exception => diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs index 4732c1b..bab34eb 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs @@ -32,9 +32,9 @@ public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFro futureListener.Assert_Events_NotContains(EventName.Canceled); if (expectedLoadingFrom.HasValue) - futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); else - futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); futureListener.Assert_Events_Value(EventName.Completed, success => success == true); @@ -44,19 +44,19 @@ public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFro yield return UniTask.Yield(); if (expectedLoadingFrom.HasValue) - futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); else - futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); futureListener.Assert_Events_Value(EventName.Completed, success => success == true); future.ToFutureListener(ignoreLoadingWhenLoaded: true) - .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) + .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); if (expectedLoadingFrom.HasValue) future.ToFutureListener() - .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) + .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); future.Dispose(); @@ -83,9 +83,9 @@ public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expected future.Cancel(); if (expectedLoadingFrom.HasValue) - futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); else - futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); futureListener.Assert_Events_Value(EventName.Completed, success => success == true); @@ -95,19 +95,19 @@ public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expected yield return UniTask.Yield(); if (expectedLoadingFrom.HasValue) - futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); else - futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); + futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); futureListener.Assert_Events_Value(EventName.Completed, success => success == true); future.ToFutureListener(ignoreLoadingWhenLoaded: true) - .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) + .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); if (expectedLoadingFrom.HasValue) future.ToFutureListener() - .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) + .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); future.Dispose(); @@ -137,7 +137,7 @@ public static IEnumerator LoadAndCancel(string url, FutureLoadingFrom? expectedL var task2 = future.AsTask(); var events = shouldLoadFromMemoryCache - ? new [] { EventName.LoadedFromMemoryCache, EventName.Then, EventName.Completed } + ? new [] { EventName.LoadedFromMemoryCache, EventName.Loaded, EventName.Completed } : new [] { expectedLoadingFrom.Value.ToEventName(), EventName.Canceled, EventName.Completed }; futureListener.Assert_Events_Equals(events); diff --git a/Assets/_PackageRoot/Tests/Editor/TestFutureOrder.cs b/Assets/_PackageRoot/Tests/Editor/TestFutureOrder.cs index 356230a..f9e401a 100644 --- a/Assets/_PackageRoot/Tests/Editor/TestFutureOrder.cs +++ b/Assets/_PackageRoot/Tests/Editor/TestFutureOrder.cs @@ -32,11 +32,11 @@ [UnityTest] public IEnumerator EventsLoadedWhenClear() { EventName.LoadingFromSource, EventName.LoadedFromSource, - EventName.Then, + EventName.Loaded, EventName.Completed }); futureListener.Assert_Events_Value(EventName.LoadedFromSource, sprite => sprite != null); - futureListener.Assert_Events_Value(EventName.Then, sprite => sprite != null); + futureListener.Assert_Events_Value(EventName.Loaded, sprite => sprite != null); futureListener.Assert_Events_Value(EventName.Completed, success => ((bool)success) == true); futureListener.Assert_Events_NotContains(EventName.Canceled); diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs b/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs index e829653..b6b89bf 100644 --- a/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs @@ -32,11 +32,11 @@ [UnityTest] public IEnumerator EventsLoadedWhenClear() { EventName.LoadingFromSource, EventName.LoadedFromSource, - EventName.Then, + EventName.Loaded, EventName.Completed }); futureListener.Assert_Events_Value(EventName.LoadedFromSource, sprite => sprite != null); - futureListener.Assert_Events_Value(EventName.Then, sprite => sprite != null); + futureListener.Assert_Events_Value(EventName.Loaded, sprite => sprite != null); futureListener.Assert_Events_Value(EventName.Completed, success => ((bool)success) == true); futureListener.Assert_Events_NotContains(EventName.Canceled); From 0634bc85e07c5fafcd88c4d575bbb3a63bddb63a Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 6 Mar 2025 01:09:36 -0800 Subject: [PATCH 14/33] Fixed tests --- Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs | 2 +- Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs b/Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs index d29cfe8..95935c8 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/FutureEx.cs @@ -2,7 +2,7 @@ namespace Extensions.Unity.ImageLoader.Tests.Utils { public static class FutureEx { - public static FutureListener ToFutureListener(this IFuture future, bool ignoreLoadingWhenLoaded = false, bool ignorePlaceholder = false) + public static FutureListener ToFutureListener(this IFuture future, bool ignoreLoadingWhenLoaded = false, bool ignorePlaceholder = true) => new FutureListener(future, ignoreLoadingWhenLoaded: ignoreLoadingWhenLoaded, ignorePlaceholder: ignorePlaceholder); } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs index 23ba354..149aff7 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs @@ -17,7 +17,7 @@ public IReadOnlyList Events } } - public FutureListener(IFuture future, bool ignoreLoadingWhenLoaded = false, bool ignorePlaceholder = false, DebugLevel? logLevel = null) + public FutureListener(IFuture future, bool ignoreLoadingWhenLoaded = false, bool ignorePlaceholder = true, DebugLevel? logLevel = null) { if (logLevel == null) logLevel = ImageLoader.settings.debugLevel; @@ -62,7 +62,7 @@ public FutureListener(IFuture future, bool ignoreLoadingWhenLoaded = false, b future.Loaded(value => { if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] Then: {value}"); + Debug.Log($"[FutureListener] Future[id={future.Id}] Loaded: {value}"); lock (events) events.Add(new EventData { name = EventName.Loaded, value = value }); }); From 703cf61f6c76940d5522fdbc21e36a836d5741ba Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 6 Mar 2025 01:15:55 -0800 Subject: [PATCH 15/33] Integrating placeholder tests --- .../Tests/Base/Utils/TestUtils.Load.cs | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs index bab34eb..6309a3d 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs @@ -8,7 +8,7 @@ namespace Extensions.Unity.ImageLoader.Tests.Utils { public static partial class TestUtils { - public static IEnumerator LoadFromMemoryCache(string url) => Load(url, null, FutureLoadedFrom.MemoryCache); + public static IEnumerator LoadFromMemoryCache(string url, bool usePlaceholder = false) => Load(url, null, FutureLoadedFrom.MemoryCache, usePlaceholder); public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFrom, FutureLoadedFrom expectedLoadedFrom, bool usePlaceholder = false) { var future = ImageLoader.LoadSprite(url); @@ -50,23 +50,32 @@ public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFro futureListener.Assert_Events_Value(EventName.Completed, success => success == true); - future.ToFutureListener(ignoreLoadingWhenLoaded: true) + future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: !usePlaceholder) .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); if (expectedLoadingFrom.HasValue) - future.ToFutureListener() + future.ToFutureListener(ignorePlaceholder: !usePlaceholder) .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); future.Dispose(); yield return UniTask.Yield(); } - public static IEnumerator LoadFromMemoryCacheThenCancel(string url, bool useGC) => LoadThenCancel(url, null, FutureLoadedFrom.MemoryCache, useGC); - public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expectedLoadingFrom, FutureLoadedFrom expectedLoadedFrom, bool useGC) + public static IEnumerator LoadFromMemoryCacheThenCancel(string url, bool useGC, bool usePlaceholder = false) + => LoadThenCancel(url, null, FutureLoadedFrom.MemoryCache, useGC, usePlaceholder); + public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expectedLoadingFrom, FutureLoadedFrom expectedLoadedFrom, bool useGC, bool usePlaceholder = false) { var future = ImageLoader.LoadSprite(url); - var futureListener = future.ToFutureListener(); + var futureListener = future.ToFutureListener(ignorePlaceholder: !usePlaceholder); + + if (usePlaceholder) + { + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromDiskCache], FuturePlaceholderTrigger.LoadingFromDiskCache); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromSource], FuturePlaceholderTrigger.LoadingFromSource); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.FailedToLoad], FuturePlaceholderTrigger.FailedToLoad); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.Canceled], FuturePlaceholderTrigger.Canceled); + } if (expectedLoadingFrom.HasValue) futureListener.Assert_Events_Contains(expectedLoadingFrom.Value.ToEventName()); @@ -101,30 +110,38 @@ public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expected futureListener.Assert_Events_Value(EventName.Completed, success => success == true); - future.ToFutureListener(ignoreLoadingWhenLoaded: true) + future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: !usePlaceholder) .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); if (expectedLoadingFrom.HasValue) - future.ToFutureListener() + future.ToFutureListener(ignorePlaceholder: !usePlaceholder) .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); future.Dispose(); yield return UniTask.Yield(); } - public static IEnumerator LoadFromMemoryCacheAndCancel(string url) => LoadAndCancel(url, null); - public static IEnumerator LoadAndCancel(string url, FutureLoadingFrom? expectedLoadingFrom) + public static IEnumerator LoadFromMemoryCacheAndCancel(string url, bool usePlaceholder = false) => LoadAndCancel(url, null, usePlaceholder); + public static IEnumerator LoadAndCancel(string url, FutureLoadingFrom? expectedLoadingFrom, bool usePlaceholder = false) { - yield return LoadAndCancel(url, expectedLoadingFrom, useGC: true); - yield return LoadAndCancel(url, expectedLoadingFrom, useGC: false); + yield return LoadAndCancel(url, expectedLoadingFrom, useGC: true, usePlaceholder); + yield return LoadAndCancel(url, expectedLoadingFrom, useGC: false, usePlaceholder); } - public static IEnumerator LoadAndCancel(string url, FutureLoadingFrom? expectedLoadingFrom, bool useGC) + public static IEnumerator LoadAndCancel(string url, FutureLoadingFrom? expectedLoadingFrom, bool useGC, bool usePlaceholder = false) { var future = ImageLoader.LoadSprite(url); - var futureListener = future.ToFutureListener(); + var futureListener = future.ToFutureListener(ignorePlaceholder: !usePlaceholder); var shouldLoadFromMemoryCache = !expectedLoadingFrom.HasValue; + if (usePlaceholder) + { + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromDiskCache], FuturePlaceholderTrigger.LoadingFromDiskCache); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromSource], FuturePlaceholderTrigger.LoadingFromSource); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.FailedToLoad], FuturePlaceholderTrigger.FailedToLoad); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.Canceled], FuturePlaceholderTrigger.Canceled); + } + futureListener.Assert_Events_Contains(expectedLoadingFrom.HasValue ? expectedLoadingFrom.Value.ToEventName() : EventName.LoadedFromMemoryCache); @@ -151,12 +168,12 @@ public static IEnumerator LoadAndCancel(string url, FutureLoadingFrom? expectedL futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == shouldLoadFromMemoryCache); - future.ToFutureListener() + future.ToFutureListener(ignorePlaceholder: !usePlaceholder) .Assert_Events_Equals(events) .Assert_Events_Value(EventName.Completed, success => success == shouldLoadFromMemoryCache); if (expectedLoadingFrom.HasValue && future.IsLoaded) - future.ToFutureListener(ignoreLoadingWhenLoaded: true) + future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: !usePlaceholder) .Assert_Events_Equals(events.Except(new [] { expectedLoadingFrom.Value.ToEventName() })) .Assert_Events_Value(EventName.Completed, success => success == shouldLoadFromMemoryCache); From 574d32649b9573ef39fb15ea5b105fa948486d68 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 6 Mar 2025 01:27:00 -0800 Subject: [PATCH 16/33] Add SetPlaceholder method to IFuture interface and update related implementations --- .../Runtime/Future/Future.Placeholder.cs | 5 ++++- Assets/_PackageRoot/Runtime/Future/IFuture.cs | 1 + .../Utils/FakeFuture.Implementation.IFuture.cs | 1 + .../Tests/Base/Utils/TestUtils.LoadFail.cs | 18 +++++++++++++----- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs index 56bffe2..95406e0 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs @@ -5,8 +5,11 @@ namespace Extensions.Unity.ImageLoader public partial class Future { /// - /// + /// Set a placeholder for this Future instance /// + /// new placeholder + /// triggers for setting the placeholder + /// Returns the Future instance public IFuture SetPlaceholder(T placeholder, params FuturePlaceholderTrigger[] triggers) { if (cleared || IsCancelled) diff --git a/Assets/_PackageRoot/Runtime/Future/IFuture.cs b/Assets/_PackageRoot/Runtime/Future/IFuture.cs index 2ba84e7..6e67357 100644 --- a/Assets/_PackageRoot/Runtime/Future/IFuture.cs +++ b/Assets/_PackageRoot/Runtime/Future/IFuture.cs @@ -41,6 +41,7 @@ public partial interface IFuture : IFuture, IDisposable IFuture SetUseDiskCache(bool value = true); IFuture SetUseMemoryCache(bool value = true); IFuture SetLogLevel(DebugLevel value); + IFuture SetPlaceholder(T placeholder, params FuturePlaceholderTrigger[] triggers); IFuture PassEvents(IFutureInternal to, bool passCancelled = true); IFuture PassEvents(IFutureInternal to, Func convert, bool passCancelled = true); diff --git a/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs index 4ebf13a..22c3b26 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs @@ -57,6 +57,7 @@ public void Cancel() public IFuture SetLogLevel(DebugLevel value) => throw new NotImplementedException(); public IFuture SetUseDiskCache(bool value = true) => throw new NotImplementedException(); public IFuture SetUseMemoryCache(bool value = true) => throw new NotImplementedException(); + public IFuture SetPlaceholder(T placeholder, params FuturePlaceholderTrigger[] triggers) => throw new NotImplementedException(); public UniTask StartLoading(bool ignoreImageNotFoundError = false) => throw new NotImplementedException(); public IFuture Loaded(Action onCompleted) => throw new NotImplementedException(); } diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs index 3141aec..e1c0375 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs @@ -9,12 +9,20 @@ namespace Extensions.Unity.ImageLoader.Tests.Utils { public static partial class TestUtils { - public static IEnumerator LoadFailFromMemoryCache(string url) => LoadFail(url, null); - public static IEnumerator LoadFail(string url, FutureLoadingFrom? expectedLoadingFrom) + public static IEnumerator LoadFailFromMemoryCache(string url, bool usePlaceholder = false) => LoadFail(url, null, usePlaceholder); + public static IEnumerator LoadFail(string url, FutureLoadingFrom? expectedLoadingFrom, bool usePlaceholder = false) { var timeout = TimeSpan.FromMilliseconds(100); var future = ImageLoader.LoadSprite(url).Timeout(timeout); - var futureListener = future.ToFutureListener(); + var futureListener = future.ToFutureListener(ignorePlaceholder: !usePlaceholder); + + if (usePlaceholder) + { + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromDiskCache], FuturePlaceholderTrigger.LoadingFromDiskCache); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromSource], FuturePlaceholderTrigger.LoadingFromSource); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.FailedToLoad], FuturePlaceholderTrigger.FailedToLoad); + future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.Canceled], FuturePlaceholderTrigger.Canceled); + } if (expectedLoadingFrom.HasValue) futureListener.Assert_Events_Contains(expectedLoadingFrom.Value.ToEventName()); @@ -40,12 +48,12 @@ public static IEnumerator LoadFail(string url, FutureLoadingFrom? expectedLoadin futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == false); - future.ToFutureListener(ignoreLoadingWhenLoaded: true) + future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: !usePlaceholder) .Assert_Events_Equals(events) .Assert_Events_Value(EventName.Completed, success => success == false); if (expectedLoadingFrom.HasValue) - future.ToFutureListener() + future.ToFutureListener(ignorePlaceholder: !usePlaceholder) .Assert_Events_Equals(events) .Assert_Events_Value(EventName.Completed, success => success == false); From e18c2e64d95490ac528211b12b5e96b239d87db9 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 6 Mar 2025 01:30:34 -0800 Subject: [PATCH 17/33] Disabled Player & Build tests for now --- .github/workflows/2019.4.40f1_build.yml | 4 ++-- .github/workflows/2019.4.40f1_player.yml | 4 ++-- .github/workflows/2020.3.40f1_build.yml | 4 ++-- .github/workflows/2020.3.40f1_player.yml | 4 ++-- .github/workflows/2021.3.45f1_build.yml | 4 ++-- .github/workflows/2021.3.45f1_player.yml | 4 ++-- .github/workflows/2022.3.57f1_build.yml | 4 ++-- .github/workflows/2022.3.57f1_player.yml | 4 ++-- .github/workflows/2023.1.20f1_build.yml | 4 ++-- .github/workflows/2023.1.20f1_player.yml | 4 ++-- .github/workflows/2023.2.20f1_build.yml | 4 ++-- .github/workflows/2023.2.20f1_player.yml | 4 ++-- .github/workflows/6000.0.37f1_build.yml | 4 ++-- .github/workflows/6000.0.37f1_player.yml | 4 ++-- 14 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.github/workflows/2019.4.40f1_build.yml b/.github/workflows/2019.4.40f1_build.yml index 8d209c7..ce65c55 100644 --- a/.github/workflows/2019.4.40f1_build.yml +++ b/.github/workflows/2019.4.40f1_build.yml @@ -3,10 +3,10 @@ name: 2019.4.40f1-Build on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/2019.4.40f1_player.yml b/.github/workflows/2019.4.40f1_player.yml index 7171c53..a14c9d9 100644 --- a/.github/workflows/2019.4.40f1_player.yml +++ b/.github/workflows/2019.4.40f1_player.yml @@ -3,10 +3,10 @@ name: 2019.4.40f1-Player on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/2020.3.40f1_build.yml b/.github/workflows/2020.3.40f1_build.yml index a376b6e..e2e95ad 100644 --- a/.github/workflows/2020.3.40f1_build.yml +++ b/.github/workflows/2020.3.40f1_build.yml @@ -3,10 +3,10 @@ name: 2020.3.40f1-Build on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/2020.3.40f1_player.yml b/.github/workflows/2020.3.40f1_player.yml index cd86b5a..e562c6d 100644 --- a/.github/workflows/2020.3.40f1_player.yml +++ b/.github/workflows/2020.3.40f1_player.yml @@ -3,10 +3,10 @@ name: 2020.3.40f1-Player on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/2021.3.45f1_build.yml b/.github/workflows/2021.3.45f1_build.yml index ee5c55f..25677eb 100644 --- a/.github/workflows/2021.3.45f1_build.yml +++ b/.github/workflows/2021.3.45f1_build.yml @@ -3,10 +3,10 @@ name: 2021.3.45f1-Build on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/2021.3.45f1_player.yml b/.github/workflows/2021.3.45f1_player.yml index 77b22c7..d98f817 100644 --- a/.github/workflows/2021.3.45f1_player.yml +++ b/.github/workflows/2021.3.45f1_player.yml @@ -3,10 +3,10 @@ name: 2021.3.45f1-Player on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/2022.3.57f1_build.yml b/.github/workflows/2022.3.57f1_build.yml index a506a05..78666f7 100644 --- a/.github/workflows/2022.3.57f1_build.yml +++ b/.github/workflows/2022.3.57f1_build.yml @@ -3,10 +3,10 @@ name: 2022.3.57f1-Build on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/2022.3.57f1_player.yml b/.github/workflows/2022.3.57f1_player.yml index 9cd081d..ae597ae 100644 --- a/.github/workflows/2022.3.57f1_player.yml +++ b/.github/workflows/2022.3.57f1_player.yml @@ -3,10 +3,10 @@ name: 2022.3.57f1-Player on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/2023.1.20f1_build.yml b/.github/workflows/2023.1.20f1_build.yml index c9b48b4..5a90ec2 100644 --- a/.github/workflows/2023.1.20f1_build.yml +++ b/.github/workflows/2023.1.20f1_build.yml @@ -3,10 +3,10 @@ name: 2023.1.20f1-Build on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/2023.1.20f1_player.yml b/.github/workflows/2023.1.20f1_player.yml index 87cd37c..8569731 100644 --- a/.github/workflows/2023.1.20f1_player.yml +++ b/.github/workflows/2023.1.20f1_player.yml @@ -3,10 +3,10 @@ name: 2023.1.20f1-Player on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/2023.2.20f1_build.yml b/.github/workflows/2023.2.20f1_build.yml index e305a3f..ed9dda3 100644 --- a/.github/workflows/2023.2.20f1_build.yml +++ b/.github/workflows/2023.2.20f1_build.yml @@ -3,10 +3,10 @@ name: 2023.2.20f1-Build on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/2023.2.20f1_player.yml b/.github/workflows/2023.2.20f1_player.yml index dd14f5c..8442eae 100644 --- a/.github/workflows/2023.2.20f1_player.yml +++ b/.github/workflows/2023.2.20f1_player.yml @@ -3,10 +3,10 @@ name: 2023.2.20f1-Player on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/6000.0.37f1_build.yml b/.github/workflows/6000.0.37f1_build.yml index d7d116a..201f329 100644 --- a/.github/workflows/6000.0.37f1_build.yml +++ b/.github/workflows/6000.0.37f1_build.yml @@ -3,10 +3,10 @@ name: 6000.0.37f1-Build on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: diff --git a/.github/workflows/6000.0.37f1_player.yml b/.github/workflows/6000.0.37f1_player.yml index ce84e79..9dd1e64 100644 --- a/.github/workflows/6000.0.37f1_player.yml +++ b/.github/workflows/6000.0.37f1_player.yml @@ -3,10 +3,10 @@ name: 6000.0.37f1-Player on: pull_request: branches: - - master + - master_disabled push: branches: - - master + - master_disabled jobs: editor-tests: From 7b5b384af52cebd2653d04fd574bd919cbeac8cf Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 6 Mar 2025 03:19:02 -0800 Subject: [PATCH 18/33] Refactor event assertions in TestUtils.Load to streamline event handling with placeholders --- .../Tests/Base/Utils/TestUtils.Load.cs | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs index 6309a3d..26a86d9 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs @@ -31,11 +31,15 @@ public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFro futureListener.Assert_Events_NotContains(EventName.Canceled); - if (expectedLoadingFrom.HasValue) - futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); - else - futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); + var events = expectedLoadingFrom.HasValue + ? usePlaceholder + ? new [] { expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed } + : new [] { expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed } + : usePlaceholder + ? new [] { expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed } + : new [] { expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed }; + futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == true); Assert.IsTrue(task1.IsCompleted, "Task was not cancelled but Future was cancelled"); @@ -43,19 +47,19 @@ public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFro yield return UniTask.Yield(); - if (expectedLoadingFrom.HasValue) - futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); - else - futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); - + futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == true); - future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: !usePlaceholder) + future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: true) .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); + future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: false) + .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed) + .Assert_Events_Value(EventName.Completed, success => success == true); + if (expectedLoadingFrom.HasValue) - future.ToFutureListener(ignorePlaceholder: !usePlaceholder) + future.ToFutureListener() .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); @@ -91,11 +95,15 @@ public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expected future.Cancel(); - if (expectedLoadingFrom.HasValue) - futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); - else - futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); + var events = expectedLoadingFrom.HasValue + ? usePlaceholder + ? new [] { expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed } + : new [] { expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed } + : usePlaceholder + ? new [] { expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed } + : new [] { expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed }; + futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == true); Assert.IsTrue(task1.IsCompleted, "Task was not cancelled but Future was cancelled. Probably the OnCancel subscription was cleaned up too early."); @@ -103,19 +111,19 @@ public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expected yield return UniTask.Yield(); - if (expectedLoadingFrom.HasValue) - futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); - else - futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed); - + futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == true); - future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: !usePlaceholder) + future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: true) .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); + future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: false) + .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed) + .Assert_Events_Value(EventName.Completed, success => success == true); + if (expectedLoadingFrom.HasValue) - future.ToFutureListener(ignorePlaceholder: !usePlaceholder) + future.ToFutureListener() .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); @@ -154,8 +162,12 @@ public static IEnumerator LoadAndCancel(string url, FutureLoadingFrom? expectedL var task2 = future.AsTask(); var events = shouldLoadFromMemoryCache - ? new [] { EventName.LoadedFromMemoryCache, EventName.Loaded, EventName.Completed } - : new [] { expectedLoadingFrom.Value.ToEventName(), EventName.Canceled, EventName.Completed }; + ? usePlaceholder + ? new [] { EventName.LoadedFromMemoryCache, EventName.Loaded, EventName.Consumed, EventName.Completed } + : new [] { EventName.LoadedFromMemoryCache, EventName.Loaded, EventName.Completed } + : usePlaceholder + ? new [] { expectedLoadingFrom.Value.ToEventName(), EventName.Canceled, EventName.Consumed, EventName.Completed } + : new [] { expectedLoadingFrom.Value.ToEventName(), EventName.Canceled, EventName.Completed }; futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == shouldLoadFromMemoryCache); From abae8b152bfab5e808f4d1d5958c891522e0544d Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 6 Mar 2025 03:20:16 -0800 Subject: [PATCH 19/33] Remove unused TestUtils.Placeholder class --- .../Tests/Base/Utils/TestUtils.Placeholder.cs | 66 ------------------- .../Base/Utils/TestUtils.Placeholder.cs.meta | 11 ---- 2 files changed, 77 deletions(-) delete mode 100644 Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs delete mode 100644 Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs.meta diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs deleted file mode 100644 index 5f3fb9d..0000000 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections; -using System.Linq; -using Cysharp.Threading.Tasks; -using NUnit.Framework; -using UnityEngine; -using UnityEngine.UI; - -namespace Extensions.Unity.ImageLoader.Tests.Utils -{ - public static partial class TestUtils - { - // public static IEnumerator PlaceholderFromMemoryCache(string url) => Placeholder(url, null, FutureLoadedFrom.MemoryCache); - public static IEnumerator Placeholder(string url, params FuturePlaceholderTrigger[] triggers) - { - var future = ImageLoader.LoadSprite(url); - var futureListener = future.ToFutureListener(); - - var spritePlaceholder = Texture2D.whiteTexture.ToSprite(); - - future.SetPlaceholder(spritePlaceholder, triggers); - - - // var loadedFromMemoryCache = triggers.Contains(FuturePlaceholderTrigger.LoadedFromMemoryCache); - // if (triggers.Any.HasValue) - // futureListener.Assert_Events_Contains(expectedLoadingFrom.Value.ToEventName()); - - // var task1 = future.AsTask(); - // yield return future.TimeoutCoroutine(TimeSpan.FromSeconds(10)); - // var task2 = future.AsTask(); - - // futureListener.Assert_Events_NotContains(EventName.Canceled); - - // if (expectedLoadingFrom.HasValue) - // futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); - // else - // futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); - - // futureListener.Assert_Events_Value(EventName.Completed, success => success == true); - - // Assert.IsTrue(task1.IsCompleted, "Task was not cancelled but Future was cancelled"); - // Assert.IsTrue(task2.IsCompleted, "Task was not cancelled but Future was cancelled"); - - // yield return UniTask.Yield(); - - // if (expectedLoadingFrom.HasValue) - // futureListener.Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); - // else - // futureListener.Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed); - - // futureListener.Assert_Events_Value(EventName.Completed, success => success == true); - - // future.ToFutureListener(ignoreLoadingWhenLoaded: true) - // .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) - // .Assert_Events_Value(EventName.Completed, success => success == true); - - // if (expectedLoadingFrom.HasValue) - // future.ToFutureListener() - // .Assert_Events_Equals(expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Then, EventName.Completed) - // .Assert_Events_Value(EventName.Completed, success => success == true); - - // future.Dispose(); - yield return UniTask.Yield(); - } - } -} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs.meta b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs.meta deleted file mode 100644 index a01779c..0000000 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Placeholder.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 20380b73375185a4f98b40d3e7c41a3e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From aa72b90fa1acdef43077d7137d481f69105ae442 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 6 Mar 2025 04:32:50 -0800 Subject: [PATCH 20/33] Covering placeholder with Unit tests. Improved Consume function --- .../_PackageRoot/Runtime/Future/Future.API.cs | 13 ++++ .../Tests/Base/Utils/TestUtils.Load.cs | 6 +- .../Tests/Base/Utils/TestUtils.LoadFail.cs | 8 +- .../Tests/Editor/TestFuture.Load.AndCancel.cs | 47 ++++++++---- .../Editor/TestFuture.Load.ThenCancel.cs | 76 +++++++++++-------- .../Tests/Editor/TestFuture.Load.cs | 49 ++++++++---- .../Tests/Editor/TestFuture.LoadFail.cs | 17 +++-- 7 files changed, 143 insertions(+), 73 deletions(-) diff --git a/Assets/_PackageRoot/Runtime/Future/Future.API.cs b/Assets/_PackageRoot/Runtime/Future/Future.API.cs index 486d282..f231127 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.API.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.API.cs @@ -19,8 +19,21 @@ public IFuture Consume(Action consumer, bool replace = false) if (IsLoaded) { Safe.Run(consumer, value, LogLevel); + } + else if (Status == FutureStatus.LoadingFromDiskCache || Status == FutureStatus.LoadingFromSource) + { + lock (placeholders) + if (placeholders.TryGetValue(Status, out var placeholder)) + Safe.Run(consumer, placeholder, LogLevel); + } + else if (Status == FutureStatus.FailedToLoad || Status == FutureStatus.Canceled) + { + lock (placeholders) + if (placeholders.TryGetValue(Status, out var placeholder)) + Safe.Run(consumer, placeholder, LogLevel); return this; } + lock (consumers) { if (replace) diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs index 26a86d9..d1986f1 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs @@ -33,7 +33,7 @@ public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFro var events = expectedLoadingFrom.HasValue ? usePlaceholder - ? new [] { expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed } + ? new [] { expectedLoadingFrom.Value.ToEventName(), EventName.Consumed, expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed } : new [] { expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed } : usePlaceholder ? new [] { expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed } @@ -97,7 +97,7 @@ public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expected var events = expectedLoadingFrom.HasValue ? usePlaceholder - ? new [] { expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed } + ? new [] { expectedLoadingFrom.Value.ToEventName(), EventName.Consumed, expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed } : new [] { expectedLoadingFrom.Value.ToEventName(), expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed } : usePlaceholder ? new [] { expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Consumed, EventName.Completed } @@ -166,7 +166,7 @@ public static IEnumerator LoadAndCancel(string url, FutureLoadingFrom? expectedL ? new [] { EventName.LoadedFromMemoryCache, EventName.Loaded, EventName.Consumed, EventName.Completed } : new [] { EventName.LoadedFromMemoryCache, EventName.Loaded, EventName.Completed } : usePlaceholder - ? new [] { expectedLoadingFrom.Value.ToEventName(), EventName.Canceled, EventName.Consumed, EventName.Completed } + ? new [] { expectedLoadingFrom.Value.ToEventName(), EventName.Consumed, EventName.Canceled, EventName.Consumed, EventName.Completed } : new [] { expectedLoadingFrom.Value.ToEventName(), EventName.Canceled, EventName.Completed }; futureListener.Assert_Events_Equals(events); diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs index e1c0375..e19b490 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs @@ -34,8 +34,12 @@ public static IEnumerator LoadFail(string url, FutureLoadingFrom? expectedLoadin var task2 = future.AsTask(); var events = expectedLoadingFrom.HasValue - ? new[] { expectedLoadingFrom.Value.ToEventName(), EventName.Failed, EventName.Completed } - : new[] { EventName.Failed, EventName.Completed}; + ? usePlaceholder + ? new[] { expectedLoadingFrom.Value.ToEventName(), EventName.Consumed, EventName.Failed, EventName.Consumed, EventName.Completed } + : new[] { expectedLoadingFrom.Value.ToEventName(), EventName.Failed, EventName.Completed } + : usePlaceholder + ? new[] { EventName.Failed, EventName.Consumed, EventName.Completed} + : new[] { EventName.Failed, EventName.Completed}; futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == false); diff --git a/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.AndCancel.cs b/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.AndCancel.cs index e34fdba..e918937 100644 --- a/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.AndCancel.cs +++ b/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.AndCancel.cs @@ -9,12 +9,17 @@ public partial class TestFuture [UnityTest] public IEnumerator LoadFrom_Source_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source_AndCancel); [UnityTest] public IEnumerator LoadFrom_Source_AndCancel() { - yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: true); - yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: false); - yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: true); - yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: false); + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: true, usePlaceholder: false); + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: false, usePlaceholder: false); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: true, usePlaceholder: false); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: false, usePlaceholder: false); + + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: true, usePlaceholder: true); + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: false, usePlaceholder: true); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: true, usePlaceholder: true); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: false, usePlaceholder: true); } - IEnumerator LoadFrom_Source_AndCancel(bool useDiskCache, bool useMemoryCache) + IEnumerator LoadFrom_Source_AndCancel(bool useDiskCache, bool useMemoryCache, bool usePlaceholder) { ImageLoader.settings.useDiskCache = useDiskCache; ImageLoader.settings.useMemoryCache = useMemoryCache; @@ -24,17 +29,32 @@ IEnumerator LoadFrom_Source_AndCancel(bool useDiskCache, bool useMemoryCache) yield return TestUtils.ClearEverything(message: null); } + IEnumerator LoadFrom_MemoryCache_AndCancel(bool usePlaceholder) + { + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadFromMemoryCacheAndCancel(url, usePlaceholder: usePlaceholder); + } + yield return TestUtils.ClearEverything(message: null); + } + IEnumerator LoadFrom_DiskCache_AndCancel(bool usePlaceholder) + { + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadAndCancel(url, FutureLoadingFrom.DiskCache, usePlaceholder: usePlaceholder); + } + yield return TestUtils.ClearEverything(message: null); + } [UnityTest] public IEnumerator LoadFrom_MemoryCache_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache_AndCancel); [UnityTest] public IEnumerator LoadFrom_MemoryCache_AndCancel() { ImageLoader.settings.useDiskCache = true; ImageLoader.settings.useMemoryCache = true; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadFromMemoryCacheAndCancel(url); - } + yield return LoadFrom_MemoryCache_AndCancel(usePlaceholder: false); + yield return LoadFrom_MemoryCache_AndCancel(usePlaceholder: true); } [UnityTest] public IEnumerator LoadFrom_DiskCache_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache_AndCancel); @@ -43,11 +63,8 @@ [UnityTest] public IEnumerator LoadFrom_DiskCache_AndCancel() ImageLoader.settings.useDiskCache = true; ImageLoader.settings.useMemoryCache = false; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadAndCancel(url, FutureLoadingFrom.DiskCache); - } + yield return LoadFrom_DiskCache_AndCancel(usePlaceholder: false); + yield return LoadFrom_DiskCache_AndCancel(usePlaceholder: true); } } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.ThenCancel.cs b/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.ThenCancel.cs index f48868b..430703d 100644 --- a/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.ThenCancel.cs +++ b/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.ThenCancel.cs @@ -9,45 +9,66 @@ public partial class TestFuture [UnityTest] public IEnumerator LoadFrom_Source_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source_ThenCancel); [UnityTest] public IEnumerator LoadFrom_Source_ThenCancel() { - yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: true); - yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: true); - yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: true); - yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: true, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: true, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: true, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: true, usePlaceholder: false); - yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: false); - yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: false); - yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: false); - yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: false, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: false, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: false, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: false, usePlaceholder: false); + + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: true, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: true, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: true, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: true, usePlaceholder: true); + + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: false, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: false, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: false, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: false, usePlaceholder: true); } - IEnumerator LoadFrom_Source_ThenCancel(bool useDiskCache, bool useMemoryCache, bool useGC) + IEnumerator LoadFrom_Source_ThenCancel(bool useDiskCache, bool useMemoryCache, bool useGC, bool usePlaceholder) { ImageLoader.settings.useDiskCache = useDiskCache; ImageLoader.settings.useMemoryCache = useMemoryCache; foreach (var url in TestUtils.ImageURLs) - yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source, useGC); + yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source, useGC: useGC, usePlaceholder: usePlaceholder); yield return TestUtils.ClearEverything(message: null); } - - [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache_ThenCancel); - [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel() + IEnumerator LoadFrom_MemoryCache_ThenCancel(bool useGC, bool usePlaceholder) { - ImageLoader.settings.useDiskCache = true; - ImageLoader.settings.useMemoryCache = true; - foreach (var url in TestUtils.ImageURLs) { yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadFromMemoryCacheThenCancel(url, useGC: true); + yield return TestUtils.LoadFromMemoryCacheThenCancel(url, useGC: useGC, usePlaceholder: usePlaceholder); } - // TODO: remove code duplicate yield return TestUtils.ClearEverything(message: null); + } + IEnumerator LoadFrom_DiskCache_ThenCancel(bool useGC, bool usePlaceholder) + { foreach (var url in TestUtils.ImageURLs) { yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadFromMemoryCacheThenCancel(url, useGC: false); + yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, useGC: useGC, usePlaceholder: usePlaceholder); } + yield return TestUtils.ClearEverything(message: null); + } + + [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache_ThenCancel); + [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + yield return LoadFrom_MemoryCache_ThenCancel(useGC: true, usePlaceholder: false); + yield return LoadFrom_MemoryCache_ThenCancel(useGC: false, usePlaceholder: false); + + yield return LoadFrom_MemoryCache_ThenCancel(useGC: true, usePlaceholder: true); + yield return LoadFrom_MemoryCache_ThenCancel(useGC: false, usePlaceholder: true); } [UnityTest] public IEnumerator LoadFrom_DiskCache_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache_ThenCancel); @@ -56,18 +77,11 @@ [UnityTest] public IEnumerator LoadFrom_DiskCache_ThenCancel() ImageLoader.settings.useDiskCache = true; ImageLoader.settings.useMemoryCache = false; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, useGC: true); - } - // TODO: remove code duplicate - yield return TestUtils.ClearEverything(message: null); - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, useGC: false); - } + yield return LoadFrom_DiskCache_ThenCancel(useGC: true, usePlaceholder: false); + yield return LoadFrom_DiskCache_ThenCancel(useGC: false, usePlaceholder: false); + + yield return LoadFrom_DiskCache_ThenCancel(useGC: true, usePlaceholder: true); + yield return LoadFrom_DiskCache_ThenCancel(useGC: false, usePlaceholder: true); } } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.cs b/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.cs index e7b11dd..512ae70 100644 --- a/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.cs +++ b/Assets/_PackageRoot/Tests/Editor/TestFuture.Load.cs @@ -9,21 +9,44 @@ public partial class TestFuture [UnityTest] public IEnumerator LoadFrom_Source_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source); [UnityTest] public IEnumerator LoadFrom_Source() { - yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: true); - yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: false); - yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: true); - yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: false); + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: true, usePlaceholder: false); + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: false, usePlaceholder: false); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: true, usePlaceholder: false); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: false, usePlaceholder: false); + + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: true, usePlaceholder: true); + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: false, usePlaceholder: true); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: true, usePlaceholder: true); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: false, usePlaceholder: true); } - IEnumerator LoadFrom_Source(bool useDiskCache, bool useMemoryCache) + IEnumerator LoadFrom_Source(bool useDiskCache, bool useMemoryCache, bool usePlaceholder) { ImageLoader.settings.useDiskCache = useDiskCache; ImageLoader.settings.useMemoryCache = useMemoryCache; foreach (var url in TestUtils.ImageURLs) - yield return TestUtils.Load(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source); + yield return TestUtils.Load(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source, usePlaceholder: usePlaceholder); yield return TestUtils.ClearEverything(message: null); } + IEnumerator LoadFrom_DiskCache(bool usePlaceholder) + { + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.Load(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, usePlaceholder: usePlaceholder); + } + yield return TestUtils.ClearEverything(message: null); + } + IEnumerator LoadFrom_MemoryCache(bool usePlaceholder) + { + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadFromMemoryCache(url, usePlaceholder: usePlaceholder); + } + yield return TestUtils.ClearEverything(message: null); + } [UnityTest] public IEnumerator LoadFrom_DiskCache_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache); [UnityTest] public IEnumerator LoadFrom_DiskCache() @@ -31,11 +54,8 @@ [UnityTest] public IEnumerator LoadFrom_DiskCache() ImageLoader.settings.useDiskCache = true; ImageLoader.settings.useMemoryCache = false; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.Load(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache); - } + yield return LoadFrom_DiskCache(usePlaceholder: false); + yield return LoadFrom_DiskCache(usePlaceholder: true); } [UnityTest] public IEnumerator LoadFrom_MemoryCache_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache); @@ -44,11 +64,8 @@ [UnityTest] public IEnumerator LoadFrom_MemoryCache() ImageLoader.settings.useDiskCache = true; ImageLoader.settings.useMemoryCache = true; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadFromMemoryCache(url); - } + yield return LoadFrom_MemoryCache(usePlaceholder: false); + yield return LoadFrom_MemoryCache(usePlaceholder: true); } } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Editor/TestFuture.LoadFail.cs b/Assets/_PackageRoot/Tests/Editor/TestFuture.LoadFail.cs index a37b605..4e79aa2 100644 --- a/Assets/_PackageRoot/Tests/Editor/TestFuture.LoadFail.cs +++ b/Assets/_PackageRoot/Tests/Editor/TestFuture.LoadFail.cs @@ -9,18 +9,23 @@ public partial class TestFuture [UnityTest] public IEnumerator LoadFailFrom_Source_NoLogs() => TestUtils.RunNoLogs(LoadFailFrom_Source); [UnityTest] public IEnumerator LoadFailFrom_Source() { - yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: true); - yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: false); - yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: true); - yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: false); + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: true, usePlaceholder: false); + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: false, usePlaceholder: false); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: true, usePlaceholder: false); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: false, usePlaceholder: false); + + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: true, usePlaceholder: true); + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: false, usePlaceholder: true); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: true, usePlaceholder: true); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: false, usePlaceholder: true); } - IEnumerator LoadFailFrom_Source(bool useDiskCache, bool useMemoryCache) + IEnumerator LoadFailFrom_Source(bool useDiskCache, bool useMemoryCache, bool usePlaceholder) { ImageLoader.settings.useDiskCache = useDiskCache; ImageLoader.settings.useMemoryCache = useMemoryCache; foreach (var url in TestUtils.IncorrectImageURLs()) - yield return TestUtils.LoadFail(url, FutureLoadingFrom.Source); + yield return TestUtils.LoadFail(url, FutureLoadingFrom.Source, usePlaceholder: usePlaceholder); yield return TestUtils.ClearEverything(message: null); } From 3ea95ee720886891a05c3c315cbd7cbbbbfbe627 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 6 Mar 2025 04:33:48 -0800 Subject: [PATCH 21/33] Improved Consume function --- Assets/_PackageRoot/Runtime/Future/Future.API.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/_PackageRoot/Runtime/Future/Future.API.cs b/Assets/_PackageRoot/Runtime/Future/Future.API.cs index f231127..e6e82f2 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.API.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.API.cs @@ -19,6 +19,7 @@ public IFuture Consume(Action consumer, bool replace = false) if (IsLoaded) { Safe.Run(consumer, value, LogLevel); + return this; } else if (Status == FutureStatus.LoadingFromDiskCache || Status == FutureStatus.LoadingFromSource) { From 917075822552609f162af027642baa94f11f0698 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Thu, 6 Mar 2025 23:43:12 -0800 Subject: [PATCH 22/33] Fixed Unit tests --- Assets/_PackageRoot/Runtime/Future/Future.cs | 4 +- .../Tests/Base/Utils/FutureListener.cs | 43 ++++++++++--------- .../Tests/Base/Utils/TestUtils.Load.cs | 20 ++++++++- .../Tests/Base/Utils/TestUtils.LoadFail.cs | 14 +++++- 4 files changed, 55 insertions(+), 26 deletions(-) diff --git a/Assets/_PackageRoot/Runtime/Future/Future.cs b/Assets/_PackageRoot/Runtime/Future/Future.cs index a5a1dc2..3a8d893 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.cs @@ -235,8 +235,8 @@ protected virtual void Clear() Debug.Log($"[ImageLoader] Future[id={Id}] Cleared\n{Url}"); cleared = true; - lock (placeholders) - placeholders.Clear(); + // lock (placeholders) + // placeholders.Clear(); OnLoadedFromMemoryCache = null; OnLoadingFromDiskCache = null; OnLoadedFromDiskCache = null; diff --git a/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs index 149aff7..4556c25 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/FutureListener.cs @@ -6,6 +6,9 @@ namespace Extensions.Unity.ImageLoader.Tests.Utils { public partial class FutureListener { + static uint idCounter = 0; + + uint id = idCounter++; List events = new List(); public IReadOnlyList Events @@ -23,63 +26,53 @@ public FutureListener(IFuture future, bool ignoreLoadingWhenLoaded = false, b logLevel = ImageLoader.settings.debugLevel; if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] Created"); + Debug.Log($"[FutureListener id={id}] Future[id={future.Id}] Created. FutureStatus: {future.Status}"); future.LoadedFromMemoryCache(value => { if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] LoadedFromMemoryCache: {value}"); + Debug.Log($"[FutureListener id={id}] Future[id={future.Id}] LoadedFromMemoryCache: {value}"); lock (events) events.Add(new EventData { name = EventName.LoadedFromMemoryCache, value = value }); }); future.LoadingFromDiskCache(() => { if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] LoadingFromDiskCache"); + Debug.Log($"[FutureListener id={id}] Future[id={future.Id}] LoadingFromDiskCache"); lock (events) events.Add(new EventData { name = EventName.LoadingFromDiskCache }); }, ignoreWhenLoaded: ignoreLoadingWhenLoaded); future.LoadedFromDiskCache(value => { if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] LoadedFromDiskCache: {value}"); + Debug.Log($"[FutureListener id={id}] Future[id={future.Id}] LoadedFromDiskCache: {value}"); lock (events) events.Add(new EventData { name = EventName.LoadedFromDiskCache, value = value }); }); future.LoadingFromSource(() => { if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] LoadingFromSource"); + Debug.Log($"[FutureListener id={id}] Future[id={future.Id}] LoadingFromSource"); lock (events) events.Add(new EventData { name = EventName.LoadingFromSource }); }, ignoreWhenLoaded: ignoreLoadingWhenLoaded); future.LoadedFromSource(value => { if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] LoadedFromSource: {value}"); + Debug.Log($"[FutureListener id={id}] Future[id={future.Id}] LoadedFromSource: {value}"); lock (events) events.Add(new EventData { name = EventName.LoadedFromSource, value = value }); }); future.Loaded(value => { if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] Loaded: {value}"); + Debug.Log($"[FutureListener id={id}] Future[id={future.Id}] Loaded: {value}"); lock (events) events.Add(new EventData { name = EventName.Loaded, value = value }); }); - if (!ignorePlaceholder) - { - future.Consume(value => - { - if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] Consume: {value}"); - lock (events) - events.Add(new EventData { name = EventName.Consumed, value = value }); - }); - } future.Failed(exception => { if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] Failed: {exception}"); + Debug.Log($"[FutureListener id={id}] Future[id={future.Id}] Failed: {exception}"); lock (events) events.Add(new EventData { name = EventName.Failed, value = exception }); }); @@ -88,15 +81,25 @@ public FutureListener(IFuture future, bool ignoreLoadingWhenLoaded = false, b future.Canceled(() => { if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] Canceled"); + Debug.Log($"[FutureListener id={id}] Future[id={future.Id}] Canceled"); lock (events) events.Add(new EventData { name = EventName.Canceled }); }); } + if (!ignorePlaceholder) + { + future.Consume(value => + { + if (logLevel.Value.IsActive(DebugLevel.Trace)) + Debug.Log($"[FutureListener id={id}] Future[id={future.Id}] Consume: {value}"); + lock (events) + events.Add(new EventData { name = EventName.Consumed, value = value }); + }); + } future.Completed(value => { if (logLevel.Value.IsActive(DebugLevel.Trace)) - Debug.Log($"[FutureListener] Future[id={future.Id}] Completed: {value}"); + Debug.Log($"[FutureListener id={id}] Future[id={future.Id}] Completed: {value}"); lock (events) events.Add(new EventData { name = EventName.Completed, value = value }); }); diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs index d1986f1..5a9cba9 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs @@ -50,6 +50,8 @@ public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFro futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == true); + Assert.AreEqual(future.Status, expectedLoadedFrom.AsFutureStatus()); + future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: true) .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); @@ -114,6 +116,8 @@ public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expected futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == true); + Assert.AreEqual(future.Status, expectedLoadedFrom.AsFutureStatus()); + future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: true) .Assert_Events_Equals(expectedLoadedFrom.ToEventName(), EventName.Loaded, EventName.Completed) .Assert_Events_Value(EventName.Completed, success => success == true); @@ -180,13 +184,25 @@ public static IEnumerator LoadAndCancel(string url, FutureLoadingFrom? expectedL futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == shouldLoadFromMemoryCache); + Assert.AreEqual(future.Status, shouldLoadFromMemoryCache + ? FutureStatus.LoadedFromMemoryCache + : FutureStatus.Canceled); + + var lateEvents = shouldLoadFromMemoryCache + ? usePlaceholder + ? new[] { EventName.LoadedFromMemoryCache, EventName.Loaded, EventName.Consumed, EventName.Completed } + : new[] { EventName.LoadedFromMemoryCache, EventName.Loaded, EventName.Completed } + : usePlaceholder + ? new[] { expectedLoadingFrom.Value.ToEventName(), EventName.Canceled, EventName.Consumed, EventName.Completed } + : new[] { expectedLoadingFrom.Value.ToEventName(), EventName.Canceled, EventName.Completed }; + future.ToFutureListener(ignorePlaceholder: !usePlaceholder) - .Assert_Events_Equals(events) + .Assert_Events_Equals(lateEvents) .Assert_Events_Value(EventName.Completed, success => success == shouldLoadFromMemoryCache); if (expectedLoadingFrom.HasValue && future.IsLoaded) future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: !usePlaceholder) - .Assert_Events_Equals(events.Except(new [] { expectedLoadingFrom.Value.ToEventName() })) + .Assert_Events_Equals(lateEvents.Except(new [] { expectedLoadingFrom.Value.ToEventName() })) .Assert_Events_Value(EventName.Completed, success => success == shouldLoadFromMemoryCache); future.Dispose(); diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs index e19b490..a6cd00a 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs @@ -52,13 +52,23 @@ public static IEnumerator LoadFail(string url, FutureLoadingFrom? expectedLoadin futureListener.Assert_Events_Equals(events); futureListener.Assert_Events_Value(EventName.Completed, success => success == false); + Assert.AreEqual(future.Status, FutureStatus.FailedToLoad); + + var lateEvents = expectedLoadingFrom.HasValue + ? usePlaceholder + ? new[] { expectedLoadingFrom.Value.ToEventName(), EventName.Failed, EventName.Consumed, EventName.Completed } + : new[] { expectedLoadingFrom.Value.ToEventName(), EventName.Failed, EventName.Completed } + : usePlaceholder + ? new[] { EventName.Failed, EventName.Consumed, EventName.Completed} + : new[] { EventName.Failed, EventName.Completed}; + future.ToFutureListener(ignoreLoadingWhenLoaded: true, ignorePlaceholder: !usePlaceholder) - .Assert_Events_Equals(events) + .Assert_Events_Equals(lateEvents) .Assert_Events_Value(EventName.Completed, success => success == false); if (expectedLoadingFrom.HasValue) future.ToFutureListener(ignorePlaceholder: !usePlaceholder) - .Assert_Events_Equals(events) + .Assert_Events_Equals(lateEvents) .Assert_Events_Value(EventName.Completed, success => success == false); future.Dispose(); From 5b3843cf49cbcd4a6ee5ca09e4a4dfaac1aab8ef Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Fri, 7 Mar 2025 00:54:37 -0800 Subject: [PATCH 23/33] Updated samples --- Assets/_PackageRoot/Documentation~/README.md | 72 ++++++++++--------- Assets/_PackageRoot/README.md | 72 ++++++++++--------- ...age.cs => SampleLoadSpriteConsumeImage.cs} | 0 ...a => SampleLoadSpriteConsumeImage.cs.meta} | 0 ...pleLoadSpriteConsumeIntoMultipleImages.cs} | 0 ...adSpriteConsumeIntoMultipleImages.cs.meta} | 0 ...cs => SampleLoadTextureConsumeMaterial.cs} | 0 ... SampleLoadTextureConsumeMaterial.cs.meta} | 0 .../Tests/Base/Utils/TestUtils.Load.cs | 2 +- README.md | 72 ++++++++++--------- 10 files changed, 115 insertions(+), 103 deletions(-) rename Assets/_PackageRoot/Samples/{SampleLoadSpriteThenSetImage.cs => SampleLoadSpriteConsumeImage.cs} (100%) rename Assets/_PackageRoot/Samples/{SampleLoadSpriteThenSetImage.cs.meta => SampleLoadSpriteConsumeImage.cs.meta} (100%) rename Assets/_PackageRoot/Samples/{SampleLoadSpriteThenSetIntoMultipleImages.cs => SampleLoadSpriteConsumeIntoMultipleImages.cs} (100%) rename Assets/_PackageRoot/Samples/{SampleLoadSpriteThenSetIntoMultipleImages.cs.meta => SampleLoadSpriteConsumeIntoMultipleImages.cs.meta} (100%) rename Assets/_PackageRoot/Samples/{SampleLoadTextureThenSetMaterial.cs => SampleLoadTextureConsumeMaterial.cs} (100%) rename Assets/_PackageRoot/Samples/{SampleLoadTextureThenSetMaterial.cs.meta => SampleLoadTextureConsumeMaterial.cs.meta} (100%) diff --git a/Assets/_PackageRoot/Documentation~/README.md b/Assets/_PackageRoot/Documentation~/README.md index d76caee..88302c9 100644 --- a/Assets/_PackageRoot/Documentation~/README.md +++ b/Assets/_PackageRoot/Documentation~/README.md @@ -23,13 +23,13 @@ image.sprite = await ImageLoader.LoadSprite(imageURL); Don't wait, use callback to set loaded image later: ```csharp -ImageLoader.LoadSprite(imageURL).ThenSet(image).Forget(); +ImageLoader.LoadSprite(imageURL).Consume(image).Forget(); ``` Use callback to set image and still wait for the completion: ```csharp -await ImageLoader.LoadSprite(imageURL).ThenSet(image); +await ImageLoader.LoadSprite(imageURL).Consume(image); ``` ## Features @@ -41,10 +41,10 @@ await ImageLoader.LoadSprite(imageURL).ThenSet(image); - ✔️ Avoids loading same image multiple times simultaneously, a new load task waits for completion of existed task - ✔️ Uses `UnityWebRequest` to load data which works smooth across all platforms including `WebGL` - ✔️ Cache supported on at `WebGL`. Memory cache works, Disk cache isn't allowed by the platform -- ✔️ Set into Image `ImageLoader.LoadSprite(imageURL).ThenSet(image);` -- ✔️ Set into RawImage `ImageLoader.LoadSprite(imageURL).ThenSet(rawImage);` -- ✔️ Set into Material `ImageLoader.LoadSprite(imageURL).ThenSet("_MainTex", material);` -- ✔️ Set into SpriteRenderer `ImageLoader.LoadSprite(imageURL).ThenSet(spriteRenderer);` +- ✔️ Set into Image `ImageLoader.LoadSprite(imageURL).Consume(image);` +- ✔️ Set into RawImage `ImageLoader.LoadSprite(imageURL).Consume(rawImage);` +- ✔️ Set into Material `ImageLoader.LoadSprite(imageURL).Consume("_MainTex", material);` +- ✔️ Set into SpriteRenderer `ImageLoader.LoadSprite(imageURL).Consume(spriteRenderer);` - ✔️ [Set into anything](#cancellation) - ✔️ Cancellation `ImageLoader.LoadSprite(imageURL).Cancel();` - ✔️ Cancellation callback `ImageLoader.LoadSprite(imageURL).Cancelled(() => ...);` @@ -134,6 +134,17 @@ ImageLoader.LoadSprite(imageURL) // loading process started .LoadedFromSource (sprite => Debug.Log("Loaded from source")) // on loaded from source │ // ────────────────────────────────────────────────────────────────────────────────────────────────────┘ + // ┌──────────────────────────┬───────────────────────────────────────────┐ + // │ Success lifecycle events │ │ + // └──────────────────────────┘ │ + .Loaded(sprite => Debug.Log("Loaded")) // on successfully loaded │ + // ┌────────────────────────────────────────────────────────┤ + // │ Set/Consume sprite [placeholder, successfully loaded] │ + // └────────────────────────────────────────────────────────┤ + .Consume(sprite => Debug.Log("Consumed")) // │ + .Consume(image) // │ + // ───────────────────────────────────────────────────────────────────────┘ + // ┌───────────────────────────┬──────────────────────────────────────────┐ // │ Negative lifecycle events │ │ // └───────────────────────────┘ │ @@ -141,13 +152,6 @@ ImageLoader.LoadSprite(imageURL) // loading process started .Failed(exception => Debug.LogException(exception)) // on failed to load │ // ───────────────────────────────────────────────────────────────────────┘ - // ┌──────────────────────────────────────┬──────────────────────────────┐ - // │ Successfully loaded lifecycle events │ │ - // └──────────────────────────────────────┘ │ - .Then(sprite => Debug.Log("Loaded")) // on loaded │ - .ThenSet(image) // on loaded set sprite into image │ - // ──────────────────────────────────────────────────────────────────────┘ - // ┌──────────────────────┬──────────────────────────────────────────────────────────────────────────┐ // │ The end of lifecycle │ │ // └──────────────────────┘ │ @@ -160,34 +164,34 @@ ImageLoader.LoadSprite(imageURL) // loading process started ## Load `Sprite` then set into `Image` -> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetImage.cs) +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeImage.cs) ```csharp // Load a sprite from the web and cache it for faster loading next time image.sprite = await ImageLoader.LoadSprite(imageURL); // Load a sprite from the web and set it directly to the Image component -await ImageLoader.LoadSprite(imageURL).ThenSet(image); +await ImageLoader.LoadSprite(imageURL).Consume(image); ``` ## Load `Texture2D` then set into `Material` -> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadTextureThenSetMaterial.cs) +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadTextureConsumeMaterial.cs) ```csharp // Load a Texture2D from the web and cache it for faster loading next time material.mainTexture = await ImageLoader.LoadTexture(imageURL); // Load a Texture2D from the web and set it directly to the Material -await ImageLoader.LoadTexture(imageURL).ThenSet(material); +await ImageLoader.LoadTexture(imageURL).Consume(material); ``` ## Load `Sprite` then set into multiple `Image` -> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetIntoMultipleImages.cs) +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeIntoMultipleImages.cs) ```csharp -ImageLoader.LoadSprite(imageURL).ThenSet(image1, image2).Forget(); +ImageLoader.LoadSprite(imageURL).Consume(image1, image2).Forget(); ``` ## Error handling @@ -196,12 +200,12 @@ ImageLoader.LoadSprite(imageURL).ThenSet(image1, image2).Forget(); ```csharp ImageLoader.LoadSprite(imageURL) // Attempt to load a sprite - .ThenSet(image) // If successful, set the sprite to the Image component + .Consume(image) // If successful, set the sprite to the Image component .Failed(exception => Debug.LogException(exception)) // If an error occurs, log the exception .Forget(); // Forget the task to avoid compilation warning ImageLoader.LoadSprite(imageURL) // Attempt to load a sprite - .ThenSet(image) // If successful, set the sprite to the Image component + .Consume(image) // If successful, set the sprite to the Image component .Then(sprite => image.gameObject.SetActive(true)) // If successful, activate the GameObject .Failed(exception => image.gameObject.SetActive(false)) // If an error occurs, deactivate the GameObject .Forget(); // Forget the task to avoid compilation warning @@ -216,12 +220,12 @@ ImageLoader.LoadSprite(imageURL) // Attempt to load a sprite await ImageLoader.LoadSprite(imageURL); // Load image, set image and wait -await ImageLoader.LoadSprite(imageURL).ThenSet(image); +await ImageLoader.LoadSprite(imageURL).Consume(image); // Skip waiting for completion. // To do that we can simply remove 'await' from the start. // To avoid compilation warning need to add '.Forget()'. -ImageLoader.LoadSprite(imageURL).ThenSet(image).Forget(); +ImageLoader.LoadSprite(imageURL).Consume(image).Forget(); ``` ## Cancellation @@ -234,7 +238,7 @@ Cancellation is helpful if target image consumer doesn't exist anymore. For exam ```csharp ImageLoader.LoadSprite(imageURL) - .ThenSet(image) + .Consume(image) .CancelOnEnable(this) // cancel on OnEnable event of current MonoBehaviour .CancelOnDisable(this) // cancel on OnDisable event of current MonoBehaviour .CancelOnDestroy(this); // cancel on OnDestroy event of current MonoBehaviour @@ -243,7 +247,7 @@ ImageLoader.LoadSprite(imageURL) ### Explicit cancellation ```csharp -var future = ImageLoader.LoadSprite(imageURL).ThenSet(image); +var future = ImageLoader.LoadSprite(imageURL).Consume(image); future.Cancel(); ``` @@ -254,7 +258,7 @@ var cancellationTokenSource = new CancellationTokenSource(); // loading with attached cancellation token ImageLoader.LoadSprite(imageURL, cancellationToken: cancellationTokenSource.Token) - .ThenSet(image) + .Consume(image) .Forget(); cancellationTokenSource.Cancel(); // canceling @@ -264,7 +268,7 @@ cancellationTokenSource.Cancel(); // canceling var cancellationTokenSource = new CancellationTokenSource(); ImageLoader.LoadSprite(imageURL) - .ThenSet(image) + .Consume(image) .Register(cancellationTokenSource.Token) // registering cancellation token .Forget(); @@ -274,7 +278,7 @@ cancellationTokenSource.Cancel(); // canceling ### Cancellation by `using` ```csharp -using (var future = ImageLoader.LoadSprite(imageURL).ThenSet(image)) +using (var future = ImageLoader.LoadSprite(imageURL).Consume(image)) { // future would be canceled and disposed outside of the brackets } @@ -282,18 +286,18 @@ using (var future = ImageLoader.LoadSprite(imageURL).ThenSet(image)) ```csharp ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .CancelOnDestroy(this) // cancel OnDestroy event of current gameObject .Forget(); ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .Failed(exception => Debug.LogException(exception)) // if fail print exception .CancelOnDestroy(this) // cancel OnDestroy event of current gameObject .Forget(); ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .Then(sprite => image.gameObject.SetActive(true)) // if success activate gameObject .Failed(exception => image.gameObject.SetActive(false)) // if fail deactivate gameObject .Canceled(() => Debug.Log("ImageLoading canceled")) // if cancelled @@ -317,7 +321,7 @@ Set timeout for a specific loading request (`IFuture`): ```csharp ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .Timeout(TimeSpan.FromSeconds(10)) // set timeout duration 10 seconds .Forget(); ``` @@ -438,11 +442,11 @@ reference = null; > [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleReferences.cs) -`Reference.ThenSet` has a unique feature to attach the reference to the target consumer if consumer is `UnityEngine.Component`. The reference would be disposed as only the consumer gets destroyed. +`Future>.Consume` has a unique feature to attach the reference to the target consumer if consumer is `UnityEngine.Component`. The reference would be disposed as only the consumer gets destroyed. ```csharp ImageLoader.LoadSpriteRef(imageURL) // load sprite using Reference - .ThenSet(image) // if success set sprite into image, also creates binding to `image` + .Consume(image) // if success set sprite into image, also creates binding to `image` .Forget(); ``` diff --git a/Assets/_PackageRoot/README.md b/Assets/_PackageRoot/README.md index d76caee..88302c9 100644 --- a/Assets/_PackageRoot/README.md +++ b/Assets/_PackageRoot/README.md @@ -23,13 +23,13 @@ image.sprite = await ImageLoader.LoadSprite(imageURL); Don't wait, use callback to set loaded image later: ```csharp -ImageLoader.LoadSprite(imageURL).ThenSet(image).Forget(); +ImageLoader.LoadSprite(imageURL).Consume(image).Forget(); ``` Use callback to set image and still wait for the completion: ```csharp -await ImageLoader.LoadSprite(imageURL).ThenSet(image); +await ImageLoader.LoadSprite(imageURL).Consume(image); ``` ## Features @@ -41,10 +41,10 @@ await ImageLoader.LoadSprite(imageURL).ThenSet(image); - ✔️ Avoids loading same image multiple times simultaneously, a new load task waits for completion of existed task - ✔️ Uses `UnityWebRequest` to load data which works smooth across all platforms including `WebGL` - ✔️ Cache supported on at `WebGL`. Memory cache works, Disk cache isn't allowed by the platform -- ✔️ Set into Image `ImageLoader.LoadSprite(imageURL).ThenSet(image);` -- ✔️ Set into RawImage `ImageLoader.LoadSprite(imageURL).ThenSet(rawImage);` -- ✔️ Set into Material `ImageLoader.LoadSprite(imageURL).ThenSet("_MainTex", material);` -- ✔️ Set into SpriteRenderer `ImageLoader.LoadSprite(imageURL).ThenSet(spriteRenderer);` +- ✔️ Set into Image `ImageLoader.LoadSprite(imageURL).Consume(image);` +- ✔️ Set into RawImage `ImageLoader.LoadSprite(imageURL).Consume(rawImage);` +- ✔️ Set into Material `ImageLoader.LoadSprite(imageURL).Consume("_MainTex", material);` +- ✔️ Set into SpriteRenderer `ImageLoader.LoadSprite(imageURL).Consume(spriteRenderer);` - ✔️ [Set into anything](#cancellation) - ✔️ Cancellation `ImageLoader.LoadSprite(imageURL).Cancel();` - ✔️ Cancellation callback `ImageLoader.LoadSprite(imageURL).Cancelled(() => ...);` @@ -134,6 +134,17 @@ ImageLoader.LoadSprite(imageURL) // loading process started .LoadedFromSource (sprite => Debug.Log("Loaded from source")) // on loaded from source │ // ────────────────────────────────────────────────────────────────────────────────────────────────────┘ + // ┌──────────────────────────┬───────────────────────────────────────────┐ + // │ Success lifecycle events │ │ + // └──────────────────────────┘ │ + .Loaded(sprite => Debug.Log("Loaded")) // on successfully loaded │ + // ┌────────────────────────────────────────────────────────┤ + // │ Set/Consume sprite [placeholder, successfully loaded] │ + // └────────────────────────────────────────────────────────┤ + .Consume(sprite => Debug.Log("Consumed")) // │ + .Consume(image) // │ + // ───────────────────────────────────────────────────────────────────────┘ + // ┌───────────────────────────┬──────────────────────────────────────────┐ // │ Negative lifecycle events │ │ // └───────────────────────────┘ │ @@ -141,13 +152,6 @@ ImageLoader.LoadSprite(imageURL) // loading process started .Failed(exception => Debug.LogException(exception)) // on failed to load │ // ───────────────────────────────────────────────────────────────────────┘ - // ┌──────────────────────────────────────┬──────────────────────────────┐ - // │ Successfully loaded lifecycle events │ │ - // └──────────────────────────────────────┘ │ - .Then(sprite => Debug.Log("Loaded")) // on loaded │ - .ThenSet(image) // on loaded set sprite into image │ - // ──────────────────────────────────────────────────────────────────────┘ - // ┌──────────────────────┬──────────────────────────────────────────────────────────────────────────┐ // │ The end of lifecycle │ │ // └──────────────────────┘ │ @@ -160,34 +164,34 @@ ImageLoader.LoadSprite(imageURL) // loading process started ## Load `Sprite` then set into `Image` -> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetImage.cs) +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeImage.cs) ```csharp // Load a sprite from the web and cache it for faster loading next time image.sprite = await ImageLoader.LoadSprite(imageURL); // Load a sprite from the web and set it directly to the Image component -await ImageLoader.LoadSprite(imageURL).ThenSet(image); +await ImageLoader.LoadSprite(imageURL).Consume(image); ``` ## Load `Texture2D` then set into `Material` -> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadTextureThenSetMaterial.cs) +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadTextureConsumeMaterial.cs) ```csharp // Load a Texture2D from the web and cache it for faster loading next time material.mainTexture = await ImageLoader.LoadTexture(imageURL); // Load a Texture2D from the web and set it directly to the Material -await ImageLoader.LoadTexture(imageURL).ThenSet(material); +await ImageLoader.LoadTexture(imageURL).Consume(material); ``` ## Load `Sprite` then set into multiple `Image` -> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetIntoMultipleImages.cs) +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeIntoMultipleImages.cs) ```csharp -ImageLoader.LoadSprite(imageURL).ThenSet(image1, image2).Forget(); +ImageLoader.LoadSprite(imageURL).Consume(image1, image2).Forget(); ``` ## Error handling @@ -196,12 +200,12 @@ ImageLoader.LoadSprite(imageURL).ThenSet(image1, image2).Forget(); ```csharp ImageLoader.LoadSprite(imageURL) // Attempt to load a sprite - .ThenSet(image) // If successful, set the sprite to the Image component + .Consume(image) // If successful, set the sprite to the Image component .Failed(exception => Debug.LogException(exception)) // If an error occurs, log the exception .Forget(); // Forget the task to avoid compilation warning ImageLoader.LoadSprite(imageURL) // Attempt to load a sprite - .ThenSet(image) // If successful, set the sprite to the Image component + .Consume(image) // If successful, set the sprite to the Image component .Then(sprite => image.gameObject.SetActive(true)) // If successful, activate the GameObject .Failed(exception => image.gameObject.SetActive(false)) // If an error occurs, deactivate the GameObject .Forget(); // Forget the task to avoid compilation warning @@ -216,12 +220,12 @@ ImageLoader.LoadSprite(imageURL) // Attempt to load a sprite await ImageLoader.LoadSprite(imageURL); // Load image, set image and wait -await ImageLoader.LoadSprite(imageURL).ThenSet(image); +await ImageLoader.LoadSprite(imageURL).Consume(image); // Skip waiting for completion. // To do that we can simply remove 'await' from the start. // To avoid compilation warning need to add '.Forget()'. -ImageLoader.LoadSprite(imageURL).ThenSet(image).Forget(); +ImageLoader.LoadSprite(imageURL).Consume(image).Forget(); ``` ## Cancellation @@ -234,7 +238,7 @@ Cancellation is helpful if target image consumer doesn't exist anymore. For exam ```csharp ImageLoader.LoadSprite(imageURL) - .ThenSet(image) + .Consume(image) .CancelOnEnable(this) // cancel on OnEnable event of current MonoBehaviour .CancelOnDisable(this) // cancel on OnDisable event of current MonoBehaviour .CancelOnDestroy(this); // cancel on OnDestroy event of current MonoBehaviour @@ -243,7 +247,7 @@ ImageLoader.LoadSprite(imageURL) ### Explicit cancellation ```csharp -var future = ImageLoader.LoadSprite(imageURL).ThenSet(image); +var future = ImageLoader.LoadSprite(imageURL).Consume(image); future.Cancel(); ``` @@ -254,7 +258,7 @@ var cancellationTokenSource = new CancellationTokenSource(); // loading with attached cancellation token ImageLoader.LoadSprite(imageURL, cancellationToken: cancellationTokenSource.Token) - .ThenSet(image) + .Consume(image) .Forget(); cancellationTokenSource.Cancel(); // canceling @@ -264,7 +268,7 @@ cancellationTokenSource.Cancel(); // canceling var cancellationTokenSource = new CancellationTokenSource(); ImageLoader.LoadSprite(imageURL) - .ThenSet(image) + .Consume(image) .Register(cancellationTokenSource.Token) // registering cancellation token .Forget(); @@ -274,7 +278,7 @@ cancellationTokenSource.Cancel(); // canceling ### Cancellation by `using` ```csharp -using (var future = ImageLoader.LoadSprite(imageURL).ThenSet(image)) +using (var future = ImageLoader.LoadSprite(imageURL).Consume(image)) { // future would be canceled and disposed outside of the brackets } @@ -282,18 +286,18 @@ using (var future = ImageLoader.LoadSprite(imageURL).ThenSet(image)) ```csharp ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .CancelOnDestroy(this) // cancel OnDestroy event of current gameObject .Forget(); ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .Failed(exception => Debug.LogException(exception)) // if fail print exception .CancelOnDestroy(this) // cancel OnDestroy event of current gameObject .Forget(); ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .Then(sprite => image.gameObject.SetActive(true)) // if success activate gameObject .Failed(exception => image.gameObject.SetActive(false)) // if fail deactivate gameObject .Canceled(() => Debug.Log("ImageLoading canceled")) // if cancelled @@ -317,7 +321,7 @@ Set timeout for a specific loading request (`IFuture`): ```csharp ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .Timeout(TimeSpan.FromSeconds(10)) // set timeout duration 10 seconds .Forget(); ``` @@ -438,11 +442,11 @@ reference = null; > [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleReferences.cs) -`Reference.ThenSet` has a unique feature to attach the reference to the target consumer if consumer is `UnityEngine.Component`. The reference would be disposed as only the consumer gets destroyed. +`Future>.Consume` has a unique feature to attach the reference to the target consumer if consumer is `UnityEngine.Component`. The reference would be disposed as only the consumer gets destroyed. ```csharp ImageLoader.LoadSpriteRef(imageURL) // load sprite using Reference - .ThenSet(image) // if success set sprite into image, also creates binding to `image` + .Consume(image) // if success set sprite into image, also creates binding to `image` .Forget(); ``` diff --git a/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetImage.cs b/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeImage.cs similarity index 100% rename from Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetImage.cs rename to Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeImage.cs diff --git a/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetImage.cs.meta b/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeImage.cs.meta similarity index 100% rename from Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetImage.cs.meta rename to Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeImage.cs.meta diff --git a/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetIntoMultipleImages.cs b/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeIntoMultipleImages.cs similarity index 100% rename from Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetIntoMultipleImages.cs rename to Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeIntoMultipleImages.cs diff --git a/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetIntoMultipleImages.cs.meta b/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeIntoMultipleImages.cs.meta similarity index 100% rename from Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetIntoMultipleImages.cs.meta rename to Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeIntoMultipleImages.cs.meta diff --git a/Assets/_PackageRoot/Samples/SampleLoadTextureThenSetMaterial.cs b/Assets/_PackageRoot/Samples/SampleLoadTextureConsumeMaterial.cs similarity index 100% rename from Assets/_PackageRoot/Samples/SampleLoadTextureThenSetMaterial.cs rename to Assets/_PackageRoot/Samples/SampleLoadTextureConsumeMaterial.cs diff --git a/Assets/_PackageRoot/Samples/SampleLoadTextureThenSetMaterial.cs.meta b/Assets/_PackageRoot/Samples/SampleLoadTextureConsumeMaterial.cs.meta similarity index 100% rename from Assets/_PackageRoot/Samples/SampleLoadTextureThenSetMaterial.cs.meta rename to Assets/_PackageRoot/Samples/SampleLoadTextureConsumeMaterial.cs.meta diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs index 5a9cba9..6166c68 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs @@ -196,7 +196,7 @@ public static IEnumerator LoadAndCancel(string url, FutureLoadingFrom? expectedL ? new[] { expectedLoadingFrom.Value.ToEventName(), EventName.Canceled, EventName.Consumed, EventName.Completed } : new[] { expectedLoadingFrom.Value.ToEventName(), EventName.Canceled, EventName.Completed }; - future.ToFutureListener(ignorePlaceholder: !usePlaceholder) + var lateFutureListener = future.ToFutureListener(ignorePlaceholder: !usePlaceholder) .Assert_Events_Equals(lateEvents) .Assert_Events_Value(EventName.Completed, success => success == shouldLoadFromMemoryCache); diff --git a/README.md b/README.md index d76caee..88302c9 100644 --- a/README.md +++ b/README.md @@ -23,13 +23,13 @@ image.sprite = await ImageLoader.LoadSprite(imageURL); Don't wait, use callback to set loaded image later: ```csharp -ImageLoader.LoadSprite(imageURL).ThenSet(image).Forget(); +ImageLoader.LoadSprite(imageURL).Consume(image).Forget(); ``` Use callback to set image and still wait for the completion: ```csharp -await ImageLoader.LoadSprite(imageURL).ThenSet(image); +await ImageLoader.LoadSprite(imageURL).Consume(image); ``` ## Features @@ -41,10 +41,10 @@ await ImageLoader.LoadSprite(imageURL).ThenSet(image); - ✔️ Avoids loading same image multiple times simultaneously, a new load task waits for completion of existed task - ✔️ Uses `UnityWebRequest` to load data which works smooth across all platforms including `WebGL` - ✔️ Cache supported on at `WebGL`. Memory cache works, Disk cache isn't allowed by the platform -- ✔️ Set into Image `ImageLoader.LoadSprite(imageURL).ThenSet(image);` -- ✔️ Set into RawImage `ImageLoader.LoadSprite(imageURL).ThenSet(rawImage);` -- ✔️ Set into Material `ImageLoader.LoadSprite(imageURL).ThenSet("_MainTex", material);` -- ✔️ Set into SpriteRenderer `ImageLoader.LoadSprite(imageURL).ThenSet(spriteRenderer);` +- ✔️ Set into Image `ImageLoader.LoadSprite(imageURL).Consume(image);` +- ✔️ Set into RawImage `ImageLoader.LoadSprite(imageURL).Consume(rawImage);` +- ✔️ Set into Material `ImageLoader.LoadSprite(imageURL).Consume("_MainTex", material);` +- ✔️ Set into SpriteRenderer `ImageLoader.LoadSprite(imageURL).Consume(spriteRenderer);` - ✔️ [Set into anything](#cancellation) - ✔️ Cancellation `ImageLoader.LoadSprite(imageURL).Cancel();` - ✔️ Cancellation callback `ImageLoader.LoadSprite(imageURL).Cancelled(() => ...);` @@ -134,6 +134,17 @@ ImageLoader.LoadSprite(imageURL) // loading process started .LoadedFromSource (sprite => Debug.Log("Loaded from source")) // on loaded from source │ // ────────────────────────────────────────────────────────────────────────────────────────────────────┘ + // ┌──────────────────────────┬───────────────────────────────────────────┐ + // │ Success lifecycle events │ │ + // └──────────────────────────┘ │ + .Loaded(sprite => Debug.Log("Loaded")) // on successfully loaded │ + // ┌────────────────────────────────────────────────────────┤ + // │ Set/Consume sprite [placeholder, successfully loaded] │ + // └────────────────────────────────────────────────────────┤ + .Consume(sprite => Debug.Log("Consumed")) // │ + .Consume(image) // │ + // ───────────────────────────────────────────────────────────────────────┘ + // ┌───────────────────────────┬──────────────────────────────────────────┐ // │ Negative lifecycle events │ │ // └───────────────────────────┘ │ @@ -141,13 +152,6 @@ ImageLoader.LoadSprite(imageURL) // loading process started .Failed(exception => Debug.LogException(exception)) // on failed to load │ // ───────────────────────────────────────────────────────────────────────┘ - // ┌──────────────────────────────────────┬──────────────────────────────┐ - // │ Successfully loaded lifecycle events │ │ - // └──────────────────────────────────────┘ │ - .Then(sprite => Debug.Log("Loaded")) // on loaded │ - .ThenSet(image) // on loaded set sprite into image │ - // ──────────────────────────────────────────────────────────────────────┘ - // ┌──────────────────────┬──────────────────────────────────────────────────────────────────────────┐ // │ The end of lifecycle │ │ // └──────────────────────┘ │ @@ -160,34 +164,34 @@ ImageLoader.LoadSprite(imageURL) // loading process started ## Load `Sprite` then set into `Image` -> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetImage.cs) +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeImage.cs) ```csharp // Load a sprite from the web and cache it for faster loading next time image.sprite = await ImageLoader.LoadSprite(imageURL); // Load a sprite from the web and set it directly to the Image component -await ImageLoader.LoadSprite(imageURL).ThenSet(image); +await ImageLoader.LoadSprite(imageURL).Consume(image); ``` ## Load `Texture2D` then set into `Material` -> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadTextureThenSetMaterial.cs) +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadTextureConsumeMaterial.cs) ```csharp // Load a Texture2D from the web and cache it for faster loading next time material.mainTexture = await ImageLoader.LoadTexture(imageURL); // Load a Texture2D from the web and set it directly to the Material -await ImageLoader.LoadTexture(imageURL).ThenSet(material); +await ImageLoader.LoadTexture(imageURL).Consume(material); ``` ## Load `Sprite` then set into multiple `Image` -> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteThenSetIntoMultipleImages.cs) +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeIntoMultipleImages.cs) ```csharp -ImageLoader.LoadSprite(imageURL).ThenSet(image1, image2).Forget(); +ImageLoader.LoadSprite(imageURL).Consume(image1, image2).Forget(); ``` ## Error handling @@ -196,12 +200,12 @@ ImageLoader.LoadSprite(imageURL).ThenSet(image1, image2).Forget(); ```csharp ImageLoader.LoadSprite(imageURL) // Attempt to load a sprite - .ThenSet(image) // If successful, set the sprite to the Image component + .Consume(image) // If successful, set the sprite to the Image component .Failed(exception => Debug.LogException(exception)) // If an error occurs, log the exception .Forget(); // Forget the task to avoid compilation warning ImageLoader.LoadSprite(imageURL) // Attempt to load a sprite - .ThenSet(image) // If successful, set the sprite to the Image component + .Consume(image) // If successful, set the sprite to the Image component .Then(sprite => image.gameObject.SetActive(true)) // If successful, activate the GameObject .Failed(exception => image.gameObject.SetActive(false)) // If an error occurs, deactivate the GameObject .Forget(); // Forget the task to avoid compilation warning @@ -216,12 +220,12 @@ ImageLoader.LoadSprite(imageURL) // Attempt to load a sprite await ImageLoader.LoadSprite(imageURL); // Load image, set image and wait -await ImageLoader.LoadSprite(imageURL).ThenSet(image); +await ImageLoader.LoadSprite(imageURL).Consume(image); // Skip waiting for completion. // To do that we can simply remove 'await' from the start. // To avoid compilation warning need to add '.Forget()'. -ImageLoader.LoadSprite(imageURL).ThenSet(image).Forget(); +ImageLoader.LoadSprite(imageURL).Consume(image).Forget(); ``` ## Cancellation @@ -234,7 +238,7 @@ Cancellation is helpful if target image consumer doesn't exist anymore. For exam ```csharp ImageLoader.LoadSprite(imageURL) - .ThenSet(image) + .Consume(image) .CancelOnEnable(this) // cancel on OnEnable event of current MonoBehaviour .CancelOnDisable(this) // cancel on OnDisable event of current MonoBehaviour .CancelOnDestroy(this); // cancel on OnDestroy event of current MonoBehaviour @@ -243,7 +247,7 @@ ImageLoader.LoadSprite(imageURL) ### Explicit cancellation ```csharp -var future = ImageLoader.LoadSprite(imageURL).ThenSet(image); +var future = ImageLoader.LoadSprite(imageURL).Consume(image); future.Cancel(); ``` @@ -254,7 +258,7 @@ var cancellationTokenSource = new CancellationTokenSource(); // loading with attached cancellation token ImageLoader.LoadSprite(imageURL, cancellationToken: cancellationTokenSource.Token) - .ThenSet(image) + .Consume(image) .Forget(); cancellationTokenSource.Cancel(); // canceling @@ -264,7 +268,7 @@ cancellationTokenSource.Cancel(); // canceling var cancellationTokenSource = new CancellationTokenSource(); ImageLoader.LoadSprite(imageURL) - .ThenSet(image) + .Consume(image) .Register(cancellationTokenSource.Token) // registering cancellation token .Forget(); @@ -274,7 +278,7 @@ cancellationTokenSource.Cancel(); // canceling ### Cancellation by `using` ```csharp -using (var future = ImageLoader.LoadSprite(imageURL).ThenSet(image)) +using (var future = ImageLoader.LoadSprite(imageURL).Consume(image)) { // future would be canceled and disposed outside of the brackets } @@ -282,18 +286,18 @@ using (var future = ImageLoader.LoadSprite(imageURL).ThenSet(image)) ```csharp ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .CancelOnDestroy(this) // cancel OnDestroy event of current gameObject .Forget(); ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .Failed(exception => Debug.LogException(exception)) // if fail print exception .CancelOnDestroy(this) // cancel OnDestroy event of current gameObject .Forget(); ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .Then(sprite => image.gameObject.SetActive(true)) // if success activate gameObject .Failed(exception => image.gameObject.SetActive(false)) // if fail deactivate gameObject .Canceled(() => Debug.Log("ImageLoading canceled")) // if cancelled @@ -317,7 +321,7 @@ Set timeout for a specific loading request (`IFuture`): ```csharp ImageLoader.LoadSprite(imageURL) // load sprite - .ThenSet(image) // if success set sprite into image + .Consume(image) // if success set sprite into image .Timeout(TimeSpan.FromSeconds(10)) // set timeout duration 10 seconds .Forget(); ``` @@ -438,11 +442,11 @@ reference = null; > [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleReferences.cs) -`Reference.ThenSet` has a unique feature to attach the reference to the target consumer if consumer is `UnityEngine.Component`. The reference would be disposed as only the consumer gets destroyed. +`Future>.Consume` has a unique feature to attach the reference to the target consumer if consumer is `UnityEngine.Component`. The reference would be disposed as only the consumer gets destroyed. ```csharp ImageLoader.LoadSpriteRef(imageURL) // load sprite using Reference - .ThenSet(image) // if success set sprite into image, also creates binding to `image` + .Consume(image) // if success set sprite into image, also creates binding to `image` .Forget(); ``` From 4ab20bb2d42fcd5b619664c9dddd1dcc00813767 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Fri, 7 Mar 2025 01:40:14 -0800 Subject: [PATCH 24/33] Updated placeholder documentation --- Assets/_PackageRoot/Documentation~/README.md | 21 +++++++++++++++ Assets/_PackageRoot/README.md | 21 +++++++++++++++ .../Runtime/Future/Future.Placeholder.cs | 15 +++++++++-- .../Runtime/Future/FutureEnums.cs | 2 +- .../Runtime/Future/FutureEnumsEx.cs | 24 ++++++++--------- Assets/_PackageRoot/Runtime/Future/IFuture.cs | 2 +- .../_PackageRoot/Samples/SamplePlaceholder.cs | 27 +++++++++++++++++++ .../Samples/SamplePlaceholder.cs.meta | 11 ++++++++ .../FakeFuture.Implementation.IFuture.cs | 2 +- .../Tests/Base/Utils/TestUtils.Load.cs | 24 ++++++++--------- .../Tests/Base/Utils/TestUtils.LoadFail.cs | 8 +++--- .../Tests/Base/Utils/TestUtils.cs | 10 +++---- README.md | 21 +++++++++++++++ 13 files changed, 150 insertions(+), 38 deletions(-) create mode 100644 Assets/_PackageRoot/Samples/SamplePlaceholder.cs create mode 100644 Assets/_PackageRoot/Samples/SamplePlaceholder.cs.meta diff --git a/Assets/_PackageRoot/Documentation~/README.md b/Assets/_PackageRoot/Documentation~/README.md index 88302c9..98cd081 100644 --- a/Assets/_PackageRoot/Documentation~/README.md +++ b/Assets/_PackageRoot/Documentation~/README.md @@ -65,6 +65,7 @@ await ImageLoader.LoadSprite(imageURL).Consume(image); - [Load `Sprite` then set into multiple `Image`](#load-sprite-then-set-into-multiple-image) - [Error handling](#error-handling) - [Async `await` and `Forget`](#async-await-and-forget) + - [Placeholder](#placeholder) - [Cancellation](#cancellation) - [Cancel by MonoBehaviour events](#cancel-by-monobehaviour-events) - [Explicit cancellation](#explicit-cancellation) @@ -228,6 +229,26 @@ await ImageLoader.LoadSprite(imageURL).Consume(image); ImageLoader.LoadSprite(imageURL).Consume(image).Forget(); ``` +## Placeholder + +While the target image is loading it would be a good idea to set placeholder image. Also, it works well for setting image if loading fails. + +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SamplePlaceholder.cs) + +```csharp +ImageLoader.LoadSprite(imageURL) + // set placeholder in all conditions + .SetPlaceholder(placeholder1) + + // set placeholder in a specific conditions + .SetPlaceholder(placeholder2, PlaceholderTrigger.LoadingFromSource) + .SetPlaceholder(placeholder3, PlaceholderTrigger.FailedToLoad) + + // set consumer + .Consume(image) + .Forget(); +``` + ## Cancellation Cancellation is helpful if target image consumer doesn't exist anymore. For example the `Image` was destroyed because another level had been loaded. The is not much sense to continue to load the image. It would safe some network traffic, CPU resources, and RAM. `IFuture` provides wide range of options to cancel the ongoing loading process. diff --git a/Assets/_PackageRoot/README.md b/Assets/_PackageRoot/README.md index 88302c9..98cd081 100644 --- a/Assets/_PackageRoot/README.md +++ b/Assets/_PackageRoot/README.md @@ -65,6 +65,7 @@ await ImageLoader.LoadSprite(imageURL).Consume(image); - [Load `Sprite` then set into multiple `Image`](#load-sprite-then-set-into-multiple-image) - [Error handling](#error-handling) - [Async `await` and `Forget`](#async-await-and-forget) + - [Placeholder](#placeholder) - [Cancellation](#cancellation) - [Cancel by MonoBehaviour events](#cancel-by-monobehaviour-events) - [Explicit cancellation](#explicit-cancellation) @@ -228,6 +229,26 @@ await ImageLoader.LoadSprite(imageURL).Consume(image); ImageLoader.LoadSprite(imageURL).Consume(image).Forget(); ``` +## Placeholder + +While the target image is loading it would be a good idea to set placeholder image. Also, it works well for setting image if loading fails. + +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SamplePlaceholder.cs) + +```csharp +ImageLoader.LoadSprite(imageURL) + // set placeholder in all conditions + .SetPlaceholder(placeholder1) + + // set placeholder in a specific conditions + .SetPlaceholder(placeholder2, PlaceholderTrigger.LoadingFromSource) + .SetPlaceholder(placeholder3, PlaceholderTrigger.FailedToLoad) + + // set consumer + .Consume(image) + .Forget(); +``` + ## Cancellation Cancellation is helpful if target image consumer doesn't exist anymore. For example the `Image` was destroyed because another level had been loaded. The is not much sense to continue to load the image. It would safe some network traffic, CPU resources, and RAM. `IFuture` provides wide range of options to cancel the ongoing loading process. diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs index 95406e0..873620d 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs @@ -5,12 +5,23 @@ namespace Extensions.Unity.ImageLoader public partial class Future { /// - /// Set a placeholder for this Future instance + /// Set a placeholder in all conditions for this Future instance + /// + /// new placeholder + /// Returns the Future instance + public IFuture SetPlaceholder(T placeholder) => SetPlaceholder(placeholder, + PlaceholderTrigger.LoadingFromDiskCache, + PlaceholderTrigger.LoadingFromSource, + PlaceholderTrigger.FailedToLoad, + PlaceholderTrigger.Canceled); + + /// + /// Set a placeholder in a specific condition for this Future instance /// /// new placeholder /// triggers for setting the placeholder /// Returns the Future instance - public IFuture SetPlaceholder(T placeholder, params FuturePlaceholderTrigger[] triggers) + public IFuture SetPlaceholder(T placeholder, params PlaceholderTrigger[] triggers) { if (cleared || IsCancelled) { diff --git a/Assets/_PackageRoot/Runtime/Future/FutureEnums.cs b/Assets/_PackageRoot/Runtime/Future/FutureEnums.cs index 00d2ff4..02e2ce7 100644 --- a/Assets/_PackageRoot/Runtime/Future/FutureEnums.cs +++ b/Assets/_PackageRoot/Runtime/Future/FutureEnums.cs @@ -24,7 +24,7 @@ public enum FutureLoadingFrom DiskCache = 2, Source = 4 } - public enum FuturePlaceholderTrigger + public enum PlaceholderTrigger { LoadingFromDiskCache = 2, LoadingFromSource = 4, diff --git a/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs b/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs index da7f69b..9c93e7f 100644 --- a/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs +++ b/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs @@ -4,35 +4,35 @@ public static class FutureEnumEx { public static FutureStatus AsFutureStatus(this FutureLoadedFrom value) => (FutureStatus)value; public static FutureStatus AsFutureStatus(this FutureLoadingFrom value) => (FutureStatus)value; - public static FutureStatus AsFutureStatus(this FuturePlaceholderTrigger value) => (FutureStatus)value; + public static FutureStatus AsFutureStatus(this PlaceholderTrigger value) => (FutureStatus)value; public static FutureLoadedFrom AsFutureLoadedFrom(this FutureStatus value) => (FutureLoadedFrom)value; public static FutureLoadedFrom AsFutureLoadedFrom(this FutureLoadingFrom value) => (FutureLoadedFrom)value; - public static FutureLoadedFrom AsFutureLoadedFrom(this FuturePlaceholderTrigger value) => (FutureLoadedFrom)value; + public static FutureLoadedFrom AsFutureLoadedFrom(this PlaceholderTrigger value) => (FutureLoadedFrom)value; public static FutureLoadingFrom AsFutureLoadingFrom(this FutureStatus value) => (FutureLoadingFrom)value; public static FutureLoadingFrom AsFutureLoadingFrom(this FutureLoadedFrom value) => (FutureLoadingFrom)value; - public static FutureLoadingFrom AsFutureLoadingFrom(this FuturePlaceholderTrigger value) => (FutureLoadingFrom)value; + public static FutureLoadingFrom AsFutureLoadingFrom(this PlaceholderTrigger value) => (FutureLoadingFrom)value; - public static FuturePlaceholderTrigger AsFuturePlaceholderTrigger(this FutureStatus value) => (FuturePlaceholderTrigger)value; - public static FuturePlaceholderTrigger AsFuturePlaceholderTrigger(this FutureLoadedFrom value) => (FuturePlaceholderTrigger)value; - public static FuturePlaceholderTrigger AsFuturePlaceholderTrigger(this FutureLoadingFrom value) => (FuturePlaceholderTrigger)value; + public static PlaceholderTrigger AsPlaceholderTrigger(this FutureStatus value) => (PlaceholderTrigger)value; + public static PlaceholderTrigger AsPlaceholderTrigger(this FutureLoadedFrom value) => (PlaceholderTrigger)value; + public static PlaceholderTrigger AsPlaceholderTrigger(this FutureLoadingFrom value) => (PlaceholderTrigger)value; public static bool IsEqual(this FutureStatus value1, FutureLoadedFrom value2) => (int)value1 == (int)value2; public static bool IsEqual(this FutureStatus value1, FutureLoadingFrom value2) => (int)value1 == (int)value2; - public static bool IsEqual(this FutureStatus value1, FuturePlaceholderTrigger value2) => (int)value1 == (int)value2; + public static bool IsEqual(this FutureStatus value1, PlaceholderTrigger value2) => (int)value1 == (int)value2; public static bool IsEqual(this FutureLoadedFrom value1, FutureStatus value2) => (int)value1 == (int)value2; public static bool IsEqual(this FutureLoadedFrom value1, FutureLoadingFrom value2) => (int)value1 == (int)value2; - public static bool IsEqual(this FutureLoadedFrom value1, FuturePlaceholderTrigger value2) => (int)value1 == (int)value2; + public static bool IsEqual(this FutureLoadedFrom value1, PlaceholderTrigger value2) => (int)value1 == (int)value2; public static bool IsEqual(this FutureLoadingFrom value1, FutureStatus value2) => (int)value1 == (int)value2; public static bool IsEqual(this FutureLoadingFrom value1, FutureLoadedFrom value2) => (int)value1 == (int)value2; - public static bool IsEqual(this FutureLoadingFrom value1, FuturePlaceholderTrigger value2) => (int)value1 == (int)value2; + public static bool IsEqual(this FutureLoadingFrom value1, PlaceholderTrigger value2) => (int)value1 == (int)value2; - public static bool IsEqual(this FuturePlaceholderTrigger value1, FutureStatus value2) => (int)value1 == (int)value2; - public static bool IsEqual(this FuturePlaceholderTrigger value1, FutureLoadedFrom value2) => (int)value1 == (int)value2; - public static bool IsEqual(this FuturePlaceholderTrigger value1, FutureLoadingFrom value2) => (int)value1 == (int)value2; + public static bool IsEqual(this PlaceholderTrigger value1, FutureStatus value2) => (int)value1 == (int)value2; + public static bool IsEqual(this PlaceholderTrigger value1, FutureLoadedFrom value2) => (int)value1 == (int)value2; + public static bool IsEqual(this PlaceholderTrigger value1, FutureLoadingFrom value2) => (int)value1 == (int)value2; } } diff --git a/Assets/_PackageRoot/Runtime/Future/IFuture.cs b/Assets/_PackageRoot/Runtime/Future/IFuture.cs index 6e67357..e1e74f3 100644 --- a/Assets/_PackageRoot/Runtime/Future/IFuture.cs +++ b/Assets/_PackageRoot/Runtime/Future/IFuture.cs @@ -41,7 +41,7 @@ public partial interface IFuture : IFuture, IDisposable IFuture SetUseDiskCache(bool value = true); IFuture SetUseMemoryCache(bool value = true); IFuture SetLogLevel(DebugLevel value); - IFuture SetPlaceholder(T placeholder, params FuturePlaceholderTrigger[] triggers); + IFuture SetPlaceholder(T placeholder, params PlaceholderTrigger[] triggers); IFuture PassEvents(IFutureInternal to, bool passCancelled = true); IFuture PassEvents(IFutureInternal to, Func convert, bool passCancelled = true); diff --git a/Assets/_PackageRoot/Samples/SamplePlaceholder.cs b/Assets/_PackageRoot/Samples/SamplePlaceholder.cs new file mode 100644 index 0000000..897f49a --- /dev/null +++ b/Assets/_PackageRoot/Samples/SamplePlaceholder.cs @@ -0,0 +1,27 @@ +using Extensions.Unity.ImageLoader; +using UnityEngine; +using UnityEngine.UI; + +public class SamplePlaceholder : MonoBehaviour +{ + [SerializeField] string imageURL; // URL of the image to be loaded + [SerializeField] Image image; // UI Image component to display the loaded sprite + [SerializeField] Sprite placeholder1; + [SerializeField] Sprite placeholder2; + [SerializeField] Sprite placeholder3; + + void Start() + { + ImageLoader.LoadSprite(imageURL) + // set placeholder in all conditions + .SetPlaceholder(placeholder1) + + // set placeholder in a specific conditions + .SetPlaceholder(placeholder2, PlaceholderTrigger.LoadingFromSource) + .SetPlaceholder(placeholder3, PlaceholderTrigger.FailedToLoad) + + // set consumer + .Consume(image) + .Forget(); + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Samples/SamplePlaceholder.cs.meta b/Assets/_PackageRoot/Samples/SamplePlaceholder.cs.meta new file mode 100644 index 0000000..8d4f3fe --- /dev/null +++ b/Assets/_PackageRoot/Samples/SamplePlaceholder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b1d60cfba4bd2d64ea9b2b3999e87a01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs index 22c3b26..315de94 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/FakeFuture.Implementation.IFuture.cs @@ -57,7 +57,7 @@ public void Cancel() public IFuture SetLogLevel(DebugLevel value) => throw new NotImplementedException(); public IFuture SetUseDiskCache(bool value = true) => throw new NotImplementedException(); public IFuture SetUseMemoryCache(bool value = true) => throw new NotImplementedException(); - public IFuture SetPlaceholder(T placeholder, params FuturePlaceholderTrigger[] triggers) => throw new NotImplementedException(); + public IFuture SetPlaceholder(T placeholder, params PlaceholderTrigger[] triggers) => throw new NotImplementedException(); public UniTask StartLoading(bool ignoreImageNotFoundError = false) => throw new NotImplementedException(); public IFuture Loaded(Action onCompleted) => throw new NotImplementedException(); } diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs index 6166c68..bf66e2c 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.Load.cs @@ -16,10 +16,10 @@ public static IEnumerator Load(string url, FutureLoadingFrom? expectedLoadingFro if (usePlaceholder) { - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromDiskCache], FuturePlaceholderTrigger.LoadingFromDiskCache); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromSource], FuturePlaceholderTrigger.LoadingFromSource); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.FailedToLoad], FuturePlaceholderTrigger.FailedToLoad); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.Canceled], FuturePlaceholderTrigger.Canceled); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.LoadingFromDiskCache], PlaceholderTrigger.LoadingFromDiskCache); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.LoadingFromSource], PlaceholderTrigger.LoadingFromSource); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.FailedToLoad], PlaceholderTrigger.FailedToLoad); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.Canceled], PlaceholderTrigger.Canceled); } if (expectedLoadingFrom.HasValue) @@ -77,10 +77,10 @@ public static IEnumerator LoadThenCancel(string url, FutureLoadingFrom? expected if (usePlaceholder) { - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromDiskCache], FuturePlaceholderTrigger.LoadingFromDiskCache); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromSource], FuturePlaceholderTrigger.LoadingFromSource); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.FailedToLoad], FuturePlaceholderTrigger.FailedToLoad); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.Canceled], FuturePlaceholderTrigger.Canceled); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.LoadingFromDiskCache], PlaceholderTrigger.LoadingFromDiskCache); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.LoadingFromSource], PlaceholderTrigger.LoadingFromSource); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.FailedToLoad], PlaceholderTrigger.FailedToLoad); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.Canceled], PlaceholderTrigger.Canceled); } if (expectedLoadingFrom.HasValue) @@ -148,10 +148,10 @@ public static IEnumerator LoadAndCancel(string url, FutureLoadingFrom? expectedL if (usePlaceholder) { - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromDiskCache], FuturePlaceholderTrigger.LoadingFromDiskCache); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromSource], FuturePlaceholderTrigger.LoadingFromSource); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.FailedToLoad], FuturePlaceholderTrigger.FailedToLoad); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.Canceled], FuturePlaceholderTrigger.Canceled); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.LoadingFromDiskCache], PlaceholderTrigger.LoadingFromDiskCache); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.LoadingFromSource], PlaceholderTrigger.LoadingFromSource); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.FailedToLoad], PlaceholderTrigger.FailedToLoad); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.Canceled], PlaceholderTrigger.Canceled); } futureListener.Assert_Events_Contains(expectedLoadingFrom.HasValue diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs index a6cd00a..8076c04 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.LoadFail.cs @@ -18,10 +18,10 @@ public static IEnumerator LoadFail(string url, FutureLoadingFrom? expectedLoadin if (usePlaceholder) { - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromDiskCache], FuturePlaceholderTrigger.LoadingFromDiskCache); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.LoadingFromSource], FuturePlaceholderTrigger.LoadingFromSource); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.FailedToLoad], FuturePlaceholderTrigger.FailedToLoad); - future.SetPlaceholder(placeholderSprites[FuturePlaceholderTrigger.Canceled], FuturePlaceholderTrigger.Canceled); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.LoadingFromDiskCache], PlaceholderTrigger.LoadingFromDiskCache); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.LoadingFromSource], PlaceholderTrigger.LoadingFromSource); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.FailedToLoad], PlaceholderTrigger.FailedToLoad); + future.SetPlaceholder(placeholderSprites[PlaceholderTrigger.Canceled], PlaceholderTrigger.Canceled); } if (expectedLoadingFrom.HasValue) diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs index 418834a..5d048bf 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs @@ -20,12 +20,12 @@ public static partial class TestUtils public static IEnumerable IncorrectImageURLs(int count = 3) => Enumerable.Range(0, count).Select(_ => IncorrectImageURL); public static readonly byte[] CorruptedTextureBytes = new byte[] { 0 }; - public static readonly Dictionary placeholderSprites = new Dictionary + public static readonly Dictionary placeholderSprites = new Dictionary { - { FuturePlaceholderTrigger.LoadingFromDiskCache, Texture2D.whiteTexture.ToSprite() }, - { FuturePlaceholderTrigger.LoadingFromSource, Texture2D.blackTexture.ToSprite() }, - { FuturePlaceholderTrigger.FailedToLoad, Texture2D.redTexture.ToSprite() }, - { FuturePlaceholderTrigger.Canceled, Texture2D.grayTexture.ToSprite() } + { PlaceholderTrigger.LoadingFromDiskCache, Texture2D.whiteTexture.ToSprite() }, + { PlaceholderTrigger.LoadingFromSource, Texture2D.blackTexture.ToSprite() }, + { PlaceholderTrigger.FailedToLoad, Texture2D.redTexture.ToSprite() }, + { PlaceholderTrigger.Canceled, Texture2D.grayTexture.ToSprite() } }; public static IEnumerator ClearEverything(string message) diff --git a/README.md b/README.md index 88302c9..98cd081 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ await ImageLoader.LoadSprite(imageURL).Consume(image); - [Load `Sprite` then set into multiple `Image`](#load-sprite-then-set-into-multiple-image) - [Error handling](#error-handling) - [Async `await` and `Forget`](#async-await-and-forget) + - [Placeholder](#placeholder) - [Cancellation](#cancellation) - [Cancel by MonoBehaviour events](#cancel-by-monobehaviour-events) - [Explicit cancellation](#explicit-cancellation) @@ -228,6 +229,26 @@ await ImageLoader.LoadSprite(imageURL).Consume(image); ImageLoader.LoadSprite(imageURL).Consume(image).Forget(); ``` +## Placeholder + +While the target image is loading it would be a good idea to set placeholder image. Also, it works well for setting image if loading fails. + +> [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SamplePlaceholder.cs) + +```csharp +ImageLoader.LoadSprite(imageURL) + // set placeholder in all conditions + .SetPlaceholder(placeholder1) + + // set placeholder in a specific conditions + .SetPlaceholder(placeholder2, PlaceholderTrigger.LoadingFromSource) + .SetPlaceholder(placeholder3, PlaceholderTrigger.FailedToLoad) + + // set consumer + .Consume(image) + .Forget(); +``` + ## Cancellation Cancellation is helpful if target image consumer doesn't exist anymore. For example the `Image` was destroyed because another level had been loaded. The is not much sense to continue to load the image. It would safe some network traffic, CPU resources, and RAM. `IFuture` provides wide range of options to cancel the ongoing loading process. From 7f5971dabbfd6de5f68e1756c444606992dbdbf4 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Fri, 7 Mar 2025 01:47:15 -0800 Subject: [PATCH 25/33] Refactoring of the placeholder setting --- .../Runtime/Future/Future.Placeholder.cs | 11 --- .../Runtime/Future/Future.PlaceholderEx.cs | 19 ++++++ ...r.cs.meta => Future.PlaceholderEx.cs.meta} | 2 +- .../Runtime/Future/Future.Setter.cs | 67 ------------------- 4 files changed, 20 insertions(+), 79 deletions(-) create mode 100644 Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs rename Assets/_PackageRoot/Runtime/Future/{Future.Setter.cs.meta => Future.PlaceholderEx.cs.meta} (83%) delete mode 100644 Assets/_PackageRoot/Runtime/Future/Future.Setter.cs diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs index 873620d..44700f3 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs @@ -4,17 +4,6 @@ namespace Extensions.Unity.ImageLoader { public partial class Future { - /// - /// Set a placeholder in all conditions for this Future instance - /// - /// new placeholder - /// Returns the Future instance - public IFuture SetPlaceholder(T placeholder) => SetPlaceholder(placeholder, - PlaceholderTrigger.LoadingFromDiskCache, - PlaceholderTrigger.LoadingFromSource, - PlaceholderTrigger.FailedToLoad, - PlaceholderTrigger.Canceled); - /// /// Set a placeholder in a specific condition for this Future instance /// diff --git a/Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs b/Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs new file mode 100644 index 0000000..e4a2abd --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs @@ -0,0 +1,19 @@ +using UnityEditor.PackageManager; +using UnityEngine; + +namespace Extensions.Unity.ImageLoader +{ + public static partial class FutureEx + { + /// + /// Set a placeholder in all conditions for this Future instance + /// + /// new placeholder + /// Returns the Future instance + public static IFuture SetPlaceholder(this IFuture future, T placeholder) => future.SetPlaceholder(placeholder, + PlaceholderTrigger.LoadingFromDiskCache, + PlaceholderTrigger.LoadingFromSource, + PlaceholderTrigger.FailedToLoad, + PlaceholderTrigger.Canceled); + } +} diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Setter.cs.meta b/Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs.meta similarity index 83% rename from Assets/_PackageRoot/Runtime/Future/Future.Setter.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs.meta index 87a056a..ca1d310 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.Setter.cs.meta +++ b/Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 79d466ddba9aff945b8b29cc2a155a85 +guid: 4aeccdcda9945a64fa430418911813c5 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Setter.cs b/Assets/_PackageRoot/Runtime/Future/Future.Setter.cs deleted file mode 100644 index 96fa44f..0000000 --- a/Assets/_PackageRoot/Runtime/Future/Future.Setter.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Cysharp.Threading.Tasks; -using System; -using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.UI; - -namespace Extensions.Unity.ImageLoader -{ - public static partial class FutureEx - { - // /// - // /// Set image into array of the generic target instances - // /// - // /// Setter function that gets Target instance and Sprite instance, it should set the Sprite value into Target instance - // /// Array of generic Target instances - // /// Returns async Future - // public static IFuture Setter(this IFuture future, Action setter, params T[] targets) - // => future.Then(sprite => - // { - // UniTask.Post(() => // using only MainThread to set any images to any targets - // { - // foreach (var target in targets) - // { - // if (ReferenceEquals(target, null) || target == null || (target is UIBehaviour uiBehaviour && IsDestroyed(uiBehaviour))) - // { - // if (future.LogLevel.IsActive(DebugLevel.Warning)) - // Debug.LogWarning($"[ImageLoader] Future[id={future.Id}] The target is null. Can't set image into it. Skipping."); - // continue; - // } - // Safe.Run(setter, target, sprite, future.LogLevel); - // } - // }); - // }); - - // /// - // /// Set image into array of Images - // /// - // /// Array of Images - // /// Returns async Future - // public static IFuture Setter(this IFuture future, params Image[] images) - // => future.Setter((target, sprite) => target.sprite = sprite, images); - - // /// - // /// Set image into array of RawImages - // /// - // /// Array of RawImages - // /// Returns async Future - // public static IFuture Setter(this IFuture future, params RawImage[] rawImages) - // => future.Setter((target, sprite) => target.texture = sprite?.texture, rawImages); - - // /// - // /// Set image into array of SpriteRenderers - // /// - // /// Array of SpriteRenderers - // /// Returns async Future - // public static IFuture Setter(this IFuture future, params SpriteRenderer[] spriteRenderers) - // => future.Setter((target, sprite) => target.sprite = sprite, spriteRenderers); - - // /// - // /// Set image into array of Materials - // /// - // /// Array of Materials - // /// Returns async Future - // public static IFuture Setter(this IFuture future, string propertyName = "_MainTex", params Material[] materials) - // => future.Setter((target, sprite) => target.SetTexture(propertyName, sprite?.texture), materials); - } -} From 71f2492952faca1bc6a11023436cacce48bb889b Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Fri, 7 Mar 2025 23:36:54 -0800 Subject: [PATCH 26/33] Added SetPlaceholder functions for all input types --- .../Runtime/Future/Extensions.meta | 8 ++ .../FutureEx.CancelOn.cs} | 0 .../FutureEx.CancelOn.cs.meta} | 0 .../FutureEx.Consume.cs} | 0 .../FutureEx.Consume.cs.meta} | 0 .../FutureEx.ConsumeRef.cs} | 0 .../FutureEx.ConsumeRef.cs.meta} | 0 .../Extensions/FutureEx.Placeholder.Color.cs | 85 ++++++++++++ .../FutureEx.Placeholder.Color.cs.meta | 11 ++ .../FutureEx.Placeholder.ColorHex.cs | 121 ++++++++++++++++++ .../FutureEx.Placeholder.ColorHex.cs.meta | 11 ++ .../FutureEx.Placeholder.cs} | 15 ++- .../FutureEx.Placeholder.cs.meta} | 0 .../FutureEx.Register.cs} | 0 .../FutureEx.Register.cs.meta} | 0 .../FutureEx.Timeout.cs} | 0 .../FutureEx.Timeout.cs.meta} | 0 Assets/_PackageRoot/Runtime/Future/Utils.meta | 8 ++ .../Future/{ => Utils}/FutureAwaiter.cs | 0 .../Future/{ => Utils}/FutureAwaiter.cs.meta | 0 .../Runtime/Future/{ => Utils}/FutureEnums.cs | 0 .../Future/{ => Utils}/FutureEnums.cs.meta | 0 .../Future/{ => Utils}/FutureEnumsEx.cs | 0 .../Future/{ => Utils}/FutureEnumsEx.cs.meta | 0 24 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 Assets/_PackageRoot/Runtime/Future/Extensions.meta rename Assets/_PackageRoot/Runtime/Future/{Future.CancelOn.cs => Extensions/FutureEx.CancelOn.cs} (100%) rename Assets/_PackageRoot/Runtime/Future/{Future.CancelOn.cs.meta => Extensions/FutureEx.CancelOn.cs.meta} (100%) rename Assets/_PackageRoot/Runtime/Future/{Future.Consume.cs => Extensions/FutureEx.Consume.cs} (100%) rename Assets/_PackageRoot/Runtime/Future/{Future.Consume.cs.meta => Extensions/FutureEx.Consume.cs.meta} (100%) rename Assets/_PackageRoot/Runtime/Future/{Future.ConsumeRef.cs => Extensions/FutureEx.ConsumeRef.cs} (100%) rename Assets/_PackageRoot/Runtime/Future/{Future.ConsumeRef.cs.meta => Extensions/FutureEx.ConsumeRef.cs.meta} (100%) create mode 100644 Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs create mode 100644 Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs.meta create mode 100644 Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.ColorHex.cs create mode 100644 Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.ColorHex.cs.meta rename Assets/_PackageRoot/Runtime/Future/{Future.PlaceholderEx.cs => Extensions/FutureEx.Placeholder.cs} (50%) rename Assets/_PackageRoot/Runtime/Future/{Future.PlaceholderEx.cs.meta => Extensions/FutureEx.Placeholder.cs.meta} (100%) rename Assets/_PackageRoot/Runtime/Future/{Future.Register.cs => Extensions/FutureEx.Register.cs} (100%) rename Assets/_PackageRoot/Runtime/Future/{Future.Register.cs.meta => Extensions/FutureEx.Register.cs.meta} (100%) rename Assets/_PackageRoot/Runtime/Future/{Future.Timeout.cs => Extensions/FutureEx.Timeout.cs} (100%) rename Assets/_PackageRoot/Runtime/Future/{Future.Timeout.cs.meta => Extensions/FutureEx.Timeout.cs.meta} (100%) create mode 100644 Assets/_PackageRoot/Runtime/Future/Utils.meta rename Assets/_PackageRoot/Runtime/Future/{ => Utils}/FutureAwaiter.cs (100%) rename Assets/_PackageRoot/Runtime/Future/{ => Utils}/FutureAwaiter.cs.meta (100%) rename Assets/_PackageRoot/Runtime/Future/{ => Utils}/FutureEnums.cs (100%) rename Assets/_PackageRoot/Runtime/Future/{ => Utils}/FutureEnums.cs.meta (100%) rename Assets/_PackageRoot/Runtime/Future/{ => Utils}/FutureEnumsEx.cs (100%) rename Assets/_PackageRoot/Runtime/Future/{ => Utils}/FutureEnumsEx.cs.meta (100%) diff --git a/Assets/_PackageRoot/Runtime/Future/Extensions.meta b/Assets/_PackageRoot/Runtime/Future/Extensions.meta new file mode 100644 index 0000000..ff27b8f --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Future/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 04fbd9d8ff04b2d4397b3008b80044d3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Runtime/Future/Future.CancelOn.cs b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.CancelOn.cs similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.CancelOn.cs rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.CancelOn.cs diff --git a/Assets/_PackageRoot/Runtime/Future/Future.CancelOn.cs.meta b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.CancelOn.cs.meta similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.CancelOn.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.CancelOn.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Consume.cs b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Consume.cs similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.Consume.cs rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Consume.cs diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Consume.cs.meta b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Consume.cs.meta similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.Consume.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Consume.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/Future.ConsumeRef.cs b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.ConsumeRef.cs similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.ConsumeRef.cs rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.ConsumeRef.cs diff --git a/Assets/_PackageRoot/Runtime/Future/Future.ConsumeRef.cs.meta b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.ConsumeRef.cs.meta similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.ConsumeRef.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.ConsumeRef.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs new file mode 100644 index 0000000..24b577b --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Concurrent; +using UnityEngine; + +namespace Extensions.Unity.ImageLoader +{ + public static partial class FutureEx + { + /// + /// Set a placeholder in all conditions for this Future instance + /// + /// new placeholder + /// Returns the Future instance + public static IFuture SetPlaceholder(this IFuture future, Color color) => future.SetPlaceholder(color, + PlaceholderTrigger.LoadingFromDiskCache, + PlaceholderTrigger.LoadingFromSource, + PlaceholderTrigger.FailedToLoad, + PlaceholderTrigger.Canceled); + + /// + /// Set a placeholder in specified conditions for this Future instance + /// + /// hex color to fill solid color + /// Returns the Future instance + public static IFuture SetPlaceholder(this IFuture future, Color color, params PlaceholderTrigger[] triggers) + => future.SetPlaceholder(ColorUtility.ToHtmlStringRGBA(color), triggers); + + /// + /// Set a placeholder in all conditions for this Future instance + /// + /// new placeholder + /// Returns the Future instance + public static IFuture SetPlaceholder(this IFuture future, Color color) => future.SetPlaceholder(color, + PlaceholderTrigger.LoadingFromDiskCache, + PlaceholderTrigger.LoadingFromSource, + PlaceholderTrigger.FailedToLoad, + PlaceholderTrigger.Canceled); + + /// + /// Set a placeholder in specified conditions for this Future instance + /// + /// hex color to fill solid color + /// Returns the Future instance + public static IFuture SetPlaceholder(this IFuture future, Color color, params PlaceholderTrigger[] triggers) + => future.SetPlaceholder(ColorUtility.ToHtmlStringRGBA(color), triggers); + + /// + /// Set a placeholder in all conditions for this Future instance + /// + /// new placeholder + /// Returns the Future instance + public static IFuture> SetPlaceholder(this IFuture> future, Color color) => future.SetPlaceholder(color, + PlaceholderTrigger.LoadingFromDiskCache, + PlaceholderTrigger.LoadingFromSource, + PlaceholderTrigger.FailedToLoad, + PlaceholderTrigger.Canceled); + + /// + /// Set a placeholder in specified conditions for this Future instance + /// + /// hex color to fill solid color + /// Returns the Future instance + public static IFuture> SetPlaceholder(this IFuture> future, Color color, params PlaceholderTrigger[] triggers) + => future.SetPlaceholder(ColorUtility.ToHtmlStringRGBA(color), triggers); + + /// + /// Set a placeholder in all conditions for this Future instance + /// + /// new placeholder + /// Returns the Future instance + public static IFuture> SetPlaceholder(this IFuture> future, Color color) => future.SetPlaceholder(color, + PlaceholderTrigger.LoadingFromDiskCache, + PlaceholderTrigger.LoadingFromSource, + PlaceholderTrigger.FailedToLoad, + PlaceholderTrigger.Canceled); + + /// + /// Set a placeholder in specified conditions for this Future instance + /// + /// hex color to fill solid color + /// Returns the Future instance + public static IFuture> SetPlaceholder(this IFuture> future, Color color, params PlaceholderTrigger[] triggers) + => future.SetPlaceholder(ColorUtility.ToHtmlStringRGBA(color), triggers); + } +} diff --git a/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs.meta b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs.meta new file mode 100644 index 0000000..c4fda6e --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9956fc41dbd96e345b77b3d39e81b365 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.ColorHex.cs b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.ColorHex.cs new file mode 100644 index 0000000..6160384 --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.ColorHex.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Concurrent; +using UnityEngine; + +namespace Extensions.Unity.ImageLoader +{ + public static partial class FutureEx + { + /// + /// Set a placeholder in all conditions for this Future instance + /// + /// new placeholder + /// Returns the Future instance + public static IFuture SetPlaceholder(this IFuture future, string hexColor) => future.SetPlaceholder(hexColor, + PlaceholderTrigger.LoadingFromDiskCache, + PlaceholderTrigger.LoadingFromSource, + PlaceholderTrigger.FailedToLoad, + PlaceholderTrigger.Canceled); + + /// + /// Set a placeholder in specified conditions for this Future instance + /// + /// hex color to fill solid color + /// Returns the Future instance + public static IFuture SetPlaceholder(this IFuture future, string hexColor, params PlaceholderTrigger[] triggers) + => future.SetPlaceholder(GetOrCreate(hexColor, color + => CreateFillTexture(color)), triggers); + + /// + /// Set a placeholder in all conditions for this Future instance + /// + /// new placeholder + /// Returns the Future instance + public static IFuture SetPlaceholder(this IFuture future, string hexColor) => future.SetPlaceholder(hexColor, + PlaceholderTrigger.LoadingFromDiskCache, + PlaceholderTrigger.LoadingFromSource, + PlaceholderTrigger.FailedToLoad, + PlaceholderTrigger.Canceled); + + + /// + /// Set a placeholder in specified conditions for this Future instance + /// + /// hex color to fill solid color + /// Returns the Future instance + public static IFuture SetPlaceholder(this IFuture future, string hexColor, params PlaceholderTrigger[] triggers) + => future.SetPlaceholder(GetOrCreate(hexColor, color + => GetOrCreate(hexColor, color2 + => CreateFillTexture(color2)) + .ToSprite()), triggers); + + /// + /// Set a placeholder in all conditions for this Future instance + /// + /// new placeholder + /// Returns the Future instance + public static IFuture> SetPlaceholder(this IFuture> future, string hexColor) => future.SetPlaceholder(hexColor, + PlaceholderTrigger.LoadingFromDiskCache, + PlaceholderTrigger.LoadingFromSource, + PlaceholderTrigger.FailedToLoad, + PlaceholderTrigger.Canceled); + /// + /// Set a placeholder in specified conditions for this Future instance + /// + /// hex color to fill solid color + /// Returns the Future instance + public static IFuture> SetPlaceholder(this IFuture> future, string hexColor, params PlaceholderTrigger[] triggers) + => future.SetPlaceholder( + GetOrCreate(hexColor, color => new Reference(hexColor, + GetOrCreate(hexColor, color2 + => CreateFillTexture(color2)))) + .SetKeep(), triggers); + + /// + /// Set a placeholder in all conditions for this Future instance + /// + /// new placeholder + /// Returns the Future instance + public static IFuture> SetPlaceholder(this IFuture> future, string hexColor) => future.SetPlaceholder(hexColor, + PlaceholderTrigger.LoadingFromDiskCache, + PlaceholderTrigger.LoadingFromSource, + PlaceholderTrigger.FailedToLoad, + PlaceholderTrigger.Canceled); + + /// + /// Set a placeholder in specified conditions for this Future instance + /// + /// hex color to fill solid color + /// Returns the Future instance + public static IFuture> SetPlaceholder(this IFuture> future, string hexColor, params PlaceholderTrigger[] triggers) + => future.SetPlaceholder( + GetOrCreate(hexColor, color => new Reference(hexColor, + GetOrCreate(hexColor, color2 => // sprite + GetOrCreate(hexColor, color3 => // texture + CreateFillTexture(color3)) + .ToSprite()))) + .SetKeep(), triggers); + + public static T GetOrCreate(string hexColor, Func create) + { + var type = typeof(T); + if (!colors.ContainsKey(type)) + colors[type] = new ConcurrentDictionary(); + + if (!colors[type].ContainsKey(hexColor)) + { + if (ColorUtility.TryParseHtmlString(hexColor, out var color)) + { + colors[type][hexColor] = create(color); + } + else + { + Debug.LogWarning($"[ImageLoader] FutureEx.SetPlaceholder: Invalid hex color '{hexColor}'"); + colors[type][hexColor] = create(Color.magenta); + } + } + + return (T)colors[type][hexColor]; + } + } +} diff --git a/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.ColorHex.cs.meta b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.ColorHex.cs.meta new file mode 100644 index 0000000..531a07a --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.ColorHex.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1dfd6496938bff140b68e9420e44a0ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.cs similarity index 50% rename from Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.cs index e4a2abd..70b88a0 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs +++ b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.cs @@ -1,10 +1,23 @@ -using UnityEditor.PackageManager; +using System; +using System.Collections.Concurrent; +using System.Linq; using UnityEngine; namespace Extensions.Unity.ImageLoader { public static partial class FutureEx { + const int PlaceholderSolidColorTextureSize = 2; + static ConcurrentDictionary> colors = new ConcurrentDictionary>(); + + public static Texture2D CreateFillTexture(this Color color, int width = PlaceholderSolidColorTextureSize, int height = PlaceholderSolidColorTextureSize) + { + var texture = new Texture2D(width, height); + texture.SetPixels(Enumerable.Repeat(color, width * height).ToArray()); + texture.Apply(); + return texture; + } + /// /// Set a placeholder in all conditions for this Future instance /// diff --git a/Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs.meta b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.cs.meta similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.PlaceholderEx.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Register.cs b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Register.cs similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.Register.cs rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Register.cs diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Register.cs.meta b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Register.cs.meta similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.Register.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Register.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Timeout.cs b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Timeout.cs similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.Timeout.cs rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Timeout.cs diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Timeout.cs.meta b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Timeout.cs.meta similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/Future.Timeout.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Timeout.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/Utils.meta b/Assets/_PackageRoot/Runtime/Future/Utils.meta new file mode 100644 index 0000000..47bbb78 --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Future/Utils.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c15aa2758e1abd746beb83376e6f3a15 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Runtime/Future/FutureAwaiter.cs b/Assets/_PackageRoot/Runtime/Future/Utils/FutureAwaiter.cs similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/FutureAwaiter.cs rename to Assets/_PackageRoot/Runtime/Future/Utils/FutureAwaiter.cs diff --git a/Assets/_PackageRoot/Runtime/Future/FutureAwaiter.cs.meta b/Assets/_PackageRoot/Runtime/Future/Utils/FutureAwaiter.cs.meta similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/FutureAwaiter.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Utils/FutureAwaiter.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/FutureEnums.cs b/Assets/_PackageRoot/Runtime/Future/Utils/FutureEnums.cs similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/FutureEnums.cs rename to Assets/_PackageRoot/Runtime/Future/Utils/FutureEnums.cs diff --git a/Assets/_PackageRoot/Runtime/Future/FutureEnums.cs.meta b/Assets/_PackageRoot/Runtime/Future/Utils/FutureEnums.cs.meta similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/FutureEnums.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Utils/FutureEnums.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs b/Assets/_PackageRoot/Runtime/Future/Utils/FutureEnumsEx.cs similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs rename to Assets/_PackageRoot/Runtime/Future/Utils/FutureEnumsEx.cs diff --git a/Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs.meta b/Assets/_PackageRoot/Runtime/Future/Utils/FutureEnumsEx.cs.meta similarity index 100% rename from Assets/_PackageRoot/Runtime/Future/FutureEnumsEx.cs.meta rename to Assets/_PackageRoot/Runtime/Future/Utils/FutureEnumsEx.cs.meta From 0f7fb5ba352c3e75ca100f7714400b9aaa2ee233 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Fri, 7 Mar 2025 23:43:18 -0800 Subject: [PATCH 27/33] Updated tests --- .../Runtime/TestFuture.Load.AndCancel.cs | 47 ++++++++---- .../Runtime/TestFuture.Load.ThenCancel.cs | 76 +++++++++++-------- .../Tests/Runtime/TestFuture.Load.cs | 49 ++++++++---- .../Tests/Runtime/TestFuture.LoadFail.cs | 17 +++-- .../Tests/Runtime/TestFuture.Placeholder.cs | 54 +++++++++++++ .../Runtime/TestFuture.Placeholder.cs.meta | 11 +++ .../Tests/Runtime/TestFutureOrder.cs | 2 +- 7 files changed, 187 insertions(+), 69 deletions(-) create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.Placeholder.cs create mode 100644 Assets/_PackageRoot/Tests/Runtime/TestFuture.Placeholder.cs.meta diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs index e34fdba..e918937 100644 --- a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.AndCancel.cs @@ -9,12 +9,17 @@ public partial class TestFuture [UnityTest] public IEnumerator LoadFrom_Source_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source_AndCancel); [UnityTest] public IEnumerator LoadFrom_Source_AndCancel() { - yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: true); - yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: false); - yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: true); - yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: false); + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: true, usePlaceholder: false); + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: false, usePlaceholder: false); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: true, usePlaceholder: false); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: false, usePlaceholder: false); + + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: true, usePlaceholder: true); + yield return LoadFrom_Source_AndCancel(useDiskCache: true, useMemoryCache: false, usePlaceholder: true); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: true, usePlaceholder: true); + yield return LoadFrom_Source_AndCancel(useDiskCache: false, useMemoryCache: false, usePlaceholder: true); } - IEnumerator LoadFrom_Source_AndCancel(bool useDiskCache, bool useMemoryCache) + IEnumerator LoadFrom_Source_AndCancel(bool useDiskCache, bool useMemoryCache, bool usePlaceholder) { ImageLoader.settings.useDiskCache = useDiskCache; ImageLoader.settings.useMemoryCache = useMemoryCache; @@ -24,17 +29,32 @@ IEnumerator LoadFrom_Source_AndCancel(bool useDiskCache, bool useMemoryCache) yield return TestUtils.ClearEverything(message: null); } + IEnumerator LoadFrom_MemoryCache_AndCancel(bool usePlaceholder) + { + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadFromMemoryCacheAndCancel(url, usePlaceholder: usePlaceholder); + } + yield return TestUtils.ClearEverything(message: null); + } + IEnumerator LoadFrom_DiskCache_AndCancel(bool usePlaceholder) + { + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadAndCancel(url, FutureLoadingFrom.DiskCache, usePlaceholder: usePlaceholder); + } + yield return TestUtils.ClearEverything(message: null); + } [UnityTest] public IEnumerator LoadFrom_MemoryCache_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache_AndCancel); [UnityTest] public IEnumerator LoadFrom_MemoryCache_AndCancel() { ImageLoader.settings.useDiskCache = true; ImageLoader.settings.useMemoryCache = true; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadFromMemoryCacheAndCancel(url); - } + yield return LoadFrom_MemoryCache_AndCancel(usePlaceholder: false); + yield return LoadFrom_MemoryCache_AndCancel(usePlaceholder: true); } [UnityTest] public IEnumerator LoadFrom_DiskCache_AndCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache_AndCancel); @@ -43,11 +63,8 @@ [UnityTest] public IEnumerator LoadFrom_DiskCache_AndCancel() ImageLoader.settings.useDiskCache = true; ImageLoader.settings.useMemoryCache = false; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadAndCancel(url, FutureLoadingFrom.DiskCache); - } + yield return LoadFrom_DiskCache_AndCancel(usePlaceholder: false); + yield return LoadFrom_DiskCache_AndCancel(usePlaceholder: true); } } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs index f48868b..430703d 100644 --- a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.ThenCancel.cs @@ -9,45 +9,66 @@ public partial class TestFuture [UnityTest] public IEnumerator LoadFrom_Source_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source_ThenCancel); [UnityTest] public IEnumerator LoadFrom_Source_ThenCancel() { - yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: true); - yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: true); - yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: true); - yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: true, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: true, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: true, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: true, usePlaceholder: false); - yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: false); - yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: false); - yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: false); - yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: false, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: false, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: false, usePlaceholder: false); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: false, usePlaceholder: false); + + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: true, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: true, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: true, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: true, usePlaceholder: true); + + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: true, useGC: false, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: true, useMemoryCache: false, useGC: false, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: true, useGC: false, usePlaceholder: true); + yield return LoadFrom_Source_ThenCancel(useDiskCache: false, useMemoryCache: false, useGC: false, usePlaceholder: true); } - IEnumerator LoadFrom_Source_ThenCancel(bool useDiskCache, bool useMemoryCache, bool useGC) + IEnumerator LoadFrom_Source_ThenCancel(bool useDiskCache, bool useMemoryCache, bool useGC, bool usePlaceholder) { ImageLoader.settings.useDiskCache = useDiskCache; ImageLoader.settings.useMemoryCache = useMemoryCache; foreach (var url in TestUtils.ImageURLs) - yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source, useGC); + yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source, useGC: useGC, usePlaceholder: usePlaceholder); yield return TestUtils.ClearEverything(message: null); } - - [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache_ThenCancel); - [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel() + IEnumerator LoadFrom_MemoryCache_ThenCancel(bool useGC, bool usePlaceholder) { - ImageLoader.settings.useDiskCache = true; - ImageLoader.settings.useMemoryCache = true; - foreach (var url in TestUtils.ImageURLs) { yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadFromMemoryCacheThenCancel(url, useGC: true); + yield return TestUtils.LoadFromMemoryCacheThenCancel(url, useGC: useGC, usePlaceholder: usePlaceholder); } - // TODO: remove code duplicate yield return TestUtils.ClearEverything(message: null); + } + IEnumerator LoadFrom_DiskCache_ThenCancel(bool useGC, bool usePlaceholder) + { foreach (var url in TestUtils.ImageURLs) { yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadFromMemoryCacheThenCancel(url, useGC: false); + yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, useGC: useGC, usePlaceholder: usePlaceholder); } + yield return TestUtils.ClearEverything(message: null); + } + + [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache_ThenCancel); + [UnityTest] public IEnumerator LoadFrom_MemoryCache_ThenCancel() + { + ImageLoader.settings.useDiskCache = true; + ImageLoader.settings.useMemoryCache = true; + + yield return LoadFrom_MemoryCache_ThenCancel(useGC: true, usePlaceholder: false); + yield return LoadFrom_MemoryCache_ThenCancel(useGC: false, usePlaceholder: false); + + yield return LoadFrom_MemoryCache_ThenCancel(useGC: true, usePlaceholder: true); + yield return LoadFrom_MemoryCache_ThenCancel(useGC: false, usePlaceholder: true); } [UnityTest] public IEnumerator LoadFrom_DiskCache_ThenCancel_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache_ThenCancel); @@ -56,18 +77,11 @@ [UnityTest] public IEnumerator LoadFrom_DiskCache_ThenCancel() ImageLoader.settings.useDiskCache = true; ImageLoader.settings.useMemoryCache = false; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, useGC: true); - } - // TODO: remove code duplicate - yield return TestUtils.ClearEverything(message: null); - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadThenCancel(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, useGC: false); - } + yield return LoadFrom_DiskCache_ThenCancel(useGC: true, usePlaceholder: false); + yield return LoadFrom_DiskCache_ThenCancel(useGC: false, usePlaceholder: false); + + yield return LoadFrom_DiskCache_ThenCancel(useGC: true, usePlaceholder: true); + yield return LoadFrom_DiskCache_ThenCancel(useGC: false, usePlaceholder: true); } } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs index e7b11dd..512ae70 100644 --- a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Load.cs @@ -9,21 +9,44 @@ public partial class TestFuture [UnityTest] public IEnumerator LoadFrom_Source_NoLogs() => TestUtils.RunNoLogs(LoadFrom_Source); [UnityTest] public IEnumerator LoadFrom_Source() { - yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: true); - yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: false); - yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: true); - yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: false); + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: true, usePlaceholder: false); + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: false, usePlaceholder: false); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: true, usePlaceholder: false); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: false, usePlaceholder: false); + + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: true, usePlaceholder: true); + yield return LoadFrom_Source(useDiskCache: true, useMemoryCache: false, usePlaceholder: true); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: true, usePlaceholder: true); + yield return LoadFrom_Source(useDiskCache: false, useMemoryCache: false, usePlaceholder: true); } - IEnumerator LoadFrom_Source(bool useDiskCache, bool useMemoryCache) + IEnumerator LoadFrom_Source(bool useDiskCache, bool useMemoryCache, bool usePlaceholder) { ImageLoader.settings.useDiskCache = useDiskCache; ImageLoader.settings.useMemoryCache = useMemoryCache; foreach (var url in TestUtils.ImageURLs) - yield return TestUtils.Load(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source); + yield return TestUtils.Load(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source, usePlaceholder: usePlaceholder); yield return TestUtils.ClearEverything(message: null); } + IEnumerator LoadFrom_DiskCache(bool usePlaceholder) + { + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.Load(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache, usePlaceholder: usePlaceholder); + } + yield return TestUtils.ClearEverything(message: null); + } + IEnumerator LoadFrom_MemoryCache(bool usePlaceholder) + { + foreach (var url in TestUtils.ImageURLs) + { + yield return ImageLoader.LoadSprite(url).AsCoroutine(); + yield return TestUtils.LoadFromMemoryCache(url, usePlaceholder: usePlaceholder); + } + yield return TestUtils.ClearEverything(message: null); + } [UnityTest] public IEnumerator LoadFrom_DiskCache_NoLogs() => TestUtils.RunNoLogs(LoadFrom_DiskCache); [UnityTest] public IEnumerator LoadFrom_DiskCache() @@ -31,11 +54,8 @@ [UnityTest] public IEnumerator LoadFrom_DiskCache() ImageLoader.settings.useDiskCache = true; ImageLoader.settings.useMemoryCache = false; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.Load(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache); - } + yield return LoadFrom_DiskCache(usePlaceholder: false); + yield return LoadFrom_DiskCache(usePlaceholder: true); } [UnityTest] public IEnumerator LoadFrom_MemoryCache_NoLogs() => TestUtils.RunNoLogs(LoadFrom_MemoryCache); @@ -44,11 +64,8 @@ [UnityTest] public IEnumerator LoadFrom_MemoryCache() ImageLoader.settings.useDiskCache = true; ImageLoader.settings.useMemoryCache = true; - foreach (var url in TestUtils.ImageURLs) - { - yield return ImageLoader.LoadSprite(url).AsCoroutine(); - yield return TestUtils.LoadFromMemoryCache(url); - } + yield return LoadFrom_MemoryCache(usePlaceholder: false); + yield return LoadFrom_MemoryCache(usePlaceholder: true); } } } \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs b/Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs index a37b605..4e79aa2 100644 --- a/Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.LoadFail.cs @@ -9,18 +9,23 @@ public partial class TestFuture [UnityTest] public IEnumerator LoadFailFrom_Source_NoLogs() => TestUtils.RunNoLogs(LoadFailFrom_Source); [UnityTest] public IEnumerator LoadFailFrom_Source() { - yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: true); - yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: false); - yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: true); - yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: false); + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: true, usePlaceholder: false); + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: false, usePlaceholder: false); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: true, usePlaceholder: false); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: false, usePlaceholder: false); + + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: true, usePlaceholder: true); + yield return LoadFailFrom_Source(useDiskCache: true, useMemoryCache: false, usePlaceholder: true); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: true, usePlaceholder: true); + yield return LoadFailFrom_Source(useDiskCache: false, useMemoryCache: false, usePlaceholder: true); } - IEnumerator LoadFailFrom_Source(bool useDiskCache, bool useMemoryCache) + IEnumerator LoadFailFrom_Source(bool useDiskCache, bool useMemoryCache, bool usePlaceholder) { ImageLoader.settings.useDiskCache = useDiskCache; ImageLoader.settings.useMemoryCache = useMemoryCache; foreach (var url in TestUtils.IncorrectImageURLs()) - yield return TestUtils.LoadFail(url, FutureLoadingFrom.Source); + yield return TestUtils.LoadFail(url, FutureLoadingFrom.Source, usePlaceholder: usePlaceholder); yield return TestUtils.ClearEverything(message: null); } diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Placeholder.cs b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Placeholder.cs new file mode 100644 index 0000000..151e016 --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Placeholder.cs @@ -0,0 +1,54 @@ +using UnityEngine.TestTools; +using System.Collections; +using Extensions.Unity.ImageLoader.Tests.Utils; + +namespace Extensions.Unity.ImageLoader.Tests +{ + public partial class TestFuture + { + // [UnityTest] public IEnumerator Placeholder_Source_NoLogs() => TestUtils.RunNoLogs(Placeholder_Source); + // [UnityTest] public IEnumerator Placeholder_Source() + // { + // yield return Placeholder_Source(useDiskCache: true, useMemoryCache: true); + // yield return Placeholder_Source(useDiskCache: true, useMemoryCache: false); + // yield return Placeholder_Source(useDiskCache: false, useMemoryCache: true); + // yield return Placeholder_Source(useDiskCache: false, useMemoryCache: false); + // } + // IEnumerator Placeholder_Source(bool useDiskCache, bool useMemoryCache) + // { + // ImageLoader.settings.useDiskCache = useDiskCache; + // ImageLoader.settings.useMemoryCache = useMemoryCache; + + // foreach (var url in TestUtils.ImageURLs) + // yield return TestUtils.Placeholder(url, FutureLoadingFrom.Source, FutureLoadedFrom.Source); + + // yield return TestUtils.ClearEverything(message: null); + // } + + // [UnityTest] public IEnumerator Placeholder_DiskCache_NoLogs() => TestUtils.RunNoLogs(Placeholder_DiskCache); + // [UnityTest] public IEnumerator Placeholder_DiskCache() + // { + // ImageLoader.settings.useDiskCache = true; + // ImageLoader.settings.useMemoryCache = false; + + // foreach (var url in TestUtils.ImageURLs) + // { + // yield return ImageLoader.LoadSprite(url).AsCoroutine(); + // yield return TestUtils.Placeholder(url, FutureLoadingFrom.DiskCache, FutureLoadedFrom.DiskCache); + // } + // } + + // [UnityTest] public IEnumerator Placeholder_MemoryCache_NoLogs() => TestUtils.RunNoLogs(Placeholder_MemoryCache); + // [UnityTest] public IEnumerator Placeholder_MemoryCache() + // { + // ImageLoader.settings.useDiskCache = true; + // ImageLoader.settings.useMemoryCache = true; + + // foreach (var url in TestUtils.ImageURLs) + // { + // yield return ImageLoader.LoadSprite(url).AsCoroutine(); + // yield return TestUtils.LoadFromMemoryCache(url); + // } + // } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFuture.Placeholder.cs.meta b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Placeholder.cs.meta new file mode 100644 index 0000000..cbe4a1c --- /dev/null +++ b/Assets/_PackageRoot/Tests/Runtime/TestFuture.Placeholder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 598cc762ff08ae843a93e2a01eda6290 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs b/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs index b6b89bf..f9e401a 100644 --- a/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs +++ b/Assets/_PackageRoot/Tests/Runtime/TestFutureOrder.cs @@ -24,7 +24,7 @@ [UnityTest] public IEnumerator EventsLoadedWhenClear() var startTime = DateTime.Now; var future = new FutureSprite(url); - var futureListener = new FutureListener(future, ignorePlaceholder: true); + var futureListener = new FutureListener(future); var task = future.StartLoading().AsTask(); yield return task.TimeoutCoroutine(TimeSpan.FromSeconds(10)); From a38c71a927226beac823b1a945f66f8152bee63a Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Fri, 7 Mar 2025 23:45:36 -0800 Subject: [PATCH 28/33] Updated README --- Assets/_PackageRoot/Documentation~/README.md | 10 +--------- Assets/_PackageRoot/README.md | 10 +--------- README.md | 10 +--------- 3 files changed, 3 insertions(+), 27 deletions(-) diff --git a/Assets/_PackageRoot/Documentation~/README.md b/Assets/_PackageRoot/Documentation~/README.md index 98cd081..2a4c08e 100644 --- a/Assets/_PackageRoot/Documentation~/README.md +++ b/Assets/_PackageRoot/Documentation~/README.md @@ -2,15 +2,7 @@ ![npm](https://img.shields.io/npm/v/extensions.unity.imageloader) [![openupm](https://img.shields.io/npm/v/extensions.unity.imageloader?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/extensions.unity.imageloader/) ![License](https://img.shields.io/github/license/IvanMurzak/Unity-ImageLoader) [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) -| Unity Version | Editor test | Player test | Build test | -|---------------|-------------|-------------|------------| -| 2019.4.40f1 | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_player.yml?label=2019.4.40f1-Player) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_build.yml?label=2019.4.40f1-Build) | -| 2020.3.40f1 | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_player.yml?label=2020.3.40f1-Player) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_build.yml?label=2020.3.40f1-Build) | -| 2021.3.45f1 | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_player.yml?label=2021.3.45f1-Player) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_build.yml?label=2021.3.45f1-Build) | -| 2022.3.57f1 | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_player.yml?label=2022.3.57f1-Player) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_build.yml?label=2022.3.57f1-Build) | -| 2023.1.20f1 | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_player.yml?label=2023.1.20f1-Player) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_build.yml?label=2023.1.20f1-Build) | -| 2023.2.20f1 | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_player.yml?label=2023.2.20f1-Player) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_build.yml?label=2023.2.20f1-Build) | -| 6000.0.37f1 | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_player.yml?label=6000.0.37f1-Player) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_build.yml?label=6000.0.37f1-Build) | +![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) Async image loader with two caching layers for Unity. It supports loading images from web or local paths and provides memory and disk caching to optimize performance. The package includes features for automatic image setting, cancellation handling, error handling, and lifecycle management. diff --git a/Assets/_PackageRoot/README.md b/Assets/_PackageRoot/README.md index 98cd081..2a4c08e 100644 --- a/Assets/_PackageRoot/README.md +++ b/Assets/_PackageRoot/README.md @@ -2,15 +2,7 @@ ![npm](https://img.shields.io/npm/v/extensions.unity.imageloader) [![openupm](https://img.shields.io/npm/v/extensions.unity.imageloader?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/extensions.unity.imageloader/) ![License](https://img.shields.io/github/license/IvanMurzak/Unity-ImageLoader) [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) -| Unity Version | Editor test | Player test | Build test | -|---------------|-------------|-------------|------------| -| 2019.4.40f1 | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_player.yml?label=2019.4.40f1-Player) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_build.yml?label=2019.4.40f1-Build) | -| 2020.3.40f1 | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_player.yml?label=2020.3.40f1-Player) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_build.yml?label=2020.3.40f1-Build) | -| 2021.3.45f1 | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_player.yml?label=2021.3.45f1-Player) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_build.yml?label=2021.3.45f1-Build) | -| 2022.3.57f1 | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_player.yml?label=2022.3.57f1-Player) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_build.yml?label=2022.3.57f1-Build) | -| 2023.1.20f1 | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_player.yml?label=2023.1.20f1-Player) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_build.yml?label=2023.1.20f1-Build) | -| 2023.2.20f1 | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_player.yml?label=2023.2.20f1-Player) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_build.yml?label=2023.2.20f1-Build) | -| 6000.0.37f1 | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_player.yml?label=6000.0.37f1-Player) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_build.yml?label=6000.0.37f1-Build) | +![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) Async image loader with two caching layers for Unity. It supports loading images from web or local paths and provides memory and disk caching to optimize performance. The package includes features for automatic image setting, cancellation handling, error handling, and lifecycle management. diff --git a/README.md b/README.md index 98cd081..2a4c08e 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,7 @@ ![npm](https://img.shields.io/npm/v/extensions.unity.imageloader) [![openupm](https://img.shields.io/npm/v/extensions.unity.imageloader?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/extensions.unity.imageloader/) ![License](https://img.shields.io/github/license/IvanMurzak/Unity-ImageLoader) [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) -| Unity Version | Editor test | Player test | Build test | -|---------------|-------------|-------------|------------| -| 2019.4.40f1 | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_player.yml?label=2019.4.40f1-Player) | ![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2019.4.40f1_build.yml?label=2019.4.40f1-Build) | -| 2020.3.40f1 | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_player.yml?label=2020.3.40f1-Player) | ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2020.3.40f1_build.yml?label=2020.3.40f1-Build) | -| 2021.3.45f1 | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_player.yml?label=2021.3.45f1-Player) | ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2021.3.45f1_build.yml?label=2021.3.45f1-Build) | -| 2022.3.57f1 | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_player.yml?label=2022.3.57f1-Player) | ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2022.3.57f1_build.yml?label=2022.3.57f1-Build) | -| 2023.1.20f1 | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_player.yml?label=2023.1.20f1-Player) | ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.1.20f1_build.yml?label=2023.1.20f1-Build) | -| 2023.2.20f1 | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_player.yml?label=2023.2.20f1-Player) | ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/2023.2.20f1_build.yml?label=2023.2.20f1-Build) | -| 6000.0.37f1 | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_player.yml?label=6000.0.37f1-Player) | ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-Theme/6000.0.37f1_build.yml?label=6000.0.37f1-Build) | +![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor) Async image loader with two caching layers for Unity. It supports loading images from web or local paths and provides memory and disk caching to optimize performance. The package includes features for automatic image setting, cancellation handling, error handling, and lifecycle management. From 226b3414e3c5b78630871ab33e6debc9dce59a77 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sat, 8 Mar 2025 01:21:18 -0800 Subject: [PATCH 29/33] Refactor placeholder color handling and add ColorExtensions utility methods --- .../Extensions/FutureEx.Placeholder.Color.cs | 8 ++-- .../Runtime/Future/Future.Placeholder.cs | 12 ++++- Assets/_PackageRoot/Runtime/Future/Future.cs | 4 ++ .../Runtime/Utils/ColorExtensions.cs | 48 +++++++++++++++++++ .../Runtime/Utils/ColorExtensions.cs.meta | 11 +++++ .../_PackageRoot/Samples/SamplePlaceholder.cs | 12 ++--- 6 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 Assets/_PackageRoot/Runtime/Utils/ColorExtensions.cs create mode 100644 Assets/_PackageRoot/Runtime/Utils/ColorExtensions.cs.meta diff --git a/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs index 24b577b..116679c 100644 --- a/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs +++ b/Assets/_PackageRoot/Runtime/Future/Extensions/FutureEx.Placeholder.Color.cs @@ -23,7 +23,7 @@ public static IFuture SetPlaceholder(this IFuture future, /// hex color to fill solid color /// Returns the Future instance public static IFuture SetPlaceholder(this IFuture future, Color color, params PlaceholderTrigger[] triggers) - => future.SetPlaceholder(ColorUtility.ToHtmlStringRGBA(color), triggers); + => future.SetPlaceholder(color.ToHexRGBA(), triggers); /// /// Set a placeholder in all conditions for this Future instance @@ -42,7 +42,7 @@ public static IFuture SetPlaceholder(this IFuture future, Color /// hex color to fill solid color /// Returns the Future instance public static IFuture SetPlaceholder(this IFuture future, Color color, params PlaceholderTrigger[] triggers) - => future.SetPlaceholder(ColorUtility.ToHtmlStringRGBA(color), triggers); + => future.SetPlaceholder(color.ToHexRGBA(), triggers); /// /// Set a placeholder in all conditions for this Future instance @@ -61,7 +61,7 @@ public static IFuture> SetPlaceholder(this IFuturehex color to fill solid color /// Returns the Future instance public static IFuture> SetPlaceholder(this IFuture> future, Color color, params PlaceholderTrigger[] triggers) - => future.SetPlaceholder(ColorUtility.ToHtmlStringRGBA(color), triggers); + => future.SetPlaceholder(color.ToHexRGBA(), triggers); /// /// Set a placeholder in all conditions for this Future instance @@ -80,6 +80,6 @@ public static IFuture> SetPlaceholder(this IFuturehex color to fill solid color /// Returns the Future instance public static IFuture> SetPlaceholder(this IFuture> future, Color color, params PlaceholderTrigger[] triggers) - => future.SetPlaceholder(ColorUtility.ToHtmlStringRGBA(color), triggers); + => future.SetPlaceholder(color.ToHexRGBA(), triggers); } } diff --git a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs index 44700f3..daf2b5a 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.Placeholder.cs @@ -19,6 +19,16 @@ public IFuture SetPlaceholder(T placeholder, params PlaceholderTrigger[] trig return this; } + if (triggers == null || triggers.Length == 0) + { + if (LogLevel.IsActive(DebugLevel.Error)) + Debug.LogError($"[ImageLoader] Future[id={Id}] SetPlaceholder: triggers are not specified\n{Url}"); + return this; + } + + if (LogLevel.IsActive(DebugLevel.Trace)) + Debug.Log($"[ImageLoader] Future[id={Id}] SetPlaceholder\n{Url}"); + foreach (var trigger in triggers) { if (trigger.IsEqual(Status)) @@ -28,7 +38,7 @@ public IFuture SetPlaceholder(T placeholder, params PlaceholderTrigger[] trig foreach (var setter in consumers) Safe.Run(setter, placeholder, LogLevel); } - continue; + // continue; } lock (placeholders) placeholders[trigger.AsFutureStatus()] = placeholder; diff --git a/Assets/_PackageRoot/Runtime/Future/Future.cs b/Assets/_PackageRoot/Runtime/Future/Future.cs index 3a8d893..5f2e0a1 100644 --- a/Assets/_PackageRoot/Runtime/Future/Future.cs +++ b/Assets/_PackageRoot/Runtime/Future/Future.cs @@ -225,7 +225,11 @@ void FeedConsumers(T value) lock (consumers) { foreach (var setter in consumers) + { + if (LogLevel.IsActive(DebugLevel.Trace)) + Debug.Log($"[ImageLoader] Future[id={Id}] Feed consumer\n{Url}"); Safe.Run(setter, value, LogLevel); + } } } diff --git a/Assets/_PackageRoot/Runtime/Utils/ColorExtensions.cs b/Assets/_PackageRoot/Runtime/Utils/ColorExtensions.cs new file mode 100644 index 0000000..e601c8d --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Utils/ColorExtensions.cs @@ -0,0 +1,48 @@ +using UnityEngine; + +namespace Extensions.Unity.ImageLoader +{ + public static class ColorExtensions + { + public static string ToHexRGB(this Color color, bool hexSymbol = true) => hexSymbol + ? $"#{ColorUtility.ToHtmlStringRGB(color)}" + : ColorUtility.ToHtmlStringRGB(color); + + public static string ToHexRGBA(this Color color, bool hexSymbol = true) => hexSymbol + ? $"#{ColorUtility.ToHtmlStringRGBA(color)}" + : ColorUtility.ToHtmlStringRGBA(color); + + public static Color SetR(this Color color, float r) + { + color.r = r; + return color; + } + public static Color SetG(this Color color, float g) + { + color.g = g; + return color; + } + public static Color SetB(this Color color, float b) + { + color.b = b; + return color; + } + public static Color SetA(this Color color, float a) + { + color.a = a; + return color; + } + public static bool HexToColor(this string hex, out Color color) + => ColorUtility.TryParseHtmlString(hex, out color); + + public static Color HexToColor(this string hex) + { + if (!ColorUtility.TryParseHtmlString(hex, out var color)) + { + if (ImageLoader.settings.debugLevel.IsActive(DebugLevel.Error)) + Debug.LogError($"[ImageLoader] Invalid hex color: {hex}"); + } + return color; + } + } +} \ No newline at end of file diff --git a/Assets/_PackageRoot/Runtime/Utils/ColorExtensions.cs.meta b/Assets/_PackageRoot/Runtime/Utils/ColorExtensions.cs.meta new file mode 100644 index 0000000..96a3856 --- /dev/null +++ b/Assets/_PackageRoot/Runtime/Utils/ColorExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7886578b617d9042a504ea6ece6445b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_PackageRoot/Samples/SamplePlaceholder.cs b/Assets/_PackageRoot/Samples/SamplePlaceholder.cs index 897f49a..131905a 100644 --- a/Assets/_PackageRoot/Samples/SamplePlaceholder.cs +++ b/Assets/_PackageRoot/Samples/SamplePlaceholder.cs @@ -6,19 +6,19 @@ public class SamplePlaceholder : MonoBehaviour { [SerializeField] string imageURL; // URL of the image to be loaded [SerializeField] Image image; // UI Image component to display the loaded sprite - [SerializeField] Sprite placeholder1; - [SerializeField] Sprite placeholder2; - [SerializeField] Sprite placeholder3; + [SerializeField] Sprite placeholderAny; + [SerializeField] Sprite placeholderLoadingFromSource; + [SerializeField] Color placeholderFailedToLoad = Color.red; void Start() { ImageLoader.LoadSprite(imageURL) // set placeholder in all conditions - .SetPlaceholder(placeholder1) + .SetPlaceholder(placeholderAny) // set placeholder in a specific conditions - .SetPlaceholder(placeholder2, PlaceholderTrigger.LoadingFromSource) - .SetPlaceholder(placeholder3, PlaceholderTrigger.FailedToLoad) + .SetPlaceholder(placeholderLoadingFromSource, PlaceholderTrigger.LoadingFromSource) + .SetPlaceholder(placeholderFailedToLoad, PlaceholderTrigger.FailedToLoad) // set consumer .Consume(image) From 3198b639bcabe40224082568824d03cbf4d02f15 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sat, 8 Mar 2025 01:22:20 -0800 Subject: [PATCH 30/33] Updated README --- Assets/_PackageRoot/Documentation~/README.md | 6 +++--- Assets/_PackageRoot/README.md | 6 +++--- README.md | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Assets/_PackageRoot/Documentation~/README.md b/Assets/_PackageRoot/Documentation~/README.md index 2a4c08e..f6cb8e4 100644 --- a/Assets/_PackageRoot/Documentation~/README.md +++ b/Assets/_PackageRoot/Documentation~/README.md @@ -230,11 +230,11 @@ While the target image is loading it would be a good idea to set placeholder ima ```csharp ImageLoader.LoadSprite(imageURL) // set placeholder in all conditions - .SetPlaceholder(placeholder1) + .SetPlaceholder(placeholderAny) // set placeholder in a specific conditions - .SetPlaceholder(placeholder2, PlaceholderTrigger.LoadingFromSource) - .SetPlaceholder(placeholder3, PlaceholderTrigger.FailedToLoad) + .SetPlaceholder(placeholderLoadingFromSource, PlaceholderTrigger.LoadingFromSource) + .SetPlaceholder(placeholderFailedToLoad, PlaceholderTrigger.FailedToLoad) // set consumer .Consume(image) diff --git a/Assets/_PackageRoot/README.md b/Assets/_PackageRoot/README.md index 2a4c08e..f6cb8e4 100644 --- a/Assets/_PackageRoot/README.md +++ b/Assets/_PackageRoot/README.md @@ -230,11 +230,11 @@ While the target image is loading it would be a good idea to set placeholder ima ```csharp ImageLoader.LoadSprite(imageURL) // set placeholder in all conditions - .SetPlaceholder(placeholder1) + .SetPlaceholder(placeholderAny) // set placeholder in a specific conditions - .SetPlaceholder(placeholder2, PlaceholderTrigger.LoadingFromSource) - .SetPlaceholder(placeholder3, PlaceholderTrigger.FailedToLoad) + .SetPlaceholder(placeholderLoadingFromSource, PlaceholderTrigger.LoadingFromSource) + .SetPlaceholder(placeholderFailedToLoad, PlaceholderTrigger.FailedToLoad) // set consumer .Consume(image) diff --git a/README.md b/README.md index 2a4c08e..f6cb8e4 100644 --- a/README.md +++ b/README.md @@ -230,11 +230,11 @@ While the target image is loading it would be a good idea to set placeholder ima ```csharp ImageLoader.LoadSprite(imageURL) // set placeholder in all conditions - .SetPlaceholder(placeholder1) + .SetPlaceholder(placeholderAny) // set placeholder in a specific conditions - .SetPlaceholder(placeholder2, PlaceholderTrigger.LoadingFromSource) - .SetPlaceholder(placeholder3, PlaceholderTrigger.FailedToLoad) + .SetPlaceholder(placeholderLoadingFromSource, PlaceholderTrigger.LoadingFromSource) + .SetPlaceholder(placeholderFailedToLoad, PlaceholderTrigger.FailedToLoad) // set consumer .Consume(image) From a40f3ac4324e18f0ad8818b2cd0d4d99329268b3 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sat, 8 Mar 2025 01:47:07 -0800 Subject: [PATCH 31/33] Bump version from 6.0.2 to 7.0.0 --- Assets/_PackageRoot/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/_PackageRoot/package.json b/Assets/_PackageRoot/package.json index fe9dec7..dc9ee8a 100644 --- a/Assets/_PackageRoot/package.json +++ b/Assets/_PackageRoot/package.json @@ -7,7 +7,7 @@ "url": "https://github.com/IvanMurzak" }, "license": "MIT", - "version": "6.0.2", + "version": "7.0.0", "unity": "2019.4", "description": "Asynchronous image loading from remote or local destination. It has two layers of configurable Memory and Disk cache systems.", "keywords": [ From fdb0502f6b49e80831d902156c3d6c96205d9355 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sat, 8 Mar 2025 11:33:11 -0800 Subject: [PATCH 32/33] Renamed `master` -> `main` --- .github/workflows/2019.4.40f1_build.yml | 4 ++-- .github/workflows/2019.4.40f1_editor.yml | 4 ++-- .github/workflows/2019.4.40f1_player.yml | 4 ++-- .github/workflows/2020.3.40f1_build.yml | 4 ++-- .github/workflows/2020.3.40f1_editor.yml | 4 ++-- .github/workflows/2020.3.40f1_player.yml | 4 ++-- .github/workflows/2021.3.45f1_build.yml | 4 ++-- .github/workflows/2021.3.45f1_editor.yml | 4 ++-- .github/workflows/2021.3.45f1_player.yml | 4 ++-- .github/workflows/2022.3.57f1_build.yml | 4 ++-- .github/workflows/2022.3.57f1_editor.yml | 4 ++-- .github/workflows/2022.3.57f1_player.yml | 4 ++-- .github/workflows/2023.1.20f1_build.yml | 4 ++-- .github/workflows/2023.1.20f1_editor.yml | 4 ++-- .github/workflows/2023.1.20f1_player.yml | 4 ++-- .github/workflows/2023.2.20f1_build.yml | 4 ++-- .github/workflows/2023.2.20f1_editor.yml | 4 ++-- .github/workflows/2023.2.20f1_player.yml | 4 ++-- .github/workflows/6000.0.37f1_build.yml | 4 ++-- .github/workflows/6000.0.37f1_editor.yml | 4 ++-- .github/workflows/6000.0.37f1_player.yml | 4 ++-- 21 files changed, 42 insertions(+), 42 deletions(-) diff --git a/.github/workflows/2019.4.40f1_build.yml b/.github/workflows/2019.4.40f1_build.yml index ce65c55..79c0100 100644 --- a/.github/workflows/2019.4.40f1_build.yml +++ b/.github/workflows/2019.4.40f1_build.yml @@ -3,10 +3,10 @@ name: 2019.4.40f1-Build on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/2019.4.40f1_editor.yml b/.github/workflows/2019.4.40f1_editor.yml index 67b3d2b..45e1f11 100644 --- a/.github/workflows/2019.4.40f1_editor.yml +++ b/.github/workflows/2019.4.40f1_editor.yml @@ -3,10 +3,10 @@ name: 2019.4.40f1-Editor on: pull_request: branches: - - master + - main push: branches: - - master + - main jobs: editor-tests: diff --git a/.github/workflows/2019.4.40f1_player.yml b/.github/workflows/2019.4.40f1_player.yml index a14c9d9..d06f183 100644 --- a/.github/workflows/2019.4.40f1_player.yml +++ b/.github/workflows/2019.4.40f1_player.yml @@ -3,10 +3,10 @@ name: 2019.4.40f1-Player on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/2020.3.40f1_build.yml b/.github/workflows/2020.3.40f1_build.yml index e2e95ad..91ff3b7 100644 --- a/.github/workflows/2020.3.40f1_build.yml +++ b/.github/workflows/2020.3.40f1_build.yml @@ -3,10 +3,10 @@ name: 2020.3.40f1-Build on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/2020.3.40f1_editor.yml b/.github/workflows/2020.3.40f1_editor.yml index ecac8de..b839aa1 100644 --- a/.github/workflows/2020.3.40f1_editor.yml +++ b/.github/workflows/2020.3.40f1_editor.yml @@ -3,10 +3,10 @@ name: 2020.3.40f1-Editor on: pull_request: branches: - - master + - main push: branches: - - master + - main jobs: editor-tests: diff --git a/.github/workflows/2020.3.40f1_player.yml b/.github/workflows/2020.3.40f1_player.yml index e562c6d..632f6a1 100644 --- a/.github/workflows/2020.3.40f1_player.yml +++ b/.github/workflows/2020.3.40f1_player.yml @@ -3,10 +3,10 @@ name: 2020.3.40f1-Player on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/2021.3.45f1_build.yml b/.github/workflows/2021.3.45f1_build.yml index 25677eb..0e9cb07 100644 --- a/.github/workflows/2021.3.45f1_build.yml +++ b/.github/workflows/2021.3.45f1_build.yml @@ -3,10 +3,10 @@ name: 2021.3.45f1-Build on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/2021.3.45f1_editor.yml b/.github/workflows/2021.3.45f1_editor.yml index a2894b5..411c5f8 100644 --- a/.github/workflows/2021.3.45f1_editor.yml +++ b/.github/workflows/2021.3.45f1_editor.yml @@ -3,10 +3,10 @@ name: 2021.3.45f1-Editor on: pull_request: branches: - - master + - main push: branches: - - master + - main jobs: editor-tests: diff --git a/.github/workflows/2021.3.45f1_player.yml b/.github/workflows/2021.3.45f1_player.yml index d98f817..a90b84d 100644 --- a/.github/workflows/2021.3.45f1_player.yml +++ b/.github/workflows/2021.3.45f1_player.yml @@ -3,10 +3,10 @@ name: 2021.3.45f1-Player on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/2022.3.57f1_build.yml b/.github/workflows/2022.3.57f1_build.yml index 78666f7..26abe34 100644 --- a/.github/workflows/2022.3.57f1_build.yml +++ b/.github/workflows/2022.3.57f1_build.yml @@ -3,10 +3,10 @@ name: 2022.3.57f1-Build on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/2022.3.57f1_editor.yml b/.github/workflows/2022.3.57f1_editor.yml index 7ad30ea..eaa76bc 100644 --- a/.github/workflows/2022.3.57f1_editor.yml +++ b/.github/workflows/2022.3.57f1_editor.yml @@ -3,10 +3,10 @@ name: 2022.3.57f1-Editor on: pull_request: branches: - - master + - main push: branches: - - master + - main jobs: editor-tests: diff --git a/.github/workflows/2022.3.57f1_player.yml b/.github/workflows/2022.3.57f1_player.yml index ae597ae..ae44fc3 100644 --- a/.github/workflows/2022.3.57f1_player.yml +++ b/.github/workflows/2022.3.57f1_player.yml @@ -3,10 +3,10 @@ name: 2022.3.57f1-Player on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/2023.1.20f1_build.yml b/.github/workflows/2023.1.20f1_build.yml index 5a90ec2..4c85706 100644 --- a/.github/workflows/2023.1.20f1_build.yml +++ b/.github/workflows/2023.1.20f1_build.yml @@ -3,10 +3,10 @@ name: 2023.1.20f1-Build on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/2023.1.20f1_editor.yml b/.github/workflows/2023.1.20f1_editor.yml index b51dabe..cb70fdc 100644 --- a/.github/workflows/2023.1.20f1_editor.yml +++ b/.github/workflows/2023.1.20f1_editor.yml @@ -3,10 +3,10 @@ name: 2023.1.20f1-Editor on: pull_request: branches: - - master + - main push: branches: - - master + - main jobs: editor-tests: diff --git a/.github/workflows/2023.1.20f1_player.yml b/.github/workflows/2023.1.20f1_player.yml index 8569731..e076ad5 100644 --- a/.github/workflows/2023.1.20f1_player.yml +++ b/.github/workflows/2023.1.20f1_player.yml @@ -3,10 +3,10 @@ name: 2023.1.20f1-Player on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/2023.2.20f1_build.yml b/.github/workflows/2023.2.20f1_build.yml index ed9dda3..8226e6f 100644 --- a/.github/workflows/2023.2.20f1_build.yml +++ b/.github/workflows/2023.2.20f1_build.yml @@ -3,10 +3,10 @@ name: 2023.2.20f1-Build on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/2023.2.20f1_editor.yml b/.github/workflows/2023.2.20f1_editor.yml index 1b83144..729c4ed 100644 --- a/.github/workflows/2023.2.20f1_editor.yml +++ b/.github/workflows/2023.2.20f1_editor.yml @@ -3,10 +3,10 @@ name: 2023.2.20f1-Editor on: pull_request: branches: - - master + - main push: branches: - - master + - main jobs: editor-tests: diff --git a/.github/workflows/2023.2.20f1_player.yml b/.github/workflows/2023.2.20f1_player.yml index 8442eae..60dad76 100644 --- a/.github/workflows/2023.2.20f1_player.yml +++ b/.github/workflows/2023.2.20f1_player.yml @@ -3,10 +3,10 @@ name: 2023.2.20f1-Player on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/6000.0.37f1_build.yml b/.github/workflows/6000.0.37f1_build.yml index 201f329..59f9d12 100644 --- a/.github/workflows/6000.0.37f1_build.yml +++ b/.github/workflows/6000.0.37f1_build.yml @@ -3,10 +3,10 @@ name: 6000.0.37f1-Build on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: diff --git a/.github/workflows/6000.0.37f1_editor.yml b/.github/workflows/6000.0.37f1_editor.yml index b1f06c3..11994ab 100644 --- a/.github/workflows/6000.0.37f1_editor.yml +++ b/.github/workflows/6000.0.37f1_editor.yml @@ -3,10 +3,10 @@ name: 6000.0.37f1-Editor on: pull_request: branches: - - master + - main push: branches: - - master + - main jobs: editor-tests: diff --git a/.github/workflows/6000.0.37f1_player.yml b/.github/workflows/6000.0.37f1_player.yml index 9dd1e64..3e20ef7 100644 --- a/.github/workflows/6000.0.37f1_player.yml +++ b/.github/workflows/6000.0.37f1_player.yml @@ -3,10 +3,10 @@ name: 6000.0.37f1-Player on: pull_request: branches: - - master_disabled + - main_disabled push: branches: - - master_disabled + - main_disabled jobs: editor-tests: From 40084cf7cc51fa51cae16eef483a10c7dcd7ba52 Mon Sep 17 00:00:00 2001 From: Ivan Murzak Date: Sat, 8 Mar 2025 11:34:58 -0800 Subject: [PATCH 33/33] Update image URLs in TestUtils to use 'main' branch --- Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs index 5d048bf..7ffd901 100644 --- a/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs +++ b/Assets/_PackageRoot/Tests/Base/Utils/TestUtils.cs @@ -12,9 +12,9 @@ public static partial class TestUtils { public static readonly string[] ImageURLs = { - "https://github.com/IvanMurzak/Unity-ImageLoader/raw/master/Test%20Images/ImageA.jpg", - "https://github.com/IvanMurzak/Unity-ImageLoader/raw/master/Test%20Images/ImageB.png", - "https://github.com/IvanMurzak/Unity-ImageLoader/raw/master/Test%20Images/ImageC.png" + "https://github.com/IvanMurzak/Unity-ImageLoader/raw/main/Test%20Images/ImageA.jpg", + "https://github.com/IvanMurzak/Unity-ImageLoader/raw/main/Test%20Images/ImageB.png", + "https://github.com/IvanMurzak/Unity-ImageLoader/raw/main/Test%20Images/ImageC.png" }; public static string IncorrectImageURL => $"https://doesntexist.com/{Guid.NewGuid()}.png"; public static IEnumerable IncorrectImageURLs(int count = 3) => Enumerable.Range(0, count).Select(_ => IncorrectImageURL);