From 8af0abda45c67e89ee3d78eaabfbf07f524e67dc Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Wed, 10 Jun 2020 20:38:23 -0700 Subject: [PATCH] moar testing --- .../convert/CoerceEmptyArrayTest.java | 255 ++++++++++++++++++ .../convert/EmptyArrayAsNullTest.java | 160 ----------- 2 files changed, 255 insertions(+), 160 deletions(-) create mode 100644 src/test/java/com/fasterxml/jackson/databind/convert/CoerceEmptyArrayTest.java delete mode 100644 src/test/java/com/fasterxml/jackson/databind/convert/EmptyArrayAsNullTest.java diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/CoerceEmptyArrayTest.java b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceEmptyArrayTest.java new file mode 100644 index 0000000000..ff429b8ae0 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/convert/CoerceEmptyArrayTest.java @@ -0,0 +1,255 @@ +package com.fasterxml.jackson.databind.convert; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URI; +import java.net.URL; +import java.util.*; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.cfg.CoercionAction; +import com.fasterxml.jackson.databind.cfg.CoercionInputShape; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.fasterxml.jackson.databind.type.LogicalType; + +/** + * Tests to verify implementation of [databind#540]; also for + * follow up work of: + * + * - [databind#994] + */ +public class CoerceEmptyArrayTest extends BaseMapTest +{ + private final ObjectMapper DEFAULT_MAPPER = sharedMapper(); + private final ObjectReader DEFAULT_READER = DEFAULT_MAPPER.reader(); + private final ObjectReader READER_WITH_ARRAYS = DEFAULT_READER + .with(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT); + + private final ObjectMapper MAPPER_TO_EMPTY; + { + MAPPER_TO_EMPTY = newJsonMapper(); + MAPPER_TO_EMPTY.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.AsEmpty); + } + + private final ObjectMapper MAPPER_TRY_CONVERT; + { + MAPPER_TRY_CONVERT = newJsonMapper(); + MAPPER_TRY_CONVERT.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.TryConvert); + } + + private final ObjectMapper MAPPER_TO_NULL; + { + MAPPER_TO_NULL = newJsonMapper(); + MAPPER_TO_NULL.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.AsNull); + } + + private final ObjectMapper MAPPER_TO_FAIL; + { + MAPPER_TO_FAIL = newJsonMapper(); + MAPPER_TO_FAIL.coercionConfigDefaults() + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.Fail); + } + + static class Bean { + public String a = "foo"; + + @Override + public boolean equals(Object o) { + return (o instanceof Bean) + && a.equals(((Bean) o).a); + } + } + + final static String EMPTY_ARRAY = " [\n]"; + + /* + /********************************************************** + /* Test methods, settings + /********************************************************** + */ + + public void testSettings() { + assertFalse(DEFAULT_MAPPER.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); + assertFalse(DEFAULT_READER.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); + assertTrue(READER_WITH_ARRAYS.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); + } + + /* + /********************************************************** + /* Test methods, POJOs + /********************************************************** + */ + + // [databind#540] + public void testPOJOFromEmptyArray() throws Exception + { + final Class targetType = Bean.class; + + _verifyFailForEmptyArray(DEFAULT_READER, targetType); + _verifyFailForEmptyArray(MAPPER_TO_FAIL, targetType); + + // Nulls for explicit, "TryConvert" + _verifyToNullCoercion(MAPPER_TO_NULL, targetType); + _verifyToNullCoercion(MAPPER_TRY_CONVERT, targetType); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, targetType, new Bean()); + + // But let's also check precedence: legacy setting allow, but mask for type + ObjectMapper mapper = jsonMapperBuilder() + .enable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT) + .build(); + mapper.coercionConfigFor(targetType) + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.Fail); + _verifyFailForEmptyArray(mapper, targetType); + + // and conversely + mapper = jsonMapperBuilder() + .disable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT) + .build(); + mapper.coercionConfigFor(LogicalType.POJO) + .setCoercion(CoercionInputShape.EmptyArray, CoercionAction.AsEmpty); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, targetType, new Bean()); + } + + /* + /********************************************************** + /* Test methods, Maps + /********************************************************** + */ + + public void testMapFromEmptyArray() throws Exception + { + final Class targetType = Map.class; + + _verifyFailForEmptyArray(DEFAULT_READER, targetType); + _verifyFailForEmptyArray(MAPPER_TO_FAIL, targetType); + + // Nulls for explicit, "TryConvert" + _verifyToNullCoercion(MAPPER_TO_NULL, targetType); + _verifyToNullCoercion(MAPPER_TRY_CONVERT, targetType); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, targetType, new LinkedHashMap<>()); + + // assume overrides work ok since POJOs test it + } + + public void testEnumMapFromEmptyArray() throws Exception + { + final JavaType targetType = DEFAULT_READER.getTypeFactory() + .constructType(new TypeReference>() { }); + + assertNull(MAPPER_TO_NULL.readerFor(targetType).readValue(EMPTY_ARRAY)); + + EnumMap result = MAPPER_TO_EMPTY.readerFor(targetType).readValue(EMPTY_ARRAY); + assertNotNull(result); + assertTrue(result.isEmpty()); + } + + /* + /********************************************************** + /* Test methods, scalars + /********************************************************** + */ + + public void testNumbersFromEmptyArray() throws Exception + { + for (Class targetType : new Class[] { + Boolean.class, Character.class, + Byte.class, Short.class, Integer.class, Long.class, + Float.class, Double.class, + BigInteger.class, BigDecimal.class + }) { + // Default, fail; explicit fail + _verifyFailForEmptyArray(DEFAULT_READER, targetType); + _verifyFailForEmptyArray(MAPPER_TO_FAIL, targetType); + + // Nulls for explicit, "TryConvert" + _verifyToNullCoercion(MAPPER_TO_NULL, targetType); + _verifyToNullCoercion(MAPPER_TRY_CONVERT, targetType); + } + + // But as-empty needs separate + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Boolean.class, Boolean.FALSE); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Character.class, Character.valueOf('\0')); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Byte.class, Byte.valueOf((byte) 0)); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Short.class, Short.valueOf((short) 0)); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Integer.class, Integer.valueOf(0)); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Long.class, Long.valueOf(0L)); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Float.class, Float.valueOf(0f)); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, Double.class, Double.valueOf(0d)); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, BigInteger.class, BigInteger.ZERO); + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, BigDecimal.class, new BigDecimal(BigInteger.ZERO)); + } + + public void testOtherScalarsFromEmptyArray() throws Exception + { + for (Class targetType : new Class[] { + String.class, StringBuilder.class, + UUID.class, URL.class, URI.class, + Date.class, Calendar.class + }) { + _verifyFailForEmptyArray(DEFAULT_READER, targetType); + _verifyFailForEmptyArray(MAPPER_TO_FAIL, targetType); + + // Nulls for explicit, "TryConvert" + _verifyToNullCoercion(MAPPER_TO_NULL, targetType); + _verifyToNullCoercion(MAPPER_TRY_CONVERT, targetType); + } + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, String.class, ""); + StringBuilder sb = MAPPER_TO_EMPTY.readerFor(StringBuilder.class) + .readValue(EMPTY_ARRAY); + assertEquals(0, sb.length()); + + _verifyToEmptyCoercion(MAPPER_TO_EMPTY, UUID.class, new UUID(0L, 0L)); + } + + /* + /********************************************************** + /* Helper methods + /********************************************************** + */ + + private void _verifyToNullCoercion(ObjectMapper mapper, Class cls) throws Exception { + _verifyToNullCoercion(mapper.reader(), cls); + } + + private void _verifyToNullCoercion(ObjectReader r, Class cls) throws Exception { + Object result = r.forType(cls).readValue(EMPTY_ARRAY); + if (result != null) { + fail("Expect null for "+cls.getName()+", got: "+result); + } + } + + private void _verifyToEmptyCoercion(ObjectMapper mapper, Class cls, Object exp) throws Exception { + _verifyToEmptyCoercion(mapper.reader(), cls, exp); + } + + private void _verifyToEmptyCoercion(ObjectReader r, Class cls, Object exp) throws Exception { + Object result = r.forType(cls).readValue(EMPTY_ARRAY); + if (!exp.equals(result)) { + fail("Expect value ["+exp+"] for "+cls.getName()+", got: "+result); + } + } + + private void _verifyFailForEmptyArray(ObjectMapper mapper, Class targetType) throws Exception { + _verifyFailForEmptyArray(mapper.readerFor(targetType), targetType); + } + + private void _verifyFailForEmptyArray(ObjectReader r, Class targetType) throws Exception + { + try { + r.forType(targetType).readValue(EMPTY_ARRAY); + fail("Should not accept Empty Array for "+targetType.getName()+" by default"); + } catch (MismatchedInputException e) { + verifyException(e, "from Array value (token `JsonToken.START_ARRAY`)"); + } + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/EmptyArrayAsNullTest.java b/src/test/java/com/fasterxml/jackson/databind/convert/EmptyArrayAsNullTest.java deleted file mode 100644 index 8956922f46..0000000000 --- a/src/test/java/com/fasterxml/jackson/databind/convert/EmptyArrayAsNullTest.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.fasterxml.jackson.databind.convert; - -import java.math.BigDecimal; -import java.math.BigInteger; - -import java.util.*; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.databind.exc.MismatchedInputException; - -/** - * Tests to verify implementation of [databind#540]; also for - * follow up work of: - * - * - [databind#994] - */ -public class EmptyArrayAsNullTest extends BaseMapTest -{ - private final ObjectMapper MAPPER = sharedMapper(); - private final ObjectReader DEFAULT_READER = MAPPER.reader(); - private final ObjectReader READER_WITH_ARRAYS = DEFAULT_READER - .with(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT); - - static class Bean { - public String a = "foo"; - } - - final static String EMPTY_ARRAY = " [\n]"; - - /* - /********************************************************** - /* Test methods, settings - /********************************************************** - */ - - public void testSettings() { - assertFalse(MAPPER.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); - assertFalse(DEFAULT_READER.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); - assertTrue(READER_WITH_ARRAYS.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)); - } - - /* - /********************************************************** - /* Test methods, POJOs - /********************************************************** - */ - - // [databind#540] - public void testPOJOFromEmptyArrayLegacy() throws Exception - { - // first, verify default settings which do not accept empty Array - try { - DEFAULT_READER.forType(Bean.class) - .readValue(EMPTY_ARRAY); - fail("Should not accept Empty Array for POJO by default"); - } catch (JsonMappingException e) { - verifyException(e, "from Array value (token `JsonToken.START_ARRAY`)"); - assertValidLocation(e.getLocation()); - } - - // should be ok to enable dynamically: - Bean result = READER_WITH_ARRAYS.forType(Bean.class) - .readValue(EMPTY_ARRAY); - assertNull(result); - } - - /* - /********************************************************** - /* Test methods, Maps - /********************************************************** - */ - - public void testMapFromEmptyArray() throws Exception - { - // first, verify default settings which do not accept empty Array - _verifyFailForEmptyArray(Map.class); - - // should be ok to enable dynamically: - Map result = READER_WITH_ARRAYS.forType(Map.class) - .readValue(EMPTY_ARRAY); - assertNull(result); - } - - - public void testEnumMapFromEmptyArray() throws Exception - { - - EnumMap result2 = READER_WITH_ARRAYS.forType(new TypeReference>() { }) - .readValue(EMPTY_ARRAY); - assertNull(result2); - } - - /* - /********************************************************** - /* Test methods, primitives/wrappers - /********************************************************** - */ - - public void testWrapperFromEmptyArray() throws Exception - { - _testNullWrapper(Boolean.class); - _testNullWrapper(Byte.class); - _testNullWrapper(Character.class); - _testNullWrapper(Short.class); - _testNullWrapper(Integer.class); - _testNullWrapper(Long.class); - _testNullWrapper(Float.class); - _testNullWrapper(Double.class); - } - - /* - /********************************************************** - /* Test methods, other - /********************************************************** - */ - - public void testNullStringFromEmptyArray() throws Exception { - _testNullWrapper(String.class); - } - - public void testNullEnumFromEmptyArray() throws Exception { - _testNullWrapper(ABC.class); - } - - public void testStdJdkTypesFromEmptyArray() throws Exception - { - _testNullWrapper(BigInteger.class); - _testNullWrapper(BigDecimal.class); - - _testNullWrapper(String.class); - _testNullWrapper(UUID.class); - - _testNullWrapper(Date.class); - _testNullWrapper(Calendar.class); - } - - /* - /********************************************************** - /* Helper methods - /********************************************************** - */ - - private void _testNullWrapper(Class cls) throws Exception - { - Object result = READER_WITH_ARRAYS.forType(cls).readValue(EMPTY_ARRAY); - assertNull(result); - } - - private void _verifyFailForEmptyArray(Class targetType) throws Exception - { - try { - DEFAULT_READER.forType(targetType) - .readValue(EMPTY_ARRAY); - fail("Should not accept Empty Array for "+targetType.getName()+" by default"); - } catch (MismatchedInputException e) { - verifyException(e, "from Array value (token `JsonToken.START_ARRAY`)"); - } - } -}