content: /*
   * 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 com.datastax.oss.driver.internal.core.type.codec.registry;
  
  import com.datastax.oss.driver.api.core.CqlIdentifier;
  import com.datastax.oss.driver.api.core.data.CqlDuration;
  import com.datastax.oss.driver.api.core.data.CqlVector;
  import com.datastax.oss.driver.api.core.data.TupleValue;
  import com.datastax.oss.driver.api.core.data.UdtValue;
  import com.datastax.oss.driver.api.core.type.DataTypes;
  import com.datastax.oss.driver.api.core.type.TupleType;
  import com.datastax.oss.driver.api.core.type.UserDefinedType;
  import com.datastax.oss.driver.api.core.type.codec.TypeCodecs;
  import com.datastax.oss.driver.api.core.type.reflect.GenericType;
  import com.datastax.oss.driver.internal.core.data.DefaultTupleValue;
  import com.datastax.oss.driver.internal.core.data.DefaultUdtValue;
  import com.datastax.oss.driver.internal.core.type.UserDefinedTypeBuilder;
  import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList;
  import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
  import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet;
  import com.tngtech.java.junit.dataprovider.DataProvider;
  import java.math.BigDecimal;
  import java.math.BigInteger;
  import java.net.Inet4Address;
  import java.net.InetAddress;
  import java.net.UnknownHostException;
  import java.nio.ByteBuffer;
  import java.time.Instant;
  import java.time.LocalDate;
  import java.time.LocalTime;
  import java.util.Collections;
  import java.util.UUID;
  
  @SuppressWarnings("unused")
  public class CachingCodecRegistryTestDataProviders {
  
    @DataProvider
    public static Object[][] primitiveCodecs() {
      return new Object[][] {
        {TypeCodecs.BOOLEAN},
        {TypeCodecs.TINYINT},
        {TypeCodecs.DOUBLE},
        {TypeCodecs.COUNTER},
        {TypeCodecs.FLOAT},
        {TypeCodecs.INT},
        {TypeCodecs.BIGINT},
        {TypeCodecs.SMALLINT},
        {TypeCodecs.TIMESTAMP},
        {TypeCodecs.DATE},
        {TypeCodecs.TIME},
        {TypeCodecs.BLOB},
        {TypeCodecs.TEXT},
        {TypeCodecs.ASCII},
        {TypeCodecs.VARINT},
        {TypeCodecs.DECIMAL},
        {TypeCodecs.UUID},
        {TypeCodecs.TIMEUUID},
        {TypeCodecs.INET},
        {TypeCodecs.DURATION},
      };
    }
  
    @DataProvider
    public static Object[][] primitiveCodecsWithValues() throws UnknownHostException {
      return new Object[][] {
        {true, TypeCodecs.BOOLEAN},
        {(byte) 0, TypeCodecs.TINYINT},
        {0.0, TypeCodecs.DOUBLE},
        {0.0f, TypeCodecs.FLOAT},
        {0, TypeCodecs.INT},
        {0L, TypeCodecs.BIGINT},
        {(short) 0, TypeCodecs.SMALLINT},
        {Instant.EPOCH, TypeCodecs.TIMESTAMP},
        {LocalDate.MIN, TypeCodecs.DATE},
        {LocalTime.MIDNIGHT, TypeCodecs.TIME},
        {ByteBuffer.allocate(0), TypeCodecs.BLOB},
        {"", TypeCodecs.TEXT},
        {BigInteger.ONE, TypeCodecs.VARINT},
        {BigDecimal.ONE, TypeCodecs.DECIMAL},
        {new UUID(2L, 1L), TypeCodecs.UUID},
        {InetAddress.getByName("127.0.0.1"), TypeCodecs.INET},
        {CqlDuration.newInstance(1, 2, 3), TypeCodecs.DURATION},
      };
    }
  
    @DataProvider
    public static Object[][] primitiveCodecsWithCqlTypesAndValues() throws UnknownHostException {
      return new Object[][] {
        {DataTypes.BOOLEAN, true, TypeCodecs.BOOLEAN},
        {DataTypes.TINYINT, (byte) 0, TypeCodecs.TINYINT},
        {DataTypes.DOUBLE, 0.0, TypeCodecs.DOUBLE},
        {DataTypes.FLOAT, 0.0f, TypeCodecs.FLOAT},
        {DataTypes.INT, 0, TypeCodecs.INT},
        {DataTypes.BIGINT, 0L, TypeCodecs.BIGINT},
        {DataTypes.SMALLINT, (short) 0, TypeCodecs.SMALLINT},
        {DataTypes.TIMESTAMP, Instant.EPOCH, TypeCodecs.TIMESTAMP},
        {DataTypes.DATE, LocalDate.MIN, TypeCodecs.DATE},
        {DataTypes.TIME, LocalTime.MIDNIGHT, TypeCodecs.TIME},
        {DataTypes.BLOB, ByteBuffer.allocate(0), TypeCodecs.BLOB},
        {DataTypes.TEXT, "", TypeCodecs.TEXT},
        {DataTypes.VARINT, BigInteger.ONE, TypeCodecs.VARINT},
        {DataTypes.DECIMAL, BigDecimal.ONE, TypeCodecs.DECIMAL},
        {DataTypes.UUID, new UUID(2L, 1L), TypeCodecs.UUID},
        {DataTypes.INET, InetAddress.getByName("127.0.0.1"), TypeCodecs.INET},
        {DataTypes.DURATION, CqlDuration.newInstance(1, 2, 3), TypeCodecs.DURATION},
      };
    }
  
    @DataProvider
    public static Object[][] collectionsWithCqlAndJavaTypes()
        throws UnknownHostException, ClassNotFoundException {
      TupleType tupleType = DataTypes.tupleOf(DataTypes.INT, DataTypes.listOf(DataTypes.TEXT));
      TupleValue tupleValue = tupleType.newValue();
      UserDefinedType userType =
          new UserDefinedTypeBuilder(
                  CqlIdentifier.fromInternal("ks"), CqlIdentifier.fromInternal("type"))
              .withField(CqlIdentifier.fromInternal("field1"), DataTypes.INT)
              .withField(CqlIdentifier.fromInternal("field2"), DataTypes.listOf(DataTypes.TEXT))
              .build();
      UdtValue udtValue = userType.newValue();
      return new Object[][] {
        // lists
        {
          DataTypes.listOf(DataTypes.INT),
          GenericType.listOf(Integer.class),
          GenericType.listOf(Integer.class),
          ImmutableList.of(1)
        },
        {
          DataTypes.listOf(DataTypes.TEXT),
          GenericType.listOf(String.class),
          GenericType.listOf(String.class),
          ImmutableList.of("foo")
        },
        {
          DataTypes.listOf(DataTypes.BLOB),
          GenericType.listOf(ByteBuffer.class),
          GenericType.listOf(Class.forName("java.nio.HeapByteBuffer")),
          ImmutableList.of(ByteBuffer.wrap(new byte[] {127, 0, 0, 1}))
        },
        {
          DataTypes.listOf(DataTypes.INET),
          GenericType.listOf(InetAddress.class),
          GenericType.listOf(Inet4Address.class),
          ImmutableList.of(InetAddress.getByAddress(new byte[] {127, 0, 0, 1}))
        },
        {
          DataTypes.listOf(tupleType),
          GenericType.listOf(TupleValue.class),
          GenericType.listOf(DefaultTupleValue.class),
          ImmutableList.of(tupleValue)
        },
        {
          DataTypes.listOf(userType),
          GenericType.listOf(UdtValue.class),
          GenericType.listOf(DefaultUdtValue.class),
          ImmutableList.of(udtValue)
        },
        {
          DataTypes.listOf(DataTypes.listOf(DataTypes.INT)),
          GenericType.listOf(GenericType.listOf(Integer.class)),
          GenericType.listOf(GenericType.listOf(Integer.class)),
          ImmutableList.of(ImmutableList.of(1))
        },
        {
          DataTypes.listOf(DataTypes.listOf(tupleType)),
          GenericType.listOf(GenericType.listOf(TupleValue.class)),
          GenericType.listOf(GenericType.listOf(DefaultTupleValue.class)),
          ImmutableList.of(ImmutableList.of(tupleValue))
        },
        {
          DataTypes.listOf(DataTypes.listOf(userType)),
          GenericType.listOf(GenericType.listOf(UdtValue.class)),
          GenericType.listOf(GenericType.listOf(DefaultUdtValue.class)),
          ImmutableList.of(ImmutableList.of(udtValue))
        },
        // sets
        {
          DataTypes.setOf(DataTypes.INT),
          GenericType.setOf(Integer.class),
          GenericType.setOf(Integer.class),
          ImmutableSet.of(1)
        },
        {
          DataTypes.setOf(DataTypes.TEXT),
          GenericType.setOf(String.class),
          GenericType.setOf(String.class),
          ImmutableSet.of("foo")
        },
        {
          DataTypes.setOf(DataTypes.BLOB),
          GenericType.setOf(ByteBuffer.class),
          GenericType.setOf(Class.forName("java.nio.HeapByteBuffer")),
          ImmutableSet.of(ByteBuffer.wrap(new byte[] {127, 0, 0, 1}))
        },
        {
          DataTypes.setOf(DataTypes.INET),
          GenericType.setOf(InetAddress.class),
          GenericType.setOf(Inet4Address.class),
          ImmutableSet.of(InetAddress.getByAddress(new byte[] {127, 0, 0, 1}))
        },
        {
          DataTypes.setOf(tupleType),
          GenericType.setOf(TupleValue.class),
          GenericType.setOf(DefaultTupleValue.class),
          ImmutableSet.of(tupleValue)
        },
        {
          DataTypes.setOf(userType),
          GenericType.setOf(UdtValue.class),
          GenericType.setOf(DefaultUdtValue.class),
          ImmutableSet.of(udtValue)
        },
        {
          DataTypes.setOf(DataTypes.setOf(DataTypes.INT)),
          GenericType.setOf(GenericType.setOf(Integer.class)),
          GenericType.setOf(GenericType.setOf(Integer.class)),
          ImmutableSet.of(ImmutableSet.of(1))
        },
        {
          DataTypes.setOf(DataTypes.setOf(tupleType)),
          GenericType.setOf(GenericType.setOf(TupleValue.class)),
          GenericType.setOf(GenericType.setOf(DefaultTupleValue.class)),
          ImmutableSet.of(ImmutableSet.of(tupleValue))
        },
        {
          DataTypes.setOf(DataTypes.setOf(userType)),
          GenericType.setOf(GenericType.setOf(UdtValue.class)),
          GenericType.setOf(GenericType.setOf(DefaultUdtValue.class)),
          ImmutableSet.of(ImmutableSet.of(udtValue))
        },
        // maps
        {
          DataTypes.mapOf(DataTypes.INT, DataTypes.TEXT),
          GenericType.mapOf(Integer.class, String.class),
          GenericType.mapOf(Integer.class, String.class),
          ImmutableMap.of(1, "foo")
        },
        {
          DataTypes.mapOf(DataTypes.BLOB, DataTypes.INET),
          GenericType.mapOf(ByteBuffer.class, InetAddress.class),
          GenericType.mapOf(Class.forName("java.nio.HeapByteBuffer"), Inet4Address.class),
          ImmutableMap.of(
              ByteBuffer.wrap(new byte[] {127, 0, 0, 1}),
              InetAddress.getByAddress(new byte[] {127, 0, 0, 1}))
        },
        {
          DataTypes.mapOf(tupleType, tupleType),
          GenericType.mapOf(TupleValue.class, TupleValue.class),
          GenericType.mapOf(DefaultTupleValue.class, DefaultTupleValue.class),
          ImmutableMap.of(tupleValue, tupleValue)
        },
        {
          DataTypes.mapOf(userType, userType),
          GenericType.mapOf(UdtValue.class, UdtValue.class),
          GenericType.mapOf(DefaultUdtValue.class, DefaultUdtValue.class),
          ImmutableMap.of(udtValue, udtValue)
        },
        {
          DataTypes.mapOf(DataTypes.UUID, DataTypes.mapOf(DataTypes.INT, DataTypes.TEXT)),
          GenericType.mapOf(GenericType.UUID, GenericType.mapOf(Integer.class, String.class)),
          GenericType.mapOf(GenericType.UUID, GenericType.mapOf(Integer.class, String.class)),
          ImmutableMap.of(UUID.randomUUID(), ImmutableMap.of(1, "foo"))
        },
        {
          DataTypes.mapOf(DataTypes.mapOf(userType, userType), DataTypes.mapOf(tupleType, tupleType)),
          GenericType.mapOf(
              GenericType.mapOf(UdtValue.class, UdtValue.class),
              GenericType.mapOf(TupleValue.class, TupleValue.class)),
          GenericType.mapOf(
              GenericType.mapOf(DefaultUdtValue.class, DefaultUdtValue.class),
              GenericType.mapOf(DefaultTupleValue.class, DefaultTupleValue.class)),
          ImmutableMap.of(
              ImmutableMap.of(udtValue, udtValue), ImmutableMap.of(tupleValue, tupleValue))
        },
        // vectors
        {
          DataTypes.vectorOf(DataTypes.INT, 1),
          GenericType.vectorOf(Integer.class),
          GenericType.vectorOf(Integer.class),
          CqlVector.newInstance(1)
        },
        {
          DataTypes.vectorOf(DataTypes.BIGINT, 1),
          GenericType.vectorOf(Long.class),
          GenericType.vectorOf(Long.class),
          CqlVector.newInstance(1l)
        },
        {
          DataTypes.vectorOf(DataTypes.SMALLINT, 1),
          GenericType.vectorOf(Short.class),
          GenericType.vectorOf(Short.class),
          CqlVector.newInstance((short) 1)
        },
        {
          DataTypes.vectorOf(DataTypes.TINYINT, 1),
          GenericType.vectorOf(Byte.class),
          GenericType.vectorOf(Byte.class),
          CqlVector.newInstance((byte) 1)
        },
        {
          DataTypes.vectorOf(DataTypes.FLOAT, 1),
          GenericType.vectorOf(Float.class),
          GenericType.vectorOf(Float.class),
          CqlVector.newInstance(1.0f)
        },
        {
          DataTypes.vectorOf(DataTypes.DOUBLE, 1),
          GenericType.vectorOf(Double.class),
          GenericType.vectorOf(Double.class),
          CqlVector.newInstance(1.0d)
        },
        {
          DataTypes.vectorOf(DataTypes.DECIMAL, 1),
          GenericType.vectorOf(BigDecimal.class),
          GenericType.vectorOf(BigDecimal.class),
          CqlVector.newInstance(BigDecimal.ONE)
        },
        {
          DataTypes.vectorOf(DataTypes.VARINT, 1),
          GenericType.vectorOf(BigInteger.class),
          GenericType.vectorOf(BigInteger.class),
          CqlVector.newInstance(BigInteger.ONE)
        },
        // vector with arbitrary types
        {
          DataTypes.vectorOf(DataTypes.TEXT, 2),
          GenericType.vectorOf(String.class),
          GenericType.vectorOf(String.class),
          CqlVector.newInstance("abc", "de")
        },
        {
          DataTypes.vectorOf(DataTypes.TIME, 2),
          GenericType.vectorOf(LocalTime.class),
          GenericType.vectorOf(LocalTime.class),
          CqlVector.newInstance(LocalTime.MIDNIGHT, LocalTime.NOON)
        },
        {
          DataTypes.vectorOf(DataTypes.vectorOf(DataTypes.TINYINT, 2), 2),
          GenericType.vectorOf(GenericType.vectorOf(Byte.class)),
          GenericType.vectorOf(GenericType.vectorOf(Byte.class)),
          CqlVector.newInstance(
              CqlVector.newInstance((byte) 1, (byte) 2), CqlVector.newInstance((byte) 3, (byte) 4))
        },
      };
    }
  
    @DataProvider
    public static Object[][] emptyCollectionsWithCqlAndJavaTypes() {
      TupleType tupleType = DataTypes.tupleOf(DataTypes.INT, DataTypes.listOf(DataTypes.TEXT));
      UserDefinedType userType =
          new UserDefinedTypeBuilder(
                  CqlIdentifier.fromInternal("ks"), CqlIdentifier.fromInternal("type"))
              .withField(CqlIdentifier.fromInternal("field1"), DataTypes.INT)
              .withField(CqlIdentifier.fromInternal("field2"), DataTypes.listOf(DataTypes.TEXT))
              .build();
      return new Object[][] {
        // lists
        {
          DataTypes.listOf(DataTypes.INT),
          GenericType.listOf(Integer.class),
          DataTypes.listOf(DataTypes.BOOLEAN),
          GenericType.listOf(Boolean.class),
          Collections.emptyList()
        },
        {
          DataTypes.listOf(DataTypes.TEXT),
          GenericType.listOf(String.class),
          DataTypes.listOf(DataTypes.BOOLEAN),
          GenericType.listOf(Boolean.class),
          Collections.emptyList()
        },
        {
          DataTypes.listOf(DataTypes.BLOB),
          GenericType.listOf(ByteBuffer.class),
          DataTypes.listOf(DataTypes.BOOLEAN),
          GenericType.listOf(Boolean.class),
          Collections.emptyList()
        },
        {
          DataTypes.listOf(DataTypes.INET),
          GenericType.listOf(InetAddress.class),
          DataTypes.listOf(DataTypes.BOOLEAN),
          GenericType.listOf(Boolean.class),
          Collections.emptyList()
        },
        {
          DataTypes.listOf(tupleType),
          GenericType.listOf(TupleValue.class),
          DataTypes.listOf(DataTypes.BOOLEAN),
          GenericType.listOf(Boolean.class),
          Collections.emptyList()
        },
        {
          DataTypes.listOf(userType),
          GenericType.listOf(UdtValue.class),
          DataTypes.listOf(DataTypes.BOOLEAN),
          GenericType.listOf(Boolean.class),
          Collections.emptyList()
        },
        {
          DataTypes.listOf(DataTypes.listOf(DataTypes.INT)),
          GenericType.listOf(GenericType.listOf(Integer.class)),
          DataTypes.listOf(DataTypes.listOf(DataTypes.BOOLEAN)),
          GenericType.listOf(GenericType.listOf(Boolean.class)),
          ImmutableList.of(Collections.emptyList())
        },
        {
          DataTypes.listOf(DataTypes.listOf(tupleType)),
          GenericType.listOf(GenericType.listOf(TupleValue.class)),
          DataTypes.listOf(DataTypes.listOf(DataTypes.BOOLEAN)),
          GenericType.listOf(GenericType.listOf(Boolean.class)),
          ImmutableList.of(Collections.emptyList())
        },
        {
          DataTypes.listOf(DataTypes.listOf(userType)),
          GenericType.listOf(GenericType.listOf(UdtValue.class)),
          DataTypes.listOf(DataTypes.listOf(DataTypes.BOOLEAN)),
          GenericType.listOf(GenericType.listOf(Boolean.class)),
          ImmutableList.of(Collections.emptyList())
        },
        // sets
        {
          DataTypes.setOf(DataTypes.INT),
          GenericType.setOf(Integer.class),
          DataTypes.setOf(DataTypes.BOOLEAN),
          GenericType.setOf(Boolean.class),
          Collections.emptySet()
        },
        {
          DataTypes.setOf(DataTypes.TEXT),
          GenericType.setOf(String.class),
          DataTypes.setOf(DataTypes.BOOLEAN),
          GenericType.setOf(Boolean.class),
          Collections.emptySet()
        },
        {
          DataTypes.setOf(DataTypes.BLOB),
          GenericType.setOf(ByteBuffer.class),
          DataTypes.setOf(DataTypes.BOOLEAN),
          GenericType.setOf(Boolean.class),
          Collections.emptySet()
        },
        {
          DataTypes.setOf(DataTypes.INET),
          GenericType.setOf(InetAddress.class),
          DataTypes.setOf(DataTypes.BOOLEAN),
          GenericType.setOf(Boolean.class),
          Collections.emptySet()
        },
        {
          DataTypes.setOf(tupleType),
          GenericType.setOf(TupleValue.class),
          DataTypes.setOf(DataTypes.BOOLEAN),
          GenericType.setOf(Boolean.class),
          Collections.emptySet()
        },
        {
          DataTypes.setOf(userType),
          GenericType.setOf(UdtValue.class),
          DataTypes.setOf(DataTypes.BOOLEAN),
          GenericType.setOf(Boolean.class),
          Collections.emptySet()
        },
        {
          DataTypes.setOf(DataTypes.setOf(DataTypes.INT)),
          GenericType.setOf(GenericType.setOf(Integer.class)),
          DataTypes.setOf(DataTypes.setOf(DataTypes.BOOLEAN)),
          GenericType.setOf(GenericType.setOf(Boolean.class)),
          ImmutableSet.of(Collections.emptySet())
        },
        {
          DataTypes.setOf(DataTypes.setOf(tupleType)),
          GenericType.setOf(GenericType.setOf(TupleValue.class)),
          DataTypes.setOf(DataTypes.setOf(DataTypes.BOOLEAN)),
          GenericType.setOf(GenericType.setOf(Boolean.class)),
          ImmutableSet.of(Collections.emptySet())
        },
        {
          DataTypes.setOf(DataTypes.setOf(userType)),
          GenericType.setOf(GenericType.setOf(UdtValue.class)),
          DataTypes.setOf(DataTypes.setOf(DataTypes.BOOLEAN)),
          GenericType.setOf(GenericType.setOf(Boolean.class)),
          ImmutableSet.of(Collections.emptySet())
        },
        // maps
        {
          DataTypes.mapOf(DataTypes.INT, DataTypes.TEXT),
          GenericType.mapOf(Integer.class, String.class),
          DataTypes.mapOf(DataTypes.BOOLEAN, DataTypes.BOOLEAN),
          GenericType.mapOf(Boolean.class, Boolean.class),
          Collections.emptyMap()
        },
        {
          DataTypes.mapOf(DataTypes.BLOB, DataTypes.INET),
          GenericType.mapOf(ByteBuffer.class, InetAddress.class),
          DataTypes.mapOf(DataTypes.BOOLEAN, DataTypes.BOOLEAN),
          GenericType.mapOf(Boolean.class, Boolean.class),
          Collections.emptyMap()
        },
        {
          DataTypes.mapOf(tupleType, tupleType),
          GenericType.mapOf(TupleValue.class, TupleValue.class),
          DataTypes.mapOf(DataTypes.BOOLEAN, DataTypes.BOOLEAN),
          GenericType.mapOf(Boolean.class, Boolean.class),
          Collections.emptyMap()
        },
        {
          DataTypes.mapOf(userType, userType),
          GenericType.mapOf(UdtValue.class, UdtValue.class),
          DataTypes.mapOf(DataTypes.BOOLEAN, DataTypes.BOOLEAN),
          GenericType.mapOf(Boolean.class, Boolean.class),
          Collections.emptyMap()
        },
        {
          DataTypes.mapOf(DataTypes.UUID, DataTypes.mapOf(DataTypes.INT, DataTypes.TEXT)),
          GenericType.mapOf(GenericType.UUID, GenericType.mapOf(Integer.class, String.class)),
          DataTypes.mapOf(DataTypes.UUID, DataTypes.mapOf(DataTypes.BOOLEAN, DataTypes.BOOLEAN)),
          GenericType.mapOf(GenericType.UUID, GenericType.mapOf(Boolean.class, Boolean.class)),
          ImmutableMap.of(UUID.randomUUID(), Collections.emptyMap())
        },
        {
          DataTypes.mapOf(DataTypes.mapOf(DataTypes.INT, DataTypes.TEXT), DataTypes.UUID),
          GenericType.mapOf(GenericType.mapOf(Integer.class, String.class), GenericType.UUID),
          DataTypes.mapOf(DataTypes.mapOf(DataTypes.BOOLEAN, DataTypes.BOOLEAN), DataTypes.UUID),
          GenericType.mapOf(GenericType.mapOf(Boolean.class, Boolean.class), GenericType.UUID),
          ImmutableMap.of(Collections.emptyMap(), UUID.randomUUID())
        },
        {
          DataTypes.mapOf(DataTypes.mapOf(userType, userType), DataTypes.mapOf(tupleType, tupleType)),
          GenericType.mapOf(
              GenericType.mapOf(UdtValue.class, UdtValue.class),
              GenericType.mapOf(TupleValue.class, TupleValue.class)),
          DataTypes.mapOf(
              DataTypes.mapOf(DataTypes.BOOLEAN, DataTypes.BOOLEAN),
              DataTypes.mapOf(DataTypes.BOOLEAN, DataTypes.BOOLEAN)),
          GenericType.mapOf(
              GenericType.mapOf(Boolean.class, Boolean.class),
              GenericType.mapOf(Boolean.class, Boolean.class)),
          ImmutableMap.of(Collections.emptyMap(), Collections.emptyMap())
        },
      };
    }
  
    @DataProvider
    public static Object[][] collectionsWithNullElements() {
      return new Object[][] {
        {
          Collections.singletonList(null),
          "Can't infer list codec because the first element is null "
              + "(note that CQL does not allow null values in collections)"
        },
        {
          Collections.singleton(null),
          "Can't infer set codec because the first element is null "
              + "(note that CQL does not allow null values in collections)"
        },
        {
          Collections.singletonMap("foo", null),
          "Can't infer map codec because the first key and/or value is null "
              + "(note that CQL does not allow null values in collections)"
        },
        {
          Collections.singletonMap(null, "foo"),
          "Can't infer map codec because the first key and/or value is null "
              + "(note that CQL does not allow null values in collections)"
        },
        {
          Collections.singletonMap(null, null),
          "Can't infer map codec because the first key and/or value is null "
              + "(note that CQL does not allow null values in collections)"
        },
      };
    }
  
    @DataProvider
    public static Object[][] tuplesWithCqlTypes() {
      TupleType tupleType1 = DataTypes.tupleOf(DataTypes.INT, DataTypes.TEXT);
      TupleType tupleType2 = DataTypes.tupleOf(DataTypes.INT, DataTypes.listOf(DataTypes.TEXT));
      TupleType tupleType3 = DataTypes.tupleOf(DataTypes.mapOf(tupleType1, tupleType2));
      TupleValue tupleValue1 = tupleType1.newValue(42, "foo");
      TupleValue tupleValue2 = tupleType2.newValue(42, ImmutableList.of("foo", "bar"));
      return new Object[][] {
        {tupleType1, tupleType1.newValue()},
        {tupleType1, tupleValue1},
        {tupleType2, tupleType2.newValue()},
        {tupleType2, tupleValue2},
        {tupleType3, tupleType3.newValue()},
        {tupleType3, tupleType3.newValue(ImmutableMap.of(tupleValue1, tupleValue2))},
      };
    }
  
    @DataProvider
    public static Object[][] udtsWithCqlTypes() {
      UserDefinedType userType1 =
          new UserDefinedTypeBuilder(
                  CqlIdentifier.fromInternal("ks"), CqlIdentifier.fromInternal("type"))
              .withField(CqlIdentifier.fromInternal("field1"), DataTypes.INT)
              .withField(CqlIdentifier.fromInternal("field2"), DataTypes.TEXT)
              .build();
      UserDefinedType userType2 =
          new UserDefinedTypeBuilder(
                  CqlIdentifier.fromInternal("ks"), CqlIdentifier.fromInternal("type"))
              .withField(CqlIdentifier.fromInternal("field1"), DataTypes.setOf(DataTypes.BIGINT))
              .withField(CqlIdentifier.fromInternal("field2"), DataTypes.listOf(DataTypes.TEXT))
              .build();
      UserDefinedType userType3 =
          new UserDefinedTypeBuilder(
                  CqlIdentifier.fromInternal("ks"), CqlIdentifier.fromInternal("type"))
              .withField(CqlIdentifier.fromInternal("field1"), DataTypes.mapOf(userType1, userType2))
              .build();
      UdtValue userValue1 = userType1.newValue(42, "foo");
      UdtValue userValue2 =
          userType2.newValue(ImmutableSet.of(24L, 43L), ImmutableList.of("foo", "bar"));
      return new Object[][] {
        {userType1, userType1.newValue()},
        {userType1, userValue1},
        {userType2, userType2.newValue()},
        {userType2, userValue2},
        {userType3, userType3.newValue()},
        {userType3, userType3.newValue(ImmutableMap.of(userValue1, userValue2))},
      };
    }
  }
  