/* * Copyright (C) 2012-2015 DataStax Inc. * * Licensed 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 com.datastax.driver.core; import com.datastax.driver.core.exceptions.InvalidTypeException; import com.datastax.driver.core.utils.Bytes; import org.testng.annotations.Test; import java.math.BigDecimal; import java.math.BigInteger; import java.net.InetAddress; import java.nio.ByteBuffer; import java.util.*; import static com.datastax.driver.core.Assertions.assertThat; import static com.google.common.collect.Lists.newArrayList; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; /** * DataType simple unit tests. */ public class DataTypeTest { CodecRegistry codecRegistry = new CodecRegistry(); ProtocolVersion protocolVersion = ProtocolVersion.NEWEST_SUPPORTED; static boolean exclude(DataType t) { return t.getName() == DataType.Name.COUNTER || t.getName() == DataType.Name.DURATION; } /** * A test value for a primitive data type */ static class TestValue { /** * The value as a Java object */ final Object javaObject; /** * A CQL string that should parse to the value */ final String cqlInputString; /** * How the value should be formatted in CQL */ final String cqlOutputString; TestValue(Object javaObject, String cqlInputString, String cqlOutputString) { this.javaObject = javaObject; this.cqlInputString = cqlInputString; this.cqlOutputString = cqlOutputString; } } private static TestValue[] primitiveTestValues(DataType dt) { switch (dt.getName()) { case ASCII: case TEXT: case VARCHAR: return new TestValue[]{ new TestValue("foo", "'foo'", "'foo'"), new TestValue("fo'o", "'fo''o'", "'fo''o'"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case BIGINT: return new TestValue[]{ new TestValue(42L, "42", "42"), new TestValue(91294377723L, "91294377723", "91294377723"), new TestValue(-133L, "-133", "-133"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case TIMESTAMP: // input: single quotes are optional for long literals, mandatory for date patterns return new TestValue[]{ new TestValue(new Date(42L), "42", "42"), new TestValue(new Date(91294377723L), "91294377723", "91294377723"), new TestValue(new Date(-133L), "-133", "-133"), new TestValue(new Date(784041330999L), "'1994-11-05T14:15:30.999+0100'", "784041330999"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case DATE: // input: single quotes are optional for long literals, mandatory for date patterns return new TestValue[]{ new TestValue(LocalDate.fromDaysSinceEpoch(16071), "'2014-01-01'", "'2014-01-01'"), new TestValue(LocalDate.fromDaysSinceEpoch(0), "'1970-01-01'", "'1970-01-01'"), new TestValue(LocalDate.fromDaysSinceEpoch((int) (2147483648L - (1L << 31))), "'2147483648'", "'1970-01-01'"), new TestValue(LocalDate.fromDaysSinceEpoch((int) (0 - (1L << 31))), "0", "'-5877641-06-23'"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case TIME: // input: all literals must by enclosed in single quotes return new TestValue[]{ new TestValue(54012123450000L, "'54012123450000'", "'15:00:12.123450000'"), new TestValue(0L, "'0'", "'00:00:00.000000000'"), new TestValue(54012012345000L, "'15:00:12.012345000'", "'15:00:12.012345000'"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case BLOB: return new TestValue[]{ new TestValue(Bytes.fromHexString("0x2450"), "0x2450", "0x2450"), new TestValue(ByteBuffer.allocate(0), "0x", "0x"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case BOOLEAN: return new TestValue[]{ new TestValue(true, "true", "true"), new TestValue(false, "false", "false"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case DECIMAL: return new TestValue[]{ new TestValue(new BigDecimal("1.23E+8"), "1.23E+8", "1.23E+8"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case DOUBLE: return new TestValue[]{ new TestValue(2.39324324, "2.39324324", "2.39324324"), new TestValue(-12., "-12.0", "-12.0"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case FLOAT: return new TestValue[]{ new TestValue(2.39f, "2.39", "2.39"), new TestValue(-12.f, "-12.0", "-12.0"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case INET: try { return new TestValue[]{ new TestValue(InetAddress.getByName("128.2.12.3"), "'128.2.12.3'", "'128.2.12.3'"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; } catch (java.net.UnknownHostException e) { throw new RuntimeException(); } case TINYINT: return new TestValue[]{ new TestValue((byte) -4, "-4", "-4"), new TestValue((byte) 44, "44", "44"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case SMALLINT: return new TestValue[]{ new TestValue((short) -3, "-3", "-3"), new TestValue((short) 43, "43", "43"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case INT: return new TestValue[]{ new TestValue(-2, "-2", "-2"), new TestValue(42, "42", "42"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case TIMEUUID: return new TestValue[]{ new TestValue(UUID.fromString("FE2B4360-28C6-11E2-81C1-0800200C9A66"), "fe2b4360-28c6-11e2-81c1-0800200c9a66", "fe2b4360-28c6-11e2-81c1-0800200c9a66"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case UUID: return new TestValue[]{ new TestValue(UUID.fromString("FE2B4360-28C6-11E2-81C1-0800200C9A66"), "fe2b4360-28c6-11e2-81c1-0800200c9a66", "fe2b4360-28c6-11e2-81c1-0800200c9a66"), new TestValue(UUID.fromString("067e6162-3b6f-4ae2-a171-2470b63dff00"), "067e6162-3b6f-4ae2-a171-2470b63dff00", "067e6162-3b6f-4ae2-a171-2470b63dff00"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; case VARINT: return new TestValue[]{ new TestValue(new BigInteger("12387290982347987032483422342432"), "12387290982347987032483422342432", "12387290982347987032483422342432"), new TestValue(null, null, "NULL"), new TestValue(null, "null", "NULL"), new TestValue(null, "NULL", "NULL")}; default: throw new RuntimeException("Missing handling of " + dt); } } @Test(groups = "unit") public void parseNativeTest() { for (DataType dt : DataType.allPrimitiveTypes()) { if (exclude(dt)) continue; for (TestValue value : primitiveTestValues(dt)) assertThat(codecRegistry.codecFor(dt).parse(value.cqlInputString)) .as("Parsing input %s to a %s", value.cqlInputString, dt) .isEqualTo(value.javaObject); } } @Test(groups = "unit") public void formatNativeTest() { for (DataType dt : DataType.allPrimitiveTypes()) { if (exclude(dt)) continue; for (TestValue value : primitiveTestValues(dt)) assertThat(codecRegistry.codecFor(dt).format(value.javaObject)) .as("Formatting a %s expecting %s", dt, value.cqlOutputString) .isEqualTo(value.cqlOutputString); } } @Test(groups = "unit") public void parseFormatListTest() { String toParse = "['Foo','Bar','Foo''bar']"; List<String> toFormat = Arrays.asList("Foo", "Bar", "Foo'bar"); DataType dt = DataType.list(DataType.text()); assertEquals(codecRegistry.codecFor(dt).parse(toParse), toFormat); assertEquals(codecRegistry.codecFor(dt).format(toFormat), toParse); } @SuppressWarnings("serial") @Test(groups = "unit") public void parseFormatSetTest() { String toParse = "{'Foo','Bar','Foo''bar'}"; Set<String> toFormat = new LinkedHashSet<String>() {{ add("Foo"); add("Bar"); add("Foo'bar"); }}; DataType dt = DataType.set(DataType.text()); assertEquals(codecRegistry.codecFor(dt).parse(toParse), toFormat); assertEquals(codecRegistry.codecFor(dt).format(toFormat), toParse); } @SuppressWarnings("serial") @Test(groups = "unit") public void parseFormatMapTest() { String toParse = "{'Foo':3,'Bar':42,'Foo''bar':-24}"; Map<String, Integer> toFormat = new LinkedHashMap<String, Integer>() {{ put("Foo", 3); put("Bar", 42); put("Foo'bar", -24); }}; DataType dt = DataType.map(DataType.text(), DataType.cint()); assertEquals(codecRegistry.codecFor(dt).parse(toParse), toFormat); assertEquals(codecRegistry.codecFor(dt).format(toFormat), toParse); } @SuppressWarnings("serial") @Test(groups = "unit") public void parseFormatUDTTest() { String toParse = "{t:'fo''o',i:3,\"L\":['a','b'],s:{3:{a:0x01}}}"; final UserType udt1 = new UserType("ks", "t", false, Arrays.asList(new UserType.Field("a", DataType.blob())), protocolVersion, codecRegistry); UserType udt2 = new UserType("ks", "t", false, Arrays.asList( new UserType.Field("t", DataType.text()), new UserType.Field("i", DataType.cint()), new UserType.Field("L", DataType.list(DataType.text())), new UserType.Field("s", DataType.map(DataType.cint(), udt1)) ), protocolVersion, codecRegistry); UDTValue toFormat = udt2.newValue(); toFormat.setString("t", "fo'o"); toFormat.setInt("i", 3); toFormat.setList("\"L\"", Arrays.<String>asList("a", "b")); toFormat.setMap("s", new HashMap<Integer, UDTValue>() {{ put(3, udt1.newValue().setBytes("a", ByteBuffer.wrap(new byte[]{1}))); }}); assertEquals(codecRegistry.codecFor(udt2).parse(toParse), toFormat); assertEquals(codecRegistry.codecFor(udt2).format(toFormat), toParse); } @SuppressWarnings("deprecation") @Test(groups = "unit") public void parseFormatTupleTest() { String toParse = "(1,'foo',1.0)"; TupleType t = new TupleType(newArrayList(DataType.cint(), DataType.text(), DataType.cfloat()), protocolVersion, codecRegistry); TupleValue toFormat = t.newValue(1, "foo", 1.0f); assertEquals(codecRegistry.codecFor(t).parse(toParse), toFormat); assertEquals(codecRegistry.codecFor(t).format(toFormat), toParse); } @Test(groups = "unit") public void serializeDeserializeTest() { for (ProtocolVersion v : ProtocolVersion.values()) serializeDeserializeTest(v); } public void serializeDeserializeTest(ProtocolVersion version) { for (DataType dt : DataType.allPrimitiveTypes()) { if (exclude(dt)) continue; Object value = TestUtils.getFixedValue(dt); TypeCodec<Object> codec = codecRegistry.codecFor(dt); assertEquals(codec.deserialize(codec.serialize(value, version), version), value); } TypeCodec<Long> codec = codecRegistry.codecFor(DataType.bigint()); try { ByteBuffer badValue = ByteBuffer.allocate(4); codec.deserialize(badValue, version); fail("This should not have worked"); } catch (InvalidTypeException e) { /* That's what we want */ } } @Test(groups = "unit") public void serializeDeserializeCollectionsTest() { for (ProtocolVersion v : ProtocolVersion.values()) serializeDeserializeCollectionsTest(v); } public void serializeDeserializeCollectionsTest(ProtocolVersion version) { List<String> l = Arrays.asList("foo", "bar"); DataType dt = DataType.list(DataType.text()); TypeCodec<List<String>> codec = codecRegistry.codecFor(dt); assertEquals(codec.deserialize(codec.serialize(l, version), version), l); try { DataType listOfBigint = DataType.list(DataType.bigint()); codec = codecRegistry.codecFor(listOfBigint); codec.serialize(l, version); fail("This should not have worked"); } catch (InvalidTypeException e) { /* That's what we want */ } } }