实现功能:
- R 接口继承 json.Marshaler 和 json.Unmarshaler 接口
- MarshalJSON(): 将 R 实例序列化为 JSON 字节数组
- UnmarshalJSON(): 从 JSON 字节数组反序列化到 R 实例
核心特性:
- 支持 struct、map、slice 等所有类型的 JSON 序列化
- 支持嵌套结构的序列化和反序列化
- 自动智能类型转换(如 JSON 数字 float64 -> int/int64)
- 可以对嵌套字段单独序列化(如 rfx.Get("Address"))
测试覆盖:
- TestJSONMarshal: 测试各种类型的序列化
- TestJSONUnmarshal: 测试各种类型的反序列化
- TestJSONRoundTrip: 测试序列化和反序列化的往返一致性
文档更新:
- 在 README 特性列表中添加 JSON 序列化说明
- 新增"JSON 序列化和反序列化"章节
- 包含完整的使用示例和最佳实践
- 说明使用场景:API通信、配置持久化、数据传输、缓存、消息队列等
214 lines
4.7 KiB
Go
214 lines
4.7 KiB
Go
package reflux
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
// TestJSONMarshal 测试 JSON 序列化
|
|
func TestJSONMarshal(t *testing.T) {
|
|
t.Run("Marshal struct", func(t *testing.T) {
|
|
type Person struct {
|
|
Name string
|
|
Age int
|
|
}
|
|
person := Person{Name: "Alice", Age: 30}
|
|
r := New(&person)
|
|
|
|
data, err := json.Marshal(r)
|
|
if err != nil {
|
|
t.Fatalf("Marshal failed: %v", err)
|
|
}
|
|
|
|
expected := `{"Name":"Alice","Age":30}`
|
|
if string(data) != expected {
|
|
t.Errorf("Expected %s, got %s", expected, string(data))
|
|
}
|
|
})
|
|
|
|
t.Run("Marshal map", func(t *testing.T) {
|
|
m := map[string]any{
|
|
"name": "Bob",
|
|
"age": 25,
|
|
}
|
|
r := New(&m)
|
|
|
|
data, err := json.Marshal(r)
|
|
if err != nil {
|
|
t.Fatalf("Marshal failed: %v", err)
|
|
}
|
|
|
|
// 反序列化回来验证
|
|
var result map[string]any
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
t.Fatalf("Unmarshal verification failed: %v", err)
|
|
}
|
|
|
|
if result["name"] != "Bob" || result["age"].(float64) != 25 {
|
|
t.Errorf("Unexpected result: %v", result)
|
|
}
|
|
})
|
|
|
|
t.Run("Marshal slice", func(t *testing.T) {
|
|
slice := []int{1, 2, 3, 4, 5}
|
|
r := New(&slice)
|
|
|
|
data, err := json.Marshal(r)
|
|
if err != nil {
|
|
t.Fatalf("Marshal failed: %v", err)
|
|
}
|
|
|
|
expected := `[1,2,3,4,5]`
|
|
if string(data) != expected {
|
|
t.Errorf("Expected %s, got %s", expected, string(data))
|
|
}
|
|
})
|
|
|
|
t.Run("Marshal nested structure", func(t *testing.T) {
|
|
type Address struct {
|
|
City string
|
|
Country string
|
|
}
|
|
type Person struct {
|
|
Name string
|
|
Age int
|
|
Address Address
|
|
}
|
|
person := Person{
|
|
Name: "Charlie",
|
|
Age: 35,
|
|
Address: Address{
|
|
City: "Beijing",
|
|
Country: "China",
|
|
},
|
|
}
|
|
r := New(&person)
|
|
|
|
data, err := json.Marshal(r)
|
|
if err != nil {
|
|
t.Fatalf("Marshal failed: %v", err)
|
|
}
|
|
|
|
// 验证可以正确反序列化
|
|
var result Person
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
t.Fatalf("Unmarshal verification failed: %v", err)
|
|
}
|
|
|
|
if result.Name != "Charlie" || result.Age != 35 ||
|
|
result.Address.City != "Beijing" || result.Address.Country != "China" {
|
|
t.Errorf("Unexpected result: %v", result)
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestJSONUnmarshal 测试 JSON 反序列化
|
|
func TestJSONUnmarshal(t *testing.T) {
|
|
t.Run("Unmarshal to struct", func(t *testing.T) {
|
|
type Person struct {
|
|
Name string
|
|
Age int
|
|
}
|
|
person := Person{}
|
|
r := New(&person)
|
|
|
|
jsonData := `{"Name":"David","Age":40}`
|
|
if err := json.Unmarshal([]byte(jsonData), r); err != nil {
|
|
t.Fatalf("Unmarshal failed: %v", err)
|
|
}
|
|
|
|
if r.Get("Name").String() != "David" || r.Get("Age").Int() != 40 {
|
|
t.Errorf("Unexpected values after unmarshal: Name=%s, Age=%d",
|
|
r.Get("Name").String(), r.Get("Age").Int())
|
|
}
|
|
})
|
|
|
|
t.Run("Unmarshal to map", func(t *testing.T) {
|
|
m := make(map[string]any)
|
|
r := New(&m)
|
|
|
|
jsonData := `{"name":"Eve","age":28,"active":true}`
|
|
if err := json.Unmarshal([]byte(jsonData), r); err != nil {
|
|
t.Fatalf("Unmarshal failed: %v", err)
|
|
}
|
|
|
|
if r.Get("name").String() != "Eve" {
|
|
t.Errorf("Expected name=Eve, got %s", r.Get("name").String())
|
|
}
|
|
if r.Get("age").Float64() != 28 {
|
|
t.Errorf("Expected age=28, got %v", r.Get("age").Float64())
|
|
}
|
|
if !r.Get("active").Bool() {
|
|
t.Error("Expected active=true")
|
|
}
|
|
})
|
|
|
|
t.Run("Unmarshal to slice", func(t *testing.T) {
|
|
slice := []int{}
|
|
r := New(&slice)
|
|
|
|
jsonData := `[10,20,30,40,50]`
|
|
if err := json.Unmarshal([]byte(jsonData), r); err != nil {
|
|
t.Fatalf("Unmarshal failed: %v", err)
|
|
}
|
|
|
|
arr := r.Array()
|
|
if len(arr) != 5 {
|
|
t.Fatalf("Expected 5 elements, got %d", len(arr))
|
|
}
|
|
|
|
for i, expected := range []int{10, 20, 30, 40, 50} {
|
|
if arr[i].Int() != expected {
|
|
t.Errorf("arr[%d]: expected %d, got %d", i, expected, arr[i].Int())
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestJSONRoundTrip 测试序列化和反序列化往返
|
|
func TestJSONRoundTrip(t *testing.T) {
|
|
type TestCase struct {
|
|
Name string
|
|
Age int
|
|
Tags []string
|
|
}
|
|
|
|
original := TestCase{
|
|
Name: "Test",
|
|
Age: 99,
|
|
Tags: []string{"tag1", "tag2", "tag3"},
|
|
}
|
|
|
|
// 序列化
|
|
r1 := New(&original)
|
|
data, err := json.Marshal(r1)
|
|
if err != nil {
|
|
t.Fatalf("Marshal failed: %v", err)
|
|
}
|
|
|
|
// 反序列化
|
|
result := TestCase{}
|
|
r2 := New(&result)
|
|
if err := json.Unmarshal(data, r2); err != nil {
|
|
t.Fatalf("Unmarshal failed: %v", err)
|
|
}
|
|
|
|
// 验证
|
|
if r2.Get("Name").String() != "Test" {
|
|
t.Errorf("Name mismatch: got %s", r2.Get("Name").String())
|
|
}
|
|
if r2.Get("Age").Int() != 99 {
|
|
t.Errorf("Age mismatch: got %d", r2.Get("Age").Int())
|
|
}
|
|
|
|
tags := r2.Get("Tags").Array()
|
|
if len(tags) != 3 {
|
|
t.Fatalf("Tags length mismatch: got %d", len(tags))
|
|
}
|
|
for i, expected := range []string{"tag1", "tag2", "tag3"} {
|
|
if tags[i].String() != expected {
|
|
t.Errorf("Tags[%d] mismatch: expected %s, got %s", i, expected, tags[i].String())
|
|
}
|
|
}
|
|
}
|