diff --git a/lang/csharp/src/apache/test/AvroGen/AvroGenTests.cs b/lang/csharp/src/apache/test/AvroGen/AvroGenTests.cs index 2426bc27519..1f61fc547dc 100644 --- a/lang/csharp/src/apache/test/AvroGen/AvroGenTests.cs +++ b/lang/csharp/src/apache/test/AvroGen/AvroGenTests.cs @@ -161,8 +161,11 @@ class AvroGenTests ""type"": [""null"", { ""namespace"": ""org.apache.avro.codegentest.testdata"", ""name"": ""FixedInUnion"", - ""type"": ""fixed"", - ""size"": 12, + ""type"": { + ""type"": ""fixed"", + ""size"": 12, + ""name"": ""FixedName"", + }, ""logicalType"": ""decimal"", ""precision"": 28, ""scale"": 15 @@ -442,6 +445,16 @@ private Assembly TestSchema( "org/apache/avro/codegentest/some/NestedSomeNamespaceRecord.cs", "org/apache/avro/codegentest/other/NestedOtherNamespaceRecord.cs" })] + [TestCase( + _nestedLogicalTypesUnionFixedDecimal, + new string[] + { + "org.apache.avro.codegentest.testdata.NestedLogicalTypesUnionFixedDecimal" + }, + new string[] + { + "org/apache/avro/codegentest/testdata/NestedLogicalTypesUnionFixedDecimal.cs" + })] [TestCase( _nullableLogicalTypes, new string[] @@ -595,7 +608,6 @@ public void GenerateSchemaWithNamespaceMapping( [TestCase(_logicalTypesWithCustomConversion, typeof(AvroTypeException))] [TestCase(_customConversionWithLogicalTypes, typeof(SchemaParseException))] - [TestCase(_nestedLogicalTypesUnionFixedDecimal, typeof(SchemaParseException))] public void NotSupportedSchema(string schema, Type expectedException) { // Create temp folder @@ -670,26 +682,28 @@ public void NotSupportedSchema(string schema, Type expectedException) new object[] { "schematest.SchemaObject", typeof(IList) })] [TestCase(@" { - ""type"" : ""record"", - ""name"" : ""LogicalTypes"", - ""namespace"" : ""schematest"", - ""fields"" : - [ - { ""name"" : ""nullibleguid"", ""type"" : [""null"", {""type"": ""string"", ""logicalType"": ""uuid"" } ]}, - { ""name"" : ""guid"", ""type"" : {""type"": ""string"", ""logicalType"": ""uuid"" } }, - { ""name"" : ""nullibletimestampmillis"", ""type"" : [""null"", {""type"": ""long"", ""logicalType"": ""timestamp-millis""}] }, - { ""name"" : ""timestampmillis"", ""type"" : {""type"": ""long"", ""logicalType"": ""timestamp-millis""} }, - { ""name"" : ""nullibiletimestampmicros"", ""type"" : [""null"", {""type"": ""long"", ""logicalType"": ""timestamp-micros""}] }, - { ""name"" : ""timestampmicros"", ""type"" : {""type"": ""long"", ""logicalType"": ""timestamp-micros""} }, - { ""name"" : ""nullibiletimemicros"", ""type"" : [""null"", {""type"": ""long"", ""logicalType"": ""time-micros""}] }, - { ""name"" : ""timemicros"", ""type"" : {""type"": ""long"", ""logicalType"": ""time-micros""} }, - { ""name"" : ""nullibiletimemillis"", ""type"" : [""null"", {""type"": ""int"", ""logicalType"": ""time-millis""}] }, - { ""name"" : ""timemillis"", ""type"" : {""type"": ""int"", ""logicalType"": ""time-millis""} }, - { ""name"" : ""nullibledecimal"", ""type"" : [""null"", {""type"": ""bytes"", ""logicalType"": ""decimal"", ""precision"": 4, ""scale"": 2}] }, - { ""name"" : ""decimal"", ""type"" : {""type"": ""bytes"", ""logicalType"": ""decimal"", ""precision"": 4, ""scale"": 2} } - ] + ""type"" : ""record"", + ""name"" : ""LogicalTypes"", + ""namespace"" : ""schematest"", + ""fields"" : + [ + { ""name"" : ""nullibleguid"", ""type"" : [""null"", {""type"": ""string"", ""logicalType"": ""uuid"" } ]}, + { ""name"" : ""guid"", ""type"" : {""type"": ""string"", ""logicalType"": ""uuid"" } }, + { ""name"" : ""nullibletimestampmillis"", ""type"" : [""null"", {""type"": ""long"", ""logicalType"": ""timestamp-millis""}] }, + { ""name"" : ""timestampmillis"", ""type"" : {""type"": ""long"", ""logicalType"": ""timestamp-millis""} }, + { ""name"" : ""nullibiletimestampmicros"", ""type"" : [""null"", {""type"": ""long"", ""logicalType"": ""timestamp-micros""}] }, + { ""name"" : ""timestampmicros"", ""type"" : {""type"": ""long"", ""logicalType"": ""timestamp-micros""} }, + { ""name"" : ""nullibiletimemicros"", ""type"" : [""null"", {""type"": ""long"", ""logicalType"": ""time-micros""}] }, + { ""name"" : ""timemicros"", ""type"" : {""type"": ""long"", ""logicalType"": ""time-micros""} }, + { ""name"" : ""nullibiletimemillis"", ""type"" : [""null"", {""type"": ""int"", ""logicalType"": ""time-millis""}] }, + { ""name"" : ""timemillis"", ""type"" : {""type"": ""int"", ""logicalType"": ""time-millis""} }, + { ""name"" : ""nullibledecimal"", ""type"" : [""null"", {""type"": ""bytes"", ""logicalType"": ""decimal"", ""precision"": 4, ""scale"": 2}] }, + { ""name"" : ""decimal"", ""type"" : {""type"": ""bytes"", ""logicalType"": ""decimal"", ""precision"": 4, ""scale"": 2} }, + { ""name"" : ""nullibledecimalfixed"", ""type"" : [""null"", {""type"": {""type"" : ""fixed"", ""size"": 16, ""name"": ""ndf""}, ""logicalType"": ""decimal"", ""precision"": 4, ""scale"": 2}] }, + { ""name"" : ""decimalfixed"", ""type"" : {""type"": {""type"" : ""fixed"", ""size"": 16, ""name"": ""df""}, ""logicalType"": ""decimal"", ""precision"": 4, ""scale"": 2} } + ] }", - new object[] { "schematest.LogicalTypes", typeof(Guid?), typeof(Guid), typeof(DateTime?), typeof(DateTime), typeof(DateTime?), typeof(DateTime), typeof(TimeSpan?), typeof(TimeSpan), typeof(TimeSpan?), typeof(TimeSpan), typeof(AvroDecimal?), typeof(AvroDecimal) })] + new object[] { "schematest.LogicalTypes", typeof(Guid?), typeof(Guid), typeof(DateTime?), typeof(DateTime), typeof(DateTime?), typeof(DateTime), typeof(TimeSpan?), typeof(TimeSpan), typeof(TimeSpan?), typeof(TimeSpan), typeof(AvroDecimal?), typeof(AvroDecimal), typeof(AvroDecimal?), typeof(AvroDecimal) })] [TestCase(@" { ""namespace"": ""enum.base"", diff --git a/lang/csharp/src/apache/test/Util/LogicalTypeTests.cs b/lang/csharp/src/apache/test/Util/LogicalTypeTests.cs index 9630b7c6716..0b89c7d17db 100644 --- a/lang/csharp/src/apache/test/Util/LogicalTypeTests.cs +++ b/lang/csharp/src/apache/test/Util/LogicalTypeTests.cs @@ -58,15 +58,22 @@ public void TestDecimalConvert(string s, int scale, byte[] converted) Assert.AreEqual(decimalVal, (AvroDecimal)avroDecimal.ConvertToLogicalValue(converted, schema)); } - [TestCase("1234.56")] - [TestCase("-1234.56")] - [TestCase("123456789123456789.56")] - [TestCase("-123456789123456789.56")] - [TestCase("000000000000000001.01")] - [TestCase("-000000000000000001.01")] - public void TestDecimal(string s) + [Test] + public void TestDecimal( + [Values( + "1234.56", + "-1234.56", + "123456789123456789.56", + "-123456789123456789.56", + "000000000000000001.01", + "-000000000000000001.01" + )] string s, + [Values( + "\"bytes\"", + "{\"type\": \"fixed\", \"size\": 16, \"name\": \"n\"}" + )] string baseType) { - var schema = (LogicalSchema)Schema.Parse("{\"type\": \"bytes\", \"logicalType\": \"decimal\", \"precision\": 4, \"scale\": 2 }"); + var schema = (LogicalSchema)Schema.Parse($"{{\"type\": {baseType}, \"logicalType\": \"decimal\", \"precision\": 4, \"scale\": 2 }}"); var avroDecimal = new Avro.Util.Decimal(); // CultureInfo.InvariantCulture ensures that "." is always accepted as the decimal point @@ -77,10 +84,38 @@ public void TestDecimal(string s) Assert.AreEqual(decimalVal, convertedDecimalVal); } - [TestCase] - public void TestDecimalMinMax() + [Test] + public void TestDecimalScale( + [Values( + "0", + "1", + "-1", + "1234567891234567890123456789", + "-1234567891234567890123456789", + "0000000000000000000000000001", + "-0000000000000000000000000001" + )] string s, + [Values(1, 2, 3, 4, 5, 6, 7, 8)] int scale, + [Values( + "\"bytes\"", + "{\"type\": \"fixed\", \"size\": 16, \"name\": \"n\"}" + )] string baseType) { - var schema = (LogicalSchema)Schema.Parse("{\"type\": \"bytes\", \"logicalType\": \"decimal\", \"precision\": 4, \"scale\": 0 }"); + var schema = (LogicalSchema)Schema.Parse($"{{\"type\": {baseType}, \"logicalType\": \"decimal\", \"precision\": 8, \"scale\": {scale} }}"); + + var avroDecimal = new Avro.Util.Decimal(); + var decimalVal = new AvroDecimal(BigInteger.Parse(s), scale); + + var convertedDecimalVal = (AvroDecimal)avroDecimal.ConvertToLogicalValue(avroDecimal.ConvertToBaseValue(decimalVal, schema), schema); + + Assert.AreEqual(decimalVal, convertedDecimalVal); + } + + [TestCase("\"bytes\"")] + [TestCase("{\"type\": \"fixed\", \"size\": 16, \"name\": \"n\"}")] + public void TestDecimalMinMax(string baseType) + { + var schema = (LogicalSchema)Schema.Parse($"{{\"type\": {baseType}, \"logicalType\": \"decimal\", \"precision\": 4, \"scale\": 0 }}"); var avroDecimal = new Avro.Util.Decimal(); @@ -92,10 +127,11 @@ public void TestDecimalMinMax() } } - [TestCase] - public void TestDecimalOutOfRangeException() + [TestCase("\"bytes\"")] + [TestCase("{\"type\": \"fixed\", \"size\": 16, \"name\": \"n\"}")] + public void TestDecimalOutOfRangeException(string baseType) { - var schema = (LogicalSchema)Schema.Parse("{\"type\": \"bytes\", \"logicalType\": \"decimal\", \"precision\": 4, \"scale\": 2 }"); + var schema = (LogicalSchema)Schema.Parse($"{{\"type\": {baseType}, \"logicalType\": \"decimal\", \"precision\": 4, \"scale\": 2 }}"); var avroDecimal = new Avro.Util.Decimal(); var decimalVal = (AvroDecimal)1234.567M; // scale of 3 should throw ArgumentOutOfRangeException