Allow easier configuration to detect exotic charsets when the received payload does...
[plcapi.git] / tests / 3LocalhostTest.php
index a0e9b2a..bf51721 100644 (file)
@@ -5,6 +5,10 @@ include_once __DIR__ . '/../lib/xmlrpc_wrappers.inc';
 
 include_once __DIR__ . '/parse_args.php';
 
 
 include_once __DIR__ . '/parse_args.php';
 
+/**
+ * Tests which involve interaction between the client and the server.
+ * They are run against the server found in demo/server.php
+ */
 class LocalhostTest extends PHPUnit_Framework_TestCase
 {
     /** @var xmlrpc_client $client */
 class LocalhostTest extends PHPUnit_Framework_TestCase
 {
     /** @var xmlrpc_client $client */
@@ -85,16 +89,36 @@ class LocalhostTest extends PHPUnit_Framework_TestCase
         } else {
             $this->client = new xmlrpc_client($this->args['URI'], $this->args['LOCALSERVER']);
         }
         } else {
             $this->client = new xmlrpc_client($this->args['URI'], $this->args['LOCALSERVER']);
         }
-        if ($this->args['DEBUG']) {
-            $this->client->setDebug($this->args['DEBUG']);
-        }
+
+        $this->client->setDebug($this->args['DEBUG']);
         $this->client->request_compression = $this->request_compression;
         $this->client->accepted_compression = $this->accepted_compression;
 
         $this->coverageScriptUrl = 'http://' . $this->args['LOCALSERVER'] . '/' . str_replace( '/demo/server/server.php', 'tests/phpunit_coverage.php', $this->args['URI'] );
         $this->client->request_compression = $this->request_compression;
         $this->client->accepted_compression = $this->accepted_compression;
 
         $this->coverageScriptUrl = 'http://' . $this->args['LOCALSERVER'] . '/' . str_replace( '/demo/server/server.php', 'tests/phpunit_coverage.php', $this->args['URI'] );
+
+        if ($this->args['DEBUG'] == 1)
+            ob_start();
+    }
+
+    protected function tearDown()
+    {
+        if ($this->args['DEBUG'] != 1)
+            return;
+        $out = ob_get_clean();
+        $status = $this->getStatus();
+        if ($status == PHPUnit_Runner_BaseTestRunner::STATUS_ERROR
+            || $status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) {
+            echo $out;
+        }
     }
 
     }
 
