1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <string.h>
8
9 #include <glib.h>
10
11 #include <wocky/wocky.h>
12
13 #include "wocky-test-helper.h"
14
15 #define HEADER \
16 "<?xml version='1.0' encoding='UTF-8'?> " \
17 "<stream:stream xmlns='jabber:client' " \
18 " xmlns:stream='http://etherx.jabber.org/streams'> "
19
20 #define FOOTER "</stream:stream> "
21
22 #define BROKEN_HEADER \
23 "<?xml version='1.0' encoding='UTF-8'?> " \
24 "<stream:streamsss xmlns='jabber:client' " \
25 " xmlns:stream='http://etherx.jabber.org/streams'> "
26
27 #define HEADER_WITH_UNQUALIFIED_LANG \
28 "<?xml version='1.0' encoding='UTF-8'?> " \
29 "<stream:stream xmlns='jabber:client' " \
30 " xmlns:stream='http://etherx.jabber.org/streams' " \
31 " lang='fi'> "
32
33 #define BROKEN_MESSAGE \
34 " <message to='juliet@example.com' from='romeo@example.net' xml:lang='en' " \
35 " id=\"0\"> " \
36 " <body>Art thou not Romeo, and a Montague?</ody> " \
37 " </essage> "
38
39 #define MESSAGE_CHUNK0 \
40 " <message to='juliet@example.com' from='romeo@example.net' xml:lang='en' " \
41 " id=\"0\"> " \
42 " <body>Art thou not Romeo, "
43
44 #define MESSAGE_CHUNK1 \
45 " and a Montague?</body> " \
46 " </message> "
47
48 #define VCARD_MESSAGE \
49 " <iq id='v1' " \
50 " to='stpeter@jabber.org/roundabout' " \
51 " type='result'> " \
52 " <vCard xmlns='vcard-temp'> " \
53 " <FN>Peter Saint-Andre</FN> " \
54 " <N> " \
55 " <FAMILY>Saint-Andre</FAMILY> " \
56 " <GIVEN>Peter</GIVEN> " \
57 " <MIDDLE/> " \
58 " </N> " \
59 " <NICKNAME>stpeter</NICKNAME> " \
60 " <URL>http://www.xmpp.org/xsf/people/stpeter.shtml</URL> " \
61 " <BDAY>1966-08-06</BDAY> " \
62 " <ORG> " \
63 " <ORGNAME>XMPP Standards Foundation</ORGNAME> " \
64 " <ORGUNIT/> " \
65 " </ORG> " \
66 " <TITLE>Executive Director</TITLE> " \
67 " <ROLE>Patron Saint</ROLE> " \
68 " <JABBERID>stpeter@jabber.org</JABBERID> " \
69 " </vCard> " \
70 "</iq> "
71
72 #define VALID_NAMESPACE "http://garden.with.spaces"
73 #define INVALID_NAMESPACE_MESSAGE \
74 "<iq id='badger0' to='plant@collabora.cbg' type='result'> "\
75 " <branch xmlns=' "VALID_NAMESPACE" '> " \
76 " <leaf colour='green' /> " \
77 " </branch> " \
78 "</iq> "
79
80 #define WHITESPACE_PADDED_BODY " The Wench is Dead! "
81
82 #define MESSAGE_WITH_WHITESPACE_PADDED_BODY \
83 " <message to='morse@thamesvalley.police.uk' " \
84 " from='lewis@thamesvalley.police.uk'> " \
85 " <body>" WHITESPACE_PADDED_BODY "</body>" \
86 " </message>"
87
88
89 #define WHITESPACE_ONLY_BODY " "
90
91 #define MESSAGE_WITH_WHITESPACE_ONLY_BODY \
92 " <message to='morse@thamesvalley.police.uk' " \
93 " from='lewis@thamesvalley.police.uk'> " \
94 " <body>" WHITESPACE_ONLY_BODY "</body>" \
95 " </message>"
96
97 #define U_FDEF "\xe7\xb7\xaf" /* a non-character */
98 #define REPLACE "\xef\xbf\xbd" /* U+FFFD REPLACEMENT CHARACTER */
99 #define MONKEY "\xf0\x9f\x99\x88" /* U+1F648 SEE-NO-EVIL MONKEY */
100
101 #define NON_CHARACTER_CODEPOINTS U_FDEF MONKEY U_FDEF
102 #define NON_CHARACTER_CODEPOINTS_REPLACEMENT REPLACE MONKEY REPLACE
103
104 #define MESSAGE_WITH_NON_CHARACTER_CODEPOINTS \
105 " <message to='morse@thamesvalley.police.uk' " \
106 " from='lewis@thamesvalley.police.uk'> " \
107 " <body>" NON_CHARACTER_CODEPOINTS "</body>" \
108 " </message>"
109
110
111
112 static void
test_stream_no_stanzas(void)113 test_stream_no_stanzas (void)
114 {
115 WockyXmppReader *reader;
116 GError *error = NULL;
117
118 reader = wocky_xmpp_reader_new ();
119
120 g_assert (wocky_xmpp_reader_get_state (reader)
121 == WOCKY_XMPP_READER_STATE_INITIAL);
122
123 wocky_xmpp_reader_push (reader,
124 (guint8 *) HEADER FOOTER, strlen (HEADER FOOTER));
125
126 g_assert (wocky_xmpp_reader_get_state (reader)
127 == WOCKY_XMPP_READER_STATE_CLOSED);
128 g_assert (wocky_xmpp_reader_peek_stanza (reader) == NULL);
129
130 g_assert (wocky_xmpp_reader_get_state (reader)
131 == WOCKY_XMPP_READER_STATE_CLOSED);
132 g_assert (wocky_xmpp_reader_pop_stanza (reader) == NULL);
133
134 g_assert (wocky_xmpp_reader_get_state (reader)
135 == WOCKY_XMPP_READER_STATE_CLOSED);
136
137 error = wocky_xmpp_reader_get_error (reader);
138
139 g_assert_no_error (error);
140
141 g_object_unref (reader);
142 }
143
144 static void
test_stream_open_error(void)145 test_stream_open_error (void)
146 {
147 WockyXmppReader *reader;
148 GError *error = NULL;
149
150 reader = wocky_xmpp_reader_new ();
151
152 g_assert (wocky_xmpp_reader_get_state (reader)
153 == WOCKY_XMPP_READER_STATE_INITIAL);
154
155 wocky_xmpp_reader_push (reader,
156 (guint8 *) BROKEN_HEADER, strlen (BROKEN_HEADER));
157
158 g_assert (wocky_xmpp_reader_get_state (reader)
159 == WOCKY_XMPP_READER_STATE_ERROR);
160
161 error = wocky_xmpp_reader_get_error (reader);
162
163 g_assert_error (error, WOCKY_XMPP_READER_ERROR,
164 WOCKY_XMPP_READER_ERROR_INVALID_STREAM_START);
165
166 g_error_free (error);
167
168 g_object_unref (reader);
169 }
170
171 static void
test_stream_open_unqualified_lang(void)172 test_stream_open_unqualified_lang (void)
173 {
174 WockyXmppReader *reader = wocky_xmpp_reader_new ();
175
176 g_assert (wocky_xmpp_reader_get_state (reader)
177 == WOCKY_XMPP_READER_STATE_INITIAL);
178
179 wocky_xmpp_reader_push (reader,
180 (guint8 *) HEADER_WITH_UNQUALIFIED_LANG,
181 strlen (HEADER_WITH_UNQUALIFIED_LANG));
182
183 g_assert (wocky_xmpp_reader_get_state (reader)
184 == WOCKY_XMPP_READER_STATE_OPENED);
185
186 g_object_unref (reader);
187 }
188
189 static void
test_parse_error(void)190 test_parse_error (void)
191 {
192 WockyXmppReader *reader;
193 GError *error = NULL;
194
195 reader = wocky_xmpp_reader_new ();
196
197 g_assert (wocky_xmpp_reader_get_state (reader)
198 == WOCKY_XMPP_READER_STATE_INITIAL);
199
200 wocky_xmpp_reader_push (reader,
201 (guint8 *) HEADER, strlen (HEADER));
202
203 g_assert (wocky_xmpp_reader_get_state (reader)
204 == WOCKY_XMPP_READER_STATE_OPENED);
205
206 wocky_xmpp_reader_push (reader,
207 (guint8 *) BROKEN_MESSAGE, strlen (BROKEN_MESSAGE));
208
209 g_assert (wocky_xmpp_reader_get_state (reader)
210 == WOCKY_XMPP_READER_STATE_ERROR);
211
212 g_assert (wocky_xmpp_reader_peek_stanza (reader) == NULL);
213 g_assert (wocky_xmpp_reader_get_state (reader)
214 == WOCKY_XMPP_READER_STATE_ERROR);
215
216 g_assert (wocky_xmpp_reader_pop_stanza (reader) == NULL);
217 g_assert (wocky_xmpp_reader_get_state (reader)
218 == WOCKY_XMPP_READER_STATE_ERROR);
219
220 error = wocky_xmpp_reader_get_error (reader);
221
222 g_assert_error (error, WOCKY_XMPP_READER_ERROR,
223 WOCKY_XMPP_READER_ERROR_PARSE_ERROR);
224
225 g_error_free (error);
226 g_object_unref (reader);
227 }
228
229 static void
test_no_stream_parse_message(WockyXmppReader * reader)230 test_no_stream_parse_message (WockyXmppReader *reader)
231 {
232 WockyStanza *stanza;
233
234 g_assert (wocky_xmpp_reader_get_state (reader)
235 == WOCKY_XMPP_READER_STATE_OPENED);
236
237 wocky_xmpp_reader_push (reader,
238 (guint8 *) MESSAGE_CHUNK0, strlen (MESSAGE_CHUNK0));
239
240 g_assert (wocky_xmpp_reader_pop_stanza (reader) == NULL);
241
242 g_assert (wocky_xmpp_reader_get_state (reader)
243 == WOCKY_XMPP_READER_STATE_OPENED);
244
245 wocky_xmpp_reader_push (reader,
246 (guint8 *) MESSAGE_CHUNK1, strlen (MESSAGE_CHUNK1));
247
248 g_assert (wocky_xmpp_reader_get_state (reader)
249 == WOCKY_XMPP_READER_STATE_OPENED);
250
251 g_assert ((stanza = wocky_xmpp_reader_peek_stanza (reader)) != NULL);
252 g_assert ((stanza = wocky_xmpp_reader_pop_stanza (reader)) != NULL);
253 g_assert (wocky_xmpp_reader_get_state (reader)
254 == WOCKY_XMPP_READER_STATE_CLOSED);
255
256 g_object_unref (stanza);
257
258 }
259
260 static void
test_no_stream_hunks(void)261 test_no_stream_hunks (void)
262 {
263 WockyXmppReader *reader;
264
265 reader = wocky_xmpp_reader_new_no_stream ();
266 test_no_stream_parse_message (reader);
267
268 g_object_unref (reader);
269 }
270
271 static void
test_no_stream_reset(void)272 test_no_stream_reset (void)
273 {
274 WockyXmppReader *reader;
275
276 reader = wocky_xmpp_reader_new_no_stream ();
277
278 /* whole message, reset, whole message, reset */
279 test_no_stream_parse_message (reader);
280 wocky_xmpp_reader_reset (reader);
281
282 test_no_stream_parse_message (reader);
283 wocky_xmpp_reader_reset (reader);
284
285 /* push half a message and reset the parser*/
286 g_assert (wocky_xmpp_reader_get_state (reader)
287 == WOCKY_XMPP_READER_STATE_OPENED);
288 wocky_xmpp_reader_push (reader,
289 (guint8 *) MESSAGE_CHUNK0, strlen (MESSAGE_CHUNK0));
290 wocky_xmpp_reader_reset (reader);
291
292 /* And push a whole message through again */
293 test_no_stream_parse_message (reader);
294
295 g_object_unref (reader);
296 }
297
298 /* libXML2 doesn't like the vcard-temp namespace test if we can still
299 correctly parse it */
300 static void
test_vcard_namespace(void)301 test_vcard_namespace (void)
302 {
303 WockyXmppReader *reader;
304 WockyStanza *stanza;
305
306 reader = wocky_xmpp_reader_new_no_stream ();
307
308 wocky_xmpp_reader_push (reader,
309 (guint8 *) VCARD_MESSAGE, strlen (VCARD_MESSAGE));
310
311 g_assert ((stanza = wocky_xmpp_reader_pop_stanza (reader)) != NULL);
312 g_assert (wocky_xmpp_reader_get_state (reader)
313 == WOCKY_XMPP_READER_STATE_CLOSED);
314
315 g_object_unref (stanza);
316 g_object_unref (reader);
317 }
318
319 static void
test_invalid_namespace(void)320 test_invalid_namespace (void)
321 {
322 WockyXmppReader *reader;
323 WockyStanza *stanza;
324
325 reader = wocky_xmpp_reader_new_no_stream ();
326
327 wocky_xmpp_reader_push (reader,
328 (guint8 *) INVALID_NAMESPACE_MESSAGE, strlen (INVALID_NAMESPACE_MESSAGE));
329
330 g_assert ((stanza = wocky_xmpp_reader_pop_stanza (reader)) != NULL);
331 g_assert (wocky_xmpp_reader_get_state (reader)
332 == WOCKY_XMPP_READER_STATE_CLOSED);
333
334 g_assert_cmpstr (VALID_NAMESPACE, ==,
335 wocky_node_get_ns (
336 wocky_node_get_child (wocky_stanza_get_top_node (stanza), "branch")));
337
338 g_object_unref (stanza);
339 g_object_unref (reader);
340 }
341
342 /* Helper function for the whitespace body tests */
343 static void
test_body_with_alternative(const gchar * xml,const gchar * expected_body_text,const gchar * alt_body_text)344 test_body_with_alternative (
345 const gchar *xml,
346 const gchar *expected_body_text,
347 const gchar *alt_body_text)
348 {
349 WockyXmppReader *reader = wocky_xmpp_reader_new_no_stream ();
350 WockyStanza *stanza;
351 WockyNode *body;
352
353 wocky_xmpp_reader_push (reader, (guint8 *) xml, strlen (xml));
354
355 stanza = wocky_xmpp_reader_pop_stanza (reader);
356 g_assert (stanza != NULL);
357
358 body = wocky_node_get_child (wocky_stanza_get_top_node (stanza), "body");
359 g_assert (body != NULL);
360
361 g_assert (g_utf8_validate (body->content, -1, NULL));
362
363 if (alt_body_text == NULL)
364 {
365 g_assert_cmpstr (body->content, ==, expected_body_text);
366 }
367 else
368 {
369 if (wocky_strdiff (body->content, expected_body_text) &&
370 wocky_strdiff (body->content, alt_body_text))
371 {
372 g_error ("Body text «%s» was neither «%s» nor «%s»",
373 body->content, expected_body_text, alt_body_text);
374 }
375 }
376
377 g_object_unref (stanza);
378 g_object_unref (reader);
379 }
380
381 static void
test_body(const gchar * xml,const gchar * exp)382 test_body (const gchar *xml,
383 const gchar *exp)
384 {
385 test_body_with_alternative (xml, exp, NULL);
386 }
387
388 /* Test that whitespace around the text contents of a message isn't ignored */
389 static void
test_whitespace_padding(void)390 test_whitespace_padding (void)
391 {
392 test_body (MESSAGE_WITH_WHITESPACE_PADDED_BODY, WHITESPACE_PADDED_BODY);
393 }
394
395 /* Test that a message body consisting entirely of whitespace isn't ignored */
396 static void
test_whitespace_only(void)397 test_whitespace_only (void)
398 {
399 test_body (MESSAGE_WITH_WHITESPACE_ONLY_BODY, WHITESPACE_ONLY_BODY);
400 }
401
402 /* Test that a message body containing non-character codepoints is
403 * handled "appropriately". Older GLib replaces them with U+FFFD,
404 * newer GLib keeps them as-is. */
405 static void
test_non_character_codepoints(void)406 test_non_character_codepoints (void)
407 {
408 test_body_with_alternative (MESSAGE_WITH_NON_CHARACTER_CODEPOINTS,
409 NON_CHARACTER_CODEPOINTS,
410 NON_CHARACTER_CODEPOINTS_REPLACEMENT);
411 }
412
413 static void
check_namespaces(WockyXmppReader * reader,const gchar * xml,const gchar * expected_namespace)414 check_namespaces (
415 WockyXmppReader *reader,
416 const gchar *xml,
417 const gchar *expected_namespace)
418 {
419 WockyStanza *stanza;
420 WockyNode *top_node, *body_node;
421
422 wocky_xmpp_reader_push (reader, (const guint8 *) xml, strlen (xml));
423 stanza = wocky_xmpp_reader_pop_stanza (reader);
424 g_assert (stanza != NULL);
425 top_node = wocky_stanza_get_top_node (stanza);
426 g_assert (top_node != NULL);
427 g_assert_cmpstr (expected_namespace, ==, wocky_node_get_ns (top_node));
428 body_node = wocky_node_get_first_child (top_node);
429 g_assert (body_node != NULL);
430 g_assert_cmpstr (expected_namespace, ==, wocky_node_get_ns (body_node));
431
432 g_object_unref (stanza);
433 wocky_xmpp_reader_reset (reader);
434 }
435
436 static void
test_no_stream_default_namespace(WockyXmppReader * reader,const gchar * expected_default_namespace)437 test_no_stream_default_namespace (
438 WockyXmppReader *reader,
439 const gchar *expected_default_namespace)
440 {
441 /* Regardless of the reader's default namespace, a root node with an
442 * explicitly-specified namespace should get that namespace.
443 */
444 check_namespaces (reader,
445 "<message xmlns='" WOCKY_XMPP_NS_JABBER_CLIENT "'>"
446 "<body>hai</body></message>",
447 WOCKY_XMPP_NS_JABBER_CLIENT);
448
449 /* What namespace the nodes here end up in depends on the reader's default.
450 */
451 check_namespaces (reader, "<message><body>hai</body></message>",
452 expected_default_namespace);
453 }
454
455 static void
test_no_stream_default_default_namespace(void)456 test_no_stream_default_default_namespace (void)
457 {
458 WockyXmppReader *reader = wocky_xmpp_reader_new_no_stream ();
459
460 /* WockyXmppReader defaults to the empty namespace. */
461 test_no_stream_default_namespace (reader, "");
462
463 g_object_unref (reader);
464 }
465
466 static void
test_no_stream_specified_default_namespace(void)467 test_no_stream_specified_default_namespace (void)
468 {
469 #define WEIRD "wocky:weird:namespace"
470 WockyXmppReader *reader = wocky_xmpp_reader_new_no_stream_ns (WEIRD);
471
472 test_no_stream_default_namespace (reader, WEIRD);
473
474 g_object_unref (reader);
475 #undef WEIRD
476 }
477
478 int
main(int argc,char ** argv)479 main (int argc,
480 char **argv)
481 {
482 int result;
483
484 test_init (argc, argv);
485
486 g_test_add_func ("/xmpp-reader/stream-no-stanzas", test_stream_no_stanzas);
487 g_test_add_func ("/xmpp-reader/stream-open-error", test_stream_open_error);
488 g_test_add_func ("/xmpp-reader/stream-open-unqualified-lang",
489 test_stream_open_unqualified_lang);
490 g_test_add_func ("/xmpp-reader/parse-error", test_parse_error);
491 g_test_add_func ("/xmpp-reader/no-stream-hunks", test_no_stream_hunks);
492 g_test_add_func ("/xmpp-reader/no-stream-resetting", test_no_stream_reset);
493 g_test_add_func ("/xmpp-reader/vcard-namespace", test_vcard_namespace);
494 g_test_add_func ("/xmpp-reader/invalid-namespace", test_invalid_namespace);
495 g_test_add_func ("/xmpp-reader/whitespace-padding", test_whitespace_padding);
496 g_test_add_func ("/xmpp-reader/whitespace-only", test_whitespace_only);
497 g_test_add_func ("/xmpp-reader/utf-non-character-codepoints",
498 test_non_character_codepoints);
499 g_test_add_func ("/xmpp-reader/no-stream-default-default-namespace",
500 test_no_stream_default_default_namespace);
501 g_test_add_func ("/xmpp-reader/no-stream-specified-default-namespace",
502 test_no_stream_specified_default_namespace);
503
504 result = g_test_run ();
505 test_deinit ();
506 return result;
507 }
508