Commit 60fd773d authored by csharptest's avatar csharptest Committed by rogerk

Completed work and testing for manually reading/writing start/end message

parent 819b7154
......@@ -17,12 +17,6 @@ namespace Google.ProtocolBuffers.Serialization
/// <summary> Constructs a new reader </summary>
protected AbstractReader() { MaxDepth = DefaultMaxDepth; }
/// <summary> Constructs a new child reader </summary>
protected AbstractReader(AbstractReader copyFrom)
{
_depth = copyFrom._depth + 1;
MaxDepth = copyFrom.MaxDepth;
}
/// <summary> Gets or sets the maximum recursion depth allowed </summary>
public int MaxDepth { get; set; }
......@@ -116,12 +110,12 @@ namespace Google.ProtocolBuffers.Serialization
/// <summary>
/// Reads the root-message preamble specific to this formatter
/// </summary>
public abstract AbstractReader ReadStartMessage();
public abstract void ReadMessageStart();
/// <summary>
/// Reads the root-message close specific to this formatter
/// </summary>
public abstract void ReadEndMessage();
public abstract void ReadMessageEnd();
/// <summary>
/// Merges the input stream into the provided IBuilderLite
......
......@@ -11,10 +11,6 @@ namespace Google.ProtocolBuffers.Serialization
{
/// <summary> Constructs a new reader </summary>
protected AbstractTextReader() { }
/// <summary> Constructs a new child reader </summary>
protected AbstractTextReader(AbstractTextReader copyFrom)
: base(copyFrom)
{ }
/// <summary>
/// Reads a typed field as a string
......
......@@ -45,23 +45,23 @@ namespace Google.ProtocolBuffers.Serialization
/// <summary>
/// Used to write any nessary root-message preamble. After this call you can call
/// IMessageLite.MergeTo(...) and complete the message with a call to EndMessage().
/// IMessageLite.MergeTo(...) and complete the message with a call to WriteMessageEnd().
/// These three calls are identical to just calling WriteMessage(message);
/// </summary>
/// <example>
/// AbstractWriter writer;
/// writer.StartMessage();
/// writer.WriteMessageStart();
/// message.WriteTo(writer);
/// writer.EndMessage();
/// writer.WriteMessageEnd();
/// // ... or, but not both ...
/// writer.WriteMessage(message);
/// </example>
public abstract void StartMessage();
public abstract void WriteMessageStart();
/// <summary>
/// Used to complete a root-message previously started with a call to StartMessage()
/// Used to complete a root-message previously started with a call to WriteMessageStart()
/// </summary>
public abstract void EndMessage();
public abstract void WriteMessageEnd();
/// <summary>
/// Writes a Boolean value
......
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using Google.ProtocolBuffers.Descriptors;
......@@ -25,17 +25,14 @@ namespace Google.ProtocolBuffers.Serialization
/// <summary>
/// No-op
/// </summary>
public override AbstractReader ReadStartMessage()
{
return this;
}
public override void ReadMessageStart()
{ }
/// <summary>
/// No-op
/// </summary>
public override void ReadEndMessage()
{
}
public override void ReadMessageEnd()
{ }
/// <summary>
/// Merges the contents of stream into the provided message builder
......
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using Google.ProtocolBuffers.Descriptors;
......@@ -57,13 +57,13 @@ namespace Google.ProtocolBuffers.Serialization
/// <summary>
/// No-op
/// </summary>
public override void StartMessage()
public override void WriteMessageStart()
{ }
/// <summary>
/// No-op
/// </summary>
public override void EndMessage()
public override void WriteMessageEnd()
{ }
/// <summary>
......
......@@ -3,7 +3,7 @@ using System.IO;
using System.Xml;
using System.Text;
namespace Google.ProtocolBuffers.Serialization
namespace Google.ProtocolBuffers.Serialization.Http
{
/// <summary>
/// Extensions and helpers to abstract the reading/writing of messages by a client-specified content type.
......@@ -29,14 +29,14 @@ namespace Google.ProtocolBuffers.Serialization
else if (inputType == FormatType.Json)
{
JsonFormatReader reader = JsonFormatReader.CreateInstance(input);
codedInput = reader.ReadStartMessage();
codedInput = reader;
}
else if (inputType == FormatType.Xml)
{
XmlFormatReader reader = XmlFormatReader.CreateInstance(input);
reader.RootElementName = options.XmlReaderRootElementName;
reader.Options = options.XmlReaderOptions;
codedInput = reader.ReadStartMessage();
codedInput = reader;
}
else
throw new NotSupportedException();
......@@ -56,6 +56,7 @@ namespace Google.ProtocolBuffers.Serialization
public static TBuilder MergeFrom<TBuilder>(this TBuilder builder, MessageFormatOptions options, string contentType, Stream input) where TBuilder : IBuilderLite
{
ICodedInputStream codedInput = CreateInputStream(options, contentType, input);
codedInput.ReadMessageStart();
return (TBuilder)builder.WeakMergeFrom(codedInput, options.ExtensionRegistry);
}
......@@ -82,13 +83,12 @@ namespace Google.ProtocolBuffers.Serialization
{
writer.Formatted();
}
writer.StartMessage();
codedOutput = writer;
}
else if (outputType == FormatType.Xml)
{
XmlFormatWriter writer;
if (options.FormattedOutput)
if (!options.FormattedOutput)
{
writer = XmlFormatWriter.CreateInstance(output);
}
......@@ -99,7 +99,7 @@ namespace Google.ProtocolBuffers.Serialization
CheckCharacters = false,
NewLineHandling = NewLineHandling.Entitize,
OmitXmlDeclaration = true,
Encoding = Encoding.UTF8,
Encoding = new UTF8Encoding(false),
Indent = true,
IndentChars = " ",
NewLineChars = Environment.NewLine,
......@@ -108,7 +108,6 @@ namespace Google.ProtocolBuffers.Serialization
}
writer.RootElementName = options.XmlWriterRootElementName;
writer.Options = options.XmlWriterOptions;
writer.StartMessage();
codedOutput = writer;
}
else
......@@ -126,19 +125,17 @@ namespace Google.ProtocolBuffers.Serialization
/// <param name="output">The stream to write the message to</param>
public static void WriteTo(this IMessageLite message, MessageFormatOptions options, string contentType, Stream output)
{
using (ICodedOutputStream codedOutput = CreateOutputStream(options, contentType, output))
{
message.WriteTo(codedOutput);
ICodedOutputStream codedOutput = CreateOutputStream(options, contentType, output);
// This is effectivly done by Dispose(); however, if you need to finalize a message
// without disposing the underlying stream, this is the only way to do it.
if (codedOutput is AbstractWriter)
((AbstractWriter)codedOutput).EndMessage();
// Output the appropriate message preamble
codedOutput.WriteMessageStart();
codedOutput.Flush();
}
}
// Write the message content to the output
message.WriteTo(codedOutput);
// Write the closing message fragment
codedOutput.WriteMessageEnd();
}
enum FormatType { ProtoBuffer, Json, Xml };
......
using System;
namespace Google.ProtocolBuffers.Serialization
namespace Google.ProtocolBuffers.Serialization.Http
{
/// <summary>
/// Defines control information for the various formatting used with HTTP services
......
......@@ -3,7 +3,7 @@ using System.Text;
using Google.ProtocolBuffers;
using System.IO;
namespace Google.ProtocolBuffers.Serialization
namespace Google.ProtocolBuffers.Serialization.Http
{
/// <summary>
/// Extensions for the IRpcServerStub
......@@ -25,6 +25,7 @@ namespace Google.ProtocolBuffers.Serialization
string contentType, Stream input, string responseType, Stream output)
{
ICodedInputStream codedInput = MessageFormatFactory.CreateInputStream(options, contentType, input);
codedInput.ReadMessageStart();
IMessageLite response = stub.CallMethod(methodName, codedInput, options.ExtensionRegistry);
response.WriteTo(options, responseType, output);
}
......
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
......@@ -103,19 +103,18 @@ namespace Google.ProtocolBuffers.Serialization
/// <summary>
/// Reads the root-message preamble specific to this formatter
/// </summary>
public override AbstractReader ReadStartMessage()
public override void ReadMessageStart()
{
_input.Consume('{');
_stopChar.Push('}');
_state = ReaderState.BeginObject;
return this;
}
/// <summary>
/// Reads the root-message close specific to this formatter
/// </summary>
public override void ReadEndMessage()
public override void ReadMessageEnd()
{
_input.Consume((char)_stopChar.Pop());
_state = ReaderState.EndValue;
......@@ -126,9 +125,9 @@ namespace Google.ProtocolBuffers.Serialization
/// </summary>
public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)
{
AbstractReader rdr = ReadStartMessage();
builder.WeakMergeFrom(rdr, registry);
rdr.ReadEndMessage();
ReadMessageStart();
builder.WeakMergeFrom(this, registry);
ReadMessageEnd();
return builder;
}
......
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
......@@ -101,7 +101,7 @@ namespace Google.ProtocolBuffers.Serialization
private class JsonStreamWriter : JsonFormatWriter
{
#if SILVERLIGHT2 || COMPACT_FRAMEWORK_35
static readonly Encoding Encoding = Encoding.UTF8;
static readonly Encoding Encoding = new UTF8Encoding(false);
#else
private static readonly Encoding Encoding = Encoding.ASCII;
#endif
......@@ -244,9 +244,10 @@ namespace Google.ProtocolBuffers.Serialization
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing && _counter.Count == 1)
if (disposing)
{
EndMessage();
while(_counter.Count > 1)
WriteMessageEnd();
}
base.Dispose(disposing);
......@@ -458,17 +459,17 @@ namespace Google.ProtocolBuffers.Serialization
/// </summary>
public override void WriteMessage(IMessageLite message)
{
StartMessage();
WriteMessageStart();
message.WriteTo(this);
EndMessage();
WriteMessageEnd();
}
/// <summary>
/// Used to write the root-message preamble, in json this is the left-curly brace '{'.
/// After this call you can call IMessageLite.MergeTo(...) and complete the message with
/// a call to EndMessage().
/// a call to WriteMessageEnd().
/// </summary>
public override void StartMessage()
public override void WriteMessageStart()
{
if (_isArray)
{
......@@ -479,9 +480,9 @@ namespace Google.ProtocolBuffers.Serialization
}
/// <summary>
/// Used to complete a root-message previously started with a call to StartMessage()
/// Used to complete a root-message previously started with a call to WriteMessageStart()
/// </summary>
public override void EndMessage()
public override void WriteMessageEnd()
{
_counter.RemoveAt(_counter.Count - 1);
WriteLine("}");
......
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
......@@ -14,8 +14,23 @@ namespace Google.ProtocolBuffers.Serialization
{
public const string DefaultRootElementName = XmlFormatWriter.DefaultRootElementName;
private readonly XmlReader _input;
private readonly Stack<ElementStack> _elements;
private string _rootElementName;
private struct ElementStack
{
public readonly string LocalName;
public readonly int Depth;
public readonly bool IsEmpty;
public ElementStack(string localName, int depth, bool isEmpty) : this()
{
LocalName = localName;
IsEmpty = isEmpty;
Depth = depth;
}
}
private static XmlReaderSettings DefaultSettings
{
get
......@@ -72,20 +87,10 @@ namespace Google.ProtocolBuffers.Serialization
{
_input = input;
_rootElementName = DefaultRootElementName;
_elements = new Stack<ElementStack>();
Options = XmlReaderOptions.None;
}
/// <summary>
/// Constructs the XmlFormatReader with the XmlReader and options
/// </summary>
protected XmlFormatReader(XmlFormatReader copyFrom, XmlReader input)
: base(copyFrom)
{
_input = input;
_rootElementName = copyFrom._rootElementName;
Options = copyFrom.Options;
}
/// <summary>
/// Gets or sets the options to use when reading the xml
/// </summary>
......@@ -113,20 +118,6 @@ namespace Google.ProtocolBuffers.Serialization
}
}
private XmlFormatReader CloneWith(XmlReader rdr)
{
XmlFormatReader copy = new XmlFormatReader(this, rdr);
return copy;
}
private void NextElement()
{
while (!_input.IsStartElement() && _input.Read())
{
continue;
}
}
private static void Assert(bool cond)
{
if (!cond)
......@@ -138,36 +129,49 @@ namespace Google.ProtocolBuffers.Serialization
/// <summary>
/// Reads the root-message preamble specific to this formatter
/// </summary>
public override AbstractReader ReadStartMessage()
public override void ReadMessageStart()
{
return ReadStartMessage(_rootElementName);
ReadMessageStart(_rootElementName);
}
public AbstractReader ReadStartMessage(string element)
/// <summary>
/// Reads the root-message preamble specific to this formatter
/// </summary>
public void ReadMessageStart(string element)
{
string field;
Assert(PeekNext(out field) && field == element);
XmlReader child = _input.ReadSubtree();
while (!child.IsStartElement() && child.Read())
while (!_input.IsStartElement() && _input.Read())
{
continue;
}
child.Read();
return CloneWith(child);
Assert(_input.IsStartElement() && _input.LocalName == element);
_elements.Push(new ElementStack(element, _input.Depth, _input.IsEmptyElement));
_input.Read();
}
/// <summary>
/// Reads the root-message close specific to this formatter, MUST be called
/// on the reader obtained from ReadStartMessage(string element).
/// on the reader obtained from ReadMessageStart(string element).
/// </summary>
public override void ReadEndMessage()
public override void ReadMessageEnd()
{
Assert(0 == _input.Depth);
if(_input.NodeType == XmlNodeType.EndElement)
Assert(_elements.Count > 0);
ElementStack stop = _elements.Peek();
while (_input.NodeType != XmlNodeType.EndElement && _input.NodeType != XmlNodeType.Element
&& _input.Depth > stop.Depth && _input.Read())
{
continue;
}
if (!stop.IsEmpty)
{
Assert(_input.NodeType == XmlNodeType.EndElement
&& _input.LocalName == stop.LocalName
&& _input.Depth == stop.Depth);
_input.Read();
}
_elements.Pop();
}
/// <summary>
......@@ -192,9 +196,9 @@ namespace Google.ProtocolBuffers.Serialization
public TBuilder Merge<TBuilder>(string element, TBuilder builder, ExtensionRegistry registry)
where TBuilder : IBuilderLite
{
string field;
Assert(PeekNext(out field) && field == element);
ReadMessage(builder, registry);
ReadMessageStart(element);
builder.WeakMergeFrom(this, registry);
ReadMessageEnd();
return builder;
}
......@@ -207,7 +211,21 @@ namespace Google.ProtocolBuffers.Serialization
/// </remarks>
protected override bool PeekNext(out string field)
{
NextElement();
ElementStack stopNode;
if (_elements.Count == 0)
{
stopNode = new ElementStack(null, _input.Depth - 1, false);
}
else
{
stopNode = _elements.Peek();
}
while (!_input.IsStartElement() && _input.Depth > stopNode.Depth && _input.Read())
{
continue;
}
if (_input.IsStartElement())
{
field = _input.LocalName;
......@@ -270,20 +288,9 @@ namespace Google.ProtocolBuffers.Serialization
protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry)
{
Assert(_input.IsStartElement());
if (!_input.IsEmptyElement)
{
int depth = _input.Depth;
XmlReader child = _input.ReadSubtree();
while (!child.IsStartElement() && child.Read())
{
continue;
}
child.Read();
builder.WeakMergeFrom(CloneWith(child), registry);
Assert(depth == _input.Depth && _input.NodeType == XmlNodeType.EndElement);
}
_input.Read();
ReadMessageStart(_input.LocalName);
builder.WeakMergeFrom(this, registry);
ReadMessageEnd();
return true;
}
......@@ -305,27 +312,16 @@ namespace Google.ProtocolBuffers.Serialization
{
yield return item;
}
yield break;
}
if (!_input.IsEmptyElement)
else
{
int depth = _input.Depth;
XmlReader child = _input.ReadSubtree();
while (!child.IsStartElement() && child.Read())
{
continue;
}
child.Read();
foreach (string item in CloneWith(child).NonNestedArrayItems("item"))
ReadMessageStart(field);
foreach (string item in NonNestedArrayItems("item"))
{
yield return item;
}
Assert(depth == _input.Depth && _input.NodeType == XmlNodeType.EndElement);
ReadMessageEnd();
}
_input.Read();
yield break;
}
}
}
\ No newline at end of file
using System;
using System;
using System.Collections;
using System.IO;
using System.Text;
......@@ -14,10 +14,12 @@ namespace Google.ProtocolBuffers.Serialization
/// </summary>
public class XmlFormatWriter : AbstractTextWriter
{
private static readonly Encoding DefaultEncoding = new UTF8Encoding(false);
public const string DefaultRootElementName = "root";
private const int NestedArrayFlag = 0x0001;
private readonly XmlWriter _output;
private string _rootElementName;
private int _messageOpenCount;
private static XmlWriterSettings DefaultSettings(Encoding encoding)
{
......@@ -43,7 +45,7 @@ namespace Google.ProtocolBuffers.Serialization
/// </summary>
public static XmlFormatWriter CreateInstance(Stream output)
{
return new XmlFormatWriter(XmlWriter.Create(output, DefaultSettings(Encoding.UTF8)));
return new XmlFormatWriter(XmlWriter.Create(output, DefaultSettings(DefaultEncoding)));
}
/// <summary>
......@@ -65,6 +67,7 @@ namespace Google.ProtocolBuffers.Serialization
protected XmlFormatWriter(XmlWriter output)
{
_output = output;
_messageOpenCount = 0;
_rootElementName = DefaultRootElementName;
}
......@@ -75,8 +78,8 @@ namespace Google.ProtocolBuffers.Serialization
{
if (disposing)
{
if (_output.WriteState != WriteState.Closed && _output.WriteState != WriteState.Start)
_output.WriteEndDocument();
while(_messageOpenCount > 0)
WriteMessageEnd();
_output.Close();
}
......@@ -128,9 +131,9 @@ namespace Google.ProtocolBuffers.Serialization
/// <summary>
/// Used to write the root-message preamble, in xml this is open element for RootElementName,
/// by default "&lt;root&gt;". After this call you can call IMessageLite.MergeTo(...) and
/// complete the message with a call to EndMessage().
/// complete the message with a call to WriteMessageEnd().
/// </summary>
public override void StartMessage()
public override void WriteMessageStart()
{
StartMessage(_rootElementName);
}
......@@ -138,7 +141,7 @@ namespace Google.ProtocolBuffers.Serialization
/// <summary>
/// Used to write the root-message preamble, in xml this is open element for elementName.
/// After this call you can call IMessageLite.MergeTo(...) and complete the message with
/// a call to EndMessage().
/// a call to WriteMessageEnd().
/// </summary>
public void StartMessage(string elementName)
{
......@@ -151,15 +154,20 @@ namespace Google.ProtocolBuffers.Serialization
{
_output.WriteStartElement(elementName);
}
_messageOpenCount++;
}
/// <summary>
/// Used to complete a root-message previously started with a call to StartMessage()
/// Used to complete a root-message previously started with a call to WriteMessageStart()
/// </summary>
public override void EndMessage()
public override void WriteMessageEnd()
{
if (_messageOpenCount <= 0)
throw new InvalidOperationException();
_output.WriteEndElement();
_output.Flush();
_messageOpenCount--;
}
/// <summary>
......@@ -177,7 +185,7 @@ namespace Google.ProtocolBuffers.Serialization
{
StartMessage(elementName);
message.WriteTo(this);
EndMessage();
WriteMessageEnd();
}
/// <summary>
......
......@@ -106,6 +106,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReflectionTester.cs" />
<Compile Include="ServiceTest.cs" />
<Compile Include="TestMimeMessageFormats.cs" />
<Compile Include="TestProtos\UnitTestCSharpOptionsProtoFile.cs" />
<Compile Include="TestProtos\UnitTestCustomOptionsProtoFile.cs" />
<Compile Include="TestProtos\UnitTestEmbedOptimizeForProtoFile.cs" />
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Google.ProtocolBuffers.Serialization;
using Google.ProtocolBuffers.Serialization.Http;
using Google.ProtocolBuffers.TestProtos;
using NUnit.Framework;
namespace Google.ProtocolBuffers
{
[TestFixture]
public class TestMimeMessageFormats
{
// There is a whole host of various json mime types in use around the net, this is the set we accept...
readonly IEnumerable<string> JsonTypes = new string[] { "application/json", "application/x-json", "application/x-javascript", "text/javascript", "text/x-javascript", "text/x-json", "text/json" };
readonly IEnumerable<string> XmlTypes = new string[] { "text/xml", "application/xml" };
readonly IEnumerable<string> ProtobufTypes = new string[] { "application/binary", "application/x-protobuf", "application/vnd.google.protobuf" };
[Test]
public void TestReadJsonMimeTypes()
{
foreach (string type in JsonTypes)
{
Assert.IsTrue(
MessageFormatFactory.CreateInputStream(new MessageFormatOptions(), type, Stream.Null)
is JsonFormatReader);
}
Assert.IsTrue(
MessageFormatFactory.CreateInputStream(new MessageFormatOptions() { DefaultContentType = "application/json" }, null, Stream.Null)
is JsonFormatReader);
}
[Test]
public void TestWriteJsonMimeTypes()
{
foreach (string type in JsonTypes)
{
Assert.IsTrue(
MessageFormatFactory.CreateOutputStream(new MessageFormatOptions(), type, Stream.Null)
is JsonFormatWriter);
}
Assert.IsTrue(
MessageFormatFactory.CreateOutputStream(new MessageFormatOptions() { DefaultContentType = "application/json" }, null, Stream.Null)
is JsonFormatWriter);
}
[Test]
public void TestReadXmlMimeTypes()
{
foreach (string type in XmlTypes)
{
Assert.IsTrue(
MessageFormatFactory.CreateInputStream(new MessageFormatOptions(), type, Stream.Null)
is XmlFormatReader);
}
Assert.IsTrue(
MessageFormatFactory.CreateInputStream(new MessageFormatOptions() { DefaultContentType = "application/xml" }, null, Stream.Null)
is XmlFormatReader);
}
[Test]
public void TestWriteXmlMimeTypes()
{
foreach (string type in XmlTypes)
{
Assert.IsTrue(
MessageFormatFactory.CreateOutputStream(new MessageFormatOptions(), type, Stream.Null)
is XmlFormatWriter);
}
Assert.IsTrue(
MessageFormatFactory.CreateOutputStream(new MessageFormatOptions() { DefaultContentType = "application/xml" }, null, Stream.Null)
is XmlFormatWriter);
}
[Test]
public void TestReadProtoMimeTypes()
{
foreach (string type in ProtobufTypes)
{
Assert.IsTrue(
MessageFormatFactory.CreateInputStream(new MessageFormatOptions(), type, Stream.Null)
is CodedInputStream);
}
Assert.IsTrue(
MessageFormatFactory.CreateInputStream(new MessageFormatOptions() { DefaultContentType = "application/vnd.google.protobuf" }, null, Stream.Null)
is CodedInputStream);
}
[Test]
public void TestWriteProtoMimeTypes()
{
foreach (string type in ProtobufTypes)
{
Assert.IsTrue(
MessageFormatFactory.CreateOutputStream(new MessageFormatOptions(), type, Stream.Null)
is CodedOutputStream);
}
Assert.IsTrue(
MessageFormatFactory.CreateOutputStream(new MessageFormatOptions() { DefaultContentType = "application/vnd.google.protobuf" }, null, Stream.Null)
is CodedOutputStream);
}
[Test]
public void TestMergeFromJsonType()
{
TestXmlMessage msg = new TestXmlMessage.Builder().MergeFrom(
new MessageFormatOptions(), "application/json", new MemoryStream(Encoding.ASCII.GetBytes(
TestXmlMessage.CreateBuilder().SetText("a").SetNumber(1).Build().ToJson()
)))
.Build();
Assert.AreEqual("a", msg.Text);
Assert.AreEqual(1, msg.Number);
}
[Test]
public void TestMergeFromXmlType()
{
TestXmlMessage msg = new TestXmlMessage.Builder().MergeFrom(
new MessageFormatOptions(), "application/xml", new MemoryStream(Encoding.ASCII.GetBytes(
TestXmlMessage.CreateBuilder().SetText("a").SetNumber(1).Build().ToXml()
)))
.Build();
Assert.AreEqual("a", msg.Text);
Assert.AreEqual(1, msg.Number);
}
[Test]
public void TestMergeFromProtoType()
{
TestXmlMessage msg = new TestXmlMessage.Builder().MergeFrom(
new MessageFormatOptions(), "application/vnd.google.protobuf", new MemoryStream(
TestXmlMessage.CreateBuilder().SetText("a").SetNumber(1).Build().ToByteArray()
))
.Build();
Assert.AreEqual("a", msg.Text);
Assert.AreEqual(1, msg.Number);
}
[Test]
public void TestWriteToJsonType()
{
MemoryStream ms = new MemoryStream();
TestXmlMessage.CreateBuilder().SetText("a").SetNumber(1).Build()
.WriteTo(new MessageFormatOptions(), "application/json", ms);
Assert.AreEqual(@"{""text"":""a"",""number"":1}", Encoding.UTF8.GetString(ms.ToArray()));
}
[Test]
public void TestWriteToXmlType()
{
MemoryStream ms = new MemoryStream();
TestXmlMessage.CreateBuilder().SetText("a").SetNumber(1).Build()
.WriteTo(new MessageFormatOptions(), "application/xml", ms);
Assert.AreEqual("<root><text>a</text><number>1</number></root>", Encoding.UTF8.GetString(ms.ToArray()));
}
[Test]
public void TestWriteToProtoType()
{
MemoryStream ms = new MemoryStream();
TestXmlMessage.CreateBuilder().SetText("a").SetNumber(1).Build()
.WriteTo(new MessageFormatOptions(), "application/vnd.google.protobuf", ms);
byte[] bytes = TestXmlMessage.CreateBuilder().SetText("a").SetNumber(1).Build().ToByteArray();
Assert.AreEqual(bytes, ms.ToArray());
}
[Test]
public void TestXmlReaderOptions()
{
MemoryStream ms = new MemoryStream();
XmlFormatWriter.CreateInstance(ms)
.SetOptions(XmlWriterOptions.OutputNestedArrays)
.WriteMessage("my-root-node", TestXmlMessage.CreateBuilder().SetText("a").AddNumbers(1).AddNumbers(2).Build());
ms.Position = 0;
MessageFormatOptions options = new MessageFormatOptions()
{
XmlReaderOptions = XmlReaderOptions.ReadNestedArrays,
XmlReaderRootElementName = "my-root-node"
};
TestXmlMessage msg = new TestXmlMessage.Builder().MergeFrom(
options, "application/xml", ms)
.Build();
Assert.AreEqual("a", msg.Text);
Assert.AreEqual(1, msg.NumbersList[0]);
Assert.AreEqual(2, msg.NumbersList[1]);
}
[Test]
public void TestXmlWriterOptions()
{
TestXmlMessage message = TestXmlMessage.CreateBuilder().SetText("a").AddNumbers(1).AddNumbers(2).Build();
MessageFormatOptions options = new MessageFormatOptions()
{
XmlWriterOptions = XmlWriterOptions.OutputNestedArrays,
XmlWriterRootElementName = "root-node"
};
MemoryStream ms = new MemoryStream();
message.WriteTo(options, "application/xml", ms);
ms.Position = 0;
TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
XmlFormatReader.CreateInstance(ms)
.SetOptions(XmlReaderOptions.ReadNestedArrays)
.Merge("root-node", builder);
Assert.AreEqual("a", builder.Text);
Assert.AreEqual(1, builder.NumbersList[0]);
Assert.AreEqual(2, builder.NumbersList[1]);
}
[Test]
public void TestJsonFormatted()
{
MemoryStream ms = new MemoryStream();
TestXmlMessage.CreateBuilder().SetText("a").SetNumber(1).Build()
.WriteTo(new MessageFormatOptions() { FormattedOutput = true }, "application/json", ms);
Assert.AreEqual("{\r\n \"text\": \"a\",\r\n \"number\": 1\r\n}", Encoding.UTF8.GetString(ms.ToArray()));
}
[Test]
public void TestXmlFormatted()
{
MemoryStream ms = new MemoryStream();
TestXmlMessage.CreateBuilder().SetText("a").SetNumber(1).Build()
.WriteTo(new MessageFormatOptions() { FormattedOutput = true }, "application/xml", ms);
Assert.AreEqual("<root>\r\n <text>a</text>\r\n <number>1</number>\r\n</root>", Encoding.UTF8.GetString(ms.ToArray()));
}
}
}
\ No newline at end of file
......@@ -45,7 +45,7 @@ namespace Google.ProtocolBuffers
using (TextWriter output = new StringWriter())
using (AbstractWriter writer = JsonFormatWriter.CreateInstance(output))
{
writer.StartMessage(); //manually begin the message, output is '{'
writer.WriteMessageStart(); //manually begin the message, output is '{'
writer.Flush();
Assert.AreEqual("{", output.ToString());
......@@ -56,7 +56,7 @@ namespace Google.ProtocolBuffers
writer.Flush();
Assert.AreEqual(@"{""valid"":true", output.ToString());
writer.EndMessage(); //manually write the end message '}'
writer.WriteMessageEnd(); //manually write the end message '}'
Assert.AreEqual(@"{""valid"":true}", output.ToString());
}
}
......@@ -65,13 +65,13 @@ namespace Google.ProtocolBuffers
public void Example_ReadJsonUsingICodedInputStream()
{
TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
AbstractReader reader = JsonFormatReader.CreateInstance(@"{""valid"":true}");
ICodedInputStream reader = JsonFormatReader.CreateInstance(@"{""valid"":true}");
AbstractReader stream = reader.ReadStartMessage(); //manually read the begin the message '{'
reader.ReadMessageStart(); //manually read the begin the message '{'
builder.MergeFrom(stream); //write the message normally
builder.MergeFrom(reader); //write the message normally
stream.ReadEndMessage(); //manually read the end message '}'
reader.ReadMessageEnd(); //manually read the end message '}'
}
protected string Content;
......@@ -401,6 +401,28 @@ namespace Google.ProtocolBuffers
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,ExpectedException(typeof(RecursionLimitExceededException))]
public void TestRecursiveLimit()
{
......
......@@ -48,12 +48,12 @@ namespace Google.ProtocolBuffers
using (TextWriter output = new StringWriter())
using (AbstractWriter writer = XmlFormatWriter.CreateInstance(output))
{
writer.StartMessage(); //manually begin the message, output is '{'
writer.WriteMessageStart(); //manually begin the message, output is '{'
ICodedOutputStream stream = writer;
message.WriteTo(stream); //write the message normally
writer.EndMessage(); //manually write the end message '}'
writer.WriteMessageEnd(); //manually write the end message '}'
Assert.AreEqual(@"<root><valid>true</valid></root>", output.ToString());
}
}
......@@ -62,13 +62,13 @@ namespace Google.ProtocolBuffers
public void Example_ReadXmlUsingICodedInputStream()
{
TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
AbstractReader reader = XmlFormatReader.CreateInstance(@"<root><valid>true</valid></root>");
ICodedInputStream reader = XmlFormatReader.CreateInstance(@"<root><valid>true</valid></root>");
AbstractReader stream = reader.ReadStartMessage(); //manually read the begin the message '{'
reader.ReadMessageStart(); //manually read the begin the message '{'
builder.MergeFrom(stream); //write the message normally
builder.MergeFrom(reader); //read the message normally
stream.ReadEndMessage(); //manually read the end message '}'
reader.ReadMessageEnd(); //manually read the end message '}'
}
[Test]
......@@ -387,13 +387,54 @@ namespace Google.ProtocolBuffers
public void TestXmlReadEmptyRoot()
{
TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
AbstractReader reader = XmlFormatReader.CreateInstance(@"<root/>");
ICodedInputStream reader = XmlFormatReader.CreateInstance(@"<root/>");
AbstractReader stream = reader.ReadStartMessage(); //manually read the begin the message '{'
reader.ReadMessageStart(); //manually read the begin the message '{'
builder.MergeFrom(stream); //write the message normally
builder.MergeFrom(reader); //write the message normally
stream.ReadEndMessage(); //manually read the end message '}'
reader.ReadMessageEnd(); //manually read the end message '}'
}
[Test]
public void TestXmlReadEmptyChild()
{
TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
ICodedInputStream reader = XmlFormatReader.CreateInstance(@"<root><text /></root>");
reader.ReadMessageStart(); //manually read the begin the message '{'
builder.MergeFrom(reader); //write the message normally
Assert.IsTrue(builder.HasText);
Assert.AreEqual(String.Empty, builder.Text);
}
[Test]
public void TestXmlReadWriteWithoutRoot()
{
TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder();
TestXmlMessage message = builder.SetText("abc").SetNumber(123).Build();
string xml;
using (StringWriter sw = new StringWriter())
{
ICodedOutputStream output = XmlFormatWriter.CreateInstance(
XmlWriter.Create(sw, new XmlWriterSettings() { ConformanceLevel = ConformanceLevel.Fragment }));
message.WriteTo(output);
output.Flush();
xml = sw.ToString();
}
Assert.AreEqual("<text>abc</text><number>123</number>", xml);
TestXmlMessage copy;
using (XmlReader xr = XmlReader.Create(new StringReader(xml), new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Fragment }))
{
ICodedInputStream input = XmlFormatReader.CreateInstance(xr);
copy = TestXmlMessage.CreateBuilder().MergeFrom(input).Build();
}
Assert.AreEqual(message, copy);
}
[Test, ExpectedException(typeof(RecursionLimitExceededException))]
......
......@@ -144,6 +144,9 @@ namespace Google.ProtocolBuffers
#endregion
void ICodedInputStream.ReadMessageStart() { }
void ICodedInputStream.ReadMessageEnd() { }
#region Validation
/// <summary>
......
......@@ -136,6 +136,9 @@ namespace Google.ProtocolBuffers
}
}
void ICodedOutputStream.WriteMessageStart() { }
void ICodedOutputStream.WriteMessageEnd() { Flush(); }
#region Writing of unknown fields
[Obsolete]
......
......@@ -45,6 +45,24 @@ namespace Google.ProtocolBuffers
{
public interface ICodedInputStream
{
/// <summary>
/// Reads any message initialization data expected from the input stream
/// </summary>
/// <remarks>
/// This is primarily used by text formats and unnecessary for protobuffers' own
/// binary format. The API for MessageStart/End was added for consistent handling
/// of output streams regardless of the actual writer implementation.
/// </remarks>
void ReadMessageStart();
/// <summary>
/// Reads any message finalization data expected from the input stream
/// </summary>
/// <remarks>
/// This is primarily used by text formats and unnecessary for protobuffers' own
/// binary format. The API for MessageStart/End was added for consistent handling
/// of output streams regardless of the actual writer implementation.
/// </remarks>
void ReadMessageEnd();
/// <summary>
/// Attempt to read a field tag, returning false if we have reached the end
/// of the input data.
......
......@@ -51,6 +51,24 @@ namespace Google.ProtocolBuffers
/// </summary>
public interface ICodedOutputStream : IDisposable
{
/// <summary>
/// Writes any message initialization data needed to the output stream
/// </summary>
/// <remarks>
/// This is primarily used by text formats and unnecessary for protobuffers' own
/// binary format. The API for MessageStart/End was added for consistent handling
/// of output streams regardless of the actual writer implementation.
/// </remarks>
void WriteMessageStart();
/// <summary>
/// Writes any message finalization data needed to the output stream
/// </summary>
/// <remarks>
/// This is primarily used by text formats and unnecessary for protobuffers' own
/// binary format. The API for MessageStart/End was added for consistent handling
/// of output streams regardless of the actual writer implementation.
/// </remarks>
void WriteMessageEnd();
/// <summary>
/// Indicates that all temporary buffers be written to the final output.
/// </summary>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment