package ui import ( "reflect" "strings" "testing" ) func TestBuildConnString(t *testing.T) { tests := []struct { name string fields ConnFields mask bool want string }{ { name: "postgres defaults with db", fields: func() ConnFields { f := DefaultConnFields(ConnPostgres); f.Database = "app"; return f }(), want: "postgres://postgres@localhost:5432/app?sslmode=disable", }, { name: "postgres password unmasked", fields: ConnFields{Kind: ConnPostgres, Host: "db", Port: "5433", Database: "x", User: "u", Password: "p@ss/w", SSLMode: "require"}, want: "postgres://u:p%40ss%2Fw@db:5433/x?sslmode=require", }, { name: "postgres password masked", fields: ConnFields{Kind: ConnPostgres, Host: "db", Port: "5432", Database: "x", User: "u", Password: "secret"}, mask: true, want: "postgres://u:****@db:5432/x", }, { name: "mssql", fields: ConnFields{Kind: ConnMSSQL, Host: "sql", Port: "1433", Database: "shop", User: "sa", Password: "pw", SSLMode: "disable"}, want: "sqlserver://sa:pw@sql:1433?database=shop&encrypt=disable", }, { name: "sqlite is the plain path", fields: ConnFields{Kind: ConnSQLite, FilePath: "/tmp/a b.db"}, want: "/tmp/a b.db", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := BuildConnString(tt.fields, tt.mask); got != tt.want { t.Errorf("got %q, want %q", got, tt.want) } }) } } func TestMaskedBuildHidesPassword(t *testing.T) { f := ConnFields{Kind: ConnMSSQL, Host: "h", User: "u", Password: "hunter2"} if got := BuildConnString(f, true); strings.Contains(got, "hunter2") { t.Errorf("masked string leaks password: %q", got) } } func TestParseConnString(t *testing.T) { tests := []struct { name string in string want ConnFields }{ { name: "postgres full", in: "postgres://u:p%40ss@db:5433/app?sslmode=require&application_name=x", want: ConnFields{Kind: ConnPostgres, Host: "db", Port: "5433", Database: "app", User: "u", Password: "p@ss", SSLMode: "require"}, }, { name: "postgresql scheme, default port", in: "postgresql://u@db/app", want: ConnFields{Kind: ConnPostgres, Host: "db", Port: "5432", Database: "app", User: "u"}, }, { name: "mssql", in: "sqlserver://sa:pw@sql:1444?database=shop&encrypt=true", want: ConnFields{Kind: ConnMSSQL, Host: "sql", Port: "1444", Database: "shop", User: "sa", Password: "pw", SSLMode: "true"}, }, { name: "sqlite path", in: "/data/app.db", want: ConnFields{Kind: ConnSQLite, FilePath: "/data/app.db"}, }, { name: "sqlite scheme", in: "sqlite:///data/app.db", want: ConnFields{Kind: ConnSQLite, FilePath: "/data/app.db"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := ParseConnString(tt.in, ConnPostgres) if err != nil { t.Fatal(err) } got.Extra = nil if !reflect.DeepEqual(got, tt.want) { t.Errorf("got %+v, want %+v", got, tt.want) } }) } } func TestParseConnStringEmptyUsesHintDefaults(t *testing.T) { got, err := ParseConnString(" ", ConnMSSQL) if err != nil { t.Fatal(err) } if got.Kind != ConnMSSQL || got.Port != "1433" || got.Host != "localhost" { t.Errorf("unexpected defaults: %+v", got) } } func TestParseConnStringInvalid(t *testing.T) { if _, err := ParseConnString("postgres://u:p@host:badport/db", ConnPostgres); err == nil { t.Error("expected error for invalid port") } } func TestConnStringRoundTrip(t *testing.T) { for _, in := range []string{ "postgres://u:pw@db:5433/app?application_name=x&sslmode=require", "sqlserver://sa:pw@sql:1433?application+name=x&database=shop&encrypt=false", } { f, err := ParseConnString(in, ConnPostgres) if err != nil { t.Fatal(err) } if got := BuildConnString(f, false); got != in { t.Errorf("round trip: got %q, want %q", got, in) } } } func TestTestConnectionSQLite(t *testing.T) { if err := TestConnection(ConnFields{Kind: ConnSQLite}); err == nil { t.Error("expected error for empty path") } if err := TestConnection(ConnFields{Kind: ConnSQLite, FilePath: t.TempDir() + "/missing.db"}); err == nil { t.Error("expected error for missing file") } }