blob: d4c5fbc200c3de9cd28e4afeb753828b2dd62022 [file] [log] [blame]
// Copyright 2016 The Vanadium 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 pattern
import (
"testing"
"v.io/v23/verror"
)
type patternTest struct {
pattern string
escChar rune
wantRegex string
wantFixedPrefix string
wantNoWildcards bool
matches []string
nonMatches []string
}
func TestPatternParse(t *testing.T) {
tests := []patternTest{
{
"abc", '\\',
"^abc$",
"abc", true,
[]string{"abc"},
[]string{"a", "abcd", "xabc"},
},
{
"abc%", '\\',
"^abc.*?$",
"abc", false,
[]string{"abc", "abcd", "abcabc"},
[]string{"xabcd"},
},
{
"abc_", '\\',
"^abc.$",
"abc", false,
[]string{"abcd", "abc1"},
[]string{"abc", "xabcd", "abcde"},
},
{
"*%*_%", '*',
"^%_.*?$",
"%_", false,
[]string{"%_", "%_abc"},
[]string{"%a", "abc%_abc"},
},
{
"abc^_", '^',
"^abc_$",
"abc_", true,
[]string{"abc_"},
[]string{"abc", "xabcd", "abcde"},
},
{
"abc^%", '^',
"^abc%$",
"abc%", true,
[]string{"abc%"},
[]string{"abc", "xabcd", "abcde"},
},
{
"abc^^%", '^',
"^abc\\^.*?$",
"abc^", false,
[]string{"abc^", "abc^de", "abc^%"},
[]string{"abc", "abcd", "xabc^d"},
},
{
"abc_efg", '\\',
"^abc.efg$",
"abc", false,
[]string{"abcdefg"},
[]string{"abc", "xabcd", "abcde", "abcdefgh"},
},
{
"abc%def", '\\',
"^abc.*?def$",
"abc", false,
[]string{"abcdefdef", "abcdef", "abcdefghidef"},
[]string{"abcdefg", "abcdefde"},
},
{
"[0-9]*abc%def", '\\',
"^\\[0-9\\]\\*abc.*?def$",
"[0-9]*abc", false,
[]string{"[0-9]*abcdefdef", "[0-9]*abcdef", "[0-9]*abcdefghidef"},
[]string{"0abcdefg", "9abcdefde", "[0-9]abcdefg", "[0-9]abcdefg", "[0-9]abcdefg"},
},
{
"abc\x00%def\x00", '\x00', // nul character doesn't escape
"^abc\x00.*?def\x00$",
"abc\x00", false,
[]string{"abc\x00defdef\x00", "abc\x00def\x00", "abc\x00defghidef\x00"},
[]string{"abcdef\x00", "abc%def", "abc\x00defg", "abc\x00def\x00de", "abc\x00defdef"},
},
}
for _, test := range tests {
p, err := ParseWithEscapeChar(test.pattern, test.escChar)
if err != nil {
t.Fatalf("failed to parse pattern %q: %v", test.pattern, err)
}
if got, want := p.regex.String(), test.wantRegex; got != want {
t.Errorf("pattern %q: expected regex %q, got %q", test.pattern, want, got)
}
if got, want := p.fixedPrefix, test.wantFixedPrefix; got != want {
t.Errorf("pattern %q: expected fixedPrefix %q, got %q", test.pattern, want, got)
}
if got, want := p.noWildcards, test.wantNoWildcards; got != want {
t.Errorf("pattern %q: expected noWildcards %v, got %v", test.pattern, want, got)
}
// Make sure all expected matches actually match.
for _, m := range test.matches {
if !p.MatchString(m) {
t.Errorf("pattern %q: expected %q to match", test.pattern, m)
}
}
// Make sure all expected nonMatches actually don't match.
for _, n := range test.nonMatches {
if p.MatchString(n) {
t.Errorf("pattern %q: expected %q to not match", test.pattern, n)
}
}
}
}
func TestPatternParseError(t *testing.T) {
escChar := '#'
errorPatterns := []string{
"#",
"abc#",
"a#bc",
"a%bc##de#_f#gh",
"a%bc##de#_f#",
"###",
"###a_",
"a#bc%de",
}
for _, p := range errorPatterns {
if _, err := ParseWithEscapeChar(p, escChar); verror.ErrorID(err) != ErrInvalidEscape.ID {
t.Errorf("pattern %q: expected ErrInvalidEscape, got %v", p, err)
}
}
}
type escapeTest struct {
literal string
escChar rune
wantPattern string
}
func TestPatternEscape(t *testing.T) {
tests := []escapeTest{
{
"abc", '#',
"abc",
},
{
"abcabc", 'b',
"abbcabbc",
},
{
"ab%c", '#',
"ab#%c",
},
{
"_abc%&", '&',
"&_abc&%&&",
},
{
"___", '^',
"^_^_^_",
},
{
"abc%", '\\',
"abc\\%",
},
{
"_同步数据库_", '钒',
"钒_同步数据库钒_",
},
}
for _, test := range tests {
ep := EscapeWithEscapeChar(test.literal, test.escChar)
if got, want := ep, test.wantPattern; got != want {
t.Errorf("literal %q: expected escape %q, got %q", test.literal, want, got)
}
if p, err := ParseWithEscapeChar(ep, test.escChar); err != nil {
t.Fatalf("failed to parse escaped pattern %q: %v", ep, err)
} else if !p.noWildcards {
t.Errorf("literal %q: escaped pattern contains unescaped wildcards", test.literal)
}
}
}