Mercurial > irccd
annotate tests/test-plugin-tictactoe.c @ 1011:a35537c50f09
irccd: hide conn implementation
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 17 Feb 2021 20:05:00 +0100 |
parents | 3ea3361f0fc7 |
children | 8f8ce47aba8a |
rev | line source |
---|---|
995 | 1 /* |
2 * test-plugin-tictactoe.c -- test tictactoe plugin | |
3 * | |
4 * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #include <err.h> | |
20 | |
21 #define GREATEST_USE_ABBREVS 0 | |
22 #include <greatest.h> | |
23 | |
24 #include <irccd/compat.h> | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
25 #include <irccd/conn.h> |
1001
b01f5d65d62a
misc: various fixes for glibc
David Demelier <markand@malikania.fr>
parents:
995
diff
changeset
|
26 #include <irccd/irccd.h> |
995 | 27 #include <irccd/js-plugin.h> |
28 #include <irccd/log.h> | |
29 #include <irccd/plugin.h> | |
30 #include <irccd/server.h> | |
31 #include <irccd/util.h> | |
32 | |
33 #define CALL(t, m) do { \ | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
34 memset(server->conn->out, 0, sizeof (server->conn->out)); \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
35 irc_plugin_handle(plugin, &(const struct irc_event) { \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
36 .type = t, \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
37 .server = server, \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
38 .message = { \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
39 .origin = "jean!jean@localhost", \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
40 .channel = "#hangman", \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
41 .message = m \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
42 } \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
43 }); \ |
995 | 44 } while (0) |
45 | |
46 #define CALL_EX(t, o, c, m) do { \ | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
47 memset(server->conn->out, 0, sizeof (server->conn->out)); \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
48 irc_plugin_handle(plugin, &(const struct irc_event) { \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
49 .type = t, \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
50 .server = server, \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
51 .message = { \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
52 .origin = o, \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
53 .channel = c, \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
54 .message = m \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
55 } \ |
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
56 }); \ |
995 | 57 } while (0) |
58 | |
59 static struct irc_server *server; | |
60 static struct irc_plugin *plugin; | |
61 | |
62 static void | |
63 setup(void *udata) | |
64 { | |
65 (void)udata; | |
66 | |
67 server = irc_server_new("test", "t", "t", "t", "127.0.0.1", 6667); | |
68 plugin = js_plugin_open("tictactoe", CMAKE_SOURCE_DIR "/plugins/tictactoe/tictactoe.js"); | |
69 | |
70 if (!plugin) | |
71 errx(1, "could not load plugin"); | |
72 | |
1001
b01f5d65d62a
misc: various fixes for glibc
David Demelier <markand@malikania.fr>
parents:
995
diff
changeset
|
73 irc_bot_init(); |
995 | 74 irc_server_incref(server); |
75 irc_plugin_set_template(plugin, "draw", "draw=#{channel}:#{command}:#{nickname}:#{plugin}:#{server}"); | |
76 irc_plugin_set_template(plugin, "invalid", "invalid=#{channel}:#{command}:#{nickname}:#{origin}:#{plugin}:#{server}"); | |
77 irc_plugin_set_template(plugin, "running", "running=#{channel}:#{command}:#{nickname}:#{origin}:#{plugin}:#{server}"); | |
78 irc_plugin_set_template(plugin, "turn", "turn=#{channel}:#{command}:#{nickname}:#{plugin}:#{server}"); | |
79 irc_plugin_set_template(plugin, "used", "used=#{channel}:#{command}:#{nickname}:#{origin}:#{plugin}:#{server}"); | |
80 irc_plugin_set_template(plugin, "win", "win=#{channel}:#{command}:#{nickname}:#{plugin}:#{server}"); | |
81 irc_plugin_load(plugin); | |
82 | |
83 /* We need tw players on a channel to play the game. */ | |
84 irc_server_join(server, "#tictactoe", NULL); | |
1004
3ea3361f0fc7
irccd: now track modes
David Demelier <markand@malikania.fr>
parents:
1001
diff
changeset
|
85 irc_channel_add(LIST_FIRST(&server->channels), "a", 0); |
3ea3361f0fc7
irccd: now track modes
David Demelier <markand@malikania.fr>
parents:
1001
diff
changeset
|
86 irc_channel_add(LIST_FIRST(&server->channels), "b", 0); |
1001
b01f5d65d62a
misc: various fixes for glibc
David Demelier <markand@malikania.fr>
parents:
995
diff
changeset
|
87 |
995 | 88 /* Fake server connected to send data. */ |
89 server->state = IRC_SERVER_STATE_CONNECTED; | |
90 } | |
91 | |
92 static void | |
93 teardown(void *udata) | |
94 { | |
95 (void)udata; | |
96 | |
97 irc_plugin_finish(plugin); | |
98 irc_server_decref(server); | |
99 } | |
100 | |
101 static char | |
102 next(void) | |
103 { | |
104 const char *lines[5] = {0}; | |
105 char player = 0, *buf; | |
106 | |
107 /* We need to skip 4 lines.*/ | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
108 buf = irc_util_strdup(server->conn->out); |
995 | 109 irc_util_split(buf, lines, 5, '\n'); |
110 | |
111 if (!lines[4] || sscanf(lines[4], "PRIVMSG #tictactoe :turn=#tictactoe:!tictactoe:%c:tictactoe:test\r\n", &player) != 1) | |
112 errx(1, "could not determine player"); | |
113 | |
114 free(buf); | |
115 | |
116 return player; | |
117 } | |
118 | |
119 static void | |
120 play(const char *value) | |
121 { | |
122 char player[] = { next(), '\0' }; | |
123 | |
124 CALL_EX(IRC_EVENT_MESSAGE, player, "#tictactoe", (char *)value); | |
125 } | |
126 | |
127 GREATEST_TEST | |
128 basics_win(void) | |
129 { | |
130 const char *lines[5] = {0}; | |
131 char k1, k2; | |
132 | |
133 CALL_EX(IRC_EVENT_COMMAND, "a", "#tictactoe", "b"); | |
134 | |
135 play("a 1"); | |
136 play("b1"); | |
137 play("a 2"); | |
138 play("b2"); | |
139 play("a3"); | |
140 | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
141 GREATEST_ASSERT_EQ(5U, irc_util_split(server->conn->out, lines, 5, '\n')); |
995 | 142 GREATEST_ASSERT_EQ(0, sscanf(lines[0], "PRIVMSG #tictactoe : a b c\r")); |
143 GREATEST_ASSERT_EQ(2, sscanf(lines[1], "PRIVMSG #tictactoe :1 %c %c .\r", &k1, &k2)); | |
144 GREATEST_ASSERT_EQ(2, sscanf(lines[2], "PRIVMSG #tictactoe :2 %c %c .\r", &k1, &k2)); | |
145 GREATEST_ASSERT_EQ(1, sscanf(lines[3], "PRIVMSG #tictactoe :3 %c . .\r", &k1)); | |
146 GREATEST_ASSERT_EQ(1, sscanf(lines[4], "PRIVMSG #tictactoe :win=#tictactoe:!tictactoe:%c:tictactoe:test\r\n", &k1)); | |
147 | |
148 GREATEST_PASS(); | |
149 } | |
150 | |
151 GREATEST_TEST | |
152 basics_draw(void) | |
153 { | |
154 /* | |
155 * a b c | |
156 * 1 o x o | |
157 * 2 o x x | |
158 * 3 x o x | |
159 */ | |
160 const char *lines[5] = {0}; | |
161 char k1, k2, k3; | |
162 | |
163 CALL_EX(IRC_EVENT_COMMAND, "a", "#tictactoe", "b"); | |
164 | |
165 play("b 2"); | |
166 play("c 1"); | |
167 play("c 3"); | |
168 play("b 3"); | |
169 play("c 2"); | |
170 play("a 2"); | |
171 play("a 3"); | |
172 play("a 1"); | |
173 play("b 1"); | |
174 | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
175 GREATEST_ASSERT_EQ(5U, irc_util_split(server->conn->out, lines, 5, '\n')); |
995 | 176 GREATEST_ASSERT_EQ(0, sscanf(lines[0], "PRIVMSG #tictactoe : a b c\r")); |
177 GREATEST_ASSERT_EQ(3, sscanf(lines[1], "PRIVMSG #tictactoe :1 %c %c %c\r", &k1, &k2, &k3)); | |
178 GREATEST_ASSERT_EQ(3, sscanf(lines[2], "PRIVMSG #tictactoe :2 %c %c %c\r", &k1, &k2, &k3)); | |
179 GREATEST_ASSERT_EQ(3, sscanf(lines[3], "PRIVMSG #tictactoe :3 %c %c %c\r", &k1, &k2, &k3)); | |
180 GREATEST_ASSERT_EQ(1, sscanf(lines[4], "PRIVMSG #tictactoe :draw=#tictactoe:!tictactoe:%c:tictactoe:test\r\n", &k1)); | |
181 | |
182 GREATEST_PASS(); | |
183 } | |
184 | |
185 GREATEST_TEST | |
186 basics_used(void) | |
187 { | |
188 char k1, k2; | |
189 | |
190 CALL_EX(IRC_EVENT_COMMAND, "a", "#tictactoe", "b"); | |
191 | |
192 play("a 1"); | |
193 play("a 1"); | |
194 | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
195 GREATEST_ASSERT_EQ(2, sscanf(server->conn->out, "PRIVMSG #tictactoe :used=#tictactoe:!tictactoe:%c:%c:tictactoe:test\r\n", &k1, &k2)); |
995 | 196 |
197 GREATEST_PASS(); | |
198 } | |
199 | |
200 GREATEST_TEST | |
201 basics_invalid(void) | |
202 { | |
203 char k1, k2; | |
204 | |
205 /* Player select itself. */ | |
206 CALL_EX(IRC_EVENT_COMMAND, "a", "#tictactoe", "a"); | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
207 GREATEST_ASSERT_EQ(2, sscanf(server->conn->out, "PRIVMSG #tictactoe :invalid=#tictactoe:!tictactoe:%c:%c:tictactoe:test\r\n", &k1, &k2)); |
995 | 208 |
209 /* Player select the bot. */ | |
210 CALL_EX(IRC_EVENT_COMMAND, "a", "#tictactoe", "t"); | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
211 GREATEST_ASSERT_EQ(2, sscanf(server->conn->out, "PRIVMSG #tictactoe :invalid=#tictactoe:!tictactoe:%c:%c:tictactoe:test\r\n", &k1, &k2)); |
995 | 212 |
213 /* Someone not on the channel. */ | |
214 CALL_EX(IRC_EVENT_COMMAND, "a", "#tictactoe", "jean"); | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
215 GREATEST_ASSERT_EQ(2, sscanf(server->conn->out, "PRIVMSG #tictactoe :invalid=#tictactoe:!tictactoe:%c:%c:tictactoe:test\r\n", &k1, &k2)); |
995 | 216 |
217 GREATEST_PASS(); | |
218 } | |
219 | |
220 GREATEST_TEST | |
221 basics_random(void) | |
222 { | |
223 /* | |
224 * Ensure that the first player is not always the originator, start the | |
225 * game for at most 100 times to avoid forever loop. | |
226 */ | |
227 int count = 0, a = 0, b = 0; | |
228 | |
229 /* Last player turn is the winner. */ | |
230 while (count++ < 100) { | |
231 CALL_EX(IRC_EVENT_COMMAND, "a", "#tictactoe", "b"); | |
232 | |
233 play("a 1"); | |
234 play("b 1"); | |
235 play("a 2"); | |
236 play("b 2"); | |
237 | |
238 /* This is the player that will win. */ | |
239 if (next() == 'a') | |
240 a = 1; | |
241 else | |
242 b = 1; | |
243 | |
244 play("a 3"); | |
245 } | |
246 | |
247 GREATEST_ASSERT(a); | |
248 GREATEST_ASSERT(b); | |
249 | |
250 GREATEST_PASS(); | |
251 } | |
252 | |
253 GREATEST_TEST | |
254 basics_disconnect(void) | |
255 { | |
256 CALL_EX(IRC_EVENT_COMMAND, "a", "#tictactoe", "b"); | |
257 | |
258 irc_plugin_handle(plugin, &(const struct irc_event) { | |
259 .type = IRC_EVENT_DISCONNECT, | |
260 .server = server | |
261 }); | |
262 | |
263 play("a 1"); | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
264 GREATEST_ASSERT_STR_EQ("", server->conn->out); |
1001
b01f5d65d62a
misc: various fixes for glibc
David Demelier <markand@malikania.fr>
parents:
995
diff
changeset
|
265 |
995 | 266 GREATEST_PASS(); |
267 } | |
268 | |
269 GREATEST_TEST | |
270 basics_kick(void) | |
271 { | |
272 CALL_EX(IRC_EVENT_COMMAND, "a", "#tictactoe", "b"); | |
273 | |
274 irc_plugin_handle(plugin, &(const struct irc_event) { | |
275 .type = IRC_EVENT_KICK, | |
276 .server = server, | |
277 .kick = { | |
278 .origin = "god", | |
279 .channel = "#TiCTaCToE", | |
280 .target = "a", | |
281 .reason = "No reason, I do what I want." | |
282 } | |
283 }); | |
284 | |
285 play("a 1"); | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
286 GREATEST_ASSERT_STR_EQ("", server->conn->out); |
995 | 287 |
288 GREATEST_PASS(); | |
289 } | |
290 | |
291 GREATEST_TEST | |
292 basics_part(void) | |
293 { | |
294 CALL_EX(IRC_EVENT_COMMAND, "a", "#tictactoe", "b"); | |
295 | |
296 irc_plugin_handle(plugin, &(const struct irc_event) { | |
297 .type = IRC_EVENT_PART, | |
298 .server = server, | |
299 .part = { | |
300 .origin = "a", | |
301 .channel = "#TiCTaCToE", | |
302 .reason = "I'm too bad at this game." | |
303 } | |
304 }); | |
305 | |
306 play("a 1"); | |
1011
a35537c50f09
irccd: hide conn implementation
David Demelier <markand@malikania.fr>
parents:
1004
diff
changeset
|
307 GREATEST_ASSERT_STR_EQ("", server->conn->out); |
995 | 308 |
309 GREATEST_PASS(); | |
310 } | |
311 | |
312 GREATEST_SUITE(suite_basics) | |
313 { | |
314 GREATEST_SET_SETUP_CB(setup, NULL); | |
315 GREATEST_SET_TEARDOWN_CB(teardown, NULL); | |
316 GREATEST_RUN_TEST(basics_win); | |
317 GREATEST_RUN_TEST(basics_draw); | |
318 GREATEST_RUN_TEST(basics_used); | |
319 GREATEST_RUN_TEST(basics_invalid); | |
320 GREATEST_RUN_TEST(basics_random); | |
321 GREATEST_RUN_TEST(basics_disconnect); | |
322 GREATEST_RUN_TEST(basics_kick); | |
323 GREATEST_RUN_TEST(basics_part); | |
324 } | |
325 | |
326 GREATEST_MAIN_DEFS(); | |
327 | |
328 int | |
329 main(int argc, char **argv) | |
330 { | |
331 GREATEST_MAIN_BEGIN(); | |
332 GREATEST_RUN_SUITE(suite_basics); | |
333 GREATEST_MAIN_END(); | |
334 | |
335 return 0; | |
336 } |