groovy git commit: GROOVY-7630 - JsonSlurper LAX and INDEX_OVERLAY parser with invalid number (closes #189)

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

groovy git commit: GROOVY-7630 - JsonSlurper LAX and INDEX_OVERLAY parser with invalid number (closes #189)

jwagenleitner-2
Repository: groovy
Updated Branches:
  refs/heads/master 738b5f669 -> 73f5979a4


GROOVY-7630 - JsonSlurper LAX and INDEX_OVERLAY parser with invalid number (closes #189)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/73f5979a
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/73f5979a
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/73f5979a

Branch: refs/heads/master
Commit: 73f5979a468f1508134eba20ce503630b0fe0cc7
Parents: 738b5f6
Author: John Wagenleitner <[hidden email]>
Authored: Sat Nov 14 23:08:04 2015 -0800
Committer: John Wagenleitner <[hidden email]>
Committed: Mon Dec 21 09:34:21 2015 -0800

----------------------------------------------------------------------
 .../groovy/json/internal/JsonFastParser.java    | 37 ++++++++++++++++---
 .../groovy/json/internal/JsonParserLax.java     | 39 ++++++++++++++++++++
 .../groovy/json/JsonSlurperLaxTest.groovy       | 27 ++++++++++++++
 .../groovy/groovy/json/JsonSlurperTest.groovy   | 37 ++++++++++++++++++-
 4 files changed, 133 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/73f5979a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
index cb56a82..c088b4d 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
@@ -163,6 +163,8 @@ public class JsonFastParser extends JsonParserCharArray {
         char currentChar;
         boolean doubleFloat = false;
         boolean foundDot = false;
+        boolean foundSign = false;
+        boolean foundExp = false;
 
         if (minus && index + 1 < array.length) {
             index++;
@@ -176,19 +178,42 @@ public class JsonFastParser extends JsonParserCharArray {
                 break;
             } else if (isDelimiter(currentChar)) {
                 break;
-            } else if (currentChar == '.') {
-                if (foundDot) {
-                    complain("unexpected character " + currentChar);
-                }
-                foundDot = true;
-                doubleFloat = true;
             } else if (isDecimalChar(currentChar)) {
+                switch (currentChar) {
+                    case DECIMAL_POINT:
+                        if (foundDot || foundExp) { complain("unexpected character " + currentChar); }
+                        foundDot = true;
+                        break;
+                    case LETTER_E:
+                    case LETTER_BIG_E:
+                        if (foundExp) { complain("unexpected character " + currentChar); }
+                        foundExp = true;
+                        break;
+                    case MINUS:
+                    case PLUS:
+                        if (foundSign || !foundExp) { complain("unexpected character " + currentChar); }
+                        if (foundExp && array[index - 1] != LETTER_E && array[index - 1] != LETTER_BIG_E) {
+                            complain("unexpected character " + currentChar);
+                        }
+                        foundSign = true;
+                        break;
+                }
                 doubleFloat = true;
+            } else {
+                complain("unexpected character " + currentChar);
             }
             index++;
             if (index >= array.length) break;
         }
 
+        // Handle the case where the exponential number ends without the actual exponent
+        if (foundExp) {
+            char prevChar = array[index - 1];
+            if (prevChar == LETTER_E || prevChar == LETTER_BIG_E || prevChar == MINUS || prevChar == PLUS) {
+                complain("unexpected character " + currentChar);
+            }
+        }
+
         __index = index;
         __currentChar = currentChar;
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/73f5979a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
index 1172fd4..0238b35 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
@@ -370,6 +370,13 @@ public class JsonParserLax extends JsonParserCharArray {
         }
     }
 
+    /**
+     * Decodes a number from a JSON value.  If at any point it is determined that
+     * the value is not a valid number the value is treated as a {@code String}.
+     *
+     * @param minus indicate whether the number is negative
+     * @return a number, or {@code String} if not a valid number
+     */
     protected final Value decodeNumberLax(boolean minus) {
         char[] array = charArray;
 
@@ -377,6 +384,9 @@ public class JsonParserLax extends JsonParserCharArray {
         int index = __index;
         char currentChar;
         boolean doubleFloat = false;
+        boolean foundDot = false;
+        boolean foundSign = false;
+        boolean foundExp = false;
 
         if (minus && index + 1 < array.length) {
             index++;
@@ -391,12 +401,41 @@ public class JsonParserLax extends JsonParserCharArray {
             } else if (isDelimiter(currentChar)) {
                 break;
             } else if (isDecimalChar(currentChar)) {
+                switch (currentChar) {
+                    case DECIMAL_POINT:
+                        if (foundDot || foundExp) { return decodeStringLax(); }
+                        foundDot = true;
+                        break;
+                    case LETTER_E:
+                    case LETTER_BIG_E:
+                        if (foundExp) { return decodeStringLax(); }
+                        foundExp = true;
+                        break;
+                    case MINUS:
+                    case PLUS:
+                        if (foundSign || !foundExp) { return decodeStringLax(); }
+                        if (foundExp && array[index - 1] != LETTER_E && array[index - 1] != LETTER_BIG_E) {
+                            return decodeStringLax();
+                        }
+                        foundSign = true;
+                        break;
+                }
                 doubleFloat = true;
+            } else {
+                return decodeStringLax();
             }
             index++;
             if (index >= array.length) break;
         }
 
+        // Handle the case where the exponential number ends without the actual exponent
+        if (foundExp) {
+            char prevChar = array[index - 1];
+            if (prevChar == LETTER_E || prevChar == LETTER_BIG_E || prevChar == MINUS || prevChar == PLUS) {
+                return decodeStringLax();
+            }
+        }
+
         __index = index;
         __currentChar = currentChar;
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/73f5979a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperLaxTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperLaxTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperLaxTest.groovy
index 38c161f..e5524b6 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperLaxTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperLaxTest.groovy
@@ -121,4 +121,31 @@ class JsonSlurperLaxTest extends JsonSlurperTest {
         assert map["he said"] == '"fire all your guns at once baby, and explode into the night"'
         assert map.the == "end"
     }
+
+    @Override
+    void testInvalidNumbers() {
+        // should be parsed as Strings
+        assert parser.parseText('{"num": 1a}').num == '1a'
+        assert parser.parseText('{"num": -1a}').num == '-1a'
+        assert parser.parseText('[98ab9]')[0] == '98ab9'
+        assert parser.parseText('[12/25/1980]')[0] == '12/25/1980'
+        assert parser.parseText('{"num": 1980-12-25}').num == '1980-12-25'
+        assert parser.parseText('{"num": 1.2ee5}').num == '1.2ee5'
+        assert parser.parseText('{"num": 1.2EE5}').num == '1.2EE5'
+        assert parser.parseText('{"num": 1.2Ee5}').num == '1.2Ee5'
+        assert parser.parseText('{"num": 1.2e++5}').num == '1.2e++5'
+        assert parser.parseText('{"num": 1.2e--5}').num == '1.2e--5'
+        assert parser.parseText('{"num": 1.2e+-5}').num == '1.2e+-5'
+        assert parser.parseText('{"num": 1.2+e5}').num == '1.2+e5'
+        assert parser.parseText('{"num": 1.2E5+}').num == '1.2E5+'
+        assert parser.parseText('{"num": 1.2e5+}').num == '1.2e5+'
+        assert parser.parseText('{"num": 37e-5.5}').num == '37e-5.5'
+        assert parser.parseText('{"num": 6.92e}').num == '6.92e'
+        assert parser.parseText('{"num": 6.92E}').num == '6.92E'
+        assert parser.parseText('{"num": 6.92e-}').num == '6.92e-'
+        assert parser.parseText('{"num": 6.92e+}').num == '6.92e+'
+        assert parser.parseText('{"num": 6+}').num == '6+'
+        assert parser.parseText('{"num": 6-}').num == '6-'
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/groovy/blob/73f5979a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
index 95f52ca..b8068df 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
@@ -274,7 +274,6 @@ class JsonSlurperTest extends GroovyTestCase {
         shouldFail(JsonException) { parser.parseText('["a"')        }
         shouldFail(JsonException) { parser.parseText('["a", ')      }
         shouldFail(JsonException) { parser.parseText('["a", true')  }
-        shouldFail(JsonException) { parser.parseText('[1.1.1]')     }
     }
 
     void testBackSlashEscaping() {
@@ -317,4 +316,40 @@ class JsonSlurperTest extends GroovyTestCase {
 
         assertEquals(Date.class, o.a.class)
     }
+
+    void testInvalidNumbers() {
+        shouldFail(JsonException) { parser.parseText('[1.1.1]') }
+        shouldFail(JsonException) { parser.parseText('{"num": 1a}') }
+        shouldFail(JsonException) { parser.parseText('{"num": 1A}') }
+        shouldFail(JsonException) { parser.parseText('{"num": -1a}') }
+        shouldFail(JsonException) { parser.parseText('[98ab9]') }
+        shouldFail(JsonException) { parser.parseText('[-98ab9]') }
+        shouldFail(JsonException) { parser.parseText('[12/25/1980]') }
+
+        // TODO: Exception class differs from this point by parser type
+        // Probably something to be addressed at some point.
+        Class exceptional = JsonException
+        if (parser.type == JsonParserType.CHAR_BUFFER) {
+            exceptional = NumberFormatException
+        }
+
+        shouldFail(exceptional) { parser.parseText('{"num": 1980-12-25}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 1.2ee5}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 1.2EE5}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 1.2Ee5}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 1.2e++5}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 1.2e--5}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 1.2e+-5}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 1.2+e5}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 1.2E5+}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 1.2e5+}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 37e-5.5}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 6.92e}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 6.92E}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 6.92e-}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 6.92e+}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 6+}') }
+        shouldFail(exceptional) { parser.parseText('{"num": 6-}') }
+    }
+
 }