--- /dev/null
+#include <limits.h>
+#include <stdlib.h>
+
+#include "xmlrpc_config.h"
+
+#include "girstring.h"
+#include "casprintf.h"
+#include "xmlrpc-c/base.h"
+#include "xmlrpc-c/xmlparser.h"
+
+#include "test.h"
+#include "xml_data.h"
+#include "parse_xml.h"
+
+
+
+static void test_expat (void)
+{
+ xmlrpc_env env;
+ xml_element *elem, *array, *data, *value1, *i4;
+ char *cdata;
+ size_t size;
+
+ xmlrpc_env_init(&env);
+
+ /* Parse a moderately complex XML document. */
+ xml_parse(&env, expat_data, strlen(expat_data), &elem);
+ TEST_NO_FAULT(&env);
+ TEST(elem != NULL);
+
+ /* Verify our results. */
+ TEST(streq(xml_element_name(elem), "value"));
+ TEST(xml_element_children_size(elem) == 1);
+ array = xml_element_children(elem)[0];
+ TEST(streq(xml_element_name(array), "array"));
+ TEST(xml_element_children_size(array) == 1);
+ data = xml_element_children(array)[0];
+ TEST(streq(xml_element_name(data), "data"));
+ TEST(xml_element_children_size(data) > 1);
+ value1 = xml_element_children(data)[0];
+ TEST(streq(xml_element_name(value1), "value"));
+ TEST(xml_element_children_size(value1) == 1);
+ i4 = xml_element_children(value1)[0];
+ TEST(streq(xml_element_name(i4), "i4"));
+ TEST(xml_element_children_size(i4) == 0);
+ cdata = xml_element_cdata(i4);
+ size = xml_element_cdata_size(i4);
+ TEST(size == strlen("2147483647"));
+ TEST(memcmp(cdata, "2147483647", strlen("2147483647")) == 0);
+
+ /* Test cleanup code (w/memprof). */
+ xml_element_free(elem);
+
+ /* Test broken XML */
+ xml_parse(&env, expat_error_data, strlen(expat_error_data), &elem);
+ TEST(env.fault_occurred);
+
+ xmlrpc_env_clean(&env);
+}
+
+
+
+static void
+validateParseResponseResult(xmlrpc_value * const valueP) {
+
+ xmlrpc_env env;
+
+ xmlrpc_value * s;
+ xmlrpc_int32 int_max;
+ xmlrpc_int32 int_min;
+ xmlrpc_int32 int_one;
+ xmlrpc_bool bool_false;
+ xmlrpc_bool bool_true;
+ char * str_hello;
+ char * str_untagged;
+ char * datetime;
+ unsigned char * b64_data;
+ size_t b64_len;
+ double negone;
+ double zero;
+ double one;
+
+ xmlrpc_env_init(&env);
+
+ xmlrpc_decompose_value(
+ &env, valueP, "((iibbs68())idddSs)",
+ &int_max, &int_min,
+ &bool_false, &bool_true, &str_hello,
+ &b64_data, &b64_len, &datetime,
+ &int_one, &negone, &zero, &one, &s, &str_untagged);
+
+ TEST_NO_FAULT(&env);
+ TEST(int_max == INT_MAX);
+ TEST(int_min == INT_MIN);
+ TEST(!bool_false);
+ TEST(bool_true);
+ TEST(strlen(str_hello) == strlen("Hello, world! <&>"));
+ TEST(streq(str_hello, "Hello, world! <&>"));
+ TEST(b64_len == 11);
+ TEST(memcmp(b64_data, "base64 data", b64_len) == 0);
+ TEST(streq(datetime, "19980717T14:08:55"));
+ TEST(int_one == 1);
+ TEST(negone == -1.0);
+ TEST(zero == 0.0);
+ TEST(one == 1.0);
+ TEST(streq(str_untagged, "Untagged string"));
+ free(str_hello);
+ free(b64_data);
+ free(datetime);
+ free(str_untagged);
+
+ {
+ /* Analyze the contents of our struct. */
+
+ xmlrpc_value * sval;
+ int size, sval_int;
+
+ TEST(s != NULL);
+ size = xmlrpc_struct_size(&env, s);
+ TEST_NO_FAULT(&env);
+ TEST(size == 2);
+ sval = xmlrpc_struct_get_value(&env, s, "ten <&>");
+ TEST_NO_FAULT(&env);
+ xmlrpc_decompose_value(&env, sval, "i", &sval_int);
+ TEST_NO_FAULT(&env);
+ TEST(sval_int == 10);
+ sval = xmlrpc_struct_get_value(&env, s, "twenty");
+ TEST_NO_FAULT(&env);
+ xmlrpc_decompose_value(&env, sval, "i", &sval_int);
+ TEST_NO_FAULT(&env);
+ TEST(sval_int == 20);
+ xmlrpc_DECREF(s);
+ }
+
+ xmlrpc_env_clean(&env);
+}
+
+
+
+static void
+testParseGoodResponse(void) {
+
+ xmlrpc_env env;
+ xmlrpc_value * valueP;
+ int faultCode;
+ const char * faultString;
+
+ xmlrpc_env_init(&env);
+
+ xmlrpc_parse_response2(&env, good_response_xml, strlen(good_response_xml),
+ &valueP, &faultCode, &faultString);
+
+ TEST_NO_FAULT(&env);
+ TEST(faultString == NULL);
+
+ validateParseResponseResult(valueP);
+
+ xmlrpc_DECREF(valueP);
+
+ /* Try it again with old interface */
+
+ valueP = xmlrpc_parse_response(&env,
+ good_response_xml,
+ strlen(good_response_xml));
+ TEST_NO_FAULT(&env);
+ TEST(valueP != NULL);
+
+ validateParseResponseResult(valueP);
+
+ xmlrpc_DECREF(valueP);
+
+ xmlrpc_env_clean(&env);
+
+}
+
+
+
+static void
+testParseBadResponse(void) {
+/*----------------------------------------------------------------------------
+ Test parsing of data that is supposed to be a response, but is not
+ valid. Either not valid XML or not valid XML-RPC.
+-----------------------------------------------------------------------------*/
+ unsigned int i;
+
+ {
+ xmlrpc_env env;
+ xmlrpc_value * valueP;
+ int faultCode;
+ const char * faultString;
+
+ /* First, test some poorly-formed XML data. */
+ xmlrpc_env_init(&env);
+
+ xmlrpc_parse_response2(&env,
+ unparseable_value, strlen(unparseable_value),
+ &valueP, &faultCode, &faultString);
+
+ TEST_FAULT(&env, XMLRPC_PARSE_ERROR);
+ xmlrpc_env_clean(&env);
+
+ xmlrpc_env_init(&env);
+
+ /* And again with the old interface */
+ valueP = xmlrpc_parse_response(&env, unparseable_value,
+ strlen(unparseable_value));
+ TEST_FAULT(&env, XMLRPC_PARSE_ERROR);
+ xmlrpc_env_clean(&env);
+ TEST(valueP == NULL);
+ }
+
+ /* Try with good XML, but bad XML-RPC. For this test, we test up to
+ but not including the <value> in a successful RPC response.
+ */
+
+ /* Next, check for bogus responses. These are all well-formed XML, but
+ ** they aren't legal XML-RPC. */
+ for (i = 15; bad_responses[i] != NULL; ++i) {
+ const char * const bad_resp = bad_responses[i];
+ xmlrpc_env env;
+ xmlrpc_value * v;
+ xml_element *elem;
+
+ xmlrpc_env_init(&env);
+
+ /* First, check to make sure that our test case is well-formed XML.
+ ** (It's easy to make mistakes when writing the test cases!) */
+ xml_parse(&env, bad_resp, strlen(bad_resp), &elem);
+ TEST_NO_FAULT(&env);
+ xml_element_free(elem);
+
+ /* Now, make sure the higher-level routine barfs appropriately. */
+ v = xmlrpc_parse_response(&env, bad_resp, strlen(bad_resp));
+ TEST(env.fault_occurred);
+ TEST(env.fault_code != 0); /* We use 0 as a code in our bad faults. */
+ TEST(v == NULL);
+ xmlrpc_env_clean(&env);
+ }
+
+ /* Try with good XML, good XML-RPC response, except that the value
+ isn't valid XML-RPC
+ */
+ for (i = 0; bad_values[i] != NULL; ++i) {
+ const char * const bad_resp = bad_values[i];
+ xmlrpc_env env;
+ xmlrpc_value * valueP;
+ xml_element *elem;
+ int faultCode;
+ const char * faultString;
+
+ xmlrpc_env_init(&env);
+
+ /* First, check to make sure that our test case is well-formed XML.
+ ** (It's easy to make mistakes when writing the test cases!) */
+ xml_parse(&env, bad_resp, strlen(bad_resp), &elem);
+ TEST_NO_FAULT(&env);
+ xml_element_free(elem);
+
+ /* Now, make sure the higher-level routine barfs appropriately. */
+
+ xmlrpc_parse_response2(&env, bad_resp, strlen(bad_resp),
+ &valueP, &faultCode, &faultString);
+
+ TEST_FAULT(&env, XMLRPC_PARSE_ERROR);
+ xmlrpc_env_clean(&env);
+
+ xmlrpc_env_init(&env);
+
+ /* And again with the old interface */
+
+ valueP = xmlrpc_parse_response(&env, bad_resp, strlen(bad_resp));
+ TEST_FAULT(&env, XMLRPC_PARSE_ERROR);
+ TEST(valueP == NULL);
+ xmlrpc_env_clean(&env);
+ }
+}
+
+
+
+static void
+testParseFaultResponse(void) {
+/*----------------------------------------------------------------------------
+ Test parsing of a valid response that indicates the RPC failed.
+-----------------------------------------------------------------------------*/
+ xmlrpc_env env;
+
+ xmlrpc_env_init(&env);
+
+ {
+ xmlrpc_value * resultP;
+ int faultCode;
+ const char * faultString;
+
+ xmlrpc_parse_response2(&env,
+ serialized_fault, strlen(serialized_fault),
+ &resultP, &faultCode, &faultString);
+
+ TEST_NO_FAULT(&env);
+ TEST(faultString != NULL);
+ TEST(faultCode == 6);
+ TEST(streq(faultString, "A fault occurred"));
+ strfree(faultString);
+ }
+ /* Now with the old interface */
+ {
+ xmlrpc_value * valueP;
+ xmlrpc_env fault;
+
+ /* Parse a valid fault. */
+ xmlrpc_env_init(&fault);
+ valueP = xmlrpc_parse_response(&fault, serialized_fault,
+ strlen(serialized_fault));
+
+ TEST(fault.fault_occurred);
+ TEST(fault.fault_code == 6);
+ TEST(streq(fault.fault_string, "A fault occurred"));
+ xmlrpc_env_clean(&fault);
+ }
+
+ xmlrpc_env_clean(&env);
+}
+
+
+
+static void
+test_parse_xml_call(void) {
+
+ xmlrpc_env env;
+ const char *method_name;
+ xmlrpc_value *params;
+ int i1, i2;
+ const char **bad_call;
+ xml_element *elem;
+
+ xmlrpc_env_init(&env);
+
+ /* Parse a valid call. */
+ xmlrpc_parse_call(&env, serialized_call, strlen(serialized_call),
+ &method_name, ¶ms);
+ TEST_NO_FAULT(&env);
+ TEST(params != NULL);
+ xmlrpc_decompose_value(&env, params, "(ii)", &i1, &i2);
+ xmlrpc_DECREF(params);
+ TEST_NO_FAULT(&env);
+ TEST(streq(method_name, "gloom&doom"));
+ TEST(i1 == 10 && i2 == 20);
+ strfree(method_name);
+
+ /* Test some poorly-formed XML data. */
+ xmlrpc_parse_call(&env, unparseable_value, strlen(unparseable_value),
+ &method_name, ¶ms);
+ TEST_FAULT(&env, XMLRPC_PARSE_ERROR);
+ TEST(method_name == NULL && params == NULL);
+
+ /* Next, check for bogus values. These are all well-formed XML, but
+ they aren't legal XML-RPC.
+ */
+ for (bad_call = bad_calls; *bad_call != NULL; ++bad_call) {
+
+ /* First, check to make sure that our test case is well-formed XML.
+ ** (It's easy to make mistakes when writing the test cases!) */
+ xml_parse(&env, *bad_call, strlen(*bad_call), &elem);
+ TEST_NO_FAULT(&env);
+ xml_element_free(elem);
+
+ /* Now, make sure the higher-level routine barfs appropriately. */
+ xmlrpc_parse_call(&env, *bad_call, strlen(*bad_call),
+ &method_name, ¶ms);
+ TEST_FAULT(&env, XMLRPC_PARSE_ERROR);
+ TEST(method_name == NULL && params == NULL);
+ }
+ xmlrpc_env_clean(&env);
+}
+
+
+
+void
+test_parse_xml(void) {
+
+ printf("Running XML parsing tests.\n");
+ test_expat();
+ testParseGoodResponse();
+ testParseFaultResponse();
+ testParseBadResponse();
+ test_parse_xml_call();
+ printf("\n");
+ printf("XML parsing tests done.\n");
+}