Skip to content

Commit 1ae43bd

Browse files
author
rikkarth
committed
fix(stleary#887): regressions, unit tests
- JSONArray now evaluates EOF accordingly for empty Array inputs. - JSONTokener fixed indentation - externalized two JSONMLTest cases
1 parent cf00ef3 commit 1ae43bd

File tree

8 files changed

+218
-81
lines changed

8 files changed

+218
-81
lines changed

src/main/java/org/json/JSONArray.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,13 @@ private void parseTokener(JSONTokener x, JSONParserConfiguration jsonParserConfi
136136
case ']':
137137
if (strictMode) {
138138
cursor = x.nextClean();
139-
boolean isNotEoF = !x.end();
139+
boolean isEoF = x.end();
140140

141-
if (isNotEoF && x.getArrayLevel() == 0) {
141+
if (isEoF) {
142+
break;
143+
}
144+
145+
if (x.getArrayLevel() == 0) {
142146
throw x.syntaxError(getInvalidCharErrorMsg(cursor));
143147
}
144148

src/main/java/org/json/JSONTokener.java

Lines changed: 56 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -325,77 +325,66 @@ public char nextClean() throws JSONException {
325325

326326

327327
/**
328-
* Return the characters up to the next close quote character.
329-
* Backslash processing is done. The formal JSON format does not
330-
* allow strings in single quotes, but an implementation is allowed to
331-
* accept them.
332-
* If strictMode is true, this implementation will not accept unbalanced quotes (e.g will not accept <code>"test'</code>).
328+
* Return the characters up to the next close quote character. Backslash processing is done. The formal JSON format
329+
* does not allow strings in single quotes, but an implementation is allowed to accept them.
330+
*
333331
* @param quote The quoting character, either
334332
* <code>"</code>&nbsp;<small>(double quote)</small> or
335333
* <code>'</code>&nbsp;<small>(single quote)</small>.
336-
* @param strictMode If true, this implementation will not accept unbalanced quotes (e.g will not accept <code>"test'</code>).
337334
* @return A String.
338335
* @throws JSONException Unterminated string or unbalanced quotes if strictMode == true.
339336
*/
340-
public String nextString(char quote, boolean strictMode) throws JSONException {
337+
public String nextString(char quote) throws JSONException {
341338
char c;
342339
StringBuilder sb = new StringBuilder();
343340
for (;;) {
344341
c = this.next();
345342
switch (c) {
346-
case 0:
347-
case '\n':
348-
case '\r':
349-
throw this.syntaxError("Unterminated string. " +
343+
case 0:
344+
case '\n':
345+
case '\r':
346+
throw this.syntaxError("Unterminated string. " +
350347
"Character with int code " + (int) c + " is not allowed within a quoted string.");
351-
case '\\':
352-
c = this.next();
353-
switch (c) {
354-
case 'b':
355-
sb.append('\b');
356-
break;
357-
case 't':
358-
sb.append('\t');
359-
break;
360-
case 'n':
361-
sb.append('\n');
362-
break;
363-
case 'f':
364-
sb.append('\f');
365-
break;
366-
case 'r':
367-
sb.append('\r');
368-
break;
369-
case 'u':
370-
String next = this.next(4);
371-
try {
372-
sb.append((char)Integer.parseInt(next, 16));
373-
} catch (NumberFormatException e) {
374-
throw this.syntaxError("Illegal escape. " +
375-
"\\u must be followed by a 4 digit hexadecimal number. \\" + next + " is not valid.", e);
376-
}
377-
break;
378-
case '"':
379-
case '\'':
380348
case '\\':
381-
case '/':
382-
sb.append(c);
349+
c = this.next();
350+
switch (c) {
351+
case 'b':
352+
sb.append('\b');
353+
break;
354+
case 't':
355+
sb.append('\t');
356+
break;
357+
case 'n':
358+
sb.append('\n');
359+
break;
360+
case 'f':
361+
sb.append('\f');
362+
break;
363+
case 'r':
364+
sb.append('\r');
365+
break;
366+
case 'u':
367+
String next = this.next(4);
368+
try {
369+
sb.append((char) Integer.parseInt(next, 16));
370+
} catch (NumberFormatException e) {
371+
throw this.syntaxError("Illegal escape. " +
372+
"\\u must be followed by a 4 digit hexadecimal number. \\" + next
373+
+ " is not valid.",
374+
e);
375+
}
376+
break;
377+
case '"':
378+
case '\'':
379+
case '\\':
380+
case '/':
381+
sb.append(c);
382+
break;
383+
default:
384+
throw this.syntaxError("Illegal escape. Escape sequence \\" + c + " is not valid.");
385+
}
383386
break;
384387
default:
385-
throw this.syntaxError("Illegal escape. Escape sequence \\" + c + " is not valid.");
386-
}
387-
break;
388-
default:
389-
if (strictMode && c == '\"' && quote != c) {
390-
throw this.syntaxError(String.format(
391-
"Field contains unbalanced quotes. Starts with %s but ends with double quote.", quote));
392-
}
393-
394-
if (strictMode && c == '\'' && quote != c) {
395-
throw this.syntaxError(String.format(
396-
"Field contains unbalanced quotes. Starts with %s but ends with single quote.", quote));
397-
}
398-
399388
if (c == quote) {
400389
return sb.toString();
401390
}
@@ -404,7 +393,6 @@ public String nextString(char quote, boolean strictMode) throws JSONException {
404393
}
405394
}
406395

407-
408396
/**
409397
* Get the text up but not including the specified character or the
410398
* end of line, whichever comes first.
@@ -528,15 +516,24 @@ private JSONArray getJsonArray() {
528516
}
529517
}
530518

519+
/**
520+
* Get the next simple value from the JSON input. Simple values include strings (wrapped in single or double
521+
* quotes), numbers, booleans, and null. This method is called when the next character is not '{' or '['.
522+
*
523+
* @param c The starting character.
524+
* @param jsonParserConfiguration The configuration object containing parsing options.
525+
* @return The parsed simple value.
526+
* @throws JSONException If there is a syntax error or the value does not adhere to the configuration rules.
527+
*/
531528
Object nextSimpleValue(char c, JSONParserConfiguration jsonParserConfiguration) {
532529
boolean strictMode = jsonParserConfiguration.isStrictMode();
533530

534-
if(strictMode && c == '\''){
531+
if (strictMode && c == '\'') {
535532
throw this.syntaxError("Single quote wrap not allowed in strict mode");
536533
}
537534

538535
if (c == '"' || c == '\'') {
539-
return this.nextString(c, strictMode);
536+
return this.nextString(c);
540537
}
541538

542539
return parsedUnquotedText(c, strictMode);

src/test/java/org/json/junit/CDLTest.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,12 @@ public class CDLTest {
2424
* String of lines where the column names are in the first row,
2525
* and all subsequent rows are values. All keys and values should be legal.
2626
*/
27-
// TODO: This regression causes several unit tests to fail in strictMode.
28-
// a single quote embedded in a valid st ring value should be allowed.
29-
// This probably needs to be fixed in the strictMode parser.
3027
private static final String LINES = "Col 1, Col 2, \tCol 3, Col 4, Col 5, Col 6, Col 7\n" +
3128
"val1, val2, val3, val4, val5, val6, val7\n" +
3229
"1, 2, 3, 4\t, 5, 6, 7\n" +
3330
"true, false, true, true, false, false, false\n" +
3431
"0.23, 57.42, 5e27, -234.879, 2.34e5, 0.0, 9e-3\n" +
35-
// "\"va\tl1\", \"v\bal2\", \"val3\", \"val\f4\", \"val5\", \"va'l6\", val7\n";
36-
"\"va\tl1\", \"v\bal2\", \"val3\", \"val\f4\", \"val5\", \"val6\", val7\n";
32+
"\"va\tl1\", \"v\bal2\", \"val3\", \"val\f4\", \"val5\", \"va'l6\", val7\n";
3733

3834
/**
3935
* CDL.toJSONArray() adds all values as strings, with no filtering or
@@ -46,8 +42,7 @@ public class CDLTest {
4642
"{\"Col 1\":\"1\", \"Col 2\":\"2\", \"Col 3\":\"3\", \"Col 4\":\"4\", \"Col 5\":\"5\", \"Col 6\":\"6\", \"Col 7\":\"7\"}, " +
4743
"{\"Col 1\":\"true\", \"Col 2\":\"false\", \"Col 3\":\"true\", \"Col 4\":\"true\", \"Col 5\":\"false\", \"Col 6\":\"false\", \"Col 7\":\"false\"}, " +
4844
"{\"Col 1\":\"0.23\", \"Col 2\":\"57.42\", \"Col 3\":\"5e27\", \"Col 4\":\"-234.879\", \"Col 5\":\"2.34e5\", \"Col 6\":\"0.0\", \"Col 7\":\"9e-3\"}, " +
49-
// "{\"Col 1\":\"va\tl1\", \"Col 2\":\"v\bal2\", \"Col 3\":\"val3\", \"Col 4\":\"val\f4\", \"Col 5\":\"val5\", \"Col 6\":\"va'l6\", \"Col 7\":\"val7\"}]";
50-
"{\"Col 1\":\"va\tl1\", \"Col 2\":\"v\bal2\", \"Col 3\":\"val3\", \"Col 4\":\"val\f4\", \"Col 5\":\"val5\", \"Col 6\":\"val6\", \"Col 7\":\"val7\"}]";
45+
"{\"Col 1\":\"va\tl1\", \"Col 2\":\"v\bal2\", \"Col 3\":\"val3\", \"Col 4\":\"val\f4\", \"Col 5\":\"val5\", \"Col 6\":\"va'l6\", \"Col 7\":\"val7\"}]";
5146

5247
/**
5348
* Attempts to create a JSONArray from a null string.

src/test/java/org/json/junit/JSONMLTest.java

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66

77
import static org.junit.Assert.*;
88

9+
import java.io.IOException;
10+
import java.nio.file.Files;
11+
import java.nio.file.Paths;
12+
import java.util.stream.Collectors;
13+
import java.util.stream.Stream;
914
import org.json.*;
1015
import org.junit.Test;
1116

@@ -648,16 +653,10 @@ public void toJSONObjectToJSONArray() {
648653
// create a JSON array from the original string and make sure it
649654
// looks as expected
650655
JSONArray jsonArray = JSONML.toJSONArray(xmlStr);
651-
// TODO: The next 2 test cases fail due to a strictMode regression. They should be isolated in separate
652-
// test cases and fixed.
653-
// JSONArray expectedJsonArray = new JSONArray(expectedJSONArrayStr);
654-
// Util.compareActualVsExpectedJsonArrays(jsonArray,expectedJsonArray);
655656

656657
// restore the XML, then make another JSONArray and make sure it
657658
// looks as expected
658659
String jsonArrayXmlToStr = JSONML.toString(jsonArray);
659-
// JSONArray finalJsonArray = JSONML.toJSONArray(jsonArrayXmlToStr);
660-
// Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray);
661660

662661
// lastly, confirm the restored JSONObject XML and JSONArray XML look
663662
// reasonably similar
@@ -666,6 +665,31 @@ public void toJSONObjectToJSONArray() {
666665
Util.compareActualVsExpectedJsonObjects(jsonObjectFromObject, jsonObjectFromArray);
667666
}
668667

668+
@Test
669+
public void givenXmlStr_testToJSONArray_shouldEqualExpectedArray() throws IOException {
670+
try (Stream<String> jsonLines = Files.lines(
671+
Paths.get("src/test/resources/JSONArrayExpectedTestCaseForToJsonArrayTest.json"));
672+
Stream<String> xmlLines = Files.lines(Paths.get("src/test/resources/XmlTestCaseTestToJsonArray.xml"))) {
673+
674+
String xmlStr = xmlLines.collect(Collectors.joining());
675+
String expectedJSONArrayStr = jsonLines.collect(Collectors.joining());
676+
677+
JSONArray jsonArray = JSONML.toJSONArray(xmlStr);
678+
JSONArray expectedJsonArray = new JSONArray(expectedJSONArrayStr);
679+
680+
assertEquals(expectedJsonArray.toString(), jsonArray.toString());
681+
//TODO Util.compareActualVsExpectedJsonArrays can be replaced with above assertEquals(expectedJsonArray.toString(), jsonArray.toString())
682+
Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
683+
684+
String jsonArrayXmlToStr = JSONML.toString(jsonArray);
685+
686+
JSONArray finalJsonArray = JSONML.toJSONArray(jsonArrayXmlToStr);
687+
688+
//TODO Util.compareActualVsExpectedJsonArrays can be replaced with assertEquals(expectedJsonArray.toString(), finalJsonArray.toString())
689+
Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray);
690+
}
691+
}
692+
669693
/**
670694
* Convert an XML document which contains embedded comments into
671695
* a JSONArray. Use JSONML.toString() to turn it into a string, then

src/test/java/org/json/junit/JSONParserConfigurationTest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,15 @@ public void givenInvalidInputArrays_testStrictModeTrue_shouldThrowJsonException(
4747
}
4848

4949
@Test
50-
public void givenEmptyArray_testStrictModeTrue_shouldNotThrowJsonException(){
50+
public void givenEmptyArray_testStrictModeTrue_shouldNotThrowJsonException() {
5151
JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration()
5252
.withStrictMode(true);
5353

5454
String testCase = "[]";
5555

5656
JSONArray jsonArray = new JSONArray(testCase, jsonParserConfiguration);
57-
System.out.println(jsonArray);
57+
58+
assertEquals(testCase, jsonArray.toString());
5859
}
5960

6061
@Test
@@ -215,7 +216,7 @@ public void givenNonCompliantQuotes_testStrictModeTrue_shouldThrowJsonExceptionW
215216
() -> new JSONArray(testCaseFour, jsonParserConfiguration));
216217

217218
assertEquals(
218-
"Field contains unbalanced quotes. Starts with \" but ends with single quote. at 6 [character 7 line 1]",
219+
"Value 'test' is not surrounded by quotes at 13 [character 14 line 1]",
219220
jeOne.getMessage());
220221
assertEquals(
221222
"Single quote wrap not allowed in strict mode at 2 [character 3 line 1]",

src/test/java/org/json/junit/JSONTokenerTest.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,9 @@ public void testValid() {
9494
checkValid(" {} ",JSONObject.class);
9595
checkValid("{\"a\":1}",JSONObject.class);
9696
checkValid(" {\"a\":1} ",JSONObject.class);
97-
// TODO: strictMode regression, needs to be fixed.
98-
// checkValid("[]",JSONArray.class);
97+
checkValid("[]",JSONArray.class);
9998
checkValid(" [] ",JSONArray.class);
100-
// TODO: strictMode regression, needs to be fixed
101-
// checkValid("[1,2]",JSONArray.class);
99+
checkValid("[1,2]",JSONArray.class);
102100
checkValid("\n\n[1,2]\n\n",JSONArray.class);
103101
// TODO: strictMode regression, needs to be fixed
104102
// checkValid("1 2", String.class);
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
[
2+
"addresses",
3+
{
4+
"xsi:noNamespaceSchemaLocation": "test.xsd",
5+
"xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance"
6+
},
7+
[
8+
"address",
9+
{
10+
"addrType": "my address"
11+
},
12+
[
13+
"name",
14+
{
15+
"nameType": "my name"
16+
},
17+
"Joe Tester"
18+
],
19+
[
20+
"street",
21+
"Baker street 5"
22+
],
23+
[
24+
"NothingHere",
25+
{
26+
"except": "an attribute"
27+
}
28+
],
29+
[
30+
"TrueValue",
31+
true
32+
],
33+
[
34+
"FalseValue",
35+
false
36+
],
37+
[
38+
"NullValue",
39+
null
40+
],
41+
[
42+
"PositiveValue",
43+
42
44+
],
45+
[
46+
"NegativeValue",
47+
-23
48+
],
49+
[
50+
"DoubleValue",
51+
-23.45
52+
],
53+
[
54+
"Nan",
55+
"-23x.45"
56+
],
57+
[
58+
"ArrayOfNum",
59+
[
60+
"value",
61+
1
62+
],
63+
[
64+
"value",
65+
2
66+
],
67+
[
68+
"value",
69+
[
70+
"subValue",
71+
{
72+
"svAttr": "svValue"
73+
},
74+
"abc"
75+
]
76+
],
77+
[
78+
"value",
79+
3
80+
],
81+
[
82+
"value",
83+
4.1
84+
],
85+
[
86+
"value",
87+
5.2
88+
]
89+
]
90+
]
91+
]

0 commit comments

Comments
 (0)