using LanMountainDesktop.Services.AirAppMarket; using Xunit; namespace LanMountainDesktop.Tests; public sealed class AirAppMarketIndexDocumentTests { [Fact] public void Load_WithFlatV3Entry_MapsDisplayFieldsAndWorkspacePath() { var document = AirAppMarketIndexDocument.Load(CreateFlatIndexJson(), "test-index.json"); var plugin = Assert.Single(document.AirApps); var source = Assert.Single(plugin.PackageSources); Assert.Equal("LanMountainDesktop.SampleAirApp", plugin.Id); Assert.Equal("LanMountain Sample AirApp", plugin.Name); Assert.Equal("SDK v5 sample plugin.", plugin.Description); Assert.Equal("LanMountainDesktop", plugin.Author); Assert.Equal("0.4.0", plugin.Version); Assert.Equal("5.0.0", plugin.ApiVersion); Assert.Equal("0.0.1", plugin.MinHostVersion); Assert.Equal("https://raw.githubusercontent.com/wwiinnddyy/LanAirApp/main/airappmarket/assets/sample-plugin.svg", plugin.IconUrl); Assert.Equal("https://raw.githubusercontent.com/wwiinnddyy/LanMountainDesktop.SampleAirApp/main/README.md", plugin.ReadmeUrl); Assert.Equal("workspace://LanMountainDesktop.SampleAirApp/LanMountainDesktop.SampleAirApp.0.4.0.laapp", source.Url); Assert.Equal(AirAppPackageSourceKind.WorkspaceLocal, source.SourceKind); } [Fact] public void Load_WithLegacyNestedV2Entry_RejectsUnsupportedSchema() { var exception = Assert.Throws(() => AirAppMarketIndexDocument.Load(CreateNestedV2IndexJson(), "legacy-index.json")); Assert.Contains("schemaVersion '2.0.0'", exception.Message, StringComparison.Ordinal); Assert.Contains("only supports '3.0.0'", exception.Message, StringComparison.Ordinal); } private static string CreateFlatIndexJson(string repositoryName = "LanMountainDesktop.SampleAirApp") { return $$""" { "schemaVersion": "3.0.0", "sourceId": "official", "sourceName": "LanAirApp", "generatedAt": "2026-04-29T00:00:00Z", "contracts": [], "plugins": [ { "pluginId": "LanMountainDesktop.SampleAirApp", "name": "LanMountain Sample AirApp", "description": "SDK v5 sample plugin.", "author": "LanMountainDesktop", "version": "0.4.0", "apiVersion": "5.0.0", "minHostVersion": "0.0.1", "entranceAssembly": "LanMountainDesktop.SampleAirApp.dll", "iconUrl": "https://raw.githubusercontent.com/wwiinnddyy/LanAirApp/main/airappmarket/assets/sample-plugin.svg", "readmeUrl": "https://raw.githubusercontent.com/wwiinnddyy/{{repositoryName}}/main/README.md", "projectUrl": "https://github.com/wwiinnddyy/{{repositoryName}}", "homepageUrl": "https://github.com/wwiinnddyy/{{repositoryName}}", "repositoryUrl": "https://github.com/wwiinnddyy/{{repositoryName}}", "releaseTag": "v0.4.0", "releaseAssetName": "LanMountainDesktop.SampleAirApp.0.4.0.laapp", "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "packageSizeBytes": 1024, "publishedAt": "2026-04-29T00:00:00Z", "updatedAt": "2026-04-29T00:00:00Z", "releaseNotes": "Reference plugin for SDK v5 validation.", "tags": [ "official", "sdk" ], "sharedContracts": [], "desktopComponents": [ "LanMountainDesktop.SampleAirApp.StatusClock" ], "settingsSections": [ "status" ], "exports": [], "messageTypes": [], "packageSources": [ { "kind": "workspaceLocal", "url": "workspace://LanMountainDesktop.SampleAirApp/LanMountainDesktop.SampleAirApp.0.4.0.laapp" } ] } ] } """; } private static string CreateNestedV2IndexJson(string repositoryName = "LanMountainDesktop.SampleAirApp") { return $$""" { "schemaVersion": "2.0.0", "sourceId": "official", "sourceName": "LanAirApp", "generatedAt": "2026-04-29T00:00:00Z", "contracts": [], "plugins": [ { "manifest": { "id": "LanMountainDesktop.SampleAirApp", "name": "LanMountain Sample AirApp", "description": "SDK v5 sample plugin.", "author": "LanMountainDesktop", "version": "0.4.0", "apiVersion": "5.0.0", "entranceAssembly": "LanMountainDesktop.SampleAirApp.dll", "sharedContracts": [] }, "compatibility": { "minHostVersion": "0.0.1", "apiVersion": "5.0.0" }, "repository": { "projectUrl": "https://github.com/wwiinnddyy/{{repositoryName}}", "readmeUrl": "https://raw.githubusercontent.com/wwiinnddyy/{{repositoryName}}/main/README.md", "homepageUrl": "https://github.com/wwiinnddyy/{{repositoryName}}", "repositoryUrl": "https://github.com/wwiinnddyy/{{repositoryName}}", "iconUrl": "https://raw.githubusercontent.com/wwiinnddyy/LanAirApp/main/airappmarket/assets/sample-plugin.svg", "tags": [ "official", "sdk" ], "releaseNotes": "Reference plugin for SDK v5 validation." }, "publication": { "releaseTag": "v0.4.0", "releaseAssetName": "LanMountainDesktop.SampleAirApp.0.4.0.laapp", "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "packageSizeBytes": 1024, "publishedAt": "2026-04-29T00:00:00Z", "updatedAt": "2026-04-29T00:00:00Z", "packageSources": [ { "kind": "workspaceLocal", "path": "workspace://LanMountainDesktop.SampleAirApp/LanMountainDesktop.SampleAirApp.0.4.0.laapp", "assetName": "LanMountainDesktop.SampleAirApp.0.4.0.laapp", "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sizeBytes": 1024, "releaseTag": "v0.4.0", "priority": 0 } ] }, "capabilities": { "desktopComponents": [ "LanMountainDesktop.SampleAirApp.StatusClock" ], "settingsSections": [ "status" ] } } ] } """; } }