Add test for the method signature of wrapped functions
[plcapi.git] / tests / 3LocalhostTest.php
1 <?php
2
3 include_once __DIR__ . '/../lib/xmlrpc.inc';
4 include_once __DIR__ . '/../lib/xmlrpc_wrappers.inc';
5
6 include_once __DIR__ . '/parse_args.php';
7
8 /**
9  * Tests which involve interaction between the client and the server.
10  * They are run against the server found in demo/server.php
11  */
12 class LocalhostTest extends PHPUnit_Framework_TestCase
13 {
14     /** @var xmlrpc_client $client */
15     protected $client = null;
16     protected $method = 'http';
17     protected $timeout = 10;
18     protected $request_compression = null;
19     protected $accepted_compression = '';
20     protected $args = array();
21
22     protected static $failed_tests = array();
23
24     protected $testId;
25     /** @var boolean $collectCodeCoverageInformation */
26     protected $collectCodeCoverageInformation;
27     protected $coverageScriptUrl;
28
29     public static function fail($message = '')
30     {
31         // save in a static var that this particular test has failed
32         // (but only if not called from subclass objects / multitests)
33         if (function_exists('debug_backtrace') && strtolower(get_called_class()) == 'localhosttests') {
34             $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
35             for ($i = 0; $i < count($trace); $i++) {
36                 if (strpos($trace[$i]['function'], 'test') === 0) {
37                     self::$failed_tests[$trace[$i]['function']] = true;
38                     break;
39                 }
40             }
41         }
42
43         parent::fail($message);
44     }
45
46     /**
47      * Reimplemented to allow us to collect code coverage info from the target server.
48      * Code taken from PHPUnit_Extensions_Selenium2TestCase
49      *
50      * @param PHPUnit_Framework_TestResult $result
51      * @return PHPUnit_Framework_TestResult
52      * @throws Exception
53      */
54     public function run(PHPUnit_Framework_TestResult $result = NULL)
55     {
56         $this->testId = get_class($this) . '__' . $this->getName();
57
58         if ($result === NULL) {
59             $result = $this->createResult();
60         }
61
62         $this->collectCodeCoverageInformation = $result->getCollectCodeCoverageInformation();
63
64         parent::run($result);
65
66         if ($this->collectCodeCoverageInformation) {
67             $coverage = new PHPUnit_Extensions_SeleniumCommon_RemoteCoverage(
68                 $this->coverageScriptUrl,
69                 $this->testId
70             );
71             $result->getCodeCoverage()->append(
72                 $coverage->get(), $this
73             );
74         }
75
76         // do not call this before to give the time to the Listeners to run
77         //$this->getStrategy()->endOfTest($this->session);
78
79         return $result;
80     }
81
82     public function setUp()
83     {
84         $this->args = argParser::getArgs();
85
86         $server = explode(':', $this->args['LOCALSERVER']);
87         if (count($server) > 1) {
88             $this->client = new xmlrpc_client($this->args['URI'], $server[0], $server[1]);
89         } else {
90             $this->client = new xmlrpc_client($this->args['URI'], $this->args['LOCALSERVER']);
91         }
92
93         $this->client->setDebug($this->args['DEBUG']);
94         $this->client->request_compression = $this->request_compression;
95         $this->client->accepted_compression = $this->accepted_compression;
96
97         $this->coverageScriptUrl = 'http://' . $this->args['LOCALSERVER'] . '/' . str_replace( '/demo/server/server.php', 'tests/phpunit_coverage.php', $this->args['URI'] );
98
99         if ($this->args['DEBUG'] == 1)
100             ob_start();
101     }
102
103     protected function tearDown()
104     {
105         if ($this->args['DEBUG'] != 1)
106             return;
107         $out = ob_get_clean();
108         $status = $this->getStatus();
109         if ($status == PHPUnit_Runner_BaseTestRunner::STATUS_ERROR
110             || $status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) {
111             echo $out;
112         }
113     }
114
115     protected function send($msg, $errorCode = 0, $returnResponse = false)
116     {
117         if ($this->collectCodeCoverageInformation) {
118             $this->client->setCookie('PHPUNIT_SELENIUM_TEST_ID', $this->testId);
119         }
120
121         $r = $this->client->send($msg, $this->timeout, $this->method);
122         // for multicall, return directly array of responses
123         if (is_array($r)) {
124             return $r;
125         }
126         if (is_array($errorCode)) {
127             $this->assertContains($r->faultCode(), $errorCode, 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
128         } else {
129             $this->assertEquals($errorCode, $r->faultCode(), 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
130         }
131         if (!$r->faultCode()) {
132             if ($returnResponse) {
133                 return $r;
134             } else {
135                 return $r->value();
136             }
137         } else {
138             return;
139         }
140     }
141
142     public function testString()
143     {
144         $sendString = "here are 3 \"entities\": < > & " .
145             "and here's a dollar sign: \$pretendvarname and a backslash too: " . chr(92) .
146             " - isn't that great? \\\"hackery\\\" at it's best " .
147             " also don't want to miss out on \$item[0]. " .
148             "The real weird stuff follows: CRLF here" . chr(13) . chr(10) .
149             "a simple CR here" . chr(13) .
150             "a simple LF here" . chr(10) .
151             "and then LFCR" . chr(10) . chr(13) .
152             "last but not least weird names: G" . chr(252) . "nter, El" . chr(232) . "ne, and an xml comment closing tag: -->";
153         $f = new xmlrpcmsg('examples.stringecho', array(
154             new xmlrpcval($sendString, 'string'),
155         ));
156         $v = $this->send($f);
157         if ($v) {
158             // when sending/receiving non-US-ASCII encoded strings, XML says cr-lf can be normalized.
159             // so we relax our tests...
160             $l1 = strlen($sendString);
161             $l2 = strlen($v->scalarval());
162             if ($l1 == $l2) {
163                 $this->assertEquals($sendString, $v->scalarval());
164             } else {
165                 $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendString), $v->scalarval());
166             }
167         }
168     }
169
170     public function testLatin1String()
171     {
172         $sendString =
173             "last but not least weird names: G" . chr(252) . "nter, El" . chr(232) . "ne";
174         $f = '<?xml version="1.0" encoding="ISO-8859-1"?><methodCall><methodName>examples.stringecho</methodName><params><param><value>'.
175             $sendString.
176             '</value></param></params></methodCall>';
177         $v = $this->send($f);
178         if ($v) {
179             $this->assertEquals($sendString, $v->scalarval());
180         }
181     }
182
183     /*public function testLatin1Method()
184     {
185         $f = new xmlrpcmsg("tests.iso88591methodname." . chr(224) . chr(252) . chr(232), array(
186             new xmlrpcval('hello')
187         ));
188         $v = $this->send($f);
189         if ($v) {
190             $this->assertEquals('hello', $v->scalarval());
191         }
192     }*/
193
194     public function testUtf8Method()
195     {
196         PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'UTF-8';
197         $f = new xmlrpcmsg("tests.utf8methodname." . 'κόσμε', array(
198             new xmlrpcval('hello')
199         ));
200         $v = $this->send($f);
201         if ($v) {
202             $this->assertEquals('hello', $v->scalarval());
203         }
204         PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'ISO-8859-1';
205     }
206
207     public function testAddingDoubles()
208     {
209         // note that rounding errors mean we
210         // keep precision to sensible levels here ;-)
211         $a = 12.13;
212         $b = -23.98;
213         $f = new xmlrpcmsg('examples.addtwodouble', array(
214             new xmlrpcval($a, 'double'),
215             new xmlrpcval($b, 'double'),
216         ));
217         $v = $this->send($f);
218         if ($v) {
219             $this->assertEquals($a + $b, $v->scalarval());
220         }
221     }
222
223     public function testAdding()
224     {
225         $f = new xmlrpcmsg('examples.addtwo', array(
226             new xmlrpcval(12, 'int'),
227             new xmlrpcval(-23, 'int'),
228         ));
229         $v = $this->send($f);
230         if ($v) {
231             $this->assertEquals(12 - 23, $v->scalarval());
232         }
233     }
234
235     public function testInvalidNumber()
236     {
237         $f = new xmlrpcmsg('examples.addtwo', array(
238             new xmlrpcval('fred', 'int'),
239             new xmlrpcval("\"; exec('ls')", 'int'),
240         ));
241         $v = $this->send($f);
242         /// @todo a fault condition should be generated here
243         /// by the server, which we pick up on
244         if ($v) {
245             $this->assertEquals(0, $v->scalarval());
246         }
247     }
248
249     public function testBoolean()
250     {
251         $f = new xmlrpcmsg('examples.invertBooleans', array(
252             new xmlrpcval(array(
253                 new xmlrpcval(true, 'boolean'),
254                 new xmlrpcval(false, 'boolean'),
255                 new xmlrpcval(1, 'boolean'),
256                 new xmlrpcval(0, 'boolean')
257             ),
258                 'array'
259             ),));
260         $answer = '0101';
261         $v = $this->send($f);
262         if ($v) {
263             $sz = $v->arraysize();
264             $got = '';
265             for ($i = 0; $i < $sz; $i++) {
266                 $b = $v->arraymem($i);
267                 if ($b->scalarval()) {
268                     $got .= '1';
269                 } else {
270                     $got .= '0';
271                 }
272             }
273             $this->assertEquals($answer, $got);
274         }
275     }
276
277     public function testBase64()
278     {
279         $sendString = 'Mary had a little lamb,
280 Whose fleece was white as snow,
281 And everywhere that Mary went
282 the lamb was sure to go.
283
284 Mary had a little lamb
285 She tied it to a pylon
286 Ten thousand volts went down its back
287 And turned it into nylon';
288         $f = new xmlrpcmsg('examples.decode64', array(
289             new xmlrpcval($sendString, 'base64'),
290         ));
291         $v = $this->send($f);
292         if ($v) {
293             if (strlen($sendString) == strlen($v->scalarval())) {
294                 $this->assertEquals($sendString, $v->scalarval());
295             } else {
296                 $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendString), $v->scalarval());
297             }
298         }
299     }
300
301     public function testDateTime()
302     {
303         $time = time();
304         $t1 = new xmlrpcval($time, 'dateTime.iso8601');
305         $t2 = new xmlrpcval(iso8601_encode($time), 'dateTime.iso8601');
306         $this->assertEquals($t1->serialize(), $t2->serialize());
307         if (class_exists('DateTime')) {
308             $datetime = new DateTime();
309             // skip this test for php 5.2. It is a bit harder there to build a DateTime from unix timestamp with proper TZ info
310             if (is_callable(array($datetime, 'setTimestamp'))) {
311                 $t3 = new xmlrpcval($datetime->setTimestamp($time), 'dateTime.iso8601');
312                 $this->assertEquals($t1->serialize(), $t3->serialize());
313             }
314         }
315     }
316
317     public function testCountEntities()
318     {
319         $sendString = "h'fd>onc>>l>>rw&bpu>q>e<v&gxs<ytjzkami<";
320         $f = new xmlrpcmsg('validator1.countTheEntities', array(
321             new xmlrpcval($sendString, 'string'),
322         ));
323         $v = $this->send($f);
324         if ($v) {
325             $got = '';
326             $expected = '37210';
327             $expect_array = array('ctLeftAngleBrackets', 'ctRightAngleBrackets', 'ctAmpersands', 'ctApostrophes', 'ctQuotes');
328             while (list(, $val) = each($expect_array)) {
329                 $b = $v->structmem($val);
330                 $got .= $b->me['int'];
331             }
332             $this->assertEquals($expected, $got);
333         }
334     }
335
336     public function _multicall_msg($method, $params)
337     {
338         $struct['methodName'] = new xmlrpcval($method, 'string');
339         $struct['params'] = new xmlrpcval($params, 'array');
340
341         return new xmlrpcval($struct, 'struct');
342     }
343
344     public function testServerMulticall()
345     {
346         // We manually construct a system.multicall() call to ensure
347         // that the server supports it.
348
349         // NB: This test will NOT pass if server does not support system.multicall.
350
351         // Based on http://xmlrpc-c.sourceforge.net/hacks/test_multicall.py
352         $good1 = $this->_multicall_msg(
353             'system.methodHelp',
354             array(php_xmlrpc_encode('system.listMethods')));
355         $bad = $this->_multicall_msg(
356             'test.nosuch',
357             array(php_xmlrpc_encode(1), php_xmlrpc_encode(2)));
358         $recursive = $this->_multicall_msg(
359             'system.multicall',
360             array(new xmlrpcval(array(), 'array')));
361         $good2 = $this->_multicall_msg(
362             'system.methodSignature',
363             array(php_xmlrpc_encode('system.listMethods')));
364         $arg = new xmlrpcval(
365             array($good1, $bad, $recursive, $good2),
366             'array'
367         );
368
369         $f = new xmlrpcmsg('system.multicall', array($arg));
370         $v = $this->send($f);
371         if ($v) {
372             //$this->assertTrue($r->faultCode() == 0, "fault from system.multicall");
373             $this->assertTrue($v->arraysize() == 4, "bad number of return values");
374
375             $r1 = $v->arraymem(0);
376             $this->assertTrue(
377                 $r1->kindOf() == 'array' && $r1->arraysize() == 1,
378                 "did not get array of size 1 from good1"
379             );
380
381             $r2 = $v->arraymem(1);
382             $this->assertTrue(
383                 $r2->kindOf() == 'struct',
384                 "no fault from bad"
385             );
386
387             $r3 = $v->arraymem(2);
388             $this->assertTrue(
389                 $r3->kindOf() == 'struct',
390                 "recursive system.multicall did not fail"
391             );
392
393             $r4 = $v->arraymem(3);
394             $this->assertTrue(
395                 $r4->kindOf() == 'array' && $r4->arraysize() == 1,
396                 "did not get array of size 1 from good2"
397             );
398         }
399     }
400
401     public function testClientMulticall1()
402     {
403         // NB: This test will NOT pass if server does not support system.multicall.
404
405         $this->client->no_multicall = false;
406
407         $good1 = new xmlrpcmsg('system.methodHelp',
408             array(php_xmlrpc_encode('system.listMethods')));
409         $bad = new xmlrpcmsg('test.nosuch',
410             array(php_xmlrpc_encode(1), php_xmlrpc_encode(2)));
411         $recursive = new xmlrpcmsg('system.multicall',
412             array(new xmlrpcval(array(), 'array')));
413         $good2 = new xmlrpcmsg('system.methodSignature',
414             array(php_xmlrpc_encode('system.listMethods'))
415         );
416
417         $r = $this->send(array($good1, $bad, $recursive, $good2));
418         if ($r) {
419             $this->assertTrue(count($r) == 4, "wrong number of return values");
420         }
421
422         $this->assertTrue($r[0]->faultCode() == 0, "fault from good1");
423         if (!$r[0]->faultCode()) {
424             $val = $r[0]->value();
425             $this->assertTrue(
426                 $val->kindOf() == 'scalar' && $val->scalartyp() == 'string',
427                 "good1 did not return string"
428             );
429         }
430         $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad");
431         $this->assertTrue($r[2]->faultCode() != 0, "no fault from recursive system.multicall");
432         $this->assertTrue($r[3]->faultCode() == 0, "fault from good2");
433         if (!$r[3]->faultCode()) {
434             $val = $r[3]->value();
435             $this->assertTrue($val->kindOf() == 'array', "good2 did not return array");
436         }
437         // This is the only assert in this test which should fail
438         // if the test server does not support system.multicall.
439         $this->assertTrue($this->client->no_multicall == false,
440             "server does not support system.multicall"
441         );
442     }
443
444     public function testClientMulticall2()
445     {
446         // NB: This test will NOT pass if server does not support system.multicall.
447
448         $this->client->no_multicall = true;
449
450         $good1 = new xmlrpcmsg('system.methodHelp',
451             array(php_xmlrpc_encode('system.listMethods')));
452         $bad = new xmlrpcmsg('test.nosuch',
453             array(php_xmlrpc_encode(1), php_xmlrpc_encode(2)));
454         $recursive = new xmlrpcmsg('system.multicall',
455             array(new xmlrpcval(array(), 'array')));
456         $good2 = new xmlrpcmsg('system.methodSignature',
457             array(php_xmlrpc_encode('system.listMethods'))
458         );
459
460         $r = $this->send(array($good1, $bad, $recursive, $good2));
461         if ($r) {
462             $this->assertTrue(count($r) == 4, "wrong number of return values");
463         }
464
465         $this->assertTrue($r[0]->faultCode() == 0, "fault from good1");
466         if (!$r[0]->faultCode()) {
467             $val = $r[0]->value();
468             $this->assertTrue(
469                 $val->kindOf() == 'scalar' && $val->scalartyp() == 'string',
470                 "good1 did not return string");
471         }
472         $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad");
473         $this->assertTrue($r[2]->faultCode() == 0, "fault from (non recursive) system.multicall");
474         $this->assertTrue($r[3]->faultCode() == 0, "fault from good2");
475         if (!$r[3]->faultCode()) {
476             $val = $r[3]->value();
477             $this->assertTrue($val->kindOf() == 'array', "good2 did not return array");
478         }
479     }
480
481     public function testClientMulticall3()
482     {
483         // NB: This test will NOT pass if server does not support system.multicall.
484
485         $this->client->return_type = 'phpvals';
486         $this->client->no_multicall = false;
487
488         $good1 = new xmlrpcmsg('system.methodHelp',
489             array(php_xmlrpc_encode('system.listMethods')));
490         $bad = new xmlrpcmsg('test.nosuch',
491             array(php_xmlrpc_encode(1), php_xmlrpc_encode(2)));
492         $recursive = new xmlrpcmsg('system.multicall',
493             array(new xmlrpcval(array(), 'array')));
494         $good2 = new xmlrpcmsg('system.methodSignature',
495             array(php_xmlrpc_encode('system.listMethods'))
496         );
497
498         $r = $this->send(array($good1, $bad, $recursive, $good2));
499         if ($r) {
500             $this->assertTrue(count($r) == 4, "wrong number of return values");
501         }
502         $this->assertTrue($r[0]->faultCode() == 0, "fault from good1");
503         if (!$r[0]->faultCode()) {
504             $val = $r[0]->value();
505             $this->assertTrue(
506                 is_string($val), "good1 did not return string");
507         }
508         $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad");
509         $this->assertTrue($r[2]->faultCode() != 0, "no fault from recursive system.multicall");
510         $this->assertTrue($r[3]->faultCode() == 0, "fault from good2");
511         if (!$r[3]->faultCode()) {
512             $val = $r[3]->value();
513             $this->assertTrue(is_array($val), "good2 did not return array");
514         }
515         $this->client->return_type = 'xmlrpcvals';
516     }
517
518     public function testCatchWarnings()
519     {
520         $f = new xmlrpcmsg('tests.generatePHPWarning', array(
521             new xmlrpcval('whatever', 'string'),
522         ));
523         $v = $this->send($f);
524         if ($v) {
525             $this->assertEquals(true, $v->scalarval());
526         }
527     }
528
529     public function testCatchExceptions()
530     {
531         $f = new xmlrpcmsg('tests.raiseException', array(
532             new xmlrpcval('whatever', 'string'),
533         ));
534         $v = $this->send($f, $GLOBALS['xmlrpcerr']['server_error']);
535         $this->client->path = $this->args['URI'] . '?EXCEPTION_HANDLING=1';
536         $v = $this->send($f, 1); // the error code of the expected exception
537         $this->client->path = $this->args['URI'] . '?EXCEPTION_HANDLING=2';
538         // depending on whether display_errors is ON or OFF on the server, we will get back a different error here,
539         // as php will generate an http status code of either 200 or 500...
540         $v = $this->send($f, array($GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcerr']['http_error']));
541     }
542
543     public function testZeroParams()
544     {
545         $f = new xmlrpcmsg('system.listMethods');
546         $v = $this->send($f);
547     }
548
549     public function testCodeInjectionServerSide()
550     {
551         $f = new xmlrpcmsg('system.MethodHelp');
552         $f->payload = "<?xml version=\"1.0\"?><methodCall><methodName>validator1.echoStructTest</methodName><params><param><value><struct><member><name>','')); echo('gotcha!'); die(); //</name></member></struct></value></param></params></methodCall>";
553         $v = $this->send($f);
554         if ($v) {
555             $this->assertEquals(0, $v->structsize());
556         }
557     }
558
559     public function testServerWrappedFunction()
560     {
561         $f = new xmlrpcmsg('tests.getStateName.2', array(
562             new xmlrpcval(23, 'int'),
563         ));
564         $v = $this->send($f);
565         $this->assertEquals('Michigan', $v->scalarval());
566
567         // this generates an exception in the function which was wrapped, which is by default wrapped in a known error response
568         $f = new xmlrpcmsg('tests.getStateName.2', array(
569             new xmlrpcval(0, 'int'),
570         ));
571         $v = $this->send($f, $GLOBALS['xmlrpcerr']['server_error']);
572
573         // check if the generated function dispatch map is fine, by checking if the server registered it
574         $f = new xmlrpcmsg('system.methodSignature', array(
575             new xmlrpcval('tests.getStateName.2'),
576         ));
577         $v = $this->send($f);
578         $encoder = new \PhpXmlRpc\Encoder();
579         $this->assertEquals(array(array('string', 'int')), $encoder->decode($v));
580     }
581
582     public function testServerWrappedFunctionAsSource()
583     {
584         $f = new xmlrpcmsg('tests.getStateName.6', array(
585             new xmlrpcval(23, 'int'),
586         ));
587         $v = $this->send($f);
588         $this->assertEquals('Michigan', $v->scalarval());
589
590         // this generates an exception in the function which was wrapped, which is by default wrapped in a known error response
591         $f = new xmlrpcmsg('tests.getStateName.6', array(
592             new xmlrpcval(0, 'int'),
593         ));
594         $v = $this->send($f, $GLOBALS['xmlrpcerr']['server_error']);
595     }
596
597     public function testServerWrappedObjectMethods()
598     {
599         $f = new xmlrpcmsg('tests.getStateName.3', array(
600             new xmlrpcval(23, 'int'),
601         ));
602         $v = $this->send($f);
603         $this->assertEquals('Michigan', $v->scalarval());
604
605         $f = new xmlrpcmsg('tests.getStateName.4', array(
606             new xmlrpcval(23, 'int'),
607         ));
608         $v = $this->send($f);
609         $this->assertEquals('Michigan', $v->scalarval());
610
611         $f = new xmlrpcmsg('tests.getStateName.5', array(
612             new xmlrpcval(23, 'int'),
613         ));
614         $v = $this->send($f);
615         $this->assertEquals('Michigan', $v->scalarval());
616
617         $f = new xmlrpcmsg('tests.getStateName.7', array(
618             new xmlrpcval(23, 'int'),
619         ));
620         $v = $this->send($f);
621         $this->assertEquals('Michigan', $v->scalarval());
622
623         $f = new xmlrpcmsg('tests.getStateName.8', array(
624             new xmlrpcval(23, 'int'),
625         ));
626         $v = $this->send($f);
627         $this->assertEquals('Michigan', $v->scalarval());
628
629         $f = new xmlrpcmsg('tests.getStateName.9', array(
630             new xmlrpcval(23, 'int'),
631         ));
632         $v = $this->send($f);
633         $this->assertEquals('Michigan', $v->scalarval());
634     }
635
636     public function testServerWrappedObjectMethodsAsSource()
637     {
638         $f = new xmlrpcmsg('tests.getStateName.7', array(
639             new xmlrpcval(23, 'int'),
640         ));
641         $v = $this->send($f);
642         $this->assertEquals('Michigan', $v->scalarval());
643
644         $f = new xmlrpcmsg('tests.getStateName.8', array(
645             new xmlrpcval(23, 'int'),
646         ));
647         $v = $this->send($f);
648         $this->assertEquals('Michigan', $v->scalarval());
649
650         $f = new xmlrpcmsg('tests.getStateName.9', array(
651             new xmlrpcval(23, 'int'),
652         ));
653         $v = $this->send($f);
654         $this->assertEquals('Michigan', $v->scalarval());
655     }
656
657     public function testServerClosure()
658     {
659         $f = new xmlrpcmsg('tests.getStateName.10', array(
660             new xmlrpcval(23, 'int'),
661         ));
662         $v = $this->send($f);
663         $this->assertEquals('Michigan', $v->scalarval());
664     }
665
666     public function testServerWrappedClosure()
667     {
668         $f = new xmlrpcmsg('tests.getStateName.11', array(
669             new xmlrpcval(23, 'int'),
670         ));
671         $v = $this->send($f);
672         $this->assertEquals('Michigan', $v->scalarval());
673     }
674
675     public function testServerWrappedClass()
676     {
677         $f = new xmlrpcmsg('tests.xmlrpcServerMethodsContainer.findState', array(
678             new xmlrpcval(23, 'int'),
679         ));
680         $v = $this->send($f);
681         $this->assertEquals('Michigan', $v->scalarval());
682     }
683
684     public function testWrappedMethod()
685     {
686         // make a 'deep client copy' as the original one might have many properties set
687         $func = wrap_xmlrpc_method($this->client, 'examples.getStateName', array('simple_client_copy' => 0));
688         if ($func == false) {
689             $this->fail('Registration of examples.getStateName failed');
690         } else {
691             $v = $func(23);
692             // work around bug in current version of phpunit
693             if (is_object($v)) {
694                 $v = var_export($v, true);
695             }
696             $this->assertEquals('Michigan', $v);
697         }
698     }
699
700     public function testWrappedMethodAsSource()
701     {
702         // make a 'deep client copy' as the original one might have many properties set
703         $func = wrap_xmlrpc_method($this->client, 'examples.getStateName', array('simple_client_copy' => 0, 'return_source' => true));
704         if ($func == false) {
705             $this->fail('Registration of examples.getStateName failed');
706         } else {
707             eval($func['source']);
708             $func = $func['function'];
709             $v = $func(23);
710             // work around bug in current version of phpunit
711             if (is_object($v)) {
712                 $v = var_export($v, true);
713             }
714             $this->assertEquals('Michigan', $v);
715         }
716     }
717
718     public function testWrappedClass()
719     {
720         // make a 'deep client copy' as the original one might have many properties set
721         // also for speed only wrap one method of the whole server
722         $class = wrap_xmlrpc_server($this->client, array('simple_client_copy' => 0, 'method_filter' => '/examples\.getStateName/' ));
723         if ($class == '') {
724             $this->fail('Registration of remote server failed');
725         } else {
726             $obj = new $class();
727             $v = $obj->examples_getStateName(23);
728             // work around bug in current version of phpunit
729             if (is_object($v)) {
730                 $v = var_export($v, true);
731             }
732             $this->assertEquals('Michigan', $v);
733         }
734     }
735
736     public function testGetCookies()
737     {
738         // let server set to us some cookies we tell it
739         $cookies = array(
740             //'c1' => array(),
741             'c2' => array('value' => 'c2'),
742             'c3' => array('value' => 'c3', 'expires' => time() + 60 * 60 * 24 * 30),
743             'c4' => array('value' => 'c4', 'expires' => time() + 60 * 60 * 24 * 30, 'path' => '/'),
744             'c5' => array('value' => 'c5', 'expires' => time() + 60 * 60 * 24 * 30, 'path' => '/', 'domain' => 'localhost'),
745         );
746         $cookiesval = php_xmlrpc_encode($cookies);
747         $f = new xmlrpcmsg('examples.setcookies', array($cookiesval));
748         $r = $this->send($f, 0, true);
749         if ($r) {
750             $v = $r->value();
751             $this->assertEquals(1, $v->scalarval());
752             // now check if we decoded the cookies as we had set them
753             $rcookies = $r->cookies();
754             // remove extra cookies which might have been set by proxies
755             foreach ($rcookies as $c => $v) {
756                 if (!in_array($c, array('c2', 'c3', 'c4', 'c5'))) {
757                     unset($rcookies[$c]);
758                 }
759                 // Seems like we get this when using php-fpm and php 5.5+ ...
760                 if (isset($rcookies[$c]['Max-Age'])) {
761                     unset($rcookies[$c]['Max-Age']);
762                 }
763             }
764             foreach ($cookies as $c => $v) {
765                 // format for date string in cookies: 'Mon, 31 Oct 2005 13:50:56 GMT'
766                 // but PHP versions differ on that, some use 'Mon, 31-Oct-2005 13:50:56 GMT'...
767                 if (isset($v['expires'])) {
768                     if (isset($rcookies[$c]['expires']) && strpos($rcookies[$c]['expires'], '-')) {
769                         $cookies[$c]['expires'] = gmdate('D, d\-M\-Y H:i:s \G\M\T', $cookies[$c]['expires']);
770                     } else {
771                         $cookies[$c]['expires'] = gmdate('D, d M Y H:i:s \G\M\T', $cookies[$c]['expires']);
772                     }
773                 }
774             }
775
776             $this->assertEquals($cookies, $rcookies);
777         }
778     }
779
780     public function testSetCookies()
781     {
782         // let server set to us some cookies we tell it
783         $cookies = array(
784             'c0' => null,
785             'c1' => 1,
786             'c2' => '2 3',
787             'c3' => '!@#$%^&*()_+|}{":?><,./\';[]\\=-',
788         );
789         $f = new xmlrpcmsg('examples.getcookies', array());
790         foreach ($cookies as $cookie => $val) {
791             $this->client->setCookie($cookie, $val);
792             $cookies[$cookie] = (string)$cookies[$cookie];
793         }
794         $r = $this->client->send($f, $this->timeout, $this->method);
795         $this->assertEquals(0, $r->faultCode(), 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
796         if (!$r->faultCode()) {
797             $v = $r->value();
798             $v = php_xmlrpc_decode($v);
799
800             // take care for the extra cookie used for coverage collection
801             if (isset($v['PHPUNIT_SELENIUM_TEST_ID'])) {
802                 unset($v['PHPUNIT_SELENIUM_TEST_ID']);
803             }
804
805             // on IIS and Apache getallheaders returns something slightly different...
806             $this->assertEquals($cookies, $v);
807         }
808     }
809
810     public function testSendTwiceSameMsg()
811     {
812         $f = new xmlrpcmsg('examples.stringecho', array(
813             new xmlrpcval('hello world', 'string'),
814         ));
815         $v1 = $this->send($f);
816         $v2 = $this->send($f);
817         if ($v1 && $v2) {
818             $this->assertEquals($v1, $v2);
819         }
820     }
821 }