FieldCodecTest.cs 8.44 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2015 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

using System.Collections.Generic;
using System.IO;
35
using System.Reflection;
36 37 38 39 40 41 42
using Google.Protobuf.TestProtos;
using NUnit.Framework;

namespace Google.Protobuf
{
    public class FieldCodecTest
    {
43
#pragma warning disable 0414 // Used by tests via reflection - do not remove!
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
        private static readonly List<ICodecTestData> Codecs = new List<ICodecTestData>
        {
            new FieldCodecTestData<bool>(FieldCodec.ForBool(100), true, "Bool"),
            new FieldCodecTestData<string>(FieldCodec.ForString(100), "sample", "String"),
            new FieldCodecTestData<ByteString>(FieldCodec.ForBytes(100), ByteString.CopyFrom(1, 2, 3), "Bytes"),
            new FieldCodecTestData<int>(FieldCodec.ForInt32(100), -1000, "Int32"),
            new FieldCodecTestData<int>(FieldCodec.ForSInt32(100), -1000, "SInt32"),
            new FieldCodecTestData<int>(FieldCodec.ForSFixed32(100), -1000, "SFixed32"),
            new FieldCodecTestData<uint>(FieldCodec.ForUInt32(100), 1234, "UInt32"),
            new FieldCodecTestData<uint>(FieldCodec.ForFixed32(100), 1234, "Fixed32"),
            new FieldCodecTestData<long>(FieldCodec.ForInt64(100), -1000, "Int64"),
            new FieldCodecTestData<long>(FieldCodec.ForSInt64(100), -1000, "SInt64"),
            new FieldCodecTestData<long>(FieldCodec.ForSFixed64(100), -1000, "SFixed64"),
            new FieldCodecTestData<ulong>(FieldCodec.ForUInt64(100), 1234, "UInt64"),
            new FieldCodecTestData<ulong>(FieldCodec.ForFixed64(100), 1234, "Fixed64"),
            new FieldCodecTestData<float>(FieldCodec.ForFloat(100), 1234.5f, "Float"),
            new FieldCodecTestData<double>(FieldCodec.ForDouble(100), 1234567890.5d, "Double"),
            new FieldCodecTestData<ForeignEnum>(
62
                FieldCodec.ForEnum(100, t => (int) t, t => (ForeignEnum) t), ForeignEnum.ForeignBaz, "Enum"),
63 64 65
            new FieldCodecTestData<ForeignMessage>(
                FieldCodec.ForMessage(100, ForeignMessage.Parser), new ForeignMessage { C = 10 }, "Message"),
        };
66
#pragma warning restore 0414
67 68

        [Test, TestCaseSource("Codecs")]
69
        public void RoundTripWithTag(ICodecTestData codec)
70
        {
71 72 73 74 75 76 77
            codec.TestRoundTripWithTag();
        }

        [Test, TestCaseSource("Codecs")]
        public void RoundTripRaw(ICodecTestData codec)
        {
            codec.TestRoundTripRaw();
78 79 80 81 82
        }

        [Test, TestCaseSource("Codecs")]
        public void CalculateSize(ICodecTestData codec)
        {
83
            codec.TestCalculateSizeWithTag();
84 85 86 87 88 89 90 91
        }

        [Test, TestCaseSource("Codecs")]
        public void DefaultValue(ICodecTestData codec)
        {
            codec.TestDefaultValue();
        }

92 93 94 95 96 97 98 99 100
        [Test, TestCaseSource("Codecs")]
        public void FixedSize(ICodecTestData codec)
        {
            codec.TestFixedSize();
        }

        // This is ugly, but it means we can have a non-generic interface.
        // It feels like NUnit should support this better, but I don't know
        // of any better ways right now.
101 102
        public interface ICodecTestData
        {
103 104 105
            void TestRoundTripRaw();
            void TestRoundTripWithTag();
            void TestCalculateSizeWithTag();
106
            void TestDefaultValue();
107
            void TestFixedSize();
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
        }

        public class FieldCodecTestData<T> : ICodecTestData
        {
            private readonly FieldCodec<T> codec;
            private readonly T sampleValue;
            private readonly string name;

            public FieldCodecTestData(FieldCodec<T> codec, T sampleValue, string name)
            {
                this.codec = codec;
                this.sampleValue = sampleValue;
                this.name = name;
            }

123 124 125
            public void TestRoundTripRaw()
            {
                var stream = new MemoryStream();
126
                var codedOutput = new CodedOutputStream(stream);
127 128 129
                codec.ValueWriter(codedOutput, sampleValue);
                codedOutput.Flush();
                stream.Position = 0;
130
                var codedInput = new CodedInputStream(stream);
131 132 133 134 135
                Assert.AreEqual(sampleValue, codec.ValueReader(codedInput));
                Assert.IsTrue(codedInput.IsAtEnd);
            }

            public void TestRoundTripWithTag()
136 137
            {
                var stream = new MemoryStream();
138
                var codedOutput = new CodedOutputStream(stream);
139
                codec.WriteTagAndValue(codedOutput, sampleValue);
140 141
                codedOutput.Flush();
                stream.Position = 0;
142
                var codedInput = new CodedInputStream(stream);
143
                codedInput.AssertNextTag(codec.Tag);
144 145 146 147
                Assert.AreEqual(sampleValue, codec.Read(codedInput));
                Assert.IsTrue(codedInput.IsAtEnd);
            }

148
            public void TestCalculateSizeWithTag()
149 150
            {
                var stream = new MemoryStream();
151
                var codedOutput = new CodedOutputStream(stream);
152
                codec.WriteTagAndValue(codedOutput, sampleValue);
153
                codedOutput.Flush();
154
                Assert.AreEqual(stream.Position, codec.CalculateSizeWithTag(sampleValue));
155 156 157 158
            }

            public void TestDefaultValue()
            {
159
                // WriteTagAndValue ignores default values
160
                var stream = new MemoryStream();
161 162 163
                CodedOutputStream codedOutput;
#if !NET35
                codedOutput = new CodedOutputStream(stream);
164
                codec.WriteTagAndValue(codedOutput, codec.DefaultValue);
165 166
                codedOutput.Flush();
                Assert.AreEqual(0, stream.Position);
167
                Assert.AreEqual(0, codec.CalculateSizeWithTag(codec.DefaultValue));
168
                if (typeof(T).GetTypeInfo().IsValueType)
169 170 171
                {
                    Assert.AreEqual(default(T), codec.DefaultValue);
                }
172
#endif
173

174 175 176
                // The plain ValueWriter/ValueReader delegates don't.
                if (codec.DefaultValue != null) // This part isn't appropriate for message types.
                {
177
                    codedOutput = new CodedOutputStream(stream);
178 179 180 181 182
                    codec.ValueWriter(codedOutput, codec.DefaultValue);
                    codedOutput.Flush();
                    Assert.AreNotEqual(0, stream.Position);
                    Assert.AreEqual(stream.Position, codec.ValueSizeCalculator(codec.DefaultValue));
                    stream.Position = 0;
183
                    var codedInput = new CodedInputStream(stream);
184 185 186
                    Assert.AreEqual(codec.DefaultValue, codec.ValueReader(codedInput));
                }
            }
187

188 189 190 191 192
            public void TestFixedSize()
            {
                Assert.AreEqual(name.Contains("Fixed"), codec.FixedSize != 0);
            }

193 194 195 196 197 198 199
            public override string ToString()
            {
                return name;
            }
        }
    }
}