initial load of upstream version 1.06.32
[xmlrpc-c] / src / cpp / test / test.cpp
1 #include <string>
2 #include <iostream>
3 #include <iomanip>
4 #include <vector>
5 #include <sstream>
6 #include <memory>
7 #include <time.h>
8 #include <cstring>
9
10 #include "xmlrpc-c/girerr.hpp"
11 using girerr::error;
12 #include "transport_config.h"
13 #include "xmlrpc-c/base.hpp"
14 #include "xmlrpc-c/oldcppwrapper.hpp"
15 #include "xmlrpc-c/registry.hpp"
16
17 #include "testclient.hpp"
18 #include "server_abyss.hpp"
19 #include "tools.hpp"
20
21 using namespace xmlrpc_c;
22 using namespace std;
23
24 //=========================================================================
25 //  Test Harness
26 //=========================================================================
27 // 
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.
31 //
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
35 //  the new style.
36
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.
42 //
43 //  To run the tests, type './cpptest'.
44 //  To check for memory leaks, install RedHat's 'memprof' utility, and
45 //  type 'memprof cpptest'.
46 //
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.
50
51
52 class sampleAddMethod : public method {
53 public:
54     sampleAddMethod() {
55         this->_signature = "i:ii";
56         this->_help = "This method adds two integers together";
57     }
58     void
59     execute(xmlrpc_c::paramList const& paramList,
60             value *             const  retvalP) {
61         
62         int const addend(paramList.getInt(0));
63         int const adder(paramList.getInt(1));
64         
65         paramList.verifyEnd(2);
66         
67         *retvalP = value_int(addend + adder);
68     }
69 };
70
71
72
73 class nameMethod : public defaultMethod {
74
75     void
76     execute(string              const& methodName,
77             xmlrpc_c::paramList const& ,  // paramList
78             value *             const  retvalP) {
79         
80         *retvalP = value_string(string("no such method: ") + methodName);
81     }
82 };
83
84
85 //=========================================================================
86 //  Test Suites
87 //=========================================================================
88
89 void 
90 test_fault (void) {
91
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");
96
97     // Extract and examine the underlying xmlrpc_env struct.
98     xmlrpc_env *env1 = fault1.getFaultEnv();
99     TEST(env1 != NULL);
100     TEST(env1->fault_occurred);
101     TEST(env1->fault_code == 6);
102     TEST(strcmp(env1->fault_string, "Sample fault") == 0);
103
104     // Test our copy constructor.
105     XmlRpcFault fault2 = fault1;
106     TEST(fault2.getFaultCode() == 6);
107     TEST(fault2.getFaultString() == "Sample fault");
108     
109     // Construct a fault from a pre-existing xmlrpc_env structure.
110     xmlrpc_env env3;
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");
117     
118     // Attempt to construct a fault from a fault-free xmlrpc_env.
119     xmlrpc_env env4;
120     xmlrpc_env_init(&env4);
121     try {
122         XmlRpcFault fault4 = XmlRpcFault(&env4);
123         TEST_FAILED("Constructed invalid XmlRpcFault");
124     } catch (XmlRpcFault const& fault) {
125         TEST_PASSED();
126         TEST(fault.getFaultCode() == XMLRPC_INTERNAL_ERROR);
127     }
128     xmlrpc_env_clean(&env4);
129 }
130
131
132
133 void test_env (void) {
134
135     // Declare these here to prevent silly compiler warnings about
136     // potentially uninitialized variables.
137     XmlRpcEnv env1;
138     XmlRpcEnv env2;
139
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");
147
148     // Test throwIfFaultOccurred.
149     try {
150         env2.throwIfFaultOccurred();
151         TEST_PASSED();
152     } catch (XmlRpcFault const& fault) {
153         TEST_FAILED("We threw a fault when one hadn't occurred");
154     } 
155     xmlrpc_env_set_fault(env2, 9, "Fault 9");
156     try {
157         env2.throwIfFaultOccurred();
158         TEST_FAILED("A fault occurred, and we didn't throw it");
159     } catch (XmlRpcFault const& fault) {
160         TEST_PASSED();
161         TEST(fault.getFaultCode() == 9);
162         TEST(fault.getFaultString() == "Fault 9");
163     } 
164     
165     // Make sure we can't get a fault if one hasn't occurred.
166     XmlRpcEnv env3;
167     try {
168         XmlRpcFault fault3 = env3.getFault();
169         TEST_FAILED("We retrieved a non-existant fault");
170     } catch (XmlRpcFault const& fault) {
171         TEST_PASSED();
172         TEST(fault.getFaultCode() == XMLRPC_INTERNAL_ERROR);
173     }
174 }
175
176 void test_value (void) {
177     XmlRpcEnv env;
178
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;
186     xmlrpc_DECREF(v);
187
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();
193     TEST(borrowed == v);
194
195     // Make a reference.
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();
200     TEST(made == v);
201     xmlrpc_DECREF(made);
202
203     // Test our default constructor.
204     XmlRpcValue val5;
205     TEST(val5.getBool() == false);
206
207     // Test our type introspection.
208     TEST(XmlRpcValue::makeInt(0).getType() == XMLRPC_TYPE_INT);
209     
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();
223
224     // Test Base64 values.
225     const unsigned char *b64_data;
226     size_t b64_len;
227     XmlRpcValue val6 = XmlRpcValue::makeBase64((unsigned char*) "a\0\0b", 4);
228     val6.getBase64(b64_data, b64_len);
229     TEST(b64_len == 4);
230     TEST(memcmp(b64_data, "a\0\0b", 4) == 0);
231
232     // Test arrays.
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");
241
242     // Test structs.
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++) {
252         string key;
253         XmlRpcValue value;
254         strct.structGetKeyAndValue(i, key, value);
255         TEST(key + "val" == value.getString());
256     }
257 }
258
259
260
261 static void
262 testXmlRpcCpp() {
263 /*----------------------------------------------------------------------------
264    Test the legacy XmlRpcCpp.cpp library
265 -----------------------------------------------------------------------------*/
266     cout << "Testing XmlRpcCpp library..." << endl;
267
268     test_fault();
269     test_env();
270     test_value();
271 }
272
273
274
275 class intTestSuite : public testSuite {
276 public:
277     virtual string suiteName() {
278         return "intTestSuite";
279     }
280     virtual void runtests(unsigned int const) {
281         value_int int1(7);
282         TEST(static_cast<int>(int1) == 7);
283         value_int int2(-7);
284         TEST(static_cast<int>(int2) == -7);
285         value val1(int1);
286         TEST(val1.type() == value::TYPE_INT);
287         value_int int3(val1);
288         TEST(static_cast<int>(int3) == 7);
289         try {
290             value_int int4(value_double(3.7));
291             TEST_FAILED("invalid cast double-int suceeded");
292         } catch (error) {}
293     }
294 };
295
296
297
298 class doubleTestSuite : public testSuite {
299 public:
300     virtual string suiteName() {
301         return "doubleTestSuite";
302     }
303     virtual void runtests(unsigned int const) {
304         value_double double1(3.14);
305         TEST(static_cast<double>(double1) == 3.14);
306         value val1(double1);
307         TEST(val1.type() == value::TYPE_DOUBLE);
308         value_double double2(val1);
309         TEST(static_cast<double>(double2) == 3.14);
310         try {
311             value_double double4(value_int(4));
312             TEST_FAILED("invalid cast int-double suceeded");
313         } catch (error) {}
314     }
315 };
316
317
318
319 class booleanTestSuite : public testSuite {
320 public:
321     virtual string suiteName() {
322         return "booleanTestSuite";
323     }
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);
333         try {
334             value_boolean boolean4(value_int(4));
335             TEST_FAILED("invalid cast int-boolean suceeded");
336         } catch (error) {}
337     }
338 };
339
340
341
342 class datetimeTestSuite : public testSuite {
343 public:
344     virtual string suiteName() {
345         return "datetimeTestSuite";
346     }
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);
357         try {
358             value_datetime datetime4(value_int(4));
359             TEST_FAILED("invalid cast int-datetime suceeded");
360         } catch (error) {}
361     }
362 };
363
364
365
366 class stringTestSuite : public testSuite {
367 public:
368     virtual string suiteName() {
369         return "stringTestSuite";
370     }
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");
376         value val1(string1);
377         TEST(val1.type() == value::TYPE_STRING);
378         value_string string3(val1);
379         TEST(static_cast<string>(string3) == "hello world");
380         try {
381             value_string string4(value_int(4));
382             TEST_FAILED("invalid cast int-string suceeded");
383         } catch (error) {}
384     }
385 };
386
387
388
389 class bytestringTestSuite : public testSuite {
390 public:
391     virtual string suiteName() {
392         return "bytestringTestSuite";
393     }
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);
399
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);
409         try {
410             value_bytestring bytestring4(value_int(4));
411             TEST_FAILED("invalid cast int-bytestring suceeded");
412         } catch (error) {}
413     }
414 };
415
416
417
418 class nilTestSuite : public testSuite {
419 public:
420     virtual string suiteName() {
421         return "nilTestSuite";
422     }
423     virtual void runtests(unsigned int const) {
424         value_nil nil1;
425         value val1(nil1);
426         TEST(val1.type() == value::TYPE_NIL);
427         value_nil nil2(val1);
428         try {
429             value_nil nil4(value_int(4));
430             TEST_FAILED("invalid cast int-nil suceeded");
431         } catch (error) {}
432     }
433 };
434
435
436
437 class structTestSuite : public testSuite {
438 public:
439     virtual string suiteName() {
440         return "structTestSuite";
441     }
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);
446         
447         value_struct struct1(structData);
448
449         map<string, value> dataReadBack(struct1);
450
451         TEST(static_cast<int>(value_int(dataReadBack["the_integer"])) == 9);
452
453         value val1(struct1);
454         TEST(val1.type() == value::TYPE_STRUCT);
455         value_struct struct2(val1);
456         try {
457             value_struct struct4(value_int(4));
458             TEST_FAILED("invalid cast int-struct suceeded");
459         } catch (error) {}
460     }
461 };
462
463
464
465 class arrayTestSuite : public testSuite {
466 public:
467     virtual string suiteName() {
468         return "arrayTestSuite";
469     }
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);
476
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])) == 
485              "hello world");
486
487         value val1(array1);
488         TEST(val1.type() == value::TYPE_ARRAY);
489         value_array array2(val1);
490         TEST(array2.size() == 3);
491         try {
492             value_array array4(value_int(4));
493             TEST_FAILED("invalid cast int-array suceeded");
494         } catch (error) {}
495     }
496 };
497
498
499
500 class valueTestSuite : public testSuite {
501
502 public:
503     virtual string suiteName() {
504         return "valueTestSuite";
505     }
506     virtual void runtests(unsigned int const indentation) {
507
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);
517     }
518 };
519
520
521 namespace {
522 string const noElementFoundXml(
523     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
524     "<methodResponse>\r\n"
525     "<fault>\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>"
532     "</member>\r\n"
533     "</struct></value>\r\n"
534     "</fault>\r\n"
535     "</methodResponse>\r\n"
536     );
537
538 string const sampleAddGoodCallXml(
539     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
540     "<methodCall>\r\n"
541     "<methodName>sample.add</methodName>\r\n"
542     "<params>\r\n"
543     "<param><value><i4>5</i4></value></param>\r\n"
544     "<param><value><i4>7</i4></value></param>\r\n"
545     "</params>\r\n"
546     "</methodCall>\r\n"
547     );
548
549 string const sampleAddGoodResponseXml(
550     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
551     "<methodResponse>\r\n"
552     "<params>\r\n"
553     "<param><value><i4>12</i4></value></param>\r\n"
554     "</params>\r\n"
555     "</methodResponse>\r\n"
556     );
557
558
559 string const sampleAddBadCallXml(
560     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
561     "<methodCall>\r\n"
562     "<methodName>sample.add</methodName>\r\n"
563     "<params>\r\n"
564     "<param><value><i4>5</i4></value></param>\r\n"
565     "</params>\r\n"
566     "</methodCall>\r\n"
567     );
568
569 string const sampleAddBadResponseXml(
570     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
571     "<methodResponse>\r\n"
572     "<fault>\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"
579     "</fault>\r\n"
580     "</methodResponse>\r\n"
581     );
582
583
584 string const nonexistentMethodCallXml(
585     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
586     "<methodCall>\r\n"
587     "<methodName>nosuchmethod</methodName>\r\n"
588     "<params>\r\n"
589     "<param><value><i4>5</i4></value></param>\r\n"
590     "<param><value><i4>7</i4></value></param>\r\n"
591     "</params>\r\n"
592     "</methodCall>\r\n"
593     );
594
595 string const nonexistentMethodYesDefResponseXml(
596     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
597     "<methodResponse>\r\n"
598     "<params>\r\n"
599     "<param><value><string>no such method: nosuchmethod</string>"
600     "</value></param>\r\n"
601     "</params>\r\n"
602     "</methodResponse>\r\n"
603     );
604
605 string const nonexistentMethodNoDefResponseXml(
606     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
607     "<methodResponse>\r\n"
608     "<fault>\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>"
614     "</member>\r\n"
615     "</struct></value>\r\n"
616     "</fault>\r\n"
617     "</methodResponse>\r\n"
618     );
619
620 } // namespace
621
622
623 class paramListTestSuite : public testSuite {
624
625 public:
626     virtual string suiteName() {
627         return "paramListTestSuite";
628     }
629     virtual void runtests(unsigned int const) {
630
631         paramList paramList1;
632         TEST(paramList1.size() == 0);
633
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());
656
657         TEST(paramList1.size() == 10);
658
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) 
669              == timeZero);
670         TEST(paramList1.getDatetime_sec(4, paramList::TC_NO_PAST)
671              == timeFuture);
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);
680
681         paramList paramList2(5);
682         TEST(paramList2.size() == 0);
683     }
684 };
685
686 class registryRegMethodTestSuite : public testSuite {
687
688 public:
689     virtual string suiteName() {
690         return "registryRegMethodTestSuite";
691     }
692     virtual void runtests(unsigned int) {
693
694         xmlrpc_c::registry myRegistry;
695         
696         myRegistry.addMethod("sample.add", 
697                              xmlrpc_c::methodPtr(new sampleAddMethod));
698         
699         myRegistry.disableIntrospection();
700         {
701             string response;
702             myRegistry.processCall("", &response);
703             TEST(response == noElementFoundXml);
704         }
705         {
706             string response;
707             myRegistry.processCall(sampleAddGoodCallXml, &response);
708             TEST(response == sampleAddGoodResponseXml);
709         }
710         {
711             string response;
712             myRegistry.processCall(sampleAddBadCallXml, &response);
713             TEST(response == sampleAddBadResponseXml);
714         }
715     }
716 };
717
718
719
720 class registryDefaultMethodTestSuite : public testSuite {
721
722 public:
723     virtual string suiteName() {
724         return "registryDefaultMethodTestSuite";
725     }
726     virtual void runtests(unsigned int) {
727
728         xmlrpc_c::registry myRegistry;
729         
730         myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
731
732         {
733             string response;
734             myRegistry.processCall(sampleAddGoodCallXml, &response);
735             TEST(response == sampleAddGoodResponseXml);
736         }
737         {
738             string response;
739             myRegistry.processCall(nonexistentMethodCallXml, &response);
740             TEST(response == nonexistentMethodNoDefResponseXml);
741         }
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));
746
747         {
748             string response;
749             myRegistry.processCall(nonexistentMethodCallXml, &response);
750             TEST(response == nonexistentMethodYesDefResponseXml);
751         }
752     }
753 };
754
755
756
757 class registryTestSuite : public testSuite {
758
759 public:
760     virtual string suiteName() {
761         return "registryTestSuite";
762     }
763     virtual void runtests(unsigned int const indentation) {
764
765         registryRegMethodTestSuite().run(indentation+1);
766         registryDefaultMethodTestSuite().run(indentation+1);
767     }
768 };
769
770
771
772 //=========================================================================
773 //  Test Driver
774 //=========================================================================
775
776 int 
777 main(int argc, char**) {
778     
779     int retval;
780
781     if (argc-1 > 0) {
782         cout << "Program takes no arguments" << endl;
783         exit(1);
784     }
785
786     bool testsPassed;
787
788     try {
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);
795
796         testXmlRpcCpp();
797
798         testsPassed = true;
799     } catch (error const& error) {
800         cout << "Unexpected error thrown:  " << error.what() << endl;
801         testsPassed = false;
802     } catch (XmlRpcFault const& fault) {
803         cout << "Unexpected XML-RPC fault when running test suites." << endl
804              << "Fault #" << fault.getFaultCode()
805              << ": " << fault.getFaultString() << endl;
806         testsPassed = false;
807     } catch (...) {
808         cout << "Unexpected exception when running test suites." << endl;
809         testsPassed = false;
810     }
811
812     if (testsPassed) {
813         cout << "PASSED" << endl;
814         retval = 0;
815     } else {
816         cout << "FAILED" << endl;
817         retval = 1;
818     }
819     return retval;
820 }