3 include_once __DIR__ . '/../lib/xmlrpc.inc';
4 include_once __DIR__ . '/../lib/xmlrpc_wrappers.inc';
6 include_once __DIR__ . '/parse_args.php';
8 include_once __DIR__ . '/PolyfillTestCase.php';
10 use PHPUnit\Framework\TestResult;
13 * Tests which involve interaction between the client and the server.
14 * They are run against the server found in demo/server.php
16 class LocalhostTest extends PhpXmlRpc_PolyfillTestCase
18 /** @var xmlrpc_client $client */
19 protected $client = null;
20 protected $method = 'http';
21 protected $timeout = 10;
22 protected $request_compression = null;
23 protected $accepted_compression = '';
24 protected $args = array();
26 protected static $failed_tests = array();
29 /** @var boolean $collectCodeCoverageInformation */
30 protected $collectCodeCoverageInformation;
31 protected $coverageScriptUrl;
34 * @todo instead of overriding run via _fail, implement PHPUnit_Framework_TestListener - IFF there is such an API portable across PHPUnit 5 to 9...
36 public static function _fail($message = '')
38 // save in a static var that this particular test has failed
39 // (but only if not called from subclass objects / multitests)
40 if (function_exists('debug_backtrace') && strtolower(get_called_class()) == 'localhosttests') {
41 $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
42 for ($i = 0; $i < count($trace); $i++) {
43 if (strpos($trace[$i]['function'], 'test') === 0) {
44 self::$failed_tests[$trace[$i]['function']] = true;
50 parent::_fail($message);
54 * Reimplemented to allow us to collect code coverage info from the target server.
55 * Code taken from PHPUnit_Extensions_Selenium2TestCase
57 * @param TestResult $result
61 * @todo instead of overriding run via _run, subclass PHPUnit_Extensions_TestDecorator - IFF there is such an API portable across PHPUnit 5 to 9...
63 public function _run($result = NULL)
65 $this->testId = get_class($this) . '__' . $this->getName();
67 if ($result === NULL) {
68 $result = $this->createResult();
71 $this->collectCodeCoverageInformation = $result->getCollectCodeCoverageInformation();
73 parent::_run($result);
75 if ($this->collectCodeCoverageInformation) {
76 $coverage = new PHPUnit_Extensions_SeleniumCommon_RemoteCoverage(
77 $this->coverageScriptUrl,
80 $result->getCodeCoverage()->append(
81 $coverage->get(), $this
85 // do not call this before to give the time to the Listeners to run
86 //$this->getStrategy()->endOfTest($this->session);
91 public function set_up()
93 $this->args = argParser::getArgs();
95 $server = explode(':', $this->args['HTTPSERVER']);
96 if (count($server) > 1) {
97 $this->client = new xmlrpc_client($this->args['HTTPURI'], $server[0], $server[1]);
99 $this->client = new xmlrpc_client($this->args['HTTPURI'], $this->args['HTTPSERVER']);
102 $this->client->setDebug($this->args['DEBUG']);
103 $this->client->request_compression = $this->request_compression;
104 $this->client->accepted_compression = $this->accepted_compression;
106 $this->coverageScriptUrl = 'http://' . $this->args['HTTPSERVER'] . '/' . str_replace( '/demo/server/server.php', 'tests/phpunit_coverage.php', $this->args['HTTPURI'] );
108 if ($this->args['DEBUG'] == 1)
112 protected function tear_down()
114 if ($this->args['DEBUG'] != 1)
116 $out = ob_get_clean();
117 $status = $this->getStatus();
118 if ($status == PHPUnit_Runner_BaseTestRunner::STATUS_ERROR
119 || $status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) {
125 * @param PhpXmlRpc\Request|array $msg
126 * @param int|array $errorCode
127 * @param bool $returnResponse
128 * @return mixed|\PhpXmlRpc\Response|\PhpXmlRpc\Response[]|\PhpXmlRpc\Value|string|null
130 protected function send($msg, $errorCode = 0, $returnResponse = false)
132 if ($this->collectCodeCoverageInformation) {
133 $this->client->setCookie('PHPUNIT_SELENIUM_TEST_ID', $this->testId);
136 $r = $this->client->send($msg, $this->timeout, $this->method);
137 // for multicall, return directly array of responses
141 if (is_array($errorCode)) {
142 $this->assertContains($r->faultCode(), $errorCode, 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
144 $this->assertEquals($errorCode, $r->faultCode(), 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
146 if (!$r->faultCode()) {
147 if ($returnResponse) {
158 * Adds (and replaces) query params to the url currently used by the client
161 protected function addQueryParams($data)
163 $query = parse_url($this->client->path, PHP_URL_QUERY);
164 parse_str($query, $vars);
165 $query = http_build_query(array_merge($vars, $data));
166 $this->client->path = parse_url($this->client->path, PHP_URL_PATH) . '?' . $query;
169 public function testString()
171 $sendString = "here are 3 \"entities\": < > & " .
172 "and here's a dollar sign: \$pretendvarname and a backslash too: " . chr(92) .
173 " - isn't that great? \\\"hackery\\\" at it's best " .
174 " also don't want to miss out on \$item[0]. " .
175 "The real weird stuff follows: CRLF here" . chr(13) . chr(10) .
176 "a simple CR here" . chr(13) .
177 "a simple LF here" . chr(10) .
178 "and then LFCR" . chr(10) . chr(13) .
179 "last but not least weird names: G" . chr(252) . "nter, El" . chr(232) . "ne, and an xml comment closing tag: -->";
180 $m = new xmlrpcmsg('examples.stringecho', array(
181 new xmlrpcval($sendString, 'string'),
183 $v = $this->send($m);
185 // when sending/receiving non-US-ASCII encoded strings, XML says cr-lf can be normalized.
186 // so we relax our tests...
187 $l1 = strlen($sendString);
188 $l2 = strlen($v->scalarval());
190 $this->assertEquals($sendString, $v->scalarval());
192 $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendString), $v->scalarval());
197 public function testLatin1String()
200 "last but not least weird names: G" . chr(252) . "nter, El" . chr(232) . "ne";
201 $x = '<?xml version="1.0" encoding="ISO-8859-1"?><methodCall><methodName>examples.stringecho</methodName><params><param><value>'.
203 '</value></param></params></methodCall>';
204 $v = $this->send($x);
206 $this->assertEquals($sendString, $v->scalarval());
210 public function testExoticCharsetsRequests()
212 // note that we should disable this call also when mbstring is missing server-side
213 if (!function_exists('mb_convert_encoding')) {
214 $this->markTestSkipped('Miss mbstring extension to test exotic charsets');
217 $sendString = 'κόσμε'; // Greek word 'kosme'. NB: NOT a valid ISO8859 string!
218 $str = '<?xml version="1.0" encoding="_ENC_"?>
220 <methodName>examples.stringecho</methodName>
223 <value><string>'.$sendString.'</string></value>
228 PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'UTF-8';
229 // we have to set the encoding declaration either in the http header or xml prolog, as mb_detect_encoding
230 // (used on the server side) will fail recognizing these 2 charsets
231 $v = $this->send(mb_convert_encoding(str_replace('_ENC_', 'UCS-4', $str), 'UCS-4', 'UTF-8'));
232 $this->assertEquals($sendString, $v->scalarval());
233 $v = $this->send(mb_convert_encoding(str_replace('_ENC_', 'UTF-16', $str), 'UTF-16', 'UTF-8'));
234 $this->assertEquals($sendString, $v->scalarval());
235 PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'ISO-8859-1';
238 public function testExoticCharsetsRequests2()
240 // note that we should disable this call also when mbstring is missing server-side
241 if (!function_exists('mb_convert_encoding')) {
242 $this->markTestSkipped('Miss mbstring extension to test exotic charsets');
245 $sendString = '安室奈美恵'; // No idea what this means :-) NB: NOT a valid ISO8859 string!
246 $str = '<?xml version="1.0"?>
248 <methodName>examples.stringecho</methodName>
251 <value><string>'.$sendString.'</string></value>
256 PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'UTF-8';
257 // no encoding declaration either in the http header or xml prolog, let mb_detect_encoding
258 // (used on the server side) sort it out
259 $this->addQueryParams(array('DETECT_ENCODINGS' => array('EUC-JP', 'UTF-8')));
260 $v = $this->send(mb_convert_encoding($str, 'EUC-JP', 'UTF-8'));
261 $this->assertEquals($sendString, $v->scalarval());
262 PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'ISO-8859-1';
265 public function testExoticCharsetsRequests3()
267 // note that we should disable this call also when mbstring is missing server-side
268 if (!function_exists('mb_convert_encoding')) {
269 $this->markTestSkipped('Miss mbstring extension to test exotic charsets');
272 $sendString = utf8_decode('élève');
273 $str = '<?xml version="1.0"?>
275 <methodName>examples.stringecho</methodName>
278 <value><string>'.$sendString.'</string></value>
283 // no encoding declaration either in the http header or xml prolog, let mb_detect_encoding
284 // (used on the server side) sort it out
285 $this->addQueryParams(array('DETECT_ENCODINGS' => array('ISO-8859-1', 'UTF-8')));
286 $v = $this->send($str);
287 $this->assertEquals($sendString, $v->scalarval());
290 /*public function testLatin1Method()
292 $f = new xmlrpcmsg("tests.iso88591methodname." . chr(224) . chr(252) . chr(232), array(
293 new xmlrpcval('hello')
295 $v = $this->send($f);
297 $this->assertEquals('hello', $v->scalarval());
301 public function testUtf8Method()
303 PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'UTF-8';
304 $m = new xmlrpcmsg("tests.utf8methodname." . 'κόσμε', array(
305 new xmlrpcval('hello')
307 $v = $this->send($m);
309 $this->assertEquals('hello', $v->scalarval());
311 PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'ISO-8859-1';
314 public function testAddingDoubles()
316 // note that rounding errors mean we
317 // keep precision to sensible levels here ;-)
320 $m = new xmlrpcmsg('examples.addtwodouble', array(
321 new xmlrpcval($a, 'double'),
322 new xmlrpcval($b, 'double'),
324 $v = $this->send($m);
326 $this->assertEquals($a + $b, $v->scalarval());
330 public function testAdding()
332 $m = new xmlrpcmsg('examples.addtwo', array(
333 new xmlrpcval(12, 'int'),
334 new xmlrpcval(-23, 'int'),
336 $v = $this->send($m);
338 $this->assertEquals(12 - 23, $v->scalarval());
342 public function testInvalidNumber()
344 $m = new xmlrpcmsg('examples.addtwo', array(
345 new xmlrpcval('fred', 'int'),
346 new xmlrpcval("\"; exec('ls')", 'int'),
348 $v = $this->send($m);
349 /// @todo a fault condition should be generated here
350 /// by the server, which we pick up on
352 $this->assertEquals(0, $v->scalarval());
356 public function testBoolean()
358 $m = new xmlrpcmsg('examples.invertBooleans', array(
360 new xmlrpcval(true, 'boolean'),
361 new xmlrpcval(false, 'boolean'),
362 new xmlrpcval(1, 'boolean'),
363 new xmlrpcval(0, 'boolean')
368 $v = $this->send($m);
370 $sz = $v->arraysize();
372 for ($i = 0; $i < $sz; $i++) {
373 $b = $v->arraymem($i);
374 if ($b->scalarval()) {
380 $this->assertEquals($answer, $got);
384 public function testBase64()
386 $sendString = 'Mary had a little lamb,
387 Whose fleece was white as snow,
388 And everywhere that Mary went
389 the lamb was sure to go.
391 Mary had a little lamb
392 She tied it to a pylon
393 Ten thousand volts went down its back
394 And turned it into nylon';
395 $m = new xmlrpcmsg('examples.decode64', array(
396 new xmlrpcval($sendString, 'base64'),
398 $v = $this->send($m);
400 if (strlen($sendString) == strlen($v->scalarval())) {
401 $this->assertEquals($sendString, $v->scalarval());
403 $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendString), $v->scalarval());
408 public function testDateTime()
411 $t1 = new xmlrpcval($time, 'dateTime.iso8601');
412 $t2 = new xmlrpcval(iso8601_encode($time), 'dateTime.iso8601');
413 $this->assertEquals($t1->serialize(), $t2->serialize());
414 if (class_exists('DateTime')) {
415 $datetime = new DateTime();
416 // skip this test for php 5.2. It is a bit harder there to build a DateTime from unix timestamp with proper TZ info
417 if (is_callable(array($datetime, 'setTimestamp'))) {
418 $t3 = new xmlrpcval($datetime->setTimestamp($time), 'dateTime.iso8601');
419 $this->assertEquals($t1->serialize(), $t3->serialize());
424 public function testCountEntities()
426 $sendString = "h'fd>onc>>l>>rw&bpu>q>e<v&gxs<ytjzkami<";
427 $m = new xmlrpcmsg('validator1.countTheEntities', array(
428 new xmlrpcval($sendString, 'string'),
430 $v = $this->send($m);
434 $expect_array = array('ctLeftAngleBrackets', 'ctRightAngleBrackets', 'ctAmpersands', 'ctApostrophes', 'ctQuotes');
435 foreach($expect_array as $val) {
436 $b = $v->structmem($val);
437 $got .= $b->me['int'];
439 $this->assertEquals($expected, $got);
443 public function _multicall_msg($method, $params)
445 $struct['methodName'] = new xmlrpcval($method, 'string');
446 $struct['params'] = new xmlrpcval($params, 'array');
448 return new xmlrpcval($struct, 'struct');
451 public function testServerMulticall()
453 // We manually construct a system.multicall() call to ensure
454 // that the server supports it.
456 // NB: This test will NOT pass if server does not support system.multicall.
458 // Based on http://xmlrpc-c.sourceforge.net/hacks/test_multicall.py
459 $good1 = $this->_multicall_msg(
461 array(php_xmlrpc_encode('system.listMethods')));
462 $bad = $this->_multicall_msg(
464 array(php_xmlrpc_encode(1), php_xmlrpc_encode(2)));
465 $recursive = $this->_multicall_msg(
467 array(new xmlrpcval(array(), 'array')));
468 $good2 = $this->_multicall_msg(
469 'system.methodSignature',
470 array(php_xmlrpc_encode('system.listMethods')));
471 $arg = new xmlrpcval(
472 array($good1, $bad, $recursive, $good2),
476 $m = new xmlrpcmsg('system.multicall', array($arg));
477 $v = $this->send($m);
479 //$this->assertTrue($r->faultCode() == 0, "fault from system.multicall");
480 $this->assertTrue($v->arraysize() == 4, "bad number of return values");
482 $r1 = $v->arraymem(0);
484 $r1->kindOf() == 'array' && $r1->arraysize() == 1,
485 "did not get array of size 1 from good1"
488 $r2 = $v->arraymem(1);
490 $r2->kindOf() == 'struct',
494 $r3 = $v->arraymem(2);
496 $r3->kindOf() == 'struct',
497 "recursive system.multicall did not fail"
500 $r4 = $v->arraymem(3);
502 $r4->kindOf() == 'array' && $r4->arraysize() == 1,
503 "did not get array of size 1 from good2"
508 public function testClientMulticall1()
510 // NB: This test will NOT pass if server does not support system.multicall.
512 $noMultiCall = $this->client->no_multicall;
513 $this->client->no_multicall = false;
515 $good1 = new xmlrpcmsg('system.methodHelp',
516 array(php_xmlrpc_encode('system.listMethods')));
517 $bad = new xmlrpcmsg('test.nosuch',
518 array(php_xmlrpc_encode(1), php_xmlrpc_encode(2)));
519 $recursive = new xmlrpcmsg('system.multicall',
520 array(new xmlrpcval(array(), 'array')));
521 $good2 = new xmlrpcmsg('system.methodSignature',
522 array(php_xmlrpc_encode('system.listMethods'))
525 $r = $this->send(array($good1, $bad, $recursive, $good2));
527 $this->assertTrue(count($r) == 4, "wrong number of return values");
530 $this->assertTrue($r[0]->faultCode() == 0, "fault from good1");
531 if (!$r[0]->faultCode()) {
532 $val = $r[0]->value();
534 $val->kindOf() == 'scalar' && $val->scalartyp() == 'string',
535 "good1 did not return string"
538 $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad");
539 $this->assertTrue($r[2]->faultCode() != 0, "no fault from recursive system.multicall");
540 $this->assertTrue($r[3]->faultCode() == 0, "fault from good2");
541 if (!$r[3]->faultCode()) {
542 $val = $r[3]->value();
543 $this->assertTrue($val->kindOf() == 'array', "good2 did not return array");
545 // This is the only assert in this test which should fail
546 // if the test server does not support system.multicall.
547 $this->assertTrue($this->client->no_multicall == false,
548 "server does not support system.multicall"
551 $this->client->no_multicall = $noMultiCall;
554 public function testClientMulticall2()
556 // NB: This test will NOT pass if server does not support system.multicall.
558 $noMultiCall = $this->client->no_multicall;
559 $this->client->no_multicall = true;
561 $good1 = new xmlrpcmsg('system.methodHelp',
562 array(php_xmlrpc_encode('system.listMethods')));
563 $bad = new xmlrpcmsg('test.nosuch',
564 array(php_xmlrpc_encode(1), php_xmlrpc_encode(2)));
565 $recursive = new xmlrpcmsg('system.multicall',
566 array(new xmlrpcval(array(), 'array')));
567 $good2 = new xmlrpcmsg('system.methodSignature',
568 array(php_xmlrpc_encode('system.listMethods'))
571 $r = $this->send(array($good1, $bad, $recursive, $good2));
573 $this->assertTrue(count($r) == 4, "wrong number of return values");
576 $this->assertTrue($r[0]->faultCode() == 0, "fault from good1");
577 if (!$r[0]->faultCode()) {
578 $val = $r[0]->value();
580 $val->kindOf() == 'scalar' && $val->scalartyp() == 'string',
581 "good1 did not return string");
583 $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad");
584 $this->assertTrue($r[2]->faultCode() == 0, "fault from (non recursive) system.multicall");
585 $this->assertTrue($r[3]->faultCode() == 0, "fault from good2");
586 if (!$r[3]->faultCode()) {
587 $val = $r[3]->value();
588 $this->assertTrue($val->kindOf() == 'array', "good2 did not return array");
591 $this->client->no_multicall = $noMultiCall;
594 public function testClientMulticall3()
596 // NB: This test will NOT pass if server does not support system.multicall.
598 $noMultiCall = $this->client->no_multicall;
599 $returnType = $this->client->return_type;
601 $this->client->return_type = 'phpvals';
602 $this->client->no_multicall = false;
604 $good1 = new xmlrpcmsg('system.methodHelp',
605 array(php_xmlrpc_encode('system.listMethods')));
606 $bad = new xmlrpcmsg('test.nosuch',
607 array(php_xmlrpc_encode(1), php_xmlrpc_encode(2)));
608 $recursive = new xmlrpcmsg('system.multicall',
609 array(new xmlrpcval(array(), 'array')));
610 $good2 = new xmlrpcmsg('system.methodSignature',
611 array(php_xmlrpc_encode('system.listMethods'))
614 $r = $this->send(array($good1, $bad, $recursive, $good2));
616 $this->assertTrue(count($r) == 4, "wrong number of return values");
618 $this->assertTrue($r[0]->faultCode() == 0, "fault from good1");
619 if (!$r[0]->faultCode()) {
620 $val = $r[0]->value();
622 is_string($val), "good1 did not return string");
624 $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad");
625 $this->assertTrue($r[2]->faultCode() != 0, "no fault from recursive system.multicall");
626 $this->assertTrue($r[3]->faultCode() == 0, "fault from good2");
627 if (!$r[3]->faultCode()) {
628 $val = $r[3]->value();
629 $this->assertTrue(is_array($val), "good2 did not return array");
632 $this->client->return_type = $returnType;
633 $this->client->no_multicall = $noMultiCall;
636 public function testCatchWarnings()
638 $m = new xmlrpcmsg('tests.generatePHPWarning', array(
639 new xmlrpcval('whatever', 'string'),
641 $v = $this->send($m);
643 $this->assertEquals(true, $v->scalarval());
647 public function testCatchExceptions()
649 $m = new xmlrpcmsg('tests.raiseException', array(
650 new xmlrpcval('whatever', 'string'),
652 $v = $this->send($m, $GLOBALS['xmlrpcerr']['server_error']);
653 $this->addQueryParams(array('EXCEPTION_HANDLING' => 1));
654 $v = $this->send($m, 1); // the error code of the expected exception
655 $this->addQueryParams(array('EXCEPTION_HANDLING' => 2));
656 // depending on whether display_errors is ON or OFF on the server, we will get back a different error here,
657 // as php will generate an http status code of either 200 or 500...
658 $v = $this->send($m, array($GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcerr']['http_error']));
661 public function testZeroParams()
663 $m = new xmlrpcmsg('system.listMethods');
664 $v = $this->send($m);
667 public function testNullParams()
669 $m = new xmlrpcmsg('tests.getStateName.12', array(
670 new xmlrpcval('whatever', 'null'),
671 new xmlrpcval(23, 'int'),
673 $v = $this->send($m);
675 $this->assertEquals('Michigan', $v->scalarval());
677 $m = new xmlrpcmsg('tests.getStateName.12', array(
678 new xmlrpcval(23, 'int'),
679 new xmlrpcval('whatever', 'null'),
681 $v = $this->send($m);
683 $this->assertEquals('Michigan', $v->scalarval());
685 $m = new xmlrpcmsg('tests.getStateName.12', array(
686 new xmlrpcval(23, 'int')
688 $v = $this->send($m, array($GLOBALS['xmlrpcerr']['incorrect_params']));
691 public function testCodeInjectionServerSide()
693 $m = new xmlrpcmsg('system.MethodHelp');
694 $m->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>";
695 $v = $this->send($m);
697 $this->assertEquals(0, $v->structsize());
701 public function testServerWrappedFunction()
703 $m = new xmlrpcmsg('tests.getStateName.2', array(
704 new xmlrpcval(23, 'int'),
706 $v = $this->send($m);
707 $this->assertEquals('Michigan', $v->scalarval());
709 // this generates an exception in the function which was wrapped, which is by default wrapped in a known error response
710 $m = new xmlrpcmsg('tests.getStateName.2', array(
711 new xmlrpcval(0, 'int'),
713 $v = $this->send($m, $GLOBALS['xmlrpcerr']['server_error']);
715 // check if the generated function dispatch map is fine, by checking if the server registered it
716 $m = new xmlrpcmsg('system.methodSignature', array(
717 new xmlrpcval('tests.getStateName.2'),
719 $v = $this->send($m);
720 $encoder = new \PhpXmlRpc\Encoder();
721 $this->assertEquals(array(array('string', 'int')), $encoder->decode($v));
724 public function testServerWrappedFunctionAsSource()
726 $m = new xmlrpcmsg('tests.getStateName.6', array(
727 new xmlrpcval(23, 'int'),
729 $v = $this->send($m);
730 $this->assertEquals('Michigan', $v->scalarval());
732 // this generates an exception in the function which was wrapped, which is by default wrapped in a known error response
733 $m = new xmlrpcmsg('tests.getStateName.6', array(
734 new xmlrpcval(0, 'int'),
736 $v = $this->send($m, $GLOBALS['xmlrpcerr']['server_error']);
739 public function testServerWrappedObjectMethods()
741 $m = new xmlrpcmsg('tests.getStateName.3', array(
742 new xmlrpcval(23, 'int'),
744 $v = $this->send($m);
745 $this->assertEquals('Michigan', $v->scalarval());
747 $m = new xmlrpcmsg('tests.getStateName.4', array(
748 new xmlrpcval(23, 'int'),
750 $v = $this->send($m);
751 $this->assertEquals('Michigan', $v->scalarval());
753 $m = new xmlrpcmsg('tests.getStateName.5', array(
754 new xmlrpcval(23, 'int'),
756 $v = $this->send($m);
757 $this->assertEquals('Michigan', $v->scalarval());
759 $m = new xmlrpcmsg('tests.getStateName.7', array(
760 new xmlrpcval(23, 'int'),
762 $v = $this->send($m);
763 $this->assertEquals('Michigan', $v->scalarval());
765 $m = new xmlrpcmsg('tests.getStateName.8', array(
766 new xmlrpcval(23, 'int'),
768 $v = $this->send($m);
769 $this->assertEquals('Michigan', $v->scalarval());
771 $m = new xmlrpcmsg('tests.getStateName.9', array(
772 new xmlrpcval(23, 'int'),
774 $v = $this->send($m);
775 $this->assertEquals('Michigan', $v->scalarval());
778 public function testServerWrappedObjectMethodsAsSource()
780 $m = new xmlrpcmsg('tests.getStateName.7', array(
781 new xmlrpcval(23, 'int'),
783 $v = $this->send($m);
784 $this->assertEquals('Michigan', $v->scalarval());
786 $m = new xmlrpcmsg('tests.getStateName.8', array(
787 new xmlrpcval(23, 'int'),
789 $v = $this->send($m);
790 $this->assertEquals('Michigan', $v->scalarval());
792 $m = new xmlrpcmsg('tests.getStateName.9', array(
793 new xmlrpcval(23, 'int'),
795 $v = $this->send($m);
796 $this->assertEquals('Michigan', $v->scalarval());
799 public function testServerClosure()
801 $m = new xmlrpcmsg('tests.getStateName.10', array(
802 new xmlrpcval(23, 'int'),
804 $v = $this->send($m);
805 $this->assertEquals('Michigan', $v->scalarval());
808 public function testServerWrappedClosure()
810 $m = new xmlrpcmsg('tests.getStateName.11', array(
811 new xmlrpcval(23, 'int'),
813 $v = $this->send($m);
814 $this->assertEquals('Michigan', $v->scalarval());
817 public function testServerWrappedClass()
819 $m = new xmlrpcmsg('tests.xmlrpcServerMethodsContainer.findState', array(
820 new xmlrpcval(23, 'int'),
822 $v = $this->send($m);
823 $this->assertEquals('Michigan', $v->scalarval());
826 public function testWrappedMethod()
828 // make a 'deep client copy' as the original one might have many properties set
829 $func = wrap_xmlrpc_method($this->client, 'examples.getStateName', array('simple_client_copy' => 0));
830 if ($func == false) {
831 $this->fail('Registration of examples.getStateName failed');
834 // work around bug in current (or old?) version of phpunit when reporting the error
835 /*if (is_object($v)) {
836 $v = var_export($v, true);
838 $this->assertEquals('Michigan', $v);
842 public function testWrappedMethodAsSource()
844 // make a 'deep client copy' as the original one might have many properties set
845 $func = wrap_xmlrpc_method($this->client, 'examples.getStateName', array('simple_client_copy' => 0, 'return_source' => true));
846 if ($func == false) {
847 $this->fail('Registration of examples.getStateName failed');
849 eval($func['source']);
850 $func = $func['function'];
852 // work around bug in current (or old?) version of phpunit when reporting the error
853 /*if (is_object($v)) {
854 $v = var_export($v, true);
856 $this->assertEquals('Michigan', $v);
860 public function testWrappedClass()
862 // make a 'deep client copy' as the original one might have many properties set
863 // also for speed only wrap one method of the whole server
864 $class = wrap_xmlrpc_server($this->client, array('simple_client_copy' => 0, 'method_filter' => '/examples\.getStateName/' ));
866 $this->fail('Registration of remote server failed');
869 if (!is_callable(array($obj, 'examples_getStateName'))) {
870 $this->fail('Registration of remote server failed to import method "examples_getStateName"');
872 $v = $obj->examples_getStateName(23);
873 // work around bug in current (or old?) version of phpunit when reporting the error
874 /*if (is_object($v)) {
875 $v = var_export($v, true);
877 $this->assertEquals('Michigan', $v);
882 public function testTransferOfObjectViaWrapping()
884 // make a 'deep client copy' as the original one might have many properties set
885 $func = wrap_xmlrpc_method($this->client, 'tests.returnPhpObject', array('simple_client_copy' => 0,
886 'decode_php_objs' => true));
887 if ($func == false) {
888 $this->fail('Registration of tests.returnPhpObject failed');
891 $obj = new stdClass();
892 $obj->hello = 'world';
893 $this->assertEquals($obj, $v);
897 public function testGetCookies()
899 // let server set to us some cookies we tell it
902 'c2' => array('value' => 'c2'),
903 'c3' => array('value' => 'c3', 'expires' => time() + 60 * 60 * 24 * 30),
904 'c4' => array('value' => 'c4', 'expires' => time() + 60 * 60 * 24 * 30, 'path' => '/'),
905 'c5' => array('value' => 'c5', 'expires' => time() + 60 * 60 * 24 * 30, 'path' => '/', 'domain' => 'localhost'),
907 $cookiesval = php_xmlrpc_encode($cookies);
908 $m = new xmlrpcmsg('examples.setcookies', array($cookiesval));
909 $r = $this->send($m, 0, true);
912 $this->assertEquals(1, $v->scalarval());
913 // now check if we decoded the cookies as we had set them
914 $rcookies = $r->cookies();
915 // remove extra cookies which might have been set by proxies
916 foreach ($rcookies as $c => $v) {
917 if (!in_array($c, array('c2', 'c3', 'c4', 'c5'))) {
918 unset($rcookies[$c]);
920 // Seems like we get this when using php-fpm and php 5.5+ ...
921 if (isset($rcookies[$c]['Max-Age'])) {
922 unset($rcookies[$c]['Max-Age']);
925 foreach ($cookies as $c => $v) {
926 // format for date string in cookies: 'Mon, 31 Oct 2005 13:50:56 GMT'
927 // but PHP versions differ on that, some use 'Mon, 31-Oct-2005 13:50:56 GMT'...
928 if (isset($v['expires'])) {
929 if (isset($rcookies[$c]['expires']) && strpos($rcookies[$c]['expires'], '-')) {
930 $cookies[$c]['expires'] = gmdate('D, d\-M\-Y H:i:s \G\M\T', $cookies[$c]['expires']);
932 $cookies[$c]['expires'] = gmdate('D, d M Y H:i:s \G\M\T', $cookies[$c]['expires']);
937 $this->assertEquals($cookies, $rcookies);
941 public function testSetCookies()
943 // let server set to us some cookies we tell it
948 'c3' => '!@#$%^&*()_+|}{":?><,./\';[]\\=-',
950 $m = new xmlrpcmsg('examples.getcookies', array());
951 foreach ($cookies as $cookie => $val) {
952 $this->client->setCookie($cookie, $val);
953 $cookies[$cookie] = (string)$cookies[$cookie];
955 $r = $this->client->send($m, $this->timeout, $this->method);
956 $this->assertEquals(0, $r->faultCode(), 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
957 if (!$r->faultCode()) {
959 $v = php_xmlrpc_decode($v);
961 // take care for the extra cookie used for coverage collection
962 if (isset($v['PHPUNIT_SELENIUM_TEST_ID'])) {
963 unset($v['PHPUNIT_SELENIUM_TEST_ID']);
966 // on IIS and Apache getallheaders returns something slightly different...
967 $this->assertEquals($cookies, $v);
971 public function testServerComments()
973 $m = new xmlrpcmsg('tests.xmlrpcServerMethodsContainer.debugMessageGenerator', array(
974 new xmlrpcval('hello world', 'string'),
976 $r = $this->send($m, 0, true);
977 $this->assertStringContainsString('hello world', $r->raw_data);
980 public function testSendTwiceSameMsg()
982 $m = new xmlrpcmsg('examples.stringecho', array(
983 new xmlrpcval('hello world', 'string'),
985 $v1 = $this->send($m);
986 $v2 = $this->send($m);
988 $this->assertEquals($v1, $v2);