446 lines
12 KiB
Go
446 lines
12 KiB
Go
// Copyright (c) Liam Stanley <me@liamstanley.io>. All rights reserved. Use
|
|
// of this source code is governed by the MIT license that can be found in
|
|
// the LICENSE file.
|
|
|
|
package girc
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
func BenchmarkFormat(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
Fmt("{red}test{c}")
|
|
}
|
|
}
|
|
|
|
func BenchmarkFormatLong(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
Fmt("{red}test {blue}2 {red}3 {brown} {italic}test{c}")
|
|
}
|
|
}
|
|
|
|
func BenchmarkStripFormat(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
TrimFmt("{red}test{c}")
|
|
}
|
|
}
|
|
|
|
func BenchmarkStripFormatLong(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
TrimFmt("{red}test {blue}2 {red}3 {brown} {italic}test{c}")
|
|
}
|
|
}
|
|
|
|
func BenchmarkStripRaw(b *testing.B) {
|
|
text := Fmt("{red}test{c}")
|
|
for i := 0; i < b.N; i++ {
|
|
StripRaw(text)
|
|
}
|
|
}
|
|
|
|
func BenchmarkStripRawLong(b *testing.B) {
|
|
text := Fmt("{red}test {blue}2 {red}3 {brown} {italic}test{c}")
|
|
for i := 0; i < b.N; i++ {
|
|
StripRaw(text)
|
|
}
|
|
}
|
|
|
|
var testsFormat = []struct {
|
|
name string
|
|
test string
|
|
want string
|
|
}{
|
|
{name: "middle", test: "test{red}test{c}test", want: "test\x0304test\x03test"},
|
|
{name: "middle with bold", test: "test{red}{b}test{c}test", want: "test\x0304\x02test\x03test"},
|
|
{name: "start, end", test: "{red}test{c}", want: "\x0304test\x03"},
|
|
{name: "start, middle, end", test: "{red}te{red}st{c}", want: "\x0304te\x0304st\x03"},
|
|
{name: "partial", test: "{redtest{c}", want: "{redtest\x03"},
|
|
{name: "inside", test: "{re{c}d}test{c}", want: "{re\x03d}test\x03"},
|
|
{name: "nothing", test: "this is a test.", want: "this is a test."},
|
|
{name: "fg and bg", test: "{red,yellow}test{c}", want: "\x0304,08test\x03"},
|
|
{name: "just bg", test: "{,yellow}test{c}", want: "test\x03"},
|
|
{name: "just red", test: "{red}test", want: "\x0304test"},
|
|
{name: "just cyan", test: "{cyan}test", want: "\x0311test"},
|
|
}
|
|
|
|
func FuzzFormat(f *testing.F) {
|
|
for _, tc := range testsFormat {
|
|
f.Add(tc.test)
|
|
}
|
|
|
|
f.Fuzz(func(t *testing.T, orig string) {
|
|
got := Fmt(orig)
|
|
got2 := Fmt(got)
|
|
|
|
if utf8.ValidString(orig) {
|
|
if !utf8.ValidString(got) {
|
|
t.Errorf("produced invalid UTF-8 string %q", got)
|
|
}
|
|
|
|
if !utf8.ValidString(got2) {
|
|
t.Errorf("produced invalid UTF-8 string %q", got2)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestFormat(t *testing.T) {
|
|
for _, tt := range testsFormat {
|
|
if got := Fmt(tt.test); got != tt.want {
|
|
t.Errorf("%s: Format(%q) = %q, want %q", tt.name, tt.test, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
var testsStripFormat = []struct {
|
|
name string
|
|
test string
|
|
want string
|
|
}{
|
|
{name: "start, end", test: "{red}test{c}", want: "test"},
|
|
{name: "start, middle, end", test: "{red}te{red}st{c}", want: "test"},
|
|
{name: "partial", test: "{redtest{c}", want: "{redtest"},
|
|
{name: "inside", test: "{re{c}d}test{c}", want: "{red}test"},
|
|
{name: "nothing", test: "this is a test.", want: "this is a test."},
|
|
}
|
|
|
|
func FuzzStripFormat(f *testing.F) {
|
|
for _, tc := range testsStripFormat {
|
|
f.Add(tc.test)
|
|
}
|
|
|
|
f.Fuzz(func(t *testing.T, orig string) {
|
|
got := TrimFmt(orig)
|
|
got2 := TrimFmt(got)
|
|
|
|
if utf8.ValidString(orig) {
|
|
if !utf8.ValidString(got) {
|
|
t.Errorf("produced invalid UTF-8 string %q", got)
|
|
}
|
|
|
|
if !utf8.ValidString(got2) {
|
|
t.Errorf("produced invalid UTF-8 string %q", got2)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestStripFormat(t *testing.T) {
|
|
for _, tt := range testsStripFormat {
|
|
if got := TrimFmt(tt.test); got != tt.want {
|
|
t.Errorf("%s: StripFormat(%q) = %q, want %q", tt.name, tt.test, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
var testsStripRaw = []struct {
|
|
name string
|
|
test string // gets passed to Format() before sent
|
|
want string
|
|
}{
|
|
{name: "start, end", test: "{red}{b}test{c}", want: "test"},
|
|
{name: "start, end in numbers", test: "{red}1234{c}", want: "1234"},
|
|
{name: "start, middle, end", test: "{red}te{red}st{c}", want: "test"},
|
|
{name: "partial", test: "{redtest{c}", want: "{redtest"},
|
|
{name: "inside", test: "{re{c}d}test{c}", want: "{red}test"},
|
|
{name: "fg+bg colors start", test: "{red,yellow}test{c}", want: "test"},
|
|
{name: "fg+bg colors start in numbers", test: "{red,yellow}1234{c}", want: "1234"},
|
|
{name: "fg+bg colors end", test: "test{,yellow}", want: "test"},
|
|
{name: "bg colors start", test: "{,yellow}test{c}", want: "test"},
|
|
{name: "inside", test: "{re{c}d}test{c}", want: "{red}test"},
|
|
{name: "nothing", test: "this is a test.", want: "this is a test."},
|
|
}
|
|
|
|
func FuzzStripRaw(f *testing.F) {
|
|
for _, tc := range testsStripRaw {
|
|
f.Add(tc.test)
|
|
}
|
|
|
|
f.Fuzz(func(t *testing.T, orig string) {
|
|
got := StripRaw(orig)
|
|
got2 := StripRaw(got)
|
|
|
|
if utf8.ValidString(orig) {
|
|
if !utf8.ValidString(got) {
|
|
t.Errorf("produced invalid UTF-8 string %q", got)
|
|
}
|
|
|
|
if !utf8.ValidString(got2) {
|
|
t.Errorf("produced invalid UTF-8 string %q", got2)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestStripRaw(t *testing.T) {
|
|
for _, tt := range testsStripRaw {
|
|
if got := StripRaw(Fmt(tt.test)); got != tt.want {
|
|
t.Fatalf("%s: StripRaw(%q) = %q, want %q", tt.name, tt.test, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
var testsValidNick = []struct {
|
|
name string
|
|
test string
|
|
want bool
|
|
}{
|
|
{name: "normal", test: "test", want: true},
|
|
{name: "empty", test: "", want: false},
|
|
{name: "hyphen and special", test: "test[-]", want: true},
|
|
{name: "invalid middle", test: "test!test", want: false},
|
|
{name: "invalid dot middle", test: "test.test", want: false},
|
|
{name: "end", test: "test!", want: false},
|
|
{name: "invalid start", test: "!test", want: false},
|
|
{name: "backslash and numeric", test: "test[\\0", want: true},
|
|
{name: "long", test: "test123456789AZBKASDLASMDLKM", want: true},
|
|
{name: "index 0 dash", test: "-test", want: false},
|
|
{name: "index 0 numeric", test: "0test", want: false},
|
|
{name: "RFC1459 non-lowercase-converted", test: "test^", want: true},
|
|
{name: "RFC1459 non-lowercase-converted", test: "test~", want: false},
|
|
}
|
|
|
|
func FuzzValidNick(f *testing.F) {
|
|
for _, tc := range testsValidNick {
|
|
f.Add(tc.test)
|
|
}
|
|
|
|
f.Fuzz(func(t *testing.T, orig string) {
|
|
_ = IsValidNick(orig)
|
|
})
|
|
}
|
|
|
|
func TestIsValidNick(t *testing.T) {
|
|
for _, tt := range testsValidNick {
|
|
if got := IsValidNick(tt.test); got != tt.want {
|
|
t.Errorf("%s: IsValidNick(%q) = %v, want %v", tt.name, tt.test, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
var testsValidChannel = []struct {
|
|
name string
|
|
test string
|
|
want bool
|
|
}{
|
|
{name: "valid channel", test: "#valid", want: true},
|
|
{name: "invalid channel comma", test: "#invalid,", want: false},
|
|
{name: "invalid channel space", test: "#inva lid", want: false},
|
|
{name: "valid channel with numerics", test: "#1valid0", want: true},
|
|
{name: "valid channel with special", test: "#valid[]test", want: true},
|
|
{name: "valid channel with special", test: "#[]valid[]test[]", want: true},
|
|
{name: "just hash", test: "#", want: false},
|
|
{name: "empty", test: "", want: false},
|
|
{name: "invalid prefix", test: "$invalid", want: false},
|
|
{name: "too long", test: "#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", want: false},
|
|
{name: "valid id prefix", test: "!12345test", want: true},
|
|
{name: "invalid id length", test: "!1234", want: false},
|
|
{name: "invalid id length", test: "!12345", want: false},
|
|
{name: "invalid id prefix", test: "!test1invalid", want: false},
|
|
}
|
|
|
|
func FuzzValidChannel(f *testing.F) {
|
|
for _, tc := range testsValidChannel {
|
|
f.Add(tc.test)
|
|
}
|
|
|
|
f.Fuzz(func(t *testing.T, orig string) {
|
|
_ = IsValidChannel(orig)
|
|
})
|
|
}
|
|
|
|
func TestIsValidChannel(t *testing.T) {
|
|
for _, tt := range testsValidChannel {
|
|
if got := IsValidChannel(tt.test); got != tt.want {
|
|
t.Errorf("%s: IsValidChannel(%q) = %v, want %v", tt.name, tt.test, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
var testsValidUser = []struct {
|
|
name string
|
|
test string
|
|
want bool
|
|
}{
|
|
{name: "user without ident server", test: "~test", want: true},
|
|
{name: "user with ident server", test: "test", want: true},
|
|
{name: "non-alphanumeric first index", test: "-test", want: false},
|
|
{name: "non-alphanumeric first index", test: "[test]", want: false},
|
|
{name: "numeric first index", test: "0test", want: true},
|
|
{name: "blank", test: "", want: false},
|
|
{name: "just tilde", test: "~", want: false},
|
|
{name: "special chars", test: "test-----", want: true},
|
|
{name: "special chars", test: "test-[]-", want: true},
|
|
{name: "special chars, invalid after first index", test: "t!--", want: false},
|
|
}
|
|
|
|
func FuzzValidUser(f *testing.F) {
|
|
for _, tc := range testsValidUser {
|
|
f.Add(tc.test)
|
|
}
|
|
|
|
f.Fuzz(func(t *testing.T, orig string) {
|
|
_ = IsValidUser(orig)
|
|
})
|
|
}
|
|
|
|
func TestIsValidUser(t *testing.T) {
|
|
for _, tt := range testsValidUser {
|
|
if got := IsValidUser(tt.test); got != tt.want {
|
|
t.Errorf("%s: IsValidUser(%q) = %v, want %v", tt.name, tt.test, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
var testsToRFC1459 = []struct {
|
|
in string
|
|
want string
|
|
}{
|
|
{"", ""},
|
|
{"a", "a"},
|
|
{"abcd", "abcd"},
|
|
{"AbcD", "abcd"},
|
|
{"!@#$%^&*()_+-=", "!@#$%~&*()_+-="},
|
|
{"Abcd[]", "abcd{}"},
|
|
}
|
|
|
|
func FuzzToRFC1459(f *testing.F) {
|
|
for _, tc := range testsToRFC1459 {
|
|
f.Add(tc.in)
|
|
}
|
|
|
|
f.Fuzz(func(t *testing.T, orig string) {
|
|
got := ToRFC1459(orig)
|
|
|
|
if utf8.ValidString(orig) && !utf8.ValidString(got) {
|
|
t.Errorf("produced invalid UTF-8 string %q", got)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestToRFC1459(t *testing.T) {
|
|
for _, tt := range testsToRFC1459 {
|
|
if got := ToRFC1459(tt.in); got != tt.want {
|
|
t.Errorf("ToRFC1459() = %q, want %q", got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
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")
|
|
}
|
|
}
|
|
}
|
|
|
|
func testGlobMatch(t *testing.T, subj, pattern string) {
|
|
if !Glob(subj, pattern) {
|
|
t.Fatalf("'%s' should match '%s'", pattern, subj)
|
|
}
|
|
}
|
|
|
|
func testGlobNoMatch(t *testing.T, subj, pattern string) {
|
|
if Glob(subj, pattern) {
|
|
t.Fatalf("'%s' should not match '%s'", pattern, subj)
|
|
}
|
|
}
|
|
|
|
func TestEmptyPattern(t *testing.T) {
|
|
testGlobMatch(t, "", "")
|
|
testGlobNoMatch(t, "test", "")
|
|
}
|
|
|
|
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, "")
|
|
}
|
|
}
|
|
|
|
func TestPatternWithoutGlobs(t *testing.T) {
|
|
testGlobMatch(t, "test", "test")
|
|
}
|
|
|
|
var testsGlob = []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.
|
|
}
|
|
|
|
func FuzzGlob(f *testing.F) {
|
|
for _, tc := range testsGlob {
|
|
f.Add(tc, tc)
|
|
}
|
|
|
|
f.Fuzz(func(t *testing.T, orig, orig2 string) {
|
|
_ = Glob(orig, orig2)
|
|
})
|
|
}
|
|
|
|
func TestGlob(t *testing.T) {
|
|
for _, pattern := range testsGlob {
|
|
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)
|
|
}
|
|
}
|