// Copyright (c) 2025-2026 GeWuYou // SPDX-License-Identifier: Apache-2.0 using System.IO; using Microsoft.CodeAnalysis; namespace GFramework.SourceGenerators.Tests.Config; /// /// 验证 schema 配置生成器对对象 / 数组 enum 文档输出的快照行为。 /// [TestFixture] public class SchemaConfigGeneratorEnumTests { /// /// 验证对象 enum 文档输出与快照保持一致。 /// [Test] public Task Snapshot_Should_Preserve_Object_Enum_Documentation() { const string source = """ namespace TestApp { public sealed class Dummy { } } """; const string schema = """ { "type": "object", "required": ["id", "reward"], "properties": { "id": { "type": "integer" }, "reward": { "type": "object", "required": ["gold", "itemId"], "properties": { "gold": { "type": "integer" }, "itemId": { "type": "string" } }, "enum": [ { "gold": 10, "itemId": "potion" }, { "gold": 50, "itemId": "gem" } ] } } } """; var result = SchemaGeneratorTestDriver.Run( source, ("monster.schema.json", schema)); Assert.That(result.Results.Single().Diagnostics, Is.Empty); return AssertSnapshotAsync(result, "MonsterConfig.ObjectEnum.g.txt"); } /// /// 验证数组项 enum 文档回退输出与快照保持一致。 /// [Test] public Task Snapshot_Should_Preserve_Array_Item_Enum_Documentation_Fallback() { const string source = """ namespace TestApp { public sealed class Dummy { } } """; const string schema = """ { "type": "object", "required": ["id", "dropItemIds"], "properties": { "id": { "type": "integer" }, "dropItemIds": { "type": "array", "items": { "type": "string", "enum": ["fire", "ice", "earth"] } } } } """; var result = SchemaGeneratorTestDriver.Run( source, ("monster.schema.json", schema)); Assert.That(result.Results.Single().Diagnostics, Is.Empty); return AssertSnapshotAsync(result, "MonsterConfig.ArrayItemEnum.g.txt"); } /// /// 验证对象数组项 enum 文档回退输出与快照保持一致。 /// [Test] public Task Snapshot_Should_Preserve_Array_Object_Item_Enum_Documentation_Fallback() { const string source = """ namespace TestApp { public sealed class Dummy { } } """; const string schema = """ { "type": "object", "required": ["id", "phases"], "properties": { "id": { "type": "integer" }, "phases": { "type": "array", "items": { "type": "object", "required": ["wave", "monsterId"], "properties": { "wave": { "type": "integer" }, "monsterId": { "type": "string" } }, "enum": [ { "wave": 1, "monsterId": "slime" }, { "wave": 2, "monsterId": "goblin" } ] } } } } """; var result = SchemaGeneratorTestDriver.Run( source, ("monster.schema.json", schema)); Assert.That(result.Results.Single().Diagnostics, Is.Empty); return AssertSnapshotAsync(result, "MonsterConfig.ArrayObjectItemEnum.g.txt"); } /// /// 对单个生成文件执行快照断言。 /// /// 生成器运行结果。 /// 快照文件名。 private static async Task AssertSnapshotAsync( GeneratorDriverRunResult result, string snapshotFileName) { var generatedSources = result.Results .Single() .GeneratedSources .ToDictionary( static sourceResult => sourceResult.HintName, static sourceResult => sourceResult.SourceText.ToString(), StringComparer.Ordinal); if (!generatedSources.TryGetValue("MonsterConfig.g.cs", out var actual)) { Assert.Fail("Generated source 'MonsterConfig.g.cs' was not found."); return; } var snapshotFolder = Path.Combine( TestContext.CurrentContext.TestDirectory, "..", "..", "..", "Config", "snapshots", "SchemaConfigGeneratorEnum"); snapshotFolder = Path.GetFullPath(snapshotFolder); var path = Path.Combine(snapshotFolder, snapshotFileName); if (!File.Exists(path)) { Directory.CreateDirectory(snapshotFolder); await File.WriteAllTextAsync(path, actual).ConfigureAwait(false); Assert.Fail($"Snapshot not found. Generated new snapshot at:\n{path}"); } var expected = await File.ReadAllTextAsync(path).ConfigureAwait(false); Assert.That( Normalize(expected), Is.EqualTo(Normalize(actual)), $"Snapshot mismatch: MonsterConfig.g.cs ({snapshotFileName})"); } /// /// 标准化快照文本以避免平台换行差异。 /// /// 原始文本。 /// 标准化后的文本。 private static string Normalize(string text) { return text.Replace("\r\n", "\n", StringComparison.Ordinal).Trim(); } }