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(TestAllTypes.Descriptor); 52 53 int count = 0; 54 while (RunTest(input, output, typeRegistry)) 55 { 56 count++; 57 } 58 Console.Error.WriteLine("Received EOF after {0} tests", count); 59 } 60 RunTest(BinaryReader input, BinaryWriter output, TypeRegistry typeRegistry)61 private static bool RunTest(BinaryReader input, BinaryWriter output, TypeRegistry typeRegistry) 62 { 63 int? size = ReadInt32(input); 64 if (size == null) 65 { 66 return false; 67 } 68 byte[] inputData = input.ReadBytes(size.Value); 69 if (inputData.Length != size.Value) 70 { 71 throw new EndOfStreamException("Read " + inputData.Length + " bytes of data when expecting " + size); 72 } 73 ConformanceRequest request = ConformanceRequest.Parser.ParseFrom(inputData); 74 ConformanceResponse response = PerformRequest(request, typeRegistry); 75 byte[] outputData = response.ToByteArray(); 76 output.Write(outputData.Length); 77 output.Write(outputData); 78 // Ready for another test... 79 return true; 80 } 81 PerformRequest(ConformanceRequest request, TypeRegistry typeRegistry)82 private static ConformanceResponse PerformRequest(ConformanceRequest request, TypeRegistry typeRegistry) 83 { 84 TestAllTypes message; 85 try 86 { 87 switch (request.PayloadCase) 88 { 89 case ConformanceRequest.PayloadOneofCase.JsonPayload: 90 var parser = new JsonParser(new JsonParser.Settings(20, typeRegistry)); 91 message = parser.Parse<TestAllTypes>(request.JsonPayload); 92 break; 93 case ConformanceRequest.PayloadOneofCase.ProtobufPayload: 94 message = TestAllTypes.Parser.ParseFrom(request.ProtobufPayload); 95 break; 96 default: 97 throw new Exception("Unsupported request payload: " + request.PayloadCase); 98 } 99 } 100 catch (InvalidProtocolBufferException e) 101 { 102 return new ConformanceResponse { ParseError = e.Message }; 103 } 104 catch (InvalidJsonException e) 105 { 106 return new ConformanceResponse { ParseError = e.Message }; 107 } 108 try 109 { 110 switch (request.RequestedOutputFormat) 111 { 112 case global::Conformance.WireFormat.Json: 113 var formatter = new JsonFormatter(new JsonFormatter.Settings(false, typeRegistry)); 114 return new ConformanceResponse { JsonPayload = formatter.Format(message) }; 115 case global::Conformance.WireFormat.Protobuf: 116 return new ConformanceResponse { ProtobufPayload = message.ToByteString() }; 117 default: 118 throw new Exception("Unsupported request output format: " + request.PayloadCase); 119 } 120 } 121 catch (InvalidOperationException e) 122 { 123 return new ConformanceResponse { SerializeError = e.Message }; 124 } 125 } 126 ReadInt32(BinaryReader input)127 private static int? ReadInt32(BinaryReader input) 128 { 129 byte[] bytes = input.ReadBytes(4); 130 if (bytes.Length == 0) 131 { 132 // Cleanly reached the end of the stream 133 return null; 134 } 135 if (bytes.Length != 4) 136 { 137 throw new EndOfStreamException("Read " + bytes.Length + " bytes of size when expecting 4"); 138 } 139 return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); 140 } 141 } 142 } 143