You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
349 lines
9.0 KiB
349 lines
9.0 KiB
package engine
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestComprehensiveSQLSuite tests all kinds of SQL patterns to ensure robustness
|
|
func TestComprehensiveSQLSuite(t *testing.T) {
|
|
engine := NewTestSQLEngine()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
sql string
|
|
shouldPanic bool
|
|
shouldError bool
|
|
desc string
|
|
}{
|
|
// =========== BASIC QUERIES ===========
|
|
{
|
|
name: "Basic_Select_All",
|
|
sql: "SELECT * FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Basic select all columns",
|
|
},
|
|
{
|
|
name: "Basic_Select_Column",
|
|
sql: "SELECT id FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Basic select single column",
|
|
},
|
|
{
|
|
name: "Basic_Select_Multiple_Columns",
|
|
sql: "SELECT id, status FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Basic select multiple columns",
|
|
},
|
|
|
|
// =========== ARITHMETIC EXPRESSIONS (FIXED) ===========
|
|
{
|
|
name: "Arithmetic_Multiply_FIXED",
|
|
sql: "SELECT id*2 FROM user_events",
|
|
shouldPanic: false, // Fixed: no longer panics
|
|
shouldError: false,
|
|
desc: "FIXED: Arithmetic multiplication works",
|
|
},
|
|
{
|
|
name: "Arithmetic_Add",
|
|
sql: "SELECT id+10 FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Arithmetic addition works",
|
|
},
|
|
{
|
|
name: "Arithmetic_Subtract",
|
|
sql: "SELECT id-5 FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Arithmetic subtraction works",
|
|
},
|
|
{
|
|
name: "Arithmetic_Divide",
|
|
sql: "SELECT id/3 FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Arithmetic division works",
|
|
},
|
|
{
|
|
name: "Arithmetic_Complex",
|
|
sql: "SELECT id*2+10 FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Complex arithmetic expression works",
|
|
},
|
|
|
|
// =========== STRING OPERATIONS ===========
|
|
{
|
|
name: "String_Concatenation",
|
|
sql: "SELECT 'hello' || 'world' FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "String concatenation",
|
|
},
|
|
{
|
|
name: "String_Column_Concat",
|
|
sql: "SELECT status || '_suffix' FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Column string concatenation",
|
|
},
|
|
|
|
// =========== FUNCTIONS ===========
|
|
{
|
|
name: "Function_LENGTH",
|
|
sql: "SELECT LENGTH('hello') FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "LENGTH function with literal",
|
|
},
|
|
{
|
|
name: "Function_LENGTH_Column",
|
|
sql: "SELECT LENGTH(status) FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "LENGTH function with column",
|
|
},
|
|
{
|
|
name: "Function_UPPER",
|
|
sql: "SELECT UPPER('hello') FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "UPPER function",
|
|
},
|
|
{
|
|
name: "Function_Nested",
|
|
sql: "SELECT LENGTH(UPPER('hello')) FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Nested functions",
|
|
},
|
|
|
|
// =========== FUNCTIONS WITH ARITHMETIC ===========
|
|
{
|
|
name: "Function_Arithmetic",
|
|
sql: "SELECT LENGTH('hello') + 10 FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Function with arithmetic",
|
|
},
|
|
{
|
|
name: "Function_Arithmetic_Complex",
|
|
sql: "SELECT LENGTH(status) * 2 + 5 FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Function with complex arithmetic",
|
|
},
|
|
|
|
// =========== TABLE REFERENCES ===========
|
|
{
|
|
name: "Table_Simple",
|
|
sql: "SELECT * FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Simple table reference",
|
|
},
|
|
{
|
|
name: "Table_With_Database",
|
|
sql: "SELECT * FROM ecommerce.user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Table with database qualifier",
|
|
},
|
|
{
|
|
name: "Table_Quoted",
|
|
sql: `SELECT * FROM "user_events"`,
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Quoted table name",
|
|
},
|
|
|
|
// =========== WHERE CLAUSES ===========
|
|
{
|
|
name: "Where_Simple",
|
|
sql: "SELECT * FROM user_events WHERE id = 1",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Simple WHERE clause",
|
|
},
|
|
{
|
|
name: "Where_String",
|
|
sql: "SELECT * FROM user_events WHERE status = 'active'",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "WHERE clause with string",
|
|
},
|
|
|
|
// =========== LIMIT/OFFSET ===========
|
|
{
|
|
name: "Limit_Only",
|
|
sql: "SELECT * FROM user_events LIMIT 10",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "LIMIT clause only",
|
|
},
|
|
{
|
|
name: "Limit_Offset",
|
|
sql: "SELECT * FROM user_events LIMIT 10 OFFSET 5",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "LIMIT with OFFSET",
|
|
},
|
|
|
|
// =========== DATETIME FUNCTIONS ===========
|
|
{
|
|
name: "DateTime_CURRENT_DATE",
|
|
sql: "SELECT CURRENT_DATE FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "CURRENT_DATE function",
|
|
},
|
|
{
|
|
name: "DateTime_NOW",
|
|
sql: "SELECT NOW() FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "NOW() function",
|
|
},
|
|
{
|
|
name: "DateTime_EXTRACT",
|
|
sql: "SELECT EXTRACT(YEAR FROM CURRENT_DATE) FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "EXTRACT function",
|
|
},
|
|
|
|
// =========== EDGE CASES ===========
|
|
{
|
|
name: "Empty_String",
|
|
sql: "SELECT '' FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Empty string literal",
|
|
},
|
|
{
|
|
name: "Multiple_Spaces",
|
|
sql: "SELECT id FROM user_events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Query with multiple spaces",
|
|
},
|
|
{
|
|
name: "Mixed_Case",
|
|
sql: "Select ID from User_Events",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "Mixed case SQL",
|
|
},
|
|
|
|
// =========== SHOW STATEMENTS ===========
|
|
{
|
|
name: "Show_Databases",
|
|
sql: "SHOW DATABASES",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "SHOW DATABASES statement",
|
|
},
|
|
{
|
|
name: "Show_Tables",
|
|
sql: "SHOW TABLES",
|
|
shouldPanic: false,
|
|
shouldError: false,
|
|
desc: "SHOW TABLES statement",
|
|
},
|
|
}
|
|
|
|
var panicTests []string
|
|
var errorTests []string
|
|
var successTests []string
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Capture panics
|
|
var panicValue interface{}
|
|
func() {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
panicValue = r
|
|
}
|
|
}()
|
|
|
|
result, err := engine.ExecuteSQL(context.Background(), tc.sql)
|
|
|
|
if tc.shouldPanic {
|
|
if panicValue == nil {
|
|
t.Errorf("FAIL: Expected panic for %s, but query completed normally", tc.desc)
|
|
panicTests = append(panicTests, "FAIL: "+tc.desc)
|
|
return
|
|
} else {
|
|
t.Logf("PASS: EXPECTED PANIC: %s - %v", tc.desc, panicValue)
|
|
panicTests = append(panicTests, "PASS: "+tc.desc+" (reproduced)")
|
|
return
|
|
}
|
|
}
|
|
|
|
if panicValue != nil {
|
|
t.Errorf("FAIL: Unexpected panic for %s: %v", tc.desc, panicValue)
|
|
panicTests = append(panicTests, "FAIL: "+tc.desc+" (unexpected panic)")
|
|
return
|
|
}
|
|
|
|
if tc.shouldError {
|
|
if err == nil && (result == nil || result.Error == nil) {
|
|
t.Errorf("FAIL: Expected error for %s, but query succeeded", tc.desc)
|
|
errorTests = append(errorTests, "FAIL: "+tc.desc)
|
|
return
|
|
} else {
|
|
t.Logf("PASS: Expected error: %s", tc.desc)
|
|
errorTests = append(errorTests, "PASS: "+tc.desc)
|
|
return
|
|
}
|
|
}
|
|
|
|
if err != nil {
|
|
t.Errorf("FAIL: Unexpected error for %s: %v", tc.desc, err)
|
|
errorTests = append(errorTests, "FAIL: "+tc.desc+" (unexpected error)")
|
|
return
|
|
}
|
|
|
|
if result != nil && result.Error != nil {
|
|
t.Errorf("FAIL: Unexpected result error for %s: %v", tc.desc, result.Error)
|
|
errorTests = append(errorTests, "FAIL: "+tc.desc+" (unexpected result error)")
|
|
return
|
|
}
|
|
|
|
t.Logf("PASS: Success: %s", tc.desc)
|
|
successTests = append(successTests, "PASS: "+tc.desc)
|
|
}()
|
|
})
|
|
}
|
|
|
|
// Summary report
|
|
separator := strings.Repeat("=", 80)
|
|
t.Log("\n" + separator)
|
|
t.Log("COMPREHENSIVE SQL TEST SUITE SUMMARY")
|
|
t.Log(separator)
|
|
t.Logf("Total Tests: %d", len(testCases))
|
|
t.Logf("Successful: %d", len(successTests))
|
|
t.Logf("Panics: %d", len(panicTests))
|
|
t.Logf("Errors: %d", len(errorTests))
|
|
t.Log(separator)
|
|
|
|
if len(panicTests) > 0 {
|
|
t.Log("\nPANICS TO FIX:")
|
|
for _, test := range panicTests {
|
|
t.Log(" " + test)
|
|
}
|
|
}
|
|
|
|
if len(errorTests) > 0 {
|
|
t.Log("\nERRORS TO INVESTIGATE:")
|
|
for _, test := range errorTests {
|
|
t.Log(" " + test)
|
|
}
|
|
}
|
|
}
|