refactor(source-generators-tests): 收敛自动注册模块测试告警

- 重构 AutoRegisterModuleGeneratorTests 的内联测试源码与快照常量,降低 MA0051 方法长度并保持生成断言不变
- 更新 analyzer warning reduction 的 tracking 与 trace,记录 RP-032 的验证结果和下一步恢复点
This commit is contained in:
gewuyou 2026-04-23 11:48:14 +08:00
parent 31ae1460a9
commit 9d251ab1f8
3 changed files with 358 additions and 318 deletions

View File

@ -4,109 +4,323 @@ using GFramework.SourceGenerators.Tests.Core;
namespace GFramework.SourceGenerators.Tests.Architectures;
[TestFixture]
/// <summary>
/// 验证 <see cref="AutoRegisterModuleGenerator" /> 在模块自动注册场景下的生成契约与输出顺序。
/// </summary>
public class AutoRegisterModuleGeneratorTests
{
private const string AttributeOrderSource = """
using System;
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
namespace GFramework.Core.SourceGenerators.Abstractions.Architectures
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class AutoRegisterModuleAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterModelAttribute : Attribute
{
public RegisterModelAttribute(Type modelType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterSystemAttribute : Attribute
{
public RegisterSystemAttribute(Type systemType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterUtilityAttribute : Attribute
{
public RegisterUtilityAttribute(Type utilityType) { }
}
}
namespace GFramework.Core.Abstractions.Architectures
{
public interface IArchitecture
{
T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel;
T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem;
T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility;
}
}
namespace GFramework.Core.Abstractions.Model
{
public interface IModel { }
}
namespace GFramework.Core.Abstractions.Systems
{
public interface ISystem { }
}
namespace GFramework.Core.Abstractions.Utility
{
public interface IUtility { }
}
namespace TestApp
{
using GFramework.Core.Abstractions.Model;
using GFramework.Core.Abstractions.Systems;
using GFramework.Core.Abstractions.Utility;
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
public sealed class PlayerModel : IModel { }
public sealed class CombatSystem : ISystem { }
public sealed class AudioUtility : IUtility { }
[AutoRegisterModule]
[RegisterSystem(typeof(CombatSystem))]
[RegisterModel(typeof(PlayerModel))]
[RegisterUtility(typeof(AudioUtility))]
public partial class GameplayModule
{
}
}
""";
private const string AttributeOrderExpected = """
// <auto-generated />
#nullable enable
namespace TestApp;
partial class GameplayModule
{
public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture)
{
architecture.RegisterSystem(new global::TestApp.CombatSystem());
architecture.RegisterModel(new global::TestApp.PlayerModel());
architecture.RegisterUtility(new global::TestApp.AudioUtility());
}
}
""";
private const string DeterministicOrderCommonSource = """
using System;
namespace GFramework.Core.SourceGenerators.Abstractions.Architectures
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class AutoRegisterModuleAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterModelAttribute : Attribute
{
public RegisterModelAttribute(Type modelType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterSystemAttribute : Attribute
{
public RegisterSystemAttribute(Type systemType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterUtilityAttribute : Attribute
{
public RegisterUtilityAttribute(Type utilityType) { }
}
}
namespace GFramework.Core.Abstractions.Architectures
{
public interface IArchitecture
{
T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel;
T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem;
T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility;
}
}
namespace GFramework.Core.Abstractions.Model
{
public interface IModel { }
}
namespace GFramework.Core.Abstractions.Systems
{
public interface ISystem { }
}
namespace GFramework.Core.Abstractions.Utility
{
public interface IUtility { }
}
namespace TestApp
{
using GFramework.Core.Abstractions.Model;
using GFramework.Core.Abstractions.Systems;
using GFramework.Core.Abstractions.Utility;
public sealed class PlayerModel : IModel { }
public sealed class CombatSystem : ISystem { }
public sealed class AudioUtility : IUtility { }
}
""";
private const string DeterministicOrderPartASource = """
namespace TestApp
{
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
// Padding ensures this attribute lives later in the file than the attributes in PartB.
// The generator should still place it first because PartA sorts before PartB.
// padding 01
// padding 02
// padding 03
// padding 04
// padding 05
// padding 06
// padding 07
// padding 08
// padding 09
// padding 10
[AutoRegisterModule]
[RegisterUtility(typeof(AudioUtility))]
public partial class GameplayModule
{
}
}
""";
private const string DeterministicOrderPartBSource = """
namespace TestApp
{
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
[RegisterSystem(typeof(CombatSystem))]
[RegisterModel(typeof(PlayerModel))]
public partial class GameplayModule
{
}
}
""";
private const string DeterministicOrderExpected = """
// <auto-generated />
#nullable enable
namespace TestApp;
partial class GameplayModule
{
public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture)
{
architecture.RegisterUtility(new global::TestApp.AudioUtility());
architecture.RegisterSystem(new global::TestApp.CombatSystem());
architecture.RegisterModel(new global::TestApp.PlayerModel());
}
}
""";
private const string TypeConstraintSource = """
#nullable enable
using System;
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
namespace GFramework.Core.SourceGenerators.Abstractions.Architectures
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class AutoRegisterModuleAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterModelAttribute : Attribute
{
public RegisterModelAttribute(Type modelType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterSystemAttribute : Attribute
{
public RegisterSystemAttribute(Type systemType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterUtilityAttribute : Attribute
{
public RegisterUtilityAttribute(Type utilityType) { }
}
}
namespace GFramework.Core.Abstractions.Architectures
{
public interface IArchitecture
{
T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel;
T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem;
T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility;
}
}
namespace GFramework.Core.Abstractions.Model
{
public interface IModel { }
}
namespace GFramework.Core.Abstractions.Systems
{
public interface ISystem { }
}
namespace GFramework.Core.Abstractions.Utility
{
public interface IUtility { }
}
namespace TestApp
{
using GFramework.Core.Abstractions.Model;
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
public sealed class PlayerModel : IModel { }
[AutoRegisterModule]
[RegisterModel(typeof(PlayerModel))]
public partial class GameplayModule<TNullableRef, TNotNull, TUnmanaged>
where TNullableRef : class?
where TNotNull : notnull
where TUnmanaged : unmanaged
{
}
}
""";
private const string TypeConstraintExpected = """
// <auto-generated />
#nullable enable
namespace TestApp;
partial class GameplayModule<TNullableRef, TNotNull, TUnmanaged>
where TNullableRef : class?
where TNotNull : notnull
where TUnmanaged : unmanaged
{
public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture)
{
architecture.RegisterModel(new global::TestApp.PlayerModel());
}
}
""";
/// <summary>
/// 验证同一声明上的注册特性会按照源码中的书写顺序生成安装代码。
/// </summary>
[Test]
public async Task Generates_Module_Install_Method_In_Attribute_Order()
public Task Generates_Module_Install_Method_In_Attribute_Order()
{
const string source = """
using System;
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
namespace GFramework.Core.SourceGenerators.Abstractions.Architectures
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class AutoRegisterModuleAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterModelAttribute : Attribute
{
public RegisterModelAttribute(Type modelType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterSystemAttribute : Attribute
{
public RegisterSystemAttribute(Type systemType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterUtilityAttribute : Attribute
{
public RegisterUtilityAttribute(Type utilityType) { }
}
}
namespace GFramework.Core.Abstractions.Architectures
{
public interface IArchitecture
{
T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel;
T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem;
T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility;
}
}
namespace GFramework.Core.Abstractions.Model
{
public interface IModel { }
}
namespace GFramework.Core.Abstractions.Systems
{
public interface ISystem { }
}
namespace GFramework.Core.Abstractions.Utility
{
public interface IUtility { }
}
namespace TestApp
{
using GFramework.Core.Abstractions.Model;
using GFramework.Core.Abstractions.Systems;
using GFramework.Core.Abstractions.Utility;
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
public sealed class PlayerModel : IModel { }
public sealed class CombatSystem : ISystem { }
public sealed class AudioUtility : IUtility { }
[AutoRegisterModule]
[RegisterSystem(typeof(CombatSystem))]
[RegisterModel(typeof(PlayerModel))]
[RegisterUtility(typeof(AudioUtility))]
public partial class GameplayModule
{
}
}
""";
const string expected = """
// <auto-generated />
#nullable enable
namespace TestApp;
partial class GameplayModule
{
public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture)
{
architecture.RegisterSystem(new global::TestApp.CombatSystem());
architecture.RegisterModel(new global::TestApp.PlayerModel());
architecture.RegisterUtility(new global::TestApp.AudioUtility());
}
}
""";
await GeneratorTest<AutoRegisterModuleGenerator>.RunAsync(
source,
("TestApp_GameplayModule.AutoRegisterModule.g.cs", expected));
return GeneratorTest<AutoRegisterModuleGenerator>.RunAsync(
AttributeOrderSource,
("TestApp_GameplayModule.AutoRegisterModule.g.cs", AttributeOrderExpected));
}
/// <summary>
@ -115,140 +329,20 @@ public class AutoRegisterModuleGeneratorTests
[Test]
public async Task Generates_Module_Install_Method_In_Deterministic_Order_Across_Partial_Declarations()
{
const string commonSource = """
using System;
namespace GFramework.Core.SourceGenerators.Abstractions.Architectures
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class AutoRegisterModuleAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterModelAttribute : Attribute
{
public RegisterModelAttribute(Type modelType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterSystemAttribute : Attribute
{
public RegisterSystemAttribute(Type systemType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterUtilityAttribute : Attribute
{
public RegisterUtilityAttribute(Type utilityType) { }
}
}
namespace GFramework.Core.Abstractions.Architectures
{
public interface IArchitecture
{
T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel;
T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem;
T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility;
}
}
namespace GFramework.Core.Abstractions.Model
{
public interface IModel { }
}
namespace GFramework.Core.Abstractions.Systems
{
public interface ISystem { }
}
namespace GFramework.Core.Abstractions.Utility
{
public interface IUtility { }
}
namespace TestApp
{
using GFramework.Core.Abstractions.Model;
using GFramework.Core.Abstractions.Systems;
using GFramework.Core.Abstractions.Utility;
public sealed class PlayerModel : IModel { }
public sealed class CombatSystem : ISystem { }
public sealed class AudioUtility : IUtility { }
}
""";
const string partASource = """
namespace TestApp
{
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
// Padding ensures this attribute lives later in the file than the attributes in PartB.
// The generator should still place it first because PartA sorts before PartB.
// padding 01
// padding 02
// padding 03
// padding 04
// padding 05
// padding 06
// padding 07
// padding 08
// padding 09
// padding 10
[AutoRegisterModule]
[RegisterUtility(typeof(AudioUtility))]
public partial class GameplayModule
{
}
}
""";
const string partBSource = """
namespace TestApp
{
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
[RegisterSystem(typeof(CombatSystem))]
[RegisterModel(typeof(PlayerModel))]
public partial class GameplayModule
{
}
}
""";
const string expected = """
// <auto-generated />
#nullable enable
namespace TestApp;
partial class GameplayModule
{
public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture)
{
architecture.RegisterUtility(new global::TestApp.AudioUtility());
architecture.RegisterSystem(new global::TestApp.CombatSystem());
architecture.RegisterModel(new global::TestApp.PlayerModel());
}
}
""";
var test = new CSharpSourceGeneratorTest<AutoRegisterModuleGenerator, DefaultVerifier>
{
TestState =
{
Sources =
{
("Common.cs", commonSource),
("GameplayModule.PartA.cs", partASource),
("GameplayModule.PartB.cs", partBSource)
("Common.cs", DeterministicOrderCommonSource),
("GameplayModule.PartA.cs", DeterministicOrderPartASource),
("GameplayModule.PartB.cs", DeterministicOrderPartBSource)
},
GeneratedSources =
{
(typeof(AutoRegisterModuleGenerator), "TestApp_GameplayModule.AutoRegisterModule.g.cs",
NormalizeLineEndings(expected))
NormalizeLineEndings(DeterministicOrderExpected))
}
},
DisabledDiagnostics = { "GF_Common_Trace_001" }
@ -261,102 +355,11 @@ public class AutoRegisterModuleGeneratorTests
/// 验证生成器会保留可空引用、notnull 与 unmanaged 约束。
/// </summary>
[Test]
public async Task Generates_Type_Constraints_For_NullableReference_NotNull_And_Unmanaged()
public Task Generates_Type_Constraints_For_NullableReference_NotNull_And_Unmanaged()
{
const string source = """
#nullable enable
using System;
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
namespace GFramework.Core.SourceGenerators.Abstractions.Architectures
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class AutoRegisterModuleAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterModelAttribute : Attribute
{
public RegisterModelAttribute(Type modelType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterSystemAttribute : Attribute
{
public RegisterSystemAttribute(Type systemType) { }
}
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class RegisterUtilityAttribute : Attribute
{
public RegisterUtilityAttribute(Type utilityType) { }
}
}
namespace GFramework.Core.Abstractions.Architectures
{
public interface IArchitecture
{
T RegisterModel<T>(T model) where T : GFramework.Core.Abstractions.Model.IModel;
T RegisterSystem<T>(T system) where T : GFramework.Core.Abstractions.Systems.ISystem;
T RegisterUtility<T>(T utility) where T : GFramework.Core.Abstractions.Utility.IUtility;
}
}
namespace GFramework.Core.Abstractions.Model
{
public interface IModel { }
}
namespace GFramework.Core.Abstractions.Systems
{
public interface ISystem { }
}
namespace GFramework.Core.Abstractions.Utility
{
public interface IUtility { }
}
namespace TestApp
{
using GFramework.Core.Abstractions.Model;
using GFramework.Core.SourceGenerators.Abstractions.Architectures;
public sealed class PlayerModel : IModel { }
[AutoRegisterModule]
[RegisterModel(typeof(PlayerModel))]
public partial class GameplayModule<TNullableRef, TNotNull, TUnmanaged>
where TNullableRef : class?
where TNotNull : notnull
where TUnmanaged : unmanaged
{
}
}
""";
const string expected = """
// <auto-generated />
#nullable enable
namespace TestApp;
partial class GameplayModule<TNullableRef, TNotNull, TUnmanaged>
where TNullableRef : class?
where TNotNull : notnull
where TUnmanaged : unmanaged
{
public void Install(global::GFramework.Core.Abstractions.Architectures.IArchitecture architecture)
{
architecture.RegisterModel(new global::TestApp.PlayerModel());
}
}
""";
await GeneratorTest<AutoRegisterModuleGenerator>.RunAsync(
source,
("TestApp_GameplayModule.AutoRegisterModule.g.cs", expected));
return GeneratorTest<AutoRegisterModuleGenerator>.RunAsync(
TypeConstraintSource,
("TestApp_GameplayModule.AutoRegisterModule.g.cs", TypeConstraintExpected));
}
/// <summary>

View File

@ -7,8 +7,8 @@
## 当前恢复点
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-031`
- 当前阶段:`Phase 31`
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-032`
- 当前阶段:`Phase 32`
- 当前焦点:
- 已完成 `GFramework.Core` 当前 `MA0016` / `MA0002` / `MA0015` / `MA0077` 低风险收口批次
- 已复核 `net10.0` 下的 `MA0158` 基线:`GFramework.Core` / `GFramework.Cqrs` 当前共有 `16` 个 object lock
@ -57,10 +57,14 @@
场景已收敛为模板化 helper保留原有快照目录与生成器输入语义不变
- 当前 `GFramework.SourceGenerators.Tests` Release build 基线已从 `49` 条降到 `43` 条;`LoggerGeneratorSnapshotTests.cs`
已不再出现在 `MA0051` 列表中
- 已完成 `GFramework.SourceGenerators.Tests/Architectures/AutoRegisterModuleGeneratorTests.cs``MA0051` 收口:
将内联测试源码与期望快照抽到类级常量、补齐测试类 XML 文档,并将仅作转发的异步测试改为直接返回 `Task`
- 当前 `GFramework.SourceGenerators.Tests` Release build 基线已从 `43` 条降到 `40` 条;
`AutoRegisterModuleGeneratorTests.cs` 已不再出现在 `MA0051` 列表中
- `GFramework.Godot``Timing.cs` 已同步适配新事件签名,但当前 worktree 的 Godot restore 资产仍受 Windows fallback package folder 干扰,独立 build 需在修复资产后补跑
- 后续继续按 warning 类型和数量批处理,而不是回退到按单文件切片推进
- 下一轮默认继续拆分 `GFramework.SourceGenerators.Tests``MA0051` 热点,优先处理
`AutoRegisterModuleGeneratorTests``GeneratorSnapshotTest``ContextGetGeneratorTests`
`GeneratorSnapshotTest` 或 `ContextGetGeneratorTests`
- 单次 `boot` 的工作树改动上限控制在约 `100` 个文件以内,避免 recovery context 与 review 面同时失控
- 若任务边界互不冲突,允许使用不同模型的 subagent 并行处理不同 warning 类型或不同目录,但必须遵守显式 ownership
@ -98,6 +102,8 @@
全部收敛为 `MA0051`
- 已完成 `LoggerGeneratorSnapshotTests` 的单文件 `MA0051` 收口;当前 `GFramework.SourceGenerators.Tests` Release build 基线已降到
`43` 条,并通过 focused snapshot tests 保持行为不变
- 已完成 `AutoRegisterModuleGeneratorTests` 的单文件 `MA0051` 收口;当前 `GFramework.SourceGenerators.Tests` Release build 基线已降到
`40` 条,并通过 focused generator tests 保持输出契约不变
## 当前活跃事实
@ -138,6 +144,8 @@
通过 schema 类型比较 helper 与显式 `StringComparison.Ordinal` 清空当前项目的 `MA0006`
- `RP-020` 继续拆分 `SchemaConfigGenerator.cs``MA0051` 热点,将当前项目 warnings-only 基线从 `19` 条降到 `9` 条,
并用 focused schema generator tests 验证 50 个用例通过
- `RP-032` 已完成 `AutoRegisterModuleGeneratorTests` 的 3 个 `MA0051` 收口:通过提取类级常量承载测试源码与快照,保持
生成文件名、断言路径与源生成输出不变;`GFramework.SourceGenerators.Tests` warnings-only 基线由 `43` 降至 `40`
- `RP-021` 使用 `$gframework-pr-review` 复核当前分支 PR #269 后,修复仍在本地成立的 4 个项:将
`CqrsHandlerRegistryGenerator` 拆分为职责清晰的 partial 文件、为 `ContextAwareGenerator` 生成字段增加稳定前缀并补上
`SetContextProvider` 的运行时 null 校验、为 `Option<T>` 补齐 `<remarks>`,并新增字段重名场景的生成器快照测试

View File

@ -1,5 +1,34 @@
# Analyzer Warning Reduction 追踪
## 2026-04-23 — RP-032
### 阶段:`AutoRegisterModuleGeneratorTests.cs` `MA0051` 收口RP-032
- 启动复核:
- 按 `gframework-boot` 流程恢复当前 worktree读取 `AGENTS.md``.ai/environment/tools.ai.yaml`
`ai-plan/public/README.md` 与 active topic 跟踪文件,确认当前分支 `fix/analyzer-warning-reduction-batch`
仍映射到 `analyzer-warning-reduction`
- 先用
`dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release -t:Rebuild --no-restore --disable-build-servers -m:1 -p:UseSharedCompilation=false -p:RestoreFallbackFolders="" -nologo -clp:"Summary;WarningsOnly"`
复核当前 `MA0051` 热点,确认 `AutoRegisterModuleGeneratorTests.cs` 仍有 `3` 个超长方法,适合作为单文件低风险写集
- 决策:
- 保持 `AutoRegisterModuleGeneratorTests` 的测试输入、生成文件名、快照文本与断言结构不变,只收敛方法长度
- 采用“提取类级常量承载大段测试源码与期望输出”的方式,避免引入新的共享 helper 或改变场景组装顺序
- 验证阶段改为串行执行 build/test避免和同项目并行运行时拿到不完整 `bin/Release` 输出
- 实施调整:
- 为 `AutoRegisterModuleGeneratorTests` 补齐测试类 XML 文档
- 将 3 个长测试方法中的源码与期望快照提取为类级 `const string`,保留原有生成文件名与断言目标
- 将仅转发 `GeneratorTest.RunAsync(...)` 的两个异步测试改为直接返回 `Task`
- 验证结果:
- `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release -t:Rebuild --no-restore --disable-build-servers -m:1 -p:UseSharedCompilation=false -p:RestoreFallbackFolders="" -nologo -clp:"Summary;WarningsOnly"`
- 结果:`40 Warning(s)``0 Error(s)``AutoRegisterModuleGeneratorTests.cs` 已不再出现在 `MA0051` 列表中
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --no-restore --disable-build-servers --filter FullyQualifiedName~AutoRegisterModuleGeneratorTests -m:1 -p:RestoreFallbackFolders="" -nologo`
- 结果:`3 Passed``0 Failed`
- 下一步建议:
- 若继续压缩 `GFramework.SourceGenerators.Tests``MA0051`,优先处理仅剩单个超长方法的
`GFramework.SourceGenerators.Tests/Core/GeneratorSnapshotTest.cs`
- 若希望单次继续多降几条 warning则改选 `ContextGetGeneratorTests.cs`,但需要接受更大的单文件写集
## 2026-04-23 — RP-031
### 阶段:`LoggerGeneratorSnapshotTests.cs` `MA0051` 收口RP-031