AsyncPropertyName0xFF1784Test.java
package tools.jackson.core.unittest.async;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import tools.jackson.core.*;
import tools.jackson.core.exc.StreamReadException;
import tools.jackson.core.json.JsonFactory;
import tools.jackson.core.json.JsonReadFeature;
import tools.jackson.core.unittest.testutil.AsyncReaderWrapper;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Tests for [jackson-core#1784]: non-blocking variant of
* {@code tools.jackson.core.unittest.read.PropertyName0xFF1784Test}.
*/
class AsyncPropertyName0xFF1784Test extends AsyncTestBase
{
enum Variant {
BYTE_ARRAY, BYTE_BUFFER;
AsyncReaderWrapper wrap(JsonFactory f, int bytesPerRead, byte[] data)
{
switch (this) {
case BYTE_ARRAY: return asyncForBytes(f, bytesPerRead, data, 0);
case BYTE_BUFFER: return asyncForByteBuffer(f, bytesPerRead, data, 0);
default: throw new IllegalStateException();
}
}
}
// Lengths 1, 3, 4, 6 and 9 give last quads of 1, 3, 4, 2 and 1 bytes
private static final String[] NAMES = { "a", "abc", "abcd", "abcdef", "abcdefghi" };
private static final int[] BYTES_PER_READ = { 1, 2, 3, 1000 };
private final JsonFactory APOS_FACTORY = JsonFactory.builder()
.enable(JsonReadFeature.ALLOW_SINGLE_QUOTES)
.build();
private final JsonFactory UNQUOTED_FACTORY = JsonFactory.builder()
.enable(JsonReadFeature.ALLOW_UNQUOTED_PROPERTY_NAMES)
.build();
@ParameterizedTest
@EnumSource(Variant.class)
void ffAfterSameNameInDocument(Variant v) throws Exception
{
for (int bpr : BYTES_PER_READ) {
for (String name : NAMES) {
for (int pos = 0; pos <= name.length(); ++pos) {
String invalid = withFF(name, pos);
_verifyRejected(v, newStreamFactory(), bpr, name, invalid, "\"");
_verifyRejected(v, APOS_FACTORY, bpr, name, invalid, "'");
if (pos > 0) { // unquoted name cannot start with 0xFF
_verifyRejected(v, UNQUOTED_FACTORY, bpr, name, invalid, "");
}
}
}
}
}
@ParameterizedTest
@EnumSource(Variant.class)
void ffAfterSameNameInEarlierDocument(Variant v) throws Exception
{
for (int bpr : BYTES_PER_READ) {
for (String name : NAMES) {
JsonFactory f = newStreamFactory();
try (AsyncReaderWrapper r = v.wrap(f, bpr, doc("{\"" + name + "\":1}"))) {
while (r.nextToken() != null) { }
}
try (AsyncReaderWrapper r = v.wrap(f, bpr,
doc("{\"" + withFF(name, name.length() - 1) + "\":2}"))) {
assertToken(JsonToken.START_OBJECT, r.nextToken());
r.nextToken();
fail("Should not pass, got name '" + r.currentName() + "'");
} catch (StreamReadException e) {
verifyException(e, "Invalid UTF-8 start byte 0xff");
}
}
}
}
private void _verifyRejected(Variant v, JsonFactory f, int bpr, String name, String invalid, String q)
throws Exception
{
try (AsyncReaderWrapper r = v.wrap(f, bpr, doc("{" + q + name + q + ":1," + q + invalid + q + ":2}"))) {
assertToken(JsonToken.START_OBJECT, r.nextToken());
assertToken(JsonToken.PROPERTY_NAME, r.nextToken());
assertEquals(name, r.currentName());
assertToken(JsonToken.VALUE_NUMBER_INT, r.nextToken());
r.nextToken();
fail("Should not pass, got name '" + r.currentName() + "'");
} catch (StreamReadException e) {
verifyException(e, "Invalid UTF-8 start byte 0xff");
}
}
// '~' in result marks the 0xFF byte, see doc()
private static String withFF(String name, int pos) {
return new StringBuilder(name).insert(pos, '~').toString();
}
private static byte[] doc(String json) {
return json.replace('~', '��').getBytes(java.nio.charset.StandardCharsets.ISO_8859_1);
}
}