diff --git a/lang/csharp/src/apache/main/Schema/LogicalSchema.cs b/lang/csharp/src/apache/main/Schema/LogicalSchema.cs index 181260f2ca2..c2e589eeb33 100644 --- a/lang/csharp/src/apache/main/Schema/LogicalSchema.cs +++ b/lang/csharp/src/apache/main/Schema/LogicalSchema.cs @@ -54,7 +54,7 @@ private LogicalSchema(Schema baseSchema, string logicalTypeName, PropertyMap pr { BaseSchema = baseSchema ?? throw new ArgumentNullException(nameof(baseSchema)); LogicalTypeName = logicalTypeName; - LogicalType = LogicalTypeFactory.Instance.GetFromLogicalSchema(this); + LogicalType = LogicalTypeFactory.Instance.GetFromLogicalSchema(this, true); } /// diff --git a/lang/csharp/src/apache/main/Util/LogicalTypeFactory.cs b/lang/csharp/src/apache/main/Util/LogicalTypeFactory.cs index f4086ab5a27..d6f8dce9512 100644 --- a/lang/csharp/src/apache/main/Util/LogicalTypeFactory.cs +++ b/lang/csharp/src/apache/main/Util/LogicalTypeFactory.cs @@ -45,7 +45,7 @@ private LogicalTypeFactory() { TimeMicrosecond.LogicalTypeName, new TimeMicrosecond() }, { TimestampMillisecond.LogicalTypeName, new TimestampMillisecond() }, { TimestampMicrosecond.LogicalTypeName, new TimestampMicrosecond() }, - { Uuid.LogicalTypeName, new Uuid() } + { Uuid.LogicalTypeName, new Uuid() }, }; } @@ -67,22 +67,22 @@ public void Register(LogicalType logicalType) /// A . public LogicalType GetFromLogicalSchema(LogicalSchema schema, bool ignoreInvalidOrUnknown = false) { - try - { - if (!_logicalTypes.TryGetValue(schema.LogicalTypeName, out LogicalType logicalType)) - throw new AvroTypeException("Logical type '" + schema.LogicalTypeName + "' is not supported."); + LogicalType logicalType = null; + if (_logicalTypes.TryGetValue(schema.LogicalTypeName, out logicalType)) + { logicalType.ValidateSchema(schema); - - return logicalType; } - catch (AvroTypeException) + else if (ignoreInvalidOrUnknown) + { + logicalType = new UnknownLogicalType(schema); + } + else { - if (!ignoreInvalidOrUnknown) - throw; + throw new AvroTypeException("Logical type '" + schema.LogicalTypeName + "' is not supported."); } - return null; + return logicalType; } } } diff --git a/lang/csharp/src/apache/main/Util/UnknownLogicalType.cs b/lang/csharp/src/apache/main/Util/UnknownLogicalType.cs new file mode 100644 index 00000000000..2e3229e8b06 --- /dev/null +++ b/lang/csharp/src/apache/main/Util/UnknownLogicalType.cs @@ -0,0 +1,163 @@ +/* + * 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.Text; + +namespace Avro.Util +{ + /// + /// Class UnknownLogicalType. + /// Implements the + /// + /// + public class UnknownLogicalType : LogicalType + { + /// + /// Gets the schema. + /// + /// The schema. + public LogicalSchema Schema { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The schema. + public UnknownLogicalType(LogicalSchema schema) : base(schema.LogicalTypeName) + { + this.Schema = schema; + } + + /// + /// Converts a logical value to an instance of its base type. + /// + /// The logical value to convert. + /// The schema that represents the target of the conversion. + /// An object representing the encoded value of the base type. + public override object ConvertToBaseValue(object logicalValue, LogicalSchema schema) + { + switch (schema.Name) + { + case @"string": + return (System.String)logicalValue; + case @"boolean": + return (System.Boolean)logicalValue; + case @"int": + return (System.Int32)logicalValue; + case @"long": + return (System.Int64)logicalValue; + case @"float": + return (System.Single)logicalValue; + case @"double": + return (System.Double)logicalValue; + case @"bytes": + return (System.Byte[])logicalValue; + default: + return logicalValue; + } + } + + /// + /// Converts a base value to an instance of the logical type. + /// + /// The base value to convert. + /// The schema that represents the target of the conversion. + /// An object representing the encoded value of the logical type. + public override object ConvertToLogicalValue(object baseValue, LogicalSchema schema) + { + switch (schema.Name) + { + case @"string": + return (System.String)baseValue; + case @"boolean": + return (System.Boolean)baseValue; + case @"int": + return (System.Int32)baseValue; + case @"long": + return (System.Int64)baseValue; + case @"float": + return (System.Single)baseValue; + case @"double": + return (System.Double)baseValue; + case @"bytes": + return (System.Byte[])baseValue; + default: + return baseValue; + } + } + + /// + /// Retrieve the .NET type that is represented by the logical type implementation. + /// + /// A flag indicating whether it should be nullible. + /// Type. + public override Type GetCSharpType(bool nullible) + { + // handle all Primitive Types + switch (this.Schema.BaseSchema.Name) + { + case @"string": + return typeof(System.String); + case @"boolean": + return nullible ? typeof(System.Boolean?) : typeof(System.Boolean); + case @"int": + return nullible ? typeof(System.Int32?) : typeof(System.Int32); + case @"long": + return nullible ? typeof(System.Int64?) : typeof(System.Int64); + case @"float": + return nullible ? typeof(System.Single?) : typeof(System.Single); + case @"double": + return nullible ? typeof(System.Double?) : typeof(System.Double); + case @"bytes": + return nullible ? typeof(System.Byte?[]) : typeof(System.Byte[]); + default: + return typeof(System.Object); + } + } + + /// + /// Determines if a given object is an instance of the logical type. + /// + /// The logical value to test. + /// true if [is instance of logical type] [the specified logical value]; otherwise, false. + public override bool IsInstanceOfLogicalType(object logicalValue) + { + // handle all Primitive Types + switch (this.Schema.BaseSchema.Name) + { + case @"string": + return logicalValue is System.String; + case @"boolean": + return logicalValue is System.Boolean; + case @"int": + return logicalValue is System.Int32; + case @"long": + return logicalValue is System.Int64; + case @"float": + return logicalValue is System.Single; + case @"double": + return logicalValue is System.Double; + case @"bytes": + return logicalValue is System.Byte[]; + default: + return true; + } + } + + } +} diff --git a/lang/csharp/src/apache/test/AvroGen/AvroGenSchemaTests.cs b/lang/csharp/src/apache/test/AvroGen/AvroGenSchemaTests.cs index 807acbda92a..cc0dccdef78 100644 --- a/lang/csharp/src/apache/test/AvroGen/AvroGenSchemaTests.cs +++ b/lang/csharp/src/apache/test/AvroGen/AvroGenSchemaTests.cs @@ -606,9 +606,9 @@ public void GenerateSchemaWithNamespaceMapping( AvroGenHelper.TestSchema(schema, typeNamesToCheck, new Dictionary { { namespaceMappingFrom, namespaceMappingTo } }, generatedFilesToCheck); } - [TestCase(_logicalTypesWithCustomConversion, typeof(AvroTypeException))] - [TestCase(_customConversionWithLogicalTypes, typeof(SchemaParseException))] - public void NotSupportedSchema(string schema, Type expectedException) + [TestCase(_logicalTypesWithCustomConversion, typeof(AvroTypeException), 0)] + [TestCase(_customConversionWithLogicalTypes, typeof(SchemaParseException), 1)] + public void NotSupportedSchema(string schema, Type expectedException, int expectedResult) { // Create temp folder string outputDir = AvroGenHelper.CreateEmptyTemporaryFolder(out string uniqueId); @@ -619,7 +619,8 @@ public void NotSupportedSchema(string schema, Type expectedException) string schemaFileName = Path.Combine(outputDir, $"{uniqueId}.avsc"); System.IO.File.WriteAllText(schemaFileName, schema); - Assert.That(AvroGenTool.GenSchema(schemaFileName, outputDir, new Dictionary(), false), Is.EqualTo(1)); + Assert.That(AvroGenTool.GenSchema(schemaFileName, outputDir, new Dictionary(), false), Is.EqualTo(expectedResult)); + } finally { diff --git a/lang/csharp/src/apache/test/File/FileTests.cs b/lang/csharp/src/apache/test/File/FileTests.cs index 0ef81c9766f..abb3f9c6076 100644 --- a/lang/csharp/src/apache/test/File/FileTests.cs +++ b/lang/csharp/src/apache/test/File/FileTests.cs @@ -35,6 +35,34 @@ public class FileTests const string specificSchema = "{\"type\":\"record\",\"name\":\"Foo\",\"namespace\":\"Avro.Test.File\",\"fields\":" + "[{\"name\":\"name\",\"type\":[\"null\",\"string\"]},{\"name\":\"age\",\"type\":\"int\"}]}"; + /// + /// This test case added to confirm standalone serialization / deserialization behavior of new type UnknownLogicalType + /// + const string unknowLogicalTypeSchema = @" +{ + ""type"" : ""record"", + ""name"" : ""Foo"", + ""namespace"" : ""Avro.Test.File"", + ""fields"": [ + { + ""name"" :""name"", + ""type"": [ + ""null"", + { + ""logicalType"": ""varchar"", + ""maxLength"": 65, + ""type"": ""string"" + } + ] + }, + { + ""name"" : ""age"", + ""type"" : ""int"" + } + ] +} +"; + private static IEnumerable TestSpecificDataSource() { foreach (Codec.Type codecType in Enum.GetValues(typeof(Codec.Type))) @@ -100,6 +128,11 @@ private static IEnumerable TestSpecificDataSource() new object[] { "Bob", 9 }, new object[] { null, 48 } }, codecType).SetName("{m}(Case3,{2})"); + + yield return new TestCaseData(unknowLogicalTypeSchema, new object[] + { + new object[] { "John", 23 } + }, codecType).SetName("{m}(Case4,{2})"); } } diff --git a/lang/csharp/src/apache/test/Schema/SchemaTests.cs b/lang/csharp/src/apache/test/Schema/SchemaTests.cs index 319e9a95be3..4cc4e1d0158 100644 --- a/lang/csharp/src/apache/test/Schema/SchemaTests.cs +++ b/lang/csharp/src/apache/test/Schema/SchemaTests.cs @@ -19,6 +19,7 @@ using System.Collections.Generic; using NUnit.Framework; using System.Linq; +using Avro.Util; namespace Avro.Test { @@ -548,12 +549,76 @@ public void TestLogicalPrimitive(string s, string baseType, string logicalType) testToString(sc); } + // Make sure unknown type is carried thru to LogicalTypeName [TestCase("{\"type\": \"int\", \"logicalType\": \"unknown\"}", "unknown")] public void TestUnknownLogical(string s, string unknownType) { - var err = Assert.Throws(() => Schema.Parse(s)); + var schema = Schema.Parse(s); + Assert.IsNotNull(schema); // make sure Variable is not null + Assert.IsInstanceOf(typeof(LogicalSchema), schema); - Assert.AreEqual("Logical type '" + unknownType + "' is not supported.", err.Message); + var logicalSchema = schema as LogicalSchema; + Assert.IsNotNull(logicalSchema); // make sure Variable is not null + Assert.IsInstanceOf(typeof(UnknownLogicalType), logicalSchema.LogicalType); + + Assert.AreEqual(logicalSchema.LogicalTypeName, unknownType); + } + + /* + { + "fields": [ + { + "default": 0, + "name": "firstField", + "type": "int" + }, + { + "default": null, + "name": "secondField", + "type": [ + "null", + { + "logicalType": "varchar", + "maxLength": 65, + "type": "string" + } + ] + } + ], + "name": "sample_schema", + "type": "record" + } + */ + + // Before Change will throw Avro.AvroTypeException: 'Logical type 'varchar' is not supported.' + // Per AVRO Spec (v1.8.0 - v1.11.1) ... Logical Types Section + // Language implementations must ignore unknown logical types when reading, and should use the underlying Avro type. + [TestCase("{\"fields\": [{\"default\": 0,\"name\": \"firstField\",\"type\": \"int\"},{\"default\": null,\"name\": \"secondField\",\"type\": [\"null\",{\"logicalType\": \"varchar\",\"maxLength\": 65,\"type\": \"string\"}]}],\"name\": \"sample_schema\",\"type\": \"record\"}")] + public void TestUnknownLogicalType(string schemaText) + { + var schema = Avro.Schema.Parse(schemaText); + Assert.IsNotNull(schema); + + var secondField = ((RecordSchema)schema).Fields.FirstOrDefault(f => f.Name == @"secondField"); + Assert.IsNotNull(secondField); + + var secondFieldSchema = (secondField).Schema; + Assert.IsNotNull(secondFieldSchema); + + var secondFieldUnionSchema = (UnionSchema)secondFieldSchema; + Assert.IsNotNull(secondFieldUnionSchema); + + var props = secondFieldUnionSchema.Schemas.Where(s => s.Props != null).ToList(); + Assert.IsNotNull(props); + Assert.IsTrue(props.Count == 1); + + var prop = props[0]; + // Confirm that the unknown logical type is ignored and the underlying AVRO type is used + Assert.IsTrue(prop.Name == @"string"); + var logicalSchema = prop as LogicalSchema; + Assert.IsInstanceOf(typeof(UnknownLogicalType), logicalSchema.LogicalType); + + Assert.AreEqual(logicalSchema.LogicalTypeName, @"varchar"); } [TestCase("{\"type\": \"map\", \"values\": \"long\"}", "long")] diff --git a/lang/csharp/src/apache/test/Util/UnknownLogicalTypeTests.cs b/lang/csharp/src/apache/test/Util/UnknownLogicalTypeTests.cs new file mode 100644 index 00000000000..539b8df04dd --- /dev/null +++ b/lang/csharp/src/apache/test/Util/UnknownLogicalTypeTests.cs @@ -0,0 +1,188 @@ +/* + * 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.Data.SqlTypes; +using System.Globalization; +using System.Net.Sockets; +using System.Numerics; +using Avro.Util; +using NUnit.Framework; +using NUnit.Framework.Constraints; + +namespace Avro.test.Util +{ + /// + /// This tests added to confirm standalone operation of new type UnknownLogicalType that implements LogicalType + /// + [TestFixture] + class UnknownLogicalTypeTests + { + [TestCase(typeof(System.String), "", "{\"type\": \"string\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Boolean), true, "{\"type\": \"boolean\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int32), Int32.MinValue, "{\"type\": \"int\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int64), Int64.MinValue, "{\"type\": \"long\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Single), Single.MinValue, "{\"type\": \"float\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Double), Double.MinValue, "{\"type\": \"double\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Byte[]), new byte[] { }, "{\"type\": \"bytes\", \"logicalType\": \"unknown\"}")] + public void TestConvertToBaseValue_IsTrue(Type baseType, object logicalValue, string schemaText) + { + var schema = (LogicalSchema)Schema.Parse(schemaText); + + var logicalType = new UnknownLogicalType(schema); + + var baseValue = logicalType.ConvertToBaseValue(logicalValue, schema); + + Assert.AreEqual(baseValue, Convert.ChangeType(logicalValue, baseType)); + } + + [TestCase(typeof(System.Byte[]), "", "{\"type\": \"string\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Double), true, "{\"type\": \"boolean\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Single), Int32.MinValue, "{\"type\": \"int\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Boolean), Int64.MinValue, "{\"type\": \"long\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int32), Single.MinValue, "{\"type\": \"float\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int64), Double.MinValue, "{\"type\": \"double\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.String), new byte[] { }, "{\"type\": \"bytes\", \"logicalType\": \"unknown\"}")] + public void TestConvertToBaseValue_IsFalse(Type baseType, object logicalValue, string schemaText) + { + var schema = (LogicalSchema)Schema.Parse(schemaText); + + var logicalType = new UnknownLogicalType(schema); + + var baseValue = logicalType.ConvertToBaseValue(logicalValue, schema); + + Assert.AreNotEqual(baseValue.GetType(), baseType); + } + + [TestCase(typeof(System.String), "", "{\"type\": \"string\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Boolean), true, "{\"type\": \"boolean\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int32), Int32.MinValue, "{\"type\": \"int\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int64), Int64.MinValue, "{\"type\": \"long\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Single), Single.MinValue, "{\"type\": \"float\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Double), Double.MinValue, "{\"type\": \"double\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Byte[]), new byte[] { }, "{\"type\": \"bytes\", \"logicalType\": \"unknown\"}")] + public void TestConvertToLogicalValue_IsTrue(Type baseType, object logicalValue, string schemaText) + { + var schema = (LogicalSchema)Schema.Parse(schemaText); + + var logicalType = new UnknownLogicalType(schema); + + var baseValue = logicalType.ConvertToLogicalValue(logicalValue, schema); + + Assert.AreEqual(baseValue, Convert.ChangeType(logicalValue, baseType)); + } + + [TestCase(typeof(System.Byte[]), "", "{\"type\": \"string\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Double), true, "{\"type\": \"boolean\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Single), Int32.MinValue, "{\"type\": \"int\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Boolean), Int64.MinValue, "{\"type\": \"long\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int32), Single.MinValue, "{\"type\": \"float\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int64), Double.MinValue, "{\"type\": \"double\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.String), new byte[] { }, "{\"type\": \"bytes\", \"logicalType\": \"unknown\"}")] + public void TestConvertToLogicalValue_IsFalse(Type baseType, object logicalValue, string schemaText) + { + var schema = (LogicalSchema)Schema.Parse(schemaText); + + var logicalType = new UnknownLogicalType(schema); + + var baseValue = logicalType.ConvertToLogicalValue(logicalValue, schema); + + Assert.AreNotEqual(baseValue.GetType(), baseType); + } + + [TestCase(typeof(System.String), false, "{\"type\": \"string\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Boolean), false, "{\"type\": \"boolean\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int32), false, "{\"type\": \"int\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int64), false, "{\"type\": \"long\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Single), false, "{\"type\": \"float\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Double), false, "{\"type\": \"double\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Byte[]), false, "{\"type\": \"bytes\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.String), true, "{\"type\": \"string\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Boolean?), true, "{\"type\": \"boolean\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int32?), true, "{\"type\": \"int\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int64?), true, "{\"type\": \"long\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Single?), true, "{\"type\": \"float\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Double?), true, "{\"type\": \"double\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Byte?[]), true, "{\"type\": \"bytes\", \"logicalType\": \"unknown\"}")] + public void TestGetCSharpType_IsTrue(Type type, bool isNullable, string schemaText) + { + var schema = (LogicalSchema)Schema.Parse(schemaText); + + var logicalType = new UnknownLogicalType(schema); + + Assert.AreEqual(logicalType.GetCSharpType(isNullable), type); + } + + //[TestCase(typeof(System.String), true, "{\"type\": \"string\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Boolean), true, "{\"type\": \"boolean\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int32), true, "{\"type\": \"int\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int64), true, "{\"type\": \"long\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Single), true, "{\"type\": \"float\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Double), true, "{\"type\": \"double\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Byte[]), true, "{\"type\": \"bytes\", \"logicalType\": \"unknown\"}")] + //[TestCase(typeof(System.String), false, "{\"type\": \"string\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Boolean?), false, "{\"type\": \"boolean\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int32?), false, "{\"type\": \"int\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Int64?), false, "{\"type\": \"long\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Single?), false, "{\"type\": \"float\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Double?), false, "{\"type\": \"double\", \"logicalType\": \"unknown\"}")] + [TestCase(typeof(System.Byte?[]), false, "{\"type\": \"bytes\", \"logicalType\": \"unknown\"}")] + public void TestGetCSharpType_IsFalse(Type type, bool isNullable, string schemaText) + { + var schema = (LogicalSchema)Schema.Parse(schemaText); + + var logicalType = new UnknownLogicalType(schema); + + Assert.AreNotEqual(logicalType.GetCSharpType(isNullable), type); + } + + [TestCase("", "{\"type\": \"string\", \"logicalType\": \"unknown\"}")] + [TestCase(true, "{\"type\": \"boolean\", \"logicalType\": \"unknown\"}")] + [TestCase(Int32.MinValue, "{\"type\": \"int\", \"logicalType\": \"unknown\"}")] + [TestCase(Int64.MinValue, "{\"type\": \"long\", \"logicalType\": \"unknown\"}")] + [TestCase(Single.MinValue, "{\"type\": \"float\", \"logicalType\": \"unknown\"}")] + [TestCase(Double.MinValue, "{\"type\": \"double\", \"logicalType\": \"unknown\"}")] + [TestCase(new byte[] { } , "{\"type\": \"bytes\", \"logicalType\": \"unknown\"}")] + public void TestIsInstanceOfLogicalType_IsTrue(object logicalValue, string schemaText) + { + var schema = (LogicalSchema)Schema.Parse(schemaText); + + var logicalType = new UnknownLogicalType(schema); + + Assert.IsTrue(logicalType.IsInstanceOfLogicalType(logicalValue)); + } + + [TestCase(Int32.MinValue, "{\"type\": \"string\", \"logicalType\": \"unknown\"}")] + [TestCase(new byte[] { }, "{\"type\": \"boolean\", \"logicalType\": \"unknown\"}")] + [TestCase(Int64.MinValue, "{\"type\": \"int\", \"logicalType\": \"unknown\"}")] + [TestCase(Single.MinValue, "{\"type\": \"long\", \"logicalType\": \"unknown\"}")] + [TestCase(Double.MinValue, "{\"type\": \"float\", \"logicalType\": \"unknown\"}")] + [TestCase(new byte[] { }, "{\"type\": \"double\", \"logicalType\": \"unknown\"}")] + [TestCase("", "{\"type\": \"bytes\", \"logicalType\": \"unknown\"}")] + public void TestIsInstanceOfLogicalType_IsFalse(object logicalValue, string schemaText) + { + var schema = (LogicalSchema)Schema.Parse(schemaText); + + var logicalType = new UnknownLogicalType(schema); + + Assert.IsFalse(logicalType.IsInstanceOfLogicalType(logicalValue)); + } + + // See also a new test in Avro.Tests.File in TestSpecificDataSource using unknowLogicalTypeSchema + } +}