GFramework/GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs
GeWuYou ec4e2edeab feat(config): 添加AI-First游戏内容配置系统
- 实现YAML配置文件与JSON Schema结构描述支持
- 提供一对象一文件的目录组织方式
- 集成Source Generator生成配置类型和表包装代码
- 添加VS Code插件支持配置浏览和表单编辑功能
- 实现运行时只读查询和开发期热重载机制
- 支持跨表引用校验和轻量元数据复用
- 添加配置加载异常诊断和批量编辑入口
2026-04-03 21:17:39 +08:00

134 lines
5.0 KiB
C#

using System.IO;
using GFramework.Game.Config;
using GFramework.Game.Config.Generated;
namespace GFramework.Game.Tests.Config;
/// <summary>
/// 验证消费者项目通过 `schemas/**/*.schema.json` 自动拾取 schema 后,
/// 可以直接编译并使用生成的注册辅助、强类型访问入口与运行时加载链路。
/// </summary>
[TestFixture]
public class GeneratedConfigConsumerIntegrationTests
{
/// <summary>
/// 为每个端到端测试准备独立的配置根目录,避免编译期 schema 资产与运行时写入互相污染。
/// </summary>
[SetUp]
public void SetUp()
{
_rootPath = Path.Combine(Path.GetTempPath(), "GFramework.GeneratedConfigTests", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(_rootPath);
}
/// <summary>
/// 清理测试过程中创建的临时消费者目录。
/// </summary>
[TearDown]
public void TearDown()
{
if (Directory.Exists(_rootPath))
{
Directory.Delete(_rootPath, true);
}
}
private string _rootPath = null!;
/// <summary>
/// 验证生成器自动拾取消费者项目的 schema 后,
/// 可以用生成的注册辅助完成加载,并通过强类型表包装访问运行时数据。
/// </summary>
[Test]
public async Task LoadAsync_Should_Support_Generated_Bindings_In_Consumer_Project()
{
CreateFile(
"schemas/monster.schema.json",
"""
{
"title": "Monster Config",
"description": "Defines one monster entry for the end-to-end consumer integration test.",
"type": "object",
"required": ["id", "name", "hp"],
"properties": {
"id": {
"type": "integer",
"description": "Monster identifier."
},
"name": {
"type": "string",
"description": "Monster display name."
},
"hp": {
"type": "integer",
"description": "Monster base health."
}
}
}
""");
CreateFile(
"monster/slime.yaml",
"""
id: 1
name: Slime
hp: 10
""");
CreateFile(
"monster/goblin.yaml",
"""
id: 2
name: Goblin
hp: 30
""");
var registry = new ConfigRegistry();
var loader = new YamlConfigLoader(_rootPath)
.RegisterMonsterTable();
await loader.LoadAsync(registry);
var table = registry.GetMonsterTable();
Assert.Multiple(() =>
{
Assert.That(MonsterConfigBindings.ConfigDomain, Is.EqualTo("monster"));
Assert.That(MonsterConfigBindings.TableName, Is.EqualTo("monster"));
Assert.That(MonsterConfigBindings.ConfigRelativePath, Is.EqualTo("monster"));
Assert.That(MonsterConfigBindings.SchemaRelativePath, Is.EqualTo("schemas/monster.schema.json"));
Assert.That(MonsterConfigBindings.Metadata.ConfigDomain, Is.EqualTo(MonsterConfigBindings.ConfigDomain));
Assert.That(MonsterConfigBindings.Metadata.TableName, Is.EqualTo(MonsterConfigBindings.TableName));
Assert.That(MonsterConfigBindings.Metadata.ConfigRelativePath,
Is.EqualTo(MonsterConfigBindings.ConfigRelativePath));
Assert.That(MonsterConfigBindings.Metadata.SchemaRelativePath,
Is.EqualTo(MonsterConfigBindings.SchemaRelativePath));
Assert.That(MonsterConfigBindings.References.All, Is.Empty);
Assert.That(MonsterConfigBindings.References.TryGetByDisplayPath("dropItems", out _), Is.False);
Assert.That(table.Count, Is.EqualTo(2));
Assert.That(table.Get(1).Name, Is.EqualTo("Slime"));
Assert.That(table.Get(2).Hp, Is.EqualTo(30));
Assert.That(registry.TryGetMonsterTable(out var generatedTable), Is.True);
Assert.That(generatedTable, Is.Not.Null);
Assert.That(generatedTable!.All().Select(static config => config.Name),
Is.EquivalentTo(new[] { "Slime", "Goblin" }));
});
}
/// <summary>
/// 在临时消费者根目录中创建测试文件。
/// </summary>
/// <param name="relativePath">相对根目录的文件路径。</param>
/// <param name="content">要写入的文件内容。</param>
private void CreateFile(
string relativePath,
string content)
{
var path = Path.Combine(_rootPath, relativePath.Replace('/', Path.DirectorySeparatorChar));
var directoryPath = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
File.WriteAllText(path, content.Replace("\n", Environment.NewLine, StringComparison.Ordinal));
}
}