package repository import ( "context" "slices" "strings" "testing" "time" ) func TestOpenPostGISDoesNotExposeInvalidDSN(t *testing.T) { secret := "do-not-leak" _, err := OpenPostGIS(context.Background(), PostGISOptions{ DSN: "postgresql://user:" + secret + "%zz@localhost/database", MaxConns: 1, ConnectTimeout: time.Second, QueryTimeout: time.Second, }) if err == nil { t.Fatal("OpenPostGIS() error = nil") } if strings.Contains(err.Error(), secret) { t.Fatalf("OpenPostGIS() leaked DSN content: %v", err) } } func TestValidateReadinessAcceptsExpectedGeometryContracts(t *testing.T) { report := validReadinessReport() if err := validateReadiness(report, 4326); err != nil { t.Fatalf("validateReadiness() error = %v", err) } } func TestValidateReadinessRejectsUnsafeSpatialMetadata(t *testing.T) { tests := []struct { name string mutate func(*ReadinessReport) want string }{ { name: "SRID zero", mutate: func(report *ReadinessReport) { report.Tables[0].SRIDs = []int{0} }, want: "unexpected SRID 0", }, { name: "mixed SRID", mutate: func(report *ReadinessReport) { report.Tables[1].SRIDs = []int{4326, 3857} }, want: "unexpected SRID 3857", }, { name: "unexpected geometry type", mutate: func(report *ReadinessReport) { report.Tables[2].GeometryTypes = []string{"POLYGON"} }, want: "unexpected geometry type POLYGON", }, { name: "coordinate outside WGS84", mutate: func(report *ReadinessReport) { report.Tables[0].OutOfBoundsCount = 1 }, want: "outside WGS84 bounds", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { report := validReadinessReport() tt.mutate(&report) err := validateReadiness(report, 4326) if err == nil || !strings.Contains(err.Error(), tt.want) { t.Fatalf("validateReadiness() error = %v, want %q", err, tt.want) } }) } } func TestValidateReadinessAllowsInvalidGeometriesThatQueriesExclude(t *testing.T) { report := validReadinessReport() report.Tables[5].InvalidCount = 4 report.Tables[6].InvalidCount = 4 report.Tables[7].InvalidCount = 27 if err := validateReadiness(report, 4326); err != nil { t.Fatalf("validateReadiness() error = %v", err) } } func TestTableAuditWarningsExposeExcludedInvalidGeometries(t *testing.T) { audit := TableAudit{ Table: "st_2_fanghuowangge", RowCount: 2, NullGeometryCount: 1, EmptyGeometryCount: 1, InvalidCount: 1, HasGISTIndex: false, } warnings := tableAuditWarnings(audit) for _, want := range []string{ "st_2_fanghuowangge:null_geometries_excluded", "st_2_fanghuowangge:empty_geometries_excluded", "st_2_fanghuowangge:invalid_geometries_excluded", "st_2_fanghuowangge:missing_gist_geometry_index", } { if !slices.Contains(warnings, want) { t.Fatalf("warnings = %#v, want %q", warnings, want) } } } func TestSpatialQueriesKeepScopeAndBoundsParameterized(t *testing.T) { nearbyQueries := []struct { name string query string wantScopePredicates int }{ {name: "water sources", query: nearbyWaterSourcesSQL, wantScopePredicates: 2}, {name: "command posts", query: commandPostCandidatesSQL, wantScopePredicates: 2}, {name: "access lines", query: nearbyAccessLinesSQL, wantScopePredicates: 1}, {name: "risk areas", query: nearbyRiskAreasSQL, wantScopePredicates: 2}, } for _, tt := range nearbyQueries { query := tt.query for _, required := range []string{"$3::boolean", "ANY($4::text[])", "$5", "LIMIT $6", "ST_SRID", "ST_IsValid", "ST_IsEmpty", "ST_Expand"} { if !strings.Contains(query, required) { t.Fatalf("%s query lacks %q", tt.name, required) } } if got := strings.Count(query, "($3::boolean OR"); got != tt.wantScopePredicates { t.Fatalf("%s query has %d scope predicates, want %d", tt.name, got, tt.wantScopePredicates) } if got := strings.Count(query, "ANY($4::text[])"); got != tt.wantScopePredicates { t.Fatalf("%s query has %d town predicates, want %d", tt.name, got, tt.wantScopePredicates) } } for index, query := range []string{resolveIncidentContextSQL, responsibleUnitsSQL} { for _, required := range []string{"$3::boolean", "ANY($4::text[])", "ST_SRID", "ST_IsValid", "ST_Covers"} { if !strings.Contains(query, required) { t.Fatalf("cover query %d lacks %q", index, required) } } if got := strings.Count(query, "($3::boolean OR"); got != 1 { t.Fatalf("cover query %d has %d scope predicates, want 1", index, got) } } } func TestPlaceCandidateSearchKeepsTermScopeAndLimitParameterized(t *testing.T) { for _, required := range []string{ "lower($1::text)", "($2::boolean OR", "ANY($3::text[])", "LIMIT $4", "strpos", "recorded_point", "representative_point", "ST_Force2D", "ST_IsValid", } { if !strings.Contains(placeCandidateSearchSQL, required) { t.Fatalf("place candidate query lacks %q", required) } } if got := strings.Count(placeCandidateSearchSQL, "($2::boolean OR"); got != len(spatialTableSpecs) { t.Fatalf("place candidate query has %d scope predicates, want %d", got, len(spatialTableSpecs)) } if got := strings.Count(placeCandidateSearchSQL, "ST_IsValid("); got != len(spatialTableSpecs) { t.Fatalf("place candidate query has %d validity filters, want %d", got, len(spatialTableSpecs)) } for _, spec := range spatialTableSpecs { if !strings.Contains(placeCandidateSearchSQL, "public."+spec.name) { t.Fatalf("place candidate query does not include %s", spec.name) } } } func TestSpatialQueriesDoNotSelectSensitiveContactColumns(t *testing.T) { queries := strings.Join([]string{ placeCandidateSearchSQL, resolveIncidentContextSQL, nearbyWaterSourcesSQL, commandPostCandidatesSQL, nearbyAccessLinesSQL, responsibleUnitsSQL, nearbyRiskAreasSQL, }, "\n") for _, forbidden := range []string{ "bpld", "bplddh", "csj", "csjdh", "lxdh", "zjwgfzr", "zjfzrlxfs", "fhzddc", "fhzddclxfs", "chzbry", "shzbry", "zbry", ".bz", } { if strings.Contains(strings.ToLower(queries), strings.ToLower(forbidden)) { t.Fatalf("spatial SQL references sensitive contact column %s", forbidden) } } } func TestQuoteIdentifierEscapesEmbeddedQuotes(t *testing.T) { if got, want := quoteIdentifier(`safe"name`), `"safe""name"`; got != want { t.Fatalf("quoteIdentifier() = %q, want %q", got, want) } } func validReadinessReport() ReadinessReport { report := ReadinessReport{Tables: make([]TableAudit, 0, len(spatialTableSpecs))} for _, spec := range spatialTableSpecs { report.Tables = append(report.Tables, TableAudit{ Table: spec.name, RowCount: 2, GeometryTypes: []string{spec.geometryTypes[0]}, SRIDs: []int{4326}, HasGISTIndex: true, }) } return report }