| /* |
| * 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 |
| * |
| * http://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.arrow.variant; |
| |
| import static org.junit.jupiter.api.Assertions.assertArrayEquals; |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertFalse; |
| import static org.junit.jupiter.api.Assertions.assertNotEquals; |
| import static org.junit.jupiter.api.Assertions.assertNotNull; |
| import static org.junit.jupiter.api.Assertions.assertNull; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| |
| import java.math.BigDecimal; |
| import java.nio.ByteBuffer; |
| import java.util.UUID; |
| import org.apache.arrow.memory.ArrowBuf; |
| import org.apache.arrow.memory.BufferAllocator; |
| import org.apache.arrow.memory.RootAllocator; |
| import org.apache.parquet.variant.VariantBuilder; |
| import org.junit.jupiter.api.AfterEach; |
| import org.junit.jupiter.api.BeforeEach; |
| import org.junit.jupiter.api.Test; |
| |
| public class TestVariant { |
| |
| private BufferAllocator allocator; |
| |
| @BeforeEach |
| void beforeEach() { |
| allocator = new RootAllocator(); |
| } |
| |
| @AfterEach |
| void afterEach() { |
| allocator.close(); |
| } |
| |
| static Variant buildVariant(VariantBuilder builder) { |
| org.apache.parquet.variant.Variant parquetVariant = builder.build(); |
| ByteBuffer valueBuf = parquetVariant.getValueBuffer(); |
| ByteBuffer metaBuf = parquetVariant.getMetadataBuffer(); |
| byte[] valueBytes = new byte[valueBuf.remaining()]; |
| byte[] metaBytes = new byte[metaBuf.remaining()]; |
| valueBuf.get(valueBytes); |
| metaBuf.get(metaBytes); |
| return new Variant(metaBytes, valueBytes); |
| } |
| |
| public static Variant variantString(String value) { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendString(value); |
| return buildVariant(builder); |
| } |
| |
| @Test |
| void testConstructionWithArrowBuf() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendInt(42); |
| Variant source = buildVariant(builder); |
| int metaLen = source.getMetadataBuffer().remaining(); |
| int valueLen = source.getValueBuffer().remaining(); |
| |
| try (ArrowBuf metadataArrowBuf = allocator.buffer(metaLen + 2); |
| ArrowBuf valueArrowBuf = allocator.buffer(valueLen + 3)) { |
| metadataArrowBuf.setBytes(2, source.getMetadataBuffer()); |
| valueArrowBuf.setBytes(3, source.getValueBuffer()); |
| |
| Variant variant = |
| new Variant(metadataArrowBuf, 2, 2 + metaLen, valueArrowBuf, 3, 3 + valueLen); |
| |
| assertEquals(Variant.Type.INT, variant.getType()); |
| assertEquals(42, variant.getInt()); |
| } |
| } |
| |
| @Test |
| void testNullType() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendNull(); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.NULL, variant.getType()); |
| } |
| |
| @Test |
| void testBooleanType() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendBoolean(true); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.BOOLEAN, variant.getType()); |
| assertTrue(variant.getBoolean()); |
| |
| builder = new VariantBuilder(); |
| builder.appendBoolean(false); |
| variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.BOOLEAN, variant.getType()); |
| assertFalse(variant.getBoolean()); |
| } |
| |
| @Test |
| void testByteType() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendByte((byte) 42); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.BYTE, variant.getType()); |
| assertEquals((byte) 42, variant.getByte()); |
| } |
| |
| @Test |
| void testShortType() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendShort((short) 1234); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.SHORT, variant.getType()); |
| assertEquals((short) 1234, variant.getShort()); |
| } |
| |
| @Test |
| void testIntType() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendInt(123456); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.INT, variant.getType()); |
| assertEquals(123456, variant.getInt()); |
| } |
| |
| @Test |
| void testLongType() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendLong(9876543210L); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.LONG, variant.getType()); |
| assertEquals(9876543210L, variant.getLong()); |
| } |
| |
| @Test |
| void testFloatType() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendFloat(3.14f); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.FLOAT, variant.getType()); |
| assertEquals(3.14f, variant.getFloat(), 0.001f); |
| } |
| |
| @Test |
| void testDoubleType() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendDouble(3.14159265359); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.DOUBLE, variant.getType()); |
| assertEquals(3.14159265359, variant.getDouble(), 0.0000001); |
| } |
| |
| @Test |
| void testStringType() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendString("hello world"); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.STRING, variant.getType()); |
| assertEquals("hello world", variant.getString()); |
| } |
| |
| @Test |
| void testDecimalType() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendDecimal(new BigDecimal("123.456")); |
| Variant variant = buildVariant(builder); |
| |
| assertTrue( |
| variant.getType() == Variant.Type.DECIMAL4 |
| || variant.getType() == Variant.Type.DECIMAL8 |
| || variant.getType() == Variant.Type.DECIMAL16); |
| assertEquals(new BigDecimal("123.456"), variant.getDecimal()); |
| } |
| |
| @Test |
| void testBinaryType() { |
| VariantBuilder builder = new VariantBuilder(); |
| byte[] data = new byte[] {1, 2, 3, 4, 5}; |
| builder.appendBinary(ByteBuffer.wrap(data)); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.BINARY, variant.getType()); |
| ByteBuffer result = variant.getBinary(); |
| byte[] resultBytes = new byte[result.remaining()]; |
| result.get(resultBytes); |
| assertArrayEquals(data, resultBytes); |
| } |
| |
| @Test |
| void testUuidType() { |
| VariantBuilder builder = new VariantBuilder(); |
| UUID uuid = UUID.randomUUID(); |
| builder.appendUUID(uuid); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.UUID, variant.getType()); |
| assertEquals(uuid, variant.getUUID()); |
| } |
| |
| @Test |
| void testDateType() { |
| VariantBuilder builder = new VariantBuilder(); |
| int daysSinceEpoch = 19000; |
| builder.appendDate(daysSinceEpoch); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.DATE, variant.getType()); |
| } |
| |
| @Test |
| void testTimestampTzType() { |
| VariantBuilder builder = new VariantBuilder(); |
| long micros = System.currentTimeMillis() * 1000; |
| builder.appendTimestampTz(micros); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.TIMESTAMP_TZ, variant.getType()); |
| } |
| |
| @Test |
| void testTimestampNtzType() { |
| VariantBuilder builder = new VariantBuilder(); |
| long micros = System.currentTimeMillis() * 1000; |
| builder.appendTimestampNtz(micros); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.TIMESTAMP_NTZ, variant.getType()); |
| } |
| |
| @Test |
| void testTimeType() { |
| VariantBuilder builder = new VariantBuilder(); |
| long micros = 12345678L; |
| builder.appendTime(micros); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.TIME, variant.getType()); |
| } |
| |
| @Test |
| void testObjectType() { |
| VariantBuilder builder = new VariantBuilder(); |
| var objBuilder = builder.startObject(); |
| objBuilder.appendKey("name"); |
| objBuilder.appendString("test"); |
| objBuilder.appendKey("value"); |
| objBuilder.appendInt(42); |
| builder.endObject(); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.OBJECT, variant.getType()); |
| assertEquals(2, variant.numObjectElements()); |
| |
| Variant nameField = variant.getFieldByKey("name"); |
| assertNotNull(nameField); |
| assertEquals(Variant.Type.STRING, nameField.getType()); |
| assertEquals("test", nameField.getString()); |
| |
| Variant valueField = variant.getFieldByKey("value"); |
| assertNotNull(valueField); |
| assertEquals(Variant.Type.INT, valueField.getType()); |
| assertEquals(42, valueField.getInt()); |
| |
| assertNull(variant.getFieldByKey("nonexistent")); |
| |
| // Empty object |
| builder = new VariantBuilder(); |
| builder.startObject(); |
| builder.endObject(); |
| Variant emptyObj = buildVariant(builder); |
| assertEquals(Variant.Type.OBJECT, emptyObj.getType()); |
| assertEquals(0, emptyObj.numObjectElements()); |
| } |
| |
| @Test |
| void testObjectFieldAtIndex() { |
| VariantBuilder builder = new VariantBuilder(); |
| var objBuilder = builder.startObject(); |
| objBuilder.appendKey("alpha"); |
| objBuilder.appendInt(1); |
| objBuilder.appendKey("beta"); |
| objBuilder.appendInt(2); |
| builder.endObject(); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.OBJECT, variant.getType()); |
| assertEquals(2, variant.numObjectElements()); |
| |
| Variant.ObjectField field0 = variant.getFieldAtIndex(0); |
| assertNotNull(field0); |
| assertNotNull(field0.key); |
| assertNotNull(field0.value); |
| |
| Variant.ObjectField field1 = variant.getFieldAtIndex(1); |
| assertNotNull(field1); |
| assertNotNull(field1.key); |
| assertNotNull(field1.value); |
| } |
| |
| @Test |
| void testArrayType() { |
| VariantBuilder builder = new VariantBuilder(); |
| var arrayBuilder = builder.startArray(); |
| arrayBuilder.appendInt(1); |
| arrayBuilder.appendInt(2); |
| arrayBuilder.appendInt(3); |
| builder.endArray(); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.ARRAY, variant.getType()); |
| assertEquals(3, variant.numArrayElements()); |
| |
| Variant elem0 = variant.getElementAtIndex(0); |
| assertNotNull(elem0); |
| assertEquals(Variant.Type.INT, elem0.getType()); |
| assertEquals(1, elem0.getInt()); |
| |
| Variant elem1 = variant.getElementAtIndex(1); |
| assertEquals(2, elem1.getInt()); |
| |
| Variant elem2 = variant.getElementAtIndex(2); |
| assertEquals(3, elem2.getInt()); |
| |
| assertNull(variant.getElementAtIndex(-1)); |
| assertNull(variant.getElementAtIndex(3)); |
| |
| // Empty array |
| builder = new VariantBuilder(); |
| builder.startArray(); |
| builder.endArray(); |
| Variant emptyArr = buildVariant(builder); |
| assertEquals(Variant.Type.ARRAY, emptyArr.getType()); |
| assertEquals(0, emptyArr.numArrayElements()); |
| } |
| |
| @Test |
| void testNestedStructure() { |
| VariantBuilder builder = new VariantBuilder(); |
| var objBuilder = builder.startObject(); |
| objBuilder.appendKey("items"); |
| var arrayBuilder = objBuilder.startArray(); |
| arrayBuilder.appendString("a"); |
| arrayBuilder.appendString("b"); |
| objBuilder.endArray(); |
| builder.endObject(); |
| Variant variant = buildVariant(builder); |
| |
| assertEquals(Variant.Type.OBJECT, variant.getType()); |
| Variant items = variant.getFieldByKey("items"); |
| assertNotNull(items); |
| assertEquals(Variant.Type.ARRAY, items.getType()); |
| assertEquals(2, items.numArrayElements()); |
| assertEquals("a", items.getElementAtIndex(0).getString()); |
| assertEquals("b", items.getElementAtIndex(1).getString()); |
| } |
| |
| @Test |
| void testEquals() { |
| VariantBuilder builder1 = new VariantBuilder(); |
| builder1.appendString("test"); |
| Variant variant1 = buildVariant(builder1); |
| |
| VariantBuilder builder2 = new VariantBuilder(); |
| builder2.appendString("test"); |
| Variant variant2 = buildVariant(builder2); |
| |
| VariantBuilder builder3 = new VariantBuilder(); |
| builder3.appendString("different"); |
| Variant variant3 = buildVariant(builder3); |
| |
| assertEquals(variant1, variant1); |
| assertEquals(variant1, variant2); |
| assertNotEquals(variant1, variant3); |
| assertNotEquals(variant1, null); |
| assertNotEquals(variant1, "not a variant"); |
| } |
| |
| @Test |
| void testHashCode() { |
| VariantBuilder builder1 = new VariantBuilder(); |
| builder1.appendInt(42); |
| Variant variant1 = buildVariant(builder1); |
| |
| VariantBuilder builder2 = new VariantBuilder(); |
| builder2.appendInt(42); |
| Variant variant2 = buildVariant(builder2); |
| |
| assertEquals(variant1.hashCode(), variant2.hashCode()); |
| } |
| |
| @Test |
| void testToString() { |
| VariantBuilder builder = new VariantBuilder(); |
| builder.appendString("test"); |
| Variant variant = buildVariant(builder); |
| |
| String str = variant.toString(); |
| assertNotNull(str); |
| assertTrue(str.contains("type=")); |
| } |
| |
| @Test |
| void testTypeEnumsMatch() { |
| for (Variant.Type arrowType : Variant.Type.values()) { |
| org.apache.parquet.variant.Variant.Type parquetType = |
| org.apache.parquet.variant.Variant.Type.valueOf(arrowType.name()); |
| assertEquals(arrowType, Variant.Type.fromParquet(parquetType)); |
| } |
| for (org.apache.parquet.variant.Variant.Type parquetType : |
| org.apache.parquet.variant.Variant.Type.values()) { |
| Variant.Type arrowType = Variant.Type.valueOf(parquetType.name()); |
| assertEquals(parquetType.name(), arrowType.name()); |
| } |
| } |
| } |