3 * NB: do not let your IDE fool you. The correct encoding for this file is NOT UTF8.
5 include_once __DIR__ . '/../lib/xmlrpc.inc';
6 include_once __DIR__ . '/../lib/xmlrpcs.inc';
9 * Tests involving parsing of xml and handling of xmlrpc values
11 class ParsingBugsTests extends PHPUnit_Framework_TestCase
13 public $args = array();
15 protected function setUp()
17 $this->args = argParser::getArgs();
18 if ($this->args['DEBUG'] == 1)
22 protected function tearDown()
24 if ($this->args['DEBUG'] != 1)
26 $out = ob_get_clean();
27 $status = $this->getStatus();
28 if ($status == PHPUnit_Runner_BaseTestRunner::STATUS_ERROR
29 || $status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) {
34 protected function newMsg($methodName, $params = array())
36 $msg = new xmlrpcmsg($methodName, $params);
37 $msg->setDebug($this->args['DEBUG']);
41 public function testMinusOneString()
43 $v = new xmlrpcval('-1');
44 $u = new xmlrpcval('-1', 'string');
45 $t = new xmlrpcval(-1, 'string');
46 $this->assertEquals($v->scalarval(), $u->scalarval());
47 $this->assertEquals($v->scalarval(), $t->scalarval());
51 * This looks funny, and we might call it a bug. But we strive for 100 backwards compat...
53 public function testMinusOneInt()
56 $v = new xmlrpcval(-1);
57 $this->assertEquals($u->scalarval(), $v->scalarval());
60 public function testUnicodeInMemberName()
62 $str = "G" . chr(252) . "nter, El" . chr(232) . "ne";
63 $v = array($str => new xmlrpcval(1));
64 $r = new xmlrpcresp(new xmlrpcval($v, 'struct'));
66 $m = $this->newMsg('dummy');
67 $r = $m->parseResponse($r);
69 $this->assertEquals(true, $v->structmemexists($str));
72 public function testUnicodeInErrorString()
74 $response = utf8_encode(
75 '<?xml version="1.0"?>
77 <!-- found by G. giunta, covers what happens when lib receives
78 UTF8 chars in response text and comments -->
79 <!-- ' . chr(224) . chr(252) . chr(232) . 'àüè -->
85 <name>faultCode</name>
86 <value><int>888</int></value>
89 <name>faultString</name>
90 <value><string>' . chr(224) . chr(252) . chr(232) . 'àüè</string></value>
96 $m = $this->newMsg('dummy');
97 $r = $m->parseResponse($response);
98 $v = $r->faultString();
99 $this->assertEquals(chr(224) . chr(252) . chr(232) . chr(224) . chr(252) . chr(232), $v);
102 public function testValidNumbers()
104 $m = $this->newMsg('dummy');
106 '<?xml version="1.0"?>
113 <name>integer1</name>
114 <value><int>01</int></value>
118 <value><double>01.10</double></value>
121 <name>integer2</name>
122 <value><int>+1</int></value>
126 <value><double>+1.10</double></value>
130 <value><double>-1.10e2</double></value>
137 $r = $m->parseResponse($fp);
139 $s = $v->structmem('integer1');
140 $t = $v->structmem('float1');
141 $u = $v->structmem('integer2');
142 $w = $v->structmem('float2');
143 $x = $v->structmem('float3');
144 $this->assertEquals(1, $s->scalarval());
145 $this->assertEquals(1.1, $t->scalarval());
146 $this->assertEquals(1, $u->scalarval());
147 $this->assertEquals(1.1, $w->scalarval());
148 $this->assertEquals(-110.0, $x->scalarval());
151 public function testAddScalarToStruct()
153 $v = new xmlrpcval(array('a' => 'b'), 'struct');
154 // use @ operator in case error_log gets on screen
155 $r = @$v->addscalar('c');
156 $this->assertEquals(0, $r);
159 public function testAddStructToStruct()
161 $v = new xmlrpcval(array('a' => new xmlrpcval('b')), 'struct');
162 $r = $v->addstruct(array('b' => new xmlrpcval('c')));
163 $this->assertEquals(2, $v->structsize());
164 $this->assertEquals(1, $r);
165 $r = $v->addstruct(array('b' => new xmlrpcval('b')));
166 $this->assertEquals(2, $v->structsize());
169 public function testAddArrayToArray()
171 $v = new xmlrpcval(array(new xmlrpcval('a'), new xmlrpcval('b')), 'array');
172 $r = $v->addarray(array(new xmlrpcval('b'), new xmlrpcval('c')));
173 $this->assertEquals(4, $v->arraysize());
174 $this->assertEquals(1, $r);
177 public function testEncodeArray()
180 $v = php_xmlrpc_encode($r);
181 $this->assertEquals('array', $v->kindof());
184 public function testEncodeRecursive()
186 $v = php_xmlrpc_encode(php_xmlrpc_encode('a simple string'));
187 $this->assertEquals('scalar', $v->kindof());
190 public function testBrokenRequests()
192 $s = new xmlrpc_server();
193 // omitting the 'params' tag: not tolerated by the lib anymore
194 $f = '<?xml version="1.0"?>
196 <methodName>system.methodHelp</methodName>
198 <value><string>system.methodHelp</string></value>
201 $r = $s->parserequest($f);
202 $this->assertEquals(15, $r->faultCode());
203 // omitting a 'param' tag
204 $f = '<?xml version="1.0"?>
206 <methodName>system.methodHelp</methodName>
208 <value><string>system.methodHelp</string></value>
211 $r = $s->parserequest($f);
212 $this->assertEquals(15, $r->faultCode());
213 // omitting a 'value' tag
214 $f = '<?xml version="1.0"?>
216 <methodName>system.methodHelp</methodName>
218 <param><string>system.methodHelp</string></param>
221 $r = $s->parserequest($f);
222 $this->assertEquals(15, $r->faultCode());
225 public function testBrokenResponses()
227 $m = $this->newMsg('dummy');
228 // omitting the 'params' tag: no more tolerated by the lib...
229 $f = '<?xml version="1.0"?>
232 <value><string>system.methodHelp</string></value>
235 $r = $m->parseResponse($f);
236 $this->assertEquals(2, $r->faultCode());
237 // omitting the 'param' tag: no more tolerated by the lib...
238 $f = '<?xml version="1.0"?>
241 <value><string>system.methodHelp</string></value>
244 $r = $m->parseResponse($f);
245 $this->assertEquals(2, $r->faultCode());
246 // omitting a 'value' tag: KO
247 $f = '<?xml version="1.0"?>
250 <param><string>system.methodHelp</string></param>
253 $r = $m->parseResponse($f);
254 $this->assertEquals(2, $r->faultCode());
257 public function testBuggyHttp()
259 $s = $this->newMsg('dummy');
260 $f = 'HTTP/1.1 100 Welcome to the jungle
263 X-Content-Marx-Brothers: Harpo
265 Content-Length: who knows?
269 <?xml version="1.0"?>
270 <!-- First of all, let\'s check out if the lib properly handles a commented </methodResponse> tag... -->
271 <methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
272 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
275 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
276 <script type="text\javascript">document.write(\'Hello, my name is added nag, I\\\'m happy to serve your content for free\');</script>
278 $r = $s->parseResponse($f);
280 $s = $v->structmem('content');
281 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
284 public function testStringBug()
286 $s = $this->newMsg('dummy');
287 $f = '<?xml version="1.0"?>
289 <!-- found by 2z69xks7bpy001@sneakemail.com, amongst others
290 covers what happens when there\'s character data after </string>
291 and before </value> -->
304 <name>sessionID</name>
306 <string>S300510007I</string>
314 $r = $s->parseResponse($f);
316 $s = $v->structmem('sessionID');
317 $this->assertEquals('S300510007I', $s->scalarval());
320 public function testWhiteSpace()
322 $s = $this->newMsg('dummy');
323 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
324 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
327 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
329 $r = $s->parseResponse($f);
331 $s = $v->structmem('content');
332 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
335 public function testDoubleDataInArrayTag()
337 $s = $this->newMsg('dummy');
338 $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
341 </array></value></param></params></methodResponse>
343 $r = $s->parseResponse($f);
344 $v = $r->faultCode();
345 $this->assertEquals(2, $v);
346 $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
347 <data><value>Hello world</value></data>
349 </array></value></param></params></methodResponse>
351 $r = $s->parseResponse($f);
352 $v = $r->faultCode();
353 $this->assertEquals(2, $v);
356 public function testDoubleStuffInValueTag()
358 $s = $this->newMsg('dummy');
359 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
360 <string>hello world</string>
361 <array><data></data></array>
362 </value></param></params></methodResponse>
364 $r = $s->parseResponse($f);
365 $v = $r->faultCode();
366 $this->assertEquals(2, $v);
367 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
368 <string>hello</string>
369 <string>world</string>
370 </value></param></params></methodResponse>
372 $r = $s->parseResponse($f);
373 $v = $r->faultCode();
374 $this->assertEquals(2, $v);
375 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
376 <string>hello</string>
377 <struct><member><name>hello><value>world</value></member></struct>
378 </value></param></params></methodResponse>
380 $r = $s->parseResponse($f);
381 $v = $r->faultCode();
382 $this->assertEquals(2, $v);
385 public function testAutodecodeResponse()
387 $s = $this->newMsg('dummy');
388 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
389 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
392 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
394 $r = $s->parseResponse($f, true, 'phpvals');
397 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s);
400 public function testNoDecodeResponse()
402 $s = $this->newMsg('dummy');
403 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
404 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
407 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>';
408 $r = $s->parseResponse($f, true, 'xml');
410 $this->assertEquals($f, $v);
413 public function testAutoCoDec()
415 $data1 = array(1, 1.0, 'hello world', true, '20051021T23:43:00', -1, 11.0, '~!@#$%^&*()_+|', false, '20051021T23:43:00');
416 $data2 = array('zero' => $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1);
417 $data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2);
418 //$keys = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine');
419 $v1 = php_xmlrpc_encode($data, array('auto_dates'));
420 $v2 = php_xmlrpc_decode_xml($v1->serialize());
421 $this->assertEquals($v1, $v2);
422 $r1 = new PhpXmlRpc\Response($v1);
423 $r2 = php_xmlrpc_decode_xml($r1->serialize());
424 $r2->serialize(); // needed to set internal member payload
425 $this->assertEquals($r1, $r2);
426 $m1 = new PhpXmlRpc\Request('hello dolly', array($v1));
427 $m2 = php_xmlrpc_decode_xml($m1->serialize());
428 $m2->serialize(); // needed to set internal member payload
429 $this->assertEquals($m1, $m2);
432 public function testUTF8Request()
434 $sendstring = 'κόσμε'; // Greek word 'kosme'. NB: NOT a valid ISO8859 string!
435 $GLOBALS['xmlrpc_internalencoding'] = 'UTF-8';
436 \PhpXmlRpc\PhpXmlRpc::importGlobals();
437 $f = new xmlrpcval($sendstring, 'string');
438 $v = $f->serialize();
439 $this->assertEquals("<value><string>κόσμε</string></value>\n", $v);
440 $GLOBALS['xmlrpc_internalencoding'] = 'ISO-8859-1';
441 \PhpXmlRpc\PhpXmlRpc::importGlobals();
444 public function testUTF8Response()
446 $string = chr(224) . chr(252) . chr(232);
448 $s = $this->newMsg('dummy');
449 $f = "HTTP/1.1 200 OK\r\nContent-type: text/xml; charset=UTF-8\r\n\r\n" . '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
450 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>' . utf8_encode($string) . '</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
452 $r = $s->parseResponse($f, false, 'phpvals');
455 $this->assertEquals($string, $v);
457 $f = '<?xml version="1.0" encoding="UTF-8"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
458 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>' . utf8_encode($string) . '</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
460 $r = $s->parseResponse($f, false, 'phpvals');
463 $this->assertEquals($string, $v);
465 $r = php_xmlrpc_decode_xml($f);
467 $v = $v->structmem('content')->scalarval();
468 $this->assertEquals($string, $v);
471 public function testLatin1Response()
473 $string = chr(224) . chr(252) . chr(232);
475 $s = $this->newMsg('dummy');
476 $f = "HTTP/1.1 200 OK\r\nContent-type: text/xml; charset=ISO-8859-1\r\n\r\n" . '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
477 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>' . $string . '</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
479 $r = $s->parseResponse($f, false, 'phpvals');
482 $this->assertEquals($string, $v);
484 $f = '<?xml version="1.0" encoding="ISO-8859-1"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
485 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>' . $string . '</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
487 $r = $s->parseResponse($f, false, 'phpvals');
490 $this->assertEquals($string, $v);
492 $r = php_xmlrpc_decode_xml($f);
494 $v = $v->structmem('content')->scalarval();
495 $this->assertEquals($string, $v);
498 public function testUTF8IntString()
500 $v = new xmlrpcval(100, 'int');
501 $s = $v->serialize('UTF-8');
502 $this->assertequals("<value><int>100</int></value>\n", $s);
505 public function testStringInt()
507 $v = new xmlrpcval('hello world', 'int');
508 $s = $v->serialize();
509 $this->assertequals("<value><int>0</int></value>\n", $s);
512 public function testStructMemExists()
514 $v = php_xmlrpc_encode(array('hello' => 'world'));
515 $b = $v->structmemexists('hello');
516 $this->assertequals(true, $b);
517 $b = $v->structmemexists('world');
518 $this->assertequals(false, $b);
521 public function testNilvalue()
523 // default case: we do not accept nil values received
524 $v = new xmlrpcval('hello', 'null');
525 $r = new xmlrpcresp($v);
526 $s = $r->serialize();
527 $m = $this->newMsg('dummy');
528 $r = $m->parseresponse($s);
529 $this->assertequals(2, $r->faultCode());
530 // enable reception of nil values
531 $GLOBALS['xmlrpc_null_extension'] = true;
532 \PhpXmlRpc\PhpXmlRpc::importGlobals();
533 $r = $m->parseresponse($s);
535 $this->assertequals('null', $v->scalartyp());
536 // test with the apache version: EX:NIL
537 $GLOBALS['xmlrpc_null_apache_encoding'] = true;
538 \PhpXmlRpc\PhpXmlRpc::importGlobals();
540 $v = new xmlrpcval('hello', 'null');
541 $s = $v->serialize();
542 $this->assertequals(1, preg_match('#<value><ex:nil/></value>#', $s));
544 $r = new xmlrpcresp($v);
545 $s = $r->serialize();
546 $r = $m->parseresponse($s);
548 $this->assertequals('null', $v->scalartyp());
549 $GLOBALS['xmlrpc_null_extension'] = false;
550 \PhpXmlRpc\PhpXmlRpc::importGlobals();
551 $r = $m->parseresponse($s);
552 $this->assertequals(2, $r->faultCode());
555 public function TestLocale()
557 $locale = setlocale(LC_NUMERIC, 0);
558 /// @todo on php 5.3/win setting locale to german does not seem to set decimal separator to comma...
559 if (setlocale(LC_NUMERIC, 'deu', 'de_DE@euro', 'de_DE', 'de', 'ge') !== false) {
560 $v = new xmlrpcval(1.1, 'double');
561 if (strpos($v->scalarval(), ',') == 1) {
562 $r = $v->serialize();
563 $this->assertequals(false, strpos($r, ','));
564 setlocale(LC_NUMERIC, $locale);
566 setlocale(LC_NUMERIC, $locale);
567 $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
570 $this->markTestSkipped('did not find a locale which sets decimal separator to comma');