• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2015 Google Inc.  All rights reserved.
4 //
5 // Use of this source code is governed by a BSD-style
6 // license that can be found in the LICENSE file or at
7 // https://developers.google.com/open-source/licenses/bsd
8 #endregion
9 
10 using System.Collections.Generic;
11 using System.IO;
12 using System.Reflection;
13 using Google.Protobuf.TestProtos;
14 using NUnit.Framework;
15 
16 namespace Google.Protobuf
17 {
18     public class FieldCodecTest
19     {
20 #pragma warning disable 0414 // Used by tests via reflection - do not remove!
21         private static readonly List<ICodecTestData> Codecs = new List<ICodecTestData>
22         {
23             new FieldCodecTestData<bool>(FieldCodec.ForBool(100), true, "FixedBool"),
24             new FieldCodecTestData<string>(FieldCodec.ForString(100), "sample", "String"),
25             new FieldCodecTestData<ByteString>(FieldCodec.ForBytes(100), ByteString.CopyFrom(1, 2, 3), "Bytes"),
26             new FieldCodecTestData<int>(FieldCodec.ForInt32(100), -1000, "Int32"),
27             new FieldCodecTestData<int>(FieldCodec.ForSInt32(100), -1000, "SInt32"),
28             new FieldCodecTestData<int>(FieldCodec.ForSFixed32(100), -1000, "SFixed32"),
29             new FieldCodecTestData<uint>(FieldCodec.ForUInt32(100), 1234, "UInt32"),
30             new FieldCodecTestData<uint>(FieldCodec.ForFixed32(100), 1234, "Fixed32"),
31             new FieldCodecTestData<long>(FieldCodec.ForInt64(100), -1000, "Int64"),
32             new FieldCodecTestData<long>(FieldCodec.ForSInt64(100), -1000, "SInt64"),
33             new FieldCodecTestData<long>(FieldCodec.ForSFixed64(100), -1000, "SFixed64"),
34             new FieldCodecTestData<ulong>(FieldCodec.ForUInt64(100), 1234, "UInt64"),
35             new FieldCodecTestData<ulong>(FieldCodec.ForFixed64(100), 1234, "Fixed64"),
36             new FieldCodecTestData<float>(FieldCodec.ForFloat(100), 1234.5f, "FixedFloat"),
37             new FieldCodecTestData<double>(FieldCodec.ForDouble(100), 1234567890.5d, "FixedDouble"),
38             new FieldCodecTestData<ForeignEnum>(
39                 FieldCodec.ForEnum(100, t => (int) t, t => (ForeignEnum) t), ForeignEnum.ForeignBaz, "Enum"),
40             new FieldCodecTestData<ForeignMessage>(
41                 FieldCodec.ForMessage(100, ForeignMessage.Parser), new ForeignMessage { C = 10 }, "Message"),
42         };
43 #pragma warning restore 0414
44 
45         [Test, TestCaseSource("Codecs")]
RoundTripWithTag(ICodecTestData codec)46         public void RoundTripWithTag(ICodecTestData codec)
47         {
48             codec.TestRoundTripWithTag();
49         }
50 
51         [Test, TestCaseSource("Codecs")]
RoundTripRaw(ICodecTestData codec)52         public void RoundTripRaw(ICodecTestData codec)
53         {
54             codec.TestRoundTripRaw();
55         }
56 
57         [Test, TestCaseSource("Codecs")]
CalculateSize(ICodecTestData codec)58         public void CalculateSize(ICodecTestData codec)
59         {
60             codec.TestCalculateSizeWithTag();
61         }
62 
63         [Test, TestCaseSource("Codecs")]
DefaultValue(ICodecTestData codec)64         public void DefaultValue(ICodecTestData codec)
65         {
66             codec.TestDefaultValue();
67         }
68 
69         [Test, TestCaseSource("Codecs")]
FixedSize(ICodecTestData codec)70         public void FixedSize(ICodecTestData codec)
71         {
72             codec.TestFixedSize();
73         }
74 
75         // This is ugly, but it means we can have a non-generic interface.
76         // It feels like NUnit should support this better, but I don't know
77         // of any better ways right now.
78         public interface ICodecTestData
79         {
TestRoundTripRaw()80             void TestRoundTripRaw();
TestRoundTripWithTag()81             void TestRoundTripWithTag();
TestCalculateSizeWithTag()82             void TestCalculateSizeWithTag();
TestDefaultValue()83             void TestDefaultValue();
TestFixedSize()84             void TestFixedSize();
85         }
86 
87         public class FieldCodecTestData<T> : ICodecTestData
88         {
89             private readonly FieldCodec<T> codec;
90             private readonly T sampleValue;
91             private readonly string name;
92 
FieldCodecTestData(FieldCodec<T> codec, T sampleValue, string name)93             public FieldCodecTestData(FieldCodec<T> codec, T sampleValue, string name)
94             {
95                 this.codec = codec;
96                 this.sampleValue = sampleValue;
97                 this.name = name;
98             }
99 
TestRoundTripRaw()100             public void TestRoundTripRaw()
101             {
102                 var stream = new MemoryStream();
103                 var codedOutput = new CodedOutputStream(stream);
104                 WriteContext.Initialize(codedOutput, out WriteContext ctx);
105                 try
106                 {
107                     // only write the value using the codec
108                     codec.ValueWriter(ref ctx, sampleValue);
109                 }
110                 finally
111                 {
112                     ctx.CopyStateTo(codedOutput);
113                 }
114 
115                 codedOutput.Flush();
116                 stream.Position = 0;
117                 var codedInput = new CodedInputStream(stream);
118                 Assert.AreEqual(sampleValue, codec.Read(codedInput));
119                 Assert.IsTrue(codedInput.IsAtEnd);
120             }
121 
TestRoundTripWithTag()122             public void TestRoundTripWithTag()
123             {
124                 var stream = new MemoryStream();
125                 var codedOutput = new CodedOutputStream(stream);
126                 codec.WriteTagAndValue(codedOutput, sampleValue);
127                 codedOutput.Flush();
128                 stream.Position = 0;
129                 var codedInput = new CodedInputStream(stream);
130                 codedInput.AssertNextTag(codec.Tag);
131                 Assert.AreEqual(sampleValue, codec.Read(codedInput));
132                 Assert.IsTrue(codedInput.IsAtEnd);
133             }
134 
TestCalculateSizeWithTag()135             public void TestCalculateSizeWithTag()
136             {
137                 var stream = new MemoryStream();
138                 var codedOutput = new CodedOutputStream(stream);
139                 codec.WriteTagAndValue(codedOutput, sampleValue);
140                 codedOutput.Flush();
141                 Assert.AreEqual(stream.Position, codec.CalculateSizeWithTag(sampleValue));
142             }
143 
TestDefaultValue()144             public void TestDefaultValue()
145             {
146                 // WriteTagAndValue ignores default values
147                 var stream = new MemoryStream();
148                 CodedOutputStream codedOutput;
149                 codedOutput = new CodedOutputStream(stream);
150                 codec.WriteTagAndValue(codedOutput, codec.DefaultValue);
151                 codedOutput.Flush();
152                 Assert.AreEqual(0, stream.Position);
153                 Assert.AreEqual(0, codec.CalculateSizeWithTag(codec.DefaultValue));
154                 if (typeof(T).GetTypeInfo().IsValueType)
155                 {
156                     Assert.AreEqual(default(T), codec.DefaultValue);
157                 }
158 
159                 // The plain ValueWriter/ValueReader delegates don't.
160                 if (codec.DefaultValue != null) // This part isn't appropriate for message types.
161                 {
162                     codedOutput = new CodedOutputStream(stream);
163                     WriteContext.Initialize(codedOutput, out WriteContext ctx);
164                     try
165                     {
166                         // only write the value using the codec
167                         codec.ValueWriter(ref ctx, codec.DefaultValue);
168                     }
169                     finally
170                     {
171                         ctx.CopyStateTo(codedOutput);
172                     }
173 
174                     codedOutput.Flush();
175                     Assert.AreNotEqual(0, stream.Position);
176                     Assert.AreEqual(stream.Position, codec.ValueSizeCalculator(codec.DefaultValue));
177                     stream.Position = 0;
178                     var codedInput = new CodedInputStream(stream);
179                     Assert.AreEqual(codec.DefaultValue, codec.Read(codedInput));
180                 }
181             }
182 
TestFixedSize()183             public void TestFixedSize()
184             {
185                 Assert.AreEqual(name.Contains("Fixed"), codec.FixedSize != 0);
186             }
187 
ToString()188             public override string ToString()
189             {
190                 return name;
191             }
192         }
193     }
194 }
195