Browse Source

Merge pull request #1662 from haberman/jsconformance

Conformance tests for JavaScript (Node.js). 15 tests are failing.
Joshua Haberman 8 years ago
parent
commit
c565e25c7d

+ 18 - 6
conformance/Makefile.am

@@ -21,6 +21,7 @@ other_language_protoc_outputs =                                \
   conformance_pb2.py                                           \
   conformance_pb2.py                                           \
   Conformance.pbobjc.h                                         \
   Conformance.pbobjc.h                                         \
   Conformance.pbobjc.m                                         \
   Conformance.pbobjc.m                                         \
+  conformance_pb.js                                            \
   conformance_pb.rb                                            \
   conformance_pb.rb                                            \
   com/google/protobuf/Any.java                                 \
   com/google/protobuf/Any.java                                 \
   com/google/protobuf/AnyOrBuilder.java                        \
   com/google/protobuf/AnyOrBuilder.java                        \
@@ -183,6 +184,7 @@ EXTRA_DIST =                  \
   failure_list_cpp.txt        \
   failure_list_cpp.txt        \
   failure_list_csharp.txt     \
   failure_list_csharp.txt     \
   failure_list_java.txt       \
   failure_list_java.txt       \
+  failure_list_js.txt         \
   failure_list_objc.txt       \
   failure_list_objc.txt       \
   failure_list_python.txt     \
   failure_list_python.txt     \
   failure_list_python_cpp.txt \
   failure_list_python_cpp.txt \
@@ -230,12 +232,19 @@ conformance_objc-conformance_objc.$(OBJEXT): Conformance.pbobjc.h google/protobu
 
 
 endif
 endif
 
 
+# JavaScript well-known types are expected to be in a directory called
+# google-protobuf, because they are usually in the google-protobuf npm
+# package.  But we want to use the sources from our tree, so we recreate
+# that directory structure here.
+google-protobuf:
+	mkdir google-protobuf
+
 if USE_EXTERNAL_PROTOC
 if USE_EXTERNAL_PROTOC
 
 
 # Some implementations include pre-generated versions of well-known types.
 # Some implementations include pre-generated versions of well-known types.
-protoc_middleman: $(conformance_protoc_inputs) $(well_known_type_protoc_inputs)
-	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. --java_out=. --ruby_out=. --objc_out=. --python_out=. --php_out=. $(conformance_protoc_inputs)
-	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. --java_out=. --ruby_out=. --python_out=. --php_out=. $(well_known_type_protoc_inputs)
+protoc_middleman: $(conformance_protoc_inputs) $(well_known_type_protoc_inputs) google-protobuf
+	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. --java_out=. --ruby_out=. --objc_out=. --python_out=. --php_out=. --js_out=import_style=commonjs,binary:. $(conformance_protoc_inputs)
+	$(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. --java_out=. --ruby_out=. --python_out=. --php_out=. --js_out=import_style=commonjs,binary:google-protobuf $(well_known_type_protoc_inputs)
 	## $(PROTOC) -I$(srcdir) -I$(top_srcdir) --java_out=lite:lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs)
 	## $(PROTOC) -I$(srcdir) -I$(top_srcdir) --java_out=lite:lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs)
 	touch protoc_middleman
 	touch protoc_middleman
 
 
@@ -244,9 +253,9 @@ else
 # We have to cd to $(srcdir) before executing protoc because $(protoc_inputs) is
 # We have to cd to $(srcdir) before executing protoc because $(protoc_inputs) is
 # relative to srcdir, which may not be the same as the current directory when
 # relative to srcdir, which may not be the same as the current directory when
 # building out-of-tree.
 # building out-of-tree.
-protoc_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(conformance_protoc_inputs) $(well_known_type_protoc_inputs)
-	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd --java_out=$$oldpwd --ruby_out=$$oldpwd --objc_out=$$oldpwd --python_out=$$oldpwd --php_out=$$oldpwd $(conformance_protoc_inputs) )
-	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd --java_out=$$oldpwd --ruby_out=$$oldpwd --python_out=$$oldpwd --php_out=$$oldpwd $(well_known_type_protoc_inputs) )
+protoc_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(conformance_protoc_inputs) $(well_known_type_protoc_inputs) google-protobuf
+	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd --java_out=$$oldpwd --ruby_out=$$oldpwd --objc_out=$$oldpwd --python_out=$$oldpwd --php_out=$$oldpwd --js_out=import_style=commonjs,binary:$$oldpwd $(conformance_protoc_inputs) )
+	oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd --java_out=$$oldpwd --ruby_out=$$oldpwd --python_out=$$oldpwd --php_out=$$oldpwd --js_out=import_style=commonjs,binary:$$oldpwd/google-protobuf $(well_known_type_protoc_inputs) )
 	## @mkdir -p lite
 	## @mkdir -p lite
 	## oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --java_out=lite:$$oldpwd/lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs) )
 	## oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --java_out=lite:$$oldpwd/lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs) )
 	touch protoc_middleman
 	touch protoc_middleman
