306 lines
7.4 KiB
Go
306 lines
7.4 KiB
Go
package engine
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"git.kingecg.top/kingecg/gomog/pkg/types"
|
|
)
|
|
|
|
// TestExpr 测试 $expr 操作符
|
|
func TestExpr(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
doc map[string]interface{}
|
|
filter types.Filter
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "simple comparison with $expr",
|
|
doc: map[string]interface{}{"qty": 10, "minQty": 5},
|
|
filter: types.Filter{
|
|
"$expr": types.Filter{
|
|
"$gt": []interface{}{"$qty", "$minQty"},
|
|
},
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "comparison fails with $expr",
|
|
doc: map[string]interface{}{"qty": 3, "minQty": 5},
|
|
filter: types.Filter{
|
|
"$expr": types.Filter{
|
|
"$gt": []interface{}{"$qty", "$minQty"},
|
|
},
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "equality check with $expr",
|
|
doc: map[string]interface{}{"a": 5, "b": 5},
|
|
filter: types.Filter{
|
|
"$expr": types.Filter{
|
|
"$eq": []interface{}{"$a", "$b"},
|
|
},
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "arithmetic in $expr",
|
|
doc: map[string]interface{}{"price": 100, "tax": 10},
|
|
filter: types.Filter{
|
|
"$expr": types.Filter{
|
|
"$gt": []interface{}{
|
|
types.Filter{"$add": []interface{}{"$price", "$tax"}},
|
|
float64(100),
|
|
},
|
|
},
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "conditional in $expr",
|
|
doc: map[string]interface{}{"score": 85},
|
|
filter: types.Filter{
|
|
"$expr": types.Filter{
|
|
"$gte": []interface{}{"$score", float64(80)},
|
|
},
|
|
},
|
|
expected: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := MatchFilter(tt.doc, tt.filter)
|
|
if result != tt.expected {
|
|
t.Errorf("MatchFilter() = %v, want %v", result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestJSONSchema 测试 $jsonSchema 验证操作符
|
|
func TestJSONSchema(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
doc map[string]interface{}
|
|
schema map[string]interface{}
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "bsonType object validation",
|
|
doc: map[string]interface{}{"name": "Alice", "age": 25},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "required fields validation",
|
|
doc: map[string]interface{}{"name": "Alice", "age": 25},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"required": []interface{}{"name", "age"},
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "required fields missing",
|
|
doc: map[string]interface{}{"name": "Alice"},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"required": []interface{}{"name", "email"},
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "properties validation",
|
|
doc: map[string]interface{}{"name": "Alice", "age": 25},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"properties": map[string]interface{}{
|
|
"name": map[string]interface{}{"bsonType": "string"},
|
|
"age": map[string]interface{}{"bsonType": "int"},
|
|
},
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "enum validation",
|
|
doc: map[string]interface{}{"status": "active"},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"properties": map[string]interface{}{
|
|
"status": map[string]interface{}{
|
|
"enum": []interface{}{"active", "inactive", "pending"},
|
|
},
|
|
},
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "enum validation fails",
|
|
doc: map[string]interface{}{"status": "unknown"},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"properties": map[string]interface{}{
|
|
"status": map[string]interface{}{
|
|
"enum": []interface{}{"active", "inactive"},
|
|
},
|
|
},
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "minimum validation",
|
|
doc: map[string]interface{}{"age": 25},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"properties": map[string]interface{}{
|
|
"age": map[string]interface{}{
|
|
"bsonType": "int",
|
|
"minimum": float64(0),
|
|
"maximum": float64(150),
|
|
},
|
|
},
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "minimum validation fails",
|
|
doc: map[string]interface{}{"age": -5},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"properties": map[string]interface{}{
|
|
"age": map[string]interface{}{
|
|
"minimum": float64(0),
|
|
},
|
|
},
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "minLength validation",
|
|
doc: map[string]interface{}{"name": "Alice"},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"properties": map[string]interface{}{
|
|
"name": map[string]interface{}{
|
|
"bsonType": "string",
|
|
"minLength": float64(1),
|
|
"maxLength": float64(50),
|
|
},
|
|
},
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "pattern validation",
|
|
doc: map[string]interface{}{"email": "test@example.com"},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"properties": map[string]interface{}{
|
|
"email": map[string]interface{}{
|
|
"bsonType": "string",
|
|
"pattern": `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`,
|
|
},
|
|
},
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "pattern validation fails",
|
|
doc: map[string]interface{}{"email": "invalid-email"},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"properties": map[string]interface{}{
|
|
"email": map[string]interface{}{
|
|
"pattern": `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`,
|
|
},
|
|
},
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "array items validation",
|
|
doc: map[string]interface{}{"scores": []interface{}{85, 90, 95}},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"properties": map[string]interface{}{
|
|
"scores": map[string]interface{}{
|
|
"bsonType": "array",
|
|
"items": map[string]interface{}{
|
|
"bsonType": "int",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "anyOf validation",
|
|
doc: map[string]interface{}{"type": "A", "fieldA": "value"},
|
|
schema: map[string]interface{}{
|
|
"bsonType": "object",
|
|
"anyOf": []interface{}{
|
|
map[string]interface{}{
|
|
"properties": map[string]interface{}{
|
|
"type": map[string]interface{}{"enum": []interface{}{"A"}},
|
|
"fieldA": map[string]interface{}{"bsonType": "string"},
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"properties": map[string]interface{}{
|
|
"type": map[string]interface{}{"enum": []interface{}{"B"}},
|
|
"fieldB": map[string]interface{}{"bsonType": "int"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
filter := types.Filter{"$jsonSchema": tt.schema}
|
|
result := MatchFilter(tt.doc, filter)
|
|
if result != tt.expected {
|
|
t.Errorf("MatchFilter with $jsonSchema() = %v, want %v", result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestIsTrueValue 测试 isTrueValue 辅助函数
|
|
func TestIsTrueValue(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
value interface{}
|
|
expected bool
|
|
}{
|
|
{"nil value", nil, false},
|
|
{"bool true", true, true},
|
|
{"bool false", false, false},
|
|
{"int non-zero", 42, true},
|
|
{"int zero", 0, false},
|
|
{"float64 non-zero", 3.14, true},
|
|
{"float64 zero", 0.0, false},
|
|
{"string non-empty", "hello", true},
|
|
{"string empty", "", false},
|
|
{"array non-empty", []interface{}{1, 2}, true},
|
|
{"array empty", []interface{}{}, false},
|
|
{"map non-empty", map[string]interface{}{"a": 1}, true},
|
|
{"map empty", map[string]interface{}{}, false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := isTrueValue(tt.value)
|
|
if result != tt.expected {
|
|
t.Errorf("isTrueValue(%v) = %v, want %v", tt.value, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|