package format import ( "strings" "testing" "git.warky.dev/wdevs/pgtidy/pkg/config" ) func TestCommentsPreserved(t *testing.T) { cases := []struct { name string a, b string wantErr bool }{ {"identical", "select 1; -- note", "select 1;\n-- note", false}, {"reindented block comment", "/* a\n b */ select 1", " /* a\nb */\nselect 1", false}, {"crlf line comment", "-- note\r\nselect 1", "-- note\nselect 1", false}, {"dropped comment", "select 1; -- keep me\nselect 2;", "select 1;\nselect 2;", true}, {"merged comments", "-- one\n-- two\nselect 1", "-- one -- two\nselect 1", true}, {"reworded comment", "-- alpha\nselect 1", "-- beta\nselect 1", true}, {"comment inside body preserved", // -- inside a dollar-quoted body "do $$ begin\n-- inner\nperform 1;\nend $$;", "DO\n$$\nbegin\n -- inner\n perform 1;\nend\n$$;", false}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { err := CommentsPreserved(c.a, c.b) if (err != nil) != c.wantErr { t.Fatalf("CommentsPreserved(%q, %q) err = %v, wantErr %v", c.a, c.b, err, c.wantErr) } }) } } func TestCommentsPreservedIgnoresCodeText(t *testing.T) { // A ( ; keyword etc. inside a comment must not be read as code by the check. a := "select 1; -- ( begin case end ) ;\nselect 2;" b := "select 1;\nselect 2;\n-- ( begin case end ) ;" if err := CommentsPreserved(a, b); err != nil { t.Fatalf("comment content that looks like code tripped the check: %v", err) } } func TestStructurallyBalanced(t *testing.T) { if err := StructurallyBalanced("select f((a+b)*c) from t", "select f( ( a + b ) * c )\nfrom t"); err != nil { t.Errorf("whitespace-only reformat flagged: %v", err) } // Delimiters that live inside a comment or a string must not count. if err := StructurallyBalanced("select ')(' as x -- ((((\nfrom t", "select ')(' as x\n-- ((((\nfrom t"); err != nil { t.Errorf("comment/string delimiters counted: %v", err) } if err := StructurallyBalanced("select (a) from t", "select (a from t"); err == nil { t.Errorf("dropped ')' not detected") } } func TestVerifySafeCatchesNonIdempotent(t *testing.T) { src := "create function f() returns void language sql as $$ select 1 $$;" out := format(src) if err := VerifySafe(src, out, config.Default()); err != nil { t.Fatalf("clean format rejected: %v", err) } // A hand-mangled "output" that differs from what the formatter would produce // must be rejected (idempotence gate). if err := VerifySafe(src, out+"\n\n\n", config.Default()); err == nil { t.Errorf("non-idempotent output accepted") } } func TestVerifySafeBlockCommentInBody(t *testing.T) { // Regression: a multi-line /* */ comment inside a PL/pgSQL body was being // re-split and reindented as if its lines were statements. src := "CREATE FUNCTION f() RETURNS void LANGUAGE plpgsql AS $$\n" + "BEGIN\n" + " /*\n" + " update t u\n" + " set x = 1\n" + " where u.id = 2\n" + " and u.y = 3;\n" + " */\n" + " perform 1;\n" + "END $$;\n" out := format(src) if err := VerifySafe(src, out, config.Default()); err != nil { t.Fatalf("block comment in body mangled: %v", err) } if !strings.Contains(out, "where u.id = 2") { t.Errorf("block comment interior lost a line:\n%s", out) } }