[Git][java-team/openjson][upstream] New upstream version 1.0.13

Tony Mancill (@tmancill) gitlab at salsa.debian.org
Sun Jul 2 01:45:25 BST 2023



Tony Mancill pushed to branch upstream at Debian Java Maintainers / openjson


Commits:
8072e7c4 by tony mancill at 2023-07-01T17:09:03-07:00
New upstream version 1.0.13
- - - - -


7 changed files:

- README.md
- pom.xml
- src/main/java/com/github/openjson/JSONTokener.java
- src/test/java/com/github/openjson/JSONFunctionTestObject.java
- src/test/java/com/github/openjson/JSONTokenerTest.java
- src/test/java/com/github/openjson/SelfUseTest.java
- + src/test/java/com/github/openjson/issues/Issue18Test.java


Changes:

=====================================
README.md
=====================================
@@ -1,4 +1,4 @@
-# Open JSON [![Build Status](https://travis-ci.org/openjson/openjson.svg?branch=master)](https://travis-ci.org/openjson/openjson) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
+# Open JSON [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
 
 This code is extracted from the Android project to allow
 a clean-room implementation of the popular JSON API to be


=====================================
pom.xml
=====================================
@@ -6,7 +6,7 @@
 
     <groupId>com.github.openjson</groupId>
     <artifactId>openjson</artifactId>
-    <version>1.0.12</version>
+    <version>1.0.13</version>
 
     <packaging>jar</packaging>
     <name>Open JSON</name>
@@ -43,7 +43,7 @@
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
-            <version>4.12</version>
+            <version>4.13.2</version>
             <scope>test</scope>
         </dependency>
     </dependencies>


=====================================
src/main/java/com/github/openjson/JSONTokener.java
=====================================
@@ -35,8 +35,8 @@ import java.io.Reader;
  * String query = object.getString("query");
  * JSONArray locations = object.getJSONArray("locations");</pre>
  *
- * <p>For best interoperability and performance use JSON that complies with
- * RFC 4627, such as that generated by {@link JSONStringer}. For legacy reasons
+ * <p>For the best interoperability and performance use JSON that complies with
+ * RFC 4627, such as that generated by {@link JSONStringer}. For legacy reasons,
  * this parser is lenient, so a successful parse does not indicate that the
  * input string was valid JSON. All of the following syntax errors will be
  * ignored:
@@ -56,7 +56,7 @@ import java.io.Reader;
  * </ul>
  *
  * <p>Each tokener may be used to parse a single JSON string. Instances of this
- * class are not thread safe. Although this class is nonfinal, it was not
+ * class are not thread safe. Although this class is non-final, it was not
  * designed for inheritance and should not be subclassed. In particular,
  * self-use by overrideable methods is not specified. See <i>Effective Java</i>
  * Item 17, "Design and Document or inheritance or else prohibit it" for further
