using System; using System.IO; using System.Runtime.InteropServices; using System.Text; using EnumOptions = Google.ProtocolBuffers.TestProtos.EnumOptions; using Google.ProtocolBuffers.DescriptorProtos; using Google.ProtocolBuffers.Serialization; using Google.ProtocolBuffers.TestProtos; using NUnit.Framework; namespace Google.ProtocolBuffers { public class TestWriterFormatJson { [Test] public void Example_FromJson() { TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder(); //3.5: builder.MergeFromJson(@"{""valid"":true}"); Extensions.MergeFromJson(builder, @"{""valid"":true}"); TestXmlMessage message = builder.Build(); Assert.AreEqual(true, message.Valid); } [Test] public void Example_ToJson() { TestXmlMessage message = TestXmlMessage.CreateBuilder() .SetValid(true) .Build(); //3.5: string json = message.ToJson(); string json = Extensions.ToJson(message); Assert.AreEqual(@"{""valid"":true}", json); } [Test] public void Example_WriteJsonUsingICodedOutputStream() { TestXmlMessage message = TestXmlMessage.CreateBuilder() .SetValid(true) .Build(); using (TextWriter output = new StringWriter()) { ICodedOutputStream writer = JsonFormatWriter.CreateInstance(output); writer.WriteMessageStart(); //manually begin the message, output is '{' writer.Flush(); Assert.AreEqual("{", output.ToString()); ICodedOutputStream stream = writer; message.WriteTo(stream); //write the message normally writer.Flush(); Assert.AreEqual(@"{""valid"":true", output.ToString()); writer.WriteMessageEnd(); //manually write the end message '}' Assert.AreEqual(@"{""valid"":true}", output.ToString()); } } [Test] public void Example_ReadJsonUsingICodedInputStream() { TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder(); ICodedInputStream reader = JsonFormatReader.CreateInstance(@"{""valid"":true}"); reader.ReadMessageStart(); //manually read the begin the message '{' builder.MergeFrom(reader); //write the message normally reader.ReadMessageEnd(); //manually read the end message '}' } protected string Content; [System.Diagnostics.DebuggerNonUserCode] protected void FormatterAssert(TMessage message, params string[] expecting) where TMessage : IMessageLite { StringWriter sw = new StringWriter(); JsonFormatWriter.CreateInstance(sw).WriteMessage(message); Content = sw.ToString(); ExtensionRegistry registry = ExtensionRegistry.CreateInstance(); UnittestExtrasXmltest.RegisterAllExtensions(registry); IMessageLite copy = JsonFormatReader.CreateInstance(Content) .Merge(message.WeakCreateBuilderForType(), registry).WeakBuild(); Assert.AreEqual(typeof(TMessage), copy.GetType()); Assert.AreEqual(message, copy); foreach (string expect in expecting) { Assert.IsTrue(Content.IndexOf(expect) >= 0); } } [Test] public void TestToJsonParseFromJson() { TestAllTypes msg = new TestAllTypes.Builder().SetDefaultBool(true).Build(); string json = Extensions.ToJson(msg); Assert.AreEqual("{\"default_bool\":true}", json); TestAllTypes copy = Extensions.MergeFromJson(new TestAllTypes.Builder(), json).Build(); Assert.IsTrue(copy.HasDefaultBool && copy.DefaultBool); Assert.AreEqual(msg, copy); } [Test] public void TestToJsonParseFromJsonReader() { TestAllTypes msg = new TestAllTypes.Builder().SetDefaultBool(true).Build(); string json = Extensions.ToJson(msg); Assert.AreEqual("{\"default_bool\":true}", json); TestAllTypes copy = Extensions.MergeFromJson(new TestAllTypes.Builder(), new StringReader(json)).Build(); Assert.IsTrue(copy.HasDefaultBool && copy.DefaultBool); Assert.AreEqual(msg, copy); } [Test] public void TestJsonFormatted() { TestXmlMessage message = TestXmlMessage.CreateBuilder() .SetValid(true) .SetNumber(0x1010) .AddChildren(TestXmlMessage.Types.Children.CreateBuilder()) .AddChildren(TestXmlMessage.Types.Children.CreateBuilder().AddOptions(EnumOptions.ONE)) .AddChildren(TestXmlMessage.Types.Children.CreateBuilder().AddOptions(EnumOptions.ONE).AddOptions(EnumOptions.TWO)) .AddChildren(TestXmlMessage.Types.Children.CreateBuilder().SetBinary(ByteString.CopyFromUtf8("abc"))) .Build(); StringWriter sw = new StringWriter(); JsonFormatWriter.CreateInstance(sw).Formatted() .WriteMessage(message); string json = sw.ToString(); TestXmlMessage copy = JsonFormatReader.CreateInstance(json) .Merge(TestXmlMessage.CreateBuilder()).Build(); Assert.AreEqual(message, copy); } [Test] public void TestEmptyMessage() { FormatterAssert( TestXmlChild.CreateBuilder() .Build(), @"{}" ); } [Test] public void TestRepeatedField() { FormatterAssert( TestXmlChild.CreateBuilder() .AddOptions(EnumOptions.ONE) .AddOptions(EnumOptions.TWO) .Build(), @"{""options"":[""ONE"",""TWO""]}" ); } [Test] public void TestNestedEmptyMessage() { FormatterAssert( TestXmlMessage.CreateBuilder() .SetChild(TestXmlChild.CreateBuilder().Build()) .Build(), @"{""child"":{}}" ); } [Test] public void TestNestedMessage() { FormatterAssert( TestXmlMessage.CreateBuilder() .SetChild(TestXmlChild.CreateBuilder().AddOptions(EnumOptions.TWO).Build()) .Build(), @"{""child"":{""options"":[""TWO""]}}" ); } [Test] public void TestBooleanTypes() { FormatterAssert( TestXmlMessage.CreateBuilder() .SetValid(true) .Build(), @"{""valid"":true}" ); } [Test] public void TestFullMessage() { FormatterAssert( TestXmlMessage.CreateBuilder() .SetValid(true) .SetText("text") .AddTextlines("a") .AddTextlines("b") .AddTextlines("c") .SetNumber(0x1010101010) .AddNumbers(1) .AddNumbers(2) .AddNumbers(3) .SetChild(TestXmlChild.CreateBuilder().AddOptions(EnumOptions.ONE).SetBinary(ByteString.CopyFrom(new byte[1]))) .AddChildren(TestXmlMessage.Types.Children.CreateBuilder().AddOptions(EnumOptions.TWO).SetBinary(ByteString.CopyFrom(new byte[2]))) .AddChildren(TestXmlMessage.Types.Children.CreateBuilder().AddOptions(EnumOptions.THREE).SetBinary(ByteString.CopyFrom(new byte[3]))) .Build(), @"""text"":""text""", @"[""a"",""b"",""c""]", @"[1,2,3]", @"""child"":{", @"""children"":[{", @"AA==", @"AAA=", @"AAAA", 0x1010101010L.ToString() ); } [Test] public void TestMessageWithXmlText() { FormatterAssert( TestXmlMessage.CreateBuilder() .SetText("") .Build(), @"{""text"":""<\/text>""}" ); } [Test] public void TestWithEscapeChars() { FormatterAssert( TestXmlMessage.CreateBuilder() .SetText(" \t <- \"leading space and trailing\" -> \\ \xef54 \x0000 \xFF \xFFFF \b \f \r \n \t ") .Build(), "{\"text\":\" \\t <- \\\"leading space and trailing\\\" -> \\\\ \\uef54 \\u0000 \\u00ff \\uffff \\b \\f \\r \\n \\t \"}" ); } [Test] public void TestWithExtensionText() { FormatterAssert( TestXmlMessage.CreateBuilder() .SetValid(false) .SetExtension(UnittestExtrasXmltest.ExtensionText, " extension text value ! ") .Build(), @"{""valid"":false,""extension_text"":"" extension text value ! ""}" ); } [Test] public void TestWithExtensionNumber() { FormatterAssert( TestXmlMessage.CreateBuilder() .SetExtension(UnittestExtrasXmltest.ExtensionMessage, new TestXmlExtension.Builder().SetNumber(42).Build()) .Build(), @"{""number"":42}" ); } [Test] public void TestWithExtensionArray() { FormatterAssert( TestXmlMessage.CreateBuilder() .AddExtension(UnittestExtrasXmltest.ExtensionNumber, 100) .AddExtension(UnittestExtrasXmltest.ExtensionNumber, 101) .AddExtension(UnittestExtrasXmltest.ExtensionNumber, 102) .Build(), @"{""extension_number"":[100,101,102]}" ); } [Test] public void TestWithExtensionEnum() { FormatterAssert( TestXmlMessage.CreateBuilder() .SetExtension(UnittestExtrasXmltest.ExtensionEnum, EnumOptions.ONE) .Build(), @"{""extension_enum"":""ONE""}" ); } [Test] public void TestMessageWithExtensions() { FormatterAssert( TestXmlMessage.CreateBuilder() .SetValid(true) .SetText("text") .SetExtension(UnittestExtrasXmltest.ExtensionText, "extension text") .SetExtension(UnittestExtrasXmltest.ExtensionMessage, new TestXmlExtension.Builder().SetNumber(42).Build()) .AddExtension(UnittestExtrasXmltest.ExtensionNumber, 100) .AddExtension(UnittestExtrasXmltest.ExtensionNumber, 101) .AddExtension(UnittestExtrasXmltest.ExtensionNumber, 102) .SetExtension(UnittestExtrasXmltest.ExtensionEnum, EnumOptions.ONE) .Build(), @"""text"":""text""", @"""valid"":true", @"""extension_enum"":""ONE""", @"""extension_text"":""extension text""", @"""extension_number"":[100,101,102]", @"""extension_message"":{""number"":42}" ); } [Test] public void TestMessageMissingExtensions() { TestXmlMessage original = TestXmlMessage.CreateBuilder() .SetValid(true) .SetText("text") .SetExtension(UnittestExtrasXmltest.ExtensionText, " extension text value ! ") .SetExtension(UnittestExtrasXmltest.ExtensionMessage, new TestXmlExtension.Builder().SetNumber(42).Build()) .AddExtension(UnittestExtrasXmltest.ExtensionNumber, 100) .AddExtension(UnittestExtrasXmltest.ExtensionNumber, 101) .AddExtension(UnittestExtrasXmltest.ExtensionNumber, 102) .SetExtension(UnittestExtrasXmltest.ExtensionEnum, EnumOptions.ONE) .Build(); TestXmlMessage message = original.ToBuilder() .ClearExtension(UnittestExtrasXmltest.ExtensionText) .ClearExtension(UnittestExtrasXmltest.ExtensionMessage) .ClearExtension(UnittestExtrasXmltest.ExtensionNumber) .ClearExtension(UnittestExtrasXmltest.ExtensionEnum) .Build(); JsonFormatWriter writer = JsonFormatWriter.CreateInstance(); writer.WriteMessage(original); Content = writer.ToString(); IMessageLite copy = JsonFormatReader.CreateInstance(Content) .Merge(message.CreateBuilderForType()).Build(); Assert.AreNotEqual(original, message); Assert.AreNotEqual(original, copy); Assert.AreEqual(message, copy); } [Test] public void TestMergeFields() { TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder(); builder.MergeFrom(JsonFormatReader.CreateInstance("\"valid\": true")); builder.MergeFrom(JsonFormatReader.CreateInstance("\"text\": \"text\", \"number\": \"411\"")); Assert.AreEqual(true, builder.Valid); Assert.AreEqual("text", builder.Text); Assert.AreEqual(411, builder.Number); } [Test] public void TestMessageArray() { JsonFormatWriter writer = JsonFormatWriter.CreateInstance().Formatted(); using (writer.StartArray()) { writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(1).AddTextlines("a").Build()); writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(2).AddTextlines("b").Build()); writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(3).AddTextlines("c").Build()); } string json = writer.ToString(); JsonFormatReader reader = JsonFormatReader.CreateInstance(json); TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder(); int ordinal = 0; foreach (JsonFormatReader r in reader.EnumerateArray()) { r.Merge(builder); Assert.AreEqual(++ordinal, builder.Number); } Assert.AreEqual(3, ordinal); Assert.AreEqual(3, builder.TextlinesCount); } [Test] public void TestNestedMessageArray() { JsonFormatWriter writer = JsonFormatWriter.CreateInstance(); using (writer.StartArray()) { using (writer.StartArray()) { writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(1).AddTextlines("a").Build()); writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(2).AddTextlines("b").Build()); } using (writer.StartArray()) writer.WriteMessage(TestXmlMessage.CreateBuilder().SetNumber(3).AddTextlines("c").Build()); } string json = writer.ToString(); JsonFormatReader reader = JsonFormatReader.CreateInstance(json); TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder(); int ordinal = 0; foreach (JsonFormatReader r in reader.EnumerateArray()) foreach (JsonFormatReader r2 in r.EnumerateArray()) { r2.Merge(builder); Assert.AreEqual(++ordinal, builder.Number); } Assert.AreEqual(3, ordinal); Assert.AreEqual(3, builder.TextlinesCount); } [Test] public void TestReadWriteJsonWithoutRoot() { TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder(); TestXmlMessage message = builder.SetText("abc").SetNumber(123).Build(); string Json; using (StringWriter sw = new StringWriter()) { ICodedOutputStream output = JsonFormatWriter.CreateInstance(sw); message.WriteTo(output); output.Flush(); Json = sw.ToString(); } Assert.AreEqual(@"""text"":""abc"",""number"":123", Json); ICodedInputStream input = JsonFormatReader.CreateInstance(Json); TestXmlMessage copy = TestXmlMessage.CreateBuilder().MergeFrom(input).Build(); Assert.AreEqual(message, copy); } [Test] public void TestRecursiveLimit() { StringBuilder sb = new StringBuilder(8192); for (int i = 0; i < 80; i++) { sb.Append("{\"child\":"); } Assert.Throws(() => Extensions.MergeFromJson(new TestXmlRescursive.Builder(), sb.ToString()).Build()); } [Test] public void FailWithEmptyText() { Assert.Throws(() => JsonFormatReader.CreateInstance("").Merge(TestXmlMessage.CreateBuilder())); } [Test] public void FailWithUnexpectedValue() { Assert.Throws(() => JsonFormatReader.CreateInstance("{{}}").Merge(TestXmlMessage.CreateBuilder())); } [Test] public void FailWithUnQuotedName() { Assert.Throws(() => JsonFormatReader.CreateInstance("{name:{}}").Merge(TestXmlMessage.CreateBuilder())); } [Test] public void FailWithUnexpectedType() { Assert.Throws(() => JsonFormatReader.CreateInstance("{\"valid\":{}}").Merge(TestXmlMessage.CreateBuilder())); } // See issue 64 for background. [Test] public void ToJsonRequiringBufferExpansion() { string s = new string('.', 4086); var opts = FileDescriptorProto.CreateBuilder() .SetName(s) .SetPackage("package") .BuildPartial(); Assert.NotNull(Extensions.ToJson(opts)); } } }