blob: e06254d7f243172a8e8dd86ed76999423360b987 [file] [log] [blame]
Jon Skeet0aac0e42009-09-09 18:48:02 +01001#region Copyright notice and license
Jon Skeet60c059b2008-10-23 21:17:56 +01002// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
Jon Skeet68036862008-10-22 13:30:34 +01006// http://code.google.com/p/protobuf/
7//
Jon Skeet60c059b2008-10-23 21:17:56 +01008// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
Jon Skeet68036862008-10-22 13:30:34 +010011//
Jon Skeet60c059b2008-10-23 21:17:56 +010012// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
Jon Skeet68036862008-10-22 13:30:34 +010021//
Jon Skeet60c059b2008-10-23 21:17:56 +010022// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet0aac0e42009-09-09 18:48:02 +010033#endregion
34
Jon Skeet17ded822010-05-19 21:07:58 +010035using System.IO;
Jon Skeet68036862008-10-22 13:30:34 +010036using Google.ProtocolBuffers.Descriptors;
37using Google.ProtocolBuffers.TestProtos;
38using NUnit.Framework;
39
40namespace Google.ProtocolBuffers {
41 /// <summary>
42 /// Miscellaneous tests for message operations that apply to both
43 /// generated and dynamic messages.
44 /// </summary>
45 [TestFixture]
46 public class MessageTest {
47 // =================================================================
48 // Message-merging tests.
49
50 private static readonly TestAllTypes MergeSource = new TestAllTypes.Builder {
51 OptionalInt32 = 1,
52 OptionalString = "foo",
53 OptionalForeignMessage = ForeignMessage.DefaultInstance,
54 }.AddRepeatedString("bar").Build();
55
56 private static readonly TestAllTypes MergeDest = new TestAllTypes.Builder {
57 OptionalInt64 = 2,
58 OptionalString = "baz",
59 OptionalForeignMessage = new ForeignMessage.Builder { C=3 }.Build(),
60 }.AddRepeatedString("qux").Build();
61
62 private const string MergeResultText =
63 "optional_int32: 1\n" +
64 "optional_int64: 2\n" +
65 "optional_string: \"foo\"\n" +
66 "optional_foreign_message {\n" +
67 " c: 3\n" +
68 "}\n" +
69 "repeated_string: \"qux\"\n" +
70 "repeated_string: \"bar\"\n";
71
72 [Test]
73 public void MergeFrom() {
74 TestAllTypes result = TestAllTypes.CreateBuilder(MergeDest).MergeFrom(MergeSource).Build();
75
76 Assert.AreEqual(MergeResultText, result.ToString());
77 }
78
79 /// <summary>
80 /// Test merging a DynamicMessage into a GeneratedMessage.
81 /// As long as they have the same descriptor, this should work, but it is an
82 /// entirely different code path.
83 /// </summary>
84 [Test]
85 public void MergeFromDynamic() {
86 TestAllTypes result = (TestAllTypes) TestAllTypes.CreateBuilder(MergeDest)
87 .MergeFrom(DynamicMessage.CreateBuilder(MergeSource).Build())
88 .Build();
89
90 Assert.AreEqual(MergeResultText, result.ToString());
91 }
92
93 /// <summary>
94 /// Test merging two DynamicMessages.
95 /// </summary>
96 [Test]
97 public void DynamicMergeFrom() {
98 DynamicMessage result = (DynamicMessage) DynamicMessage.CreateBuilder(MergeDest)
99 .MergeFrom((DynamicMessage) DynamicMessage.CreateBuilder(MergeSource).Build())
100 .Build();
101
102 Assert.AreEqual(MergeResultText, result.ToString());
103 }
104
105 // =================================================================
106 // Required-field-related tests.
107
108 private static readonly TestRequired TestRequiredUninitialized = TestRequired.DefaultInstance;
109 private static readonly TestRequired TestRequiredInitialized = new TestRequired.Builder {
110 A = 1, B = 2, C = 3
111 }.Build();
112
113 [Test]
114 public void Initialization() {
115 TestRequired.Builder builder = TestRequired.CreateBuilder();
116
117 Assert.IsFalse(builder.IsInitialized);
118 builder.A = 1;
119 Assert.IsFalse(builder.IsInitialized);
120 builder.B = 1;
121 Assert.IsFalse(builder.IsInitialized);
122 builder.C = 1;
123 Assert.IsTrue(builder.IsInitialized);
124 }
125
126 [Test]
127 public void RequiredForeign() {
128 TestRequiredForeign.Builder builder = TestRequiredForeign.CreateBuilder();
129
130 Assert.IsTrue(builder.IsInitialized);
131
132 builder.SetOptionalMessage(TestRequiredUninitialized);
133 Assert.IsFalse(builder.IsInitialized);
134
135 builder.SetOptionalMessage(TestRequiredInitialized);
136 Assert.IsTrue(builder.IsInitialized);
137
138 builder.AddRepeatedMessage(TestRequiredUninitialized);
139 Assert.IsFalse(builder.IsInitialized);
140
141 builder.SetRepeatedMessage(0, TestRequiredInitialized);
142 Assert.IsTrue(builder.IsInitialized);
143 }
144
145 [Test]
146 public void RequiredExtension() {
147 TestAllExtensions.Builder builder = TestAllExtensions.CreateBuilder();
148
149 Assert.IsTrue(builder.IsInitialized);
150
151 builder.SetExtension(TestRequired.Single, TestRequiredUninitialized);
152 Assert.IsFalse(builder.IsInitialized);
153
154 builder.SetExtension(TestRequired.Single, TestRequiredInitialized);
155 Assert.IsTrue(builder.IsInitialized);
156
157 builder.AddExtension(TestRequired.Multi, TestRequiredUninitialized);
158 Assert.IsFalse(builder.IsInitialized);
159
160 builder.SetExtension(TestRequired.Multi, 0, TestRequiredInitialized);
161 Assert.IsTrue(builder.IsInitialized);
162 }
163
164 [Test]
165 public void RequiredDynamic() {
166 MessageDescriptor descriptor = TestRequired.Descriptor;
167 DynamicMessage.Builder builder = DynamicMessage.CreateBuilder(descriptor);
168
169 Assert.IsFalse(builder.IsInitialized);
170 builder[descriptor.FindDescriptor<FieldDescriptor>("a")] = 1;
171 Assert.IsFalse(builder.IsInitialized);
172 builder[descriptor.FindDescriptor<FieldDescriptor>("b")] = 1;
173 Assert.IsFalse(builder.IsInitialized);
174 builder[descriptor.FindDescriptor<FieldDescriptor>("c")] = 1;
175 Assert.IsTrue(builder.IsInitialized);
176 }
177
178 [Test]
179 public void RequiredDynamicForeign() {
180 MessageDescriptor descriptor = TestRequiredForeign.Descriptor;
181 DynamicMessage.Builder builder = DynamicMessage.CreateBuilder(descriptor);
182
183 Assert.IsTrue(builder.IsInitialized);
184
185 builder[descriptor.FindDescriptor<FieldDescriptor>("optional_message")] = TestRequiredUninitialized;
186 Assert.IsFalse(builder.IsInitialized);
187
188 builder[descriptor.FindDescriptor<FieldDescriptor>("optional_message")] = TestRequiredInitialized;
189 Assert.IsTrue(builder.IsInitialized);
190
191 builder.AddRepeatedField(descriptor.FindDescriptor<FieldDescriptor>("repeated_message"), TestRequiredUninitialized);
192 Assert.IsFalse(builder.IsInitialized);
193
194 builder.SetRepeatedField(descriptor.FindDescriptor<FieldDescriptor>("repeated_message"), 0, TestRequiredInitialized);
195 Assert.IsTrue(builder.IsInitialized);
196 }
197
198 [Test]
199 public void UninitializedException() {
200 try {
201 TestRequired.CreateBuilder().Build();
202 Assert.Fail("Should have thrown an exception.");
203 } catch (UninitializedMessageException e) {
204 Assert.AreEqual("Message missing required fields: a, b, c", e.Message);
205 }
206 }
207
208 [Test]
209 public void BuildPartial() {
210 // We're mostly testing that no exception is thrown.
211 TestRequired message = TestRequired.CreateBuilder().BuildPartial();
212 Assert.IsFalse(message.IsInitialized);
213 }
214
215 [Test]
216 public void NestedUninitializedException() {
217 try {
218 TestRequiredForeign.CreateBuilder()
219 .SetOptionalMessage(TestRequiredUninitialized)
220 .AddRepeatedMessage(TestRequiredUninitialized)
221 .AddRepeatedMessage(TestRequiredUninitialized)
222 .Build();
223 Assert.Fail("Should have thrown an exception.");
224 } catch (UninitializedMessageException e) {
225 Assert.AreEqual(
226 "Message missing required fields: " +
227 "optional_message.a, " +
228 "optional_message.b, " +
229 "optional_message.c, " +
230 "repeated_message[0].a, " +
231 "repeated_message[0].b, " +
232 "repeated_message[0].c, " +
233 "repeated_message[1].a, " +
234 "repeated_message[1].b, " +
235 "repeated_message[1].c",
236 e.Message);
237 }
238 }
239
240 [Test]
241 public void BuildNestedPartial() {
242 // We're mostly testing that no exception is thrown.
243 TestRequiredForeign message =
244 TestRequiredForeign.CreateBuilder()
245 .SetOptionalMessage(TestRequiredUninitialized)
246 .AddRepeatedMessage(TestRequiredUninitialized)
247 .AddRepeatedMessage(TestRequiredUninitialized)
248 .BuildPartial();
249 Assert.IsFalse(message.IsInitialized);
250 }
251
252 [Test]
253 public void ParseUnititialized() {
254 try {
255 TestRequired.ParseFrom(ByteString.Empty);
256 Assert.Fail("Should have thrown an exception.");
257 } catch (InvalidProtocolBufferException e) {
258 Assert.AreEqual("Message missing required fields: a, b, c", e.Message);
259 }
260 }
261
262 [Test]
263 public void ParseNestedUnititialized() {
264 ByteString data =
265 TestRequiredForeign.CreateBuilder()
266 .SetOptionalMessage(TestRequiredUninitialized)
267 .AddRepeatedMessage(TestRequiredUninitialized)
268 .AddRepeatedMessage(TestRequiredUninitialized)
269 .BuildPartial().ToByteString();
270
271 try {
272 TestRequiredForeign.ParseFrom(data);
273 Assert.Fail("Should have thrown an exception.");
274 } catch (InvalidProtocolBufferException e) {
275 Assert.AreEqual(
276 "Message missing required fields: " +
277 "optional_message.a, " +
278 "optional_message.b, " +
279 "optional_message.c, " +
280 "repeated_message[0].a, " +
281 "repeated_message[0].b, " +
282 "repeated_message[0].c, " +
283 "repeated_message[1].a, " +
284 "repeated_message[1].b, " +
285 "repeated_message[1].c",
286 e.Message);
287 }
288 }
289
290 [Test]
291 public void DynamicUninitializedException() {
292 try {
293 DynamicMessage.CreateBuilder(TestRequired.Descriptor).Build();
294 Assert.Fail("Should have thrown an exception.");
295 } catch (UninitializedMessageException e) {
296 Assert.AreEqual("Message missing required fields: a, b, c", e.Message);
297 }
298 }
299
300 [Test]
301 public void DynamicBuildPartial() {
302 // We're mostly testing that no exception is thrown.
303 DynamicMessage message = DynamicMessage.CreateBuilder(TestRequired.Descriptor).BuildPartial();
304 Assert.IsFalse(message.Initialized);
305 }
306
307 [Test]
308 public void DynamicParseUnititialized() {
309 try {
310 MessageDescriptor descriptor = TestRequired.Descriptor;
311 DynamicMessage.ParseFrom(descriptor, ByteString.Empty);
312 Assert.Fail("Should have thrown an exception.");
313 } catch (InvalidProtocolBufferException e) {
314 Assert.AreEqual("Message missing required fields: a, b, c", e.Message);
315 }
316 }
Jon Skeet17ded822010-05-19 21:07:58 +0100317
318 [Test]
319 public void PackedTypesWrittenDirectlyToStream() {
320 TestPackedTypes message = new TestPackedTypes.Builder {PackedInt32List = {0, 1, 2}}.Build();
321 MemoryStream stream = new MemoryStream();
322 message.WriteTo(stream);
323 stream.Position = 0;
324 TestPackedTypes readMessage = TestPackedTypes.ParseFrom(stream);
325 Assert.AreEqual(message, readMessage);
326 }
Jon Skeet68036862008-10-22 13:30:34 +0100327 }
328
329}