-    protected function send($msg, $errrorcode = 0, $return_response = false)
+    /**
+     * @param PhpXmlRpc\Request|array $msg
+     * @param int|array $errorCode
+     * @param bool $returnResponse
+     * @return mixed|\PhpXmlRpc\Response|\PhpXmlRpc\Response[]|\PhpXmlRpc\Value|string|void
+     */
+    protected function send($msg, $errorCode = 0, $returnResponse = false)
     {
         if ($this->collectCodeCoverageInformation) {
             $this->client->setCookie('PHPUNIT_SELENIUM_TEST_ID', $this->testId);
     {
         if ($this->collectCodeCoverageInformation) {
             $this->client->setCookie('PHPUNIT_SELENIUM_TEST_ID', $this->testId);
@@ -105,13 +129,13 @@ class LocalhostTest extends PHPUnit_Framework_TestCase
         if (is_array($r)) {
             return $r;
         }
         if (is_array($r)) {
             return $r;
         }
-        if (is_array($errrorcode)) {
-            $this->assertContains($r->faultCode(), $errrorcode, 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
+        if (is_array($errorCode)) {
+            $this->assertContains($r->faultCode(), $errorCode, 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
         } else {
         } else {
-            $this->assertEquals($r->faultCode(), $errrorcode, 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
+            $this->assertEquals($errorCode, $r->faultCode(), 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
         }
         if (!$r->faultCode()) {
         }
         if (!$r->faultCode()) {
-            if ($return_response) {
+            if ($returnResponse) {
                 return $r;
             } else {
                 return $r->value();
                 return $r;
             } else {
                 return $r->value();
@@ -123,7 +147,7 @@ class LocalhostTest extends PHPUnit_Framework_TestCase
 
     public function testString()
     {
 
     public function testString()
     {
-        $sendstring = "here are 3 \"entities\": < > & " .
+        $sendString = "here are 3 \"entities\": < > & " .
             "and here's a dollar sign: \$pretendvarname and a backslash too: " . chr(92) .
             " - isn't that great? \\\"hackery\\\" at it's best " .
             " also don't want to miss out on \$item[0]. " .
             "and here's a dollar sign: \$pretendvarname and a backslash too: " . chr(92) .
             " - isn't that great? \\\"hackery\\\" at it's best " .
             " also don't want to miss out on \$item[0]. " .
@@ -132,34 +156,113 @@ class LocalhostTest extends PHPUnit_Framework_TestCase
             "a simple LF here" . chr(10) .
             "and then LFCR" . chr(10) . chr(13) .
             "last but not least weird names: G" . chr(252) . "nter, El" . chr(232) . "ne, and an xml comment closing tag: -->";
             "a simple LF here" . chr(10) .
             "and then LFCR" . chr(10) . chr(13) .
             "last but not least weird names: G" . chr(252) . "nter, El" . chr(232) . "ne, and an xml comment closing tag: -->";
-        $f = new xmlrpcmsg('examples.stringecho', array(
-            new xmlrpcval($sendstring, 'string'),
+        $m = new xmlrpcmsg('examples.stringecho', array(
+            new xmlrpcval($sendString, 'string'),
         ));
         ));
-        $v = $this->send($f);
+        $v = $this->send($m);
         if ($v) {
             // when sending/receiving non-US-ASCII encoded strings, XML says cr-lf can be normalized.
             // so we relax our tests...
         if ($v) {
             // when sending/receiving non-US-ASCII encoded strings, XML says cr-lf can be normalized.
             // so we relax our tests...
-            $l1 = strlen($sendstring);
+            $l1 = strlen($sendString);
             $l2 = strlen($v->scalarval());
             if ($l1 == $l2) {
             $l2 = strlen($v->scalarval());
             if ($l1 == $l2) {
-                $this->assertEquals($sendstring, $v->scalarval());
+                $this->assertEquals($sendString, $v->scalarval());
             } else {
             } else {
-                $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendstring), $v->scalarval());
+                $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendString), $v->scalarval());
             }
         }
     }
 
     public function testLatin1String()
     {
             }
         }
     }
 
     public function testLatin1String()
     {
-        $sendstring =
+        $sendString =
             "last but not least weird names: G" . chr(252) . "nter, El" . chr(232) . "ne";
             "last but not least weird names: G" . chr(252) . "nter, El" . chr(232) . "ne";
-        $f = '<?xml version="1.0" encoding="iso-8859-1"?><methodCall><methodName>examples.stringecho</methodName><params><param><value>'.
-            $sendstring.
+        $x = '<?xml version="1.0" encoding="ISO-8859-1"?><methodCall><methodName>examples.stringecho</methodName><params><param><value>'.
+            $sendString.
             '</value></param></params></methodCall>';
             '</value></param></params></methodCall>';
+        $v = $this->send($x);
+        if ($v) {
+            $this->assertEquals($sendString, $v->scalarval());
+        }
+    }
+
+    public function testExoticCharsetsRequests()
+    {
+        // note that we should disable this call also when mbstring is missing server-side
+        if (!function_exists('mb_convert_encoding')) {
+            $this->markTestSkipped('Miss mbstring extension to test exotic charsets');
+            return;
+        }
+        $sendString = 'κόσμε'; // Greek word 'kosme'. NB: NOT a valid ISO8859 string!
+        $str = '<?xml version="1.0" encoding="_ENC_"?>
+<methodCall>
+    <methodName>examples.stringecho</methodName>
+    <params>
+        <param>
+        <value><string>'.$sendString.'</string></value>
+        </param>
+    </params>
+</methodCall>';
+
+        PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'UTF-8';
+        // we have to set the encoding declaration either in the http header or xml prolog, as mb_detect_encoding
+        // (used on the server side) will fail recognizing these 2 charsets
+        $v = $this->send(mb_convert_encoding(str_replace('_ENC_', 'UCS-4', $str), 'UCS-4', 'UTF-8'));
+        $this->assertEquals($sendString, $v->scalarval());
+        $v = $this->send(mb_convert_encoding(str_replace('_ENC_', 'UTF-16', $str), 'UTF-16', 'UTF-8'));
+        $this->assertEquals($sendString, $v->scalarval());
+        PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'ISO-8859-1';
+    }
+
+    public function testExoticCharsetsRequests2()
+    {
+        // note that we should disable this call also when mbstring is missing server-side
+        if (!function_exists('mb_convert_encoding')) {
+            $this->markTestSkipped('Miss mbstring extension to test exotic charsets');
+            return;
+        }
+        $sendString = '安室奈美恵'; // No idea what this means :-) NB: NOT a valid ISO8859 string!
+        $str = '<?xml version="1.0"?>
+<methodCall>
+    <methodName>examples.stringecho</methodName>
+    <params>
+        <param>
+        <value><string>'.$sendString.'</string></value>
+        </param>
+    </params>
+</methodCall>';
+
+        PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'UTF-8';
+        // no encoding declaration either in the http header or xml prolog, let mb_detect_encoding
+        // (used on the server side) sort it out
+        $this->client->path = $this->args['URI'].'?DETECT_ENCODINGS[]=EUC-JP&DETECT_ENCODINGS[]=UTF-8';
+        $v = $this->send(mb_convert_encoding($str, 'EUC-JP', 'UTF-8'));
+        $this->assertEquals($sendString, $v->scalarval());
+        PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'ISO-8859-1';
+    }
+
+    /*public function testLatin1Method()
+    {
+        $f = new xmlrpcmsg("tests.iso88591methodname." . chr(224) . chr(252) . chr(232), array(
+            new xmlrpcval('hello')
+        ));
         $v = $this->send($f);
         if ($v) {
         $v = $this->send($f);
         if ($v) {
-            $this->assertEquals($sendstring, $v->scalarval());
+            $this->assertEquals('hello', $v->scalarval());
+        }
+    }*/
+
+    public function testUtf8Method()
+    {
+        PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'UTF-8';
+        $m = new xmlrpcmsg("tests.utf8methodname." . 'κόσμε', array(
+            new xmlrpcval('hello')
+        ));
+        $v = $this->send($m);
+        if ($v) {
+            $this->assertEquals('hello', $v->scalarval());
         }
         }
+        PhpXmlRpc\PhpXmlRpc::$xmlrpc_internalencoding = 'ISO-8859-1';
     }
 
     public function testAddingDoubles()
     }
 
     public function testAddingDoubles()
@@ -168,11 +271,11 @@ class LocalhostTest extends PHPUnit_Framework_TestCase
         // keep precision to sensible levels here ;-)
         $a = 12.13;
         $b = -23.98;
         // keep precision to sensible levels here ;-)
         $a = 12.13;
         $b = -23.98;
-        $f = new xmlrpcmsg('examples.addtwodouble', array(
+        $m = new xmlrpcmsg('examples.addtwodouble', array(
             new xmlrpcval($a, 'double'),
             new xmlrpcval($b, 'double'),
         ));
             new xmlrpcval($a, 'double'),
             new xmlrpcval($b, 'double'),
         ));
-        $v = $this->send($f);
+        $v = $this->send($m);
         if ($v) {
             $this->assertEquals($a + $b, $v->scalarval());
         }
         if ($v) {
             $this->assertEquals($a + $b, $v->scalarval());
         }
@@ -180,11 +283,11 @@ class LocalhostTest extends PHPUnit_Framework_TestCase
 
     public function testAdding()
     {
 
     public function testAdding()
     {
-        $f = new xmlrpcmsg('examples.addtwo', array(
+        $m = new xmlrpcmsg('examples.addtwo', array(
             new xmlrpcval(12, 'int'),
             new xmlrpcval(-23, 'int'),
         ));
             new xmlrpcval(12, 'int'),
             new xmlrpcval(-23, 'int'),
         ));
-        $v = $this->send($f);
+        $v = $this->send($m);
         if ($v) {
             $this->assertEquals(12 - 23, $v->scalarval());
         }
         if ($v) {
             $this->assertEquals(12 - 23, $v->scalarval());
         }
@@ -192,11 +295,11 @@ class LocalhostTest extends PHPUnit_Framework_TestCase
 
     public function testInvalidNumber()
     {
 
     public function testInvalidNumber()
     {
-        $f = new xmlrpcmsg('examples.addtwo', array(
+        $m = new xmlrpcmsg('examples.addtwo', array(
             new xmlrpcval('fred', 'int'),
             new xmlrpcval("\"; exec('ls')", 'int'),
         ));
             new xmlrpcval('fred', 'int'),
             new xmlrpcval("\"; exec('ls')", 'int'),
         ));
-        $v = $this->send($f);
+        $v = $this->send($m);
         /// @todo a fault condition should be generated here
         /// by the server, which we pick up on
         if ($v) {
         /// @todo a fault condition should be generated here
         /// by the server, which we pick up on
         if ($v) {
@@ -206,19 +309,17 @@ class LocalhostTest extends PHPUnit_Framework_TestCase
 
     public function testBoolean()
     {
 
     public function testBoolean()
     {
-        $f = new xmlrpcmsg('examples.invertBooleans', array(
+        $m = new xmlrpcmsg('examples.invertBooleans', array(
             new xmlrpcval(array(
                 new xmlrpcval(true, 'boolean'),
                 new xmlrpcval(false, 'boolean'),
                 new xmlrpcval(1, 'boolean'),
             new xmlrpcval(array(
                 new xmlrpcval(true, 'boolean'),
                 new xmlrpcval(false, 'boolean'),
                 new xmlrpcval(1, 'boolean'),
-                new xmlrpcval(0, 'boolean'),
-                //new xmlrpcval('true', 'boolean'),
-                //new xmlrpcval('false', 'boolean')
+                new xmlrpcval(0, 'boolean')
             ),
                 'array'
             ),));
         $answer = '0101';
             ),
                 'array'
             ),));
         $answer = '0101';
-        $v = $this->send($f);
+        $v = $this->send($m);
         if ($v) {
             $sz = $v->arraysize();
             $got = '';
         if ($v) {
             $sz = $v->arraysize();
             $got = '';
@@ -236,7 +337,7 @@ class LocalhostTest extends PHPUnit_Framework_TestCase
 
     public function testBase64()
     {
 
     public function testBase64()
     {
-        $sendstring = 'Mary had a little lamb,
+        $sendString = 'Mary had a little lamb,
 Whose fleece was white as snow,
 And everywhere that Mary went
 the lamb was sure to go.
 Whose fleece was white as snow,
 And everywhere that Mary went
 the lamb was sure to go.
@@ -245,15 +346,15 @@ Mary had a little lamb
 She tied it to a pylon
 Ten thousand volts went down its back
 And turned it into nylon';
 She tied it to a pylon
 Ten thousand volts went down its back
 And turned it into nylon';
-        $f = new xmlrpcmsg('examples.decode64', array(
-            new xmlrpcval($sendstring, 'base64'),
+        $m = new xmlrpcmsg('examples.decode64', array(
+            new xmlrpcval($sendString, 'base64'),
         ));
         ));
-        $v = $this->send($f);
+        $v = $this->send($m);
         if ($v) {
         if ($v) {
-            if (strlen($sendstring) == strlen($v->scalarval())) {
-                $this->assertEquals($sendstring, $v->scalarval());
+            if (strlen($sendString) == strlen($v->scalarval())) {
+                $this->assertEquals($sendString, $v->scalarval());
             } else {
             } else {
-                $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendstring), $v->scalarval());
+                $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendString), $v->scalarval());
             }
         }
     }
             }
         }
     }
@@ -276,11 +377,11 @@ And turned it into nylon';
 
     public function testCountEntities()
     {
 
     public function testCountEntities()
     {
-        $sendstring = "h'fd>onc>>l>>rw&bpu>q>e<v&gxs<ytjzkami<";
-        $f = new xmlrpcmsg('validator1.countTheEntities', array(
-            new xmlrpcval($sendstring, 'string'),
+        $sendString = "h'fd>onc>>l>>rw&bpu>q>e<v&gxs<ytjzkami<";
+        $m = new xmlrpcmsg('validator1.countTheEntities', array(
+            new xmlrpcval($sendString, 'string'),
         ));
         ));
-        $v = $this->send($f);
+        $v = $this->send($m);
         if ($v) {
             $got = '';
             $expected = '37210';
         if ($v) {
             $got = '';
             $expected = '37210';
@@ -326,8 +427,8 @@ And turned it into nylon';
             'array'
         );
 
             'array'
         );
 
-        $f = new xmlrpcmsg('system.multicall', array($arg));
-        $v = $this->send($f);
+        $m = new xmlrpcmsg('system.multicall', array($arg));
+        $v = $this->send($m);
         if ($v) {
             //$this->assertTrue($r->faultCode() == 0, "fault from system.multicall");
             $this->assertTrue($v->arraysize() == 4, "bad number of return values");
         if ($v) {
             //$this->assertTrue($r->faultCode() == 0, "fault from system.multicall");
             $this->assertTrue($v->arraysize() == 4, "bad number of return values");
@@ -477,95 +578,261 @@ And turned it into nylon';
 
     public function testCatchWarnings()
     {
 
     public function testCatchWarnings()
     {
-        $f = new xmlrpcmsg('examples.generatePHPWarning', array(
+        $m = new xmlrpcmsg('tests.generatePHPWarning', array(
             new xmlrpcval('whatever', 'string'),
         ));
             new xmlrpcval('whatever', 'string'),
         ));
-        $v = $this->send($f);
+        $v = $this->send($m);
         if ($v) {
         if ($v) {
-            $this->assertEquals($v->scalarval(), true);
+            $this->assertEquals(true, $v->scalarval());
         }
     }
 
     public function testCatchExceptions()
     {
         }
     }
 
     public function testCatchExceptions()
     {
-        $f = new xmlrpcmsg('examples.raiseException', array(
+        $m = new xmlrpcmsg('tests.raiseException', array(
             new xmlrpcval('whatever', 'string'),
         ));
             new xmlrpcval('whatever', 'string'),
         ));
-        $v = $this->send($f, $GLOBALS['xmlrpcerr']['server_error']);
+        $v = $this->send($m, $GLOBALS['xmlrpcerr']['server_error']);
         $this->client->path = $this->args['URI'] . '?EXCEPTION_HANDLING=1';
         $this->client->path = $this->args['URI'] . '?EXCEPTION_HANDLING=1';
-        $v = $this->send($f, 1);
+        $v = $this->send($m, 1); // the error code of the expected exception
         $this->client->path = $this->args['URI'] . '?EXCEPTION_HANDLING=2';
         // depending on whether display_errors is ON or OFF on the server, we will get back a different error here,
         // as php will generate an http status code of either 200 or 500...
         $this->client->path = $this->args['URI'] . '?EXCEPTION_HANDLING=2';
         // depending on whether display_errors is ON or OFF on the server, we will get back a different error here,
         // as php will generate an http status code of either 200 or 500...
-        $v = $this->send($f, array($GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcerr']['http_error']));
+        $v = $this->send($m, array($GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcerr']['http_error']));
     }
 
     public function testZeroParams()
     {
     }
 
     public function testZeroParams()
     {
-        $f = new xmlrpcmsg('system.listMethods');
-        $v = $this->send($f);
+        $m = new xmlrpcmsg('system.listMethods');
+        $v = $this->send($m);
+    }
+
+    public function testNullParams()
+    {
+        $m = new xmlrpcmsg('tests.getStateName.12', array(
+            new xmlrpcval('whatever', 'null'),
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        if ($v) {
+            $this->assertEquals('Michigan', $v->scalarval());
+        }
+        $m = new xmlrpcmsg('tests.getStateName.12', array(
+            new xmlrpcval(23, 'int'),
+            new xmlrpcval('whatever', 'null'),
+        ));
+        $v = $this->send($m);
+        if ($v) {
+            $this->assertEquals('Michigan', $v->scalarval());
+        }
+        $m = new xmlrpcmsg('tests.getStateName.12', array(
+            new xmlrpcval(23, 'int')
+        ));
+        $v = $this->send($m, array($GLOBALS['xmlrpcerr']['incorrect_params']));
     }
 
     public function testCodeInjectionServerSide()
     {
     }
 
     public function testCodeInjectionServerSide()
     {
-        $f = new xmlrpcmsg('system.MethodHelp');
-        $f->payload = "<?xml version=\"1.0\"?><methodCall><methodName>validator1.echoStructTest</methodName><params><param><value><struct><member><name>','')); echo('gotcha!'); die(); //</name></member></struct></value></param></params></methodCall>";
-        $v = $this->send($f);
-        //$v = $r->faultCode();
+        $m = new xmlrpcmsg('system.MethodHelp');
+        $m->payload = "<?xml version=\"1.0\"?><methodCall><methodName>validator1.echoStructTest</methodName><params><param><value><struct><member><name>','')); echo('gotcha!'); die(); //</name></member></struct></value></param></params></methodCall>";
+        $v = $this->send($m);
         if ($v) {
             $this->assertEquals(0, $v->structsize());
         }
     }
 
         if ($v) {
             $this->assertEquals(0, $v->structsize());
         }
     }
 
-    public function testAutoRegisteredFunction()
+    public function testServerWrappedFunction()
     {
     {
-        $f = new xmlrpcmsg('examples.php.getStateName', array(
+        $m = new xmlrpcmsg('tests.getStateName.2', array(
             new xmlrpcval(23, 'int'),
         ));
             new xmlrpcval(23, 'int'),
         ));
-        $v = $this->send($f);
-        if ($v) {
-            $this->assertEquals('Michigan', $v->scalarval());
-        } else {
-            $this->fail('Note: server can only auto register functions if running with PHP 5.0.3 and up');
-        }
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+
+        // this generates an exception in the function which was wrapped, which is by default wrapped in a known error response
+        $m = new xmlrpcmsg('tests.getStateName.2', array(
+            new xmlrpcval(0, 'int'),
+        ));
+        $v = $this->send($m, $GLOBALS['xmlrpcerr']['server_error']);
+
+        // check if the generated function dispatch map is fine, by checking if the server registered it
+        $m = new xmlrpcmsg('system.methodSignature', array(
+            new xmlrpcval('tests.getStateName.2'),
+        ));
+        $v = $this->send($m);
+        $encoder = new \PhpXmlRpc\Encoder();
+        $this->assertEquals(array(array('string', 'int')), $encoder->decode($v));
     }
 
     }
 
-    public function testAutoRegisteredClass()
+    public function testServerWrappedFunctionAsSource()
     {
     {
-        $f = new xmlrpcmsg('examples.php2.getStateName', array(
+        $m = new xmlrpcmsg('tests.getStateName.6', array(
             new xmlrpcval(23, 'int'),
         ));
             new xmlrpcval(23, 'int'),
         ));
-        $v = $this->send($f);
-        if ($v) {
-            $this->assertEquals('Michigan', $v->scalarval());
-            $f = new xmlrpcmsg('examples.php3.getStateName', array(
-                new xmlrpcval(23, 'int'),
-            ));
-            $v = $this->send($f);
-            if ($v) {
-                $this->assertEquals('Michigan', $v->scalarval());
-            }
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+
+        // this generates an exception in the function which was wrapped, which is by default wrapped in a known error response
+        $m = new xmlrpcmsg('tests.getStateName.6', array(
+            new xmlrpcval(0, 'int'),
+        ));
+        $v = $this->send($m, $GLOBALS['xmlrpcerr']['server_error']);
+    }
+
+    public function testServerWrappedObjectMethods()
+    {
+        $m = new xmlrpcmsg('tests.getStateName.3', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+
+        $m = new xmlrpcmsg('tests.getStateName.4', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+
+        $m = new xmlrpcmsg('tests.getStateName.5', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+
+        $m = new xmlrpcmsg('tests.getStateName.7', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+
+        $m = new xmlrpcmsg('tests.getStateName.8', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+
+        $m = new xmlrpcmsg('tests.getStateName.9', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+    }
+
+    public function testServerWrappedObjectMethodsAsSource()
+    {
+        $m = new xmlrpcmsg('tests.getStateName.7', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+
+        $m = new xmlrpcmsg('tests.getStateName.8', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+
+        $m = new xmlrpcmsg('tests.getStateName.9', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+    }
+
+    public function testServerClosure()
+    {
+        $m = new xmlrpcmsg('tests.getStateName.10', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+    }
+
+    public function testServerWrappedClosure()
+    {
+        $m = new xmlrpcmsg('tests.getStateName.11', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+    }
+
+    public function testServerWrappedClass()
+    {
+        $m = new xmlrpcmsg('tests.xmlrpcServerMethodsContainer.findState', array(
+            new xmlrpcval(23, 'int'),
+        ));
+        $v = $this->send($m);
+        $this->assertEquals('Michigan', $v->scalarval());
+    }
+
+    public function testWrappedMethod()
+    {
+        // make a 'deep client copy' as the original one might have many properties set
+        $func = wrap_xmlrpc_method($this->client, 'examples.getStateName', array('simple_client_copy' => 0));
+        if ($func == false) {
+            $this->fail('Registration of examples.getStateName failed');
         } else {
         } else {
-            $this->fail('Note: server can only auto register class methods if running with PHP 5.0.3 and up');
+            $v = $func(23);
+            // work around bug in current (or old?) version of phpunit when reporting the error
+            /*if (is_object($v)) {
+                $v = var_export($v, true);
+            }*/
+            $this->assertEquals('Michigan', $v);
         }
     }
 
         }
     }
 
-    public function testAutoRegisteredMethod()
+    public function testWrappedMethodAsSource()
     {
         // make a 'deep client copy' as the original one might have many properties set
     {
         // make a 'deep client copy' as the original one might have many properties set
-        $func = wrap_xmlrpc_method($this->client, 'examples.getStateName', array('simple_client_copy' => 1));
-        if ($func == '') {
+        $func = wrap_xmlrpc_method($this->client, 'examples.getStateName', array('simple_client_copy' => 0, 'return_source' => true));
+        if ($func == false) {
             $this->fail('Registration of examples.getStateName failed');
         } else {
             $this->fail('Registration of examples.getStateName failed');
         } else {
+            eval($func['source']);
+            $func = $func['function'];
             $v = $func(23);
             $v = $func(23);
-            // work around bug in current version of phpunit
-            if (is_object($v)) {
+            // work around bug in current (or old?) version of phpunit when reporting the error
+            /*if (is_object($v)) {
                 $v = var_export($v, true);
                 $v = var_export($v, true);
-            }
+            }*/
+            $this->assertEquals('Michigan', $v);
+        }
+    }
+
+    public function testWrappedClass()
+    {
+        // make a 'deep client copy' as the original one might have many properties set
+        // also for speed only wrap one method of the whole server
+        $class = wrap_xmlrpc_server($this->client, array('simple_client_copy' => 0, 'method_filter' => '/examples\.getStateName/' ));
+        if ($class == '') {
+            $this->fail('Registration of remote server failed');
+        } else {
+            $obj = new $class();
+            $v = $obj->examples_getStateName(23);
+            // work around bug in current (or old?) version of phpunit when reporting the error
+            /*if (is_object($v)) {
+                $v = var_export($v, true);
+            }*/
             $this->assertEquals('Michigan', $v);
         }
     }
 
             $this->assertEquals('Michigan', $v);
         }
     }
 
+    public function testTransferOfObjectViaWrapping()
+    {
+        // make a 'deep client copy' as the original one might have many properties set
+        $func = wrap_xmlrpc_method($this->client, 'tests.returnPhpObject', array('simple_client_copy' => true,
+            'decode_php_objs' => true));
+        if ($func == false) {
+            $this->fail('Registration of tests.returnPhpObject failed');
+        } else {
+            $v = $func();
+            $obj = new stdClass();
+            $obj->hello = 'world';
+            $this->assertEquals($obj, $v);
+        }
+    }
+
     public function testGetCookies()
     {
         // let server set to us some cookies we tell it
     public function testGetCookies()
     {
         // let server set to us some cookies we tell it
@@ -577,8 +844,8 @@ And turned it into nylon';
             'c5' => array('value' => 'c5', 'expires' => time() + 60 * 60 * 24 * 30, 'path' => '/', 'domain' => 'localhost'),
         );
         $cookiesval = php_xmlrpc_encode($cookies);
             'c5' => array('value' => 'c5', 'expires' => time() + 60 * 60 * 24 * 30, 'path' => '/', 'domain' => 'localhost'),
         );
         $cookiesval = php_xmlrpc_encode($cookies);
-        $f = new xmlrpcmsg('examples.setcookies', array($cookiesval));
-        $r = $this->send($f, 0, true);
+        $m = new xmlrpcmsg('examples.setcookies', array($cookiesval));
+        $r = $this->send($m, 0, true);
         if ($r) {
             $v = $r->value();
             $this->assertEquals(1, $v->scalarval());
         if ($r) {
             $v = $r->value();
             $this->assertEquals(1, $v->scalarval());
@@ -619,13 +886,13 @@ And turned it into nylon';
             'c2' => '2 3',
             'c3' => '!@#$%^&*()_+|}{":?><,./\';[]\\=-',
         );
             'c2' => '2 3',
             'c3' => '!@#$%^&*()_+|}{":?><,./\';[]\\=-',
         );
-        $f = new xmlrpcmsg('examples.getcookies', array());
+        $m = new xmlrpcmsg('examples.getcookies', array());
         foreach ($cookies as $cookie => $val) {
             $this->client->setCookie($cookie, $val);
             $cookies[$cookie] = (string)$cookies[$cookie];
         }
         foreach ($cookies as $cookie => $val) {
             $this->client->setCookie($cookie, $val);
             $cookies[$cookie] = (string)$cookies[$cookie];
         }
-        $r = $this->client->send($f, $this->timeout, $this->method);
-        $this->assertEquals($r->faultCode(), 0, 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
+        $r = $this->client->send($m, $this->timeout, $this->method);
+        $this->assertEquals(0, $r->faultCode(), 'Error ' . $r->faultCode() . ' connecting to server: ' . $r->faultString());
         if (!$r->faultCode()) {
             $v = $r->value();
             $v = php_xmlrpc_decode($v);
         if (!$r->faultCode()) {
             $v = $r->value();
             $v = php_xmlrpc_decode($v);
@@ -636,20 +903,28 @@ And turned it into nylon';
             }
 
             // on IIS and Apache getallheaders returns something slightly different...
             }
 
             // on IIS and Apache getallheaders returns something slightly different...
-            $this->assertEquals($v, $cookies);
+            $this->assertEquals($cookies, $v);
         }
     }
 
         }
     }
 
+    public function testServerComments()
+    {
+        $m = new xmlrpcmsg('tests.xmlrpcServerMethodsContainer.debugMessageGenerator', array(
+            new xmlrpcval('hello world', 'string'),
+        ));
+        $r = $this->send($m, 0, true);
+        $this->assertContains('hello world', $r->raw_data);
+    }
+
     public function testSendTwiceSameMsg()
     {
     public function testSendTwiceSameMsg()
     {
-        $f = new xmlrpcmsg('examples.stringecho', array(
+        $m = new xmlrpcmsg('examples.stringecho', array(
             new xmlrpcval('hello world', 'string'),
         ));
             new xmlrpcval('hello world', 'string'),
         ));
-        $v1 = $this->send($f);
-        $v2 = $this->send($f);
-        //$v = $r->faultCode();
+        $v1 = $this->send($m);
+        $v2 = $this->send($m);
         if ($v1 && $v2) {
         if ($v1 && $v2) {
-            $this->assertEquals($v2, $v1);
+            $this->assertEquals($v1, $v2);
         }
     }
 }
         }
     }
 }