implement ToRFC1459(); implement Glob()
This commit is contained in:
parent
fcef03e022
commit
4ec34eb268
61
format.go
61
format.go
@ -232,3 +232,64 @@ func IsValidUser(name string) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// ToRFC1459 converts a string to the stripped down conversion within RFC
|
||||
// 1459. This will do things like replace an "A" with an "a", "[]" with "{}",
|
||||
// and so forth. Useful to compare two nicknames.
|
||||
func ToRFC1459(input string) (out string) {
|
||||
for i := 0; i < len(input); i++ {
|
||||
if input[i] >= 65 && input[i] <= 94 {
|
||||
out += string(rune(input[i]) + 32)
|
||||
} else {
|
||||
out += string(input[i])
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
const globChar = "*"
|
||||
|
||||
// Glob will test a string pattern, potentially containing globs, against a
|
||||
// string. The glob character is *.
|
||||
func Glob(input, match string) bool {
|
||||
// Empty pattern.
|
||||
if match == "" {
|
||||
return input == match
|
||||
}
|
||||
|
||||
// If a glob, match all.
|
||||
if match == globChar {
|
||||
return true
|
||||
}
|
||||
|
||||
parts := strings.Split(match, globChar)
|
||||
|
||||
if len(parts) == 1 {
|
||||
// No globs, test for equality.
|
||||
return input == match
|
||||
}
|
||||
|
||||
leadingGlob, trailingGlob := strings.HasPrefix(match, globChar), strings.HasSuffix(match, globChar)
|
||||
last := len(parts) - 1
|
||||
|
||||
// Check prefix first.
|
||||
if !leadingGlob && !strings.HasPrefix(input, parts[0]) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check middle section.
|
||||
for i := 1; i < last; i++ {
|
||||
if !strings.Contains(input, parts[i]) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Trim already-evaluated text from input during loop over match
|
||||
// text.
|
||||
idx := strings.Index(input, parts[i]) + len(parts[i])
|
||||
input = input[idx:]
|
||||
}
|
||||
|
||||
// Check suffix last.
|
||||
return trailingGlob || strings.HasSuffix(input, parts[last])
|
||||
}
|
||||
|
142
format_test.go
142
format_test.go
@ -5,6 +5,7 @@
|
||||
package girc
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -215,3 +216,144 @@ func TestIsValidUser(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToRFC1459(t *testing.T) {
|
||||
cases := []struct {
|
||||
in string
|
||||
want string
|
||||
}{
|
||||
{"", ""},
|
||||
{"a", "a"},
|
||||
{"abcd", "abcd"},
|
||||
{"AbcD", "abcd"},
|
||||
{"!@#$%^&*()_+-=", "!@#$%~&*()_+-="},
|
||||
{"Abcd[]", "abcd{}"},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
if got := ToRFC1459(tt.in); got != tt.want {
|
||||
t.Errorf("ToRFC1459() = %q, want %q", got, tt.want)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func BenchmarkGlob(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
if !Glob("*quick*fox*dog", "The quick brown fox jumped over the lazy dog") {
|
||||
b.Fatalf("should match")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func testGlobMatch(t *testing.T, subj, pattern string) {
|
||||
if !Glob(subj, pattern) {
|
||||
t.Fatalf("'%s' should match '%s'", pattern, subj)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func testGlobNoMatch(t *testing.T, subj, pattern string) {
|
||||
if Glob(subj, pattern) {
|
||||
t.Fatalf("'%s' should not match '%s'", pattern, subj)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func TestEmptyPattern(t *testing.T) {
|
||||
testGlobMatch(t, "", "")
|
||||
testGlobNoMatch(t, "test", "")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func TestEmptySubject(t *testing.T) {
|
||||
cases := []string{
|
||||
"",
|
||||
"*",
|
||||
"**",
|
||||
"***",
|
||||
"****************",
|
||||
strings.Repeat("*", 1000000),
|
||||
}
|
||||
|
||||
for _, pattern := range cases {
|
||||
testGlobMatch(t, "", pattern)
|
||||
}
|
||||
|
||||
cases = []string{
|
||||
// No globs/non-glob characters.
|
||||
"test",
|
||||
"*test*",
|
||||
|
||||
// Trailing characters.
|
||||
"*x",
|
||||
"*****************x",
|
||||
strings.Repeat("*", 1000000) + "x",
|
||||
|
||||
// Leading characters.
|
||||
"x*",
|
||||
"x*****************",
|
||||
"x" + strings.Repeat("*", 1000000),
|
||||
|
||||
// Mixed leading/trailing characters.
|
||||
"x*x",
|
||||
"x****************x",
|
||||
"x" + strings.Repeat("*", 1000000) + "x",
|
||||
}
|
||||
|
||||
for _, pattern := range cases {
|
||||
testGlobNoMatch(t, pattern, "")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func TestPatternWithoutGlobs(t *testing.T) {
|
||||
testGlobMatch(t, "test", "test")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func TestGlob(t *testing.T) {
|
||||
cases := []string{
|
||||
"*test", // Leading.
|
||||
"this*", // Trailing.
|
||||
"this*test", // Middle.
|
||||
"*is *", // String in between two.
|
||||
"*is*a*", // Lots.
|
||||
"**test**", // Double glob characters.
|
||||
"**is**a***test*", // Varying number.
|
||||
"* *", // White space between.
|
||||
"*", // Lone.
|
||||
"**********", // Nothing but globs.
|
||||
"*Ѿ*", // Unicode.
|
||||
"*is a ϗѾ *", // Mixed ASCII/unicode.
|
||||
}
|
||||
|
||||
for _, pattern := range cases {
|
||||
testGlobMatch(t, "this is a ϗѾ test", pattern)
|
||||
}
|
||||
|
||||
cases = []string{
|
||||
"test*", // Implicit substring match.
|
||||
"*is", // Partial match.
|
||||
"*no*", // Globs without a match between them.
|
||||
" ", // Plain white space.
|
||||
"* ", // Trailing white space.
|
||||
" *", // Leading white space.
|
||||
"*ʤ*", // Non-matching unicode.
|
||||
}
|
||||
|
||||
// Non-matches
|
||||
for _, pattern := range cases {
|
||||
testGlobNoMatch(t, "this is a test", pattern)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user