diff --git a/GFramework.SourceGenerators.Tests/Analyzers/ContextRegistrationAnalyzerTests.cs b/GFramework.SourceGenerators.Tests/Analyzers/ContextRegistrationAnalyzerTests.cs index 20d25f24..28a0283b 100644 --- a/GFramework.SourceGenerators.Tests/Analyzers/ContextRegistrationAnalyzerTests.cs +++ b/GFramework.SourceGenerators.Tests/Analyzers/ContextRegistrationAnalyzerTests.cs @@ -132,462 +132,545 @@ public sealed class ContextRegistrationAnalyzerTests } """; - [Test] - public async Task Reports_Warning_When_FieldInjectedModel_Is_Not_Registered() - { - var markup = MarkupTestSource.Parse( - Wrap(""" - namespace TestApp - { - using GFramework.Core.Abstractions.Model; - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Architectures; - using GFramework.Core.SourceGenerators.Abstractions.Rule; - - public interface IInventoryModel : IModel { } - - public sealed class InventoryPanelSystem : ISystem - { - [GetModel] - private IInventoryModel {|#0:_model|} = null!; - } - - public sealed class GameArchitecture : Architecture - { - protected override void OnInitialize() - { - RegisterSystem(new InventoryPanelSystem()); - } - } - } - """)); + // Keep scenario fixtures at class scope so MA0051 reduction does not change analyzer inputs or markup spans. + private const string MissingFieldInjectedModelRegistrationSource = """ + namespace TestApp + { + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Architectures; + using GFramework.Core.SourceGenerators.Abstractions.Rule; - await AnalyzerTestDriver.RunAsync( - markup.Source, - markup.WithSpan( - new DiagnosticResult("GF_ContextRegistration_001", DiagnosticSeverity.Warning) - .WithArguments("IInventoryModel", "InventoryPanelSystem", "GameArchitecture"), - "0")); + public interface IInventoryModel : IModel { } + + public sealed class InventoryPanelSystem : ISystem + { + [GetModel] + private IInventoryModel {|#0:_model|} = null!; + } + + public sealed class GameArchitecture : Architecture + { + protected override void OnInitialize() + { + RegisterSystem(new InventoryPanelSystem()); + } + } + } + """; + + private const string RegisteredFieldInjectedModelSource = """ + namespace TestApp + { + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Architectures; + using GFramework.Core.SourceGenerators.Abstractions.Rule; + + public interface IInventoryModel : IModel { } + + public sealed class InventoryModel : IInventoryModel { } + + public sealed class InventoryPanelSystem : ISystem + { + [GetModel] + private IInventoryModel _model = null!; + } + + public sealed class GameArchitecture : Architecture + { + protected override void OnInitialize() + { + RegisterModel(new InventoryModel()); + RegisterSystem(new InventoryPanelSystem()); + } + } + } + """; + + private const string MissingHandWrittenGetSystemRegistrationSource = """ + namespace TestApp + { + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Abstractions.Utility; + using GFramework.Core.Architectures; + using GFramework.Core.Extensions; + + public interface ICombatSystem : ISystem { } + + public sealed class UiUtility : IUtility + { + public void Initialize() + { + {|#0:this.GetSystem()|}; + } + } + + public sealed class GameArchitecture : Architecture + { + protected override void OnInitialize() + { + RegisterUtility(new UiUtility()); + } + } + } + """; + + private const string ModuleProvidedModelRegistrationSource = """ + namespace TestApp + { + using GFramework.Core.Abstractions.Architectures; + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Architectures; + using GFramework.Core.SourceGenerators.Abstractions.Rule; + + public interface IInventoryModel : IModel { } + + public sealed class InventoryModel : IInventoryModel { } + + public sealed class InventoryPanelSystem : ISystem + { + [GetModel] + private IInventoryModel _model = null!; + } + + public sealed class InventoryModule : IArchitectureModule + { + public void Install(IArchitecture architecture) + { + architecture.RegisterModel(new InventoryModel()); + } + } + + public sealed class GameArchitecture : Architecture + { + protected override void OnInitialize() + { + InstallModule(new InventoryModule()); + RegisterSystem(new InventoryPanelSystem()); + } + } + } + """; + + private const string AmbiguousOwningArchitectureSource = """ + namespace TestApp + { + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Architectures; + using GFramework.Core.SourceGenerators.Abstractions.Rule; + + public interface IInventoryModel : IModel { } + + public sealed class InventoryPanelSystem : ISystem + { + [GetModel] + private IInventoryModel _model = null!; + } + + public sealed class FirstArchitecture : Architecture + { + protected override void OnInitialize() + { + RegisterSystem(new InventoryPanelSystem()); + } + } + + public sealed class SecondArchitecture : Architecture + { + protected override void OnInitialize() + { + RegisterSystem(new InventoryPanelSystem()); + } + } + } + """; + + private const string MissingGetUtilitiesRegistrationSource = """ + namespace TestApp + { + using System.Collections.Generic; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Abstractions.Utility; + using GFramework.Core.Architectures; + using GFramework.Core.SourceGenerators.Abstractions.Rule; + + public interface IInventoryUtility : IUtility { } + + public sealed class InventoryPanelSystem : ISystem + { + [GetUtilities] + private IReadOnlyList {|#0:_utilities|} = null!; + } + + public sealed class GameArchitecture : Architecture + { + protected override void OnInitialize() + { + RegisterSystem(new InventoryPanelSystem()); + } + } + } + """; + + private const string DerivedArchitectureVirtualHelperRegistrationSource = """ + namespace TestApp + { + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Architectures; + using GFramework.Core.SourceGenerators.Abstractions.Rule; + + public interface IInventoryModel : IModel { } + + public sealed class InventoryModel : IInventoryModel { } + + public abstract class ArchitectureBase : Architecture + { + protected override void OnInitialize() + { + RegisterComponents(); + } + + protected virtual void RegisterComponents() + { + } + } + + public sealed class InventoryPanelSystem : ISystem + { + [GetModel] + private IInventoryModel _model = null!; + } + + public sealed class GameArchitecture : ArchitectureBase + { + protected override void RegisterComponents() + { + RegisterModel(new InventoryModel()); + RegisterSystem(new InventoryPanelSystem()); + } + } + } + """; + + private const string DerivedModuleVirtualHelperRegistrationSource = """ + namespace TestApp + { + using GFramework.Core.Abstractions.Architectures; + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Architectures; + using GFramework.Core.SourceGenerators.Abstractions.Rule; + + public interface IInventoryModel : IModel { } + + public sealed class InventoryModel : IInventoryModel { } + + public abstract class ModuleBase : IArchitectureModule + { + public void Install(IArchitecture architecture) + { + RegisterComponents(architecture); + } + + protected virtual void RegisterComponents(IArchitecture architecture) + { + } + } + + public sealed class DerivedInventoryModule : ModuleBase + { + protected override void RegisterComponents(IArchitecture architecture) + { + architecture.RegisterModel(new InventoryModel()); + } + } + + public sealed class InventoryPanelSystem : ISystem + { + [GetModel] + private IInventoryModel _model = null!; + } + + public sealed class GameArchitecture : Architecture + { + protected override void OnInitialize() + { + InstallModule(new DerivedInventoryModule()); + RegisterSystem(new InventoryPanelSystem()); + } + } + } + """; + + private const string DerivedArchitectureBaseHelperCallSource = """ + namespace TestApp + { + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Architectures; + using GFramework.Core.SourceGenerators.Abstractions.Rule; + + public interface IInventoryModel : IModel { } + + public sealed class InventoryModel : IInventoryModel { } + + public sealed class InventoryPanelSystem : ISystem + { + [GetModel] + private IInventoryModel {|#0:_model|} = null!; + } + + public abstract class ArchitectureBase : Architecture + { + protected virtual void RegisterComponents() + { + RegisterSystem(new InventoryPanelSystem()); + } + } + + public sealed class GameArchitecture : ArchitectureBase + { + protected override void OnInitialize() + { + base.RegisterComponents(); + } + + protected override void RegisterComponents() + { + RegisterModel(new InventoryModel()); + RegisterSystem(new InventoryPanelSystem()); + } + } + } + """; + + private const string DerivedModuleBaseHelperCallSource = """ + namespace TestApp + { + using GFramework.Core.Abstractions.Architectures; + using GFramework.Core.Abstractions.Model; + using GFramework.Core.Abstractions.Systems; + using GFramework.Core.Architectures; + using GFramework.Core.SourceGenerators.Abstractions.Rule; + + public interface IInventoryModel : IModel { } + + public sealed class InventoryModel : IInventoryModel { } + + public sealed class InventoryPanelSystem : ISystem + { + [GetModel] + private IInventoryModel {|#0:_model|} = null!; + } + + public abstract class ModuleBase : IArchitectureModule + { + public virtual void Install(IArchitecture architecture) + { + } + + protected virtual void RegisterComponents(IArchitecture architecture) + { + architecture.RegisterSystem(new InventoryPanelSystem()); + } + } + + public sealed class DerivedInventoryModule : ModuleBase + { + public override void Install(IArchitecture architecture) + { + base.RegisterComponents(architecture); + } + + protected override void RegisterComponents(IArchitecture architecture) + { + architecture.RegisterModel(new InventoryModel()); + architecture.RegisterSystem(new InventoryPanelSystem()); + } + } + + public sealed class GameArchitecture : Architecture + { + protected override void OnInitialize() + { + InstallModule(new DerivedInventoryModule()); + } + } + } + """; + + /// + /// 验证字段注入模型未注册时会报告缺失注册告警。 + /// + [Test] + public Task Reports_Warning_When_FieldInjectedModel_Is_Not_Registered() + { + return RunWarningScenarioAsync( + MissingFieldInjectedModelRegistrationSource, + CreateContextRegistrationWarning( + "GF_ContextRegistration_001", + "IInventoryModel", + "InventoryPanelSystem", + "GameArchitecture")); } + /// + /// 验证字段注入模型已注册时不会产生误报。 + /// [Test] - public async Task Does_Not_Report_When_FieldInjectedModel_Is_Registered() + public Task Does_Not_Report_When_FieldInjectedModel_Is_Registered() { - await AnalyzerTestDriver.RunAsync( - Wrap(""" - namespace TestApp - { - using GFramework.Core.Abstractions.Model; - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Architectures; - using GFramework.Core.SourceGenerators.Abstractions.Rule; - - public interface IInventoryModel : IModel { } - - public sealed class InventoryModel : IInventoryModel { } - - public sealed class InventoryPanelSystem : ISystem - { - [GetModel] - private IInventoryModel _model = null!; - } - - public sealed class GameArchitecture : Architecture - { - protected override void OnInitialize() - { - RegisterModel(new InventoryModel()); - RegisterSystem(new InventoryPanelSystem()); - } - } - } - """)); + return RunNoDiagnosticScenarioAsync(RegisteredFieldInjectedModelSource); } + /// + /// 验证手写扩展方法访问未注册 System 时会报告缺失注册告警。 + /// [Test] - public async Task Reports_Warning_When_HandWrittenGetSystem_Call_Has_No_Registration() + public Task Reports_Warning_When_HandWrittenGetSystem_Call_Has_No_Registration() { - var markup = MarkupTestSource.Parse( - Wrap(""" - namespace TestApp - { - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Abstractions.Utility; - using GFramework.Core.Architectures; - using GFramework.Core.Extensions; - - public interface ICombatSystem : ISystem { } - - public sealed class UiUtility : IUtility - { - public void Initialize() - { - {|#0:this.GetSystem()|}; - } - } - - public sealed class GameArchitecture : Architecture - { - protected override void OnInitialize() - { - RegisterUtility(new UiUtility()); - } - } - } - """)); - - await AnalyzerTestDriver.RunAsync( - markup.Source, - markup.WithSpan( - new DiagnosticResult("GF_ContextRegistration_002", DiagnosticSeverity.Warning) - .WithArguments("ICombatSystem", "UiUtility", "GameArchitecture"), - "0")); + return RunWarningScenarioAsync( + MissingHandWrittenGetSystemRegistrationSource, + CreateContextRegistrationWarning( + "GF_ContextRegistration_002", + "ICombatSystem", + "UiUtility", + "GameArchitecture")); } + /// + /// 验证模块安装链路提供注册时分析器会把该注册视为有效来源。 + /// [Test] - public async Task Does_Not_Report_When_Registration_Comes_From_Installed_Module() + public Task Does_Not_Report_When_Registration_Comes_From_Installed_Module() { - await AnalyzerTestDriver.RunAsync( - Wrap(""" - namespace TestApp - { - using GFramework.Core.Abstractions.Architectures; - using GFramework.Core.Abstractions.Model; - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Architectures; - using GFramework.Core.SourceGenerators.Abstractions.Rule; - - public interface IInventoryModel : IModel { } - - public sealed class InventoryModel : IInventoryModel { } - - public sealed class InventoryPanelSystem : ISystem - { - [GetModel] - private IInventoryModel _model = null!; - } - - public sealed class InventoryModule : IArchitectureModule - { - public void Install(IArchitecture architecture) - { - architecture.RegisterModel(new InventoryModel()); - } - } - - public sealed class GameArchitecture : Architecture - { - protected override void OnInitialize() - { - InstallModule(new InventoryModule()); - RegisterSystem(new InventoryPanelSystem()); - } - } - } - """)); + return RunNoDiagnosticScenarioAsync(ModuleProvidedModelRegistrationSource); } + /// + /// 验证无法唯一推导所属 Architecture 时分析器保持静默以避免误报。 + /// [Test] - public async Task Does_Not_Report_When_Owning_Architecture_Cannot_Be_Uniquely_Determined() + public Task Does_Not_Report_When_Owning_Architecture_Cannot_Be_Uniquely_Determined() { - await AnalyzerTestDriver.RunAsync( - Wrap(""" - namespace TestApp - { - using GFramework.Core.Abstractions.Model; - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Architectures; - using GFramework.Core.SourceGenerators.Abstractions.Rule; - - public interface IInventoryModel : IModel { } - - public sealed class InventoryPanelSystem : ISystem - { - [GetModel] - private IInventoryModel _model = null!; - } - - public sealed class FirstArchitecture : Architecture - { - protected override void OnInitialize() - { - RegisterSystem(new InventoryPanelSystem()); - } - } - - public sealed class SecondArchitecture : Architecture - { - protected override void OnInitialize() - { - RegisterSystem(new InventoryPanelSystem()); - } - } - } - """)); + return RunNoDiagnosticScenarioAsync(AmbiguousOwningArchitectureSource); } + /// + /// 验证集合注入 Utility 缺失注册时仍会报告对应告警。 + /// [Test] - public async Task Reports_Warning_When_GetUtilities_Field_Has_No_Registered_Utility() + public Task Reports_Warning_When_GetUtilities_Field_Has_No_Registered_Utility() { - var markup = MarkupTestSource.Parse( - Wrap(""" - namespace TestApp - { - using System.Collections.Generic; - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Abstractions.Utility; - using GFramework.Core.Architectures; - using GFramework.Core.SourceGenerators.Abstractions.Rule; - - public interface IInventoryUtility : IUtility { } - - public sealed class InventoryPanelSystem : ISystem - { - [GetUtilities] - private IReadOnlyList {|#0:_utilities|} = null!; - } - - public sealed class GameArchitecture : Architecture - { - protected override void OnInitialize() - { - RegisterSystem(new InventoryPanelSystem()); - } - } - } - """)); - - await AnalyzerTestDriver.RunAsync( - markup.Source, - markup.WithSpan( - new DiagnosticResult("GF_ContextRegistration_003", DiagnosticSeverity.Warning) - .WithArguments("IInventoryUtility", "InventoryPanelSystem", "GameArchitecture"), - "0")); + return RunWarningScenarioAsync( + MissingGetUtilitiesRegistrationSource, + CreateContextRegistrationWarning( + "GF_ContextRegistration_003", + "IInventoryUtility", + "InventoryPanelSystem", + "GameArchitecture")); } + /// + /// 验证基类初始化经由虚方法分派到派生实现时,派生注册仍会被识别。 + /// [Test] - public async Task + public Task Does_Not_Report_When_Inherited_OnInitialize_Calls_Virtual_Helper_Overridden_In_Derived_Architecture() { - await AnalyzerTestDriver.RunAsync( - Wrap(""" - namespace TestApp - { - using GFramework.Core.Abstractions.Model; - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Architectures; - using GFramework.Core.SourceGenerators.Abstractions.Rule; - - public interface IInventoryModel : IModel { } - - public sealed class InventoryModel : IInventoryModel { } - - public abstract class ArchitectureBase : Architecture - { - protected override void OnInitialize() - { - RegisterComponents(); - } - - protected virtual void RegisterComponents() - { - } - } - - public sealed class InventoryPanelSystem : ISystem - { - [GetModel] - private IInventoryModel _model = null!; - } - - public sealed class GameArchitecture : ArchitectureBase - { - protected override void RegisterComponents() - { - RegisterModel(new InventoryModel()); - RegisterSystem(new InventoryPanelSystem()); - } - } - } - """)); + return RunNoDiagnosticScenarioAsync(DerivedArchitectureVirtualHelperRegistrationSource); } + /// + /// 验证模块基类通过虚方法转发注册时,派生模块的注册依然会被识别。 + /// [Test] - public async Task Does_Not_Report_When_Inherited_Module_Install_Calls_Virtual_Helper_Overridden_In_Derived_Module() + public Task Does_Not_Report_When_Inherited_Module_Install_Calls_Virtual_Helper_Overridden_In_Derived_Module() { - await AnalyzerTestDriver.RunAsync( - Wrap(""" - namespace TestApp - { - using GFramework.Core.Abstractions.Architectures; - using GFramework.Core.Abstractions.Model; - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Architectures; - using GFramework.Core.SourceGenerators.Abstractions.Rule; - - public interface IInventoryModel : IModel { } - - public sealed class InventoryModel : IInventoryModel { } - - public abstract class ModuleBase : IArchitectureModule - { - public void Install(IArchitecture architecture) - { - RegisterComponents(architecture); - } - - protected virtual void RegisterComponents(IArchitecture architecture) - { - } - } - - public sealed class DerivedInventoryModule : ModuleBase - { - protected override void RegisterComponents(IArchitecture architecture) - { - architecture.RegisterModel(new InventoryModel()); - } - } - - public sealed class InventoryPanelSystem : ISystem - { - [GetModel] - private IInventoryModel _model = null!; - } - - public sealed class GameArchitecture : Architecture - { - protected override void OnInitialize() - { - InstallModule(new DerivedInventoryModule()); - RegisterSystem(new InventoryPanelSystem()); - } - } - } - """)); + return RunNoDiagnosticScenarioAsync(DerivedModuleVirtualHelperRegistrationSource); } + /// + /// 验证显式调用基类 helper 时,分析器按基类实际执行的注册路径发出告警。 + /// [Test] - public async Task Reports_Warning_When_Derived_Architecture_Explicitly_Calls_Base_Helper() + public Task Reports_Warning_When_Derived_Architecture_Explicitly_Calls_Base_Helper() { - var markup = MarkupTestSource.Parse( - Wrap(""" - namespace TestApp - { - using GFramework.Core.Abstractions.Model; - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Architectures; - using GFramework.Core.SourceGenerators.Abstractions.Rule; - - public interface IInventoryModel : IModel { } - - public sealed class InventoryModel : IInventoryModel { } - - public sealed class InventoryPanelSystem : ISystem - { - [GetModel] - private IInventoryModel {|#0:_model|} = null!; - } - - public abstract class ArchitectureBase : Architecture - { - protected virtual void RegisterComponents() - { - RegisterSystem(new InventoryPanelSystem()); - } - } - - public sealed class GameArchitecture : ArchitectureBase - { - protected override void OnInitialize() - { - base.RegisterComponents(); - } - - protected override void RegisterComponents() - { - RegisterModel(new InventoryModel()); - RegisterSystem(new InventoryPanelSystem()); - } - } - } - """)); + return RunWarningScenarioAsync( + DerivedArchitectureBaseHelperCallSource, + CreateContextRegistrationWarning( + "GF_ContextRegistration_001", + "IInventoryModel", + "InventoryPanelSystem", + "GameArchitecture")); + } - await AnalyzerTestDriver.RunAsync( + /// + /// 验证模块显式调用基类 helper 时,分析器按实际执行的安装路径发出告警。 + /// + [Test] + public Task Reports_Warning_When_Derived_Module_Explicitly_Calls_Base_Helper() + { + return RunWarningScenarioAsync( + DerivedModuleBaseHelperCallSource, + CreateContextRegistrationWarning( + "GF_ContextRegistration_001", + "IInventoryModel", + "InventoryPanelSystem", + "GameArchitecture")); + } + + /// + /// 运行包含诊断标记的 analyzer 场景,并把预期诊断绑定到统一的 `#0` span。 + /// + /// 不含公共前导代码的测试源码。 + /// 需要命中的预期诊断。 + /// 代表 analyzer 验证流程的异步任务。 + private static Task RunWarningScenarioAsync(string source, DiagnosticResult expectedDiagnostic) + { + MarkupTestSource markup = MarkupTestSource.Parse(Wrap(source)); + return AnalyzerTestDriver.RunAsync( markup.Source, - markup.WithSpan( - new DiagnosticResult("GF_ContextRegistration_001", DiagnosticSeverity.Warning) - .WithArguments("IInventoryModel", "InventoryPanelSystem", "GameArchitecture"), - "0")); + markup.WithSpan(expectedDiagnostic, "0")); } - [Test] - public async Task Reports_Warning_When_Derived_Module_Explicitly_Calls_Base_Helper() + /// + /// 运行不应产生诊断的 analyzer 场景。 + /// + /// 不含公共前导代码的测试源码。 + /// 代表 analyzer 验证流程的异步任务。 + private static Task RunNoDiagnosticScenarioAsync(string source) { - var markup = MarkupTestSource.Parse( - Wrap(""" - namespace TestApp - { - using GFramework.Core.Abstractions.Architectures; - using GFramework.Core.Abstractions.Model; - using GFramework.Core.Abstractions.Systems; - using GFramework.Core.Architectures; - using GFramework.Core.SourceGenerators.Abstractions.Rule; - - public interface IInventoryModel : IModel { } - - public sealed class InventoryModel : IInventoryModel { } - - public sealed class InventoryPanelSystem : ISystem - { - [GetModel] - private IInventoryModel {|#0:_model|} = null!; - } - - public abstract class ModuleBase : IArchitectureModule - { - public virtual void Install(IArchitecture architecture) - { - } - - protected virtual void RegisterComponents(IArchitecture architecture) - { - architecture.RegisterSystem(new InventoryPanelSystem()); - } - } - - public sealed class DerivedInventoryModule : ModuleBase - { - public override void Install(IArchitecture architecture) - { - base.RegisterComponents(architecture); - } - - protected override void RegisterComponents(IArchitecture architecture) - { - architecture.RegisterModel(new InventoryModel()); - architecture.RegisterSystem(new InventoryPanelSystem()); - } - } - - public sealed class GameArchitecture : Architecture - { - protected override void OnInitialize() - { - InstallModule(new DerivedInventoryModule()); - } - } - } - """)); - - await AnalyzerTestDriver.RunAsync( - markup.Source, - markup.WithSpan( - new DiagnosticResult("GF_ContextRegistration_001", DiagnosticSeverity.Warning) - .WithArguments("IInventoryModel", "InventoryPanelSystem", "GameArchitecture"), - "0")); + return AnalyzerTestDriver.RunAsync(Wrap(source)); } + /// + /// 构造 Context 注册分析器的统一预期诊断,以保持断言参数顺序稳定。 + /// + /// 预期诊断 ID。 + /// 缺失注册的服务或依赖类型。 + /// 触发访问的拥有者类型。 + /// 推导出的所属 Architecture 类型。 + /// 配置好参数的预期诊断结果。 + private static DiagnosticResult CreateContextRegistrationWarning( + string diagnosticId, + string serviceType, + string ownerType, + string architectureType) + { + return new DiagnosticResult(diagnosticId, DiagnosticSeverity.Warning) + .WithArguments(serviceType, ownerType, architectureType); + } + + /// + /// 将公共测试前导代码与具体场景源码拼接为完整编译单元。 + /// + /// 具体测试场景源码。 + /// 包含公共前导代码的完整源码文本。 private static string Wrap(string source) { return $"{TestPreamble}{Environment.NewLine}{Environment.NewLine}{source}";