Make latin-1 tests more ide-proof
[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         $t = new xmlrpcval(-1, 'string');
15         $this->assertEquals($u->scalarval(), $v->scalarval());
16         $this->assertEquals($t->scalarval(), $v->scalarval());
17     }
18
19     /**
20      * This looks funny, and we might call it a bug. But we strive for 100 backwards compat...
21      */
22     public function testMinusOneInt()
23     {
24         $v = new xmlrpcval(-1);
25         $u = new xmlrpcval();
26         $this->assertEquals($u->scalarval(), $v->scalarval());
27     }
28
29     public function testUnicodeInMemberName()
30     {
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'));
34         $r = $r->serialize();
35         $m = new xmlrpcmsg('dummy');
36         $r = $m->parseResponse($r);
37         $v = $r->value();
38         $this->assertEquals($v->structmemexists($str), true);
39     }
40
41     public function testUnicodeInErrorString()
42     {
43         $response = utf8_encode(
44             '<?xml version="1.0"?>
45 <!-- $Id -->
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) . '&#224;&#252;&#232; -->
49 <methodResponse>
50 <fault>
51 <value>
52 <struct>
53 <member>
54 <name>faultCode</name>
55 <value><int>888</int></value>
56 </member>
57 <member>
58 <name>faultString</name>
59 <value><string>' . chr(224) . chr(252) . chr(232) . '&#224;&#252;&#232;</string></value>
60 </member>
61 </struct>
62 </value>
63 </fault>
64 </methodResponse>');
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);
69     }
70
71     public function testValidNumbers()
72     {
73         $m = new xmlrpcmsg('dummy');
74         $fp =
75             '<?xml version="1.0"?>
76 <methodResponse>
77 <params>
78 <param>
79 <value>
80 <struct>
81 <member>
82 <name>integer1</name>
83 <value><int>01</int></value>
84 </member>
85 <member>
86 <name>float1</name>
87 <value><double>01.10</double></value>
88 </member>
89 <member>
90 <name>integer2</name>
91 <value><int>+1</int></value>
92 </member>
93 <member>
94 <name>float2</name>
95 <value><double>+1.10</double></value>
96 </member>
97 <member>
98 <name>float3</name>
99 <value><double>-1.10e2</double></value>
100 </member>
101 </struct>
102 </value>
103 </param>
104 </params>
105 </methodResponse>';
106         $r = $m->parseResponse($fp);
107         $v = $r->value();
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());
118     }
119
120     public function testAddScalarToStruct()
121     {
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);
126     }
127
128     public function testAddStructToStruct()
129     {
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());
136     }
137
138     public function testAddArrayToArray()
139     {
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);
144     }
145
146     public function testEncodeArray()
147     {
148         $r = range(1, 100);
149         $v = php_xmlrpc_encode($r);
150         $this->assertEquals('array', $v->kindof());
151     }
152
153     public function testEncodeRecursive()
154     {
155         $v = php_xmlrpc_encode(php_xmlrpc_encode('a simple string'));
156         $this->assertEquals('scalar', $v->kindof());
157     }
158
159     public function testBrokenRequests()
160     {
161         $s = new xmlrpc_server();
162         // omitting the 'params' tag: not tolerated by the lib anymore
163         $f = '<?xml version="1.0"?>
164 <methodCall>
165 <methodName>system.methodHelp</methodName>
166 <param>
167 <value><string>system.methodHelp</string></value>
168 </param>
169 </methodCall>';
170         $r = $s->parserequest($f);
171         $this->assertEquals(15, $r->faultCode());
172         // omitting a 'param' tag
173         $f = '<?xml version="1.0"?>
174 <methodCall>
175 <methodName>system.methodHelp</methodName>
176 <params>
177 <value><string>system.methodHelp</string></value>
178 </params>
179 </methodCall>';
180         $r = $s->parserequest($f);
181         $this->assertEquals(15, $r->faultCode());
182         // omitting a 'value' tag
183         $f = '<?xml version="1.0"?>
184 <methodCall>
185 <methodName>system.methodHelp</methodName>
186 <params>
187 <param><string>system.methodHelp</string></param>
188 </params>
189 </methodCall>';
190         $r = $s->parserequest($f);
191         $this->assertEquals(15, $r->faultCode());
192     }
193
194     public function testBrokenResponses()
195     {
196         $m = new xmlrpcmsg('dummy');
197         //$m->debug = 1;
198         // omitting the 'params' tag: no more tolerated by the lib...
199         $f = '<?xml version="1.0"?>
200 <methodResponse>
201 <param>
202 <value><string>system.methodHelp</string></value>
203 </param>
204 </methodResponse>';
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"?>
209 <methodResponse>
210 <params>
211 <value><string>system.methodHelp</string></value>
212 </params>
213 </methodResponse>';
214         $r = $m->parseResponse($f);
215         $this->assertEquals(2, $r->faultCode());
216         // omitting a 'value' tag: KO
217         $f = '<?xml version="1.0"?>
218 <methodResponse>
219 <params>
220 <param><string>system.methodHelp</string></param>
221 </params>
222 </methodResponse>';
223         $r = $m->parseResponse($f);
224         $this->assertEquals(2, $r->faultCode());
225     }
226
227     public function testBuggyHttp()
228     {
229         $s = new xmlrpcmsg('dummy');
230         $f = 'HTTP/1.1 100 Welcome to the jungle
231
232 HTTP/1.0 200 OK
233 X-Content-Marx-Brothers: Harpo
234         Chico and Groucho
235 Content-Length: who knows?
236
237
238
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
243
244
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>
247  ';
248         $r = $s->parseResponse($f);
249         $v = $r->value();
250         $s = $v->structmem('content');
251         $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
252     }
253
254     public function testStringBug()
255     {
256         $s = new xmlrpcmsg('dummy');
257         $f = '<?xml version="1.0"?>
258 <!-- $Id -->
259 <!-- found by 2z69xks7bpy001@sneakemail.com, amongst others
260  covers what happens when there\'s character data after </string>
261  and before </value> -->
262 <methodResponse>
263 <params>
264 <param>
265 <value>
266 <struct>
267 <member>
268 <name>success</name>
269 <value>
270 <boolean>1</boolean>
271 </value>
272 </member>
273 <member>
274 <name>sessionID</name>
275 <value>
276 <string>S300510007I</string>
277 </value>
278 </member>
279 </struct>
280 </value>
281 </param>
282 </params>
283 </methodResponse> ';
284         $r = $s->parseResponse($f);
285         $v = $r->value();
286         $s = $v->structmem('sessionID');
287         $this->assertEquals('S300510007I', $s->scalarval());
288     }
289
290     public function testWhiteSpace()
291     {
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
295
296
297 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
298 ';
299         $r = $s->parseResponse($f);
300         $v = $r->value();
301         $s = $v->structmem('content');
302         $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
303     }
304
305     public function testDoubleDataInArrayTag()
306     {
307         $s = new xmlrpcmsg('dummy');
308         $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
309 <data></data>
310 <data></data>
311 </array></value></param></params></methodResponse>
312 ';
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>
318 <data></data>
319 </array></value></param></params></methodResponse>
320 ';
321         $r = $s->parseResponse($f);
322         $v = $r->faultCode();
323         $this->assertEquals(2, $v);
324     }
325
326     public function testDoubleStuffInValueTag()
327     {
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>
333 ';
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>
341 ';
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>
349 ';
350         $r = $s->parseResponse($f);
351         $v = $r->faultCode();
352         $this->assertEquals(2, $v);
353     }
354
355     public function testAutodecodeResponse()
356     {
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
360
361
362 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
363 ';
364         $r = $s->parseResponse($f, true, 'phpvals');
365         $v = $r->value();
366         $s = $v['content'];
367         $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s);
368     }
369
370     public function testNoDecodeResponse()
371     {
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
375
376
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');
379         $v = $r->value();
380         $this->assertEquals($f, $v);
381     }
382
383     public function testAutoCoDec()
384     {
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);
400     }
401
402     public function testUTF8Request()
403     {
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>&#954;&#8057;&#963;&#956;&#949;</string></value>\n", $v);
410         $GLOBALS['xmlrpc_internalencoding'] = 'ISO-8859-1';
411         \PhpXmlRpc\PhpXmlRpc::importGlobals();
412     }
413
414     public function testUTF8Response()
415     {
416         $string = chr(224) . chr(252) . chr(232);
417
418         $s = new xmlrpcmsg('dummy');
419         $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>
420 <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>
421 ';
422         $r = $s->parseResponse($f, false, 'phpvals');
423         $v = $r->value();
424         $v = $v['content'];
425         $this->assertEquals($string, $v);
426
427         $f = '<?xml version="1.0" encoding="utf-8"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
428 <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>
429 ';
430         $r = $s->parseResponse($f, false, 'phpvals');
431         $v = $r->value();
432         $v = $v['content'];
433         $this->assertEquals($string, $v);
434
435         $r = php_xmlrpc_decode_xml($f);
436         $v = $r->value();
437         $v = $v->structmem('content')->scalarval();
438         $this->assertEquals($string, $v);
439     }
440
441     public function testLatin1Response()
442     {
443         $string = chr(224) . chr(252) . chr(232);
444
445         $s = new xmlrpcmsg('dummy');
446         $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>
447 <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>
448 ';
449         $r = $s->parseResponse($f, false, 'phpvals');
450         $v = $r->value();
451         $v = $v['content'];
452         $this->assertEquals($string, $v);
453
454         $f = '<?xml version="1.0" encoding="iso-8859-1"?><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>' . $string . '</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
456 ';
457         $r = $s->parseResponse($f, false, 'phpvals');
458         $v = $r->value();
459         $v = $v['content'];
460         $this->assertEquals($string, $v);
461
462         $r = php_xmlrpc_decode_xml($f);
463         $v = $r->value();
464         $v = $v->structmem('content')->scalarval();
465         $this->assertEquals($string, $v);
466     }
467
468     public function testUTF8IntString()
469     {
470         $v = new xmlrpcval(100, 'int');
471         $s = $v->serialize('UTF-8');
472         $this->assertequals("<value><int>100</int></value>\n", $s);
473     }
474
475     public function testStringInt()
476     {
477         $v = new xmlrpcval('hello world', 'int');
478         $s = $v->serialize();
479         $this->assertequals("<value><int>0</int></value>\n", $s);
480     }
481
482     public function testStructMemExists()
483     {
484         $v = php_xmlrpc_encode(array('hello' => 'world'));
485         $b = $v->structmemexists('hello');
486         $this->assertequals(true, $b);
487         $b = $v->structmemexists('world');
488         $this->assertequals(false, $b);
489     }
490
491     public function testNilvalue()
492     {
493         // default case: we do not accept nil values received
494         $v = new xmlrpcval('hello', 'null');
495         $r = new xmlrpcresp($v);
496         $s = $r->serialize();
497         $m = new xmlrpcmsg('dummy');
498         $r = $m->parseresponse($s);
499         $this->assertequals(2, $r->faultCode());
500         // enable reception of nil values
501         $GLOBALS['xmlrpc_null_extension'] = true;
502         \PhpXmlRpc\PhpXmlRpc::importGlobals();
503         $r = $m->parseresponse($s);
504         $v = $r->value();
505         $this->assertequals('null', $v->scalartyp());
506         // test with the apache version: EX:NIL
507         $GLOBALS['xmlrpc_null_apache_encoding'] = true;
508         \PhpXmlRpc\PhpXmlRpc::importGlobals();
509         // serialization
510         $v = new xmlrpcval('hello', 'null');
511         $s = $v->serialize();
512         $this->assertequals(1, preg_match('#<value><ex:nil/></value>#', $s));
513         // deserialization
514         $r = new xmlrpcresp($v);
515         $s = $r->serialize();
516         $r = $m->parseresponse($s);
517         $v = $r->value();
518         $this->assertequals('null', $v->scalartyp());
519         $GLOBALS['xmlrpc_null_extension'] = false;
520         \PhpXmlRpc\PhpXmlRpc::importGlobals();
521         $r = $m->parseresponse($s);
522         $this->assertequals(2, $r->faultCode());
523     }
524
525     public function TestLocale()
526     {
527         $locale = setlocale(LC_NUMERIC, 0);
528         /// @todo on php 5.3/win setting locale to german does not seem to set decimal separator to comma...
529         if (setlocale(LC_NUMERIC, 'deu', 'de_DE@euro', 'de_DE', 'de', 'ge') !== false) {
530             $v = new xmlrpcval(1.1, 'double');
531             if (strpos($v->scalarval(), ',') == 1) {
532                 $r = $v->serialize();
533                 $this->assertequals(false, strpos($r, ','));
534                 setlocale(LC_NUMERIC, $locale);
535             } else {
536                 setlocale(LC_NUMERIC, $locale);
537                 $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
538             }
539         } else {
540             $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
541         }
542     }
543 }