PatternDeserializerTest.java

package tools.jackson.databind.deser.jdk;

import java.util.regex.Pattern;

import org.junit.jupiter.api.Test;

import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.exc.InvalidFormatException;
import tools.jackson.databind.module.SimpleModule;

import static org.junit.jupiter.api.Assertions.*;

import static tools.jackson.databind.testutil.DatabindTestUtil.*;

/**
 * Tests for {@link PatternDeserializer}.
 */
public class PatternDeserializerTest
{
    private final ObjectMapper MAPPER = newJsonMapper();

    @Test
    public void patternDeser() throws Exception
    {
        Pattern exp = Pattern.compile("abc:\\s?(\\d+)");
        // Ok: easiest way is to just serialize first; problem
        // is the backslash
        String json = MAPPER.writeValueAsString(exp);
        Pattern result = MAPPER.readValue(json, Pattern.class);
        assertEquals(exp.pattern(), result.pattern());

        // [databind#3290]: actually need to retain at least trailing space
        // (and since we do that, just retain all...)
        exp = Pattern.compile("^WIN\\ ");
        json = MAPPER.writeValueAsString(exp);
        result = MAPPER.readValue(json, Pattern.class);
        assertEquals(exp.pattern(), result.pattern());

        // [databind#3598]: should also handle invalid pattern serialization
        // somewhat gracefully
        try {
            MAPPER.readValue(q("[abc"), Pattern.class);
            fail("Should not pass");
        } catch (InvalidFormatException e) {
            verifyException(e, "Cannot deserialize value of type `java.util.regex.Pattern` from String \"[abc\"");
            verifyException(e, "Invalid pattern, problem");
        }
    }

    // No length limit by default
    @Test
    public void defaultPatternLengthUnlimited() throws Exception
    {
        String longPattern = "a".repeat(50_000);
        assertEquals(longPattern, MAPPER.readValue(q(longPattern), Pattern.class).pattern());
    }

    // Maximum length is configurable by explicitly registering the deserializer
    @Test
    public void customPatternLengthLimit() throws Exception
    {
        ObjectMapper mapper = _mapperWithMaxLength(10);

        assertEquals("a".repeat(10),
                mapper.readValue(q("a".repeat(10)), Pattern.class).pattern());

        try {
            mapper.readValue(q("a".repeat(11)), Pattern.class);
            fail("Should not pass");
        } catch (InvalidFormatException e) {
            verifyException(e, "regex pattern length (11) exceeds maximum (10)");
        }
    }

    // Length checking can be disabled altogether with UNLIMITED_PATTERN_LENGTH
    @Test
    public void unlimitedPatternLength() throws Exception
    {
        ObjectMapper mapper = _mapperWithMaxLength(PatternDeserializer.UNLIMITED_PATTERN_LENGTH);

        String hugePattern = "a".repeat(50_000);
        assertEquals(hugePattern, mapper.readValue(q(hugePattern), Pattern.class).pattern());
    }

    @Test
    public void invalidMaxLength() throws Exception
    {
        assertThrows(IllegalArgumentException.class, () -> new PatternDeserializer(0));
        assertThrows(IllegalArgumentException.class, () -> new PatternDeserializer(-2));
        // but -1 means "unlimited", and is accepted
        assertNotNull(new PatternDeserializer(PatternDeserializer.UNLIMITED_PATTERN_LENGTH));
    }

    private ObjectMapper _mapperWithMaxLength(int maxPatternLength) {
        SimpleModule module = new SimpleModule();
        module.addDeserializer(Pattern.class, new PatternDeserializer(maxPatternLength));
        return jsonMapperBuilder().addModule(module).build();
    }
}