2 (c) 2006 Jelmer Vernooij <jelmer@nl.linux.org>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "ctrlproxy.h"
24 #include "internals.h"
26 void stack_process(struct linestack_context *ctx, struct irc_network_state *ns, const char *line)
29 l = irc_parse_line(line);
31 g_assert(state_handle_data(ns, l));
32 g_assert(linestack_insert_line(ctx, l, FROM_SERVER, ns));
36 #define null_equal(a,b) { \
37 if ((a) == NULL && (b) == NULL) \
39 if ((a) == NULL || (b) == NULL) \
43 static gboolean list_equal(GList *list1, GList *list2, GEqualFunc eq)
46 null_equal(list1, list2);
48 for (gl1 = list1, gl2 = list2; gl1 && gl2; gl1 = gl1->next, gl2 = gl2->next) {
49 if (!eq(gl1->data, gl2->data))
53 if (gl1 != NULL || gl2 != NULL)
59 static gboolean modes_equal(const irc_modes_t a, const irc_modes_t b)
61 return modes_cmp(a, b) == 0;
64 static gboolean str_equal(const char *a, const char *b)
68 return g_str_equal(a, b);
71 static gboolean channel_nick_equal(const struct channel_nick *nick1, const struct channel_nick *nick2)
73 null_equal(nick1, nick2);
75 return modes_equal(nick1->modes, nick2->modes) &&
76 str_equal(nick1->global_nick->nick, nick2->global_nick->nick) &&
77 str_equal(nick1->channel->name, nick2->channel->name);
80 static gboolean banlist_entry_equal(const struct nicklist_entry *entry1, const struct nicklist_entry *entry2)
82 null_equal(entry1, entry2);
84 return str_equal(entry1->hostmask, entry2->hostmask) &&
85 str_equal(entry1->by, entry2->by) &&
86 entry1->time_set == entry2->time_set;
89 static gboolean channel_state_equal(const struct irc_channel_state *channel1, const struct irc_channel_state *channel2)
92 null_equal(channel1, channel2);
94 for (i = 0; i < MAXMODES; i++) {
95 if (!str_equal(channel1->chanmode_option[i], channel2->chanmode_option[i]))
98 if (!list_equal(channel1->chanmode_nicklist[i], channel2->chanmode_nicklist[i], (GEqualFunc)banlist_entry_equal))
102 return str_equal(channel1->name, channel2->name) &&
103 str_equal(channel1->topic, channel2->topic) &&
104 channel1->mode == channel2->mode &&
105 !memcmp(channel1->modes, channel2->modes, 255) &&
106 channel1->namreply_started == channel2->namreply_started &&
107 channel1->invitelist_started == channel2->invitelist_started &&
108 channel1->exceptlist_started == channel2->exceptlist_started &&
109 channel1->banlist_started == channel2->banlist_started &&
110 list_equal(channel1->nicks, channel2->nicks, (GEqualFunc)channel_nick_equal);
113 static gboolean network_info_equal(const struct irc_network_info *info1, const struct irc_network_info *info2)
115 null_equal(info1, info2);
117 return str_equal(info1->name, info2->name) &&
118 str_equal(info1->server, info2->server) &&
119 str_equal(info1->supported_user_modes, info2->supported_user_modes) &&
120 str_equal(info1->supported_channel_modes, info2->supported_channel_modes) &&
121 str_equal(info1->prefix, info2->prefix) &&
122 str_equal(info1->chantypes, info2->chantypes) &&
123 str_equal(info1->charset, info2->charset) &&
124 ((info1->chanmodes == NULL && info2->chanmodes == NULL) ||
125 (str_equal(info1->chanmodes[0], info2->chanmodes[0]) &&
126 str_equal(info1->chanmodes[1], info2->chanmodes[1]) &&
127 str_equal(info1->chanmodes[2], info2->chanmodes[2]) &&
128 str_equal(info1->chanmodes[3], info2->chanmodes[3]))) &&
129 info1->keylen == info2->keylen &&
130 info1->silence == info2->silence &&
131 info1->channellen == info2->channellen &&
132 info1->awaylen == info2->awaylen &&
133 info1->maxtargets == info2->maxtargets &&
134 info1->nicklen == info2->nicklen &&
135 info1->userlen == info2->userlen &&
136 info1->hostlen == info2->hostlen &&
137 info1->maxchannels == info2->maxchannels &&
138 info1->topiclen == info2->topiclen &&
139 info1->maxbans == info2->maxbans &&
140 info1->maxmodes == info2->maxmodes &&
141 info1->wallchops == info2->wallchops &&
142 info1->wallvoices == info2->wallvoices &&
143 info1->rfc2812 == info2->rfc2812 &&
144 info1->penalty == info2->penalty &&
145 info1->forced_nick_changes == info2->forced_nick_changes &&
146 info1->safelist == info2->safelist &&
147 info1->userip == info2->userip &&
148 info1->cprivmsg == info2->cprivmsg &&
149 info1->cnotice == info2->cnotice &&
150 info1->knock == info2->knock &&
151 info1->vchannels == info2->vchannels &&
152 info1->whox == info2->whox &&
153 info1->callerid == info2->callerid &&
154 info1->accept == info2->accept &&
155 info1->capab == info2->capab &&
156 info1->casemapping == info2->casemapping;
159 static gboolean network_nick_equal(const struct network_nick *nick1, const struct network_nick *nick2)
161 null_equal(nick1, nick2);
163 return nick1->query == nick2->query &&
164 str_equal(nick1->nick, nick2->nick) &&
165 str_equal(nick1->fullname, nick2->fullname) &&
166 str_equal(nick1->username, nick2->username) &&
167 str_equal(nick1->hostname, nick2->hostname) &&
168 !memcmp(nick1->modes, nick2->modes, 255) &&
169 list_equal(nick1->channel_nicks, nick2->channel_nicks,
170 (GEqualFunc)channel_nick_equal);
173 static gboolean network_state_equal(const struct irc_network_state *state1,
174 const struct irc_network_state *state2)
176 null_equal(state1, state2);
178 return network_nick_equal(&state1->me, &state2->me) &&
179 network_info_equal(state1->info, state2->info) &&
180 list_equal(state1->channels, state2->channels,
181 (GEqualFunc)channel_state_equal) &&
182 list_equal(state1->nicks, state2->nicks,
183 (GEqualFunc)network_nick_equal);
186 const char *get_linestack_tempdir(const char *base)
188 return g_build_filename("/tmp", base, NULL);
191 START_TEST(test_empty)
192 struct irc_network_state *ns1, *ns2;
193 struct linestack_context *ctx;
195 ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
196 ctx = create_linestack(get_linestack_tempdir("test_empty"), TRUE, ns1);
198 ns2 = linestack_get_state(ctx, NULL);
200 fail_unless (network_state_equal(ns1, ns2),
201 "Network state returned not equal");
205 struct irc_network_state *ns1;
206 struct linestack_context *ctx;
208 struct irc_client *cl;
210 GIOChannel *ch1, *ch2;
213 ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
214 ctx = create_linestack(get_linestack_tempdir("msg"), TRUE, ns1);
216 lm = linestack_get_marker(ctx);
218 stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
219 stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi");
221 g_io_channel_pair(&ch1, &ch2);
222 g_io_channel_set_flags(ch1, G_IO_FLAG_NONBLOCK, NULL);
223 g_io_channel_set_flags(ch2, G_IO_FLAG_NONBLOCK, NULL);
224 cl = client_init_iochannel(NULL, ch1, "test");
225 g_io_channel_unref(ch1);
227 linestack_send(ctx, lm, NULL, cl, FALSE, FALSE, 0);
228 client_disconnect(cl, "foo");
230 g_io_channel_read_to_end(ch2, &raw, NULL, NULL);
232 fail_unless(!strcmp(raw, ":bla!Gebruikersnaam@Computernaam JOIN #bla\r\n"
233 ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi\r\n"
237 START_TEST(test_join_part)
238 struct irc_network_state *ns1;
239 struct linestack_context *ctx;
241 struct irc_client *cl;
243 GIOChannel *ch1, *ch2;
246 ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
247 ctx = create_linestack(get_linestack_tempdir("join_part"), TRUE, ns1);
249 lm = linestack_get_marker(ctx);
251 stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
252 stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam PART #bla :hihi");
254 g_io_channel_pair(&ch1, &ch2);
255 g_io_channel_set_flags(ch1, G_IO_FLAG_NONBLOCK, NULL);
256 g_io_channel_set_flags(ch2, G_IO_FLAG_NONBLOCK, NULL);
257 cl = client_init_iochannel(NULL, ch1, "test");
258 g_io_channel_unref(ch1);
260 linestack_send(ctx, lm, NULL, cl, FALSE, FALSE, 0);
261 g_main_iteration(FALSE);
262 client_disconnect(cl, "foo");
263 g_main_iteration(FALSE);
264 g_io_channel_read_to_end(ch2, &raw, NULL, NULL);
266 fail_unless(!strcmp(raw, ":bla!Gebruikersnaam@Computernaam JOIN #bla\r\n"
267 ":bla!Gebruikersnaam@Computernaam PART #bla :hihi\r\n"
268 "ERROR :foo\r\n"), "Got %s", raw);
273 START_TEST(test_skip_msg)
274 struct irc_network_state *ns1;
275 struct linestack_context *ctx;
277 struct irc_client *cl;
279 GIOChannel *ch1, *ch2;
282 ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
283 ctx = create_linestack(get_linestack_tempdir("skip_msg"), TRUE, ns1);
285 stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :haha");
287 lm = linestack_get_marker(ctx);
289 stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
290 stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi");
292 g_io_channel_pair(&ch1, &ch2);
293 g_io_channel_set_flags(ch1, G_IO_FLAG_NONBLOCK, NULL);
294 g_io_channel_set_flags(ch2, G_IO_FLAG_NONBLOCK, NULL);
295 cl = client_init_iochannel(NULL, ch1, "test");
296 g_io_channel_unref(ch1);
298 linestack_send(ctx, lm, NULL, cl, FALSE, FALSE, 0);
299 client_disconnect(cl, "foo");
301 g_io_channel_read_to_end(ch2, &raw, NULL, NULL);
303 fail_unless(!strcmp(raw, ":bla!Gebruikersnaam@Computernaam JOIN #bla\r\n"
304 ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi\r\n"
308 START_TEST(test_object_msg)
309 struct irc_network_state *ns1;
310 struct linestack_context *ctx;
312 struct irc_client *cl;
314 GIOChannel *ch1, *ch2;
317 ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
318 ctx = create_linestack(get_linestack_tempdir("get_object_msg"), TRUE, ns1);
320 lm = linestack_get_marker(ctx);
322 stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #foo");
323 stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
324 stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #foo :hihi");
325 stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bar :hihi");
326 stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #blablie :hihi");
327 stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi");
329 g_io_channel_pair(&ch1, &ch2);
330 g_io_channel_set_flags(ch1, G_IO_FLAG_NONBLOCK, NULL);
331 g_io_channel_set_flags(ch2, G_IO_FLAG_NONBLOCK, NULL);
332 cl = client_init_iochannel(NULL, ch1, "test");
333 g_io_channel_unref(ch1);
335 linestack_send_object(ctx, "#bla", lm, NULL, cl, FALSE, FALSE, 0);
336 client_disconnect(cl, "foo");
338 g_io_channel_read_to_end(ch2, &raw, NULL, NULL);
340 fail_unless(!strcmp(raw, ":bla!Gebruikersnaam@Computernaam JOIN #bla\r\n"
341 ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi\r\n"
346 START_TEST(test_object_open)
347 struct irc_network_state *ns1;
348 struct linestack_context *ctx;
350 struct irc_client *cl;
352 GIOChannel *ch1, *ch2;
357 ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
358 ctx = create_linestack(get_linestack_tempdir("test_object_open"), TRUE, ns1);
360 lm = linestack_get_marker(ctx);
362 stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #foo");
363 stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
364 stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #foo :hihi");
365 stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bar :hihi");
366 stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #blablie :hihi");
367 stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi");
369 for (j = 0; j < 4; j++) {
370 g_io_channel_pair(&ch1, &ch2);
371 g_io_channel_set_flags(ch1, G_IO_FLAG_NONBLOCK, NULL);
372 g_io_channel_set_flags(ch2, G_IO_FLAG_NONBLOCK, NULL);
373 cl = client_init_iochannel(NULL, ch1, "test");
374 g_io_channel_unref(ch1);
376 linestack_send_object(ctx, "#bla", NULL, NULL, cl, FALSE, FALSE, 0);
377 client_disconnect(cl, "foo");
379 g_io_channel_read_to_end(ch2, &raw, NULL, NULL);
381 fail_unless(!strcmp(raw, ":bla!Gebruikersnaam@Computernaam JOIN #bla\r\n"
382 ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi\r\n"
387 START_TEST(test_join)
388 struct irc_network_state *ns1, *ns2;
389 struct linestack_context *ctx;
391 ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
392 ctx = create_linestack(get_linestack_tempdir("test_join"), TRUE, ns1);
394 stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
396 ns2 = linestack_get_state(ctx, linestack_get_marker(ctx));
398 fail_unless (network_state_equal(ns1, ns2), "Network state returned not equal");
403 static gboolean line_track(struct irc_line *l, time_t t, void *data)
405 fail_unless(!strcmp(l->args[0], "PRIVMSG"));
406 fail_unless(seen == atoi(l->args[1]));
411 START_TEST(bench_lots_of_lines)
412 struct irc_network_state *ns1;
413 struct linestack_context *ctx;
414 linestack_marker marker;
417 ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
418 ctx = create_linestack(get_linestack_tempdir("lots of lines"), TRUE, ns1);
419 marker = linestack_get_marker(ctx);
423 for (i = 0; i < 10000; i++)
424 linestack_insert_line(ctx, irc_parse_linef("PRIVMSG :%d", i),
427 linestack_traverse(ctx, marker, NULL, line_track, stderr);
430 Suite *linestack_suite()
432 Suite *s = suite_create("linestack");
433 TCase *tc_core = tcase_create("core");
434 suite_add_tcase(s, tc_core);
435 tcase_add_test(tc_core, test_empty);
436 tcase_add_test(tc_core, test_join);
437 tcase_add_test(tc_core, test_msg);
438 tcase_add_test(tc_core, test_skip_msg);
439 tcase_add_test(tc_core, test_object_msg);
440 tcase_add_test(tc_core, test_object_open);
441 tcase_add_test(tc_core, test_join_part);
442 tcase_add_test(tc_core, bench_lots_of_lines);