AsyncNonStdParsingTest.java
package com.fasterxml.jackson.core.json.async;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.async.AsyncTestBase;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.testsupport.AsyncReaderWrapper;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
class AsyncNonStdParsingTest extends AsyncTestBase
{
@Test
void largeUnquotedNames() throws Exception
{
final JsonFactory f = JsonFactory.builder()
.enable(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES)
.build();
StringBuilder sb = new StringBuilder(5000);
sb.append("[\n");
final int REPS = 1050;
for (int i = 0; i < REPS; ++i) {
if (i > 0) {
sb.append(',');
if ((i & 7) == 0) {
sb.append('\n');
}
}
sb.append("{");
sb.append("abc").append(i&127).append(':');
sb.append((i & 1) != 0);
sb.append("}\n");
}
sb.append("]");
String doc = sb.toString();
_testLargeUnquoted(f, REPS, doc, 0, 99);
_testLargeUnquoted(f, REPS, doc, 0, 5);
_testLargeUnquoted(f, REPS, doc, 0, 3);
_testLargeUnquoted(f, REPS, doc, 0, 2);
_testLargeUnquoted(f, REPS, doc, 0, 1);
_testLargeUnquoted(f, REPS, doc, 1, 99);
_testLargeUnquoted(f, REPS, doc, 1, 1);
}
private void _testLargeUnquoted(JsonFactory f, int reps, String doc,
int offset, int readSize) throws Exception
{
AsyncReaderWrapper p = createParser(f, doc, offset, readSize);
assertToken(JsonToken.START_ARRAY, p.nextToken());
for (int i = 0; i < reps; ++i) {
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("abc"+(i&127), p.currentName());
assertToken(((i&1) != 0) ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE, p.nextToken());
assertToken(JsonToken.END_OBJECT, p.nextToken());
}
assertToken(JsonToken.END_ARRAY, p.nextToken());
p.close();
}
@Test
void simpleUnquotedNames() throws Exception
{
final JsonFactory f = JsonFactory.builder()
.enable(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES)
.build();
_testSimpleUnquoted(f, 0, 99);
_testSimpleUnquoted(f, 0, 5);
_testSimpleUnquoted(f, 0, 3);
_testSimpleUnquoted(f, 0, 2);
_testSimpleUnquoted(f, 0, 1);
_testSimpleUnquoted(f, 1, 99);
_testSimpleUnquoted(f, 1, 3);
_testSimpleUnquoted(f, 1, 1);
}
private void _testSimpleUnquoted(JsonFactory f,
int offset, int readSize) throws Exception
{
String doc = "{ a : 1, _foo:true, $:\"money!\", \" \":null }";
AsyncReaderWrapper p = createParser(f, doc, offset, readSize);
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("a", p.currentName());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("_foo", p.currentName());
assertToken(JsonToken.VALUE_TRUE, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("$", p.currentName());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("money!", p.currentText());
// and then regular quoted one should still work too:
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals(" ", p.currentName());
assertToken(JsonToken.VALUE_NULL, p.nextToken());
assertToken(JsonToken.END_OBJECT, p.nextToken());
p.close();
// Another thing, as per [jackson-cre#102]: numbers
p = createParser(f, "{ 123:true,4:false }", offset, readSize);
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("123", p.currentName());
assertToken(JsonToken.VALUE_TRUE, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("4", p.currentName());
assertToken(JsonToken.VALUE_FALSE, p.nextToken());
assertToken(JsonToken.END_OBJECT, p.nextToken());
p.close();
}
/**
* Test to verify that the default parser settings do not
* accept single-quotes for String values (field names,
* textual values)
*/
@Test
void aposQuotingDisabled() throws Exception
{
JsonFactory f = new JsonFactory();
_testSingleQuotesDefault(f, 0, 99);
_testSingleQuotesDefault(f, 0, 5);
_testSingleQuotesDefault(f, 0, 3);
_testSingleQuotesDefault(f, 0, 1);
_testSingleQuotesDefault(f, 1, 99);
_testSingleQuotesDefault(f, 1, 1);
}
private void _testSingleQuotesDefault(JsonFactory f,
int offset, int readSize) throws Exception
{
// First, let's see that by default they are not allowed
String JSON = "[ 'text' ]";
AsyncReaderWrapper p = createParser(f, JSON, offset, readSize);
assertToken(JsonToken.START_ARRAY, p.nextToken());
try {
p.nextToken();
fail("Expected exception");
} catch (JsonParseException e) {
verifyException(e, "Unexpected character ('''");
} finally {
p.close();
}
JSON = "{ 'a':1 }";
p = createParser(f, JSON, offset, readSize);
assertToken(JsonToken.START_OBJECT, p.nextToken());
try {
p.nextToken();
fail("Expected exception");
} catch (JsonParseException e) {
verifyException(e, "Unexpected character ('''");
} finally {
p.close();
}
}
/**
* Test to verify optional handling of
* single quotes, to allow handling invalid (but, alas, common)
* JSON.
*/
@Test
void aposQuotingEnabled() throws Exception
{
final JsonFactory f = JsonFactory.builder()
.enable(JsonReadFeature.ALLOW_SINGLE_QUOTES)
.build();
_testAposQuotingEnabled(f, 0, 99);
_testAposQuotingEnabled(f, 0, 5);
_testAposQuotingEnabled(f, 0, 3);
_testAposQuotingEnabled(f, 0, 2);
_testAposQuotingEnabled(f, 0, 1);
_testAposQuotingEnabled(f, 1, 99);
_testAposQuotingEnabled(f, 2, 1);
_testAposQuotingEnabled(f, 1, 1);
}
private void _testAposQuotingEnabled(JsonFactory f,
int offset, int readSize) throws Exception
{
String UNINAME = String.format("Uni%c-key-%c", UNICODE_2BYTES, UNICODE_3BYTES);
String UNIVALUE = String.format("Uni%c-value-%c", UNICODE_3BYTES, UNICODE_2BYTES);
String JSON = String.format(
"{ 'a' : 1, \"foobar\": 'b', '_abcde1234':'d', '\"' : '\"\"', '':'', '%s':'%s'}",
UNINAME, UNIVALUE);
AsyncReaderWrapper p = createParser(f, JSON, offset, readSize);
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("a", p.currentText());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals("1", p.currentText());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("foobar", p.currentText());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("b", p.currentText());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("_abcde1234", p.currentText());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("d", p.currentText());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("\"", p.currentText());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("\"\"", p.currentText());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("", p.currentText());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("", p.currentText());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals(UNINAME, p.currentText());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals(UNIVALUE, p.currentText());
assertToken(JsonToken.END_OBJECT, p.nextToken());
p.close();
JSON = "{'b':1,'array':[{'b':3}],'ob':{'b':4,'x':0,'y':'"+UNICODE_SEGMENT+"','a':false }}";
p = createParser(f, JSON, offset, readSize);
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("b", p.currentName());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertToken(JsonToken.START_ARRAY, p.nextToken());
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("b", p.currentName());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(3, p.getIntValue());
assertToken(JsonToken.END_OBJECT, p.nextToken());
assertToken(JsonToken.END_ARRAY, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("b", p.currentName());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(4, p.getIntValue());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("x", p.currentName());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(0, p.getIntValue());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("y", p.currentName());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals(UNICODE_SEGMENT, p.currentText());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("a", p.currentName());
assertToken(JsonToken.VALUE_FALSE, p.nextToken());
assertToken(JsonToken.END_OBJECT, p.nextToken());
assertToken(JsonToken.END_OBJECT, p.nextToken());
p.close();
}
// test to verify that we implicitly allow escaping of apostrophe
@Test
void singleQuotesEscaped() throws Exception
{
final JsonFactory f = JsonFactory.builder()
.enable(JsonReadFeature.ALLOW_SINGLE_QUOTES)
.build();
_testSingleQuotesEscaped(f, 0, 99);
_testSingleQuotesEscaped(f, 0, 5);
_testSingleQuotesEscaped(f, 0, 3);
_testSingleQuotesEscaped(f, 0, 1);
_testSingleQuotesEscaped(f, 1, 99);
_testSingleQuotesEscaped(f, 1, 1);
}
private void _testSingleQuotesEscaped(JsonFactory f,
int offset, int readSize) throws Exception
{
String JSON = "[ '16\\'' ]";
AsyncReaderWrapper p = createParser(f, JSON, offset, readSize);
assertToken(JsonToken.START_ARRAY, p.nextToken());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("16'", p.currentText());
assertToken(JsonToken.END_ARRAY, p.nextToken());
p.close();
}
@Test
void nonStandardNameChars() throws Exception
{
final JsonFactory f = JsonFactory.builder()
.enable(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES)
.build();
_testNonStandardNameChars(f, 0, 99);
_testNonStandardNameChars(f, 0, 6);
_testNonStandardNameChars(f, 0, 3);
_testNonStandardNameChars(f, 0, 1);
_testNonStandardNameChars(f, 1, 99);
_testNonStandardNameChars(f, 2, 1);
}
private void _testNonStandardNameChars(JsonFactory f,
int offset, int readSize) throws Exception
{
String JSON = "{ @type : \"mytype\", #color : 123, *error* : true, "
+" hyphen-ated : \"yes\", me+my : null"
+"}";
AsyncReaderWrapper p = createParser(f, JSON, offset, readSize);
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("@type", p.currentText());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("mytype", p.currentText());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("#color", p.currentText());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(123, p.getIntValue());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("*error*", p.currentText());
assertToken(JsonToken.VALUE_TRUE, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("hyphen-ated", p.currentText());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("yes", p.currentText());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertEquals("me+my", p.currentText());
assertToken(JsonToken.VALUE_NULL, p.nextToken());
assertToken(JsonToken.END_OBJECT, p.nextToken());
p.close();
}
@Test
void nonStandarBackslashQuotingForValues() throws Exception
{
_testNonStandarBackslashQuoting(0, 99);
_testNonStandarBackslashQuoting(0, 6);
_testNonStandarBackslashQuoting(0, 3);
_testNonStandarBackslashQuoting(0, 1);
_testNonStandarBackslashQuoting(2, 99);
_testNonStandarBackslashQuoting(1, 1);
}
private void _testNonStandarBackslashQuoting(
int offset, int readSize) throws Exception
{
// first: verify that we get an exception
JsonFactory f = new JsonFactory();
final String JSON = q("\\'");
AsyncReaderWrapper p = createParser(f, JSON, offset, readSize);
try {
p.nextToken();
p.currentText();
fail("Should have thrown an exception for doc <"+JSON+">");
} catch (JsonParseException e) {
verifyException(e, "unrecognized character escape");
} finally {
p.close();
}
// and then verify it's ok...
f = f.rebuild()
.enable(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER)
.build();
p = createParser(f, JSON, offset, readSize);
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("'", p.currentText());
p.close();
}
private AsyncReaderWrapper createParser(JsonFactory f, String doc,
int offset, int readSize) throws IOException
{
return asyncForBytes(f, readSize, _jsonDoc(doc), offset);
}
}