@@ -335,6 +344,9 @@ test_python: protoc_middleman conformance-test-runner
 test_python_cpp: protoc_middleman conformance-test-runner
 test_python_cpp: protoc_middleman conformance-test-runner
 	./conformance-test-runner --enforce_recommended --failure_list failure_list_python_cpp.txt ./conformance_python.py
 	./conformance-test-runner --enforce_recommended --failure_list failure_list_python_cpp.txt ./conformance_python.py
 
 
+test_nodejs: protoc_middleman conformance-test-runner $(other_language_protoc_outputs)
+	NODE_PATH=../js:. ./conformance-test-runner --enforce_recommended --failure_list failure_list_js.txt ./conformance_nodejs.js
+
 if OBJC_CONFORMANCE_TEST
 if OBJC_CONFORMANCE_TEST
 
 
 test_objc: protoc_middleman conformance-test-runner conformance-objc
 test_objc: protoc_middleman conformance-test-runner conformance-objc

+ 30 - 2
conformance/README.md

@@ -19,11 +19,39 @@ directory to build `protoc`, since all the tests depend on it.
 
 
     $ make
     $ make
 
 
-Then to run the tests against the C++ implementation, run:
+Running the tests for C++
+-------------------------
+
+To run the tests against the C++ implementation, run:
 
 
     $ cd conformance && make test_cpp
     $ cd conformance && make test_cpp
 
 
-More tests and languages will be added soon!
+Running the tests for JavaScript (Node.js)
+------------------------------------------
+
+To run the JavaScript tests against Node.js, make sure you have "node"
+on your path and then run:
+
+    $ cd conformance && make test_nodejs
+
+Running the tests for Ruby (MRI)
+--------------------------------
+
+To run the Ruby tests against MRI, first build the C extension:
+
+    $ cd ruby && rake
+
+Then run the tests like so:
+
+    $ cd conformance && make test_ruby
+
+Running the tests for other languages
+-------------------------------------
+
+Most of the languages in the Protobuf source tree are set up to run
+conformance tests.  However some of them are more tricky to set up
+properly.  See `tests.sh` in the base of the repository to see how
+Travis runs the tests.
 
 
 Testing other Protocol Buffer implementations
 Testing other Protocol Buffer implementations
 ---------------------------------------------
 ---------------------------------------------

+ 168 - 0
conformance/conformance_nodejs.js

