Files
go-trustlog/internal/helpers/validate_test.go
ryan 0ec1d3b87d refactor: 更改module路径为独立仓库路径
- go.yandata.net/iod/iod/go-trustlog → go.yandata.net/wangsiyuan/go-trustlog
- 更新 go.mod module声明
- 更新 README.md 安装说明
- 批量更新所有 .go 文件中的 import 路径
- 61个文件受影响

这样go-trustlog可以作为独立SDK使用
2025-12-26 14:35:39 +08:00

187 lines
4.1 KiB
Go

package helpers_test
import (
"sync"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.yandata.net/wangsiyuan/go-trustlog/internal/helpers"
)
func TestGetValidator(t *testing.T) {
t.Run("返回有效的validator实例", func(t *testing.T) {
v := helpers.GetValidator()
require.NotNil(t, v, "Validator不应该为nil")
})
t.Run("单例模式:多次调用返回同一个实例", func(t *testing.T) {
v1 := helpers.GetValidator()
v2 := helpers.GetValidator()
v3 := helpers.GetValidator()
// 使用指针比较,确保是同一个实例
assert.Same(t, v1, v2, "第一次和第二次调用应该返回同一个实例")
assert.Same(t, v2, v3, "第二次和第三次调用应该返回同一个实例")
assert.Same(t, v1, v3, "第一次和第三次调用应该返回同一个实例")
})
t.Run("并发获取validator应该安全", func(t *testing.T) {
const concurrency = 100
validators := make([]interface{}, concurrency)
var wg sync.WaitGroup
wg.Add(concurrency)
for i := range concurrency {
go func(idx int) {
defer wg.Done()
v := helpers.GetValidator()
// 存储validator实例
validators[idx] = v
}(i)
}
wg.Wait()
// 验证所有goroutine获取的是同一个实例
firstValidator := validators[0]
for i := 1; i < concurrency; i++ {
assert.Same(t, firstValidator, validators[i],
"并发调用第%d次获取的validator应该与第一次相同", i)
}
})
t.Run("validator可以正常工作", func(t *testing.T) {
v := helpers.GetValidator()
// 测试一个简单的结构体验证
type TestStruct struct {
Name string `validate:"required,min=2,max=10"`
Email string `validate:"required,email"`
Age int `validate:"gte=0,lte=120"`
}
// 有效的结构体
validData := TestStruct{
Name: "John",
Email: "john@example.com",
Age: 30,
}
err := v.Struct(validData)
require.NoError(t, err, "有效的数据不应该产生验证错误")
// 无效的结构体 - 缺少必填字段
invalidData1 := TestStruct{
Name: "",
Age: 30,
}
err = v.Struct(invalidData1)
require.Error(t, err, "缺少必填字段应该产生验证错误")
// 无效的结构体 - 字段值超出范围
invalidData2 := TestStruct{
Name: "John",
Email: "john@example.com",
Age: 150,
}
err = v.Struct(invalidData2)
require.Error(t, err, "年龄超出范围应该产生验证错误")
// 无效的结构体 - 邮箱格式错误
invalidData3 := TestStruct{
Name: "John",
Email: "invalid-email",
Age: 30,
}
err = v.Struct(invalidData3)
assert.Error(t, err, "无效的邮箱格式应该产生验证错误")
})
}
func TestGetValidator_InitializationOnce(t *testing.T) {
// 这个测试验证 sync.Once 确保初始化只执行一次
const calls = 1000
var wg sync.WaitGroup
wg.Add(calls)
results := make([]interface{}, calls)
for i := range calls {
go func(idx int) {
defer wg.Done()
v := helpers.GetValidator()
results[idx] = v
}(i)
}
wg.Wait()
// 所有结果应该指向同一个实例
first := results[0]
for i := 1; i < calls; i++ {
assert.Same(t, first, results[i],
"所有调用应该返回完全相同的validator实例")
}
}
func TestGetValidator_ValidatorFunctionality(t *testing.T) {
v := helpers.GetValidator()
tests := []struct {
name string
data interface{}
wantErr bool
}{
{
name: "结构体字段验证-成功",
data: struct {
Field string `validate:"required"`
}{
Field: "value",
},
wantErr: false,
},
{
name: "结构体字段验证-失败",
data: struct {
Field string `validate:"required"`
}{
Field: "",
},
wantErr: true,
},
{
name: "数字范围验证-成功",
data: struct {
Count int `validate:"min=1,max=100"`
}{
Count: 50,
},
wantErr: false,
},
{
name: "数字范围验证-失败",
data: struct {
Count int `validate:"min=1,max=100"`
}{
Count: 200,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := v.Struct(tt.data)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}