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
|
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
|
package girc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"testing"
|
"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