cmake: avoid de-duplication of user's CXXFLAGS
[quassel.git] / tests / common / ircdecodertest.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2022 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
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.                                           *
9  *                                                                         *
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.                          *
14  *                                                                         *
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  ***************************************************************************/
20
21 #include <ostream>
22
23 #include "testglobal.h"
24 #include "ircdecoder.h"
25 #include "irctag.h"
26
27 struct IrcMessage
28 {
29     std::map<IrcTagKey, std::string> tags;
30     std::string prefix;
31     std::string cmd;
32     std::vector<std::string> params;
33
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)) {}
36
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)) {}
39
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)) {}
42
43     friend bool operator==(const IrcMessage& a, const IrcMessage& b)
44     {
45         return a.tags == b.tags &&
46                a.prefix == b.prefix &&
47                a.cmd == b.cmd &&
48                a.params == b.params;
49     }
50
51     friend std::ostream& operator<<(std::ostream& o, const IrcMessage& m)
52     {
53         o << "(tags={";
54         for (const std::pair<IrcTagKey, std::string> entry: m.tags) {
55             o << entry.first << "='" << entry.second << "', ";
56         }
57         o << "}, prefix=" << m.prefix << ", cmd=" << m.cmd << ", params=[";
58         for (const std::string& param : m.params) {
59             o << "'" << param << "', ";
60         }
61         o << "])";
62         return o;
63     }
64 };
65
66
67 IrcMessage parse(const std::string& message)
68 {
69     QHash<IrcTagKey, QString> tags;
70     QString prefix;
71     QString cmd;
72     QList<QByteArray> params;
73
74     IrcDecoder::parseMessage([](const QByteArray& data) {
75         return QString::fromUtf8(data);
76     }, QByteArray::fromStdString(message), tags, prefix, cmd, params);
77
78     std::map<IrcTagKey, std::string> actualTags;
79     for (const IrcTagKey& key : tags.keys()) {
80         actualTags[key] = tags[key].toStdString();
81     }
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());
87     }
88
89     return IrcMessage{actualTags, actualPrefix, actualCmd, actualParams};
90 }
91
92 TEST(IrcDecoderTest, simple)
93 {
94     EXPECT_EQ(parse("foo bar baz asdf"),
95               IrcMessage("",
96                          "foo",
97                          {"bar", "baz", "asdf"}));
98 }
99
100 TEST(IrcDecoderTest, with_source)
101 {
102     EXPECT_EQ(parse(":coolguy foo bar baz asdf"),
103               IrcMessage("coolguy",
104                          "foo",
105                          {"bar", "baz", "asdf"}));
106 }
107
108 TEST(IrcDecoderTest, with_trailing_param)
109 {
110     EXPECT_EQ(parse("foo bar baz :asdf quux"),
111               IrcMessage("",
112                          "foo",
113                          {"bar", "baz", "asdf quux"}));
114     EXPECT_EQ(parse("foo bar baz :"),
115               IrcMessage("",
116                          "foo",
117                          {"bar", "baz", ""}));
118     EXPECT_EQ(parse("foo bar baz ::asdf"),
119               IrcMessage("",
120                          "foo",
121                          {"bar", "baz", ":asdf"}));
122 }
123
124 TEST(IrcDecoderTest, with_source_and_trailing_param)
125 {
126     EXPECT_EQ(parse(":coolguy foo bar baz :asdf quux"),
127               IrcMessage("coolguy",
128                          "foo",
129                          {"bar", "baz", "asdf quux"}));
130     EXPECT_EQ(parse(":coolguy foo bar baz :  asdf quux "),
131               IrcMessage("coolguy",
132                          "foo",
133                          {"bar", "baz", "  asdf quux "}));
134     EXPECT_EQ(parse(":coolguy PRIVMSG bar :lol :) "),
135               IrcMessage("coolguy",
136                          "PRIVMSG",
137                          {"bar", "lol :) "}));
138     EXPECT_EQ(parse(":coolguy foo bar baz :  "),
139               IrcMessage("coolguy",
140                          "foo",
141                          {"bar", "baz", "  "}));
142 }
143
144 TEST(IrcDecoderTest, with_tags)
145 {
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"}},
151                          "",
152                          "foo"));
153
154     EXPECT_EQ(parse("@a=b foo"),
155               IrcMessage(
156                   {{IrcTagKey("a"),  "b"}},
157                   "",
158                   "foo"));
159
160     EXPECT_EQ(parse("@example.com/a=b foo"),
161               IrcMessage(
162                   {{IrcTagKey("example.com", "a"),  "b"}},
163                   "",
164                   "foo"));
165
166     EXPECT_EQ(parse("@example.com/subfolder/to/a=b foo"),
167               IrcMessage(
168                   {{IrcTagKey("example.com/subfolder/to", "a"),  "b"}},
169                   "",
170                   "foo"));
171
172     EXPECT_EQ(parse("@v\\/e\\/n\\/d\\/o\\/r/tag=b foo"),
173               IrcMessage(
174                   {{IrcTagKey("v\\/e\\/n\\/d\\/o\\/r", "tag"),  "b"}},
175                   "",
176                   "foo"));
177 }
178
179 TEST(IrcDecoderTest, with_escaped_tags)
180 {
181     EXPECT_EQ(parse("@a=b\\\\and\\nk;c=72\\s45;d=gh\\:764 foo"),
182               IrcMessage({{IrcTagKey("a"), "b\\and\nk"},
183                           {IrcTagKey("c"), "72 45"},
184                           {IrcTagKey("d"), "gh;764"}},
185                          "",
186                          "foo"));
187 }
188
189 TEST(IrcDecoderTest, with_tags_and_source)
190 {
191     EXPECT_EQ(parse("@c;h=;a=b :quux ab cd"),
192               IrcMessage({{IrcTagKey("c"), ""},
193                           {IrcTagKey("h"), ""},
194                           {IrcTagKey("a"), "b"}},
195                          "quux",
196                          "ab",
197                          {"cd"}));
198 }
199
200 TEST(IrcDecoderTest, different_forms_of_last_param)
201 {
202     EXPECT_EQ(parse(":src JOIN #chan"),
203               IrcMessage("src",
204                          "JOIN",
205                          {"#chan"}));
206     EXPECT_EQ(parse(":src JOIN :#chan"),
207               IrcMessage("src",
208                          "JOIN",
209                          {"#chan"}));
210 }
211
212 TEST(IrcDecoderTest, with_and_without_last_param)
213 {
214     EXPECT_EQ(parse(":src AWAY"),
215               IrcMessage("src",
216                          "AWAY"));
217     EXPECT_EQ(parse(":src AWAY "),
218               IrcMessage("src",
219                          "AWAY"));
220 }
221
222 TEST(IrcDecoderTest, tab_is_not_considered_SPACE)
223 {
224     EXPECT_EQ(parse(":cool\tguy foo bar baz"),
225               IrcMessage("cool\tguy",
226                          "foo",
227                          {"bar", "baz"}));
228 }
229
230 TEST(IrcDecoderTest, with_weird_control_codes_in_the_source)
231 {
232     EXPECT_EQ(parse(":coolguy!ag@net""\x03""5w""\x03""ork.admin PRIVMSG foo :bar baz"),
233               IrcMessage("coolguy!ag@net""\x03""5w""\x03""ork.admin",
234                          "PRIVMSG",
235                          {"foo", "bar baz"}));
236     EXPECT_EQ(parse(":coolguy!~ag@n""\x02""et""\x03""05w""\x0f""ork.admin PRIVMSG foo :bar baz"),
237               IrcMessage("coolguy!~ag@n""\x02""et""\x03""05w""\x0f""ork.admin",
238                          "PRIVMSG",
239                          {"foo", "bar baz"}));
240 }
241
242 TEST(IrcDecoderTest, with_tags_source_and_params)
243 {
244     EXPECT_EQ(parse("@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4 :irc.example.com COMMAND param1 param2 :param3 param3"),
245               IrcMessage({{IrcTagKey("tag1"),            "value1"},
246                           {IrcTagKey("tag2"),            ""},
247                           {IrcTagKey("vendor1", "tag3"), "value2"},
248                           {IrcTagKey("vendor2", "tag4"), ""}},
249                          "irc.example.com",
250                          "COMMAND",
251                          {"param1", "param2", "param3 param3"}));
252     EXPECT_EQ(parse(":irc.example.com COMMAND param1 param2 :param3 param3"),
253               IrcMessage("irc.example.com",
254                          "COMMAND",
255                          {"param1", "param2", "param3 param3"}));
256     EXPECT_EQ(parse("@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4 COMMAND param1 param2 :param3 param3"),
257               IrcMessage({{IrcTagKey("tag1"),            "value1"},
258                           {IrcTagKey("tag2"),            ""},
259                           {IrcTagKey("vendor1", "tag3"), "value2"},
260                           {IrcTagKey("vendor2", "tag4"), ""}},
261                          "",
262                          "COMMAND",
263                          {"param1", "param2", "param3 param3"}));
264     EXPECT_EQ(parse("COMMAND"),
265               IrcMessage("",
266                          "COMMAND"));
267     EXPECT_EQ(parse("@foo=\\\\\\\\\\:\\\\s\\s\\r\\n COMMAND"),
268               IrcMessage({{IrcTagKey("foo"), "\\\\;\\s \r\n"}},
269                          "",
270                          "COMMAND"));
271 }
272
273 TEST(IrcDecoderTest, broken_messages_from_unreal)
274 {
275     EXPECT_EQ(parse(":gravel.mozilla.org 432  #momo :Erroneous Nickname: Illegal characters"),
276               IrcMessage("gravel.mozilla.org",
277                          "432",
278                          {"#momo", "Erroneous Nickname: Illegal characters"}));
279     EXPECT_EQ(parse(":gravel.mozilla.org MODE #tckk +n "),
280               IrcMessage("gravel.mozilla.org",
281                          "MODE",
282                          {"#tckk", "+n"}));
283     EXPECT_EQ(parse(":services.esper.net MODE #foo-bar +o foobar  "),
284               IrcMessage("services.esper.net",
285                          "MODE",
286                          {"#foo-bar", "+o", "foobar"}));
287 }
288
289 TEST(IrcDecoderTest, tag_values)
290 {
291     EXPECT_EQ(parse("@tag1=value\\\\ntest COMMAND"),
292               IrcMessage({{IrcTagKey("tag1"), "value\\ntest"}},
293                          "",
294                          "COMMAND"));
295     EXPECT_EQ(parse("@tag1=value\\1 COMMAND"),
296               IrcMessage({{IrcTagKey("tag1"), "value1"}},
297                          "",
298                          "COMMAND"));
299     EXPECT_EQ(parse("@tag1=value1\\ COMMAND"),
300               IrcMessage({{IrcTagKey("tag1"), "value1"}},
301                          "",
302                          "COMMAND"));
303 }