mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-22 00:54:26 +08:00
feat.融合桌面组件展示优化
This commit is contained in:
216
LanMountainDesktop.Tests/FusedDesktopLibraryMetadataTests.cs
Normal file
216
LanMountainDesktop.Tests/FusedDesktopLibraryMetadataTests.cs
Normal file
@@ -0,0 +1,216 @@
|
||||
using System.Text.Json;
|
||||
using Avalonia.Controls;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.ComponentSystem.Extensions;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Views.Components;
|
||||
using Xunit;
|
||||
|
||||
namespace LanMountainDesktop.Tests;
|
||||
|
||||
public sealed class FusedDesktopLibraryMetadataTests : IDisposable
|
||||
{
|
||||
private readonly string _tempRoot = Path.Combine(
|
||||
Path.GetTempPath(),
|
||||
"LanMountainDesktop.Tests",
|
||||
nameof(FusedDesktopLibraryMetadataTests),
|
||||
Guid.NewGuid().ToString("N"));
|
||||
|
||||
[Fact]
|
||||
public void PluginDesktopComponentDescriptionMetadata_ReachesRuntimeDescriptor()
|
||||
{
|
||||
const string componentId = "plugin.metadata.widget";
|
||||
var registration = new PluginDesktopComponentRegistration(
|
||||
_ => new Border(),
|
||||
new PluginDesktopComponentOptions
|
||||
{
|
||||
ComponentId = componentId,
|
||||
DisplayName = "Metadata Widget",
|
||||
IconKey = "Apps",
|
||||
Category = "Plugins",
|
||||
Description = "Plugin supplied description.",
|
||||
DescriptionLocalizationKey = "plugin.metadata.description"
|
||||
});
|
||||
|
||||
Assert.Equal("Plugin supplied description.", registration.Description);
|
||||
Assert.Equal("plugin.metadata.description", registration.DescriptionLocalizationKey);
|
||||
|
||||
var registry = ComponentRegistry.CreateDefault().RegisterComponents(
|
||||
[
|
||||
new DesktopComponentDefinition(
|
||||
registration.ComponentId,
|
||||
registration.DisplayName,
|
||||
registration.IconKey,
|
||||
registration.Category,
|
||||
registration.MinWidthCells,
|
||||
registration.MinHeightCells,
|
||||
registration.AllowStatusBarPlacement,
|
||||
registration.AllowDesktopPlacement,
|
||||
Description: registration.Description,
|
||||
DescriptionLocalizationKey: registration.DescriptionLocalizationKey)
|
||||
]);
|
||||
var runtimeRegistry = new DesktopComponentRuntimeRegistry(
|
||||
registry,
|
||||
[
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
componentId,
|
||||
displayNameLocalizationKey: registration.DisplayNameLocalizationKey,
|
||||
_ => new Border(),
|
||||
cornerRadiusResolver: (Func<double, double>?)null)
|
||||
]);
|
||||
|
||||
Assert.True(runtimeRegistry.TryGetDescriptor(componentId, out var descriptor));
|
||||
Assert.Equal("Plugin supplied description.", descriptor.Description);
|
||||
Assert.Equal("plugin.metadata.description", descriptor.DescriptionLocalizationKey);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void JsonComponentExtensionProvider_LoadsOptionalDescriptionMetadata()
|
||||
{
|
||||
var extensionDirectory = Path.Combine(_tempRoot, "extensions");
|
||||
Directory.CreateDirectory(extensionDirectory);
|
||||
File.WriteAllText(
|
||||
Path.Combine(extensionDirectory, "components.json"),
|
||||
"""
|
||||
[
|
||||
{
|
||||
"id": "json.description.widget",
|
||||
"displayName": "JSON Description Widget",
|
||||
"iconKey": "Apps",
|
||||
"category": "Extensions",
|
||||
"description": "Description from JSON.",
|
||||
"descriptionLocalizationKey": "json.description.widget.description"
|
||||
},
|
||||
{
|
||||
"id": "json.default.widget",
|
||||
"displayName": "JSON Default Widget",
|
||||
"description": " ",
|
||||
"descriptionLocalizationKey": " "
|
||||
}
|
||||
]
|
||||
""");
|
||||
|
||||
var definitions = JsonComponentExtensionProvider
|
||||
.LoadProvidersFromDirectory(extensionDirectory)
|
||||
.SelectMany(provider => provider.GetComponents())
|
||||
.ToDictionary(definition => definition.Id, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var described = definitions["json.description.widget"];
|
||||
Assert.Equal("Description from JSON.", described.Description);
|
||||
Assert.Equal("json.description.widget.description", described.DescriptionLocalizationKey);
|
||||
|
||||
var defaults = definitions["json.default.widget"];
|
||||
Assert.Null(defaults.Description);
|
||||
Assert.Null(defaults.DescriptionLocalizationKey);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FusedDesktopLibraryLocalizationFiles_ContainRequiredKeys()
|
||||
{
|
||||
var requiredKeys = new[]
|
||||
{
|
||||
"fused_desktop.library.title",
|
||||
"fused_desktop.library.add_button",
|
||||
"fused_desktop.library.find_more",
|
||||
"fused_desktop.library.empty_selection",
|
||||
"fused_desktop.library.component_summary_format"
|
||||
};
|
||||
|
||||
foreach (var language in new[] { "zh-CN", "en-US", "ja-JP", "ko-KR" })
|
||||
{
|
||||
var json = ReadRepositoryFile("LanMountainDesktop", "Localization", $"{language}.json");
|
||||
var table = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
|
||||
Assert.NotNull(table);
|
||||
foreach (var key in requiredKeys)
|
||||
{
|
||||
Assert.True(table!.ContainsKey(key), $"{language} is missing {key}.");
|
||||
Assert.False(string.IsNullOrWhiteSpace(table[key]), $"{language} has an empty {key}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FusedDesktopLibraryLifecycle_KeepsAddOpenAndUsesEditModeBoundary()
|
||||
{
|
||||
var appSource = ReadRepositoryFile("LanMountainDesktop", "App.axaml.cs");
|
||||
var openSource = ExtractMethodSource(appSource, "OpenFusedDesktopComponentLibraryFromUi");
|
||||
var closedSource = ExtractMethodSource(appSource, "OnFusedComponentLibraryWindowClosed");
|
||||
var librarySource = ReadRepositoryFile("LanMountainDesktop", "Views", "FusedDesktopComponentLibraryWindow.axaml.cs");
|
||||
var addSource = ExtractMethodSource(librarySource, "OnAddComponentRequested");
|
||||
|
||||
Assert.Contains("EnterEditMode()", openSource);
|
||||
Assert.Contains("ExitEditMode()", closedSource);
|
||||
Assert.Contains("AddComponent(componentId, this)", addSource);
|
||||
Assert.DoesNotContain("Close()", addSource);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(_tempRoot))
|
||||
{
|
||||
Directory.Delete(_tempRoot, recursive: true);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private static string ReadRepositoryFile(params string[] segments)
|
||||
{
|
||||
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (directory is not null)
|
||||
{
|
||||
var candidate = Path.Combine(new[] { directory.FullName }.Concat(segments).ToArray());
|
||||
if (File.Exists(candidate))
|
||||
{
|
||||
return File.ReadAllText(candidate);
|
||||
}
|
||||
|
||||
if (File.Exists(Path.Combine(directory.FullName, "LanMountainDesktop.slnx")))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
||||
throw new FileNotFoundException($"Could not locate repository file '{Path.Combine(segments)}'.");
|
||||
}
|
||||
|
||||
private static string ExtractMethodSource(string source, string methodName)
|
||||
{
|
||||
var methodIndex = source.IndexOf($"private void {methodName}(", StringComparison.Ordinal);
|
||||
if (methodIndex < 0)
|
||||
{
|
||||
methodIndex = source.IndexOf($"private bool {methodName}(", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
Assert.True(methodIndex >= 0, $"Could not locate method '{methodName}'.");
|
||||
|
||||
var braceIndex = source.IndexOf('{', methodIndex);
|
||||
Assert.True(braceIndex >= 0, $"Could not locate method body for '{methodName}'.");
|
||||
|
||||
var depth = 0;
|
||||
for (var i = braceIndex; i < source.Length; i++)
|
||||
{
|
||||
if (source[i] == '{')
|
||||
{
|
||||
depth++;
|
||||
}
|
||||
else if (source[i] == '}')
|
||||
{
|
||||
depth--;
|
||||
if (depth == 0)
|
||||
{
|
||||
return source.Substring(methodIndex, i - methodIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Could not extract method '{methodName}'.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user