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 function testMinusOneString()
12 $v = new xmlrpcval('-1');
13 $u = new xmlrpcval('-1', 'string');
14 $t = new xmlrpcval(-1, 'string');
15 $this->assertEquals($u->scalarval(), $v->scalarval());
16 $this->assertEquals($t->scalarval(), $v->scalarval());
20 * This looks funny, and we might call it a bug. But we strive for 100 backwards compat...
22 public function testMinusOneInt()
24 $v = new xmlrpcval(-1);
26 $this->assertEquals($u->scalarval(), $v->scalarval());
29 public function testUnicodeInMemberName()
31 $str = "G" . chr(252) . "nter, El" . chr(232) . "ne";
32 $v = array($str => new xmlrpcval(1));
33 $r = new xmlrpcresp(new xmlrpcval($v, 'struct'));
35 $m = new xmlrpcmsg('dummy');
36 $r = $m->parseResponse($r);
38 $this->assertEquals($v->structmemexists($str), true);
41 public function testUnicodeInErrorString()
43 $response = utf8_encode(
44 '<?xml version="1.0"?>
46 <!-- found by G. giunta, covers what happens when lib receives
47 UTF8 chars in response text and comments -->
48 <!-- ' . chr(224) . chr(252) . chr(232) . 'àüè -->
54 <name>faultCode</name>
55 <value><int>888</int></value>
58 <name>faultString</name>
59 <value><string>' . chr(224) . chr(252) . chr(232) . 'àüè</string></value>
65 $m = new xmlrpcmsg('dummy');
66 $r = $m->parseResponse($response);
67 $v = $r->faultString();
68 $this->assertEquals(chr(224) . chr(252) . chr(232) . chr(224) . chr(252) . chr(232), $v);
71 public function testValidNumbers()
73 $m = new xmlrpcmsg('dummy');
75 '<?xml version="1.0"?>
83 <value><int>01</int></value>
87 <value><double>01.10</double></value>
91 <value><int>+1</int></value>
95 <value><double>+1.10</double></value>
99 <value><double>-1.10e2</double></value>
106 $r = $m->parseResponse($fp);
108 $s = $v->structmem('integer1');
109 $t = $v->structmem('float1');
110 $u = $v->structmem('integer2');
111 $w = $v->structmem('float2');
112 $x = $v->structmem('float3');
113 $this->assertEquals(1, $s->scalarval());
114 $this->assertEquals(1.1, $t->scalarval());
115 $this->assertEquals(1, $u->scalarval());
116 $this->assertEquals(1.1, $w->scalarval());
117 $this->assertEquals(-110.0, $x->scalarval());
120 public function testAddScalarToStruct()
122 $v = new xmlrpcval(array('a' => 'b'), 'struct');
123 // use @ operator in case error_log gets on screen
124 $r = @$v->addscalar('c');
125 $this->assertEquals(0, $r);
128 public function testAddStructToStruct()
130 $v = new xmlrpcval(array('a' => new xmlrpcval('b')), 'struct');
131 $r = $v->addstruct(array('b' => new xmlrpcval('c')));
132 $this->assertEquals(2, $v->structsize());
133 $this->assertEquals(1, $r);
134 $r = $v->addstruct(array('b' => new xmlrpcval('b')));
135 $this->assertEquals(2, $v->structsize());
138 public function testAddArrayToArray()
140 $v = new xmlrpcval(array(new xmlrpcval('a'), new xmlrpcval('b')), 'array');
141 $r = $v->addarray(array(new xmlrpcval('b'), new xmlrpcval('c')));
142 $this->assertEquals(4, $v->arraysize());
143 $this->assertEquals(1, $r);
146 public function testEncodeArray()
149 $v = php_xmlrpc_encode($r);
150 $this->assertEquals('array', $v->kindof());
153 public function testEncodeRecursive()
155 $v = php_xmlrpc_encode(php_xmlrpc_encode('a simple string'));
156 $this->assertEquals('scalar', $v->kindof());
159 public function testBrokenRequests()
161 $s = new xmlrpc_server();
162 // omitting the 'params' tag: not tolerated by the lib anymore
163 $f = '<?xml version="1.0"?>
165 <methodName>system.methodHelp</methodName>
167 <value><string>system.methodHelp</string></value>
170 $r = $s->parserequest($f);
171 $this->assertEquals(15, $r->faultCode());
172 // omitting a 'param' tag
173 $f = '<?xml version="1.0"?>
175 <methodName>system.methodHelp</methodName>
177 <value><string>system.methodHelp</string></value>
180 $r = $s->parserequest($f);
181 $this->assertEquals(15, $r->faultCode());
182 // omitting a 'value' tag
183 $f = '<?xml version="1.0"?>
185 <methodName>system.methodHelp</methodName>
187 <param><string>system.methodHelp</string></param>
190 $r = $s->parserequest($f);
191 $this->assertEquals(15, $r->faultCode());
194 public function testBrokenResponses()
196 $m = new xmlrpcmsg('dummy');
198 // omitting the 'params' tag: no more tolerated by the lib...
199 $f = '<?xml version="1.0"?>
202 <value><string>system.methodHelp</string></value>
205 $r = $m->parseResponse($f);
206 $this->assertEquals(2, $r->faultCode());
207 // omitting the 'param' tag: no more tolerated by the lib...
208 $f = '<?xml version="1.0"?>
211 <value><string>system.methodHelp</string></value>
214 $r = $m->parseResponse($f);
215 $this->assertEquals(2, $r->faultCode());
216 // omitting a 'value' tag: KO
217 $f = '<?xml version="1.0"?>
220 <param><string>system.methodHelp</string></param>
223 $r = $m->parseResponse($f);
224 $this->assertEquals(2, $r->faultCode());
227 public function testBuggyHttp()
229 $s = new xmlrpcmsg('dummy');
230 $f = 'HTTP/1.1 100 Welcome to the jungle
233 X-Content-Marx-Brothers: Harpo
235 Content-Length: who knows?
239 <?xml version="1.0"?>
240 <!-- First of all, let\'s check out if the lib properly handles a commented </methodResponse> tag... -->
241 <methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
242 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
245 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
246 <script type="text\javascript">document.write(\'Hello, my name is added nag, I\\\'m happy to serve your content for free\');</script>
248 $r = $s->parseResponse($f);
250 $s = $v->structmem('content');
251 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
254 public function testStringBug()
256 $s = new xmlrpcmsg('dummy');
257 $f = '<?xml version="1.0"?>
259 <!-- found by 2z69xks7bpy001@sneakemail.com, amongst others
260 covers what happens when there\'s character data after </string>
261 and before </value> -->
274 <name>sessionID</name>
276 <string>S300510007I</string>
284 $r = $s->parseResponse($f);
286 $s = $v->structmem('sessionID');
287 $this->assertEquals('S300510007I', $s->scalarval());
290 public function testWhiteSpace()
292 $s = new xmlrpcmsg('dummy');
293 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
294 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
297 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
299 $r = $s->parseResponse($f);
301 $s = $v->structmem('content');
302 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
305 public function testDoubleDataInArrayTag()
307 $s = new xmlrpcmsg('dummy');
308 $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
311 </array></value></param></params></methodResponse>
313 $r = $s->parseResponse($f);
314 $v = $r->faultCode();
315 $this->assertEquals(2, $v);
316 $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
317 <data><value>Hello world</value></data>
319 </array></value></param></params></methodResponse>
321 $r = $s->parseResponse($f);
322 $v = $r->faultCode();
323 $this->assertEquals(2, $v);
326 public function testDoubleStuffInValueTag()
328 $s = new xmlrpcmsg('dummy');
329 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
330 <string>hello world</string>
331 <array><data></data></array>
332 </value></param></params></methodResponse>
334 $r = $s->parseResponse($f);
335 $v = $r->faultCode();
336 $this->assertEquals(2, $v);
337 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
338 <string>hello</string>
339 <string>world</string>
340 </value></param></params></methodResponse>
342 $r = $s->parseResponse($f);
343 $v = $r->faultCode();
344 $this->assertEquals(2, $v);
345 $f = '<?xml version="1.0"?><methodResponse><params><param><value>
346 <string>hello</string>
347 <struct><member><name>hello><value>world</value></member></struct>
348 </value></param></params></methodResponse>
350 $r = $s->parseResponse($f);
351 $v = $r->faultCode();
352 $this->assertEquals(2, $v);
355 public function testAutodecodeResponse()
357 $s = new xmlrpcmsg('dummy');
358 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
359 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
362 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
364 $r = $s->parseResponse($f, true, 'phpvals');
367 $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s);
370 public function testNoDecodeResponse()
372 $s = new xmlrpcmsg('dummy');
373 $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
374 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
377 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>';
378 $r = $s->parseResponse($f, true, 'xml');
380 $this->assertEquals($f, $v);
383 public function testAutoCoDec()
385 $data1 = array(1, 1.0, 'hello world', true, '20051021T23:43:00', -1, 11.0, '~!@#$%^&*()_+|', false, '20051021T23:43:00');
386 $data2 = array('zero' => $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1);
387 $data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2);
388 //$keys = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine');
389 $v1 = php_xmlrpc_encode($data, array('auto_dates'));
390 $v2 = php_xmlrpc_decode_xml($v1->serialize());
391 $this->assertEquals($v1, $v2);
392 $r1 = new PhpXmlRpc\Response($v1);
393 $r2 = php_xmlrpc_decode_xml($r1->serialize());
394 $r2->serialize(); // needed to set internal member payload
395 $this->assertEquals($r1, $r2);
396 $m1 = new PhpXmlRpc\Request('hello dolly', array($v1));
397 $m2 = php_xmlrpc_decode_xml($m1->serialize());
398 $m2->serialize(); // needed to set internal member payload
399 $this->assertEquals($m1, $m2);
402 public function testUTF8Request()
404 $sendstring = 'κόσμε'; // Greek word 'kosme'. NB: NOT a valid ISO8859 string!
405 $GLOBALS['xmlrpc_internalencoding'] = 'UTF-8';
406 \PhpXmlRpc\PhpXmlRpc::importGlobals();
407 $f = new xmlrpcval($sendstring, 'string');
408 $v = $f->serialize();
409 $this->assertEquals("<value><string>κόσμε</string></value>\n", $v);
410 $GLOBALS['xmlrpc_internalencoding'] = 'ISO-8859-1';
411 \PhpXmlRpc\PhpXmlRpc::importGlobals();
414 public function testUTF8Response()
416 $s = new xmlrpcmsg('dummy');
417 $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>
418 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>' . utf8_encode('������') . '</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
420 $r = $s->parseResponse($f, false, 'phpvals');
423 $this->assertEquals("������", $v);
424 $f = '<?xml version="1.0" encoding="utf-8"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
425 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>' . utf8_encode('������') . '</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
427 $r = $s->parseResponse($f, false, 'phpvals');
430 $this->assertEquals("������", $v);
433 public function testUTF8IntString()
435 $v = new xmlrpcval(100, 'int');
436 $s = $v->serialize('UTF-8');
437 $this->assertequals("<value><int>100</int></value>\n", $s);
440 public function testStringInt()
442 $v = new xmlrpcval('hello world', 'int');
443 $s = $v->serialize();
444 $this->assertequals("<value><int>0</int></value>\n", $s);
447 public function testStructMemExists()
449 $v = php_xmlrpc_encode(array('hello' => 'world'));
450 $b = $v->structmemexists('hello');
451 $this->assertequals(true, $b);
452 $b = $v->structmemexists('world');
453 $this->assertequals(false, $b);
456 public function testNilvalue()
458 // default case: we do not accept nil values received
459 $v = new xmlrpcval('hello', 'null');
460 $r = new xmlrpcresp($v);
461 $s = $r->serialize();
462 $m = new xmlrpcmsg('dummy');
463 $r = $m->parseresponse($s);
464 $this->assertequals(2, $r->faultCode());
465 // enable reception of nil values
466 $GLOBALS['xmlrpc_null_extension'] = true;
467 \PhpXmlRpc\PhpXmlRpc::importGlobals();
468 $r = $m->parseresponse($s);
470 $this->assertequals('null', $v->scalartyp());
471 // test with the apache version: EX:NIL
472 $GLOBALS['xmlrpc_null_apache_encoding'] = true;
473 \PhpXmlRpc\PhpXmlRpc::importGlobals();
475 $v = new xmlrpcval('hello', 'null');
476 $s = $v->serialize();
477 $this->assertequals(1, preg_match('#<value><ex:nil/></value>#', $s));
479 $r = new xmlrpcresp($v);
480 $s = $r->serialize();
481 $r = $m->parseresponse($s);
483 $this->assertequals('null', $v->scalartyp());
484 $GLOBALS['xmlrpc_null_extension'] = false;
485 \PhpXmlRpc\PhpXmlRpc::importGlobals();
486 $r = $m->parseresponse($s);
487 $this->assertequals(2, $r->faultCode());
490 public function TestLocale()
492 $locale = setlocale(LC_NUMERIC, 0);
493 /// @todo on php 5.3/win setting locale to german does not seem to set decimal separator to comma...
494 if (setlocale(LC_NUMERIC, 'deu', 'de_DE@euro', 'de_DE', 'de', 'ge') !== false) {
495 $v = new xmlrpcval(1.1, 'double');
496 if (strpos($v->scalarval(), ',') == 1) {
497 $r = $v->serialize();
498 $this->assertequals(false, strpos($r, ','));
499 setlocale(LC_NUMERIC, $locale);
501 setlocale(LC_NUMERIC, $locale);
502 $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
505 $this->markTestSkipped('did not find a locale which sets decimal separator to comma');