mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
test(cqrs): 补齐 stream invoker gate 回归
- 补充 stream invoker descriptor 与 descriptor entry 缺失时整体跳过 provider 元数据的生成器回归 - 优化测试辅助重命名逻辑,精确模拟 metadata name 缺失而不破坏其余合同编译 - 更新 cqrs-rewrite 跟踪与追踪,记录 PR #307 follow-up 的恢复点和验证结果
This commit is contained in:
parent
83528742bb
commit
9296def108
@ -3156,6 +3156,58 @@ public class CqrsHandlerRegistryGeneratorTests
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当 runtime 缺少 <c>CqrsStreamInvokerDescriptor</c> 时,
|
||||
/// 生成器不会继续发射依赖描述符类型的 stream provider 元数据。
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Type()
|
||||
{
|
||||
var source = RenameTypeIdentifier(
|
||||
StreamInvokerProviderSource,
|
||||
"CqrsStreamInvokerDescriptor",
|
||||
"MissingCqrsStreamInvokerDescriptor");
|
||||
var generatedSource = RunGenerator(source);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(
|
||||
generatedSource,
|
||||
Does.Contain(
|
||||
"internal sealed class __GFrameworkGeneratedCqrsHandlerRegistry : global::GFramework.Cqrs.ICqrsHandlerRegistry"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("ICqrsStreamInvokerProvider"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("IEnumeratesCqrsStreamInvokerDescriptors"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("CqrsStreamInvokerDescriptorEntry("));
|
||||
Assert.That(generatedSource, Does.Not.Contain("InvokeStreamHandler0"));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当 runtime 缺少 <c>CqrsStreamInvokerDescriptorEntry</c> 时,
|
||||
/// 生成器不会继续保留 stream provider 的枚举接口或静态 invoker 元数据。
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Entry_Type()
|
||||
{
|
||||
var source = RenameTypeIdentifier(
|
||||
StreamInvokerProviderSource,
|
||||
"CqrsStreamInvokerDescriptorEntry",
|
||||
"MissingCqrsStreamInvokerDescriptorEntry");
|
||||
var generatedSource = RunGenerator(source);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(
|
||||
generatedSource,
|
||||
Does.Contain(
|
||||
"internal sealed class __GFrameworkGeneratedCqrsHandlerRegistry : global::GFramework.Cqrs.ICqrsHandlerRegistry"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("ICqrsStreamInvokerProvider"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("IEnumeratesCqrsStreamInvokerDescriptors"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("CqrsStreamInvokerDescriptorEntry("));
|
||||
Assert.That(generatedSource, Does.Not.Contain("InvokeStreamHandler0"));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当 stream handler 仍需走 precise reflected 注册时,
|
||||
/// 生成器即使检测到 stream invoker provider runtime 合同,也不会错误发射无法稳定表达隐藏请求/响应类型的 provider 元数据。
|
||||
@ -3258,6 +3310,66 @@ public class CqrsHandlerRegistryGeneratorTests
|
||||
return source.Remove(startIndex, endIndex - startIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅按完整类型标识符重命名测试输入中的合同类型,避免误伤共享前缀的其他类型名。
|
||||
/// </summary>
|
||||
/// <param name="source">原始测试源码。</param>
|
||||
/// <param name="originalTypeName">原始合同类型名。</param>
|
||||
/// <param name="replacementTypeName">替换后的占位类型名。</param>
|
||||
/// <returns>完成精确类型重命名后的源码。</returns>
|
||||
private static string RenameTypeIdentifier(string source, string originalTypeName, string replacementTypeName)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(source);
|
||||
ArgumentNullException.ThrowIfNull(originalTypeName);
|
||||
ArgumentNullException.ThrowIfNull(replacementTypeName);
|
||||
|
||||
var result = new System.Text.StringBuilder(source.Length);
|
||||
var currentIndex = 0;
|
||||
|
||||
while (currentIndex < source.Length)
|
||||
{
|
||||
var matchIndex = source.IndexOf(originalTypeName, currentIndex, StringComparison.Ordinal);
|
||||
if (matchIndex < 0)
|
||||
{
|
||||
result.Append(source, currentIndex, source.Length - currentIndex);
|
||||
break;
|
||||
}
|
||||
|
||||
result.Append(source, currentIndex, matchIndex - currentIndex);
|
||||
|
||||
if (IsIdentifierBoundary(source, matchIndex - 1) &&
|
||||
IsIdentifierBoundary(source, matchIndex + originalTypeName.Length))
|
||||
{
|
||||
result.Append(replacementTypeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Append(originalTypeName);
|
||||
}
|
||||
|
||||
currentIndex = matchIndex + originalTypeName.Length;
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断给定位置是否位于 C# 标识符边界,用于避免把共享前缀的其他类型名一并改写。
|
||||
/// </summary>
|
||||
/// <param name="source">待检查的完整源码。</param>
|
||||
/// <param name="index">边界位置;允许落在字符串两端之外。</param>
|
||||
/// <returns>若当前位置不在标识符内部,则返回 <see langword="true" />。</returns>
|
||||
private static bool IsIdentifierBoundary(string source, int index)
|
||||
{
|
||||
if (index < 0 || index >= source.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var character = source[index];
|
||||
return !char.IsLetterOrDigit(character) && character != '_';
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统计生成源码中某个固定片段的出现次数,用于锁定程序集级 fallback 特性的发射个数。
|
||||
/// </summary>
|
||||
|
||||
@ -7,7 +7,7 @@ CQRS 迁移与收敛。
|
||||
|
||||
## 当前恢复点
|
||||
|
||||
- 恢复点编号:`CQRS-REWRITE-RP-075`
|
||||
- 恢复点编号:`CQRS-REWRITE-RP-076`
|
||||
- 当前阶段:`Phase 8`
|
||||
- 当前焦点:
|
||||
- 已完成一轮 `CQRS vs Mediator` 只读评估归档,结论已沉淀到 `archive/todos/cqrs-vs-mediator-assessment-rp063.md`
|
||||
@ -74,6 +74,9 @@ CQRS 迁移与收敛。
|
||||
- 已完成一轮 invoker provider gate 合同回归:
|
||||
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 现新增四条回归,分别锁定 request / stream 在缺少 `ICqrsRequestInvokerProvider`、`IEnumeratesCqrsRequestInvokerDescriptors`、`ICqrsStreamInvokerProvider` 或 `IEnumeratesCqrsStreamInvokerDescriptors` 时,generator 都会整体跳过对应 provider 元数据发射
|
||||
- 本轮最初采用固定源码片段替换来裁剪测试输入,但因三引号字符串缩进差异导致 helper 过脆;当前已收敛为按稳定起止标记移除源码块的 `RemoveBlock(...)` helper,避免 gate 回归依赖精确空格对齐
|
||||
- 已完成一轮 stream invoker descriptor gate 合同补强:
|
||||
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 现额外新增两条 stream gate 回归,分别锁定 runtime 缺少 `CqrsStreamInvokerDescriptor` 或 `CqrsStreamInvokerDescriptorEntry` 时,generator 同样会整体跳过 stream provider 元数据发射
|
||||
- 本轮补强直接对应 `CqrsHandlerRegistryGenerator` 中 `supportsStreamInvokerProvider` 的四项合同探测,避免此前只覆盖 provider / enumerator 缺失而漏掉 descriptor 两条分支
|
||||
- 已完成一轮 generated invoker provider runtime 失败边界修复:
|
||||
- `GFramework.Cqrs.Tests/Cqrs/CqrsGeneratedRequestInvokerProviderTests.cs` 现新增 request / stream 两组 `non-static invoker` 与 `incompatible invoker` 回归,锁定 dispatcher 在首次绑定阶段会显式拒绝非法 generated descriptor
|
||||
- `GFramework.Cqrs/Internal/CqrsDispatcher.cs` 现把 `Delegate.CreateDelegate(...)` 抛出的 `ArgumentException` 统一包装为已有 XML 文档承诺的 `InvalidOperationException`,保持 request / stream 两条错误消息语义一致
|
||||
|
||||
@ -2,6 +2,30 @@
|
||||
|
||||
## 2026-04-30
|
||||
|
||||
### 阶段:PR #307 stream invoker gate 回归补强(CQRS-REWRITE-RP-076)
|
||||
|
||||
- 继续沿用 `$gframework-pr-review` 对 `PR #307` 的 latest-head review triage,只处理本地仍成立且写集可控的 generator regression gap
|
||||
- 主线程复核 `GFramework.Cqrs.SourceGenerators/Cqrs/CqrsHandlerRegistryGenerator.cs:88-92` 后确认:`supportsStreamInvokerProvider` 依赖四项合同,但现有测试只覆盖 `ICqrsStreamInvokerProvider` 与 `IEnumeratesCqrsStreamInvokerDescriptors` 缺失分支,确实遗漏 `CqrsStreamInvokerDescriptor` / `CqrsStreamInvokerDescriptorEntry`
|
||||
- 本轮实现收敛:
|
||||
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 新增两条 `RemoveBlock(...)` 回归,分别移除 `CqrsStreamInvokerDescriptor` 与 `CqrsStreamInvokerDescriptorEntry` 合同定义
|
||||
- 新回归继续锁定统一结果:当 stream invoker runtime 合同四者缺一时,generated registry 不会残留 provider 接口、descriptor entry 枚举或静态 invoker 桥接
|
||||
- active tracking 已把恢复点推进到 `RP-076`,避免 PR review 结论只体现在测试代码里
|
||||
|
||||
### 验证(RP-076)
|
||||
|
||||
- `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release`
|
||||
- 结果:通过,`0 warning / 0 error`
|
||||
- 备注:首轮并发跑 build/test 时出现过 `MSB3248` / `MSB3026` 输出文件占用噪音;按仓库规则改为串行复核后,本轮 authoritative build 结果为干净通过
|
||||
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Enumerator|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Entry_Type|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"`
|
||||
- 结果:通过,`5/5` passed
|
||||
- 备注:新增两条 descriptor gate 回归与既有 stream happy-path 一并通过,确认 `supportsStreamInvokerProvider` 的四项合同缺一不可
|
||||
|
||||
### 当前下一步(RP-076)
|
||||
|
||||
1. 提交本轮 `PR #307` stream gate 合同补强与 `ai-plan` 恢复点更新
|
||||
2. 后续若继续处理 review,优先清点 request 侧是否也存在同构遗漏,再决定是否追加同批对称测试
|
||||
3. 保持忽略工作区里无关的 `.gitignore` 本地改动,不把它混入本轮提交
|
||||
|
||||
### 阶段:PR #307 review follow-up 收敛(CQRS-REWRITE-RP-075)
|
||||
|
||||
- 在 `RP-074` 后继续沿用 `gframework-batch-boot 50` 的低风险切片策略,本轮只处理 `$gframework-pr-review` 对当前 `PR #307` 仍然成立的本地问题
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user