| // Copyright 2021 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package fuzzy_test |
| |
| import ( |
| "testing" |
| |
| . "golang.org/x/tools/internal/fuzzy" |
| ) |
| |
| func TestSymbolMatchIndex(t *testing.T) { |
| tests := []struct { |
| pattern, input string |
| want int |
| }{ |
| {"test", "foo.TestFoo", 4}, |
| {"test", "test", 0}, |
| {"test", "Test", 0}, |
| {"test", "est", -1}, |
| {"t", "shortest", 7}, |
| {"", "foo", -1}, |
| {"", string([]rune{0}), -1}, // verify that we don't default to an empty pattern. |
| {"anything", "", -1}, |
| } |
| |
| for _, test := range tests { |
| matcher := NewSymbolMatcher(test.pattern) |
| if got, _ := matcher.Match([]string{test.input}); got != test.want { |
| t.Errorf("NewSymbolMatcher(%q).Match(%q) = %v, _, want %v, _", test.pattern, test.input, got, test.want) |
| } |
| } |
| } |
| |
| func TestSymbolRanking(t *testing.T) { |
| matcher := NewSymbolMatcher("test") |
| |
| // symbols to match, in ascending order of ranking. |
| symbols := []string{ |
| "this.is.better.than.most", |
| "test.foo.bar", |
| "thebest", |
| "test.foo", |
| "test.foo", |
| "atest", |
| "testage", |
| "tTest", |
| "foo.test", |
| "test", |
| } |
| prev := 0.0 |
| for _, sym := range symbols { |
| _, score := matcher.Match([]string{sym}) |
| t.Logf("Match(%q) = %v", sym, score) |
| if score < prev { |
| t.Errorf("Match(%q) = _, %v, want > %v", sym, score, prev) |
| } |
| prev = score |
| } |
| } |
| |
| // Test that we strongly prefer exact matches. |
| // |
| // In golang/go#60027, we preferred "Runner" for the query "rune" over several |
| // results containing the word "rune" exactly. Following this observation, |
| // scoring was tweaked to more strongly emphasize sequential characters and |
| // exact matches. |
| func TestSymbolRanking_Issue60027(t *testing.T) { |
| matcher := NewSymbolMatcher("rune") |
| |
| // symbols to match, in ascending order of ranking. |
| symbols := []string{ |
| "Runner", |
| "singleRuneParam", |
| "Config.ifsRune", |
| "Parser.rune", |
| } |
| prev := 0.0 |
| for _, sym := range symbols { |
| _, score := matcher.Match([]string{sym}) |
| t.Logf("Match(%q) = %v", sym, score) |
| if score < prev { |
| t.Errorf("Match(%q) = _, %v, want > %v", sym, score, prev) |
| } |
| prev = score |
| } |
| } |
| |
| func TestChunkedMatch(t *testing.T) { |
| matcher := NewSymbolMatcher("test") |
| |
| chunked := [][]string{ |
| {"test"}, |
| {"", "test"}, |
| {"test", ""}, |
| {"te", "st"}, |
| } |
| |
| for _, chunks := range chunked { |
| offset, score := matcher.Match(chunks) |
| if offset != 0 || score != 1.0 { |
| t.Errorf("Match(%v) = %v, %v, want 0, 1.0", chunks, offset, score) |
| } |
| } |
| } |