mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-08 01:24:31 +08:00
refactor(sourcegenerators-tests): 收敛 SchemaConfigGeneratorTests 结构性警告
- 重构 SchemaConfigGeneratorTests 的共享 runtime fixture 与 generated-source helper,清理当前 MA0051 长方法 - 补充 project-level registration catalog 的专用契约断言,保持生成输出验证语义不变 - 更新 analyzer-warning-reduction 的 tracking 与 trace,记录基线降至 15 条并切换下一步恢复点
This commit is contained in:
parent
aa879d2c9a
commit
2915624e60
@ -6,6 +6,67 @@ namespace GFramework.SourceGenerators.Tests.Config;
|
||||
[TestFixture]
|
||||
public class SchemaConfigGeneratorTests
|
||||
{
|
||||
// Keep shared fixture sources at class scope so MA0051 reduction does not change generator inputs.
|
||||
private const string DummySource = """
|
||||
namespace TestApp
|
||||
{
|
||||
public sealed class Dummy
|
||||
{
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
// These runtime contracts mirror the minimal consumer surface the generator expects when emitting registration helpers.
|
||||
private const string ConfigRuntimeSource = """
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GFramework.Game.Abstractions.Config
|
||||
{
|
||||
public interface IConfigTable
|
||||
{
|
||||
Type KeyType { get; }
|
||||
Type ValueType { get; }
|
||||
int Count { get; }
|
||||
}
|
||||
|
||||
public interface IConfigTable<TKey, TValue> : IConfigTable
|
||||
where TKey : notnull
|
||||
{
|
||||
TValue Get(TKey key);
|
||||
bool TryGet(TKey key, out TValue? value);
|
||||
bool ContainsKey(TKey key);
|
||||
IReadOnlyCollection<TValue> All();
|
||||
}
|
||||
|
||||
public interface IConfigRegistry
|
||||
{
|
||||
IConfigTable<TKey, TValue> GetTable<TKey, TValue>(string name)
|
||||
where TKey : notnull;
|
||||
|
||||
bool TryGetTable<TKey, TValue>(string name, out IConfigTable<TKey, TValue>? table)
|
||||
where TKey : notnull;
|
||||
}
|
||||
}
|
||||
|
||||
namespace GFramework.Game.Config
|
||||
{
|
||||
public sealed class YamlConfigLoader
|
||||
{
|
||||
public YamlConfigLoader RegisterTable<TKey, TValue>(
|
||||
string tableName,
|
||||
string relativePath,
|
||||
string schemaRelativePath,
|
||||
Func<TValue, TKey> keySelector,
|
||||
IEqualityComparer<TKey>? comparer = null)
|
||||
where TKey : notnull
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
/// <summary>
|
||||
/// 验证 AdditionalFiles 读取被取消时会向上传播取消,而不是伪造成 schema 诊断。
|
||||
/// </summary>
|
||||
@ -1404,15 +1465,6 @@ public class SchemaConfigGeneratorTests
|
||||
[Test]
|
||||
public void Run_Should_Write_IfThenElse_Constraint_Into_Generated_Documentation()
|
||||
{
|
||||
const string source = """
|
||||
namespace TestApp
|
||||
{
|
||||
public sealed class Dummy
|
||||
{
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
const string schema = """
|
||||
{
|
||||
"type": "object",
|
||||
@ -1454,19 +1506,9 @@ public class SchemaConfigGeneratorTests
|
||||
}
|
||||
""";
|
||||
|
||||
var result = SchemaGeneratorTestDriver.Run(
|
||||
source,
|
||||
var generatedSources = RunAndCollectGeneratedSources(
|
||||
DummySource,
|
||||
("monster.schema.json", schema));
|
||||
|
||||
var generatedSources = result.Results
|
||||
.Single()
|
||||
.GeneratedSources
|
||||
.ToDictionary(
|
||||
static sourceResult => sourceResult.HintName,
|
||||
static sourceResult => sourceResult.SourceText.ToString(),
|
||||
StringComparer.Ordinal);
|
||||
|
||||
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
|
||||
Assert.That(
|
||||
generatedSources["MonsterConfig.g.cs"],
|
||||
Does.Contain(
|
||||
@ -2024,56 +2066,6 @@ public class SchemaConfigGeneratorTests
|
||||
[Test]
|
||||
public void Run_Should_Use_Custom_Config_Path_Metadata_For_Generated_Registration()
|
||||
{
|
||||
const string source = """
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GFramework.Game.Abstractions.Config
|
||||
{
|
||||
public interface IConfigTable
|
||||
{
|
||||
Type KeyType { get; }
|
||||
Type ValueType { get; }
|
||||
int Count { get; }
|
||||
}
|
||||
|
||||
public interface IConfigTable<TKey, TValue> : IConfigTable
|
||||
where TKey : notnull
|
||||
{
|
||||
TValue Get(TKey key);
|
||||
bool TryGet(TKey key, out TValue? value);
|
||||
bool ContainsKey(TKey key);
|
||||
IReadOnlyCollection<TValue> All();
|
||||
}
|
||||
|
||||
public interface IConfigRegistry
|
||||
{
|
||||
IConfigTable<TKey, TValue> GetTable<TKey, TValue>(string name)
|
||||
where TKey : notnull;
|
||||
|
||||
bool TryGetTable<TKey, TValue>(string name, out IConfigTable<TKey, TValue>? table)
|
||||
where TKey : notnull;
|
||||
}
|
||||
}
|
||||
|
||||
namespace GFramework.Game.Config
|
||||
{
|
||||
public sealed class YamlConfigLoader
|
||||
{
|
||||
public YamlConfigLoader RegisterTable<TKey, TValue>(
|
||||
string tableName,
|
||||
string relativePath,
|
||||
string schemaRelativePath,
|
||||
Func<TValue, TKey> keySelector,
|
||||
IEqualityComparer<TKey>? comparer = null)
|
||||
where TKey : notnull
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
const string schema = """
|
||||
{
|
||||
"type": "object",
|
||||
@ -2086,19 +2078,9 @@ public class SchemaConfigGeneratorTests
|
||||
}
|
||||
""";
|
||||
|
||||
var result = SchemaGeneratorTestDriver.Run(
|
||||
source,
|
||||
var generatedSources = RunAndCollectGeneratedSources(
|
||||
ConfigRuntimeSource,
|
||||
("monster.schema.json", schema));
|
||||
|
||||
var generatedSources = result.Results
|
||||
.Single()
|
||||
.GeneratedSources
|
||||
.ToDictionary(
|
||||
static sourceResult => sourceResult.HintName,
|
||||
static sourceResult => sourceResult.SourceText.ToString(),
|
||||
StringComparer.Ordinal);
|
||||
|
||||
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
|
||||
Assert.That(generatedSources["MonsterConfigBindings.g.cs"],
|
||||
Does.Contain("public const string ConfigRelativePath = \"config/monster\";"));
|
||||
Assert.That(generatedSources["MonsterConfigBindings.g.cs"], Does.Contain("Metadata.ConfigRelativePath,"));
|
||||
@ -2126,56 +2108,6 @@ public class SchemaConfigGeneratorTests
|
||||
[Test]
|
||||
public void Run_Should_Skip_Runtime_Null_Keys_When_Generating_Indexed_Lookups()
|
||||
{
|
||||
const string source = """
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GFramework.Game.Abstractions.Config
|
||||
{
|
||||
public interface IConfigTable
|
||||
{
|
||||
Type KeyType { get; }
|
||||
Type ValueType { get; }
|
||||
int Count { get; }
|
||||
}
|
||||
|
||||
public interface IConfigTable<TKey, TValue> : IConfigTable
|
||||
where TKey : notnull
|
||||
{
|
||||
TValue Get(TKey key);
|
||||
bool TryGet(TKey key, out TValue? value);
|
||||
bool ContainsKey(TKey key);
|
||||
IReadOnlyCollection<TValue> All();
|
||||
}
|
||||
|
||||
public interface IConfigRegistry
|
||||
{
|
||||
IConfigTable<TKey, TValue> GetTable<TKey, TValue>(string name)
|
||||
where TKey : notnull;
|
||||
|
||||
bool TryGetTable<TKey, TValue>(string name, out IConfigTable<TKey, TValue>? table)
|
||||
where TKey : notnull;
|
||||
}
|
||||
}
|
||||
|
||||
namespace GFramework.Game.Config
|
||||
{
|
||||
public sealed class YamlConfigLoader
|
||||
{
|
||||
public YamlConfigLoader RegisterTable<TKey, TValue>(
|
||||
string tableName,
|
||||
string relativePath,
|
||||
string schemaRelativePath,
|
||||
Func<TValue, TKey> keySelector,
|
||||
IEqualityComparer<TKey>? comparer = null)
|
||||
where TKey : notnull
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
const string schema = """
|
||||
{
|
||||
"type": "object",
|
||||
@ -2190,19 +2122,9 @@ public class SchemaConfigGeneratorTests
|
||||
}
|
||||
""";
|
||||
|
||||
var result = SchemaGeneratorTestDriver.Run(
|
||||
source,
|
||||
var generatedSources = RunAndCollectGeneratedSources(
|
||||
ConfigRuntimeSource,
|
||||
("monster.schema.json", schema));
|
||||
|
||||
var generatedSources = result.Results
|
||||
.Single()
|
||||
.GeneratedSources
|
||||
.ToDictionary(
|
||||
static sourceResult => sourceResult.HintName,
|
||||
static sourceResult => sourceResult.SourceText.ToString(),
|
||||
StringComparer.Ordinal);
|
||||
|
||||
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
|
||||
Assert.That(generatedSources["MonsterTable.g.cs"], Does.Contain("if (key is null)"));
|
||||
Assert.That(generatedSources["MonsterTable.g.cs"],
|
||||
Does.Contain("Throwing here would permanently poison the cached index for this wrapper instance."));
|
||||
@ -2391,56 +2313,6 @@ public class SchemaConfigGeneratorTests
|
||||
[Test]
|
||||
public void Run_Should_Allow_Lookup_Index_For_Direct_Root_Property_With_Dotted_Schema_Key()
|
||||
{
|
||||
const string source = """
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GFramework.Game.Abstractions.Config
|
||||
{
|
||||
public interface IConfigTable
|
||||
{
|
||||
Type KeyType { get; }
|
||||
Type ValueType { get; }
|
||||
int Count { get; }
|
||||
}
|
||||
|
||||
public interface IConfigTable<TKey, TValue> : IConfigTable
|
||||
where TKey : notnull
|
||||
{
|
||||
TValue Get(TKey key);
|
||||
bool TryGet(TKey key, out TValue? value);
|
||||
bool ContainsKey(TKey key);
|
||||
IReadOnlyCollection<TValue> All();
|
||||
}
|
||||
|
||||
public interface IConfigRegistry
|
||||
{
|
||||
IConfigTable<TKey, TValue> GetTable<TKey, TValue>(string name)
|
||||
where TKey : notnull;
|
||||
|
||||
bool TryGetTable<TKey, TValue>(string name, out IConfigTable<TKey, TValue>? table)
|
||||
where TKey : notnull;
|
||||
}
|
||||
}
|
||||
|
||||
namespace GFramework.Game.Config
|
||||
{
|
||||
public sealed class YamlConfigLoader
|
||||
{
|
||||
public YamlConfigLoader RegisterTable<TKey, TValue>(
|
||||
string tableName,
|
||||
string relativePath,
|
||||
string schemaRelativePath,
|
||||
Func<TValue, TKey> keySelector,
|
||||
IEqualityComparer<TKey>? comparer = null)
|
||||
where TKey : notnull
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
const string schema = """
|
||||
{
|
||||
"type": "object",
|
||||
@ -2455,19 +2327,9 @@ public class SchemaConfigGeneratorTests
|
||||
}
|
||||
""";
|
||||
|
||||
var result = SchemaGeneratorTestDriver.Run(
|
||||
source,
|
||||
var generatedSources = RunAndCollectGeneratedSources(
|
||||
ConfigRuntimeSource,
|
||||
("monster.schema.json", schema));
|
||||
|
||||
var generatedSources = result.Results
|
||||
.Single()
|
||||
.GeneratedSources
|
||||
.ToDictionary(
|
||||
static sourceResult => sourceResult.HintName,
|
||||
static sourceResult => sourceResult.SourceText.ToString(),
|
||||
StringComparer.Ordinal);
|
||||
|
||||
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
|
||||
Assert.That(generatedSources["MonsterTable.g.cs"], Does.Contain("FindByDisplayName(string value)"));
|
||||
Assert.That(generatedSources["MonsterTable.g.cs"], Does.Contain("_displayNameIndex"));
|
||||
}
|
||||
@ -2478,56 +2340,6 @@ public class SchemaConfigGeneratorTests
|
||||
[Test]
|
||||
public void Run_Should_Assign_Globally_Unique_Reference_Metadata_Member_Names()
|
||||
{
|
||||
const string source = """
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GFramework.Game.Abstractions.Config
|
||||
{
|
||||
public interface IConfigTable
|
||||
{
|
||||
Type KeyType { get; }
|
||||
Type ValueType { get; }
|
||||
int Count { get; }
|
||||
}
|
||||
|
||||
public interface IConfigTable<TKey, TValue> : IConfigTable
|
||||
where TKey : notnull
|
||||
{
|
||||
TValue Get(TKey key);
|
||||
bool TryGet(TKey key, out TValue? value);
|
||||
bool ContainsKey(TKey key);
|
||||
IReadOnlyCollection<TValue> All();
|
||||
}
|
||||
|
||||
public interface IConfigRegistry
|
||||
{
|
||||
IConfigTable<TKey, TValue> GetTable<TKey, TValue>(string name)
|
||||
where TKey : notnull;
|
||||
|
||||
bool TryGetTable<TKey, TValue>(string name, out IConfigTable<TKey, TValue>? table)
|
||||
where TKey : notnull;
|
||||
}
|
||||
}
|
||||
|
||||
namespace GFramework.Game.Config
|
||||
{
|
||||
public sealed class YamlConfigLoader
|
||||
{
|
||||
public YamlConfigLoader RegisterTable<TKey, TValue>(
|
||||
string tableName,
|
||||
string relativePath,
|
||||
string schemaRelativePath,
|
||||
Func<TValue, TKey> keySelector,
|
||||
IEqualityComparer<TKey>? comparer = null)
|
||||
where TKey : notnull
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
const string schema = """
|
||||
{
|
||||
"type": "object",
|
||||
@ -2561,19 +2373,9 @@ public class SchemaConfigGeneratorTests
|
||||
}
|
||||
""";
|
||||
|
||||
var result = SchemaGeneratorTestDriver.Run(
|
||||
source,
|
||||
var generatedSources = RunAndCollectGeneratedSources(
|
||||
ConfigRuntimeSource,
|
||||
("monster.schema.json", schema));
|
||||
|
||||
var generatedSources = result.Results
|
||||
.Single()
|
||||
.GeneratedSources
|
||||
.ToDictionary(
|
||||
static sourceResult => sourceResult.HintName,
|
||||
static sourceResult => sourceResult.SourceText.ToString(),
|
||||
StringComparer.Ordinal);
|
||||
|
||||
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
|
||||
Assert.That(generatedSources.TryGetValue("MonsterConfigBindings.g.cs", out var bindingsSource), Is.True);
|
||||
Assert.That(bindingsSource, Does.Contain("public static readonly ReferenceMetadata DropItems ="));
|
||||
Assert.That(bindingsSource, Does.Contain("public static readonly ReferenceMetadata DropItems1 ="));
|
||||
@ -2588,56 +2390,6 @@ public class SchemaConfigGeneratorTests
|
||||
[Test]
|
||||
public void Run_Should_Generate_Query_Helpers_Only_For_Top_Level_Scalar_Properties()
|
||||
{
|
||||
const string source = """
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GFramework.Game.Abstractions.Config
|
||||
{
|
||||
public interface IConfigTable
|
||||
{
|
||||
Type KeyType { get; }
|
||||
Type ValueType { get; }
|
||||
int Count { get; }
|
||||
}
|
||||
|
||||
public interface IConfigTable<TKey, TValue> : IConfigTable
|
||||
where TKey : notnull
|
||||
{
|
||||
TValue Get(TKey key);
|
||||
bool TryGet(TKey key, out TValue? value);
|
||||
bool ContainsKey(TKey key);
|
||||
IReadOnlyCollection<TValue> All();
|
||||
}
|
||||
|
||||
public interface IConfigRegistry
|
||||
{
|
||||
IConfigTable<TKey, TValue> GetTable<TKey, TValue>(string name)
|
||||
where TKey : notnull;
|
||||
|
||||
bool TryGetTable<TKey, TValue>(string name, out IConfigTable<TKey, TValue>? table)
|
||||
where TKey : notnull;
|
||||
}
|
||||
}
|
||||
|
||||
namespace GFramework.Game.Config
|
||||
{
|
||||
public sealed class YamlConfigLoader
|
||||
{
|
||||
public YamlConfigLoader RegisterTable<TKey, TValue>(
|
||||
string tableName,
|
||||
string relativePath,
|
||||
string schemaRelativePath,
|
||||
Func<TValue, TKey> keySelector,
|
||||
IEqualityComparer<TKey>? comparer = null)
|
||||
where TKey : notnull
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
const string schema = """
|
||||
{
|
||||
"type": "object",
|
||||
@ -2667,19 +2419,9 @@ public class SchemaConfigGeneratorTests
|
||||
}
|
||||
""";
|
||||
|
||||
var result = SchemaGeneratorTestDriver.Run(
|
||||
source,
|
||||
var generatedSources = RunAndCollectGeneratedSources(
|
||||
ConfigRuntimeSource,
|
||||
("monster.schema.json", schema));
|
||||
|
||||
var generatedSources = result.Results
|
||||
.Single()
|
||||
.GeneratedSources
|
||||
.ToDictionary(
|
||||
static sourceResult => sourceResult.HintName,
|
||||
static sourceResult => sourceResult.SourceText.ToString(),
|
||||
StringComparer.Ordinal);
|
||||
|
||||
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
|
||||
Assert.That(generatedSources.TryGetValue("MonsterTable.g.cs", out var tableSource), Is.True);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
@ -2713,56 +2455,6 @@ public class SchemaConfigGeneratorTests
|
||||
[Test]
|
||||
public void Run_Should_Generate_Project_Level_Registration_Catalog()
|
||||
{
|
||||
const string source = """
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GFramework.Game.Abstractions.Config
|
||||
{
|
||||
public interface IConfigTable
|
||||
{
|
||||
Type KeyType { get; }
|
||||
Type ValueType { get; }
|
||||
int Count { get; }
|
||||
}
|
||||
|
||||
public interface IConfigTable<TKey, TValue> : IConfigTable
|
||||
where TKey : notnull
|
||||
{
|
||||
TValue Get(TKey key);
|
||||
bool TryGet(TKey key, out TValue? value);
|
||||
bool ContainsKey(TKey key);
|
||||
IReadOnlyCollection<TValue> All();
|
||||
}
|
||||
|
||||
public interface IConfigRegistry
|
||||
{
|
||||
IConfigTable<TKey, TValue> GetTable<TKey, TValue>(string name)
|
||||
where TKey : notnull;
|
||||
|
||||
bool TryGetTable<TKey, TValue>(string name, out IConfigTable<TKey, TValue>? table)
|
||||
where TKey : notnull;
|
||||
}
|
||||
}
|
||||
|
||||
namespace GFramework.Game.Config
|
||||
{
|
||||
public sealed class YamlConfigLoader
|
||||
{
|
||||
public YamlConfigLoader RegisterTable<TKey, TValue>(
|
||||
string tableName,
|
||||
string relativePath,
|
||||
string schemaRelativePath,
|
||||
Func<TValue, TKey> keySelector,
|
||||
IEqualityComparer<TKey>? comparer = null)
|
||||
where TKey : notnull
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
const string monsterSchema = """
|
||||
{
|
||||
"type": "object",
|
||||
@ -2785,22 +2477,24 @@ public class SchemaConfigGeneratorTests
|
||||
}
|
||||
""";
|
||||
|
||||
var result = SchemaGeneratorTestDriver.Run(
|
||||
source,
|
||||
var generatedSources = RunAndCollectGeneratedSources(
|
||||
ConfigRuntimeSource,
|
||||
("monster.schema.json", monsterSchema),
|
||||
("item.schema.json", itemSchema));
|
||||
if (!generatedSources.TryGetValue("GeneratedConfigCatalog.g.cs", out var catalogSource))
|
||||
{
|
||||
Assert.Fail("Expected GeneratedConfigCatalog.g.cs to be generated.");
|
||||
}
|
||||
|
||||
var generatedSources = result.Results
|
||||
.Single()
|
||||
.GeneratedSources
|
||||
.ToDictionary(
|
||||
static sourceResult => sourceResult.HintName,
|
||||
static sourceResult => sourceResult.SourceText.ToString(),
|
||||
StringComparer.Ordinal);
|
||||
|
||||
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
|
||||
Assert.That(generatedSources.TryGetValue("GeneratedConfigCatalog.g.cs", out var catalogSource), Is.True);
|
||||
AssertGeneratedRegistrationCatalogContract(catalogSource!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断言聚合注册目录保留筛选选项、比较器透传和按条件注册的生成契约。
|
||||
/// </summary>
|
||||
/// <param name="catalogSource">`GeneratedConfigCatalog.g.cs` 的生成源码。</param>
|
||||
private static void AssertGeneratedRegistrationCatalogContract(string catalogSource)
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(catalogSource, Does.Contain("public static class GeneratedConfigCatalog"));
|
||||
@ -2852,4 +2546,24 @@ public class SchemaConfigGeneratorTests
|
||||
Assert.That(catalogSource, Does.Contain("private static bool MatchesOptionalAllowList("));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行 schema 生成器并收集生成输出,同时断言本次场景不产生诊断。
|
||||
/// </summary>
|
||||
/// <param name="source">测试输入源码。</param>
|
||||
/// <param name="additionalFiles">参与本次生成的 schema 文件集合。</param>
|
||||
/// <returns>按 HintName 索引的生成源码字典。</returns>
|
||||
private static global::System.Collections.Generic.IReadOnlyDictionary<string, string> RunAndCollectGeneratedSources(
|
||||
string source,
|
||||
params (string path, string content)[] additionalFiles)
|
||||
{
|
||||
var result = SchemaGeneratorTestDriver.Run(source, additionalFiles);
|
||||
var runResult = result.Results.Single();
|
||||
Assert.That(runResult.Diagnostics, Is.Empty);
|
||||
|
||||
return runResult.GeneratedSources.ToDictionary(
|
||||
static sourceResult => sourceResult.HintName,
|
||||
static sourceResult => sourceResult.SourceText.ToString(),
|
||||
StringComparer.Ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,9 +7,27 @@
|
||||
|
||||
## 当前恢复点
|
||||
|
||||
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-034`
|
||||
- 当前阶段:`Phase 34`
|
||||
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-036`
|
||||
- 当前阶段:`Phase 36`
|
||||
- 当前焦点:
|
||||
- 已完成 `GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs` 的 `MA0051` 收口:
|
||||
将共享 consumer runtime fixture 提取到类级常量,并把生成结果收集与 catalog 契约断言拆成小 helper,
|
||||
保持 schema 文本、断言语义与生成输出契约不变
|
||||
- 当前 `GFramework.SourceGenerators.Tests` Release warnings-only 基线已从 `22` 条降到 `15` 条;
|
||||
`SchemaConfigGeneratorTests.cs` 已不再出现在 `MA0051` 列表中,剩余热点全部集中在
|
||||
`CqrsHandlerRegistryGeneratorTests.cs`
|
||||
- 已完成 `SchemaConfigGeneratorTests` 定向验证:串行重跑 `50` 个用例全部通过;并确认先前并行 build/test
|
||||
触发的 `MSB3030` / `CS0006` 属于共享输出竞争噪音,不是代码回归
|
||||
- 已按 `gframework-boot` 重新恢复当前 worktree:确认分支 `fix/analyzer-warning-reduction-batch` 仍映射到
|
||||
`analyzer-warning-reduction`,且当前不存在 `ai-plan/private/` 私有恢复上下文
|
||||
- 已重新抓取当前分支关联的 PR #273 review 状态:PR 已处于 `CLOSED`,latest-head review 仍显示 `2` 条
|
||||
CodeRabbit open thread,但本地复核后 `GeneratorSnapshotTest` 的 snapshot 路径空值防御已显式改为
|
||||
`InvalidOperationException` 防御,`SchemaConfigGenerator` 的 `dependentSchemas` / `allOf` / conditional helper
|
||||
也已补齐 XML 文档,当前更像历史线程未随已关闭 PR 一起收敛
|
||||
- 已重新以 `GFramework.SourceGenerators.Tests` Release warnings-only build 复核当前 `MA0051` 热点:
|
||||
基线现为 `22` 条,且已不再落在 `GeneratorSnapshotTest`、`ContextRegistrationAnalyzerTests` 或
|
||||
`ContextGetGeneratorTests`,而是集中在 `CqrsHandlerRegistryGeneratorTests.cs`(`15` 条)与
|
||||
`SchemaConfigGeneratorTests.cs`(`7` 条)
|
||||
- 已完成 `GFramework.Core` 当前 `MA0016` / `MA0002` / `MA0015` / `MA0077` 低风险收口批次
|
||||
- 已复核 `net10.0` 下的 `MA0158` 基线:`GFramework.Core` / `GFramework.Cqrs` 当前共有 `16` 个 object lock
|
||||
建议点,属于跨 target 兼容性风险,不在本轮直接批量替换
|
||||
@ -124,6 +142,11 @@
|
||||
`40` 条,并通过 focused generator tests 保持输出契约不变
|
||||
- 已完成 `SchemaConfigGeneratorSnapshotTests` 的单文件 `MA0051` 收口;当前 `GFramework.SourceGenerators.Tests`
|
||||
Release build 基线已降到 `39` 条,并通过 focused snapshot test 保持生成输出契约不变
|
||||
- 已完成 `RP-035` 启动复核:确认 PR #273 已关闭、历史 open thread 暂无新的本地修复点,且
|
||||
`GFramework.SourceGenerators.Tests` 当前剩余 `MA0051` 已重排为 `CqrsHandlerRegistryGeneratorTests` /
|
||||
`SchemaConfigGeneratorTests` 两个测试写集
|
||||
- 已完成 `RP-036`:清空 `SchemaConfigGeneratorTests.cs` 当前 `MA0051`,并将
|
||||
`GFramework.SourceGenerators.Tests` Release warnings-only 基线进一步降到 `15` 条
|
||||
|
||||
## 当前活跃事实
|
||||
|
||||
@ -168,6 +191,12 @@
|
||||
生成文件名、断言路径与源生成输出不变;`GFramework.SourceGenerators.Tests` warnings-only 基线由 `43` 降至 `40`
|
||||
- `RP-033` 已完成 `SchemaConfigGeneratorSnapshotTests` 的 `MA0051` 收口:monster schema 运行时契约与 schema 输入已提取为
|
||||
类级常量,生成结果映射与快照目录解析已拆为小 helper;`GFramework.SourceGenerators.Tests` warnings-only 基线由 `40` 降至 `39`
|
||||
- `RP-035` 已完成启动级恢复核对:当前分支对应的 GitHub PR #273 已关闭,因此 remaining open thread 仅作为历史信号参考;
|
||||
下一轮应以本地 `warnings-only` build 的实时热点为主,而不是继续按已过时的 `GeneratorSnapshotTest` /
|
||||
`ContextRegistrationAnalyzerTests` 建议恢复
|
||||
- `RP-036` 已完成 `SchemaConfigGeneratorTests` 的单文件 `MA0051` 收口:共享 runtime fixture、
|
||||
generated-source 收集与 catalog 契约断言均已拆出 helper;当前测试项目剩余 `MA0051` 已全部收敛到
|
||||
`CqrsHandlerRegistryGeneratorTests`
|
||||
- `RP-021` 使用 `$gframework-pr-review` 复核当前分支 PR #269 后,修复仍在本地成立的 4 个项:将
|
||||
`CqrsHandlerRegistryGenerator` 拆分为职责清晰的 partial 文件、为 `ContextAwareGenerator` 生成字段增加稳定前缀并补上
|
||||
`SetContextProvider` 的运行时 null 校验、为 `Option<T>` 补齐 `<remarks>`,并新增字段重名场景的生成器快照测试
|
||||
@ -389,13 +418,27 @@
|
||||
- 结果:`39 Warning(s)`,`0 Error(s)`;`SchemaConfigGeneratorSnapshotTests.cs` 已不再出现在 `MA0051` 列表中
|
||||
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --no-build --disable-build-servers --filter FullyQualifiedName~SchemaConfigGeneratorSnapshotTests -m:1 -p:RestoreFallbackFolders="" -nologo`
|
||||
- 结果:`1 Passed`,`0 Failed`
|
||||
- `RP-035` 的验证结果:
|
||||
- `python3 .agents/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --json-output /tmp/current-pr-review.json`
|
||||
- 结果:成功定位当前分支关联的 `PR #273`;状态为 `CLOSED`,latest-head review threads 仍显示 `2` 条 open thread,
|
||||
test report 均为通过,MegaLinter 仅保留 docstring coverage / `dotnet-format` 历史信号
|
||||
- `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"`
|
||||
- 结果:`22 Warning(s)`,`0 Error(s)`;剩余 `MA0051` 全部集中在 `CqrsHandlerRegistryGeneratorTests.cs` 与
|
||||
`SchemaConfigGeneratorTests.cs`
|
||||
- `RP-036` 的验证结果:
|
||||
- `dotnet restore GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -p:RestoreFallbackFolders="" -nologo`
|
||||
- 结果:通过;刷新测试依赖输出,规避 `--no-build` 场景下的缺包噪音
|
||||
- `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"`
|
||||
- 结果:`15 Warning(s)`,`0 Error(s)`;`SchemaConfigGeneratorTests.cs` 已不再出现在 `MA0051` 列表中
|
||||
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --no-build --disable-build-servers --filter FullyQualifiedName~SchemaConfigGeneratorTests -m:1 -p:RestoreFallbackFolders="" -nologo`
|
||||
- 结果:`50 Passed`,`0 Failed`
|
||||
- active 跟踪文件只保留当前恢复点、活跃事实、风险与下一步,不再重复保存已完成阶段的长篇历史
|
||||
|
||||
## 下一步
|
||||
|
||||
1. 若要继续该主题,先读 active tracking,再按需展开历史归档中的 warning 热点与验证记录
|
||||
2. 下一轮优先继续 `GFramework.SourceGenerators.Tests` 的 `MA0051` 收口,先在 `GeneratorSnapshotTest`、
|
||||
`ContextRegistrationAnalyzerTests` 或 `ContextGetGeneratorTests` 中选择一个单写集推进,不再把已清零的 `MA0004` / `MA0048` 混回写集
|
||||
2. 下一轮优先继续 `GFramework.SourceGenerators.Tests` 的 `MA0051` 收口,并直接进入唯一剩余热点
|
||||
`CqrsHandlerRegistryGeneratorTests.cs`
|
||||
3. 若改回推进 `MA0158`,先设计 `net8.0` / `net9.0` / `net10.0` 多 target 条件编译方案,不直接批量替换共享源码中的
|
||||
`object` lock
|
||||
4. 若后续继续改动 `GFramework.Godot`,先修复该项目的 Linux 侧 restore 资产,再补跑独立 build
|
||||
|
||||
@ -1,5 +1,60 @@
|
||||
# Analyzer Warning Reduction 追踪
|
||||
|
||||
## 2026-04-23 — RP-036
|
||||
|
||||
### 阶段:`SchemaConfigGeneratorTests.cs` `MA0051` 收口(RP-036)
|
||||
|
||||
- 启动复核:
|
||||
- 依据 `RP-035` 的恢复结论,选择低风险单写集 `GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs`
|
||||
继续推进,而不直接跳入剩余 warning 数量更多的 `CqrsHandlerRegistryGeneratorTests.cs`
|
||||
- 先用 `dotnet build ... -clp:"Summary;WarningsOnly"` 复核当前热点,确认该文件仍承担 `7` 条 `MA0051`
|
||||
- 决策:
|
||||
- 保持全部 schema 文本、断言字符串和生成文件名不变,只收敛测试方法结构
|
||||
- 将共享 consumer runtime fixture 提到类级常量,并把 generated-source 收集与 registration catalog 契约断言
|
||||
抽成 helper,避免重复内联样板把测试方法重新撑长
|
||||
- 继续避免并行运行同一测试项目的 build/test;该 worktree 下并发验证会触发 `MSB3030` / `CS0006` 级别的输出竞争噪音
|
||||
- 实施调整:
|
||||
- 为 `SchemaConfigGeneratorTests` 新增 `DummySource` 与 `ConfigRuntimeSource` 类级常量
|
||||
- 新增 `RunAndCollectGeneratedSources(...)` 与 `AssertGeneratedRegistrationCatalogContract(...)` helper
|
||||
- 将 `if/then/else` 文档、config path、lookup index、reference metadata、query helper 与 project-level catalog
|
||||
等长测试方法切换为复用共享 fixture / helper
|
||||
- 验证结果:
|
||||
- `dotnet restore GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -p:RestoreFallbackFolders="" -nologo`
|
||||
- 结果:通过
|
||||
- `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"`
|
||||
- 结果:`15 Warning(s)`,`0 Error(s)`;`SchemaConfigGeneratorTests.cs` 已不再出现在 `MA0051` 列表中
|
||||
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --no-build --disable-build-servers --filter FullyQualifiedName~SchemaConfigGeneratorTests -m:1 -p:RestoreFallbackFolders="" -nologo`
|
||||
- 结果:`50 Passed`,`0 Failed`
|
||||
- 下一步建议:
|
||||
- 继续进入 `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs`,这是当前项目唯一剩余 `MA0051` 热点
|
||||
- 若需要再次做定向测试,保持串行执行,避免把共享输出竞争误判成实现回退
|
||||
|
||||
## 2026-04-23 — RP-035
|
||||
|
||||
### 阶段:`boot` 恢复点重建与实时热点复核(RP-035)
|
||||
|
||||
- 启动复核:
|
||||
- 按 `gframework-boot` 流程读取 `AGENTS.md`、`.ai/environment/tools.ai.yaml`、`ai-plan/public/README.md`
|
||||
与 `analyzer-warning-reduction` active tracking / trace,确认当前 worktree `GFramework-analyzer`
|
||||
仍对应分支 `fix/analyzer-warning-reduction-batch`
|
||||
- 额外检查 `ai-plan/private/`,确认当前 worktree 没有私有恢复上下文需要合并
|
||||
- 使用 `gframework-pr-review` 脚本抓取当前分支关联 PR,确认 `PR #273` 已为 `CLOSED`
|
||||
- 决策:
|
||||
- 不再把已关闭 PR 上残留的 open thread 直接当作下一轮主驱动信号;先以当前本地代码和实时 build 结果判断问题是否仍成立
|
||||
- 将后续恢复入口从“继续看 `GeneratorSnapshotTest` / `ContextRegistrationAnalyzerTests`”切回
|
||||
“重新跑 `warnings-only` build 后按真实热点推进”
|
||||
- 现场结论:
|
||||
- `GeneratorSnapshotTest` 中关于 snapshot 路径的 `Path.GetDirectoryName(...)` 已改为显式空值防御,
|
||||
相关 CodeRabbit 线程更像历史残留
|
||||
- `SchemaConfigGenerator` 在 `dependentSchemas` / `allOf` / conditional schema 校验 helper 周围已经补齐 XML 文档,
|
||||
当前也没有新的本地缺口需要仅为关闭旧线程而继续改动
|
||||
- `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"`
|
||||
结果为 `22 Warning(s)`、`0 Error(s)`;剩余 `MA0051` 已集中到
|
||||
`CqrsHandlerRegistryGeneratorTests.cs`(`15` 条)与 `SchemaConfigGeneratorTests.cs`(`7` 条)
|
||||
- 下一步建议:
|
||||
- 若保持低风险单写集,先进入 `SchemaConfigGeneratorTests.cs`
|
||||
- 若优先按 warning 数量收敛,则进入 `CqrsHandlerRegistryGeneratorTests.cs`
|
||||
|
||||
## 2026-04-23 — RP-033
|
||||
|
||||
### 阶段:`SchemaConfigGeneratorSnapshotTests.cs` `MA0051` 收口(RP-033)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user