Improve ProtoBuf.js version heuristic, add tests for oneof decoding
diff --git a/src/node/index.js b/src/node/index.js
index e41664e..ba73e3d 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -57,18 +57,53 @@
 
 grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii'));
 
+/**
+ * Load a ProtoBuf.js object as a gRPC object. The options object can provide
+ * the following options:
+ * - binaryAsBase64: deserialize bytes values as base64 strings instead of
+ *   Buffers. Defaults to false
+ * - longsAsStrings: deserialize long values as strings instead of objects.
+ *   Defaults to true
+ * - deprecatedArgumentOrder: Use the beta method argument order for client
+ *   methods, with optional arguments after the callback. Defaults to false.
+ *   This option is only a temporary stopgap measure to smooth an API breakage.
+ *   It is deprecated, and new code should not use it.
+ * - protobufjsVersion: Available values are 5, 6, and 'detect'. 5 and 6
+ *   respectively indicate that an object from the corresponding version of
+ *   ProtoBuf.js is provided in the value argument. If the option is 'detect',
+ *   gRPC will guess what the version is based on the structure of the value.
+ *   Defaults to 'detect'.
+ * @param {Object} value The ProtoBuf.js reflection object to load
+ * @param {Object=} options Options to apply to the loaded file
+ * @return {Object<string, *>} The resulting gRPC object
+ */
 exports.loadObject = function loadObject(value, options) {
   options = _.defaults(options, common.defaultGrpcOptions);
-  if (value instanceof ProtoBuf.ReflectionObject) {
-    return protobuf_js_6_common.loadObject(value, options);
+  options = _.defaults(options, {'protobufjsVersion': 'detect'});
+  var protobufjsVersion;
+  if (options.protobufjsVersion === 'detect') {
+    if (protobuf_js_6_common.isProbablyProtobufJs6(value)) {
+      protobufjsVersion = 6;
+    } else if (protobuf_js_5_common.isProbablyProtobufJs5(value)) {
+      protobufjsVersion = 5;
+    } else {
+      var error_message = 'Could not detect ProtoBuf.js version. Please ' +
+          'specify the version number with the "protobufjs_version" option';
+      throw new Error(error_message);
+    }
   } else {
-    /* If value is not a ProtoBuf.js 6 reflection object, we assume that it is
-       a ProtoBuf.js 5 reflection object, for backwards compatibility */
+    protobufjsVersion = options.protobufjsVersion;
+  }
+  switch (protobufjsVersion) {
+    case 6: return protobuf_js_6_common.loadObject(value, options);
+    case 5:
     var deprecation_message = 'Calling grpc.loadObject with an object ' +
         'generated by ProtoBuf.js 5 is deprecated. Please upgrade to ' +
         'ProtoBuf.js 6.';
     common.log(grpc.logVerbosity.INFO, deprecation_message);
     return protobuf_js_5_common.loadObject(value, options);
+    default:
+    throw new Error('Unrecognized protobufjsVersion', protobufjsVersion);
   }
 };
 
@@ -90,9 +125,8 @@
 /**
  * Load a gRPC object from a .proto file. The options object can provide the
  * following options:
- * - convertFieldsToCamelCase: Loads this file with that option on protobuf.js
- *   set as specified. See
- *   https://github.com/dcodeIO/protobuf.js/wiki/Advanced-options for details
+ * - convertFieldsToCamelCase: Load this file with field names in camel case
+ *   instead of their original case
  * - binaryAsBase64: deserialize bytes values as base64 strings instead of
  *   Buffers. Defaults to false
  * - longsAsStrings: deserialize long values as strings instead of objects.
@@ -113,6 +147,7 @@
      still the possibility of adding other formats that would be loaded
      differently */
   options = _.defaults(options, common.defaultGrpcOptions);
+  options.protobufjs_version = 6;
   var root = new ProtoBuf.Root();
   var parse_options = {keepCase: !options.convertFieldsToCamelCase};
   return loadObject(root.loadSync(applyProtoRoot(filename, root),