10 #include "xmlrpc-c/girerr.hpp"
12 #include "transport_config.h"
13 #include "xmlrpc-c/base.hpp"
14 #include "xmlrpc-c/oldcppwrapper.hpp"
15 #include "xmlrpc-c/registry.hpp"
17 #include "testclient.hpp"
18 #include "server_abyss.hpp"
21 using namespace xmlrpc_c;
24 //=========================================================================
26 //=========================================================================
28 // There are two styles of test in here. The older ones are vaguely
29 // inspired by Kent Beck's book on eXtreme Programming (XP) and use
30 // the TEST...() macros.
32 // But this style is not really appropriate for C++. It's based on
33 // code that explicitly tests for errors, as one would do in C. In C++,
34 // it is cumbersome to catch exceptions on every call, so we don't in
37 // And there's not much point in trying to count test successes and
38 // failures. Any failure is a problem, so in the new style, we just
39 // quit after we recognize one (again, more in line with regular exception
40 // throwing). With exception throwing, you can't count what _didn't_
41 // cause an exception, so there's no meaningful count of test successes.
43 // To run the tests, type './cpptest'.
44 // To check for memory leaks, install RedHat's 'memprof' utility, and
45 // type 'memprof cpptest'.
47 // If you add new tests to this file, please deallocate any data
48 // structures you use in the appropriate fashion. This allows us to test
49 // various destructor code for memory leaks.
52 class sampleAddMethod : public method {
55 this->_signature = "i:ii";
56 this->_help = "This method adds two integers together";
59 execute(xmlrpc_c::paramList const& paramList,
60 value * const retvalP) {
62 int const addend(paramList.getInt(0));
63 int const adder(paramList.getInt(1));
65 paramList.verifyEnd(2);
67 *retvalP = value_int(addend + adder);
73 class nameMethod : public defaultMethod {
76 execute(string const& methodName,
77 xmlrpc_c::paramList const& , // paramList
78 value * const retvalP) {
80 *retvalP = value_string(string("no such method: ") + methodName);
85 //=========================================================================
87 //=========================================================================
92 // Create a new fault and perform basic operations.
93 XmlRpcFault fault1 = XmlRpcFault(6, "Sample fault");
94 TEST(fault1.getFaultCode() == 6);
95 TEST(fault1.getFaultString() == "Sample fault");
97 // Extract and examine the underlying xmlrpc_env struct.
98 xmlrpc_env *env1 = fault1.getFaultEnv();
100 TEST(env1->fault_occurred);
101 TEST(env1->fault_code == 6);
102 TEST(strcmp(env1->fault_string, "Sample fault") == 0);
104 // Test our copy constructor.
105 XmlRpcFault fault2 = fault1;
106 TEST(fault2.getFaultCode() == 6);
107 TEST(fault2.getFaultString() == "Sample fault");
109 // Construct a fault from a pre-existing xmlrpc_env structure.
111 xmlrpc_env_init(&env3);
112 xmlrpc_env_set_fault(&env3, 7, "Another fault");
113 XmlRpcFault fault3 = XmlRpcFault(&env3);
114 xmlrpc_env_clean(&env3);
115 TEST(fault3.getFaultCode() == 7);
116 TEST(fault3.getFaultString() == "Another fault");
118 // Attempt to construct a fault from a fault-free xmlrpc_env.
120 xmlrpc_env_init(&env4);
122 XmlRpcFault fault4 = XmlRpcFault(&env4);
123 TEST_FAILED("Constructed invalid XmlRpcFault");
124 } catch (XmlRpcFault const& fault) {
126 TEST(fault.getFaultCode() == XMLRPC_INTERNAL_ERROR);
128 xmlrpc_env_clean(&env4);
133 void test_env (void) {
135 // Declare these here to prevent silly compiler warnings about
136 // potentially uninitialized variables.
140 // Perform simple environment tests.
141 TEST(!env1.hasFaultOccurred());
142 xmlrpc_env_set_fault(env1, 8, "Fault 8");
143 TEST(env1.hasFaultOccurred());
144 XmlRpcFault fault1 = env1.getFault();
145 TEST(fault1.getFaultCode() == 8);
146 TEST(fault1.getFaultString() == "Fault 8");
148 // Test throwIfFaultOccurred.
150 env2.throwIfFaultOccurred();
152 } catch (XmlRpcFault const& fault) {
153 TEST_FAILED("We threw a fault when one hadn't occurred");
155 xmlrpc_env_set_fault(env2, 9, "Fault 9");
157 env2.throwIfFaultOccurred();
158 TEST_FAILED("A fault occurred, and we didn't throw it");
159 } catch (XmlRpcFault const& fault) {
161 TEST(fault.getFaultCode() == 9);
162 TEST(fault.getFaultString() == "Fault 9");
165 // Make sure we can't get a fault if one hasn't occurred.
168 XmlRpcFault fault3 = env3.getFault();
169 TEST_FAILED("We retrieved a non-existant fault");
170 } catch (XmlRpcFault const& fault) {
172 TEST(fault.getFaultCode() == XMLRPC_INTERNAL_ERROR);
176 void test_value (void) {
179 // Test basic reference counting behavior.
180 xmlrpc_value *v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 1);
181 env.throwIfFaultOccurred();
182 XmlRpcValue val1 = XmlRpcValue(v, XmlRpcValue::CONSUME_REFERENCE);
183 v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 2);
184 env.throwIfFaultOccurred();
185 XmlRpcValue val2 = v;
188 // Borrow a reference.
189 v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 3);
190 env.throwIfFaultOccurred();
191 XmlRpcValue val3 = XmlRpcValue(v, XmlRpcValue::CONSUME_REFERENCE);
192 xmlrpc_value *borrowed = val3.borrowReference();
196 v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 4);
197 env.throwIfFaultOccurred();
198 XmlRpcValue val4 = XmlRpcValue(v, XmlRpcValue::CONSUME_REFERENCE);
199 xmlrpc_value *made = val4.makeReference();
203 // Test our default constructor.
205 TEST(val5.getBool() == false);
207 // Test our type introspection.
208 TEST(XmlRpcValue::makeInt(0).getType() == XMLRPC_TYPE_INT);
210 // Test our basic data types.
211 TEST(XmlRpcValue::makeInt(30).getInt() == 30);
212 TEST(XmlRpcValue::makeInt(-30).getInt() == -30);
213 TEST(XmlRpcValue::makeBool(true).getBool() == true);
214 TEST(XmlRpcValue::makeBool(false).getBool() == false);
215 TEST(XmlRpcValue::makeDateTime("19980717T14:08:55").getRawDateTime() ==
216 "19980717T14:08:55");
217 TEST(XmlRpcValue::makeString("foo").getString() == "foo");
218 TEST(XmlRpcValue::makeString("bar", 3).getString() == "bar");
219 TEST(XmlRpcValue::makeString("bar", 3).getString() == "bar");
220 TEST(XmlRpcValue::makeString("a\0b").getString() == string("a\0b"));
221 XmlRpcValue::makeArray().getArray();
222 XmlRpcValue::makeStruct().getStruct();
224 // Test Base64 values.
225 const unsigned char *b64_data;
227 XmlRpcValue val6 = XmlRpcValue::makeBase64((unsigned char*) "a\0\0b", 4);
228 val6.getBase64(b64_data, b64_len);
230 TEST(memcmp(b64_data, "a\0\0b", 4) == 0);
233 XmlRpcValue array = XmlRpcValue::makeArray();
234 TEST(array.arraySize() == 0);
235 array.arrayAppendItem(XmlRpcValue::makeString("foo"));
236 TEST(array.arraySize() == 1);
237 array.arrayAppendItem(XmlRpcValue::makeString("bar"));
238 TEST(array.arraySize() == 2);
239 TEST(array.arrayGetItem(0).getString() == "foo");
240 TEST(array.arrayGetItem(1).getString() == "bar");
243 XmlRpcValue strct = XmlRpcValue::makeStruct();
244 TEST(strct.structSize() == 0);
245 strct.structSetValue("foo", XmlRpcValue::makeString("fooval"));
246 TEST(strct.structSize() == 1);
247 strct.structSetValue("bar", XmlRpcValue::makeString("barval"));
248 TEST(strct.structSize() == 2);
249 TEST(strct.structHasKey("bar"));
250 TEST(!strct.structHasKey("nosuch"));
251 for (size_t i = 0; i < strct.structSize(); i++) {
254 strct.structGetKeyAndValue(i, key, value);
255 TEST(key + "val" == value.getString());
263 /*----------------------------------------------------------------------------
264 Test the legacy XmlRpcCpp.cpp library
265 -----------------------------------------------------------------------------*/
266 cout << "Testing XmlRpcCpp library..." << endl;
275 class intTestSuite : public testSuite {
277 virtual string suiteName() {
278 return "intTestSuite";
280 virtual void runtests(unsigned int const) {
282 TEST(static_cast<int>(int1) == 7);
284 TEST(static_cast<int>(int2) == -7);
286 TEST(val1.type() == value::TYPE_INT);
287 value_int int3(val1);
288 TEST(static_cast<int>(int3) == 7);
290 value_int int4(value_double(3.7));
291 TEST_FAILED("invalid cast double-int suceeded");
298 class doubleTestSuite : public testSuite {
300 virtual string suiteName() {
301 return "doubleTestSuite";
303 virtual void runtests(unsigned int const) {
304 value_double double1(3.14);
305 TEST(static_cast<double>(double1) == 3.14);
307 TEST(val1.type() == value::TYPE_DOUBLE);
308 value_double double2(val1);
309 TEST(static_cast<double>(double2) == 3.14);
311 value_double double4(value_int(4));
312 TEST_FAILED("invalid cast int-double suceeded");
319 class booleanTestSuite : public testSuite {
321 virtual string suiteName() {
322 return "booleanTestSuite";
324 virtual void runtests(unsigned int const) {
325 value_boolean boolean1(true);
326 TEST(static_cast<bool>(boolean1) == true);
327 value_boolean boolean2(false);
328 TEST(static_cast<bool>(boolean2) == false);
329 value val1(boolean1);
330 TEST(val1.type() == value::TYPE_BOOLEAN);
331 value_boolean boolean3(val1);
332 TEST(static_cast<bool>(boolean3) == true);
334 value_boolean boolean4(value_int(4));
335 TEST_FAILED("invalid cast int-boolean suceeded");
342 class datetimeTestSuite : public testSuite {
344 virtual string suiteName() {
345 return "datetimeTestSuite";
347 virtual void runtests(unsigned int const) {
348 time_t const testTime(900684535);
349 value_datetime datetime1("19980717T14:08:55");
350 TEST(static_cast<time_t>(datetime1) == testTime);
351 value_datetime datetime2(testTime);
352 TEST(static_cast<time_t>(datetime2) == testTime);
353 value val1(datetime1);
354 TEST(val1.type() == value::TYPE_DATETIME);
355 value_datetime datetime3(val1);
356 TEST(static_cast<time_t>(datetime3) == testTime);
358 value_datetime datetime4(value_int(4));
359 TEST_FAILED("invalid cast int-datetime suceeded");
366 class stringTestSuite : public testSuite {
368 virtual string suiteName() {
369 return "stringTestSuite";
371 virtual void runtests(unsigned int const) {
372 value_string string1("hello world");
373 TEST(static_cast<string>(string1) == "hello world");
374 value_string string2("embedded\0null");
375 TEST(static_cast<string>(string2) == "embedded\0null");
377 TEST(val1.type() == value::TYPE_STRING);
378 value_string string3(val1);
379 TEST(static_cast<string>(string3) == "hello world");
381 value_string string4(value_int(4));
382 TEST_FAILED("invalid cast int-string suceeded");
389 class bytestringTestSuite : public testSuite {
391 virtual string suiteName() {
392 return "bytestringTestSuite";
394 virtual void runtests(unsigned int const) {
395 unsigned char bytestringArray[] = {0x10, 0x11, 0x12, 0x13, 0x14};
396 vector<unsigned char>
397 bytestringData(&bytestringArray[0], &bytestringArray[4]);
398 value_bytestring bytestring1(bytestringData);
400 vector<unsigned char> const dataReadBack1(
401 bytestring1.vectorUcharValue());
402 TEST(dataReadBack1 == bytestringData);
403 value val1(bytestring1);
404 TEST(val1.type() == value::TYPE_BYTESTRING);
405 value_bytestring bytestring2(val1);
406 vector<unsigned char> const dataReadBack2(
407 bytestring2.vectorUcharValue());
408 TEST(dataReadBack2 == bytestringData);
410 value_bytestring bytestring4(value_int(4));
411 TEST_FAILED("invalid cast int-bytestring suceeded");
418 class nilTestSuite : public testSuite {
420 virtual string suiteName() {
421 return "nilTestSuite";
423 virtual void runtests(unsigned int const) {
426 TEST(val1.type() == value::TYPE_NIL);
427 value_nil nil2(val1);
429 value_nil nil4(value_int(4));
430 TEST_FAILED("invalid cast int-nil suceeded");
437 class structTestSuite : public testSuite {
439 virtual string suiteName() {
440 return "structTestSuite";
442 virtual void runtests(unsigned int const) {
443 map<string, value> structData;
444 pair<string, value> member("the_integer", value_int(9));
445 structData.insert(member);
447 value_struct struct1(structData);
449 map<string, value> dataReadBack(struct1);
451 TEST(static_cast<int>(value_int(dataReadBack["the_integer"])) == 9);
454 TEST(val1.type() == value::TYPE_STRUCT);
455 value_struct struct2(val1);
457 value_struct struct4(value_int(4));
458 TEST_FAILED("invalid cast int-struct suceeded");
465 class arrayTestSuite : public testSuite {
467 virtual string suiteName() {
468 return "arrayTestSuite";
470 virtual void runtests(unsigned int const) {
471 vector<value> arrayData;
472 arrayData.push_back(value_int(7));
473 arrayData.push_back(value_double(2.78));
474 arrayData.push_back(value_string("hello world"));
475 value_array array1(arrayData);
477 TEST(array1.size() == 3);
478 vector<value> dataReadBack1(array1.vectorValueValue());
479 TEST(dataReadBack1[0].type() == value::TYPE_INT);
480 TEST(static_cast<int>(value_int(dataReadBack1[0])) == 7);
481 TEST(dataReadBack1[1].type() == value::TYPE_DOUBLE);
482 TEST(static_cast<double>(value_double(dataReadBack1[1])) == 2.78);
483 TEST(dataReadBack1[2].type() == value::TYPE_STRING);
484 TEST(static_cast<string>(value_string(dataReadBack1[2])) ==
488 TEST(val1.type() == value::TYPE_ARRAY);
489 value_array array2(val1);
490 TEST(array2.size() == 3);
492 value_array array4(value_int(4));
493 TEST_FAILED("invalid cast int-array suceeded");
500 class valueTestSuite : public testSuite {
503 virtual string suiteName() {
504 return "valueTestSuite";
506 virtual void runtests(unsigned int const indentation) {
508 intTestSuite().run(indentation+1);
509 doubleTestSuite().run(indentation+1);
510 booleanTestSuite().run(indentation+1);
511 datetimeTestSuite().run(indentation+1);
512 stringTestSuite().run(indentation+1);
513 bytestringTestSuite().run(indentation+1);
514 nilTestSuite().run(indentation+1);
515 structTestSuite().run(indentation+1);
516 arrayTestSuite().run(indentation+1);
522 string const noElementFoundXml(
523 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
524 "<methodResponse>\r\n"
526 "<value><struct>\r\n"
527 "<member><name>faultCode</name>\r\n"
528 "<value><i4>-503</i4></value></member>\r\n"
529 "<member><name>faultString</name>\r\n"
530 "<value><string>Call XML not a proper XML-RPC call. "
531 "Call is not valid XML. no element found</string></value>"
533 "</struct></value>\r\n"
535 "</methodResponse>\r\n"
538 string const sampleAddGoodCallXml(
539 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
541 "<methodName>sample.add</methodName>\r\n"
543 "<param><value><i4>5</i4></value></param>\r\n"
544 "<param><value><i4>7</i4></value></param>\r\n"
549 string const sampleAddGoodResponseXml(
550 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
551 "<methodResponse>\r\n"
553 "<param><value><i4>12</i4></value></param>\r\n"
555 "</methodResponse>\r\n"
559 string const sampleAddBadCallXml(
560 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
562 "<methodName>sample.add</methodName>\r\n"
564 "<param><value><i4>5</i4></value></param>\r\n"
569 string const sampleAddBadResponseXml(
570 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
571 "<methodResponse>\r\n"
573 "<value><struct>\r\n"
574 "<member><name>faultCode</name>\r\n"
575 "<value><i4>-501</i4></value></member>\r\n"
576 "<member><name>faultString</name>\r\n"
577 "<value><string>Not enough parameters</string></value></member>\r\n"
578 "</struct></value>\r\n"
580 "</methodResponse>\r\n"
584 string const nonexistentMethodCallXml(
585 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
587 "<methodName>nosuchmethod</methodName>\r\n"
589 "<param><value><i4>5</i4></value></param>\r\n"
590 "<param><value><i4>7</i4></value></param>\r\n"
595 string const nonexistentMethodYesDefResponseXml(
596 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
597 "<methodResponse>\r\n"
599 "<param><value><string>no such method: nosuchmethod</string>"
600 "</value></param>\r\n"
602 "</methodResponse>\r\n"
605 string const nonexistentMethodNoDefResponseXml(
606 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
607 "<methodResponse>\r\n"
609 "<value><struct>\r\n"
610 "<member><name>faultCode</name>\r\n"
611 "<value><i4>-506</i4></value></member>\r\n"
612 "<member><name>faultString</name>\r\n"
613 "<value><string>Method 'nosuchmethod' not defined</string></value>"
615 "</struct></value>\r\n"
617 "</methodResponse>\r\n"
623 class paramListTestSuite : public testSuite {
626 virtual string suiteName() {
627 return "paramListTestSuite";
629 virtual void runtests(unsigned int const) {
631 paramList paramList1;
632 TEST(paramList1.size() == 0);
634 paramList1.add(value_int(7));
635 paramList1.add(value_boolean(true));
636 paramList1.add(value_double(3.14));
637 time_t const timeZero(0);
638 paramList1.add(value_datetime(timeZero));
639 time_t const timeFuture(time(NULL)+100);
640 paramList1.add(value_datetime(timeFuture));
641 paramList1.add(value_string("hello world"));
642 unsigned char bytestringArray[] = {0x10, 0x11, 0x12, 0x13, 0x14};
643 vector<unsigned char>
644 bytestringData(&bytestringArray[0], &bytestringArray[4]);
645 paramList1.add(value_bytestring(bytestringData));
646 vector<value> arrayData;
647 arrayData.push_back(value_int(7));
648 arrayData.push_back(value_double(2.78));
649 arrayData.push_back(value_string("hello world"));
650 paramList1.add(value_array(arrayData));
651 map<string, value> structData;
652 pair<string, value> member("the_integer", value_int(9));
653 structData.insert(member);
654 paramList1.add(value_struct(structData));
655 paramList1.add(value_nil());
657 TEST(paramList1.size() == 10);
659 TEST(paramList1.getInt(0) == 7);
660 TEST(paramList1.getInt(0, 7) == 7);
661 TEST(paramList1.getInt(0, -5, 7) == 7);
662 TEST(paramList1.getBoolean(1) == true);
663 TEST(paramList1.getDouble(2) == 3.14);
664 TEST(paramList1.getDouble(2, 1) == 3.14);
665 TEST(paramList1.getDouble(2, 1, 4) == 3.14);
666 TEST(paramList1.getDatetime_sec(3) == 0);
667 TEST(paramList1.getDatetime_sec(3, paramList::TC_ANY) == timeZero);
668 TEST(paramList1.getDatetime_sec(3, paramList::TC_NO_FUTURE)
670 TEST(paramList1.getDatetime_sec(4, paramList::TC_NO_PAST)
672 TEST(paramList1.getString(5) == "hello world");
673 TEST(paramList1.getBytestring(6)[0] == 0x10);
674 TEST(paramList1.getArray(7).size() == 3);
675 TEST(paramList1.getArray(7, 3).size() == 3);
676 TEST(paramList1.getArray(7, 1, 3).size() == 3);
677 paramList1.getStruct(8)["the_integer"];
678 paramList1.getNil(9);
679 paramList1.verifyEnd(10);
681 paramList paramList2(5);
682 TEST(paramList2.size() == 0);
686 class registryRegMethodTestSuite : public testSuite {
689 virtual string suiteName() {
690 return "registryRegMethodTestSuite";
692 virtual void runtests(unsigned int) {
694 xmlrpc_c::registry myRegistry;
696 myRegistry.addMethod("sample.add",
697 xmlrpc_c::methodPtr(new sampleAddMethod));
699 myRegistry.disableIntrospection();
702 myRegistry.processCall("", &response);
703 TEST(response == noElementFoundXml);
707 myRegistry.processCall(sampleAddGoodCallXml, &response);
708 TEST(response == sampleAddGoodResponseXml);
712 myRegistry.processCall(sampleAddBadCallXml, &response);
713 TEST(response == sampleAddBadResponseXml);
720 class registryDefaultMethodTestSuite : public testSuite {
723 virtual string suiteName() {
724 return "registryDefaultMethodTestSuite";
726 virtual void runtests(unsigned int) {
728 xmlrpc_c::registry myRegistry;
730 myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
734 myRegistry.processCall(sampleAddGoodCallXml, &response);
735 TEST(response == sampleAddGoodResponseXml);
739 myRegistry.processCall(nonexistentMethodCallXml, &response);
740 TEST(response == nonexistentMethodNoDefResponseXml);
742 // We're actually violating the spirit of setDefaultMethod by
743 // doing this to a registry that's already been used, but as long
744 // as it works, it's a convenient way to implement this test.
745 myRegistry.setDefaultMethod(defaultMethodPtr(new nameMethod));
749 myRegistry.processCall(nonexistentMethodCallXml, &response);
750 TEST(response == nonexistentMethodYesDefResponseXml);
757 class registryTestSuite : public testSuite {
760 virtual string suiteName() {
761 return "registryTestSuite";
763 virtual void runtests(unsigned int const indentation) {
765 registryRegMethodTestSuite().run(indentation+1);
766 registryDefaultMethodTestSuite().run(indentation+1);
772 //=========================================================================
774 //=========================================================================
777 main(int argc, char**) {
782 cout << "Program takes no arguments" << endl;
789 // Add your test suites here.
790 valueTestSuite().run(0);
791 paramListTestSuite().run(0);
792 registryTestSuite().run(0);
793 serverAbyssTestSuite().run(0);
794 clientTestSuite().run(0);
799 } catch (error const& error) {
800 cout << "Unexpected error thrown: " << error.what() << endl;
802 } catch (XmlRpcFault const& fault) {
803 cout << "Unexpected XML-RPC fault when running test suites." << endl
804 << "Fault #" << fault.getFaultCode()
805 << ": " << fault.getFaultString() << endl;
808 cout << "Unexpected exception when running test suites." << endl;
813 cout << "PASSED" << endl;
816 cout << "FAILED" << endl;