blob: 2d558af5ca38765fabb97c7dbc9040392f12502a [file] [log] [blame]
Jon Skeet60c059b2008-10-23 21:17:56 +01001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// http://github.com/jskeet/dotnet-protobufs/
4// Original C++/Java/Python code:
Jon Skeet68036862008-10-22 13:30:34 +01005// http://code.google.com/p/protobuf/
6//
Jon Skeet60c059b2008-10-23 21:17:56 +01007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are
9// met:
Jon Skeet68036862008-10-22 13:30:34 +010010//
Jon Skeet60c059b2008-10-23 21:17:56 +010011// * Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// * Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17// * Neither the name of Google Inc. nor the names of its
18// contributors may be used to endorse or promote products derived from
19// this software without specific prior written permission.
Jon Skeet68036862008-10-22 13:30:34 +010020//
Jon Skeet60c059b2008-10-23 21:17:56 +010021// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet2e6dc122009-05-29 06:34:52 +010032using System.IO;
Jon Skeet68036862008-10-22 13:30:34 +010033using System.Reflection;
34using Google.ProtocolBuffers.Descriptors;
35using Google.ProtocolBuffers.TestProtos;
36using NUnit.Framework;
37
38namespace Google.ProtocolBuffers {
39 [TestFixture]
40 public class WireFormatTest {
41
42 /// <summary>
43 /// Keeps the attributes on FieldType and the switch statement in WireFormat in sync.
44 /// </summary>
45 [Test]
46 public void FieldTypeToWireTypeMapping() {
47 foreach (FieldInfo field in typeof(FieldType).GetFields(BindingFlags.Static | BindingFlags.Public)) {
48 FieldType fieldType = (FieldType)field.GetValue(null);
49 FieldMappingAttribute mapping = (FieldMappingAttribute)field.GetCustomAttributes(typeof(FieldMappingAttribute), false)[0];
50 Assert.AreEqual(mapping.WireType, WireFormat.GetWireType(fieldType));
51 }
52 }
53
54 [Test]
55 public void Serialization() {
56 TestAllTypes message = TestUtil.GetAllSet();
57
58 ByteString rawBytes = message.ToByteString();
59 Assert.AreEqual(rawBytes.Length, message.SerializedSize);
60
61 TestAllTypes message2 = TestAllTypes.ParseFrom(rawBytes);
62
63 TestUtil.AssertAllFieldsSet(message2);
64 }
65
66 [Test]
Jon Skeet25a28582009-02-18 16:06:22 +000067 public void SerializationPacked() {
68 TestPackedTypes message = TestUtil.GetPackedSet();
69 ByteString rawBytes = message.ToByteString();
70 Assert.AreEqual(rawBytes.Length, message.SerializedSize);
71 TestPackedTypes message2 = TestPackedTypes.ParseFrom(rawBytes);
72 TestUtil.AssertPackedFieldsSet(message2);
73 }
74
75 [Test]
Jon Skeet68036862008-10-22 13:30:34 +010076 public void SerializeExtensions() {
77 // TestAllTypes and TestAllExtensions should have compatible wire formats,
Jon Skeet25a28582009-02-18 16:06:22 +000078 // so if we serialize a TestAllExtensions then parse it as TestAllTypes
Jon Skeet68036862008-10-22 13:30:34 +010079 // it should work.
Jon Skeet68036862008-10-22 13:30:34 +010080 TestAllExtensions message = TestUtil.GetAllExtensionsSet();
81 ByteString rawBytes = message.ToByteString();
82 Assert.AreEqual(rawBytes.Length, message.SerializedSize);
83
84 TestAllTypes message2 = TestAllTypes.ParseFrom(rawBytes);
85
86 TestUtil.AssertAllFieldsSet(message2);
87 }
88
89 [Test]
Jon Skeet25a28582009-02-18 16:06:22 +000090 public void SerializePackedExtensions() {
91 // TestPackedTypes and TestPackedExtensions should have compatible wire
92 // formats; check that they serialize to the same string.
93 TestPackedExtensions message = TestUtil.GetPackedExtensionsSet();
94 ByteString rawBytes = message.ToByteString();
95
96 TestPackedTypes message2 = TestUtil.GetPackedSet();
97 ByteString rawBytes2 = message2.ToByteString();
98
99 Assert.AreEqual(rawBytes, rawBytes2);
100 }
101
102 [Test]
Jon Skeet2e6dc122009-05-29 06:34:52 +0100103 public void SerializeDelimited() {
104 MemoryStream stream = new MemoryStream();
105 TestUtil.GetAllSet().WriteDelimitedTo(stream);
106 stream.WriteByte(12);
107 TestUtil.GetPackedSet().WriteDelimitedTo(stream);
108 stream.WriteByte(34);
109
110 stream.Position = 0;
111
112 TestUtil.AssertAllFieldsSet(TestAllTypes.ParseDelimitedFrom(stream));
113 Assert.AreEqual(12, stream.ReadByte());
114 TestUtil.AssertPackedFieldsSet(TestPackedTypes.ParseDelimitedFrom(stream));
115 Assert.AreEqual(34, stream.ReadByte());
116 Assert.AreEqual(-1, stream.ReadByte());
117 }
118
119 [Test]
Jon Skeet68036862008-10-22 13:30:34 +0100120 public void ParseExtensions() {
121 // TestAllTypes and TestAllExtensions should have compatible wire formats,
122 // so if we serealize a TestAllTypes then parse it as TestAllExtensions
123 // it should work.
124
125 TestAllTypes message = TestUtil.GetAllSet();
126 ByteString rawBytes = message.ToByteString();
127
128 ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
129 TestUtil.RegisterAllExtensions(registry);
130 registry = registry.AsReadOnly();
131
Jon Skeet25a28582009-02-18 16:06:22 +0000132 TestAllExtensions message2 = TestAllExtensions.ParseFrom(rawBytes, registry);
Jon Skeet68036862008-10-22 13:30:34 +0100133
134 TestUtil.AssertAllExtensionsSet(message2);
135 }
136
137 [Test]
Jon Skeet25a28582009-02-18 16:06:22 +0000138 public void ParsePackedExtensions() {
139 // Ensure that packed extensions can be properly parsed.
140 TestPackedExtensions message = TestUtil.GetPackedExtensionsSet();
141 ByteString rawBytes = message.ToByteString();
142
143 ExtensionRegistry registry = TestUtil.CreateExtensionRegistry();
144
145 TestPackedExtensions message2 = TestPackedExtensions.ParseFrom(rawBytes, registry);
146 TestUtil.AssertPackedExtensionsSet(message2);
147 }
148
149 [Test]
Jon Skeet68036862008-10-22 13:30:34 +0100150 public void ExtensionsSerializedSize() {
151 Assert.AreEqual(TestUtil.GetAllSet().SerializedSize, TestUtil.GetAllExtensionsSet().SerializedSize);
152 }
153
Jon Skeet2e6dc122009-05-29 06:34:52 +0100154 private static void AssertFieldsInOrder(ByteString data) {
Jon Skeet68036862008-10-22 13:30:34 +0100155 CodedInputStream input = data.CreateCodedInput();
156 uint previousTag = 0;
157
158 while (true) {
159 uint tag = input.ReadTag();
160 if (tag == 0) {
161 break;
162 }
163
164 Assert.IsTrue(tag > previousTag);
165 previousTag = tag;
166 input.SkipField(tag);
167 }
168 }
169
170 [Test]
171 public void InterleavedFieldsAndExtensions() {
172 // Tests that fields are written in order even when extension ranges
173 // are interleaved with field numbers.
174 ByteString data =
175 TestFieldOrderings.CreateBuilder()
176 .SetMyInt(1)
177 .SetMyString("foo")
178 .SetMyFloat(1.0F)
179 .SetExtension(UnitTestProtoFile.MyExtensionInt, 23)
180 .SetExtension(UnitTestProtoFile.MyExtensionString, "bar")
181 .Build().ToByteString();
182 AssertFieldsInOrder(data);
183
184 MessageDescriptor descriptor = TestFieldOrderings.Descriptor;
185 ByteString dynamic_data =
186 DynamicMessage.CreateBuilder(TestFieldOrderings.Descriptor)
187 .SetField(descriptor.FindDescriptor<FieldDescriptor>("my_int"), 1L)
188 .SetField(descriptor.FindDescriptor<FieldDescriptor>("my_string"), "foo")
189 .SetField(descriptor.FindDescriptor<FieldDescriptor>("my_float"), 1.0F)
190 .SetField(UnitTestProtoFile.MyExtensionInt.Descriptor, 23)
191 .SetField(UnitTestProtoFile.MyExtensionString.Descriptor, "bar")
192 .WeakBuild().ToByteString();
193 AssertFieldsInOrder(dynamic_data);
194 }
195
196 private const int UnknownTypeId = 1550055;
197 private static readonly int TypeId1 = TestMessageSetExtension1.Descriptor.Extensions[0].FieldNumber;
198 private static readonly int TypeId2 = TestMessageSetExtension2.Descriptor.Extensions[0].FieldNumber;
199
200 [Test]
201 public void SerializeMessageSet() {
202 // Set up a TestMessageSet with two known messages and an unknown one.
203 TestMessageSet messageSet =
204 TestMessageSet.CreateBuilder()
205 .SetExtension(
206 TestMessageSetExtension1.MessageSetExtension,
207 TestMessageSetExtension1.CreateBuilder().SetI(123).Build())
208 .SetExtension(
209 TestMessageSetExtension2.MessageSetExtension,
210 TestMessageSetExtension2.CreateBuilder().SetStr("foo").Build())
211 .SetUnknownFields(
212 UnknownFieldSet.CreateBuilder()
213 .AddField(UnknownTypeId,
214 UnknownField.CreateBuilder()
215 .AddLengthDelimited(ByteString.CopyFromUtf8("bar"))
216 .Build())
217 .Build())
218 .Build();
219
220 ByteString data = messageSet.ToByteString();
221
222 // Parse back using RawMessageSet and check the contents.
223 RawMessageSet raw = RawMessageSet.ParseFrom(data);
224
225 Assert.AreEqual(0, raw.UnknownFields.FieldDictionary.Count);
226
227 Assert.AreEqual(3, raw.ItemCount);
228 Assert.AreEqual(TypeId1, raw.ItemList[0].TypeId);
229 Assert.AreEqual(TypeId2, raw.ItemList[1].TypeId);
230 Assert.AreEqual(UnknownTypeId, raw.ItemList[2].TypeId);
231
232 TestMessageSetExtension1 message1 = TestMessageSetExtension1.ParseFrom(raw.GetItem(0).Message.ToByteArray());
233 Assert.AreEqual(123, message1.I);
234
235 TestMessageSetExtension2 message2 = TestMessageSetExtension2.ParseFrom(raw.GetItem(1).Message.ToByteArray());
236 Assert.AreEqual("foo", message2.Str);
237
238 Assert.AreEqual("bar", raw.GetItem(2).Message.ToStringUtf8());
239 }
240
241 [Test]
242 public void ParseMessageSet() {
243 ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
244 extensionRegistry.Add(TestMessageSetExtension1.MessageSetExtension);
245 extensionRegistry.Add(TestMessageSetExtension2.MessageSetExtension);
246
247 // Set up a RawMessageSet with two known messages and an unknown one.
248 RawMessageSet raw =
249 RawMessageSet.CreateBuilder()
250 .AddItem(
251 RawMessageSet.Types.Item.CreateBuilder()
252 .SetTypeId(TypeId1)
253 .SetMessage(
254 TestMessageSetExtension1.CreateBuilder()
255 .SetI(123)
256 .Build().ToByteString())
257 .Build())
258 .AddItem(
259 RawMessageSet.Types.Item.CreateBuilder()
260 .SetTypeId(TypeId2)
261 .SetMessage(
262 TestMessageSetExtension2.CreateBuilder()
263 .SetStr("foo")
264 .Build().ToByteString())
265 .Build())
266 .AddItem(
267 RawMessageSet.Types.Item.CreateBuilder()
268 .SetTypeId(UnknownTypeId)
269 .SetMessage(ByteString.CopyFromUtf8("bar"))
270 .Build())
271 .Build();
272
273 ByteString data = raw.ToByteString();
274
275 // Parse as a TestMessageSet and check the contents.
276 TestMessageSet messageSet =
277 TestMessageSet.ParseFrom(data, extensionRegistry);
278
279 Assert.AreEqual(123, messageSet.GetExtension(TestMessageSetExtension1.MessageSetExtension).I);
280 Assert.AreEqual("foo", messageSet.GetExtension(TestMessageSetExtension2.MessageSetExtension).Str);
281
282 // Check for unknown field with type LENGTH_DELIMITED,
283 // number UNKNOWN_TYPE_ID, and contents "bar".
284 UnknownFieldSet unknownFields = messageSet.UnknownFields;
285 Assert.AreEqual(1, unknownFields.FieldDictionary.Count);
286 Assert.IsTrue(unknownFields.HasField(UnknownTypeId));
287
288 UnknownField field = unknownFields[UnknownTypeId];
289 Assert.AreEqual(1, field.LengthDelimitedList.Count);
290 Assert.AreEqual("bar", field.LengthDelimitedList[0].ToStringUtf8());
291 }
292
293 }
294}