From: Roger Meier Date: Tue, 24 Jan 2012 18:42:46 +0000 (+0000) Subject: THRIFT-1478 TJSONProtocol in PHP X-Git-Tag: 0.9.1~460 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=33b720a958987fd8edf9021c8d40de9e338314b1;p=common%2Fthrift.git THRIFT-1478 TJSONProtocol in PHP Patch: Greg Fodor, Andrew Grumet, Roger Meier git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1235403 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/configure.ac b/configure.ac index cd5f0da0..db1591f8 100755 --- a/configure.ac +++ b/configure.ac @@ -216,6 +216,9 @@ if test "$with_php_extension" = "yes"; then fi AM_CONDITIONAL(WITH_PHP_EXTENSION, [test "$have_php_extension" = "yes"]) +AC_PATH_PROG([PHPUNIT], [phpunit]) +AM_CONDITIONAL(HAVE_PHPUNIT, [test "x$PHPUNIT" != "x"]) + AX_THRIFT_LIB(ruby, [Ruby], yes) have_ruby=no if test "$with_ruby" = "yes"; then @@ -487,6 +490,7 @@ AC_CONFIG_FILES([ lib/perl/Makefile lib/perl/test/Makefile lib/php/Makefile + lib/php/test/Makefile lib/py/Makefile lib/rb/Makefile test/Makefile diff --git a/lib/php/Makefile.am b/lib/php/Makefile.am old mode 100644 new mode 100755 index 07242f9a..b7c7100b --- a/lib/php/Makefile.am +++ b/lib/php/Makefile.am @@ -17,6 +17,11 @@ # under the License. # + +if WITH_TESTS +SUBDIRS = test +endif + %.so: cd src/ext/thrift_protocol/ \ && $(MAKE) diff --git a/lib/php/src/protocol/TJSONProtocol.php b/lib/php/src/protocol/TJSONProtocol.php new file mode 100755 index 00000000..b7eaa07f --- /dev/null +++ b/lib/php/src/protocol/TJSONProtocol.php @@ -0,0 +1,808 @@ + 1) { + switch (substr($name, 0, 1)) { + case 'd': + $result = TType::DOUBLE; + break; + case 'i': + switch (substr($name, 1, 1)) { + case '8': + $result = TType::BYTE; + break; + case '1': + $result = TType::I16; + break; + case '3': + $result = TType::I32; + break; + case '6': + $result = TType::I64; + break; + } + break; + case 'l': + $result = TType::LST; + break; + case 'm': + $result = TType::MAP; + break; + case 'r': + $result = TType::STRUCT; + break; + case 's': + if (substr($name, 1, 1) == 't') { + $result = TType::STRING; + } + else if (substr($name, 1, 1) == 'e') { + $result = TType::SET; + } + break; + case 't': + $result = TType::BOOL; + break; + } + } + if ($result == TType::STOP) { + throw new TProtocolException("Unrecognized type", TProtocolException::INVALID_DATA); + } + return $result; + } + + public $contextStack_ = array(); + public $context_; + public $reader_; + + private function pushContext($c) { + array_push($this->contextStack_, $this->context_); + $this->context_ = $c; + } + + private function popContext() { + $this->context_ = array_pop($this->contextStack_); + } + + public function __construct($trans) { + parent::__construct($trans); + $this->context_ = new TJSONProtocol_JSONBaseContext(); + $this->reader_ = new TJSONProtocol_LookaheadReader($this); + } + + public function reset() { + $this->contextStack_ = array(); + $this->context_ = new TJSONProtocol_JSONBaseContext(); + $this->reader_ = new TJSONProtocol_LookaheadReader($this); + } + + private $tmpbuf_ = array(4); + + public function readJSONSyntaxChar($b) { + $ch = $this->reader_->read(); + + if (substr($ch, 0, 1) != $b) { + throw new TProtocolException("Unexpected character: " . $ch, TProtocolException::INVALID_DATA); + } + } + + private function hexVal($s) { + for ($i = 0; $i < strlen($s); $i++) { + $ch = substr($s, $i, 1); + + if (!($ch >= "a" && $ch <= "f") && !($ch >= "0" && $ch <= "9")) { + throw new TProtocolException("Expected hex character " . $ch, TProtocolException::INVALID_DATA); + } + } + + return hexdec($s); + } + + private function hexChar($val) { + return dechex($val); + } + + private function writeJSONString($b) { + $this->context_->write(); + + if (is_numeric($b) && $this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + + $this->trans_->write(json_encode($b)); + + if (is_numeric($b) && $this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + } + + private function writeJSONInteger($num) { + $this->context_->write(); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + + $this->trans_->write($num); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + } + + private function writeJSONDouble($num) { + $this->context_->write(); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + + $this->trans_->write(json_encode($num)); + + if ($this->context_->escapeNum()) { + $this->trans_->write(self::QUOTE); + } + } + + private function writeJSONBase64($data) { + $this->context_->write(); + $this->trans_->write(self::QUOTE); + $this->trans_->write(json_encode(base64_encode($data))); + $this->trans_->write(self::QUOTE); + } + + private function writeJSONObjectStart() { + $this->context_->write(); + $this->trans_->write(self::LBRACE); + $this->pushContext(new TJSONProtocol_JSONPairContext($this)); + } + + private function writeJSONObjectEnd() { + $this->popContext(); + $this->trans_->write(self::RBRACE); + } + + private function writeJSONArrayStart() { + $this->context_->write(); + $this->trans_->write(self::LBRACKET); + $this->pushContext(new TJSONProtocol_JSONListContext($this)); + } + + private function writeJSONArrayEnd() { + $this->popContext(); + $this->trans_->write(self::RBRACKET); + } + + private function readJSONString($skipContext) { + if (!$skipContext) { + $this->context_->read(); + } + + $jsonString = ''; + $lastChar = NULL; + while (true) { + $ch = $this->reader_->read(); + $jsonString .= $ch; + if ($ch == self::QUOTE && + $lastChar !== NULL && + $lastChar !== self::ESCSEQ) { + break; + } + if ($ch == self::ESCSEQ && $lastChar == self::ESCSEQ) { + $lastChar = self::DOUBLEESC; + } else { + $lastChar = $ch; + } + } + return json_decode($jsonString); + } + + private function isJSONNumeric($b) { + switch ($b) { + case '+': + case '-': + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'E': + case 'e': + return true; + } + return false; + } + + private function readJSONNumericChars() { + $strbld = array(); + + while (true) { + $ch = $this->reader_->peek(); + + if (!$this->isJSONNumeric($ch)) { + break; + } + + $strbld[] = $this->reader_->read(); + } + + return implode("", $strbld); + } + + private function readJSONInteger() { + $this->context_->read(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + $str = $this->readJSONNumericChars(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + if (!is_numeric($str)) { + throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA); + } + + return intval($str); + } + + /** + * Identical to readJSONInteger but without the final cast. + * Needed for proper handling of i64 on 32 bit machines. Why a + * separate function? So we don't have to force the rest of the + * use cases through the extra conditional. + */ + private function readJSONIntegerAsString() { + $this->context_->read(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + $str = $this->readJSONNumericChars(); + + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + if (!is_numeric($str)) { + throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA); + } + + return $str; + } + + private function readJSONDouble() { + $this->context_->read(); + + if (substr($this->reader_->peek(), 0, 1) == self::QUOTE) { + $arr = $this->readJSONString(true); + + if ($arr == "NaN") { + return NAN; + } else if ($arr == "Infinity") { + return INF; + } else if (!$this->context_->escapeNum()) { + throw new TProtocolException("Numeric data unexpectedly quoted " . $arr, + TProtocolException::INVALID_DATA); + } + + return floatval($arr); + } else { + if ($this->context_->escapeNum()) { + $this->readJSONSyntaxChar(self::QUOTE); + } + + return floatval($this->readJSONNumericChars()); + } + } + + private function readJSONBase64() { + $arr = $this->readJSONString(false); + $data = base64_decode($arr, true); + + if ($data === false) { + throw new TProtocolException("Invalid base64 data " . $arr, TProtocolException::INVALID_DATA); + } + + return $data; + } + + private function readJSONObjectStart() { + $this->context_->read(); + $this->readJSONSyntaxChar(self::LBRACE); + $this->pushContext(new TJSONProtocol_JSONPairContext($this)); + } + + private function readJSONObjectEnd() { + $this->readJSONSyntaxChar(self::RBRACE); + $this->popContext(); + } + + private function readJSONArrayStart() + { + $this->context_->read(); + $this->readJSONSyntaxChar(self::LBRACKET); + $this->pushContext(new TJSONProtocol_JSONListContext($this)); + } + + private function readJSONArrayEnd() { + $this->readJSONSyntaxChar(self::RBRACKET); + $this->popContext(); + } + + /** + * Writes the message header + * + * @param string $name Function name + * @param int $type message type TMessageType::CALL or TMessageType::REPLY + * @param int $seqid The sequence id of this message + */ + public function writeMessageBegin($name, $type, $seqid) { + $this->writeJSONArrayStart(); + $this->writeJSONInteger(self::VERSION); + $this->writeJSONString($name); + $this->writeJSONInteger($type); + $this->writeJSONInteger($seqid); + } + + /** + * Close the message + */ + public function writeMessageEnd() { + $this->writeJSONArrayEnd(); + } + + /** + * Writes a struct header. + * + * @param string $name Struct name + * @throws TException on write error + * @return int How many bytes written + */ + public function writeStructBegin($name) { + $this->writeJSONObjectStart(); + } + + /** + * Close a struct. + * + * @throws TException on write error + * @return int How many bytes written + */ + public function writeStructEnd() { + $this->writeJSONObjectEnd(); + } + + public function writeFieldBegin($fieldName, $fieldType, $fieldId) { + $this->writeJSONInteger($fieldId); + $this->writeJSONObjectStart(); + $this->writeJSONString($this->getTypeNameForTypeID($fieldType)); + } + + public function writeFieldEnd() { + $this->writeJsonObjectEnd(); + } + + public function writeFieldStop() { + } + + public function writeMapBegin($keyType, $valType, $size) { + $this->writeJSONArrayStart(); + $this->writeJSONString($this->getTypeNameForTypeID($keyType)); + $this->writeJSONString($this->getTypeNameForTypeID($valType)); + $this->writeJSONInteger($size); + $this->writeJSONObjectStart(); + } + + public function writeMapEnd() { + $this->writeJSONObjectEnd(); + $this->writeJSONArrayEnd(); + } + + public function writeListBegin($elemType, $size) { + $this->writeJSONArrayStart(); + $this->writeJSONString($this->getTypeNameForTypeID($elemType)); + $this->writeJSONInteger($size); + } + + public function writeListEnd() { + $this->writeJSONArrayEnd(); + } + + public function writeSetBegin($elemType, $size) { + $this->writeJSONArrayStart(); + $this->writeJSONString($this->getTypeNameForTypeID($elemType)); + $this->writeJSONInteger($size); + } + + public function writeSetEnd() { + $this->writeJSONArrayEnd(); + } + + public function writeBool($bool) { + $this->writeJSONInteger($bool ? 1 : 0); + } + + public function writeByte($byte) { + $this->writeJSONInteger($byte); + } + + public function writeI16($i16) { + $this->writeJSONInteger($i16); + } + + public function writeI32($i32) { + $this->writeJSONInteger($i32); + } + + public function writeI64($i64) { + $this->writeJSONInteger($i64); + } + + public function writeDouble($dub) { + $this->writeJSONDouble($dub); + } + + public function writeString($str) { + $this->writeJSONString($str); + } + + /** + * Reads the message header + * + * @param string $name Function name + * @param int $type message type TMessageType::CALL or TMessageType::REPLY + * @parem int $seqid The sequence id of this message + */ + public function readMessageBegin(&$name, &$type, &$seqid) { + $this->readJSONArrayStart(); + + if ($this->readJSONInteger() != self::VERSION) { + throw new TProtocolException("Message contained bad version", TProtocolException::BAD_VERSION); + } + + $name = $this->readJSONString(false); + $type = $this->readJSONInteger(); + $seqid = $this->readJSONInteger(); + + return true; + } + + /** + * Read the close of message + */ + public function readMessageEnd() { + $this->readJSONArrayEnd(); + } + + public function readStructBegin(&$name) { + $this->readJSONObjectStart(); + return 0; + } + + public function readStructEnd() { + $this->readJSONObjectEnd(); + } + + public function readFieldBegin(&$name, &$fieldType, &$fieldId) { + $ch = $this->reader_->peek(); + $name = ""; + + if (substr($ch, 0, 1) == self::RBRACE) { + $fieldType = TType::STOP; + } else { + $fieldId = $this->readJSONInteger(); + $this->readJSONObjectStart(); + $fieldType = $this->getTypeIDForTypeName($this->readJSONString(false)); + } + } + + public function readFieldEnd() { + $this->readJSONObjectEnd(); + } + + public function readMapBegin(&$keyType, &$valType, &$size) { + $this->readJSONArrayStart(); + $keyType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $valType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $size = $this->readJSONInteger(); + $this->readJSONObjectStart(); + } + + public function readMapEnd() { + $this->readJSONObjectEnd(); + $this->readJSONArrayEnd(); + } + + public function readListBegin(&$elemType, &$size) { + $this->readJSONArrayStart(); + $elemType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $size = $this->readJSONInteger(); + return true; + } + + public function readListEnd() { + $this->readJSONArrayEnd(); + } + + public function readSetBegin(&$elemType, &$size) { + $this->readJSONArrayStart(); + $elemType = $this->getTypeIDForTypeName($this->readJSONString(false)); + $size = $this->readJSONInteger(); + return true; + } + + public function readSetEnd() { + $this->readJSONArrayEnd(); + } + + public function readBool(&$bool) { + $bool = $this->readJSONInteger() == 0 ? false : true; + return true; + } + + public function readByte(&$byte) { + $byte = $this->readJSONInteger(); + return true; + } + + public function readI16(&$i16) { + $i16 = $this->readJSONInteger(); + return true; + } + + public function readI32(&$i32) { + $i32 = $this->readJSONInteger(); + return true; + } + + public function readI64(&$i64) { + if ( PHP_INT_SIZE === 4 ) { + $i64 = $this->readJSONIntegerAsString(); + } else { + $i64 = $this->readJSONInteger(); + } + return true; + } + + public function readDouble(&$dub) { + $dub = $this->readJSONDouble(); + return true; + } + + public function readString(&$str) { + $str = $this->readJSONString(false); + return true; + } +} + +/** + * JSON Protocol Factory + */ +class TJSONProtocolFactory implements TProtocolFactory +{ + public function __construct() + { + } + + public function getProtocol($trans) + { + return new TJSONProtocol($trans); + } +} + +class TJSONProtocol_JSONBaseContext +{ + function escapeNum() + { + return false; + } + + function write() + { + } + + function read() + { + } +} + +class TJSONProtocol_JSONListContext extends TJSONProtocol_JSONBaseContext +{ + private $first_ = true; + private $p_; + + public function __construct($p) { + $this->p_ = $p; + } + + public function write() { + if ($this->first_) { + $this->first_ = false; + } else { + $this->p_->getTransport()->write(TJSONProtocol::COMMA); + } + } + + public function read() { + if ($this->first_) { + $this->first_ = false; + } else { + $this->p_->readJSONSyntaxChar(TJSONProtocol::COMMA); + } + } +} + +class TJSONProtocol_JSONPairContext extends TJSONProtocol_JSONBaseContext { + private $first_ = true; + private $colon_ = true; + private $p_ = null; + + public function __construct($p) { + $this->p_ = $p; + } + + public function write() { + if ($this->first_) { + $this->first_ = false; + $this->colon_ = true; + } else { + $this->p_->getTransport()->write($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA); + $this->colon_ = !$this->colon_; + } + } + + public function read() { + if ($this->first_) { + $this->first_ = false; + $this->colon_ = true; + } else { + $this->p_->readJSONSyntaxChar($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA); + $this->colon_ = !$this->colon_; + } + } + + public function escapeNum() { + return $this->colon_; + } +} + +class TJSONProtocol_LookaheadReader +{ + private $hasData_ = false; + private $data_ = array(); + private $p_; + + public function __construct($p) + { + $this->p_ = $p; + } + + public function read() { + if ($this->hasData_) { + $this->hasData_ = false; + } else { + $this->data_ = $this->p_->getTransport()->readAll(1); + } + + return substr($this->data_, 0, 1); + } + + public function peek() { + if (!$this->hasData_) { + $this->data_ = $this->p_->getTransport()->readAll(1); + } + + $this->hasData_ = true; + return substr($this->data_, 0, 1); + } +} + + diff --git a/lib/php/test/Fixtures.php b/lib/php/test/Fixtures.php new file mode 100755 index 00000000..de7d9aaf --- /dev/null +++ b/lib/php/test/Fixtures.php @@ -0,0 +1,188 @@ +<><"; + + self::$testArgs['testString3'] = + "string that ends in double-backslash \\\\"; + + self::$testArgs['testDouble'] = 3.1415926535898; + + self::$testArgs['testByte'] = 0x01; + + self::$testArgs['testI32'] = pow( 2, 30 ); + + if ( PHP_INT_SIZE == 8 ) + { + self::$testArgs['testI64'] = pow( 2, 60 ); + } + else + { + self::$testArgs['testI64'] = "1152921504606847000"; + } + + self::$testArgs['testStruct'] = + new ThriftTest_Xtruct( + array( + 'string_thing' => 'worked', + 'byte_thing' => 0x01, + 'i32_thing' => pow( 2, 30 ), + 'i64_thing' => self::$testArgs['testI64'] + ) + ); + + self::$testArgs['testNestNested'] = + new ThriftTest_Xtruct( + array( + 'string_thing' => 'worked', + 'byte_thing' => 0x01, + 'i32_thing' => pow( 2, 30 ), + 'i64_thing' => self::$testArgs['testI64'] + ) + ); + + self::$testArgs['testNest'] = + new ThriftTest_Xtruct2( + array( + 'byte_thing' => 0x01, + 'struct_thing' => self::$testArgs['testNestNested'], + 'i32_thing' => pow( 2, 15 ) + ) + ); + + self::$testArgs['testMap'] = + array( + 7 => 77, + 8 => 88, + 9 => 99 + ); + + self::$testArgs['testStringMap'] = + array( + "a" => "123", + "a b" => "with spaces ", + "same" => "same", + "0" => "numeric key", + "longValue" => self::$testArgs['testString1'], + self::$testArgs['testString1'] => "long key" + ); + + self::$testArgs['testSet'] = array( 1 => true, 5 => true, 6 => true ); + + self::$testArgs['testList'] = array( 1, 2, 3 ); + + self::$testArgs['testEnum'] = ThriftTest_Numberz::ONE; + + self::$testArgs['testTypedef'] = 69; + + self::$testArgs['testMapMapExpectedResult'] = + array( + 4 => array( + 1 => 1, + 2 => 2, + 3 => 3, + 4 => 4, + ), + -4 => array( + -4 => -4, + -3 => -3, + -2 => -2, + -1 => -1 + ) + ); + + // testInsanity ... takes a few steps to set up! + + $xtruct1 = + new ThriftTest_Xtruct( + array( + 'string_thing' => 'Goodbye4', + 'byte_thing' => 4, + 'i32_thing' => 4, + 'i64_thing' => 4 + ) + ); + + $xtruct2 = + new ThriftTest_Xtruct( + array( + 'string_thing' => 'Hello2', + 'byte_thing' =>2, + 'i32_thing' => 2, + 'i64_thing' => 2 + ) + ); + + $userMap = + array( + ThriftTest_Numberz::FIVE => 5, + ThriftTest_Numberz::EIGHT => 8 + ); + + $insanity2 = + new ThriftTest_Insanity( + array( + 'userMap' => $userMap, + 'xtructs' => array($xtruct1,$xtruct2) + ) + ); + + $insanity3 = $insanity2; + + $insanity6 = + new ThriftTest_Insanity( + array( + 'userMap' => null, + 'xtructs' => null + ) + ); + + self::$testArgs['testInsanityExpectedResult'] = + array( + "1" => array( + ThriftTest_Numberz::TWO => $insanity2, + ThriftTest_Numberz::THREE => $insanity3 + ), + "2" => array( + ThriftTest_Numberz::SIX => $insanity6 + ) + ); + + } +} diff --git a/lib/php/test/Makefile.am b/lib/php/test/Makefile.am new file mode 100755 index 00000000..7739ac8a --- /dev/null +++ b/lib/php/test/Makefile.am @@ -0,0 +1,36 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +THRIFT = $(top_builddir)/compiler/cpp/thrift + +stubs: ../../../test/ThriftTest.thrift + mkdir -p ../src/packages + $(THRIFT) --gen php -r --out ../src/packages ../../../test/ThriftTest.thrift + +if HAVE_PHPUNIT +check: stubs + $(PHPUNIT) protocol/TestTJSONProtocol.php +endif + +clean-local: + $(RM) -r gen-php + +EXTRA_DIST = \ + Fixtures.cpp \ + protocol/TestTJSONProtocol.php diff --git a/lib/php/test/protocol/TestTJSONProtocol.php b/lib/php/test/protocol/TestTJSONProtocol.php new file mode 100755 index 00000000..79d8908f --- /dev/null +++ b/lib/php/test/protocol/TestTJSONProtocol.php @@ -0,0 +1,555 @@ +transport = new TMemoryBuffer(); + $this->protocol = new TJSONProtocol($this->transport); + $this->transport->open(); + } + + /*** + * WRITE TESTS + */ + + public function testVoid_Write() + { + $args = new ThriftTest_ThriftTest_testVoid_args(); + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testVoid']; + + $this->assertEquals( $expected, $actual ); + } + + public function testString1_Write() + { + $args = new ThriftTest_ThriftTest_testString_args(); + $args->thing = Fixtures::$testArgs['testString1']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testString1']; + + #$this->assertEquals( $expected, $actual ); + } + + public function testString2_Write() + { + $args = new ThriftTest_ThriftTest_testString_args(); + $args->thing = Fixtures::$testArgs['testString2']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testString2']; + + $this->assertEquals( $expected, $actual ); + } + + public function testDouble_Write() + { + $args = new ThriftTest_ThriftTest_testDouble_args(); + $args->thing = Fixtures::$testArgs['testDouble']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testDouble']; + + $this->assertEquals( $expected, $actual ); + } + + public function testByte_Write() + { + $args = new ThriftTest_ThriftTest_testByte_args(); + $args->thing = Fixtures::$testArgs['testByte']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testByte']; + + $this->assertEquals( $expected, $actual ); + } + + public function testI32_Write() + { + $args = new ThriftTest_ThriftTest_testI32_args(); + $args->thing = Fixtures::$testArgs['testI32']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testI32']; + + $this->assertEquals( $expected, $actual ); + } + + public function testI64_Write() + { + $args = new ThriftTest_ThriftTest_testI64_args(); + $args->thing = Fixtures::$testArgs['testI64']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testI64']; + + $this->assertEquals( $expected, $actual ); + } + + public function testStruct_Write() + { + $args = new ThriftTest_ThriftTest_testStruct_args(); + $args->thing = Fixtures::$testArgs['testStruct']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testStruct']; + + $this->assertEquals( $expected, $actual ); + } + + public function testNest_Write() + { + $args = new ThriftTest_ThriftTest_testNest_args(); + $args->thing = Fixtures::$testArgs['testNest']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testNest']; + + $this->assertEquals( $expected, $actual ); + } + + public function testMap_Write() + { + $args = new ThriftTest_ThriftTest_testMap_args(); + $args->thing = Fixtures::$testArgs['testMap']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testMap']; + + $this->assertEquals( $expected, $actual ); + } + + public function testStringMap_Write() + { + $args = new ThriftTest_ThriftTest_testStringMap_args(); + $args->thing = Fixtures::$testArgs['testStringMap']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testStringMap']; + + $this->assertEquals( $expected, $actual ); + } + + public function testSet_Write() + { + $args = new ThriftTest_ThriftTest_testSet_args(); + $args->thing = Fixtures::$testArgs['testSet']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testSet']; + + $this->assertEquals( $expected, $actual ); + } + + public function testList_Write() + { + $args = new ThriftTest_ThriftTest_testList_args(); + $args->thing = Fixtures::$testArgs['testList']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testList']; + + $this->assertEquals( $expected, $actual ); + } + + public function testEnum_Write() + { + $args = new ThriftTest_ThriftTest_testEnum_args(); + $args->thing = Fixtures::$testArgs['testEnum']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testEnum']; + + $this->assertEquals( $expected, $actual ); + } + + public function testTypedef_Write() + { + $args = new ThriftTest_ThriftTest_testTypedef_args(); + $args->thing = Fixtures::$testArgs['testTypedef']; + + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testTypedef']; + + $this->assertEquals( $expected, $actual ); + } + + /*** + * READ TESTS + */ + + public function testVoid_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testVoid'] + ); + $args = new ThriftTest_ThriftTest_testVoid_args(); + $args->read( $this->protocol ); + } + + public function testString1_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testString1'] + ); + $args = new ThriftTest_ThriftTest_testString_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testString1']; + + $this->assertEquals( $expected, $actual ); + } + + public function testString2_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testString2'] + ); + $args = new ThriftTest_ThriftTest_testString_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testString2']; + + $this->assertEquals( $expected, $actual ); + } + + public function testString3_Write() + { + $args = new ThriftTest_ThriftTest_testString_args(); + $args->thing = Fixtures::$testArgs['testString3']; + $args->write( $this->protocol ); + + $actual = $this->transport->read( BUFSIZ ); + $expected = TestTJSONProtocol_Fixtures::$testArgsJSON['testString3']; + + $this->assertEquals( $expected, $actual ); + } + + public function testDouble_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testDouble'] + ); + $args = new ThriftTest_ThriftTest_testDouble_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testDouble']; + + $this->assertEquals( $expected, $actual ); + } + + public function testByte_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testByte'] + ); + $args = new ThriftTest_ThriftTest_testByte_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testByte']; + + $this->assertEquals( $expected, $actual ); + } + + public function testI32_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testI32'] + ); + $args = new ThriftTest_ThriftTest_testI32_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testI32']; + + $this->assertEquals( $expected, $actual ); + } + + public function testI64_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testI64'] + ); + $args = new ThriftTest_ThriftTest_testI64_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testI64']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testStruct_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testStruct'] + ); + $args = new ThriftTest_ThriftTest_testStruct_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testStruct']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testNest_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testNest'] + ); + $args = new ThriftTest_ThriftTest_testNest_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testNest']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testMap_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testMap'] + ); + $args = new ThriftTest_ThriftTest_testMap_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testMap']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testStringMap_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testStringMap'] + ); + $args = new ThriftTest_ThriftTest_testStringMap_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testStringMap']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testSet_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testSet'] + ); + $args = new ThriftTest_ThriftTest_testSet_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testSet']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testList_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testList'] + ); + $args = new ThriftTest_ThriftTest_testList_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testList']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testEnum_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testEnum'] + ); + $args = new ThriftTest_ThriftTest_testEnum_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testEnum']; + + $this->assertEquals( $expected, $actual ); + + } + + public function testTypedef_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testTypedef'] + ); + $args = new ThriftTest_ThriftTest_testTypedef_args(); + $args->read( $this->protocol ); + + $actual = $args->thing; + $expected = Fixtures::$testArgs['testTypedef']; + + $this->assertEquals( $expected, $actual ); + } + + public function testMapMap_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testMapMap'] + ); + $result = new ThriftTest_ThriftTest_testMapMap_result(); + $result->read( $this->protocol ); + + $actual = $result->success; + $expected = Fixtures::$testArgs['testMapMapExpectedResult']; + + $this->assertEquals( $expected, $actual ); + } + + public function testInsanity_Read() + { + $this->transport->write( + TestTJSONProtocol_Fixtures::$testArgsJSON['testInsanity'] + ); + $result = new ThriftTest_ThriftTest_testInsanity_result(); + $result->read( $this->protocol ); + + $actual = $result->success; + $expected = Fixtures::$testArgs['testInsanityExpectedResult']; + + $this->assertEquals( $expected, $actual ); + } + +} + +class TestTJSONProtocol_Fixtures +{ + public static $testArgsJSON = array(); + + public static function populateTestArgsJSON() + { + self::$testArgsJSON['testVoid'] = '{}'; + + self::$testArgsJSON['testString1'] = '{"1":{"str":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e"}}'; + + self::$testArgsJSON['testString2'] = '{"1":{"str":"quote: \\\\\" backslash: forwardslash-escaped: \\\\\/ backspace: \\\\b formfeed: \f newline: \n return: \r tab: now-all-of-them-together: \"\\\\\\\\\/\\\\b\n\r\t now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"}}'; + + self::$testArgsJSON['testString3'] = '{"1":{"str":"string that ends in double-backslash \\\\\\\\"}}'; + + self::$testArgsJSON['testDouble'] = '{"1":{"dbl":3.1415926535898}}'; + + self::$testArgsJSON['testByte'] = '{"1":{"i8":1}}'; + + self::$testArgsJSON['testI32'] = '{"1":{"i32":1073741824}}'; + + self::$testArgsJSON['testI64'] = '{"1":{"i64":1152921504606847000}}'; + + self::$testArgsJSON['testStruct'] = '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}}}'; + + self::$testArgsJSON['testNest'] = '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}},"3":{"i32":32768}}}}'; + + self::$testArgsJSON['testMap'] = '{"1":{"map":["i32","i32",3,{"7":77,"8":88,"9":99}]}}'; + + self::$testArgsJSON['testStringMap'] = '{"1":{"map":["str","str",6,{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}]}}'; + + self::$testArgsJSON['testSet'] = '{"1":{"set":["i32",3,1,5,6]}}'; + + self::$testArgsJSON['testList'] = '{"1":{"lst":["i32",3,1,2,3]}}'; + + self::$testArgsJSON['testEnum'] = '{"1":{"i32":1}}'; + + self::$testArgsJSON['testTypedef'] = '{"1":{"i64":69}}'; + + self::$testArgsJSON['testMapMap'] = '{"0":{"map":["i32","map",2,{"4":["i32","i32",4,{"1":1,"2":2,"3":3,"4":4}],"-4":["i32","i32",4,{"-4":-4,"-3":-3,"-2":-2,"-1":-1}]}]}}'; + + self::$testArgsJSON['testInsanity'] = '{"0":{"map":["i64","map",2,{"1":["i32","rec",2,{"2":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}},"3":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}}}],"2":["i32","rec",1,{"6":{}}]}]}}'; + + } +}