blob: 5cf5725397827203172b78a1eeb561d760fdf719 [file] [log] [blame]
/**
* 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.Collections;
using System.IO;
using NUnit.Framework;
using Avro.IO;
using Avro.Reflect;
namespace Avro.Test
{
[TestFixture]
class TestReflect
{
enum EnumResolutionEnum
{
THIRD,
FIRST,
SECOND
}
class EnumResolutionRecord
{
public EnumResolutionEnum enumType { get; set; }
}
class NullableEnumResolutionRecord
{
public EnumResolutionEnum? enumType { get; set; }
}
[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 EnumResolutionRecord();
Schema readerSchema = Schema.Parse("{\"type\":\"record\",\"name\":\"EnumRecord\",\"namespace\":\"Avro.Test\"," +
"\"fields\":[{\"name\":\"enumType\",\"type\": { \"type\": \"enum\", \"name\":" +
" \"EnumType\", \"symbols\": [\"THIRD\", \"FIRST\", \"SECOND\"]} }]}");;
testRecord.enumType = EnumResolutionEnum.SECOND;
// serialize
var stream = serialize(writerSchema, testRecord);
// deserialize
var rec2 = deserialize<EnumResolutionRecord>(stream, writerSchema, readerSchema);
Assert.AreEqual( EnumResolutionEnum.SECOND, rec2.enumType );
}
[TestCase]
public void TestNullableEnumResolution()
{
Schema writerSchema = Schema.Parse("{\"type\":\"record\",\"name\":\"EnumRecord\",\"namespace\":\"Avro.Test\"," +
"\"fields\":[{\"name\":\"enumType\",\"type\":[\"null\", { \"type\": \"enum\", \"name\": " +
"\"EnumType\",\"symbols\": [\"THIRD\", \"FIRST\", \"SECOND\"]}] }]}");
var testRecord = new NullableEnumResolutionRecord();
Schema readerSchema = Schema.Parse("{\"type\":\"record\",\"name\":\"EnumRecord\",\"namespace\":\"Avro.Test\"," +
"\"fields\":[{\"name\":\"enumType\",\"type\":[\"null\", { \"type\": \"enum\", \"name\": " +
"\"EnumType\", \"symbols\": [\"THIRD\", \"FIRST\", \"SECOND\"]}] }]}");
testRecord.enumType = EnumResolutionEnum.SECOND;
// serialize
var stream = serialize(writerSchema, testRecord);
// deserialize
var rec2 = deserialize<NullableEnumResolutionRecord>(stream, writerSchema, readerSchema);
Assert.AreEqual( EnumResolutionEnum.SECOND, rec2.enumType );
}
private static S deserialize<S>(Stream ms, Schema ws, Schema rs) where S : class
{
long initialPos = ms.Position;
var r = new ReflectReader<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
{
input.Position = startPos;
var reader = new ReflectReader<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.
AssertReflectRecordEqual(rs, expected, ws, output, reader.Reader.ClassCache);
}
private static Stream serialize<T>(Schema ws, T actual)
{
var ms = new MemoryStream();
Encoder e = new BinaryEncoder(ms);
var w = new ReflectWriter<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 ReflectWriter<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 AssertReflectRecordEqual(Schema schema1, object rec1, Schema schema2, object rec2, ClassCache cache)
{
var recordSchema = (RecordSchema) schema1;
foreach (var f in recordSchema.Fields)
{
var rec1Val = cache.GetClass(recordSchema).GetValue(rec1, f);
var rec2Val = cache.GetClass(recordSchema).GetValue(rec2, f);
if (rec1Val.GetType().IsClass)
{
AssertReflectRecordEqual(f.Schema, rec1Val, f.Schema, rec2Val, cache);
}
else if (rec1Val is IList)
{
var schema1List = f.Schema as ArraySchema;
var rec1List = (IList) rec1Val;
if( rec1List.Count > 0 )
{
var rec2List = (IList) rec2Val;
Assert.AreEqual(rec1List.Count, rec2List.Count);
for (int j = 0; j < rec1List.Count; j++)
{
AssertReflectRecordEqual(schema1List.ItemSchema, rec1List[j], schema1List.ItemSchema, rec2List[j], cache);
}
}
else
{
Assert.AreEqual(rec1Val, rec2Val);
}
}
else if (rec1Val is IDictionary)
{
var schema1Map = f.Schema as MapSchema;
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 (f.Schema is RecordSchema)
{
AssertReflectRecordEqual(f.Schema as RecordSchema, val1, f.Schema as RecordSchema, val2, cache);
}
else
{
Assert.AreEqual(val1, val2);
}
}
}
else
{
Assert.AreEqual(rec1Val, rec2Val);
}
}
}
}
}