#nullable enable using System; using System.Collections.Generic; using Cysharp.Threading.Tasks; using NUnit.Framework; using ShrinkApp; using UnityEngine; using Object = UnityEngine.Object; namespace ShrinkContext.AppAdapter.Tests { public class CompositionProfileTests { [Test] public void JsonRoundTrip_PreservesEntryIsolationAndInterceptMetadata() { var document = new ShrinkAppCompositionDocument(false, new[] { new ShrinkAppCompositionEntry( "app.a", enabled: false, isolate: new[] { new ShrinkAppCompositionIsolate("service", "community") }, intercept: new[] { new ShrinkAppCompositionIntercept("service", new[] { new ShrinkAppCompositionMetadata("access", "read-only") }) }) }); var restored = ShrinkAppCompositionDocument.FromJson(document.ToJson()); Assert.IsFalse(restored.includeUnlistedEntries); Assert.AreEqual(1, restored.entries.Count); Assert.IsFalse(restored.entries[0].enabled); Assert.AreEqual("community", restored.entries[0].isolate[0].realm); Assert.AreEqual("read-only", restored.entries[0].intercept[0].metadata[0].value); } [Test] public void ApplyComposition_RestrictsEntriesAndKeepsSettingsDisabledModules() { var settings = ScriptableObject.CreateInstance(); settings.disabledModuleIds = new[] { "app.a" }; var host = new ShrinkAppLoaderHost(settings, new IShrinkAppModuleInstaller[] { new ProfileInstaller("app.a"), new ProfileInstaller("app.b") }); try { host.ApplyComposition(new ShrinkAppCompositionDocument(false, new[] { new ShrinkAppCompositionEntry("app.a", enabled: true) })); TestAwait.Run(host.StartAsync()); Assert.IsTrue(host.IsModuleDisabled("app.a"), "profile enabled 不应覆盖 ShrinkAppSettings 的显式禁用"); Assert.IsTrue(host.IsModuleDisabled("app.b"), "未列出的条目应被显式组合排除"); Assert.IsFalse(host.TryGetModuleFiber("app.a", out _)); Assert.IsFalse(host.TryGetModuleFiber("app.b", out _)); Assert.Throws(() => TestAwait.Run(host.SetModuleDisabledAsync("app.b", false))); } finally { if (host.IsRunning) TestAwait.Run(host.ShutdownAsync()); Object.DestroyImmediate(settings); } } [Test] public void ApplyComposition_RejectsUnknownFactoryBeforeStarting() { var settings = ScriptableObject.CreateInstance(); try { var host = new ShrinkAppLoaderHost(settings, new[] { new ProfileInstaller("app.a") }); var error = Assert.Throws(() => host.ApplyComposition( new ShrinkAppCompositionDocument(false, new[] { new ShrinkAppCompositionEntry("app.unknown") }))); StringAssert.Contains("no registered module/component factory", error!.Message); } finally { Object.DestroyImmediate(settings); } } private sealed class ProfileInstaller : IShrinkAppModuleInstaller { public ProfileInstaller(string moduleId) { ModuleId = moduleId; } public string ModuleId { get; } public int Order => 0; public IReadOnlyList DependsOn => Array.Empty(); public void RegisterServices(ShrinkAppContext context) { } public UniTask InitializeAsync(ShrinkAppContext context) => UniTask.CompletedTask; } } }