1 
2 import com.google.protobuf.conformance.Conformance;
3 import com.google.protobuf.util.JsonFormat;
4 import com.google.protobuf.util.JsonFormat.TypeRegistry;
5 import com.google.protobuf.InvalidProtocolBufferException;
6 
7 class ConformanceJava {
8   private int testCount = 0;
9   private TypeRegistry typeRegistry;
10 
11   private boolean readFromStdin(byte[] buf, int len) throws Exception {
12     int ofs = 0;
13     while (len > 0) {
14       int read = System.in.read(buf, ofs, len);
15       if (read == -1) {
16         return false;  // EOF
17       }
18       ofs += read;
19       len -= read;
20     }
21 
22     return true;
23   }
24 
25   private void writeToStdout(byte[] buf) throws Exception {
26     System.out.write(buf);
27   }
28 
29   // Returns -1 on EOF (the actual values will always be positive).
30   private int readLittleEndianIntFromStdin() throws Exception {
31     byte[] buf = new byte[4];
32     if (!readFromStdin(buf, 4)) {
33       return -1;
34     }
35     return (buf[0] & 0xff)
36         | ((buf[1] & 0xff) << 8)
37         | ((buf[2] & 0xff) << 16)
38         | ((buf[3] & 0xff) << 24);
39   }
40 
41   private void writeLittleEndianIntToStdout(int val) throws Exception {
42     byte[] buf = new byte[4];
43     buf[0] = (byte)val;
44     buf[1] = (byte)(val >> 8);
45     buf[2] = (byte)(val >> 16);
46     buf[3] = (byte)(val >> 24);
47     writeToStdout(buf);
48   }
49 
50   private Conformance.ConformanceResponse doTest(Conformance.ConformanceRequest request) {
51     Conformance.TestAllTypes testMessage;
52 
53     switch (request.getPayloadCase()) {
54       case PROTOBUF_PAYLOAD: {
55         try {
56           testMessage = Conformance.TestAllTypes.parseFrom(request.getProtobufPayload());
57         } catch (InvalidProtocolBufferException e) {
58           return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
59         }
60         break;
61       }
62       case JSON_PAYLOAD: {
63         try {
64           Conformance.TestAllTypes.Builder builder = Conformance.TestAllTypes.newBuilder();
65           JsonFormat.parser().usingTypeRegistry(typeRegistry)
66               .merge(request.getJsonPayload(), builder);
67           testMessage = builder.build();
68         } catch (InvalidProtocolBufferException e) {
69           return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
70         }
71         break;
72       }
73       case PAYLOAD_NOT_SET: {
74         throw new RuntimeException("Request didn't have payload.");
75       }
76 
77       default: {
78         throw new RuntimeException("Unexpected payload case.");
79       }
80     }
81 
82     switch (request.getRequestedOutputFormat()) {
83       case UNSPECIFIED:
84         throw new RuntimeException("Unspecified output format.");
85 
86       case PROTOBUF:
87         return Conformance.ConformanceResponse.newBuilder().setProtobufPayload(testMessage.toByteString()).build();
88 
89       case JSON:
90         try {
91           return Conformance.ConformanceResponse.newBuilder().setJsonPayload(
92               JsonFormat.printer().usingTypeRegistry(typeRegistry).print(testMessage)).build();
93         } catch (InvalidProtocolBufferException | IllegalArgumentException e) {
94           return Conformance.ConformanceResponse.newBuilder().setSerializeError(
95               e.getMessage()).build();
96         }
97 
98       default: {
99         throw new RuntimeException("Unexpected request output.");
100       }
101     }
102   }
103 
104   private boolean doTestIo() throws Exception {
105     int bytes = readLittleEndianIntFromStdin();
106 
107     if (bytes == -1) {
108       return false;  // EOF
109     }
110 
111     byte[] serializedInput = new byte[bytes];
112 
113     if (!readFromStdin(serializedInput, bytes)) {
114       throw new RuntimeException("Unexpected EOF from test program.");
115     }
116 
117     Conformance.ConformanceRequest request =
118         Conformance.ConformanceRequest.parseFrom(serializedInput);
119     Conformance.ConformanceResponse response = doTest(request);
120     byte[] serializedOutput = response.toByteArray();
121 
122     writeLittleEndianIntToStdout(serializedOutput.length);
123     writeToStdout(serializedOutput);
124 
125     return true;
126   }
127 
128   public void run() throws Exception {
129     typeRegistry = TypeRegistry.newBuilder().add(
130         Conformance.TestAllTypes.getDescriptor()).build();
131     while (doTestIo()) {
132       this.testCount++;
133     }
134 
135     System.err.println("ConformanceJava: received EOF from test runner after " +
136         this.testCount + " tests");
137   }
138 
139   public static void main(String[] args) throws Exception {
140     new ConformanceJava().run();
141   }
142 }
143