1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2001-2003, Ximian, Inc.
11 #include <libsoup/soup.h>
13 #include "test-utils.h"
15 static SoupSession *session;
16 static const char *default_uri = "http://127.0.0.1:47524/xmlrpc-server.php";
17 static const char *uri = NULL;
18 static gboolean server_test = FALSE;
20 static const char *const value_type[] = {
33 do_xmlrpc (const char *method, GValue *retval, ...)
41 va_start (args, retval);
42 params = soup_value_array_from_args (args);
45 body = soup_xmlrpc_build_method_call (method, params->values,
47 g_value_array_free (params);
51 msg = soup_message_new ("POST", uri);
52 soup_message_set_request (msg, "text/xml", SOUP_MEMORY_TAKE,
54 soup_session_send_message (session, msg);
56 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
57 debug_printf (1, "ERROR: %d %s\n", msg->status_code,
63 if (!soup_xmlrpc_parse_method_response (msg->response_body->data,
64 msg->response_body->length,
67 debug_printf (1, "FAULT: %d %s\n", err->code, err->message);
70 debug_printf (1, "ERROR: could not parse response\n");
80 check_xmlrpc (GValue *value, GType type, ...)
84 if (!G_VALUE_HOLDS (value, type)) {
85 debug_printf (1, "ERROR: could not parse response\n");
86 g_value_unset (value);
90 va_start (args, type);
91 SOUP_VALUE_GETV (value, type, args);
100 int i, val, sum, result;
104 debug_printf (1, "sum (array of int -> int): ");
106 ints = g_value_array_new (10);
107 for (i = sum = 0; i < 10; i++) {
109 debug_printf (2, "%s%d", i == 0 ? "[" : ", ", val);
110 soup_value_array_append (ints, G_TYPE_INT, val);
113 debug_printf (2, "] -> ");
115 ok = (do_xmlrpc ("sum", &retval,
116 G_TYPE_VALUE_ARRAY, ints,
118 check_xmlrpc (&retval, G_TYPE_INT, &result));
119 g_value_array_free (ints);
124 debug_printf (2, "%d: ", result);
125 debug_printf (1, "%s\n", result == sum ? "OK!" : "WRONG!");
126 return result == sum;
130 test_countBools (void)
133 int i, trues, falses;
135 int ret_trues, ret_falses;
139 debug_printf (1, "countBools (array of boolean -> struct of ints): ");
141 bools = g_value_array_new (10);
142 for (i = trues = falses = 0; i < 10; i++) {
143 val = rand () > (RAND_MAX / 2);
144 debug_printf (2, "%s%c", i == 0 ? "[" : ", ", val ? 'T' : 'F');
145 soup_value_array_append (bools, G_TYPE_BOOLEAN, val);
151 debug_printf (2, "] -> ");
153 ok = (do_xmlrpc ("countBools", &retval,
154 G_TYPE_VALUE_ARRAY, bools,
156 check_xmlrpc (&retval, G_TYPE_HASH_TABLE, &result));
157 g_value_array_free (bools);
161 if (!soup_value_hash_lookup (result, "true", G_TYPE_INT, &ret_trues)) {
162 debug_printf (1, "NO 'true' value in response\n");
165 if (!soup_value_hash_lookup (result, "false", G_TYPE_INT, &ret_falses)) {
166 debug_printf (1, "NO 'false' value in response\n");
169 g_hash_table_destroy (result);
171 debug_printf (2, "{ true: %d, false: %d } ", ret_trues, ret_falses);
172 ok = (trues == ret_trues) && (falses == ret_falses);
173 debug_printf (1, "%s\n", ok ? "OK!" : "WRONG!");
180 GByteArray *data, *result;
184 gsize digest_len = sizeof (digest);
188 debug_printf (1, "md5sum (base64 -> base64): ");
190 data = g_byte_array_new ();
191 g_byte_array_set_size (data, 256);
192 for (i = 0; i < data->len; i++)
193 data->data[i] = (char)(rand ());
195 checksum = g_checksum_new (G_CHECKSUM_MD5);
196 g_checksum_update (checksum, data->data, data->len);
197 g_checksum_get_digest (checksum, digest, &digest_len);
198 g_checksum_free (checksum);
200 ok = (do_xmlrpc ("md5sum", &retval,
201 SOUP_TYPE_BYTE_ARRAY, data,
203 check_xmlrpc (&retval, SOUP_TYPE_BYTE_ARRAY, &result));
204 g_byte_array_free (data, TRUE);
208 if (result->len != digest_len) {
209 debug_printf (1, "result has WRONG length (%d)\n", result->len);
210 g_byte_array_free (result, TRUE);
214 ok = (memcmp (digest, result->data, digest_len) == 0);
215 debug_printf (1, "%s\n", ok ? "OK!" : "WRONG!");
216 g_byte_array_free (result, TRUE);
221 test_dateChange (void)
223 GHashTable *structval;
224 SoupDate *date, *result;
229 debug_printf (1, "dateChange (date, struct of ints -> time): ");
231 date = soup_date_new (1970 + (rand () % 50),
237 if (debug_level >= 2) {
238 timestamp = soup_date_to_string (date, SOUP_DATE_ISO8601_XMLRPC);
239 debug_printf (2, "date: %s, {", timestamp);
243 structval = soup_value_hash_new ();
246 date->year = 1970 + (rand () % 50);
247 debug_printf (2, "tm_year: %d, ", date->year - 1900);
248 soup_value_hash_insert (structval, "tm_year",
249 G_TYPE_INT, date->year - 1900);
252 date->month = 1 + rand () % 12;
253 debug_printf (2, "tm_mon: %d, ", date->month - 1);
254 soup_value_hash_insert (structval, "tm_mon",
255 G_TYPE_INT, date->month - 1);
258 date->day = 1 + rand () % 28;
259 debug_printf (2, "tm_mday: %d, ", date->day);
260 soup_value_hash_insert (structval, "tm_mday",
261 G_TYPE_INT, date->day);
264 date->hour = rand () % 24;
265 debug_printf (2, "tm_hour: %d, ", date->hour);
266 soup_value_hash_insert (structval, "tm_hour",
267 G_TYPE_INT, date->hour);
270 date->minute = rand () % 60;
271 debug_printf (2, "tm_min: %d, ", date->minute);
272 soup_value_hash_insert (structval, "tm_min",
273 G_TYPE_INT, date->minute);
276 date->second = rand () % 60;
277 debug_printf (2, "tm_sec: %d, ", date->second);
278 soup_value_hash_insert (structval, "tm_sec",
279 G_TYPE_INT, date->second);
282 debug_printf (2, "} -> ");
284 ok = (do_xmlrpc ("dateChange", &retval,
285 SOUP_TYPE_DATE, date,
286 G_TYPE_HASH_TABLE, structval,
288 check_xmlrpc (&retval, SOUP_TYPE_DATE, &result));
289 g_hash_table_destroy (structval);
291 soup_date_free (date);
295 if (debug_level >= 2) {
296 timestamp = soup_date_to_string (result, SOUP_DATE_ISO8601_XMLRPC);
297 debug_printf (2, "%s: ", timestamp);
301 ok = ((date->year == result->year) &&
302 (date->month == result->month) &&
303 (date->day == result->day) &&
304 (date->hour == result->hour) &&
305 (date->minute == result->minute) &&
306 (date->second == result->second));
307 soup_date_free (date);
308 soup_date_free (result);
310 debug_printf (1, "%s\n", ok ? "OK!" : "WRONG!");
314 static const char *const echo_strings[] = {
318 "& so is <this>"
320 #define N_ECHO_STRINGS G_N_ELEMENTS (echo_strings)
322 static const char *const echo_strings_broken[] = {
326 "amp; so is lt;thisgt;"
332 GValueArray *originals, *echoes;
335 gboolean php_bug = FALSE;
337 debug_printf (1, "echo (array of string -> array of string): ");
339 originals = g_value_array_new (N_ECHO_STRINGS);
340 for (i = 0; i < N_ECHO_STRINGS; i++) {
341 soup_value_array_append (originals, G_TYPE_STRING, echo_strings[i]);
342 debug_printf (2, "%s\"%s\"", i == 0 ? "[" : ", ", echo_strings[i]);
344 debug_printf (2, "] -> ");
346 if (!(do_xmlrpc ("echo", &retval,
347 G_TYPE_VALUE_ARRAY, originals,
349 check_xmlrpc (&retval, G_TYPE_VALUE_ARRAY, &echoes))) {
350 g_value_array_free (originals);
353 g_value_array_free (originals);
355 if (debug_level >= 2) {
356 for (i = 0; i < echoes->n_values; i++) {
357 debug_printf (2, "%s\"%s\"", i == 0 ? "[" : ", ",
358 g_value_get_string (&echoes->values[i]));
360 debug_printf (2, "] -> ");
363 if (echoes->n_values != N_ECHO_STRINGS) {
364 debug_printf (1, " WRONG! Wrong number of return strings");
365 g_value_array_free (echoes);
369 for (i = 0; i < echoes->n_values; i++) {
370 if (strcmp (echo_strings[i], g_value_get_string (&echoes->values[i])) != 0) {
371 if (!server_test && strcmp (echo_strings_broken[i], g_value_get_string (&echoes->values[i])) == 0)
374 debug_printf (1, " WRONG! Mismatch at %d\n", i + 1);
375 g_value_array_free (echoes);
382 debug_printf (1, "WRONG, but it's php's fault\n");
384 debug_printf (1, "OK!\n");
385 g_value_array_free (echoes);
390 do_bad_xmlrpc (const char *body)
396 msg = soup_message_new ("POST", uri);
397 soup_message_set_request (msg, "text/xml", SOUP_MEMORY_COPY,
398 body, strlen (body));
399 soup_session_send_message (session, msg);
401 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
402 debug_printf (1, "ERROR: %d %s\n", msg->status_code,
404 g_object_unref (msg);
408 if (!soup_xmlrpc_parse_method_response (msg->response_body->data,
409 msg->response_body->length,
412 debug_printf (1, "FAULT: %d %s (OK!)\n",
413 err->code, err->message);
415 g_object_unref (msg);
418 debug_printf (1, "ERROR: could not parse response\n");
420 debug_printf (1, "Unexpectedly got successful response!\n");
422 g_object_unref (msg);
427 test_fault_malformed (void)
429 debug_printf (1, "malformed request: ");
431 return do_bad_xmlrpc ("<methodCall/>");
435 test_fault_method (void)
437 debug_printf (1, "request to non-existent method: ");
439 return do_bad_xmlrpc ("<methodCall><methodName>no_such_method</methodName><params><param><value><int>1</int></value></param></params></methodCall>");
443 test_fault_args (void)
445 debug_printf (1, "request with invalid args: ");
447 return do_bad_xmlrpc ("<methodCall><methodName>sum</methodName><params><param><value><int>1</int></value></param></params></methodCall>");
450 static GOptionEntry xmlrpc_entries[] = {
451 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uri,
452 "Alternate URI for server", NULL },
453 { "server-test", 's', 0, G_OPTION_ARG_NONE, &server_test,
454 "If this is being run from xmlrpc-server-test", NULL },
459 main (int argc, char **argv)
461 test_init (argc, argv, xmlrpc_entries);
470 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
474 if (!test_countBools ())
478 if (!test_dateChange ())
482 if (!test_fault_malformed ())
484 if (!test_fault_method ())
486 if (!test_fault_args ())
489 soup_test_session_abort_unref (session);