@@ -0,0 +1,168 @@
+#!/usr/bin/env node
+
+/*
+ * Protocol Buffers - Google's data interchange format
+ * Copyright 2008 Google Inc.  All rights reserved.
+ * https://developers.google.com/protocol-buffers/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var conformance = require('conformance_pb');
+var test_messages_proto3 = require('google/protobuf/test_messages_proto3_pb');
+var fs = require('fs');
+
+var testCount = 0;
+
+function doTest(request) {
+  var testMessage;
+  var response = new conformance.ConformanceResponse();
+
+  try {
+    if (request.getRequestedOutputFormat() === conformance.WireFormat.JSON) {
+      response.setSkipped("JSON not supported.");
+      return response;
+    }
+
+    switch (request.getPayloadCase()) {
+      case conformance.ConformanceRequest.PayloadCase.PROTOBUF_PAYLOAD:
+        try {
+          testMessage = test_messages_proto3.TestAllTypes.deserializeBinary(
+              request.getProtobufPayload());
+        } catch (err) {
+          response.setParseError(err.toString());
+          return response;
+        }
+
+      case conformance.ConformanceRequest.PayloadCase.JSON_PAYLOAD:
+        response.setSkipped("JSON not supported.");
+        return response;
+
+      case conformance.ConformanceRequest.PayloadCase.PAYLOAD_NOT_SET:
+        response.setRuntimeError("Request didn't have payload");
+        return response;
+    }
+
+    switch (request.getRequestedOutputFormat()) {
+      case conformance.WireFormat.UNSPECIFIED:
+        response.setRuntimeError("Unspecified output format");
+        return response;
+
+      case conformance.WireFormat.PROTOBUF:
+        response.setProtobufPayload(testMessage.serializeBinary());
+
+      case conformance.WireFormat.JSON:
+        response.setSkipped("JSON not supported.");
+        return response;
+
+      default:
+        throw "Request didn't have requested output format";
+    }
+  } catch (err) {
+    response.setRuntimeError(err.toString());
+  }
+
+  return response;
+}
+
+function onEof(totalRead) {
+  if (totalRead == 0) {
+    return undefined;
+  } else {
+    throw "conformance_nodejs: premature EOF on stdin.";
+  }
+}
+
+// Utility function to read a buffer of N bytes.
+function readBuffer(bytes) {
+  var buf = new Buffer(bytes);
+  var totalRead = 0;
+  while (totalRead < bytes) {
+    var read = 0;
+    try {
+      read = fs.readSync(process.stdin.fd, buf, totalRead, bytes - totalRead);
+    } catch (e) {
+      if (e.code == 'EOF') {
+        return onEof(totalRead)
+      } else if (e.code == 'EAGAIN') {
+      } else {
+        throw "conformance_nodejs: Error reading from stdin." + e;
+      }
+    }
+
+    totalRead += read;
+  }
+
+  return buf;
+}
+
+function writeBuffer(buffer) {
+  var totalWritten = 0;
+  while (totalWritten < buffer.length) {
+    totalWritten += fs.writeSync(
+        process.stdout.fd, buffer, totalWritten, buffer.length - totalWritten);
+  }
+}
+
+// Returns true if the test ran successfully, false on legitimate EOF.
+// If EOF is encountered in an unexpected place, raises IOError.
+function doTestIo() {
+  var lengthBuf = readBuffer(4);
+  if (!lengthBuf) {
+    return false;
+  }
+
+  var length = lengthBuf.readInt32LE(0);
+  var serializedRequest = readBuffer(length);
+  if (!serializedRequest) {
+    throw "conformance_nodejs: Failed to read request.";
+  }
+
+  serializedRequest = new Uint8Array(serializedRequest);
+  var request =
+      conformance.ConformanceRequest.deserializeBinary(serializedRequest);
+  var response = doTest(request);
+
+  var serializedResponse = response.serializeBinary();
+
+  lengthBuf = new Buffer(4);
+  lengthBuf.writeInt32LE(serializedResponse.length, 0);
+  writeBuffer(lengthBuf);
+  writeBuffer(new Buffer(serializedResponse));
+
+  testCount += 1
+
+  return true;
+}
+
+while (true) {
+  if (!doTestIo()) {
+    console.error('conformance_nodejs: received EOF from test runner ' +
+                  "after " + testCount + " tests, exiting")
+    break;
+  }
+}

+ 15 - 0
conformance/failure_list_js.txt

@@ -0,0 +1,15 @@
+Required.ProtobufInput.RepeatedScalarSelectsLast.INT32.ProtobufOutput
+Required.ProtobufInput.RepeatedScalarSelectsLast.UINT32.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.BOOL.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.DOUBLE.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.FIXED32.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.FIXED64.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.FLOAT.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.INT32.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.INT64.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.SFIXED32.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.SFIXED64.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.SINT32.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.SINT64.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.UINT32.ProtobufOutput
+Required.ProtobufInput.ValidDataRepeated.UINT64.ProtobufOutput

+ 4 - 0
js/binary/utils.js

@@ -970,6 +970,10 @@ jspb.utils.byteSourceToUint8Array = function(data) {
     return /** @type {!Uint8Array} */(new Uint8Array(data));
     return /** @type {!Uint8Array} */(new Uint8Array(data));
   }
   }
 
 
+  if (data.constructor === Buffer) {
+    return /** @type {!Uint8Array} */(new Uint8Array(data));
+  }
+
   if (data.constructor === Array) {
   if (data.constructor === Array) {
     data = /** @type {!Array.<number>} */(data);
     data = /** @type {!Array.<number>} */(data);
     return /** @type {!Uint8Array} */(new Uint8Array(data));
     return /** @type {!Uint8Array} */(new Uint8Array(data));

+ 1 - 1
js/message.js

@@ -202,7 +202,7 @@ goog.define('jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS', COMPILED);
 
 
 
 
 /**
 /**
- * Does this browser support Uint8Aray typed arrays?
+ * Does this JavaScript environment support Uint8Aray typed arrays?
  * @type {boolean}
  * @type {boolean}
  * @private
  * @private
  */
  */

+ 1 - 0
tests.sh

@@ -350,6 +350,7 @@ build_ruby_all() {
 build_javascript() {
 build_javascript() {
   internal_build_cpp
   internal_build_cpp
   cd js && npm install && npm test && cd ..
   cd js && npm install && npm test && cd ..
+  cd conformance && make test_nodejs && cd ..
 }
 }
 
 
 generate_php_test_proto() {
 generate_php_test_proto() {