blob: db0d4a91a62684c93a660e32e3a3be8cfb5a6cd1 [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;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using Avro.IO;
using Avro.Reflect;
using NUnit.Framework;
using System.Collections;
namespace Avro.Test
{
[TestFixture]
public class TestUnion
{
public const string BaseClassSchema = @"
[
{ ""type"" : ""record"", ""name"" : ""Dervied1"", ""fields"" :
[
{ ""name"" : ""A"", ""type"" : ""string""},
{ ""name"" : ""B"", ""type"" : ""int""}
]
},
{ ""type"" : ""record"", ""name"" : ""Dervied2"", ""fields"" :
[
{ ""name"" : ""A"", ""type"" : ""string""},
{ ""name"" : ""C"", ""type"" : ""double""}
]
},
]
";
public class BaseClass
{
public string A { get; set; }
}
public class Derived1 : BaseClass
{
public int B { get; set; }
}
public class Derived2 : BaseClass
{
public double C { get; set; }
}
/// <summary>
/// Test with a union that represents derived classes.
/// </summary>
[TestCase]
public void BaseClassTest()
{
var schema = Schema.Parse(BaseClassSchema);
var derived1write = new Derived1() { A = "derived1", B = 7 };
var derived2write = new Derived2() { A = "derived2", C = 3.14 };
// union types (except for [null, type]) need to be manually registered
var unionSchema = schema as UnionSchema;
var cache = new ClassCache();
cache.LoadClassCache(typeof(Derived1), unionSchema[0]);
cache.LoadClassCache(typeof(Derived2), unionSchema[1]);
var x = schema as RecordSchema;
var writer = new ReflectWriter<BaseClass>(schema, cache);
var reader = new ReflectReader<BaseClass>(schema, schema, cache);
using (var stream = new MemoryStream(256))
{
var encoder = new BinaryEncoder(stream);
writer.Write(derived1write, encoder);
writer.Write(derived2write, encoder);
stream.Seek(0, SeekOrigin.Begin);
var decoder = new BinaryDecoder(stream);
var derived1read = (Derived1)reader.Read(decoder);
var derived2read = (Derived2)reader.Read(decoder);
Assert.AreEqual(derived1read.A, derived1write.A);
Assert.AreEqual(derived1read.B, derived1write.B);
Assert.AreEqual(derived2read.A, derived2write.A);
Assert.AreEqual(derived2read.C, derived2write.C);
}
}
/// <summary>
/// If you fail to manually register types within a union that has more than one non-null
/// schema, creating a <see cref="ReflectWriter{T}"/> throws an exception.
/// </summary>
[TestCase]
public void ThrowsIfClassesNotLoadedTest()
{
var schema = Schema.Parse(BaseClassSchema);
var cache = new ClassCache();
Assert.Throws<AvroException>(() => new ReflectWriter<BaseClass>(schema, cache));
}
[TestCase]
public void NullableTest()
{
var nullableSchema = @"
[
""null"",
{ ""type"" : ""record"", ""name"" : ""Dervied2"", ""fields"" :
[
{ ""name"" : ""A"", ""type"" : ""string""},
{ ""name"" : ""C"", ""type"" : ""double""}
]
},
]
";
var schema = Schema.Parse(nullableSchema);
var derived2write = new Derived2() { A = "derived2", C = 3.14 };
var writer = new ReflectWriter<Derived2>(schema);
var reader = new ReflectReader<Derived2>(schema, schema);
using (var stream = new MemoryStream(256))
{
var encoder = new BinaryEncoder(stream);
writer.Write(derived2write, encoder);
writer.Write(null, encoder);
stream.Seek(0, SeekOrigin.Begin);
var decoder = new BinaryDecoder(stream);
var derived2read = reader.Read(decoder);
var derived2null = reader.Read(decoder);
Assert.AreEqual(derived2read.A, derived2write.A);
Assert.AreEqual(derived2read.C, derived2write.C);
Assert.IsNull(derived2null);
}
}
[TestCase]
public void HeterogeneousTest()
{
var heterogeneousSchema = @"
[
""string"",
""null"",
{ ""type"" : ""record"", ""name"" : ""Dervied2"", ""fields"" :
[
{ ""name"" : ""A"", ""type"" : ""string""},
{ ""name"" : ""C"", ""type"" : ""double""}
]
},
]
";
var schema = Schema.Parse(heterogeneousSchema);
var derived2write = new Derived2() { A = "derived2", C = 3.14 };
// union types (except for [null, type]) need to be manually registered
var unionSchema = schema as UnionSchema;
var cache = new ClassCache();
cache.LoadClassCache(typeof(Derived2), unionSchema[2]);
var writer = new ReflectWriter<object>(schema, cache);
var reader = new ReflectReader<object>(schema, schema, cache);
using (var stream = new MemoryStream(256))
{
var encoder = new BinaryEncoder(stream);
writer.Write(derived2write, encoder);
writer.Write("string value", encoder);
writer.Write(null, encoder);
stream.Seek(0, SeekOrigin.Begin);
var decoder = new BinaryDecoder(stream);
var derived2read = (Derived2)reader.Read(decoder);
var stringRead = (string)reader.Read(decoder);
var nullRead = reader.Read(decoder);
Assert.AreEqual(derived2read.A, derived2write.A);
Assert.AreEqual(derived2read.C, derived2write.C);
Assert.AreEqual(stringRead, "string value");
Assert.IsNull(nullRead);
}
}
}
}