Przeglądaj źródła

Adopt upb change for timestamp and duration json to php (#5106)

* Adopt upb change for timestamp and duration json to php

* Remove unused code

* Re-sync upb

* Fix php implementation timestamp json parsing

* Fix strptime use local timezone on mac.

* Remove succeeding tests

* Resync

* Add tests for values

* Fix php tests

* Fix encoder handlers change default value

Previously, oneofsubmsg_handler and submsg_handler change zval's default value directly.
The fix use REPLACE_ZVAL_VALUE which create a copy of parsed value and assign it to zval.
Paul Yang 7 lat temu
rodzic
commit
9bda1f19bf

+ 2 - 37
conformance/failure_list_php_c.txt

@@ -5,8 +5,6 @@ Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
 Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator
-Recommended.Proto3.JsonInput.DurationHas9FractionalDigits.Validator
-Recommended.Proto3.JsonInput.DurationHasZeroFractionalDigit.Validator
 Recommended.Proto3.JsonInput.Int64FieldBeString.Validator
 Recommended.Proto3.JsonInput.MapFieldValueIsNull
 Recommended.Proto3.JsonInput.OneofZeroBytes.JsonOutput
@@ -18,13 +16,12 @@ Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate
 Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate
 Recommended.Proto3.JsonInput.TimestampHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.TimestampHas6FractionalDigits.Validator
-Recommended.Proto3.JsonInput.TimestampHas9FractionalDigits.Validator
-Recommended.Proto3.JsonInput.TimestampHasZeroFractionalDigit.Validator
-Recommended.Proto3.JsonInput.TimestampZeroNormalized.Validator
 Recommended.Proto3.JsonInput.Uint64FieldBeString.Validator
 Recommended.Proto3.ProtobufInput.OneofZeroBytes.JsonOutput
 Required.DurationProtoInputTooLarge.JsonOutput
 Required.DurationProtoInputTooSmall.JsonOutput
+Required.TimestampProtoInputTooLarge.JsonOutput
+Required.TimestampProtoInputTooSmall.JsonOutput
 Required.Proto3.JsonInput.Any.JsonOutput
 Required.Proto3.JsonInput.Any.ProtobufOutput
 Required.Proto3.JsonInput.AnyNested.JsonOutput
@@ -51,12 +48,8 @@ Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldNan.JsonOutput
-Required.Proto3.JsonInput.DurationMaxValue.JsonOutput
-Required.Proto3.JsonInput.DurationMaxValue.ProtobufOutput
 Required.Proto3.JsonInput.DurationMinValue.JsonOutput
-Required.Proto3.JsonInput.DurationMinValue.ProtobufOutput
 Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput
-Required.Proto3.JsonInput.DurationRepeatedValue.ProtobufOutput
 Required.Proto3.JsonInput.FieldMask.JsonOutput
 Required.Proto3.JsonInput.FieldMask.ProtobufOutput
 Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
@@ -73,36 +66,8 @@ Required.Proto3.JsonInput.StringFieldUnicodeEscape.JsonOutput
 Required.Proto3.JsonInput.StringFieldUnicodeEscape.ProtobufOutput
 Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.JsonOutput
 Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
-Required.Proto3.JsonInput.Struct.JsonOutput
-Required.Proto3.JsonInput.Struct.ProtobufOutput
-Required.Proto3.JsonInput.TimestampMaxValue.JsonOutput
-Required.Proto3.JsonInput.TimestampMaxValue.ProtobufOutput
-Required.Proto3.JsonInput.TimestampMinValue.JsonOutput
-Required.Proto3.JsonInput.TimestampMinValue.ProtobufOutput
-Required.Proto3.JsonInput.TimestampRepeatedValue.JsonOutput
-Required.Proto3.JsonInput.TimestampRepeatedValue.ProtobufOutput
-Required.Proto3.JsonInput.TimestampWithNegativeOffset.JsonOutput
-Required.Proto3.JsonInput.TimestampWithNegativeOffset.ProtobufOutput
-Required.Proto3.JsonInput.TimestampWithPositiveOffset.JsonOutput
-Required.Proto3.JsonInput.TimestampWithPositiveOffset.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptBool.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptBool.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptFloat.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptFloat.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptInteger.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptInteger.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptList.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptList.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptNull.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptNull.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptObject.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptObject.ProtobufOutput
-Required.Proto3.JsonInput.ValueAcceptString.JsonOutput
-Required.Proto3.JsonInput.ValueAcceptString.ProtobufOutput
 Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
 Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
 Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
 Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
 Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
-Required.TimestampProtoInputTooLarge.JsonOutput
-Required.TimestampProtoInputTooSmall.JsonOutput

+ 69 - 46
php/ext/google/protobuf/encode_decode.c

@@ -132,6 +132,12 @@ static void stackenv_uninit(stackenv* se) {
 // Parsing.
 // -----------------------------------------------------------------------------
 
+// TODO(teboring): This shoud be a bit in upb_msgdef
+static bool is_wrapper_msg(const upb_msgdef *msg) {
+  return !strcmp(upb_filedef_name(upb_msgdef_upcast(msg)->file),
+                 "google/protobuf/wrappers.proto");
+}
+
 #define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs)
 
 // Creates a handlerdata that simply contains the offset for this field.
@@ -420,13 +426,13 @@ static void *submsg_handler(void *closure, const void *hd) {
   if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(message_data(msg), submsgdata->ofs,
                                             CACHED_VALUE*))) == IS_NULL) {
 #if PHP_MAJOR_VERSION < 7
-    zval* val = NULL;
-    MAKE_STD_ZVAL(val);
-    ZVAL_OBJ(val, subklass->create_object(subklass TSRMLS_CC));
-    MessageHeader* intern = UNBOX(MessageHeader, val);
+    zval val;
+    ZVAL_OBJ(&val, subklass->create_object(subklass TSRMLS_CC));
+    MessageHeader* intern = UNBOX(MessageHeader, &val);
     custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC);
