blob: 1aa3c3a03ae4c068edf6b8f59ce20aa783d11d04 [file]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections;
using System.IO;
using NUnit.Framework;
using Avro.IO;
using Avro.Specific;
using Avro.Test.Specific;
using System.Collections.Generic;
using Avro.Generic;
using Avro.Test.Generic;
using Avro.Test.Specific.@return;
#if !NETCOREAPP
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Reflection;
#endif
namespace Avro.Test
{
[TestFixture]
class SpecificTests
{
#if !NETCOREAPP // System.CodeDom compilation not supported in .NET Core: https://github.com/dotnet/corefx/issues/12180
// The dynamically created assembly used in the test below can only be created
// once otherwise repeated tests will fail as the same type name will exist in
// multiple assemblies and so the type in the test and the type found by ObjectCreator
// will differ. This single CompilerResults only works so long as there is only one test.
// If additional tests are added then each test will need its own CompilerResults.
private static CompilerResults compres;
[TestCase(@"{
""protocol"" : ""MyProtocol"",
""namespace"" : ""com.foo"",
""types"" : [
{
""type"" : ""record"",
""name"" : ""A"",
""fields"" : [ { ""name"" : ""f1"", ""type"" : ""long"" } ]
},
{
""type"" : ""enum"",
""name"" : ""MyEnum"",
""symbols"" : [ ""A"", ""B"", ""C"" ]
},
{
""type"": ""fixed"",
""size"": 16,
""name"": ""MyFixed""
},
{
""type"" : ""record"",
""name"" : ""Z"",
""fields"" :
[
{ ""name"" : ""myUInt"", ""type"" : [ ""int"", ""null"" ] },
{ ""name"" : ""myULong"", ""type"" : [ ""long"", ""null"" ] },
{ ""name"" : ""myUBool"", ""type"" : [ ""boolean"", ""null"" ] },
{ ""name"" : ""myUDouble"", ""type"" : [ ""double"", ""null"" ] },
{ ""name"" : ""myUFloat"", ""type"" : [ ""float"", ""null"" ] },
{ ""name"" : ""myUBytes"", ""type"" : [ ""bytes"", ""null"" ] },
{ ""name"" : ""myUString"", ""type"" : [ ""string"", ""null"" ] },
{ ""name"" : ""myInt"", ""type"" : ""int"" },
{ ""name"" : ""myLong"", ""type"" : ""long"" },
{ ""name"" : ""myBool"", ""type"" : ""boolean"" },
{ ""name"" : ""myDouble"", ""type"" : ""double"" },
{ ""name"" : ""myFloat"", ""type"" : ""float"" },
{ ""name"" : ""myBytes"", ""type"" : ""bytes"" },
{ ""name"" : ""myString"", ""type"" : ""string"" },
{ ""name"" : ""myNull"", ""type"" : ""null"" },
{ ""name"" : ""myFixed"", ""type"" : ""MyFixed"" },
{ ""name"" : ""myA"", ""type"" : ""A"" },
{ ""name"" : ""myE"", ""type"" : ""MyEnum"" },
{ ""name"" : ""myArray"", ""type"" : { ""type"" : ""array"", ""items"" : ""bytes"" } },
{ ""name"" : ""myArray2"", ""type"" : { ""type"" : ""array"", ""items"" : { ""type"" : ""record"", ""name"" : ""newRec"", ""fields"" : [ { ""name"" : ""f1"", ""type"" : ""long""} ] } } },
{ ""name"" : ""myMap"", ""type"" : { ""type"" : ""map"", ""values"" : ""string"" } },
{ ""name"" : ""myMap2"", ""type"" : { ""type"" : ""map"", ""values"" : ""newRec"" } },
{ ""name"" : ""myObject"", ""type"" : [ ""MyEnum"", ""A"", ""null"" ] },
{ ""name"" : ""myArray3"", ""type"" : { ""type"" : ""array"", ""items"" : { ""type"" : ""array"", ""items"" : [ ""double"", ""string"", ""null"" ] } } }
]
}
]
}"
, new object[] {3, // index of the schema to serialize
"com.foo.Z", // name of the schema to serialize
@"// Console.WriteLine(""Constructing com.foo.Z..."");", // Empty Constructor.
@"
// Console.WriteLine(""Populating com.foo.Z..."");
string bytes = ""bytes sample text"";
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
myUInt=1;
myULong=2;
myUBool=true;
myUDouble=(double)3;
myUFloat=(float)4.5;
myUBytes = encoding.GetBytes(bytes);
myUString=""Hello"";
myInt=1;
myLong=2;
myBool=true;
myDouble=(double)3;
myFloat=(float)4.5;
myBytes=encoding.GetBytes(bytes);
myString=""Hello"";
myNull=null;
string fixedstr = ""My fixed record0"";
myFixed=new MyFixed(); myFixed.Value = encoding.GetBytes(fixedstr);
myA=new A(); myA.f1 = 10;
myE=com.foo.MyEnum.C;
myArray=new List<byte[]>();
myArray.Add(encoding.GetBytes(""a""));
myArray2 = new List<com.foo.newRec>();
com.foo.newRec rec = new com.foo.newRec();
rec.f1 = 50;
myArray2.Add(rec);
myMap = new Dictionary<string, string>();
myMap.Add(""key"", ""value"");
myMap2 = new Dictionary<string, com.foo.newRec>();
com.foo.newRec newrec = new com.foo.newRec();
newrec.f1 = 1200;
myMap2.Add(""A"", newrec);
myObject = myA;
IList<System.Object> o1 = new List<System.Object>();
o1.Add((double)1123123121);
o1.Add((double)2);
o1.Add(null);
o1.Add(""fred"");
IList<System.Object> o2 = new List<System.Object>();
o2.Add((double)1);
o2.Add((double)32531);
o2.Add((double)4);
o2.Add((double)555);
o2.Add((double)0);
myArray3 = new List<IList<System.Object>>();
myArray3.Add(o1);
myArray3.Add(o2);
"}, TestName = "TestSpecific")]
public void TestSpecific(string str, object[] result)
{
if(compres == null)
{
Protocol protocol = Protocol.Parse(str);
var codegen = new CodeGen();
codegen.AddProtocol(protocol);
var compileUnit = codegen.GenerateCode();
// add a constructor to the main class using the passed assignment statements
CodeTypeDeclaration ctd = compileUnit.Namespaces[0].Types[(int)result[0]];
CodeConstructor constructor = new CodeConstructor();
constructor.Attributes = MemberAttributes.Public;
CodeSnippetExpression snippet = new CodeSnippetExpression((string)result[2]);
constructor.Statements.Add(snippet);
ctd.Members.Add(constructor);
// add a function to the main class to populate the data
// This has been moved from constructor, as it was causing some tests to pass that shouldn't when referencing a blank object on READ.
CodeMemberMethod method = new CodeMemberMethod();
method.Attributes = MemberAttributes.Public;
method.Name = "Populate";
CodeSnippetExpression snippet2 = new CodeSnippetExpression((string)result[3]);
method.Statements.Add(snippet2);
ctd.Members.Add(method);
// compile
var comparam = new CompilerParameters(new string[] { "netstandard.dll" });
comparam.ReferencedAssemblies.Add("System.dll");
comparam.ReferencedAssemblies.Add(Path.Combine(TestContext.CurrentContext.TestDirectory, "Avro.dll"));
comparam.GenerateInMemory = true;
var ccp = new Microsoft.CSharp.CSharpCodeProvider();
var units = new CodeCompileUnit[] { compileUnit };
compres = ccp.CompileAssemblyFromDom(comparam, units);
Assert.IsNotNull(compres);
if (compres.Errors.Count > 0)
{
for (int i = 0; i < compres.Errors.Count; i++)
Console.WriteLine(compres.Errors[i]);
}
Assert.IsTrue(compres.Errors.Count == 0);
}
// create record
ISpecificRecord rec = compres.CompiledAssembly.CreateInstance((string)result[1]) as ISpecificRecord;
// Call populate to put some data in it.
Type recType = rec.GetType(); ;
MethodInfo methodInfo = recType.GetMethod("Populate");
methodInfo.Invoke(rec, null);
var x1 = compres.CompiledAssembly.FullName;
Assert.IsFalse(rec == null);
// serialize
var stream = serialize(rec.Schema, rec);
// deserialize
var rec2 = deserialize<ISpecificRecord>(stream, rec.Schema, rec.Schema);
Assert.IsFalse(rec2 == null);
AssertSpecificRecordEqual(rec, rec2);
}
#endif
[TestCase]
public void TestEnumResolution()
{
Schema writerSchema = Schema.Parse("{\"type\":\"record\",\"name\":\"EnumRecord\",\"namespace\":\"Avro.Test\"," +
"\"fields\":[{\"name\":\"enumType\",\"type\": { \"type\": \"enum\", \"name\": \"EnumType\", \"symbols\": [\"FIRST\", \"SECOND\"]} }]}");
var testRecord = new EnumRecord();
Schema readerSchema = testRecord.Schema;
testRecord.enumType = EnumType.SECOND;
// serialize
var stream = serialize(writerSchema, testRecord);
// deserialize
var rec2 = deserialize<EnumRecord>(stream, writerSchema, readerSchema);
Assert.AreEqual( EnumType.SECOND, rec2.enumType );
}
[Test]
public void TestEnumDefault()
{
//writerSchema has "SECOND"
Schema writerSchema = Schema.Parse("{ \"type\": \"record\", \"name\": \"EnumRecord\", \"fields\": [ { \"name\": \"enumType\", \"type\": { \"type\": \"enum\", \"name\": \"EnumType\", \"symbols\": [ \"DEFAULT\", \"FIRST\", \"SECOND\", \"THIRD\" ], \"default\": \"DEFAULT\" } } ] }");
Schema readerSchema = Schema.Parse("{ \"type\": \"record\", \"name\": \"EnumRecord\", \"fields\": [ { \"name\": \"enumType\", \"type\": { \"type\": \"enum\", \"name\": \"EnumType\", \"symbols\": [ \"DEFAULT\", \"FIRST\", \"THIRD\" ], \"default\": \"DEFAULT\" } } ] }");
//readerSchema is missing "SECOND" so should therefore be "DEFAULT"
var testRecord = new EnumRecord {enumType = EnumType.SECOND};
// serialize
var stream = serialize(writerSchema, testRecord);
// deserialize
var rec2 = deserialize<EnumRecord>(stream, writerSchema, readerSchema);
Assert.AreEqual(EnumType.DEFAULT, rec2.enumType);
}
[TestCase(0L)]
[TestCase(100L)]
[TestCase(-100L)]
[TestCase(0.0)]
[TestCase(100.0)]
[TestCase(-100.0)]
public void TestDoubleLongUnion(object value)
{
var testRecord = new DoubleLongUnionRecord();
testRecord.Property = value;
// serialize
var stream = serialize(DoubleLongUnionRecord._SCHEMA, testRecord);
// deserialize
var rec2 = deserialize<DoubleLongUnionRecord>(stream, DoubleLongUnionRecord._SCHEMA, DoubleLongUnionRecord._SCHEMA);
Assert.AreEqual(value, rec2.Property);
Assert.AreEqual(value.GetType(), rec2.Property.GetType());
}
[TestCase(0)]
[TestCase(100)]
[TestCase(-100)]
[TestCase(0.0f)]
[TestCase(100.0f)]
[TestCase(-100.0f)]
[TestCase("0")]
[TestCase("100")]
public void TestDoubleLongUnionNoMatchException(object value)
{
Assert.Throws<AvroException>(() => serialize(DoubleLongUnionRecord._SCHEMA, new DoubleLongUnionRecord() { Property = value }));
}
[Test]
public void TestArrayWithReservedWords()
{
var srcRecord = new ComplexTypeWithReservedWords
{
Record = new Record
{
name = "Name"
},
ArrayItems = new List<ArrayItem>
{
new ArrayItem
{
id = 2,
name = "ArrayName"
}
}
};
var stream = serialize(ComplexTypeWithReservedWords._SCHEMA, srcRecord);
var dstRecord = deserialize<ComplexTypeWithReservedWords>(stream, ComplexTypeWithReservedWords._SCHEMA, ComplexTypeWithReservedWords._SCHEMA);
Assert.NotNull(dstRecord);
Assert.AreEqual("Name", dstRecord.Record.name);
Assert.AreEqual(1, dstRecord.ArrayItems.Count);
Assert.AreEqual("ArrayName", dstRecord.ArrayItems[0].name);
Assert.AreEqual(2, dstRecord.ArrayItems[0].id);
}
[Test]
public void TestEmbeddedGenerics()
{
var srcRecord = new EmbeddedGenericsRecord
{
OptionalIntList = new List<int?> { 1, 2, null, 3, null, null },
OptionalUserList = new List<EmbeddedGenericRecordUser>
{
new EmbeddedGenericRecordUser { name = "1" },
new EmbeddedGenericRecordUser { name = "2" },
null,
new EmbeddedGenericRecordUser { name = "3" },
null,
null,
},
OptionalIntMatrix = new List<IList<IList<int?>>>
{
new List<IList<int?>>
{
new List<int?> { null, 2, },
new List<int?> { null, null },
},
new List<IList<int?>>
{
new List<int?> { 5, 6, },
},
new List<IList<int?>> { },
},
OptionalUserMatrix = new List<IList<IList<EmbeddedGenericRecordUser>>>
{
new List<IList<EmbeddedGenericRecordUser>>
{
new List<EmbeddedGenericRecordUser>
{
null,
new EmbeddedGenericRecordUser { name = "2" },
},
new List<EmbeddedGenericRecordUser> { null, null },
},
new List<IList<EmbeddedGenericRecordUser>>
{
new List<EmbeddedGenericRecordUser>
{
new EmbeddedGenericRecordUser { name = "5" },
new EmbeddedGenericRecordUser { name = "6" },
},
},
new List<IList<EmbeddedGenericRecordUser>> { },
},
IntMatrix = new List<IList<IList<int>>>
{
new List<IList<int>>
{
new List<int> { 1, 2, },
new List<int> { 3, 4, },
},
new List<IList<int>>
{
new List<int> { 5, 6, },
},
new List<IList<int>> { },
},
UserMatrix = new List<IList<IList<EmbeddedGenericRecordUser>>>
{
new List<IList<EmbeddedGenericRecordUser>>
{
new List<EmbeddedGenericRecordUser>
{
new EmbeddedGenericRecordUser { name = "1" },
new EmbeddedGenericRecordUser { name = "2" },
},
new List<EmbeddedGenericRecordUser>
{
new EmbeddedGenericRecordUser { name = "3" },
new EmbeddedGenericRecordUser { name = "4" },
},
},
new List<IList<EmbeddedGenericRecordUser>>
{
new List<EmbeddedGenericRecordUser>
{
new EmbeddedGenericRecordUser { name = "5" },
new EmbeddedGenericRecordUser { name = "6" },
},
},
new List<IList<EmbeddedGenericRecordUser>> { },
}
};
var stream = serialize(EmbeddedGenericsRecord._SCHEMA, srcRecord);
var dstRecord = deserialize<EmbeddedGenericsRecord>(stream,
EmbeddedGenericsRecord._SCHEMA, EmbeddedGenericsRecord._SCHEMA);
Assert.NotNull(dstRecord);
Assert.AreEqual(1, dstRecord.OptionalIntList[0]);
Assert.AreEqual(2, dstRecord.OptionalIntList[1]);
Assert.AreEqual(null, dstRecord.OptionalIntList[2]);
Assert.AreEqual(3, dstRecord.OptionalIntList[3]);
Assert.AreEqual(null, dstRecord.OptionalIntList[4]);
Assert.AreEqual(null, dstRecord.OptionalIntList[5]);
Assert.AreEqual("1", dstRecord.OptionalUserList[0].name);
Assert.AreEqual("2", dstRecord.OptionalUserList[1].name);
Assert.AreEqual(null, dstRecord.OptionalUserList[2]);
Assert.AreEqual("3", dstRecord.OptionalUserList[3].name);
Assert.AreEqual(null, dstRecord.OptionalUserList[4]);
Assert.AreEqual(null, dstRecord.OptionalUserList[5]);
Assert.AreEqual(null, dstRecord.OptionalIntMatrix[0][0][0]);
Assert.AreEqual(2, dstRecord.OptionalIntMatrix[0][0][1]);
Assert.AreEqual(null, dstRecord.OptionalIntMatrix[0][1][0]);
Assert.AreEqual(null, dstRecord.OptionalIntMatrix[0][1][1]);
Assert.AreEqual(5, dstRecord.OptionalIntMatrix[1][0][0]);
Assert.AreEqual(6, dstRecord.OptionalIntMatrix[1][0][1]);
Assert.AreEqual(0, dstRecord.OptionalIntMatrix[2].Count);
Assert.AreEqual(null, dstRecord.OptionalUserMatrix[0][0][0]);
Assert.AreEqual("2", dstRecord.OptionalUserMatrix[0][0][1].name);
Assert.AreEqual(null, dstRecord.OptionalUserMatrix[0][1][0]);
Assert.AreEqual(null, dstRecord.OptionalUserMatrix[0][1][1]);
Assert.AreEqual("5", dstRecord.OptionalUserMatrix[1][0][0].name);
Assert.AreEqual("6", dstRecord.OptionalUserMatrix[1][0][1].name);
Assert.AreEqual(0, dstRecord.OptionalUserMatrix[2].Count);
Assert.AreEqual(1, dstRecord.IntMatrix[0][0][0]);
Assert.AreEqual(2, dstRecord.IntMatrix[0][0][1]);
Assert.AreEqual(3, dstRecord.IntMatrix[0][1][0]);
Assert.AreEqual(4, dstRecord.IntMatrix[0][1][1]);
Assert.AreEqual(5, dstRecord.IntMatrix[1][0][0]);
Assert.AreEqual(6, dstRecord.IntMatrix[1][0][1]);
Assert.AreEqual(0, dstRecord.IntMatrix[2].Count);
Assert.AreEqual("1", dstRecord.UserMatrix[0][0][0].name);
Assert.AreEqual("2", dstRecord.UserMatrix[0][0][1].name);
Assert.AreEqual("3", dstRecord.UserMatrix[0][1][0].name);
Assert.AreEqual("4", dstRecord.UserMatrix[0][1][1].name);
Assert.AreEqual("5", dstRecord.UserMatrix[1][0][0].name);
Assert.AreEqual("6", dstRecord.UserMatrix[1][0][1].name);
Assert.AreEqual(0, dstRecord.UserMatrix[2].Count);
}
private static void serializeGeneric<T>(string writerSchema, T actual, out Stream stream, out Schema ws)
{
var ms = new MemoryStream();
Encoder e = new BinaryEncoder(ms);
ws = Schema.Parse(writerSchema);
GenericWriter<T> w = new GenericWriter<T>(ws);
w.Write(actual, e);
ms.Flush();
ms.Position = 0;
stream = ms;
}
[Test]
public void DeserializeToLogicalTypeWithDefault()
{
var writerSchemaString = @"{
""type"": ""record"",
""name"": ""RecordWithOptionalLogicalType"",
""namespace"": ""Avro.Test.Specific.return"",
""fields"": [
]}";
var writerSchema = Schema.Parse(writerSchemaString);
Stream stream;
serializeGeneric(writerSchemaString,
GenericTests.MkRecord(new object[] { }, (RecordSchema)writerSchema),
out stream,
out _);
RecordWithOptionalLogicalType output = deserialize<RecordWithOptionalLogicalType>(stream, writerSchema, RecordWithOptionalLogicalType._SCHEMA);
Assert.AreEqual(output.x, new DateTime(1970, 1, 11));
}
private static S deserialize<S>(Stream ms, Schema ws, Schema rs) where S : class, ISpecificRecord
{
long initialPos = ms.Position;
var r = new SpecificReader<S>(ws, rs);
Decoder d = new BinaryDecoder(ms);
S output = r.Read(null, d);
Assert.AreEqual(ms.Length, ms.Position); // Ensure we have read everything.
checkAlternateDeserializers(output, ms, initialPos, ws, rs);
return output;
}
private static void checkAlternateDeserializers<S>(S expected, Stream input, long startPos, Schema ws, Schema rs) where S : class, ISpecificRecord
{
input.Position = startPos;
var reader = new SpecificDatumReader<S>(ws, rs);
Decoder d = new BinaryDecoder(input);
S output = reader.Read(null, d);
Assert.AreEqual(input.Length, input.Position); // Ensure we have read everything.
AssertSpecificRecordEqual(expected, output);
}
private static Stream serialize<T>(Schema ws, T actual)
{
var ms = new MemoryStream();
Encoder e = new BinaryEncoder(ms);
var w = new SpecificWriter<T>(ws);
w.Write(actual, e);
ms.Flush();
ms.Position = 0;
checkAlternateSerializers(ms.ToArray(), actual, ws);
return ms;
}
private static void checkAlternateSerializers<T>(byte[] expected, T value, Schema ws)
{
var ms = new MemoryStream();
var writer = new SpecificDatumWriter<T>(ws);
var e = new BinaryEncoder(ms);
writer.Write(value, e);
var output = ms.ToArray();
Assert.AreEqual(expected.Length, output.Length);
Assert.True(expected.SequenceEqual(output));
}
private static void AssertSpecificRecordEqual(ISpecificRecord rec1, ISpecificRecord rec2)
{
if (rec1 == null && rec2 == null)
{
// Both are null, that's equivalent.
return;
}
var recordSchema = (RecordSchema) rec1.Schema;
for (int i = 0; i < recordSchema.Count; i++)
{
var rec1Val = rec1.Get(i);
var rec2Val = rec2.Get(i);
if (rec1Val is ISpecificRecord)
{
AssertSpecificRecordEqual((ISpecificRecord)rec1Val, (ISpecificRecord)rec2Val);
}
else if (rec1Val is IList)
{
AssertListEqual((IList)rec1Val, (IList)rec2Val);
}
else if (rec1Val is IDictionary)
{
var rec1Dict = (IDictionary) rec1Val;
var rec2Dict = (IDictionary) rec2Val;
Assert.AreEqual(rec2Dict.Count, rec2Dict.Count);
foreach (var key in rec1Dict.Keys)
{
var val1 = rec1Dict[key];
var val2 = rec2Dict[key];
if (val1 is ISpecificRecord)
{
AssertSpecificRecordEqual((ISpecificRecord)val1, (ISpecificRecord)val2);
}
else
{
Assert.AreEqual(val1, val2);
}
}
}
else
{
Assert.AreEqual(rec1Val, rec2Val);
}
}
}
/// <summary>
/// Asserts that two lists are equal, delegating the work of comparing
/// <see cref="ISpecificRecord"/> entries to
/// <see cref="AssertSpecificRecordEqual(ISpecificRecord, ISpecificRecord)"/>.
/// </summary>
/// <param name="expected">Expected list value.</param>
/// <param name="actual">Actual list value.</param>
private static void AssertListEqual(IList expected, IList actual)
{
Assert.AreEqual(expected.Count, actual.Count);
for (var i = 0; i < expected.Count; ++i)
{
// Perform null checks first
if (expected[i] == null)
{
Assert.Null(actual[i]);
continue;
}
else
{
Assert.NotNull(actual[i]);
}
if (expected[i] is ISpecificRecord expectedRecord)
{
var actualRecord = actual[i] as ISpecificRecord;
Assert.NotNull(actualRecord, "Expected entry that implements ISpecificRecord," +
$" but was {actual[i].GetType().Name}");
AssertSpecificRecordEqual(expectedRecord, actualRecord);
}
else if (expected[i] is IList expectedList)
{
var actualList = actual[i] as IList;
Assert.NotNull(actualList, "Expected entry that implements IList," +
$" but was {actual[i].GetType().Name}");
AssertListEqual(expectedList, actualList);
}
else
{
Assert.AreEqual(expected, actual);
}
}
}
}
public enum EnumType
{
DEFAULT, //putting the default first here so there isn't an ordinal collision for testing defaults
FIRST,
SECOND,
THIRD,
}
class EnumRecord : ISpecificRecord
{
public EnumType enumType { get; set; }
public Schema Schema
{
get
{
return Schema.Parse(@"{
""type"":""record"",
""name"":""EnumRecord"",
""namespace"":""Avro.Test"",
""fields"":[
{
""name"":""enumType"",
""type"":{
""type"":""enum"",
""name"":""EnumType"",
""symbols"":[
""DEFAULT"",
""FIRST"",
""SECOND"",
""THIRD""
]
},
""default"": ""DEFAULT""
}
]
}");
}
}
public object Get(int fieldPos)
{
return enumType;
}
public void Put(int fieldPos, object fieldValue)
{
enumType = (EnumType)fieldValue;
}
}
}