mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2025-12-13 17:10:36 +00:00
413 lines
10 KiB
Go
413 lines
10 KiB
Go
package common
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/bitechdev/ResolveSpec/pkg/modelregistry"
|
|
)
|
|
|
|
func TestSanitizeWhereClause(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
where string
|
|
tableName string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "trivial conditions in parentheses",
|
|
where: "(true AND true AND true)",
|
|
tableName: "mastertask",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "trivial conditions without parentheses",
|
|
where: "true AND true AND true",
|
|
tableName: "mastertask",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "single trivial condition",
|
|
where: "true",
|
|
tableName: "mastertask",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "valid condition with parentheses - no prefix added",
|
|
where: "(status = 'active')",
|
|
tableName: "users",
|
|
expected: "status = 'active'",
|
|
},
|
|
{
|
|
name: "mixed trivial and valid conditions - no prefix added",
|
|
where: "true AND status = 'active' AND 1=1",
|
|
tableName: "users",
|
|
expected: "status = 'active'",
|
|
},
|
|
{
|
|
name: "condition with correct table prefix - unchanged",
|
|
where: "users.status = 'active'",
|
|
tableName: "users",
|
|
expected: "users.status = 'active'",
|
|
},
|
|
{
|
|
name: "condition with incorrect table prefix - fixed",
|
|
where: "wrong_table.status = 'active'",
|
|
tableName: "users",
|
|
expected: "users.status = 'active'",
|
|
},
|
|
{
|
|
name: "multiple conditions with incorrect prefix - fixed",
|
|
where: "wrong_table.status = 'active' AND wrong_table.age > 18",
|
|
tableName: "users",
|
|
expected: "users.status = 'active' AND users.age > 18",
|
|
},
|
|
{
|
|
name: "multiple valid conditions without prefix - no prefix added",
|
|
where: "status = 'active' AND age > 18",
|
|
tableName: "users",
|
|
expected: "status = 'active' AND age > 18",
|
|
},
|
|
{
|
|
name: "no table name provided",
|
|
where: "status = 'active'",
|
|
tableName: "",
|
|
expected: "status = 'active'",
|
|
},
|
|
{
|
|
name: "empty where clause",
|
|
where: "",
|
|
tableName: "users",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "mixed correct and incorrect prefixes",
|
|
where: "users.status = 'active' AND wrong_table.age > 18",
|
|
tableName: "users",
|
|
expected: "users.status = 'active' AND users.age > 18",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := SanitizeWhereClause(tt.where, tt.tableName)
|
|
if result != tt.expected {
|
|
t.Errorf("SanitizeWhereClause(%q, %q) = %q; want %q", tt.where, tt.tableName, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStripOuterParentheses(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "single level parentheses",
|
|
input: "(true)",
|
|
expected: "true",
|
|
},
|
|
{
|
|
name: "multiple levels",
|
|
input: "((true))",
|
|
expected: "true",
|
|
},
|
|
{
|
|
name: "no parentheses",
|
|
input: "true",
|
|
expected: "true",
|
|
},
|
|
{
|
|
name: "mismatched parentheses",
|
|
input: "(true",
|
|
expected: "(true",
|
|
},
|
|
{
|
|
name: "complex expression",
|
|
input: "(a AND b)",
|
|
expected: "a AND b",
|
|
},
|
|
{
|
|
name: "nested but not outer",
|
|
input: "(a AND (b OR c)) AND d",
|
|
expected: "(a AND (b OR c)) AND d",
|
|
},
|
|
{
|
|
name: "with spaces",
|
|
input: " ( true ) ",
|
|
expected: "true",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := stripOuterParentheses(tt.input)
|
|
if result != tt.expected {
|
|
t.Errorf("stripOuterParentheses(%q) = %q; want %q", tt.input, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIsTrivialCondition(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected bool
|
|
}{
|
|
{"true", "true", true},
|
|
{"true with spaces", " true ", true},
|
|
{"TRUE uppercase", "TRUE", true},
|
|
{"1=1", "1=1", true},
|
|
{"1 = 1", "1 = 1", true},
|
|
{"true = true", "true = true", true},
|
|
{"valid condition", "status = 'active'", false},
|
|
{"false", "false", false},
|
|
{"column name", "is_active", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := IsTrivialCondition(tt.input)
|
|
if result != tt.expected {
|
|
t.Errorf("IsTrivialCondition(%q) = %v; want %v", tt.input, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExtractTableAndColumn(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expectedTable string
|
|
expectedCol string
|
|
}{
|
|
{
|
|
name: "qualified column with equals",
|
|
input: "users.status = 'active'",
|
|
expectedTable: "users",
|
|
expectedCol: "status",
|
|
},
|
|
{
|
|
name: "qualified column with greater than",
|
|
input: "users.age > 18",
|
|
expectedTable: "users",
|
|
expectedCol: "age",
|
|
},
|
|
{
|
|
name: "qualified column with LIKE",
|
|
input: "users.name LIKE '%john%'",
|
|
expectedTable: "users",
|
|
expectedCol: "name",
|
|
},
|
|
{
|
|
name: "qualified column with IN",
|
|
input: "users.status IN ('active', 'pending')",
|
|
expectedTable: "users",
|
|
expectedCol: "status",
|
|
},
|
|
{
|
|
name: "unqualified column",
|
|
input: "status = 'active'",
|
|
expectedTable: "",
|
|
expectedCol: "",
|
|
},
|
|
{
|
|
name: "qualified with backticks",
|
|
input: "`users`.`status` = 'active'",
|
|
expectedTable: "users",
|
|
expectedCol: "status",
|
|
},
|
|
{
|
|
name: "schema.table.column reference",
|
|
input: "public.users.status = 'active'",
|
|
expectedTable: "public.users",
|
|
expectedCol: "status",
|
|
},
|
|
{
|
|
name: "empty string",
|
|
input: "",
|
|
expectedTable: "",
|
|
expectedCol: "",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
table, col := extractTableAndColumn(tt.input)
|
|
if table != tt.expectedTable || col != tt.expectedCol {
|
|
t.Errorf("extractTableAndColumn(%q) = (%q, %q); want (%q, %q)",
|
|
tt.input, table, col, tt.expectedTable, tt.expectedCol)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSanitizeWhereClauseWithPreloads(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
where string
|
|
tableName string
|
|
options *RequestOptions
|
|
expected string
|
|
}{
|
|
{
|
|
name: "preload relation prefix is preserved",
|
|
where: "Department.name = 'Engineering'",
|
|
tableName: "users",
|
|
options: &RequestOptions{
|
|
Preload: []PreloadOption{
|
|
{Relation: "Department"},
|
|
},
|
|
},
|
|
expected: "Department.name = 'Engineering'",
|
|
},
|
|
{
|
|
name: "multiple preload relations - all preserved",
|
|
where: "Department.name = 'Engineering' AND Manager.status = 'active'",
|
|
tableName: "users",
|
|
options: &RequestOptions{
|
|
Preload: []PreloadOption{
|
|
{Relation: "Department"},
|
|
{Relation: "Manager"},
|
|
},
|
|
},
|
|
expected: "Department.name = 'Engineering' AND Manager.status = 'active'",
|
|
},
|
|
{
|
|
name: "mix of main table and preload relation",
|
|
where: "users.status = 'active' AND Department.name = 'Engineering'",
|
|
tableName: "users",
|
|
options: &RequestOptions{
|
|
Preload: []PreloadOption{
|
|
{Relation: "Department"},
|
|
},
|
|
},
|
|
expected: "users.status = 'active' AND Department.name = 'Engineering'",
|
|
},
|
|
{
|
|
name: "incorrect prefix fixed when not a preload relation",
|
|
where: "wrong_table.status = 'active' AND Department.name = 'Engineering'",
|
|
tableName: "users",
|
|
options: &RequestOptions{
|
|
Preload: []PreloadOption{
|
|
{Relation: "Department"},
|
|
},
|
|
},
|
|
expected: "users.status = 'active' AND Department.name = 'Engineering'",
|
|
},
|
|
{
|
|
name: "no options provided - works as before",
|
|
where: "wrong_table.status = 'active'",
|
|
tableName: "users",
|
|
options: nil,
|
|
expected: "users.status = 'active'",
|
|
},
|
|
{
|
|
name: "empty preload list - works as before",
|
|
where: "wrong_table.status = 'active'",
|
|
tableName: "users",
|
|
options: &RequestOptions{Preload: []PreloadOption{}},
|
|
expected: "users.status = 'active'",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var result string
|
|
if tt.options != nil {
|
|
result = SanitizeWhereClause(tt.where, tt.tableName, tt.options)
|
|
} else {
|
|
result = SanitizeWhereClause(tt.where, tt.tableName)
|
|
}
|
|
if result != tt.expected {
|
|
t.Errorf("SanitizeWhereClause(%q, %q, options) = %q; want %q", tt.where, tt.tableName, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Test model for model-aware sanitization tests
|
|
type MasterTask struct {
|
|
ID int `bun:"id,pk"`
|
|
Name string `bun:"name"`
|
|
Status string `bun:"status"`
|
|
UserID int `bun:"user_id"`
|
|
}
|
|
|
|
func TestSanitizeWhereClauseWithModel(t *testing.T) {
|
|
// Register the test model
|
|
err := modelregistry.RegisterModel(MasterTask{}, "mastertask")
|
|
if err != nil {
|
|
// Model might already be registered, ignore error
|
|
t.Logf("Model registration returned: %v", err)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
where string
|
|
tableName string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "valid column without prefix - no prefix added",
|
|
where: "status = 'active'",
|
|
tableName: "mastertask",
|
|
expected: "status = 'active'",
|
|
},
|
|
{
|
|
name: "multiple valid columns without prefix - no prefix added",
|
|
where: "status = 'active' AND user_id = 123",
|
|
tableName: "mastertask",
|
|
expected: "status = 'active' AND user_id = 123",
|
|
},
|
|
{
|
|
name: "incorrect table prefix on valid column - fixed",
|
|
where: "wrong_table.status = 'active'",
|
|
tableName: "mastertask",
|
|
expected: "mastertask.status = 'active'",
|
|
},
|
|
{
|
|
name: "incorrect prefix on invalid column - not fixed",
|
|
where: "wrong_table.invalid_column = 'value'",
|
|
tableName: "mastertask",
|
|
expected: "wrong_table.invalid_column = 'value'",
|
|
},
|
|
{
|
|
name: "mix of valid and trivial conditions",
|
|
where: "true AND status = 'active' AND 1=1",
|
|
tableName: "mastertask",
|
|
expected: "status = 'active'",
|
|
},
|
|
{
|
|
name: "parentheses with valid column - no prefix added",
|
|
where: "(status = 'active')",
|
|
tableName: "mastertask",
|
|
expected: "status = 'active'",
|
|
},
|
|
{
|
|
name: "correct prefix - unchanged",
|
|
where: "mastertask.status = 'active'",
|
|
tableName: "mastertask",
|
|
expected: "mastertask.status = 'active'",
|
|
},
|
|
{
|
|
name: "multiple conditions with mixed prefixes",
|
|
where: "mastertask.status = 'active' AND wrong_table.user_id = 123",
|
|
tableName: "mastertask",
|
|
expected: "mastertask.status = 'active' AND mastertask.user_id = 123",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := SanitizeWhereClause(tt.where, tt.tableName)
|
|
if result != tt.expected {
|
|
t.Errorf("SanitizeWhereClause(%q, %q) = %q; want %q", tt.where, tt.tableName, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|