Add 'php/phpxmlrpc/' from commit 'cd5dbb4a511e7a616a61187a5de1a611a9748cbd'
[plcapi.git] / php / phpxmlrpc / 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 include_once __DIR__ . '/parse_args.php';
9
10 /**
11  * Tests involving parsing of xml and handling of xmlrpc values
12  */
13 class ParsingBugsTests extends PHPUnit_Framework_TestCase
14 {
15     public $args = array();
16
17     protected function setUp()
18     {
19         $this->args = argParser::getArgs();
20         if ($this->args['DEBUG'] == 1)
21             ob_start();
22     }
23
24     protected function tearDown()
25     {
26         if ($this->args['DEBUG'] != 1)
27             return;
28         $out = ob_get_clean();
29         $status = $this->getStatus();
30         if ($status == PHPUnit_Runner_BaseTestRunner::STATUS_ERROR
31             || $status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) {
32             echo $out;
33         }
34     }
35
36     protected function newMsg($methodName, $params = array())
37     {
38         $msg = new xmlrpcmsg($methodName, $params);
39         $msg->setDebug($this->args['DEBUG']);
40         return $msg;
41     }
42
43     public function testMinusOneString()
44     {
45         $v = new xmlrpcval('-1');
46         $u = new xmlrpcval('-1', 'string');
47         $t = new xmlrpcval(-1, 'string');
48         $this->assertEquals($v->scalarval(), $u->scalarval());
49         $this->assertEquals($v->scalarval(), $t->scalarval());
50     }
51
52     /**
53      * This looks funny, and we might call it a bug. But we strive for 100 backwards compat...
54      */
55     public function testMinusOneInt()
56     {
57         $u = new xmlrpcval();
58         $v = new xmlrpcval(-1);
59         $this->assertEquals($u->scalarval(), $v->scalarval());
60     }
61
62     public function testUnicodeInMemberName()
63     {
64         $str = "G" . chr(252) . "nter, El" . chr(232) . "ne";
65         $v = array($str => new xmlrpcval(1));
66         $r = new xmlrpcresp(new xmlrpcval($v, 'struct'));
67         $r = $r->serialize();
68         $m = $this->newMsg('dummy');
69         $r = $m->parseResponse($r);
70         $v = $r->value();
71         $this->assertEquals(true, $v->structmemexists($str));
72     }
73
74     public function testUnicodeInErrorString()
75     {
76         $response = utf8_encode(
77             '<?xml version="1.0"?>
78 <!-- $Id -->
79 <!-- found by G. giunta, covers what happens when lib receives
80   UTF8 chars in response text and comments -->
81 <!-- ' . chr(224) . chr(252) . chr(232) . '&#224;&#252;&#232; -->
82 <methodResponse>
83 <fault>
84 <value>
85 <struct>
86 <member>
87 <name>faultCode</name>
88 <value><int>888</int></value>
89 </member>
90 <member>
91 <name>faultString</name>
92 <value><string>' . chr(224) . chr(252) . chr(232) . '&#224;&#252;&#232;</string></value>
93 </member>
94 </struct>
95 </value>
96 </fault>
97 </methodResponse>');
98         $m = $this->newMsg('dummy');
99         $r = $m->parseResponse($response);
100         $v = $r->faultString();
101         $this->assertEquals(chr(224) . chr(252) . chr(232) . chr(224) . chr(252) . chr(232), $v);
102     }
103
104     public function testValidNumbers()
105     {
106         $m = $this->newMsg('dummy');
107         $fp =
108             '<?xml version="1.0"?>
109 <methodResponse>
110 <params>
111 <param>
112 <value>
113 <struct>
114 <member>
115 <name>integer1</name>
116 <value><int>01</int></value>
117 </member>
118 <member>
119 <name>integer2</name>
120 <value><int>+1</int></value>
121 </member>
122 <member>
123 <name>integer3</name>
124 <value><i4>1</i4></value>
125 </member>
126 <member>
127 <name>float1</name>
128 <value><double>01.10</double></value>
129 </member>
130 <member>
131 <name>float2</name>
132 <value><double>+1.10</double></value>
133 </member>
134 <member>
135 <name>float3</name>
136 <value><double>-1.10e2</double></value>
137 </member>
138 </struct>
139 </value>
140 </param>
141 </params>
142 </methodResponse>';
143         $r = $m->parseResponse($fp);
144         $v = $r->value();
145         $s = $v->structmem('integer1');
146         $t = $v->structmem('integer2');
147         $u = $v->structmem('integer3');
148         $x = $v->structmem('float1');
149         $y = $v->structmem('float2');
150         $z = $v->structmem('float3');
151         $this->assertEquals(1, $s->scalarval());
152         $this->assertEquals(1, $t->scalarval());
153         $this->assertEquals(1, $u->scalarval());
154
155         $this->assertEquals(1.1, $x->scalarval());
156         $this->assertEquals(1.1, $y->scalarval());
157         $this->assertEquals(-110.0, $z->scalarval());
158     }
159
160     public function testI8()
161     {
162         if (PHP_INT_SIZE == 4 ) {
163             $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
164             return;
165         }
166
167         $m = $this->newMsg('dummy');
168         $fp =
169             '<?xml version="1.0"?>
170 <methodResponse>
171 <params>
172 <param>
173 <value>
174 <struct>
175 <member>
176 <name>integer1</name>
177 <value><i8>1</i8></value>
178 </member>
179 </struct>
180 </value>
181 </param>
182 </params>
183 </methodResponse>';
184         $r = $m->parseResponse($fp);
185         $v = $r->value();
186         $s = $v->structmem('integer1');
187         $this->assertEquals(1, $s->scalarval());
188     }
189
190     public function testAddScalarToStruct()
191     {
192         $v = new xmlrpcval(array('a' => 'b'), 'struct');
193         // use @ operator in case error_log gets on screen
194         $r = @$v->addscalar('c');
195         $this->assertEquals(0, $r);
196     }
197
198     public function testAddStructToStruct()
199     {
200         $v = new xmlrpcval(array('a' => new xmlrpcval('b')), 'struct');
201         $r = $v->addstruct(array('b' => new xmlrpcval('c')));
202         $this->assertEquals(2, $v->structsize());
203         $this->assertEquals(1, $r);
204         $r = $v->addstruct(array('b' => new xmlrpcval('b')));
205         $this->assertEquals(2, $v->structsize());
206     }
207
208     public function testAddArrayToArray()
209     {
210         $v = new xmlrpcval(array(new xmlrpcval('a'), new xmlrpcval('b')), 'array');
211         $r = $v->addarray(array(new xmlrpcval('b'), new xmlrpcval('c')));
212         $this->assertEquals(4, $v->arraysize());
213         $this->assertEquals(1, $r);
214     }
215
216     public function testEncodeArray()
217     {
218         $r = range(1, 100);
219         $v = php_xmlrpc_encode($r);
220         $this->assertEquals('array', $v->kindof());
221     }
222
223     public function testEncodeRecursive()
224     {
225         $v = php_xmlrpc_encode(php_xmlrpc_encode('a simple string'));
226         $this->assertEquals('scalar', $v->kindof());
227     }
228
229     public function testBrokenRequests()
230     {
231         $s = new xmlrpc_server();
232         // omitting the 'params' tag: not tolerated by the lib anymore
233         $f = '<?xml version="1.0"?>
234 <methodCall>
235 <methodName>system.methodHelp</methodName>
236 <param>
237 <value><string>system.methodHelp</string></value>
238 </param>
239 </methodCall>';
240         $r = $s->parserequest($f);
241         $this->assertEquals(15, $r->faultCode());
242         // omitting a 'param' tag
243         $f = '<?xml version="1.0"?>
244 <methodCall>
245 <methodName>system.methodHelp</methodName>
246 <params>
247 <value><string>system.methodHelp</string></value>
248 </params>
249 </methodCall>';
250         $r = $s->parserequest($f);
251         $this->assertEquals(15, $r->faultCode());
252         // omitting a 'value' tag
253         $f = '<?xml version="1.0"?>
254 <methodCall>
255 <methodName>system.methodHelp</methodName>
256 <params>
257 <param><string>system.methodHelp</string></param>
258 </params>
259 </methodCall>';
260         $r = $s->parserequest($f);
261         $this->assertEquals(15, $r->faultCode());
262     }
263
264     public function testBrokenResponses()
265     {
266         $m = $this->newMsg('dummy');
267         // omitting the 'params' tag: no more tolerated by the lib...
268         $f = '<?xml version="1.0"?>
269 <methodResponse>
270 <param>
271 <value><string>system.methodHelp</string></value>
272 </param>
273 </methodResponse>';
274         $r = $m->parseResponse($f);
275         $this->assertEquals(2, $r->faultCode());
276         // omitting the 'param' tag: no more tolerated by the lib...
277         $f = '<?xml version="1.0"?>
278 <methodResponse>
279 <params>
280 <value><string>system.methodHelp</string></value>
281 </params>
282 </methodResponse>';
283         $r = $m->parseResponse($f);
284         $this->assertEquals(2, $r->faultCode());
285         // omitting a 'value' tag: KO
286         $f = '<?xml version="1.0"?>
287 <methodResponse>
288 <params>
289 <param><string>system.methodHelp</string></param>
290 </params>
291 </methodResponse>';
292         $r = $m->parseResponse($f);
293         $this->assertEquals(2, $r->faultCode());
294     }
295
296     public function testBuggyHttp()
297     {
298         $s = $this->newMsg('dummy');
299         $f = 'HTTP/1.1 100 Welcome to the jungle
300
301 HTTP/1.0 200 OK
302 X-Content-Marx-Brothers: Harpo
303         Chico and Groucho
304 Content-Length: who knows?
305
306
307
308 <?xml version="1.0"?>
309 <!-- First of all, let\'s check out if the lib properly handles a commented </methodResponse> tag... -->
310 <methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
311 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
312
313
314 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
315 <script type="text\javascript">document.write(\'Hello, my name is added nag, I\\\'m happy to serve your content for free\');</script>
316  ';
317         $r = $s->parseResponse($f);
318         $v = $r->value();
319         $s = $v->structmem('content');
320         $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
321     }
322
323     public function testStringBug()
324     {
325         $s = $this->newMsg('dummy');
326         $f = '<?xml version="1.0"?>
327 <!-- $Id -->
328 <!-- found by 2z69xks7bpy001@sneakemail.com, amongst others
329  covers what happens when there\'s character data after </string>
330  and before </value> -->
331 <methodResponse>
332 <params>
333 <param>
334 <value>
335 <struct>
336 <member>
337 <name>success</name>
338 <value>
339 <boolean>1</boolean>
340 </value>
341 </member>
342 <member>
343 <name>sessionID</name>
344 <value>
345 <string>S300510007I</string>
346 </value>
347 </member>
348 </struct>
349 </value>
350 </param>
351 </params>
352 </methodResponse> ';
353         $r = $s->parseResponse($f);
354         $v = $r->value();
355         $s = $v->structmem('sessionID');
356         $this->assertEquals('S300510007I', $s->scalarval());
357     }
358
359     public function testWhiteSpace()
360     {
361         $s = $this->newMsg('dummy');
362         $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
363 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
364
365
366 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
367 ';
368         $r = $s->parseResponse($f);
369         $v = $r->value();
370         $s = $v->structmem('content');
371         $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval());
372     }
373
374     public function testDoubleDataInArrayTag()
375     {
376         $s = $this->newMsg('dummy');
377         $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
378 <data></data>
379 <data></data>
380 </array></value></param></params></methodResponse>
381 ';
382         $r = $s->parseResponse($f);
383         $v = $r->faultCode();
384         $this->assertEquals(2, $v);
385         $f = '<?xml version="1.0"?><methodResponse><params><param><value><array>
386 <data><value>Hello world</value></data>
387 <data></data>
388 </array></value></param></params></methodResponse>
389 ';
390         $r = $s->parseResponse($f);
391         $v = $r->faultCode();
392         $this->assertEquals(2, $v);
393     }
394
395     public function testDoubleStuffInValueTag()
396     {
397         $s = $this->newMsg('dummy');
398         $f = '<?xml version="1.0"?><methodResponse><params><param><value>
399 <string>hello world</string>
400 <array><data></data></array>
401 </value></param></params></methodResponse>
402 ';
403         $r = $s->parseResponse($f);
404         $v = $r->faultCode();
405         $this->assertEquals(2, $v);
406         $f = '<?xml version="1.0"?><methodResponse><params><param><value>
407 <string>hello</string>
408 <string>world</string>
409 </value></param></params></methodResponse>
410 ';
411         $r = $s->parseResponse($f);
412         $v = $r->faultCode();
413         $this->assertEquals(2, $v);
414         $f = '<?xml version="1.0"?><methodResponse><params><param><value>
415 <string>hello</string>
416 <struct><member><name>hello><value>world</value></member></struct>
417 </value></param></params></methodResponse>
418 ';
419         $r = $s->parseResponse($f);
420         $v = $r->faultCode();
421         $this->assertEquals(2, $v);
422     }
423
424     public function testAutodecodeResponse()
425     {
426         $s = $this->newMsg('dummy');
427         $f = '<?xml version="1.0"?><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>hello world. 2 newlines follow
429
430
431 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>
432 ';
433         $r = $s->parseResponse($f, true, 'phpvals');
434         $v = $r->value();
435         $s = $v['content'];
436         $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s);
437     }
438
439     public function testNoDecodeResponse()
440     {
441         $s = $this->newMsg('dummy');
442         $f = '<?xml version="1.0"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
443 <member><name>dateCreated</name><value><dateTime.iso8601>20011126T09:17:52</dateTime.iso8601></value></member><member><name>content</name><value>hello world. 2 newlines follow
444
445
446 and there they were.</value></member><member><name>postid</name><value>7414222</value></member></struct></value></param></params></methodResponse>';
447         $r = $s->parseResponse($f, true, 'xml');
448         $v = $r->value();
449         $this->assertEquals($f, $v);
450     }
451
452     public function testAutoCoDec()
453     {
454         $data1 = array(1, 1.0, 'hello world', true, '20051021T23:43:00', -1, 11.0, '~!@#$%^&*()_+|', false, '20051021T23:43:00');
455         $data2 = array('zero' => $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1);
456         $data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2);
457         //$keys = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine');
458         $v1 = php_xmlrpc_encode($data, array('auto_dates'));
459         $v2 = php_xmlrpc_decode_xml($v1->serialize());
460         $this->assertEquals($v1, $v2);
461         $r1 = new PhpXmlRpc\Response($v1);
462         $r2 = php_xmlrpc_decode_xml($r1->serialize());
463         $r2->serialize(); // needed to set internal member payload
464         $this->assertEquals($r1, $r2);
465         $m1 = new PhpXmlRpc\Request('hello dolly', array($v1));
466         $m2 = php_xmlrpc_decode_xml($m1->serialize());
467         $m2->serialize(); // needed to set internal member payload
468         $this->assertEquals($m1, $m2);
469     }
470
471     public function testUTF8Request()
472     {
473         $sendstring = 'κόσμε'; // Greek word 'kosme'. NB: NOT a valid ISO8859 string!
474         $GLOBALS['xmlrpc_internalencoding'] = 'UTF-8';
475         \PhpXmlRpc\PhpXmlRpc::importGlobals();
476         $f = new xmlrpcval($sendstring, 'string');
477         $v = $f->serialize();
478         $this->assertEquals("<value><string>&#954;&#8057;&#963;&#956;&#949;</string></value>\n", $v);
479         $GLOBALS['xmlrpc_internalencoding'] = 'ISO-8859-1';
480         \PhpXmlRpc\PhpXmlRpc::importGlobals();
481     }
482
483     public function testUTF8Response()
484     {
485         $string = chr(224) . chr(252) . chr(232);
486
487         $s = $this->newMsg('dummy');
488         $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>
489 <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>
490 ';
491         $r = $s->parseResponse($f, false, 'phpvals');
492         $v = $r->value();
493         $v = $v['content'];
494         $this->assertEquals($string, $v);
495
496         $f = '<?xml version="1.0" encoding="UTF-8"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
497 <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>
498 ';
499         $r = $s->parseResponse($f, false, 'phpvals');
500         $v = $r->value();
501         $v = $v['content'];
502         $this->assertEquals($string, $v);
503
504         $r = php_xmlrpc_decode_xml($f);
505         $v = $r->value();
506         $v = $v->structmem('content')->scalarval();
507         $this->assertEquals($string, $v);
508     }
509
510     public function testLatin1Response()
511     {
512         $string = chr(224) . chr(252) . chr(232);
513
514         $s = $this->newMsg('dummy');
515         $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>
516 <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>
517 ';
518         $r = $s->parseResponse($f, false, 'phpvals');
519         $v = $r->value();
520         $v = $v['content'];
521         $this->assertEquals($string, $v);
522
523         $f = '<?xml version="1.0" encoding="ISO-8859-1"?><methodResponse><params><param><value><struct><member><name>userid</name><value>311127</value></member>
524 <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>
525 ';
526         $r = $s->parseResponse($f, false, 'phpvals');
527         $v = $r->value();
528         $v = $v['content'];
529         $this->assertEquals($string, $v);
530
531         $r = php_xmlrpc_decode_xml($f);
532         $v = $r->value();
533         $v = $v->structmem('content')->scalarval();
534         $this->assertEquals($string, $v);
535     }
536
537     public function testUTF8IntString()
538     {
539         $v = new xmlrpcval(100, 'int');
540         $s = $v->serialize('UTF-8');
541         $this->assertequals("<value><int>100</int></value>\n", $s);
542     }
543
544     public function testStringInt()
545     {
546         $v = new xmlrpcval('hello world', 'int');
547         $s = $v->serialize();
548         $this->assertequals("<value><int>0</int></value>\n", $s);
549     }
550
551     public function testStructMemExists()
552     {
553         $v = php_xmlrpc_encode(array('hello' => 'world'));
554         $b = $v->structmemexists('hello');
555         $this->assertequals(true, $b);
556         $b = $v->structmemexists('world');
557         $this->assertequals(false, $b);
558     }
559
560     public function testNilvalue()
561     {
562         // default case: we do not accept nil values received
563         $v = new xmlrpcval('hello', 'null');
564         $r = new xmlrpcresp($v);
565         $s = $r->serialize();
566         $m = $this->newMsg('dummy');
567         $r = $m->parseresponse($s);
568         $this->assertequals(2, $r->faultCode());
569         // enable reception of nil values
570         $GLOBALS['xmlrpc_null_extension'] = true;
571         \PhpXmlRpc\PhpXmlRpc::importGlobals();
572         $r = $m->parseresponse($s);
573         $v = $r->value();
574         $this->assertequals('null', $v->scalartyp());
575         // test with the apache version: EX:NIL
576         $GLOBALS['xmlrpc_null_apache_encoding'] = true;
577         \PhpXmlRpc\PhpXmlRpc::importGlobals();
578         // serialization
579         $v = new xmlrpcval('hello', 'null');
580         $s = $v->serialize();
581         $this->assertequals(1, preg_match('#<value><ex:nil/></value>#', $s));
582         // deserialization
583         $r = new xmlrpcresp($v);
584         $s = $r->serialize();
585         $r = $m->parseresponse($s);
586         $v = $r->value();
587         $this->assertequals('null', $v->scalartyp());
588         $GLOBALS['xmlrpc_null_extension'] = false;
589         \PhpXmlRpc\PhpXmlRpc::importGlobals();
590         $r = $m->parseresponse($s);
591         $this->assertequals(2, $r->faultCode());
592     }
593
594     public function testLocale()
595     {
596         $locale = setlocale(LC_NUMERIC, 0);
597         /// @todo on php 5.3/win setting locale to german does not seem to set decimal separator to comma...
598         if (setlocale(LC_NUMERIC, 'deu', 'de_DE@euro', 'de_DE', 'de', 'ge') !== false) {
599             $v = new xmlrpcval(1.1, 'double');
600             if (strpos($v->scalarval(), ',') == 1) {
601                 $r = $v->serialize();
602                 $this->assertequals(false, strpos($r, ','));
603                 setlocale(LC_NUMERIC, $locale);
604             } else {
605                 setlocale(LC_NUMERIC, $locale);
606                 $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
607             }
608         } else {
609             $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
610         }
611     }
612
613     public function testArrayAccess()
614     {
615         $v1 = new xmlrpcval(array(new xmlrpcval('one'), new xmlrpcval('two')), 'array');
616         $this->assertequals(1, count($v1));
617         $out = array('me' => array(), 'mytype' => 2, '_php_class' => null);
618         foreach($v1 as $key => $val)
619         {
620             $expected = each($out);
621             $this->assertequals($expected['key'], $key);
622             if (gettype($expected['value']) == 'array') {
623                 $this->assertequals('array', gettype($val));
624             } else {
625                 $this->assertequals($expected['value'], $val);
626             }
627         }
628
629         $v2 = new \PhpXmlRpc\Value(array(new \PhpXmlRpc\Value('one'), new \PhpXmlRpc\Value('two')), 'array');
630         $this->assertequals(2, count($v2));
631         $out = array(0 => 'object', 1 => 'object');
632         foreach($v2 as $key => $val)
633         {
634             $expected = each($out);
635             $this->assertequals($expected['key'], $key);
636             $this->assertequals($expected['value'], gettype($val));
637         }
638     }
639 }