Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions GFramework.Game.Tests/Config/YamlConfigLoaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,52 @@ public void LoadAsync_Should_Throw_When_Scalar_Value_Is_Not_Declared_In_Schema_E
});
}

/// <summary>
/// 验证标量 <c>const</c> 限制会在运行时被拒绝。
/// </summary>
[Test]
public void LoadAsync_Should_Throw_When_Scalar_Value_Does_Not_Match_Schema_Const()
{
CreateConfigFile(
"monster/slime.yaml",
"""
id: 1
name: Slime
rarity: rare
""");
CreateSchemaFile(
"schemas/monster.schema.json",
"""
{
"type": "object",
"required": ["id", "name", "rarity"],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"rarity": {
"type": "string",
"const": "common"
}
}
}
""");

var loader = new YamlConfigLoader(_rootPath)
.RegisterTable<int, MonsterConfigStub>("monster", "monster", "schemas/monster.schema.json",
static config => config.Id);
var registry = new ConfigRegistry();

var exception = Assert.ThrowsAsync<ConfigLoadException>(async () => await loader.LoadAsync(registry));

Assert.Multiple(() =>
{
Assert.That(exception, Is.Not.Null);
Assert.That(exception!.Message, Does.Contain("constant value"));
Assert.That(exception.Message, Does.Contain("\"common\""));
Assert.That(registry.Count, Is.EqualTo(0));
});
}

/// <summary>
/// 验证数值最小值与最大值约束会在运行时被统一拒绝。
/// </summary>
Expand Down Expand Up @@ -1198,6 +1244,58 @@ public void LoadAsync_Should_Throw_When_Array_Item_Is_Not_Declared_In_Schema_Enu
});
}

/// <summary>
/// 验证数组 <c>const</c> 限制会保留元素顺序并按完整序列比较。
/// </summary>
[Test]
public void LoadAsync_Should_Throw_When_Array_Value_Does_Not_Match_Schema_Const()
{
CreateConfigFile(
"monster/slime.yaml",
"""
id: 1
name: Slime
dropItemIds:
- gem
- potion
""");
CreateSchemaFile(
"schemas/monster.schema.json",
"""
{
"type": "object",
"required": ["id", "name"],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"dropItemIds": {
"type": "array",
"const": ["potion", "gem"],
"items": {
"type": "string"
}
}
}
}
""");

var loader = new YamlConfigLoader(_rootPath)
.RegisterTable<int, MonsterDropArrayConfigStub>("monster", "monster", "schemas/monster.schema.json",
static config => config.Id);
var registry = new ConfigRegistry();

var exception = Assert.ThrowsAsync<ConfigLoadException>(async () => await loader.LoadAsync(registry));

Assert.Multiple(() =>
{
Assert.That(exception, Is.Not.Null);
Assert.That(exception!.Message, Does.Contain("dropItemIds"));
Assert.That(exception.Message, Does.Contain("potion"));
Assert.That(exception.Message, Does.Contain("gem"));
Assert.That(registry.Count, Is.EqualTo(0));
});
}

/// <summary>
/// 验证嵌套对象中的必填字段同样会按 schema 在运行时生效。
/// </summary>
Expand Down Expand Up @@ -1248,6 +1346,63 @@ public void LoadAsync_Should_Throw_When_Nested_Object_Is_Missing_Required_Proper
});
}

/// <summary>
/// 验证嵌套对象 <c>const</c> 限制会按完整对象内容比较。
/// </summary>
[Test]
public void LoadAsync_Should_Throw_When_Nested_Object_Does_Not_Match_Schema_Const()
{
CreateConfigFile(
"monster/slime.yaml",
"""
id: 1
name: Slime
reward:
gold: 10
currency: gem
""");
CreateSchemaFile(
"schemas/monster.schema.json",
"""
{
"type": "object",
"required": ["id", "name", "reward"],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"reward": {
"type": "object",
"properties": {
"gold": { "type": "integer" },
"currency": { "type": "string" }
},
"const": {
"gold": 10,
"currency": "coin"
}
}
}
}
""");

var loader = new YamlConfigLoader(_rootPath)
.RegisterTable<int, MonsterNestedConfigStub>("monster", "monster", "schemas/monster.schema.json",
static config => config.Id);
var registry = new ConfigRegistry();

var exception = Assert.ThrowsAsync<ConfigLoadException>(async () => await loader.LoadAsync(registry));

Assert.Multiple(() =>
{
Assert.That(exception, Is.Not.Null);
Assert.That(exception!.Message, Does.Contain("reward"));
Assert.That(exception.Message, Does.Contain("\"gold\""));
Assert.That(exception.Message, Does.Contain("\"currency\""));
Assert.That(exception.Message, Does.Contain("\"coin\""));
Assert.That(registry.Count, Is.EqualTo(0));
});
}

/// <summary>
/// 验证对象字段不满足 <c>minProperties</c> 时会在运行时被拒绝。
/// </summary>
Expand Down
Loading
Loading