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