mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-01 19:04:47 +00:00
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@8545 d0543943-73ff-0310-b7d9-9358b9ac24b2
564 lines
16 KiB
C
564 lines
16 KiB
C
#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
|
|
testParseNumberValue(void) {
|
|
|
|
char const xmldata[] =
|
|
XML_PROLOGUE
|
|
"<methodCall>\r\n"
|
|
"<methodName>test</methodName>\r\n"
|
|
"<params>\r\n"
|
|
"<param><value><int>2147483647</int></value></param>\r\n" \
|
|
"<param><value><int>-2147483648</int></value></param>\r\n" \
|
|
"<param><value><i1>10</i1></value></param>\r\n"
|
|
"<param><value><i2>10</i2></value></param>\r\n"
|
|
"<param><value><i4>10</i4></value></param>\r\n"
|
|
"<param><value><i8>10</i8></value></param>\r\n"
|
|
"<param><value><ex.i8>10</ex.i8></value></param>\r\n"
|
|
"<param><value><double>10</double></value></param>\r\n"
|
|
"<param><value><double>10.1</double></value></param>\r\n"
|
|
"<param><value><double>-10.1</double></value></param>\r\n"
|
|
"<param><value><double>+10.1</double></value></param>\r\n"
|
|
"<param><value><double>0</double></value></param>\r\n"
|
|
"<param><value><double>.01</double></value></param>\r\n"
|
|
"<param><value><double>5.</double></value></param>\r\n"
|
|
"<param><value><double>5.3E6</double></value></param>\r\n"
|
|
"<param><value><double> 1</double></value></param>\r\n"
|
|
"</params>\r\n"
|
|
"</methodCall>\r\n";
|
|
|
|
xmlrpc_env env;
|
|
xmlrpc_value * paramArrayP;
|
|
const char * methodName;
|
|
int arraySize;
|
|
xmlrpc_int int_max, int_min;
|
|
xmlrpc_int32 i_i1, i_i2, i_i4;
|
|
xmlrpc_int64 i_i8, i_ex_i8;
|
|
double d1, d2, d3, d4, d5, d6, d7, d8, d9;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
xmlrpc_parse_call(&env, xmldata, strlen(xmldata),
|
|
&methodName, ¶mArrayP);
|
|
TEST_NO_FAULT(&env);
|
|
|
|
arraySize = xmlrpc_array_size(&env, paramArrayP);
|
|
TEST_NO_FAULT(&env);
|
|
|
|
TEST(arraySize == 16);
|
|
|
|
xmlrpc_decompose_value(
|
|
&env, paramArrayP, "(iiiiiIIddddddddd)",
|
|
&int_max, &int_min, &i_i1, &i_i2, &i_i4, &i_i8, &i_ex_i8,
|
|
&d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9);
|
|
|
|
TEST_NO_FAULT(&env);
|
|
|
|
TEST(int_max == INT_MAX);
|
|
TEST(int_min == INT_MIN);
|
|
TEST(i_i1 == 10);
|
|
TEST(i_i2 == 10);
|
|
TEST(i_i4 == 10);
|
|
TEST(i_i8 == 10);
|
|
TEST(i_ex_i8 == 10);
|
|
TESTFLOATEQUAL(d1, 10.0);
|
|
TESTFLOATEQUAL(d2, 10.1);
|
|
TESTFLOATEQUAL(d3, -10.1);
|
|
TESTFLOATEQUAL(d4, +10.1);
|
|
TESTFLOATEQUAL(d5, 0.0);
|
|
TESTFLOATEQUAL(d6, 0.01);
|
|
TESTFLOATEQUAL(d7, 5.0);
|
|
TESTFLOATEQUAL(d8, 5.3E6);
|
|
TESTFLOATEQUAL(d9, 1.0);
|
|
|
|
xmlrpc_DECREF(paramArrayP);
|
|
strfree(methodName);
|
|
|
|
xmlrpc_env_clean(&env);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
testParseMiscSimpleValue(void) {
|
|
|
|
char const xmldata[] =
|
|
XML_PROLOGUE
|
|
"<methodCall>\r\n"
|
|
"<methodName>test</methodName>\r\n"
|
|
"<params>\r\n"
|
|
"<param><value><string>hello</string></value></param>\r\n"
|
|
"<param><value><boolean>0</boolean></value></param>\r\n"
|
|
"<param><value><boolean>1</boolean></value></param>\r\n"
|
|
"<param><value><dateTime.iso8601>19980717T14:08:55</dateTime.iso8601>"
|
|
"</value></param>\r\n"
|
|
"<param><value><base64>YmFzZTY0IGRhdGE=</base64></value></param>\r\n"
|
|
"<param><value><nil/></value></param>\r\n"
|
|
"<param><value><ex.nil/></value></param>\r\n"
|
|
"</params>\r\n"
|
|
"</methodCall>\r\n";
|
|
|
|
xmlrpc_env env;
|
|
xmlrpc_value * paramArrayP;
|
|
const char * methodName;
|
|
int arraySize;
|
|
const char * str_hello;
|
|
xmlrpc_bool b_false, b_true;
|
|
const char * datetime;
|
|
unsigned char * b64_data;
|
|
size_t b64_len;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
xmlrpc_parse_call(&env, xmldata, strlen(xmldata),
|
|
&methodName, ¶mArrayP);
|
|
TEST_NO_FAULT(&env);
|
|
|
|
arraySize = xmlrpc_array_size(&env, paramArrayP);
|
|
TEST_NO_FAULT(&env);
|
|
|
|
TEST(arraySize == 7);
|
|
|
|
xmlrpc_decompose_value(
|
|
&env, paramArrayP, "(sbb86nn)",
|
|
&str_hello, &b_false, &b_true, &datetime, &b64_data, &b64_len);
|
|
|
|
TEST_NO_FAULT(&env);
|
|
|
|
TEST(streq(str_hello, "hello"));
|
|
TEST(!b_false);
|
|
TEST(b_true);
|
|
TEST(streq(datetime, "19980717T14:08:55"));
|
|
TEST(b64_len == 11);
|
|
TEST(memcmp(b64_data, "base64 data", b64_len) == 0);
|
|
|
|
free(b64_data);
|
|
strfree(str_hello);
|
|
strfree(datetime);
|
|
xmlrpc_DECREF(paramArrayP);
|
|
strfree(methodName);
|
|
|
|
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
|
|
testParseBadResponseXml(void) {
|
|
/*----------------------------------------------------------------------------
|
|
Test parsing of data that is supposed to be a response, but in not
|
|
even valid XML.
|
|
-----------------------------------------------------------------------------*/
|
|
xmlrpc_env env;
|
|
xmlrpc_value * valueP;
|
|
int faultCode;
|
|
const char * faultString;
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
testParseBadResponseXmlRpc(void) {
|
|
/*----------------------------------------------------------------------------
|
|
Test parsing of data that is supposed to be a response, and is valid
|
|
XML, but is not valid XML-RPC.
|
|
-----------------------------------------------------------------------------*/
|
|
unsigned int i;
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
testParseBadResult(void) {
|
|
/*----------------------------------------------------------------------------
|
|
Test parsing of data that is supposed to be a response, but is not
|
|
valid. It looks like a valid success response, but the result value
|
|
is not valid XML-RPC.
|
|
-----------------------------------------------------------------------------*/
|
|
unsigned int i;
|
|
|
|
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
|
|
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.
|
|
-----------------------------------------------------------------------------*/
|
|
testParseBadResponseXml();
|
|
|
|
testParseBadResponseXmlRpc();
|
|
|
|
testParseBadResult();
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
testParseNumberValue();
|
|
testParseMiscSimpleValue();
|
|
testParseGoodResponse();
|
|
testParseFaultResponse();
|
|
testParseBadResponse();
|
|
test_parse_xml_call();
|
|
printf("\n");
|
|
printf("XML parsing tests done.\n");
|
|
}
|