-    php_proto_zval_ptr_dtor(*DEREF(message_data(msg), submsgdata->ofs, zval**));
-    *DEREF(message_data(msg), submsgdata->ofs, zval**) = val;
+    REPLACE_ZVAL_VALUE(DEREF(message_data(msg), submsgdata->ofs, zval**),
+                       &val, 1);
+    zval_dtor(&val);
 #else
     zend_object* obj = subklass->create_object(subklass TSRMLS_CC);
     ZVAL_OBJ(DEREF(message_data(msg), submsgdata->ofs, zval*), obj);
@@ -765,9 +771,16 @@ static void* oneofsubmsg_handler(void* closure, const void* hd) {
     // Create new message.
     DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*) =
         OBJ_PROP(&msg->std, oneofdata->property_ofs);
-    ZVAL_OBJ(CACHED_PTR_TO_ZVAL_PTR(
-        DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*)),
-        subklass->create_object(subklass TSRMLS_CC));
+#if PHP_MAJOR_VERSION < 7
+    zval val;
+    ZVAL_OBJ(&val, subklass->create_object(subklass TSRMLS_CC));
+    REPLACE_ZVAL_VALUE(DEREF(message_data(msg), oneofdata->ofs, zval**),
+                       &val, 1);
+    zval_dtor(&val);
+#else
+    zend_object* obj = subklass->create_object(subklass TSRMLS_CC);
+    ZVAL_OBJ(DEREF(message_data(msg), oneofdata->ofs, zval*), obj);
+#endif
   }
 
   DEREF(message_data(msg), oneofdata->case_ofs, uint32_t) =
@@ -1080,24 +1093,25 @@ static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
 // -----------------------------------------------------------------------------
 
 static void putmsg(zval* msg, const Descriptor* desc, upb_sink* sink,
-                   int depth TSRMLS_DC);
+                   int depth, bool is_json TSRMLS_DC);
 static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
-                      upb_sink* sink, int depth TSRMLS_DC);
+                      upb_sink* sink, int depth, bool is_json TSRMLS_DC);
 
-static void putstr(zval* str, const upb_fielddef* f, upb_sink* sink);
+static void putstr(zval* str, const upb_fielddef* f, upb_sink* sink,
+                   bool force_default);
 
 static void putrawstr(const char* str, int len, const upb_fielddef* f,
-                      upb_sink* sink);
+                      upb_sink* sink, bool force_default);
 
 static void putsubmsg(zval* submsg, const upb_fielddef* f, upb_sink* sink,
-                      int depth TSRMLS_DC);
+                      int depth, bool is_json TSRMLS_DC);
 static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f,
