-
-
Notifications
You must be signed in to change notification settings - Fork 799
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
1 parent
ef9f0c9
commit 717cd6b
Showing
3 changed files
with
215 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
204 changes: 204 additions & 0 deletions
204
src/test/java/com/fasterxml/jackson/failing/LocationOfError1180Test.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
package com.fasterxml.jackson.failing; | ||
|
||
import java.nio.charset.StandardCharsets; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.stream.Stream; | ||
|
||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.Arguments; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
|
||
import com.fasterxml.jackson.core.*; | ||
import com.fasterxml.jackson.core.async.ByteArrayFeeder; | ||
import com.fasterxml.jackson.core.exc.StreamReadException; | ||
|
||
import static com.fasterxml.jackson.core.BaseTest.a2q; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
/** | ||
* Tests that the {@link JsonLocation} attached to a thrown {@link StreamReadException} | ||
* due to invalid JSON points to the correct character. | ||
*/ | ||
public class LocationOfError1180Test | ||
{ | ||
static final JsonFactory JSON_F = new JsonFactory(); | ||
|
||
/** Represents the different parser backends */ | ||
public enum ParserVariant | ||
{ | ||
BYTE_ARRAY( | ||
(String input) -> JSON_F.createParser(input.getBytes(StandardCharsets.UTF_8)), | ||
true, // supports byte offsets in reported location | ||
false, // supports character offsets in reported location | ||
true // supports column numbers in reported location | ||
), | ||
CHAR_ARRAY( | ||
(String input) -> JSON_F.createParser(input.toCharArray()), | ||
false, | ||
true, | ||
true | ||
), | ||
ASYNC( | ||
(String input) -> { | ||
JsonParser parser = JSON_F.createNonBlockingByteArrayParser(); | ||
ByteArrayFeeder feeder = (ByteArrayFeeder) parser.getNonBlockingInputFeeder(); | ||
assertTrue(feeder.needMoreInput()); | ||
|
||
byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8); | ||
feeder.feedInput(inputBytes, 0, inputBytes.length); | ||
feeder.endOfInput(); | ||
|
||
return parser; | ||
}, | ||
true, | ||
false, | ||
true | ||
) | ||
; | ||
|
||
ParserVariant( | ||
ParserGenerator parserGenerator, | ||
boolean supportsByteOffset, | ||
boolean supportsCharOffset, | ||
boolean supportsColumnNr | ||
) | ||
{ | ||
_parserGenerator = parserGenerator; | ||
|
||
this.supportsByteOffset = supportsByteOffset; | ||
this.supportsCharOffset = supportsCharOffset; | ||
this.supportsColumnNr = supportsColumnNr; | ||
} | ||
|
||
public JsonParser createParser(String input) throws Exception | ||
{ | ||
return _parserGenerator.createParser(input); | ||
} | ||
|
||
private final ParserGenerator _parserGenerator; | ||
public final boolean supportsByteOffset; | ||
public final boolean supportsCharOffset; | ||
public final boolean supportsColumnNr; | ||
} | ||
|
||
/** Collection of differing invalid JSON input cases to test */ | ||
private static final List<InvalidJson> INVALID_JSON_CASES = Arrays.asList( | ||
new InvalidJson( | ||
"Incorrect case for false literal", | ||
"{\"isThisValidJson\": FALSE}", | ||
24, | ||
24, | ||
1, | ||
25 | ||
), | ||
new InvalidJson( | ||
"Incorrect case for true literal", | ||
"{\"shouldYouAvoidWritingJsonLikeThis\": TRUE}", | ||
41, | ||
41, | ||
1, | ||
42 | ||
), | ||
new InvalidJson( | ||
"Incorrect case for null literal", | ||
"{\"licensePlate\": NULL}", | ||
20, | ||
20, | ||
1, | ||
21 | ||
), | ||
// NOTE: to be removed, eventually | ||
new InvalidJson( | ||
"Invalid JSON with raw unicode character", | ||
// javac will parse the 3-byte unicode control sequence, it will be passed to the parser as a raw unicode character | ||
a2q("{'validJson':'\u274c','right', 'here'}"), | ||
26, | ||
24, | ||
1, | ||
25 | ||
) | ||
); | ||
|
||
@ParameterizedTest | ||
@MethodSource("_generateTestData") | ||
public void testParserBackendWithInvalidJson(ParserVariant variant, InvalidJson invalidJson) | ||
throws Exception | ||
{ | ||
try (JsonParser parser = variant.createParser(invalidJson.input)) | ||
{ | ||
StreamReadException e = Assertions.assertThrows( | ||
StreamReadException.class, | ||
() -> { | ||
// Blindly advance the parser through the end of input | ||
while (parser.nextToken() != null) {} | ||
} | ||
); | ||
|
||
JsonLocation location = e.getLocation(); | ||
assertEquals(invalidJson.lineNr, location.getLineNr()); | ||
final String msg = e.getOriginalMessage(); | ||
|
||
if (variant.supportsByteOffset) | ||
{ | ||
assertEquals("Incorrect byte offset (for '"+msg+"')", | ||
invalidJson.byteOffset, location.getByteOffset()); | ||
} | ||
if (variant.supportsCharOffset) | ||
{ | ||
assertEquals("Incorrect char offset (for '"+msg+"')", | ||
invalidJson.charOffset, location.getCharOffset()); | ||
} | ||
if (variant.supportsColumnNr) | ||
{ | ||
assertEquals("Incorrect column (for '"+msg+"')", | ||
invalidJson.columnNr, location.getColumnNr()); | ||
} | ||
} | ||
} | ||
|
||
private static Stream<Arguments> _generateTestData() | ||
{ | ||
return Arrays.stream(ParserVariant.values()) | ||
.flatMap(parserVariant -> INVALID_JSON_CASES.stream().map( | ||
invalidJson -> Arguments.of(parserVariant, invalidJson) | ||
)); | ||
} | ||
|
||
@FunctionalInterface | ||
public interface ParserGenerator | ||
{ | ||
JsonParser createParser(String input) throws Exception; | ||
} | ||
|
||
static class InvalidJson | ||
{ | ||
InvalidJson(String name, String input, int byteOffset, int charOffset, | ||
int lineNr, int columnNr) | ||
{ | ||
_name = name; | ||
|
||
this.input = input; | ||
this.byteOffset = byteOffset; | ||
this.charOffset = charOffset; | ||
this.lineNr = lineNr; | ||
this.columnNr = columnNr; | ||
} | ||
|
||
@Override | ||
public String toString() | ||
{ | ||
return _name; | ||
} | ||
|
||
private final String _name; | ||
public final String input; | ||
public final int byteOffset; | ||
public final int charOffset; | ||
public final int lineNr; | ||
public final int columnNr; | ||
} | ||
} |