From 7df89c47d70aba69d0abd61802868b09de1c3140 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Sat, 10 Feb 2024 18:54:14 -0800 Subject: [PATCH] Backport part of junit5 changes to 2.16 --- .../jackson/core/JUnit5TestBase.java | 210 ++++++++++++++++++ .../core/read/ParserErrorHandlingTest.java | 25 ++- 2 files changed, 227 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/fasterxml/jackson/core/JUnit5TestBase.java diff --git a/src/test/java/com/fasterxml/jackson/core/JUnit5TestBase.java b/src/test/java/com/fasterxml/jackson/core/JUnit5TestBase.java new file mode 100644 index 0000000000..d9c899fa16 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/core/JUnit5TestBase.java @@ -0,0 +1,210 @@ +package com.fasterxml.jackson.core; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInput; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import com.fasterxml.jackson.core.testsupport.MockDataInput; +import com.fasterxml.jackson.core.testsupport.ThrottledInputStream; +import com.fasterxml.jackson.core.testsupport.ThrottledReader; + +import static org.junit.jupiter.api.Assertions.fail; + +/** + * Intended replacement for {@link BaseTest} + */ +public class JUnit5TestBase +{ + protected final static int MODE_INPUT_STREAM = 0; + protected final static int MODE_INPUT_STREAM_THROTTLED = 1; + protected final static int MODE_READER = 2; + protected final static int MODE_READER_THROTTLED = 3; + protected final static int MODE_DATA_INPUT = 4; + + protected final static int[] ALL_MODES = new int[] { + MODE_INPUT_STREAM, + MODE_INPUT_STREAM_THROTTLED, + MODE_READER, + MODE_READER_THROTTLED, + MODE_DATA_INPUT + }; + + protected final static int[] ALL_BINARY_MODES = new int[] { + MODE_INPUT_STREAM, + MODE_INPUT_STREAM_THROTTLED, + MODE_DATA_INPUT + }; + + protected final static int[] ALL_TEXT_MODES = new int[] { + MODE_READER, + MODE_READER_THROTTLED + }; + + // DataInput not streaming + protected final static int[] ALL_STREAMING_MODES = new int[] { + MODE_INPUT_STREAM, + MODE_INPUT_STREAM_THROTTLED, + MODE_READER, + MODE_READER_THROTTLED + }; + + /* + /********************************************************************** + /* Factory methods + /********************************************************************** + */ + + protected JsonFactory newStreamFactory() { + return new JsonFactory(); + } + + protected JsonFactoryBuilder streamFactoryBuilder() { + return (JsonFactoryBuilder) JsonFactory.builder(); + } + + protected JsonParser createParser(TokenStreamFactory f, int mode, String doc) throws IOException + { + switch (mode) { + case MODE_INPUT_STREAM: + return createParserUsingStream(f, doc, "UTF-8"); + case MODE_INPUT_STREAM_THROTTLED: + return f.createParser(new ThrottledInputStream(utf8Bytes(doc), 1)); + case MODE_READER: + return createParserUsingReader(f, doc); + case MODE_READER_THROTTLED: + return f.createParser(new ThrottledReader(doc, 1)); + case MODE_DATA_INPUT: + return createParserForDataInput(f, new MockDataInput(doc)); + default: + } + throw new RuntimeException("internal error"); + } + + protected JsonParser createParser(TokenStreamFactory f, int mode, byte[] doc) throws IOException + { + switch (mode) { + case MODE_INPUT_STREAM: + return f.createParser(new ByteArrayInputStream(doc)); + case MODE_INPUT_STREAM_THROTTLED: + return f.createParser(new ThrottledInputStream(doc, 1)); + case MODE_READER: + return f.createParser(new StringReader(new String(doc, "UTF-8"))); + case MODE_READER_THROTTLED: + return f.createParser(new ThrottledReader(new String(doc, "UTF-8"), 1)); + case MODE_DATA_INPUT: + return createParserForDataInput(f, new MockDataInput(doc)); + default: + } + throw new RuntimeException("internal error"); + } + + protected JsonParser createParserUsingReader(TokenStreamFactory f, String input) + throws IOException + { + return f.createParser(new StringReader(input)); + } + + protected JsonParser createParserUsingStream(TokenStreamFactory f, + String input, String encoding) + throws IOException + { + + /* 23-Apr-2008, tatus: UTF-32 is not supported by JDK, have to + * use our own codec too (which is not optimal since there's + * a chance both encoder and decoder might have bugs, but ones + * that cancel each other out or such) + */ + byte[] data; + if (encoding.equalsIgnoreCase("UTF-32")) { + data = encodeInUTF32BE(input); + } else { + data = input.getBytes(encoding); + } + InputStream is = new ByteArrayInputStream(data); + return f.createParser(is); + } + + protected JsonParser createParserForDataInput(TokenStreamFactory f, + DataInput input) + throws IOException + { + return f.createParser(input); + } + + /* + /********************************************************************** + /* Assertions + /********************************************************************** + */ + + protected void assertToken(JsonToken expToken, JsonToken actToken) + { + if (actToken != expToken) { + fail("Expected token "+expToken+", current token "+actToken); + } + } + + protected void assertToken(JsonToken expToken, JsonParser p) + { + assertToken(expToken, p.currentToken()); + } + + /** + * @param e Exception to check + * @param anyMatches Array of Strings of which AT LEAST ONE ("any") has to be included + * in {@code e.getMessage()} -- using case-INSENSITIVE comparison + */ + public static void verifyException(Throwable e, String... anyMatches) + { + String msg = e.getMessage(); + String lmsg = (msg == null) ? "" : msg.toLowerCase(); + for (String match : anyMatches) { + String lmatch = match.toLowerCase(); + if (lmsg.indexOf(lmatch) >= 0) { + return; + } + } + fail("Expected an exception with one of substrings ("+Arrays.asList(anyMatches)+"): got one with message \""+msg+"\""); + } + + /* + /********************************************************************** + /* Escaping/quoting + /********************************************************************** + */ + + protected String q(String str) { + return '"'+str+'"'; + } + + protected String a2q(String json) { + return json.replace("'", "\""); + } + + protected byte[] utf8Bytes(String str) { + return str.getBytes(StandardCharsets.UTF_8); + } + + protected String utf8String(ByteArrayOutputStream bytes) { + return new String(bytes.toByteArray(), StandardCharsets.UTF_8); + } + + public static byte[] encodeInUTF32BE(String input) + { + int len = input.length(); + byte[] result = new byte[len * 4]; + int ptr = 0; + for (int i = 0; i < len; ++i, ptr += 4) { + char c = input.charAt(i); + result[ptr] = result[ptr+1] = (byte) 0; + result[ptr+2] = (byte) (c >> 8); + result[ptr+3] = (byte) c; + } + return result; + } +} diff --git a/src/test/java/com/fasterxml/jackson/core/read/ParserErrorHandlingTest.java b/src/test/java/com/fasterxml/jackson/core/read/ParserErrorHandlingTest.java index f9c56781b0..8b013f703e 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/ParserErrorHandlingTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/ParserErrorHandlingTest.java @@ -2,30 +2,38 @@ import java.io.IOException; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.*; + +import static org.junit.jupiter.api.Assertions.*; public class ParserErrorHandlingTest - extends com.fasterxml.jackson.core.BaseTest + extends JUnit5TestBase { + private final JsonFactory JSON_F = newStreamFactory(); + + @Test public void testInvalidKeywordsBytes() throws Exception { _testInvalidKeywords(MODE_INPUT_STREAM); _testInvalidKeywords(MODE_INPUT_STREAM_THROTTLED); _testInvalidKeywords(MODE_DATA_INPUT); } + @Test public void testInvalidKeywordsChars() throws Exception { _testInvalidKeywords(MODE_READER); } // Tests for [core#105] ("eager number parsing misses errors") + @Test public void testMangledIntsBytes() throws Exception { _testMangledNumbersInt(MODE_INPUT_STREAM); _testMangledNumbersInt(MODE_INPUT_STREAM_THROTTLED); _testMangledNumbersInt(MODE_DATA_INPUT); } + @Test public void testMangledFloatsBytes() throws Exception { _testMangledNumbersFloat(MODE_INPUT_STREAM); _testMangledNumbersFloat(MODE_INPUT_STREAM_THROTTLED); @@ -34,6 +42,7 @@ public void testMangledFloatsBytes() throws Exception { _testMangledNumbersFloat(MODE_DATA_INPUT); } + @Test public void testMangledNumbersChars() throws Exception { _testMangledNumbersInt(MODE_READER); _testMangledNumbersFloat(MODE_READER); @@ -65,7 +74,7 @@ private void doTestInvalidKeyword1(int mode, String value) throws IOException { String doc = "{ \"key1\" : "+value+" }"; - JsonParser p = createParser(mode, doc); + JsonParser p = createParser(JSON_F, mode, doc); assertToken(JsonToken.START_OBJECT, p.nextToken()); // Note that depending on parser impl, we may // get the exception early or late... @@ -82,7 +91,7 @@ private void doTestInvalidKeyword1(int mode, String value) // Try as root-level value as well: doc = value + " "; // may need space after for DataInput - p = createParser(mode, doc); + p = createParser(JSON_F, mode, doc); try { p.nextToken(); fail("Expected an exception for malformed value keyword"); @@ -96,7 +105,7 @@ private void doTestInvalidKeyword1(int mode, String value) private void _testMangledNumbersInt(int mode) throws Exception { - JsonParser p = createParser(mode, "123true"); + JsonParser p = createParser(JSON_F, mode, "123true"); try { JsonToken t = p.nextToken(); fail("Should have gotten an exception; instead got token: "+t); @@ -109,7 +118,7 @@ private void _testMangledNumbersInt(int mode) throws Exception private void _testMangledNumbersFloat(int mode) throws Exception { // Also test with floats - JsonParser p = createParser(mode, "1.5false"); + JsonParser p = createParser(JSON_F, mode, "1.5false"); try { JsonToken t = p.nextToken(); fail("Should have gotten an exception; instead got token: "+t);