diff --git a/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs b/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs index 1c71dc9516..15e0424ed2 100644 --- a/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs +++ b/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs @@ -82,6 +82,10 @@ namespace Google.ProtocolBuffers.Serialization { if (_bufferPos >= _buffer.Length) { + if (_output == null) + { + _output = new StringWriter(new StringBuilder(_buffer.Length * 2)); + } Flush(); } _buffer[_bufferPos++] = ch; diff --git a/src/ProtocolBuffers.Test/ByteStringTest.cs b/src/ProtocolBuffers.Test/ByteStringTest.cs index 97425fe894..003307aef5 100644 --- a/src/ProtocolBuffers.Test/ByteStringTest.cs +++ b/src/ProtocolBuffers.Test/ByteStringTest.cs @@ -34,6 +34,7 @@ #endregion +using System; using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -127,5 +128,21 @@ namespace Google.ProtocolBuffers ByteString bs = ByteString.CopyFrom("\u20ac", Encoding.Unicode); Assert.AreEqual("\u20ac", bs.ToString(Encoding.Unicode)); } + + [TestMethod] + public void FromBase64_WithText() + { + byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6}; + string base64 = Convert.ToBase64String(data); + ByteString bs = ByteString.FromBase64(base64); + TestUtil.AssertBytesEqual(data, bs.ToByteArray()); + } + + [TestMethod] + public void FromBase64_Empty() + { + // Optimization which also fixes issue 61. + Assert.AreSame(ByteString.Empty, ByteString.FromBase64("")); + } } } \ No newline at end of file diff --git a/src/ProtocolBuffers.Test/TestWriterFormatJson.cs b/src/ProtocolBuffers.Test/TestWriterFormatJson.cs index 86a3e3002d..b658086cd9 100644 --- a/src/ProtocolBuffers.Test/TestWriterFormatJson.cs +++ b/src/ProtocolBuffers.Test/TestWriterFormatJson.cs @@ -1,9 +1,11 @@ using System; using System.IO; using System.Text; +using Google.ProtocolBuffers.DescriptorProtos; using Google.ProtocolBuffers.Serialization; using Microsoft.VisualStudio.TestTools.UnitTesting; using Google.ProtocolBuffers.TestProtos; +using EnumOptions = Google.ProtocolBuffers.TestProtos.EnumOptions; namespace Google.ProtocolBuffers { @@ -152,6 +154,7 @@ namespace Google.ProtocolBuffers @"{}" ); } + [TestMethod] public void TestRepeatedField() { @@ -163,6 +166,7 @@ namespace Google.ProtocolBuffers @"{""options"":[""ONE"",""TWO""]}" ); } + [TestMethod] public void TestNestedEmptyMessage() { @@ -173,6 +177,7 @@ namespace Google.ProtocolBuffers @"{""child"":{}}" ); } + [TestMethod] public void TestNestedMessage() { @@ -183,6 +188,7 @@ namespace Google.ProtocolBuffers @"{""child"":{""options"":[""TWO""]}}" ); } + [TestMethod] public void TestBooleanTypes() { @@ -193,6 +199,7 @@ namespace Google.ProtocolBuffers @"{""valid"":true}" ); } + [TestMethod] public void TestFullMessage() { @@ -222,6 +229,7 @@ namespace Google.ProtocolBuffers 0x1010101010L.ToString() ); } + [TestMethod] public void TestMessageWithXmlText() { @@ -232,6 +240,7 @@ namespace Google.ProtocolBuffers @"{""text"":""<\/text>""}" ); } + [TestMethod] public void TestWithEscapeChars() { @@ -242,6 +251,7 @@ namespace Google.ProtocolBuffers "{\"text\":\" \\t <- \\\"leading space and trailing\\\" -> \\\\ \\uef54 \\u0000 \\u00ff \\uffff \\b \\f \\r \\n \\t \"}" ); } + [TestMethod] public void TestWithExtensionText() { @@ -253,6 +263,7 @@ namespace Google.ProtocolBuffers @"{""valid"":false,""extension_text"":"" extension text value ! ""}" ); } + [TestMethod] public void TestWithExtensionNumber() { @@ -264,6 +275,7 @@ namespace Google.ProtocolBuffers @"{""number"":42}" ); } + [TestMethod] public void TestWithExtensionArray() { @@ -276,6 +288,7 @@ namespace Google.ProtocolBuffers @"{""extension_number"":[100,101,102]}" ); } + [TestMethod] public void TestWithExtensionEnum() { @@ -286,6 +299,7 @@ namespace Google.ProtocolBuffers @"{""extension_enum"":""ONE""}" ); } + [TestMethod] public void TestMessageWithExtensions() { @@ -308,6 +322,7 @@ namespace Google.ProtocolBuffers @"""extension_message"":{""number"":42}" ); } + [TestMethod] public void TestMessageMissingExtensions() { @@ -340,6 +355,7 @@ namespace Google.ProtocolBuffers Assert.AreNotEqual(original, copy); Assert.AreEqual(message, copy); } + [TestMethod] public void TestMergeFields() { @@ -350,6 +366,7 @@ namespace Google.ProtocolBuffers Assert.AreEqual("text", builder.Text); Assert.AreEqual(411, builder.Number); } + [TestMethod] public void TestMessageArray() { @@ -374,6 +391,7 @@ namespace Google.ProtocolBuffers Assert.AreEqual(3, ordinal); Assert.AreEqual(3, builder.TextlinesCount); } + [TestMethod] public void TestNestedMessageArray() { @@ -403,6 +421,7 @@ namespace Google.ProtocolBuffers Assert.AreEqual(3, ordinal); Assert.AreEqual(3, builder.TextlinesCount); } + [TestMethod] public void TestReadWriteJsonWithoutRoot() { @@ -425,6 +444,7 @@ namespace Google.ProtocolBuffers Assert.AreEqual(message, copy); } + [TestMethod,ExpectedException(typeof(RecursionLimitExceededException))] public void TestRecursiveLimit() { @@ -433,29 +453,46 @@ namespace Google.ProtocolBuffers sb.Append("{\"child\":"); TestXmlRescursive msg = Extensions.MergeFromJson(new TestXmlRescursive.Builder(), sb.ToString()).Build(); } + [TestMethod, ExpectedException(typeof(FormatException))] public void FailWithEmptyText() { JsonFormatReader.CreateInstance("") .Merge(TestXmlMessage.CreateBuilder()); } + [TestMethod, ExpectedException(typeof(FormatException))] public void FailWithUnexpectedValue() { JsonFormatReader.CreateInstance("{{}}") .Merge(TestXmlMessage.CreateBuilder()); } + [TestMethod, ExpectedException(typeof(FormatException))] public void FailWithUnQuotedName() { JsonFormatReader.CreateInstance("{name:{}}") .Merge(TestXmlMessage.CreateBuilder()); } + [TestMethod, ExpectedException(typeof(FormatException))] public void FailWithUnexpectedType() { JsonFormatReader.CreateInstance("{\"valid\":{}}") .Merge(TestXmlMessage.CreateBuilder()); } + + // See issue 64 for background. + [TestMethod] + public void ToJsonRequiringBufferExpansion() + { + string s = new string('.', 4086); + var opts = FileDescriptorProto.CreateBuilder() + .SetName(s) + .SetPackage("package") + .BuildPartial(); + + Assert.NotNull(opts.ToJson()); + } } } diff --git a/src/ProtocolBuffers/ByteString.cs b/src/ProtocolBuffers/ByteString.cs index 8b7bd06c6b..434865b7f3 100644 --- a/src/ProtocolBuffers/ByteString.cs +++ b/src/ProtocolBuffers/ByteString.cs @@ -129,7 +129,9 @@ namespace Google.ProtocolBuffers /// public static ByteString FromBase64(string bytes) { - return new ByteString(Convert.FromBase64String(bytes)); + // By handling the empty string explicitly, we not only optimize but we fix a + // problem on CF 2.0. See issue 61 for details. + return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes)); } ///