Fix invalid cache lookups

This commit is contained in:
Junegunn Choi 2017-08-08 13:22:30 +09:00
parent b208aa675e
commit 999d374f0c
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627
3 changed files with 56 additions and 29 deletions

View File

@ -10,12 +10,12 @@ import (
// fuzzy
// 'exact
// ^exact-prefix
// exact-suffix$
// !not-fuzzy
// !'not-exact
// !^not-exact-prefix
// !not-exact-suffix$
// ^prefix-exact
// suffix-exact$
// !inverse-exact
// !'inverse-fuzzy
// !^inverse-prefix-exact
// !inverse-suffix-exact$
type termType int
@ -32,7 +32,6 @@ type term struct {
inv bool
text []rune
caseSensitive bool
origText []rune
}
type termSet []term
@ -101,7 +100,7 @@ func BuildPattern(fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case,
for idx, term := range termSet {
// If the query contains inverse search terms or OR operators,
// we cannot cache the search scope
if !cacheable || idx > 0 || term.inv || !fuzzy && term.typ != termExact {
if !cacheable || idx > 0 || term.inv || fuzzy && term.typ != termFuzzy || !fuzzy && term.typ != termExact {
cacheable = false
break Loop
}
@ -153,7 +152,6 @@ func parseTerms(fuzzy bool, caseMode Case, normalize bool, str string) []termSet
if !caseSensitive {
text = lowerText
}
origText := []rune(text)
if !fuzzy {
typ = termExact
}
@ -204,8 +202,7 @@ func parseTerms(fuzzy bool, caseMode Case, normalize bool, str string) []termSet
typ: typ,
inv: inv,
text: textRunes,
caseSensitive: caseSensitive,
origText: origText})
caseSensitive: caseSensitive})
switchSet = true
}
}
@ -236,7 +233,7 @@ func (p *Pattern) CacheKey() string {
cacheableTerms := []string{}
for _, termSet := range p.termSets {
if len(termSet) == 1 && !termSet[0].inv && (p.fuzzy || termSet[0].typ == termExact) {
cacheableTerms = append(cacheableTerms, string(termSet[0].origText))
cacheableTerms = append(cacheableTerms, string(termSet[0].text))
}
}
return strings.Join(cacheableTerms, " ")

View File

@ -33,19 +33,11 @@ func TestParseTermsExtended(t *testing.T) {
terms[8][3].typ != termExact || !terms[8][3].inv {
t.Errorf("%s", terms)
}
for idx, termSet := range terms[:8] {
for _, termSet := range terms[:8] {
term := termSet[0]
if len(term.text) != 3 {
t.Errorf("%s", term)
}
if idx > 0 && len(term.origText) != 4+idx/5 {
t.Errorf("%s", term)
}
}
for _, term := range terms[8] {
if len(term.origText) != 4 {
t.Errorf("%s", term)
}
}
}
@ -167,6 +159,7 @@ func TestOrigTextAndTransformed(t *testing.T) {
func TestCacheKey(t *testing.T) {
test := func(extended bool, patStr string, expected string, cacheable bool) {
clearPatternCache()
pat := BuildPattern(true, algo.FuzzyMatchV2, extended, CaseSmart, false, true, true, []Range{}, Delimiter{}, []rune(patStr))
if pat.CacheKey() != expected {
t.Errorf("Expected: %s, actual: %s", expected, pat.CacheKey())
@ -188,19 +181,24 @@ func TestCacheKey(t *testing.T) {
}
func TestCacheable(t *testing.T) {
test := func(fuzzy bool, str string, cacheable bool) {
test := func(fuzzy bool, str string, expected string, cacheable bool) {
clearPatternCache()
pat := BuildPattern(fuzzy, algo.FuzzyMatchV2, true, CaseSmart, true, true, true, []Range{}, Delimiter{}, []rune(str))
if pat.CacheKey() != expected {
t.Errorf("Expected: %s, actual: %s", expected, pat.CacheKey())
}
if cacheable != pat.cacheable {
t.Errorf("Invalid Pattern.cacheable for \"%s\": %v (expected: %v)", str, pat.cacheable, cacheable)
}
clearPatternCache()
}
test(true, "foo bar", true)
test(true, "foo 'bar", true)
test(true, "foo !bar", false)
test(true, "foo bar", "foo bar", true)
test(true, "foo 'bar", "foo bar", false)
test(true, "foo !bar", "foo", false)
test(false, "foo bar", true)
test(false, "foo '", true)
test(false, "foo 'bar", false)
test(false, "foo !bar", false)
test(false, "foo bar", "foo bar", true)
test(false, "foo 'bar", "foo", false)
test(false, "foo '", "foo", true)
test(false, "foo 'bar", "foo", false)
test(false, "foo !bar", "foo", false)
}

View File

@ -719,6 +719,38 @@ class TestGoFZF < TestBase
tmux.send_keys :Enter
end
def test_invalid_cache_query_type
command = %[(echo 'foo\\$bar'; echo 'barfoo'; echo 'foo^bar'; echo \\"foo'1-2\\"; seq 100) | #{fzf}]
# Suffix match
tmux.send_keys command, :Enter
tmux.until { |lines| lines.match_count == 104 }
tmux.send_keys 'foo$'
tmux.until { |lines| lines.match_count == 1 }
tmux.send_keys 'bar'
tmux.until { |lines| lines.match_count == 1 }
tmux.send_keys :Enter
# Prefix match
tmux.prepare
tmux.send_keys command, :Enter
tmux.until { |lines| lines.match_count == 104 }
tmux.send_keys '^bar'
tmux.until { |lines| lines.match_count == 1 }
tmux.send_keys 'C-a', 'foo'
tmux.until { |lines| lines.match_count == 1 }
tmux.send_keys :Enter
# Exact match
tmux.prepare
tmux.send_keys command, :Enter
tmux.until { |lines| lines.match_count == 104 }
tmux.send_keys "'12"
tmux.until { |lines| lines.match_count == 1 }
tmux.send_keys 'C-a', 'foo'
tmux.until { |lines| lines.match_count == 1 }
end
def test_smart_case_for_each_term
assert_equal 1, `echo Foo bar | #{FZF} -x -f "foo Fbar" | wc -l`.to_i
end