package pgsql import ( "reflect" "testing" ) func TestExtractWithClause(t *testing.T) { tests := []struct { name string input string want string }{ {"empty", "", ""}, {"no clause", "opclass=vector_cosine_ops", ""}, {"simple", "WITH (lists=100)", "lists=100"}, {"lowercase", "with (m = 16, ef_construction = 64)", "m = 16, ef_construction = 64"}, { "index definition", "CREATE INDEX i ON t USING ivfflat (embedding vector_cosine_ops) WITH (lists='100')", "lists='100'", }, {"paren inside quotes", "with (key_field='id(x)')", "key_field='id(x)'"}, {"dollar quoted", "with (options = $$f(x)$$)", "options = $$f(x)$$"}, {"word boundary", "swith (lists=100)", ""}, {"not followed by paren", "with lists=100", ""}, {"unterminated", "with (lists=100", ""}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := ExtractWithClause(tt.input); got != tt.want { t.Errorf("ExtractWithClause(%q) = %q, want %q", tt.input, got, tt.want) } }) } } func TestSplitStorageParameters(t *testing.T) { tests := []struct { name string input string want []string }{ {"empty", "", []string{}}, {"single", "lists=100", []string{"lists=100"}}, {"multiple", "m = 16, ef_construction = 64", []string{"m = 16", "ef_construction = 64"}}, {"comma in quotes", "key_field='a,b', m=16", []string{"key_field='a,b'", "m=16"}}, {"comma in dollar quotes", "options=$$a,b$$, m=16", []string{"options=$$a,b$$", "m=16"}}, {"comma in brackets", "options=[1,2], m=16", []string{"options=[1,2]", "m=16"}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := SplitStorageParameters(tt.input); !reflect.DeepEqual(got, tt.want) { t.Errorf("SplitStorageParameters(%q) = %v, want %v", tt.input, got, tt.want) } }) } } func TestParseStorageParameter(t *testing.T) { tests := []struct { name string input string wantKey string wantValue string wantOK bool }{ {"bare", "lists=100", "lists", "100", true}, {"spaced and uppercased key", " Lists = 100 ", "lists", "100", true}, {"quoted", "key_field='id'", "key_field", "'id'", true}, {"dollar quoted", "options=$$a$$", "options", "$$a$$", true}, {"boolean", "deduplicate_items=true", "deduplicate_items", "true", true}, {"float", "fillfactor=90.5", "fillfactor", "90.5", true}, {"no equals", "please drop everything", "", "", false}, {"empty value", "lists=", "", "", false}, {"quoted key rejected", "'lists'=100", "", "", false}, {"injection rejected", "lists=100); drop table t", "", "", false}, {"unterminated quote rejected", "key_field='id", "", "", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { key, value, ok := ParseStorageParameter(tt.input) if key != tt.wantKey || value != tt.wantValue || ok != tt.wantOK { t.Errorf("ParseStorageParameter(%q) = (%q, %q, %v), want (%q, %q, %v)", tt.input, key, value, ok, tt.wantKey, tt.wantValue, tt.wantOK) } }) } } func TestNormalizeStorageParameterValue(t *testing.T) { tests := map[string]string{ "'100'": "100", "'90.5'": "90.5", "'true'": "true", "'id'": "'id'", "100": "100", "$$a,b$$": "$$a,b$$", "'": "'", "''": "''", } for input, want := range tests { if got := NormalizeStorageParameterValue(input); got != want { t.Errorf("NormalizeStorageParameterValue(%q) = %q, want %q", input, got, want) } } }