From 651ba62ab5a9c35e157380e2fd89cf77febb47b9 Mon Sep 17 00:00:00 2001
From: Adam Cozzette <acozzette@google.com>
Date: Mon, 6 Mar 2017 15:12:19 -0800
Subject: [PATCH] JS: ensure that extension values are serialized even if
 they're falsy

There was a bug where for JavaScript we would only serialize an
extension value if it evaluated as truthy, which meant that values like
0 would get silently dropped (even in proto2, where field presence is
significant). This fixes issue #2605, and takes care of the output of
toObject() in addition to the binary format.
---
 js/binary/proto_test.js | 6 ++----
 js/message.js           | 4 ++--
 js/message_test.js      | 3 ++-
 3 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/js/binary/proto_test.js b/js/binary/proto_test.js
index f86dc6455b..f5e1b6bbf0 100644
--- a/js/binary/proto_test.js
+++ b/js/binary/proto_test.js
@@ -283,8 +283,7 @@ function checkAllFields(original, copy) {
  * @param {!proto.jspb.test.TestExtendable} msg
  */
 function checkExtensions(msg) {
-  assertEquals(-42,
-      msg.getExtension(proto.jspb.test.extendOptionalInt32));
+  assertEquals(0, msg.getExtension(proto.jspb.test.extendOptionalInt32));
   assertEquals(-0x7fffffff00000000,
       msg.getExtension(proto.jspb.test.extendOptionalInt64));
   assertEquals(0x80000000,
@@ -512,8 +511,7 @@ describe('protoBinaryTest', function() {
    * @param {proto.jspb.test.TestExtendable} msg
    */
   function fillExtensions(msg) {
-    msg.setExtension(
-        proto.jspb.test.extendOptionalInt32, -42);
+    msg.setExtension(proto.jspb.test.extendOptionalInt32, 0);
     msg.setExtension(
         proto.jspb.test.extendOptionalInt64, -0x7fffffff00000000);
     msg.setExtension(
diff --git a/js/message.js b/js/message.js
index 05d34e9d95..4e2517d3e6 100644
--- a/js/message.js
+++ b/js/message.js
@@ -497,7 +497,7 @@ jspb.Message.toObjectExtension = function(proto, obj, extensions,
   for (var fieldNumber in extensions) {
     var fieldInfo = extensions[fieldNumber];
     var value = getExtensionFn.call(proto, fieldInfo);
-    if (value) {
+    if (goog.isDefAndNotNull(value)) {
       for (var name in fieldInfo.fieldName) {
         if (fieldInfo.fieldName.hasOwnProperty(name)) {
           break; // the compiled field name
@@ -541,7 +541,7 @@ jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
                       'without binary serialization support');
     }
     var value = getExtensionFn.call(proto, fieldInfo);
-    if (value) {
+    if (goog.isDefAndNotNull(value)) {
       if (fieldInfo.isMessageType()) {
         // If the message type of the extension was generated without binary
         // support, there may not be a binary message serializer function, and
diff --git a/js/message_test.js b/js/message_test.js
index a2c5763dde..2298742d77 100644
--- a/js/message_test.js
+++ b/js/message_test.js
@@ -693,10 +693,11 @@ describe('Message test suite', function() {
      });
 
   it('testToObject_hasExtensionField', function() {
-    var data = new proto.jspb.test.HasExtensions(['str1', {100: ['ext1']}]);
+    var data = new proto.jspb.test.HasExtensions(['str1', {100: ['ext1'], 102: ''}]);
     var obj = data.toObject();
     assertEquals('str1', obj.str1);
     assertEquals('ext1', obj.extField.ext1);
+    assertEquals('', obj.str);
   });
 
   it('testGetExtension', function() {