From 420f938bac63af49c00292c7c09eb0d237ce4e0b Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 16 Apr 2015 12:50:39 -0700 Subject: Added conformance test support for Java. Change-Id: I4c81808e6ace77d2b5737a43417045321b0b10f0 --- conformance/ConformanceJava.java | 120 +++++++++++++++++++++++++++++++++ conformance/Makefile.am | 31 ++++++--- conformance/conformance.proto | 1 + conformance/conformance_test_runner.cc | 4 +- 4 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 conformance/ConformanceJava.java diff --git a/conformance/ConformanceJava.java b/conformance/ConformanceJava.java new file mode 100644 index 00000000..c1a53141 --- /dev/null +++ b/conformance/ConformanceJava.java @@ -0,0 +1,120 @@ + +import com.google.protobuf.conformance.Conformance; +import com.google.protobuf.InvalidProtocolBufferException; + +class ConformanceJava { + private int testCount = 0; + + private boolean readFromStdin(byte[] buf, int len) throws Exception { + int ofs = 0; + while (len > 0) { + int read = System.in.read(buf, ofs, len); + if (read == -1) { + return false; // EOF + } + ofs += read; + len -= read; + } + + return true; + } + + private void writeToStdout(byte[] buf) throws Exception { + System.out.write(buf); + } + + // Returns -1 on EOF (the actual values will always be positive). + private int readLittleEndianIntFromStdin() throws Exception { + byte[] buf = new byte[4]; + if (!readFromStdin(buf, 4)) { + return -1; + } + return buf[0] | (buf[1] << 1) | (buf[2] << 2) | (buf[3] << 3); + } + + private void writeLittleEndianIntToStdout(int val) throws Exception { + byte[] buf = new byte[4]; + buf[0] = (byte)val; + buf[1] = (byte)(val >> 8); + buf[2] = (byte)(val >> 16); + buf[3] = (byte)(val >> 24); + writeToStdout(buf); + } + + private Conformance.ConformanceResponse doTest(Conformance.ConformanceRequest request) { + Conformance.TestAllTypes testMessage; + + switch (request.getPayloadCase()) { + case PROTOBUF_PAYLOAD: { + try { + testMessage = Conformance.TestAllTypes.parseFrom(request.getProtobufPayload()); + } catch (InvalidProtocolBufferException e) { + return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build(); + } + break; + } + case JSON_PAYLOAD: { + return Conformance.ConformanceResponse.newBuilder().setRuntimeError("JSON not yet supported.").build(); + } + case PAYLOAD_NOT_SET: { + throw new RuntimeException("Request didn't have payload."); + } + + default: { + throw new RuntimeException("Unexpected payload case."); + } + } + + switch (request.getRequestedOutput()) { + case UNSPECIFIED: + throw new RuntimeException("Unspecified output format."); + + case PROTOBUF: + return Conformance.ConformanceResponse.newBuilder().setProtobufPayload(testMessage.toByteString()).build(); + + case JSON: + return Conformance.ConformanceResponse.newBuilder().setRuntimeError("JSON not yet supported.").build(); + + default: { + throw new RuntimeException("Unexpected request output."); + } + } + } + + private boolean doTestIo() throws Exception { + int bytes = readLittleEndianIntFromStdin(); + + if (bytes == -1) { + return false; // EOF + } + + byte[] serializedInput = new byte[bytes]; + + if (!readFromStdin(serializedInput, bytes)) { + throw new RuntimeException("Unexpected EOF from test program."); + } + + Conformance.ConformanceRequest request = + Conformance.ConformanceRequest.parseFrom(serializedInput); + Conformance.ConformanceResponse response = doTest(request); + byte[] serializedOutput = response.toByteArray(); + + writeLittleEndianIntToStdout(serializedOutput.length); + writeToStdout(serializedOutput); + + return true; + } + + public void run() throws Exception { + while (doTestIo()) { + // Empty. + } + + System.err.println("ConformanceJava: received EOF from test runner after " + + this.testCount + " tests"); + } + + public static void main(String[] args) throws Exception { + new ConformanceJava().run(); + } +} diff --git a/conformance/Makefile.am b/conformance/Makefile.am index 0c4eae75..59bb2576 100644 --- a/conformance/Makefile.am +++ b/conformance/Makefile.am @@ -21,30 +21,43 @@ conformance_cpp_CPPFLAGS = -I$(top_srcdir)/src if USE_EXTERNAL_PROTOC -unittest_proto_middleman: $(protoc_inputs) - $(PROTOC) -I$(srcdir) --cpp_out=. $^ - touch unittest_proto_middleman +protoc_middleman: $(protoc_inputs) + $(PROTOC) -I$(srcdir) --cpp_out=. --java_out=. $^ + touch protoc_middleman else # 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 # building out-of-tree. -unittest_proto_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(protoc_inputs) - oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. --cpp_out=$$oldpwd $(protoc_inputs) ) - touch unittest_proto_middleman +protoc_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(protoc_inputs) + oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. --cpp_out=$$oldpwd --java_out=$$oldpwd $(protoc_inputs) ) + touch protoc_middleman endif -$(protoc_outputs): unittest_proto_middleman +$(protoc_outputs): protoc_middleman BUILT_SOURCES = $(protoc_outputs) -CLEANFILES = $(protoc_outputs) unittest_proto_middleman +CLEANFILES = $(protoc_outputs) protoc_middleman javac_middleman conformance-java MAINTAINERCLEANFILES = \ Makefile.in +javac_middleman: ConformanceJava.java protoc_middleman + javac ConformanceJava.java com/google/protobuf/conformance/Conformance.java + @touch javac_middleman + +conformance-java: javac_middleman + @echo "Writing shortcut script conformance-java..." + @echo '#! /bin/sh' > conformance-java + @echo 'java -classpath .:$$CLASSPATH ConformanceJava "$$@"' >> conformance-java + @chmod +x conformance-java + # Targets for actually running tests. -test_cpp: unittest_proto_middleman conformance-test-runner conformance-cpp +test_cpp: protoc_middleman conformance-test-runner conformance-cpp ./conformance-test-runner ./conformance-cpp + +test_java: protoc_middleman conformance-test-runner conformance-java + ./conformance-test-runner ./conformance-java diff --git a/conformance/conformance.proto b/conformance/conformance.proto index 0fb66cf9..7b676898 100644 --- a/conformance/conformance.proto +++ b/conformance/conformance.proto @@ -30,6 +30,7 @@ syntax = "proto3"; package conformance; +option java_package = "com.google.protobuf.conformance"; // This defines the conformance testing protocol. This protocol exists between // the conformance test suite itself and the code being tested. For each test, diff --git a/conformance/conformance_test_runner.cc b/conformance/conformance_test_runner.cc index 21277700..ca5877bd 100644 --- a/conformance/conformance_test_runner.cc +++ b/conformance/conformance_test_runner.cc @@ -48,9 +48,9 @@ // Every test consists of a ConformanceRequest/ConformanceResponse // request/reply pair. The protocol on the pipe is simply: // -// 1. tester sends 4-byte length N +// 1. tester sends 4-byte length N (little endian) // 2. tester sends N bytes representing a ConformanceRequest proto -// 3. testee sends 4-byte length M +// 3. testee sends 4-byte length M (little endian) // 4. testee sends M bytes representing a ConformanceResponse proto #include -- cgit v1.2.3