@Test
public void testFromMapAttrWithInvalidValue() {

  class Clazz extends AttrComposite {
    AttrBoolean attrBoolean =
        attributes.register("attrBoolean", AttrBoolean.builder().defaultValue(null));
    AttrInteger attrInteger =
        attributes.register("attrInteger", AttrInteger.builder().defaultValue(null));
    AttrDouble attrDouble =
        attributes.register("attrDouble", AttrDouble.builder().defaultValue(null));
    AttrString attrString =
        attributes.register("attrString", AttrString.builder().defaultValue(null));
    AttrEnum<EnumClazz> attrEnum =
        attributes.register("attrEnum", AttrEnum.builder(EnumClazz.class).defaultValue(null));
    AttrObject<Clazz> attrObject =
        attributes.register(
            "attrObject", AttrObject.builder(Clazz.class).defaultValue(null, () -> new Clazz()));
    AttrObjectArray<Clazz> attrObjectArray =
        attributes.register(
            "attrObjectArray",
            AttrObjectArray.builder(Clazz.class, () -> new Clazz()).defaultValue(null));
  }
  AliasMapper mapper = new AliasMapper();
  mapper.alias("clazz", Clazz.class, () -> new Clazz());
  Assertions.assertThatExceptionOfType(IllegalArgumentException.class)
      .isThrownBy(
          () -> {
            Map<String, Object> map = Collections.singletonMap("extraKey", "");
            Attrs.populate(new Clazz(), map, mapper::fromName);
          });
  Assertions.assertThatExceptionOfType(IllegalArgumentException.class)
      .isThrownBy(
          () -> {
            Map<String, Object> map =
                Collections.singletonMap(
                    "attrObject", Collections.singletonMap("extraKey", "invalid-value"));
            Attrs.populate(new Clazz(), map, mapper::fromName);
          });
  for (Object value : Arrays.asList(true, false, null)) {
    checkValueLegal(mapper, new Clazz(), "attrBoolean", value);
  }
  for (Object value : Arrays.asList(10, "true", 10d, new Object[0], new ArrayList<>())) {
    checkValueIllegal(mapper, new Clazz(), "attrBoolean", (c) -> c.attrBoolean.get(), value);
  }
  for (Object value : Arrays.asList(10, 10f, 10d, null)) {
    checkValueLegal(mapper, new Clazz(), "attrInteger", value);
  }
  for (Object value :
      Arrays.asList(
          true,
          "true",
          10.1f,
          10.1d,
          Long.MAX_VALUE,
          Double.NaN,
          new Object[0],
          new ArrayList<>())) {
    checkValueIllegal(mapper, new Clazz(), "attrInteger", (c) -> c.attrInteger.get(), value);
  }
  for (Object value : Arrays.asList(10, 10f, 10d, null, Double.NaN, Double.MAX_VALUE)) {
    checkValueLegal(mapper, new Clazz(), "attrDouble", value);
  }
  for (Object value : Arrays.asList(true, "true", new Object[0], new ArrayList<>())) {
    checkValueIllegal(mapper, new Clazz(), "attrDouble", (c) -> c.attrDouble.get(), value);
  }
  for (Object value : Arrays.asList(null, "abc", "")) {
    checkValueLegal(mapper, new Clazz(), "attrString", value);
  }
  for (Object value : Arrays.asList(true, 10, 10d, new Object[0], new ArrayList<>())) {
    checkValueIllegal(mapper, new Clazz(), "attrString", (c) -> c.attrString.get(), value);
  }
  for (Object value : Arrays.asList(null, EnumClazz.FOO, EnumClazz.FOO.name())) {
    checkValueLegal(mapper, new Clazz(), "attrEnum", value);
  }
  for (Object value :
      Arrays.asList(true, 10, 10d, "NONVALUE", new Object[0], new ArrayList<>())) {
    checkValueIllegal(mapper, new Clazz(), "attrEnum", (c) -> c.attrEnum.get(), value);
  }
  for (Object value : Arrays.asList(null, new HashMap<>())) {
    checkValueLegal(mapper, new Clazz(), "attrObject", value);
  }
  for (Object value :
      Arrays.asList(
          true,
          10,
          10d,
          "NONVALUE",
          Collections.singletonMap("attrInteger", "invalid-value"),
          new Object(),
          new Object[0],
          new ArrayList<>())) {
    checkValueIllegal(mapper, new Clazz(), "attrObject", (c) -> c.attrObject.get(), value);
  }
  for (Object value :
      Arrays.asList(
          null,
          new ArrayList<>(),
          new Object[] {Collections.emptyMap(), Collections.singletonMap("attrString", "foo")})) {
    checkValueLegal(mapper, new Clazz(), "attrObjectArray", value);
  }
  for (Object value :
      Arrays.asList(true, 10, 10d, new Object(), new Object[] {"invalid-value"})) {
    checkValueIllegal(
        mapper, new Clazz(), "attrObjectArray", (c) -> c.attrObjectArray.get(), value);
  }
}