using System.IO; using GFramework.Core.SourceGenerators.Rule; using GFramework.SourceGenerators.Tests.Core; namespace GFramework.SourceGenerators.Tests.Rule; /// /// 上下文感知生成器快照测试类 /// 用于测试ContextAwareGenerator源代码生成器的输出快照 /// [TestFixture] public class ContextAwareGeneratorSnapshotTests { /// /// 测试ContextAwareGenerator源代码生成器的快照功能 /// 验证生成器对带有ContextAware特性的类的处理结果 /// /// 异步任务,无返回值 [Test] public async Task Snapshot_ContextAwareGenerator() { // 定义测试用的源代码,包含ContextAware特性和相关接口定义 const string source = """ using System; namespace GFramework.Core.SourceGenerators.Abstractions.Rule { [AttributeUsage(AttributeTargets.Class)] public sealed class ContextAwareAttribute : Attribute { } } namespace GFramework.Core.Abstractions.Rule { public interface IContextAware { void SetContext( GFramework.Core.Abstractions.Architectures.IArchitectureContext context); GFramework.Core.Abstractions.Architectures.IArchitectureContext GetContext(); } } namespace GFramework.Core.Abstractions.Architectures { public interface IArchitectureContext { } public interface IArchitectureContextProvider { IArchitectureContext GetContext(); bool TryGetContext(out T? context) where T : class, IArchitectureContext; } } namespace GFramework.Core.Architectures { using GFramework.Core.Abstractions.Architectures; public sealed class GameContextProvider : IArchitectureContextProvider { public IArchitectureContext GetContext() => null; public bool TryGetContext(out T? context) where T : class, IArchitectureContext { context = null; return false; } } public static class GameContext { public static IArchitectureContext GetFirstArchitectureContext() => null; } } namespace TestApp { using GFramework.Core.SourceGenerators.Abstractions.Rule; using GFramework.Core.Abstractions.Rule; [ContextAware] public partial class MyRule : IContextAware { } } """; // 执行生成器快照测试,将生成的代码与预期快照进行比较 await GeneratorSnapshotTest.RunAsync( source, GetSnapshotFolder()); } /// /// 验证生成器在用户 partial 类型已经声明常见上下文字段名时仍能生成可编译代码。 /// /// 异步任务,无返回值。 [Test] public async Task Snapshot_ContextAwareGenerator_With_User_Field_Name_Collisions() { const string source = """ using System; namespace GFramework.Core.SourceGenerators.Abstractions.Rule { [AttributeUsage(AttributeTargets.Class)] public sealed class ContextAwareAttribute : Attribute { } } namespace GFramework.Core.Abstractions.Rule { public interface IContextAware { void SetContext( GFramework.Core.Abstractions.Architectures.IArchitectureContext context); GFramework.Core.Abstractions.Architectures.IArchitectureContext GetContext(); } } namespace GFramework.Core.Abstractions.Architectures { public interface IArchitectureContext { } public interface IArchitectureContextProvider { IArchitectureContext GetContext(); bool TryGetContext(out T? context) where T : class, IArchitectureContext; } } namespace GFramework.Core.Architectures { using GFramework.Core.Abstractions.Architectures; public sealed class GameContextProvider : IArchitectureContextProvider { public IArchitectureContext GetContext() => null; public bool TryGetContext(out T? context) where T : class, IArchitectureContext { context = null; return false; } } } namespace TestApp { using GFramework.Core.SourceGenerators.Abstractions.Rule; using GFramework.Core.Abstractions.Rule; using GFramework.Core.Abstractions.Architectures; [ContextAware] public partial class CollisionProneRule : IContextAware { private readonly string _context = "user-field"; private static readonly string _contextProvider = "user-provider"; private static readonly object _contextSync = new(); } } """; await GeneratorSnapshotTest.RunAsync( source, GetSnapshotFolder()); } /// /// 将运行时测试目录映射回仓库内已提交的上下文感知生成器快照目录。 /// /// 快照目录的绝对路径。 private static string GetSnapshotFolder() { return Path.GetFullPath( Path.Combine( TestContext.CurrentContext.TestDirectory, "..", "..", "..", "Rule", "snapshots", "ContextAwareGenerator")); } }