329 lines
12 KiB
Go
329 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 (
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func mockEvent() *Event {
|
|
return &Event{
|
|
Source: &Source{Name: "nick", Ident: "user", Host: "host.com"},
|
|
Command: "PRIVMSG",
|
|
Params: []string{"#channel", "1 2 3"},
|
|
}
|
|
}
|
|
|
|
func TestParseSource(t *testing.T) {
|
|
type args struct {
|
|
raw string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantSrc *Source
|
|
}{
|
|
{name: "full", args: args{raw: "nick!user@hostname.com"}, wantSrc: &Source{
|
|
Name: "nick", Ident: "user", Host: "hostname.com",
|
|
}},
|
|
{name: "special chars", args: args{raw: "^[]nick!~user@test.host---name.com"}, wantSrc: &Source{
|
|
Name: "^[]nick", Ident: "~user", Host: "test.host---name.com",
|
|
}},
|
|
{name: "short", args: args{raw: "a!b@c"}, wantSrc: &Source{
|
|
Name: "a", Ident: "b", Host: "c",
|
|
}},
|
|
{name: "short", args: args{raw: "a!b"}, wantSrc: &Source{
|
|
Name: "a", Ident: "b", Host: "",
|
|
}},
|
|
{name: "short", args: args{raw: "a@b"}, wantSrc: &Source{
|
|
Name: "a", Ident: "", Host: "b",
|
|
}},
|
|
{name: "short", args: args{raw: "test"}, wantSrc: &Source{
|
|
Name: "test", Ident: "", Host: "",
|
|
}},
|
|
}
|
|
for _, tt := range tests {
|
|
gotSrc := ParseSource(tt.args.raw)
|
|
|
|
if !reflect.DeepEqual(gotSrc, tt.wantSrc) {
|
|
t.Errorf("ParseSource() = %v, want %v", gotSrc, tt.wantSrc)
|
|
}
|
|
|
|
if gotSrc.Len() != tt.wantSrc.Len() {
|
|
t.Errorf("ParseSource().Len() = %v, want %v", gotSrc.Len(), tt.wantSrc.Len())
|
|
}
|
|
|
|
if gotSrc.String() != tt.wantSrc.String() {
|
|
t.Errorf("ParseSource().String() = %v, want %v", gotSrc.String(), tt.wantSrc.String())
|
|
}
|
|
|
|
if gotSrc.IsServer() != tt.wantSrc.IsServer() {
|
|
t.Errorf("ParseSource().IsServer() = %v, want %v", gotSrc.IsServer(), tt.wantSrc.IsServer())
|
|
}
|
|
|
|
if gotSrc.IsHostmask() != tt.wantSrc.IsHostmask() {
|
|
t.Errorf("ParseSource().IsHostmask() = %v, want %v", gotSrc.IsHostmask(), tt.wantSrc.IsHostmask())
|
|
}
|
|
|
|
if !reflect.DeepEqual(gotSrc.Bytes(), tt.wantSrc.Bytes()) {
|
|
t.Errorf("ParseSource().Bytes() = %v, want %v", gotSrc, tt.wantSrc)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseEvent(t *testing.T) {
|
|
tests := []struct {
|
|
in string
|
|
want string
|
|
}{
|
|
{in: "", want: ""},
|
|
{in: ":host.domain.com TEST", want: ":host.domain.com TEST"},
|
|
{in: ":host.domain.com TEST\r\n", want: ":host.domain.com TEST"},
|
|
{in: ":host.domain.com TEST arg1 arg2", want: ":host.domain.com TEST arg1 arg2"},
|
|
{in: ":host.domain.com TEST :", want: ":host.domain.com TEST :"},
|
|
{in: ":host.domain.com TEST ::", want: ":host.domain.com TEST ::"},
|
|
{in: ":host.domain.com TEST :test1", want: ":host.domain.com TEST test1"},
|
|
{in: ":host.domain.com TEST :test:test", want: ":host.domain.com TEST test:test"},
|
|
{in: ":host.domain.com TEST :test1 :test", want: ":host.domain.com TEST :test1 :test"},
|
|
{in: ":host.domain.com TEST :test1 test2", want: ":host.domain.com TEST :test1 test2"},
|
|
{in: ":host.domain.com TEST arg1 arg2 :test1", want: ":host.domain.com TEST arg1 arg2 test1"},
|
|
{in: ":host.domain.com TEST arg1 arg=:10 :test1", want: ":host.domain.com TEST arg1 arg=:10 test1"},
|
|
{in: ":nick!user@host TEST :test1", want: ":nick!user@host TEST test1"},
|
|
{in: ":nick!user@host TEST :test1 test2", want: ":nick!user@host TEST :test1 test2"},
|
|
// This should succeeded even though "want" has a colon (even though
|
|
// there are no spaces in the target). This is because the truncating
|
|
// happens after the event is encoded, not during.
|
|
{in: ":nick!user@host TEST :test0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000LONG TEXT TRUNCATED HERE", want: ":nick!user@host TEST :test0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
|
|
{in: "@aaa=bbb;ccc;example.com/ddd=eee :nick!user@host TEST :test 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000LONG TEXT TRUNCATED HERE", want: "@aaa=bbb;ccc;example.com/ddd=eee :nick!user@host TEST :test 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
|
|
{in: "@aaa=bbb :nick!user@host TEST :test1", want: "@aaa=bbb :nick!user@host TEST test1"},
|
|
{in: "@aaa=bbb;+ccc;example.com/ddd=eee :nick!user@host TEST :test1", want: "@aaa=bbb;+ccc;example.com/ddd=eee :nick!user@host TEST test1"},
|
|
{in: "@bbb=aaa;aaa :nick!user@host TEST :test1 test2", want: "@aaa;bbb=aaa :nick!user@host TEST :test1 test2"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := ParseEvent(tt.in)
|
|
|
|
if got == nil && tt.want == "" {
|
|
continue
|
|
}
|
|
|
|
if got == nil {
|
|
t.Errorf("ParseEvent: got nil, want: %s", tt.want)
|
|
}
|
|
|
|
if got.String() != tt.want {
|
|
if got.Tags != nil {
|
|
if len(got.String()) != len(tt.want) {
|
|
t.Fatalf("ParseEvent: length exception in tag parse: got %q, want %q", got.String(), tt.want)
|
|
}
|
|
} else {
|
|
t.Fatalf("ParseEvent: got %q, want %q", got.String(), tt.want)
|
|
}
|
|
}
|
|
|
|
if got.Len() != len(tt.want) {
|
|
if got.Len() > 510 {
|
|
continue
|
|
}
|
|
t.Fatalf("Event.Len: got %d from %q, want %d", got.Len(), got.String(), len(tt.want))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEventCopy(t *testing.T) {
|
|
var nilEvent *Event
|
|
|
|
if event := nilEvent.Copy(); event != nil {
|
|
t.Fatalf("Event.Copy: returned non-nil on nil event: %#v", event)
|
|
}
|
|
|
|
msg := "@aaa=bbb;ccc;example.com/ddd=eee :nick!user@host TEST arg1 arg2 :test1"
|
|
event := ParseEvent(msg)
|
|
|
|
eventCopy := event.Copy()
|
|
|
|
if !reflect.DeepEqual(event, eventCopy) {
|
|
t.Fatalf("Event.Copy: want %#v, got %#v", event, eventCopy)
|
|
}
|
|
|
|
// Since Event.Copy() calls Source.Copy()...
|
|
if !reflect.DeepEqual(event.Source, eventCopy.Source) {
|
|
t.Fatalf("Source.Copy: want %#v, got %#v", event.Source, eventCopy.Source)
|
|
}
|
|
|
|
event.Source = nil
|
|
if src := event.Source.Copy(); src != nil {
|
|
t.Fatalf("Source.Copy: returned non-nil on nil source: %#v", src)
|
|
}
|
|
}
|
|
|
|
func TestEventIs(t *testing.T) {
|
|
event := ParseEvent(":nick!user@host PRIVMSG #test :\x01ACTION this is a test\x01")
|
|
|
|
if !event.IsAction() {
|
|
t.Fatalf("Event.IsAction: returned false on %#v", event)
|
|
}
|
|
event.Command = "TEST"
|
|
if event.IsAction() {
|
|
t.Fatalf("Event.IsAction: returned true though not privmsg; %#v", event)
|
|
}
|
|
event.Command = "PRIVMSG"
|
|
|
|
event.Params[len(event.Params)-1] = event.StripAction()
|
|
if event.IsAction() || event.Last() != "this is a test" {
|
|
t.Fatalf("Event.IsAction: returned true on %#v or trailing is not \"this is a test\": %q", event, event.Last())
|
|
}
|
|
|
|
if !event.IsFromChannel() {
|
|
t.Fatalf("Event.IsFromChannel: returned false on %#v", event)
|
|
}
|
|
|
|
event.Command = "TEST"
|
|
if event.IsFromChannel() {
|
|
t.Fatalf("Event.IsFromChannel: returned true though not privmsg; %#v", event)
|
|
}
|
|
|
|
event.Params[0] = "user1"
|
|
if event.IsFromUser() {
|
|
t.Fatalf("Event.IsFromUser: returned true when not privmsg; %#v", event)
|
|
}
|
|
|
|
event.Command = "PRIVMSG"
|
|
if !event.IsFromUser() {
|
|
t.Fatalf("Event.IsFromUser: returned false on %#v", event)
|
|
}
|
|
}
|
|
|
|
func TestEventSourceTagEquals(t *testing.T) {
|
|
// This should test events themselves, as well as tags and sources.
|
|
cases := []struct {
|
|
before, after string
|
|
equals bool
|
|
}{
|
|
{
|
|
before: ":nick!user@host PRIVMSG #test :This is a test",
|
|
after: ":nick!user@host PRIVMSG #test :This is a test",
|
|
equals: true,
|
|
},
|
|
{
|
|
before: ":nick!user@host PRIVMSG #test :This is a test",
|
|
after: ":nick!user@host1 PRIVMSG #test :This is a test",
|
|
equals: false,
|
|
},
|
|
{
|
|
before: ":nick!user@host PRIVMSG #test :This is a test",
|
|
after: ":nick!user@host PRIVMSG #tes :This is a test",
|
|
equals: false,
|
|
},
|
|
{
|
|
before: "@aaa=bbb;ccc;example.com/ddd=eee :nick!user@host PRIVMSG #test :This is a test",
|
|
after: "@aaa=bbb;ccc;example.com/ddd=eee :nick!user@host PRIVMSG #test :This is a test",
|
|
equals: true,
|
|
},
|
|
{
|
|
before: "@aaa=bbb;ccc;example.com/ddd=eee :nick!user@host PRIVMSG #test :This is a test",
|
|
after: "@aaa=bbb;ccc :nick!user@host PRIVMSG #test :This is a test",
|
|
equals: true,
|
|
},
|
|
{
|
|
before: ":nick!user@host PRIVMSG #test :This is a test",
|
|
after: "@aaa=bbb;ccc :nick!user@host PRIVMSG #test :This is a test",
|
|
equals: true,
|
|
},
|
|
{
|
|
before: "@account=bbb;ccc :nick!user@host PRIVMSG #test :This is a test",
|
|
after: "@aaa=bbb;ccc :nick!user@host PRIVMSG #test :This is a test",
|
|
equals: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range cases {
|
|
before := ParseEvent(tt.before)
|
|
after := ParseEvent(tt.after)
|
|
equals := before.Equals(after)
|
|
|
|
// It should be equal the opposite direction too.
|
|
if op := after.Equals(before); equals != op {
|
|
t.Fatalf("Event.Equals reverse order doesn't match forward order. before: %#v, after: %#v", before, after)
|
|
}
|
|
|
|
if equals != tt.equals {
|
|
t.Fatalf("Event.Equals: returned %t (wanted %t) on copied event. before: %#v, after: %#v", equals, tt.equals, before, after)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEventIRCDocsParseTests(t *testing.T) {
|
|
// Some of these are pulled from https://github.com/ircdocs/parser-tests.
|
|
// TODO: do result checks in an automated form from parser-tests.
|
|
cases := []string{
|
|
"foo bar baz asdf",
|
|
"foo bar baz :asdf",
|
|
":src AWAY",
|
|
":src AWAY :",
|
|
":coolguy foo bar baz asdf",
|
|
":coolguy foo bar baz :asdf",
|
|
"foo bar baz :asdf quux",
|
|
"foo bar baz :",
|
|
"foo bar baz ::asdf",
|
|
":coolguy foo bar baz :asdf quux",
|
|
":coolguy foo bar baz : asdf quux ",
|
|
":coolguy PRIVMSG bar :lol :) ",
|
|
":coolguy foo bar baz :",
|
|
":coolguy foo bar baz : ",
|
|
":coolguy foo b\tar baz",
|
|
":coolguy foo b\tar :baz",
|
|
"@asd :coolguy foo bar baz : ",
|
|
"@a=b\\\\and\\nk;d=gh\\:764 foo",
|
|
"@d=gh\\:764;a=b\\\\and\\nk foo",
|
|
"@a=b\\\\and\\nk;d=gh\\:764 foo par1 par2",
|
|
"@a=b\\\\and\\nk;d=gh\\:764 foo par1 :par2",
|
|
"@d=gh\\:764;a=b\\\\and\\nk foo par1 par2",
|
|
"@d=gh\\:764;a=b\\\\and\\nk foo par1 :par2",
|
|
"@foo=\\\\\\\\\\:\\\\s\\s\\r\\n COMMAND",
|
|
"foo bar baz asdf",
|
|
":coolguy foo bar baz asdf",
|
|
"foo bar baz :asdf quux",
|
|
"foo bar baz :",
|
|
"foo bar baz ::asdf",
|
|
":coolguy foo bar baz :asdf quux",
|
|
":coolguy foo bar baz : asdf quux ",
|
|
":coolguy PRIVMSG bar :lol :) ",
|
|
":coolguy foo bar baz :",
|
|
":coolguy foo bar baz : ",
|
|
"@a=b;c=32;k;rt=ql7 foo",
|
|
"@a=b\\\\and\\nk;c=72\\s45;d=gh\\:764 foo",
|
|
"@c;h=;a=b :quux ab cd",
|
|
":src JOIN #chan",
|
|
":src JOIN :#chan",
|
|
":src AWAY",
|
|
":src AWAY ",
|
|
":cool\tguy foo bar baz",
|
|
":coolguy!ag@net\x035w\x03ork.admin PRIVMSG foo :bar baz",
|
|
":coolguy!~ag@n\x02et\x0305w\x0fork.admin PRIVMSG foo :bar baz",
|
|
"@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4= :irc.example.com COMMAND param1 param2 :param3 param3",
|
|
":irc.example.com COMMAND param1 param2 :param3 param3",
|
|
"@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4 COMMAND param1 param2 :param3 param3",
|
|
"COMMAND",
|
|
"@foo=\\\\\\\\\\:\\\\s\\s\\r\\n COMMAND",
|
|
":gravel.mozilla.org 432 #momo :Erroneous Nickname: Illegal characters",
|
|
":gravel.mozilla.org MODE #tckk +n ",
|
|
":services.esper.net MODE #foo-bar +o foobar ",
|
|
"@tag1=value\\\\ntest COMMAND",
|
|
"@tag1=value\\1 COMMAND",
|
|
"@tag1=value1\\ COMMAND",
|
|
"@tag1=1;tag2=3;tag3=4;tag1=5 COMMAND",
|
|
"@tag1=1;tag2=3;tag3=4;tag1=5;vendor/tag2=8 COMMAND",
|
|
":SomeOp MODE #channel :+i",
|
|
":SomeOp MODE #channel +oo SomeUser :AnotherUser",
|
|
}
|
|
|
|
for _, tt := range cases {
|
|
// Basic test to just verify it doesn't panic.
|
|
_ = ParseEvent(tt)
|
|
}
|
|
}
|