-                         upb_sink* sink, int depth TSRMLS_DC);
+                         upb_sink* sink, int depth, bool is_json TSRMLS_DC);
 
 static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
-                     int depth TSRMLS_DC);
+                     int depth, bool is_json TSRMLS_DC);
 static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
-                   int depth TSRMLS_DC);
+                   int depth, bool is_json TSRMLS_DC);
 
 static upb_selector_t getsel(const upb_fielddef* f, upb_handlertype_t type) {
   upb_selector_t ret;
@@ -1106,8 +1120,10 @@ static upb_selector_t getsel(const upb_fielddef* f, upb_handlertype_t type) {
   return ret;
 }
 
-static void put_optional_value(const void* memory, int len, const upb_fielddef* f,
-                               int depth, upb_sink* sink TSRMLS_DC) {
+static void put_optional_value(const void* memory, int len,
+                               const upb_fielddef* f,
+                               int depth, upb_sink* sink,
+                               bool is_json TSRMLS_DC) {
   assert(upb_fielddef_label(f) == UPB_LABEL_OPTIONAL);
 
   switch (upb_fielddef_type(f)) {
@@ -1132,7 +1148,8 @@ static void put_optional_value(const void* memory, int len, const upb_fielddef*
 #undef T
     case UPB_TYPE_STRING:
     case UPB_TYPE_BYTES:
-      putrawstr(memory, len, f, sink);
+      putrawstr(memory, len, f, sink,
+                is_json && is_wrapper_msg(upb_fielddef_containingtype(f)));
       break;
     case UPB_TYPE_MESSAGE: {
 #if PHP_MAJOR_VERSION < 7
@@ -1142,7 +1159,7 @@ static void put_optional_value(const void* memory, int len, const upb_fielddef*
           (MessageHeader*)((char*)(*(zend_object**)memory) -
               XtOffsetOf(MessageHeader, std));
 #endif
-      putrawsubmsg(submsg, f, sink, depth TSRMLS_CC);
+      putrawsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC);
       break;
     }
     default:
@@ -1181,7 +1198,7 @@ static int raw_value_len(void* memory, int len, const upb_fielddef* f) {
 }
 
 static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
-                   int depth TSRMLS_DC) {
+                   int depth, bool is_json TSRMLS_DC) {
   upb_sink subsink;
   const upb_fielddef* key_field;
   const upb_fielddef* value_field;
@@ -1209,13 +1226,14 @@ static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
 
     // Serialize key.
     const char *key = map_iter_key(&it, &len);
-    put_optional_value(key, len, key_field, depth + 1, &entry_sink TSRMLS_CC);
+    put_optional_value(key, len, key_field, depth + 1,
+                       &entry_sink, is_json TSRMLS_CC);
 
     // Serialize value.
     upb_value value = map_iter_value(&it, &len);
     put_optional_value(raw_value(upb_value_memory(&value), value_field),
                        raw_value_len(upb_value_memory(&value), len, value_field),
-                       value_field, depth + 1, &entry_sink TSRMLS_CC);
+                       value_field, depth + 1, &entry_sink, is_json TSRMLS_CC);
 
     upb_sink_endmsg(&entry_sink, &status);
     upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
@@ -1225,13 +1243,13 @@ static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
 }
 
 static void putmsg(zval* msg_php, const Descriptor* desc, upb_sink* sink,
-                   int depth TSRMLS_DC) {
+                   int depth, bool is_json TSRMLS_DC) {
   MessageHeader* msg = UNBOX(MessageHeader, msg_php);
-  putrawmsg(msg, desc, sink, depth TSRMLS_CC);
+  putrawmsg(msg, desc, sink, depth, is_json TSRMLS_CC);
 }
 
 static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
-                      upb_sink* sink, int depth TSRMLS_DC) {
+                      upb_sink* sink, int depth, bool is_json TSRMLS_DC) {
   upb_msg_field_iter i;
   upb_status status;
 
@@ -1268,31 +1286,34 @@ static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
       zval* map = CACHED_PTR_TO_ZVAL_PTR(
           DEREF(message_data(msg), offset, CACHED_VALUE*));
       if (map != NULL) {
-        putmap(map, f, sink, depth TSRMLS_CC);
+        putmap(map, f, sink, depth, is_json TSRMLS_CC);
       }
     } else if (upb_fielddef_isseq(f)) {
       zval* array = CACHED_PTR_TO_ZVAL_PTR(
           DEREF(message_data(msg), offset, CACHED_VALUE*));
       if (array != NULL) {
-        putarray(array, f, sink, depth TSRMLS_CC);
+        putarray(array, f, sink, depth, is_json TSRMLS_CC);
       }
     } else if (upb_fielddef_isstring(f)) {
       zval* str = CACHED_PTR_TO_ZVAL_PTR(
           DEREF(message_data(msg), offset, CACHED_VALUE*));
-      if (containing_oneof || Z_STRLEN_P(str) > 0) {
-        putstr(str, f, sink);
+      if (containing_oneof || (is_json && is_wrapper_msg(desc->msgdef)) ||
+          Z_STRLEN_P(str) > 0) {
+        putstr(str, f, sink, is_json && is_wrapper_msg(desc->msgdef));
       }
     } else if (upb_fielddef_issubmsg(f)) {
       putsubmsg(CACHED_PTR_TO_ZVAL_PTR(
                     DEREF(message_data(msg), offset, CACHED_VALUE*)),
-                f, sink, depth TSRMLS_CC);
+                f, sink, depth, is_json TSRMLS_CC);
     } else {
       upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
 
 #define T(upbtypeconst, upbtype, ctype, default_value)     \
   case upbtypeconst: {                                     \
     ctype value = DEREF(message_data(msg), offset, ctype); \
-    if (containing_oneof || value != default_value) {      \
+    if (containing_oneof ||                                \
+        (is_json && is_wrapper_msg(desc->msgdef)) ||       \
+        value != default_value) {                          \
       upb_sink_put##upbtype(sink, sel, value);             \
     }                                                      \
   } break;
@@ -1325,7 +1346,8 @@ static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
   upb_sink_endmsg(sink, &status);
 }
 
-static void putstr(zval* str, const upb_fielddef *f, upb_sink *sink) {
+static void putstr(zval* str, const upb_fielddef *f,
+                   upb_sink *sink, bool force_default) {
   upb_sink subsink;
 
   if (ZVAL_IS_NULL(str)) return;
@@ -1336,7 +1358,7 @@ static void putstr(zval* str, const upb_fielddef *f, upb_sink *sink) {
                     &subsink);
 
   // For oneof string field, we may get here with string length is zero.
-  if (Z_STRLEN_P(str) > 0) {
+  if (Z_STRLEN_P(str) > 0 || force_default) {
     // Ensure that the string has the correct encoding. We also check at
     // field-set time, but the user may have mutated the string object since
     // then.
@@ -1353,10 +1375,10 @@ static void putstr(zval* str, const upb_fielddef *f, upb_sink *sink) {
 }
 
 static void putrawstr(const char* str, int len, const upb_fielddef* f,
-                      upb_sink* sink) {
+                      upb_sink* sink, bool force_default) {
   upb_sink subsink;
 
-  if (len == 0) return;
+  if (len == 0 && !force_default) return;
 
   // Ensure that the string has the correct encoding. We also check at field-set
   // time, but the user may have mutated the string object since then.
@@ -1372,27 +1394,27 @@ static void putrawstr(const char* str, int len, const upb_fielddef* f,
 }
 
 static void putsubmsg(zval* submsg_php, const upb_fielddef* f, upb_sink* sink,
-                      int depth TSRMLS_DC) {
+                      int depth, bool is_json TSRMLS_DC) {
   if (Z_TYPE_P(submsg_php) == IS_NULL) return;
 
   MessageHeader *submsg = UNBOX(MessageHeader, submsg_php);
-  putrawsubmsg(submsg, f, sink, depth TSRMLS_CC);
+  putrawsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC);
 }
 
 static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f,
-                         upb_sink* sink, int depth TSRMLS_DC) {
+                         upb_sink* sink, int depth, bool is_json TSRMLS_DC) {
   upb_sink subsink;
 
   Descriptor* subdesc =
       UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(upb_fielddef_msgsubdef(f)));
 
   upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
-  putrawmsg(submsg, subdesc, &subsink, depth + 1 TSRMLS_CC);
+  putrawmsg(submsg, subdesc, &subsink, depth + 1, is_json TSRMLS_CC);
   upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
 }
 
 static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
-                     int depth TSRMLS_DC) {
+                     int depth, bool is_json TSRMLS_DC) {
   upb_sink subsink;
   upb_fieldtype_t type = upb_fielddef_type(f);
   upb_selector_t sel = 0;
@@ -1436,7 +1458,8 @@ static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
         const char* rawstr = ZSTR_VAL(*(zend_string**)memory);
         int len = ZSTR_LEN(*(zend_string**)memory);
 #endif
-        putrawstr(rawstr, len, f, &subsink);
+        putrawstr(rawstr, len, f, &subsink,
+                  is_json && is_wrapper_msg(upb_fielddef_containingtype(f)));
         break;
       }
       case UPB_TYPE_MESSAGE: {
@@ -1447,7 +1470,7 @@ static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
             (MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) -
                 XtOffsetOf(MessageHeader, std));
 #endif
-        putrawsubmsg(submsg, f, &subsink, depth TSRMLS_CC);
+        putrawsubmsg(submsg, f, &subsink, depth, is_json TSRMLS_CC);
         break;
       }
 
@@ -1504,7 +1527,7 @@ void serialize_to_string(zval* val, zval* return_value TSRMLS_DC) {
     stackenv_init(&se, "Error occurred during encoding: %s");
     encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
 
-    putmsg(val, desc, upb_pb_encoder_input(encoder), 0 TSRMLS_CC);
+    putmsg(val, desc, upb_pb_encoder_input(encoder), 0, false TSRMLS_CC);
 
     PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1);
 
@@ -1571,7 +1594,7 @@ PHP_METHOD(Message, serializeToJsonString) {
     stackenv_init(&se, "Error occurred during encoding: %s");
     printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink);
 
-    putmsg(getThis(), desc, upb_json_printer_input(printer), 0 TSRMLS_CC);
+    putmsg(getThis(), desc, upb_json_printer_input(printer), 0, true TSRMLS_CC);
 
     PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1);
 

Plik diff jest za duży
+ 244 - 1646
php/ext/google/protobuf/upb.c


Plik diff jest za duży
+ 876 - 800
php/ext/google/protobuf/upb.h


+ 2 - 2
php/src/Google/Protobuf/Internal/GPBUtil.php

@@ -438,8 +438,8 @@ class GPBUtil
                 $nanoseconds = intval($nanoseconds);
 
                 // remove the nanoseconds and preceding period from the timestamp
-                $date = substr($timestamp, 0, $periodIndex - 1);
-                $timezone = substr($timestamp, $periodIndex + $nanosecondsLength);
+                $date = substr($timestamp, 0, $periodIndex);
+                $timezone = substr($timestamp, $periodIndex + $nanosecondsLength + 1);
                 $timestamp = $date.$timezone;
             }
         }

