// Step 411: PostgreSQL Parser Tests (12 tests) #include "ast/PostgreSQLParser.h" #include "Pipeline.h" #include "ast/SqlNodes.h" #include "ast/Function.h" #include #include #include static int passed = 0, failed = 0; #define TEST(name) { std::cout << " " << #name << "... "; } #define PASS() { std::cout << "PASS\n"; ++passed; } #define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; } #define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } else {} template T* firstStatementOf(const Module* mod, const std::string& conceptName) { for (auto* s : mod->getChildren("statements")) { if (s->conceptType == conceptName) return static_cast(s); } return nullptr; } void test_parse_create_table() { TEST(parse_create_table); auto mod = PostgreSQLParser::parsePostgreSQL( "CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT NOT NULL);\n"); CHECK(mod != nullptr, "module is null"); auto* t = firstStatementOf(mod.get(), "TableDeclaration"); CHECK(t != nullptr, "expected table declaration"); CHECK(t->name == "users", "expected table users"); CHECK(t->getChildren("columns").size() >= 2, "expected parsed columns"); PASS(); } void test_parse_select_query() { TEST(parse_select_query); auto mod = PostgreSQLParser::parsePostgreSQL("SELECT id, name FROM users;\n"); auto* q = firstStatementOf(mod.get(), "SelectQuery"); CHECK(q != nullptr, "expected select query"); CHECK(q->getChild("from") != nullptr, "expected from child"); PASS(); } void test_parse_insert_statement() { TEST(parse_insert_statement); auto mod = PostgreSQLParser::parsePostgreSQL( "INSERT INTO users (id, name) VALUES (1, 'a');\n"); auto* ins = firstStatementOf(mod.get(), "InsertStatement"); CHECK(ins != nullptr, "expected insert"); CHECK(ins->tableName == "users", "expected insert table users"); PASS(); } void test_parse_update_statement() { TEST(parse_update_statement); auto mod = PostgreSQLParser::parsePostgreSQL( "UPDATE users SET name = 'b' WHERE id = 1;\n"); auto* up = firstStatementOf(mod.get(), "UpdateStatement"); CHECK(up != nullptr, "expected update"); CHECK(up->tableName == "users", "expected update table users"); CHECK(up->getChild("where") != nullptr, "expected where clause"); PASS(); } void test_parse_delete_statement() { TEST(parse_delete_statement); auto mod = PostgreSQLParser::parsePostgreSQL("DELETE FROM users WHERE id = 2;\n"); auto* del = firstStatementOf(mod.get(), "DeleteStatement"); CHECK(del != nullptr, "expected delete"); CHECK(del->tableName == "users", "expected delete table users"); CHECK(del->getChild("where") != nullptr, "expected where"); PASS(); } void test_parse_join_and_where() { TEST(parse_join_and_where); auto mod = PostgreSQLParser::parsePostgreSQL( "SELECT u.id FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.active = true;\n"); auto* q = firstStatementOf(mod.get(), "SelectQuery"); CHECK(q != nullptr, "expected select"); CHECK(!q->getChildren("joins").empty(), "expected join clause"); CHECK(q->getChild("where") != nullptr, "expected where clause"); PASS(); } void test_parse_postgres_types_serial_jsonb_array() { TEST(parse_postgres_types_serial_jsonb_array); auto mod = PostgreSQLParser::parsePostgreSQL( "CREATE TABLE events (id SERIAL, payload JSONB, tags TEXT[]);\n"); auto* t = firstStatementOf(mod.get(), "TableDeclaration"); CHECK(t != nullptr, "expected table"); auto cols = t->getChildren("columns"); CHECK(cols.size() == 3, "expected 3 columns"); CHECK(static_cast(cols[0])->dataType == "SERIAL", "expected SERIAL"); CHECK(static_cast(cols[1])->dataType == "JSONB", "expected JSONB"); CHECK(static_cast(cols[2])->dataType == "TEXT[]", "expected TEXT[]"); PASS(); } void test_parse_schema_qualified_names() { TEST(parse_schema_qualified_names); auto mod = PostgreSQLParser::parsePostgreSQL( "CREATE TABLE public.accounts (id BIGINT, email TEXT);\n"); auto* t = firstStatementOf(mod.get(), "TableDeclaration"); CHECK(t != nullptr, "expected table"); CHECK(t->name == "public.accounts", "expected schema-qualified name"); CHECK(t->schema == "public", "expected schema public"); PASS(); } void test_parse_create_index() { TEST(parse_create_index); auto mod = PostgreSQLParser::parsePostgreSQL( "CREATE UNIQUE INDEX idx_users_email ON users (email);\n"); auto* idx = firstStatementOf(mod.get(), "IndexDefinition"); CHECK(idx != nullptr, "expected index"); CHECK(idx->name == "idx_users_email", "expected index name"); CHECK(idx->tableName == "users", "expected table name"); CHECK(idx->unique, "expected unique index"); PASS(); } void test_parse_do_block_and_plpgsql_function_markers() { TEST(parse_do_block_and_plpgsql_function_markers); auto mod = PostgreSQLParser::parsePostgreSQL( "DO $$ BEGIN RAISE NOTICE 'x'; END $$;\n" "CREATE FUNCTION add_one(x INTEGER) RETURNS INTEGER AS $$ BEGIN RETURN x + 1; END; $$ LANGUAGE plpgsql;\n"); auto fns = mod->getChildren("functions"); CHECK(fns.size() >= 2, "expected function markers for DO and CREATE FUNCTION"); bool hasDo = false, hasFn = false; for (auto* f : fns) { auto* fn = static_cast(f); if (fn->name == "do_block") hasDo = true; if (fn->name == "add_one") hasFn = true; } CHECK(hasDo && hasFn, "expected both markers"); PASS(); } void test_parse_with_diagnostics_entrypoint() { TEST(parse_with_diagnostics_entrypoint); auto result = PostgreSQLParser::parsePostgreSQLWithDiagnostics( "SELECT DISTINCT id FROM users;\n"); CHECK(result.module != nullptr, "module null"); auto* q = firstStatementOf(result.module.get(), "SelectQuery"); CHECK(q != nullptr, "expected select"); CHECK(q->distinct, "expected distinct flag"); PASS(); } void test_pipeline_parse_routing_aliases() { TEST(pipeline_parse_routing_aliases); Pipeline p; std::vector d1, d2; auto m1 = p.parse("SELECT id FROM users;\n", "postgresql", d1); auto m2 = p.parse("SELECT id FROM users;\n", "postgres", d2); CHECK(m1 != nullptr && m2 != nullptr, "expected parse success"); CHECK(m1->targetLanguage == "postgresql", "expected postgresql target"); CHECK(m2->targetLanguage == "postgresql", "expected alias target"); PASS(); } int main() { std::cout << "Step 411: PostgreSQL Parser Tests\n"; test_parse_create_table(); // 1 test_parse_select_query(); // 2 test_parse_insert_statement(); // 3 test_parse_update_statement(); // 4 test_parse_delete_statement(); // 5 test_parse_join_and_where(); // 6 test_parse_postgres_types_serial_jsonb_array(); // 7 test_parse_schema_qualified_names(); // 8 test_parse_create_index(); // 9 test_parse_do_block_and_plpgsql_function_markers(); // 10 test_parse_with_diagnostics_entrypoint(); // 11 test_pipeline_parse_routing_aliases(); // 12 std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n"; return failed == 0 ? 0 : 1; }