167 lines
4.8 KiB
C#

using FluentAssertions;
using Workflow.Application.Form.Schema;
using Xunit;
namespace BuildFlow.Workflow.Tests.Form;
public class SchemaDifferTests
{
private const string OldSchema = """
{
"type": "object",
"properties": {
"name": { "type": "string", "title": "姓名", "required": true, "x-component": "Input" },
"age": { "type": "number", "title": "年龄", "x-component": "InputNumber" },
"gender": { "type": "string", "title": "性别", "x-component": "Select" }
}
}
""";
[Fact]
public void Diff_NoChanges_ReturnsEmpty()
{
var diff = SchemaDiffer.Diff(OldSchema, OldSchema);
diff.Added.Should().BeEmpty();
diff.Removed.Should().BeEmpty();
diff.Modified.Should().BeEmpty();
}
[Fact]
public void Diff_DetectsAddedField()
{
var newSchema = """
{
"type": "object",
"properties": {
"name": { "type": "string", "title": "姓名", "required": true, "x-component": "Input" },
"age": { "type": "number", "title": "年龄", "x-component": "InputNumber" },
"gender": { "type": "string", "title": "性别", "x-component": "Select" },
"email": { "type": "string", "title": "邮箱", "x-component": "Input" }
}
}
""";
var diff = SchemaDiffer.Diff(OldSchema, newSchema);
diff.Added.Should().ContainSingle(f => f.Path == "email");
diff.Removed.Should().BeEmpty();
diff.Modified.Should().BeEmpty();
}
[Fact]
public void Diff_DetectsRemovedField()
{
var newSchema = """
{
"type": "object",
"properties": {
"name": { "type": "string", "title": "姓名", "required": true, "x-component": "Input" },
"age": { "type": "number", "title": "年龄", "x-component": "InputNumber" }
}
}
""";
var diff = SchemaDiffer.Diff(OldSchema, newSchema);
diff.Removed.Should().ContainSingle(f => f.Path == "gender");
diff.Added.Should().BeEmpty();
}
[Fact]
public void Diff_DetectsComponentChange()
{
var newSchema = """
{
"type": "object",
"properties": {
"name": { "type": "string", "title": "姓名", "required": true, "x-component": "Input" },
"age": { "type": "number", "title": "年龄", "x-component": "Input" },
"gender": { "type": "string", "title": "性别", "x-component": "Select" }
}
}
""";
var diff = SchemaDiffer.Diff(OldSchema, newSchema);
diff.Modified.Should().ContainSingle(f => f.Path == "age" && f.Change!.Contains("组件"));
}
[Fact]
public void Diff_DetectsRequiredChange()
{
var newSchema = """
{
"type": "object",
"properties": {
"name": { "type": "string", "title": "姓名", "x-component": "Input" },
"age": { "type": "number", "title": "年龄", "x-component": "InputNumber" },
"gender": { "type": "string", "title": "性别", "x-component": "Select" }
}
}
""";
var diff = SchemaDiffer.Diff(OldSchema, newSchema);
diff.Modified.Should().ContainSingle(f => f.Path == "name" && f.Change!.Contains("必填"));
}
[Fact]
public void Diff_HandlesNullInputs()
{
var diff = SchemaDiffer.Diff(null, null);
diff.Added.Should().BeEmpty();
diff.Removed.Should().BeEmpty();
diff.Modified.Should().BeEmpty();
}
[Fact]
public void Diff_HandlesInvalidJson()
{
var diff = SchemaDiffer.Diff("not json", "{ }");
// 无效的旧 schema 视为空,新 schema 也空,无差异
diff.Added.Should().BeEmpty();
diff.Removed.Should().BeEmpty();
}
[Fact]
public void Diff_HandlesNestedFields()
{
var oldNested = """
{
"type": "object",
"properties": {
"card": {
"type": "void",
"x-component": "Card",
"properties": {
"name": { "type": "string", "title": "姓名", "x-component": "Input" }
}
}
}
}
""";
var newNested = """
{
"type": "object",
"properties": {
"card": {
"type": "void",
"x-component": "Card",
"properties": {
"name": { "type": "string", "title": "姓名", "x-component": "Input" },
"age": { "type": "number", "title": "年龄", "x-component": "InputNumber" }
}
}
}
}
""";
var diff = SchemaDiffer.Diff(oldNested, newNested);
diff.Added.Should().ContainSingle(f => f.Path == "card.age");
}
}