blob: fbc0ff07a540bcaa55e0fcac166cfba2d476c9a5 [file] [log] [blame]
Jon Skeetb2ac8682015-07-15 13:17:42 +01001#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
Jon Skeet8a0312b2015-07-16 17:03:06 +010033using System;
Jon Skeetb2ac8682015-07-15 13:17:42 +010034using Google.Protobuf.TestProtos;
35using NUnit.Framework;
Jon Skeet8a0312b2015-07-16 17:03:06 +010036using System.Collections;
Jon Skeet34878cb2015-07-17 06:41:46 +010037using System.IO;
Jon Skeetb2ac8682015-07-15 13:17:42 +010038
39namespace Google.Protobuf.WellKnownTypes
40{
41 public class WrappersTest
42 {
43 [Test]
44 public void NullIsDefault()
45 {
46 var message = new TestWellKnownTypes();
47 Assert.IsNull(message.StringField);
48 Assert.IsNull(message.BytesField);
49 Assert.IsNull(message.BoolField);
50 Assert.IsNull(message.FloatField);
51 Assert.IsNull(message.DoubleField);
52 Assert.IsNull(message.Int32Field);
53 Assert.IsNull(message.Int64Field);
54 Assert.IsNull(message.Uint32Field);
55 Assert.IsNull(message.Uint64Field);
56 }
57
58 [Test]
Jon Skeet8a0312b2015-07-16 17:03:06 +010059 public void NonDefaultSingleValues()
60 {
61 var message = new TestWellKnownTypes
62 {
63 StringField = "x",
64 BytesField = ByteString.CopyFrom(1, 2, 3),
65 BoolField = true,
66 FloatField = 12.5f,
67 DoubleField = 12.25d,
68 Int32Field = 1,
69 Int64Field = 2,
70 Uint32Field = 3,
71 Uint64Field = 4
72 };
73
74 var bytes = message.ToByteArray();
75 var parsed = TestWellKnownTypes.Parser.ParseFrom(bytes);
76
77 Assert.AreEqual("x", parsed.StringField);
78 Assert.AreEqual(ByteString.CopyFrom(1, 2, 3), parsed.BytesField);
79 Assert.AreEqual(true, parsed.BoolField);
80 Assert.AreEqual(12.5f, parsed.FloatField);
81 Assert.AreEqual(12.25d, parsed.DoubleField);
82 Assert.AreEqual(1, parsed.Int32Field);
83 Assert.AreEqual(2L, parsed.Int64Field);
84 Assert.AreEqual(3U, parsed.Uint32Field);
85 Assert.AreEqual(4UL, parsed.Uint64Field);
86 }
87
88 [Test]
Jon Skeetb2ac8682015-07-15 13:17:42 +010089 public void NonNullDefaultIsPreservedThroughSerialization()
90 {
91 var message = new TestWellKnownTypes
92 {
93 StringField = "",
94 BytesField = ByteString.Empty,
95 BoolField = false,
96 FloatField = 0f,
97 DoubleField = 0d,
98 Int32Field = 0,
99 Int64Field = 0,
100 Uint32Field = 0,
101 Uint64Field = 0
102 };
103
104 var bytes = message.ToByteArray();
105 var parsed = TestWellKnownTypes.Parser.ParseFrom(bytes);
106
Jon Skeet8a0312b2015-07-16 17:03:06 +0100107 Assert.AreEqual("", parsed.StringField);
108 Assert.AreEqual(ByteString.Empty, parsed.BytesField);
109 Assert.AreEqual(false, parsed.BoolField);
110 Assert.AreEqual(0f, parsed.FloatField);
111 Assert.AreEqual(0d, parsed.DoubleField);
112 Assert.AreEqual(0, parsed.Int32Field);
113 Assert.AreEqual(0L, parsed.Int64Field);
114 Assert.AreEqual(0U, parsed.Uint32Field);
115 Assert.AreEqual(0UL, parsed.Uint64Field);
116 }
117
118 [Test]
119 public void RepeatedWrappersProhibitNullItems()
120 {
121 var message = new RepeatedWellKnownTypes();
122 Assert.Throws<ArgumentNullException>(() => message.BoolField.Add((bool?) null));
123 Assert.Throws<ArgumentNullException>(() => message.Int32Field.Add((int?) null));
124 Assert.Throws<ArgumentNullException>(() => message.StringField.Add((string) null));
125 Assert.Throws<ArgumentNullException>(() => message.BytesField.Add((ByteString) null));
126 }
127
128 [Test]
129 public void RepeatedWrappersSerializeDeserialize()
130 {
131 var message = new RepeatedWellKnownTypes
132 {
133 BoolField = { true, false },
134 BytesField = { ByteString.CopyFrom(1, 2, 3), ByteString.CopyFrom(4, 5, 6), ByteString.Empty },
135 DoubleField = { 12.5, -1.5, 0d },
136 FloatField = { 123.25f, -20f, 0f },
137 Int32Field = { int.MaxValue, int.MinValue, 0 },
138 Int64Field = { long.MaxValue, long.MinValue, 0L },
139 StringField = { "First", "Second", "" },
140 Uint32Field = { uint.MaxValue, uint.MinValue, 0U },
141 Uint64Field = { ulong.MaxValue, ulong.MinValue, 0UL },
142 };
143 var bytes = message.ToByteArray();
144 var parsed = RepeatedWellKnownTypes.Parser.ParseFrom(bytes);
145
146 Assert.AreEqual(message, parsed);
147 // Just to test a single value for sanity...
148 Assert.AreEqual("Second", message.StringField[1]);
149 }
150
151 [Test]
152 public void MapWrappersSerializeDeserialize()
153 {
154 var message = new MapWellKnownTypes
155 {
156 BoolField = { { 10, false }, { 20, true } },
157 BytesField = {
158 { -1, ByteString.CopyFrom(1, 2, 3) },
159 { 10, ByteString.CopyFrom(4, 5, 6) },
160 { 1000, ByteString.Empty },
161 { 10000, null }
162 },
163 DoubleField = { { 1, 12.5 }, { 10, -1.5 }, { 20, 0d } },
164 FloatField = { { 2, 123.25f }, { 3, -20f }, { 4, 0f } },
165 Int32Field = { { 5, int.MaxValue }, { 6, int.MinValue }, { 7, 0 } },
166 Int64Field = { { 8, long.MaxValue }, { 9, long.MinValue }, { 10, 0L } },
167 StringField = { { 11, "First" }, { 12, "Second" }, { 13, "" }, { 14, null } },
168 Uint32Field = { { 15, uint.MaxValue }, { 16, uint.MinValue }, { 17, 0U } },
169 Uint64Field = { { 18, ulong.MaxValue }, { 19, ulong.MinValue }, { 20, 0UL } },
170 };
Jon Skeet3da90e92015-07-16 21:34:10 +0100171
172 var bytes = message.ToByteArray();
173 var parsed = MapWellKnownTypes.Parser.ParseFrom(bytes);
174
175 Assert.AreEqual(message, parsed);
176 // Just to test a single value for sanity...
177 Assert.AreEqual("Second", message.StringField[12]);
Jon Skeet8a0312b2015-07-16 17:03:06 +0100178 }
179
180 [Test]
181 public void Reflection_SingleValues()
182 {
183 var message = new TestWellKnownTypes
184 {
185 StringField = "x",
186 BytesField = ByteString.CopyFrom(1, 2, 3),
187 BoolField = true,
188 FloatField = 12.5f,
189 DoubleField = 12.25d,
190 Int32Field = 1,
191 Int64Field = 2,
192 Uint32Field = 3,
193 Uint64Field = 4
194 };
Jon Skeetc1c6b2d2015-07-22 19:57:29 +0100195 var fields = TestWellKnownTypes.Descriptor.Fields;
Jon Skeet8a0312b2015-07-16 17:03:06 +0100196
Jon Skeetc1c6b2d2015-07-22 19:57:29 +0100197 Assert.AreEqual("x", fields[TestWellKnownTypes.StringFieldFieldNumber].Accessor.GetValue(message));
198 Assert.AreEqual(ByteString.CopyFrom(1, 2, 3), fields[TestWellKnownTypes.BytesFieldFieldNumber].Accessor.GetValue(message));
199 Assert.AreEqual(true, fields[TestWellKnownTypes.BoolFieldFieldNumber].Accessor.GetValue(message));
200 Assert.AreEqual(12.5f, fields[TestWellKnownTypes.FloatFieldFieldNumber].Accessor.GetValue(message));
201 Assert.AreEqual(12.25d, fields[TestWellKnownTypes.DoubleFieldFieldNumber].Accessor.GetValue(message));
202 Assert.AreEqual(1, fields[TestWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message));
203 Assert.AreEqual(2L, fields[TestWellKnownTypes.Int64FieldFieldNumber].Accessor.GetValue(message));
204 Assert.AreEqual(3U, fields[TestWellKnownTypes.Uint32FieldFieldNumber].Accessor.GetValue(message));
205 Assert.AreEqual(4UL, fields[TestWellKnownTypes.Uint64FieldFieldNumber].Accessor.GetValue(message));
Jon Skeet8a0312b2015-07-16 17:03:06 +0100206
207 // And a couple of null fields...
208 message.StringField = null;
209 message.FloatField = null;
Jon Skeetc1c6b2d2015-07-22 19:57:29 +0100210 Assert.IsNull(fields[TestWellKnownTypes.StringFieldFieldNumber].Accessor.GetValue(message));
211 Assert.IsNull(fields[TestWellKnownTypes.FloatFieldFieldNumber].Accessor.GetValue(message));
Jon Skeet8a0312b2015-07-16 17:03:06 +0100212 }
213
214 [Test]
215 public void Reflection_RepeatedFields()
216 {
217 // Just a single example... note that we can't have a null value here
218 var message = new RepeatedWellKnownTypes { Int32Field = { 1, 2 } };
Jon Skeetc1c6b2d2015-07-22 19:57:29 +0100219 var fields = RepeatedWellKnownTypes.Descriptor.Fields;
220 var list = (IList) fields[RepeatedWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message);
Jon Skeet8a0312b2015-07-16 17:03:06 +0100221 CollectionAssert.AreEqual(new[] { 1, 2 }, list);
222 }
223
224 [Test]
225 public void Reflection_MapFields()
226 {
227 // Just a single example... note that we can't have a null value here
228 var message = new MapWellKnownTypes { Int32Field = { { 1, 2 }, { 3, null } } };
Jon Skeetc1c6b2d2015-07-22 19:57:29 +0100229 var fields = MapWellKnownTypes.Descriptor.Fields;
230 var dictionary = (IDictionary) fields[MapWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message);
Jon Skeet8a0312b2015-07-16 17:03:06 +0100231 Assert.AreEqual(2, dictionary[1]);
232 Assert.IsNull(dictionary[3]);
233 Assert.IsTrue(dictionary.Contains(3));
234 }
235
Jon Skeet34878cb2015-07-17 06:41:46 +0100236 [Test]
237 public void Oneof()
238 {
239 var message = new OneofWellKnownTypes { EmptyField = new Empty() };
240 // Start off with a non-wrapper
241 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.EmptyField, message.OneofFieldCase);
242 AssertOneofRoundTrip(message);
243
244 message.StringField = "foo";
245 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.StringField, message.OneofFieldCase);
246 AssertOneofRoundTrip(message);
247
248 message.StringField = "foo";
249 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.StringField, message.OneofFieldCase);
250 AssertOneofRoundTrip(message);
251
252 message.DoubleField = 0.0f;
253 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.DoubleField, message.OneofFieldCase);
254 AssertOneofRoundTrip(message);
255
256 message.DoubleField = 1.0f;
257 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.DoubleField, message.OneofFieldCase);
258 AssertOneofRoundTrip(message);
259
260 message.ClearOneofField();
261 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.None, message.OneofFieldCase);
262 AssertOneofRoundTrip(message);
263 }
264
265 private void AssertOneofRoundTrip(OneofWellKnownTypes message)
266 {
267 // Normal roundtrip, but explicitly checking the case...
268 var bytes = message.ToByteArray();
269 var parsed = OneofWellKnownTypes.Parser.ParseFrom(bytes);
270 Assert.AreEqual(message, parsed);
271 Assert.AreEqual(message.OneofFieldCase, parsed.OneofFieldCase);
272 }
273
Jon Skeet8a0312b2015-07-16 17:03:06 +0100274 [Test]
275 [TestCase("x", "y", "y")]
276 [TestCase("x", "", "x")]
277 [TestCase("x", null, "x")]
278 [TestCase("", "y", "y")]
279 [TestCase("", "", "")]
280 [TestCase("", null, "")]
281 [TestCase(null, "y", "y")]
282 [TestCase(null, "", "")]
283 [TestCase(null, null, null)]
284 public void Merging(string original, string merged, string expected)
285 {
286 var originalMessage = new TestWellKnownTypes { StringField = original };
287 var mergingMessage = new TestWellKnownTypes { StringField = merged };
288 originalMessage.MergeFrom(mergingMessage);
289 Assert.AreEqual(expected, originalMessage.StringField);
290
291 // Try it using MergeFrom(CodedInputStream) too...
292 originalMessage = new TestWellKnownTypes { StringField = original };
293 originalMessage.MergeFrom(mergingMessage.ToByteArray());
294 Assert.AreEqual(expected, originalMessage.StringField);
Jon Skeetb2ac8682015-07-15 13:17:42 +0100295 }
Jon Skeet34878cb2015-07-17 06:41:46 +0100296
297 // Merging is odd with wrapper types, due to the way that default values aren't emitted in
298 // the binary stream. In fact we cheat a little bit - a message with an explicitly present default
299 // value will have that default value ignored.
300 [Test]
301 public void MergingCornerCase()
302 {
303 var message = new TestWellKnownTypes { Int32Field = 5 };
304
305 // Create a byte array which has the data of an Int32Value explicitly containing a value of 0.
306 // This wouldn't normally happen.
307 byte[] bytes;
308 var wrapperTag = WireFormat.MakeTag(TestWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited);
309 var valueTag = WireFormat.MakeTag(Int32Value.ValueFieldNumber, WireFormat.WireType.Varint);
310 using (var stream = new MemoryStream())
311 {
Jon Skeet0e0e0c92015-08-03 11:08:53 +0100312 var coded = new CodedOutputStream(stream);
Jon Skeet34878cb2015-07-17 06:41:46 +0100313 coded.WriteTag(wrapperTag);
314 coded.WriteLength(2); // valueTag + a value 0, each one byte
315 coded.WriteTag(valueTag);
316 coded.WriteInt32(0);
317 coded.Flush();
318 bytes = stream.ToArray();
319 }
320
321 message.MergeFrom(bytes);
322 // A normal implementation would have 0 now, as the explicit default would have been overwritten the 5.
323 Assert.AreEqual(5, message.Int32Field);
324 }
Jon Skeet5bdc5722015-08-06 11:40:43 +0100325
326 [Test]
327 public void UnknownFieldInWrapper()
328 {
329 var stream = new MemoryStream();
330 var output = new CodedOutputStream(stream);
331 var wrapperTag = WireFormat.MakeTag(TestWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited);
332 var unknownTag = WireFormat.MakeTag(15, WireFormat.WireType.Varint);
333 var valueTag = WireFormat.MakeTag(Int32Value.ValueFieldNumber, WireFormat.WireType.Varint);
334
335 output.WriteTag(wrapperTag);
336 output.WriteLength(4); // unknownTag + value 5 + valueType + value 6, each 1 byte
337 output.WriteTag(unknownTag);
338 output.WriteInt32((int) valueTag); // Sneakily "pretend" it's a tag when it's really a value
339 output.WriteTag(valueTag);
340 output.WriteInt32(6);
341
342 output.Flush();
343 stream.Position = 0;
344
345 var message = TestWellKnownTypes.Parser.ParseFrom(stream);
346 Assert.AreEqual(6, message.Int32Field);
347 }
Jon Skeetb2ac8682015-07-15 13:17:42 +0100348 }
349}