0868a91815fcc5f71e81045d9f992fb5e286df26
[plcapi.git] / tests / 1ParsingBugsTest.php
1 <?php
2 /**
3  * NB: do not let your IDE fool you. The correct encoding for this file is NOT UTF8.
4  */
5 include_once __DIR__ . '/../lib/xmlrpc.inc';
6 include_once __DIR__ . '/../lib/xmlrpcs.inc';
7
8 class ParsingBugsTests extends PHPUnit_Framework_TestCase
9 {
10     public function testMinusOneString()
11     {
12         $v = new xmlrpcval('-1');
13         $u = new xmlrpcval('-1', 'string');
14         $this->assertEquals($u->scalarval(), $v->scalarval());
15     }
16
17     public function testMinusOneInt()
18     {
19         $v = new xmlrpcval(-1);
20         $u = new xmlrpcval(-1, 'string');
21         $this->assertEquals($u->scalarval(), $v->scalarval());
22     }
23
24     public function testUnicodeInMemberName()
25     {
26         $str = "G" . chr(252) . "nter, El" . chr(232) . "ne";
27         $v = array($str => new xmlrpcval(1));
28         $r = new xmlrpcresp(new xmlrpcval($v, 'struct'));
29         $r = $r->serialize();
30         $m = new xmlrpcmsg('dummy');
31         $r = $m->parseResponse($r);
32         $v = $r->value();
33         $this->assertEquals($v->structmemexists($str), true);
34     }
35
36     public function testUnicodeInErrorString()
37     {
38         $response = utf8_encode(
39             '<?xml version="1.0"?>
40 <!-- $Id -->
41 <!-- found by G. giunta, covers what happens when lib receives
42   UTF8 chars in response text and comments -->
43 <!-- ' . chr(224) . chr(252) . chr(232) . '&#224;&#252;&#232; -->
44 <methodResponse>
45 <fault>
46 <value>
47 <struct>
48 <member>
49 <name>faultCode</name>
50 <value><int>888</int></value>
51 </member>
52 <member>
53 <name>faultString</name>
54 <value><string>' . chr(224) . chr(252) . chr(232) . '&#224;&#252;&#232;</string></value>
55 </member>
56 </struct>
57 </value>
58 </fault>
59 </methodResponse>');
60         $m = new xmlrpcmsg('dummy');
61         $r = $m->parseResponse($response);
62         $v = $r->faultString();
63         $this->assertEquals(chr(224) . chr(252) . chr(232) . chr(224) . chr(252) . chr(232), $v);
64     }
65
66     public function testValidNumbers()
67     {
68         $m = new xmlrpcmsg('dummy');
69         $fp =
70             '<?xml version="1.0"?>
71 <methodResponse>
72 <params>
73 <param>
74 <value>
75 <struct>
76 <member>
77 <name>integer1</name>
78 <value><int>01</int></value>
79 </member>
80 <member>
81 <name>float1</name>
82 <value><double>01.10</double></value>
83 </member>
84 <member>
85 <name>integer2</name>
86 <value><int>+1</int></value>
87 </member>
88 <member>
89 <name>float2</name>
90 <value><double>+1.10</double></value>
91 </member>
92 <member>
93 <name>float3</name>
94 <value><double>-1.10e2</double></value>
95 </member>
96 </struct>
97 </value>
98 </param>
99 </params>
100 </methodResponse>';
101         $r = $m->parseResponse($fp);
102         $v = $r->value();
103         $s = $v->structmem('integer1');
104         $t = $v->structmem('float1');
105         $u = $v->structmem('integer2');
106         $w = $v->structmem('float2');
107         $x = $v->structmem('float3');
108         $this->assertEquals(1, $s->scalarval());
109         $this->assertEquals(1.1, $t->scalarval());
110         $this->assertEquals(1, $u->scalarval());
111         $this->assertEquals(1.1, $w->scalarval());
112         $this->assertEquals(-110.0, $x->scalarval());
113     }
114
115     public function testAddScalarToStruct()
116     {
117         $v = new xmlrpcval(array('a' => 'b'), 'struct');
118         // use @ operator in case error_log gets on screen
119         $r = @$v->addscalar('c');
120         $this->assertEquals(0, $r);
121     }
122
123     public function testAddStructToStruct()
124     {
125         $v = new xmlrpcval(array('a' => new xmlrpcval('b')), 'struct');
126         $r = $v->addstruct(array('b' => new xmlrpcval('c')));
127         $this->assertEquals(2, $v->structsize());
128         $this->assertEquals(1, $r);
129         $r = $v->addstruct(array('b' => new xmlrpcval('b')));
130         $this->assertEquals(2, $v->structsize());
131     }
132
133     public function testAddArrayToArray()
134     {
135         $v = new xmlrpcval(array(new xmlrpcval('a'), new xmlrpcval('b')), 'array');
136         $r = $v->addarray(array(new xmlrpcval('b'), new xmlrpcval('c')));
137         $this->assertEquals(4, $v->arraysize());
138         $this->assertEquals(1, $r);
139     }
140
141     public function testEncodeArray()
142     {
143         $r = range(1, 100);
144         $v = php_xmlrpc_encode($r);
145         $this->assertEquals('array', $v->kindof());
146     }
147
148     public function testEncodeRecursive()
149     {
150         $v = php_xmlrpc_encode(php_xmlrpc_encode('a simple string'));
151         $this->assertEquals('scalar', $v->kindof());
152     }
153
154     public function testBrokenRequests()
155     {
156         $s = new xmlrpc_server();
157         // omitting the 'params' tag: not tolerated by the lib anymore
158         $f = '<?xml version="1.0"?>
159 <methodCall>
160 <methodName>system.methodHelp</methodName>
161 <param>
162 <value><string>system.methodHelp</string></value>
163 </param>
164 </methodCall>';
165         $r = $s->parserequest($f);
166         $this->assertEquals(15, $r->faultCode());
167         // omitting a 'param' tag
168         $f = '<?xml version="1.0"?>
169 <methodCall>
170 <methodName>system.methodHelp</methodName>
171 <params>
172 <value><string>system.methodHelp</string></value>
173 </params>
174 </methodCall>';
175         $r = $s->parserequest($f);
176         $this->assertEquals(15, $r->faultCode());
177         // omitting a 'value' tag
178         $f = '<?xml version="1.0"?>
179 <methodCall>
180 <methodName>system.methodHelp</methodName>
181 <params>
182 <param><string>system.methodHelp</string></param>
183 </params>
184 </methodCall>';
185         $r = $s->parserequest($f);
186         $this->assertEquals(15, $r->faultCode());
187     }
188
189     public function testBrokenResponses()
190     {
191         $m = new xmlrpcmsg('dummy');
192         //$m->debug = 1;
193         // omitting the 'params' tag: no more tolerated by the lib...
194         $f = '<?xml version="1.0"?>
195 <methodResponse>
196 <param>
197 <value><string>system.methodHelp</string></value>
198 </param>
199 </methodResponse>';
200         $r = $m->parseResponse($f);
201         $this->assertEquals(2, $r->faultCode());
202         // omitting the 'param' tag: no more tolerated by the lib...
203         $f = '<?xml version="1.0"?>
204 <methodResponse>
205 <params>
206 <value><string>system.methodHelp</string></value>
207 </params>
208 </methodResponse>';
209         $r = $m->parseResponse($f);
210         $this->assertEquals(2, $r->faultCode());
211         // omitting a 'value' tag: KO
212         $f = '<?xml version="1.0"?>
213 <methodResponse>
214 <params>
215 <param><string>system.methodHelp</string></param>
216 </params>
217 </methodResponse>';
218         $r = $m->parseResponse($f);
219         $this->assertEquals(2, $r->faultCode());
220     }
221
222     public function testBuggyHttp()
223     {
224         $s = new xmlrpcmsg('dummy');
225         $f = 'HTTP/1.1 100 Welcome to the jungle
226
227 HTTP/1.0 200 OK
228 X-Content-Marx-Brothers: Harpo
229         Chico and Groucho
230 Content-Length: who knows?
231
232
233
234 <?xml version="1.0"?>
235 <!-- First of all, let\'s check out if the lib properly handles a commented </methodResponse> tag... -->
236 <methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
237 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
238
239
240 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
241 <script type="text\javascript">document.write(\'Hello, my name is added nag, I\\\'m happy to serve your content for free\');</script>
242  ';
243         $r = $s->parseResponse($f);
244         $v = $r->value();
245         $s = $v->structmem('content');
246         $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
247     }
248
249     public function testStringBug()
250     {
251         $s = new xmlrpcmsg('dummy');
252         $f = '<?xml version="1.0"?>
253 <!-- $Id -->
254 <!-- found by 2z69xks7bpy001@sneakemail.com, amongst others
255  covers what happens when there\'s character data after </string>
256  and before </value> -->
257 <methodResponse>
258 <params>
259 <param>
260 <value>
261 <struct>
262 <member>
263 <name>success</name>
264 <value>
265 <boolean>1</boolean>
266 </value>
267 </member>
268 <member>
269 <name>sessionID</name>
270 <value>
271 <string>S300510007I</string>
272 </value>
273 </member>
274 </struct>
275 </value>
276 </param>
277 </params>
278 </methodResponse> ';
279         $r = $s->parseResponse($f);
280         $v = $r->value();
281         $s = $v->structmem('sessionID');
282         $this->assertEquals('S300510007I', $s->scalarval());
283     }
284
285     public function testWhiteSpace()
286     {
287         $s = new xmlrpcmsg('dummy');
288         $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
289 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
290
291
292 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
293 ';
294         $r = $s->parseResponse($f);
295         $v = $r->value();
296         $s = $v->structmem('content');
297         $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
298     }
299
300     public function testDoubleDataInArrayTag()
301     {
302         $s = new xmlrpcmsg('dummy');
303         $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
304 <data></data>
305 <data></data>
306 </array></value></param></params></methodResponse>
307 ';
308         $r = $s->parseResponse($f);
309         $v = $r->faultCode();
310         $this->assertEquals(2, $v);
311         $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
312 <data><value>Hello world</value></data>
313 <data></data>
314 </array></value></param></params></methodResponse>
315 ';
316         $r = $s->parseResponse($f);
317         $v = $r->faultCode();
318         $this->assertEquals(2, $v);
319     }
320
321     public function testDoubleStuffInValueTag()
322     {
323         $s = new xmlrpcmsg('dummy');
324         $f = '<?xml version="1.0"?><methodResponse><params><param><value>
325 <string>hello world</string>
326 <array><data></data></array>
327 </value></param></params></methodResponse>
328 ';
329         $r = $s->parseResponse($f);
330         $v = $r->faultCode();
331         $this->assertEquals(2, $v);
332         $f = '<?xml version="1.0"?><methodResponse><params><param><value>
333 <string>hello</string>
334 <string>world</string>
335 </value></param></params></methodResponse>
336 ';
337         $r = $s->parseResponse($f);
338         $v = $r->faultCode();
339         $this->assertEquals(2, $v);
340         $f = '<?xml version="1.0"?><methodResponse><params><param><value>
341 <string>hello</string>
342 <struct><member><name>hello><value>world</value></member></struct>
343 </value></param></params></methodResponse>
344 ';
345         $r = $s->parseResponse($f);
346         $v = $r->faultCode();
347         $this->assertEquals(2, $v);
348     }
349
350     public function testAutodecodeResponse()
351     {
352         $s = new xmlrpcmsg('dummy');
353         $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
354 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
355
356
357 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
358 ';
359         $r = $s->parseResponse($f, true, 'phpvals');
360         $v = $r->value();
361         $s = $v['content'];
362         $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s);
363     }
364
365     public function testNoDecodeResponse()
366     {
367         $s = new xmlrpcmsg('dummy');
368         $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
369 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
370
371
372 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>';
373         $r = $s->parseResponse($f, true, 'xml');
374         $v = $r->value();
375         $this->assertEquals($f, $v);
376     }
377
378     public function testAutoCoDec()
379     {
380         $data1 = array(1, 1.0, 'hello world', true, '20051021T23:43:00', -1, 11.0, '~!@#$%^&*()_+|', false, '20051021T23:43:00');
381         $data2 = array('zero' => $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1);
382         $data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2);
383         //$keys = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine');
384         $v1 = php_xmlrpc_encode($data, array('auto_dates'));
385         $v2 = php_xmlrpc_decode_xml($v1->serialize());
386         $this->assertEquals($v1, $v2);
387         $r1 = new PhpXmlRpc\Response($v1);
388         $r2 = php_xmlrpc_decode_xml($r1->serialize());
389         $r2->serialize(); // needed to set internal member payload
390         $this->assertEquals($r1, $r2);
391         $m1 = new PhpXmlRpc\Request('hello dolly', array($v1));
392         $m2 = php_xmlrpc_decode_xml($m1->serialize());
393         $m2->serialize(); // needed to set internal member payload
394         $this->assertEquals($m1, $m2);
395     }
396
397     public function testUTF8Request()
398     {
399         $sendstring = 'κόσμε'; // Greek word 'kosme'. NB: NOT a valid ISO8859 string!
400         $GLOBALS['xmlrpc_internalencoding'] = 'UTF-8';
401         \PhpXmlRpc\PhpXmlRpc::importGlobals();
402         $f = new xmlrpcval($sendstring, 'string');
403         $v = $f->serialize();
404         $this->assertEquals("<value><string>&#954;&#8057;&#963;&#956;&#949;</string></value>\n", $v);
405         $GLOBALS['xmlrpc_internalencoding'] = 'ISO-8859-1';
406         \PhpXmlRpc\PhpXmlRpc::importGlobals();
407     }
408
409     public function testUTF8Response()
410     {
411         $s = new xmlrpcmsg('dummy');
412         $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>
413 <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>
414 ';
415         $r = $s->parseResponse($f, false, 'phpvals');
416         $v = $r->value();
417         $v = $v['content'];
418         $this->assertEquals("������", $v);
419         $f = '<?xml version="1.0" encoding="utf-8"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
420 <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>
421 ';
422         $r = $s->parseResponse($f, false, 'phpvals');
423         $v = $r->value();
424         $v = $v['content'];
425         $this->assertEquals("������", $v);
426     }
427
428     public function testUTF8IntString()
429     {
430         $v = new xmlrpcval(100, 'int');
431         $s = $v->serialize('UTF-8');
432         $this->assertequals("<value><int>100</int></value>\n", $s);
433     }
434
435     public function testStringInt()
436     {
437         $v = new xmlrpcval('hello world', 'int');
438         $s = $v->serialize();
439         $this->assertequals("<value><int>0</int></value>\n", $s);
440     }
441
442     public function testStructMemExists()
443     {
444         $v = php_xmlrpc_encode(array('hello' => 'world'));
445         $b = $v->structmemexists('hello');
446         $this->assertequals(true, $b);
447         $b = $v->structmemexists('world');
448         $this->assertequals(false, $b);
449     }
450
451     public function testNilvalue()
452     {
453         // default case: we do not accept nil values received
454         $v = new xmlrpcval('hello', 'null');
455         $r = new xmlrpcresp($v);
456         $s = $r->serialize();
457         $m = new xmlrpcmsg('dummy');
458         $r = $m->parseresponse($s);
459         $this->assertequals(2, $r->faultCode());
460         // enable reception of nil values
461         $GLOBALS['xmlrpc_null_extension'] = true;
462         \PhpXmlRpc\PhpXmlRpc::importGlobals();
463         $r = $m->parseresponse($s);
464         $v = $r->value();
465         $this->assertequals('null', $v->scalartyp());
466         // test with the apache version: EX:NIL
467         $GLOBALS['xmlrpc_null_apache_encoding'] = true;
468         \PhpXmlRpc\PhpXmlRpc::importGlobals();
469         // serialization
470         $v = new xmlrpcval('hello', 'null');
471         $s = $v->serialize();
472         $this->assertequals(1, preg_match('#<value><ex:nil/></value>#', $s));
473         // deserialization
474         $r = new xmlrpcresp($v);
475         $s = $r->serialize();
476         $r = $m->parseresponse($s);
477         $v = $r->value();
478         $this->assertequals('null', $v->scalartyp());
479         $GLOBALS['xmlrpc_null_extension'] = false;
480         \PhpXmlRpc\PhpXmlRpc::importGlobals();
481         $r = $m->parseresponse($s);
482         $this->assertequals(2, $r->faultCode());
483     }
484
485     public function TestLocale()
486     {
487         $locale = setlocale(LC_NUMERIC, 0);
488         /// @todo on php 5.3/win setting locale to german does not seem to set decimal separator to comma...
489         if (setlocale(LC_NUMERIC, 'deu', 'de_DE@euro', 'de_DE', 'de', 'ge') !== false) {
490             $v = new xmlrpcval(1.1, 'double');
491             if (strpos($v->scalarval(), ',') == 1) {
492                 $r = $v->serialize();
493                 $this->assertequals(false, strpos($r, ','));
494                 setlocale(LC_NUMERIC, $locale);
495             } else {
496                 setlocale(LC_NUMERIC, $locale);
497                 $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
498             }
499         } else {
500             $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
501         }
502     }
503 }