54b14993b98ae6384661e12bae95124b3515b102
[jelmer/ctrlproxy.git] / testsuite / test-linestack.c
1 /*
2         (c) 2006 Jelmer Vernooij <jelmer@nl.linux.org>
3
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 2 of the License, or
7         (at your option) any later version.
8
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.
13
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.
17 */
18
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <check.h>
23 #include "ctrlproxy.h"
24 #include "torture.h"
25
26 void stack_process(struct linestack_context *ctx, struct network_state *ns, const char *line)
27 {
28         struct line *l;
29         l = irc_parse_line(line);
30         g_assert(l);
31         g_assert(state_handle_data(ns, l));
32         g_assert(linestack_insert_line(ctx, l, FROM_SERVER, ns));
33         free_line(l);
34 }
35
36 #define null_equal(a,b) { \
37         if ((a) == NULL && (b) == NULL) \
38                 return TRUE; \
39         if ((a) == NULL || (b) == NULL) \
40         return FALSE; \
41 }
42
43 static gboolean list_equal(GList *list1, GList *list2, GEqualFunc eq)
44 {
45         GList *gl1, *gl2;
46         null_equal(list1, list2);
47
48         for (gl1 = list1, gl2 = list2; gl1 && gl2; gl1 = gl1->next, gl2 = gl2->next) {
49                 if (!eq(gl1->data, gl2->data))
50                         return FALSE;
51         }
52
53         if (gl1 != NULL || gl2 != NULL)
54                 return FALSE;
55
56         return TRUE;
57 }
58
59 static gboolean str_equal(const char *a, const char *b)
60 {
61         null_equal(a, b);
62
63         return g_str_equal(a, b);
64 }
65
66 static gboolean channel_nick_equal(const struct channel_nick *nick1, const struct channel_nick *nick2)
67 {
68         null_equal(nick1, nick2);
69
70         return nick1->mode == nick2->mode &&
71                    str_equal(nick1->global_nick->nick, nick2->global_nick->nick) &&
72                    str_equal(nick1->channel->name, nick2->channel->name);
73 }
74
75 static gboolean banlist_entry_equal(const struct banlist_entry *entry1, const struct banlist_entry *entry2)
76 {
77         null_equal(entry1, entry2);
78
79         return str_equal(entry1->hostmask, entry2->hostmask) &&
80                    str_equal(entry1->by, entry2->by) &&
81                    entry1->time_set == entry2->time_set;
82 }
83
84 static gboolean channel_state_equal(const struct channel_state *channel1, const struct channel_state *channel2)
85 {
86         null_equal(channel1, channel2);
87
88         return str_equal(channel1->name, channel2->name) &&
89                    str_equal(channel1->key, channel2->key) &&
90                    str_equal(channel1->topic, channel2->topic) &&
91                    channel1->mode == channel2->mode &&
92                    !memcmp(channel1->modes, channel2->modes, 255) &&
93                    channel1->namreply_started == channel2->namreply_started &&
94                    channel1->invitelist_started == channel2->invitelist_started &&
95                    channel1->exceptlist_started == channel2->exceptlist_started &&
96                    channel1->banlist_started == channel2->banlist_started &&
97                    channel1->limit == channel2->limit &&
98                    list_equal(channel1->nicks, channel2->nicks, (GEqualFunc)channel_nick_equal) &&
99                    list_equal(channel1->banlist, channel2->banlist, (GEqualFunc)banlist_entry_equal) &&
100                    list_equal(channel1->invitelist, channel2->invitelist, (GEqualFunc)str_equal) &&
101                    list_equal(channel1->exceptlist, channel2->exceptlist, (GEqualFunc)str_equal);
102 }
103
104 static gboolean network_info_equal(const struct network_info *info1, const struct network_info *info2)
105 {
106         null_equal(info1, info2);
107
108         return str_equal(info1->name, info2->name) &&
109                    str_equal(info1->server, info2->server) &&
110                    str_equal(info1->supported_user_modes, info2->supported_user_modes) &&
111                    str_equal(info1->supported_channel_modes, info2->supported_channel_modes) &&
112                    str_equal(info1->prefix, info2->prefix) &&
113                    str_equal(info1->chantypes, info2->chantypes) &&
114                    str_equal(info1->charset, info2->charset) &&
115                    ((info1->chanmodes == NULL && info2->chanmodes == NULL) ||
116                    (str_equal(info1->chanmodes[0], info2->chanmodes[0]) &&
117                    str_equal(info1->chanmodes[1], info2->chanmodes[1]) &&
118                    str_equal(info1->chanmodes[2], info2->chanmodes[2]) &&
119                    str_equal(info1->chanmodes[3], info2->chanmodes[3]))) &&
120                    info1->keylen == info2->keylen &&
121                    info1->silence == info2->silence &&
122                    info1->channellen == info2->channellen &&
123                    info1->awaylen == info2->awaylen &&
124                    info1->maxtargets == info2->maxtargets &&
125                    info1->nicklen == info2->nicklen &&
126                    info1->userlen == info2->userlen &&
127                    info1->hostlen == info2->hostlen &&
128                    info1->maxchannels == info2->maxchannels &&
129                    info1->topiclen == info2->topiclen &&
130                    info1->maxbans == info2->maxbans &&
131                    info1->maxmodes == info2->maxmodes &&
132                    info1->wallchops == info2->wallchops &&
133                    info1->wallvoices == info2->wallvoices &&
134                    info1->rfc2812 == info2->rfc2812 &&
135                    info1->penalty == info2->penalty &&
136                    info1->forced_nick_changes == info2->forced_nick_changes &&
137                    info1->safelist == info2->safelist &&
138                    info1->userip == info2->userip &&
139                    info1->cprivmsg == info2->cprivmsg &&
140                    info1->cnotice == info2->cnotice &&
141                    info1->knock == info2->knock &&
142                    info1->vchannels == info2->vchannels &&
143                    info1->whox == info2->whox &&
144                    info1->callerid == info2->callerid &&
145                    info1->accept == info2->accept &&
146                    info1->capab == info2->capab &&
147                    info1->casemapping == info2->casemapping;
148 }
149
150 static gboolean network_nick_equal(const struct network_nick *nick1, const struct network_nick *nick2)
151 {
152         null_equal(nick1, nick2);
153
154         return nick1->query == nick2->query &&
155                    str_equal(nick1->nick, nick2->nick) &&
156                    str_equal(nick1->fullname, nick2->fullname) &&
157                    str_equal(nick1->username, nick2->username) &&
158                    str_equal(nick1->hostname, nick2->hostname) &&
159                    !memcmp(nick1->modes, nick2->modes, 255) &&
160                    list_equal(nick1->channel_nicks, nick2->channel_nicks, 
161                                           (GEqualFunc)channel_nick_equal);
162 }
163
164 static gboolean network_state_equal(const struct network_state *state1, 
165                                                                         const struct network_state *state2)
166 {
167         null_equal(state1, state2);
168
169         return network_nick_equal(&state1->me, &state2->me) &&
170                    network_info_equal(&state1->info, &state2->info) &&
171                    list_equal(state1->channels, state2->channels, 
172                                           (GEqualFunc)channel_state_equal) &&
173                    list_equal(state1->nicks, state2->nicks, 
174                                           (GEqualFunc)network_nick_equal);
175 }
176
177 static struct ctrlproxy_config *my_config;
178
179 extern const struct linestack_ops linestack_file;
180
181 START_TEST(test_empty)
182         struct network_state *ns1, *ns2;
183         struct linestack_context *ctx;
184         
185         ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
186         ctx = create_linestack(&linestack_file, "test", my_config, ns1);
187
188         ns2 = linestack_get_state(ctx, NULL);
189
190         fail_unless (network_state_equal(ns1, ns2), 
191                                  "Network state returned not equal");
192 END_TEST
193
194 START_TEST(test_msg)
195         struct network_state *ns1;
196         struct linestack_context *ctx;
197         struct linestack_marker *lm;
198         struct client *cl;
199
200         GIOChannel *ch1, *ch2;
201         char *raw;
202         
203         ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
204         ctx = create_linestack(&linestack_file, "test", my_config, ns1);
205
206         lm = linestack_get_marker(ctx);
207
208         stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
209         stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi");
210
211         g_io_channel_pair(&ch1, &ch2);
212         g_io_channel_set_flags(ch1, G_IO_FLAG_NONBLOCK, NULL);
213         g_io_channel_set_flags(ch2, G_IO_FLAG_NONBLOCK, NULL);
214         cl = client_init(NULL, ch1, "test");
215         g_io_channel_unref(ch1);
216
217         linestack_send(ctx, lm, NULL, cl);
218         disconnect_client(cl, "foo");
219
220         g_io_channel_read_to_end(ch2, &raw, NULL, NULL);
221
222         fail_unless(!strcmp(raw, ":bla!Gebruikersnaam@Computernaam JOIN #bla\r\n"
223                                                      ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi\r\n"
224                                                          "ERROR :foo\r\n"));
225 END_TEST
226
227 START_TEST(test_join_part)
228         struct network_state *ns1;
229         struct linestack_context *ctx;
230         struct linestack_marker *lm;
231         struct client *cl;
232
233         GIOChannel *ch1, *ch2;
234         char *raw;
235         
236         ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
237         ctx = create_linestack(&linestack_file, "test", my_config, ns1);
238
239         lm = linestack_get_marker(ctx);
240
241         stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
242         stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam PART #bla :hihi");
243
244         g_io_channel_pair(&ch1, &ch2);
245         g_io_channel_set_flags(ch1, G_IO_FLAG_NONBLOCK, NULL);
246         g_io_channel_set_flags(ch2, G_IO_FLAG_NONBLOCK, NULL);
247         cl = client_init(NULL, ch1, "test");
248         g_io_channel_unref(ch1);
249
250         linestack_send(ctx, lm, NULL, cl);
251         disconnect_client(cl, "foo");
252
253         g_io_channel_read_to_end(ch2, &raw, NULL, NULL);
254
255         fail_unless(!strcmp(raw, ":bla!Gebruikersnaam@Computernaam JOIN #bla\r\n"
256                                                      ":bla!Gebruikersnaam@Computernaam PART #bla :hihi\r\n"
257                                                          "ERROR :foo\r\n"));
258 END_TEST
259
260
261
262 START_TEST(test_skip_msg)
263         struct network_state *ns1;
264         struct linestack_context *ctx;
265         struct linestack_marker *lm;
266         struct client *cl;
267
268         GIOChannel *ch1, *ch2;
269         char *raw;
270         
271         ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
272         ctx = create_linestack(&linestack_file, "test", my_config, ns1);
273
274         stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :haha");
275
276         lm = linestack_get_marker(ctx);
277
278         stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
279         stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi");
280
281         g_io_channel_pair(&ch1, &ch2);
282         g_io_channel_set_flags(ch1, G_IO_FLAG_NONBLOCK, NULL);
283         g_io_channel_set_flags(ch2, G_IO_FLAG_NONBLOCK, NULL);
284         cl = client_init(NULL, ch1, "test");
285         g_io_channel_unref(ch1);
286
287         linestack_send(ctx, lm, NULL, cl);
288         disconnect_client(cl, "foo");
289
290         g_io_channel_read_to_end(ch2, &raw, NULL, NULL);
291
292         fail_unless(!strcmp(raw, ":bla!Gebruikersnaam@Computernaam JOIN #bla\r\n"
293                                                      ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi\r\n"
294                                                          "ERROR :foo\r\n"));
295 END_TEST
296
297 START_TEST(test_object_msg)
298         struct network_state *ns1;
299         struct linestack_context *ctx;
300         struct linestack_marker *lm;
301         struct client *cl;
302
303         GIOChannel *ch1, *ch2;
304         char *raw;
305         
306         ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
307         ctx = create_linestack(&linestack_file, "test", my_config, ns1);
308
309         lm = linestack_get_marker(ctx);
310
311         stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #foo");
312         stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
313         stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #foo :hihi");
314         stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bar :hihi");
315         stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #blablie :hihi");
316         stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi");
317
318         g_io_channel_pair(&ch1, &ch2);
319         g_io_channel_set_flags(ch1, G_IO_FLAG_NONBLOCK, NULL);
320         g_io_channel_set_flags(ch2, G_IO_FLAG_NONBLOCK, NULL);
321         cl = client_init(NULL, ch1, "test");
322         g_io_channel_unref(ch1);
323
324         linestack_send_object(ctx, "#bla", lm, NULL, cl);
325         disconnect_client(cl, "foo");
326
327         g_io_channel_read_to_end(ch2, &raw, NULL, NULL);
328
329         fail_unless(!strcmp(raw, ":bla!Gebruikersnaam@Computernaam JOIN #bla\r\n"
330                                                      ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi\r\n"
331                                                          "ERROR :foo\r\n"));
332 END_TEST
333
334
335 START_TEST(test_object_open)
336         struct network_state *ns1;
337         struct linestack_context *ctx;
338         struct linestack_marker *lm;
339         struct client *cl;
340
341         GIOChannel *ch1, *ch2;
342         char *raw;
343
344         int j;
345         
346         ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
347         ctx = create_linestack(&linestack_file, "test", my_config, ns1);
348
349         lm = linestack_get_marker(ctx);
350
351         stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #foo");
352         stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
353         stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #foo :hihi");
354         stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bar :hihi");
355         stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #blablie :hihi");
356         stack_process(ctx, ns1, ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi");
357
358         for (j = 0; j < 4; j++) {
359                 g_io_channel_pair(&ch1, &ch2);
360                 g_io_channel_set_flags(ch1, G_IO_FLAG_NONBLOCK, NULL);
361                 g_io_channel_set_flags(ch2, G_IO_FLAG_NONBLOCK, NULL);
362                 cl = client_init(NULL, ch1, "test");
363                 g_io_channel_unref(ch1);
364
365                 linestack_send_object(ctx, "#bla", NULL, NULL, cl);
366                 disconnect_client(cl, "foo");
367
368                 g_io_channel_read_to_end(ch2, &raw, NULL, NULL);
369
370                 fail_unless(!strcmp(raw, ":bla!Gebruikersnaam@Computernaam JOIN #bla\r\n"
371                                                 ":bloe!Gebruikersnaam@Computernaam PRIVMSG #bla :hihi\r\n"
372                                                 "ERROR :foo\r\n"));
373         }
374 END_TEST
375
376 START_TEST(test_join)
377         struct network_state *ns1, *ns2;
378         struct linestack_context *ctx;
379         
380         ns1 = network_state_init("bla", "Gebruikersnaam", "Computernaam");
381         ctx = create_linestack(&linestack_file, "test", my_config, ns1);
382
383         stack_process(ctx, ns1, ":bla!Gebruikersnaam@Computernaam JOIN #bla");
384
385         ns2 = linestack_get_state(ctx, linestack_get_marker(ctx));
386
387         fail_unless (network_state_equal(ns1, ns2), "Network state returned not equal");
388 END_TEST
389
390 Suite *linestack_suite()
391 {
392         Suite *s = suite_create("linestack");
393         TCase *tc_core = tcase_create("core");
394         my_config = g_new0(struct ctrlproxy_config, 1);
395         my_config->config_dir = "/tmp";
396         suite_add_tcase(s, tc_core);
397         tcase_add_test(tc_core, test_empty);
398         tcase_add_test(tc_core, test_join);
399         tcase_add_test(tc_core, test_msg);
400         tcase_add_test(tc_core, test_skip_msg);
401         tcase_add_test(tc_core, test_object_msg);
402         tcase_add_test(tc_core, test_object_open);
403         tcase_add_test(tc_core, test_join_part);
404         return s;
405 }