Skip to content

Commit ac92852

Browse files
TimelordUKclaude
andcommitted
Add regression tests for F3 format preservation
Added 7 comprehensive tests to ensure parentheses are preserved when formatting SQL queries for multi-line editing mode: - test_format_preserves_simple_parentheses: Basic OR grouping - test_format_preserves_complex_parentheses: Mixed AND/OR with groups - test_format_preserves_nested_parentheses: Nested parentheses validation - test_format_preserves_method_calls_in_parentheses: Method calls in groups - test_format_preserves_multiple_groups: Multiple parenthesized groups - test_format_preserves_date_ranges: DateTime expressions with grouping - test_format_multiline_layout: Verifies proper multi-line structure These tests ensure that the F3 multi-line editor will always preserve critical query structure, preventing regressions that would break complex trade filtering queries. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 7d43062 commit ac92852

1 file changed

Lines changed: 115 additions & 0 deletions

File tree

sql-cli/src/recursive_parser.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2319,4 +2319,119 @@ mod tests {
23192319
// Should correctly parse the AND chain inside parentheses
23202320
assert!(where_clause.conditions.len() > 0);
23212321
}
2322+
2323+
// Format preservation tests - ensure F3 multi-line mode preserves parentheses
2324+
#[test]
2325+
fn test_format_preserves_simple_parentheses() {
2326+
let query = r#"SELECT * FROM trades WHERE (status = "active" OR status = "pending")"#;
2327+
let formatted = format_sql_pretty_compact(query, 5);
2328+
let formatted_text = formatted.join(" ");
2329+
2330+
// Check parentheses are preserved
2331+
assert!(formatted_text.contains("(status"));
2332+
assert!(formatted_text.contains("\"pending\")"));
2333+
2334+
// Count parentheses
2335+
let original_parens = query.chars().filter(|c| *c == '(' || *c == ')').count();
2336+
let formatted_parens = formatted_text.chars().filter(|c| *c == '(' || *c == ')').count();
2337+
assert_eq!(original_parens, formatted_parens, "Parentheses should be preserved");
2338+
}
2339+
2340+
#[test]
2341+
fn test_format_preserves_complex_parentheses() {
2342+
let query = r#"SELECT * FROM trades WHERE (symbol = "AAPL" OR symbol = "GOOGL") AND price > 100"#;
2343+
let formatted = format_sql_pretty_compact(query, 5);
2344+
let formatted_text = formatted.join(" ");
2345+
2346+
// Check the grouped OR condition is preserved
2347+
assert!(formatted_text.contains("(symbol"));
2348+
assert!(formatted_text.contains("\"GOOGL\")"));
2349+
2350+
// Verify parentheses count
2351+
let original_parens = query.chars().filter(|c| *c == '(' || *c == ')').count();
2352+
let formatted_parens = formatted_text.chars().filter(|c| *c == '(' || *c == ')').count();
2353+
assert_eq!(original_parens, formatted_parens);
2354+
}
2355+
2356+
#[test]
2357+
fn test_format_preserves_nested_parentheses() {
2358+
let query = r#"SELECT * FROM trades WHERE ((symbol = "AAPL" OR symbol = "GOOGL") AND price > 100) OR status = "cancelled""#;
2359+
let formatted = format_sql_pretty_compact(query, 5);
2360+
let formatted_text = formatted.join(" ");
2361+
2362+
// Count nested parentheses
2363+
let original_parens = query.chars().filter(|c| *c == '(' || *c == ')').count();
2364+
let formatted_parens = formatted_text.chars().filter(|c| *c == '(' || *c == ')').count();
2365+
assert_eq!(original_parens, formatted_parens, "Nested parentheses should be preserved");
2366+
assert_eq!(original_parens, 4, "Should have 4 parentheses total");
2367+
}
2368+
2369+
#[test]
2370+
fn test_format_preserves_method_calls_in_parentheses() {
2371+
let query = r#"SELECT * FROM trades WHERE (symbol.StartsWith("A") OR symbol.StartsWith("G")) AND volume > 1000000"#;
2372+
let formatted = format_sql_pretty_compact(query, 5);
2373+
let formatted_text = formatted.join(" ");
2374+
2375+
// Check method calls are preserved with their parentheses
2376+
assert!(formatted_text.contains("(symbol.StartsWith"));
2377+
assert!(formatted_text.contains("StartsWith(\"A\")"));
2378+
assert!(formatted_text.contains("StartsWith(\"G\")"));
2379+
2380+
// Count all parentheses (including method calls)
2381+
let original_parens = query.chars().filter(|c| *c == '(' || *c == ')').count();
2382+
let formatted_parens = formatted_text.chars().filter(|c| *c == '(' || *c == ')').count();
2383+
assert_eq!(original_parens, formatted_parens);
2384+
assert_eq!(original_parens, 6, "Should have 6 parentheses (1 group + 2 method calls)");
2385+
}
2386+
2387+
#[test]
2388+
fn test_format_preserves_multiple_groups() {
2389+
let query = r#"SELECT * FROM trades WHERE (symbol = "AAPL" OR symbol = "GOOGL") AND (price > 100 AND price < 500)"#;
2390+
let formatted = format_sql_pretty_compact(query, 5);
2391+
let formatted_text = formatted.join(" ");
2392+
2393+
// Both groups should be preserved
2394+
assert!(formatted_text.contains("(symbol"));
2395+
assert!(formatted_text.contains("(price"));
2396+
2397+
let original_parens = query.chars().filter(|c| *c == '(' || *c == ')').count();
2398+
let formatted_parens = formatted_text.chars().filter(|c| *c == '(' || *c == ')').count();
2399+
assert_eq!(original_parens, formatted_parens);
2400+
assert_eq!(original_parens, 4, "Should have 4 parentheses (2 groups)");
2401+
}
2402+
2403+
#[test]
2404+
fn test_format_preserves_date_ranges() {
2405+
let query = r#"SELECT * FROM trades WHERE (executionDate > DateTime(2024, 1, 1) AND executionDate < DateTime(2024, 12, 31))"#;
2406+
let formatted = format_sql_pretty_compact(query, 5);
2407+
let formatted_text = formatted.join(" ");
2408+
2409+
// Check DateTime functions and grouping are preserved
2410+
assert!(formatted_text.contains("(executionDate"));
2411+
assert!(formatted_text.contains("DateTime(2024, 1, 1)"));
2412+
assert!(formatted_text.contains("DateTime(2024, 12, 31)"));
2413+
2414+
let original_parens = query.chars().filter(|c| *c == '(' || *c == ')').count();
2415+
let formatted_parens = formatted_text.chars().filter(|c| *c == '(' || *c == ')').count();
2416+
assert_eq!(original_parens, formatted_parens);
2417+
}
2418+
2419+
#[test]
2420+
fn test_format_multiline_layout() {
2421+
// Test that formatted output has proper multi-line structure
2422+
let query = r#"SELECT * FROM trades WHERE (symbol = "AAPL" OR symbol = "GOOGL") AND price > 100"#;
2423+
let formatted = format_sql_pretty_compact(query, 5);
2424+
2425+
// Should have SELECT, FROM, WHERE, and condition lines
2426+
assert!(formatted.len() >= 4, "Should have multiple lines");
2427+
assert_eq!(formatted[0], "SELECT");
2428+
assert!(formatted[1].trim().starts_with("*"));
2429+
assert!(formatted[2].starts_with("FROM"));
2430+
assert_eq!(formatted[3], "WHERE");
2431+
2432+
// WHERE conditions should be indented
2433+
let where_lines: Vec<_> = formatted.iter().skip(4).collect();
2434+
assert!(where_lines.iter().any(|l| l.contains("(symbol")));
2435+
assert!(where_lines.iter().any(|l| l.trim() == "AND"));
2436+
}
23222437
}

0 commit comments

Comments
 (0)