@@ -64,6 +64,14 @@ import java.io.Reader;
  */
 public class JSONTokener {
 
+    /**
+     * Maximum allowed JSON nesting level supported by the parser.
+     * Used to avoid StackOverflow errors.
+     * For backward compatibility, the value can be changed (globally) using a system property.
+     */
+    public static final int MAX_NESTING_LEVEL =
+            Integer.getInteger("com.github.openjson.MAX_NESTING_LEVEL", 100);
+
     /**
      * The input JSON.
      */
@@ -108,16 +116,24 @@ public class JSONTokener {
      * @throws JSONException if the input is malformed.
      */
     public Object nextValue() throws JSONException {
+        return nextValue(0);
+    }
+
+    private Object nextValue(int nestingLevel) throws JSONException {
+        if (nestingLevel >= MAX_NESTING_LEVEL) {
+            throw new JSONException("Failed to parse input. JSONTokener." +
+                    "MAX_NESTING_LEVEL is reached: " + MAX_NESTING_LEVEL);
+        }
         int c = nextCleanInternal();
         switch (c) {
             case -1:
                 throw syntaxError("End of input");
 
             case '{':
-                return readObject();
+                return readObject(nestingLevel);
 
             case '[':
-                return readArray();
+                return readArray(nestingLevel);
 
             case '\'':
             case '"':
@@ -343,8 +359,7 @@ public class JSONTokener {
         }
 
         /* ... finally give up. We have an unquoted string */
-        //noinspection RedundantStringConstructorCall
-        return new String(literal); // a new string avoids leaking memory
+        return literal; // a new string avoids leaking memory
     }
 
     /**
@@ -366,7 +381,7 @@ public class JSONTokener {
      * Reads a sequence of key/value pairs and the trailing closing brace '}' of
      * an object. The opening brace '{' should have already been read.
      */
-    private JSONObject readObject() throws JSONException {
+    private JSONObject readObject(int nestingLevel) throws JSONException {
         JSONObject result = new JSONObject();
 
         /* Peek to see if this is the empty object. */
@@ -378,7 +393,7 @@ public class JSONTokener {
         }
 
         while (true) {
-            Object name = nextValue();
+            Object name = nextValue(nestingLevel + 1);
             if (!(name instanceof String)) {
                 if (name == null) {
                     throw syntaxError("Names cannot be null");
@@ -389,9 +404,8 @@ public class JSONTokener {
             }
 
             /*
-             * Expect the name/value separator to be either a colon ':', an
-             * equals sign '=', or an arrow "=>". The last two are bogus but we
-             * include them because that's what the original implementation did.
+             * Expect the name/value separator to be either a colon ':', an equals sign '=', or an arrow "=>".
+             * The last two are bogus, but we include them because that's what the original implementation did.
              */
             int separator = nextCleanInternal();
             if (separator != ':' && separator != '=') {
@@ -401,7 +415,7 @@ public class JSONTokener {
                 pos++;
             }
 
-            result.put((String) name, nextValue());
+            result.put((String) name, nextValue(nestingLevel + 1));
 
             switch (nextCleanInternal()) {
                 case '}':
@@ -421,7 +435,7 @@ public class JSONTokener {
      * "[]" yields an empty array, but "[,]" returns a two-element array
      * equivalent to "[null,null]".
      */
-    private JSONArray readArray() throws JSONException {
+    private JSONArray readArray(int nestingLevel) throws JSONException {
         JSONArray result = new JSONArray();
 
         /* to cover input that ends with ",]". */
@@ -446,7 +460,7 @@ public class JSONTokener {
                     pos--;
             }
 
-            result.put(nextValue());
+            result.put(nextValue(nestingLevel + 1));
 
             switch (nextCleanInternal()) {
                 case ']':
@@ -500,8 +514,8 @@ public class JSONTokener {
 
     /**
      * Returns the next available character, or the null character '\0' if all
-     * input has been exhausted. The return value of this method is ambiguous
-     * for JSON strings that contain the character '\0'.
+     * inputs have been exhausted.
+     * The return value of this method is ambiguous for JSON strings that contain the character '\0'.
      *
      * @return the next character.
      */
@@ -510,8 +524,8 @@ public class JSONTokener {
     }
 
     /**
-     * Returns the next available character if it equals {@code c}. Otherwise an
-     * exception is thrown.
+     * Returns the next available character if it equals {@code c}.
+     * Otherwise, an exception is thrown.
      *
      * @param c The character we are looking for.
      * @return the next character.
@@ -608,7 +622,7 @@ public class JSONTokener {
     }
 
     /**
-     * Advances past all input up to but not including the next occurrence of
+     * Advances past all inputs up to but not including the next occurrence of
      * {@code to}. If the remaining input doesn't contain {@code to}, the input
      * is unchanged.
      *


=====================================
src/test/java/com/github/openjson/JSONFunctionTestObject.java
=====================================
@@ -4,7 +4,7 @@ package com.github.openjson;
  * Class to test the function hack
  */
 public class JSONFunctionTestObject {
-    private String value;
+    private final String value;
 
     public JSONFunctionTestObject(String value) {
         this.value = value;
@@ -14,4 +14,4 @@ public class JSONFunctionTestObject {
     public String toString() {
         return value;
     }
-}
\ No newline at end of file
+}


=====================================
src/test/java/com/github/openjson/JSONTokenerTest.java
=====================================
@@ -17,13 +17,16 @@
 package com.github.openjson;
 
 import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
 
 /**
  * This black box test was written without inspecting the non-free org.json sourcecode.
  */
-public class JSONTokenerTest extends TestCase {
+public class JSONTokenerTest {
 
+    @Test
     public void testNulls() throws JSONException {
         // JSONTokener accepts null, only to fail later on almost all APIs!
         new JSONTokener((String) null).back();
@@ -94,12 +97,12 @@ public class JSONTokenerTest extends TestCase {
         } catch (NullPointerException ignored) {
         }
 
-        assertEquals("foo! at character 0 of null",
-                new JSONTokener((String) null).syntaxError("foo!").getMessage());
+        assertEquals("foo! at character 0 of null", new JSONTokener((String) null).syntaxError("foo!").getMessage());
 
         assertEquals(" at character 0 of null", new JSONTokener((String) null).toString());
     }
 
+    @Test
     public void testEmptyString() throws JSONException {
         JSONTokener backTokener = new JSONTokener("");
         backTokener.back();
@@ -131,11 +134,11 @@ public class JSONTokenerTest extends TestCase {
         }
         new JSONTokener("").skipPast("ABC");
         assertEquals('\0', new JSONTokener("").skipTo('A'));
-        assertEquals("foo! at character 0 of ",
-                new JSONTokener("").syntaxError("foo!").getMessage());
+        assertEquals("foo! at character 0 of ", new JSONTokener("").syntaxError("foo!").getMessage());
         assertEquals(" at character 0 of ", new JSONTokener("").toString());
     }
 
+    @Test
     public void testCharacterNavigation() throws JSONException {
         JSONTokener abcdeTokener = new JSONTokener("ABCDE");
         assertEquals('A', abcdeTokener.next());
@@ -154,6 +157,7 @@ public class JSONTokenerTest extends TestCase {
         assertEquals('E', abcdeTokener.next());
     }
 
+    @Test
     public void testBackNextAndMore() throws JSONException {
         JSONTokener abcTokener = new JSONTokener("ABC");
         assertTrue(abcTokener.more());
@@ -173,6 +177,7 @@ public class JSONTokenerTest extends TestCase {
         assertEquals('A', abcTokener.next());
     }
 
+    @Test
     public void testNextMatching() throws JSONException {
         JSONTokener abcdTokener = new JSONTokener("ABCD");
         assertEquals('A', abcdTokener.next('A'));
@@ -190,6 +195,7 @@ public class JSONTokenerTest extends TestCase {
         }
     }
 
+    @Test
     public void testNextN() throws JSONException {
         JSONTokener abcdeTokener = new JSONTokener("ABCDEF");
         assertEquals("", abcdeTokener.next(0));
@@ -206,6 +212,7 @@ public class JSONTokenerTest extends TestCase {
         }
     }
 
+    @Test
     public void testNextNWithAllRemaining() throws JSONException {
         JSONTokener tokener = new JSONTokener("ABCDEF");
         tokener.next(3);
@@ -218,6 +225,7 @@ public class JSONTokenerTest extends TestCase {
         }
     }
 
+    @Test
     public void testNext0() throws JSONException {
         JSONTokener tokener = new JSONTokener("ABCDEF");
         tokener.next(5);
@@ -231,6 +239,7 @@ public class JSONTokenerTest extends TestCase {
         }
     }
 
+    @Test
     public void testNextCleanComments() throws JSONException {
         JSONTokener tokener = new JSONTokener(
                 "  A  /*XX*/B/*XX//XX\n//XX\nXX*/C//X//X//X\nD/*X*///X\n");
@@ -241,6 +250,7 @@ public class JSONTokenerTest extends TestCase {
         assertEquals('\0', tokener.nextClean());
     }
 
+    @Test
     public void testNextCleanNestedCStyleComments() throws JSONException {
         JSONTokener tokener = new JSONTokener("A /* B /* C */ D */ E");
         assertEquals('A', tokener.nextClean());
@@ -254,6 +264,7 @@ public class JSONTokenerTest extends TestCase {
      * Some applications rely on parsing '#' to lead an end-of-line comment.
      * http://b/2571423
      */
+    @Test
     public void testNextCleanHashComments() throws JSONException {
         JSONTokener tokener = new JSONTokener("A # B */ /* C */ \nD #");
         assertEquals('A', tokener.nextClean());
@@ -261,15 +272,16 @@ public class JSONTokenerTest extends TestCase {
         assertEquals('\0', tokener.nextClean());
     }
 
+    @Test
     public void testNextCleanCommentsTrailingSingleSlash() throws JSONException {
         JSONTokener tokener = new JSONTokener(" / S /");
         assertEquals('/', tokener.nextClean());
         assertEquals('S', tokener.nextClean());
         assertEquals('/', tokener.nextClean());
-        assertEquals("nextClean doesn't consume a trailing slash",
-                '\0', tokener.nextClean());
+        assertEquals("nextClean doesn't consume a trailing slash", '\0', tokener.nextClean());
     }
 
+    @Test
     public void testNextCleanTrailingOpenComment() throws JSONException {
         try {
             new JSONTokener("  /* ").nextClean();
@@ -279,17 +291,19 @@ public class JSONTokenerTest extends TestCase {
         assertEquals('\0', new JSONTokener("  // ").nextClean());
     }
 
+    @Test
     public void testNextCleanNewlineDelimiters() throws JSONException {
         assertEquals('B', new JSONTokener("  // \r\n  B ").nextClean());
         assertEquals('B', new JSONTokener("  // \n  B ").nextClean());
         assertEquals('B', new JSONTokener("  // \r  B ").nextClean());
     }
 
+    @Test
     public void testNextCleanSkippedWhitespace() throws JSONException {
         assertEquals("character tabulation", 'A', new JSONTokener("\tA").nextClean());
-        assertEquals("line feed",            'A', new JSONTokener("\nA").nextClean());
-        assertEquals("carriage return",      'A', new JSONTokener("\rA").nextClean());
-        assertEquals("space",                'A', new JSONTokener(" A").nextClean());
+        assertEquals("line feed", 'A', new JSONTokener("\nA").nextClean());
+        assertEquals("carriage return", 'A', new JSONTokener("\rA").nextClean());
+        assertEquals("space", 'A', new JSONTokener(" A").nextClean());
     }
 
     /**
@@ -297,44 +311,45 @@ public class JSONTokenerTest extends TestCase {
      * <a href="https://spreadsheets.google.com/pub?key=pd8dAQyHbdewRsnE5x5GzKQ">list
      * of whitespace characters</a>.
      */
+    @Test
     public void testNextCleanRetainedWhitespace() throws JSONException {
-        assertNotClean("null",                      '\u0000');
-        assertNotClean("next line",                 '\u0085');
-        assertNotClean("non-breaking space",        '\u00a0');
-        assertNotClean("ogham space mark",          '\u1680');
+        assertNotClean("null", '\u0000');
+        assertNotClean("next line", '\u0085');
+        assertNotClean("non-breaking space", '\u00a0');
+        assertNotClean("ogham space mark", '\u1680');
         assertNotClean("mongolian vowel separator", '\u180e');
-        assertNotClean("en quad",                   '\u2000');
-        assertNotClean("em quad",                   '\u2001');
-        assertNotClean("en space",                  '\u2002');
-        assertNotClean("em space",                  '\u2003');
-        assertNotClean("three-per-em space",        '\u2004');
-        assertNotClean("four-per-em space",         '\u2005');
-        assertNotClean("six-per-em space",          '\u2006');
-        assertNotClean("figure space",              '\u2007');
-        assertNotClean("punctuation space",         '\u2008');
-        assertNotClean("thin space",                '\u2009');
-        assertNotClean("hair space",                '\u200a');
-        assertNotClean("zero-width space",          '\u200b');
-        assertNotClean("left-to-right mark",        '\u200e');
-        assertNotClean("right-to-left mark",        '\u200f');
-        assertNotClean("line separator",            '\u2028');
-        assertNotClean("paragraph separator",       '\u2029');
+        assertNotClean("en quad", '\u2000');
+        assertNotClean("em quad", '\u2001');
+        assertNotClean("en space", '\u2002');
+        assertNotClean("em space", '\u2003');
+        assertNotClean("three-per-em space", '\u2004');
+        assertNotClean("four-per-em space", '\u2005');
+        assertNotClean("six-per-em space", '\u2006');
+        assertNotClean("figure space", '\u2007');
+        assertNotClean("punctuation space", '\u2008');
+        assertNotClean("thin space", '\u2009');
+        assertNotClean("hair space", '\u200a');
+        assertNotClean("zero-width space", '\u200b');
+        assertNotClean("left-to-right mark", '\u200e');
+        assertNotClean("right-to-left mark", '\u200f');
+        assertNotClean("line separator", '\u2028');
+        assertNotClean("paragraph separator", '\u2029');
         assertNotClean("narrow non-breaking space", '\u202f');
         assertNotClean("medium mathematical space", '\u205f');
-        assertNotClean("ideographic space",         '\u3000');
-        assertNotClean("line tabulation",           '\u000b');
-        assertNotClean("form feed",                 '\u000c');
-        assertNotClean("information separator 4",   '\u001c');
-        assertNotClean("information separator 3",   '\u001d');
-        assertNotClean("information separator 2",   '\u001e');
-        assertNotClean("information separator 1",   '\u001f');
+        assertNotClean("ideographic space", '\u3000');
+        assertNotClean("line tabulation", '\u000b');
+        assertNotClean("form feed", '\u000c');
+        assertNotClean("information separator 4", '\u001c');
+        assertNotClean("information separator 3", '\u001d');
+        assertNotClean("information separator 2", '\u001e');
+        assertNotClean("information separator 1", '\u001f');
     }
 
     private void assertNotClean(String name, char c) throws JSONException {
-        assertEquals("The character " + name + " is not whitespace according to the JSON spec.",
-                c, new JSONTokener(new String(new char[] { c, 'A' })).nextClean());
+        assertEquals("The character " + name + " is not whitespace according to the JSON spec.", c, new JSONTokener(new String(new char[]{c, 'A'})).nextClean());
     }
 
+    @Test
     public void testNextString() throws JSONException {
         assertEquals("", new JSONTokener("'").nextString('\''));
         assertEquals("", new JSONTokener("\"").nextString('\"'));
@@ -357,6 +372,7 @@ public class JSONTokenerTest extends TestCase {
         assertFalse(tokener.more());
     }
 
+    @Test
     public void testNextStringNoDelimiter() throws JSONException {
         try {
             new JSONTokener("").nextString('\'');
@@ -374,6 +390,7 @@ public class JSONTokenerTest extends TestCase {
         }
     }
 
+    @Test
     public void testNextStringEscapedQuote() throws JSONException {
         try {
             new JSONTokener("abc\\").nextString('"');
@@ -393,6 +410,7 @@ public class JSONTokenerTest extends TestCase {
         assertEquals("abc\tdef", new JSONTokener("abc\\tdef\"ghi").nextString('"'));
     }
 
+    @Test
     public void testNextStringUnicodeEscaped() throws JSONException {
         // we're mixing Java escaping like \\ and JavaScript escaping like \\u
         assertEquals("abc def", new JSONTokener("abc\\u0020def\"ghi").nextString('"'));
@@ -422,12 +440,14 @@ public class JSONTokenerTest extends TestCase {
         }
     }
 
+    @Test
     public void testNextStringNonQuote() throws JSONException {
         assertEquals("AB", new JSONTokener("ABC").nextString('C'));
         assertEquals("ABCD", new JSONTokener("AB\\CDC").nextString('C'));
         assertEquals("AB\nC", new JSONTokener("AB\\nCn").nextString('n'));
     }
 
+    @Test
     public void testNextTo() throws JSONException {
         assertEquals("ABC", new JSONTokener("ABCDEFG").nextTo("DHI"));
         assertEquals("ABCDEF", new JSONTokener("ABCDEF").nextTo(""));
@@ -469,16 +489,19 @@ public class JSONTokenerTest extends TestCase {
         }
     }
 
+    @Test
     public void testNextToTrimming() {
         assertEquals("ABC", new JSONTokener("\t ABC \tDEF").nextTo("DE"));
         assertEquals("ABC", new JSONTokener("\t ABC \tDEF").nextTo('D'));
     }
 
+    @Test
     public void testNextToTrailing() {
         assertEquals("ABC DEF", new JSONTokener("\t ABC DEF \t").nextTo("G"));
         assertEquals("ABC DEF", new JSONTokener("\t ABC DEF \t").nextTo('G'));
     }
 
+    @Test
     public void testNextToDoesntStopOnNull() {
         String message = "nextTo() shouldn't stop after \\0 characters";
         JSONTokener tokener = new JSONTokener(" \0\t \fABC \n DEF");
@@ -487,6 +510,7 @@ public class JSONTokenerTest extends TestCase {
         assertEquals(message, "", tokener.nextTo("D"));
     }
 
+    @Test
     public void testNextToConsumesNull() {
         String message = "nextTo shouldn't consume \\0.";
         JSONTokener tokener = new JSONTokener("ABC\0DEF");
@@ -495,6 +519,7 @@ public class JSONTokenerTest extends TestCase {
         assertEquals(message, "DEF", tokener.nextTo("\0"));
     }
 
+    @Test
     public void testSkipPast() {
         JSONTokener tokener = new JSONTokener("ABCDEF");
         tokener.skipPast("ABC");
@@ -543,6 +568,7 @@ public class JSONTokenerTest extends TestCase {
         }
     }
 
+    @Test
     public void testSkipTo() {
         JSONTokener tokener = new JSONTokener("ABCDEF");
         tokener.skipTo('A');
@@ -567,35 +593,39 @@ public class JSONTokenerTest extends TestCase {
         assertEquals('D', tokener.next());
     }
 
+    @Test
     public void testSkipToStopsOnNull() {
         JSONTokener tokener = new JSONTokener("ABC\0DEF");
         tokener.skipTo('F');
         assertEquals("skipTo shouldn't stop when it sees '\\0'", 'F', tokener.next());
     }
 
+    @Test
     public void testBomIgnoredAsFirstCharacterOfDocument() throws JSONException {
         JSONTokener tokener = new JSONTokener("\ufeff[]");
         JSONArray array = (JSONArray) tokener.nextValue();
         assertEquals(0, array.length());
     }
 
+    @Test
     public void testBomTreatedAsCharacterInRestOfDocument() throws JSONException {
         JSONTokener tokener = new JSONTokener("[\ufeff]");
         JSONArray array = (JSONArray) tokener.nextValue();
         assertEquals(1, array.length());
     }
 
+    @Test
     public void testDehexchar() {
-        assertEquals( 0, JSONTokener.dehexchar('0'));
-        assertEquals( 1, JSONTokener.dehexchar('1'));
-        assertEquals( 2, JSONTokener.dehexchar('2'));
-        assertEquals( 3, JSONTokener.dehexchar('3'));
-        assertEquals( 4, JSONTokener.dehexchar('4'));
-        assertEquals( 5, JSONTokener.dehexchar('5'));
-        assertEquals( 6, JSONTokener.dehexchar('6'));
-        assertEquals( 7, JSONTokener.dehexchar('7'));
-        assertEquals( 8, JSONTokener.dehexchar('8'));
-        assertEquals( 9, JSONTokener.dehexchar('9'));
+        assertEquals(0, JSONTokener.dehexchar('0'));
+        assertEquals(1, JSONTokener.dehexchar('1'));
+        assertEquals(2, JSONTokener.dehexchar('2'));
+        assertEquals(3, JSONTokener.dehexchar('3'));
+        assertEquals(4, JSONTokener.dehexchar('4'));
+        assertEquals(5, JSONTokener.dehexchar('5'));
+        assertEquals(6, JSONTokener.dehexchar('6'));
+        assertEquals(7, JSONTokener.dehexchar('7'));
+        assertEquals(8, JSONTokener.dehexchar('8'));
+        assertEquals(9, JSONTokener.dehexchar('9'));
         assertEquals(10, JSONTokener.dehexchar('A'));
         assertEquals(11, JSONTokener.dehexchar('B'));
         assertEquals(12, JSONTokener.dehexchar('C'));
@@ -616,4 +646,69 @@ public class JSONTokenerTest extends TestCase {
             assertEquals("dehexchar " + c, -1, JSONTokener.dehexchar((char) c));
         }
     }
+
+    @Test
+    public void testNoStackOverflowArray() throws JSONException {
+        String jsonString = generateNestedArray(JSONTokener.MAX_NESTING_LEVEL);
+        new JSONTokener(jsonString).nextValue();
+    }
+
+    @Test
+    public void testStackOverflowArray() throws JSONException {
+        String jsonString = generateNestedArray(JSONTokener.MAX_NESTING_LEVEL + 1);
+        Throwable throwable = null;
+        try {
+            new JSONTokener(jsonString).nextValue();
+        } catch (Throwable t) {
+            throwable = t;
+        }
+        assertIsMaxNestingLevelException(throwable);
+    }
+
+    private static String generateNestedArray(int depth) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < depth; i++) {
+            sb.append('[');
+        }
+        for (int i = 0; i < depth; i++) {
+            sb.append(']');
+        }
+        return sb.toString();
+    }
+
+    @Test
+    public void testNoStackOverflowObject() throws JSONException {
+        String jsonString = generateNestedObject(JSONTokener.MAX_NESTING_LEVEL);
+        new JSONTokener(jsonString).nextValue();
+    }
+
+    @Test
+    public void testStackOverflowObject() throws JSONException {
+        String jsonString = generateNestedObject(JSONTokener.MAX_NESTING_LEVEL + 1);
+        Throwable throwable = null;
+        try {
+            new JSONTokener(jsonString).nextValue();
+        } catch (Throwable t) {
+            throwable = t;
+        }
+        assertIsMaxNestingLevelException(throwable);
+    }
+
+    public static void assertIsMaxNestingLevelException(Throwable throwable) {
+        assertNotNull(throwable);
+        assertTrue(throwable instanceof JSONException);
+        assertTrue(throwable.getMessage().contains("MAX_NESTING_LEVEL"));
+    }
+
+    private static String generateNestedObject(int depth) {
+        StringBuilder sb = new StringBuilder("{");
+        for (int i = 0; i < depth - 1; i++) {
+            sb.append("\"a\":{");
+        }
+        for (int i = 0; i < depth + 1; i++) {
+            sb.append('}');
+        }
+        sb.append('}');
+        return sb.toString();
+    }
 }


=====================================
src/test/java/com/github/openjson/SelfUseTest.java
=====================================
@@ -289,6 +289,6 @@ public class SelfUseTest {
     @Test
     public void testNextValue() throws JSONException {
         tokener.nextValue();
-        assertEquals(4, tokenerNextValueCalls);
+        assertEquals(1, tokenerNextValueCalls);
     }
 }


=====================================
src/test/java/com/github/openjson/issues/Issue18Test.java
=====================================
@@ -0,0 +1,57 @@
+package com.github.openjson.issues;
+
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONException;
+import com.github.openjson.JSONObject;
+import com.github.openjson.JSONTokener;
+import org.junit.Test;
+
+import static com.github.openjson.JSONTokenerTest.assertIsMaxNestingLevelException;
+
+public class Issue18Test {
+    private final static int TOO_DEEP_NESTING = 9999;
+
+    public static String buildNestedDoc(int nesting, String open, String close, String content) {
+        StringBuilder sb = new StringBuilder(nesting * (open.length() + close.length()));
+        for (int i = 0; i < nesting; ++i) {
+            sb.append(open);
+            if ((i & 31) == 0) {
+                sb.append("\n");
+            }
+        }
+        sb.append("\n").append(content).append("\n");
+        for (int i = 0; i < nesting; ++i) {
+            sb.append(close);
+            if ((i & 31) == 0) {
+                sb.append("\n");
+            }
+        }
+        return sb.toString();
+    }
+
+    @Test
+    public void test1() {
+        String tooDeepArray = buildNestedDoc(TOO_DEEP_NESTING, "[ ", "] ", "x");
+        JSONTokener jsonTokener = new JSONTokener(tooDeepArray);
+        Throwable throwable = null;
+        try {
+            new JSONArray(jsonTokener);
+        } catch (JSONException e) {
+            throwable = e;
+        }
+        assertIsMaxNestingLevelException(throwable);
+    }
+
+    @Test
+    public void test2() {
+        String tooDeepObject = "{" + buildNestedDoc(TOO_DEEP_NESTING, "\"a\": { ", "} ", "y") + "}";
+        Throwable throwable = null;
+        JSONTokener jsonTokener2 = new JSONTokener(tooDeepObject);
+        try {
+            new JSONObject(jsonTokener2);
+        } catch (JSONException e) {
+            throwable = e;
+        }
+        assertIsMaxNestingLevelException(throwable);
+    }
+}



View it on GitLab: https://salsa.debian.org/java-team/openjson/-/commit/8072e7c49e682c33d1ca900c560398926bf21100

-- 
View it on GitLab: https://salsa.debian.org/java-team/openjson/-/commit/8072e7c49e682c33d1ca900c560398926bf21100
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20230702/abf3a630/attachment.htm>


More information about the pkg-java-commits mailing list