Upstream: merge in some changes

This commit is contained in:
kayos@tcp.direct 2022-05-02 21:15:53 -07:00
parent f6b2020909
commit 18243520dc
Signed by: kayos
GPG Key ID: 4B841471B4BEE979
12 changed files with 370 additions and 258 deletions

View File

@ -553,7 +553,7 @@ func handleMOTD(c *Client, e Event) {
}
// Otherwise, assume we're getting sent the MOTD line-by-line.
if len(c.state.motd) != 0 {
if c.state.motd != "" {
c.state.motd += "\n"
}
c.state.motd += e.Last()

2
cap.go
View File

@ -62,7 +62,7 @@ func possibleCapList(c *Client) map[string][]string {
if !c.Config.DisableSTS && !c.Config.SSL {
// If fallback supported, and we failed recently, don't try negotiating STS.
// ONLY do this fallback if we're expired (primarily useful during the first
// sts negotation).
// sts negotiation).
if time.Since(c.state.sts.lastFailed) < 5*time.Minute && !c.Config.DisableSTSFallback {
c.debug.Println("skipping strict transport policy negotiation; failed within the last 5 minutes")
} else {

View File

@ -34,26 +34,36 @@ func TestCapSupported(t *testing.T) {
}
}
func TestParseCap(t *testing.T) {
tests := []struct {
in string
want map[string]map[string]string
}{
{in: "sts=port=6697,duration=1234567890,preload", want: map[string]map[string]string{"sts": {"duration": "1234567890", "preload": "", "port": "6697"}}},
{in: "userhost-in-names", want: map[string]map[string]string{"userhost-in-names": nil}},
{in: "userhost-in-names test2", want: map[string]map[string]string{"userhost-in-names": nil, "test2": nil}},
{in: "example/name=test", want: map[string]map[string]string{"example/name": {"test": ""}}},
{
in: "userhost-in-names example/name example/name2=test=1,test2=true",
want: map[string]map[string]string{
"userhost-in-names": nil,
"example/name": nil,
"example/name2": {"test": "1", "test2": "true"},
},
var testsParseCap = []struct {
in string
want map[string]map[string]string
}{
{in: "sts=port=6697,duration=1234567890,preload", want: map[string]map[string]string{"sts": {"duration": "1234567890", "preload": "", "port": "6697"}}},
{in: "userhost-in-names", want: map[string]map[string]string{"userhost-in-names": nil}},
{in: "userhost-in-names test2", want: map[string]map[string]string{"userhost-in-names": nil, "test2": nil}},
{in: "example/name=test", want: map[string]map[string]string{"example/name": {"test": ""}}},
{
in: "userhost-in-names example/name example/name2=test=1,test2=true",
want: map[string]map[string]string{
"userhost-in-names": nil,
"example/name": nil,
"example/name2": {"test": "1", "test2": "true"},
},
},
}
func FuzzParseCap(f *testing.F) {
for _, tc := range testsParseCap {
f.Add(tc.in)
}
for _, tt := range tests {
f.Fuzz(func(t *testing.T, orig string) {
_ = parseCap(orig)
})
}
func TestParseCap(t *testing.T) {
for _, tt := range testsParseCap {
got := parseCap(tt.in)
if !reflect.DeepEqual(got, tt.want) {

View File

@ -11,7 +11,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"os"
@ -275,10 +274,10 @@ func (conf *Config) isValid() error {
}
if !IsValidNick(conf.Nick) {
return &ErrInvalidConfig{Conf: *conf, err: errors.New("bad nickname specified: " + conf.Nick)}
return &ErrInvalidConfig{Conf: *conf, err: fmt.Errorf("bad nickname specified: %s", conf.Nick)}
}
if !IsValidUser(conf.User) {
return &ErrInvalidConfig{Conf: *conf, err: errors.New("bad user/ident specified: " + conf.User)}
return &ErrInvalidConfig{Conf: *conf, err: fmt.Errorf("bad user/ident specified: %s", conf.Nick)}
}
return nil
@ -320,7 +319,7 @@ func New(config Config) *Client {
if envDebug {
c.debug = log.New(os.Stderr, "debug:", log.Ltime|log.Lshortfile)
} else {
c.debug = log.New(ioutil.Discard, "", 0)
c.debug = log.New(io.Discard, "", 0)
}
} else {
if envDebug {
@ -850,7 +849,7 @@ func (c *Client) debugLogEvent(e *Event, dropped bool) {
if pretty, ok := e.Pretty(); ok {
fmt.Fprintln(c.Config.Out, StripRaw(pretty))
_, _ = fmt.Fprintln(c.Config.Out, StripRaw(pretty))
}
}
}

View File

@ -36,7 +36,7 @@ func (cmd *Commands) Join(channels ...string) {
continue
}
if len(buffer) == 0 {
if buffer == "" {
buffer = channels[i]
} else {
buffer += "," + channels[i]
@ -366,7 +366,7 @@ func (cmd *Commands) List(channels ...string) {
continue
}
if len(buffer) == 0 {
if buffer == "" {
buffer = channels[i]
} else {
buffer += "," + channels[i]

17
conn.go
View File

@ -167,18 +167,6 @@ func (c *ircConn) decode() (event *Event, err error) {
return event, nil
}
/*
func (c *ircConn) encode(event *Event) error {
if _, err := c.io.Write(event.Bytes()); err != nil {
return err
}
if _, err := c.io.Write(endline); err != nil {
return err
}
return c.io.Flush()
}
*/
func (c *ircConn) newReadWriter() {
c.io = bufio.NewReadWriter(bufio.NewReader(c.sock), bufio.NewWriter(c.sock))
}
@ -609,9 +597,8 @@ func (c *Client) pingLoop(ctx context.Context, errs chan error, working *int32)
past = true
}
if time.Since(c.conn.lastPong.Load().(time.Time)) > c.Config.PingDelay+(120*time.Second) {
// It's 60 seconds over what out ping delay is, connection
// has probably dropped.
if time.Since(c.conn.lastPong.Load().(time.Time)) > c.Config.PingDelay+(180*time.Second) {
// It's 180 seconds over what out ping delay is, connection has probably dropped.
err := ErrTimedOut{
TimeSinceSuccess: time.Since(c.conn.lastPong.Load().(time.Time)),

View File

@ -14,7 +14,7 @@ import (
"time"
)
func mockBuffers() (in *bytes.Buffer, out *bytes.Buffer, irc *ircConn) {
func mockBuffers() (in, out *bytes.Buffer, irc *ircConn) {
in = &bytes.Buffer{}
out = &bytes.Buffer{}
irc = &ircConn{
@ -88,7 +88,7 @@ func TestRate(t *testing.T) {
}
}
func genMockConn() (client *Client, clientConn net.Conn, serverConn net.Conn) {
func genMockConn() (client *Client, clientConn, serverConn net.Conn) {
client = New(Config{
Server: "dummy.int",
Port: 6667,
@ -107,7 +107,7 @@ func mockReadBuffer(conn net.Conn) {
// Accept all outgoing writes from the client.
b := bufio.NewReader(conn)
for {
conn.SetReadDeadline(time.Now().Add(10 * time.Second))
_ = conn.SetReadDeadline(time.Now().Add(10 * time.Second))
_, err := b.ReadString(byte('\n'))
if err != nil {
return

View File

@ -104,8 +104,8 @@ func EncodeCTCP(ctcp *CTCPEvent) (out string) {
// EncodeCTCPRaw is much like EncodeCTCP, however accepts a raw command and
// string as input.
func EncodeCTCPRaw(cmd, text string) (out string) {
if len(cmd) <= 0 {
return ""
if cmd == "" {
return cmd
}
out = string(ctcpDelim) + cmd
@ -191,9 +191,8 @@ func (c *CTCP) Set(cmd string, handler func(client *Client, ctcp CTCPEvent)) {
return
}
c.mu.Lock()
defer c.mu.Unlock()
c.handlers[cmd] = handler
c.mu.Unlock()
}
// SetBg is much like Set, however the handler is executed in the background,

View File

@ -9,26 +9,40 @@ import (
"sync/atomic"
"testing"
"time"
"unicode/utf8"
)
var testsEncodeCTCP = []struct {
name string
test *CTCPEvent
want string
}{
{name: "command only", test: &CTCPEvent{Command: "TEST", Text: ""}, want: "\001TEST\001"},
{name: "command with args", test: &CTCPEvent{Command: "TEST", Text: "TEST"}, want: "\001TEST TEST\001"},
{name: "nil command", test: &CTCPEvent{Command: "", Text: "TEST"}, want: ""},
{name: "nil event", test: nil, want: ""},
}
func FuzzEncodeCTCP(f *testing.F) {
for _, tc := range testsEncodeCTCP {
if tc.test == nil {
continue
}
f.Add(tc.test.Command, tc.test.Text)
}
f.Fuzz(func(t *testing.T, cmd, text string) {
got := EncodeCTCP(&CTCPEvent{Command: cmd, Text: text})
if utf8.ValidString(cmd) && utf8.ValidString(text) && !utf8.ValidString(got) {
t.Errorf("produced invalid UTF-8 string %q", got)
}
})
}
func TestEncodeCTCP(t *testing.T) {
type args struct {
ctcp *CTCPEvent
}
tests := []struct {
name string
args args
want string
}{
{name: "command only", args: args{ctcp: &CTCPEvent{Command: "TEST", Text: ""}}, want: "\001TEST\001"},
{name: "command with args", args: args{ctcp: &CTCPEvent{Command: "TEST", Text: "TEST"}}, want: "\001TEST TEST\001"},
{name: "nil command", args: args{ctcp: &CTCPEvent{Command: "", Text: "TEST"}}, want: ""},
{name: "nil event", args: args{ctcp: nil}, want: ""},
}
for _, tt := range tests {
if got := EncodeCTCP(tt.args.ctcp); got != tt.want {
for _, tt := range testsEncodeCTCP {
if got := EncodeCTCP(tt.test); got != tt.want {
t.Errorf("%s: encodeCTCP() = %q, want %q", tt.name, got, tt.want)
}
}
@ -110,7 +124,8 @@ func TestCall(t *testing.T) {
atomic.AddUint64(&counter, 1)
})
if ctcp.call(New(Config{}), &CTCPEvent{Command: "TEST"}); atomic.LoadUint64(&counter) != 1 {
ctcp.call(New(Config{}), &CTCPEvent{Command: "TEST"})
if atomic.LoadUint64(&counter) != 1 {
t.Fatal("regular execution: call() didn't increase counter")
}
ctcp.Clear("TEST")
@ -120,7 +135,8 @@ func TestCall(t *testing.T) {
})
ctcp.call(New(Config{}), &CTCPEvent{Command: "TEST"})
if time.Sleep(250 * time.Millisecond); atomic.LoadUint64(&counter) != 2 {
time.Sleep(250 * time.Millisecond)
if atomic.LoadUint64(&counter) != 2 {
t.Fatal("goroutine execution: call() in goroutine didn't increase counter")
}
ctcp.Clear("TEST")
@ -129,14 +145,15 @@ func TestCall(t *testing.T) {
atomic.AddUint64(&counter, 1)
})
if ctcp.call(New(Config{}), &CTCPEvent{Command: "TEST"}); atomic.LoadUint64(&counter) != 3 {
ctcp.call(New(Config{}), &CTCPEvent{Command: "TEST"})
if atomic.LoadUint64(&counter) != 3 {
t.Fatal("wildcard execution: call() didn't increase counter")
}
ctcp.Clear("*")
ctcp.Clear("TEST")
if ctcp.call(New(Config{}), &CTCPEvent{Command: "TEST"}); atomic.LoadUint64(&counter) != 3 {
ctcp.call(New(Config{}), &CTCPEvent{Command: "TEST"})
if atomic.LoadUint64(&counter) != 3 {
t.Fatal("empty execution: call() with no handler incremented the counter")
}
}

View File

@ -52,7 +52,7 @@ func ParseEvent(raw string) (e *Event) {
i = 0
}
if raw[0] == messagePrefix {
if raw != "" && raw[0] == messagePrefix {
// Prefix ends with a space.
i = strings.IndexByte(raw, eventSpace)
@ -313,7 +313,9 @@ func (e *Event) Bytes() []byte {
buffer.Truncate(maxLength)
}
out := buffer.Bytes()
// If we truncated in the middle of a utf8 character, we need to remove
// the other (now invalid) bytes.
out := bytes.ToValidUTF8(buffer.Bytes(), nil)
// Strip newlines and carriage returns.
for i := 0; i < len(out); i++ {
@ -638,7 +640,7 @@ func (s *Source) IsHostmask() bool {
// IsServer returns true if this source looks like a server name.
func (s *Source) IsServer() bool {
return len(s.Ident) <= 0 && len(s.Host) <= 0
return s.Ident == "" && s.Host == ""
}
// writeTo is an utility function to write the source to the bytes.Buffer

View File

@ -127,10 +127,10 @@ func Fmt(text string) string {
// See Fmt() for more information.
func TrimFmt(text string) string {
for color := range fmtColors {
text = strings.Replace(text, string(fmtOpenChar)+color+string(fmtCloseChar), "", -1)
text = strings.ReplaceAll(text, string(fmtOpenChar)+color+string(fmtCloseChar), "")
}
for code := range fmtCodes {
text = strings.Replace(text, string(fmtOpenChar)+code+string(fmtCloseChar), "", -1)
text = strings.ReplaceAll(text, string(fmtOpenChar)+code+string(fmtCloseChar), "")
}
return text
@ -138,7 +138,7 @@ func TrimFmt(text string) string {
// This is really the only fastest way of doing this (marginally better than
// actually trying to parse it manually.)
var reStripColor = regexp.MustCompile(`\x03([019]?[0-9](,[019]?[0-9])?)?`)
var reStripColor = regexp.MustCompile(`\x03([019]?\d(,[019]?\d)?)?`)
// StripRaw tries to strip all ASCII format codes that are used for IRC.
// Primarily, foreground/background colors, and other control bytes like
@ -148,7 +148,7 @@ func StripRaw(text string) string {
text = reStripColor.ReplaceAllString(text, "")
for _, code := range fmtCodes {
text = strings.Replace(text, code, "", -1)
text = strings.ReplaceAll(text, code, "")
}
return text
@ -219,7 +219,7 @@ func IsValidChannel(channel string) bool {
// digit = 0x30-0x39
// special = 0x5B-0x60 / 0x7B-0x7D
func IsValidNick(nick string) bool {
if len(nick) <= 0 {
if nick == "" {
return false
}
@ -256,7 +256,7 @@ func IsValidNick(nick string) bool {
// user = 1*( %x01-09 / %x0B-0C / %x0E-1F / %x21-3F / %x41-FF )
// ; any octet except NUL, CR, LF, " " and "@"
func IsValidUser(name string) bool {
if len(name) <= 0 {
if name == "" {
return false
}

View File

@ -7,6 +7,7 @@ package girc
import (
"strings"
"testing"
"unicode/utf8"
)
func BenchmarkFormat(b *testing.B) {
@ -47,207 +48,294 @@ func BenchmarkStripRawLong(b *testing.B) {
}
}
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) {
type args struct {
text string
}
tests := []struct {
name string
args args
want string
}{
{name: "middle", args: args{text: "test{red}test{c}test"}, want: "test\x0304test\x03test"},
{name: "middle with bold", args: args{text: "test{red}{b}test{c}test"}, want: "test\x0304\x02test\x03test"},
{name: "start, end", args: args{text: "{red}test{c}"}, want: "\x0304test\x03"},
{name: "start, middle, end", args: args{text: "{red}te{red}st{c}"}, want: "\x0304te\x0304st\x03"},
{name: "partial", args: args{text: "{redtest{c}"}, want: "{redtest\x03"},
{name: "inside", args: args{text: "{re{c}d}test{c}"}, want: "{re\x03d}test\x03"},
{name: "nothing", args: args{text: "this is a test."}, want: "this is a test."},
{name: "fg and bg", args: args{text: "{red,yellow}test{c}"}, want: "\x0304,08test\x03"},
{name: "just bg", args: args{text: "{,yellow}test{c}"}, want: "test\x03"},
{name: "just red", args: args{text: "{red}test"}, want: "\x0304test"},
{name: "just cyan", args: args{text: "{cyan}test"}, want: "\x0311test"},
}
for _, tt := range tests {
if got := Fmt(tt.args.text); got != tt.want {
t.Errorf("%s: Format(%q) = %q, want %q", tt.name, tt.args.text, got, tt.want)
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) {
type args struct {
text string
}
tests := []struct {
name string
args args
want string
}{
{name: "start, end", args: args{text: "{red}test{c}"}, want: "test"},
{name: "start, middle, end", args: args{text: "{red}te{red}st{c}"}, want: "test"},
{name: "partial", args: args{text: "{redtest{c}"}, want: "{redtest"},
{name: "inside", args: args{text: "{re{c}d}test{c}"}, want: "{red}test"},
{name: "nothing", args: args{text: "this is a test."}, want: "this is a test."},
}
for _, tt := range tests {
if got := TrimFmt(tt.args.text); got != tt.want {
t.Errorf("%s: StripFormat(%q) = %q, want %q", tt.name, tt.args.text, got, tt.want)
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) {
type args struct {
text string
}
tests := []struct {
name string
args args // gets passed to Format() before sent
want string
}{
{name: "start, end", args: args{text: "{red}{b}test{c}"}, want: "test"},
{name: "start, end in numbers", args: args{text: "{red}1234{c}"}, want: "1234"},
{name: "start, middle, end", args: args{text: "{red}te{red}st{c}"}, want: "test"},
{name: "partial", args: args{text: "{redtest{c}"}, want: "{redtest"},
{name: "inside", args: args{text: "{re{c}d}test{c}"}, want: "{red}test"},
{name: "fg+bg colors start", args: args{text: "{red,yellow}test{c}"}, want: "test"},
{name: "fg+bg colors start in numbers", args: args{text: "{red,yellow}1234{c}"}, want: "1234"},
{name: "fg+bg colors end", args: args{text: "test{,yellow}"}, want: "test"},
{name: "bg colors start", args: args{text: "{,yellow}test{c}"}, want: "test"},
{name: "inside", args: args{text: "{re{c}d}test{c}"}, want: "{red}test"},
{name: "nothing", args: args{text: "this is a test."}, want: "this is a test."},
}
for _, tt := range tests {
if got := StripRaw(Fmt(tt.args.text)); got != tt.want {
t.Fatalf("%s: StripRaw(%q) = %q, want %q", tt.name, tt.args.text, got, tt.want)
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) {
type args struct {
nick string
}
tests := []struct {
name string
args args
want bool
}{
{name: "normal", args: args{nick: "test"}, want: true},
{name: "empty", args: args{nick: ""}, want: false},
{name: "hyphen and special", args: args{nick: "test[-]"}, want: true},
{name: "invalid middle", args: args{nick: "test!test"}, want: false},
{name: "invalid dot middle", args: args{nick: "test.test"}, want: false},
{name: "end", args: args{nick: "test!"}, want: false},
{name: "invalid start", args: args{nick: "!test"}, want: false},
{name: "backslash and numeric", args: args{nick: "test[\\0"}, want: true},
{name: "long", args: args{nick: "test123456789AZBKASDLASMDLKM"}, want: true},
{name: "index 0 dash", args: args{nick: "-test"}, want: false},
{name: "index 0 numeric", args: args{nick: "0test"}, want: false},
{name: "RFC1459 non-lowercase-converted", args: args{nick: "test^"}, want: true},
{name: "RFC1459 non-lowercase-converted", args: args{nick: "test~"}, want: false},
}
for _, tt := range tests {
if got := IsValidNick(tt.args.nick); got != tt.want {
t.Errorf("%s: IsValidNick(%q) = %v, want %v", tt.name, tt.args.nick, got, tt.want)
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) {
type args struct {
channel string
}
tests := []struct {
name string
args args
want bool
}{
{name: "valid channel", args: args{channel: "#valid"}, want: true},
{name: "invalid channel comma", args: args{channel: "#invalid,"}, want: false},
{name: "invalid channel space", args: args{channel: "#inva lid"}, want: false},
{name: "valid channel with numerics", args: args{channel: "#1valid0"}, want: true},
{name: "valid channel with special", args: args{channel: "#valid[]test"}, want: true},
{name: "valid channel with special", args: args{channel: "#[]valid[]test[]"}, want: true},
{name: "just hash", args: args{channel: "#"}, want: false},
{name: "empty", args: args{channel: ""}, want: false},
{name: "invalid prefix", args: args{channel: "$invalid"}, want: false},
{name: "too long", args: args{channel: "#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, want: false},
{name: "valid id prefix", args: args{channel: "!12345test"}, want: true},
{name: "invalid id length", args: args{channel: "!1234"}, want: false},
{name: "invalid id length", args: args{channel: "!12345"}, want: false},
{name: "invalid id prefix", args: args{channel: "!test1invalid"}, want: false},
}
for _, tt := range tests {
if got := IsValidChannel(tt.args.channel); got != tt.want {
t.Errorf("%s: IsValidChannel(%q) = %v, want %v", tt.name, tt.args.channel, got, tt.want)
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) {
type args struct {
name string
}
tests := []struct {
name string
args args
want bool
}{
{name: "user without ident server", args: args{name: "~test"}, want: true},
{name: "user with ident server", args: args{name: "test"}, want: true},
{name: "non-alphanumeric first index", args: args{name: "-test"}, want: false},
{name: "non-alphanumeric first index", args: args{name: "[test]"}, want: false},
{name: "numeric first index", args: args{name: "0test"}, want: true},
{name: "blank", args: args{name: ""}, want: false},
{name: "just tilde", args: args{name: "~"}, want: false},
{name: "special chars", args: args{name: "test-----"}, want: true},
{name: "special chars", args: args{name: "test-[]-"}, want: true},
{name: "special chars, invalid after first index", args: args{name: "t!--"}, want: false},
}
for _, tt := range tests {
if got := IsValidUser(tt.args.name); got != tt.want {
t.Errorf("%s: IsValidUser(%q) = %v, want %v", tt.name, tt.args.name, got, tt.want)
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)
}
}
}
func TestToRFC1459(t *testing.T) {
cases := []struct {
in string
want string
}{
{"", ""},
{"a", "a"},
{"abcd", "abcd"},
{"AbcD", "abcd"},
{"!@#$%^&*()_+-=", "!@#$%~&*()_+-="},
{"Abcd[]", "abcd{}"},
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)
}
for _, tt := range cases {
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")
// }
// }
//
// 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")
}
}
}
func testGlobMatch(t *testing.T, subj, pattern string) {
if !Glob(subj, pattern) {
@ -310,27 +398,37 @@ func TestPatternWithoutGlobs(t *testing.T) {
testGlobMatch(t, "test", "test")
}
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.
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)
}
for _, pattern := range cases {
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{
cases := []string{
"test*", // Implicit substring match.
"*is", // Partial match.
"*no*", // Globs without a match between them.