1 #region Copyright notice and license 2 // Protocol Buffers - Google's data interchange format 3 // Copyright 2015 Google Inc. All rights reserved. 4 // https://developers.google.com/protocol-buffers/ 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions are 8 // met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following disclaimer 14 // in the documentation and/or other materials provided with the 15 // distribution. 16 // * Neither the name of Google Inc. nor the names of its 17 // contributors may be used to endorse or promote products derived from 18 // this software without specific prior written permission. 19 // 20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 #endregion 32 33 using Conformance; 34 using Google.Protobuf.Reflection; 35 using System; 36 using System.IO; 37 38 namespace Google.Protobuf.Conformance 39 { 40 /// <summary> 41 /// Conformance tests. The test runner will provide JSON or proto data on stdin, 42 /// and this program will produce its output on stdout. 43 /// </summary> 44 class Program 45 { Main(string[] args)46 private static void Main(string[] args) 47 { 48 // This way we get the binary streams instead of readers/writers. 49 var input = new BinaryReader(Console.OpenStandardInput()); 50 var output = new BinaryWriter(Console.OpenStandardOutput()); 51 var typeRegistry = TypeRegistry.FromMessages( 52 ProtobufTestMessages.Proto3.TestAllTypesProto3.Descriptor, 53 ProtobufTestMessages.Proto2.TestAllTypesProto2.Descriptor); 54 55 int count = 0; 56 while (RunTest(input, output, typeRegistry)) 57 { 58 count++; 59 } 60 Console.Error.WriteLine("Received EOF after {0} tests", count); 61 } 62 RunTest(BinaryReader input, BinaryWriter output, TypeRegistry typeRegistry)63 private static bool RunTest(BinaryReader input, BinaryWriter output, TypeRegistry typeRegistry) 64 { 65 int? size = ReadInt32(input); 66 if (size == null) 67 { 68 return false; 69 } 70 byte[] inputData = input.ReadBytes(size.Value); 71 if (inputData.Length != size.Value) 72 { 73 throw new EndOfStreamException("Read " + inputData.Length + " bytes of data when expecting " + size); 74 } 75 ConformanceRequest request = ConformanceRequest.Parser.ParseFrom(inputData); 76 ConformanceResponse response = PerformRequest(request, typeRegistry); 77 byte[] outputData = response.ToByteArray(); 78 output.Write(outputData.Length); 79 output.Write(outputData); 80 // Ready for another test... 81 return true; 82 } 83 PerformRequest(ConformanceRequest request, TypeRegistry typeRegistry)84 private static ConformanceResponse PerformRequest(ConformanceRequest request, TypeRegistry typeRegistry) 85 { 86 ExtensionRegistry proto2ExtensionRegistry = new ExtensionRegistry 87 { 88 ProtobufTestMessages.Proto2.TestMessagesProto2Extensions.ExtensionInt32, 89 ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension1.Extensions.MessageSetExtension, 90 ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension2.Extensions.MessageSetExtension 91 }; 92 IMessage message; 93 try 94 { 95 switch (request.PayloadCase) 96 { 97 case ConformanceRequest.PayloadOneofCase.JsonPayload: 98 if (request.TestCategory == global::Conformance.TestCategory.JsonIgnoreUnknownParsingTest) 99 { 100 return new ConformanceResponse { Skipped = "CSharp doesn't support skipping unknown fields in json parsing." }; 101 } 102 var parser = new JsonParser(new JsonParser.Settings(20, typeRegistry)); 103 switch (request.MessageType) 104 { 105 case "protobuf_test_messages.proto3.TestAllTypesProto3": 106 message = parser.Parse<ProtobufTestMessages.Proto3.TestAllTypesProto3>(request.JsonPayload); 107 break; 108 case "protobuf_test_messages.proto2.TestAllTypesProto2": 109 message = parser.Parse<ProtobufTestMessages.Proto2.TestAllTypesProto2>(request.JsonPayload); 110 break; 111 default: 112 throw new Exception($" Protobuf request doesn't have specific payload type ({request.MessageType})"); 113 } 114 break; 115 case ConformanceRequest.PayloadOneofCase.ProtobufPayload: 116 switch (request.MessageType) 117 { 118 case "protobuf_test_messages.proto3.TestAllTypesProto3": 119 message = ProtobufTestMessages.Proto3.TestAllTypesProto3.Parser.ParseFrom(request.ProtobufPayload); 120 break; 121 case "protobuf_test_messages.proto2.TestAllTypesProto2": 122 message = ProtobufTestMessages.Proto2.TestAllTypesProto2.Parser 123 .WithExtensionRegistry(proto2ExtensionRegistry) 124 .ParseFrom(request.ProtobufPayload); 125 break; 126 default: 127 throw new Exception($" Protobuf request doesn't have specific payload type ({request.MessageType})"); 128 } 129 break; 130 case ConformanceRequest.PayloadOneofCase.TextPayload: 131 return new ConformanceResponse { Skipped = "CSharp doesn't support text format" }; 132 default: 133 throw new Exception("Unsupported request payload: " + request.PayloadCase); 134 } 135 } 136 catch (InvalidProtocolBufferException e) 137 { 138 return new ConformanceResponse { ParseError = e.Message }; 139 } 140 catch (InvalidJsonException e) 141 { 142 return new ConformanceResponse { ParseError = e.Message }; 143 } 144 try 145 { 146 switch (request.RequestedOutputFormat) 147 { 148 case global::Conformance.WireFormat.Json: 149 var formatter = new JsonFormatter(new JsonFormatter.Settings(false, typeRegistry)); 150 return new ConformanceResponse { JsonPayload = formatter.Format(message) }; 151 case global::Conformance.WireFormat.Protobuf: 152 return new ConformanceResponse { ProtobufPayload = message.ToByteString() }; 153 default: 154 throw new Exception("Unsupported request output format: " + request.RequestedOutputFormat); 155 } 156 } 157 catch (InvalidOperationException e) 158 { 159 return new ConformanceResponse { SerializeError = e.Message }; 160 } 161 } 162 ReadInt32(BinaryReader input)163 private static int? ReadInt32(BinaryReader input) 164 { 165 byte[] bytes = input.ReadBytes(4); 166 if (bytes.Length == 0) 167 { 168 // Cleanly reached the end of the stream 169 return null; 170 } 171 if (bytes.Length != 4) 172 { 173 throw new EndOfStreamException("Read " + bytes.Length + " bytes of size when expecting 4"); 174 } 175 return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); 176 } 177 } 178 } 179