2021-10-08 03:22:06 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import "testing"
|
|
|
|
|
|
|
|
func TestParsing(t *testing.T) {
|
|
|
|
testcases := []struct {
|
|
|
|
input string
|
|
|
|
output *Message
|
|
|
|
}{
|
|
|
|
// these inputs are based on
|
|
|
|
// https://github.com/ircdocs/parser-tests/blob/master/tests/msg-split.yaml
|
|
|
|
// and https://modern.ircdocs.horse/#messages
|
|
|
|
{
|
|
|
|
input: `:irc.example.com CAP LS * :multi-prefix extended-join sasl`,
|
|
|
|
output: &Message{
|
|
|
|
Source: "irc.example.com",
|
|
|
|
Command: CAP,
|
|
|
|
Parameters: []string{"LS", "*", "multi-prefix extended-join sasl"},
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `@id=234AB :dan!d@localhost PRIVMSG #chan :Hey what's up!`,
|
|
|
|
output: &Message{
|
2021-10-09 19:28:12 +00:00
|
|
|
Tags: []Tag{{"id", "234AB"}},
|
2021-10-08 03:22:06 +00:00
|
|
|
Source: "dan!d@localhost",
|
|
|
|
Command: PRIVMSG,
|
|
|
|
Parameters: []string{"#chan", "Hey what's up!"},
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `@a=b;c=32;k;rt=ql7 :dan!d@localhost PRIVMSG #chan :Hey what's up!`,
|
|
|
|
output: &Message{
|
2021-10-09 19:28:12 +00:00
|
|
|
Tags: []Tag{{"a", "b"}, {"c", "32"}, {"k", ""}, {"rt", "ql7"}},
|
2021-10-08 03:22:06 +00:00
|
|
|
Source: "dan!d@localhost",
|
|
|
|
Command: PRIVMSG,
|
|
|
|
Parameters: []string{"#chan", "Hey what's up!"},
|
|
|
|
}},
|
2021-10-09 18:08:55 +00:00
|
|
|
{
|
|
|
|
input: `@a=b\\and\nk;c=72\s45;d=gh\:764 CAP`,
|
|
|
|
output: &Message{
|
2021-10-09 19:28:12 +00:00
|
|
|
Tags: []Tag{{"a", "b\\and\nk"}, {"c", "72 45"}, {"d", `gh;764`}},
|
|
|
|
Command: CAP,
|
2021-10-09 18:08:55 +00:00
|
|
|
}},
|
2021-10-08 03:22:06 +00:00
|
|
|
{
|
|
|
|
input: `@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4= :dan!d@localhost PRIVMSG #chan :Hey what's up!`,
|
|
|
|
output: &Message{
|
2021-10-09 19:28:12 +00:00
|
|
|
Tags: []Tag{{"tag1", "value1"}, {"tag2", ""}, {"vendor1/tag3", "value2"}, {"vendor2/tag4", ""}},
|
2021-10-08 03:22:06 +00:00
|
|
|
Source: "dan!d@localhost",
|
|
|
|
Command: PRIVMSG,
|
|
|
|
Parameters: []string{"#chan", "Hey what's up!"},
|
|
|
|
}},
|
2021-10-09 18:08:55 +00:00
|
|
|
{
|
|
|
|
input: ":src AWAY",
|
|
|
|
output: &Message{
|
|
|
|
Source: "src",
|
|
|
|
Command: AWAY,
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: ":src AWAY ",
|
|
|
|
output: &Message{
|
|
|
|
Source: "src",
|
|
|
|
Command: AWAY,
|
|
|
|
}},
|
2021-10-08 03:22:06 +00:00
|
|
|
{
|
|
|
|
input: `CAP REQ :sasl`,
|
|
|
|
output: &Message{
|
|
|
|
Command: CAP,
|
|
|
|
Parameters: []string{"REQ", "sasl"},
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `CAP REQ :`,
|
|
|
|
output: &Message{
|
|
|
|
Command: CAP,
|
|
|
|
Parameters: []string{"REQ", ""},
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `CAP REQ ::asdf`,
|
|
|
|
output: &Message{
|
|
|
|
Command: CAP,
|
|
|
|
Parameters: []string{"REQ", ":asdf"},
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `CAP REQ : asdf qwer`,
|
|
|
|
output: &Message{
|
|
|
|
Command: CAP,
|
|
|
|
Parameters: []string{"REQ", " asdf qwer"},
|
|
|
|
}},
|
2021-10-09 18:08:55 +00:00
|
|
|
{
|
|
|
|
input: ":coolguy!ag@net\x035w\x03ork.admin PRIVMSG foo :bar baz",
|
|
|
|
output: &Message{
|
|
|
|
Source: "coolguy!ag@net\x035w\x03ork.admin",
|
|
|
|
Command: PRIVMSG,
|
|
|
|
Parameters: []string{"foo", "bar baz"},
|
|
|
|
}},
|
2021-10-08 03:22:06 +00:00
|
|
|
{
|
|
|
|
input: `:coolguy PRIVMSG bar :lol :) `,
|
|
|
|
output: &Message{
|
|
|
|
Source: "coolguy",
|
|
|
|
Command: PRIVMSG,
|
|
|
|
Parameters: []string{"bar", "lol :) "},
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `:gravel.mozilla.org 432 #momo :Erroneous Nickname: Illegal characters`,
|
|
|
|
output: &Message{
|
|
|
|
Source: "gravel.mozilla.org",
|
|
|
|
Command: ERR_ERRONEUSNICKNAME,
|
|
|
|
Parameters: []string{"#momo", "Erroneous Nickname: Illegal characters"},
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `:gravel.mozilla.org MODE #tckk +n `,
|
|
|
|
output: &Message{
|
|
|
|
Source: "gravel.mozilla.org",
|
|
|
|
Command: MODE,
|
|
|
|
Parameters: []string{"#tckk", "+n"},
|
|
|
|
}},
|
2021-10-09 18:08:55 +00:00
|
|
|
{
|
|
|
|
input: ":services.esper.net MODE #foo-bar +o foobar ",
|
|
|
|
output: &Message{
|
|
|
|
Source: "services.esper.net",
|
|
|
|
Command: MODE,
|
|
|
|
Parameters: []string{"#foo-bar", "+o", "foobar"},
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `@tag1=value\\ntest COMMAND`,
|
|
|
|
output: &Message{
|
2021-10-09 19:28:12 +00:00
|
|
|
Tags: []Tag{{"tag1", `value\ntest`}},
|
2021-10-09 18:08:55 +00:00
|
|
|
Command: command("COMMAND"),
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `@tag1=value\1 COMMAND`,
|
|
|
|
output: &Message{
|
2021-10-09 19:28:12 +00:00
|
|
|
Tags: []Tag{{"tag1", `value1`}},
|
2021-10-09 18:08:55 +00:00
|
|
|
Command: command("COMMAND"),
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `@tag1=value\ COMMAND`,
|
|
|
|
output: &Message{
|
2021-10-09 19:28:12 +00:00
|
|
|
Tags: []Tag{{"tag1", `value`}},
|
2021-10-09 18:08:55 +00:00
|
|
|
Command: command("COMMAND"),
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `@tag1=1;tag2=3;tag3=4;tag1=5 COMMAND`,
|
|
|
|
output: &Message{
|
2021-10-09 19:28:12 +00:00
|
|
|
Tags: []Tag{{"tag1", "5"}, {"tag2", "3"}, {"tag3", "4"}},
|
2021-10-09 18:08:55 +00:00
|
|
|
Command: command("COMMAND"),
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `@tag1=1;tag2=3;tag3=4;tag1=5;vendor/tag2=8 COMMAND`,
|
|
|
|
output: &Message{
|
2021-10-09 19:28:12 +00:00
|
|
|
Tags: []Tag{{"tag1", "5"}, {"tag2", "3"}, {"tag3", "4"}, {"vendor/tag2", "8"}},
|
2021-10-09 18:08:55 +00:00
|
|
|
Command: command("COMMAND"),
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `:SomeOp MODE #channel :+i`,
|
|
|
|
output: &Message{
|
|
|
|
Source: "SomeOp",
|
|
|
|
Command: MODE,
|
|
|
|
Parameters: []string{"#channel", "+i"},
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
input: `:SomeOp MODE #channel +oo SomeUser :AnotherUser`,
|
|
|
|
output: &Message{
|
|
|
|
Source: "SomeOp",
|
|
|
|
Command: MODE,
|
|
|
|
Parameters: []string{"#channel", "+oo", "SomeUser", "AnotherUser"},
|
|
|
|
}},
|
2021-10-08 03:22:06 +00:00
|
|
|
}
|
|
|
|
for _, tc := range testcases {
|
|
|
|
m := &Message{Raw: tc.input}
|
|
|
|
m.ParseMessage()
|
|
|
|
if len(tc.output.Tags) != len(m.Tags) {
|
|
|
|
t.Logf("tags: actual: %v, expected: %v", m.Tags, tc.output.Tags)
|
|
|
|
t.Fail()
|
|
|
|
}
|
2021-10-09 18:08:55 +00:00
|
|
|
for i := range tc.output.Tags {
|
|
|
|
if tc.output.Tags[i] != m.Tags[i] {
|
2021-10-09 19:28:12 +00:00
|
|
|
t.Logf("tags: actual: %+v, expected: %+v", m.Tags[i], tc.output.Tags[i])
|
2021-10-09 18:08:55 +00:00
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
}
|
2021-10-08 03:22:06 +00:00
|
|
|
if tc.output.Source != m.Source {
|
|
|
|
t.Logf("source: actual: %v, expected: %v", m.Source, tc.output.Source)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
if tc.output.Command != m.Command {
|
|
|
|
t.Logf("command: actual: %v, expected: %v", m.Command, tc.output.Command)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
if len(tc.output.Parameters) != len(m.Parameters) {
|
|
|
|
t.Logf("parameters: actual: %v (%d), expected: %v (%d)", m.Parameters, len(m.Parameters), tc.output.Parameters, len(tc.output.Parameters))
|
|
|
|
t.Fail()
|
|
|
|
}
|
2021-10-09 18:08:55 +00:00
|
|
|
for i := range tc.output.Parameters {
|
|
|
|
if tc.output.Parameters[i] != m.Parameters[i] {
|
|
|
|
t.Logf("parameters: actual: %v, expected: %v", m.Parameters[i], tc.output.Parameters[i])
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
}
|
2021-10-08 03:22:06 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-09 19:28:12 +00:00
|
|
|
|
|
|
|
func TestCanonicalization(t *testing.T) {
|
|
|
|
testcases := []struct {
|
|
|
|
input *Message
|
|
|
|
output string
|
|
|
|
}{
|
|
|
|
// these outputs are based on
|
|
|
|
// https://github.com/ircdocs/parser-tests/blob/master/tests/msg-split.yaml
|
|
|
|
// and https://modern.ircdocs.horse/#messages
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Source: "irc.example.com",
|
|
|
|
Command: CAP,
|
|
|
|
Parameters: []string{"LS", "*", "multi-prefix extended-join sasl"},
|
|
|
|
},
|
|
|
|
output: `:irc.example.com CAP LS * :multi-prefix extended-join sasl`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Tags: []Tag{{"id", "234AB"}},
|
|
|
|
Source: "dan!d@localhost",
|
|
|
|
Command: PRIVMSG,
|
|
|
|
Parameters: []string{"#chan", "Hey what's up!"},
|
|
|
|
},
|
|
|
|
output: `@id=234AB :dan!d@localhost PRIVMSG #chan :Hey what's up!`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Tags: []Tag{{"a", "b"}, {"c", "32"}, {"k", ""}, {"rt", "ql7"}},
|
|
|
|
Source: "dan!d@localhost",
|
|
|
|
Command: PRIVMSG,
|
|
|
|
Parameters: []string{"#chan", "Hey what's up!"},
|
|
|
|
},
|
|
|
|
output: `@a=b;c=32;k;rt=ql7 :dan!d@localhost PRIVMSG #chan :Hey what's up!`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Tags: []Tag{{"a", "b\\and\nk"}, {"c", "72 45"}, {"d", `gh;764`}},
|
|
|
|
Command: CAP,
|
|
|
|
},
|
|
|
|
output: `@a=b\\and\nk;c=72\s45;d=gh\:764 CAP`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Tags: []Tag{{"tag1", "value1"}, {"tag2", ""}, {"vendor1/tag3", "value2"}, {"vendor2/tag4", ""}},
|
|
|
|
Source: "dan!d@localhost",
|
|
|
|
Command: PRIVMSG,
|
|
|
|
Parameters: []string{"#chan", "Hey what's up!"},
|
|
|
|
},
|
|
|
|
output: `@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4 :dan!d@localhost PRIVMSG #chan :Hey what's up!`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Source: "src",
|
|
|
|
Command: AWAY,
|
|
|
|
},
|
|
|
|
output: ":src AWAY",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Command: CAP,
|
|
|
|
Parameters: []string{"REQ", "sasl"},
|
|
|
|
},
|
|
|
|
output: `CAP REQ sasl`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Command: CAP,
|
|
|
|
Parameters: []string{"REQ", ""},
|
|
|
|
},
|
|
|
|
output: `CAP REQ :`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Command: CAP,
|
|
|
|
Parameters: []string{"REQ", ":asdf"},
|
|
|
|
},
|
|
|
|
output: `CAP REQ ::asdf`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Command: CAP,
|
|
|
|
Parameters: []string{"REQ", " asdf qwer"},
|
|
|
|
},
|
|
|
|
output: `CAP REQ : asdf qwer`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Source: "coolguy",
|
|
|
|
Command: PRIVMSG,
|
|
|
|
Parameters: []string{"bar", "lol :) "},
|
|
|
|
},
|
|
|
|
output: `:coolguy PRIVMSG bar :lol :) `,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Source: "coolguy!ag@net\x035w\x03ork.admin",
|
|
|
|
Command: PRIVMSG,
|
|
|
|
Parameters: []string{"foo", "bar baz"},
|
|
|
|
},
|
|
|
|
output: ":coolguy!ag@net\x035w\x03ork.admin PRIVMSG foo :bar baz",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
input: &Message{
|
|
|
|
Tags: []Tag{{"tag1", `value\ntest`}},
|
|
|
|
Command: command("COMMAND"),
|
|
|
|
},
|
|
|
|
output: `@tag1=value\\ntest COMMAND`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range testcases {
|
|
|
|
output := string(tc.input.Canonicalize())
|
|
|
|
if output != tc.output {
|
|
|
|
t.Logf("received '%s', expected '%s'", output, tc.output)
|
|
|
|
t.Fail()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|