gomog/internal/engine/query_batch2_test.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": map[string]interface{}{
"$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)
}
})
}
}