AsyncSignedNumberTest.java
package tools.jackson.core.unittest.json.async;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;
import tools.jackson.core.json.JsonFactory;
import tools.jackson.core.JsonToken;
import tools.jackson.core.unittest.async.AsyncTestBase;
import tools.jackson.core.json.JsonReadFeature;
import tools.jackson.core.unittest.testutil.AsyncReaderWrapper;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Tests that the non-blocking parser decodes signed numbers to correct values,
* with same text as blocking parsers (sign retained, [core#784]),
* regardless of chunking.
*/
class AsyncSignedNumberTest extends AsyncTestBase
{
private final JsonFactory F = JsonFactory.builder()
.enable(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS)
.enable(JsonReadFeature.ALLOW_LEADING_ZEROS_FOR_NUMBERS)
.build();
private final static int[] BYTES_PER_READ = { 1, 2, 3, 5, 100 };
@Test
void signedZeroInArray() throws Exception
{
_testInArray("+0", JsonToken.VALUE_NUMBER_INT, "+0", 0.0);
_testInArray("-0", JsonToken.VALUE_NUMBER_INT, "-0", 0.0);
_testInArray("+00", JsonToken.VALUE_NUMBER_INT, "+0", 0.0);
_testInArray("-00", JsonToken.VALUE_NUMBER_INT, "-0", 0.0);
_testInArray("+05", JsonToken.VALUE_NUMBER_INT, "+5", 5.0);
_testInArray("+0.5", JsonToken.VALUE_NUMBER_FLOAT, "+0.5", 0.5);
_testInArray("-0.5", JsonToken.VALUE_NUMBER_FLOAT, "-0.5", -0.5);
_testInArray("+0e2", JsonToken.VALUE_NUMBER_FLOAT, "+0e2", 0.0);
}
// Root-level value ending at end-of-input
@Test
void signedZeroAtRootEOF() throws Exception
{
_testAtRoot("+0", "+0", 0);
_testAtRoot("-0", "-0", 0);
_testAtRoot("0", "0", 0);
}
// 18/19-digit values exercise the long fast paths of number decoding
@Test
void longValuesWithPlusSign() throws Exception
{
_testLong("+999999999999999999", 999999999999999999L);
_testLong("+0999999999999999999", 999999999999999999L);
_testLong("+1000000000000000000", 1000000000000000000L);
_testLong("+9223372036854775807", Long.MAX_VALUE);
_testLong("-999999999999999999", -999999999999999999L);
_testLong("-0999999999999999999", -999999999999999999L);
_testLong("+2147483648", 2147483648L);
}
@Test
void bigIntegerWithPlusSign() throws Exception
{
final String json = "[+9223372036854775808]";
for (int bytesPerRead : BYTES_PER_READ) {
for (boolean bb : new boolean[] { false, true }) {
AsyncReaderWrapper p = _parser(json, bytesPerRead, bb);
assertToken(JsonToken.START_ARRAY, p.nextToken());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(new BigInteger("9223372036854775808"), p.getBigIntegerValue());
assertToken(JsonToken.END_ARRAY, p.nextToken());
p.close();
}
}
}
private void _testLong(String value, long exp) throws Exception
{
final String json = "[" + value + "]";
for (int bytesPerRead : BYTES_PER_READ) {
for (boolean bb : new boolean[] { false, true }) {
AsyncReaderWrapper p = _parser(json, bytesPerRead, bb);
assertToken(JsonToken.START_ARRAY, p.nextToken());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(exp, p.getLongValue(), "for " + json + ", " + bytesPerRead + " bytes/read");
// sign retained in text, but leading zeroes trimmed
assertEquals((value.startsWith("+") ? "+" : "") + exp, p.currentText());
assertToken(JsonToken.END_ARRAY, p.nextToken());
p.close();
}
}
}
private void _testInArray(String value, JsonToken expToken, String expText,
double expValue) throws Exception
{
final String json = "[" + value + "]";
for (int bytesPerRead : BYTES_PER_READ) {
for (boolean bb : new boolean[] { false, true }) {
AsyncReaderWrapper p = _parser(json, bytesPerRead, bb);
assertToken(JsonToken.START_ARRAY, p.nextToken());
assertToken(expToken, p.nextToken());
assertEquals(expText, p.currentText(), "for " + json + ", " + bytesPerRead + " bytes/read");
assertEquals(expValue, p.getDoubleValue());
assertToken(JsonToken.END_ARRAY, p.nextToken());
p.close();
}
}
}
private void _testAtRoot(String json, String expText, int expValue) throws Exception
{
for (int bytesPerRead : BYTES_PER_READ) {
for (boolean bb : new boolean[] { false, true }) {
AsyncReaderWrapper p = _parser(json, bytesPerRead, bb);
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(expText, p.currentText(), "for " + json + ", " + bytesPerRead + " bytes/read");
assertEquals(expValue, p.getIntValue());
p.close();
}
}
}
private AsyncReaderWrapper _parser(String json, int bytesPerRead, boolean bb)
throws Exception
{
byte[] doc = json.getBytes(StandardCharsets.UTF_8);
return bb ? asyncForByteBuffer(F, bytesPerRead, doc, 0)
: asyncForBytes(F, bytesPerRead, doc, 0);
}
}