• 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                 codedOutput.Flush();
115                 stream.Position = 0;
116                 var codedInput = new CodedInputStream(stream);
117                 Assert.AreEqual(sampleValue, codec.Read(codedInput));
118                 Assert.IsTrue(codedInput.IsAtEnd);
119             }
120 
TestRoundTripWithTag()121             public void TestRoundTripWithTag()
122             {
123                 var stream = new MemoryStream();
124                 var codedOutput = new CodedOutputStream(stream);
125                 codec.WriteTagAndValue(codedOutput, sampleValue);
126                 codedOutput.Flush();
127                 stream.Position = 0;
128                 var codedInput = new CodedInputStream(stream);
129                 codedInput.AssertNextTag(codec.Tag);
130                 Assert.AreEqual(sampleValue, codec.Read(codedInput));
131                 Assert.IsTrue(codedInput.IsAtEnd);
132             }
133 
TestCalculateSizeWithTag()134             public void TestCalculateSizeWithTag()
135             {
136                 var stream = new MemoryStream();
137                 var codedOutput = new CodedOutputStream(stream);
138                 codec.WriteTagAndValue(codedOutput, sampleValue);
139                 codedOutput.Flush();
140                 Assert.AreEqual(stream.Position, codec.CalculateSizeWithTag(sampleValue));
141             }
142 
TestDefaultValue()143             public void TestDefaultValue()
144             {
145                 // WriteTagAndValue ignores default values
146                 var stream = new MemoryStream();
147                 var codedOutput = new CodedOutputStream(stream);
148                 codec.WriteTagAndValue(codedOutput, codec.DefaultValue);
149                 codedOutput.Flush();
150                 Assert.AreEqual(0, stream.Position);
151                 Assert.AreEqual(0, codec.CalculateSizeWithTag(codec.DefaultValue));
152                 if (typeof(T).GetTypeInfo().IsValueType)
153                 {
154                     Assert.AreEqual(default(T), codec.DefaultValue);
155                 }
156 
157                 // The plain ValueWriter/ValueReader delegates don't.
158                 if (codec.DefaultValue != null) // This part isn't appropriate for message types.
159                 {
160                     codedOutput = new CodedOutputStream(stream);
161                     WriteContext.Initialize(codedOutput, out WriteContext ctx);
162                     try
163                     {
164                         // only write the value using the codec
165                         codec.ValueWriter(ref ctx, codec.DefaultValue);
166                     }
167                     finally
168                     {
169                         ctx.CopyStateTo(codedOutput);
170                     }
171                     codedOutput.Flush();
172                     Assert.AreNotEqual(0, stream.Position);
173                     Assert.AreEqual(stream.Position, codec.ValueSizeCalculator(codec.DefaultValue));
174                     stream.Position = 0;
175                     var codedInput = new CodedInputStream(stream);
176                     Assert.AreEqual(codec.DefaultValue, codec.Read(codedInput));
177                 }
178             }
179 
TestFixedSize()180             public void TestFixedSize()
181             {
182                 Assert.AreEqual(name.Contains("Fixed"), codec.FixedSize != 0);
183             }
184 
ToString()185             public override string ToString()
186             {
187                 return name;
188             }
189         }
190     }
191 }
192