1 /***************************************************************************
2 * Copyright (C) 2005-2019 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
23 #include "testglobal.h"
24 #include "ircdecoder.h"
29 std::map<IrcTagKey, std::string> tags;
32 std::vector<std::string> params;
34 explicit IrcMessage(std::map<IrcTagKey, std::string> tags, std::string prefix, std::string cmd, std::vector<std::string> params = {})
35 : tags(std::move(tags)), prefix(std::move(prefix)), cmd(std::move(cmd)), params(std::move(params)) {}
37 explicit IrcMessage(std::initializer_list<std::pair<const IrcTagKey, std::string>> tags, std::string prefix, std::string cmd, std::vector<std::string> params = {})
38 : tags(tags), prefix(std::move(prefix)), cmd(std::move(cmd)), params(std::move(params)) {}
40 explicit IrcMessage(std::string prefix, std::string cmd, std::vector<std::string> params = {})
41 : tags({}), prefix(std::move(prefix)), cmd(std::move(cmd)), params(std::move(params)) {}
43 friend bool operator==(const IrcMessage& a, const IrcMessage& b)
45 return a.tags == b.tags &&
46 a.prefix == b.prefix &&
51 friend std::ostream& operator<<(std::ostream& o, const IrcMessage& m)
54 for (const std::pair<IrcTagKey, std::string> entry: m.tags) {
55 o << entry.first << "='" << entry.second << "', ";
57 o << "}, prefix=" << m.prefix << ", cmd=" << m.cmd << ", params=[";
58 for (const std::string& param : m.params) {
59 o << "'" << param << "', ";
67 IrcMessage parse(const std::string& message)
69 QHash<IrcTagKey, QString> tags;
72 QList<QByteArray> params;
74 IrcDecoder::parseMessage([](const QByteArray& data) {
75 return QString::fromUtf8(data);
76 }, QByteArray::fromStdString(message), tags, prefix, cmd, params);
78 std::map<IrcTagKey, std::string> actualTags;
79 for (const IrcTagKey& key : tags.keys()) {
80 actualTags[key] = tags[key].toStdString();
82 std::string actualPrefix = prefix.toStdString();
83 std::string actualCmd = cmd.toStdString();
84 std::vector<std::string> actualParams;
85 for (const QByteArray& param : params) {
86 actualParams.push_back(param.toStdString());
89 return IrcMessage{actualTags, actualPrefix, actualCmd, actualParams};
92 TEST(IrcDecoderTest, simple)
94 EXPECT_EQ(parse("foo bar baz asdf"),
97 {"bar", "baz", "asdf"}));
100 TEST(IrcDecoderTest, with_source)
102 EXPECT_EQ(parse(":coolguy foo bar baz asdf"),
103 IrcMessage("coolguy",
105 {"bar", "baz", "asdf"}));
108 TEST(IrcDecoderTest, with_trailing_param)
110 EXPECT_EQ(parse("foo bar baz :asdf quux"),
113 {"bar", "baz", "asdf quux"}));
114 EXPECT_EQ(parse("foo bar baz :"),
117 {"bar", "baz", ""}));
118 EXPECT_EQ(parse("foo bar baz ::asdf"),
121 {"bar", "baz", ":asdf"}));
124 TEST(IrcDecoderTest, with_source_and_trailing_param)
126 EXPECT_EQ(parse(":coolguy foo bar baz :asdf quux"),
127 IrcMessage("coolguy",
129 {"bar", "baz", "asdf quux"}));
130 EXPECT_EQ(parse(":coolguy foo bar baz : asdf quux "),
131 IrcMessage("coolguy",
133 {"bar", "baz", " asdf quux "}));
134 EXPECT_EQ(parse(":coolguy PRIVMSG bar :lol :) "),
135 IrcMessage("coolguy",
137 {"bar", "lol :) "}));
138 EXPECT_EQ(parse(":coolguy foo bar baz : "),
139 IrcMessage("coolguy",
141 {"bar", "baz", " "}));
144 TEST(IrcDecoderTest, with_tags)
146 EXPECT_EQ(parse("@a=b;c=32;k;rt=ql7 foo"),
147 IrcMessage({{IrcTagKey("a"), "b"},
148 {IrcTagKey("c"), "32"},
149 {IrcTagKey("k"), ""},
150 {IrcTagKey("rt"), "ql7"}},
155 TEST(IrcDecoderTest, with_escaped_tags)
157 EXPECT_EQ(parse("@a=b\\\\and\\nk;c=72\\s45;d=gh\\:764 foo"),
158 IrcMessage({{IrcTagKey("a"), "b\\and\nk"},
159 {IrcTagKey("c"), "72 45"},
160 {IrcTagKey("d"), "gh;764"}},
165 TEST(IrcDecoderTest, with_tags_and_source)
167 EXPECT_EQ(parse("@c;h=;a=b :quux ab cd"),
168 IrcMessage({{IrcTagKey("c"), ""},
169 {IrcTagKey("h"), ""},
170 {IrcTagKey("a"), "b"}},
176 TEST(IrcDecoderTest, different_forms_of_last_param)
178 EXPECT_EQ(parse(":src JOIN #chan"),
182 EXPECT_EQ(parse(":src JOIN :#chan"),
188 TEST(IrcDecoderTest, with_and_without_last_param)
190 EXPECT_EQ(parse(":src AWAY"),
193 EXPECT_EQ(parse(":src AWAY "),
198 TEST(IrcDecoderTest, tab_is_not_considered_SPACE)
200 EXPECT_EQ(parse(":cool\tguy foo bar baz"),
201 IrcMessage("cool\tguy",
206 TEST(IrcDecoderTest, with_weird_control_codes_in_the_source)
208 EXPECT_EQ(parse(":coolguy!ag@net""\x03""5w""\x03""ork.admin PRIVMSG foo :bar baz"),
209 IrcMessage("coolguy!ag@net""\x03""5w""\x03""ork.admin",
211 {"foo", "bar baz"}));
212 EXPECT_EQ(parse(":coolguy!~ag@n""\x02""et""\x03""05w""\x0f""ork.admin PRIVMSG foo :bar baz"),
213 IrcMessage("coolguy!~ag@n""\x02""et""\x03""05w""\x0f""ork.admin",
215 {"foo", "bar baz"}));
218 TEST(IrcDecoderTest, with_tags_source_and_params)
220 EXPECT_EQ(parse("@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4 :irc.example.com COMMAND param1 param2 :param3 param3"),
221 IrcMessage({{IrcTagKey("tag1"), "value1"},
222 {IrcTagKey("tag2"), ""},
223 {IrcTagKey("vendor1", "tag3"), "value2"},
224 {IrcTagKey("vendor2", "tag4"), ""}},
227 {"param1", "param2", "param3 param3"}));
228 EXPECT_EQ(parse(":irc.example.com COMMAND param1 param2 :param3 param3"),
229 IrcMessage("irc.example.com",
231 {"param1", "param2", "param3 param3"}));
232 EXPECT_EQ(parse("@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4 COMMAND param1 param2 :param3 param3"),
233 IrcMessage({{IrcTagKey("tag1"), "value1"},
234 {IrcTagKey("tag2"), ""},
235 {IrcTagKey("vendor1", "tag3"), "value2"},
236 {IrcTagKey("vendor2", "tag4"), ""}},
239 {"param1", "param2", "param3 param3"}));
240 EXPECT_EQ(parse("COMMAND"),
243 EXPECT_EQ(parse("@foo=\\\\\\\\\\:\\\\s\\s\\r\\n COMMAND"),
244 IrcMessage({{IrcTagKey("foo"), "\\\\;\\s \r\n"}},
249 TEST(IrcDecoderTest, broken_messages_from_unreal)
251 EXPECT_EQ(parse(":gravel.mozilla.org 432 #momo :Erroneous Nickname: Illegal characters"),
252 IrcMessage("gravel.mozilla.org",
254 {"#momo", "Erroneous Nickname: Illegal characters"}));
255 EXPECT_EQ(parse(":gravel.mozilla.org MODE #tckk +n "),
256 IrcMessage("gravel.mozilla.org",
259 EXPECT_EQ(parse(":services.esper.net MODE #foo-bar +o foobar "),
260 IrcMessage("services.esper.net",
262 {"#foo-bar", "+o", "foobar"}));
265 TEST(IrcDecoderTest, tag_values)
267 EXPECT_EQ(parse("@tag1=value\\\\ntest COMMAND"),
268 IrcMessage({{IrcTagKey("tag1"), "value\\ntest"}},
271 EXPECT_EQ(parse("@tag1=value\\1 COMMAND"),
272 IrcMessage({{IrcTagKey("tag1"), "value1"}},
275 EXPECT_EQ(parse("@tag1=value1\\ COMMAND"),
276 IrcMessage({{IrcTagKey("tag1"), "value1"}},