diff --git a/GFramework.SourceGenerators.Tests/Bases/PriorityGeneratorSnapshotTests.cs b/GFramework.SourceGenerators.Tests/Bases/PriorityGeneratorSnapshotTests.cs index 79da21bb..be019c6f 100644 --- a/GFramework.SourceGenerators.Tests/Bases/PriorityGeneratorSnapshotTests.cs +++ b/GFramework.SourceGenerators.Tests/Bases/PriorityGeneratorSnapshotTests.cs @@ -50,12 +50,7 @@ public class PriorityGeneratorSnapshotTests await GeneratorSnapshotTest.RunAsync( source, - Path.Combine( - TestContext.CurrentContext.TestDirectory, - "bases", - "snapshots", - "PriorityGenerator", - "BasicPriority")); + GetSnapshotFolder("BasicPriority")); } /// @@ -98,12 +93,7 @@ public class PriorityGeneratorSnapshotTests await GeneratorSnapshotTest.RunAsync( source, - Path.Combine( - TestContext.CurrentContext.TestDirectory, - "bases", - "snapshots", - "PriorityGenerator", - "NegativePriority")); + GetSnapshotFolder("NegativePriority")); } /// @@ -156,12 +146,7 @@ public class PriorityGeneratorSnapshotTests await GeneratorSnapshotTest.RunAsync( source, - Path.Combine( - TestContext.CurrentContext.TestDirectory, - "bases", - "snapshots", - "PriorityGenerator", - "PriorityGroup")); + GetSnapshotFolder("PriorityGroup")); } /// @@ -204,11 +189,25 @@ public class PriorityGeneratorSnapshotTests await GeneratorSnapshotTest.RunAsync( source, + GetSnapshotFolder("GenericClass")); + } + + /// + /// 将运行时测试目录映射回仓库内已提交的 Priority 生成器快照目录。 + /// + /// 快照场景名称。 + /// 场景对应的绝对快照目录。 + private static string GetSnapshotFolder(string scenarioName) + { + return Path.GetFullPath( Path.Combine( TestContext.CurrentContext.TestDirectory, - "bases", + "..", + "..", + "..", + "Bases", "snapshots", "PriorityGenerator", - "GenericClass")); + scenarioName)); } } diff --git a/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/BasicPriority/TestApp_MySystem.Priority.g.cs b/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/BasicPriority/TestApp_MySystem.Priority.g.cs new file mode 100644 index 00000000..2a6756fe --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/BasicPriority/TestApp_MySystem.Priority.g.cs @@ -0,0 +1,12 @@ +// +#nullable enable + +namespace TestApp; + +partial class MySystem : global::GFramework.Core.Abstractions.Bases.IPrioritized +{ + /// + /// 获取优先级值: 10 + /// + public int Priority => 10; +} \ No newline at end of file diff --git a/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/GenericClass/TestApp_GenericSystem_T_.Priority.g.cs b/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/GenericClass/TestApp_GenericSystem_T_.Priority.g.cs new file mode 100644 index 00000000..a0ce6997 --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/GenericClass/TestApp_GenericSystem_T_.Priority.g.cs @@ -0,0 +1,12 @@ +// +#nullable enable + +namespace TestApp; + +partial class GenericSystem : global::GFramework.Core.Abstractions.Bases.IPrioritized +{ + /// + /// 获取优先级值: 20 + /// + public int Priority => 20; +} \ No newline at end of file diff --git a/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/NegativePriority/TestApp_CriticalSystem.Priority.g.cs b/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/NegativePriority/TestApp_CriticalSystem.Priority.g.cs new file mode 100644 index 00000000..bd6b4af3 --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/NegativePriority/TestApp_CriticalSystem.Priority.g.cs @@ -0,0 +1,12 @@ +// +#nullable enable + +namespace TestApp; + +partial class CriticalSystem : global::GFramework.Core.Abstractions.Bases.IPrioritized +{ + /// + /// 获取优先级值: -100 + /// + public int Priority => -100; +} \ No newline at end of file diff --git a/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/PriorityGroup/TestApp_HighPrioritySystem.Priority.g.cs b/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/PriorityGroup/TestApp_HighPrioritySystem.Priority.g.cs new file mode 100644 index 00000000..737acd1a --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Bases/snapshots/PriorityGenerator/PriorityGroup/TestApp_HighPrioritySystem.Priority.g.cs @@ -0,0 +1,12 @@ +// +#nullable enable + +namespace TestApp; + +partial class HighPrioritySystem : global::GFramework.Core.Abstractions.Bases.IPrioritized +{ + /// + /// 获取优先级值: -50 + /// + public int Priority => -50; +} \ No newline at end of file diff --git a/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTest.cs b/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTest.cs index fcc0df3e..f464cb74 100644 --- a/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTest.cs +++ b/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTest.cs @@ -21,25 +21,45 @@ public static class GeneratorSnapshotTest string snapshotFolder, Func? snapshotFileNameSelector = null) { - var test = new CSharpSourceGeneratorTest - { - TestState = - { - Sources = { source } - }, - TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck, - DisabledDiagnostics = { "GF_Common_Trace_001" } - }; + var syntaxTree = CSharpSyntaxTree.ParseText(source); + var compilation = CSharpCompilation.Create( + $"{typeof(TGenerator).Name}SnapshotTests", + [syntaxTree], + MetadataReferenceTestBuilder.GetRuntimeMetadataReferences(), + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + GeneratorDriver driver = CSharpGeneratorDriver.Create( + generators: [CreateGenerator()], + parseOptions: (CSharpParseOptions)syntaxTree.Options); + driver = driver.RunGeneratorsAndUpdateCompilation( + compilation, + out var updatedCompilation, + out _); - await test.RunAsync(); + var compilationErrors = updatedCompilation.GetDiagnostics() + .Where(static diagnostic => diagnostic.Severity == DiagnosticSeverity.Error) + .ToArray(); + Assert.That( + compilationErrors, + Is.Empty, + () => + $"编译生成的代码时出现错误:{Environment.NewLine}{string.Join(Environment.NewLine, compilationErrors.Select(static diagnostic => diagnostic.ToString()))}"); - var generated = test.TestState.GeneratedSources; + var runResult = driver.GetRunResult(); + var generated = runResult.Results + .SelectMany(static result => result.GeneratedSources) + .OrderBy(static source => source.HintName, StringComparer.Ordinal) + .Select(static source => (filename: source.HintName, content: source.SourceText.ToString())) + .ToArray(); + Assert.That( + generated, + Is.Not.Empty, + $"Generator '{typeof(TGenerator).FullName}' did not produce any sources."); foreach (var (filename, content) in generated) { // 不同测试套件可能需要将生成文件映射到非 .cs 快照,以避免测试资产被当作可编译源码参与构建。 var snapshotFileName = snapshotFileNameSelector?.Invoke(filename) ?? filename; - var path = Path.Combine( + var path = ResolveSnapshotPath( snapshotFolder, snapshotFileName); @@ -71,4 +91,52 @@ public static class GeneratorSnapshotTest { return text.Replace("\r\n", "\n").Trim(); } + + /// + /// 创建可由 Roslyn 驱动直接执行的源生成器实例,并统一兼容经典与增量生成器。 + /// + /// 适配后的源生成器实例。 + /// 当测试类型既不是源生成器也不是增量生成器时抛出。 + private static ISourceGenerator CreateGenerator() + { + var generator = new TGenerator(); + return generator switch + { + ISourceGenerator sourceGenerator => sourceGenerator, + IIncrementalGenerator incrementalGenerator => incrementalGenerator.AsSourceGenerator(), + _ => throw new InvalidOperationException( + $"Generator type '{typeof(TGenerator).FullName}' must implement {nameof(ISourceGenerator)} or {nameof(IIncrementalGenerator)}.") + }; + } + + /// + /// 解析并验证快照路径,确保文件名映射不会逃逸出当前快照根目录。 + /// + /// 快照根目录。 + /// 映射后的快照文件名。 + /// 可安全访问的快照绝对路径。 + /// + /// 当映射结果为空白、为绝对路径,或通过相对路径越界到快照目录之外时抛出。 + /// + private static string ResolveSnapshotPath(string snapshotFolder, string snapshotFileName) + { + if (string.IsNullOrWhiteSpace(snapshotFileName) || Path.IsPathRooted(snapshotFileName)) + { + throw new InvalidOperationException($"Invalid snapshot file name: {snapshotFileName}"); + } + + // 先规范化根目录再做包含关系判断,避免 `..` 或平台大小写差异导致的目录逃逸。 + var snapshotRoot = Path.TrimEndingDirectorySeparator(Path.GetFullPath(snapshotFolder)); + var snapshotPath = Path.GetFullPath(Path.Combine(snapshotRoot, snapshotFileName)); + var comparison = OperatingSystem.IsWindows() + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal; + + if (!snapshotPath.StartsWith(snapshotRoot + Path.DirectorySeparatorChar, comparison)) + { + throw new InvalidOperationException($"Snapshot path escapes root folder: {snapshotFileName}"); + } + + return snapshotPath; + } } diff --git a/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTestSecurityTests.cs b/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTestSecurityTests.cs new file mode 100644 index 00000000..b52fa027 --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTestSecurityTests.cs @@ -0,0 +1,91 @@ +using System.IO; +using GFramework.Core.SourceGenerators.Enums; + +namespace GFramework.SourceGenerators.Tests.Core; + +/// +/// 验证快照测试辅助器对快照文件路径映射的安全约束。 +/// +[TestFixture] +public class GeneratorSnapshotTestSecurityTests +{ + private const string EnumAttributeNamespace = "GFramework.Core.SourceGenerators.Abstractions.Enums"; + + /// + /// 验证快照文件名映射返回绝对路径时,会在访问文件系统前被拒绝。 + /// + [Test] + public void RunAsync_SnapshotFileNameSelectorReturnsAbsolutePath_ThrowsInvalidOperationException() + { + var snapshotRoot = CreateSnapshotRoot(); + var source = BuildSource(); + + Assert.ThrowsAsync(async () => + await GeneratorSnapshotTest.RunAsync( + source, + snapshotRoot, + _ => Path.Combine(snapshotRoot, "Status.EnumExtensions.g.cs"))); + } + + /// + /// 验证快照文件名映射尝试通过父级目录片段逃逸根目录时,会在访问文件系统前被拒绝。 + /// + [Test] + public void RunAsync_SnapshotFileNameSelectorEscapesSnapshotRoot_ThrowsInvalidOperationException() + { + var snapshotRoot = CreateSnapshotRoot(); + var source = BuildSource(); + + Assert.ThrowsAsync(async () => + await GeneratorSnapshotTest.RunAsync( + source, + snapshotRoot, + _ => Path.Combine("..", "escaped", "Status.EnumExtensions.g.cs"))); + } + + /// + /// 为安全测试创建隔离的快照根目录路径,避免不同用例共享状态。 + /// + /// 当前用例专属的快照根目录绝对路径。 + private static string CreateSnapshotRoot() + { + return Path.Combine( + TestContext.CurrentContext.WorkDirectory, + "temp-snapshots", + TestContext.CurrentContext.Test.ID, + Guid.NewGuid().ToString("N")); + } + + /// + /// 构造可稳定触发枚举扩展生成器输出的最小测试源码。 + /// + /// 包含测试属性与目标枚举的完整源码。 + private static string BuildSource() + { + return $$""" + using System; + + namespace {{EnumAttributeNamespace}} + { + [AttributeUsage(AttributeTargets.Enum)] + public sealed class GenerateEnumExtensionsAttribute : Attribute + { + public bool GenerateIsMethods { get; set; } = true; + public bool GenerateIsInMethod { get; set; } = true; + } + } + + namespace TestApp + { + using {{EnumAttributeNamespace}}; + + [GenerateEnumExtensions] + public enum Status + { + Active, + Inactive + } + } + """; + } +} diff --git a/GFramework.SourceGenerators.Tests/Enums/EnumExtensionsGeneratorSnapshotTests.cs b/GFramework.SourceGenerators.Tests/Enums/EnumExtensionsGeneratorSnapshotTests.cs index 459f4640..f5fa2157 100644 --- a/GFramework.SourceGenerators.Tests/Enums/EnumExtensionsGeneratorSnapshotTests.cs +++ b/GFramework.SourceGenerators.Tests/Enums/EnumExtensionsGeneratorSnapshotTests.cs @@ -34,6 +34,26 @@ public class EnumExtensionsGeneratorSnapshotTests GetSnapshotFileName); } + /// + /// 验证未提供快照文件名映射时,会直接按生成文件名进行快照比对。 + /// + [Test] + public async Task Snapshot_BasicEnum_IsMethods_DefaultSnapshotFileNameSelector() + { + var source = BuildSource( + """ + public enum Status + { + Active, + Inactive + } + """); + + await GeneratorSnapshotTest.RunAsync( + source, + GetSnapshotFolder("BasicEnum_IsMethods_DefaultSnapshotFileNameSelector")); + } + /// /// 验证默认配置在较小枚举上仍会生成集合判断方法。 /// diff --git a/GFramework.SourceGenerators.Tests/Enums/snapshots/EnumExtensionsGenerator/BasicEnum_IsMethods_DefaultSnapshotFileNameSelector/Status.EnumExtensions.g.cs b/GFramework.SourceGenerators.Tests/Enums/snapshots/EnumExtensionsGenerator/BasicEnum_IsMethods_DefaultSnapshotFileNameSelector/Status.EnumExtensions.g.cs new file mode 100644 index 00000000..2897d09c --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Enums/snapshots/EnumExtensionsGenerator/BasicEnum_IsMethods_DefaultSnapshotFileNameSelector/Status.EnumExtensions.g.cs @@ -0,0 +1,21 @@ +// +using System; +namespace TestApp +{ + public static partial class StatusExtensions + { + /// 是否为 Active + public static bool IsActive(this TestApp.Status value) => value == TestApp.Status.Active; + + /// 是否为 Inactive + public static bool IsInactive(this TestApp.Status value) => value == TestApp.Status.Inactive; + + /// 判断是否属于指定集合 + public static bool IsIn(this TestApp.Status value, params TestApp.Status[] values) + { + if (values == null) return false; + foreach (var v in values) if (value == v) return true; + return false; + } + } +} diff --git a/GFramework.SourceGenerators.Tests/Logging/LoggerGeneratorSnapshotTests.cs b/GFramework.SourceGenerators.Tests/Logging/LoggerGeneratorSnapshotTests.cs index 07bb60a2..83a11648 100644 --- a/GFramework.SourceGenerators.Tests/Logging/LoggerGeneratorSnapshotTests.cs +++ b/GFramework.SourceGenerators.Tests/Logging/LoggerGeneratorSnapshotTests.cs @@ -96,12 +96,7 @@ public class LoggerGeneratorSnapshotTests await GeneratorSnapshotTest.RunAsync( source, - Path.Combine( - TestContext.CurrentContext.TestDirectory, - "logging", - "snapshots", - "LoggerGenerator", - "DefaultConfiguration_Class")); + GetSnapshotFolder("DefaultConfiguration_Class")); } [Test] @@ -193,12 +188,7 @@ public class LoggerGeneratorSnapshotTests await GeneratorSnapshotTest.RunAsync( source, - Path.Combine( - TestContext.CurrentContext.TestDirectory, - "logging", - "snapshots", - "LoggerGenerator", - "CustomName_Class")); + GetSnapshotFolder("CustomName_Class")); } [Test] @@ -290,12 +280,7 @@ public class LoggerGeneratorSnapshotTests await GeneratorSnapshotTest.RunAsync( source, - Path.Combine( - TestContext.CurrentContext.TestDirectory, - "logging", - "snapshots", - "LoggerGenerator", - "CustomFieldName_Class")); + GetSnapshotFolder("CustomFieldName_Class")); } [Test] @@ -387,12 +372,7 @@ public class LoggerGeneratorSnapshotTests await GeneratorSnapshotTest.RunAsync( source, - Path.Combine( - TestContext.CurrentContext.TestDirectory, - "logging", - "snapshots", - "LoggerGenerator", - "InstanceField_Class")); + GetSnapshotFolder("InstanceField_Class")); } [Test] @@ -484,12 +464,7 @@ public class LoggerGeneratorSnapshotTests await GeneratorSnapshotTest.RunAsync( source, - Path.Combine( - TestContext.CurrentContext.TestDirectory, - "logging", - "snapshots", - "LoggerGenerator", - "PublicField_Class")); + GetSnapshotFolder("PublicField_Class")); } [Test] @@ -581,11 +556,25 @@ public class LoggerGeneratorSnapshotTests await GeneratorSnapshotTest.RunAsync( source, + GetSnapshotFolder("GenericClass")); + } + + /// + /// 将运行时测试目录映射回仓库内已提交的日志生成器快照目录。 + /// + /// 快照场景名称。 + /// 场景对应的绝对快照目录。 + private static string GetSnapshotFolder(string scenarioName) + { + return Path.GetFullPath( Path.Combine( TestContext.CurrentContext.TestDirectory, - "logging", + "..", + "..", + "..", + "Logging", "snapshots", "LoggerGenerator", - "GenericClass")); + scenarioName)); } } diff --git a/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/CustomFieldName_Class/MyService.Logger.g.cs b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/CustomFieldName_Class/MyService.Logger.g.cs new file mode 100644 index 00000000..bc4a50ae --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/CustomFieldName_Class/MyService.Logger.g.cs @@ -0,0 +1,11 @@ +// +using GFramework.Core.Abstractions.Logging; +using GFramework.Core.Logging; + +namespace TestApp; + +partial class MyService +{ + /// Auto-generated logger + private static readonly ILogger MyLogger = LoggerFactoryResolver.Provider.CreateLogger("MyService"); +} diff --git a/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/CustomName_Class/MyService.Logger.g.cs b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/CustomName_Class/MyService.Logger.g.cs new file mode 100644 index 00000000..02bcfad9 --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/CustomName_Class/MyService.Logger.g.cs @@ -0,0 +1,11 @@ +// +using GFramework.Core.Abstractions.Logging; +using GFramework.Core.Logging; + +namespace TestApp; + +partial class MyService +{ + /// Auto-generated logger + private static readonly ILogger _log = LoggerFactoryResolver.Provider.CreateLogger("MyService"); +} diff --git a/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/DefaultConfiguration_Class/MyService.Logger.g.cs b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/DefaultConfiguration_Class/MyService.Logger.g.cs new file mode 100644 index 00000000..02bcfad9 --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/DefaultConfiguration_Class/MyService.Logger.g.cs @@ -0,0 +1,11 @@ +// +using GFramework.Core.Abstractions.Logging; +using GFramework.Core.Logging; + +namespace TestApp; + +partial class MyService +{ + /// Auto-generated logger + private static readonly ILogger _log = LoggerFactoryResolver.Provider.CreateLogger("MyService"); +} diff --git a/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/GenericClass/MyService.Logger.g.cs b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/GenericClass/MyService.Logger.g.cs new file mode 100644 index 00000000..f06bd74d --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/GenericClass/MyService.Logger.g.cs @@ -0,0 +1,11 @@ +// +using GFramework.Core.Abstractions.Logging; +using GFramework.Core.Logging; + +namespace TestApp; + +partial class MyService +{ + /// Auto-generated logger + private static readonly ILogger _log = LoggerFactoryResolver.Provider.CreateLogger("MyService"); +} diff --git a/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/InstanceField_Class/MyService.Logger.g.cs b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/InstanceField_Class/MyService.Logger.g.cs new file mode 100644 index 00000000..05e566e4 --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/InstanceField_Class/MyService.Logger.g.cs @@ -0,0 +1,11 @@ +// +using GFramework.Core.Abstractions.Logging; +using GFramework.Core.Logging; + +namespace TestApp; + +partial class MyService +{ + /// Auto-generated logger + private readonly ILogger _log = LoggerFactoryResolver.Provider.CreateLogger("MyService"); +} diff --git a/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/PublicField_Class/MyService.Logger.g.cs b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/PublicField_Class/MyService.Logger.g.cs new file mode 100644 index 00000000..19326d76 --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Logging/snapshots/LoggerGenerator/PublicField_Class/MyService.Logger.g.cs @@ -0,0 +1,11 @@ +// +using GFramework.Core.Abstractions.Logging; +using GFramework.Core.Logging; + +namespace TestApp; + +partial class MyService +{ + /// Auto-generated logger + public static readonly ILogger _log = LoggerFactoryResolver.Provider.CreateLogger("MyService"); +} diff --git a/GFramework.SourceGenerators.Tests/Rule/ContextAwareGeneratorSnapshotTests.cs b/GFramework.SourceGenerators.Tests/Rule/ContextAwareGeneratorSnapshotTests.cs index e7b352bf..6b84bb12 100644 --- a/GFramework.SourceGenerators.Tests/Rule/ContextAwareGeneratorSnapshotTests.cs +++ b/GFramework.SourceGenerators.Tests/Rule/ContextAwareGeneratorSnapshotTests.cs @@ -86,9 +86,22 @@ public class ContextAwareGeneratorSnapshotTests // 执行生成器快照测试,将生成的代码与预期快照进行比较 await GeneratorSnapshotTest.RunAsync( source, + GetSnapshotFolder()); + } + + /// + /// 将运行时测试目录映射回仓库内已提交的上下文感知生成器快照目录。 + /// + /// 快照目录的绝对路径。 + private static string GetSnapshotFolder() + { + return Path.GetFullPath( Path.Combine( TestContext.CurrentContext.TestDirectory, - "rule", + "..", + "..", + "..", + "Rule", "snapshots", "ContextAwareGenerator")); } diff --git a/GFramework.SourceGenerators.Tests/Rule/snapshots/ContextAwareGenerator/MyRule.ContextAware.g.cs b/GFramework.SourceGenerators.Tests/Rule/snapshots/ContextAwareGenerator/MyRule.ContextAware.g.cs new file mode 100644 index 00000000..54df8881 --- /dev/null +++ b/GFramework.SourceGenerators.Tests/Rule/snapshots/ContextAwareGenerator/MyRule.ContextAware.g.cs @@ -0,0 +1,55 @@ +// +#nullable enable + +namespace TestApp; + +partial class MyRule : global::GFramework.Core.Abstractions.Rule.IContextAware +{ + private global::GFramework.Core.Abstractions.Architectures.IArchitectureContext? _context; + private static global::GFramework.Core.Abstractions.Architectures.IArchitectureContextProvider? _contextProvider; + + /// + /// 自动获取的架构上下文(懒加载,默认使用 GameContextProvider) + /// + protected global::GFramework.Core.Abstractions.Architectures.IArchitectureContext Context + { + get + { + if (_context == null) + { + _contextProvider ??= new global::GFramework.Core.Architectures.GameContextProvider(); + _context = _contextProvider.GetContext(); + } + + return _context; + } + } + + /// + /// 配置上下文提供者(用于测试或多架构场景) + /// + /// 上下文提供者实例 + public static void SetContextProvider(global::GFramework.Core.Abstractions.Architectures.IArchitectureContextProvider provider) + { + _contextProvider = provider; + } + + /// + /// 重置上下文提供者为默认值(用于测试清理) + /// + public static void ResetContextProvider() + { + _contextProvider = null; + } + + void global::GFramework.Core.Abstractions.Rule.IContextAware.SetContext(global::GFramework.Core.Abstractions.Architectures.IArchitectureContext context) + { + _context = context; + } + + global::GFramework.Core.Abstractions.Architectures.IArchitectureContext global::GFramework.Core.Abstractions.Rule.IContextAware.GetContext() + { + return Context; + } + +} \ No newline at end of file