FuzzFormat fuzzes the AST formatter by parsing arbitrary SQL then formatting. Neither parse nor format should panic - errors are fine, panics are bugs.
(f *testing.F)
| 25 | // FuzzFormat fuzzes the AST formatter by parsing arbitrary SQL then formatting. |
| 26 | // Neither parse nor format should panic - errors are fine, panics are bugs. |
| 27 | func FuzzFormat(f *testing.F) { |
| 28 | seeds := []string{ |
| 29 | "SELECT 1", |
| 30 | "SELECT * FROM users", |
| 31 | "SELECT id, name FROM users WHERE active = TRUE", |
| 32 | "SELECT DISTINCT status FROM orders", |
| 33 | "SELECT * FROM users LIMIT 10 OFFSET 20", |
| 34 | "SELECT * FROM users ORDER BY name DESC", |
| 35 | "SELECT dept, COUNT(*) FROM emp GROUP BY dept HAVING COUNT(*) > 5", |
| 36 | "SELECT COUNT(*) AS total FROM users", |
| 37 | "INSERT INTO users (name, email) VALUES ('Alice', 'a@b.com')", |
| 38 | "INSERT INTO users (name) VALUES ('Alice'), ('Bob')", |
| 39 | "UPDATE users SET name = 'Bob' WHERE id = 1", |
| 40 | "DELETE FROM users WHERE id = 1", |
| 41 | "SELECT * FROM users WHERE id IN (1, 2, 3)", |
| 42 | "SELECT * FROM users WHERE age BETWEEN 18 AND 65", |
| 43 | "SELECT * FROM users WHERE email IS NULL", |
| 44 | "SELECT * FROM users WHERE name LIKE '%alice%'", |
| 45 | "SELECT * FROM users WHERE id IN (SELECT user_id FROM orders)", |
| 46 | "SELECT * FROM users WHERE EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id)", |
| 47 | "SELECT CASE WHEN x > 0 THEN 'pos' ELSE 'neg' END FROM t", |
| 48 | "SELECT CAST(price AS INTEGER) FROM products", |
| 49 | "SELECT * FROM users LEFT JOIN orders ON users.id = orders.user_id", |
| 50 | "CREATE TABLE users (id INTEGER PRIMARY KEY, name VARCHAR(255) NOT NULL)", |
| 51 | "DROP TABLE IF EXISTS users CASCADE", |
| 52 | "SELECT id FROM a UNION SELECT id FROM b", |
| 53 | "SELECT id FROM a UNION ALL SELECT id FROM b", |
| 54 | "WITH cte AS (SELECT 1) SELECT * FROM cte", |
| 55 | "SELECT ROW_NUMBER() OVER (PARTITION BY a ORDER BY b) FROM t", |
| 56 | "SELECT data->>'name' FROM t", |
| 57 | "MERGE INTO t USING s ON t.id = s.id WHEN MATCHED THEN UPDATE SET t.a = s.a", |
| 58 | "", |
| 59 | "SELECT", |
| 60 | ";;;", |
| 61 | "SELECT (((", |
| 62 | } |
| 63 | |
| 64 | for _, s := range seeds { |
| 65 | f.Add(s) |
| 66 | } |
| 67 | |
| 68 | formatStyles := []ast.FormatOptions{ |
| 69 | ast.CompactStyle(), |
| 70 | ast.ReadableStyle(), |
| 71 | {KeywordCase: ast.KeywordLower, NewlinePerClause: true, IndentWidth: 4}, |
| 72 | {KeywordCase: ast.KeywordPreserve}, |
| 73 | } |
| 74 | |
| 75 | f.Fuzz(func(t *testing.T, sql string) { |
| 76 | parsed, err := gosqlx.Parse(sql) |
| 77 | if err != nil { |
| 78 | return // parse errors are expected for fuzzed input |
| 79 | } |
| 80 | defer ast.ReleaseAST(parsed) |
| 81 | |
| 82 | // Format with multiple styles - must not panic |
| 83 | for _, style := range formatStyles { |
| 84 | _ = formatter.FormatAST(parsed, style) |
nothing calls this directly
no test coverage detected