TestSchema_Generate_FieldNotFound 断言字段缺失时报错, 但用例里没有设置 Required: true。按 Field.Required 的文档语义, 只有 Required 为 true 时字段 缺失才算错误, 否则取到 nil 继续 —— 所以这个测试一直是失败状态, 应该是在 Required 引入之前写的, 加了 Required 之后没有同步更新。 修正: 给用例加上 Required: true, 让它真正测到报错分支。 另补 TestSchema_Generate_OptionalFieldNotFound 覆盖非必需分支 —— Required 此前在整个包里没有任何测试覆盖。
529 lines
12 KiB
Go
529 lines
12 KiB
Go
package fieldx
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
// TestSchemaFromJSON_Simple 测试从 JSON 创建简单 Schema
|
|
func TestSchemaFromJSON_Simple(t *testing.T) {
|
|
jsonStr := `{
|
|
"name": {
|
|
"type": "field",
|
|
"value": "userName"
|
|
},
|
|
"status": {
|
|
"type": "string",
|
|
"value": "active"
|
|
}
|
|
}`
|
|
|
|
schema, err := SchemaFromJSON(jsonStr)
|
|
if err != nil {
|
|
t.Fatalf("SchemaFromJSON() error = %v", err)
|
|
}
|
|
|
|
if schema["name"].Type != FieldTypeField {
|
|
t.Errorf("name.Type = %v, want %v", schema["name"].Type, FieldTypeField)
|
|
}
|
|
|
|
if schema["status"].Type != FieldTypeString {
|
|
t.Errorf("status.Type = %v, want %v", schema["status"].Type, FieldTypeString)
|
|
}
|
|
|
|
// 测试生成
|
|
source := map[string]any{
|
|
"userName": "Alice",
|
|
}
|
|
|
|
result, err := schema.Generate(source)
|
|
if err != nil {
|
|
t.Fatalf("Generate() error = %v", err)
|
|
}
|
|
|
|
if result["name"] != "Alice" {
|
|
t.Errorf("result[name] = %v, want Alice", result["name"])
|
|
}
|
|
|
|
if result["status"] != "active" {
|
|
t.Errorf("result[status] = %v, want active", result["status"])
|
|
}
|
|
}
|
|
|
|
// TestSchemaFromJSON_Nested 测试嵌套对象
|
|
func TestSchemaFromJSON_Nested(t *testing.T) {
|
|
jsonStr := `{
|
|
"type": {
|
|
"type": "string",
|
|
"value": "user_profile"
|
|
},
|
|
"user": {
|
|
"type": "object",
|
|
"fields": {
|
|
"id": {
|
|
"type": "field",
|
|
"value": "userId"
|
|
},
|
|
"name": {
|
|
"type": "field",
|
|
"value": "userName"
|
|
}
|
|
}
|
|
}
|
|
}`
|
|
|
|
schema, err := SchemaFromJSON(jsonStr)
|
|
if err != nil {
|
|
t.Fatalf("SchemaFromJSON() error = %v", err)
|
|
}
|
|
|
|
if schema["user"].Type != FieldTypeObject {
|
|
t.Errorf("user.Type = %v, want %v", schema["user"].Type, FieldTypeObject)
|
|
}
|
|
|
|
// 测试生成
|
|
source := map[string]any{
|
|
"userId": 123,
|
|
"userName": "Alice",
|
|
}
|
|
|
|
result, err := schema.Generate(source)
|
|
if err != nil {
|
|
t.Fatalf("Generate() error = %v", err)
|
|
}
|
|
|
|
if result["type"] != "user_profile" {
|
|
t.Errorf("type = %v, want user_profile", result["type"])
|
|
}
|
|
|
|
user := result["user"].(map[string]any)
|
|
if user["id"] != 123 {
|
|
t.Errorf("user.id = %v, want 123", user["id"])
|
|
}
|
|
|
|
if user["name"] != "Alice" {
|
|
t.Errorf("user.name = %v, want Alice", user["name"])
|
|
}
|
|
}
|
|
|
|
// TestSchemaFromJSON_NestedPath 测试嵌套路径访问
|
|
func TestSchemaFromJSON_NestedPath(t *testing.T) {
|
|
jsonStr := `{
|
|
"userId": {
|
|
"type": "field",
|
|
"value": "user.id"
|
|
},
|
|
"userEmail": {
|
|
"type": "field",
|
|
"value": "user.contact.email"
|
|
}
|
|
}`
|
|
|
|
schema, err := SchemaFromJSON(jsonStr)
|
|
if err != nil {
|
|
t.Fatalf("SchemaFromJSON() error = %v", err)
|
|
}
|
|
|
|
// 测试嵌套源数据
|
|
source := map[string]any{
|
|
"user": map[string]any{
|
|
"id": 456,
|
|
"contact": map[string]any{
|
|
"email": "alice@example.com",
|
|
},
|
|
},
|
|
}
|
|
|
|
result, err := schema.Generate(source)
|
|
if err != nil {
|
|
t.Fatalf("Generate() error = %v", err)
|
|
}
|
|
|
|
if result["userId"] != 456 {
|
|
t.Errorf("userId = %v, want 456", result["userId"])
|
|
}
|
|
|
|
if result["userEmail"] != "alice@example.com" {
|
|
t.Errorf("userEmail = %v, want alice@example.com", result["userEmail"])
|
|
}
|
|
}
|
|
|
|
// TestSchemaFromJSON_ComplexNested 测试复杂嵌套结构
|
|
func TestSchemaFromJSON_ComplexNested(t *testing.T) {
|
|
jsonStr := `{
|
|
"type": {
|
|
"type": "string",
|
|
"value": "user_profile"
|
|
},
|
|
"user": {
|
|
"type": "object",
|
|
"fields": {
|
|
"id": {
|
|
"type": "field",
|
|
"value": "userId"
|
|
},
|
|
"contact": {
|
|
"type": "object",
|
|
"fields": {
|
|
"email": {
|
|
"type": "field",
|
|
"value": "email"
|
|
},
|
|
"phone": {
|
|
"type": "string",
|
|
"value": "N/A"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}`
|
|
|
|
schema, err := SchemaFromJSON(jsonStr)
|
|
if err != nil {
|
|
t.Fatalf("SchemaFromJSON() error = %v", err)
|
|
}
|
|
|
|
source := map[string]any{
|
|
"userId": 123,
|
|
"email": "test@example.com",
|
|
}
|
|
|
|
result, err := schema.Generate(source)
|
|
if err != nil {
|
|
t.Fatalf("Generate() error = %v", err)
|
|
}
|
|
|
|
if result["type"] != "user_profile" {
|
|
t.Errorf("type = %v, want user_profile", result["type"])
|
|
}
|
|
|
|
user := result["user"].(map[string]any)
|
|
if user["id"] != 123 {
|
|
t.Errorf("user.id = %v, want 123", user["id"])
|
|
}
|
|
|
|
contact := user["contact"].(map[string]any)
|
|
if contact["email"] != "test@example.com" {
|
|
t.Errorf("contact.email = %v, want test@example.com", contact["email"])
|
|
}
|
|
|
|
if contact["phone"] != "N/A" {
|
|
t.Errorf("contact.phone = %v, want N/A", contact["phone"])
|
|
}
|
|
}
|
|
|
|
// TestSchemaFromJSON_InvalidJSON 测试无效 JSON
|
|
func TestSchemaFromJSON_InvalidJSON(t *testing.T) {
|
|
jsonStr := `{invalid json}`
|
|
|
|
_, err := SchemaFromJSON(jsonStr)
|
|
if err == nil {
|
|
t.Error("SchemaFromJSON() expected error for invalid JSON, got nil")
|
|
}
|
|
}
|
|
|
|
// TestSchemaFromJSON_EmptyJSON 测试空 JSON
|
|
func TestSchemaFromJSON_EmptyJSON(t *testing.T) {
|
|
jsonStr := `{}`
|
|
|
|
schema, err := SchemaFromJSON(jsonStr)
|
|
if err != nil {
|
|
t.Fatalf("SchemaFromJSON() error = %v", err)
|
|
}
|
|
|
|
if len(schema) != 0 {
|
|
t.Errorf("schema length = %v, want 0", len(schema))
|
|
}
|
|
}
|
|
|
|
// TestSchemaFromMap_StringType 测试从 Map 创建字符串类型
|
|
func TestSchemaFromMap_StringType(t *testing.T) {
|
|
data := map[string]any{
|
|
"status": map[string]any{
|
|
"type": "string",
|
|
"value": "active",
|
|
},
|
|
}
|
|
|
|
schema, err := SchemaFromMap(data)
|
|
if err != nil {
|
|
t.Fatalf("SchemaFromMap() error = %v", err)
|
|
}
|
|
|
|
if schema["status"].Type != FieldTypeString {
|
|
t.Errorf("status.Type = %v, want %v", schema["status"].Type, FieldTypeString)
|
|
}
|
|
|
|
if schema["status"].Value != "active" {
|
|
t.Errorf("status.Value = %v, want active", schema["status"].Value)
|
|
}
|
|
}
|
|
|
|
// TestSchemaFromMap_FieldType 测试从 Map 创建字段类型
|
|
func TestSchemaFromMap_FieldType(t *testing.T) {
|
|
data := map[string]any{
|
|
"name": map[string]any{
|
|
"type": "field",
|
|
"value": "userName",
|
|
},
|
|
}
|
|
|
|
schema, err := SchemaFromMap(data)
|
|
if err != nil {
|
|
t.Fatalf("SchemaFromMap() error = %v", err)
|
|
}
|
|
|
|
if schema["name"].Type != FieldTypeField {
|
|
t.Errorf("name.Type = %v, want %v", schema["name"].Type, FieldTypeField)
|
|
}
|
|
|
|
if schema["name"].Value != "userName" {
|
|
t.Errorf("name.Value = %v, want userName", schema["name"].Value)
|
|
}
|
|
}
|
|
|
|
// TestSchemaFromMap_ObjectType 测试从 Map 创建对象类型
|
|
func TestSchemaFromMap_ObjectType(t *testing.T) {
|
|
data := map[string]any{
|
|
"user": map[string]any{
|
|
"type": "object",
|
|
"fields": map[string]any{
|
|
"id": map[string]any{
|
|
"type": "field",
|
|
"value": "userId",
|
|
},
|
|
"name": map[string]any{
|
|
"type": "string",
|
|
"value": "default_name",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
schema, err := SchemaFromMap(data)
|
|
if err != nil {
|
|
t.Fatalf("SchemaFromMap() error = %v", err)
|
|
}
|
|
|
|
if schema["user"].Type != FieldTypeObject {
|
|
t.Errorf("user.Type = %v, want %v", schema["user"].Type, FieldTypeObject)
|
|
}
|
|
|
|
if schema["user"].Fields["id"].Type != FieldTypeField {
|
|
t.Errorf("user.fields.id.Type = %v, want %v", schema["user"].Fields["id"].Type, FieldTypeField)
|
|
}
|
|
|
|
if schema["user"].Fields["name"].Value != "default_name" {
|
|
t.Errorf("user.fields.name.Value = %v, want default_name", schema["user"].Fields["name"].Value)
|
|
}
|
|
}
|
|
|
|
// TestSchemaFromMap_InvalidData 测试无效数据
|
|
func TestSchemaFromMap_InvalidData(t *testing.T) {
|
|
data := map[string]any{
|
|
"field1": "invalid",
|
|
}
|
|
|
|
_, err := SchemaFromMap(data)
|
|
if err == nil {
|
|
t.Error("SchemaFromMap() expected error for invalid data, got nil")
|
|
}
|
|
}
|
|
|
|
// TestSchema_Unmarshal 测试直接使用 json.Unmarshal
|
|
func TestSchema_Unmarshal(t *testing.T) {
|
|
jsonStr := `{
|
|
"name": {
|
|
"type": "field",
|
|
"value": "userName"
|
|
},
|
|
"status": {
|
|
"type": "string",
|
|
"value": "active"
|
|
}
|
|
}`
|
|
|
|
var schema Schema
|
|
err := json.Unmarshal([]byte(jsonStr), &schema)
|
|
if err != nil {
|
|
t.Fatalf("json.Unmarshal() error = %v", err)
|
|
}
|
|
|
|
if schema["name"].Type != FieldTypeField {
|
|
t.Errorf("name.Type = %v, want %v", schema["name"].Type, FieldTypeField)
|
|
}
|
|
|
|
// 测试生成
|
|
source := map[string]any{
|
|
"userName": "Alice",
|
|
}
|
|
|
|
result, err := schema.Generate(source)
|
|
if err != nil {
|
|
t.Fatalf("Generate() error = %v", err)
|
|
}
|
|
|
|
if result["name"] != "Alice" {
|
|
t.Errorf("result[name] = %v, want Alice", result["name"])
|
|
}
|
|
}
|
|
|
|
// TestSchema_UnmarshalInStruct 测试在结构体中使用 Schema
|
|
func TestSchema_UnmarshalInStruct(t *testing.T) {
|
|
type Config struct {
|
|
Name string `json:"name"`
|
|
Schema Schema `json:"schema"`
|
|
}
|
|
|
|
jsonStr := `{
|
|
"name": "test_config",
|
|
"schema": {
|
|
"userId": {
|
|
"type": "field",
|
|
"value": "user.id"
|
|
},
|
|
"userName": {
|
|
"type": "field",
|
|
"value": "user.name"
|
|
}
|
|
}
|
|
}`
|
|
|
|
var config Config
|
|
err := json.Unmarshal([]byte(jsonStr), &config)
|
|
if err != nil {
|
|
t.Fatalf("json.Unmarshal() error = %v", err)
|
|
}
|
|
|
|
if config.Name != "test_config" {
|
|
t.Errorf("config.Name = %v, want test_config", config.Name)
|
|
}
|
|
|
|
if config.Schema["userId"].Type != FieldTypeField {
|
|
t.Errorf("userId.Type = %v, want %v", config.Schema["userId"].Type, FieldTypeField)
|
|
}
|
|
|
|
// 测试生成
|
|
source := map[string]any{
|
|
"user": map[string]any{
|
|
"id": 123,
|
|
"name": "Alice",
|
|
},
|
|
}
|
|
|
|
result, err := config.Schema.Generate(source)
|
|
if err != nil {
|
|
t.Fatalf("Generate() error = %v", err)
|
|
}
|
|
|
|
if result["userId"] != 123 {
|
|
t.Errorf("userId = %v, want 123", result["userId"])
|
|
}
|
|
|
|
if result["userName"] != "Alice" {
|
|
t.Errorf("userName = %v, want Alice", result["userName"])
|
|
}
|
|
}
|
|
|
|
// TestSchema_Generate_FieldNotFound 测试 Required 字段不存在时报错
|
|
func TestSchema_Generate_FieldNotFound(t *testing.T) {
|
|
schema := Schema{
|
|
"name": Field{
|
|
Type: FieldTypeField,
|
|
Value: "nonExistentField",
|
|
Required: true,
|
|
},
|
|
}
|
|
|
|
source := map[string]any{
|
|
"otherField": "value",
|
|
}
|
|
|
|
_, err := schema.Generate(source)
|
|
if err == nil {
|
|
t.Error("Generate() expected error for non-existent required field, got nil")
|
|
}
|
|
}
|
|
|
|
// TestSchema_Generate_OptionalFieldNotFound 测试非 Required 字段不存在时返回 nil 而不报错
|
|
//
|
|
// 这是 Required 的另一半语义(见 Field.Required 的文档): 只有 Required 为 true
|
|
// 时字段缺失才算错误,否则取到 nil 继续。
|
|
func TestSchema_Generate_OptionalFieldNotFound(t *testing.T) {
|
|
schema := Schema{
|
|
"name": Field{
|
|
Type: FieldTypeField,
|
|
Value: "nonExistentField",
|
|
// Required 默认为 false
|
|
},
|
|
}
|
|
|
|
source := map[string]any{
|
|
"otherField": "value",
|
|
}
|
|
|
|
result, err := schema.Generate(source)
|
|
if err != nil {
|
|
t.Fatalf("Generate() 非必需字段缺失不应报错, 得到: %v", err)
|
|
}
|
|
if v, ok := result["name"]; !ok {
|
|
t.Error("Generate() 应该产出 name 键")
|
|
} else if v != nil {
|
|
t.Errorf("Generate() name = %v, 期望 nil", v)
|
|
}
|
|
}
|
|
|
|
// TestSchema_Generate_AllTypes 测试所有字段类型组合
|
|
func TestSchema_Generate_AllTypes(t *testing.T) {
|
|
schema := Schema{
|
|
"fixedValue": Field{
|
|
Type: FieldTypeString,
|
|
Value: "constant",
|
|
},
|
|
"dynamicValue": Field{
|
|
Type: FieldTypeField,
|
|
Value: "inputValue",
|
|
},
|
|
"nestedObject": Field{
|
|
Type: FieldTypeObject,
|
|
Fields: Schema{
|
|
"innerFixed": Field{
|
|
Type: FieldTypeString,
|
|
Value: "inner_constant",
|
|
},
|
|
"innerDynamic": Field{
|
|
Type: FieldTypeField,
|
|
Value: "inputValue",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
source := map[string]any{
|
|
"inputValue": "test_value",
|
|
}
|
|
|
|
result, err := schema.Generate(source)
|
|
if err != nil {
|
|
t.Fatalf("Generate() error = %v", err)
|
|
}
|
|
|
|
if result["fixedValue"] != "constant" {
|
|
t.Errorf("fixedValue = %v, want constant", result["fixedValue"])
|
|
}
|
|
|
|
if result["dynamicValue"] != "test_value" {
|
|
t.Errorf("dynamicValue = %v, want test_value", result["dynamicValue"])
|
|
}
|
|
|
|
nested := result["nestedObject"].(map[string]any)
|
|
if nested["innerFixed"] != "inner_constant" {
|
|
t.Errorf("innerFixed = %v, want inner_constant", nested["innerFixed"])
|
|
}
|
|
|
|
if nested["innerDynamic"] != "test_value" {
|
|
t.Errorf("innerDynamic = %v, want test_value", nested["innerDynamic"])
|
|
}
|
|
}
|