Skip to content

Commit

Permalink
Added conformance test support for Java.
Browse files Browse the repository at this point in the history
Change-Id: I4c81808e6ace77d2b5737a43417045321b0b10f0
  • Loading branch information
haberman committed Apr 16, 2015
1 parent 4e63b52 commit 420f938
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 11 deletions.
120 changes: 120 additions & 0 deletions conformance/ConformanceJava.java
Original file line number Diff line number Diff line change
@@ -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();
}
}
31 changes: 22 additions & 9 deletions conformance/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions conformance/conformance.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions conformance/conformance_test_runner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 <errno.h>
Expand Down

0 comments on commit 420f938

Please sign in to comment.