@Test
@SuppressWarnings("Unchecked")
public void shouldHandleMap() {

  Codec<Map<String, Integer>> mapCodec =
      mapper.codecFor(new RawType.RawMap(primitive(ASCII), primitive(INT)));
  Codec<Map<String, Integer>> mapCodec2 =
      mapper.codecFor(new RawType.RawMap(primitive(ASCII), primitive(INT)));
  assertThat(mapCodec).isSameAs(mapCodec2);
  Map<String, Integer> m = new LinkedHashMap<>();
  m.put("hello", 8675);
  m.put("world", 309);
  String mapStr =
      "0x000000020000000568656c6c6f00000004000021e300000005776f726c640000000400000135";
  encodeAndDecode(mapCodec, m, mapStr);
  encodeAndDecode(mapCodec, null, null, Collections.emptyMap());
  encodeObjectAndDecode(mapCodec, m, m);
  encodeObjectAndDecode(mapCodec, null, null, Collections.emptyMap());
  encodeObjectAndDecode(mapCodec, Optional.of(12), null, Collections.emptyMap());
  // Null values not allowed.
  try {
    Map<String, Integer> mWithNull = new LinkedHashMap<>();
    mWithNull.put("Hello", null);
    encodeAndDecode(mapCodec, mWithNull, "");
    fail("Expected NPE");
  } catch (NullPointerException e) {
    // expected
  }
  // Map not matching codec for key.
  try {
    Map mIntKey = new LinkedHashMap<>();
    mIntKey.put(5, 6);
    encodeAndDecode(mapCodec, mIntKey, "");
    fail("Expected InvalidTypeException");
  } catch (InvalidTypeException e) {
    // expected
    assertThat(e.getCause()).isInstanceOf(ClassCastException.class);
  }
  // Map not matching codec for value.
  try {
    Map mStrVal = new LinkedHashMap<>();
    mStrVal.put("hello", "world");
    encodeAndDecode(mapCodec, mStrVal, "");
    fail("Expected InvalidTypeException");
  } catch (InvalidTypeException e) {
    // expected
    assertThat(e.getCause()).isInstanceOf(ClassCastException.class);
  }
  // Underflow while decoding
  try {
    ByteBuffer buf = mapCodec.encode(m);
    // half limit so buffer is truncated.
    buf.limit(buf.limit() / 2);
    mapCodec.decode(buf);
    fail("Expected InvalidTypeException");
  } catch (InvalidTypeException e) { // expected
  }
  // Values of map should be mapped using encodeObject
  // In this case we have a codec that calls for map<ascii, int> but we give it a Map<Integer,
  // String>
  // The codec should properly convert to Map<String, Integer> when encoding.
  Map<Integer, String> swapMap1 = new HashMap<>();
  swapMap1.put(0, "1");
  swapMap1.put(1, "0");
  Map<String, Integer> swapMap0 = new HashMap<>();
  swapMap0.put("0", 1);
  swapMap0.put("1", 0);
  encodeObjectAndDecode(mapCodec, swapMap1, swapMap0);
}