+ 10 - 2
php/src/Google/Protobuf/Internal/Message.php

@@ -1157,9 +1157,17 @@ class Message
     public function parseFromJsonStream($input)
     {
         $array = json_decode($input->getData(), true, 512, JSON_BIGINT_AS_STRING);
+        if ($this instanceof \Google\Protobuf\ListValue) {
+            $array = ["values"=>$array];
+        }
         if (is_null($array)) {
-            throw new GPBDecodeException(
-                "Cannot decode json string.");
+            if ($this instanceof \Google\Protobuf\Value) {
+              $this->setNullValue(\Google\Protobuf\NullValue::NULL_VALUE);
+              return;
+            } else {
+              throw new GPBDecodeException(
+                  "Cannot decode json string: " . $input->getData());
+            }
         }
         try {
             $this->mergeFromJsonArray($array);

+ 182 - 0
php/tests/encode_decode_test.php

@@ -20,6 +20,9 @@ use Google\Protobuf\UInt64Value;
 use Google\Protobuf\BoolValue;
 use Google\Protobuf\StringValue;
 use Google\Protobuf\BytesValue;
+use Google\Protobuf\Value;
+use Google\Protobuf\ListValue;
+use Google\Protobuf\Struct;
 
 class EncodeDecodeTest extends TestBase
 {
@@ -40,6 +43,13 @@ class EncodeDecodeTest extends TestBase
         $this->assertEquals(false, $m->getValue());
     }
 
+    public function testEncodeTopLevelBoolValue()
+    {
+        $m = new BoolValue();
+        $m->setValue(true);
+        $this->assertSame("true", $m->serializeToJsonString());
+    }
+
     public function testDecodeTopLevelDoubleValue()
     {
         $m = new DoubleValue();
@@ -47,6 +57,13 @@ class EncodeDecodeTest extends TestBase
         $this->assertEquals(1.5, $m->getValue());
     }
 
+    public function testEncodeTopLevelDoubleValue()
+    {
+        $m = new DoubleValue();
+        $m->setValue(1.5);
+        $this->assertSame("1.5", $m->serializeToJsonString());
+    }
+
     public function testDecodeTopLevelFloatValue()
     {
         $m = new FloatValue();
@@ -54,6 +71,13 @@ class EncodeDecodeTest extends TestBase
         $this->assertEquals(1.5, $m->getValue());
     }
 
+    public function testEncodeTopLevelFloatValue()
+    {
+        $m = new FloatValue();
+        $m->setValue(1.5);
+        $this->assertSame("1.5", $m->serializeToJsonString());
+    }
+
     public function testDecodeTopLevelInt32Value()
     {
         $m = new Int32Value();
@@ -61,6 +85,13 @@ class EncodeDecodeTest extends TestBase
         $this->assertEquals(1, $m->getValue());
     }
 
+    public function testEncodeTopLevelInt32Value()
+    {
+        $m = new Int32Value();
+        $m->setValue(1);
+        $this->assertSame("1", $m->serializeToJsonString());
+    }
+
     public function testDecodeTopLevelUInt32Value()
     {
         $m = new UInt32Value();
@@ -68,6 +99,13 @@ class EncodeDecodeTest extends TestBase
         $this->assertEquals(1, $m->getValue());
     }
 
+    public function testEncodeTopLevelUInt32Value()
+    {
+        $m = new UInt32Value();
+        $m->setValue(1);
+        $this->assertSame("1", $m->serializeToJsonString());
+    }
+
     public function testDecodeTopLevelInt64Value()
     {
         $m = new Int64Value();
@@ -75,6 +113,13 @@ class EncodeDecodeTest extends TestBase
         $this->assertEquals(1, $m->getValue());
     }
 
+    # public function testEncodeTopLevelInt64Value()
+    # {
+    #     $m = new Int64Value();
+    #     $m->setValue(1);
+    #     $this->assertSame("\"1\"", $m->serializeToJsonString());
+    # }
+
     public function testDecodeTopLevelUInt64Value()
     {
         $m = new UInt64Value();
@@ -82,6 +127,13 @@ class EncodeDecodeTest extends TestBase
         $this->assertEquals(1, $m->getValue());
     }
 
+    # public function testEncodeTopLevelUInt64Value()
+    # {
+    #     $m = new UInt64Value();
+    #     $m->setValue(1);
+    #     $this->assertSame("\"1\"", $m->serializeToJsonString());
+    # }
+
     public function testDecodeTopLevelStringValue()
     {
         $m = new StringValue();
@@ -89,6 +141,13 @@ class EncodeDecodeTest extends TestBase
         $this->assertSame("a", $m->getValue());
     }
 
+    public function testEncodeTopLevelStringValue()
+    {
+        $m = new StringValue();
+        $m->setValue("a");
+        $this->assertSame("\"a\"", $m->serializeToJsonString());
+    }
+
     public function testDecodeTopLevelBytesValue()
     {
         $m = new BytesValue();
@@ -96,6 +155,13 @@ class EncodeDecodeTest extends TestBase
         $this->assertSame("a", $m->getValue());
     }
 
+    public function testEncodeTopLevelBytesValue()
+    {
+        $m = new BytesValue();
+        $m->setValue("a");
+        $this->assertSame("\"YQ==\"", $m->serializeToJsonString());
+    }
+
     public function testEncode()
     {
         $from = new TestMessage();
@@ -603,4 +669,120 @@ class EncodeDecodeTest extends TestBase
         $to->mergeFromJsonString($data);
         $this->expectFields($to);
     }
+
+    public function testDecodeDuration()
+    {
+        $m = new Google\Protobuf\Duration();
+        $m->mergeFromJsonString("\"1234.5678s\"");
+        $this->assertEquals(1234, $m->getSeconds());
+        $this->assertEquals(567800000, $m->getNanos());
+    }
+
+    public function testEncodeDuration()
+    {
+        $m = new Google\Protobuf\Duration();
+        $m->setSeconds(1234);
+        $m->setNanos(999999999);
+        $this->assertEquals("\"1234.999999999s\"", $m->serializeToJsonString());
+    }
+
+    public function testDecodeTimestamp()
+    {
+        $m = new Google\Protobuf\Timestamp();
+        $m->mergeFromJsonString("\"2000-01-01T00:00:00.123456789Z\"");
+        $this->assertEquals(946684800, $m->getSeconds());
+        $this->assertEquals(123456789, $m->getNanos());
+    }
+
+    public function testEncodeTimestamp()
+    {
+        $m = new Google\Protobuf\Timestamp();
+        $m->setSeconds(946684800);
+        $m->setNanos(123456789);
+        $this->assertEquals("\"2000-01-01T00:00:00.123456789Z\"",
+                            $m->serializeToJsonString());
+    }
+
+    public function testDecodeTopLevelValue()
+    {
+        $m = new Value();
+        $m->mergeFromJsonString("\"a\"");
+        $this->assertSame("a", $m->getStringValue());
+
+        $m = new Value();
+        $m->mergeFromJsonString("1.5");
+        $this->assertSame(1.5, $m->getNumberValue());
+
+        $m = new Value();
+        $m->mergeFromJsonString("true");
+        $this->assertSame(true, $m->getBoolValue());
+
+        $m = new Value();
+        $m->mergeFromJsonString("null");
+        $this->assertSame("null_value", $m->getKind());
+
+        $m = new Value();
+        $m->mergeFromJsonString("[1]");
+        $this->assertSame("list_value", $m->getKind());
+
+        $m = new Value();
+        $m->mergeFromJsonString("{\"a\":1}");
+        $this->assertSame("struct_value", $m->getKind());
+    }
+
+    public function testEncodeTopLevelValue()
+    {
+        $m = new Value();
+        $m->setStringValue("a");
+        $this->assertSame("\"a\"", $m->serializeToJsonString());
+
+        $m = new Value();
+        $m->setNumberValue(1.5);
+        $this->assertSame("1.5", $m->serializeToJsonString());
+
+        $m = new Value();
+        $m->setBoolValue(true);
+        $this->assertSame("true", $m->serializeToJsonString());
+
+        $m = new Value();
+        $m->setNullValue(0);
+        $this->assertSame("null", $m->serializeToJsonString());
+    }
+
+    public function testDecodeTopLevelListValue()
+    {
+        $m = new ListValue();
+        $m->mergeFromJsonString("[1]");
+        $this->assertSame(1.0, $m->getValues()[0]->getNumberValue());
+    }
+
+    public function testEncodeTopLevelListValue()
+    {
+        $m = new ListValue();
+        $arr = $m->getValues();
+        $sub = new Value();
+        $sub->setNumberValue(1.5);
+        $arr[] = $sub;
+        $this->assertSame("[1.5]", $m->serializeToJsonString());
+    }
+
+    public function testDecodeTopLevelStruct()
+    {
+        $m = new Struct();
+        $m->mergeFromJsonString("{\"a\":{\"b\":1}}");
+        $this->assertSame(1.0, $m->getFields()["a"]
+                                 ->getStructValue()
+                                 ->getFields()["b"]->getNumberValue());
+    }
+
+    public function testEncodeTopLevelStruct()
+    {
+        $m = new Struct();
+        $map = $m->getFields();
+        $sub = new Value();
+        $sub->setNumberValue(1.5);
+        $map["a"] = $sub;
+        $this->assertSame("{\"a\":1.5}", $m->serializeToJsonString());
+    }
+
 }

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików