blob: 0a2943d270a3cfb3889e4f68a0ef9ee35f2c3cf0 [file] [log] [blame]
package org.codehaus.jackson.impl;
import org.codehaus.jackson.*;
public class TestParserNonStandard
extends main.BaseTest
{
// // // And then tests to verify [JACKSON-69]:
public void testSimpleUnquoted() throws Exception
{
_testSimpleUnquoted(false);
_testSimpleUnquoted(true);
}
public void testLargeUnquoted() throws Exception
{
_testLargeUnquoted(false);
_testLargeUnquoted(true);
}
public void testSingleQuotesDefault() throws Exception
{
_testSingleQuotesDefault(false);
_testSingleQuotesDefault(true);
}
public void testSingleQuotesEnabled() throws Exception
{
_testSingleQuotesEnabled(false);
_testSingleQuotesEnabled(true);
_testSingleQuotesEscaped(false);
_testSingleQuotesEscaped(true);
}
// Test for [JACKSON-267], allowing '@' as name char, for unquoted names
public void testNonStandardNameChars() throws Exception
{
_testNonStandardNameChars(false);
_testNonStandardNameChars(true);
}
// Test for [JACKSON-300]
public void testNonStandardAnyCharQuoting() throws Exception
{
_testNonStandarBackslashQuoting(false);
_testNonStandarBackslashQuoting(true);
}
// Test for [JACKSON-358]
public void testLeadingZeroesUTF8() throws Exception {
_testLeadingZeroes(true, false);
_testLeadingZeroes(true, true);
}
public void testLeadingZeroesReader() throws Exception {
_testLeadingZeroes(false, false);
_testLeadingZeroes(false, true);
}
// [JACKSON-142]: allow NaN
public void testAllowNaN() throws Exception {
_testAllowNaN(false);
_testAllowNaN(true);
}
// [JACKSON-142]: allow +Inf/-Inf
public void testAllowInfinity() throws Exception {
_testAllowInf(false);
_testAllowInf(true);
}
/*
/****************************************************************
/* Secondary test methods
/****************************************************************
*/
private void _testLargeUnquoted(boolean useStream) throws Exception
{
StringBuilder sb = new StringBuilder(5000);
sb.append("[\n");
//final int REPS = 2000;
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 JSON = sb.toString();
JsonFactory f = new JsonFactory();
f.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
JsonParser jp = useStream ?
createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON)
;
assertToken(JsonToken.START_ARRAY, jp.nextToken());
for (int i = 0; i < REPS; ++i) {
assertToken(JsonToken.START_OBJECT, jp.nextToken());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("abc"+(i&127), jp.getCurrentName());
assertToken(((i&1) != 0) ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE, jp.nextToken());
assertToken(JsonToken.END_OBJECT, jp.nextToken());
}
assertToken(JsonToken.END_ARRAY, jp.nextToken());
}
private void _testSimpleUnquoted(boolean useStream) throws Exception
{
final String JSON = "{ a : 1, _foo:true, $:\"money!\", \" \":null }";
JsonFactory f = new JsonFactory();
f.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
JsonParser jp = useStream ?
createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON)
;
assertToken(JsonToken.START_OBJECT, jp.nextToken());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("a", jp.getCurrentName());
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("_foo", jp.getCurrentName());
assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("$", jp.getCurrentName());
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
assertEquals("money!", jp.getText());
// and then regular quoted one should still work too:
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals(" ", jp.getCurrentName());
assertToken(JsonToken.VALUE_NULL, jp.nextToken());
assertToken(JsonToken.END_OBJECT, jp.nextToken());
}
/**
* Test to verify that the default parser settings do not
* accept single-quotes for String values (field names,
* textual values)
*/
private void _testSingleQuotesDefault(boolean useStream) throws Exception
{
JsonFactory f = new JsonFactory();
// First, let's see that by default they are not allowed
String JSON = "[ 'text' ]";
JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.START_ARRAY, jp.nextToken());
try {
jp.nextToken();
fail("Expected exception");
} catch (JsonParseException e) {
verifyException(e, "Unexpected character ('''");
}
JSON = "{ 'a':1 }";
jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.START_OBJECT, jp.nextToken());
try {
jp.nextToken();
fail("Expected exception");
} catch (JsonParseException e) {
verifyException(e, "Unexpected character ('''");
}
}
/**
* Test to verify [JACKSON-173], optional handling of
* single quotes, to allow handling invalid (but, alas, common)
* JSON.
*/
private void _testSingleQuotesEnabled(boolean useStream) throws Exception
{
JsonFactory f = new JsonFactory();
f.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
String JSON = "{ 'a' : 1, \"foobar\": 'b', '_abcde1234':'d', '\"' : '\"\"', '':'' }";
JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.START_OBJECT, jp.nextToken());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("a", jp.getText());
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
assertEquals("1", jp.getText());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("foobar", jp.getText());
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
assertEquals("b", jp.getText());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("_abcde1234", jp.getText());
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
assertEquals("d", jp.getText());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("\"", jp.getText());
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
//assertEquals("\"\"", jp.getText());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("", jp.getText());
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
assertEquals("", jp.getText());
assertToken(JsonToken.END_OBJECT, jp.nextToken());
}
// test to verify that we implicitly allow escaping of apostrophe [JACKSON-548]
private void _testSingleQuotesEscaped(boolean useStream) throws Exception
{
JsonFactory f = new JsonFactory();
f.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
String JSON = "[ '16\\'' ]";
JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.START_ARRAY, jp.nextToken());
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
assertEquals("16'", jp.getText());
assertToken(JsonToken.END_ARRAY, jp.nextToken());
}
private void _testNonStandardNameChars(boolean useStream) throws Exception
{
JsonFactory f = new JsonFactory();
f.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
String JSON = "{ @type : \"mytype\", #color : 123, *error* : true, "
+" hyphen-ated : \"yes\", me+my : null"
+"}";
JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.START_OBJECT, jp.nextToken());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("@type", jp.getText());
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
assertEquals("mytype", jp.getText());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("#color", jp.getText());
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
assertEquals(123, jp.getIntValue());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("*error*", jp.getText());
assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("hyphen-ated", jp.getText());
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
assertEquals("yes", jp.getText());
assertToken(JsonToken.FIELD_NAME, jp.nextToken());
assertEquals("me+my", jp.getText());
assertToken(JsonToken.VALUE_NULL, jp.nextToken());
assertToken(JsonToken.END_OBJECT, jp.nextToken());
jp.close();
}
private void _testNonStandarBackslashQuoting(boolean useStream) throws Exception
{
// first: verify that we get an exception
JsonFactory f = new JsonFactory();
assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER));
final String JSON = quote("\\'");
JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
try {
jp.nextToken();
jp.getText();
fail("Should have thrown an exception for doc <"+JSON+">");
} catch (JsonParseException e) {
verifyException(e, "unrecognized character escape");
}
// and then verify it's ok...
f.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
assertTrue(f.isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER));
jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
assertEquals("'", jp.getText());
}
private void _testLeadingZeroes(boolean useStream, boolean appendSpace) throws Exception
{
// first: verify that we get an exception
JsonFactory f = new JsonFactory();
assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS));
String JSON = "00003";
if (appendSpace) {
JSON += " ";
}
JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
try {
jp.nextToken();
jp.getText();
fail("Should have thrown an exception for doc <"+JSON+">");
} catch (JsonParseException e) {
verifyException(e, "invalid numeric value");
}
// and then verify it's ok when enabled
f.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
assertTrue(f.isEnabled(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS));
jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
assertEquals(3, jp.getIntValue());
assertEquals("3", jp.getText());
jp.close();
// Plus, also: verify that leading zero magnitude is ok:
JSON = "0"+Integer.MAX_VALUE;
if (appendSpace) {
JSON += " ";
}
jp = useStream ? createParserUsingStream(f, JSON, "UTF-8") : createParserUsingReader(f, JSON);
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
assertEquals(String.valueOf(Integer.MAX_VALUE), jp.getText());
assertEquals(Integer.MAX_VALUE, jp.getIntValue());
Number nr = jp.getNumberValue();
assertSame(Integer.class, nr.getClass());
jp.close();
}
private void _testAllowNaN(boolean useStream) throws Exception
{
final String JSON = "[ NaN]";
JsonFactory f = new JsonFactory();
assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS));
// without enabling, should get an exception
JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.START_ARRAY, jp.nextToken());
try {
jp.nextToken();
fail("Expected exception");
} catch (Exception e) {
verifyException(e, "non-standard");
}
// we can enable it dynamically (impl detail)
f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.START_ARRAY, jp.nextToken());
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
double d = jp.getDoubleValue();
assertTrue(Double.isNaN(d));
assertEquals("NaN", jp.getText());
assertToken(JsonToken.END_ARRAY, jp.nextToken());
jp.close();
// finally, should also work with skipping
f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.START_ARRAY, jp.nextToken());
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
assertToken(JsonToken.END_ARRAY, jp.nextToken());
jp.close();
}
private void _testAllowInf(boolean useStream) throws Exception
{
final String JSON = "[ -INF, +INF, +Infinity,-Infinity ]";
JsonFactory f = new JsonFactory();
assertFalse(f.isEnabled(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS));
// without enabling, should get an exception
JsonParser jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.START_ARRAY, jp.nextToken());
try {
jp.nextToken();
fail("Expected exception");
} catch (Exception e) {
verifyException(e, "Non-standard token '-INF'");
}
f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.START_ARRAY, jp.nextToken());
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
double d = jp.getDoubleValue();
assertEquals("-INF", jp.getText());
assertTrue(Double.isInfinite(d));
assertTrue(d == Double.NEGATIVE_INFINITY);
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
d = jp.getDoubleValue();
assertEquals("+INF", jp.getText());
assertTrue(Double.isInfinite(d));
assertTrue(d == Double.POSITIVE_INFINITY);
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
d = jp.getDoubleValue();
assertEquals("+Infinity", jp.getText());
assertTrue(Double.isInfinite(d));
assertTrue(d == Double.POSITIVE_INFINITY);
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
d = jp.getDoubleValue();
assertEquals("-Infinity", jp.getText());
assertTrue(Double.isInfinite(d));
assertTrue(d == Double.NEGATIVE_INFINITY);
assertToken(JsonToken.END_ARRAY, jp.nextToken());
jp.close();
// finally, should also work with skipping
f.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
jp = useStream ? createParserUsingStream(f, JSON, "UTF-8")
: createParserUsingReader(f, JSON);
assertToken(JsonToken.START_ARRAY, jp.nextToken());
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
assertToken(JsonToken.END_ARRAY, jp.nextToken());
jp.close();
}
}