This is an automated email from the ASF dual-hosted git repository. rskraba pushed a commit to branch branch-1.11 in repository https://gitbox.apache.org/repos/asf/avro.git
commit 7464920d0577c8466f3cd6165538fc0bfb05d089 Author: clesaec <[email protected]> AuthorDate: Fri Sep 9 18:54:06 2022 +0200 AVRO-2831: add ResolverTest (#1858) * AVRO-2831: add unit test on Avro * AVRO-2831: add unit test on Avro * AVRO-2831: Add license to TestResolver.java --- .../src/main/java/org/apache/avro/Resolver.java | 10 +- .../test/java/org/apache/avro/TestResolver.java | 122 +++++++++++++++++++++ 2 files changed, 123 insertions(+), 9 deletions(-) diff --git a/lang/java/avro/src/main/java/org/apache/avro/Resolver.java b/lang/java/avro/src/main/java/org/apache/avro/Resolver.java index 9db847c2c..117c9e391 100644 --- a/lang/java/avro/src/main/java/org/apache/avro/Resolver.java +++ b/lang/java/avro/src/main/java/org/apache/avro/Resolver.java @@ -286,16 +286,10 @@ public class Resolver { throw new IllegalArgumentException("Only use when reader and writer are different."); Schema.Type wt = w.getType(); switch (r.getType()) { - case INT: - switch (wt) { - case INT: - return true; - } - break; + case LONG: switch (wt) { case INT: - case LONG: return true; } break; @@ -303,7 +297,6 @@ public class Resolver { switch (wt) { case INT: case LONG: - case FLOAT: return true; } break; @@ -312,7 +305,6 @@ public class Resolver { case INT: case LONG: case FLOAT: - case DOUBLE: return true; } break; diff --git a/lang/java/avro/src/test/java/org/apache/avro/TestResolver.java b/lang/java/avro/src/test/java/org/apache/avro/TestResolver.java new file mode 100644 index 000000000..1d3919319 --- /dev/null +++ b/lang/java/avro/src/test/java/org/apache/avro/TestResolver.java @@ -0,0 +1,122 @@ +/* + * 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. + */ +package org.apache.avro; + +import java.io.IOException; +import java.util.Arrays; + +import org.apache.avro.data.TimeConversions; +import org.apache.avro.generic.IndexedRecord; +import org.apache.avro.io.DatumReader; +import org.apache.avro.io.DecoderFactory; +import org.apache.avro.io.FastReaderBuilder; +import org.apache.avro.io.JsonDecoder; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class TestResolver { + + /** + * Test promote action INT -> LONG, with logical type for LONG. + */ + @Test + void resolveTime() { + final Schema writeSchema = Schema.create(Schema.Type.INT); + final Schema readSchema = new TimeConversions.TimeMicrosConversion().getRecommendedSchema(); // LONG + + Resolver.Action action = Resolver.resolve(writeSchema, readSchema); + Assertions.assertNotNull(action); + MatcherAssert.assertThat("Wrong class for action", action, Matchers.instanceOf(Resolver.Promote.class)); + Assertions.assertEquals(action.type, Resolver.Action.Type.PROMOTE); + Assertions.assertNotNull(action.logicalType); + } + + /** + * Test union type with promote action INT -> LONG, with logical type for LONG. + */ + @Test + void resolveUnion() { + final Schema schema = new TimeConversions.TimeMicrosConversion().getRecommendedSchema(); + + final Schema writeSchema = Schema.createUnion(Schema.create(Schema.Type.INT)); + final Schema readSchema = Schema.createUnion(schema); + + Resolver.Action action = Resolver.resolve(writeSchema, readSchema); + Assertions.assertNotNull(action); + Assertions.assertEquals(action.type, Resolver.Action.Type.WRITER_UNION); + MatcherAssert.assertThat("Wrong class for action", action, Matchers.instanceOf(Resolver.WriterUnion.class)); + + Assertions.assertEquals(1, ((Resolver.WriterUnion) action).actions.length); + Resolver.Action innerAction = ((Resolver.WriterUnion) action).actions[0]; + + MatcherAssert.assertThat("Wrong class for action", innerAction, Matchers.instanceOf(Resolver.ReaderUnion.class)); + Resolver.ReaderUnion innerUnionAction = (Resolver.ReaderUnion) innerAction; + Resolver.Action promoteAction = innerUnionAction.actualAction; + Assertions.assertEquals(promoteAction.type, Resolver.Action.Type.PROMOTE); + Assertions.assertNotNull(promoteAction.logicalType); + } + + @Test + void resolveEnum() throws IOException { + final Schema writeSchema = Schema.createEnum("myEnum", "", "n1", Arrays.asList("e1", "e3", "e4")); + final Schema readSchema = Schema.createEnum("myEnum", "", "n1", Arrays.asList("e1", "e2", "e3"), "e2"); + + Resolver.Action action = Resolver.resolve(writeSchema, readSchema); + Assertions.assertNotNull(action); + Assertions.assertEquals(action.type, Resolver.Action.Type.ENUM); + MatcherAssert.assertThat("Wrong class for action", action, Matchers.instanceOf(Resolver.EnumAdjust.class)); + Resolver.EnumAdjust adjust = (Resolver.EnumAdjust) action; + + Assertions.assertArrayEquals(new int[] { 0, 2, 1 }, adjust.adjustments); + Assertions.assertEquals("e1", adjust.values[0].toString()); + Assertions.assertEquals("e3", adjust.values[1].toString()); + Assertions.assertEquals("e2", adjust.values[2].toString()); + + FastReaderBuilder reader = FastReaderBuilder.get(); + Schema writeRecord = Schema.createRecord("rec1", "", "", false, + Arrays.asList(new Schema.Field("f1", writeSchema, ""))); + Schema readRecord = Schema.createRecord("rec1", "", "", false, + Arrays.asList(new Schema.Field("f1", readSchema, ""))); + DatumReader<Object> datumReader = reader.createDatumReader(writeRecord, readRecord); + JsonDecoder e2 = DecoderFactory.get().jsonDecoder(readRecord, "{ \"f1\" : \"e2\" }"); + Object read = datumReader.read(null, e2); + Assertions.assertNotNull(read); + MatcherAssert.assertThat("", read, Matchers.instanceOf(IndexedRecord.class)); + IndexedRecord result = (IndexedRecord) read; + Assertions.assertEquals("e3", result.get(0).toString()); + } + + @Test + void promoteIsValid() { + Assertions.assertThrows(IllegalArgumentException.class, + () -> Resolver.Promote.isValid(Schema.create(Schema.Type.INT), Schema.create(Schema.Type.INT))); + + Assertions.assertTrue(Resolver.Promote.isValid(Schema.create(Schema.Type.INT), Schema.create(Schema.Type.LONG))); + Assertions.assertFalse(Resolver.Promote.isValid(Schema.create(Schema.Type.LONG), Schema.create(Schema.Type.INT))); + + Assertions.assertTrue(Resolver.Promote.isValid(Schema.create(Schema.Type.INT), Schema.create(Schema.Type.FLOAT))); + Assertions.assertFalse(Resolver.Promote.isValid(Schema.create(Schema.Type.FLOAT), Schema.create(Schema.Type.INT))); + + Assertions + .assertTrue(Resolver.Promote.isValid(Schema.create(Schema.Type.FLOAT), Schema.create(Schema.Type.DOUBLE))); + Assertions + .assertFalse(Resolver.Promote.isValid(Schema.create(Schema.Type.DOUBLE), Schema.create(Schema.Type.FLOAT))); + } +}
