Files
YMhut-box-C-/src/YMhut.Box.Tests/ToolCatalogTests.cs
T
QWQLwToo 7ecc6a8923
build-winui / winui (push) Has been cancelled
Add WinUI and core source
2026-06-26 13:27:13 +08:00

299 lines
14 KiB
C#

using Microsoft.VisualStudio.TestTools.UnitTesting;
using YMhut.Box.Core.Tools;
namespace YMhut.Box.Tests;
[TestClass]
public sealed class ToolCatalogTests
{
[TestMethod]
public void DefaultCatalogContainsRequiredNativePages()
{
var catalog = new ToolCatalog();
Assert.IsNotNull(catalog.GetById("safe_browser"));
Assert.IsNotNull(catalog.GetById("media_player"));
Assert.IsNotNull(catalog.GetById("text_splitter"));
Assert.IsNotNull(catalog.GetById("loan_emi_calculator"));
Assert.IsNotNull(catalog.GetById("number_base_converter"));
Assert.IsNotNull(catalog.GetById("ymhut_uutool_suite"));
Assert.IsNotNull(catalog.GetById("html_js_playground"));
Assert.IsNotNull(catalog.GetById("timezone_abbr_lookup"));
Assert.IsNotNull(catalog.GetById("percentage_change_calculator"));
Assert.IsNotNull(catalog.GetById("dev_environment_config"));
Assert.IsNull(catalog.GetById("mmd_model_studio"));
foreach (var id in new[]
{
"compression_codec",
"totp_generator",
"color_contrast_checker",
"url_redirect_trace",
"image_metadata_inspector",
"markdown_preview"
})
{
Assert.IsNotNull(catalog.GetById(id), id);
}
Assert.IsGreaterThanOrEqualTo(160, catalog.Modules.Count);
}
[TestMethod]
public void SearchFiltersByQueryAndCategory()
{
var catalog = new ToolCatalog();
var results = catalog.Search("browser", ToolCategory.Network).ToList();
Assert.HasCount(1, results);
Assert.AreEqual("safe_browser", results[0].Id);
}
[TestMethod]
public void ToolViewModelStartsWithInlinePreviewHidden()
{
var module = new ToolCatalog().GetById("json_formatter")!;
var viewModel = (ToolModuleViewModel)module.CreateViewModel();
Assert.IsFalse(viewModel.InlinePreviewLoaded);
}
[TestMethod]
public void EveryCatalogToolHasNativeWinUiPageSpec()
{
var catalog = new ToolCatalog();
var specs = ToolPageSpecCatalog.CreateFor(catalog);
Assert.HasCount(catalog.Modules.Count, specs);
foreach (var module in catalog.Modules)
{
Assert.IsTrue(specs.ContainsKey(module.Id), module.Id);
var spec = specs[module.Id];
Assert.AreEqual(module.Id, spec.ToolId);
Assert.IsTrue(Enum.IsDefined(spec.Layout), module.Id);
Assert.IsNotEmpty(spec.ParameterControls, module.Id);
Assert.IsTrue(Enum.IsDefined(spec.AssistPanelMode), module.Id);
Assert.IsTrue(Enum.IsDefined(spec.InteractionMode), module.Id);
Assert.IsTrue(Enum.IsDefined(spec.PageExperience), module.Id);
Assert.IsTrue(Enum.IsDefined(spec.PageDensity), module.Id);
Assert.IsTrue(Enum.IsDefined(spec.ResultPriority), module.Id);
Assert.IsFalse(string.IsNullOrWhiteSpace(spec.DefaultFocusTarget), module.Id);
if (spec.PageExperience != ToolPageExperienceKind.LivePreview)
{
Assert.IsFalse(string.IsNullOrWhiteSpace(spec.PrimaryActionLabel), module.Id);
}
if (spec.PrimaryInput != ToolPrimaryInputKind.None)
{
Assert.IsNotEmpty(spec.Parameters, module.Id);
}
Assert.IsFalse(string.IsNullOrWhiteSpace(spec.EmptyState), module.Id);
Assert.IsFalse(string.IsNullOrWhiteSpace(spec.ErrorHint), module.Id);
}
}
[TestMethod]
public void RepresentativeToolSpecsUseGalleryNativeControls()
{
var catalog = new ToolCatalog();
Assert.AreEqual(ToolPrimaryInputKind.MultilineText, ToolPageSpecCatalog.For(catalog.GetById("json_formatter")!).PrimaryInput);
Assert.AreEqual(ToolResultKind.JsonTree, ToolPageSpecCatalog.For(catalog.GetById("json_formatter")!).Result);
Assert.AreEqual(ToolPrimaryInputKind.FixedOptions, ToolPageSpecCatalog.For(catalog.GetById("system_tool")!).PrimaryInput);
Assert.AreEqual(ToolLayoutKind.SystemLauncher, ToolPageSpecCatalog.For(catalog.GetById("system_tool")!).Layout);
Assert.AreEqual(ToolPrimaryInputKind.None, ToolPageSpecCatalog.For(catalog.GetById("baidu_hot")!).PrimaryInput);
Assert.IsTrue(ToolPageSpecCatalog.For(catalog.GetById("archive_tool")!).RequiresFilePicker);
Assert.IsTrue(ToolPageSpecCatalog.For(catalog.GetById("image_metadata_inspector")!).RequiresFilePicker);
Assert.AreEqual(ToolLayoutKind.CodecWorkbench, ToolPageSpecCatalog.For(catalog.GetById("compression_codec")!).Layout);
Assert.AreEqual(ToolLayoutKind.SecurityWorkbench, ToolPageSpecCatalog.For(catalog.GetById("totp_generator")!).Layout);
Assert.AreEqual(ToolLayoutKind.TextWorkbench, ToolPageSpecCatalog.For(catalog.GetById("color_contrast_checker")!).Layout);
Assert.AreEqual(ToolLayoutKind.QueryDashboard, ToolPageSpecCatalog.For(catalog.GetById("url_redirect_trace")!).Layout);
Assert.AreEqual(ToolLayoutKind.FormatterWorkbench, ToolPageSpecCatalog.For(catalog.GetById("markdown_preview")!).Layout);
Assert.AreEqual(ToolLayoutKind.RandomCinema, ToolPageSpecCatalog.For(catalog.GetById("random_cinema")!).Layout);
Assert.AreEqual(ToolCategory.Image, catalog.GetById("random_cinema")!.Metadata.Category);
}
[TestMethod]
public void ModelStudioToolIsRemovedFromCatalogAndSpecs()
{
var catalog = new ToolCatalog();
Assert.IsNull(catalog.GetById("mmd_model_studio"));
Assert.IsFalse(ToolPageSpecCatalog.CreateFor(catalog).ContainsKey("mmd_model_studio"));
}
[TestMethod]
public void ToolAssistAndInteractionModesMatchRepresentativeExperience()
{
var catalog = new ToolCatalog();
Assert.AreEqual(ToolAssistPanelMode.Custom, ToolPageSpecCatalog.For(catalog.GetById("color_picker")!).AssistPanelMode);
Assert.AreEqual(ToolInteractionMode.LivePreview, ToolPageSpecCatalog.For(catalog.GetById("color_picker")!).InteractionMode);
Assert.AreEqual(ToolPageExperienceKind.LivePreview, ToolPageSpecCatalog.For(catalog.GetById("color_picker")!).PageExperience);
Assert.AreEqual(ToolAssistPanelMode.Hidden, ToolPageSpecCatalog.For(catalog.GetById("system_info")!).AssistPanelMode);
Assert.AreEqual(ToolAssistPanelMode.Hidden, ToolPageSpecCatalog.For(catalog.GetById("baidu_hot")!).AssistPanelMode);
Assert.AreEqual(ToolAssistPanelMode.RulesOnly, ToolPageSpecCatalog.For(catalog.GetById("json_formatter")!).AssistPanelMode);
Assert.AreEqual(ToolAssistPanelMode.RulesOnly, ToolPageSpecCatalog.For(catalog.GetById("base64_codec")!).AssistPanelMode);
Assert.AreEqual(ToolAssistPanelMode.SourceOnly, ToolPageSpecCatalog.For(catalog.GetById("weather")!).AssistPanelMode);
Assert.AreEqual(ToolInteractionMode.ReferenceBrowser, ToolPageSpecCatalog.For(catalog.GetById("mime_lookup")!).InteractionMode);
Assert.AreEqual(ToolPageExperienceKind.RemoteDashboard, ToolPageSpecCatalog.For(catalog.GetById("baidu_hot")!).PageExperience);
Assert.AreEqual(ToolPageExperienceKind.FormCalculator, ToolPageSpecCatalog.For(catalog.GetById("bmi_calculator")!).PageExperience);
Assert.AreEqual(ToolPageExperienceKind.FileWorkflow, ToolPageSpecCatalog.For(catalog.GetById("archive_tool")!).PageExperience);
}
[TestMethod]
public void RuleDrivenToolsHaveRuleSpecsAndSourceOnlyCopyIsSanitized()
{
var catalog = new ToolCatalog();
var specs = ToolPageSpecCatalog.CreateFor(catalog);
foreach (var spec in specs.Values.Where(spec => spec.AssistPanelMode == ToolAssistPanelMode.RulesOnly))
{
Assert.IsTrue(spec.Rules.Count > 0 || spec.RequiresFilePicker || spec.ParameterControls.Contains(ToolParameterControlKind.NumberBox), spec.ToolId);
}
foreach (var spec in specs.Values.Where(spec => spec.AssistPanelMode == ToolAssistPanelMode.SourceOnly))
{
var uiCopy = $"{spec.EmptyState} {spec.ErrorHint}";
Assert.IsFalse(uiCopy.Contains("http://", StringComparison.OrdinalIgnoreCase), spec.ToolId);
Assert.IsFalse(uiCopy.Contains("https://", StringComparison.OrdinalIgnoreCase), spec.ToolId);
Assert.IsFalse(uiCopy.Contains(".json", StringComparison.OrdinalIgnoreCase), spec.ToolId);
}
}
[TestMethod]
public void RuleAndParameterSpecsCarryBilingualText()
{
var catalog = new ToolCatalog();
var json = ToolPageSpecCatalog.For(catalog.GetById("json_formatter")!);
var port = ToolPageSpecCatalog.For(catalog.GetById("port_lookup")!);
Assert.AreEqual("模式", json.Rules[0].LocalizedLabel?.ForLanguage("zh-CN"));
Assert.AreEqual("Mode", json.Rules[0].LocalizedLabel?.ForLanguage("en-US"));
Assert.AreEqual("格式化", json.Rules[0].Options[0].LocalizedLabel?.ForLanguage("zh-CN"));
Assert.AreEqual("Format", json.Rules[0].Options[0].LocalizedLabel?.ForLanguage("en-US"));
Assert.AreEqual("来源", port.Rules[0].LocalizedLabel?.ForLanguage("zh-CN"));
Assert.AreEqual("Source", port.Rules[0].LocalizedLabel?.ForLanguage("en-US"));
Assert.AreEqual("预设", port.Parameters[0].LocalizedLabel?.ForLanguage("zh-CN"));
Assert.AreEqual("Preset", port.Parameters[0].LocalizedLabel?.ForLanguage("en-US"));
}
[TestMethod]
public void PageExperienceRulesKeepToolPagesCompact()
{
var catalog = new ToolCatalog();
var color = ToolPageSpecCatalog.For(catalog.GetById("color_picker")!);
Assert.AreEqual(ToolPageExperienceKind.LivePreview, color.PageExperience);
Assert.AreEqual(string.Empty, color.PrimaryActionLabel);
var hot = ToolPageSpecCatalog.For(catalog.GetById("hotboard")!);
Assert.AreEqual(ToolPageExperienceKind.RemoteDashboard, hot.PageExperience);
Assert.IsFalse(hot.AutoRunOnOpen);
Assert.AreEqual("查询", hot.PrimaryActionLabel);
Assert.IsTrue(hot.ShowInputHeader);
var bmi = ToolPageSpecCatalog.For(catalog.GetById("bmi_calculator")!);
Assert.AreEqual(ToolPageExperienceKind.FormCalculator, bmi.PageExperience);
Assert.AreEqual("计算", bmi.PrimaryActionLabel);
Assert.AreNotEqual(ToolPrimaryInputKind.MultilineText, bmi.PrimaryInput);
var json = ToolPageSpecCatalog.For(catalog.GetById("json_formatter")!);
Assert.AreEqual(ToolPageExperienceKind.OneShotTransform, json.PageExperience);
Assert.AreEqual("格式化", json.PrimaryActionLabel);
}
[TestMethod]
public void CalculatorToolSpecsUseNativeFormInputsByArity()
{
var catalog = new ToolCatalog();
Assert.AreEqual(ToolPrimaryInputKind.NumberPair, ToolPageSpecCatalog.For(catalog.GetById("bmi_calculator")!).PrimaryInput);
Assert.AreEqual(ToolPrimaryInputKind.NumberTriple, ToolPageSpecCatalog.For(catalog.GetById("loan_emi_calculator")!).PrimaryInput);
Assert.AreEqual(ToolPrimaryInputKind.NumberQuad, ToolPageSpecCatalog.For(catalog.GetById("compound_interest_calculator")!).PrimaryInput);
Assert.AreEqual(ToolPrimaryInputKind.DateRange, ToolPageSpecCatalog.For(catalog.GetById("shelf_life")!).PrimaryInput);
Assert.IsTrue(ToolPageSpecCatalog.For(catalog.GetById("shelf_life")!).UsesNumberBox);
}
[TestMethod]
public void SpecsCoverEveryStructuredResultKind()
{
var catalog = new ToolCatalog();
var resultKinds = catalog.Modules
.Select(module => ToolPageSpecCatalog.For(module).Result)
.Distinct()
.ToHashSet();
foreach (ToolResultKind kind in Enum.GetValues<ToolResultKind>())
{
Assert.Contains(kind, resultKinds, kind.ToString());
}
}
[TestMethod]
public async Task ToolExecutorReturnsStructuredDocuments()
{
var catalog = new ToolCatalog();
var samples = new Dictionary<string, string>
{
["json_formatter"] = "{\"name\":\"YMhut Box\"}",
["base64_codec"] = "YMhut Box",
["bmi_calculator"] = "70 1.75",
["text_diff"] = "WinUI\n---\nWinUI 3",
["color_picker"] = "#3399ff"
};
foreach (var sample in samples)
{
var module = catalog.GetById(sample.Key)!;
var result = await ToolExecutor.ExecuteAsync(module, sample.Value);
Assert.IsTrue(result.Ok, sample.Key);
Assert.IsNotNull(result.Document, sample.Key);
Assert.AreEqual(module.Id, result.Document.ToolId);
Assert.IsNotEmpty(result.Document.Blocks, sample.Key);
Assert.AreEqual(result.Output, result.Document.RawText);
}
}
[TestMethod]
public void EveryResultKindBuildsStructuredDocumentBlocks()
{
var catalog = new ToolCatalog();
var samples = new Dictionary<string, string>
{
["ascii_art"] = "YMhut",
["xml_formatter"] = "<root><name>YMhut</name></root>",
["json_formatter"] = "{\"name\":\"YMhut\"}",
["base64_codec"] = "Encode:\nWU1odXQ=",
["regex_tool"] = "match | value\n1 | YMhut",
["hotboard"] = "1. YMhut 热点",
["cctv_news"] = "1. 新闻标题",
["qr_generator"] = "https://example.com/qr.png",
["smart_search"] = "Bing - https://www.bing.com/search?q=YMhut",
["archive_tool"] = "已创建归档:sample.zip",
["text_diff"] = "- old\n+ new",
["hash_manifest_verify"] = "OK hello",
["color_picker"] = "HEX: #336699\nRGB: 51, 102, 153",
["number_base"] = "DEC: 255\nHEX: 0xFF",
["system_tool"] = "OS: Windows\nProcessors: 8",
["random_cinema"] = "https://example.com/media.mp4",
["port_lookup"] = "数据源:YMhut Reference Data / IANA\n80 - HTTP: 网页服务"
};
foreach (ToolResultKind kind in Enum.GetValues<ToolResultKind>())
{
var module = catalog.Modules.FirstOrDefault(module => ToolPageSpecCatalog.For(module).Result == kind);
Assert.IsNotNull(module, kind.ToString());
var output = samples.TryGetValue(module.Id, out var sample) ? sample : "Key: Value\nItem: Result";
var document = ToolResultBuilder.FromOutput(module, output, "zh-CN");
Assert.AreEqual(module.Id, document.ToolId, kind.ToString());
Assert.AreEqual(kind, document.ResultKind, kind.ToString());
Assert.IsNotEmpty(document.Blocks, kind.ToString());
Assert.AreEqual("ok", document.Status, kind.ToString());
}
}
}