blob: 7f366926fa02c4c016f63467e20d3a054b4b8c47 [file] [log] [blame]
Jon Skeet286edc02015-06-26 20:11:34 +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
33using System.Collections.Generic;
34using System.IO;
Jon Skeet10a8fb42016-07-14 22:01:47 +010035using System.Reflection;
Jon Skeet286edc02015-06-26 20:11:34 +010036using Google.Protobuf.TestProtos;
37using NUnit.Framework;
38
39namespace Google.Protobuf
40{
41 public class FieldCodecTest
42 {
Jon Skeet99a81d22015-08-04 07:10:36 +010043#pragma warning disable 0414 // Used by tests via reflection - do not remove!
Jon Skeet286edc02015-06-26 20:11:34 +010044 private static readonly List<ICodecTestData> Codecs = new List<ICodecTestData>
45 {
WilliamWhispell59284452019-03-08 17:35:21 -050046 new FieldCodecTestData<bool>(FieldCodec.ForBool(100), true, "FixedBool"),
Jon Skeet286edc02015-06-26 20:11:34 +010047 new FieldCodecTestData<string>(FieldCodec.ForString(100), "sample", "String"),
48 new FieldCodecTestData<ByteString>(FieldCodec.ForBytes(100), ByteString.CopyFrom(1, 2, 3), "Bytes"),
49 new FieldCodecTestData<int>(FieldCodec.ForInt32(100), -1000, "Int32"),
50 new FieldCodecTestData<int>(FieldCodec.ForSInt32(100), -1000, "SInt32"),
51 new FieldCodecTestData<int>(FieldCodec.ForSFixed32(100), -1000, "SFixed32"),
52 new FieldCodecTestData<uint>(FieldCodec.ForUInt32(100), 1234, "UInt32"),
53 new FieldCodecTestData<uint>(FieldCodec.ForFixed32(100), 1234, "Fixed32"),
54 new FieldCodecTestData<long>(FieldCodec.ForInt64(100), -1000, "Int64"),
55 new FieldCodecTestData<long>(FieldCodec.ForSInt64(100), -1000, "SInt64"),
56 new FieldCodecTestData<long>(FieldCodec.ForSFixed64(100), -1000, "SFixed64"),
57 new FieldCodecTestData<ulong>(FieldCodec.ForUInt64(100), 1234, "UInt64"),
58 new FieldCodecTestData<ulong>(FieldCodec.ForFixed64(100), 1234, "Fixed64"),
WilliamWhispell59284452019-03-08 17:35:21 -050059 new FieldCodecTestData<float>(FieldCodec.ForFloat(100), 1234.5f, "FixedFloat"),
60 new FieldCodecTestData<double>(FieldCodec.ForDouble(100), 1234567890.5d, "FixedDouble"),
Jon Skeet286edc02015-06-26 20:11:34 +010061 new FieldCodecTestData<ForeignEnum>(
Jon Skeet84ea2c72016-04-08 12:33:09 +010062 FieldCodec.ForEnum(100, t => (int) t, t => (ForeignEnum) t), ForeignEnum.ForeignBaz, "Enum"),
Jon Skeet286edc02015-06-26 20:11:34 +010063 new FieldCodecTestData<ForeignMessage>(
64 FieldCodec.ForMessage(100, ForeignMessage.Parser), new ForeignMessage { C = 10 }, "Message"),
65 };
Jon Skeet99a81d22015-08-04 07:10:36 +010066#pragma warning restore 0414
Jon Skeet286edc02015-06-26 20:11:34 +010067
68 [Test, TestCaseSource("Codecs")]
Jon Skeetf34d37a2015-06-30 13:16:20 +010069 public void RoundTripWithTag(ICodecTestData codec)
Jon Skeet286edc02015-06-26 20:11:34 +010070 {
Jon Skeetf34d37a2015-06-30 13:16:20 +010071 codec.TestRoundTripWithTag();
72 }
73
74 [Test, TestCaseSource("Codecs")]
75 public void RoundTripRaw(ICodecTestData codec)
76 {
77 codec.TestRoundTripRaw();
Jon Skeet286edc02015-06-26 20:11:34 +010078 }
79
80 [Test, TestCaseSource("Codecs")]
81 public void CalculateSize(ICodecTestData codec)
82 {
Jon Skeetf34d37a2015-06-30 13:16:20 +010083 codec.TestCalculateSizeWithTag();
Jon Skeet286edc02015-06-26 20:11:34 +010084 }
85
86 [Test, TestCaseSource("Codecs")]
87 public void DefaultValue(ICodecTestData codec)
88 {
89 codec.TestDefaultValue();
90 }
91
Jon Skeet14f22222015-07-03 11:41:37 +010092 [Test, TestCaseSource("Codecs")]
93 public void FixedSize(ICodecTestData codec)
94 {
95 codec.TestFixedSize();
96 }
97
98 // This is ugly, but it means we can have a non-generic interface.
99 // It feels like NUnit should support this better, but I don't know
100 // of any better ways right now.
Jon Skeet286edc02015-06-26 20:11:34 +0100101 public interface ICodecTestData
102 {
Jon Skeetf34d37a2015-06-30 13:16:20 +0100103 void TestRoundTripRaw();
104 void TestRoundTripWithTag();
105 void TestCalculateSizeWithTag();
Jon Skeet286edc02015-06-26 20:11:34 +0100106 void TestDefaultValue();
Jon Skeet14f22222015-07-03 11:41:37 +0100107 void TestFixedSize();
Jon Skeet286edc02015-06-26 20:11:34 +0100108 }
109
110 public class FieldCodecTestData<T> : ICodecTestData
111 {
112 private readonly FieldCodec<T> codec;
113 private readonly T sampleValue;
114 private readonly string name;
115
116 public FieldCodecTestData(FieldCodec<T> codec, T sampleValue, string name)
117 {
118 this.codec = codec;
119 this.sampleValue = sampleValue;
120 this.name = name;
121 }
122
Jon Skeetf34d37a2015-06-30 13:16:20 +0100123 public void TestRoundTripRaw()
124 {
125 var stream = new MemoryStream();
Jon Skeet0e0e0c92015-08-03 11:08:53 +0100126 var codedOutput = new CodedOutputStream(stream);
Jan Tattermuschca7bc462020-05-29 08:51:37 +0200127 WriteContext.Initialize(codedOutput, out WriteContext ctx);
128 try
129 {
Jan Tattermuschc06812b2020-06-08 17:13:15 +0200130 // only write the value using the codec
Jan Tattermuschca7bc462020-05-29 08:51:37 +0200131 codec.ValueWriter(ref ctx, sampleValue);
132 }
133 finally
134 {
135 ctx.CopyStateTo(codedOutput);
136 }
137
Jon Skeetf34d37a2015-06-30 13:16:20 +0100138 codedOutput.Flush();
139 stream.Position = 0;
Jon Skeet0e0e0c92015-08-03 11:08:53 +0100140 var codedInput = new CodedInputStream(stream);
Jan Tattermuschea605382020-03-31 18:56:05 +0200141 Assert.AreEqual(sampleValue, codec.Read(codedInput));
Jon Skeetf34d37a2015-06-30 13:16:20 +0100142 Assert.IsTrue(codedInput.IsAtEnd);
143 }
144
145 public void TestRoundTripWithTag()
Jon Skeet286edc02015-06-26 20:11:34 +0100146 {
147 var stream = new MemoryStream();
Jon Skeet0e0e0c92015-08-03 11:08:53 +0100148 var codedOutput = new CodedOutputStream(stream);
Jon Skeetb9d1d382015-06-29 10:30:09 +0100149 codec.WriteTagAndValue(codedOutput, sampleValue);
Jon Skeet286edc02015-06-26 20:11:34 +0100150 codedOutput.Flush();
151 stream.Position = 0;
Jon Skeet0e0e0c92015-08-03 11:08:53 +0100152 var codedInput = new CodedInputStream(stream);
Jon Skeetf34d37a2015-06-30 13:16:20 +0100153 codedInput.AssertNextTag(codec.Tag);
Jon Skeet286edc02015-06-26 20:11:34 +0100154 Assert.AreEqual(sampleValue, codec.Read(codedInput));
155 Assert.IsTrue(codedInput.IsAtEnd);
156 }
157
Jon Skeetf34d37a2015-06-30 13:16:20 +0100158 public void TestCalculateSizeWithTag()
Jon Skeet286edc02015-06-26 20:11:34 +0100159 {
160 var stream = new MemoryStream();
Jon Skeet0e0e0c92015-08-03 11:08:53 +0100161 var codedOutput = new CodedOutputStream(stream);
Jon Skeetb9d1d382015-06-29 10:30:09 +0100162 codec.WriteTagAndValue(codedOutput, sampleValue);
Jon Skeet286edc02015-06-26 20:11:34 +0100163 codedOutput.Flush();
Jon Skeetb9d1d382015-06-29 10:30:09 +0100164 Assert.AreEqual(stream.Position, codec.CalculateSizeWithTag(sampleValue));
Jon Skeet286edc02015-06-26 20:11:34 +0100165 }
166
167 public void TestDefaultValue()
168 {
Jon Skeetf34d37a2015-06-30 13:16:20 +0100169 // WriteTagAndValue ignores default values
Jon Skeet286edc02015-06-26 20:11:34 +0100170 var stream = new MemoryStream();
Jan Tattermuschea605382020-03-31 18:56:05 +0200171 CodedOutputStream codedOutput;
John Brockc9b2c8f2017-02-13 15:34:35 -0800172#if !NET35
173 codedOutput = new CodedOutputStream(stream);
Jon Skeetb9d1d382015-06-29 10:30:09 +0100174 codec.WriteTagAndValue(codedOutput, codec.DefaultValue);
Jon Skeet286edc02015-06-26 20:11:34 +0100175 codedOutput.Flush();
176 Assert.AreEqual(0, stream.Position);
Jon Skeetb9d1d382015-06-29 10:30:09 +0100177 Assert.AreEqual(0, codec.CalculateSizeWithTag(codec.DefaultValue));
Jon Skeet10a8fb42016-07-14 22:01:47 +0100178 if (typeof(T).GetTypeInfo().IsValueType)
Jon Skeet286edc02015-06-26 20:11:34 +0100179 {
180 Assert.AreEqual(default(T), codec.DefaultValue);
181 }
John Brockc9b2c8f2017-02-13 15:34:35 -0800182#endif
Jon Skeet286edc02015-06-26 20:11:34 +0100183
Jon Skeetf34d37a2015-06-30 13:16:20 +0100184 // The plain ValueWriter/ValueReader delegates don't.
185 if (codec.DefaultValue != null) // This part isn't appropriate for message types.
186 {
Jon Skeet0e0e0c92015-08-03 11:08:53 +0100187 codedOutput = new CodedOutputStream(stream);
Jan Tattermuschca7bc462020-05-29 08:51:37 +0200188 WriteContext.Initialize(codedOutput, out WriteContext ctx);
189 try
190 {
Jan Tattermuschc06812b2020-06-08 17:13:15 +0200191 // only write the value using the codec
Jan Tattermuschca7bc462020-05-29 08:51:37 +0200192 codec.ValueWriter(ref ctx, codec.DefaultValue);
193 }
194 finally
195 {
196 ctx.CopyStateTo(codedOutput);
197 }
198
Jon Skeetf34d37a2015-06-30 13:16:20 +0100199 codedOutput.Flush();
200 Assert.AreNotEqual(0, stream.Position);
201 Assert.AreEqual(stream.Position, codec.ValueSizeCalculator(codec.DefaultValue));
202 stream.Position = 0;
Jon Skeet0e0e0c92015-08-03 11:08:53 +0100203 var codedInput = new CodedInputStream(stream);
Jan Tattermuschea605382020-03-31 18:56:05 +0200204 Assert.AreEqual(codec.DefaultValue, codec.Read(codedInput));
Jon Skeetf34d37a2015-06-30 13:16:20 +0100205 }
206 }
Jon Skeet286edc02015-06-26 20:11:34 +0100207
Jon Skeet14f22222015-07-03 11:41:37 +0100208 public void TestFixedSize()
209 {
210 Assert.AreEqual(name.Contains("Fixed"), codec.FixedSize != 0);
211 }
212
Jon Skeet286edc02015-06-26 20:11:34 +0100213 public override string ToString()
214 {
215 return name;
216 }
217 }
218 }
219}