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';
8 class ParsingBugsTests extends PHPUnit_Framework_TestCase
10 public $args = array();
12 protected function setUp()
14 $this->args = argParser::getArgs();
15 if ($this->args['DEBUG'] == 1)
19 protected function tearDown()
21 if ($this->args['DEBUG'] != 1)
23 $out = ob_get_clean();
24 $status = $this->getStatus();
25 if ($status == PHPUnit_Runner_BaseTestRunner::STATUS_ERROR
26 || $status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) {
31 protected function newMsg($methodName, $params = array())
33 $msg = new xmlrpcmsg($methodName, $params);
34 $msg->setDebug($this->args['DEBUG']);
38 public function testMinusOneString()
40 $v = new xmlrpcval('-1');
41 $u = new xmlrpcval('-1', 'string');
42 $t = new xmlrpcval(-1, 'string');
43 $this->assertEquals($v->scalarval(), $u->scalarval());
44 $this->assertEquals($v->scalarval(), $t->scalarval());
48 * This looks funny, and we might call it a bug. But we strive for 100 backwards compat...
50 public function testMinusOneInt()
53 $v = new xmlrpcval(-1);
54 $this->assertEquals($u->scalarval(), $v->scalarval());
57 public function testUnicodeInMemberName()
59 $str = "G" . chr(252) . "nter, El" . chr(232) . "ne";
60 $v = array($str => new xmlrpcval(1));
61 $r = new xmlrpcresp(new xmlrpcval($v, 'struct'));
63 $m = $this->newMsg('dummy');
64 $r = $m->parseResponse($r);
66 $this->assertEquals(true, $v->structmemexists($str));
69 public function testUnicodeInErrorString()
71 $response = utf8_encode(
72 '<?xml version="1.0"?>
74 <!-- found by G. giunta, covers what happens when lib receives
75 UTF8 chars in response text and comments -->
76 <!-- ' . chr(224) . chr(252) . chr(232) . 'àüè -->
82 <name>faultCode</name>
83 <value><int>888</int></value>
86 <name>faultString</name>
87 <value><string>' . chr(224) . chr(252) . chr(232) . 'àüè</string></value>
93 $m = $this->newMsg('dummy');
94 $r = $m->parseResponse($response);
95 $v = $r->faultString();
96 $this->assertEquals(chr(224) . chr(252) . chr(232) . chr(224) . chr(252) . chr(232), $v);
99 public function testValidNumbers()
101 $m = $this->newMsg('dummy');
103 '<?xml version="1.0"?>
110 <name>integer1</name>
111 <value><int>01</int></value>
115 <value><double>01.10</double></value>
118 <name>integer2</name>
119 <value><int>+1</int></value>
123 <value><double>+1.10</double></value>
127 <value><double>-1.10e2</double></value>
134 $r = $m->parseResponse($fp);
136 $s = $v->structmem('integer1');
137 $t = $v->structmem('float1');
138 $u = $v->structmem('integer2');
139 $w = $v->structmem('float2');
140 $x = $v->structmem('float3');
141 $this->assertEquals(1, $s->scalarval());
142 $this->assertEquals(1.1, $t->scalarval());
143 $this->assertEquals(1, $u->scalarval());
144 $this->assertEquals(1.1, $w->scalarval());
145 $this->assertEquals(-110.0, $x->scalarval());
148 public function testAddScalarToStruct()
150 $v = new xmlrpcval(array('a' => 'b'), 'struct');
151 // use @ operator in case error_log gets on screen
152 $r = @$v->addscalar('c');
153 $this->assertEquals(0, $r);
156 public function testAddStructToStruct()
158 $v = new xmlrpcval(array('a' => new xmlrpcval('b')), 'struct');
159 $r = $v->addstruct(array('b' => new xmlrpcval('c')));
160 $this->assertEquals(2, $v->structsize());
161 $this->assertEquals(1, $r);
162 $r = $v->addstruct(array('b' => new xmlrpcval('b')));
163 $this->assertEquals(2, $v->structsize());
166 public function testAddArrayToArray()
168 $v = new xmlrpcval(array(new xmlrpcval('a'), new xmlrpcval('b')), 'array');
169 $r = $v->addarray(array(new xmlrpcval('b'), new xmlrpcval('c')));
170 $this->assertEquals(4, $v->arraysize());
171 $this->assertEquals(1, $r);
174 public function testEncodeArray()
177 $v = php_xmlrpc_encode($r);
178 $this->assertEquals('array', $v->kindof());
181 public function testEncodeRecursive()
183 $v = php_xmlrpc_encode(php_xmlrpc_encode('a simple string'));
184 $this->assertEquals('scalar', $v->kindof());
187 public function testBrokenRequests()
189 $s = new xmlrpc_server();
190 // omitting the 'params' tag: not tolerated by the lib anymore
191 $f = '<?xml version="1.0"?>
193 <methodName>system.methodHelp</methodName>
195 <value><string>system.methodHelp</string></value>
198 $r = $s->parserequest($f);
199 $this->assertEquals(15, $r->faultCode());
200 // omitting a 'param' tag
201 $f = '<?xml version="1.0"?>
203 <methodName>system.methodHelp</methodName>
205 <value><string>system.methodHelp</string></value>
208 $r = $s->parserequest($f);
209 $this->assertEquals(15, $r->faultCode());
210 // omitting a 'value' tag
211 $f = '<?xml version="1.0"?>
213 <methodName>system.methodHelp</methodName>
215 <param><string>system.methodHelp</string></param>
218 $r = $s->parserequest($f);
219 $this->assertEquals(15, $r->faultCode());
222 public function testBrokenResponses()
224 $m = $this->newMsg('dummy');
225 // omitting the 'params' tag: no more tolerated by the lib...
226 $f = '<?xml version="1.0"?>
229 <value><string>system.methodHelp</string></value>
232 $r = $m->parseResponse($f);
233 $this->assertEquals(2, $r->faultCode());
234 // omitting the 'param' tag: no more tolerated by the lib...
235 $f = '<?xml version="1.0"?>
238 <value><string>system.methodHelp</string></value>
241 $r = $m->parseResponse($f);
242 $this->assertEquals(2, $r->faultCode());
243 // omitting a 'value' tag: KO
244 $f = '<?xml version="1.0"?>
247 <param><string>system.methodHelp</string></param>
250 $r = $m->parseResponse($f);
251 $this->assertEquals(2, $r->faultCode());
254 public function testBuggyHttp()
256 $s = $this->newMsg('dummy');
257 $f = 'HTTP/1.1 100 Welcome to the jungle
260 X-Content-Marx-Brothers: Harpo
262 Content-Length: who knows?
266 <?xml version="1.0"?>
267 <!-- First of all, let\'s check out if the lib properly handles a commented </methodResponse> tag... -->
268 <methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
269 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
272 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
273 <script type="text\javascript">document.write(\'Hello, my name is added nag, I\\\'m happy to serve your content for free\');</script>
275 $r = $s->parseResponse($f);
277 $s = $v->structmem('content');
278 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
281 public function testStringBug()
283 $s = $this->newMsg('dummy');
284 $f = '<?xml version="1.0"?>
286 <!-- found by 2z69xks7bpy001@sneakemail.com, amongst others
287 covers what happens when there\'s character data after </string>
288 and before </value> -->
301 <name>sessionID</name>
303 <string>S300510007I</string>
311 $r = $s->parseResponse($f);
313 $s = $v->structmem('sessionID');
314 $this->assertEquals('S300510007I', $s->scalarval());
317 public function testWhiteSpace()
319 $s = $this->newMsg('dummy');
320 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
321 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
324 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
326 $r = $s->parseResponse($f);
328 $s = $v->structmem('content');
329 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
332 public function testDoubleDataInArrayTag()
334 $s = $this->newMsg('dummy');
335 $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
338 </array></value></param></params></methodResponse>
340 $r = $s->parseResponse($f);
341 $v = $r->faultCode();
342 $this->assertEquals(2, $v);
343 $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
344 <data><value>Hello world</value></data>
346 </array></value></param></params></methodResponse>
348 $r = $s->parseResponse($f);
349 $v = $r->faultCode();
350 $this->assertEquals(2, $v);
353 public function testDoubleStuffInValueTag()
355 $s = $this->newMsg('dummy');
356 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
357 <string>hello world</string>
358 <array><data></data></array>
359 </value></param></params></methodResponse>
361 $r = $s->parseResponse($f);
362 $v = $r->faultCode();
363 $this->assertEquals(2, $v);
364 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
365 <string>hello</string>
366 <string>world</string>
367 </value></param></params></methodResponse>
369 $r = $s->parseResponse($f);
370 $v = $r->faultCode();
371 $this->assertEquals(2, $v);
372 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
373 <string>hello</string>
374 <struct><member><name>hello><value>world</value></member></struct>
375 </value></param></params></methodResponse>
377 $r = $s->parseResponse($f);
378 $v = $r->faultCode();
379 $this->assertEquals(2, $v);
382 public function testAutodecodeResponse()
384 $s = $this->newMsg('dummy');
385 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
386 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
389 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
391 $r = $s->parseResponse($f, true, 'phpvals');
394 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s);
397 public function testNoDecodeResponse()
399 $s = $this->newMsg('dummy');
400 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
401 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
404 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>';
405 $r = $s->parseResponse($f, true, 'xml');
407 $this->assertEquals($f, $v);
410 public function testAutoCoDec()
412 $data1 = array(1, 1.0, 'hello world', true, '20051021T23:43:00', -1, 11.0, '~!@#$%^&*()_+|', false, '20051021T23:43:00');
413 $data2 = array('zero' => $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1);
414 $data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2);
415 //$keys = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine');
416 $v1 = php_xmlrpc_encode($data, array('auto_dates'));
417 $v2 = php_xmlrpc_decode_xml($v1->serialize());
418 $this->assertEquals($v1, $v2);
419 $r1 = new PhpXmlRpc\Response($v1);
420 $r2 = php_xmlrpc_decode_xml($r1->serialize());
421 $r2->serialize(); // needed to set internal member payload
422 $this->assertEquals($r1, $r2);
423 $m1 = new PhpXmlRpc\Request('hello dolly', array($v1));
424 $m2 = php_xmlrpc_decode_xml($m1->serialize());
425 $m2->serialize(); // needed to set internal member payload
426 $this->assertEquals($m1, $m2);
429 public function testUTF8Request()
431 $sendstring = 'κόσμε'; // Greek word 'kosme'. NB: NOT a valid ISO8859 string!
432 $GLOBALS['xmlrpc_internalencoding'] = 'UTF-8';
433 \PhpXmlRpc\PhpXmlRpc::importGlobals();
434 $f = new xmlrpcval($sendstring, 'string');
435 $v = $f->serialize();
436 $this->assertEquals("<value><string>κόσμε</string></value>\n", $v);
437 $GLOBALS['xmlrpc_internalencoding'] = 'ISO-8859-1';
438 \PhpXmlRpc\PhpXmlRpc::importGlobals();
441 public function testUTF8Response()
443 $string = chr(224) . chr(252) . chr(232);
445 $s = $this->newMsg('dummy');
446 $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>
447 <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>
449 $r = $s->parseResponse($f, false, 'phpvals');
452 $this->assertEquals($string, $v);
454 $f = '<?xml version="1.0" encoding="UTF-8"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
455 <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>
457 $r = $s->parseResponse($f, false, 'phpvals');
460 $this->assertEquals($string, $v);
462 $r = php_xmlrpc_decode_xml($f);
464 $v = $v->structmem('content')->scalarval();
465 $this->assertEquals($string, $v);
468 public function testLatin1Response()
470 $string = chr(224) . chr(252) . chr(232);
472 $s = $this->newMsg('dummy');
473 $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>
474 <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>
476 $r = $s->parseResponse($f, false, 'phpvals');
479 $this->assertEquals($string, $v);
481 $f = '<?xml version="1.0" encoding="ISO-8859-1"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
482 <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>
484 $r = $s->parseResponse($f, false, 'phpvals');
487 $this->assertEquals($string, $v);
489 $r = php_xmlrpc_decode_xml($f);
491 $v = $v->structmem('content')->scalarval();
492 $this->assertEquals($string, $v);
495 public function testUTF8IntString()
497 $v = new xmlrpcval(100, 'int');
498 $s = $v->serialize('UTF-8');
499 $this->assertequals("<value><int>100</int></value>\n", $s);
502 public function testStringInt()
504 $v = new xmlrpcval('hello world', 'int');
505 $s = $v->serialize();
506 $this->assertequals("<value><int>0</int></value>\n", $s);
509 public function testStructMemExists()
511 $v = php_xmlrpc_encode(array('hello' => 'world'));
512 $b = $v->structmemexists('hello');
513 $this->assertequals(true, $b);
514 $b = $v->structmemexists('world');
515 $this->assertequals(false, $b);
518 public function testNilvalue()
520 // default case: we do not accept nil values received
521 $v = new xmlrpcval('hello', 'null');
522 $r = new xmlrpcresp($v);
523 $s = $r->serialize();
524 $m = $this->newMsg('dummy');
525 $r = $m->parseresponse($s);
526 $this->assertequals(2, $r->faultCode());
527 // enable reception of nil values
528 $GLOBALS['xmlrpc_null_extension'] = true;
529 \PhpXmlRpc\PhpXmlRpc::importGlobals();
530 $r = $m->parseresponse($s);
532 $this->assertequals('null', $v->scalartyp());
533 // test with the apache version: EX:NIL
534 $GLOBALS['xmlrpc_null_apache_encoding'] = true;
535 \PhpXmlRpc\PhpXmlRpc::importGlobals();
537 $v = new xmlrpcval('hello', 'null');
538 $s = $v->serialize();
539 $this->assertequals(1, preg_match('#<value><ex:nil/></value>#', $s));
541 $r = new xmlrpcresp($v);
542 $s = $r->serialize();
543 $r = $m->parseresponse($s);
545 $this->assertequals('null', $v->scalartyp());
546 $GLOBALS['xmlrpc_null_extension'] = false;
547 \PhpXmlRpc\PhpXmlRpc::importGlobals();
548 $r = $m->parseresponse($s);
549 $this->assertequals(2, $r->faultCode());
552 public function TestLocale()
554 $locale = setlocale(LC_NUMERIC, 0);
555 /// @todo on php 5.3/win setting locale to german does not seem to set decimal separator to comma...
556 if (setlocale(LC_NUMERIC, 'deu', 'de_DE@euro', 'de_DE', 'de', 'ge') !== false) {
557 $v = new xmlrpcval(1.1, 'double');
558 if (strpos($v->scalarval(), ',') == 1) {
559 $r = $v->serialize();
560 $this->assertequals(false, strpos($r, ','));
561 setlocale(LC_NUMERIC, $locale);
563 setlocale(LC_NUMERIC, $locale);
564 $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
567 $this->markTestSkipped('did not find a locale which sets decimal separator to comma');