From 80f9e48e64e89ca7710257939076c3e9a8000b21 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 16 Jun 2016 12:20:54 -0400 Subject: [PATCH 01/99] Moves src folder to simplify build.gradle configuration. If JSON-Java source is merged, it's src fold would now be src/main/java/org.json/ instead of src/main/org.json as well. --- .gitignore | 6 ++++++ build.gradle | 17 ++--------------- src/test/{ => java}/org/json/junit/CDLTest.java | 0 .../org/json/junit/CookieListTest.java | 0 .../{ => java}/org/json/junit/CookieTest.java | 0 .../{ => java}/org/json/junit/EnumTest.java | 0 .../{ => java}/org/json/junit/HTTPTest.java | 0 .../org/json/junit/JSONArrayTest.java | 0 .../{ => java}/org/json/junit/JSONMLTest.java | 0 .../org/json/junit/JSONObjectTest.java | 0 .../org/json/junit/JSONPointerTest.java | 0 .../org/json/junit/JSONStringerTest.java | 0 .../org/json/junit/JunitTestSuite.java | 0 src/test/{ => java}/org/json/junit/MyBean.java | 0 .../org/json/junit/MyBigNumberBean.java | 0 src/test/{ => java}/org/json/junit/MyEnum.java | 0 .../{ => java}/org/json/junit/MyEnumClass.java | 0 .../{ => java}/org/json/junit/MyEnumField.java | 0 .../{ => java}/org/json/junit/MyJsonString.java | 0 .../org/json/junit/MyPublicClass.java | 0 .../{ => java}/org/json/junit/PropertyTest.java | 0 .../org/json/junit/StringsResourceBundle.java | 0 .../{ => java}/org/json/junit/TestRunner.java | 0 src/test/{ => java}/org/json/junit/Util.java | 0 src/test/{ => java}/org/json/junit/XMLTest.java | 0 25 files changed, 8 insertions(+), 15 deletions(-) rename src/test/{ => java}/org/json/junit/CDLTest.java (100%) rename src/test/{ => java}/org/json/junit/CookieListTest.java (100%) rename src/test/{ => java}/org/json/junit/CookieTest.java (100%) rename src/test/{ => java}/org/json/junit/EnumTest.java (100%) rename src/test/{ => java}/org/json/junit/HTTPTest.java (100%) rename src/test/{ => java}/org/json/junit/JSONArrayTest.java (100%) rename src/test/{ => java}/org/json/junit/JSONMLTest.java (100%) rename src/test/{ => java}/org/json/junit/JSONObjectTest.java (100%) rename src/test/{ => java}/org/json/junit/JSONPointerTest.java (100%) rename src/test/{ => java}/org/json/junit/JSONStringerTest.java (100%) rename src/test/{ => java}/org/json/junit/JunitTestSuite.java (100%) rename src/test/{ => java}/org/json/junit/MyBean.java (100%) rename src/test/{ => java}/org/json/junit/MyBigNumberBean.java (100%) rename src/test/{ => java}/org/json/junit/MyEnum.java (100%) rename src/test/{ => java}/org/json/junit/MyEnumClass.java (100%) rename src/test/{ => java}/org/json/junit/MyEnumField.java (100%) rename src/test/{ => java}/org/json/junit/MyJsonString.java (100%) rename src/test/{ => java}/org/json/junit/MyPublicClass.java (100%) rename src/test/{ => java}/org/json/junit/PropertyTest.java (100%) rename src/test/{ => java}/org/json/junit/StringsResourceBundle.java (100%) rename src/test/{ => java}/org/json/junit/TestRunner.java (100%) rename src/test/{ => java}/org/json/junit/Util.java (100%) rename src/test/{ => java}/org/json/junit/XMLTest.java (100%) diff --git a/.gitignore b/.gitignore index 9e7b59c..7afd420 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,9 @@ build .classpath .project .settings/ +/.gradle/ +/gradle/ +/gradlew +/gradlew.bat +.gitmodules +src/main/ diff --git a/build.gradle b/build.gradle index ad186a1..d2969d4 100644 --- a/build.gradle +++ b/build.gradle @@ -4,21 +4,8 @@ apply plugin: 'jacoco' sourceSets { // Uncomment main if you have merged JSON-Java and JSON-Java-unit-test code - main { - java { - srcDir 'src' - exclude 'test/' - } - } - test { - java { - srcDir 'src/test' - exclude 'resources/' - } - resources { - srcDir 'resources' - } - } + main + test } repositories { diff --git a/src/test/org/json/junit/CDLTest.java b/src/test/java/org/json/junit/CDLTest.java similarity index 100% rename from src/test/org/json/junit/CDLTest.java rename to src/test/java/org/json/junit/CDLTest.java diff --git a/src/test/org/json/junit/CookieListTest.java b/src/test/java/org/json/junit/CookieListTest.java similarity index 100% rename from src/test/org/json/junit/CookieListTest.java rename to src/test/java/org/json/junit/CookieListTest.java diff --git a/src/test/org/json/junit/CookieTest.java b/src/test/java/org/json/junit/CookieTest.java similarity index 100% rename from src/test/org/json/junit/CookieTest.java rename to src/test/java/org/json/junit/CookieTest.java diff --git a/src/test/org/json/junit/EnumTest.java b/src/test/java/org/json/junit/EnumTest.java similarity index 100% rename from src/test/org/json/junit/EnumTest.java rename to src/test/java/org/json/junit/EnumTest.java diff --git a/src/test/org/json/junit/HTTPTest.java b/src/test/java/org/json/junit/HTTPTest.java similarity index 100% rename from src/test/org/json/junit/HTTPTest.java rename to src/test/java/org/json/junit/HTTPTest.java diff --git a/src/test/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java similarity index 100% rename from src/test/org/json/junit/JSONArrayTest.java rename to src/test/java/org/json/junit/JSONArrayTest.java diff --git a/src/test/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java similarity index 100% rename from src/test/org/json/junit/JSONMLTest.java rename to src/test/java/org/json/junit/JSONMLTest.java diff --git a/src/test/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java similarity index 100% rename from src/test/org/json/junit/JSONObjectTest.java rename to src/test/java/org/json/junit/JSONObjectTest.java diff --git a/src/test/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java similarity index 100% rename from src/test/org/json/junit/JSONPointerTest.java rename to src/test/java/org/json/junit/JSONPointerTest.java diff --git a/src/test/org/json/junit/JSONStringerTest.java b/src/test/java/org/json/junit/JSONStringerTest.java similarity index 100% rename from src/test/org/json/junit/JSONStringerTest.java rename to src/test/java/org/json/junit/JSONStringerTest.java diff --git a/src/test/org/json/junit/JunitTestSuite.java b/src/test/java/org/json/junit/JunitTestSuite.java similarity index 100% rename from src/test/org/json/junit/JunitTestSuite.java rename to src/test/java/org/json/junit/JunitTestSuite.java diff --git a/src/test/org/json/junit/MyBean.java b/src/test/java/org/json/junit/MyBean.java similarity index 100% rename from src/test/org/json/junit/MyBean.java rename to src/test/java/org/json/junit/MyBean.java diff --git a/src/test/org/json/junit/MyBigNumberBean.java b/src/test/java/org/json/junit/MyBigNumberBean.java similarity index 100% rename from src/test/org/json/junit/MyBigNumberBean.java rename to src/test/java/org/json/junit/MyBigNumberBean.java diff --git a/src/test/org/json/junit/MyEnum.java b/src/test/java/org/json/junit/MyEnum.java similarity index 100% rename from src/test/org/json/junit/MyEnum.java rename to src/test/java/org/json/junit/MyEnum.java diff --git a/src/test/org/json/junit/MyEnumClass.java b/src/test/java/org/json/junit/MyEnumClass.java similarity index 100% rename from src/test/org/json/junit/MyEnumClass.java rename to src/test/java/org/json/junit/MyEnumClass.java diff --git a/src/test/org/json/junit/MyEnumField.java b/src/test/java/org/json/junit/MyEnumField.java similarity index 100% rename from src/test/org/json/junit/MyEnumField.java rename to src/test/java/org/json/junit/MyEnumField.java diff --git a/src/test/org/json/junit/MyJsonString.java b/src/test/java/org/json/junit/MyJsonString.java similarity index 100% rename from src/test/org/json/junit/MyJsonString.java rename to src/test/java/org/json/junit/MyJsonString.java diff --git a/src/test/org/json/junit/MyPublicClass.java b/src/test/java/org/json/junit/MyPublicClass.java similarity index 100% rename from src/test/org/json/junit/MyPublicClass.java rename to src/test/java/org/json/junit/MyPublicClass.java diff --git a/src/test/org/json/junit/PropertyTest.java b/src/test/java/org/json/junit/PropertyTest.java similarity index 100% rename from src/test/org/json/junit/PropertyTest.java rename to src/test/java/org/json/junit/PropertyTest.java diff --git a/src/test/org/json/junit/StringsResourceBundle.java b/src/test/java/org/json/junit/StringsResourceBundle.java similarity index 100% rename from src/test/org/json/junit/StringsResourceBundle.java rename to src/test/java/org/json/junit/StringsResourceBundle.java diff --git a/src/test/org/json/junit/TestRunner.java b/src/test/java/org/json/junit/TestRunner.java similarity index 100% rename from src/test/org/json/junit/TestRunner.java rename to src/test/java/org/json/junit/TestRunner.java diff --git a/src/test/org/json/junit/Util.java b/src/test/java/org/json/junit/Util.java similarity index 100% rename from src/test/org/json/junit/Util.java rename to src/test/java/org/json/junit/Util.java diff --git a/src/test/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java similarity index 100% rename from src/test/org/json/junit/XMLTest.java rename to src/test/java/org/json/junit/XMLTest.java From 46a1c9acf9573d20648f101058f2e4ac51a1163a Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 16 Jun 2016 13:02:08 -0400 Subject: [PATCH 02/99] Adds test case to confirm the parsing of control characters --- .../java/org/json/junit/JSONObjectTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 6ef3615..d550139 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1564,6 +1564,26 @@ public void wrapObject() { assertTrue("expected val3", "val3".equals(mapJsonObject.query("/key3"))); } + + /** + * RFC 7159 defines control characters to be U+0000 through U+001F. This test verifies that the parser is checking for these in expected ways. + */ + @Test + public void jsonObjectParseControlCharacters(){ + for(int i = 0;i<=0x001f;i++){ + final String charString = String.valueOf((char)i); + final String source = "{\"key\":\""+charString+"\"}"; + try { + JSONObject jo = new JSONObject(source); + assertTrue("Expected "+charString+"("+i+") in the JSON Object but did not find it.",charString.equals(jo.getString("key"))); + } catch (JSONException ex) { + assertTrue("Only \\0 (U+0000), \\n (U+000A), and \\r (U+000D) should cause an error. Instead "+charString+"("+i+") caused an error", + i=='\0' || i=='\n' || i=='\r' + ); + } + } + } + /** * Explore how JSONObject handles parsing errors. */ From c5deff636bd1413fab65ee0e64484c5422fd9a6e Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 16 Jun 2016 23:59:34 -0400 Subject: [PATCH 03/99] updates README for new project layout --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d08751d..40a4ebf 100644 --- a/README.md +++ b/README.md @@ -29,15 +29,22 @@ git clone https://github.com/stleary/JSON-Java-unit-test.git . \# Create a directory structure for the JSON-Java code ```` # Windows version -md /s src\org\json +md /s src\main\java\org\json +# *nix version +mkdir -p src/main/java/org/json ```` \# clone JSON-Java ```` -git clone https://github.com/stleary/JSON-Java.git src\org\json +#Windows version +git clone https://github.com/stleary/JSON-Java.git src\main\java\org\json + +#*Nix version +git clone https://github.com/stleary/JSON-Java.git src/main/java/org/json ```` \# Build, then execute the unit tests and code coverage ```` gradle clean build test jacocoTestReport + ```` Unit test results will be in build\reports\tests\index.html
Code coverage will be in build\reports\jacoco\html\index.html From 1204ea9dcf611b874d7b0feadad86f84da4c2a63 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Fri, 17 Jun 2016 00:04:27 -0400 Subject: [PATCH 04/99] fixes a typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40a4ebf..385c222 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ When adding a new unit test, don't forget to update JunitTestSuite.java. The fundamental issues with JSON-Java testing are:
* JSONObjects are unordered, making simple string comparison ineffective. -* Comparisons via **equals()** is not currently supported. Neither JSONArray nor JSONObject overrride hashCode() or equals(), so comparison defaults to the Object equals(), which is not useful. +* Comparisons via **equals()** is not currently supported. Neither JSONArray nor JSONObject override hashCode() or equals(), so comparison defaults to the Object equals(), which is not useful. * Access to the JSONArray and JSONObject internal containers for comparison is not currently available. General issues with unit testing are:
From c2de22471172bcc1e3c328c0a171c0155fc98e06 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Fri, 8 Jul 2016 16:58:58 -0400 Subject: [PATCH 05/99] Verify opt method conversions for JSONArray and JSONObject --- src/test/java/org/json/junit/JSONArrayTest.java | 16 ++++++++++++++++ src/test/java/org/json/junit/JSONObjectTest.java | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 7643ee0..ef3a608 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -3,6 +3,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -414,6 +416,20 @@ public void opt() { assertTrue("Array opt string default implicit", "".equals(jsonArray.optString(-1))); } + + /** + * Verifies that the opt methods properly convert string values. + */ + @Test + public void optStringConversion(){ + JSONArray ja = new JSONArray("[\"123\",\"true\",\"false\"]"); + assertTrue("unexpected optBoolean value",ja.optBoolean(1,false)==true); + assertTrue("unexpected optBoolean value",ja.optBoolean(2,true)==false); + assertTrue("unexpected optInt value",ja.optInt(0,0)==123); + assertTrue("unexpected optLong value",ja.optLong(0,0)==123); + assertTrue("unexpected optDouble value",ja.optDouble(0,0.0)==123.0); + assertTrue("unexpected optBigInteger value",ja.optBigInteger(0,BigInteger.ZERO).compareTo(new BigInteger("123"))==0); + assertTrue("unexpected optBigDecimal value",ja.optBigDecimal(0,BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); } /** * Exercise the JSONArray.put(value) method with various parameters diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index d550139..08ec964 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1735,6 +1735,22 @@ public void jsonObjectOptDefault() { assertTrue("optString() should return default string", "hi".equals(jsonObject.optString("hiKey", "hi"))); } + + /** + * Verifies that the opt methods properly convert string values. + */ + @Test + public void jsonObjectOptStringConversion() { + JSONObject jo = new JSONObject("{\"int\":\"123\",\"true\":\"true\",\"false\":\"false\"}"); + assertTrue("unexpected optBoolean value",jo.optBoolean("true",false)==true); + assertTrue("unexpected optBoolean value",jo.optBoolean("false",true)==false); + assertTrue("unexpected optInt value",jo.optInt("int",0)==123); + assertTrue("unexpected optLong value",jo.optLong("int",0)==123); + assertTrue("unexpected optDouble value",jo.optDouble("int",0.0)==123.0); + assertTrue("unexpected optBigInteger value",jo.optBigInteger("int",BigInteger.ZERO).compareTo(new BigInteger("123"))==0); + assertTrue("unexpected optBigDecimal value",jo.optBigDecimal("int",BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); + + } /** * Confirm behavior when JSONObject put(key, null object) is called From 215321cd28008cfd5b2192efa16cf10f737206c3 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 18 Jul 2016 15:01:36 -0400 Subject: [PATCH 06/99] updates Test cases to support new JSONML and XML conversion options --- src/test/java/org/json/junit/JSONMLTest.java | 37 ++++++++++++++++ src/test/java/org/json/junit/XMLTest.java | 44 ++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index 953a39d..1298591 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -698,4 +698,41 @@ public void commentsInXML() { Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray); } + /** + * JSON string with lost leading zero and converted "True" to true. See test + * result in comment below. + */ + @Test + public void testToJSONArray_jsonOutput() { + final String originalXml = "011000True"; + final String expectedJsonString = "[\"root\",[\"id\",\"01\"],[\"id\",1],[\"id\",\"00\"],[\"id\",0],[\"item\",{\"id\":\"01\"}],[\"title\",true]]"; + final JSONArray actualJsonOutput = JSONML.toJSONArray(originalXml, false); + assertEquals(expectedJsonString, actualJsonOutput.toString()); + } + + /** + * JSON string cannot be reverted to original xml. See test result in + * comment below. + */ + @Test + public void testToJSONArray_reversibility() { + final String originalXml = "011000True"; + final String revertedXml = JSONML.toString(JSONML.toJSONArray(originalXml, false)); + assertNotEquals(revertedXml, originalXml); + } + + /** + * test passes when using the new method toJsonML. + */ + @Test + public void testToJsonML() { + final String originalXml = "011000True"; + final String expectedJsonString = "[\"root\",[\"id\",\"01\"],[\"id\",\"1\"],[\"id\",\"00\"],[\"id\",\"0\"],[\"item\",{\"id\":\"01\"}],[\"title\",\"True\"]]"; + final JSONArray json = JSONML.toJSONArray(originalXml,true); + assertEquals(expectedJsonString, json.toString()); + + final String reverseXml = JSONML.toString(json); + assertEquals(originalXml, reverseXml); + } + } diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index d35c8ac..2f3fea7 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -1,12 +1,14 @@ package org.json.junit; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import org.json.JSONArray; import org.json.JSONException; +import org.json.JSONML; import org.json.JSONObject; import org.json.XML; import org.junit.Rule; @@ -723,4 +725,46 @@ private void compareFileToJSONObject(String xmlStr, String expectedStr) { } */ } + + /** + * JSON string lost leading zero and converted "True" to true. + */ + @Test + public void testToJSONArray_jsonOutput() { + final String originalXml = "011000True"; + final String expectedJsonString = "{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0],\"title\":true}}"; + final JSONObject actualJsonOutput = XML.toJSONObject(originalXml, false); + + assertEquals(expectedJsonString, actualJsonOutput.toString()); + } + + /** + * JSON string cannot be reverted to original xml. + */ + @Test + public void testToJSONArray_reversibility() { + final String originalXml = "011000True"; + final String revertedXml = XML.toString(XML.toJSONObject(originalXml, false)); + + assertNotEquals(revertedXml, originalXml); + } + + /** + * test passes when using the new method toJsonArray. + */ + @Test + public void testToJsonXML() { + final String originalXml = "011000True"; + final String expectedJsonString = "{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\"],\"title\":\"True\"}}"; + + final JSONObject json = XML.toJSONObject(originalXml,true); + assertEquals(expectedJsonString, json.toString()); + + final String reverseXml = XML.toString(json); + // this reversal isn't exactly the same. use JSONML for an exact reversal + final String expectedReverseXml = "01011000True"; + + assertEquals(expectedReverseXml, reverseXml); + } + } \ No newline at end of file From c3ba4bdbe5321c0cf2eeae9829e8a6508cd4665b Mon Sep 17 00:00:00 2001 From: Nicholas Cull Date: Sat, 23 Jul 2016 19:12:51 +1000 Subject: [PATCH 07/99] Nesting depth test works as expected. --- .../java/org/json/junit/JSONStringerTest.java | 59 ++++++++++++++++--- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/src/test/java/org/json/junit/JSONStringerTest.java b/src/test/java/org/json/junit/JSONStringerTest.java index 19b46de..d4376df 100644 --- a/src/test/java/org/json/junit/JSONStringerTest.java +++ b/src/test/java/org/json/junit/JSONStringerTest.java @@ -27,7 +27,7 @@ public void nullKeyException() { jsonStringer.key(null); assertTrue("Expected an exception", false); } catch (JSONException e) { - assertTrue("Expected an exception message", + assertTrue("Expected an exception message", "Null key.". equals(e.getMessage())); } @@ -44,7 +44,7 @@ public void outOfSequenceException() { jsonStringer.key("hi"); assertTrue("Expected an exception", false); } catch (JSONException e) { - assertTrue("Expected an exception message", + assertTrue("Expected an exception message", "Misplaced key.". equals(e.getMessage())); } @@ -61,7 +61,7 @@ public void missplacedArrayException() { try { jsonStringer.array(); } catch (JSONException e) { - assertTrue("Expected an exception message", + assertTrue("Expected an exception message", "Misplaced array.". equals(e.getMessage())); } @@ -78,7 +78,7 @@ public void missplacedEndArrayException() { try { jsonStringer.endArray(); } catch (JSONException e) { - assertTrue("Expected an exception message", + assertTrue("Expected an exception message", "Misplaced endArray.". equals(e.getMessage())); } @@ -95,7 +95,7 @@ public void missplacedEndObjectException() { try { jsonStringer.endObject(); } catch (JSONException e) { - assertTrue("Expected an exception message", + assertTrue("Expected an exception message", "Misplaced endObject.". equals(e.getMessage())); } @@ -112,7 +112,7 @@ public void missplacedObjectException() { try { jsonStringer.object(); } catch (JSONException e) { - assertTrue("Expected an exception message", + assertTrue("Expected an exception message", "Misplaced object.". equals(e.getMessage())); } @@ -125,7 +125,47 @@ public void missplacedObjectException() { @Test public void exceedNestDepthException() { try { - new JSONStringer().object(). + JSONStringer s = new JSONStringer(); + s.object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). + key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(); + s.key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). @@ -165,9 +205,10 @@ public void exceedNestDepthException() { key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(); + fail("Expected an exception message"); } catch (JSONException e) { - assertTrue("Expected an exception message", - "". + assertTrue("Expected an exception message", + "Nesting too deep.". equals(e.getMessage())); } } From 72c2b911bfba67472c6d03bdb4ffa12c47b56b70 Mon Sep 17 00:00:00 2001 From: Nicholas Cull Date: Sat, 23 Jul 2016 22:33:19 +1000 Subject: [PATCH 08/99] Tests for toString(), write(), toList(), and toMap(). Explicitly test variations of toString() and write() for different indent levels, and different method overloads. Also create some tests for the new toList() and toMap() methods for coverage improvements to JSONArray and JSONObject. --- .../java/org/json/junit/JSONArrayTest.java | 195 ++++++++++++++++++ .../java/org/json/junit/JSONObjectTest.java | 180 +++++++++++++++- 2 files changed, 373 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index ef3a608..c818e8b 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -2,7 +2,10 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import java.io.StringWriter; +import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; @@ -639,6 +642,71 @@ public void notSimilar() { !jsonArray.similar(otherJsonArray)); } + /** + * Exercise JSONArray toString() method with various indent levels. + */ + @Test + public void jsonArrayToStringIndent() { + String jsonArray0Str = + "[" + + "[1,2," + + "{\"key3\":true}" + + "]," + + "{\"key1\":\"val1\",\"key2\":" + + "{\"key2\":\"val2\"}" + + "}," + + "[" + + "[1,2.1]" + + "," + + "[null]" + + "]" + + "]"; + + String jsonArray1Str = + "[\n" + + " [\n" + + " 1,\n" + + " 2,\n" + + " {\"key3\": true}\n" + + " ],\n" + + " {\n" + + " \"key1\": \"val1\",\n" + + " \"key2\": {\"key2\": \"val2\"}\n" + + " },\n" + + " [\n" + + " [\n" + + " 1,\n" + + " 2.1\n" + + " ],\n" + + " [null]\n" + + " ]\n" + + "]"; + String jsonArray4Str = + "[\n" + + " [\n" + + " 1,\n" + + " 2,\n" + + " {\"key3\": true}\n" + + " ],\n" + + " {\n" + + " \"key1\": \"val1\",\n" + + " \"key2\": {\"key2\": \"val2\"}\n" + + " },\n" + + " [\n" + + " [\n" + + " 1,\n" + + " 2.1\n" + + " ],\n" + + " [null]\n" + + " ]\n" + + "]"; + JSONArray jsonArray = new JSONArray(jsonArray0Str); + assertEquals(jsonArray0Str, jsonArray.toString()); + assertEquals(jsonArray0Str, jsonArray.toString(0)); + assertEquals(jsonArray1Str, jsonArray.toString(1)); + assertEquals(jsonArray4Str, jsonArray.toString(4)); + } + /** * Convert an empty JSONArray to JSONObject */ @@ -726,4 +794,131 @@ public void optQueryWithNoResult() { public void optQueryWithSyntaxError() { new JSONArray().optQuery("invalid"); } + + + /** + * Exercise the JSONArray write() method + */ + @Test + public void write() { + String str = "[\"value1\",\"value2\",{\"key1\":1,\"key2\":2,\"key3\":3}]"; + String expectedStr = str; + JSONArray jsonArray = new JSONArray(str); + StringWriter stringWriter = new StringWriter(); + Writer writer = jsonArray.write(stringWriter); + String actualStr = writer.toString(); + assertTrue("write() expected " + expectedStr + + "but found " + actualStr, + expectedStr.equals(actualStr)); + StringBuilder stringBuilder = new StringBuilder(); + Appendable appendable = jsonArray.write(stringBuilder); + actualStr = appendable.toString(); + assertTrue("write() expected " + expectedStr + + "but found " + actualStr, + expectedStr.equals(actualStr)); + } + + /** + * Exercise the JSONArray write(Appendable, int, int) method + */ + @Test + public void write3Param() { + String str0 = "[\"value1\",\"value2\",{\"key1\":1,\"key2\":false,\"key3\":3.14}]"; + String str2 = + "[\n" + + " \"value1\",\n" + + " \"value2\",\n" + + " {\n" + + " \"key1\": 1,\n" + + " \"key2\": false,\n" + + " \"key3\": 3.14\n" + + " }\n" + + " ]"; + String expectedStr = str0; + JSONArray jsonArray = new JSONArray(str0); + StringWriter stringWriter = new StringWriter(); + Writer writer = jsonArray.write(stringWriter, 0, 0); + String actualStr = writer.toString(); + assertEquals(expectedStr, actualStr); + expectedStr = str0; + StringBuilder stringBuilder = new StringBuilder(); + Appendable appendable = jsonArray.write(stringBuilder, 0, 0); + actualStr = appendable.toString(); + assertEquals(expectedStr, actualStr); + expectedStr = str2; + stringBuilder = new StringBuilder(); + appendable = jsonArray.write(stringBuilder, 2, 1); + actualStr = appendable.toString(); + assertEquals(expectedStr, actualStr); + } + + /** + * Exercise JSONArray toString() method with various indent levels. + */ + @Test + public void toList() { + String jsonArrayStr = + "[" + + "[1,2," + + "{\"key3\":true}" + + "]," + + "{\"key1\":\"val1\",\"key2\":" + + "{\"key2\":null}," + + "\"key3\":42,\"key4\":[]" + + "}," + + "[" + + "[\"value1\",2.1]" + + "," + + "[null]" + + "]" + + "]"; + + JSONArray jsonArray = new JSONArray(jsonArrayStr); + List list = jsonArray.toList(); + + assertTrue("List should not be null", list != null); + assertTrue("List should have 3 elements", list.size() == 3); + + List val1List = (List) list.get(0); + assertTrue("val1 should not be null", val1List != null); + assertTrue("val1 should have 3 elements", val1List.size() == 3); + + assertTrue("val1 value 1 should be 1", val1List.get(0).equals(Integer.valueOf(1))); + assertTrue("val1 value 2 should be 2", val1List.get(1).equals(Integer.valueOf(2))); + + Map key1Value3Map = (Map)val1List.get(2); + assertTrue("Map should not be null", key1Value3Map != null); + assertTrue("Map should have 1 element", key1Value3Map.size() == 1); + assertTrue("Map key3 should be true", key1Value3Map.get("key3").equals(Boolean.TRUE)); + + Map val2Map = (Map) list.get(1); + assertTrue("val2 should not be null", val2Map != null); + assertTrue("val2 should have 4 elements", val2Map.size() == 4); + assertTrue("val2 map key 1 should be val1", val2Map.get("key1").equals("val1")); + assertTrue("val2 map key 3 should be 42", val2Map.get("key3").equals(Integer.valueOf(42))); + + Map val2Key2Map = (Map)val2Map.get("key2"); + assertTrue("val2 map key 2 should not be null", val2Key2Map != null); + assertTrue("val2 map key 2 should have an entry", val2Key2Map.containsKey("key2")); + assertTrue("val2 map key 2 value should be null", val2Key2Map.get("key2") == null); + + List val2Key4List = (List)val2Map.get("key4"); + assertTrue("val2 map key 4 should not be null", val2Key4List != null); + assertTrue("val2 map key 4 should be empty", val2Key4List.isEmpty()); + + List val3List = (List) list.get(2); + assertTrue("val3 should not be null", val3List != null); + assertTrue("val3 should have 2 elements", val3List.size() == 2); + + List val3Val1List = (List)val3List.get(0); + assertTrue("val3 list val 1 should not be null", val3Val1List != null); + assertTrue("val3 list val 1 should have 2 elements", val3Val1List.size() == 2); + assertTrue("val3 list val 1 list element 1 should be value1", val3Val1List.get(0).equals("value1")); + assertTrue("val3 list val 1 list element 2 should be 2.1", val3Val1List.get(1).equals(Double.valueOf("2.1"))); + + List val3Val2List = (List)val3List.get(1); + assertTrue("val3 list val 2 should not be null", val3Val2List != null); + assertTrue("val3 list val 2 should have 1 element", val3Val2List.size() == 1); + assertTrue("val3 list val 2 list element 1 should be null", val3Val2List.get(0) == null); + } } diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 08ec964..73029e7 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -1371,6 +1372,74 @@ public void jsonObjectToString() { assertTrue("expected myVal4", "myVal4".equals(jsonObject.query("/objectKey/myKey4"))); } + /** + * Exercise JSONObject toString() method with various indent levels. + */ + @Test + public void jsonObjectToStringIndent() { + String jsonObject0Str = + "{"+ + "\"key1\":" + + "[1,2," + + "{\"key3\":true}" + + "],"+ + "\"key2\":" + + "{\"key1\":\"val1\",\"key2\":" + + "{\"key2\":\"val2\"}" + + "},"+ + "\"key3\":" + + "[" + + "[1,2.1]" + + "," + + "[null]" + + "]"+ + "}"; + + String jsonObject1Str = + "{\n" + + " \"key1\": [\n" + + " 1,\n" + + " 2,\n" + + " {\"key3\": true}\n" + + " ],\n" + + " \"key2\": {\n" + + " \"key1\": \"val1\",\n" + + " \"key2\": {\"key2\": \"val2\"}\n" + + " },\n" + + " \"key3\": [\n" + + " [\n" + + " 1,\n" + + " 2.1\n" + + " ],\n" + + " [null]\n" + + " ]\n" + + "}"; + String jsonObject4Str = + "{\n" + + " \"key1\": [\n" + + " 1,\n" + + " 2,\n" + + " {\"key3\": true}\n" + + " ],\n" + + " \"key2\": {\n" + + " \"key1\": \"val1\",\n" + + " \"key2\": {\"key2\": \"val2\"}\n" + + " },\n" + + " \"key3\": [\n" + + " [\n" + + " 1,\n" + + " 2.1\n" + + " ],\n" + + " [null]\n" + + " ]\n" + + "}"; + JSONObject jsonObject = new JSONObject(jsonObject0Str); + assertEquals(jsonObject0Str, jsonObject.toString()); + assertEquals(jsonObject0Str, jsonObject.toString(0)); + assertEquals(jsonObject1Str, jsonObject.toString(1)); + assertEquals(jsonObject4Str, jsonObject.toString(4)); + } + /** * Explores how JSONObject handles maps. Insert a string/string map * as a value in a JSONObject. It will remain a map. Convert the @@ -1441,7 +1510,7 @@ public void valueToString() { String jsonArrayStr = "[1,2,3]"; JSONArray jsonArray = new JSONArray(jsonArrayStr); - assertTrue("jsonArra valueToString() incorrect", + assertTrue("jsonArray valueToString() incorrect", JSONObject.valueToString(jsonArray).equals(jsonArray.toString())); Map map = new HashMap(); map.put("key1", "val1"); @@ -1840,7 +1909,7 @@ public void toJSONArray() { */ @Test public void write() { - String str = "{\"key\":\"value\"}"; + String str = "{\"key1\":\"value1\",\"key2\":[1,2,3]}"; String expectedStr = str; JSONObject jsonObject = new JSONObject(str); StringWriter stringWriter = new StringWriter(); @@ -1849,6 +1918,45 @@ public void write() { assertTrue("write() expected " +expectedStr+ "but found " +actualStr, expectedStr.equals(actualStr)); + StringBuilder stringBuilder = new StringBuilder(); + Appendable appendable = jsonObject.write(stringBuilder); + actualStr = appendable.toString(); + assertTrue("write() expected " +expectedStr+ + "but found " +actualStr, + expectedStr.equals(actualStr)); + } + + /** + * Exercise the JSONObject write(Appendable, int, int) method + */ + @Test + public void write3Param() { + String str0 = "{\"key1\":\"value1\",\"key2\":[1,false,3.14]}"; + String str2 = + "{\n" + + " \"key1\": \"value1\",\n" + + " \"key2\": [\n" + + " 1,\n" + + " false,\n" + + " 3.14\n" + + " ]\n" + + " }"; + String expectedStr = str0; + JSONObject jsonObject = new JSONObject(str0); + StringWriter stringWriter = new StringWriter(); + Writer writer = jsonObject.write(stringWriter,0,0); + String actualStr = writer.toString(); + assertEquals(expectedStr, actualStr); + expectedStr = str0; + StringBuilder stringBuilder = new StringBuilder(); + Appendable appendable = jsonObject.write(stringBuilder,0,0); + actualStr = appendable.toString(); + assertEquals(expectedStr, actualStr); + expectedStr = str2; + stringBuilder = new StringBuilder(); + appendable = jsonObject.write(stringBuilder,2,1); + actualStr = appendable.toString(); + assertEquals(expectedStr, actualStr); } /** @@ -1966,4 +2074,72 @@ public void invalidEscapeSequence() { String json = "{ \"\\url\": \"value\" }"; new JSONObject(json); } + + /** + * Exercise JSONObject toMap() method. + */ + @Test + public void toMap() { + String jsonObjectStr = + "{" + + "\"key1\":" + + "[1,2," + + "{\"key3\":true}" + + "]," + + "\"key2\":" + + "{\"key1\":\"val1\",\"key2\":" + + "{\"key2\":null}," + + "\"key3\":42" + + "}," + + "\"key3\":" + + "[" + + "[\"value1\",2.1]" + + "," + + "[null]" + + "]" + + "}"; + + JSONObject jsonObject = new JSONObject(jsonObjectStr); + Map map = jsonObject.toMap(); + + assertTrue("Map should not be null", map != null); + assertTrue("Map should have 3 elements", map.size() == 3); + + List key1List = (List)map.get("key1"); + assertTrue("key1 should not be null", key1List != null); + assertTrue("key1 list should have 3 elements", key1List.size() == 3); + assertTrue("key1 value 1 should be 1", key1List.get(0).equals(Integer.valueOf(1))); + assertTrue("key1 value 2 should be 2", key1List.get(1).equals(Integer.valueOf(2))); + + Map key1Value3Map = (Map)key1List.get(2); + assertTrue("Map should not be null", key1Value3Map != null); + assertTrue("Map should have 1 element", key1Value3Map.size() == 1); + assertTrue("Map key3 should be true", key1Value3Map.get("key3").equals(Boolean.TRUE)); + + Map key2Map = (Map)map.get("key2"); + assertTrue("key2 should not be null", key2Map != null); + assertTrue("key2 map should have 3 elements", key2Map.size() == 3); + assertTrue("key2 map key 1 should be val1", key2Map.get("key1").equals("val1")); + assertTrue("key2 map key 3 should be 42", key2Map.get("key3").equals(Integer.valueOf(42))); + + Map key2Val2Map = (Map)key2Map.get("key2"); + assertTrue("key2 map key 2 should not be null", key2Val2Map != null); + assertTrue("key2 map key 2 should have an entry", key2Val2Map.containsKey("key2")); + assertTrue("key2 map key 2 value should be null", key2Val2Map.get("key2") == null); + + List key3List = (List)map.get("key3"); + assertTrue("key3 should not be null", key3List != null); + assertTrue("key3 list should have 3 elements", key3List.size() == 2); + + List key3Val1List = (List)key3List.get(0); + assertTrue("key3 list val 1 should not be null", key3Val1List != null); + assertTrue("key3 list val 1 should have 2 elements", key3Val1List.size() == 2); + assertTrue("key3 list val 1 list element 1 should be value1", key3Val1List.get(0).equals("value1")); + assertTrue("key3 list val 1 list element 2 should be 2.1", key3Val1List.get(1).equals(Double.valueOf("2.1"))); + + List key3Val2List = (List)key3List.get(1); + assertTrue("key3 list val 2 should not be null", key3Val2List != null); + assertTrue("key3 list val 2 should have 1 element", key3Val2List.size() == 1); + assertTrue("key3 list val 2 list element 1 should be null", key3Val2List.get(0) == null); + } } From ae77b5cd83121555152a13407fce230992afc0c0 Mon Sep 17 00:00:00 2001 From: Nicholas Cull Date: Sat, 23 Jul 2016 22:51:50 +1000 Subject: [PATCH 09/99] Tests for deep copy and mutability of toList() and toMap(). Both toMap() and toList() return deep copies, which are also mutable. That is, any changes to the JSONObject or JSONArray do not affect the newly create Map or List, and vice-versa. The resulting objects can be altered. --- src/test/java/org/json/junit/JSONArrayTest.java | 8 ++++++++ src/test/java/org/json/junit/JSONObjectTest.java | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index c818e8b..9f0e773 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -920,5 +920,13 @@ public void toList() { assertTrue("val3 list val 2 should not be null", val3Val2List != null); assertTrue("val3 list val 2 should have 1 element", val3Val2List.size() == 1); assertTrue("val3 list val 2 list element 1 should be null", val3Val2List.get(0) == null); + + // assert that toList() is a deep copy + jsonArray.getJSONObject(1).put("key1", "still val1"); + assertTrue("val2 map key 1 should be val1", val2Map.get("key1").equals("val1")); + + // assert that the new list is mutable + assertTrue("Removing an entry should succeed", list.remove(2) != null); + assertTrue("List should have 2 elements", list.size() == 2); } } diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 73029e7..10405b0 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -2141,5 +2141,14 @@ public void toMap() { assertTrue("key3 list val 2 should not be null", key3Val2List != null); assertTrue("key3 list val 2 should have 1 element", key3Val2List.size() == 1); assertTrue("key3 list val 2 list element 1 should be null", key3Val2List.get(0) == null); + + // Assert that toMap() is a deep copy + jsonObject.getJSONArray("key3").getJSONArray(0).put(0, "still value 1"); + assertTrue("key3 list val 1 list element 1 should be value1", key3Val1List.get(0).equals("value1")); + + // assert that the new map is mutable + assertTrue("Removing a key should succeed", map.remove("key3") != null); + assertTrue("Map should have 2 elements", map.size() == 2); + } } From 6b4edbd40c115e2895af9e3c68908e5ede7ac03e Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sat, 23 Jul 2016 10:02:19 -0500 Subject: [PATCH 10/99] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 385c222..2e2fcc8 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ git clone https://github.com/stleary/JSON-Java-unit-test.git . ```` \# Create a directory structure for the JSON-Java code ```` -# Windows version -md /s src\main\java\org\json +# Windows 10 version +mkdir src\main\java\org\json # *nix version mkdir -p src/main/java/org/json ```` From 2307f6f85e535df6b925056667a7b8f4671e1a99 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sat, 23 Jul 2016 10:12:04 -0500 Subject: [PATCH 11/99] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 2e2fcc8..e45f7bf 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,13 @@ git clone https://github.com/stleary/JSON-Java.git src/main/java/org/json gradle clean build test jacocoTestReport ```` +\# Eclipse setup requires the Gradle IDE plug-in +\# I use Gradle IDE 3.6.4.201503050952-RELEASE org.springsource.ide.eclipse.gradle.feature.feature.group Pivotal Software, Inc. +```` +File > Import > Gradle project > (navigate to your directory) > Build Model > (Select your directory) > Finish +(It is not necessary to run "gradle eclipse" on the project, from the command line) +```` + Unit test results will be in build\reports\tests\index.html
Code coverage will be in build\reports\jacoco\html\index.html From cdfdaba95bb489475ea0aacdbb2f940e1a3dafe0 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sat, 23 Jul 2016 10:12:33 -0500 Subject: [PATCH 12/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e45f7bf..54e085d 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ git clone https://github.com/stleary/JSON-Java.git src/main/java/org/json gradle clean build test jacocoTestReport ```` -\# Eclipse setup requires the Gradle IDE plug-in +\# Eclipse setup requires the Gradle IDE plug-in
\# I use Gradle IDE 3.6.4.201503050952-RELEASE org.springsource.ide.eclipse.gradle.feature.feature.group Pivotal Software, Inc. ```` File > Import > Gradle project > (navigate to your directory) > Build Model > (Select your directory) > Finish From 5d8ea6fa4e91467adce884666b0a26c694701800 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sat, 23 Jul 2016 10:13:21 -0500 Subject: [PATCH 13/99] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 54e085d..faf400a 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,8 @@ gradle clean build test jacocoTestReport ```` \# Eclipse setup requires the Gradle IDE plug-in
-\# I use Gradle IDE 3.6.4.201503050952-RELEASE org.springsource.ide.eclipse.gradle.feature.feature.group Pivotal Software, Inc. +\# I use Gradle IDE 3.6.4.201503050952-RELEASE org.springsource.ide.eclipse.gradle.feature.feature.group Pivotal Software, Inc.
+\# From the Eclipse IDE: ```` File > Import > Gradle project > (navigate to your directory) > Build Model > (Select your directory) > Finish (It is not necessary to run "gradle eclipse" on the project, from the command line) From ffcfa66d7798061df9a5450ce9579d6ee6bbce9f Mon Sep 17 00:00:00 2001 From: Nicholas Cull Date: Sun, 24 Jul 2016 18:56:08 +1000 Subject: [PATCH 14/99] Add JSONString test class. This set of tests demonstrates what happens when JSONString returns various results from its toJSONString() method. Tests for null returns and exceptions thrown. Also tests what happens for non-JSONString objects. The intent is to cover JSONObject's valueToString() and writeValue() methods. --- .../java/org/json/junit/JSONStringTest.java | 310 ++++++++++++++++++ .../java/org/json/junit/JunitTestSuite.java | 7 +- 2 files changed, 314 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/json/junit/JSONStringTest.java diff --git a/src/test/java/org/json/junit/JSONStringTest.java b/src/test/java/org/json/junit/JSONStringTest.java new file mode 100644 index 0000000..c7d9d3e --- /dev/null +++ b/src/test/java/org/json/junit/JSONStringTest.java @@ -0,0 +1,310 @@ +package org.json.junit; + +import static org.junit.Assert.*; + +import java.io.StringWriter; +import java.util.*; + +import org.json.*; +import org.junit.Test; + +/** + * Tests for JSONString implementations, and the difference between + * {@link JSONObject#valueToString} and {@link JSONObject#writeValue}. + */ +public class JSONStringTest { + + /** + * This tests the JSONObject.writeValue() method. We can't test directly + * due to it being a package-protected method. Instead, we can call + * JSONArray.write(), which delegates the writing of each entry to + * writeValue(). + */ + @Test + public void writeValues() throws Exception { + JSONArray jsonArray = new JSONArray(); + jsonArray.put((Object)null); + + StringWriter writer = new StringWriter(); + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[null]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put(JSONObject.NULL); + writer = new StringWriter(); + output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[null]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put(new JSONObject()); + writer = new StringWriter(); + output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[{}]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put(new JSONArray()); + writer = new StringWriter(); + output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[[]]".equals(output)); + + jsonArray = new JSONArray(); + Map singleMap = Collections.singletonMap("key1", "value1"); + jsonArray.put((Object)singleMap); + writer = new StringWriter(); + output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[{\"key1\":\"value1\"}]".equals(output)); + + jsonArray = new JSONArray(); + List singleList = Collections.singletonList("entry1"); + jsonArray.put((Object)singleList); + writer = new StringWriter(); + output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[[\"entry1\"]]".equals(output)); + + jsonArray = new JSONArray(); + int[] intArray = new int[] { 1, 2, 3 }; + jsonArray.put(intArray); + writer = new StringWriter(); + output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[[1,2,3]]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put(24); + writer = new StringWriter(); + output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[24]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put("string value"); + writer = new StringWriter(); + output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[\"string value\"]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put(true); + writer = new StringWriter(); + output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[true]".equals(output)); + + } + + /** + * This tests the JSONObject.valueToString() method. These should be + * identical to the values above, except for the enclosing [ and ]. + */ + @Test + public void valuesToString() throws Exception { + + String output = JSONObject.valueToString(null); + assertTrue("String values should be equal", "null".equals(output)); + + output = JSONObject.valueToString(JSONObject.NULL); + assertTrue("String values should be equal", "null".equals(output)); + + output = JSONObject.valueToString(new JSONObject()); + assertTrue("String values should be equal", "{}".equals(output)); + + output = JSONObject.valueToString(new JSONArray()); + assertTrue("String values should be equal", "[]".equals(output)); + + Map singleMap = Collections.singletonMap("key1", "value1"); + output = JSONObject.valueToString(singleMap); + assertTrue("String values should be equal", "{\"key1\":\"value1\"}".equals(output)); + + List singleList = Collections.singletonList("entry1"); + output = JSONObject.valueToString(singleList); + assertTrue("String values should be equal", "[\"entry1\"]".equals(output)); + + int[] intArray = new int[] { 1, 2, 3 }; + output = JSONObject.valueToString(intArray); + assertTrue("String values should be equal", "[1,2,3]".equals(output)); + + output = JSONObject.valueToString(24); + assertTrue("String values should be equal", "24".equals(output)); + + output = JSONObject.valueToString("string value"); + assertTrue("String values should be equal", "\"string value\"".equals(output)); + + output = JSONObject.valueToString(true); + assertTrue("String values should be equal", "true".equals(output)); + + } + + /** + * Test what happens when toJSONString() returns a well-formed JSON value. + * This is the usual case. + */ + @Test + public void testJSONStringValue() throws Exception { + JSONStringValue jsonString = new JSONStringValue(); + JSONArray jsonArray = new JSONArray(); + + jsonArray.put(jsonString); + + StringWriter writer = new StringWriter(); + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[\"the JSON string value\"]".equals(output)); + + output = JSONObject.valueToString(jsonString); + assertTrue("String values should be equal", "\"the JSON string value\"".equals(output)); + } + + /** + * Test what happens when toJSONString() returns null. In one case, + * use the object's toString() method. In the other, throw a JSONException. + */ + @Test + public void testJSONNullStringValue() throws Exception { + JSONNullStringValue jsonString = new JSONNullStringValue(); + JSONArray jsonArray = new JSONArray(); + + jsonArray.put(jsonString); + + StringWriter writer = new StringWriter(); + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[\"the toString value\"]".equals(output)); + + // The first different between writeValue() and valueToString(): + // in this case, valueToString throws a JSONException + try { + output = JSONObject.valueToString(jsonString); + fail("Expected an exception, got a String value"); + } catch (Exception e) { + assertTrue("Expected JSONException", e instanceof JSONException); + assertTrue("Exception message does not match", "Bad value from toJSONString: null".equals(e.getMessage())); + } + } + + /** + * Test what happens when toJSONString() returns an exception. In both + * cases, a JSONException is thrown, with the cause and message set from + * the original exception. + */ + @Test + public void testJSONStringExceptionValue() throws Exception { + JSONStringExceptionValue jsonString = new JSONStringExceptionValue(); + JSONArray jsonArray = new JSONArray(); + + jsonArray.put(jsonString); + + StringWriter writer = new StringWriter(); + String output = null; + try { + output = jsonArray.write(writer).toString(); + fail("Expected an exception, got a String value"); + } catch (Exception e) { + assertTrue("Expected JSONException", e instanceof JSONException); + assertTrue("Exception message does not match", "the exception value".equals(e.getMessage())); + } + + try { + output = JSONObject.valueToString(jsonString); + fail("Expected an exception, got a String value"); + } catch (Exception e) { + assertTrue("Expected JSONException", e instanceof JSONException); + assertTrue("Exception message does not match", "the exception value".equals(e.getMessage())); + } + } + + /** + * Test what happens when a Java object's toString() returns a String value. + * This is the usual case. + */ + @Test + public void testStringValue() throws Exception { + StringValue nonJsonString = new StringValue(); + JSONArray jsonArray = new JSONArray(); + + jsonArray.put(nonJsonString); + + StringWriter writer = new StringWriter(); + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[\"the toString value for StringValue\"]".equals(output)); + + output = JSONObject.valueToString(nonJsonString); + assertTrue("String values should be equal", "\"the toString value for StringValue\"".equals(output)); + } + + /** + * Test what happens when a Java object's toString() returns null. + * Defaults to empty string. + */ + @Test + public void testNullStringValue() throws Exception { + NullStringValue nonJsonString = new NullStringValue(); + JSONArray jsonArray = new JSONArray(); + + jsonArray.put(nonJsonString); + + StringWriter writer = new StringWriter(); + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[\"\"]".equals(output)); + + output = JSONObject.valueToString(nonJsonString); + assertTrue("String values should be equal", "\"\"".equals(output)); + } + + /** + * A JSONString that returns a valid JSON string value. + */ + private static final class JSONStringValue implements JSONString { + + @Override + public String toJSONString() { + return "\"the JSON string value\""; + } + + @Override + public String toString() { + return "the toString value for JSONStringValue"; + } + } + + /** + * A JSONString that returns null when calling toJSONString(). + */ + private static final class JSONNullStringValue implements JSONString { + + @Override + public String toJSONString() { + return null; + } + + @Override + public String toString() { + return "the toString value"; + } + } + + /** + * A JSONString that throw an exception when calling toJSONString(). + */ + private static final class JSONStringExceptionValue implements JSONString { + + @Override + public String toJSONString() { + throw new IllegalStateException("the exception value"); + } + + @Override + public String toString() { + return "the toString value for JSONStringExceptionValue"; + } + } + + public static final class StringValue { + + @Override + public String toString() { + return "the toString value for StringValue"; + } + } + + public static final class NullStringValue { + + @Override + public String toString() { + return null; + } + } +} diff --git a/src/test/java/org/json/junit/JunitTestSuite.java b/src/test/java/org/json/junit/JunitTestSuite.java index 3863931..3a7223e 100644 --- a/src/test/java/org/json/junit/JunitTestSuite.java +++ b/src/test/java/org/json/junit/JunitTestSuite.java @@ -15,7 +15,8 @@ JSONObjectTest.class, JSONArrayTest.class, EnumTest.class, - JSONPointerTest.class + JSONPointerTest.class, + JSONStringTest.class }) -public class JunitTestSuite { -} +public class JunitTestSuite { +} From 1246e12827fce05f70ce6758df647ea436d6578b Mon Sep 17 00:00:00 2001 From: Nicholas Cull Date: Sun, 24 Jul 2016 19:39:52 +1000 Subject: [PATCH 15/99] Factor out Writer from Appendable tests. --- .../java/org/json/junit/JSONArrayTest.java | 56 ++++++++++++++++--- .../java/org/json/junit/JSONObjectTest.java | 53 +++++++++++++++--- 2 files changed, 94 insertions(+), 15 deletions(-) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 9f0e773..13dbb39 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -802,24 +802,36 @@ public void optQueryWithSyntaxError() { @Test public void write() { String str = "[\"value1\",\"value2\",{\"key1\":1,\"key2\":2,\"key3\":3}]"; - String expectedStr = str; JSONArray jsonArray = new JSONArray(str); + String expectedStr = str; StringWriter stringWriter = new StringWriter(); Writer writer = jsonArray.write(stringWriter); String actualStr = writer.toString(); assertTrue("write() expected " + expectedStr + - "but found " + actualStr, + " but found " + actualStr, expectedStr.equals(actualStr)); + } + + /** + * Exercise the JSONArray write() method using Appendable. + */ +/* + @Test + public void writeAppendable() { + String str = "[\"value1\",\"value2\",{\"key1\":1,\"key2\":2,\"key3\":3}]"; + JSONArray jsonArray = new JSONArray(str); + String expectedStr = str; StringBuilder stringBuilder = new StringBuilder(); Appendable appendable = jsonArray.write(stringBuilder); - actualStr = appendable.toString(); + String actualStr = appendable.toString(); assertTrue("write() expected " + expectedStr + - "but found " + actualStr, + " but found " + actualStr, expectedStr.equals(actualStr)); } +*/ /** - * Exercise the JSONArray write(Appendable, int, int) method + * Exercise the JSONArray write(Writer, int, int) method */ @Test public void write3Param() { @@ -834,23 +846,51 @@ public void write3Param() { " \"key3\": 3.14\n" + " }\n" + " ]"; - String expectedStr = str0; JSONArray jsonArray = new JSONArray(str0); + String expectedStr = str0; StringWriter stringWriter = new StringWriter(); Writer writer = jsonArray.write(stringWriter, 0, 0); String actualStr = writer.toString(); assertEquals(expectedStr, actualStr); - expectedStr = str0; + + expectedStr = str2; + stringWriter = new StringWriter(); + writer = jsonArray.write(stringWriter, 2, 1); + actualStr = writer.toString(); + assertEquals(expectedStr, actualStr); + } + + /** + * Exercise the JSONArray write(Appendable, int, int) method + */ +/* + @Test + public void write3ParamAppendable() { + String str0 = "[\"value1\",\"value2\",{\"key1\":1,\"key2\":false,\"key3\":3.14}]"; + String str2 = + "[\n" + + " \"value1\",\n" + + " \"value2\",\n" + + " {\n" + + " \"key1\": 1,\n" + + " \"key2\": false,\n" + + " \"key3\": 3.14\n" + + " }\n" + + " ]"; + JSONArray jsonArray = new JSONArray(str0); + String expectedStr = str0; StringBuilder stringBuilder = new StringBuilder(); Appendable appendable = jsonArray.write(stringBuilder, 0, 0); - actualStr = appendable.toString(); + String actualStr = appendable.toString(); assertEquals(expectedStr, actualStr); + expectedStr = str2; stringBuilder = new StringBuilder(); appendable = jsonArray.write(stringBuilder, 2, 1); actualStr = appendable.toString(); assertEquals(expectedStr, actualStr); } +*/ /** * Exercise JSONArray toString() method with various indent levels. diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 10405b0..df1b141 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1916,18 +1916,30 @@ public void write() { Writer writer = jsonObject.write(stringWriter); String actualStr = writer.toString(); assertTrue("write() expected " +expectedStr+ - "but found " +actualStr, + " but found " +actualStr, expectedStr.equals(actualStr)); + } + + /** + * Exercise the JSONObject write() method + */ +/* + @Test + public void writeAppendable() { + String str = "{\"key1\":\"value1\",\"key2\":[1,2,3]}"; + String expectedStr = str; + JSONObject jsonObject = new JSONObject(str); StringBuilder stringBuilder = new StringBuilder(); Appendable appendable = jsonObject.write(stringBuilder); - actualStr = appendable.toString(); + String actualStr = appendable.toString(); assertTrue("write() expected " +expectedStr+ - "but found " +actualStr, + " but found " +actualStr, expectedStr.equals(actualStr)); } +*/ /** - * Exercise the JSONObject write(Appendable, int, int) method + * Exercise the JSONObject write(Writer, int, int) method */ @Test public void write3Param() { @@ -1941,23 +1953,50 @@ public void write3Param() { " 3.14\n" + " ]\n" + " }"; - String expectedStr = str0; JSONObject jsonObject = new JSONObject(str0); + String expectedStr = str0; StringWriter stringWriter = new StringWriter(); Writer writer = jsonObject.write(stringWriter,0,0); String actualStr = writer.toString(); assertEquals(expectedStr, actualStr); - expectedStr = str0; + + expectedStr = str2; + stringWriter = new StringWriter(); + writer = jsonObject.write(stringWriter,2,1); + actualStr = writer.toString(); + assertEquals(expectedStr, actualStr); + } + + /** + * Exercise the JSONObject write(Appendable, int, int) method + */ +/* + @Test + public void write3ParamAppendable() { + String str0 = "{\"key1\":\"value1\",\"key2\":[1,false,3.14]}"; + String str2 = + "{\n" + + " \"key1\": \"value1\",\n" + + " \"key2\": [\n" + + " 1,\n" + + " false,\n" + + " 3.14\n" + + " ]\n" + + " }"; + JSONObject jsonObject = new JSONObject(str0); + String expectedStr = str0; StringBuilder stringBuilder = new StringBuilder(); Appendable appendable = jsonObject.write(stringBuilder,0,0); - actualStr = appendable.toString(); + String actualStr = appendable.toString(); assertEquals(expectedStr, actualStr); + expectedStr = str2; stringBuilder = new StringBuilder(); appendable = jsonObject.write(stringBuilder,2,1); actualStr = appendable.toString(); assertEquals(expectedStr, actualStr); } +*/ /** * Exercise the JSONObject equals() method From efe33a1e370917ca571db5b95a0372b44a052afb Mon Sep 17 00:00:00 2001 From: Nicholas Cull Date: Sun, 24 Jul 2016 19:57:01 +1000 Subject: [PATCH 16/99] Fix comment. --- src/test/java/org/json/junit/JSONStringTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/JSONStringTest.java b/src/test/java/org/json/junit/JSONStringTest.java index c7d9d3e..cba5d09 100644 --- a/src/test/java/org/json/junit/JSONStringTest.java +++ b/src/test/java/org/json/junit/JSONStringTest.java @@ -164,7 +164,7 @@ public void testJSONNullStringValue() throws Exception { String output = jsonArray.write(writer).toString(); assertTrue("String values should be equal", "[\"the toString value\"]".equals(output)); - // The first different between writeValue() and valueToString(): + // The only different between writeValue() and valueToString(): // in this case, valueToString throws a JSONException try { output = JSONObject.valueToString(jsonString); From e57881f8fa9d81ccda83e17d2379f3597b0af213 Mon Sep 17 00:00:00 2001 From: run2000 Date: Mon, 25 Jul 2016 09:44:43 +1000 Subject: [PATCH 17/99] Fail when exceptions are not thrown as expected The idiom was started in the first few methods, but not continued further down where JSONException was expected. False success may have resulted. --- src/test/java/org/json/junit/JSONStringerTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/org/json/junit/JSONStringerTest.java b/src/test/java/org/json/junit/JSONStringerTest.java index d4376df..99cdd6f 100644 --- a/src/test/java/org/json/junit/JSONStringerTest.java +++ b/src/test/java/org/json/junit/JSONStringerTest.java @@ -60,6 +60,7 @@ public void missplacedArrayException() { jsonStringer.object().endObject(); try { jsonStringer.array(); + assertTrue("Expected an exception", false); } catch (JSONException e) { assertTrue("Expected an exception message", "Misplaced array.". @@ -77,6 +78,7 @@ public void missplacedEndArrayException() { jsonStringer.object(); try { jsonStringer.endArray(); + assertTrue("Expected an exception", false); } catch (JSONException e) { assertTrue("Expected an exception message", "Misplaced endArray.". @@ -94,6 +96,7 @@ public void missplacedEndObjectException() { jsonStringer.array(); try { jsonStringer.endObject(); + assertTrue("Expected an exception", false); } catch (JSONException e) { assertTrue("Expected an exception message", "Misplaced endObject.". @@ -111,6 +114,7 @@ public void missplacedObjectException() { jsonStringer.object().endObject(); try { jsonStringer.object(); + assertTrue("Expected an exception", false); } catch (JSONException e) { assertTrue("Expected an exception message", "Misplaced object.". From a2c311527b1961ec8cefc20d8219bc72728bb7ec Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Tue, 9 Aug 2016 15:54:06 -0400 Subject: [PATCH 18/99] Updates tests to include all opt methods and verify for missing keys. --- .../java/org/json/junit/JSONArrayTest.java | 5 +- .../java/org/json/junit/JSONObjectTest.java | 48 +++++++++++++++++-- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index ef3a608..6e9fd6a 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -373,7 +373,10 @@ public void opt() { assertTrue("Array opt value out of range", null == jsonArray.opt(-1)); - assertTrue("Array opt boolean", + assertTrue("Array opt value out of range", + null == jsonArray.opt(jsonArray.length())); + + assertTrue("Array opt boolean", Boolean.TRUE == jsonArray.optBoolean(0)); assertTrue("Array opt boolean default", Boolean.FALSE == jsonArray.optBoolean(-1, Boolean.FALSE)); diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 08ec964..61043ae 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1714,20 +1714,28 @@ public void jsonObjectPutOnceNull() { } /** - * Exercise JSONObject opt(key, default) method + * Exercise JSONObject opt(key, default) method. */ @Test public void jsonObjectOptDefault() { - String str = "{\"myKey\": \"myval\"}"; + String str = "{\"myKey\": \"myval\", \"hiKey\": null}"; JSONObject jsonObject = new JSONObject(str); + assertTrue("optBigDecimal() should return default ", + BigDecimal.TEN.compareTo(jsonObject.optBigDecimal("myKey", BigDecimal.TEN))==0); + assertTrue(" should return default ", + BigInteger.TEN.compareTo(jsonObject.optBigInteger("myKey",BigInteger.TEN ))==0); assertTrue("optBoolean() should return default boolean", - Boolean.TRUE == jsonObject.optBoolean("myKey", Boolean.TRUE)); - assertTrue("optInt() should return default int", - 42 == jsonObject.optInt("myKey", 42)); + true == jsonObject.optBoolean("myKey", true)); assertTrue("optInt() should return default int", 42 == jsonObject.optInt("myKey", 42)); + assertTrue("optEnum() should return default ", + MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1))); + assertTrue("optJSONArray() should return null ", + null==jsonObject.optJSONArray("myKey")); + assertTrue("optJSONObject() should return null ", + null==jsonObject.optJSONObject("myKey")); assertTrue("optLong() should return default long", 42 == jsonObject.optLong("myKey", 42)); assertTrue("optDouble() should return default double", @@ -1736,6 +1744,36 @@ public void jsonObjectOptDefault() { "hi".equals(jsonObject.optString("hiKey", "hi"))); } + /** + * Exercise JSONObject opt(key, default) method when the key doesn't exist. + */ + @Test + public void jsonObjectOptNoKey() { + + JSONObject jsonObject = new JSONObject(); + + assertTrue("optBigDecimal() should return default ", + BigDecimal.TEN.compareTo(jsonObject.optBigDecimal("myKey", BigDecimal.TEN))==0); + assertTrue(" should return default ", + BigInteger.TEN.compareTo(jsonObject.optBigInteger("myKey",BigInteger.TEN ))==0); + assertTrue("optBoolean() should return default boolean", + true == jsonObject.optBoolean("myKey", true)); + assertTrue("optInt() should return default int", + 42 == jsonObject.optInt("myKey", 42)); + assertTrue("optEnum() should return default ", + MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1))); + assertTrue("optJSONArray() should return null ", + null==jsonObject.optJSONArray("myKey")); + assertTrue("optJSONObject() should return null ", + null==jsonObject.optJSONObject("myKey")); + assertTrue("optLong() should return default long", + 42 == jsonObject.optLong("myKey", 42)); + assertTrue("optDouble() should return default double", + 42.3 == jsonObject.optDouble("myKey", 42.3)); + assertTrue("optString() should return default string", + "hi".equals(jsonObject.optString("hiKey", "hi"))); + } + /** * Verifies that the opt methods properly convert string values. */ From 80e36eb63c976079eda49cfc070fef5bdde89f0c Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Tue, 9 Aug 2016 15:59:27 -0400 Subject: [PATCH 19/99] Fixes error messages --- src/test/java/org/json/junit/JSONObjectTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 61043ae..935b687 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1722,15 +1722,15 @@ public void jsonObjectOptDefault() { String str = "{\"myKey\": \"myval\", \"hiKey\": null}"; JSONObject jsonObject = new JSONObject(str); - assertTrue("optBigDecimal() should return default ", + assertTrue("optBigDecimal() should return default BigDecimal", BigDecimal.TEN.compareTo(jsonObject.optBigDecimal("myKey", BigDecimal.TEN))==0); - assertTrue(" should return default ", + assertTrue("optBigInteger() should return default BigInteger", BigInteger.TEN.compareTo(jsonObject.optBigInteger("myKey",BigInteger.TEN ))==0); assertTrue("optBoolean() should return default boolean", true == jsonObject.optBoolean("myKey", true)); assertTrue("optInt() should return default int", 42 == jsonObject.optInt("myKey", 42)); - assertTrue("optEnum() should return default ", + assertTrue("optEnum() should return default Enum", MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1))); assertTrue("optJSONArray() should return null ", null==jsonObject.optJSONArray("myKey")); @@ -1752,15 +1752,15 @@ public void jsonObjectOptNoKey() { JSONObject jsonObject = new JSONObject(); - assertTrue("optBigDecimal() should return default ", + assertTrue("optBigDecimal() should return default BigDecimal", BigDecimal.TEN.compareTo(jsonObject.optBigDecimal("myKey", BigDecimal.TEN))==0); - assertTrue(" should return default ", + assertTrue("optBigInteger() should return default BigInteger", BigInteger.TEN.compareTo(jsonObject.optBigInteger("myKey",BigInteger.TEN ))==0); assertTrue("optBoolean() should return default boolean", true == jsonObject.optBoolean("myKey", true)); assertTrue("optInt() should return default int", 42 == jsonObject.optInt("myKey", 42)); - assertTrue("optEnum() should return default ", + assertTrue("optEnum() should return default Enum", MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1))); assertTrue("optJSONArray() should return null ", null==jsonObject.optJSONArray("myKey")); From 8bae09f81bda5d12f1ea2d625097cdf1a113d84a Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Tue, 9 Aug 2016 16:11:46 -0400 Subject: [PATCH 20/99] removes unnecessary comparison to true --- src/test/java/org/json/junit/JSONObjectTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 935b687..d55f5df 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1727,7 +1727,7 @@ public void jsonObjectOptDefault() { assertTrue("optBigInteger() should return default BigInteger", BigInteger.TEN.compareTo(jsonObject.optBigInteger("myKey",BigInteger.TEN ))==0); assertTrue("optBoolean() should return default boolean", - true == jsonObject.optBoolean("myKey", true)); + jsonObject.optBoolean("myKey", true)); assertTrue("optInt() should return default int", 42 == jsonObject.optInt("myKey", 42)); assertTrue("optEnum() should return default Enum", @@ -1757,7 +1757,7 @@ public void jsonObjectOptNoKey() { assertTrue("optBigInteger() should return default BigInteger", BigInteger.TEN.compareTo(jsonObject.optBigInteger("myKey",BigInteger.TEN ))==0); assertTrue("optBoolean() should return default boolean", - true == jsonObject.optBoolean("myKey", true)); + jsonObject.optBoolean("myKey", true)); assertTrue("optInt() should return default int", 42 == jsonObject.optInt("myKey", 42)); assertTrue("optEnum() should return default Enum", From 5779400f26716c6c8dfc5b39fc9d4f9406f8da22 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 11 Aug 2016 12:21:49 -0400 Subject: [PATCH 21/99] test updates to make sure Enums are handled consistently. --- src/test/java/org/json/junit/EnumTest.java | 94 +++++++++++++------ src/test/java/org/json/junit/MyEnumField.java | 3 + 2 files changed, 70 insertions(+), 27 deletions(-) diff --git a/src/test/java/org/json/junit/EnumTest.java b/src/test/java/org/json/junit/EnumTest.java index ff4b294..ab4a1e5 100644 --- a/src/test/java/org/json/junit/EnumTest.java +++ b/src/test/java/org/json/junit/EnumTest.java @@ -1,13 +1,18 @@ package org.json.junit; -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; -import java.util.*; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Set; -import org.json.*; -import org.junit.*; +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Test; -import com.jayway.jsonpath.*; +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.JsonPath; /** * Enums are not explicitly supported in JSON-Java. But because enums act like @@ -50,11 +55,12 @@ public void jsonObjectFromEnum() { // validate JSON content doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expecting 2 items in top level object", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expecting 2 items in myEnumField object", ((Map)(JsonPath.read(doc, "$.myEnumField"))).size() == 2); - assertTrue("expecting 0 items in myEnum object", ((Map)(JsonPath.read(doc, "$.myEnum"))).size() == 0); - assertTrue("expecting 3", Integer.valueOf(3).equals(jsonObject.query("/myEnumField/intVal"))); - assertTrue("expecting val 3", "val 3".equals(jsonObject.query("/myEnumField/value"))); + assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); + assertTrue("expected 2 myEnumField items", "VAL3".equals((JsonPath.read(doc, "$.myEnumField")))); + assertTrue("expected 0 myEnum items", "VAL1".equals((JsonPath.read(doc, "$.myEnum")))); + + assertTrue("expecting MyEnumField.VAL3", MyEnumField.VAL3.equals(jsonObject.query("/myEnumField"))); + assertTrue("expecting MyEnum.VAL1", MyEnum.VAL1.equals(jsonObject.query("/myEnum"))); } /** @@ -87,6 +93,45 @@ public void jsonObjectFromEnumWithNames() { assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonObject.query("/VAL1"))); assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.query("/VAL2"))); assertTrue("expected VAL3", myEnumField.VAL3.equals(jsonObject.query("/VAL3"))); + } + + /** + * Verify that enums are handled consistently between JSONArray and JSONObject + */ + @Test + public void verifyEnumConsistency(){ + JSONObject jo = new JSONObject(); + + jo.put("value", MyEnumField.VAL2); + String expected="{\"value\":\"VAL2\"}"; + String actual = jo.toString(); + assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual)); + + jo.accumulate("value", MyEnumField.VAL1); + expected="{\"value\":[\"VAL2\",\"VAL1\"]}"; + actual = jo.toString(); + assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual)); + + jo.remove("value"); + jo.append("value", MyEnumField.VAL1); + expected="{\"value\":[\"VAL1\"]}"; + actual = jo.toString(); + assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual)); + + jo.put("value", EnumSet.of(MyEnumField.VAL2)); + expected="{\"value\":[\"VAL2\"]}"; + actual = jo.toString(); + assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual)); + + JSONArray ja = new JSONArray(); + ja.put(MyEnumField.VAL2); + jo.put("value", ja); + actual = jo.toString(); + assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual)); + + jo.put("value", new MyEnumField[]{MyEnumField.VAL2}); + actual = jo.toString(); + assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual)); } @@ -185,10 +230,8 @@ public void enumToString() { // validate JSON content doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected 2 myEnumField items", ((Map)(JsonPath.read(doc, "$.myEnumField"))).size() == 2); - assertTrue("expected 0 myEnum items", ((Map)(JsonPath.read(doc, "$.myEnum"))).size() == 0); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonObject.query("/myEnumField/intVal"))); - assertTrue("expected val 3", "val 3".equals(jsonObject.query("/myEnumField/value"))); + assertTrue("expected VAL3", "VAL3".equals((JsonPath.read(doc, "$.myEnumField")))); + assertTrue("expected VAL1", "VAL1".equals((JsonPath.read(doc, "$.myEnum")))); String [] names = JSONObject.getNames(myEnum); jsonObject = new JSONObject(myEnum, names); @@ -233,23 +276,20 @@ public void enumToString() { } /** - * Wrap should handle enums exactly the same way as the JSONObject(Object) - * constructor. + * Wrap should handle enums exactly as a value type like Integer, Boolean, or String. */ @Test public void wrap() { - MyEnum myEnum = MyEnum.VAL2; - JSONObject jsonObject = (JSONObject)JSONObject.wrap(myEnum); - assertTrue("simple enum has no getters", jsonObject.length() == 0); + assertTrue("simple enum has no getters", JSONObject.wrap(MyEnum.VAL2) instanceof MyEnum); MyEnumField myEnumField = MyEnumField.VAL2; - jsonObject = (JSONObject)JSONObject.wrap(myEnumField); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("enum",myEnumField); // validate JSON content Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected val 2", "val 2".equals(jsonObject.query("/value"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.query("/intVal"))); + assertTrue("expected 1 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 1); + assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.query("/enum"))); MyEnumClass myEnumClass = new MyEnumClass(); myEnumClass.setMyEnum(MyEnum.VAL1); @@ -259,11 +299,11 @@ public void wrap() { // validate JSON content doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected 2 myEnumField items", ((Map)(JsonPath.read(doc, "$.myEnumField"))).size() == 2); - assertTrue("expected 0 myEnum items", ((Map)(JsonPath.read(doc, "$.myEnum"))).size() == 0); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonObject.query("/myEnumField/intVal"))); - assertTrue("expected val 3", "val 3".equals(jsonObject.query("/myEnumField/value"))); + assertTrue("expected VAL3", "VAL3".equals((JsonPath.read(doc, "$.myEnumField")))); + assertTrue("expected VAL1", "VAL1".equals((JsonPath.read(doc, "$.myEnum")))); + assertTrue("expecting MyEnumField.VAL3", MyEnumField.VAL3.equals(jsonObject.query("/myEnumField"))); + assertTrue("expecting MyEnum.VAL1", MyEnum.VAL1.equals(jsonObject.query("/myEnum"))); } /** diff --git a/src/test/java/org/json/junit/MyEnumField.java b/src/test/java/org/json/junit/MyEnumField.java index cff565a..8f2c633 100644 --- a/src/test/java/org/json/junit/MyEnumField.java +++ b/src/test/java/org/json/junit/MyEnumField.java @@ -20,4 +20,7 @@ public String getValue() { public Integer getIntVal() { return intVal; } + public String toString(){ + return value; + } } From bbd3fd5571344d0330827e3f19ffdb3a17aed37d Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Tue, 16 Aug 2016 19:45:26 -0400 Subject: [PATCH 22/99] Adds tests for numbers --- src/test/java/org/json/junit/Fraction.java | 180 ++++++++++++++++++ .../java/org/json/junit/JSONObjectTest.java | 53 +++++- src/test/java/org/json/junit/MyNumber.java | 97 ++++++++++ .../org/json/junit/MyNumberContainer.java | 13 ++ 4 files changed, 341 insertions(+), 2 deletions(-) create mode 100644 src/test/java/org/json/junit/Fraction.java create mode 100644 src/test/java/org/json/junit/MyNumber.java create mode 100644 src/test/java/org/json/junit/MyNumberContainer.java diff --git a/src/test/java/org/json/junit/Fraction.java b/src/test/java/org/json/junit/Fraction.java new file mode 100644 index 0000000..d5d9eb6 --- /dev/null +++ b/src/test/java/org/json/junit/Fraction.java @@ -0,0 +1,180 @@ +package org.json.junit; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; + +/** + * basic fraction class, no frills. + * @author John Aylward + * + */ +public class Fraction extends Number implements Comparable { + /** + * serial id. + */ + private static final long serialVersionUID = 1L; + + /** + * value as a big decimal. + */ + private final BigDecimal bigDecimal; + + /** + * value of the denominator. + */ + private final BigInteger denominator; + /** + * value of the numerator. + */ + private final BigInteger numerator; + + /** + * @param numerator + * numerator + * @param denominator + * denominator + */ + public Fraction(final BigInteger numerator, final BigInteger denominator) { + super(); + if (numerator == null || denominator == null) { + throw new IllegalArgumentException("All values must be non-null"); + } + if (denominator.compareTo(BigInteger.ZERO)==0) { + throw new IllegalArgumentException("Divide by zero"); + } + + final BigInteger n; + final BigInteger d; + // normalize fraction + if (denominator.signum()<0) { + n = numerator.negate(); + d = denominator.negate(); + } else { + n = numerator; + d = denominator; + } + this.numerator = n; + this.denominator = d; + if (n.compareTo(BigInteger.ZERO)==0) { + this.bigDecimal = BigDecimal.ZERO; + } else if (n.compareTo(d)==0) {// i.e. 4/4, 10/10 + this.bigDecimal = BigDecimal.ONE; + } else { + this.bigDecimal = new BigDecimal(this.numerator).divide(new BigDecimal(this.denominator), + RoundingMode.HALF_EVEN); + } + } + + /** + * @param numerator + * numerator + * @param denominator + * denominator + */ + public Fraction(final long numerator, final long denominator) { + this(BigInteger.valueOf(numerator),BigInteger.valueOf(denominator)); + } + + /** + * @return the decimal + */ + public BigDecimal bigDecimalValue() { + return this.bigDecimal; + } + + @Override + public int compareTo(final Fraction o) { + // .equals call this, so no .equals compare allowed + + // if they are the same reference, just return equals + if (this == o) { + return 0; + } + + // if my denominators are already equal, just compare the numerators + if (this.denominator.compareTo(o.denominator)==0) { + return this.numerator.compareTo(o.numerator); + } + + // get numerators of common denominators + // a x ay xb + // --- --- = ---- ---- + // b y by yb + final BigInteger thisN = this.numerator.multiply(o.denominator); + final BigInteger otherN = o.numerator.multiply(this.denominator); + + return thisN.compareTo(otherN); + } + + @Override + public double doubleValue() { + return this.bigDecimal.doubleValue(); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (this.getClass() != obj.getClass()) { + return false; + } + final Fraction other = (Fraction) obj; + return this.compareTo(other) == 0; + } + + @Override + public float floatValue() { + return this.bigDecimal.floatValue(); + } + + /** + * @return the denominator + */ + public BigInteger getDenominator() { + return this.denominator; + } + + /** + * @return the numerator + */ + public BigInteger getNumerator() { + return this.numerator; + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (this.bigDecimal == null ? 0 : this.bigDecimal.hashCode()); + return result; + } + + @Override + public int intValue() { + return this.bigDecimal.intValue(); + } + + @Override + public long longValue() { + return this.bigDecimal.longValue(); + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return this.numerator + "/" + this.denominator; + } +} diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index e353ae5..8c91b53 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1,9 +1,9 @@ package org.json.junit; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -20,6 +20,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import org.json.CDL; import org.json.JSONArray; @@ -49,7 +50,7 @@ public void jsonObjectByNullBean() { MyBean myBean = null; new JSONObject(myBean); } - + /** * A JSONObject can be created with no content */ @@ -165,6 +166,54 @@ public void verifyConstructor() { expected.similar(jaObjObj)); } + /** + * Tests Number serialization. + */ + @Test + public void verifyNumberOutput(){ + JSONObject jsonObject = new JSONObject(new MyNumberContainer()); + String actual = jsonObject.toString(); + + // before wrapping of Number is allowed the number was converted as a bean + String expected = "{\"myNumber\":{\"number\":42}}"; + //String expected = "{\"myNumber\":42}"; + assertEquals("Not Equal", expected , actual); + + // put handles objects differently than the constructor. + jsonObject = new JSONObject(); + jsonObject.put("myNumber", new MyNumberContainer()); + actual = jsonObject.toString(); + // the output is the toString of the container. i.e org.json.junit.MyNumberContainer@4f063c0a + // the hex is the memory address which will change each run. + expected = "{\"myNumber\":\""+jsonObject.get("myNumber")+"\"}"; + assertEquals("Not Equal", expected , actual); + + jsonObject = new JSONObject(Collections.singletonMap("myNumber", new AtomicInteger(42))); + actual = jsonObject.toString(); + // before wrapping of Number is allowed the number was converted to a string + expected = "{\"myNumber\":\"42\"}"; + assertEquals("Not Equal", expected , actual); + + // put handles objects differently than the constructor. + jsonObject = new JSONObject(); + jsonObject.put("myNumber", new AtomicInteger(42)); + actual = jsonObject.toString(); + expected = "{\"myNumber\":42}"; + assertEquals("Not Equal", expected , actual); + + // verify Fraction output + jsonObject = new JSONObject(Collections.singletonMap("myNumber", new Fraction(4,2))); + actual = jsonObject.toString(); + expected = "{\"myNumber\":{\"denominator\":2,\"numerator\":4}}"; + assertEquals("Not Equal", expected , actual); + + jsonObject = new JSONObject(); + jsonObject.put("myNumber", new Fraction(4,2)); + actual = jsonObject.toString(); + expected = "{\"myNumber\":4/2}"; // this is NOT valid JSON!!!!!!!!!!! BUG! + assertEquals("Not Equal", expected , actual); + } + /** * Verifies that the put Collection has backwards compatability with RAW types pre-java5. */ diff --git a/src/test/java/org/json/junit/MyNumber.java b/src/test/java/org/json/junit/MyNumber.java new file mode 100644 index 0000000..243a967 --- /dev/null +++ b/src/test/java/org/json/junit/MyNumber.java @@ -0,0 +1,97 @@ +package org.json.junit; + +import java.math.BigDecimal; + +/** + * Number override for testing. Number overrides should always override + * toString, hashCode, and Equals. + * + * @see The + * Numbers Classes + * @see Formatting + * Numeric Print Output + * + * @author John Aylward + */ +public class MyNumber extends Number { + private Number number = BigDecimal.valueOf(42); + /** + */ + private static final long serialVersionUID = 1L; + + /** + * @return number! + */ + public Number getNumber() { + return this.number; + } + + @Override + public int intValue() { + return getNumber().intValue(); + } + + @Override + public long longValue() { + return getNumber().longValue(); + } + + @Override + public float floatValue() { + return getNumber().floatValue(); + } + + @Override + public double doubleValue() { + return getNumber().doubleValue(); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + * + * Number overrides should in general always override the toString method. + */ + @Override + public String toString() { + return getNumber().toString(); + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.number == null) ? 0 : this.number.hashCode()); + return result; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof MyNumber)) { + return false; + } + MyNumber other = (MyNumber) obj; + if (this.number == null) { + if (other.number != null) { + return false; + } + } else if (!this.number.equals(other.number)) { + return false; + } + return true; + } + +} diff --git a/src/test/java/org/json/junit/MyNumberContainer.java b/src/test/java/org/json/junit/MyNumberContainer.java new file mode 100644 index 0000000..524f318 --- /dev/null +++ b/src/test/java/org/json/junit/MyNumberContainer.java @@ -0,0 +1,13 @@ +package org.json.junit; + +/** + * Class that holds our MyNumber override as a property. + * @author John Aylward + */ +public class MyNumberContainer { + private MyNumber myNumber = new MyNumber(); + /** + * @return a MyNumber. + */ + public Number getMyNumber() {return this.myNumber;} +} From cbd041870432b74c3deb9b4af90c02d6b6358105 Mon Sep 17 00:00:00 2001 From: johnjaylward Date: Tue, 16 Aug 2016 21:33:54 -0400 Subject: [PATCH 23/99] Update JSONObjectTest.java fixes test to be applicable --- src/test/java/org/json/junit/JSONObjectTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 8c91b53..39e6ae5 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -181,11 +181,10 @@ public void verifyNumberOutput(){ // put handles objects differently than the constructor. jsonObject = new JSONObject(); - jsonObject.put("myNumber", new MyNumberContainer()); + jsonObject.put("myNumber", new MyNumber()); actual = jsonObject.toString(); - // the output is the toString of the container. i.e org.json.junit.MyNumberContainer@4f063c0a - // the hex is the memory address which will change each run. - expected = "{\"myNumber\":\""+jsonObject.get("myNumber")+"\"}"; + // the output is the toString of the number as a string. + expected = "{\"myNumber\":\"42\"}"; assertEquals("Not Equal", expected , actual); jsonObject = new JSONObject(Collections.singletonMap("myNumber", new AtomicInteger(42))); From a66b97f60bbae42133f472d77840e55f76ef3722 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 17 Aug 2016 11:31:12 -0400 Subject: [PATCH 24/99] fix test --- src/test/java/org/json/junit/JSONObjectTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 39e6ae5..55f7446 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -183,8 +183,8 @@ public void verifyNumberOutput(){ jsonObject = new JSONObject(); jsonObject.put("myNumber", new MyNumber()); actual = jsonObject.toString(); - // the output is the toString of the number as a string. - expected = "{\"myNumber\":\"42\"}"; + // the output is the toString of the number as a number. + expected = "{\"myNumber\":42}"; assertEquals("Not Equal", expected , actual); jsonObject = new JSONObject(Collections.singletonMap("myNumber", new AtomicInteger(42))); From 0b1dbe9369f22737cd91bec7f8905f909f71f1a3 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 17 Aug 2016 12:13:54 -0400 Subject: [PATCH 25/99] fixes test to not depend on key order --- src/test/java/org/json/junit/JSONObjectTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 55f7446..9a1d7b7 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -202,10 +202,9 @@ public void verifyNumberOutput(){ // verify Fraction output jsonObject = new JSONObject(Collections.singletonMap("myNumber", new Fraction(4,2))); - actual = jsonObject.toString(); - expected = "{\"myNumber\":{\"denominator\":2,\"numerator\":4}}"; - assertEquals("Not Equal", expected , actual); - + assertEquals("Numerator", BigInteger.valueOf(4) , jsonObject.query("/myNumber/numerator")); + assertEquals("Denominator", BigInteger.valueOf(2) , jsonObject.query("/myNumber/denominator")); + jsonObject = new JSONObject(); jsonObject.put("myNumber", new Fraction(4,2)); actual = jsonObject.toString(); From 58aebaa14fa58c920576db0560dce1c7a880f5dc Mon Sep 17 00:00:00 2001 From: stleary Date: Thu, 15 Sep 2016 21:31:28 -0500 Subject: [PATCH 26/99] fixed merge issues --- .../java/org/json/junit/JSONObjectTest.java | 81 ++++++++++++++----- 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 9a1d7b7..1b50e7a 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -171,44 +171,85 @@ public void verifyConstructor() { */ @Test public void verifyNumberOutput(){ + /** + * MyNumberContainer is a POJO, so call JSONObject(bean), + * which builds a map of getter names/values + * The only getter is getMyNumber (key=myNumber), + * whose return value is MyNumber. MyNumber extends Number, + * but is not recognized as such by wrap() per current + * implementation, so wrap() returns the default new JSONObject(bean). + * The only getter is getNumber (key=number), whose return value is + * BigDecimal(42). + */ JSONObject jsonObject = new JSONObject(new MyNumberContainer()); String actual = jsonObject.toString(); - - // before wrapping of Number is allowed the number was converted as a bean String expected = "{\"myNumber\":{\"number\":42}}"; - //String expected = "{\"myNumber\":42}"; assertEquals("Not Equal", expected , actual); - // put handles objects differently than the constructor. + /** + * JSONObject.put() handles objects differently than the + * bean constructor. Where the bean ctor wraps objects before + * placing them in the map, put() inserts the object without wrapping. + * In this case, a MyNumber instance is the value. + * The MyNumber.toString() method is responsible for + * returning a reasonable value: the string '42'. + */ jsonObject = new JSONObject(); jsonObject.put("myNumber", new MyNumber()); actual = jsonObject.toString(); - // the output is the toString of the number as a number. expected = "{\"myNumber\":42}"; assertEquals("Not Equal", expected , actual); - + + /** + * Calls the JSONObject(Map) ctor, which calls wrap() for values. + * AtomicInteger is a Number, but is not recognized by wrap(), per + * current implementation. However, the type is + * 'java.util.concurrent.atomic', so due to the 'java' prefix, + * wrap() inserts the value as a string. That is why 42 comes back + * wrapped in quotes. + */ jsonObject = new JSONObject(Collections.singletonMap("myNumber", new AtomicInteger(42))); actual = jsonObject.toString(); - // before wrapping of Number is allowed the number was converted to a string expected = "{\"myNumber\":\"42\"}"; assertEquals("Not Equal", expected , actual); - - // put handles objects differently than the constructor. + + /** + * JSONObject.put() inserts the AtomicInteger directly into the + * map not calling wrap(). In toString()->write()->writeValue(), + * AtomicInteger is recognized as a Number, and converted via + * numberToString() into the unquoted string '42'. + */ jsonObject = new JSONObject(); jsonObject.put("myNumber", new AtomicInteger(42)); actual = jsonObject.toString(); expected = "{\"myNumber\":42}"; assertEquals("Not Equal", expected , actual); - - // verify Fraction output + + /** + * Calls the JSONObject(Map) ctor, which calls wrap() for values. + * Fraction is a Number, but is not recognized by wrap(), per + * current implementation. As a POJO, Franction is handled as a + * bean and inserted into a contained JSONObject. It has 2 getters, + * for numerator and denominator. + */ jsonObject = new JSONObject(Collections.singletonMap("myNumber", new Fraction(4,2))); + assertEquals(1, jsonObject.length()); + assertEquals(2, ((JSONObject)(jsonObject.get("myNumber"))).length()); assertEquals("Numerator", BigInteger.valueOf(4) , jsonObject.query("/myNumber/numerator")); assertEquals("Denominator", BigInteger.valueOf(2) , jsonObject.query("/myNumber/denominator")); + /** + * JSONObject.put() inserts the Fraction directly into the + * map not calling wrap(). In toString()->write()->writeValue(), + * Fraction is recognized as a Number, and converted via + * numberToString() into the unquoted string '4/2'. But the + * BigDecimal sanity check fails, so writeValue() defaults + * to returning a safe JSON quoted string. Pretty slick! + */ jsonObject = new JSONObject(); jsonObject.put("myNumber", new Fraction(4,2)); actual = jsonObject.toString(); - expected = "{\"myNumber\":4/2}"; // this is NOT valid JSON!!!!!!!!!!! BUG! + expected = "{\"myNumber\":\"4/2\"}"; // valid JSON, bug fixed assertEquals("Not Equal", expected , actual); } @@ -2224,44 +2265,44 @@ public void toMap() { "}"; JSONObject jsonObject = new JSONObject(jsonObjectStr); - Map map = jsonObject.toMap(); + Map map = jsonObject.toMap(); assertTrue("Map should not be null", map != null); assertTrue("Map should have 3 elements", map.size() == 3); - List key1List = (List)map.get("key1"); + List key1List = (List)map.get("key1"); assertTrue("key1 should not be null", key1List != null); assertTrue("key1 list should have 3 elements", key1List.size() == 3); assertTrue("key1 value 1 should be 1", key1List.get(0).equals(Integer.valueOf(1))); assertTrue("key1 value 2 should be 2", key1List.get(1).equals(Integer.valueOf(2))); - Map key1Value3Map = (Map)key1List.get(2); + Map key1Value3Map = (Map)key1List.get(2); assertTrue("Map should not be null", key1Value3Map != null); assertTrue("Map should have 1 element", key1Value3Map.size() == 1); assertTrue("Map key3 should be true", key1Value3Map.get("key3").equals(Boolean.TRUE)); - Map key2Map = (Map)map.get("key2"); + Map key2Map = (Map)map.get("key2"); assertTrue("key2 should not be null", key2Map != null); assertTrue("key2 map should have 3 elements", key2Map.size() == 3); assertTrue("key2 map key 1 should be val1", key2Map.get("key1").equals("val1")); assertTrue("key2 map key 3 should be 42", key2Map.get("key3").equals(Integer.valueOf(42))); - Map key2Val2Map = (Map)key2Map.get("key2"); + Map key2Val2Map = (Map)key2Map.get("key2"); assertTrue("key2 map key 2 should not be null", key2Val2Map != null); assertTrue("key2 map key 2 should have an entry", key2Val2Map.containsKey("key2")); assertTrue("key2 map key 2 value should be null", key2Val2Map.get("key2") == null); - List key3List = (List)map.get("key3"); + List key3List = (List)map.get("key3"); assertTrue("key3 should not be null", key3List != null); assertTrue("key3 list should have 3 elements", key3List.size() == 2); - List key3Val1List = (List)key3List.get(0); + List key3Val1List = (List)key3List.get(0); assertTrue("key3 list val 1 should not be null", key3Val1List != null); assertTrue("key3 list val 1 should have 2 elements", key3Val1List.size() == 2); assertTrue("key3 list val 1 list element 1 should be value1", key3Val1List.get(0).equals("value1")); assertTrue("key3 list val 1 list element 2 should be 2.1", key3Val1List.get(1).equals(Double.valueOf("2.1"))); - List key3Val2List = (List)key3List.get(1); + List key3Val2List = (List)key3List.get(1); assertTrue("key3 list val 2 should not be null", key3Val2List != null); assertTrue("key3 list val 2 should have 1 element", key3Val2List.size() == 1); assertTrue("key3 list val 2 list element 1 should be null", key3Val2List.get(0) == null); From c8563ff93daee506201b075faf203f726319afd7 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 22 Sep 2016 12:38:30 -0400 Subject: [PATCH 27/99] new test case for XML changes --- src/test/java/org/json/junit/XMLTest.java | 31 ++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 2f3fea7..11c05d4 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -267,6 +267,35 @@ public void shouldHandleSimpleXML() { compareFileToJSONObject(xmlStr, expectedStr); } + /** + * Tests to verify that supported escapes in XML are converted to actual values. + */ + @Test + public void testXmlEscapeToJson(){ + String xmlStr = + "\n"+ + ""+ + "\""+ + "A €33"+ + "A €22€"+ + "some text ©"+ + "" " & ' < >"+ + ""; + String expectedStr = + "{\"root\":{" + + "\"rawQuote\":\"\\\"\"," + + "\"euro\":\"A €33\"," + + "\"euroX\":\"A €22€\"," + + "\"unknown\":\"some text ©\"," + + "\"known\":\"\\\" \\\" & ' < >\"" + + "}}"; + + compareStringToJSONObject(xmlStr, expectedStr); + compareReaderToJSONObject(xmlStr, expectedStr); + compareFileToJSONObject(xmlStr, expectedStr); + + } + /** * Valid XML with comments to JSONObject */ @@ -675,8 +704,8 @@ public void contentOperations() { * @param expectedStr the expected JSON string */ private void compareStringToJSONObject(String xmlStr, String expectedStr) { - JSONObject expectedJsonObject = new JSONObject(expectedStr); JSONObject jsonObject = XML.toJSONObject(xmlStr); + JSONObject expectedJsonObject = new JSONObject(expectedStr); Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); } From 5027a283c1b9c1bc81663441f0a0b23de48115cc Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 22 Sep 2016 13:09:32 -0400 Subject: [PATCH 28/99] Adds test for escaping from a JSONObject to XML --- src/test/java/org/json/junit/XMLTest.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 11c05d4..800dc93 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -1,6 +1,7 @@ package org.json.junit; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; @@ -293,7 +294,19 @@ public void testXmlEscapeToJson(){ compareStringToJSONObject(xmlStr, expectedStr); compareReaderToJSONObject(xmlStr, expectedStr); compareFileToJSONObject(xmlStr, expectedStr); - + } + + /** + * Tests that certain unicode characters are escaped. + */ + @Test + public void testJsonToXmlEscape(){ + JSONObject json = new JSONObject("{ \"amount\": \"10,00 €\", \"description\": \"Ação Válida\" }"); + String xml = XML.toString(json); + assertFalse("Escaping € failed. Found in XML output.", xml.contains("€")); + assertTrue("Escaping ç failed. Not found in XML output.", xml.contains("ç")); + assertTrue("Escaping ã failed. Not found in XML output.", xml.contains("ã")); + assertTrue("Escaping á failed. Not found in XML output.", xml.contains("á")); } /** From 2b87f334d0343774a77b1779011eaba250a2a0c9 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 22 Sep 2016 14:13:48 -0400 Subject: [PATCH 29/99] Update test cases to support ISO Control encoding changes. --- src/test/java/org/json/junit/XMLTest.java | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 800dc93..91ee420 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -297,16 +297,30 @@ public void testXmlEscapeToJson(){ } /** - * Tests that certain unicode characters are escaped. + * Tests that control characters are escaped. */ @Test public void testJsonToXmlEscape(){ - JSONObject json = new JSONObject("{ \"amount\": \"10,00 €\", \"description\": \"Ação Válida\" }"); + final String jsonSrc = "{\"amount\":\"10,00 €\"," + + "\"description\":\"Ação Válida\u0085\"," + + "\"xmlEntities\":\"\\\" ' & < >\"" + + "}"; + JSONObject json = new JSONObject(jsonSrc); String xml = XML.toString(json); - assertFalse("Escaping € failed. Found in XML output.", xml.contains("€")); + //test control character not existing + assertFalse("Escaping \u0085 failed. Found in XML output.", xml.contains("\u0085")); + assertTrue("Escaping \u0085 failed. Entity not found in XML output.", xml.contains("…")); + // test normal unicode existing + assertTrue("Escaping € failed. Not found in XML output.", xml.contains("€")); assertTrue("Escaping ç failed. Not found in XML output.", xml.contains("ç")); assertTrue("Escaping ã failed. Not found in XML output.", xml.contains("ã")); assertTrue("Escaping á failed. Not found in XML output.", xml.contains("á")); + // test XML Entities converted + assertTrue("Escaping \" failed. Not found in XML output.", xml.contains(""")); + assertTrue("Escaping ' failed. Not found in XML output.", xml.contains("'")); + assertTrue("Escaping & failed. Not found in XML output.", xml.contains("&")); + assertTrue("Escaping < failed. Not found in XML output.", xml.contains("<")); + assertTrue("Escaping > failed. Not found in XML output.", xml.contains(">")); } /** From f6a00e94c77e3b1ca6c74308696600502751efa4 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 22 Sep 2016 16:12:00 -0400 Subject: [PATCH 30/99] adds test for unicode that has surrogate pairs --- src/test/java/org/json/junit/XMLTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 91ee420..264fa44 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -281,6 +281,7 @@ public void testXmlEscapeToJson(){ "A €22€"+ "some text ©"+ "" " & ' < >"+ + "𝄢 𐅥" + ""; String expectedStr = "{\"root\":{" + @@ -288,7 +289,8 @@ public void testXmlEscapeToJson(){ "\"euro\":\"A €33\"," + "\"euroX\":\"A €22€\"," + "\"unknown\":\"some text ©\"," + - "\"known\":\"\\\" \\\" & ' < >\"" + + "\"known\":\"\\\" \\\" & ' < >\"," + + "\"high\":\"𝄢 𐅥\""+ "}}"; compareStringToJSONObject(xmlStr, expectedStr); From 97e3d6c7cee211eac60deb7a3cc3d0994e167135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bence=20Er=C5=91s?= Date: Wed, 5 Oct 2016 14:59:36 +0200 Subject: [PATCH 31/99] testcase for stleary/JSON-java#292 and adding .idea to .gitiignore --- .gitignore | 1 + src/test/java/org/json/junit/JSONPointerTest.java | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 7afd420..b7025e6 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ build /gradlew.bat .gitmodules src/main/ +.idea diff --git a/src/test/java/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java index 95fa73b..75f4ea8 100644 --- a/src/test/java/org/json/junit/JSONPointerTest.java +++ b/src/test/java/org/json/junit/JSONPointerTest.java @@ -78,6 +78,11 @@ public void uriFragmentNotation() { assertSame(document.get("foo"), query("#/foo")); } + @Test + public void uriFragmentNotationRoot() { + assertSame(document, query("#")); + } + @Test public void uriFragmentPercentHandling() { assertSame(document.get("c%d"), query("#/c%25d")); From 928179a1f3d2bd0817803277298af3bf4ee706c9 Mon Sep 17 00:00:00 2001 From: stleary Date: Tue, 14 Feb 2017 08:30:22 -0600 Subject: [PATCH 32/99] locale tests --- build.gradle | 6 +++ .../org/json/junit/JSONObjectLocaleTest.java | 48 +++++++++++++++++++ .../java/org/json/junit/JunitTestSuite.java | 1 + .../java/org/json/junit/MyLocaleBean.java | 12 +++++ 4 files changed, 67 insertions(+) create mode 100755 src/test/java/org/json/junit/JSONObjectLocaleTest.java create mode 100755 src/test/java/org/json/junit/MyLocaleBean.java diff --git a/build.gradle b/build.gradle index d2969d4..58259f9 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,12 @@ apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'jacoco' +tasks.withType(JavaCompile) { + // this subproject requires -parameters option + options.compilerArgs << '-parameters' + options.encoding = 'UTF-8' +} + sourceSets { // Uncomment main if you have merged JSON-Java and JSON-Java-unit-test code main diff --git a/src/test/java/org/json/junit/JSONObjectLocaleTest.java b/src/test/java/org/json/junit/JSONObjectLocaleTest.java new file mode 100755 index 0000000..a6cb996 --- /dev/null +++ b/src/test/java/org/json/junit/JSONObjectLocaleTest.java @@ -0,0 +1,48 @@ +package org.json.junit; + +import static org.junit.Assert.*; + +import java.util.*; + +import org.json.*; +import org.junit.*; + +/** + * Note: This file is saved as UTF-8. Do not save as ASCII or the tests will + * fail. + * + */ +public class JSONObjectLocaleTest { + /** + * JSONObject built from a bean with locale-specific keys - that is, the key + * fields are not LANG_ENGLISH. + */ + @Test + public void jsonObjectByLocaleBean() { + + MyLocaleBean myLocaleBean = new MyLocaleBean(); + + Locale.setDefault(new Locale("en")); + JSONObject jsonen = new JSONObject(myLocaleBean); + System.out.println("jsonen " + jsonen); + + Locale.setDefault(new Locale("tr")); + JSONObject jsontr = new JSONObject(myLocaleBean); + System.out.println("jsontr " + jsontr); + /** + * In this test we exercise code that handles keys of 1-char and + * multi-char length that include text from a non-English locale. + * Turkish in this case. The JSONObject code should correctly retain the + * non-EN_LANG chars in the key. + */ + assertTrue("expected beanId", + "Tlocaleüx".equals(jsonObject.getString(""))); + assertTrue("expected Tlocalü", + "Tlocaleü".equals(jsonObject.getString("ü"))); + assertTrue("expected Tlocaleüx", + "Tlocaleüx".equals((String)(jsonObject.query("/üx")))); + assertTrue("expected Tlocalü", + "Tlocaleü".equals((String)(jsonObject.query("/ü")))); + } + +} diff --git a/src/test/java/org/json/junit/JunitTestSuite.java b/src/test/java/org/json/junit/JunitTestSuite.java index 3a7223e..36bec60 100644 --- a/src/test/java/org/json/junit/JunitTestSuite.java +++ b/src/test/java/org/json/junit/JunitTestSuite.java @@ -13,6 +13,7 @@ HTTPTest.class, JSONStringerTest.class, JSONObjectTest.class, + JSONObjectLocaleTest.class, JSONArrayTest.class, EnumTest.class, JSONPointerTest.class, diff --git a/src/test/java/org/json/junit/MyLocaleBean.java b/src/test/java/org/json/junit/MyLocaleBean.java new file mode 100755 index 0000000..0d68c39 --- /dev/null +++ b/src/test/java/org/json/junit/MyLocaleBean.java @@ -0,0 +1,12 @@ +package org.json.junit; + +public class MyLocaleBean { + private final String id = "beanId"; + private final String i = "beanI"; + public String getId() { + return id; + } + public String getI() { + return i; + } +} From f41e1d012aa5dbc012a22e6890a9755d03d0fae8 Mon Sep 17 00:00:00 2001 From: stleary Date: Thu, 16 Feb 2017 20:49:37 -0600 Subject: [PATCH 33/99] tests for locale-independent keys --- .../org/json/junit/JSONObjectLocaleTest.java | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectLocaleTest.java b/src/test/java/org/json/junit/JSONObjectLocaleTest.java index a6cb996..9c80ab6 100755 --- a/src/test/java/org/json/junit/JSONObjectLocaleTest.java +++ b/src/test/java/org/json/junit/JSONObjectLocaleTest.java @@ -14,35 +14,42 @@ */ public class JSONObjectLocaleTest { /** - * JSONObject built from a bean with locale-specific keys - that is, the key - * fields are not LANG_ENGLISH. + * JSONObject built from a bean with locale-specific keys. + * In the Turkish alphabet, there are 2 versions of the letter "i". + * 'eh' I ı (dotless i) + * 'ee' İ i (dotted i) + * A problem can occur when parsing the public get methods for a bean. + * If the method starts with getI... then the key name will be lowercased + * to 'i' in English, and 'ı' in Turkish. + * We want the keys to be consistent regardless of locale, so JSON-Java + * lowercase operations are made to be locale-neutral by specifying + * Locale.ROOT. This causes 'I' to be universally lowercased to 'i' + * regardless of the locale currently in effect. */ @Test public void jsonObjectByLocaleBean() { MyLocaleBean myLocaleBean = new MyLocaleBean(); + /** + * This is just the control case which happens when the locale.ROOT + * lowercasing behavior is the same as the current locale. + */ Locale.setDefault(new Locale("en")); JSONObject jsonen = new JSONObject(myLocaleBean); - System.out.println("jsonen " + jsonen); + assertEquals("expected size 2, found: " +jsonen.length(), 2, jsonen.length()); + assertEquals("expected jsonen[i] == beanI", "beanI", jsonen.getString("i")); + assertEquals("expected jsonen[id] == beanId", "beanId", jsonen.getString("id")); - Locale.setDefault(new Locale("tr")); - JSONObject jsontr = new JSONObject(myLocaleBean); - System.out.println("jsontr " + jsontr); /** - * In this test we exercise code that handles keys of 1-char and - * multi-char length that include text from a non-English locale. - * Turkish in this case. The JSONObject code should correctly retain the - * non-EN_LANG chars in the key. + * Without the JSON-Java change, these keys would be stored internally as + * starting with the letter, 'ı' (dotless i), since the lowercasing of + * the getI and getId keys would be specific to the Turkish locale. */ - assertTrue("expected beanId", - "Tlocaleüx".equals(jsonObject.getString(""))); - assertTrue("expected Tlocalü", - "Tlocaleü".equals(jsonObject.getString("ü"))); - assertTrue("expected Tlocaleüx", - "Tlocaleüx".equals((String)(jsonObject.query("/üx")))); - assertTrue("expected Tlocalü", - "Tlocaleü".equals((String)(jsonObject.query("/ü")))); + Locale.setDefault(new Locale("tr")); + JSONObject jsontr = new JSONObject(myLocaleBean); + assertEquals("expected size 2, found: " +jsontr.length(), 2, jsontr.length()); + assertEquals("expected jsontr[i] == beanI", "beanI", jsontr.getString("i")); + assertEquals("expected jsontr[id] == beanId", "beanId", jsontr.getString("id")); } - } From e41972a57426c1e65646a2ab0634693655e33495 Mon Sep 17 00:00:00 2001 From: stleary Date: Sun, 26 Feb 2017 11:09:41 -0600 Subject: [PATCH 34/99] add a test for unquoted values --- .../java/org/json/junit/JSONObjectTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 1b50e7a..1dec2fd 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -51,6 +51,23 @@ public void jsonObjectByNullBean() { new JSONObject(myBean); } + /** + * The JSON parser is permissive of unambiguous unquoted keys and values. + * Such JSON text should be allowed, even if it does not strictly conform + * to the spec. However, after being parsed, toString() should emit strictly + * conforming JSON text. + */ + @Test + public void unquotedText() { + String str = "{key1:value1, key2:42}"; + JSONObject jsonObject = new JSONObject(str); + String textStr = jsonObject.toString(); + assertTrue("expected key1", textStr.contains("\"key1\"")); + assertTrue("expected value1", textStr.contains("\"value1\"")); + assertTrue("expected key2", textStr.contains("\"key2\"")); + assertTrue("expected 42", textStr.contains("42")); + } + /** * A JSONObject can be created with no content */ From d1a5f15f0c0e1bb55322816d3e90cb084ba5dead Mon Sep 17 00:00:00 2001 From: stleary Date: Sun, 26 Mar 2017 15:03:09 -0500 Subject: [PATCH 35/99] unit tests for query-by-JSONPointer --- .../java/org/json/junit/JSONPointerTest.java | 111 +++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java index 75f4ea8..0904b9e 100644 --- a/src/test/java/org/json/junit/JSONPointerTest.java +++ b/src/test/java/org/json/junit/JSONPointerTest.java @@ -157,7 +157,7 @@ public void tokenListIsCopiedInConstructor() { } /** - * Coverage for JSONObject queryFrom() + * Coverage for JSONObject query(String) */ @Test public void queryFromJSONObject() { @@ -187,7 +187,61 @@ public void queryFromJSONObject() { } /** - * Coverage for JSONArray queryFrom() + * Coverage for JSONObject query(JSONPointer) + */ + @Test + public void queryFromJSONObjectUsingPointer() { + String str = "{"+ + "\"stringKey\":\"hello world!\","+ + "\"arrayKey\":[0,1,2],"+ + "\"objectKey\": {"+ + "\"a\":\"aVal\","+ + "\"b\":\"bVal\""+ + "}"+ + "}"; + JSONObject jsonObject = new JSONObject(str); + Object obj = jsonObject.query(new JSONPointer("/stringKey")); + assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); + obj = jsonObject.query(new JSONPointer("/arrayKey/1")); + assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); + obj = jsonObject.query(new JSONPointer("/objectKey/b")); + assertTrue("Expected bVal", "bVal".equals(obj)); + try { + obj = jsonObject.query(new JSONPointer("/a/b/c")); + assertTrue("Expected JSONPointerException", false); + } catch (JSONPointerException e) { + assertTrue("Expected bad key/value exception", + "value [null] is not an array or object therefore its key b cannot be resolved". + equals(e.getMessage())); + } + } + + /** + * Coverage for JSONObject optQuery(JSONPointer) + */ + @Test + public void optQueryFromJSONObjectUsingPointer() { + String str = "{"+ + "\"stringKey\":\"hello world!\","+ + "\"arrayKey\":[0,1,2],"+ + "\"objectKey\": {"+ + "\"a\":\"aVal\","+ + "\"b\":\"bVal\""+ + "}"+ + "}"; + JSONObject jsonObject = new JSONObject(str); + Object obj = jsonObject.optQuery(new JSONPointer("/stringKey")); + assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); + obj = jsonObject.optQuery(new JSONPointer("/arrayKey/1")); + assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); + obj = jsonObject.optQuery(new JSONPointer("/objectKey/b")); + assertTrue("Expected bVal", "bVal".equals(obj)); + obj = jsonObject.optQuery(new JSONPointer("/a/b/c")); + assertTrue("Expected null", obj == null); + } + + /** + * Coverage for JSONArray query(String) */ @Test public void queryFromJSONArray() { @@ -214,4 +268,57 @@ public void queryFromJSONArray() { "a is not an array index".equals(e.getMessage())); } } + + /** + * Coverage for JSONArray query(JSONPointer) + */ + @Test + public void queryFromJSONArrayUsingPointer() { + String str = "["+ + "\"hello world!\","+ + "[0,1,2],"+ + "{"+ + "\"a\":\"aVal\","+ + "\"b\":\"bVal\""+ + "}"+ + "]"; + JSONArray jsonArray = new JSONArray(str); + Object obj = jsonArray.query(new JSONPointer("/0")); + assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); + obj = jsonArray.query(new JSONPointer("/1/1")); + assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); + obj = jsonArray.query(new JSONPointer("/2/b")); + assertTrue("Expected bVal", "bVal".equals(obj)); + try { + obj = jsonArray.query(new JSONPointer("/a/b/c")); + assertTrue("Expected JSONPointerException", false); + } catch (JSONPointerException e) { + assertTrue("Expected bad index exception", + "a is not an array index".equals(e.getMessage())); + } + } + + /** + * Coverage for JSONArray optQuery(JSONPointer) + */ + @Test + public void optQueryFromJSONArrayUsingPointer() { + String str = "["+ + "\"hello world!\","+ + "[0,1,2],"+ + "{"+ + "\"a\":\"aVal\","+ + "\"b\":\"bVal\""+ + "}"+ + "]"; + JSONArray jsonArray = new JSONArray(str); + Object obj = jsonArray.optQuery(new JSONPointer("/0")); + assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); + obj = jsonArray.optQuery(new JSONPointer("/1/1")); + assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); + obj = jsonArray.optQuery(new JSONPointer("/2/b")); + assertTrue("Expected bVal", "bVal".equals(obj)); + obj = jsonArray.optQuery(new JSONPointer("/a/b/c")); + assertTrue("Expected null", obj == null); + } } From 9df5d34bbee13a5d228e0feedf22d8b1039d01ed Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 27 Apr 2017 12:39:42 -0400 Subject: [PATCH 36/99] * Update link in the README to the main JSON-Java repo * Cleans up some warnings * Adds new test for bug https://github.com/stleary/JSON-java/issues/332 * Adds some resource handling for string writers using pre-java1.7 support. I know StringWriters don't need a close method called, but the tests should still handle their resources properly. --- README.md | 2 +- src/test/java/org/json/junit/EnumTest.java | 3 +- .../java/org/json/junit/JSONArrayTest.java | 100 +- src/test/java/org/json/junit/JSONMLTest.java | 75 +- .../java/org/json/junit/JSONObjectTest.java | 4707 +++++++++-------- .../java/org/json/junit/JSONStringTest.java | 681 +-- src/test/java/org/json/junit/MyEnumField.java | 8 +- .../java/org/json/junit/MyPublicClass.java | 1 + .../org/json/junit/StringsResourceBundle.java | 1 + src/test/java/org/json/junit/XMLTest.java | 3 - 10 files changed, 2878 insertions(+), 2703 deletions(-) diff --git a/README.md b/README.md index faf400a..0772d3b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Unit tests to validate the JSON-Java GitHub project code
-https://github.com/douglascrockford/JSON-java
+https://github.com/stleary/JSON-java
Gradle and Eclipse is the recommended build tool and IDE.
Run individual tests or JunitTestSuite using EclEmma Coverage, or execute the **TestRunner** application directly.
diff --git a/src/test/java/org/json/junit/EnumTest.java b/src/test/java/org/json/junit/EnumTest.java index ab4a1e5..6b97107 100644 --- a/src/test/java/org/json/junit/EnumTest.java +++ b/src/test/java/org/json/junit/EnumTest.java @@ -5,7 +5,6 @@ import java.util.EnumSet; import java.util.List; import java.util.Map; -import java.util.Set; import org.json.JSONArray; import org.json.JSONObject; @@ -92,7 +91,7 @@ public void jsonObjectFromEnumWithNames() { assertTrue("expected 3 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 3); assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonObject.query("/VAL1"))); assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.query("/VAL2"))); - assertTrue("expected VAL3", myEnumField.VAL3.equals(jsonObject.query("/VAL3"))); + assertTrue("expected VAL3", MyEnumField.VAL3.equals(jsonObject.query("/VAL3"))); } /** diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 244a693..80b78a5 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -1,11 +1,11 @@ package org.json.junit; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertEquals; +import java.io.IOException; import java.io.StringWriter; -import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; @@ -61,7 +61,7 @@ public class JSONArrayTest { @Test(expected=NullPointerException.class) public void nullException() { String str = null; - new JSONArray(str); + assertNull("Should throw an exception", new JSONArray(str)); } /** @@ -72,8 +72,7 @@ public void nullException() { public void emptStr() { String str = ""; try { - new JSONArray(str); - assertTrue("Should throw an exception", false); + assertNull("Should throw an exception", new JSONArray(str)); } catch (JSONException e) { assertTrue("Expected an exception message", "A JSONArray text must start with '[' at 1 [character 2 line 1]". @@ -90,8 +89,7 @@ public void emptStr() { public void badObject() { String str = "abc"; try { - new JSONArray((Object)str); - assertTrue("Should throw an exception", false); + assertNull("Should throw an exception", new JSONArray((Object)str)); } catch (JSONException e) { assertTrue("Expected an exception message", "JSONArray initial value should be a string or collection or array.". @@ -100,7 +98,7 @@ public void badObject() { } /** - * Verifies that the constructor has backwards compatability with RAW types pre-java5. + * Verifies that the constructor has backwards compatibility with RAW types pre-java5. */ @Test public void verifyConstructor() { @@ -130,7 +128,7 @@ public void verifyConstructor() { } /** - * Verifies that the put Collection has backwards compatability with RAW types pre-java5. + * Verifies that the put Collection has backwards compatibility with RAW types pre-java5. */ @Test public void verifyPutCollection() { @@ -164,7 +162,7 @@ public void verifyPutCollection() { /** - * Verifies that the put Map has backwards compatability with RAW types pre-java5. + * Verifies that the put Map has backwards compatibility with RAW types pre-java5. */ @Test public void verifyPutMap() { @@ -209,9 +207,10 @@ public void verifyPutMap() { * Create a JSONArray doc with a variety of different elements. * Confirm that the values can be accessed via the get[type]() API methods */ + @SuppressWarnings("boxing") @Test public void getArrayValues() { - JSONArray jsonArray = new JSONArray(arrayStr); + JSONArray jsonArray = new JSONArray(this.arrayStr); // booleans assertTrue("Array true", true == jsonArray.getBoolean(0)); @@ -255,7 +254,7 @@ public void getArrayValues() { */ @Test public void failedGetArrayValues() { - JSONArray jsonArray = new JSONArray(arrayStr); + JSONArray jsonArray = new JSONArray(this.arrayStr); try { jsonArray.getBoolean(4); assertTrue("expected getBoolean to fail", false); @@ -321,7 +320,7 @@ public void failedGetArrayValues() { */ @Test public void join() { - JSONArray jsonArray = new JSONArray(arrayStr); + JSONArray jsonArray = new JSONArray(this.arrayStr); String joinStr = jsonArray.join(","); // validate JSON @@ -357,7 +356,7 @@ public void join() { public void length() { assertTrue("expected empty JSONArray length 0", new JSONArray().length() == 0); - JSONArray jsonArray = new JSONArray(arrayStr); + JSONArray jsonArray = new JSONArray(this.arrayStr); assertTrue("expected JSONArray length 13", jsonArray.length() == 13); JSONArray nestedJsonArray = jsonArray.getJSONArray(9); assertTrue("expected JSONArray length 1", nestedJsonArray.length() == 1); @@ -368,9 +367,10 @@ public void length() { * Confirm that the values can be accessed via the opt[type](index) * and opt[type](index, default) API methods. */ + @SuppressWarnings("boxing") @Test public void opt() { - JSONArray jsonArray = new JSONArray(arrayStr); + JSONArray jsonArray = new JSONArray(this.arrayStr); assertTrue("Array opt value true", Boolean.TRUE == jsonArray.opt(0)); assertTrue("Array opt value out of range", @@ -441,6 +441,7 @@ public void optStringConversion(){ * Exercise the JSONArray.put(value) method with various parameters * and confirm the resulting JSONArray. */ + @SuppressWarnings("boxing") @Test public void put() { JSONArray jsonArray = new JSONArray(); @@ -516,6 +517,7 @@ public void put() { * Exercise the JSONArray.put(index, value) method with various parameters * and confirm the resulting JSONArray. */ + @SuppressWarnings("boxing") @Test public void putIndex() { JSONArray jsonArray = new JSONArray(); @@ -596,11 +598,11 @@ public void putIndex() { */ @Test public void remove() { - String arrayStr = + String arrayStr1 = "["+ "1"+ "]"; - JSONArray jsonArray = new JSONArray(arrayStr); + JSONArray jsonArray = new JSONArray(arrayStr1); jsonArray.remove(0); assertTrue("array should be empty", null == jsonArray.remove(5)); assertTrue("jsonArray should be empty", jsonArray.length() == 0); @@ -612,11 +614,11 @@ public void remove() { */ @Test public void notSimilar() { - String arrayStr = + String arrayStr1 = "["+ "1"+ "]"; - JSONArray jsonArray = new JSONArray(arrayStr); + JSONArray jsonArray = new JSONArray(arrayStr1); JSONArray otherJsonArray = new JSONArray(); assertTrue("arrays lengths differ", !jsonArray.similar(otherJsonArray)); @@ -745,9 +747,10 @@ public void objectArrayVsIsArray() { /** * Exercise the JSONArray iterator. */ + @SuppressWarnings("boxing") @Test public void iterator() { - JSONArray jsonArray = new JSONArray(arrayStr); + JSONArray jsonArray = new JSONArray(this.arrayStr); Iterator it = jsonArray.iterator(); assertTrue("Array true", Boolean.TRUE.equals(it.next())); @@ -803,16 +806,20 @@ public void optQueryWithSyntaxError() { * Exercise the JSONArray write() method */ @Test - public void write() { + public void write() throws IOException { String str = "[\"value1\",\"value2\",{\"key1\":1,\"key2\":2,\"key3\":3}]"; JSONArray jsonArray = new JSONArray(str); String expectedStr = str; StringWriter stringWriter = new StringWriter(); - Writer writer = jsonArray.write(stringWriter); - String actualStr = writer.toString(); - assertTrue("write() expected " + expectedStr + - " but found " + actualStr, - expectedStr.equals(actualStr)); + try { + jsonArray.write(stringWriter); + String actualStr = stringWriter.toString(); + assertTrue("write() expected " + expectedStr + + " but found " + actualStr, + expectedStr.equals(actualStr)); + } finally { + stringWriter.close(); + } } /** @@ -837,7 +844,7 @@ public void writeAppendable() { * Exercise the JSONArray write(Writer, int, int) method */ @Test - public void write3Param() { + public void write3Param() throws IOException { String str0 = "[\"value1\",\"value2\",{\"key1\":1,\"key2\":false,\"key3\":3.14}]"; String str2 = "[\n" + @@ -852,15 +859,20 @@ public void write3Param() { JSONArray jsonArray = new JSONArray(str0); String expectedStr = str0; StringWriter stringWriter = new StringWriter(); - Writer writer = jsonArray.write(stringWriter, 0, 0); - String actualStr = writer.toString(); - assertEquals(expectedStr, actualStr); - - expectedStr = str2; + try { + String actualStr = jsonArray.write(stringWriter, 0, 0).toString(); + assertEquals(expectedStr, actualStr); + } finally { + stringWriter.close(); + } stringWriter = new StringWriter(); - writer = jsonArray.write(stringWriter, 2, 1); - actualStr = writer.toString(); - assertEquals(expectedStr, actualStr); + try { + expectedStr = str2; + String actualStr = jsonArray.write(stringWriter, 2, 1).toString(); + assertEquals(expectedStr, actualStr); + } finally { + stringWriter.close(); + } } /** @@ -917,49 +929,49 @@ public void toList() { "]"; JSONArray jsonArray = new JSONArray(jsonArrayStr); - List list = jsonArray.toList(); + List list = jsonArray.toList(); assertTrue("List should not be null", list != null); assertTrue("List should have 3 elements", list.size() == 3); - List val1List = (List) list.get(0); + List val1List = (List) list.get(0); assertTrue("val1 should not be null", val1List != null); assertTrue("val1 should have 3 elements", val1List.size() == 3); assertTrue("val1 value 1 should be 1", val1List.get(0).equals(Integer.valueOf(1))); assertTrue("val1 value 2 should be 2", val1List.get(1).equals(Integer.valueOf(2))); - Map key1Value3Map = (Map)val1List.get(2); + Map key1Value3Map = (Map)val1List.get(2); assertTrue("Map should not be null", key1Value3Map != null); assertTrue("Map should have 1 element", key1Value3Map.size() == 1); assertTrue("Map key3 should be true", key1Value3Map.get("key3").equals(Boolean.TRUE)); - Map val2Map = (Map) list.get(1); + Map val2Map = (Map) list.get(1); assertTrue("val2 should not be null", val2Map != null); assertTrue("val2 should have 4 elements", val2Map.size() == 4); assertTrue("val2 map key 1 should be val1", val2Map.get("key1").equals("val1")); assertTrue("val2 map key 3 should be 42", val2Map.get("key3").equals(Integer.valueOf(42))); - Map val2Key2Map = (Map)val2Map.get("key2"); + Map val2Key2Map = (Map)val2Map.get("key2"); assertTrue("val2 map key 2 should not be null", val2Key2Map != null); assertTrue("val2 map key 2 should have an entry", val2Key2Map.containsKey("key2")); assertTrue("val2 map key 2 value should be null", val2Key2Map.get("key2") == null); - List val2Key4List = (List)val2Map.get("key4"); + List val2Key4List = (List)val2Map.get("key4"); assertTrue("val2 map key 4 should not be null", val2Key4List != null); assertTrue("val2 map key 4 should be empty", val2Key4List.isEmpty()); - List val3List = (List) list.get(2); + List val3List = (List) list.get(2); assertTrue("val3 should not be null", val3List != null); assertTrue("val3 should have 2 elements", val3List.size() == 2); - List val3Val1List = (List)val3List.get(0); + List val3Val1List = (List)val3List.get(0); assertTrue("val3 list val 1 should not be null", val3Val1List != null); assertTrue("val3 list val 1 should have 2 elements", val3Val1List.size() == 2); assertTrue("val3 list val 1 list element 1 should be value1", val3Val1List.get(0).equals("value1")); assertTrue("val3 list val 1 list element 2 should be 2.1", val3Val1List.get(1).equals(Double.valueOf("2.1"))); - List val3Val2List = (List)val3List.get(1); + List val3Val2List = (List)val3List.get(1); assertTrue("val3 list val 2 should not be null", val3Val2List != null); assertTrue("val3 list val 2 should have 1 element", val3Val2List.size() == 1); assertTrue("val3 list val 2 list element 1 should be null", val3Val2List.get(0) == null); diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index 1298591..1ad2cb4 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -711,8 +711,7 @@ public void testToJSONArray_jsonOutput() { } /** - * JSON string cannot be reverted to original xml. See test result in - * comment below. + * JSON string cannot be reverted to original xml when type guessing is used. */ @Test public void testToJSONArray_reversibility() { @@ -722,10 +721,11 @@ public void testToJSONArray_reversibility() { } /** - * test passes when using the new method toJsonML. + * JSON string cannot be reverted to original xml when type guessing is used. + * When we force all the values as string, the original text comes back. */ @Test - public void testToJsonML() { + public void testToJSONArray_reversibility2() { final String originalXml = "011000True"; final String expectedJsonString = "[\"root\",[\"id\",\"01\"],[\"id\",\"1\"],[\"id\",\"00\"],[\"id\",\"0\"],[\"item\",{\"id\":\"01\"}],[\"title\",\"True\"]]"; final JSONArray json = JSONML.toJSONArray(originalXml,true); @@ -735,4 +735,71 @@ public void testToJsonML() { assertEquals(originalXml, reverseXml); } + /** + * JSON can be reverted to original xml. + */ + @Test + public void testToJSONArray_reversibility3() { + final String originalXml = "400402"; + final JSONArray jsonArray = JSONML.toJSONArray(originalXml, false); + final String revertedXml = JSONML.toString(jsonArray); + assertEquals(revertedXml, originalXml); + } + + /** + * JSON string cannot be reverted to original xml. See test result in + * comment below. + */ + @Test + public void testToJSONObject_reversibility() { + final String originalXml = "400402"; + final JSONObject originalObject=JSONML.toJSONObject(originalXml,false); + final String originalJson = originalObject.toString(); + final String xml = JSONML.toString(originalObject); + final JSONObject revertedObject = JSONML.toJSONObject(xml, false); + final String newJson = revertedObject.toString(); + assertTrue("JSON Objects are not similar",originalObject.similar(revertedObject)); + assertEquals("original JSON does not equal the new JSON",originalJson, newJson); + } + + /** + * Test texts taken from jsonml.org. Currently our implementation FAILS this conversion but shouldn't. + * Technically JsonML should be able to transform any valid xhtml document, but ours only supports + * standard XML entities, not HTML entities. + */ + @Test + public void testAttributeConversionReversabilityHTML() { + final String originalXml = "
#5D28D1Example text here
#AF44EF127310656
#AAD034 © 
"; + final String expectedJsonString = "[\"table\",{\"class\" : \"MyTable\",\"style\" : \"background-color:yellow\"},[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#550758\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:red\"},\"Example text here\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#993101\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:green\"},\"127624015\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#E33D87\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:blue\"},\"\u00A0\",[\"span\",{ \"style\" : \"background-color:maroon\" },\"\u00A9\"],\"\u00A0\"]]]"; + final JSONArray json = JSONML.toJSONArray(originalXml,true); + final String actualJsonString = json.toString(); + + final String reverseXml = JSONML.toString(json); + assertNotEquals(originalXml, reverseXml); + + assertNotEquals(expectedJsonString, actualJsonString); + } + +// this test does not pass for the following reasons: +// 1. Our XML parser does not handle generic HTML entities, only valid XML entities. Hence   +// or other HTML specific entites would fail on reversability +// 2. Our JSON implementation for storing the XML attributes uses the standard unordered map. +// This means that can not be reversed reliably. +// /** +// * Test texts taken from jsonml.org but modified to have XML entities only. +// */ +// @Test +// public void testAttributeConversionReversabilityXML() { +// final String originalXml = "
#5D28D1Example text here
#AF44EF127310656
#AAD034&><
"; +// final String expectedJsonString = "[\"table\",{\"class\" : \"MyTable\",\"style\" : \"background-color:yellow\"},[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#550758\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:red\"},\"Example text here\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#993101\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:green\"},\"127624015\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#E33D87\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:blue\"},\"&\",[\"span\",{ \"style\" : \"background-color:maroon\" },\">\"],\"<\"]]]"; +// final JSONArray jsonML = JSONML.toJSONArray(originalXml,true); +// final String actualJsonString = jsonML.toString(); +// +// final String reverseXml = JSONML.toString(jsonML); +// // currently not equal because the hashing of the attribute objects makes the attribute +// // order not happen the same way twice +// assertEquals(originalXml, reverseXml); +// +// assertEquals(expectedJsonString, actualJsonString); +// } } diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 1dec2fd..fb32cda 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1,2336 +1,2371 @@ -package org.json.junit; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.StringReader; -import java.io.StringWriter; -import java.io.Writer; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.json.CDL; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONPointerException; -import org.json.XML; -import org.junit.Test; - -import com.jayway.jsonpath.Configuration; -import com.jayway.jsonpath.JsonPath; - -/** - * JSONObject, along with JSONArray, are the central classes of the reference app. - * All of the other classes interact with them, and JSON functionality would - * otherwise be impossible. - */ -public class JSONObjectTest { - - /** - * JSONObject built from a bean, but only using a null value. - * Nothing good is expected to happen. - * Expects NullPointerException - */ - @Test(expected=NullPointerException.class) - public void jsonObjectByNullBean() { - MyBean myBean = null; - new JSONObject(myBean); - } - - /** - * The JSON parser is permissive of unambiguous unquoted keys and values. - * Such JSON text should be allowed, even if it does not strictly conform - * to the spec. However, after being parsed, toString() should emit strictly - * conforming JSON text. - */ - @Test - public void unquotedText() { - String str = "{key1:value1, key2:42}"; - JSONObject jsonObject = new JSONObject(str); - String textStr = jsonObject.toString(); - assertTrue("expected key1", textStr.contains("\"key1\"")); - assertTrue("expected value1", textStr.contains("\"value1\"")); - assertTrue("expected key2", textStr.contains("\"key2\"")); - assertTrue("expected 42", textStr.contains("42")); - } - - /** - * A JSONObject can be created with no content - */ - @Test - public void emptyJsonObject() { - JSONObject jsonObject = new JSONObject(); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); - } - - /** - * A JSONObject can be created from another JSONObject plus a list of names. - * In this test, some of the starting JSONObject keys are not in the - * names list. - */ - @Test - public void jsonObjectByNames() { - String str = - "{"+ - "\"trueKey\":true,"+ - "\"falseKey\":false,"+ - "\"nullKey\":null,"+ - "\"stringKey\":\"hello world!\","+ - "\"escapeStringKey\":\"h\be\tllo w\u1234orld!\","+ - "\"intKey\":42,"+ - "\"doubleKey\":-23.45e67"+ - "}"; - String[] keys = {"falseKey", "stringKey", "nullKey", "doubleKey"}; - JSONObject jsonObject = new JSONObject(str); - - // validate JSON - JSONObject jsonObjectByName = new JSONObject(jsonObject, keys); - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObjectByName.toString()); - assertTrue("expected 4 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 4); - assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObjectByName.query("/falseKey"))); - assertTrue("expected \"nullKey\":null", JSONObject.NULL.equals(jsonObjectByName.query("/nullKey"))); - assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObjectByName.query("/stringKey"))); - assertTrue("expected \"doubleKey\":-23.45e67", Double.valueOf("-23.45e67").equals(jsonObjectByName.query("/doubleKey"))); - } - - /** - * JSONObjects can be built from a Map. - * In this test the map is null. - * the JSONObject(JsonTokener) ctor is not tested directly since it already - * has full coverage from other tests. - */ - @Test - public void jsonObjectByNullMap() { - Map map = null; - JSONObject jsonObject = new JSONObject(map); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); - } - - /** - * JSONObjects can be built from a Map. - * In this test all of the map entries are valid JSON types. - */ - @Test - public void jsonObjectByMap() { - Map map = new HashMap(); - map.put("trueKey", new Boolean(true)); - map.put("falseKey", new Boolean(false)); - map.put("stringKey", "hello world!"); - map.put("escapeStringKey", "h\be\tllo w\u1234orld!"); - map.put("intKey", new Long(42)); - map.put("doubleKey", new Double(-23.45e67)); - JSONObject jsonObject = new JSONObject(map); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); - assertTrue("expected \"trueKey\":true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); - assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); - assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObject.query("/stringKey"))); - assertTrue("expected \"escapeStringKey\":\"h\be\tllo w\u1234orld!\"", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/escapeStringKey"))); - assertTrue("expected \"doubleKey\":-23.45e67", Double.valueOf("-23.45e67").equals(jsonObject.query("/doubleKey"))); - } - - /** - * Verifies that the constructor has backwards compatability with RAW types pre-java5. - */ - @Test - public void verifyConstructor() { - - final JSONObject expected = new JSONObject("{\"myKey\":10}"); - - @SuppressWarnings("rawtypes") - Map myRawC = Collections.singletonMap("myKey", Integer.valueOf(10)); - JSONObject jaRaw = new JSONObject(myRawC); - - Map myCStrObj = Collections.singletonMap("myKey", - (Object) Integer.valueOf(10)); - JSONObject jaStrObj = new JSONObject(myCStrObj); - - Map myCStrInt = Collections.singletonMap("myKey", - Integer.valueOf(10)); - JSONObject jaStrInt = new JSONObject(myCStrInt); - - Map myCObjObj = Collections.singletonMap((Object) "myKey", - (Object) Integer.valueOf(10)); - JSONObject jaObjObj = new JSONObject(myCObjObj); - - assertTrue( - "The RAW Collection should give me the same as the Typed Collection", - expected.similar(jaRaw)); - assertTrue( - "The RAW Collection should give me the same as the Typed Collection", - expected.similar(jaStrObj)); - assertTrue( - "The RAW Collection should give me the same as the Typed Collection", - expected.similar(jaStrInt)); - assertTrue( - "The RAW Collection should give me the same as the Typed Collection", - expected.similar(jaObjObj)); - } - - /** - * Tests Number serialization. - */ - @Test - public void verifyNumberOutput(){ - /** - * MyNumberContainer is a POJO, so call JSONObject(bean), - * which builds a map of getter names/values - * The only getter is getMyNumber (key=myNumber), - * whose return value is MyNumber. MyNumber extends Number, - * but is not recognized as such by wrap() per current - * implementation, so wrap() returns the default new JSONObject(bean). - * The only getter is getNumber (key=number), whose return value is - * BigDecimal(42). - */ - JSONObject jsonObject = new JSONObject(new MyNumberContainer()); - String actual = jsonObject.toString(); - String expected = "{\"myNumber\":{\"number\":42}}"; - assertEquals("Not Equal", expected , actual); - - /** - * JSONObject.put() handles objects differently than the - * bean constructor. Where the bean ctor wraps objects before - * placing them in the map, put() inserts the object without wrapping. - * In this case, a MyNumber instance is the value. - * The MyNumber.toString() method is responsible for - * returning a reasonable value: the string '42'. - */ - jsonObject = new JSONObject(); - jsonObject.put("myNumber", new MyNumber()); - actual = jsonObject.toString(); - expected = "{\"myNumber\":42}"; - assertEquals("Not Equal", expected , actual); - - /** - * Calls the JSONObject(Map) ctor, which calls wrap() for values. - * AtomicInteger is a Number, but is not recognized by wrap(), per - * current implementation. However, the type is - * 'java.util.concurrent.atomic', so due to the 'java' prefix, - * wrap() inserts the value as a string. That is why 42 comes back - * wrapped in quotes. - */ - jsonObject = new JSONObject(Collections.singletonMap("myNumber", new AtomicInteger(42))); - actual = jsonObject.toString(); - expected = "{\"myNumber\":\"42\"}"; - assertEquals("Not Equal", expected , actual); - - /** - * JSONObject.put() inserts the AtomicInteger directly into the - * map not calling wrap(). In toString()->write()->writeValue(), - * AtomicInteger is recognized as a Number, and converted via - * numberToString() into the unquoted string '42'. - */ - jsonObject = new JSONObject(); - jsonObject.put("myNumber", new AtomicInteger(42)); - actual = jsonObject.toString(); - expected = "{\"myNumber\":42}"; - assertEquals("Not Equal", expected , actual); - - /** - * Calls the JSONObject(Map) ctor, which calls wrap() for values. - * Fraction is a Number, but is not recognized by wrap(), per - * current implementation. As a POJO, Franction is handled as a - * bean and inserted into a contained JSONObject. It has 2 getters, - * for numerator and denominator. - */ - jsonObject = new JSONObject(Collections.singletonMap("myNumber", new Fraction(4,2))); - assertEquals(1, jsonObject.length()); - assertEquals(2, ((JSONObject)(jsonObject.get("myNumber"))).length()); - assertEquals("Numerator", BigInteger.valueOf(4) , jsonObject.query("/myNumber/numerator")); - assertEquals("Denominator", BigInteger.valueOf(2) , jsonObject.query("/myNumber/denominator")); - - /** - * JSONObject.put() inserts the Fraction directly into the - * map not calling wrap(). In toString()->write()->writeValue(), - * Fraction is recognized as a Number, and converted via - * numberToString() into the unquoted string '4/2'. But the - * BigDecimal sanity check fails, so writeValue() defaults - * to returning a safe JSON quoted string. Pretty slick! - */ - jsonObject = new JSONObject(); - jsonObject.put("myNumber", new Fraction(4,2)); - actual = jsonObject.toString(); - expected = "{\"myNumber\":\"4/2\"}"; // valid JSON, bug fixed - assertEquals("Not Equal", expected , actual); - } - - /** - * Verifies that the put Collection has backwards compatability with RAW types pre-java5. - */ - @Test - public void verifyPutCollection() { - - final JSONObject expected = new JSONObject("{\"myCollection\":[10]}"); - - @SuppressWarnings("rawtypes") - Collection myRawC = Collections.singleton(Integer.valueOf(10)); - JSONObject jaRaw = new JSONObject(); - jaRaw.put("myCollection", myRawC); - - Collection myCObj = Collections.singleton((Object) Integer - .valueOf(10)); - JSONObject jaObj = new JSONObject(); - jaObj.put("myCollection", myCObj); - - Collection myCInt = Collections.singleton(Integer - .valueOf(10)); - JSONObject jaInt = new JSONObject(); - jaInt.put("myCollection", myCInt); - - assertTrue( - "The RAW Collection should give me the same as the Typed Collection", - expected.similar(jaRaw)); - assertTrue( - "The RAW Collection should give me the same as the Typed Collection", - expected.similar(jaObj)); - assertTrue( - "The RAW Collection should give me the same as the Typed Collection", - expected.similar(jaInt)); - } - - - /** - * Verifies that the put Map has backwards compatability with RAW types pre-java5. - */ - @Test - public void verifyPutMap() { - - final JSONObject expected = new JSONObject("{\"myMap\":{\"myKey\":10}}"); - - @SuppressWarnings("rawtypes") - Map myRawC = Collections.singletonMap("myKey", Integer.valueOf(10)); - JSONObject jaRaw = new JSONObject(); - jaRaw.put("myMap", myRawC); - - Map myCStrObj = Collections.singletonMap("myKey", - (Object) Integer.valueOf(10)); - JSONObject jaStrObj = new JSONObject(); - jaStrObj.put("myMap", myCStrObj); - - Map myCStrInt = Collections.singletonMap("myKey", - Integer.valueOf(10)); - JSONObject jaStrInt = new JSONObject(); - jaStrInt.put("myMap", myCStrInt); - - Map myCObjObj = Collections.singletonMap((Object) "myKey", - (Object) Integer.valueOf(10)); - JSONObject jaObjObj = new JSONObject(); - jaObjObj.put("myMap", myCObjObj); - - assertTrue( - "The RAW Collection should give me the same as the Typed Collection", - expected.similar(jaRaw)); - assertTrue( - "The RAW Collection should give me the same as the Typed Collection", - expected.similar(jaStrObj)); - assertTrue( - "The RAW Collection should give me the same as the Typed Collection", - expected.similar(jaStrInt)); - assertTrue( - "The RAW Collection should give me the same as the Typed Collection", - expected.similar(jaObjObj)); - } - - - /** - * JSONObjects can be built from a Map. - * In this test the map entries are not valid JSON types. - * The actual conversion is kind of interesting. - */ - @Test - public void jsonObjectByMapWithUnsupportedValues() { - Map jsonMap = new HashMap(); - // Just insert some random objects - jsonMap.put("key1", new CDL()); - jsonMap.put("key2", new Exception()); - - JSONObject jsonObject = new JSONObject(jsonMap); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected 0 key1 items", ((Map)(JsonPath.read(doc, "$.key1"))).size() == 0); - assertTrue("expected \"key2\":java.lang.Exception","java.lang.Exception".equals(jsonObject.query("/key2"))); - } - - /** - * JSONObjects can be built from a Map. - * In this test one of the map values is null - */ - @Test - public void jsonObjectByMapWithNullValue() { - Map map = new HashMap(); - map.put("trueKey", new Boolean(true)); - map.put("falseKey", new Boolean(false)); - map.put("stringKey", "hello world!"); - map.put("nullKey", null); - map.put("escapeStringKey", "h\be\tllo w\u1234orld!"); - map.put("intKey", new Long(42)); - map.put("doubleKey", new Double(-23.45e67)); - JSONObject jsonObject = new JSONObject(map); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); - assertTrue("expected \"trueKey\":true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); - assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); - assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObject.query("/stringKey"))); - assertTrue("expected \"escapeStringKey\":\"h\be\tllo w\u1234orld!\"", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/escapeStringKey"))); - assertTrue("expected \"intKey\":42", Long.valueOf("42").equals(jsonObject.query("/intKey"))); - assertTrue("expected \"doubleKey\":-23.45e67", Double.valueOf("-23.45e67").equals(jsonObject.query("/doubleKey"))); - } - - /** - * JSONObject built from a bean. In this case all but one of the - * bean getters return valid JSON types - */ - @Test - public void jsonObjectByBean() { - /** - * Default access classes have to be mocked since JSONObject, which is - * not in the same package, cannot call MyBean methods by reflection. - */ - MyBean myBean = mock(MyBean.class); - when(myBean.getDoubleKey()).thenReturn(-23.45e7); - when(myBean.getIntKey()).thenReturn(42); - when(myBean.getStringKey()).thenReturn("hello world!"); - when(myBean.getEscapeStringKey()).thenReturn("h\be\tllo w\u1234orld!"); - when(myBean.isTrueKey()).thenReturn(true); - when(myBean.isFalseKey()).thenReturn(false); - when(myBean.getStringReaderKey()).thenReturn( - new StringReader("") { - }); - - JSONObject jsonObject = new JSONObject(myBean); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 8 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 8); - assertTrue("expected 0 items in stringReaderKey", ((Map) (JsonPath.read(doc, "$.stringReaderKey"))).size() == 0); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); - assertTrue("expected hello world!","hello world!".equals(jsonObject.query("/stringKey"))); - assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/escapeStringKey"))); - assertTrue("expected 42", Integer.valueOf("42").equals(jsonObject.query("/intKey"))); - assertTrue("expected -23.45e7", Double.valueOf("-23.45e7").equals(jsonObject.query("/doubleKey"))); - // sorry, mockito artifact - assertTrue("expected 2 callbacks items", ((List)(JsonPath.read(doc, "$.callbacks"))).size() == 2); - assertTrue("expected 0 handler items", ((Map)(JsonPath.read(doc, "$.callbacks[0].handler"))).size() == 0); - assertTrue("expected 0 callbacks[1] items", ((Map)(JsonPath.read(doc, "$.callbacks[1]"))).size() == 0); - } - - /** - * A bean is also an object. But in order to test the JSONObject - * ctor that takes an object and a list of names, - * this particular bean needs some public - * data members, which have been added to the class. - */ - @Test - public void jsonObjectByObjectAndNames() { - String[] keys = {"publicString", "publicInt"}; - // just need a class that has public data members - MyPublicClass myPublicClass = new MyPublicClass(); - JSONObject jsonObject = new JSONObject(myPublicClass, keys); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected \"publicString\":\"abc\"", "abc".equals(jsonObject.query("/publicString"))); - assertTrue("expected \"publicInt\":42", Integer.valueOf(42).equals(jsonObject.query("/publicInt"))); - } - - /** - * Exercise the JSONObject from resource bundle functionality. - * The test resource bundle is uncomplicated, but provides adequate test coverage. - */ - @Test - public void jsonObjectByResourceBundle() { - JSONObject jsonObject = new - JSONObject("org.json.junit.StringsResourceBundle", - Locale.getDefault()); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected 2 greetings items", ((Map)(JsonPath.read(doc, "$.greetings"))).size() == 2); - assertTrue("expected \"hello\":\"Hello, \"", "Hello, ".equals(jsonObject.query("/greetings/hello"))); - assertTrue("expected \"world\":\"World!\"", "World!".equals(jsonObject.query("/greetings/world"))); - assertTrue("expected 2 farewells items", ((Map)(JsonPath.read(doc, "$.farewells"))).size() == 2); - assertTrue("expected \"later\":\"Later, \"", "Later, ".equals(jsonObject.query("/farewells/later"))); - assertTrue("expected \"world\":\"World!\"", "Alligator!".equals(jsonObject.query("/farewells/gator"))); - } - - /** - * Exercise the JSONObject.accumulate() method - */ - @Test - public void jsonObjectAccumulate() { - - JSONObject jsonObject = new JSONObject(); - jsonObject.accumulate("myArray", true); - jsonObject.accumulate("myArray", false); - jsonObject.accumulate("myArray", "hello world!"); - jsonObject.accumulate("myArray", "h\be\tllo w\u1234orld!"); - jsonObject.accumulate("myArray", 42); - jsonObject.accumulate("myArray", -23.45e7); - // include an unsupported object for coverage - try { - jsonObject.accumulate("myArray", Double.NaN); - assertTrue("Expected exception", false); - } catch (JSONException ignored) {} - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); - assertTrue("expected 6 myArray items", ((List)(JsonPath.read(doc, "$.myArray"))).size() == 6); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/myArray/0"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/myArray/1"))); - assertTrue("expected hello world!", "hello world!".equals(jsonObject.query("/myArray/2"))); - assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/myArray/3"))); - assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.query("/myArray/4"))); - assertTrue("expected -23.45e7", Double.valueOf(-23.45e7).equals(jsonObject.query("/myArray/5"))); - } - - /** - * Exercise the JSONObject append() functionality - */ - @Test - public void jsonObjectAppend() { - JSONObject jsonObject = new JSONObject(); - jsonObject.append("myArray", true); - jsonObject.append("myArray", false); - jsonObject.append("myArray", "hello world!"); - jsonObject.append("myArray", "h\be\tllo w\u1234orld!"); - jsonObject.append("myArray", 42); - jsonObject.append("myArray", -23.45e7); - // include an unsupported object for coverage - try { - jsonObject.append("myArray", Double.NaN); - assertTrue("Expected exception", false); - } catch (JSONException ignored) {} - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); - assertTrue("expected 6 myArray items", ((List)(JsonPath.read(doc, "$.myArray"))).size() == 6); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/myArray/0"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/myArray/1/"))); - assertTrue("expected hello world!", "hello world!".equals(jsonObject.query("/myArray/2"))); - assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/myArray/3"))); - assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.query("/myArray/4"))); - assertTrue("expected -23.45e7", Double.valueOf(-23.45e7).equals(jsonObject.query("/myArray/5"))); - } - - /** - * Exercise the JSONObject doubleToString() method - */ - @Test - public void jsonObjectDoubleToString() { - String [] expectedStrs = {"1", "1", "-23.4", "-2.345E68", "null", "null" }; - Double [] doubles = { 1.0, 00001.00000, -23.4, -23.45e67, - Double.NaN, Double.NEGATIVE_INFINITY }; - for (int i = 0; i < expectedStrs.length; ++i) { - String actualStr = JSONObject.doubleToString(doubles[i]); - assertTrue("value expected ["+expectedStrs[i]+ - "] found ["+actualStr+ "]", - expectedStrs[i].equals(actualStr)); - } - } - - /** - * Exercise some JSONObject get[type] and opt[type] methods - */ - @Test - public void jsonObjectValues() { - String str = - "{"+ - "\"trueKey\":true,"+ - "\"falseKey\":false,"+ - "\"trueStrKey\":\"true\","+ - "\"falseStrKey\":\"false\","+ - "\"stringKey\":\"hello world!\","+ - "\"intKey\":42,"+ - "\"intStrKey\":\"43\","+ - "\"longKey\":1234567890123456789,"+ - "\"longStrKey\":\"987654321098765432\","+ - "\"doubleKey\":-23.45e7,"+ - "\"doubleStrKey\":\"00001.000\","+ - "\"arrayKey\":[0,1,2],"+ - "\"objectKey\":{\"myKey\":\"myVal\"}"+ - "}"; - JSONObject jsonObject = new JSONObject(str); - assertTrue("trueKey should be true", jsonObject.getBoolean("trueKey")); - assertTrue("opt trueKey should be true", jsonObject.optBoolean("trueKey")); - assertTrue("falseKey should be false", !jsonObject.getBoolean("falseKey")); - assertTrue("trueStrKey should be true", jsonObject.getBoolean("trueStrKey")); - assertTrue("trueStrKey should be true", jsonObject.optBoolean("trueStrKey")); - assertTrue("falseStrKey should be false", !jsonObject.getBoolean("falseStrKey")); - assertTrue("stringKey should be string", - jsonObject.getString("stringKey").equals("hello world!")); - assertTrue("doubleKey should be double", - jsonObject.getDouble("doubleKey") == -23.45e7); - assertTrue("doubleStrKey should be double", - jsonObject.getDouble("doubleStrKey") == 1); - assertTrue("opt doubleKey should be double", - jsonObject.optDouble("doubleKey") == -23.45e7); - assertTrue("opt doubleKey with Default should be double", - jsonObject.optDouble("doubleStrKey", Double.NaN) == 1); - assertTrue("intKey should be int", - jsonObject.optInt("intKey") == 42); - assertTrue("opt intKey should be int", - jsonObject.optInt("intKey", 0) == 42); - assertTrue("opt intKey with default should be int", - jsonObject.getInt("intKey") == 42); - assertTrue("intStrKey should be int", - jsonObject.getInt("intStrKey") == 43); - assertTrue("longKey should be long", - jsonObject.getLong("longKey") == 1234567890123456789L); - assertTrue("opt longKey should be long", - jsonObject.optLong("longKey") == 1234567890123456789L); - assertTrue("opt longKey with default should be long", - jsonObject.optLong("longKey", 0) == 1234567890123456789L); - assertTrue("longStrKey should be long", - jsonObject.getLong("longStrKey") == 987654321098765432L); - assertTrue("xKey should not exist", - jsonObject.isNull("xKey")); - assertTrue("stringKey should exist", - jsonObject.has("stringKey")); - assertTrue("opt stringKey should string", - jsonObject.optString("stringKey").equals("hello world!")); - assertTrue("opt stringKey with default should string", - jsonObject.optString("stringKey", "not found").equals("hello world!")); - JSONArray jsonArray = jsonObject.getJSONArray("arrayKey"); - assertTrue("arrayKey should be JSONArray", - jsonArray.getInt(0) == 0 && - jsonArray.getInt(1) == 1 && - jsonArray.getInt(2) == 2); - jsonArray = jsonObject.optJSONArray("arrayKey"); - assertTrue("opt arrayKey should be JSONArray", - jsonArray.getInt(0) == 0 && - jsonArray.getInt(1) == 1 && - jsonArray.getInt(2) == 2); - JSONObject jsonObjectInner = jsonObject.getJSONObject("objectKey"); - assertTrue("objectKey should be JSONObject", - jsonObjectInner.get("myKey").equals("myVal")); - } - - /** - * Check whether JSONObject handles large or high precision numbers correctly - */ - @Test - public void stringToValueNumbersTest() { - assertTrue("-0 Should be a Double!",JSONObject.stringToValue("-0") instanceof Double); - assertTrue("-0.0 Should be a Double!",JSONObject.stringToValue("-0.0") instanceof Double); - assertTrue("'-' Should be a String!",JSONObject.stringToValue("-") instanceof String); - assertTrue( "0.2 should be a Double!", - JSONObject.stringToValue( "0.2" ) instanceof Double ); - assertTrue( "Doubles should be Doubles, even when incorrectly converting floats!", - JSONObject.stringToValue( new Double( "0.2f" ).toString() ) instanceof Double ); - /** - * This test documents a need for BigDecimal conversion. - */ - Object obj = JSONObject.stringToValue( "299792.457999999984" ); - assertTrue( "evaluates to 299792.458 doubld instead of 299792.457999999984 BigDecimal!", - obj.equals(new Double(299792.458)) ); - assertTrue( "1 should be an Integer!", - JSONObject.stringToValue( "1" ) instanceof Integer ); - assertTrue( "Integer.MAX_VALUE should still be an Integer!", - JSONObject.stringToValue( new Integer( Integer.MAX_VALUE ).toString() ) instanceof Integer ); - assertTrue( "Large integers should be a Long!", - JSONObject.stringToValue( new Long( Long.sum( Integer.MAX_VALUE, 1 ) ).toString() ) instanceof Long ); - assertTrue( "Long.MAX_VALUE should still be an Integer!", - JSONObject.stringToValue( new Long( Long.MAX_VALUE ).toString() ) instanceof Long ); - - String str = new BigInteger( new Long( Long.MAX_VALUE ).toString() ).add( BigInteger.ONE ).toString(); - assertTrue( "Really large integers currently evaluate to string", - JSONObject.stringToValue(str).equals("9223372036854775808")); - } - - /** - * This test documents numeric values which could be numerically - * handled as BigDecimal or BigInteger. It helps determine what outputs - * will change if those types are supported. - */ - @Test - public void jsonValidNumberValuesNeitherLongNorIEEE754Compatible() { - // Valid JSON Numbers, probably should return BigDecimal or BigInteger objects - String str = - "{"+ - "\"numberWithDecimals\":299792.457999999984,"+ - "\"largeNumber\":12345678901234567890,"+ - "\"preciseNumber\":0.2000000000000000111,"+ - "\"largeExponent\":-23.45e2327"+ - "}"; - JSONObject jsonObject = new JSONObject(str); - // Comes back as a double, but loses precision - assertTrue( "numberWithDecimals currently evaluates to double 299792.458", - jsonObject.get( "numberWithDecimals" ).equals( new Double( "299792.458" ) ) ); - Object obj = jsonObject.get( "largeNumber" ); - assertTrue("largeNumber currently evaluates to string", - "12345678901234567890".equals(obj)); - // comes back as a double but loses precision - assertTrue( "preciseNumber currently evaluates to double 0.2", - jsonObject.get( "preciseNumber" ).equals(new Double(0.2))); - obj = jsonObject.get( "largeExponent" ); - assertTrue("largeExponent should currently evaluates as a string", - "-23.45e2327".equals(obj)); - } - - /** - * This test documents how JSON-Java handles invalid numeric input. - */ - @Test - public void jsonInvalidNumberValues() { - // Number-notations supported by Java and invalid as JSON - String str = - "{"+ - "\"hexNumber\":-0x123,"+ - "\"tooManyZeros\":00,"+ - "\"negativeInfinite\":-Infinity,"+ - "\"negativeNaN\":-NaN,"+ - "\"negativeFraction\":-.01,"+ - "\"tooManyZerosFraction\":00.001,"+ - "\"negativeHexFloat\":-0x1.fffp1,"+ - "\"hexFloat\":0x1.0P-1074,"+ - "\"floatIdentifier\":0.1f,"+ - "\"doubleIdentifier\":0.1d"+ - "}"; - JSONObject jsonObject = new JSONObject(str); - Object obj; - obj = jsonObject.get( "hexNumber" ); - assertFalse( "hexNumber must not be a number (should throw exception!?)", - obj instanceof Number ); - assertTrue("hexNumber currently evaluates to string", - obj.equals("-0x123")); - assertTrue( "tooManyZeros currently evaluates to string", - jsonObject.get( "tooManyZeros" ).equals("00")); - obj = jsonObject.get("negativeInfinite"); - assertTrue( "negativeInfinite currently evaluates to string", - obj.equals("-Infinity")); - obj = jsonObject.get("negativeNaN"); - assertTrue( "negativeNaN currently evaluates to string", - obj.equals("-NaN")); - assertTrue( "negativeFraction currently evaluates to double -0.01", - jsonObject.get( "negativeFraction" ).equals(new Double(-0.01))); - assertTrue( "tooManyZerosFraction currently evaluates to double 0.001", - jsonObject.get( "tooManyZerosFraction" ).equals(new Double(0.001))); - assertTrue( "negativeHexFloat currently evaluates to double -3.99951171875", - jsonObject.get( "negativeHexFloat" ).equals(new Double(-3.99951171875))); - assertTrue("hexFloat currently evaluates to double 4.9E-324", - jsonObject.get("hexFloat").equals(new Double(4.9E-324))); - assertTrue("floatIdentifier currently evaluates to double 0.1", - jsonObject.get("floatIdentifier").equals(new Double(0.1))); - assertTrue("doubleIdentifier currently evaluates to double 0.1", - jsonObject.get("doubleIdentifier").equals(new Double(0.1))); - } - - /** - * Tests how JSONObject get[type] handles incorrect types - */ - @Test - public void jsonObjectNonAndWrongValues() { - String str = - "{"+ - "\"trueKey\":true,"+ - "\"falseKey\":false,"+ - "\"trueStrKey\":\"true\","+ - "\"falseStrKey\":\"false\","+ - "\"stringKey\":\"hello world!\","+ - "\"intKey\":42,"+ - "\"intStrKey\":\"43\","+ - "\"longKey\":1234567890123456789,"+ - "\"longStrKey\":\"987654321098765432\","+ - "\"doubleKey\":-23.45e7,"+ - "\"doubleStrKey\":\"00001.000\","+ - "\"arrayKey\":[0,1,2],"+ - "\"objectKey\":{\"myKey\":\"myVal\"}"+ - "}"; - JSONObject jsonObject = new JSONObject(str); - try { - jsonObject.getBoolean("nonKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("expecting an exception message", - "JSONObject[\"nonKey\"] not found.".equals(e.getMessage())); - } - try { - jsonObject.getBoolean("stringKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a Boolean.". - equals(e.getMessage())); - } - try { - jsonObject.getString("nonKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); - } - try { - jsonObject.getString("trueKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"trueKey\"] not a string.". - equals(e.getMessage())); - } - try { - jsonObject.getDouble("nonKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); - } - try { - jsonObject.getDouble("stringKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a number.". - equals(e.getMessage())); - } - try { - jsonObject.getInt("nonKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); - } - try { - jsonObject.getInt("stringKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not an int.". - equals(e.getMessage())); - } - try { - jsonObject.getLong("nonKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); - } - try { - jsonObject.getLong("stringKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a long.". - equals(e.getMessage())); - } - try { - jsonObject.getJSONArray("nonKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); - } - try { - jsonObject.getJSONArray("stringKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a JSONArray.". - equals(e.getMessage())); - } - try { - jsonObject.getJSONObject("nonKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); - } - try { - jsonObject.getJSONObject("stringKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a JSONObject.". - equals(e.getMessage())); - } - } - - /** - * This test documents an unexpected numeric behavior. - * A double that ends with .0 is parsed, serialized, then - * parsed again. On the second parse, it has become an int. - */ - @Test - public void unexpectedDoubleToIntConversion() { - String key30 = "key30"; - String key31 = "key31"; - JSONObject jsonObject = new JSONObject(); - jsonObject.put(key30, new Double(3.0)); - jsonObject.put(key31, new Double(3.1)); - - assertTrue("3.0 should remain a double", - jsonObject.getDouble(key30) == 3); - assertTrue("3.1 should remain a double", - jsonObject.getDouble(key31) == 3.1); - - // turns 3.0 into 3. - String serializedString = jsonObject.toString(); - JSONObject deserialized = new JSONObject(serializedString); - assertTrue("3.0 is now an int", deserialized.get(key30) instanceof Integer); - assertTrue("3.0 can still be interpreted as a double", - deserialized.getDouble(key30) == 3.0); - assertTrue("3.1 remains a double", deserialized.getDouble(key31) == 3.1); - } - - /** - * Document behaviors of big numbers. Includes both JSONObject - * and JSONArray tests - */ - @Test - public void bigNumberOperations() { - /** - * JSONObject tries to parse BigInteger as a bean, but it only has - * one getter, getLowestBitSet(). The value is lost and an unhelpful - * value is stored. This should be fixed. - */ - BigInteger bigInteger = new BigInteger("123456789012345678901234567890"); - JSONObject jsonObject = new JSONObject(bigInteger); - Object obj = jsonObject.get("lowestSetBit"); - assertTrue("JSONObject only has 1 value", jsonObject.length() == 1); - assertTrue("JSONObject parses BigInteger as the Integer lowestBitSet", - obj instanceof Integer); - assertTrue("this bigInteger lowestBitSet happens to be 1", - obj.equals(1)); - - /** - * JSONObject tries to parse BigDecimal as a bean, but it has - * no getters, The value is lost and no value is stored. - * This should be fixed. - */ - BigDecimal bigDecimal = new BigDecimal( - "123456789012345678901234567890.12345678901234567890123456789"); - jsonObject = new JSONObject(bigDecimal); - assertTrue("large bigDecimal is not stored", jsonObject.length() == 0); - - /** - * JSONObject put(String, Object) method stores and serializes - * bigInt and bigDec correctly. Nothing needs to change. - */ - jsonObject = new JSONObject(); - jsonObject.put("bigInt", bigInteger); - assertTrue("jsonObject.put() handles bigInt correctly", - jsonObject.get("bigInt").equals(bigInteger)); - assertTrue("jsonObject.getBigInteger() handles bigInt correctly", - jsonObject.getBigInteger("bigInt").equals(bigInteger)); - assertTrue("jsonObject.optBigInteger() handles bigInt correctly", - jsonObject.optBigInteger("bigInt", BigInteger.ONE).equals(bigInteger)); - assertTrue("jsonObject serializes bigInt correctly", - jsonObject.toString().equals("{\"bigInt\":123456789012345678901234567890}")); - jsonObject = new JSONObject(); - jsonObject.put("bigDec", bigDecimal); - assertTrue("jsonObject.put() handles bigDec correctly", - jsonObject.get("bigDec").equals(bigDecimal)); - assertTrue("jsonObject.getBigDecimal() handles bigDec correctly", - jsonObject.getBigDecimal("bigDec").equals(bigDecimal)); - assertTrue("jsonObject.optBigDecimal() handles bigDec correctly", - jsonObject.optBigDecimal("bigDec", BigDecimal.ONE).equals(bigDecimal)); - assertTrue("jsonObject serializes bigDec correctly", - jsonObject.toString().equals( - "{\"bigDec\":123456789012345678901234567890.12345678901234567890123456789}")); - - /** - * exercise some exceptions - */ - try { - jsonObject.getBigDecimal("bigInt"); - assertTrue("expected an exeption", false); - } catch (JSONException ignored) {} - obj = jsonObject.optBigDecimal("bigInt", BigDecimal.ONE); - assertTrue("expected BigDecimal", obj.equals(BigDecimal.ONE)); - try { - jsonObject.getBigInteger("bigDec"); - assertTrue("expected an exeption", false); - } catch (JSONException ignored) {} - jsonObject.put("stringKey", "abc"); - try { - jsonObject.getBigDecimal("stringKey"); - assertTrue("expected an exeption", false); - } catch (JSONException ignored) {} - obj = jsonObject.optBigInteger("bigDec", BigInteger.ONE); - assertTrue("expected BigInteger", obj.equals(BigInteger.ONE)); - - /** - * JSONObject.numberToString() works correctly, nothing to change. - */ - String str = JSONObject.numberToString(bigInteger); - assertTrue("numberToString() handles bigInteger correctly", - str.equals("123456789012345678901234567890")); - str = JSONObject.numberToString(bigDecimal); - assertTrue("numberToString() handles bigDecimal correctly", - str.equals("123456789012345678901234567890.12345678901234567890123456789")); - - /** - * JSONObject.stringToValue() turns bigInt into an accurate string, - * and rounds bigDec. This incorrect, but users may have come to - * expect this behavior. Change would be marginally better, but - * might inconvenience users. - */ - obj = JSONObject.stringToValue(bigInteger.toString()); - assertTrue("stringToValue() turns bigInteger string into string", - obj instanceof String); - obj = JSONObject.stringToValue(bigDecimal.toString()); - assertTrue("stringToValue() changes bigDecimal string", - !obj.toString().equals(bigDecimal.toString())); - - /** - * wrap() vs put() big number behavior is now the same. - */ - // bigInt map ctor - Map map = new HashMap(); - map.put("bigInt", bigInteger); - jsonObject = new JSONObject(map); - String actualFromMapStr = jsonObject.toString(); - assertTrue("bigInt in map (or array or bean) is a string", - actualFromMapStr.equals( - "{\"bigInt\":123456789012345678901234567890}")); - // bigInt put - jsonObject = new JSONObject(); - jsonObject.put("bigInt", bigInteger); - String actualFromPutStr = jsonObject.toString(); - assertTrue("bigInt from put is a number", - actualFromPutStr.equals( - "{\"bigInt\":123456789012345678901234567890}")); - // bigDec map ctor - map = new HashMap(); - map.put("bigDec", bigDecimal); - jsonObject = new JSONObject(map); - actualFromMapStr = jsonObject.toString(); - assertTrue("bigDec in map (or array or bean) is a bigDec", - actualFromMapStr.equals( - "{\"bigDec\":123456789012345678901234567890.12345678901234567890123456789}")); - // bigDec put - jsonObject = new JSONObject(); - jsonObject.put("bigDec", bigDecimal); - actualFromPutStr = jsonObject.toString(); - assertTrue("bigDec from put is a number", - actualFromPutStr.equals( - "{\"bigDec\":123456789012345678901234567890.12345678901234567890123456789}")); - // bigInt,bigDec put - JSONArray jsonArray = new JSONArray(); - jsonArray.put(bigInteger); - jsonArray.put(bigDecimal); - actualFromPutStr = jsonArray.toString(); - assertTrue("bigInt, bigDec from put is a number", - actualFromPutStr.equals( - "[123456789012345678901234567890,123456789012345678901234567890.12345678901234567890123456789]")); - assertTrue("getBigInt is bigInt", jsonArray.getBigInteger(0).equals(bigInteger)); - assertTrue("getBigDec is bigDec", jsonArray.getBigDecimal(1).equals(bigDecimal)); - assertTrue("optBigInt is bigInt", jsonArray.optBigInteger(0, BigInteger.ONE).equals(bigInteger)); - assertTrue("optBigDec is bigDec", jsonArray.optBigDecimal(1, BigDecimal.ONE).equals(bigDecimal)); - jsonArray.put(Boolean.TRUE); - try { - jsonArray.getBigInteger(2); - assertTrue("should not be able to get big int", false); - } catch (Exception ignored) {} - try { - jsonArray.getBigDecimal(2); - assertTrue("should not be able to get big dec", false); - } catch (Exception ignored) {} - assertTrue("optBigInt is default", jsonArray.optBigInteger(2, BigInteger.ONE).equals(BigInteger.ONE)); - assertTrue("optBigDec is default", jsonArray.optBigDecimal(2, BigDecimal.ONE).equals(BigDecimal.ONE)); - - // bigInt,bigDec list ctor - List list = new ArrayList(); - list.add(bigInteger); - list.add(bigDecimal); - jsonArray = new JSONArray(list); - String actualFromListStr = jsonArray.toString(); - assertTrue("bigInt, bigDec in list is a bigInt, bigDec", - actualFromListStr.equals( - "[123456789012345678901234567890,123456789012345678901234567890.12345678901234567890123456789]")); - // bigInt bean ctor - MyBigNumberBean myBigNumberBean = mock(MyBigNumberBean.class); - when(myBigNumberBean.getBigInteger()).thenReturn(new BigInteger("123456789012345678901234567890")); - jsonObject = new JSONObject(myBigNumberBean); - String actualFromBeanStr = jsonObject.toString(); - // can't do a full string compare because mockery adds an extra key/value - assertTrue("bigInt from bean ctor is a bigInt", - actualFromBeanStr.contains("123456789012345678901234567890")); - // bigDec bean ctor - myBigNumberBean = mock(MyBigNumberBean.class); - when(myBigNumberBean.getBigDecimal()).thenReturn(new BigDecimal("123456789012345678901234567890.12345678901234567890123456789")); - jsonObject = new JSONObject(myBigNumberBean); - actualFromBeanStr = jsonObject.toString(); - // can't do a full string compare because mockery adds an extra key/value - assertTrue("bigDec from bean ctor is a bigDec", - actualFromBeanStr.contains("123456789012345678901234567890.12345678901234567890123456789")); - // bigInt,bigDec wrap() - obj = JSONObject.wrap(bigInteger); - assertTrue("wrap() returns big num",obj.equals(bigInteger)); - obj = JSONObject.wrap(bigDecimal); - assertTrue("wrap() returns string",obj.equals(bigDecimal)); - - } - - /** - * The purpose for the static method getNames() methods are not clear. - * This method is not called from within JSON-Java. Most likely - * uses are to prep names arrays for: - * JSONObject(JSONObject jo, String[] names) - * JSONObject(Object object, String names[]), - */ - @Test - public void jsonObjectNames() { - JSONObject jsonObject; - - // getNames() from null JSONObject - assertTrue("null names from null Object", - null == JSONObject.getNames((Object)null)); - - // getNames() from object with no fields - assertTrue("null names from Object with no fields", - null == JSONObject.getNames(new MyJsonString())); - - // getNames from new JSONOjbect - jsonObject = new JSONObject(); - String [] names = JSONObject.getNames(jsonObject); - assertTrue("names should be null", names == null); - - - // getNames() from empty JSONObject - String emptyStr = "{}"; - jsonObject = new JSONObject(emptyStr); - assertTrue("empty JSONObject should have null names", - null == JSONObject.getNames(jsonObject)); - - // getNames() from JSONObject - String str = - "{"+ - "\"trueKey\":true,"+ - "\"falseKey\":false,"+ - "\"stringKey\":\"hello world!\","+ - "}"; - jsonObject = new JSONObject(str); - names = JSONObject.getNames(jsonObject); - JSONArray jsonArray = new JSONArray(names); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider() - .parse(jsonArray.toString()); - List docList = JsonPath.read(doc, "$"); - assertTrue("expected 3 items", docList.size() == 3); - assertTrue( - "expected to find trueKey", - ((List) JsonPath.read(doc, "$[?(@=='trueKey')]")).size() == 1); - assertTrue( - "expected to find falseKey", - ((List) JsonPath.read(doc, "$[?(@=='falseKey')]")).size() == 1); - assertTrue( - "expected to find stringKey", - ((List) JsonPath.read(doc, "$[?(@=='stringKey')]")).size() == 1); - - /** - * getNames() from an enum with properties has an interesting result. - * It returns the enum values, not the selected enum properties - */ - MyEnumField myEnumField = MyEnumField.VAL1; - names = JSONObject.getNames(myEnumField); - - // validate JSON - jsonArray = new JSONArray(names); - doc = Configuration.defaultConfiguration().jsonProvider() - .parse(jsonArray.toString()); - docList = JsonPath.read(doc, "$"); - assertTrue("expected 3 items", docList.size() == 3); - assertTrue( - "expected to find VAL1", - ((List) JsonPath.read(doc, "$[?(@=='VAL1')]")).size() == 1); - assertTrue( - "expected to find VAL2", - ((List) JsonPath.read(doc, "$[?(@=='VAL2')]")).size() == 1); - assertTrue( - "expected to find VAL3", - ((List) JsonPath.read(doc, "$[?(@=='VAL3')]")).size() == 1); - - /** - * A bean is also an object. But in order to test the static - * method getNames(), this particular bean needs some public - * data members. - */ - MyPublicClass myPublicClass = new MyPublicClass(); - names = JSONObject.getNames(myPublicClass); - - // validate JSON - jsonArray = new JSONArray(names); - doc = Configuration.defaultConfiguration().jsonProvider() - .parse(jsonArray.toString()); - docList = JsonPath.read(doc, "$"); - assertTrue("expected 2 items", docList.size() == 2); - assertTrue( - "expected to find publicString", - ((List) JsonPath.read(doc, "$[?(@=='publicString')]")).size() == 1); - assertTrue( - "expected to find publicInt", - ((List) JsonPath.read(doc, "$[?(@=='publicInt')]")).size() == 1); - } - - /** - * Populate a JSONArray from an empty JSONObject names() method. - * It should be empty. - */ - @Test - public void emptyJsonObjectNamesToJsonAray() { - JSONObject jsonObject = new JSONObject(); - JSONArray jsonArray = jsonObject.names(); - assertTrue("jsonArray should be null", jsonArray == null); - } - - /** - * Populate a JSONArray from a JSONObject names() method. - * Confirm that it contains the expected names. - */ - @Test - public void jsonObjectNamesToJsonAray() { - String str = - "{"+ - "\"trueKey\":true,"+ - "\"falseKey\":false,"+ - "\"stringKey\":\"hello world!\","+ - "}"; - - JSONObject jsonObject = new JSONObject(str); - JSONArray jsonArray = jsonObject.names(); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); - assertTrue("expected 3 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected to find trueKey", ((List) JsonPath.read(doc, "$[?(@=='trueKey')]")).size() == 1); - assertTrue("expected to find falseKey", ((List) JsonPath.read(doc, "$[?(@=='falseKey')]")).size() == 1); - assertTrue("expected to find stringKey", ((List) JsonPath.read(doc, "$[?(@=='stringKey')]")).size() == 1); - } - - /** - * Exercise the JSONObject increment() method. - */ - @Test - public void jsonObjectIncrement() { - String str = - "{"+ - "\"keyLong\":9999999991,"+ - "\"keyDouble\":1.1"+ - "}"; - JSONObject jsonObject = new JSONObject(str); - jsonObject.increment("keyInt"); - jsonObject.increment("keyInt"); - jsonObject.increment("keyLong"); - jsonObject.increment("keyDouble"); - jsonObject.increment("keyInt"); - jsonObject.increment("keyLong"); - jsonObject.increment("keyDouble"); - /** - * JSONObject constructor won't handle these types correctly, but - * adding them via put works. - */ - jsonObject.put("keyFloat", new Float(1.1)); - jsonObject.put("keyBigInt", new BigInteger("123456789123456789123456789123456780")); - jsonObject.put("keyBigDec", new BigDecimal("123456789123456789123456789123456780.1")); - jsonObject.increment("keyFloat"); - jsonObject.increment("keyFloat"); - jsonObject.increment("keyBigInt"); - jsonObject.increment("keyBigDec"); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonObject.query("/keyInt"))); - assertTrue("expected 9999999993", Long.valueOf(9999999993L).equals(jsonObject.query("/keyLong"))); - assertTrue("expected 3.1", Double.valueOf(3.1).equals(jsonObject.query("/keyDouble"))); - assertTrue("expected 123456789123456789123456789123456781", new BigInteger("123456789123456789123456789123456781").equals(jsonObject.query("/keyBigInt"))); - assertTrue("expected 123456789123456789123456789123456781.1", new BigDecimal("123456789123456789123456789123456781.1").equals(jsonObject.query("/keyBigDec"))); - - /** - * Should work the same way on any platform! @see https://docs.oracle - * .com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.3 This is the - * effect of a float to double conversion and is inherent to the - * shortcomings of the IEEE 754 format, when converting 32-bit into - * double-precision 64-bit. Java type-casts float to double. A 32 bit - * float is type-casted to 64 bit double by simply appending zero-bits - * to the mantissa (and extended the signed exponent by 3 bits.) and - * there is no way to obtain more information than it is stored in the - * 32-bits float. - * - * Like 1/3 cannot be represented as base10 number because it is - * periodically, 1/5 (for example) cannot be represented as base2 number - * since it is periodically in base2 (take a look at - * http://www.h-schmidt.net/FloatConverter/) The same happens to 3.1, - * that decimal number (base10 representation) is periodic in base2 - * representation, therefore appending zero-bits is inaccurate. Only - * repeating the periodically occuring bits (0110) would be a proper - * conversion. However one cannot detect from a 32 bit IEE754 - * representation which bits would "repeat infinitely", since the - * missing bits would not fit into the 32 bit float, i.e. the - * information needed simply is not there! - */ - assertTrue("expected 3.0999999046325684", Double.valueOf(3.0999999046325684).equals(jsonObject.query("/keyFloat"))); - - /** - * float f = 3.1f; double df = (double) f; double d = 3.1d; - * System.out.println - * (Integer.toBinaryString(Float.floatToRawIntBits(f))); - * System.out.println - * (Long.toBinaryString(Double.doubleToRawLongBits(df))); - * System.out.println - * (Long.toBinaryString(Double.doubleToRawLongBits(d))); - * - * - Float: - * seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm - * 1000000010001100110011001100110 - * - Double - * seeeeeeeeeeemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm - * 10000000 10001100110011001100110 - * 100000000001000110011001100110011000000000000000000000000000000 - * 100000000001000110011001100110011001100110011001100110011001101 - */ - - /** - * Examples of well documented but probably unexpected behavior in - * java / with 32-bit float to 64-bit float conversion. - */ - assertFalse("Document unexpected behaviour with explicit type-casting float as double!", (double)0.2f == 0.2d ); - assertFalse("Document unexpected behaviour with implicit type-cast!", 0.2f == 0.2d ); - Double d1 = new Double( 1.1f ); - Double d2 = new Double( "1.1f" ); - assertFalse( "Document implicit type cast from float to double before calling Double(double d) constructor", d1.equals( d2 ) ); - - assertTrue( "Correctly converting float to double via base10 (string) representation!", new Double( 3.1d ).equals( new Double( new Float( 3.1f ).toString() ) ) ); - - // Pinpointing the not so obvious "buggy" conversion from float to double in JSONObject - JSONObject jo = new JSONObject(); - jo.put( "bug", 3.1f ); // will call put( String key, double value ) with implicit and "buggy" type-cast from float to double - assertFalse( "The java-compiler did add some zero bits for you to the mantissa (unexpected, but well documented)", jo.get( "bug" ).equals( new Double( 3.1d ) ) ); - - JSONObject inc = new JSONObject(); - inc.put( "bug", new Float( 3.1f ) ); // This will put in instance of Float into JSONObject, i.e. call put( String key, Object value ) - assertTrue( "Everything is ok here!", inc.get( "bug" ) instanceof Float ); - inc.increment( "bug" ); // after adding 1, increment will call put( String key, double value ) with implicit and "buggy" type-cast from float to double! - // this.put(key, (Float) value + 1); - // 1. The (Object)value will be typecasted to (Float)value since it is an instanceof Float actually nothing is done. - // 2. Float instance will be autoboxed into float because the + operator will work on primitives not Objects! - // 3. A float+float operation will be performed and results into a float primitive. - // 4. There is no method that matches the signature put( String key, float value), java-compiler will choose the method - // put( String key, double value) and does an implicit type-cast(!) by appending zero-bits to the mantissa - assertTrue( "JSONObject increment converts Float to Double", jo.get( "bug" ) instanceof Double ); - // correct implementation (with change of behavior) would be: - // this.put(key, new Float((Float) value + 1)); - // Probably it would be better to deprecate the method and remove some day, while convenient processing the "payload" is not - // really in the the scope of a JSON-library (IMHO.) - - } - - /** - * Exercise JSONObject numberToString() method - */ - @Test - public void jsonObjectNumberToString() { - String str; - Double dVal; - Integer iVal = 1; - str = JSONObject.numberToString(iVal); - assertTrue("expected "+iVal+" actual "+str, iVal.toString().equals(str)); - dVal = 12.34; - str = JSONObject.numberToString(dVal); - assertTrue("expected "+dVal+" actual "+str, dVal.toString().equals(str)); - dVal = 12.34e27; - str = JSONObject.numberToString(dVal); - assertTrue("expected "+dVal+" actual "+str, dVal.toString().equals(str)); - // trailing .0 is truncated, so it doesn't quite match toString() - dVal = 5000000.0000000; - str = JSONObject.numberToString(dVal); - assertTrue("expected 5000000 actual "+str, str.equals("5000000")); - } - - /** - * Exercise JSONObject put() and similar() methods - */ - @Test - public void jsonObjectPut() { - String expectedStr = - "{"+ - "\"trueKey\":true,"+ - "\"falseKey\":false,"+ - "\"arrayKey\":[0,1,2],"+ - "\"objectKey\":{"+ - "\"myKey1\":\"myVal1\","+ - "\"myKey2\":\"myVal2\","+ - "\"myKey3\":\"myVal3\","+ - "\"myKey4\":\"myVal4\""+ - "}"+ - "}"; - JSONObject jsonObject = new JSONObject(); - jsonObject.put("trueKey", true); - jsonObject.put("falseKey", false); - Integer [] intArray = { 0, 1, 2 }; - jsonObject.put("arrayKey", Arrays.asList(intArray)); - Map myMap = new HashMap(); - myMap.put("myKey1", "myVal1"); - myMap.put("myKey2", "myVal2"); - myMap.put("myKey3", "myVal3"); - myMap.put("myKey4", "myVal4"); - jsonObject.put("objectKey", myMap); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 4 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 4); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); - assertTrue("expected 3 arrayKey items", ((List)(JsonPath.read(doc, "$.arrayKey"))).size() == 3); - assertTrue("expected 0", Integer.valueOf(0).equals(jsonObject.query("/arrayKey/0"))); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonObject.query("/arrayKey/1"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.query("/arrayKey/2"))); - assertTrue("expected 4 objectKey items", ((Map)(JsonPath.read(doc, "$.objectKey"))).size() == 4); - assertTrue("expected myVal1", "myVal1".equals(jsonObject.query("/objectKey/myKey1"))); - assertTrue("expected myVal2", "myVal2".equals(jsonObject.query("/objectKey/myKey2"))); - assertTrue("expected myVal3", "myVal3".equals(jsonObject.query("/objectKey/myKey3"))); - assertTrue("expected myVal4", "myVal4".equals(jsonObject.query("/objectKey/myKey4"))); - - jsonObject.remove("trueKey"); - JSONObject expectedJsonObject = new JSONObject(expectedStr); - assertTrue("unequal jsonObjects should not be similar", - !jsonObject.similar(expectedJsonObject)); - assertTrue("jsonObject should not be similar to jsonArray", - !jsonObject.similar(new JSONArray())); - - String aCompareValueStr = "{\"a\":\"aval\",\"b\":true}"; - String bCompareValueStr = "{\"a\":\"notAval\",\"b\":true}"; - JSONObject aCompareValueJsonObject = new JSONObject(aCompareValueStr); - JSONObject bCompareValueJsonObject = new JSONObject(bCompareValueStr); - assertTrue("different values should not be similar", - !aCompareValueJsonObject.similar(bCompareValueJsonObject)); - - String aCompareObjectStr = "{\"a\":\"aval\",\"b\":{}}"; - String bCompareObjectStr = "{\"a\":\"aval\",\"b\":true}"; - JSONObject aCompareObjectJsonObject = new JSONObject(aCompareObjectStr); - JSONObject bCompareObjectJsonObject = new JSONObject(bCompareObjectStr); - assertTrue("different nested JSONObjects should not be similar", - !aCompareObjectJsonObject.similar(bCompareObjectJsonObject)); - - String aCompareArrayStr = "{\"a\":\"aval\",\"b\":[]}"; - String bCompareArrayStr = "{\"a\":\"aval\",\"b\":true}"; - JSONObject aCompareArrayJsonObject = new JSONObject(aCompareArrayStr); - JSONObject bCompareArrayJsonObject = new JSONObject(bCompareArrayStr); - assertTrue("different nested JSONArrays should not be similar", - !aCompareArrayJsonObject.similar(bCompareArrayJsonObject)); - } - - /** - * Exercise JSONObject toString() method - */ - @Test - public void jsonObjectToString() { - String str = - "{"+ - "\"trueKey\":true,"+ - "\"falseKey\":false,"+ - "\"arrayKey\":[0,1,2],"+ - "\"objectKey\":{"+ - "\"myKey1\":\"myVal1\","+ - "\"myKey2\":\"myVal2\","+ - "\"myKey3\":\"myVal3\","+ - "\"myKey4\":\"myVal4\""+ - "}"+ - "}"; - JSONObject jsonObject = new JSONObject(str); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 4 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 4); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); - assertTrue("expected 3 arrayKey items", ((List)(JsonPath.read(doc, "$.arrayKey"))).size() == 3); - assertTrue("expected 0", Integer.valueOf(0).equals(jsonObject.query("/arrayKey/0"))); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonObject.query("/arrayKey/1"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.query("/arrayKey/2"))); - assertTrue("expected 4 objectKey items", ((Map)(JsonPath.read(doc, "$.objectKey"))).size() == 4); - assertTrue("expected myVal1", "myVal1".equals(jsonObject.query("/objectKey/myKey1"))); - assertTrue("expected myVal2", "myVal2".equals(jsonObject.query("/objectKey/myKey2"))); - assertTrue("expected myVal3", "myVal3".equals(jsonObject.query("/objectKey/myKey3"))); - assertTrue("expected myVal4", "myVal4".equals(jsonObject.query("/objectKey/myKey4"))); - } - - /** - * Exercise JSONObject toString() method with various indent levels. - */ - @Test - public void jsonObjectToStringIndent() { - String jsonObject0Str = - "{"+ - "\"key1\":" + - "[1,2," + - "{\"key3\":true}" + - "],"+ - "\"key2\":" + - "{\"key1\":\"val1\",\"key2\":" + - "{\"key2\":\"val2\"}" + - "},"+ - "\"key3\":" + - "[" + - "[1,2.1]" + - "," + - "[null]" + - "]"+ - "}"; - - String jsonObject1Str = - "{\n" + - " \"key1\": [\n" + - " 1,\n" + - " 2,\n" + - " {\"key3\": true}\n" + - " ],\n" + - " \"key2\": {\n" + - " \"key1\": \"val1\",\n" + - " \"key2\": {\"key2\": \"val2\"}\n" + - " },\n" + - " \"key3\": [\n" + - " [\n" + - " 1,\n" + - " 2.1\n" + - " ],\n" + - " [null]\n" + - " ]\n" + - "}"; - String jsonObject4Str = - "{\n" + - " \"key1\": [\n" + - " 1,\n" + - " 2,\n" + - " {\"key3\": true}\n" + - " ],\n" + - " \"key2\": {\n" + - " \"key1\": \"val1\",\n" + - " \"key2\": {\"key2\": \"val2\"}\n" + - " },\n" + - " \"key3\": [\n" + - " [\n" + - " 1,\n" + - " 2.1\n" + - " ],\n" + - " [null]\n" + - " ]\n" + - "}"; - JSONObject jsonObject = new JSONObject(jsonObject0Str); - assertEquals(jsonObject0Str, jsonObject.toString()); - assertEquals(jsonObject0Str, jsonObject.toString(0)); - assertEquals(jsonObject1Str, jsonObject.toString(1)); - assertEquals(jsonObject4Str, jsonObject.toString(4)); - } - - /** - * Explores how JSONObject handles maps. Insert a string/string map - * as a value in a JSONObject. It will remain a map. Convert the - * JSONObject to string, then create a new JSONObject from the string. - * In the new JSONObject, the value will be stored as a nested JSONObject. - * Confirm that map and nested JSONObject have the same contents. - */ - @Test - public void jsonObjectToStringSuppressWarningOnCastToMap() { - JSONObject jsonObject = new JSONObject(); - Map map = new HashMap<>(); - map.put("abc", "def"); - jsonObject.put("key", map); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); - assertTrue("expected 1 key item", ((Map)(JsonPath.read(doc, "$.key"))).size() == 1); - assertTrue("expected def", "def".equals(jsonObject.query("/key/abc"))); - } - - /** - * Explores how JSONObject handles collections. Insert a string collection - * as a value in a JSONObject. It will remain a collection. Convert the - * JSONObject to string, then create a new JSONObject from the string. - * In the new JSONObject, the value will be stored as a nested JSONArray. - * Confirm that collection and nested JSONArray have the same contents. - */ - @Test - public void jsonObjectToStringSuppressWarningOnCastToCollection() { - JSONObject jsonObject = new JSONObject(); - Collection collection = new ArrayList(); - collection.add("abc"); - // ArrayList will be added as an object - jsonObject.put("key", collection); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); - assertTrue("expected 1 key item", ((List)(JsonPath.read(doc, "$.key"))).size() == 1); - assertTrue("expected abc", "abc".equals(jsonObject.query("/key/0"))); - } - - /** - * Exercises the JSONObject.valueToString() method for various types - */ - @Test - public void valueToString() { - - assertTrue("null valueToString() incorrect", - "null".equals(JSONObject.valueToString(null))); - MyJsonString jsonString = new MyJsonString(); - assertTrue("jsonstring valueToString() incorrect", - "my string".equals(JSONObject.valueToString(jsonString))); - assertTrue("boolean valueToString() incorrect", - "true".equals(JSONObject.valueToString(Boolean.TRUE))); - assertTrue("non-numeric double", - "null".equals(JSONObject.doubleToString(Double.POSITIVE_INFINITY))); - String jsonObjectStr = - "{"+ - "\"key1\":\"val1\","+ - "\"key2\":\"val2\","+ - "\"key3\":\"val3\""+ - "}"; - JSONObject jsonObject = new JSONObject(jsonObjectStr); - assertTrue("jsonObject valueToString() incorrect", - JSONObject.valueToString(jsonObject).equals(jsonObject.toString())); - String jsonArrayStr = - "[1,2,3]"; - JSONArray jsonArray = new JSONArray(jsonArrayStr); - assertTrue("jsonArray valueToString() incorrect", - JSONObject.valueToString(jsonArray).equals(jsonArray.toString())); - Map map = new HashMap(); - map.put("key1", "val1"); - map.put("key2", "val2"); - map.put("key3", "val3"); - assertTrue("map valueToString() incorrect", - jsonObject.toString().equals(JSONObject.valueToString(map))); - Collection collection = new ArrayList(); - collection.add(new Integer(1)); - collection.add(new Integer(2)); - collection.add(new Integer(3)); - assertTrue("collection valueToString() expected: "+ - jsonArray.toString()+ " actual: "+ - JSONObject.valueToString(collection), - jsonArray.toString().equals(JSONObject.valueToString(collection))); - Integer[] array = { new Integer(1), new Integer(2), new Integer(3) }; - assertTrue("array valueToString() incorrect", - jsonArray.toString().equals(JSONObject.valueToString(array))); - } - - /** - * Confirm that https://github.com/douglascrockford/JSON-java/issues/167 is fixed. - * The following code was throwing a ClassCastException in the - * JSONObject(Map) constructor - */ - @Test - public void valueToStringConfirmException() { - Map myMap = new HashMap(); - myMap.put(1, "myValue"); - // this is the test, it should not throw an exception - String str = JSONObject.valueToString(myMap); - // confirm result, just in case - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(str); - assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); - assertTrue("expected myValue", "myValue".equals(JsonPath.read(doc, "$.1"))); - } - - /** - * Exercise the JSONObject wrap() method. Sometimes wrap() will change - * the object being wrapped, other times not. The purpose of wrap() is - * to ensure the value is packaged in a way that is compatible with how - * a JSONObject value or JSONArray value is supposed to be stored. - */ - @Test - public void wrapObject() { - // wrap(null) returns NULL - assertTrue("null wrap() incorrect", - JSONObject.NULL == JSONObject.wrap(null)); - - // wrap(Integer) returns Integer - Integer in = new Integer(1); - assertTrue("Integer wrap() incorrect", - in == JSONObject.wrap(in)); - - /** - * This test is to document the preferred behavior if BigDecimal is - * supported. Previously bd returned as a string, since it - * is recognized as being a Java package class. Now with explicit - * support for big numbers, it remains a BigDecimal - */ - Object bdWrap = JSONObject.wrap(BigDecimal.ONE); - assertTrue("BigDecimal.ONE evaluates to ONE", - bdWrap.equals(BigDecimal.ONE)); - - // wrap JSONObject returns JSONObject - String jsonObjectStr = - "{"+ - "\"key1\":\"val1\","+ - "\"key2\":\"val2\","+ - "\"key3\":\"val3\""+ - "}"; - JSONObject jsonObject = new JSONObject(jsonObjectStr); - assertTrue("JSONObject wrap() incorrect", - jsonObject == JSONObject.wrap(jsonObject)); - - // wrap collection returns JSONArray - Collection collection = new ArrayList(); - collection.add(new Integer(1)); - collection.add(new Integer(2)); - collection.add(new Integer(3)); - JSONArray jsonArray = (JSONArray) (JSONObject.wrap(collection)); - - // validate JSON - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); - assertTrue("expected 3 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/0"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/1"))); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.query("/2"))); - - // wrap Array returns JSONArray - Integer[] array = { new Integer(1), new Integer(2), new Integer(3) }; - JSONArray integerArrayJsonArray = (JSONArray)(JSONObject.wrap(array)); - - // validate JSON - doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); - assertTrue("expected 3 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/0"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/1"))); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.query("/2"))); - - // validate JSON - doc = Configuration.defaultConfiguration().jsonProvider().parse(integerArrayJsonArray.toString()); - assertTrue("expected 3 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/0"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/1"))); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.query("/2"))); - - // wrap map returns JSONObject - Map map = new HashMap(); - map.put("key1", "val1"); - map.put("key2", "val2"); - map.put("key3", "val3"); - JSONObject mapJsonObject = (JSONObject) (JSONObject.wrap(map)); - - // validate JSON - doc = Configuration.defaultConfiguration().jsonProvider().parse(mapJsonObject.toString()); - assertTrue("expected 3 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected val1", "val1".equals(mapJsonObject.query("/key1"))); - assertTrue("expected val2", "val2".equals(mapJsonObject.query("/key2"))); - assertTrue("expected val3", "val3".equals(mapJsonObject.query("/key3"))); - } - - - /** - * RFC 7159 defines control characters to be U+0000 through U+001F. This test verifies that the parser is checking for these in expected ways. - */ - @Test - public void jsonObjectParseControlCharacters(){ - for(int i = 0;i<=0x001f;i++){ - final String charString = String.valueOf((char)i); - final String source = "{\"key\":\""+charString+"\"}"; - try { - JSONObject jo = new JSONObject(source); - assertTrue("Expected "+charString+"("+i+") in the JSON Object but did not find it.",charString.equals(jo.getString("key"))); - } catch (JSONException ex) { - assertTrue("Only \\0 (U+0000), \\n (U+000A), and \\r (U+000D) should cause an error. Instead "+charString+"("+i+") caused an error", - i=='\0' || i=='\n' || i=='\r' - ); - } - } - } - - /** - * Explore how JSONObject handles parsing errors. - */ - @Test - public void jsonObjectParsingErrors() { - try { - // does not start with '{' - String str = "abc"; - new JSONObject(str); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "A JSONObject text must begin with '{' at 1 [character 2 line 1]". - equals(e.getMessage())); - } - try { - // does not end with '}' - String str = "{"; - new JSONObject(str); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "A JSONObject text must end with '}' at 2 [character 3 line 1]". - equals(e.getMessage())); - } - try { - // key with no ':' - String str = "{\"myKey\" = true}"; - new JSONObject(str); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Expected a ':' after a key at 10 [character 11 line 1]". - equals(e.getMessage())); - } - try { - // entries with no ',' separator - String str = "{\"myKey\":true \"myOtherKey\":false}"; - new JSONObject(str); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Expected a ',' or '}' at 15 [character 16 line 1]". - equals(e.getMessage())); - } - try { - // append to wrong key - String str = "{\"myKey\":true, \"myOtherKey\":false}"; - JSONObject jsonObject = new JSONObject(str); - jsonObject.append("myKey", "hello"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[myKey] is not a JSONArray.". - equals(e.getMessage())); - } - try { - // increment wrong key - String str = "{\"myKey\":true, \"myOtherKey\":false}"; - JSONObject jsonObject = new JSONObject(str); - jsonObject.increment("myKey"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Unable to increment [\"myKey\"].". - equals(e.getMessage())); - } - try { - // invalid key - String str = "{\"myKey\":true, \"myOtherKey\":false}"; - JSONObject jsonObject = new JSONObject(str); - jsonObject.get(null); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Null key.". - equals(e.getMessage())); - } - try { - // invalid numberToString() - JSONObject.numberToString((Number)null); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Null pointer". - equals(e.getMessage())); - } - try { - // null put key - JSONObject jsonObject = new JSONObject("{}"); - jsonObject.put(null, 0); - assertTrue("Expected an exception", false); - } catch (NullPointerException ignored) { - } - try { - // multiple putOnce key - JSONObject jsonObject = new JSONObject("{}"); - jsonObject.putOnce("hello", "world"); - jsonObject.putOnce("hello", "world!"); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("", true); - } - try { - // test validity of invalid double - JSONObject.testValidity(Double.NaN); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("", true); - } - try { - // test validity of invalid float - JSONObject.testValidity(Float.NEGATIVE_INFINITY); - assertTrue("Expected an exception", false); - } catch (JSONException e) { - assertTrue("", true); - } - } - - /** - * Confirm behavior when putOnce() is called with null parameters - */ - @Test - public void jsonObjectPutOnceNull() { - JSONObject jsonObject = new JSONObject(); - jsonObject.putOnce(null, null); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); - } - - /** - * Exercise JSONObject opt(key, default) method. - */ - @Test - public void jsonObjectOptDefault() { - - String str = "{\"myKey\": \"myval\", \"hiKey\": null}"; - JSONObject jsonObject = new JSONObject(str); - - assertTrue("optBigDecimal() should return default BigDecimal", - BigDecimal.TEN.compareTo(jsonObject.optBigDecimal("myKey", BigDecimal.TEN))==0); - assertTrue("optBigInteger() should return default BigInteger", - BigInteger.TEN.compareTo(jsonObject.optBigInteger("myKey",BigInteger.TEN ))==0); - assertTrue("optBoolean() should return default boolean", - jsonObject.optBoolean("myKey", true)); - assertTrue("optInt() should return default int", - 42 == jsonObject.optInt("myKey", 42)); - assertTrue("optEnum() should return default Enum", - MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1))); - assertTrue("optJSONArray() should return null ", - null==jsonObject.optJSONArray("myKey")); - assertTrue("optJSONObject() should return null ", - null==jsonObject.optJSONObject("myKey")); - assertTrue("optLong() should return default long", - 42 == jsonObject.optLong("myKey", 42)); - assertTrue("optDouble() should return default double", - 42.3 == jsonObject.optDouble("myKey", 42.3)); - assertTrue("optString() should return default string", - "hi".equals(jsonObject.optString("hiKey", "hi"))); - } - - /** - * Exercise JSONObject opt(key, default) method when the key doesn't exist. - */ - @Test - public void jsonObjectOptNoKey() { - - JSONObject jsonObject = new JSONObject(); - - assertTrue("optBigDecimal() should return default BigDecimal", - BigDecimal.TEN.compareTo(jsonObject.optBigDecimal("myKey", BigDecimal.TEN))==0); - assertTrue("optBigInteger() should return default BigInteger", - BigInteger.TEN.compareTo(jsonObject.optBigInteger("myKey",BigInteger.TEN ))==0); - assertTrue("optBoolean() should return default boolean", - jsonObject.optBoolean("myKey", true)); - assertTrue("optInt() should return default int", - 42 == jsonObject.optInt("myKey", 42)); - assertTrue("optEnum() should return default Enum", - MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1))); - assertTrue("optJSONArray() should return null ", - null==jsonObject.optJSONArray("myKey")); - assertTrue("optJSONObject() should return null ", - null==jsonObject.optJSONObject("myKey")); - assertTrue("optLong() should return default long", - 42 == jsonObject.optLong("myKey", 42)); - assertTrue("optDouble() should return default double", - 42.3 == jsonObject.optDouble("myKey", 42.3)); - assertTrue("optString() should return default string", - "hi".equals(jsonObject.optString("hiKey", "hi"))); - } - - /** - * Verifies that the opt methods properly convert string values. - */ - @Test - public void jsonObjectOptStringConversion() { - JSONObject jo = new JSONObject("{\"int\":\"123\",\"true\":\"true\",\"false\":\"false\"}"); - assertTrue("unexpected optBoolean value",jo.optBoolean("true",false)==true); - assertTrue("unexpected optBoolean value",jo.optBoolean("false",true)==false); - assertTrue("unexpected optInt value",jo.optInt("int",0)==123); - assertTrue("unexpected optLong value",jo.optLong("int",0)==123); - assertTrue("unexpected optDouble value",jo.optDouble("int",0.0)==123.0); - assertTrue("unexpected optBigInteger value",jo.optBigInteger("int",BigInteger.ZERO).compareTo(new BigInteger("123"))==0); - assertTrue("unexpected optBigDecimal value",jo.optBigDecimal("int",BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); - - } - - /** - * Confirm behavior when JSONObject put(key, null object) is called - */ - @Test - public void jsonObjectputNull() { - - // put null should remove the item. - String str = "{\"myKey\": \"myval\"}"; - JSONObject jsonObjectRemove = new JSONObject(str); - jsonObjectRemove.remove("myKey"); - - JSONObject jsonObjectPutNull = new JSONObject(str); - jsonObjectPutNull.put("myKey", (Object) null); - - // validate JSON - assertTrue("jsonObject should be empty", jsonObjectRemove.length() == 0 - && jsonObjectPutNull.length() == 0); - } - - /** - * Exercise JSONObject quote() method - * This purpose of quote() is to ensure that for strings with embedded - * quotes, the quotes are properly escaped. - */ - @Test - public void jsonObjectQuote() { - String str; - str = ""; - String quotedStr; - quotedStr = JSONObject.quote(str); - assertTrue("quote() expected escaped quotes, found "+quotedStr, - "\"\"".equals(quotedStr)); - str = "\"\""; - quotedStr = JSONObject.quote(str); - assertTrue("quote() expected escaped quotes, found "+quotedStr, - "\"\\\"\\\"\"".equals(quotedStr)); - str = "null and null will be emitted as "" - */ - String sJONull = XML.toString(jsonObjectJONull); - assertTrue("JSONObject.NULL should emit a null value", - "null".equals(sJONull)); - String sNull = XML.toString(jsonObjectNull); - assertTrue("null should emit an empty string", "".equals(sNull)); - } - - @Test(expected = JSONPointerException.class) - public void queryWithNoResult() { - new JSONObject().query("/a/b"); - } - - @Test - public void optQueryWithNoResult() { - assertNull(new JSONObject().optQuery("/a/b")); - } - - @Test(expected = IllegalArgumentException.class) - public void optQueryWithSyntaxError() { - new JSONObject().optQuery("invalid"); - } - - @Test(expected = JSONException.class) - public void invalidEscapeSequence() { - String json = "{ \"\\url\": \"value\" }"; - new JSONObject(json); - } - - /** - * Exercise JSONObject toMap() method. - */ - @Test - public void toMap() { - String jsonObjectStr = - "{" + - "\"key1\":" + - "[1,2," + - "{\"key3\":true}" + - "]," + - "\"key2\":" + - "{\"key1\":\"val1\",\"key2\":" + - "{\"key2\":null}," + - "\"key3\":42" + - "}," + - "\"key3\":" + - "[" + - "[\"value1\",2.1]" + - "," + - "[null]" + - "]" + - "}"; - - JSONObject jsonObject = new JSONObject(jsonObjectStr); - Map map = jsonObject.toMap(); - - assertTrue("Map should not be null", map != null); - assertTrue("Map should have 3 elements", map.size() == 3); - - List key1List = (List)map.get("key1"); - assertTrue("key1 should not be null", key1List != null); - assertTrue("key1 list should have 3 elements", key1List.size() == 3); - assertTrue("key1 value 1 should be 1", key1List.get(0).equals(Integer.valueOf(1))); - assertTrue("key1 value 2 should be 2", key1List.get(1).equals(Integer.valueOf(2))); - - Map key1Value3Map = (Map)key1List.get(2); - assertTrue("Map should not be null", key1Value3Map != null); - assertTrue("Map should have 1 element", key1Value3Map.size() == 1); - assertTrue("Map key3 should be true", key1Value3Map.get("key3").equals(Boolean.TRUE)); - - Map key2Map = (Map)map.get("key2"); - assertTrue("key2 should not be null", key2Map != null); - assertTrue("key2 map should have 3 elements", key2Map.size() == 3); - assertTrue("key2 map key 1 should be val1", key2Map.get("key1").equals("val1")); - assertTrue("key2 map key 3 should be 42", key2Map.get("key3").equals(Integer.valueOf(42))); - - Map key2Val2Map = (Map)key2Map.get("key2"); - assertTrue("key2 map key 2 should not be null", key2Val2Map != null); - assertTrue("key2 map key 2 should have an entry", key2Val2Map.containsKey("key2")); - assertTrue("key2 map key 2 value should be null", key2Val2Map.get("key2") == null); - - List key3List = (List)map.get("key3"); - assertTrue("key3 should not be null", key3List != null); - assertTrue("key3 list should have 3 elements", key3List.size() == 2); - - List key3Val1List = (List)key3List.get(0); - assertTrue("key3 list val 1 should not be null", key3Val1List != null); - assertTrue("key3 list val 1 should have 2 elements", key3Val1List.size() == 2); - assertTrue("key3 list val 1 list element 1 should be value1", key3Val1List.get(0).equals("value1")); - assertTrue("key3 list val 1 list element 2 should be 2.1", key3Val1List.get(1).equals(Double.valueOf("2.1"))); - - List key3Val2List = (List)key3List.get(1); - assertTrue("key3 list val 2 should not be null", key3Val2List != null); - assertTrue("key3 list val 2 should have 1 element", key3Val2List.size() == 1); - assertTrue("key3 list val 2 list element 1 should be null", key3Val2List.get(0) == null); - - // Assert that toMap() is a deep copy - jsonObject.getJSONArray("key3").getJSONArray(0).put(0, "still value 1"); - assertTrue("key3 list val 1 list element 1 should be value1", key3Val1List.get(0).equals("value1")); - - // assert that the new map is mutable - assertTrue("Removing a key should succeed", map.remove("key3") != null); - assertTrue("Map should have 2 elements", map.size() == 2); - - } -} +package org.json.junit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import org.json.CDL; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONPointerException; +import org.json.XML; +import org.junit.Test; + +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.JsonPath; + +/** + * JSONObject, along with JSONArray, are the central classes of the reference app. + * All of the other classes interact with them, and JSON functionality would + * otherwise be impossible. + */ +public class JSONObjectTest { + + /** + * JSONObject built from a bean, but only using a null value. + * Nothing good is expected to happen. + * Expects NullPointerException + */ + @Test(expected=NullPointerException.class) + public void jsonObjectByNullBean() { + assertNull("Expected an exception",new JSONObject((MyBean)null)); + } + + /** + * The JSON parser is permissive of unambiguous unquoted keys and values. + * Such JSON text should be allowed, even if it does not strictly conform + * to the spec. However, after being parsed, toString() should emit strictly + * conforming JSON text. + */ + @Test + public void unquotedText() { + String str = "{key1:value1, key2:42}"; + JSONObject jsonObject = new JSONObject(str); + String textStr = jsonObject.toString(); + assertTrue("expected key1", textStr.contains("\"key1\"")); + assertTrue("expected value1", textStr.contains("\"value1\"")); + assertTrue("expected key2", textStr.contains("\"key2\"")); + assertTrue("expected 42", textStr.contains("42")); + } + + @Test + public void testLongFromString(){ + String str = "26315000000253009"; + JSONObject json = new JSONObject(); + json.put("key", str); + + final Object actualKey = json.opt("key"); + assert str.equals(actualKey) : "Incorrect key value. Got " + actualKey + + " expected " + str; + + final long actualLong = json.optLong("key"); + assert actualLong != 0 : "Unable to extract long value for string " + str; + assert 26315000000253009L == actualLong : "Incorrect key value. Got " + + actualLong + " expected " + str; + + final String actualString = json.optString("key"); + assert str.equals(actualString) : "Incorrect key value. Got " + + actualString + " expected " + str; + } + + /** + * A JSONObject can be created with no content + */ + @Test + public void emptyJsonObject() { + JSONObject jsonObject = new JSONObject(); + assertTrue("jsonObject should be empty", jsonObject.length() == 0); + } + + /** + * A JSONObject can be created from another JSONObject plus a list of names. + * In this test, some of the starting JSONObject keys are not in the + * names list. + */ + @Test + public void jsonObjectByNames() { + String str = + "{"+ + "\"trueKey\":true,"+ + "\"falseKey\":false,"+ + "\"nullKey\":null,"+ + "\"stringKey\":\"hello world!\","+ + "\"escapeStringKey\":\"h\be\tllo w\u1234orld!\","+ + "\"intKey\":42,"+ + "\"doubleKey\":-23.45e67"+ + "}"; + String[] keys = {"falseKey", "stringKey", "nullKey", "doubleKey"}; + JSONObject jsonObject = new JSONObject(str); + + // validate JSON + JSONObject jsonObjectByName = new JSONObject(jsonObject, keys); + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObjectByName.toString()); + assertTrue("expected 4 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 4); + assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObjectByName.query("/falseKey"))); + assertTrue("expected \"nullKey\":null", JSONObject.NULL.equals(jsonObjectByName.query("/nullKey"))); + assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObjectByName.query("/stringKey"))); + assertTrue("expected \"doubleKey\":-23.45e67", Double.valueOf("-23.45e67").equals(jsonObjectByName.query("/doubleKey"))); + } + + /** + * JSONObjects can be built from a Map. + * In this test the map is null. + * the JSONObject(JsonTokener) ctor is not tested directly since it already + * has full coverage from other tests. + */ + @Test + public void jsonObjectByNullMap() { + Map map = null; + JSONObject jsonObject = new JSONObject(map); + assertTrue("jsonObject should be empty", jsonObject.length() == 0); + } + + /** + * JSONObjects can be built from a Map. + * In this test all of the map entries are valid JSON types. + */ + @Test + public void jsonObjectByMap() { + Map map = new HashMap(); + map.put("trueKey", new Boolean(true)); + map.put("falseKey", new Boolean(false)); + map.put("stringKey", "hello world!"); + map.put("escapeStringKey", "h\be\tllo w\u1234orld!"); + map.put("intKey", new Long(42)); + map.put("doubleKey", new Double(-23.45e67)); + JSONObject jsonObject = new JSONObject(map); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); + assertTrue("expected \"trueKey\":true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); + assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); + assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObject.query("/stringKey"))); + assertTrue("expected \"escapeStringKey\":\"h\be\tllo w\u1234orld!\"", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/escapeStringKey"))); + assertTrue("expected \"doubleKey\":-23.45e67", Double.valueOf("-23.45e67").equals(jsonObject.query("/doubleKey"))); + } + + /** + * Verifies that the constructor has backwards compatability with RAW types pre-java5. + */ + @Test + public void verifyConstructor() { + + final JSONObject expected = new JSONObject("{\"myKey\":10}"); + + @SuppressWarnings("rawtypes") + Map myRawC = Collections.singletonMap("myKey", Integer.valueOf(10)); + JSONObject jaRaw = new JSONObject(myRawC); + + Map myCStrObj = Collections.singletonMap("myKey", + (Object) Integer.valueOf(10)); + JSONObject jaStrObj = new JSONObject(myCStrObj); + + Map myCStrInt = Collections.singletonMap("myKey", + Integer.valueOf(10)); + JSONObject jaStrInt = new JSONObject(myCStrInt); + + Map myCObjObj = Collections.singletonMap((Object) "myKey", + (Object) Integer.valueOf(10)); + JSONObject jaObjObj = new JSONObject(myCObjObj); + + assertTrue( + "The RAW Collection should give me the same as the Typed Collection", + expected.similar(jaRaw)); + assertTrue( + "The RAW Collection should give me the same as the Typed Collection", + expected.similar(jaStrObj)); + assertTrue( + "The RAW Collection should give me the same as the Typed Collection", + expected.similar(jaStrInt)); + assertTrue( + "The RAW Collection should give me the same as the Typed Collection", + expected.similar(jaObjObj)); + } + + /** + * Tests Number serialization. + */ + @Test + public void verifyNumberOutput(){ + /** + * MyNumberContainer is a POJO, so call JSONObject(bean), + * which builds a map of getter names/values + * The only getter is getMyNumber (key=myNumber), + * whose return value is MyNumber. MyNumber extends Number, + * but is not recognized as such by wrap() per current + * implementation, so wrap() returns the default new JSONObject(bean). + * The only getter is getNumber (key=number), whose return value is + * BigDecimal(42). + */ + JSONObject jsonObject = new JSONObject(new MyNumberContainer()); + String actual = jsonObject.toString(); + String expected = "{\"myNumber\":{\"number\":42}}"; + assertEquals("Not Equal", expected , actual); + + /** + * JSONObject.put() handles objects differently than the + * bean constructor. Where the bean ctor wraps objects before + * placing them in the map, put() inserts the object without wrapping. + * In this case, a MyNumber instance is the value. + * The MyNumber.toString() method is responsible for + * returning a reasonable value: the string '42'. + */ + jsonObject = new JSONObject(); + jsonObject.put("myNumber", new MyNumber()); + actual = jsonObject.toString(); + expected = "{\"myNumber\":42}"; + assertEquals("Not Equal", expected , actual); + + /** + * Calls the JSONObject(Map) ctor, which calls wrap() for values. + * AtomicInteger is a Number, but is not recognized by wrap(), per + * current implementation. However, the type is + * 'java.util.concurrent.atomic', so due to the 'java' prefix, + * wrap() inserts the value as a string. That is why 42 comes back + * wrapped in quotes. + */ + jsonObject = new JSONObject(Collections.singletonMap("myNumber", new AtomicInteger(42))); + actual = jsonObject.toString(); + expected = "{\"myNumber\":\"42\"}"; + assertEquals("Not Equal", expected , actual); + + /** + * JSONObject.put() inserts the AtomicInteger directly into the + * map not calling wrap(). In toString()->write()->writeValue(), + * AtomicInteger is recognized as a Number, and converted via + * numberToString() into the unquoted string '42'. + */ + jsonObject = new JSONObject(); + jsonObject.put("myNumber", new AtomicInteger(42)); + actual = jsonObject.toString(); + expected = "{\"myNumber\":42}"; + assertEquals("Not Equal", expected , actual); + + /** + * Calls the JSONObject(Map) ctor, which calls wrap() for values. + * Fraction is a Number, but is not recognized by wrap(), per + * current implementation. As a POJO, Fraction is handled as a + * bean and inserted into a contained JSONObject. It has 2 getters, + * for numerator and denominator. + */ + jsonObject = new JSONObject(Collections.singletonMap("myNumber", new Fraction(4,2))); + assertEquals(1, jsonObject.length()); + assertEquals(2, ((JSONObject)(jsonObject.get("myNumber"))).length()); + assertEquals("Numerator", BigInteger.valueOf(4) , jsonObject.query("/myNumber/numerator")); + assertEquals("Denominator", BigInteger.valueOf(2) , jsonObject.query("/myNumber/denominator")); + + /** + * JSONObject.put() inserts the Fraction directly into the + * map not calling wrap(). In toString()->write()->writeValue(), + * Fraction is recognized as a Number, and converted via + * numberToString() into the unquoted string '4/2'. But the + * BigDecimal sanity check fails, so writeValue() defaults + * to returning a safe JSON quoted string. Pretty slick! + */ + jsonObject = new JSONObject(); + jsonObject.put("myNumber", new Fraction(4,2)); + actual = jsonObject.toString(); + expected = "{\"myNumber\":\"4/2\"}"; // valid JSON, bug fixed + assertEquals("Not Equal", expected , actual); + } + + /** + * Verifies that the put Collection has backwards compatibility with RAW types pre-java5. + */ + @Test + public void verifyPutCollection() { + + final JSONObject expected = new JSONObject("{\"myCollection\":[10]}"); + + @SuppressWarnings("rawtypes") + Collection myRawC = Collections.singleton(Integer.valueOf(10)); + JSONObject jaRaw = new JSONObject(); + jaRaw.put("myCollection", myRawC); + + Collection myCObj = Collections.singleton((Object) Integer + .valueOf(10)); + JSONObject jaObj = new JSONObject(); + jaObj.put("myCollection", myCObj); + + Collection myCInt = Collections.singleton(Integer + .valueOf(10)); + JSONObject jaInt = new JSONObject(); + jaInt.put("myCollection", myCInt); + + assertTrue( + "The RAW Collection should give me the same as the Typed Collection", + expected.similar(jaRaw)); + assertTrue( + "The RAW Collection should give me the same as the Typed Collection", + expected.similar(jaObj)); + assertTrue( + "The RAW Collection should give me the same as the Typed Collection", + expected.similar(jaInt)); + } + + + /** + * Verifies that the put Map has backwards compatability with RAW types pre-java5. + */ + @Test + public void verifyPutMap() { + + final JSONObject expected = new JSONObject("{\"myMap\":{\"myKey\":10}}"); + + @SuppressWarnings("rawtypes") + Map myRawC = Collections.singletonMap("myKey", Integer.valueOf(10)); + JSONObject jaRaw = new JSONObject(); + jaRaw.put("myMap", myRawC); + + Map myCStrObj = Collections.singletonMap("myKey", + (Object) Integer.valueOf(10)); + JSONObject jaStrObj = new JSONObject(); + jaStrObj.put("myMap", myCStrObj); + + Map myCStrInt = Collections.singletonMap("myKey", + Integer.valueOf(10)); + JSONObject jaStrInt = new JSONObject(); + jaStrInt.put("myMap", myCStrInt); + + Map myCObjObj = Collections.singletonMap((Object) "myKey", + (Object) Integer.valueOf(10)); + JSONObject jaObjObj = new JSONObject(); + jaObjObj.put("myMap", myCObjObj); + + assertTrue( + "The RAW Collection should give me the same as the Typed Collection", + expected.similar(jaRaw)); + assertTrue( + "The RAW Collection should give me the same as the Typed Collection", + expected.similar(jaStrObj)); + assertTrue( + "The RAW Collection should give me the same as the Typed Collection", + expected.similar(jaStrInt)); + assertTrue( + "The RAW Collection should give me the same as the Typed Collection", + expected.similar(jaObjObj)); + } + + + /** + * JSONObjects can be built from a Map. + * In this test the map entries are not valid JSON types. + * The actual conversion is kind of interesting. + */ + @Test + public void jsonObjectByMapWithUnsupportedValues() { + Map jsonMap = new HashMap(); + // Just insert some random objects + jsonMap.put("key1", new CDL()); + jsonMap.put("key2", new Exception()); + + JSONObject jsonObject = new JSONObject(jsonMap); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); + assertTrue("expected 0 key1 items", ((Map)(JsonPath.read(doc, "$.key1"))).size() == 0); + assertTrue("expected \"key2\":java.lang.Exception","java.lang.Exception".equals(jsonObject.query("/key2"))); + } + + /** + * JSONObjects can be built from a Map. + * In this test one of the map values is null + */ + @Test + public void jsonObjectByMapWithNullValue() { + Map map = new HashMap(); + map.put("trueKey", new Boolean(true)); + map.put("falseKey", new Boolean(false)); + map.put("stringKey", "hello world!"); + map.put("nullKey", null); + map.put("escapeStringKey", "h\be\tllo w\u1234orld!"); + map.put("intKey", new Long(42)); + map.put("doubleKey", new Double(-23.45e67)); + JSONObject jsonObject = new JSONObject(map); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); + assertTrue("expected \"trueKey\":true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); + assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); + assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObject.query("/stringKey"))); + assertTrue("expected \"escapeStringKey\":\"h\be\tllo w\u1234orld!\"", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/escapeStringKey"))); + assertTrue("expected \"intKey\":42", Long.valueOf("42").equals(jsonObject.query("/intKey"))); + assertTrue("expected \"doubleKey\":-23.45e67", Double.valueOf("-23.45e67").equals(jsonObject.query("/doubleKey"))); + } + + /** + * JSONObject built from a bean. In this case all but one of the + * bean getters return valid JSON types + */ + @SuppressWarnings("boxing") + @Test + public void jsonObjectByBean() { + /** + * Default access classes have to be mocked since JSONObject, which is + * not in the same package, cannot call MyBean methods by reflection. + */ + MyBean myBean = mock(MyBean.class); + when(myBean.getDoubleKey()).thenReturn(-23.45e7); + when(myBean.getIntKey()).thenReturn(42); + when(myBean.getStringKey()).thenReturn("hello world!"); + when(myBean.getEscapeStringKey()).thenReturn("h\be\tllo w\u1234orld!"); + when(myBean.isTrueKey()).thenReturn(true); + when(myBean.isFalseKey()).thenReturn(false); + when(myBean.getStringReaderKey()).thenReturn( + new StringReader("") { + }); + + JSONObject jsonObject = new JSONObject(myBean); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 8 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 8); + assertTrue("expected 0 items in stringReaderKey", ((Map) (JsonPath.read(doc, "$.stringReaderKey"))).size() == 0); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); + assertTrue("expected hello world!","hello world!".equals(jsonObject.query("/stringKey"))); + assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/escapeStringKey"))); + assertTrue("expected 42", Integer.valueOf("42").equals(jsonObject.query("/intKey"))); + assertTrue("expected -23.45e7", Double.valueOf("-23.45e7").equals(jsonObject.query("/doubleKey"))); + // sorry, mockito artifact + assertTrue("expected 2 callbacks items", ((List)(JsonPath.read(doc, "$.callbacks"))).size() == 2); + assertTrue("expected 0 handler items", ((Map)(JsonPath.read(doc, "$.callbacks[0].handler"))).size() == 0); + assertTrue("expected 0 callbacks[1] items", ((Map)(JsonPath.read(doc, "$.callbacks[1]"))).size() == 0); + } + + /** + * A bean is also an object. But in order to test the JSONObject + * ctor that takes an object and a list of names, + * this particular bean needs some public + * data members, which have been added to the class. + */ + @Test + public void jsonObjectByObjectAndNames() { + String[] keys = {"publicString", "publicInt"}; + // just need a class that has public data members + MyPublicClass myPublicClass = new MyPublicClass(); + JSONObject jsonObject = new JSONObject(myPublicClass, keys); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); + assertTrue("expected \"publicString\":\"abc\"", "abc".equals(jsonObject.query("/publicString"))); + assertTrue("expected \"publicInt\":42", Integer.valueOf(42).equals(jsonObject.query("/publicInt"))); + } + + /** + * Exercise the JSONObject from resource bundle functionality. + * The test resource bundle is uncomplicated, but provides adequate test coverage. + */ + @Test + public void jsonObjectByResourceBundle() { + JSONObject jsonObject = new + JSONObject("org.json.junit.StringsResourceBundle", + Locale.getDefault()); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); + assertTrue("expected 2 greetings items", ((Map)(JsonPath.read(doc, "$.greetings"))).size() == 2); + assertTrue("expected \"hello\":\"Hello, \"", "Hello, ".equals(jsonObject.query("/greetings/hello"))); + assertTrue("expected \"world\":\"World!\"", "World!".equals(jsonObject.query("/greetings/world"))); + assertTrue("expected 2 farewells items", ((Map)(JsonPath.read(doc, "$.farewells"))).size() == 2); + assertTrue("expected \"later\":\"Later, \"", "Later, ".equals(jsonObject.query("/farewells/later"))); + assertTrue("expected \"world\":\"World!\"", "Alligator!".equals(jsonObject.query("/farewells/gator"))); + } + + /** + * Exercise the JSONObject.accumulate() method + */ + @SuppressWarnings("boxing") + @Test + public void jsonObjectAccumulate() { + + JSONObject jsonObject = new JSONObject(); + jsonObject.accumulate("myArray", true); + jsonObject.accumulate("myArray", false); + jsonObject.accumulate("myArray", "hello world!"); + jsonObject.accumulate("myArray", "h\be\tllo w\u1234orld!"); + jsonObject.accumulate("myArray", 42); + jsonObject.accumulate("myArray", -23.45e7); + // include an unsupported object for coverage + try { + jsonObject.accumulate("myArray", Double.NaN); + assertTrue("Expected exception", false); + } catch (JSONException ignored) {} + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); + assertTrue("expected 6 myArray items", ((List)(JsonPath.read(doc, "$.myArray"))).size() == 6); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/myArray/0"))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/myArray/1"))); + assertTrue("expected hello world!", "hello world!".equals(jsonObject.query("/myArray/2"))); + assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/myArray/3"))); + assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.query("/myArray/4"))); + assertTrue("expected -23.45e7", Double.valueOf(-23.45e7).equals(jsonObject.query("/myArray/5"))); + } + + /** + * Exercise the JSONObject append() functionality + */ + @SuppressWarnings("boxing") + @Test + public void jsonObjectAppend() { + JSONObject jsonObject = new JSONObject(); + jsonObject.append("myArray", true); + jsonObject.append("myArray", false); + jsonObject.append("myArray", "hello world!"); + jsonObject.append("myArray", "h\be\tllo w\u1234orld!"); + jsonObject.append("myArray", 42); + jsonObject.append("myArray", -23.45e7); + // include an unsupported object for coverage + try { + jsonObject.append("myArray", Double.NaN); + assertTrue("Expected exception", false); + } catch (JSONException ignored) {} + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); + assertTrue("expected 6 myArray items", ((List)(JsonPath.read(doc, "$.myArray"))).size() == 6); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/myArray/0"))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/myArray/1/"))); + assertTrue("expected hello world!", "hello world!".equals(jsonObject.query("/myArray/2"))); + assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/myArray/3"))); + assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.query("/myArray/4"))); + assertTrue("expected -23.45e7", Double.valueOf(-23.45e7).equals(jsonObject.query("/myArray/5"))); + } + + /** + * Exercise the JSONObject doubleToString() method + */ + @SuppressWarnings("boxing") + @Test + public void jsonObjectDoubleToString() { + String [] expectedStrs = {"1", "1", "-23.4", "-2.345E68", "null", "null" }; + Double [] doubles = { 1.0, 00001.00000, -23.4, -23.45e67, + Double.NaN, Double.NEGATIVE_INFINITY }; + for (int i = 0; i < expectedStrs.length; ++i) { + String actualStr = JSONObject.doubleToString(doubles[i]); + assertTrue("value expected ["+expectedStrs[i]+ + "] found ["+actualStr+ "]", + expectedStrs[i].equals(actualStr)); + } + } + + /** + * Exercise some JSONObject get[type] and opt[type] methods + */ + @Test + public void jsonObjectValues() { + String str = + "{"+ + "\"trueKey\":true,"+ + "\"falseKey\":false,"+ + "\"trueStrKey\":\"true\","+ + "\"falseStrKey\":\"false\","+ + "\"stringKey\":\"hello world!\","+ + "\"intKey\":42,"+ + "\"intStrKey\":\"43\","+ + "\"longKey\":1234567890123456789,"+ + "\"longStrKey\":\"987654321098765432\","+ + "\"doubleKey\":-23.45e7,"+ + "\"doubleStrKey\":\"00001.000\","+ + "\"arrayKey\":[0,1,2],"+ + "\"objectKey\":{\"myKey\":\"myVal\"}"+ + "}"; + JSONObject jsonObject = new JSONObject(str); + assertTrue("trueKey should be true", jsonObject.getBoolean("trueKey")); + assertTrue("opt trueKey should be true", jsonObject.optBoolean("trueKey")); + assertTrue("falseKey should be false", !jsonObject.getBoolean("falseKey")); + assertTrue("trueStrKey should be true", jsonObject.getBoolean("trueStrKey")); + assertTrue("trueStrKey should be true", jsonObject.optBoolean("trueStrKey")); + assertTrue("falseStrKey should be false", !jsonObject.getBoolean("falseStrKey")); + assertTrue("stringKey should be string", + jsonObject.getString("stringKey").equals("hello world!")); + assertTrue("doubleKey should be double", + jsonObject.getDouble("doubleKey") == -23.45e7); + assertTrue("doubleStrKey should be double", + jsonObject.getDouble("doubleStrKey") == 1); + assertTrue("opt doubleKey should be double", + jsonObject.optDouble("doubleKey") == -23.45e7); + assertTrue("opt doubleKey with Default should be double", + jsonObject.optDouble("doubleStrKey", Double.NaN) == 1); + assertTrue("intKey should be int", + jsonObject.optInt("intKey") == 42); + assertTrue("opt intKey should be int", + jsonObject.optInt("intKey", 0) == 42); + assertTrue("opt intKey with default should be int", + jsonObject.getInt("intKey") == 42); + assertTrue("intStrKey should be int", + jsonObject.getInt("intStrKey") == 43); + assertTrue("longKey should be long", + jsonObject.getLong("longKey") == 1234567890123456789L); + assertTrue("opt longKey should be long", + jsonObject.optLong("longKey") == 1234567890123456789L); + assertTrue("opt longKey with default should be long", + jsonObject.optLong("longKey", 0) == 1234567890123456789L); + assertTrue("longStrKey should be long", + jsonObject.getLong("longStrKey") == 987654321098765432L); + assertTrue("xKey should not exist", + jsonObject.isNull("xKey")); + assertTrue("stringKey should exist", + jsonObject.has("stringKey")); + assertTrue("opt stringKey should string", + jsonObject.optString("stringKey").equals("hello world!")); + assertTrue("opt stringKey with default should string", + jsonObject.optString("stringKey", "not found").equals("hello world!")); + JSONArray jsonArray = jsonObject.getJSONArray("arrayKey"); + assertTrue("arrayKey should be JSONArray", + jsonArray.getInt(0) == 0 && + jsonArray.getInt(1) == 1 && + jsonArray.getInt(2) == 2); + jsonArray = jsonObject.optJSONArray("arrayKey"); + assertTrue("opt arrayKey should be JSONArray", + jsonArray.getInt(0) == 0 && + jsonArray.getInt(1) == 1 && + jsonArray.getInt(2) == 2); + JSONObject jsonObjectInner = jsonObject.getJSONObject("objectKey"); + assertTrue("objectKey should be JSONObject", + jsonObjectInner.get("myKey").equals("myVal")); + } + + /** + * Check whether JSONObject handles large or high precision numbers correctly + */ + @Test + public void stringToValueNumbersTest() { + assertTrue("-0 Should be a Double!",JSONObject.stringToValue("-0") instanceof Double); + assertTrue("-0.0 Should be a Double!",JSONObject.stringToValue("-0.0") instanceof Double); + assertTrue("'-' Should be a String!",JSONObject.stringToValue("-") instanceof String); + assertTrue( "0.2 should be a Double!", + JSONObject.stringToValue( "0.2" ) instanceof Double ); + assertTrue( "Doubles should be Doubles, even when incorrectly converting floats!", + JSONObject.stringToValue( new Double( "0.2f" ).toString() ) instanceof Double ); + /** + * This test documents a need for BigDecimal conversion. + */ + Object obj = JSONObject.stringToValue( "299792.457999999984" ); + assertTrue( "evaluates to 299792.458 doubld instead of 299792.457999999984 BigDecimal!", + obj.equals(new Double(299792.458)) ); + assertTrue( "1 should be an Integer!", + JSONObject.stringToValue( "1" ) instanceof Integer ); + assertTrue( "Integer.MAX_VALUE should still be an Integer!", + JSONObject.stringToValue( new Integer( Integer.MAX_VALUE ).toString() ) instanceof Integer ); + assertTrue( "Large integers should be a Long!", + JSONObject.stringToValue( new Long( Long.sum( Integer.MAX_VALUE, 1 ) ).toString() ) instanceof Long ); + assertTrue( "Long.MAX_VALUE should still be an Integer!", + JSONObject.stringToValue( new Long( Long.MAX_VALUE ).toString() ) instanceof Long ); + + String str = new BigInteger( new Long( Long.MAX_VALUE ).toString() ).add( BigInteger.ONE ).toString(); + assertTrue( "Really large integers currently evaluate to string", + JSONObject.stringToValue(str).equals("9223372036854775808")); + } + + /** + * This test documents numeric values which could be numerically + * handled as BigDecimal or BigInteger. It helps determine what outputs + * will change if those types are supported. + */ + @Test + public void jsonValidNumberValuesNeitherLongNorIEEE754Compatible() { + // Valid JSON Numbers, probably should return BigDecimal or BigInteger objects + String str = + "{"+ + "\"numberWithDecimals\":299792.457999999984,"+ + "\"largeNumber\":12345678901234567890,"+ + "\"preciseNumber\":0.2000000000000000111,"+ + "\"largeExponent\":-23.45e2327"+ + "}"; + JSONObject jsonObject = new JSONObject(str); + // Comes back as a double, but loses precision + assertTrue( "numberWithDecimals currently evaluates to double 299792.458", + jsonObject.get( "numberWithDecimals" ).equals( new Double( "299792.458" ) ) ); + Object obj = jsonObject.get( "largeNumber" ); + assertTrue("largeNumber currently evaluates to string", + "12345678901234567890".equals(obj)); + // comes back as a double but loses precision + assertTrue( "preciseNumber currently evaluates to double 0.2", + jsonObject.get( "preciseNumber" ).equals(new Double(0.2))); + obj = jsonObject.get( "largeExponent" ); + assertTrue("largeExponent should currently evaluates as a string", + "-23.45e2327".equals(obj)); + } + + /** + * This test documents how JSON-Java handles invalid numeric input. + */ + @Test + public void jsonInvalidNumberValues() { + // Number-notations supported by Java and invalid as JSON + String str = + "{"+ + "\"hexNumber\":-0x123,"+ + "\"tooManyZeros\":00,"+ + "\"negativeInfinite\":-Infinity,"+ + "\"negativeNaN\":-NaN,"+ + "\"negativeFraction\":-.01,"+ + "\"tooManyZerosFraction\":00.001,"+ + "\"negativeHexFloat\":-0x1.fffp1,"+ + "\"hexFloat\":0x1.0P-1074,"+ + "\"floatIdentifier\":0.1f,"+ + "\"doubleIdentifier\":0.1d"+ + "}"; + JSONObject jsonObject = new JSONObject(str); + Object obj; + obj = jsonObject.get( "hexNumber" ); + assertFalse( "hexNumber must not be a number (should throw exception!?)", + obj instanceof Number ); + assertTrue("hexNumber currently evaluates to string", + obj.equals("-0x123")); + assertTrue( "tooManyZeros currently evaluates to string", + jsonObject.get( "tooManyZeros" ).equals("00")); + obj = jsonObject.get("negativeInfinite"); + assertTrue( "negativeInfinite currently evaluates to string", + obj.equals("-Infinity")); + obj = jsonObject.get("negativeNaN"); + assertTrue( "negativeNaN currently evaluates to string", + obj.equals("-NaN")); + assertTrue( "negativeFraction currently evaluates to double -0.01", + jsonObject.get( "negativeFraction" ).equals(new Double(-0.01))); + assertTrue( "tooManyZerosFraction currently evaluates to double 0.001", + jsonObject.get( "tooManyZerosFraction" ).equals(new Double(0.001))); + assertTrue( "negativeHexFloat currently evaluates to double -3.99951171875", + jsonObject.get( "negativeHexFloat" ).equals(new Double(-3.99951171875))); + assertTrue("hexFloat currently evaluates to double 4.9E-324", + jsonObject.get("hexFloat").equals(new Double(4.9E-324))); + assertTrue("floatIdentifier currently evaluates to double 0.1", + jsonObject.get("floatIdentifier").equals(new Double(0.1))); + assertTrue("doubleIdentifier currently evaluates to double 0.1", + jsonObject.get("doubleIdentifier").equals(new Double(0.1))); + } + + /** + * Tests how JSONObject get[type] handles incorrect types + */ + @Test + public void jsonObjectNonAndWrongValues() { + String str = + "{"+ + "\"trueKey\":true,"+ + "\"falseKey\":false,"+ + "\"trueStrKey\":\"true\","+ + "\"falseStrKey\":\"false\","+ + "\"stringKey\":\"hello world!\","+ + "\"intKey\":42,"+ + "\"intStrKey\":\"43\","+ + "\"longKey\":1234567890123456789,"+ + "\"longStrKey\":\"987654321098765432\","+ + "\"doubleKey\":-23.45e7,"+ + "\"doubleStrKey\":\"00001.000\","+ + "\"arrayKey\":[0,1,2],"+ + "\"objectKey\":{\"myKey\":\"myVal\"}"+ + "}"; + JSONObject jsonObject = new JSONObject(str); + try { + jsonObject.getBoolean("nonKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("expecting an exception message", + "JSONObject[\"nonKey\"] not found.".equals(e.getMessage())); + } + try { + jsonObject.getBoolean("stringKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a Boolean.". + equals(e.getMessage())); + } + try { + jsonObject.getString("nonKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.". + equals(e.getMessage())); + } + try { + jsonObject.getString("trueKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"trueKey\"] not a string.". + equals(e.getMessage())); + } + try { + jsonObject.getDouble("nonKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.". + equals(e.getMessage())); + } + try { + jsonObject.getDouble("stringKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a number.". + equals(e.getMessage())); + } + try { + jsonObject.getInt("nonKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.". + equals(e.getMessage())); + } + try { + jsonObject.getInt("stringKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"stringKey\"] is not an int.". + equals(e.getMessage())); + } + try { + jsonObject.getLong("nonKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.". + equals(e.getMessage())); + } + try { + jsonObject.getLong("stringKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a long.". + equals(e.getMessage())); + } + try { + jsonObject.getJSONArray("nonKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.". + equals(e.getMessage())); + } + try { + jsonObject.getJSONArray("stringKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a JSONArray.". + equals(e.getMessage())); + } + try { + jsonObject.getJSONObject("nonKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.". + equals(e.getMessage())); + } + try { + jsonObject.getJSONObject("stringKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a JSONObject.". + equals(e.getMessage())); + } + } + + /** + * This test documents an unexpected numeric behavior. + * A double that ends with .0 is parsed, serialized, then + * parsed again. On the second parse, it has become an int. + */ + @Test + public void unexpectedDoubleToIntConversion() { + String key30 = "key30"; + String key31 = "key31"; + JSONObject jsonObject = new JSONObject(); + jsonObject.put(key30, new Double(3.0)); + jsonObject.put(key31, new Double(3.1)); + + assertTrue("3.0 should remain a double", + jsonObject.getDouble(key30) == 3); + assertTrue("3.1 should remain a double", + jsonObject.getDouble(key31) == 3.1); + + // turns 3.0 into 3. + String serializedString = jsonObject.toString(); + JSONObject deserialized = new JSONObject(serializedString); + assertTrue("3.0 is now an int", deserialized.get(key30) instanceof Integer); + assertTrue("3.0 can still be interpreted as a double", + deserialized.getDouble(key30) == 3.0); + assertTrue("3.1 remains a double", deserialized.getDouble(key31) == 3.1); + } + + /** + * Document behaviors of big numbers. Includes both JSONObject + * and JSONArray tests + */ + @SuppressWarnings("boxing") + @Test + public void bigNumberOperations() { + /** + * JSONObject tries to parse BigInteger as a bean, but it only has + * one getter, getLowestBitSet(). The value is lost and an unhelpful + * value is stored. This should be fixed. + */ + BigInteger bigInteger = new BigInteger("123456789012345678901234567890"); + JSONObject jsonObject = new JSONObject(bigInteger); + Object obj = jsonObject.get("lowestSetBit"); + assertTrue("JSONObject only has 1 value", jsonObject.length() == 1); + assertTrue("JSONObject parses BigInteger as the Integer lowestBitSet", + obj instanceof Integer); + assertTrue("this bigInteger lowestBitSet happens to be 1", + obj.equals(1)); + + /** + * JSONObject tries to parse BigDecimal as a bean, but it has + * no getters, The value is lost and no value is stored. + * This should be fixed. + */ + BigDecimal bigDecimal = new BigDecimal( + "123456789012345678901234567890.12345678901234567890123456789"); + jsonObject = new JSONObject(bigDecimal); + assertTrue("large bigDecimal is not stored", jsonObject.length() == 0); + + /** + * JSONObject put(String, Object) method stores and serializes + * bigInt and bigDec correctly. Nothing needs to change. + */ + jsonObject = new JSONObject(); + jsonObject.put("bigInt", bigInteger); + assertTrue("jsonObject.put() handles bigInt correctly", + jsonObject.get("bigInt").equals(bigInteger)); + assertTrue("jsonObject.getBigInteger() handles bigInt correctly", + jsonObject.getBigInteger("bigInt").equals(bigInteger)); + assertTrue("jsonObject.optBigInteger() handles bigInt correctly", + jsonObject.optBigInteger("bigInt", BigInteger.ONE).equals(bigInteger)); + assertTrue("jsonObject serializes bigInt correctly", + jsonObject.toString().equals("{\"bigInt\":123456789012345678901234567890}")); + jsonObject = new JSONObject(); + jsonObject.put("bigDec", bigDecimal); + assertTrue("jsonObject.put() handles bigDec correctly", + jsonObject.get("bigDec").equals(bigDecimal)); + assertTrue("jsonObject.getBigDecimal() handles bigDec correctly", + jsonObject.getBigDecimal("bigDec").equals(bigDecimal)); + assertTrue("jsonObject.optBigDecimal() handles bigDec correctly", + jsonObject.optBigDecimal("bigDec", BigDecimal.ONE).equals(bigDecimal)); + assertTrue("jsonObject serializes bigDec correctly", + jsonObject.toString().equals( + "{\"bigDec\":123456789012345678901234567890.12345678901234567890123456789}")); + + /** + * exercise some exceptions + */ + try { + jsonObject.getBigDecimal("bigInt"); + assertTrue("expected an exeption", false); + } catch (JSONException ignored) {} + obj = jsonObject.optBigDecimal("bigInt", BigDecimal.ONE); + assertTrue("expected BigDecimal", obj.equals(BigDecimal.ONE)); + try { + jsonObject.getBigInteger("bigDec"); + assertTrue("expected an exeption", false); + } catch (JSONException ignored) {} + jsonObject.put("stringKey", "abc"); + try { + jsonObject.getBigDecimal("stringKey"); + assertTrue("expected an exeption", false); + } catch (JSONException ignored) {} + obj = jsonObject.optBigInteger("bigDec", BigInteger.ONE); + assertTrue("expected BigInteger", obj.equals(BigInteger.ONE)); + + /** + * JSONObject.numberToString() works correctly, nothing to change. + */ + String str = JSONObject.numberToString(bigInteger); + assertTrue("numberToString() handles bigInteger correctly", + str.equals("123456789012345678901234567890")); + str = JSONObject.numberToString(bigDecimal); + assertTrue("numberToString() handles bigDecimal correctly", + str.equals("123456789012345678901234567890.12345678901234567890123456789")); + + /** + * JSONObject.stringToValue() turns bigInt into an accurate string, + * and rounds bigDec. This incorrect, but users may have come to + * expect this behavior. Change would be marginally better, but + * might inconvenience users. + */ + obj = JSONObject.stringToValue(bigInteger.toString()); + assertTrue("stringToValue() turns bigInteger string into string", + obj instanceof String); + obj = JSONObject.stringToValue(bigDecimal.toString()); + assertTrue("stringToValue() changes bigDecimal string", + !obj.toString().equals(bigDecimal.toString())); + + /** + * wrap() vs put() big number behavior is now the same. + */ + // bigInt map ctor + Map map = new HashMap(); + map.put("bigInt", bigInteger); + jsonObject = new JSONObject(map); + String actualFromMapStr = jsonObject.toString(); + assertTrue("bigInt in map (or array or bean) is a string", + actualFromMapStr.equals( + "{\"bigInt\":123456789012345678901234567890}")); + // bigInt put + jsonObject = new JSONObject(); + jsonObject.put("bigInt", bigInteger); + String actualFromPutStr = jsonObject.toString(); + assertTrue("bigInt from put is a number", + actualFromPutStr.equals( + "{\"bigInt\":123456789012345678901234567890}")); + // bigDec map ctor + map = new HashMap(); + map.put("bigDec", bigDecimal); + jsonObject = new JSONObject(map); + actualFromMapStr = jsonObject.toString(); + assertTrue("bigDec in map (or array or bean) is a bigDec", + actualFromMapStr.equals( + "{\"bigDec\":123456789012345678901234567890.12345678901234567890123456789}")); + // bigDec put + jsonObject = new JSONObject(); + jsonObject.put("bigDec", bigDecimal); + actualFromPutStr = jsonObject.toString(); + assertTrue("bigDec from put is a number", + actualFromPutStr.equals( + "{\"bigDec\":123456789012345678901234567890.12345678901234567890123456789}")); + // bigInt,bigDec put + JSONArray jsonArray = new JSONArray(); + jsonArray.put(bigInteger); + jsonArray.put(bigDecimal); + actualFromPutStr = jsonArray.toString(); + assertTrue("bigInt, bigDec from put is a number", + actualFromPutStr.equals( + "[123456789012345678901234567890,123456789012345678901234567890.12345678901234567890123456789]")); + assertTrue("getBigInt is bigInt", jsonArray.getBigInteger(0).equals(bigInteger)); + assertTrue("getBigDec is bigDec", jsonArray.getBigDecimal(1).equals(bigDecimal)); + assertTrue("optBigInt is bigInt", jsonArray.optBigInteger(0, BigInteger.ONE).equals(bigInteger)); + assertTrue("optBigDec is bigDec", jsonArray.optBigDecimal(1, BigDecimal.ONE).equals(bigDecimal)); + jsonArray.put(Boolean.TRUE); + try { + jsonArray.getBigInteger(2); + assertTrue("should not be able to get big int", false); + } catch (Exception ignored) {} + try { + jsonArray.getBigDecimal(2); + assertTrue("should not be able to get big dec", false); + } catch (Exception ignored) {} + assertTrue("optBigInt is default", jsonArray.optBigInteger(2, BigInteger.ONE).equals(BigInteger.ONE)); + assertTrue("optBigDec is default", jsonArray.optBigDecimal(2, BigDecimal.ONE).equals(BigDecimal.ONE)); + + // bigInt,bigDec list ctor + List list = new ArrayList(); + list.add(bigInteger); + list.add(bigDecimal); + jsonArray = new JSONArray(list); + String actualFromListStr = jsonArray.toString(); + assertTrue("bigInt, bigDec in list is a bigInt, bigDec", + actualFromListStr.equals( + "[123456789012345678901234567890,123456789012345678901234567890.12345678901234567890123456789]")); + // bigInt bean ctor + MyBigNumberBean myBigNumberBean = mock(MyBigNumberBean.class); + when(myBigNumberBean.getBigInteger()).thenReturn(new BigInteger("123456789012345678901234567890")); + jsonObject = new JSONObject(myBigNumberBean); + String actualFromBeanStr = jsonObject.toString(); + // can't do a full string compare because mockery adds an extra key/value + assertTrue("bigInt from bean ctor is a bigInt", + actualFromBeanStr.contains("123456789012345678901234567890")); + // bigDec bean ctor + myBigNumberBean = mock(MyBigNumberBean.class); + when(myBigNumberBean.getBigDecimal()).thenReturn(new BigDecimal("123456789012345678901234567890.12345678901234567890123456789")); + jsonObject = new JSONObject(myBigNumberBean); + actualFromBeanStr = jsonObject.toString(); + // can't do a full string compare because mockery adds an extra key/value + assertTrue("bigDec from bean ctor is a bigDec", + actualFromBeanStr.contains("123456789012345678901234567890.12345678901234567890123456789")); + // bigInt,bigDec wrap() + obj = JSONObject.wrap(bigInteger); + assertTrue("wrap() returns big num",obj.equals(bigInteger)); + obj = JSONObject.wrap(bigDecimal); + assertTrue("wrap() returns string",obj.equals(bigDecimal)); + + } + + /** + * The purpose for the static method getNames() methods are not clear. + * This method is not called from within JSON-Java. Most likely + * uses are to prep names arrays for: + * JSONObject(JSONObject jo, String[] names) + * JSONObject(Object object, String names[]), + */ + @Test + public void jsonObjectNames() { + JSONObject jsonObject; + + // getNames() from null JSONObject + assertTrue("null names from null Object", + null == JSONObject.getNames((Object)null)); + + // getNames() from object with no fields + assertTrue("null names from Object with no fields", + null == JSONObject.getNames(new MyJsonString())); + + // getNames from new JSONOjbect + jsonObject = new JSONObject(); + String [] names = JSONObject.getNames(jsonObject); + assertTrue("names should be null", names == null); + + + // getNames() from empty JSONObject + String emptyStr = "{}"; + jsonObject = new JSONObject(emptyStr); + assertTrue("empty JSONObject should have null names", + null == JSONObject.getNames(jsonObject)); + + // getNames() from JSONObject + String str = + "{"+ + "\"trueKey\":true,"+ + "\"falseKey\":false,"+ + "\"stringKey\":\"hello world!\","+ + "}"; + jsonObject = new JSONObject(str); + names = JSONObject.getNames(jsonObject); + JSONArray jsonArray = new JSONArray(names); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider() + .parse(jsonArray.toString()); + List docList = JsonPath.read(doc, "$"); + assertTrue("expected 3 items", docList.size() == 3); + assertTrue( + "expected to find trueKey", + ((List) JsonPath.read(doc, "$[?(@=='trueKey')]")).size() == 1); + assertTrue( + "expected to find falseKey", + ((List) JsonPath.read(doc, "$[?(@=='falseKey')]")).size() == 1); + assertTrue( + "expected to find stringKey", + ((List) JsonPath.read(doc, "$[?(@=='stringKey')]")).size() == 1); + + /** + * getNames() from an enum with properties has an interesting result. + * It returns the enum values, not the selected enum properties + */ + MyEnumField myEnumField = MyEnumField.VAL1; + names = JSONObject.getNames(myEnumField); + + // validate JSON + jsonArray = new JSONArray(names); + doc = Configuration.defaultConfiguration().jsonProvider() + .parse(jsonArray.toString()); + docList = JsonPath.read(doc, "$"); + assertTrue("expected 3 items", docList.size() == 3); + assertTrue( + "expected to find VAL1", + ((List) JsonPath.read(doc, "$[?(@=='VAL1')]")).size() == 1); + assertTrue( + "expected to find VAL2", + ((List) JsonPath.read(doc, "$[?(@=='VAL2')]")).size() == 1); + assertTrue( + "expected to find VAL3", + ((List) JsonPath.read(doc, "$[?(@=='VAL3')]")).size() == 1); + + /** + * A bean is also an object. But in order to test the static + * method getNames(), this particular bean needs some public + * data members. + */ + MyPublicClass myPublicClass = new MyPublicClass(); + names = JSONObject.getNames(myPublicClass); + + // validate JSON + jsonArray = new JSONArray(names); + doc = Configuration.defaultConfiguration().jsonProvider() + .parse(jsonArray.toString()); + docList = JsonPath.read(doc, "$"); + assertTrue("expected 2 items", docList.size() == 2); + assertTrue( + "expected to find publicString", + ((List) JsonPath.read(doc, "$[?(@=='publicString')]")).size() == 1); + assertTrue( + "expected to find publicInt", + ((List) JsonPath.read(doc, "$[?(@=='publicInt')]")).size() == 1); + } + + /** + * Populate a JSONArray from an empty JSONObject names() method. + * It should be empty. + */ + @Test + public void emptyJsonObjectNamesToJsonAray() { + JSONObject jsonObject = new JSONObject(); + JSONArray jsonArray = jsonObject.names(); + assertTrue("jsonArray should be null", jsonArray == null); + } + + /** + * Populate a JSONArray from a JSONObject names() method. + * Confirm that it contains the expected names. + */ + @Test + public void jsonObjectNamesToJsonAray() { + String str = + "{"+ + "\"trueKey\":true,"+ + "\"falseKey\":false,"+ + "\"stringKey\":\"hello world!\","+ + "}"; + + JSONObject jsonObject = new JSONObject(str); + JSONArray jsonArray = jsonObject.names(); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); + assertTrue("expected 3 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 3); + assertTrue("expected to find trueKey", ((List) JsonPath.read(doc, "$[?(@=='trueKey')]")).size() == 1); + assertTrue("expected to find falseKey", ((List) JsonPath.read(doc, "$[?(@=='falseKey')]")).size() == 1); + assertTrue("expected to find stringKey", ((List) JsonPath.read(doc, "$[?(@=='stringKey')]")).size() == 1); + } + + /** + * Exercise the JSONObject increment() method. + */ + @SuppressWarnings("cast") + @Test + public void jsonObjectIncrement() { + String str = + "{"+ + "\"keyLong\":9999999991,"+ + "\"keyDouble\":1.1"+ + "}"; + JSONObject jsonObject = new JSONObject(str); + jsonObject.increment("keyInt"); + jsonObject.increment("keyInt"); + jsonObject.increment("keyLong"); + jsonObject.increment("keyDouble"); + jsonObject.increment("keyInt"); + jsonObject.increment("keyLong"); + jsonObject.increment("keyDouble"); + /** + * JSONObject constructor won't handle these types correctly, but + * adding them via put works. + */ + jsonObject.put("keyFloat", new Float(1.1)); + jsonObject.put("keyBigInt", new BigInteger("123456789123456789123456789123456780")); + jsonObject.put("keyBigDec", new BigDecimal("123456789123456789123456789123456780.1")); + jsonObject.increment("keyFloat"); + jsonObject.increment("keyFloat"); + jsonObject.increment("keyBigInt"); + jsonObject.increment("keyBigDec"); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); + assertTrue("expected 3", Integer.valueOf(3).equals(jsonObject.query("/keyInt"))); + assertTrue("expected 9999999993", Long.valueOf(9999999993L).equals(jsonObject.query("/keyLong"))); + assertTrue("expected 3.1", Double.valueOf(3.1).equals(jsonObject.query("/keyDouble"))); + assertTrue("expected 123456789123456789123456789123456781", new BigInteger("123456789123456789123456789123456781").equals(jsonObject.query("/keyBigInt"))); + assertTrue("expected 123456789123456789123456789123456781.1", new BigDecimal("123456789123456789123456789123456781.1").equals(jsonObject.query("/keyBigDec"))); + + /** + * Should work the same way on any platform! @see https://docs.oracle + * .com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.3 This is the + * effect of a float to double conversion and is inherent to the + * shortcomings of the IEEE 754 format, when converting 32-bit into + * double-precision 64-bit. Java type-casts float to double. A 32 bit + * float is type-casted to 64 bit double by simply appending zero-bits + * to the mantissa (and extended the signed exponent by 3 bits.) and + * there is no way to obtain more information than it is stored in the + * 32-bits float. + * + * Like 1/3 cannot be represented as base10 number because it is + * periodically, 1/5 (for example) cannot be represented as base2 number + * since it is periodically in base2 (take a look at + * http://www.h-schmidt.net/FloatConverter/) The same happens to 3.1, + * that decimal number (base10 representation) is periodic in base2 + * representation, therefore appending zero-bits is inaccurate. Only + * repeating the periodically occurring bits (0110) would be a proper + * conversion. However one cannot detect from a 32 bit IEE754 + * representation which bits would "repeat infinitely", since the + * missing bits would not fit into the 32 bit float, i.e. the + * information needed simply is not there! + */ + assertTrue("expected 3.0999999046325684", Double.valueOf(3.0999999046325684).equals(jsonObject.query("/keyFloat"))); + + /** + * float f = 3.1f; double df = (double) f; double d = 3.1d; + * System.out.println + * (Integer.toBinaryString(Float.floatToRawIntBits(f))); + * System.out.println + * (Long.toBinaryString(Double.doubleToRawLongBits(df))); + * System.out.println + * (Long.toBinaryString(Double.doubleToRawLongBits(d))); + * + * - Float: + * seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm + * 1000000010001100110011001100110 + * - Double + * seeeeeeeeeeemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm + * 10000000 10001100110011001100110 + * 100000000001000110011001100110011000000000000000000000000000000 + * 100000000001000110011001100110011001100110011001100110011001101 + */ + + /** + * Examples of well documented but probably unexpected behavior in + * java / with 32-bit float to 64-bit float conversion. + */ + assertFalse("Document unexpected behaviour with explicit type-casting float as double!", (double)0.2f == 0.2d ); + assertFalse("Document unexpected behaviour with implicit type-cast!", 0.2f == 0.2d ); + Double d1 = new Double( 1.1f ); + Double d2 = new Double( "1.1f" ); + assertFalse( "Document implicit type cast from float to double before calling Double(double d) constructor", d1.equals( d2 ) ); + + assertTrue( "Correctly converting float to double via base10 (string) representation!", new Double( 3.1d ).equals( new Double( new Float( 3.1f ).toString() ) ) ); + + // Pinpointing the not so obvious "buggy" conversion from float to double in JSONObject + JSONObject jo = new JSONObject(); + jo.put( "bug", 3.1f ); // will call put( String key, double value ) with implicit and "buggy" type-cast from float to double + assertFalse( "The java-compiler did add some zero bits for you to the mantissa (unexpected, but well documented)", jo.get( "bug" ).equals( new Double( 3.1d ) ) ); + + JSONObject inc = new JSONObject(); + inc.put( "bug", new Float( 3.1f ) ); // This will put in instance of Float into JSONObject, i.e. call put( String key, Object value ) + assertTrue( "Everything is ok here!", inc.get( "bug" ) instanceof Float ); + inc.increment( "bug" ); // after adding 1, increment will call put( String key, double value ) with implicit and "buggy" type-cast from float to double! + // this.put(key, (Float) value + 1); + // 1. The (Object)value will be typecasted to (Float)value since it is an instanceof Float actually nothing is done. + // 2. Float instance will be autoboxed into float because the + operator will work on primitives not Objects! + // 3. A float+float operation will be performed and results into a float primitive. + // 4. There is no method that matches the signature put( String key, float value), java-compiler will choose the method + // put( String key, double value) and does an implicit type-cast(!) by appending zero-bits to the mantissa + assertTrue( "JSONObject increment converts Float to Double", jo.get( "bug" ) instanceof Double ); + // correct implementation (with change of behavior) would be: + // this.put(key, new Float((Float) value + 1)); + // Probably it would be better to deprecate the method and remove some day, while convenient processing the "payload" is not + // really in the the scope of a JSON-library (IMHO.) + + } + + /** + * Exercise JSONObject numberToString() method + */ + @SuppressWarnings("boxing") + @Test + public void jsonObjectNumberToString() { + String str; + Double dVal; + Integer iVal = 1; + str = JSONObject.numberToString(iVal); + assertTrue("expected "+iVal+" actual "+str, iVal.toString().equals(str)); + dVal = 12.34; + str = JSONObject.numberToString(dVal); + assertTrue("expected "+dVal+" actual "+str, dVal.toString().equals(str)); + dVal = 12.34e27; + str = JSONObject.numberToString(dVal); + assertTrue("expected "+dVal+" actual "+str, dVal.toString().equals(str)); + // trailing .0 is truncated, so it doesn't quite match toString() + dVal = 5000000.0000000; + str = JSONObject.numberToString(dVal); + assertTrue("expected 5000000 actual "+str, str.equals("5000000")); + } + + /** + * Exercise JSONObject put() and similar() methods + */ + @SuppressWarnings("boxing") + @Test + public void jsonObjectPut() { + String expectedStr = + "{"+ + "\"trueKey\":true,"+ + "\"falseKey\":false,"+ + "\"arrayKey\":[0,1,2],"+ + "\"objectKey\":{"+ + "\"myKey1\":\"myVal1\","+ + "\"myKey2\":\"myVal2\","+ + "\"myKey3\":\"myVal3\","+ + "\"myKey4\":\"myVal4\""+ + "}"+ + "}"; + JSONObject jsonObject = new JSONObject(); + jsonObject.put("trueKey", true); + jsonObject.put("falseKey", false); + Integer [] intArray = { 0, 1, 2 }; + jsonObject.put("arrayKey", Arrays.asList(intArray)); + Map myMap = new HashMap(); + myMap.put("myKey1", "myVal1"); + myMap.put("myKey2", "myVal2"); + myMap.put("myKey3", "myVal3"); + myMap.put("myKey4", "myVal4"); + jsonObject.put("objectKey", myMap); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 4 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 4); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); + assertTrue("expected 3 arrayKey items", ((List)(JsonPath.read(doc, "$.arrayKey"))).size() == 3); + assertTrue("expected 0", Integer.valueOf(0).equals(jsonObject.query("/arrayKey/0"))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonObject.query("/arrayKey/1"))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.query("/arrayKey/2"))); + assertTrue("expected 4 objectKey items", ((Map)(JsonPath.read(doc, "$.objectKey"))).size() == 4); + assertTrue("expected myVal1", "myVal1".equals(jsonObject.query("/objectKey/myKey1"))); + assertTrue("expected myVal2", "myVal2".equals(jsonObject.query("/objectKey/myKey2"))); + assertTrue("expected myVal3", "myVal3".equals(jsonObject.query("/objectKey/myKey3"))); + assertTrue("expected myVal4", "myVal4".equals(jsonObject.query("/objectKey/myKey4"))); + + jsonObject.remove("trueKey"); + JSONObject expectedJsonObject = new JSONObject(expectedStr); + assertTrue("unequal jsonObjects should not be similar", + !jsonObject.similar(expectedJsonObject)); + assertTrue("jsonObject should not be similar to jsonArray", + !jsonObject.similar(new JSONArray())); + + String aCompareValueStr = "{\"a\":\"aval\",\"b\":true}"; + String bCompareValueStr = "{\"a\":\"notAval\",\"b\":true}"; + JSONObject aCompareValueJsonObject = new JSONObject(aCompareValueStr); + JSONObject bCompareValueJsonObject = new JSONObject(bCompareValueStr); + assertTrue("different values should not be similar", + !aCompareValueJsonObject.similar(bCompareValueJsonObject)); + + String aCompareObjectStr = "{\"a\":\"aval\",\"b\":{}}"; + String bCompareObjectStr = "{\"a\":\"aval\",\"b\":true}"; + JSONObject aCompareObjectJsonObject = new JSONObject(aCompareObjectStr); + JSONObject bCompareObjectJsonObject = new JSONObject(bCompareObjectStr); + assertTrue("different nested JSONObjects should not be similar", + !aCompareObjectJsonObject.similar(bCompareObjectJsonObject)); + + String aCompareArrayStr = "{\"a\":\"aval\",\"b\":[]}"; + String bCompareArrayStr = "{\"a\":\"aval\",\"b\":true}"; + JSONObject aCompareArrayJsonObject = new JSONObject(aCompareArrayStr); + JSONObject bCompareArrayJsonObject = new JSONObject(bCompareArrayStr); + assertTrue("different nested JSONArrays should not be similar", + !aCompareArrayJsonObject.similar(bCompareArrayJsonObject)); + } + + /** + * Exercise JSONObject toString() method + */ + @Test + public void jsonObjectToString() { + String str = + "{"+ + "\"trueKey\":true,"+ + "\"falseKey\":false,"+ + "\"arrayKey\":[0,1,2],"+ + "\"objectKey\":{"+ + "\"myKey1\":\"myVal1\","+ + "\"myKey2\":\"myVal2\","+ + "\"myKey3\":\"myVal3\","+ + "\"myKey4\":\"myVal4\""+ + "}"+ + "}"; + JSONObject jsonObject = new JSONObject(str); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 4 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 4); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); + assertTrue("expected 3 arrayKey items", ((List)(JsonPath.read(doc, "$.arrayKey"))).size() == 3); + assertTrue("expected 0", Integer.valueOf(0).equals(jsonObject.query("/arrayKey/0"))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonObject.query("/arrayKey/1"))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.query("/arrayKey/2"))); + assertTrue("expected 4 objectKey items", ((Map)(JsonPath.read(doc, "$.objectKey"))).size() == 4); + assertTrue("expected myVal1", "myVal1".equals(jsonObject.query("/objectKey/myKey1"))); + assertTrue("expected myVal2", "myVal2".equals(jsonObject.query("/objectKey/myKey2"))); + assertTrue("expected myVal3", "myVal3".equals(jsonObject.query("/objectKey/myKey3"))); + assertTrue("expected myVal4", "myVal4".equals(jsonObject.query("/objectKey/myKey4"))); + } + + /** + * Exercise JSONObject toString() method with various indent levels. + */ + @Test + public void jsonObjectToStringIndent() { + String jsonObject0Str = + "{"+ + "\"key1\":" + + "[1,2," + + "{\"key3\":true}" + + "],"+ + "\"key2\":" + + "{\"key1\":\"val1\",\"key2\":" + + "{\"key2\":\"val2\"}" + + "},"+ + "\"key3\":" + + "[" + + "[1,2.1]" + + "," + + "[null]" + + "]"+ + "}"; + + String jsonObject1Str = + "{\n" + + " \"key1\": [\n" + + " 1,\n" + + " 2,\n" + + " {\"key3\": true}\n" + + " ],\n" + + " \"key2\": {\n" + + " \"key1\": \"val1\",\n" + + " \"key2\": {\"key2\": \"val2\"}\n" + + " },\n" + + " \"key3\": [\n" + + " [\n" + + " 1,\n" + + " 2.1\n" + + " ],\n" + + " [null]\n" + + " ]\n" + + "}"; + String jsonObject4Str = + "{\n" + + " \"key1\": [\n" + + " 1,\n" + + " 2,\n" + + " {\"key3\": true}\n" + + " ],\n" + + " \"key2\": {\n" + + " \"key1\": \"val1\",\n" + + " \"key2\": {\"key2\": \"val2\"}\n" + + " },\n" + + " \"key3\": [\n" + + " [\n" + + " 1,\n" + + " 2.1\n" + + " ],\n" + + " [null]\n" + + " ]\n" + + "}"; + JSONObject jsonObject = new JSONObject(jsonObject0Str); + assertEquals(jsonObject0Str, jsonObject.toString()); + assertEquals(jsonObject0Str, jsonObject.toString(0)); + assertEquals(jsonObject1Str, jsonObject.toString(1)); + assertEquals(jsonObject4Str, jsonObject.toString(4)); + } + + /** + * Explores how JSONObject handles maps. Insert a string/string map + * as a value in a JSONObject. It will remain a map. Convert the + * JSONObject to string, then create a new JSONObject from the string. + * In the new JSONObject, the value will be stored as a nested JSONObject. + * Confirm that map and nested JSONObject have the same contents. + */ + @Test + public void jsonObjectToStringSuppressWarningOnCastToMap() { + JSONObject jsonObject = new JSONObject(); + Map map = new HashMap<>(); + map.put("abc", "def"); + jsonObject.put("key", map); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); + assertTrue("expected 1 key item", ((Map)(JsonPath.read(doc, "$.key"))).size() == 1); + assertTrue("expected def", "def".equals(jsonObject.query("/key/abc"))); + } + + /** + * Explores how JSONObject handles collections. Insert a string collection + * as a value in a JSONObject. It will remain a collection. Convert the + * JSONObject to string, then create a new JSONObject from the string. + * In the new JSONObject, the value will be stored as a nested JSONArray. + * Confirm that collection and nested JSONArray have the same contents. + */ + @Test + public void jsonObjectToStringSuppressWarningOnCastToCollection() { + JSONObject jsonObject = new JSONObject(); + Collection collection = new ArrayList(); + collection.add("abc"); + // ArrayList will be added as an object + jsonObject.put("key", collection); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); + assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); + assertTrue("expected 1 key item", ((List)(JsonPath.read(doc, "$.key"))).size() == 1); + assertTrue("expected abc", "abc".equals(jsonObject.query("/key/0"))); + } + + /** + * Exercises the JSONObject.valueToString() method for various types + */ + @Test + public void valueToString() { + + assertTrue("null valueToString() incorrect", + "null".equals(JSONObject.valueToString(null))); + MyJsonString jsonString = new MyJsonString(); + assertTrue("jsonstring valueToString() incorrect", + "my string".equals(JSONObject.valueToString(jsonString))); + assertTrue("boolean valueToString() incorrect", + "true".equals(JSONObject.valueToString(Boolean.TRUE))); + assertTrue("non-numeric double", + "null".equals(JSONObject.doubleToString(Double.POSITIVE_INFINITY))); + String jsonObjectStr = + "{"+ + "\"key1\":\"val1\","+ + "\"key2\":\"val2\","+ + "\"key3\":\"val3\""+ + "}"; + JSONObject jsonObject = new JSONObject(jsonObjectStr); + assertTrue("jsonObject valueToString() incorrect", + JSONObject.valueToString(jsonObject).equals(jsonObject.toString())); + String jsonArrayStr = + "[1,2,3]"; + JSONArray jsonArray = new JSONArray(jsonArrayStr); + assertTrue("jsonArray valueToString() incorrect", + JSONObject.valueToString(jsonArray).equals(jsonArray.toString())); + Map map = new HashMap(); + map.put("key1", "val1"); + map.put("key2", "val2"); + map.put("key3", "val3"); + assertTrue("map valueToString() incorrect", + jsonObject.toString().equals(JSONObject.valueToString(map))); + Collection collection = new ArrayList(); + collection.add(new Integer(1)); + collection.add(new Integer(2)); + collection.add(new Integer(3)); + assertTrue("collection valueToString() expected: "+ + jsonArray.toString()+ " actual: "+ + JSONObject.valueToString(collection), + jsonArray.toString().equals(JSONObject.valueToString(collection))); + Integer[] array = { new Integer(1), new Integer(2), new Integer(3) }; + assertTrue("array valueToString() incorrect", + jsonArray.toString().equals(JSONObject.valueToString(array))); + } + + /** + * Confirm that https://github.com/douglascrockford/JSON-java/issues/167 is fixed. + * The following code was throwing a ClassCastException in the + * JSONObject(Map) constructor + */ + @SuppressWarnings("boxing") + @Test + public void valueToStringConfirmException() { + Map myMap = new HashMap(); + myMap.put(1, "myValue"); + // this is the test, it should not throw an exception + String str = JSONObject.valueToString(myMap); + // confirm result, just in case + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(str); + assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); + assertTrue("expected myValue", "myValue".equals(JsonPath.read(doc, "$.1"))); + } + + /** + * Exercise the JSONObject wrap() method. Sometimes wrap() will change + * the object being wrapped, other times not. The purpose of wrap() is + * to ensure the value is packaged in a way that is compatible with how + * a JSONObject value or JSONArray value is supposed to be stored. + */ + @Test + public void wrapObject() { + // wrap(null) returns NULL + assertTrue("null wrap() incorrect", + JSONObject.NULL == JSONObject.wrap(null)); + + // wrap(Integer) returns Integer + Integer in = new Integer(1); + assertTrue("Integer wrap() incorrect", + in == JSONObject.wrap(in)); + + /** + * This test is to document the preferred behavior if BigDecimal is + * supported. Previously bd returned as a string, since it + * is recognized as being a Java package class. Now with explicit + * support for big numbers, it remains a BigDecimal + */ + Object bdWrap = JSONObject.wrap(BigDecimal.ONE); + assertTrue("BigDecimal.ONE evaluates to ONE", + bdWrap.equals(BigDecimal.ONE)); + + // wrap JSONObject returns JSONObject + String jsonObjectStr = + "{"+ + "\"key1\":\"val1\","+ + "\"key2\":\"val2\","+ + "\"key3\":\"val3\""+ + "}"; + JSONObject jsonObject = new JSONObject(jsonObjectStr); + assertTrue("JSONObject wrap() incorrect", + jsonObject == JSONObject.wrap(jsonObject)); + + // wrap collection returns JSONArray + Collection collection = new ArrayList(); + collection.add(new Integer(1)); + collection.add(new Integer(2)); + collection.add(new Integer(3)); + JSONArray jsonArray = (JSONArray) (JSONObject.wrap(collection)); + + // validate JSON + Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); + assertTrue("expected 3 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 3); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/0"))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/1"))); + assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.query("/2"))); + + // wrap Array returns JSONArray + Integer[] array = { new Integer(1), new Integer(2), new Integer(3) }; + JSONArray integerArrayJsonArray = (JSONArray)(JSONObject.wrap(array)); + + // validate JSON + doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); + assertTrue("expected 3 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 3); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/0"))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/1"))); + assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.query("/2"))); + + // validate JSON + doc = Configuration.defaultConfiguration().jsonProvider().parse(integerArrayJsonArray.toString()); + assertTrue("expected 3 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 3); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/0"))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/1"))); + assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.query("/2"))); + + // wrap map returns JSONObject + Map map = new HashMap(); + map.put("key1", "val1"); + map.put("key2", "val2"); + map.put("key3", "val3"); + JSONObject mapJsonObject = (JSONObject) (JSONObject.wrap(map)); + + // validate JSON + doc = Configuration.defaultConfiguration().jsonProvider().parse(mapJsonObject.toString()); + assertTrue("expected 3 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 3); + assertTrue("expected val1", "val1".equals(mapJsonObject.query("/key1"))); + assertTrue("expected val2", "val2".equals(mapJsonObject.query("/key2"))); + assertTrue("expected val3", "val3".equals(mapJsonObject.query("/key3"))); + } + + + /** + * RFC 7159 defines control characters to be U+0000 through U+001F. This test verifies that the parser is checking for these in expected ways. + */ + @Test + public void jsonObjectParseControlCharacters(){ + for(int i = 0;i<=0x001f;i++){ + final String charString = String.valueOf((char)i); + final String source = "{\"key\":\""+charString+"\"}"; + try { + JSONObject jo = new JSONObject(source); + assertTrue("Expected "+charString+"("+i+") in the JSON Object but did not find it.",charString.equals(jo.getString("key"))); + } catch (JSONException ex) { + assertTrue("Only \\0 (U+0000), \\n (U+000A), and \\r (U+000D) should cause an error. Instead "+charString+"("+i+") caused an error", + i=='\0' || i=='\n' || i=='\r' + ); + } + } + } + + /** + * Explore how JSONObject handles parsing errors. + */ + @SuppressWarnings("boxing") + @Test + public void jsonObjectParsingErrors() { + try { + // does not start with '{' + String str = "abc"; + assertNull("Expected an exception",new JSONObject(str)); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "A JSONObject text must begin with '{' at 1 [character 2 line 1]". + equals(e.getMessage())); + } + try { + // does not end with '}' + String str = "{"; + assertNull("Expected an exception",new JSONObject(str)); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "A JSONObject text must end with '}' at 2 [character 3 line 1]". + equals(e.getMessage())); + } + try { + // key with no ':' + String str = "{\"myKey\" = true}"; + assertNull("Expected an exception",new JSONObject(str)); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "Expected a ':' after a key at 10 [character 11 line 1]". + equals(e.getMessage())); + } + try { + // entries with no ',' separator + String str = "{\"myKey\":true \"myOtherKey\":false}"; + assertNull("Expected an exception",new JSONObject(str)); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "Expected a ',' or '}' at 15 [character 16 line 1]". + equals(e.getMessage())); + } + try { + // append to wrong key + String str = "{\"myKey\":true, \"myOtherKey\":false}"; + JSONObject jsonObject = new JSONObject(str); + jsonObject.append("myKey", "hello"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[myKey] is not a JSONArray.". + equals(e.getMessage())); + } + try { + // increment wrong key + String str = "{\"myKey\":true, \"myOtherKey\":false}"; + JSONObject jsonObject = new JSONObject(str); + jsonObject.increment("myKey"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "Unable to increment [\"myKey\"].". + equals(e.getMessage())); + } + try { + // invalid key + String str = "{\"myKey\":true, \"myOtherKey\":false}"; + JSONObject jsonObject = new JSONObject(str); + jsonObject.get(null); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "Null key.". + equals(e.getMessage())); + } + try { + // invalid numberToString() + JSONObject.numberToString((Number)null); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "Null pointer". + equals(e.getMessage())); + } + try { + // null put key + JSONObject jsonObject = new JSONObject("{}"); + jsonObject.put(null, 0); + assertTrue("Expected an exception", false); + } catch (NullPointerException ignored) { + } + try { + // multiple putOnce key + JSONObject jsonObject = new JSONObject("{}"); + jsonObject.putOnce("hello", "world"); + jsonObject.putOnce("hello", "world!"); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("", true); + } + try { + // test validity of invalid double + JSONObject.testValidity(Double.NaN); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("", true); + } + try { + // test validity of invalid float + JSONObject.testValidity(Float.NEGATIVE_INFINITY); + assertTrue("Expected an exception", false); + } catch (JSONException e) { + assertTrue("", true); + } + } + + /** + * Confirm behavior when putOnce() is called with null parameters + */ + @Test + public void jsonObjectPutOnceNull() { + JSONObject jsonObject = new JSONObject(); + jsonObject.putOnce(null, null); + assertTrue("jsonObject should be empty", jsonObject.length() == 0); + } + + /** + * Exercise JSONObject opt(key, default) method. + */ + @Test + public void jsonObjectOptDefault() { + + String str = "{\"myKey\": \"myval\", \"hiKey\": null}"; + JSONObject jsonObject = new JSONObject(str); + + assertTrue("optBigDecimal() should return default BigDecimal", + BigDecimal.TEN.compareTo(jsonObject.optBigDecimal("myKey", BigDecimal.TEN))==0); + assertTrue("optBigInteger() should return default BigInteger", + BigInteger.TEN.compareTo(jsonObject.optBigInteger("myKey",BigInteger.TEN ))==0); + assertTrue("optBoolean() should return default boolean", + jsonObject.optBoolean("myKey", true)); + assertTrue("optInt() should return default int", + 42 == jsonObject.optInt("myKey", 42)); + assertTrue("optEnum() should return default Enum", + MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1))); + assertTrue("optJSONArray() should return null ", + null==jsonObject.optJSONArray("myKey")); + assertTrue("optJSONObject() should return null ", + null==jsonObject.optJSONObject("myKey")); + assertTrue("optLong() should return default long", + 42 == jsonObject.optLong("myKey", 42)); + assertTrue("optDouble() should return default double", + 42.3 == jsonObject.optDouble("myKey", 42.3)); + assertTrue("optString() should return default string", + "hi".equals(jsonObject.optString("hiKey", "hi"))); + } + + /** + * Exercise JSONObject opt(key, default) method when the key doesn't exist. + */ + @Test + public void jsonObjectOptNoKey() { + + JSONObject jsonObject = new JSONObject(); + + assertTrue("optBigDecimal() should return default BigDecimal", + BigDecimal.TEN.compareTo(jsonObject.optBigDecimal("myKey", BigDecimal.TEN))==0); + assertTrue("optBigInteger() should return default BigInteger", + BigInteger.TEN.compareTo(jsonObject.optBigInteger("myKey",BigInteger.TEN ))==0); + assertTrue("optBoolean() should return default boolean", + jsonObject.optBoolean("myKey", true)); + assertTrue("optInt() should return default int", + 42 == jsonObject.optInt("myKey", 42)); + assertTrue("optEnum() should return default Enum", + MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1))); + assertTrue("optJSONArray() should return null ", + null==jsonObject.optJSONArray("myKey")); + assertTrue("optJSONObject() should return null ", + null==jsonObject.optJSONObject("myKey")); + assertTrue("optLong() should return default long", + 42 == jsonObject.optLong("myKey", 42)); + assertTrue("optDouble() should return default double", + 42.3 == jsonObject.optDouble("myKey", 42.3)); + assertTrue("optString() should return default string", + "hi".equals(jsonObject.optString("hiKey", "hi"))); + } + + /** + * Verifies that the opt methods properly convert string values. + */ + @Test + public void jsonObjectOptStringConversion() { + JSONObject jo = new JSONObject("{\"int\":\"123\",\"true\":\"true\",\"false\":\"false\"}"); + assertTrue("unexpected optBoolean value",jo.optBoolean("true",false)==true); + assertTrue("unexpected optBoolean value",jo.optBoolean("false",true)==false); + assertTrue("unexpected optInt value",jo.optInt("int",0)==123); + assertTrue("unexpected optLong value",jo.optLong("int",0)==123); + assertTrue("unexpected optDouble value",jo.optDouble("int",0.0)==123.0); + assertTrue("unexpected optBigInteger value",jo.optBigInteger("int",BigInteger.ZERO).compareTo(new BigInteger("123"))==0); + assertTrue("unexpected optBigDecimal value",jo.optBigDecimal("int",BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); + + } + + /** + * Confirm behavior when JSONObject put(key, null object) is called + */ + @Test + public void jsonObjectputNull() { + + // put null should remove the item. + String str = "{\"myKey\": \"myval\"}"; + JSONObject jsonObjectRemove = new JSONObject(str); + jsonObjectRemove.remove("myKey"); + + JSONObject jsonObjectPutNull = new JSONObject(str); + jsonObjectPutNull.put("myKey", (Object) null); + + // validate JSON + assertTrue("jsonObject should be empty", jsonObjectRemove.length() == 0 + && jsonObjectPutNull.length() == 0); + } + + /** + * Exercise JSONObject quote() method + * This purpose of quote() is to ensure that for strings with embedded + * quotes, the quotes are properly escaped. + */ + @Test + public void jsonObjectQuote() { + String str; + str = ""; + String quotedStr; + quotedStr = JSONObject.quote(str); + assertTrue("quote() expected escaped quotes, found "+quotedStr, + "\"\"".equals(quotedStr)); + str = "\"\""; + quotedStr = JSONObject.quote(str); + assertTrue("quote() expected escaped quotes, found "+quotedStr, + "\"\\\"\\\"\"".equals(quotedStr)); + str = "null and null will be emitted as "" + */ + String sJONull = XML.toString(jsonObjectJONull); + assertTrue("JSONObject.NULL should emit a null value", + "null".equals(sJONull)); + String sNull = XML.toString(jsonObjectNull); + assertTrue("null should emit an empty string", "".equals(sNull)); + } + + @Test(expected = JSONPointerException.class) + public void queryWithNoResult() { + new JSONObject().query("/a/b"); + } + + @Test + public void optQueryWithNoResult() { + assertNull(new JSONObject().optQuery("/a/b")); + } + + @Test(expected = IllegalArgumentException.class) + public void optQueryWithSyntaxError() { + new JSONObject().optQuery("invalid"); + } + + @Test(expected = JSONException.class) + public void invalidEscapeSequence() { + String json = "{ \"\\url\": \"value\" }"; + assertNull("Expected an exception",new JSONObject(json)); + } + + /** + * Exercise JSONObject toMap() method. + */ + @Test + public void toMap() { + String jsonObjectStr = + "{" + + "\"key1\":" + + "[1,2," + + "{\"key3\":true}" + + "]," + + "\"key2\":" + + "{\"key1\":\"val1\",\"key2\":" + + "{\"key2\":null}," + + "\"key3\":42" + + "}," + + "\"key3\":" + + "[" + + "[\"value1\",2.1]" + + "," + + "[null]" + + "]" + + "}"; + + JSONObject jsonObject = new JSONObject(jsonObjectStr); + Map map = jsonObject.toMap(); + + assertTrue("Map should not be null", map != null); + assertTrue("Map should have 3 elements", map.size() == 3); + + List key1List = (List)map.get("key1"); + assertTrue("key1 should not be null", key1List != null); + assertTrue("key1 list should have 3 elements", key1List.size() == 3); + assertTrue("key1 value 1 should be 1", key1List.get(0).equals(Integer.valueOf(1))); + assertTrue("key1 value 2 should be 2", key1List.get(1).equals(Integer.valueOf(2))); + + Map key1Value3Map = (Map)key1List.get(2); + assertTrue("Map should not be null", key1Value3Map != null); + assertTrue("Map should have 1 element", key1Value3Map.size() == 1); + assertTrue("Map key3 should be true", key1Value3Map.get("key3").equals(Boolean.TRUE)); + + Map key2Map = (Map)map.get("key2"); + assertTrue("key2 should not be null", key2Map != null); + assertTrue("key2 map should have 3 elements", key2Map.size() == 3); + assertTrue("key2 map key 1 should be val1", key2Map.get("key1").equals("val1")); + assertTrue("key2 map key 3 should be 42", key2Map.get("key3").equals(Integer.valueOf(42))); + + Map key2Val2Map = (Map)key2Map.get("key2"); + assertTrue("key2 map key 2 should not be null", key2Val2Map != null); + assertTrue("key2 map key 2 should have an entry", key2Val2Map.containsKey("key2")); + assertTrue("key2 map key 2 value should be null", key2Val2Map.get("key2") == null); + + List key3List = (List)map.get("key3"); + assertTrue("key3 should not be null", key3List != null); + assertTrue("key3 list should have 3 elements", key3List.size() == 2); + + List key3Val1List = (List)key3List.get(0); + assertTrue("key3 list val 1 should not be null", key3Val1List != null); + assertTrue("key3 list val 1 should have 2 elements", key3Val1List.size() == 2); + assertTrue("key3 list val 1 list element 1 should be value1", key3Val1List.get(0).equals("value1")); + assertTrue("key3 list val 1 list element 2 should be 2.1", key3Val1List.get(1).equals(Double.valueOf("2.1"))); + + List key3Val2List = (List)key3List.get(1); + assertTrue("key3 list val 2 should not be null", key3Val2List != null); + assertTrue("key3 list val 2 should have 1 element", key3Val2List.size() == 1); + assertTrue("key3 list val 2 list element 1 should be null", key3Val2List.get(0) == null); + + // Assert that toMap() is a deep copy + jsonObject.getJSONArray("key3").getJSONArray(0).put(0, "still value 1"); + assertTrue("key3 list val 1 list element 1 should be value1", key3Val1List.get(0).equals("value1")); + + // assert that the new map is mutable + assertTrue("Removing a key should succeed", map.remove("key3") != null); + assertTrue("Map should have 2 elements", map.size() == 2); + + } +} diff --git a/src/test/java/org/json/junit/JSONStringTest.java b/src/test/java/org/json/junit/JSONStringTest.java index cba5d09..617b9e3 100644 --- a/src/test/java/org/json/junit/JSONStringTest.java +++ b/src/test/java/org/json/junit/JSONStringTest.java @@ -1,310 +1,371 @@ -package org.json.junit; - -import static org.junit.Assert.*; - -import java.io.StringWriter; -import java.util.*; - -import org.json.*; -import org.junit.Test; - -/** - * Tests for JSONString implementations, and the difference between - * {@link JSONObject#valueToString} and {@link JSONObject#writeValue}. - */ -public class JSONStringTest { - - /** - * This tests the JSONObject.writeValue() method. We can't test directly - * due to it being a package-protected method. Instead, we can call - * JSONArray.write(), which delegates the writing of each entry to - * writeValue(). - */ - @Test - public void writeValues() throws Exception { - JSONArray jsonArray = new JSONArray(); - jsonArray.put((Object)null); - - StringWriter writer = new StringWriter(); - String output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[null]".equals(output)); - - jsonArray = new JSONArray(); - jsonArray.put(JSONObject.NULL); - writer = new StringWriter(); - output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[null]".equals(output)); - - jsonArray = new JSONArray(); - jsonArray.put(new JSONObject()); - writer = new StringWriter(); - output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[{}]".equals(output)); - - jsonArray = new JSONArray(); - jsonArray.put(new JSONArray()); - writer = new StringWriter(); - output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[[]]".equals(output)); - - jsonArray = new JSONArray(); - Map singleMap = Collections.singletonMap("key1", "value1"); - jsonArray.put((Object)singleMap); - writer = new StringWriter(); - output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[{\"key1\":\"value1\"}]".equals(output)); - - jsonArray = new JSONArray(); - List singleList = Collections.singletonList("entry1"); - jsonArray.put((Object)singleList); - writer = new StringWriter(); - output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[[\"entry1\"]]".equals(output)); - - jsonArray = new JSONArray(); - int[] intArray = new int[] { 1, 2, 3 }; - jsonArray.put(intArray); - writer = new StringWriter(); - output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[[1,2,3]]".equals(output)); - - jsonArray = new JSONArray(); - jsonArray.put(24); - writer = new StringWriter(); - output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[24]".equals(output)); - - jsonArray = new JSONArray(); - jsonArray.put("string value"); - writer = new StringWriter(); - output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[\"string value\"]".equals(output)); - - jsonArray = new JSONArray(); - jsonArray.put(true); - writer = new StringWriter(); - output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[true]".equals(output)); - - } - - /** - * This tests the JSONObject.valueToString() method. These should be - * identical to the values above, except for the enclosing [ and ]. - */ - @Test - public void valuesToString() throws Exception { - - String output = JSONObject.valueToString(null); - assertTrue("String values should be equal", "null".equals(output)); - - output = JSONObject.valueToString(JSONObject.NULL); - assertTrue("String values should be equal", "null".equals(output)); - - output = JSONObject.valueToString(new JSONObject()); - assertTrue("String values should be equal", "{}".equals(output)); - - output = JSONObject.valueToString(new JSONArray()); - assertTrue("String values should be equal", "[]".equals(output)); - - Map singleMap = Collections.singletonMap("key1", "value1"); - output = JSONObject.valueToString(singleMap); - assertTrue("String values should be equal", "{\"key1\":\"value1\"}".equals(output)); - - List singleList = Collections.singletonList("entry1"); - output = JSONObject.valueToString(singleList); - assertTrue("String values should be equal", "[\"entry1\"]".equals(output)); - - int[] intArray = new int[] { 1, 2, 3 }; - output = JSONObject.valueToString(intArray); - assertTrue("String values should be equal", "[1,2,3]".equals(output)); - - output = JSONObject.valueToString(24); - assertTrue("String values should be equal", "24".equals(output)); - - output = JSONObject.valueToString("string value"); - assertTrue("String values should be equal", "\"string value\"".equals(output)); - - output = JSONObject.valueToString(true); - assertTrue("String values should be equal", "true".equals(output)); - - } - - /** - * Test what happens when toJSONString() returns a well-formed JSON value. - * This is the usual case. - */ - @Test - public void testJSONStringValue() throws Exception { - JSONStringValue jsonString = new JSONStringValue(); - JSONArray jsonArray = new JSONArray(); - - jsonArray.put(jsonString); - - StringWriter writer = new StringWriter(); - String output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[\"the JSON string value\"]".equals(output)); - - output = JSONObject.valueToString(jsonString); - assertTrue("String values should be equal", "\"the JSON string value\"".equals(output)); - } - - /** - * Test what happens when toJSONString() returns null. In one case, - * use the object's toString() method. In the other, throw a JSONException. - */ - @Test - public void testJSONNullStringValue() throws Exception { - JSONNullStringValue jsonString = new JSONNullStringValue(); - JSONArray jsonArray = new JSONArray(); - - jsonArray.put(jsonString); - - StringWriter writer = new StringWriter(); - String output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[\"the toString value\"]".equals(output)); - - // The only different between writeValue() and valueToString(): - // in this case, valueToString throws a JSONException - try { - output = JSONObject.valueToString(jsonString); - fail("Expected an exception, got a String value"); - } catch (Exception e) { - assertTrue("Expected JSONException", e instanceof JSONException); - assertTrue("Exception message does not match", "Bad value from toJSONString: null".equals(e.getMessage())); - } - } - - /** - * Test what happens when toJSONString() returns an exception. In both - * cases, a JSONException is thrown, with the cause and message set from - * the original exception. - */ - @Test - public void testJSONStringExceptionValue() throws Exception { - JSONStringExceptionValue jsonString = new JSONStringExceptionValue(); - JSONArray jsonArray = new JSONArray(); - - jsonArray.put(jsonString); - - StringWriter writer = new StringWriter(); - String output = null; - try { - output = jsonArray.write(writer).toString(); - fail("Expected an exception, got a String value"); - } catch (Exception e) { - assertTrue("Expected JSONException", e instanceof JSONException); - assertTrue("Exception message does not match", "the exception value".equals(e.getMessage())); - } - - try { - output = JSONObject.valueToString(jsonString); - fail("Expected an exception, got a String value"); - } catch (Exception e) { - assertTrue("Expected JSONException", e instanceof JSONException); - assertTrue("Exception message does not match", "the exception value".equals(e.getMessage())); - } - } - - /** - * Test what happens when a Java object's toString() returns a String value. - * This is the usual case. - */ - @Test - public void testStringValue() throws Exception { - StringValue nonJsonString = new StringValue(); - JSONArray jsonArray = new JSONArray(); - - jsonArray.put(nonJsonString); - - StringWriter writer = new StringWriter(); - String output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[\"the toString value for StringValue\"]".equals(output)); - - output = JSONObject.valueToString(nonJsonString); - assertTrue("String values should be equal", "\"the toString value for StringValue\"".equals(output)); - } - - /** - * Test what happens when a Java object's toString() returns null. - * Defaults to empty string. - */ - @Test - public void testNullStringValue() throws Exception { - NullStringValue nonJsonString = new NullStringValue(); - JSONArray jsonArray = new JSONArray(); - - jsonArray.put(nonJsonString); - - StringWriter writer = new StringWriter(); - String output = jsonArray.write(writer).toString(); - assertTrue("String values should be equal", "[\"\"]".equals(output)); - - output = JSONObject.valueToString(nonJsonString); - assertTrue("String values should be equal", "\"\"".equals(output)); - } - - /** - * A JSONString that returns a valid JSON string value. - */ - private static final class JSONStringValue implements JSONString { - - @Override - public String toJSONString() { - return "\"the JSON string value\""; - } - - @Override - public String toString() { - return "the toString value for JSONStringValue"; - } - } - - /** - * A JSONString that returns null when calling toJSONString(). - */ - private static final class JSONNullStringValue implements JSONString { - - @Override - public String toJSONString() { - return null; - } - - @Override - public String toString() { - return "the toString value"; - } - } - - /** - * A JSONString that throw an exception when calling toJSONString(). - */ - private static final class JSONStringExceptionValue implements JSONString { - - @Override - public String toJSONString() { - throw new IllegalStateException("the exception value"); - } - - @Override - public String toString() { - return "the toString value for JSONStringExceptionValue"; - } - } - - public static final class StringValue { - - @Override - public String toString() { - return "the toString value for StringValue"; - } - } - - public static final class NullStringValue { - - @Override - public String toString() { - return null; - } - } -} +package org.json.junit; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.*; + +import org.json.*; +import org.junit.Test; + +/** + * Tests for JSONString implementations, and the difference between + * {@link JSONObject#valueToString} and {@link JSONObject#writeValue}. + */ +public class JSONStringTest { + + /** + * This tests the JSONObject.writeValue() method. We can't test directly + * due to it being a package-protected method. Instead, we can call + * JSONArray.write(), which delegates the writing of each entry to + * writeValue(). + */ + @Test + public void writeValues() throws Exception { + JSONArray jsonArray = new JSONArray(); + jsonArray.put((Object)null); + + StringWriter writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[null]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put(JSONObject.NULL); + } finally { + writer.close(); + } + writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[null]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put(new JSONObject()); + } finally { + writer.close(); + } + writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[{}]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put(new JSONArray()); + } finally { + writer.close(); + } + writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[[]]".equals(output)); + + jsonArray = new JSONArray(); + Map singleMap = Collections.singletonMap("key1", "value1"); + jsonArray.put((Object)singleMap); + } finally { + writer.close(); + } + writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[{\"key1\":\"value1\"}]".equals(output)); + + jsonArray = new JSONArray(); + List singleList = Collections.singletonList("entry1"); + jsonArray.put((Object)singleList); + } finally { + writer.close(); + } + writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[[\"entry1\"]]".equals(output)); + + jsonArray = new JSONArray(); + int[] intArray = new int[] { 1, 2, 3 }; + jsonArray.put(intArray); + } finally { + writer.close(); + } + writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[[1,2,3]]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put(24); + } finally { + writer.close(); + } + writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[24]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put("string value"); + } finally { + writer.close(); + } + writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[\"string value\"]".equals(output)); + + jsonArray = new JSONArray(); + jsonArray.put(true); + } finally { + writer.close(); + } + writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[true]".equals(output)); + } finally { + writer.close(); + } + + } + + /** + * This tests the JSONObject.valueToString() method. These should be + * identical to the values above, except for the enclosing [ and ]. + */ + @SuppressWarnings("boxing") + @Test + public void valuesToString() throws Exception { + + String output = JSONObject.valueToString(null); + assertTrue("String values should be equal", "null".equals(output)); + + output = JSONObject.valueToString(JSONObject.NULL); + assertTrue("String values should be equal", "null".equals(output)); + + output = JSONObject.valueToString(new JSONObject()); + assertTrue("String values should be equal", "{}".equals(output)); + + output = JSONObject.valueToString(new JSONArray()); + assertTrue("String values should be equal", "[]".equals(output)); + + Map singleMap = Collections.singletonMap("key1", "value1"); + output = JSONObject.valueToString(singleMap); + assertTrue("String values should be equal", "{\"key1\":\"value1\"}".equals(output)); + + List singleList = Collections.singletonList("entry1"); + output = JSONObject.valueToString(singleList); + assertTrue("String values should be equal", "[\"entry1\"]".equals(output)); + + int[] intArray = new int[] { 1, 2, 3 }; + output = JSONObject.valueToString(intArray); + assertTrue("String values should be equal", "[1,2,3]".equals(output)); + + output = JSONObject.valueToString(24); + assertTrue("String values should be equal", "24".equals(output)); + + output = JSONObject.valueToString("string value"); + assertTrue("String values should be equal", "\"string value\"".equals(output)); + + output = JSONObject.valueToString(true); + assertTrue("String values should be equal", "true".equals(output)); + + } + + /** + * Test what happens when toJSONString() returns a well-formed JSON value. + * This is the usual case. + */ + @Test + public void testJSONStringValue() throws Exception { + JSONStringValue jsonString = new JSONStringValue(); + JSONArray jsonArray = new JSONArray(); + + jsonArray.put(jsonString); + + StringWriter writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[\"the JSON string value\"]".equals(output)); + + output = JSONObject.valueToString(jsonString); + assertTrue("String values should be equal", "\"the JSON string value\"".equals(output)); + } finally { + writer.close(); + } + } + + /** + * Test what happens when toJSONString() returns null. In one case, + * use the object's toString() method. In the other, throw a JSONException. + */ + @Test + public void testJSONNullStringValue() throws Exception { + JSONNullStringValue jsonString = new JSONNullStringValue(); + JSONArray jsonArray = new JSONArray(); + + jsonArray.put(jsonString); + + StringWriter writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[\"the toString value\"]".equals(output)); + + // The only different between writeValue() and valueToString(): + // in this case, valueToString throws a JSONException + try { + output = JSONObject.valueToString(jsonString); + fail("Expected an exception, got a String value"); + } catch (Exception e) { + assertTrue("Expected JSONException", e instanceof JSONException); + assertTrue("Exception message does not match", "Bad value from toJSONString: null".equals(e.getMessage())); + } + } finally { + writer.close(); + } + } + + /** + * Test what happens when toJSONString() returns an exception. In both + * cases, a JSONException is thrown, with the cause and message set from + * the original exception. + */ + @Test + public void testJSONStringExceptionValue() throws IOException { + JSONStringExceptionValue jsonString = new JSONStringExceptionValue(); + JSONArray jsonArray = new JSONArray(); + + jsonArray.put(jsonString); + + StringWriter writer = new StringWriter(); + try { + jsonArray.write(writer).toString(); + fail("Expected an exception, got a String value"); + } catch (JSONException e) { + assertTrue("Exception message does not match", "the exception value".equals(e.getMessage())); + } catch(Exception e) { + fail("Expected JSONException"); + } finally { + writer.close(); + } + + try { + JSONObject.valueToString(jsonString); + fail("Expected an exception, got a String value"); + } catch (JSONException e) { + assertTrue("Exception message does not match", "the exception value".equals(e.getMessage())); + } catch(Exception e) { + fail("Expected JSONException"); + } + } + + /** + * Test what happens when a Java object's toString() returns a String value. + * This is the usual case. + */ + @Test + public void testStringValue() throws Exception { + StringValue nonJsonString = new StringValue(); + JSONArray jsonArray = new JSONArray(); + + jsonArray.put(nonJsonString); + + StringWriter writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[\"the toString value for StringValue\"]".equals(output)); + + output = JSONObject.valueToString(nonJsonString); + assertTrue("String values should be equal", "\"the toString value for StringValue\"".equals(output)); + } finally { + writer.close(); + } + } + + /** + * Test what happens when a Java object's toString() returns null. + * Defaults to empty string. + */ + @Test + public void testNullStringValue() throws Exception { + NullStringValue nonJsonString = new NullStringValue(); + JSONArray jsonArray = new JSONArray(); + + jsonArray.put(nonJsonString); + + StringWriter writer = new StringWriter(); + try { + String output = jsonArray.write(writer).toString(); + assertTrue("String values should be equal", "[\"\"]".equals(output)); + + output = JSONObject.valueToString(nonJsonString); + assertTrue("String values should be equal", "\"\"".equals(output)); + } finally { + writer.close(); + } + } + + /** + * A JSONString that returns a valid JSON string value. + */ + private static final class JSONStringValue implements JSONString { + + @Override + public String toJSONString() { + return "\"the JSON string value\""; + } + + @Override + public String toString() { + return "the toString value for JSONStringValue"; + } + } + + /** + * A JSONString that returns null when calling toJSONString(). + */ + private static final class JSONNullStringValue implements JSONString { + + @Override + public String toJSONString() { + return null; + } + + @Override + public String toString() { + return "the toString value"; + } + } + + /** + * A JSONString that throw an exception when calling toJSONString(). + */ + private static final class JSONStringExceptionValue implements JSONString { + + @Override + public String toJSONString() { + throw new IllegalStateException("the exception value"); + } + + @Override + public String toString() { + return "the toString value for JSONStringExceptionValue"; + } + } + + public static final class StringValue { + + @Override + public String toString() { + return "the toString value for StringValue"; + } + } + + public static final class NullStringValue { + + @Override + public String toString() { + return null; + } + } +} diff --git a/src/test/java/org/json/junit/MyEnumField.java b/src/test/java/org/json/junit/MyEnumField.java index 8f2c633..f0833ef 100644 --- a/src/test/java/org/json/junit/MyEnumField.java +++ b/src/test/java/org/json/junit/MyEnumField.java @@ -3,6 +3,7 @@ /** * An enum that contains getters and some internal fields */ +@SuppressWarnings("boxing") public enum MyEnumField { VAL1(1, "val 1"), VAL2(2, "val 2"), @@ -15,12 +16,13 @@ private MyEnumField(Integer intVal, String value) { this.intVal = intVal; } public String getValue() { - return value; + return this.value; } public Integer getIntVal() { - return intVal; + return this.intVal; } + @Override public String toString(){ - return value; + return this.value; } } diff --git a/src/test/java/org/json/junit/MyPublicClass.java b/src/test/java/org/json/junit/MyPublicClass.java index 1f55e3e..e483d4c 100644 --- a/src/test/java/org/json/junit/MyPublicClass.java +++ b/src/test/java/org/json/junit/MyPublicClass.java @@ -3,6 +3,7 @@ /** * Need a class with some public data members for testing */ +@SuppressWarnings("boxing") public class MyPublicClass { public Integer publicInt = 42; public String publicString = "abc"; diff --git a/src/test/java/org/json/junit/StringsResourceBundle.java b/src/test/java/org/json/junit/StringsResourceBundle.java index 83d9322..d04aeaf 100644 --- a/src/test/java/org/json/junit/StringsResourceBundle.java +++ b/src/test/java/org/json/junit/StringsResourceBundle.java @@ -6,6 +6,7 @@ * A resource bundle class */ public class StringsResourceBundle extends ListResourceBundle { + @Override public Object[][] getContents() { return contents; } diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 2f3fea7..dd827bd 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -4,11 +4,8 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; -import java.io.IOException; - import org.json.JSONArray; import org.json.JSONException; -import org.json.JSONML; import org.json.JSONObject; import org.json.XML; import org.junit.Rule; From 95da4246a279d19db770f27dbb8e3d7eb5befdce Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 27 Apr 2017 12:48:43 -0400 Subject: [PATCH 37/99] fix spelling in comment --- src/test/java/org/json/junit/JSONMLTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index 1ad2cb4..df5244d 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -782,7 +782,7 @@ public void testAttributeConversionReversabilityHTML() { // this test does not pass for the following reasons: // 1. Our XML parser does not handle generic HTML entities, only valid XML entities. Hence   -// or other HTML specific entites would fail on reversability +// or other HTML specific entities would fail on reversability // 2. Our JSON implementation for storing the XML attributes uses the standard unordered map. // This means that can not be reversed reliably. // /** From c233ae709e6d4c6da2296fc366e37de290935090 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 27 Apr 2017 12:52:02 -0400 Subject: [PATCH 38/99] comment out second unreliable test --- src/test/java/org/json/junit/JSONMLTest.java | 43 ++++++++++---------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index df5244d..8ece8e5 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -762,29 +762,30 @@ public void testToJSONObject_reversibility() { assertEquals("original JSON does not equal the new JSON",originalJson, newJson); } - /** - * Test texts taken from jsonml.org. Currently our implementation FAILS this conversion but shouldn't. - * Technically JsonML should be able to transform any valid xhtml document, but ours only supports - * standard XML entities, not HTML entities. - */ - @Test - public void testAttributeConversionReversabilityHTML() { - final String originalXml = "
#5D28D1Example text here
#AF44EF127310656
#AAD034 © 
"; - final String expectedJsonString = "[\"table\",{\"class\" : \"MyTable\",\"style\" : \"background-color:yellow\"},[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#550758\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:red\"},\"Example text here\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#993101\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:green\"},\"127624015\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#E33D87\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:blue\"},\"\u00A0\",[\"span\",{ \"style\" : \"background-color:maroon\" },\"\u00A9\"],\"\u00A0\"]]]"; - final JSONArray json = JSONML.toJSONArray(originalXml,true); - final String actualJsonString = json.toString(); - - final String reverseXml = JSONML.toString(json); - assertNotEquals(originalXml, reverseXml); - - assertNotEquals(expectedJsonString, actualJsonString); - } - -// this test does not pass for the following reasons: +// these tests do not pass for the following reasons: // 1. Our XML parser does not handle generic HTML entities, only valid XML entities. Hence   -// or other HTML specific entities would fail on reversability +// or other HTML specific entities would fail on reversability // 2. Our JSON implementation for storing the XML attributes uses the standard unordered map. -// This means that can not be reversed reliably. +// This means that can not be reversed reliably. +// +// /** +// * Test texts taken from jsonml.org. Currently our implementation FAILS this conversion but shouldn't. +// * Technically JsonML should be able to transform any valid xhtml document, but ours only supports +// * standard XML entities, not HTML entities. +// */ +// @Test +// public void testAttributeConversionReversabilityHTML() { +// final String originalXml = "
#5D28D1Example text here
#AF44EF127310656
#AAD034 © 
"; +// final String expectedJsonString = "[\"table\",{\"class\" : \"MyTable\",\"style\" : \"background-color:yellow\"},[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#550758\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:red\"},\"Example text here\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#993101\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:green\"},\"127624015\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#E33D87\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:blue\"},\"\u00A0\",[\"span\",{ \"style\" : \"background-color:maroon\" },\"\u00A9\"],\"\u00A0\"]]]"; +// final JSONArray json = JSONML.toJSONArray(originalXml,true); +// final String actualJsonString = json.toString(); +// +// final String reverseXml = JSONML.toString(json); +// assertNotEquals(originalXml, reverseXml); +// +// assertNotEquals(expectedJsonString, actualJsonString); +// } +// // /** // * Test texts taken from jsonml.org but modified to have XML entities only. // */ From 1d040ec407bd5d6e2b8339af0769ad1047415ad8 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Tue, 16 May 2017 18:16:07 -0400 Subject: [PATCH 39/99] fixes errors with tests relating to https://github.com/stleary/JSON-java/pull/336 --- src/test/java/org/json/junit/JSONObjectTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index fb32cda..4af66bf 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1276,7 +1276,7 @@ public void jsonObjectIncrement() { * JSONObject constructor won't handle these types correctly, but * adding them via put works. */ - jsonObject.put("keyFloat", new Float(1.1)); + jsonObject.put("keyFloat", 1.1f); jsonObject.put("keyBigInt", new BigInteger("123456789123456789123456789123456780")); jsonObject.put("keyBigDec", new BigDecimal("123456789123456789123456789123456780.1")); jsonObject.increment("keyFloat"); @@ -1316,7 +1316,7 @@ public void jsonObjectIncrement() { * missing bits would not fit into the 32 bit float, i.e. the * information needed simply is not there! */ - assertTrue("expected 3.0999999046325684", Double.valueOf(3.0999999046325684).equals(jsonObject.query("/keyFloat"))); + assertEquals(Float.valueOf(3.1f), jsonObject.query("/keyFloat")); /** * float f = 3.1f; double df = (double) f; double d = 3.1d; @@ -1364,7 +1364,7 @@ public void jsonObjectIncrement() { // 3. A float+float operation will be performed and results into a float primitive. // 4. There is no method that matches the signature put( String key, float value), java-compiler will choose the method // put( String key, double value) and does an implicit type-cast(!) by appending zero-bits to the mantissa - assertTrue( "JSONObject increment converts Float to Double", jo.get( "bug" ) instanceof Double ); + assertTrue( "JSONObject increment converts Float to Double", jo.get( "bug" ) instanceof Float ); // correct implementation (with change of behavior) would be: // this.put(key, new Float((Float) value + 1)); // Probably it would be better to deprecate the method and remove some day, while convenient processing the "payload" is not From 49d47e3ff281a5fecc9889e2d8d37ca76e355cbd Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Tue, 16 May 2017 19:42:46 -0400 Subject: [PATCH 40/99] Adjustments to tests for https://github.com/stleary/JSON-java/pull/337/ --- src/test/java/org/json/junit/JSONObjectTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index fb32cda..f6a562d 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1001,7 +1001,8 @@ public void bigNumberOperations() { assertTrue("expected an exeption", false); } catch (JSONException ignored) {} obj = jsonObject.optBigInteger("bigDec", BigInteger.ONE); - assertTrue("expected BigInteger", obj.equals(BigInteger.ONE)); + assertTrue("expected BigInteger", obj instanceof BigInteger); + assertEquals(bigDecimal.toBigInteger(), obj); /** * JSONObject.numberToString() works correctly, nothing to change. From 2867aaa8c8c219b2eddb755df4dfda667f955f4b Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 17 May 2017 12:33:59 -0400 Subject: [PATCH 41/99] Updates test cases to support new optFloat and optNumber --- .../java/org/json/junit/JSONArrayTest.java | 14 +++++++ .../java/org/json/junit/JSONObjectTest.java | 40 +++++++++++++++---- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 80b78a5..666c03b 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -393,6 +393,20 @@ public void opt() { assertTrue("Array opt double default implicit", new Double(jsonArray.optDouble(99)).isNaN()); + assertTrue("Array opt float", + new Float(23.45e-4).equals(jsonArray.optFloat(5))); + assertTrue("Array opt float default", + new Float(1).equals(jsonArray.optFloat(0, 1))); + assertTrue("Array opt float default implicit", + new Float(jsonArray.optFloat(99)).isNaN()); + + assertTrue("Array opt Number", + new Double(23.45e-4).equals(jsonArray.optNumber(5))); + assertTrue("Array opt Number default", + new Double(1).equals(jsonArray.optNumber(0, 1d))); + assertTrue("Array opt Number default implicit", + new Double(jsonArray.optNumber(99,Double.NaN).doubleValue()).isNaN()); + assertTrue("Array opt int", new Integer(42).equals(jsonArray.optInt(7))); assertTrue("Array opt int default", diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index f6a562d..2718edf 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -614,6 +614,10 @@ public void jsonObjectValues() { jsonObject.optDouble("doubleKey") == -23.45e7); assertTrue("opt doubleKey with Default should be double", jsonObject.optDouble("doubleStrKey", Double.NaN) == 1); + assertTrue("optFloat doubleKey should be float", + jsonObject.optFloat("doubleKey") == -23.45e7f); + assertTrue("optFloat doubleKey with Default should be float", + jsonObject.optFloat("doubleStrKey", Float.NaN) == 1f); assertTrue("intKey should be int", jsonObject.optInt("intKey") == 42); assertTrue("opt intKey should be int", @@ -630,6 +634,18 @@ public void jsonObjectValues() { jsonObject.optLong("longKey", 0) == 1234567890123456789L); assertTrue("longStrKey should be long", jsonObject.getLong("longStrKey") == 987654321098765432L); + assertTrue("optNumber int should return Integer", + jsonObject.optNumber("intKey") instanceof Integer); + assertTrue("optNumber long should return Long", + jsonObject.optNumber("longKey") instanceof Long); + assertTrue("optNumber double should return Double", + jsonObject.optNumber("doubleKey") instanceof Double); + assertTrue("optNumber Str int should return BigDecimal", + jsonObject.optNumber("intStrKey") instanceof BigDecimal); + assertTrue("optNumber Str long should return BigDecimal", + jsonObject.optNumber("longStrKey") instanceof BigDecimal); + assertTrue("optNumber Str double should return BigDecimal", + jsonObject.optNumber("doubleStrKey") instanceof BigDecimal); assertTrue("xKey should not exist", jsonObject.isNull("xKey")); assertTrue("stringKey should exist", @@ -1937,9 +1953,13 @@ public void jsonObjectOptDefault() { assertTrue("optJSONObject() should return null ", null==jsonObject.optJSONObject("myKey")); assertTrue("optLong() should return default long", - 42 == jsonObject.optLong("myKey", 42)); + 42l == jsonObject.optLong("myKey", 42l)); assertTrue("optDouble() should return default double", - 42.3 == jsonObject.optDouble("myKey", 42.3)); + 42.3d == jsonObject.optDouble("myKey", 42.3d)); + assertTrue("optFloat() should return default float", + 42.3f == jsonObject.optFloat("myKey", 42.3f)); + assertTrue("optNumber() should return default Number", + 42l == jsonObject.optNumber("myKey", Long.valueOf(42)).longValue()); assertTrue("optString() should return default string", "hi".equals(jsonObject.optString("hiKey", "hi"))); } @@ -1967,9 +1987,13 @@ public void jsonObjectOptNoKey() { assertTrue("optJSONObject() should return null ", null==jsonObject.optJSONObject("myKey")); assertTrue("optLong() should return default long", - 42 == jsonObject.optLong("myKey", 42)); + 42l == jsonObject.optLong("myKey", 42l)); assertTrue("optDouble() should return default double", - 42.3 == jsonObject.optDouble("myKey", 42.3)); + 42.3d == jsonObject.optDouble("myKey", 42.3d)); + assertTrue("optFloat() should return default float", + 42.3f == jsonObject.optFloat("myKey", 42.3f)); + assertTrue("optNumber() should return default Number", + 42l == jsonObject.optNumber("myKey", Long.valueOf(42)).longValue()); assertTrue("optString() should return default string", "hi".equals(jsonObject.optString("hiKey", "hi"))); } @@ -1983,11 +2007,13 @@ public void jsonObjectOptStringConversion() { assertTrue("unexpected optBoolean value",jo.optBoolean("true",false)==true); assertTrue("unexpected optBoolean value",jo.optBoolean("false",true)==false); assertTrue("unexpected optInt value",jo.optInt("int",0)==123); - assertTrue("unexpected optLong value",jo.optLong("int",0)==123); - assertTrue("unexpected optDouble value",jo.optDouble("int",0.0)==123.0); + assertTrue("unexpected optLong value",jo.optLong("int",0)==123l); + assertTrue("unexpected optDouble value",jo.optDouble("int",0.0d)==123.0d); + assertTrue("unexpected optFloat value",jo.optFloat("int",0.0f)==123.0f); assertTrue("unexpected optBigInteger value",jo.optBigInteger("int",BigInteger.ZERO).compareTo(new BigInteger("123"))==0); assertTrue("unexpected optBigDecimal value",jo.optBigDecimal("int",BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); - + assertTrue("unexpected optBigDecimal value",jo.optBigDecimal("int",BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); + assertTrue("unexpected optNumber value",jo.optNumber("int",BigInteger.ZERO).longValue()==123l); } /** From bdb11634459de86e67390a3519770c814c23631b Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 18 May 2017 11:38:42 -0400 Subject: [PATCH 42/99] Adds conversion tests to ensure downward type coercions are handled sanely --- src/test/java/org/json/junit/JSONObjectTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 2718edf..13e4f5f 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -2003,7 +2003,7 @@ public void jsonObjectOptNoKey() { */ @Test public void jsonObjectOptStringConversion() { - JSONObject jo = new JSONObject("{\"int\":\"123\",\"true\":\"true\",\"false\":\"false\"}"); + JSONObject jo = new JSONObject("{\"int\":\"123\",\"true\":\"true\",\"false\":\"false\",\"largeNumber\":\"19007199254740993.35481234487103587486413587843213584\"}"); assertTrue("unexpected optBoolean value",jo.optBoolean("true",false)==true); assertTrue("unexpected optBoolean value",jo.optBoolean("false",true)==false); assertTrue("unexpected optInt value",jo.optInt("int",0)==123); @@ -2014,6 +2014,15 @@ public void jsonObjectOptStringConversion() { assertTrue("unexpected optBigDecimal value",jo.optBigDecimal("int",BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); assertTrue("unexpected optBigDecimal value",jo.optBigDecimal("int",BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); assertTrue("unexpected optNumber value",jo.optNumber("int",BigInteger.ZERO).longValue()==123l); + + // Test type coercion from larger to smaller + final BigDecimal largeValue = new BigDecimal("19007199254740993.35481234487103587486413587843213584"); + assertEquals(largeValue,jo.optBigDecimal("largeNumber", null)); + assertEquals(largeValue.toBigInteger(),jo.optBigInteger("largeNumber", null)); + assertEquals(largeValue.doubleValue(), jo.optDouble("largeNumber"), 0.0d); + assertEquals(largeValue.floatValue(), jo.optFloat("largeNumber"), 0.0f); + assertEquals(largeValue.longValue(), jo.optLong("largeNumber")); + assertEquals(largeValue.intValue(), jo.optInt("largeNumber")); } /** From 0150639119b76c2fc2b44d2be5ffa64976286262 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 18 May 2017 11:58:28 -0400 Subject: [PATCH 43/99] update the new coercion test to use actual values and show the parseDouble method is not robust enough for large numbers --- src/test/java/org/json/junit/JSONObjectTest.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 13e4f5f..83e0276 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -2,6 +2,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; @@ -2016,13 +2017,14 @@ public void jsonObjectOptStringConversion() { assertTrue("unexpected optNumber value",jo.optNumber("int",BigInteger.ZERO).longValue()==123l); // Test type coercion from larger to smaller - final BigDecimal largeValue = new BigDecimal("19007199254740993.35481234487103587486413587843213584"); - assertEquals(largeValue,jo.optBigDecimal("largeNumber", null)); - assertEquals(largeValue.toBigInteger(),jo.optBigInteger("largeNumber", null)); - assertEquals(largeValue.doubleValue(), jo.optDouble("largeNumber"), 0.0d); - assertEquals(largeValue.floatValue(), jo.optFloat("largeNumber"), 0.0f); - assertEquals(largeValue.longValue(), jo.optLong("largeNumber")); - assertEquals(largeValue.intValue(), jo.optInt("largeNumber")); + assertEquals(new BigInteger("19007199254740993"), jo.optBigInteger("largeNumber",null)); + assertEquals(1.9007199254740992E16, jo.optDouble("largeNumber"),0.0); + assertEquals(1.90071995E16f, jo.optFloat("largeNumber"),0.0f); + assertEquals(19007199254740993l, jo.optLong("largeNumber")); + assertEquals(1874919425, jo.optInt("largeNumber")); + + // the integer portion of the actual value is larger than a double can hold. + assertNotEquals((long)Double.parseDouble("19007199254740993.35481234487103587486413587843213584"), jo.optLong("largeNumber")); } /** From 1967bee23690ee48a8b8d2f2dccdff52cb771308 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 18 May 2017 12:11:43 -0400 Subject: [PATCH 44/99] expands the coercion tests a little more --- src/test/java/org/json/junit/JSONObjectTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 83e0276..1417e6b 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -2025,6 +2025,9 @@ public void jsonObjectOptStringConversion() { // the integer portion of the actual value is larger than a double can hold. assertNotEquals((long)Double.parseDouble("19007199254740993.35481234487103587486413587843213584"), jo.optLong("largeNumber")); + assertNotEquals((int)Double.parseDouble("19007199254740993.35481234487103587486413587843213584"), jo.optInt("largeNumber")); + assertEquals(19007199254740992l, (long)Double.parseDouble("19007199254740993.35481234487103587486413587843213584")); + assertEquals(2147483647, (int)Double.parseDouble("19007199254740993.35481234487103587486413587843213584")); } /** From cfe6851d8c9c1ff70eb7d3c98d5ffe94a40d2a11 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 18 May 2017 14:25:42 -0400 Subject: [PATCH 45/99] Adds testing for -0 with optNumber --- .../java/org/json/junit/JSONObjectTest.java | 110 ++++++++++++------ 1 file changed, 74 insertions(+), 36 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 1417e6b..1f7a5c9 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -5,6 +5,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -514,7 +515,7 @@ public void jsonObjectAccumulate() { // include an unsupported object for coverage try { jsonObject.accumulate("myArray", Double.NaN); - assertTrue("Expected exception", false); + fail("Expected exception"); } catch (JSONException ignored) {} // validate JSON @@ -545,7 +546,7 @@ public void jsonObjectAppend() { // include an unsupported object for coverage try { jsonObject.append("myArray", Double.NaN); - assertTrue("Expected exception", false); + fail("Expected exception"); } catch (JSONException ignored) {} // validate JSON @@ -595,6 +596,9 @@ public void jsonObjectValues() { "\"longStrKey\":\"987654321098765432\","+ "\"doubleKey\":-23.45e7,"+ "\"doubleStrKey\":\"00001.000\","+ + "\"BigDecimalStrKey\":\"19007199254740993.35481234487103587486413587843213584\","+ + "\"negZeroKey\":-0.0,"+ + "\"negZeroStrKey\":\"-0.0\","+ "\"arrayKey\":[0,1,2],"+ "\"objectKey\":{\"myKey\":\"myVal\"}"+ "}"; @@ -611,10 +615,26 @@ public void jsonObjectValues() { jsonObject.getDouble("doubleKey") == -23.45e7); assertTrue("doubleStrKey should be double", jsonObject.getDouble("doubleStrKey") == 1); + assertTrue("doubleKey can be float", + jsonObject.getFloat("doubleKey") == -23.45e7f); + assertTrue("doubleStrKey can be float", + jsonObject.getFloat("doubleStrKey") == 1f); assertTrue("opt doubleKey should be double", jsonObject.optDouble("doubleKey") == -23.45e7); assertTrue("opt doubleKey with Default should be double", jsonObject.optDouble("doubleStrKey", Double.NaN) == 1); + assertTrue("opt negZeroKey should be double", + Double.compare(jsonObject.optDouble("negZeroKey"), -0.0d) == 0); + assertTrue("opt negZeroStrKey with Default should be double", + Double.compare(jsonObject.optDouble("negZeroStrKey"), -0.0d) == 0); + assertTrue("optNumber negZeroKey should return Double", + jsonObject.optNumber("negZeroKey") instanceof Double); + assertTrue("optNumber negZeroStrKey should return Double", + jsonObject.optNumber("negZeroStrKey") instanceof Double); + assertTrue("optNumber negZeroKey should be -0.0", + Double.compare(jsonObject.optNumber("negZeroKey").doubleValue(), -0.0d) == 0); + assertTrue("optNumber negZeroStrKey should be -0.0", + Double.compare(jsonObject.optNumber("negZeroStrKey").doubleValue(), -0.0d) == 0); assertTrue("optFloat doubleKey should be float", jsonObject.optFloat("doubleKey") == -23.45e7f); assertTrue("optFloat doubleKey with Default should be float", @@ -641,12 +661,14 @@ public void jsonObjectValues() { jsonObject.optNumber("longKey") instanceof Long); assertTrue("optNumber double should return Double", jsonObject.optNumber("doubleKey") instanceof Double); - assertTrue("optNumber Str int should return BigDecimal", - jsonObject.optNumber("intStrKey") instanceof BigDecimal); - assertTrue("optNumber Str long should return BigDecimal", - jsonObject.optNumber("longStrKey") instanceof BigDecimal); - assertTrue("optNumber Str double should return BigDecimal", - jsonObject.optNumber("doubleStrKey") instanceof BigDecimal); + assertTrue("optNumber Str int should return Integer", + jsonObject.optNumber("intStrKey") instanceof Integer); + assertTrue("optNumber Str long should return Long", + jsonObject.optNumber("longStrKey") instanceof Long); + assertTrue("optNumber Str double should return Double", + jsonObject.optNumber("doubleStrKey") instanceof Double); + assertTrue("optNumber BigDecimalStrKey should return BigDecimal", + jsonObject.optNumber("BigDecimalStrKey") instanceof BigDecimal); assertTrue("xKey should not exist", jsonObject.isNull("xKey")); assertTrue("stringKey should exist", @@ -804,14 +826,14 @@ public void jsonObjectNonAndWrongValues() { JSONObject jsonObject = new JSONObject(str); try { jsonObject.getBoolean("nonKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("expecting an exception message", "JSONObject[\"nonKey\"] not found.".equals(e.getMessage())); } try { jsonObject.getBoolean("stringKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"stringKey\"] is not a Boolean.". @@ -819,7 +841,7 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getString("nonKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"nonKey\"] not found.". @@ -827,7 +849,7 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getString("trueKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"trueKey\"] not a string.". @@ -835,7 +857,7 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getDouble("nonKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"nonKey\"] not found.". @@ -843,7 +865,23 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getDouble("stringKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a number.". + equals(e.getMessage())); + } + try { + jsonObject.getFloat("nonKey"); + fail("Expected an exception"); + } catch (JSONException e) { + assertTrue("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.". + equals(e.getMessage())); + } + try { + jsonObject.getFloat("stringKey"); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"stringKey\"] is not a number.". @@ -851,7 +889,7 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getInt("nonKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"nonKey\"] not found.". @@ -859,7 +897,7 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getInt("stringKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"stringKey\"] is not an int.". @@ -867,7 +905,7 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getLong("nonKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"nonKey\"] not found.". @@ -875,7 +913,7 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getLong("stringKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"stringKey\"] is not a long.". @@ -883,7 +921,7 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getJSONArray("nonKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"nonKey\"] not found.". @@ -891,7 +929,7 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getJSONArray("stringKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"stringKey\"] is not a JSONArray.". @@ -899,7 +937,7 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getJSONObject("nonKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"nonKey\"] not found.". @@ -907,7 +945,7 @@ public void jsonObjectNonAndWrongValues() { } try { jsonObject.getJSONObject("stringKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[\"stringKey\"] is not a JSONObject.". @@ -1004,18 +1042,18 @@ public void bigNumberOperations() { */ try { jsonObject.getBigDecimal("bigInt"); - assertTrue("expected an exeption", false); + fail("expected an exeption"); } catch (JSONException ignored) {} obj = jsonObject.optBigDecimal("bigInt", BigDecimal.ONE); assertTrue("expected BigDecimal", obj.equals(BigDecimal.ONE)); try { jsonObject.getBigInteger("bigDec"); - assertTrue("expected an exeption", false); + fail("expected an exeption"); } catch (JSONException ignored) {} jsonObject.put("stringKey", "abc"); try { jsonObject.getBigDecimal("stringKey"); - assertTrue("expected an exeption", false); + fail("expected an exeption"); } catch (JSONException ignored) {} obj = jsonObject.optBigInteger("bigDec", BigInteger.ONE); assertTrue("expected BigInteger", obj instanceof BigInteger); @@ -1092,11 +1130,11 @@ public void bigNumberOperations() { jsonArray.put(Boolean.TRUE); try { jsonArray.getBigInteger(2); - assertTrue("should not be able to get big int", false); + fail("should not be able to get big int"); } catch (Exception ignored) {} try { jsonArray.getBigDecimal(2); - assertTrue("should not be able to get big dec", false); + fail("should not be able to get big dec"); } catch (Exception ignored) {} assertTrue("optBigInt is default", jsonArray.optBigInteger(2, BigInteger.ONE).equals(BigInteger.ONE)); assertTrue("optBigDec is default", jsonArray.optBigDecimal(2, BigDecimal.ONE).equals(BigDecimal.ONE)); @@ -1851,7 +1889,7 @@ public void jsonObjectParsingErrors() { String str = "{\"myKey\":true, \"myOtherKey\":false}"; JSONObject jsonObject = new JSONObject(str); jsonObject.append("myKey", "hello"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "JSONObject[myKey] is not a JSONArray.". @@ -1862,7 +1900,7 @@ public void jsonObjectParsingErrors() { String str = "{\"myKey\":true, \"myOtherKey\":false}"; JSONObject jsonObject = new JSONObject(str); jsonObject.increment("myKey"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "Unable to increment [\"myKey\"].". @@ -1873,7 +1911,7 @@ public void jsonObjectParsingErrors() { String str = "{\"myKey\":true, \"myOtherKey\":false}"; JSONObject jsonObject = new JSONObject(str); jsonObject.get(null); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "Null key.". @@ -1882,7 +1920,7 @@ public void jsonObjectParsingErrors() { try { // invalid numberToString() JSONObject.numberToString((Number)null); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("Expecting an exception message", "Null pointer". @@ -1892,7 +1930,7 @@ public void jsonObjectParsingErrors() { // null put key JSONObject jsonObject = new JSONObject("{}"); jsonObject.put(null, 0); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (NullPointerException ignored) { } try { @@ -1900,21 +1938,21 @@ public void jsonObjectParsingErrors() { JSONObject jsonObject = new JSONObject("{}"); jsonObject.putOnce("hello", "world"); jsonObject.putOnce("hello", "world!"); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("", true); } try { // test validity of invalid double JSONObject.testValidity(Double.NaN); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("", true); } try { // test validity of invalid float JSONObject.testValidity(Float.NEGATIVE_INFINITY); - assertTrue("Expected an exception", false); + fail("Expected an exception"); } catch (JSONException e) { assertTrue("", true); } @@ -2294,7 +2332,7 @@ public void jsonObjectNullOperations() { // assertTrue("should convert null to empty string", "".equals(string)); try { value = jsonObjectNull.get("key"); - assertTrue("get() null should throw exception", false); + fail("get() null should throw exception"); } catch (Exception ignored) {} /** From 04d76b638beada214229666d10ee24ecd3670268 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Fri, 19 May 2017 15:01:37 -0400 Subject: [PATCH 46/99] split out tests for better readability --- .../java/org/json/junit/JSONObjectTest.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 1f7a5c9..c1ea5a1 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -708,7 +708,7 @@ public void stringToValueNumbersTest() { * This test documents a need for BigDecimal conversion. */ Object obj = JSONObject.stringToValue( "299792.457999999984" ); - assertTrue( "evaluates to 299792.458 doubld instead of 299792.457999999984 BigDecimal!", + assertTrue( "evaluates to 299792.458 double instead of 299792.457999999984 BigDecimal!", obj.equals(new Double(299792.458)) ); assertTrue( "1 should be an Integer!", JSONObject.stringToValue( "1" ) instanceof Integer ); @@ -2042,7 +2042,7 @@ public void jsonObjectOptNoKey() { */ @Test public void jsonObjectOptStringConversion() { - JSONObject jo = new JSONObject("{\"int\":\"123\",\"true\":\"true\",\"false\":\"false\",\"largeNumber\":\"19007199254740993.35481234487103587486413587843213584\"}"); + JSONObject jo = new JSONObject("{\"int\":\"123\",\"true\":\"true\",\"false\":\"false\"}"); assertTrue("unexpected optBoolean value",jo.optBoolean("true",false)==true); assertTrue("unexpected optBoolean value",jo.optBoolean("false",true)==false); assertTrue("unexpected optInt value",jo.optInt("int",0)==123); @@ -2053,17 +2053,38 @@ public void jsonObjectOptStringConversion() { assertTrue("unexpected optBigDecimal value",jo.optBigDecimal("int",BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); assertTrue("unexpected optBigDecimal value",jo.optBigDecimal("int",BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); assertTrue("unexpected optNumber value",jo.optNumber("int",BigInteger.ZERO).longValue()==123l); + } + + /** + * Verifies that the opt methods properly convert string values to numbers and coerce them consistently. + */ + @Test + public void jsonObjectOptCoercion() { + JSONObject jo = new JSONObject("{\"largeNumberStr\":\"19007199254740993.35481234487103587486413587843213584\"}"); + // currently the parser doesn't recognize BigDecimal, to we have to put it manually + jo.put("largeNumber", new BigDecimal("19007199254740993.35481234487103587486413587843213584")); // Test type coercion from larger to smaller + assertEquals(new BigDecimal("19007199254740993.35481234487103587486413587843213584"), jo.optBigDecimal("largeNumber",null)); assertEquals(new BigInteger("19007199254740993"), jo.optBigInteger("largeNumber",null)); assertEquals(1.9007199254740992E16, jo.optDouble("largeNumber"),0.0); assertEquals(1.90071995E16f, jo.optFloat("largeNumber"),0.0f); assertEquals(19007199254740993l, jo.optLong("largeNumber")); assertEquals(1874919425, jo.optInt("largeNumber")); - + + // conversion from a string + assertEquals(new BigDecimal("19007199254740993.35481234487103587486413587843213584"), jo.optBigDecimal("largeNumberStr",null)); + assertEquals(new BigInteger("19007199254740993"), jo.optBigInteger("largeNumberStr",null)); + assertEquals(1.9007199254740992E16, jo.optDouble("largeNumberStr"),0.0); + assertEquals(1.90071995E16f, jo.optFloat("largeNumberStr"),0.0f); + assertEquals(19007199254740993l, jo.optLong("largeNumberStr")); + assertEquals(1874919425, jo.optInt("largeNumberStr")); + // the integer portion of the actual value is larger than a double can hold. assertNotEquals((long)Double.parseDouble("19007199254740993.35481234487103587486413587843213584"), jo.optLong("largeNumber")); assertNotEquals((int)Double.parseDouble("19007199254740993.35481234487103587486413587843213584"), jo.optInt("largeNumber")); + assertNotEquals((long)Double.parseDouble("19007199254740993.35481234487103587486413587843213584"), jo.optLong("largeNumberStr")); + assertNotEquals((int)Double.parseDouble("19007199254740993.35481234487103587486413587843213584"), jo.optInt("largeNumberStr")); assertEquals(19007199254740992l, (long)Double.parseDouble("19007199254740993.35481234487103587486413587843213584")); assertEquals(2147483647, (int)Double.parseDouble("19007199254740993.35481234487103587486413587843213584")); } From c5e4b91fa410687205205032a9b903824790f733 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Thu, 8 Jun 2017 02:25:59 -0400 Subject: [PATCH 47/99] Updates tests for better error handling changes --- src/test/java/org/json/junit/EnumTest.java | 14 +- .../java/org/json/junit/JSONObjectTest.java | 124 +++++++++++++++++- .../java/org/json/junit/JSONStringTest.java | 2 +- 3 files changed, 134 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/json/junit/EnumTest.java b/src/test/java/org/json/junit/EnumTest.java index 6b97107..53ac303 100644 --- a/src/test/java/org/json/junit/EnumTest.java +++ b/src/test/java/org/json/junit/EnumTest.java @@ -1,5 +1,7 @@ package org.json.junit; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.EnumSet; @@ -325,6 +327,7 @@ public void enumAPI() { JSONObject jsonObject = new JSONObject(); jsonObject.put("strKey", "value"); + jsonObject.put("strKey2", "VAL1"); jsonObject.put("enumKey", myEnumField); jsonObject.put("enumClassKey", myEnumClass); @@ -360,11 +363,18 @@ public void enumAPI() { // opt with default the wrong value actualEnum = jsonObject.optEnum(MyEnumField.class, "strKey", null); - assertTrue("opt null", actualEnum == null); + assertNull("opt null", actualEnum); + + // opt with default the string value + actualEnum = jsonObject.optEnum(MyEnumField.class, "strKey2", null); + assertEquals(MyEnumField.VAL1, actualEnum); // opt with default an index that does not exist actualEnum = jsonObject.optEnum(MyEnumField.class, "noKey", null); - assertTrue("opt null", actualEnum == null); + assertNull("opt null", actualEnum); + + assertNull("Expected Null when the enum class is null", + jsonObject.optEnum(null, "enumKey")); /** * Exercise the proposed enum API methods on JSONArray diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index b2d1362..ebd1cd1 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -2010,6 +2010,8 @@ public void jsonObjectOptDefault() { public void jsonObjectOptNoKey() { JSONObject jsonObject = new JSONObject(); + + assertNull(jsonObject.opt(null)); assertTrue("optBigDecimal() should return default BigDecimal", BigDecimal.TEN.compareTo(jsonObject.optBigDecimal("myKey", BigDecimal.TEN))==0); @@ -2088,6 +2090,46 @@ public void jsonObjectOptCoercion() { assertEquals(19007199254740992l, (long)Double.parseDouble("19007199254740993.35481234487103587486413587843213584")); assertEquals(2147483647, (int)Double.parseDouble("19007199254740993.35481234487103587486413587843213584")); } + + /** + * Verifies that the optBigDecimal method properly converts values to BigDecimal and coerce them consistently. + */ + @Test + public void jsonObjectOptBigDecimal() { + JSONObject jo = new JSONObject().put("int", 123).put("long", 654L) + .put("float", 1.234f).put("double", 2.345d) + .put("bigInteger", new BigInteger("1234")) + .put("bigDecimal", new BigDecimal("1234.56789")) + .put("nullVal", JSONObject.NULL); + + assertEquals(new BigDecimal("123"),jo.optBigDecimal("int", null)); + assertEquals(new BigDecimal("654"),jo.optBigDecimal("long", null)); + assertEquals(new BigDecimal(1.234f),jo.optBigDecimal("float", null)); + assertEquals(new BigDecimal(2.345d),jo.optBigDecimal("double", null)); + assertEquals(new BigDecimal("1234"),jo.optBigDecimal("bigInteger", null)); + assertEquals(new BigDecimal("1234.56789"),jo.optBigDecimal("bigDecimal", null)); + assertNull(jo.optBigDecimal("nullVal", null)); + } + + /** + * Verifies that the optBigDecimal method properly converts values to BigDecimal and coerce them consistently. + */ + @Test + public void jsonObjectOptBigInteger() { + JSONObject jo = new JSONObject().put("int", 123).put("long", 654L) + .put("float", 1.234f).put("double", 2.345d) + .put("bigInteger", new BigInteger("1234")) + .put("bigDecimal", new BigDecimal("1234.56789")) + .put("nullVal", JSONObject.NULL); + + assertEquals(new BigInteger("123"),jo.optBigInteger("int", null)); + assertEquals(new BigInteger("654"),jo.optBigInteger("long", null)); + assertEquals(new BigInteger("1"),jo.optBigInteger("float", null)); + assertEquals(new BigInteger("2"),jo.optBigInteger("double", null)); + assertEquals(new BigInteger("1234"),jo.optBigInteger("bigInteger", null)); + assertEquals(new BigInteger("1234"),jo.optBigInteger("bigDecimal", null)); + assertNull(jo.optBigDecimal("nullVal", null)); + } /** * Confirm behavior when JSONObject put(key, null object) is called @@ -2099,13 +2141,13 @@ public void jsonObjectputNull() { String str = "{\"myKey\": \"myval\"}"; JSONObject jsonObjectRemove = new JSONObject(str); jsonObjectRemove.remove("myKey"); + assertEquals("jsonObject should be empty",0 ,jsonObjectRemove.length()); JSONObject jsonObjectPutNull = new JSONObject(str); jsonObjectPutNull.put("myKey", (Object) null); + assertEquals("jsonObject should be empty",0 ,jsonObjectPutNull.length()); + - // validate JSON - assertTrue("jsonObject should be empty", jsonObjectRemove.length() == 0 - && jsonObjectPutNull.length() == 0); } /** @@ -2190,6 +2232,70 @@ public void write() throws IOException { stringWriter.close(); } } + + /** + * Confirms that exceptions thrown when writing values are wrapped properly. + */ + @Test + public void testJSONWriterException() throws IOException { + final JSONObject jsonObject = new JSONObject(); + + jsonObject.put("someKey",new BrokenToString()); + + // test single element JSONObject + try(StringWriter writer = new StringWriter();) { + jsonObject.write(writer).toString(); + fail("Expected an exception, got a String value"); + } catch (JSONException e) { + assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage()); + } catch(Exception e) { + fail("Expected JSONException"); + } + + //test multiElement + jsonObject.put("somethingElse", "a value"); + + try (StringWriter writer = new StringWriter()) { + jsonObject.write(writer).toString(); + fail("Expected an exception, got a String value"); + } catch (JSONException e) { + assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage()); + } catch(Exception e) { + fail("Expected JSONException"); + } + + // test a more complex object + try (StringWriter writer = new StringWriter()) { + new JSONObject() + .put("somethingElse", "a value") + .put("someKey", new JSONArray() + .put(new JSONObject().put("key1", new BrokenToString()))) + .write(writer).toString(); + fail("Expected an exception, got a String value"); + } catch (JSONException e) { + assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage()); + } catch(Exception e) { + fail("Expected JSONException"); + } + + // test a more slightly complex object + try (StringWriter writer = new StringWriter()) { + new JSONObject() + .put("somethingElse", "a value") + .put("someKey", new JSONArray() + .put(new JSONObject().put("key1", new BrokenToString())) + .put(12345) + ) + .write(writer).toString(); + fail("Expected an exception, got a String value"); + } catch (JSONException e) { + assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage()); + } catch(Exception e) { + fail("Expected JSONException"); + } + + } + /** * Exercise the JSONObject write() method @@ -2468,4 +2574,16 @@ public void toMap() { assertTrue("Map should have 2 elements", map.size() == 2); } + + /** + * test class for verifying write errors. + * @author John Aylward + * + */ + private static class BrokenToString { + @Override + public String toString() { + throw new IllegalStateException("Something went horribly wrong!"); + } + } } diff --git a/src/test/java/org/json/junit/JSONStringTest.java b/src/test/java/org/json/junit/JSONStringTest.java index 617b9e3..ec40dbb 100644 --- a/src/test/java/org/json/junit/JSONStringTest.java +++ b/src/test/java/org/json/junit/JSONStringTest.java @@ -242,7 +242,7 @@ public void testJSONStringExceptionValue() throws IOException { jsonArray.write(writer).toString(); fail("Expected an exception, got a String value"); } catch (JSONException e) { - assertTrue("Exception message does not match", "the exception value".equals(e.getMessage())); + assertEquals("Unable to write JSONArray value at index: 0", e.getMessage()); } catch(Exception e) { fail("Expected JSONException"); } finally { From 3081b4bd960886b1d3f81103ddc9d741869df51a Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 21 Jun 2017 14:59:42 -0400 Subject: [PATCH 48/99] Fixes for failing tests due to android integration --- src/test/java/org/json/junit/JSONMLTest.java | 64 ++++++++++---------- src/test/java/org/json/junit/XMLTest.java | 57 ++++++++--------- 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index 8ece8e5..833e934 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -42,11 +42,11 @@ public void emptyXMLException() { String xmlStr = ""; try { JSONML.toJSONArray(xmlStr); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Bad XML at 1 [character 2 line 1]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Bad XML at 0 [character 1 line 1]", + e.getMessage()); } } @@ -95,11 +95,11 @@ public void nonXMLException() { String xmlStr = "{ \"this is\": \"not xml\"}"; try { JSONML.toJSONArray(xmlStr); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Bad XML at 25 [character 26 line 1]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Bad XML at 23 [character 24 line 1]", + e.getMessage()); } } @@ -198,11 +198,11 @@ public void invalidSlashInTagException() { ""; try { JSONML.toJSONArray(xmlStr); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Misshaped tag at 176 [character 14 line 7]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Misshaped tag at 176 [character 14 line 4]", + e.getMessage()); } } @@ -223,11 +223,11 @@ public void invalidBangInTagException() { ""; try { JSONML.toJSONArray(xmlStr); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Misshaped meta tag at 216 [character 13 line 11]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Misshaped meta tag at 216 [character 13 line 7]", + e.getMessage()); } } @@ -253,11 +253,11 @@ public void invalidBangNoCloseInTagException() { ""; try { JSONML.toJSONArray(xmlStr); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Misshaped meta tag at 215 [character 13 line 11]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Misshaped meta tag at 215 [character 13 line 7]", + e.getMessage()); } } @@ -283,11 +283,11 @@ public void noCloseStartTagException() { ""; try { JSONML.toJSONArray(xmlStr); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Misplaced '<' at 194 [character 5 line 10]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Misplaced '<' at 194 [character 5 line 6]", + e.getMessage()); } } @@ -343,11 +343,11 @@ public void noCloseEndBraceException() { ""; try { JSONML.toJSONArray(xmlStr); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Misplaced '<' at 206 [character 1 line 12]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Misplaced '<' at 206 [character 1 line 7]", + e.getMessage()); } } @@ -373,11 +373,11 @@ public void invalidCDATABangInTagException() { ""; try { JSONML.toJSONArray(xmlStr); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Expected 'CDATA[' at 204 [character 11 line 9]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Expected 'CDATA[' at 204 [character 11 line 5]", + e.getMessage()); } } diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index dd827bd..11566c6 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import org.json.JSONArray; import org.json.JSONException; @@ -74,11 +75,11 @@ public void shouldHandleInvalidSlashInTag() { ""; try { XML.toJSONObject(xmlStr); - assertTrue("Expecting a JSONException", false); + fail("Expecting a JSONException"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Misshaped tag at 176 [character 14 line 5]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Misshaped tag at 176 [character 14 line 4]", + e.getMessage()); } } @@ -99,11 +100,11 @@ public void shouldHandleInvalidBangInTag() { ""; try { XML.toJSONObject(xmlStr); - assertTrue("Expecting a JSONException", false); + fail("Expecting a JSONException"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Misshaped meta tag at 215 [character 13 line 8]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Misshaped meta tag at 215 [character 13 line 7]", + e.getMessage()); } } @@ -124,11 +125,11 @@ public void shouldHandleInvalidBangNoCloseInTag() { ""; try { XML.toJSONObject(xmlStr); - assertTrue("Expecting a JSONException", false); + fail("Expecting a JSONException"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Misshaped meta tag at 214 [character 13 line 8]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Misshaped meta tag at 214 [character 13 line 7]", + e.getMessage()); } } @@ -149,11 +150,11 @@ public void shouldHandleNoCloseStartTag() { ""; try { XML.toJSONObject(xmlStr); - assertTrue("Expecting a JSONException", false); + fail("Expecting a JSONException"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Misplaced '<' at 193 [character 4 line 7]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Misplaced '<' at 193 [character 4 line 6]", + e.getMessage()); } } @@ -174,11 +175,11 @@ public void shouldHandleInvalidCDATABangInTag() { ""; try { XML.toJSONObject(xmlStr); - assertTrue("Expecting a JSONException", false); + fail("Expecting a JSONException"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Expected 'CDATA[' at 204 [character 11 line 6]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Expected 'CDATA[' at 204 [character 11 line 5]", + e.getMessage()); } } @@ -397,9 +398,9 @@ public void shouldHandleEmptyArray(){ final String expected = ""; String output1 = XML.toString(jo1,"jo"); - assertTrue("Expected an empty root tag", expected.equals(output1)); + assertEquals("Expected an empty root tag", expected, output1); String output2 = XML.toString(jo2,"jo"); - assertTrue("Expected an empty root tag", expected.equals(output2)); + assertEquals("Expected an empty root tag", expected, output2); } /** @@ -414,9 +415,9 @@ public void shouldHandleEmptyMultiArray(){ final String expected = "OneFour"; String output1 = XML.toString(jo1,"jo"); - assertTrue("Expected a matching array", expected.equals(output1)); + assertEquals("Expected a matching array", expected, output1); String output2 = XML.toString(jo2,"jo"); - assertTrue("Expected a matching array", expected.equals(output2)); + assertEquals("Expected a matching array", expected, output2); } /** @@ -431,9 +432,9 @@ public void shouldHandleNonEmptyArray(){ final String expected = "OneTwoThree"; String output1 = XML.toString(jo1,"jo"); - assertTrue("Expected a non empty root tag", expected.equals(output1)); + assertEquals("Expected a non empty root tag", expected, output1); String output2 = XML.toString(jo2,"jo"); - assertTrue("Expected a non empty root tag", expected.equals(output2)); + assertEquals("Expected a non empty root tag", expected, output2); } /** @@ -448,9 +449,9 @@ public void shouldHandleMultiArray(){ final String expected = "OneTwoThreeFour"; String output1 = XML.toString(jo1,"jo"); - assertTrue("Expected a matching array", expected.equals(output1)); + assertEquals("Expected a matching array", expected, output1); String output2 = XML.toString(jo2,"jo"); - assertTrue("Expected a matching array", expected.equals(output2)); + assertEquals("Expected a matching array", expected, output2); } /** From 971614ac8b28b40e14ab27615b098ccebcb80eb0 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 21 Jun 2017 18:28:04 -0400 Subject: [PATCH 49/99] fix expected exception message --- src/test/java/org/json/junit/JSONMLTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index 833e934..518c949 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -98,7 +98,7 @@ public void nonXMLException() { fail("Expecting an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "Bad XML at 23 [character 24 line 1]", + "Bad XML at 24 [character 25 line 1]", e.getMessage()); } } From 0e612ba8a4767cf9e5b6cae399133c234dd5a9f9 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 21 Jun 2017 19:56:00 -0400 Subject: [PATCH 50/99] More test corrections for correct position reports in error messages --- src/test/java/org/json/junit/CDLTest.java | 73 +++++++++++-------- .../java/org/json/junit/CookieListTest.java | 8 +- src/test/java/org/json/junit/CookieTest.java | 24 +++--- .../java/org/json/junit/JSONArrayTest.java | 6 +- src/test/java/org/json/junit/JSONMLTest.java | 6 +- .../java/org/json/junit/JSONObjectTest.java | 48 ++++++------ src/test/java/org/json/junit/XMLTest.java | 4 +- 7 files changed, 92 insertions(+), 77 deletions(-) diff --git a/src/test/java/org/json/junit/CDLTest.java b/src/test/java/org/json/junit/CDLTest.java index a40b014..b99e17c 100644 --- a/src/test/java/org/json/junit/CDLTest.java +++ b/src/test/java/org/json/junit/CDLTest.java @@ -61,11 +61,11 @@ public void unbalancedQuoteInName() { String badLine = "Col1, \"Col2\nVal1, Val2"; try { CDL.toJSONArray(badLine); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Missing close quote '\"'. at 12 [character 0 line 2]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Missing close quote '\"'. at 12 [character 0 line 2]", + e.getMessage()); } } @@ -78,11 +78,11 @@ public void unbalancedQuoteInValue() { String badLine = "Col1, Col2\n\"Val1, Val2"; try { CDL.toJSONArray(badLine); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Missing close quote '\"'. at 23 [character 12 line 3]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Missing close quote '\"'. at 22 [character 11 line 3]", + e.getMessage()); } } @@ -96,11 +96,11 @@ public void nullInName() { String badLine = "C\0ol1, Col2\nVal1, Val2"; try { CDL.toJSONArray(badLine); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Bad character 'o' (111). at 3 [character 4 line 1]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Bad character 'o' (111). at 2 [character 3 line 1]", + e.getMessage()); } } @@ -114,11 +114,11 @@ public void unbalancedEscapedQuote(){ String badLine = "Col1, Col2\n\"Val1, \"\"Val2\"\""; try { CDL.toJSONArray(badLine); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Missing close quote '\"'. at 27 [character 16 line 3]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Missing close quote '\"'. at 26 [character 15 line 3]", + e.getMessage()); } } @@ -128,7 +128,7 @@ public void unbalancedEscapedQuote(){ */ @Test public void singleEscapedQuote(){ - String singleEscape = "Col1, Col2\nVal1, \"\"\"Val2\""; + String singleEscape = "Col1, Col2\nVal1, \"\"\"Val2\""; JSONArray jsonArray = CDL.toJSONArray(singleEscape); String cdlStr = CDL.toString(jsonArray); @@ -136,7 +136,22 @@ public void singleEscapedQuote(){ assertTrue(cdlStr.contains("Col2")); assertTrue(cdlStr.contains("Val1")); assertTrue(cdlStr.contains("\"Val2")); + } + + /** + * Assert that there is no error for a single escaped quote within a properly + * embedded quote when not the last value. + */ + @Test + public void singleEscapedQuoteMiddleString(){ + String singleEscape = "Col1, Col2\nVal1, \"\"\"Val2\"\nVal 3,Val 4"; + JSONArray jsonArray = CDL.toJSONArray(singleEscape); + String cdlStr = CDL.toString(jsonArray); + assertTrue(cdlStr.contains("Col1")); + assertTrue(cdlStr.contains("Col2")); + assertTrue(cdlStr.contains("Val1")); + assertTrue(cdlStr.contains("\"Val2")); } /** @@ -149,12 +164,12 @@ public void badEscapedQuote(){ try { CDL.toJSONArray(badLine); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { System.out.println("Message" + e.getMessage()); - assertTrue("Expecting an exception message", - "Bad character 'V' (86). at 20 [character 9 line 3]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Bad character 'V' (86). at 20 [character 9 line 3]", + e.getMessage()); } @@ -186,8 +201,8 @@ public void emptyString() { public void onlyColumnNames() { String columnNameStr = "col1, col2, col3"; JSONArray jsonArray = CDL.toJSONArray(columnNameStr); - assertTrue("CDL should return null when only 1 row is given", - jsonArray == null); + assertNull("CDL should return null when only 1 row is given", + jsonArray); } /** @@ -197,8 +212,8 @@ public void onlyColumnNames() { public void emptyLinesToJSONArray() { String str = " , , , \n , , , "; JSONArray jsonArray = CDL.toJSONArray(str); - assertTrue("JSONArray should be null for no content", - jsonArray == null); + assertNull("JSONArray should be null for no content", + jsonArray); } /** @@ -208,8 +223,8 @@ public void emptyLinesToJSONArray() { public void emptyJSONArrayToString() { JSONArray jsonArray = new JSONArray(); String str = CDL.toString(jsonArray); - assertTrue("CDL should return null for toString(null)", - str == null); + assertNull("CDL should return null for toString(null)", + str); } /** @@ -218,8 +233,8 @@ public void emptyJSONArrayToString() { @Test public void nullJSONArraysToString() { String str = CDL.toString(null, null); - assertTrue("CDL should return null for toString(null)", - str == null); + assertNull("CDL should return null for toString(null)", + str); } /** diff --git a/src/test/java/org/json/junit/CookieListTest.java b/src/test/java/org/json/junit/CookieListTest.java index 7a710db..80cbaa8 100644 --- a/src/test/java/org/json/junit/CookieListTest.java +++ b/src/test/java/org/json/junit/CookieListTest.java @@ -47,14 +47,14 @@ public void malFormedCookieListException() { String cookieStr = "thisCookieHasNoEqualsChar"; try { CookieList.toJSONObject(cookieStr); - assertTrue("should throw an exception", false); + fail("should throw an exception"); } catch (JSONException e) { /** * Not sure of the missing char, but full string compare fails */ - assertTrue("Expecting an exception message", - e.getMessage().startsWith("Expected '=' and instead saw '") && - e.getMessage().endsWith("' at 27 [character 28 line 1]")); + assertEquals("Expecting an exception message", + "Expected '=' and instead saw '' at 25 [character 26 line 1]", + e.getMessage()); } } diff --git a/src/test/java/org/json/junit/CookieTest.java b/src/test/java/org/json/junit/CookieTest.java index 9104b60..4b7ca44 100644 --- a/src/test/java/org/json/junit/CookieTest.java +++ b/src/test/java/org/json/junit/CookieTest.java @@ -43,11 +43,11 @@ public void malFormedNameValueException() { String cookieStr = "thisCookieHasNoEqualsChar"; try { Cookie.toJSONObject(cookieStr); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - e.getMessage().startsWith("Expected '=' and instead saw '") - && e.getMessage().endsWith("' at 27 [character 28 line 1]")); + assertEquals("Expecting an exception message", + "Expected '=' and instead saw '' at 25 [character 26 line 1]", + e.getMessage()); } } @@ -61,11 +61,11 @@ public void malFormedAttributeException() { String cookieStr = "this=Cookie;myAttribute"; try { Cookie.toJSONObject(cookieStr); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Missing '=' in cookie parameter. at 25 [character 26 line 1]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Missing '=' in cookie parameter. at 23 [character 24 line 1]", + e.getMessage()); } } @@ -79,11 +79,11 @@ public void emptyStringCookieException() { String cookieStr = ""; try { Cookie.toJSONObject(cookieStr); - assertTrue("Expecting an exception", false); + fail("Expecting an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - e.getMessage().startsWith("Expected '=' and instead saw '") && - e.getMessage().endsWith("' at 2 [character 3 line 1]")); + assertEquals("Expecting an exception message", + "Expected '=' and instead saw '' at 0 [character 1 line 1]", + e.getMessage()); } } diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 666c03b..0df7c5d 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -74,9 +74,9 @@ public void emptStr() { try { assertNull("Should throw an exception", new JSONArray(str)); } catch (JSONException e) { - assertTrue("Expected an exception message", - "A JSONArray text must start with '[' at 1 [character 2 line 1]". - equals(e.getMessage())); + assertEquals("Expected an exception message", + "A JSONArray text must start with '[' at 0 [character 1 line 1]", + e.getMessage()); } } diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index 518c949..84b33ba 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -98,7 +98,7 @@ public void nonXMLException() { fail("Expecting an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "Bad XML at 24 [character 25 line 1]", + "Bad XML at 23 [character 24 line 1]", e.getMessage()); } } @@ -226,7 +226,7 @@ public void invalidBangInTagException() { fail("Expecting an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "Misshaped meta tag at 216 [character 13 line 7]", + "Misshaped meta tag at 215 [character 12 line 7]", e.getMessage()); } } @@ -256,7 +256,7 @@ public void invalidBangNoCloseInTagException() { fail("Expecting an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "Misshaped meta tag at 215 [character 13 line 7]", + "Misshaped meta tag at 214 [character 12 line 7]", e.getMessage()); } } diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index ebd1cd1..cabd41c 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1853,36 +1853,36 @@ public void jsonObjectParsingErrors() { String str = "abc"; assertNull("Expected an exception",new JSONObject(str)); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "A JSONObject text must begin with '{' at 1 [character 2 line 1]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "A JSONObject text must begin with '{' at 1 [character 2 line 1]", + e.getMessage()); } try { // does not end with '}' String str = "{"; assertNull("Expected an exception",new JSONObject(str)); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "A JSONObject text must end with '}' at 2 [character 3 line 1]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "A JSONObject text must end with '}' at 1 [character 2 line 1]", + e.getMessage()); } try { // key with no ':' String str = "{\"myKey\" = true}"; assertNull("Expected an exception",new JSONObject(str)); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Expected a ':' after a key at 10 [character 11 line 1]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Expected a ':' after a key at 10 [character 11 line 1]", + e.getMessage()); } try { // entries with no ',' separator String str = "{\"myKey\":true \"myOtherKey\":false}"; assertNull("Expected an exception",new JSONObject(str)); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Expected a ',' or '}' at 15 [character 16 line 1]". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Expected a ',' or '}' at 15 [character 16 line 1]", + e.getMessage()); } try { // append to wrong key @@ -1891,9 +1891,9 @@ public void jsonObjectParsingErrors() { jsonObject.append("myKey", "hello"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[myKey] is not a JSONArray.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[myKey] is not a JSONArray.", + e.getMessage()); } try { // increment wrong key @@ -1902,9 +1902,9 @@ public void jsonObjectParsingErrors() { jsonObject.increment("myKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Unable to increment [\"myKey\"].". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Unable to increment [\"myKey\"].", + e.getMessage()); } try { // invalid key @@ -1913,18 +1913,18 @@ public void jsonObjectParsingErrors() { jsonObject.get(null); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Null key.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Null key.", + e.getMessage()); } try { // invalid numberToString() JSONObject.numberToString((Number)null); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Null pointer". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "Null pointer", + e.getMessage()); } try { // null put key diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 11566c6..244c9e9 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -103,7 +103,7 @@ public void shouldHandleInvalidBangInTag() { fail("Expecting a JSONException"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "Misshaped meta tag at 215 [character 13 line 7]", + "Misshaped meta tag at 214 [character 12 line 7]", e.getMessage()); } } @@ -128,7 +128,7 @@ public void shouldHandleInvalidBangNoCloseInTag() { fail("Expecting a JSONException"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "Misshaped meta tag at 214 [character 13 line 7]", + "Misshaped meta tag at 213 [character 12 line 7]", e.getMessage()); } } From af39376d926b8a1aaf21646e63131e9acecfd996 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Fri, 23 Jun 2017 23:25:11 -0400 Subject: [PATCH 51/99] more fixes for testing postition information --- src/test/java/org/json/junit/CDLTest.java | 6 +- .../java/org/json/junit/JSONPointerTest.java | 22 ++- .../java/org/json/junit/JSONTokenerTest.java | 158 ++++++++++++++++++ 3 files changed, 179 insertions(+), 7 deletions(-) create mode 100644 src/test/java/org/json/junit/JSONTokenerTest.java diff --git a/src/test/java/org/json/junit/CDLTest.java b/src/test/java/org/json/junit/CDLTest.java index b99e17c..b1f9561 100644 --- a/src/test/java/org/json/junit/CDLTest.java +++ b/src/test/java/org/json/junit/CDLTest.java @@ -81,7 +81,7 @@ public void unbalancedQuoteInValue() { fail("Expecting an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "Missing close quote '\"'. at 22 [character 11 line 3]", + "Missing close quote '\"'. at 22 [character 11 line 2]", e.getMessage()); } @@ -117,7 +117,7 @@ public void unbalancedEscapedQuote(){ fail("Expecting an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "Missing close quote '\"'. at 26 [character 15 line 3]", + "Missing close quote '\"'. at 26 [character 15 line 2]", e.getMessage()); } @@ -168,7 +168,7 @@ public void badEscapedQuote(){ } catch (JSONException e) { System.out.println("Message" + e.getMessage()); assertEquals("Expecting an exception message", - "Bad character 'V' (86). at 20 [character 9 line 3]", + "Bad character 'V' (86). at 20 [character 9 line 2]", e.getMessage()); } diff --git a/src/test/java/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java index 0904b9e..19dac47 100644 --- a/src/test/java/org/json/junit/JSONPointerTest.java +++ b/src/test/java/org/json/junit/JSONPointerTest.java @@ -1,8 +1,18 @@ package org.json.junit; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -import org.json.*; +import java.io.IOException; +import java.io.InputStream; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.json.JSONPointer; +import org.json.JSONPointerException; +import org.json.JSONTokener; import org.junit.Test; public class JSONPointerTest { @@ -10,8 +20,12 @@ public class JSONPointerTest { private static final JSONObject document; static { - document = new JSONObject(new JSONTokener( - JSONPointerTest.class.getClassLoader().getResourceAsStream("jsonpointer-testdoc.json"))); + @SuppressWarnings("resource") + InputStream resourceAsStream = JSONPointerTest.class.getClassLoader().getResourceAsStream("jsonpointer-testdoc.json"); + if(resourceAsStream == null) { + throw new ExceptionInInitializerError("Unable to locate test file. Please check your development environment configuration"); + } + document = new JSONObject(new JSONTokener(resourceAsStream)); } private Object query(String pointer) { diff --git a/src/test/java/org/json/junit/JSONTokenerTest.java b/src/test/java/org/json/junit/JSONTokenerTest.java new file mode 100644 index 0000000..5fe2259 --- /dev/null +++ b/src/test/java/org/json/junit/JSONTokenerTest.java @@ -0,0 +1,158 @@ +package org.json.junit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; + +import org.json.JSONException; +import org.json.JSONTokener; +import org.junit.Test; + +/** + * Test specific to the {@link org.json.JSONTokener} class. + * @author John Aylward + * + */ +public class JSONTokenerTest { + + /** + * verify that back() fails as expected. + * @throws IOException thrown if something unexpected happens. + */ + @Test + public void verifyBackFailureZeroIndex() throws IOException { + try(Reader reader = new StringReader("some test string")) { + final JSONTokener tokener = new JSONTokener(reader); + try { + // this should fail since the index is 0; + tokener.back(); + fail("Expected an exception"); + } catch (JSONException e) { + assertEquals("Stepping back two steps is not supported", e.getMessage()); + } catch (Exception e) { + fail("Unknown Exception type " + e.getClass().getCanonicalName()+" with message "+e.getMessage()); + } + + } + } + /** + * verify that back() fails as expected. + * @throws IOException thrown if something unexpected happens. + */ + @Test + public void verifyBackFailureDoubleBack() throws IOException { + try(Reader reader = new StringReader("some test string")) { + final JSONTokener tokener = new JSONTokener(reader); + tokener.next(); + tokener.back(); + try { + // this should fail since the index is 0; + tokener.back(); + fail("Expected an exception"); + } catch (JSONException e) { + assertEquals("Stepping back two steps is not supported", e.getMessage()); + } catch (Exception e) { + fail("Unknown Exception type " + e.getClass().getCanonicalName()+" with message "+e.getMessage()); + } + } + } + + /** + * Tests the failure of the skipTo method with a buffered reader. Preferably + * we'd like this not to fail but at this time we don't have a good recovery. + * + * @throws IOException thrown if something unexpected happens. + */ + @Test + public void testSkipToFailureWithBufferedReader() throws IOException { + final byte[] superLongBuffer = new byte[1000001]; + // fill our buffer + for(int i=0;i Date: Fri, 23 Jun 2017 23:55:22 -0400 Subject: [PATCH 52/99] Updates test coverage table --- README.md | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 0772d3b..79f8724 100644 --- a/README.md +++ b/README.md @@ -101,24 +101,26 @@ A unit test has the following stages: | CDL.java | 98.8% | Reasonable test cases. | | Cookie.java | 98.9% | Reasonable test cases. | | CookieList.java |96.5% | Reasonable test cases. | -| EnumTest.java | n/a | Just documenting how enums are handled. | -| HTTP.java | 98.7%| Coverage > 90% | +| HTTP.java | 98.8%| Coverage > 90% | | HTTPTokener.java |93.2% | No test | -| JSONArray.java |95.9% | Reasonable test cases | -| JSONException.java | 26.7% | No test | -| JSONML.java | 86.8%| In progress | -| JSONObject | 94.0% | Reasonable test cases | -| JSONObject.Null | 87.5% | No test | +| JSONArray.java |88.3% | Reasonable test cases. Need new tests for newer API functions | +| JSONException.java | 100% | No test | +| JSONML.java | 84.4%| In progress | +| JSONObject | 96.7% | Reasonable test cases | +| JSONObject.Null | 77.8% | No test | +| JSONPointer | 96.3% | Reasonable test cases | +| JSONPointerException | 100% | No test | | JSONString.java | | No test | | JSONStringer.java | 93.8%| Coverage > 90% | -| JSONTokener.java | 72.1% | In progress | -| JSONWriter.java | 87.5% | No test | -| Property.java | 94.8% | Coverage > 90% | -| XML.java | 87.4% | In progress | -| XMLTokener.java| 82.7%| No test | +| JSONTokener.java | 87.5% | In progress | +| JSONWriter.java | 89.15% | No test | +| Property.java | 95.8% | Coverage > 90% | +| XML.java | 77.3% | In progress | +| XMLTokener.java| 82.4%| No test | | Files used in test | | ------------- | +| EnumTest.java | | MyBean.java | | MyBigNumberBean.java | | MyEnum.java | From 899cf528df591420ba107af445bed46d80cd316f Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Sat, 24 Jun 2017 13:10:14 -0400 Subject: [PATCH 53/99] More test cases for position information --- .../java/org/json/junit/JSONTokenerTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/test/java/org/json/junit/JSONTokenerTest.java b/src/test/java/org/json/junit/JSONTokenerTest.java index 5fe2259..dced89f 100644 --- a/src/test/java/org/json/junit/JSONTokenerTest.java +++ b/src/test/java/org/json/junit/JSONTokenerTest.java @@ -1,6 +1,8 @@ package org.json.junit; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.BufferedReader; @@ -121,7 +123,12 @@ public void testSkipToSuccessWithStringReader() throws IOException { @Test public void testNextBackComboWithNewLines() { final String testString = "this is\nA test\r\nWith some different\rNew Lines"; + // ^ ^ ^ ^ + // index positions 0 8 16 36 final JSONTokener tokener = new JSONTokener(testString); + assertEquals(" at 0 [character 1 line 1]", tokener.toString()); + assertEquals('t',tokener.next()); + assertEquals(" at 1 [character 2 line 1]", tokener.toString()); tokener.skipTo('\n'); assertEquals("skipTo() improperly modifying indexes"," at 7 [character 8 line 1]", tokener.toString()); assertEquals('\n',tokener.next()); @@ -132,10 +139,12 @@ public void testNextBackComboWithNewLines() { assertEquals(" at 8 [character 0 line 2]", tokener.toString()); tokener.skipTo('\r'); assertEquals("skipTo() improperly modifying indexes"," at 14 [character 6 line 2]", tokener.toString()); + // verify \r\n combo doesn't increment the line twice assertEquals('\r', tokener.next()); assertEquals(" at 15 [character 0 line 3]", tokener.toString()); assertEquals('\n', tokener.next()); assertEquals(" at 16 [character 0 line 3]", tokener.toString()); + // verify stepping back after reading the \n of an \r\n combo doesn't increment the line incorrectly tokener.back(); assertEquals(" at 15 [character 6 line 2]", tokener.toString()); assertEquals('\n', tokener.next()); @@ -154,5 +163,39 @@ public void testNextBackComboWithNewLines() { assertEquals(" at 36 [character 0 line 4]", tokener.toString()); assertEquals('N', tokener.next()); assertEquals(" at 37 [character 1 line 4]", tokener.toString()); + + // verify we get the same data just walking though, no calls to back + final JSONTokener t2 = new JSONTokener(testString); + for(int i=0; i<7; i++) { + assertTrue(t2.toString().startsWith(" at " + i + " ")); + assertEquals(testString.charAt(i), t2.next()); + } + assertEquals(" at 7 [character 8 line 1]", t2.toString()); + assertEquals(testString.charAt(7), t2.next()); + assertEquals(" at 8 [character 0 line 2]", t2.toString()); + for(int i=8; i<14; i++) { + assertTrue(t2.toString().startsWith(" at " + i + " ")); + assertEquals(testString.charAt(i), t2.next()); + } + assertEquals(" at 14 [character 6 line 2]", t2.toString()); + assertEquals('\r', t2.next()); + assertEquals(" at 15 [character 0 line 3]", t2.toString()); + assertEquals('\n', t2.next()); + assertEquals(" at 16 [character 0 line 3]", t2.toString()); + assertEquals('W', t2.next()); + assertEquals(" at 17 [character 1 line 3]", t2.toString()); + for(int i=17; i<37; i++) { + assertTrue(t2.toString().startsWith(" at " + i + " ")); + assertEquals(testString.charAt(i), t2.next()); + } + assertEquals(" at 37 [character 1 line 4]", t2.toString()); + for(int i=37; i Date: Sun, 9 Jul 2017 16:33:39 -0400 Subject: [PATCH 54/99] reorganize classes so test data is separate from test cases --- src/test/java/org/json/junit/EnumTest.java | 5 +++- .../org/json/junit/JSONObjectLocaleTest.java | 1 + .../java/org/json/junit/JSONObjectTest.java | 25 ++++++++----------- .../org/json/junit/data/BrokenToString.java | 13 ++++++++++ .../org/json/junit/{ => data}/Fraction.java | 2 +- .../org/json/junit/{ => data}/MyBean.java | 4 +-- .../junit/{ => data}/MyBigNumberBean.java | 4 +-- .../org/json/junit/{ => data}/MyEnum.java | 2 +- .../json/junit/{ => data}/MyEnumClass.java | 2 +- .../json/junit/{ => data}/MyEnumField.java | 2 +- .../json/junit/{ => data}/MyJsonString.java | 4 +-- .../json/junit/{ => data}/MyLocaleBean.java | 2 +- .../org/json/junit/{ => data}/MyNumber.java | 2 +- .../junit/{ => data}/MyNumberContainer.java | 2 +- .../json/junit/{ => data}/MyPublicClass.java | 2 +- .../{ => data}/StringsResourceBundle.java | 2 +- 16 files changed, 44 insertions(+), 30 deletions(-) create mode 100644 src/test/java/org/json/junit/data/BrokenToString.java rename src/test/java/org/json/junit/{ => data}/Fraction.java (99%) rename src/test/java/org/json/junit/{ => data}/MyBean.java (85%) rename src/test/java/org/json/junit/{ => data}/MyBigNumberBean.java (72%) rename src/test/java/org/json/junit/{ => data}/MyEnum.java (76%) rename src/test/java/org/json/junit/{ => data}/MyEnumClass.java (94%) rename src/test/java/org/json/junit/{ => data}/MyEnumField.java (95%) rename src/test/java/org/json/junit/{ => data}/MyJsonString.java (67%) rename src/test/java/org/json/junit/{ => data}/MyLocaleBean.java (88%) rename src/test/java/org/json/junit/{ => data}/MyNumber.java (98%) rename src/test/java/org/json/junit/{ => data}/MyNumberContainer.java (90%) rename src/test/java/org/json/junit/{ => data}/MyPublicClass.java (87%) rename src/test/java/org/json/junit/{ => data}/StringsResourceBundle.java (93%) diff --git a/src/test/java/org/json/junit/EnumTest.java b/src/test/java/org/json/junit/EnumTest.java index 53ac303..cd0d8c0 100644 --- a/src/test/java/org/json/junit/EnumTest.java +++ b/src/test/java/org/json/junit/EnumTest.java @@ -10,6 +10,9 @@ import org.json.JSONArray; import org.json.JSONObject; +import org.json.junit.data.MyEnum; +import org.json.junit.data.MyEnumClass; +import org.json.junit.data.MyEnumField; import org.junit.Test; import com.jayway.jsonpath.Configuration; @@ -195,7 +198,7 @@ public void enumValueToString() { * However, an enum within another class will not be rendered * unless that class overrides default toString() */ - String expectedStr3 = "\"org.json.junit.MyEnumClass@"; + String expectedStr3 = "\"org.json.junit.data.MyEnumClass@"; myEnumClass.setMyEnum(MyEnum.VAL1); myEnumClass.setMyEnumField(MyEnumField.VAL1); String str3 = JSONObject.valueToString(myEnumClass); diff --git a/src/test/java/org/json/junit/JSONObjectLocaleTest.java b/src/test/java/org/json/junit/JSONObjectLocaleTest.java index 9c80ab6..52ef7d5 100755 --- a/src/test/java/org/json/junit/JSONObjectLocaleTest.java +++ b/src/test/java/org/json/junit/JSONObjectLocaleTest.java @@ -5,6 +5,7 @@ import java.util.*; import org.json.*; +import org.json.junit.data.MyLocaleBean; import org.junit.*; /** diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index cabd41c..372e362 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -30,6 +30,16 @@ import org.json.JSONObject; import org.json.JSONPointerException; import org.json.XML; +import org.json.junit.data.BrokenToString; +import org.json.junit.data.Fraction; +import org.json.junit.data.MyBean; +import org.json.junit.data.MyBigNumberBean; +import org.json.junit.data.MyEnum; +import org.json.junit.data.MyEnumField; +import org.json.junit.data.MyJsonString; +import org.json.junit.data.MyNumber; +import org.json.junit.data.MyNumberContainer; +import org.json.junit.data.MyPublicClass; import org.junit.Test; import com.jayway.jsonpath.Configuration; @@ -484,7 +494,7 @@ public void jsonObjectByObjectAndNames() { @Test public void jsonObjectByResourceBundle() { JSONObject jsonObject = new - JSONObject("org.json.junit.StringsResourceBundle", + JSONObject("org.json.junit.data.StringsResourceBundle", Locale.getDefault()); // validate JSON @@ -2572,18 +2582,5 @@ public void toMap() { // assert that the new map is mutable assertTrue("Removing a key should succeed", map.remove("key3") != null); assertTrue("Map should have 2 elements", map.size() == 2); - - } - - /** - * test class for verifying write errors. - * @author John Aylward - * - */ - private static class BrokenToString { - @Override - public String toString() { - throw new IllegalStateException("Something went horribly wrong!"); - } } } diff --git a/src/test/java/org/json/junit/data/BrokenToString.java b/src/test/java/org/json/junit/data/BrokenToString.java new file mode 100644 index 0000000..585d751 --- /dev/null +++ b/src/test/java/org/json/junit/data/BrokenToString.java @@ -0,0 +1,13 @@ +package org.json.junit.data; + +/** + * test class for verifying write errors. + * @author John Aylward + * + */ +public class BrokenToString { + @Override + public String toString() { + throw new IllegalStateException("Something went horribly wrong!"); + } +} \ No newline at end of file diff --git a/src/test/java/org/json/junit/Fraction.java b/src/test/java/org/json/junit/data/Fraction.java similarity index 99% rename from src/test/java/org/json/junit/Fraction.java rename to src/test/java/org/json/junit/data/Fraction.java index d5d9eb6..c418179 100644 --- a/src/test/java/org/json/junit/Fraction.java +++ b/src/test/java/org/json/junit/data/Fraction.java @@ -1,4 +1,4 @@ -package org.json.junit; +package org.json.junit.data; import java.math.BigDecimal; import java.math.BigInteger; diff --git a/src/test/java/org/json/junit/MyBean.java b/src/test/java/org/json/junit/data/MyBean.java similarity index 85% rename from src/test/java/org/json/junit/MyBean.java rename to src/test/java/org/json/junit/data/MyBean.java index 53d150a..3190981 100644 --- a/src/test/java/org/json/junit/MyBean.java +++ b/src/test/java/org/json/junit/data/MyBean.java @@ -1,11 +1,11 @@ -package org.json.junit; +package org.json.junit.data; import java.io.*; /** * Used in testing when Bean behavior is needed */ -interface MyBean { +public interface MyBean { public Integer getIntKey(); public Double getDoubleKey(); public String getStringKey(); diff --git a/src/test/java/org/json/junit/MyBigNumberBean.java b/src/test/java/org/json/junit/data/MyBigNumberBean.java similarity index 72% rename from src/test/java/org/json/junit/MyBigNumberBean.java rename to src/test/java/org/json/junit/data/MyBigNumberBean.java index 0ca1870..934dfee 100644 --- a/src/test/java/org/json/junit/MyBigNumberBean.java +++ b/src/test/java/org/json/junit/data/MyBigNumberBean.java @@ -1,11 +1,11 @@ -package org.json.junit; +package org.json.junit.data; import java.math.*; /** * Used in testing when a Bean containing big numbers is needed */ -interface MyBigNumberBean { +public interface MyBigNumberBean { public BigInteger getBigInteger(); public BigDecimal getBigDecimal(); } \ No newline at end of file diff --git a/src/test/java/org/json/junit/MyEnum.java b/src/test/java/org/json/junit/data/MyEnum.java similarity index 76% rename from src/test/java/org/json/junit/MyEnum.java rename to src/test/java/org/json/junit/data/MyEnum.java index 0952bc2..50d9a4f 100644 --- a/src/test/java/org/json/junit/MyEnum.java +++ b/src/test/java/org/json/junit/data/MyEnum.java @@ -1,4 +1,4 @@ -package org.json.junit; +package org.json.junit.data; /** * An enum with no methods or data diff --git a/src/test/java/org/json/junit/MyEnumClass.java b/src/test/java/org/json/junit/data/MyEnumClass.java similarity index 94% rename from src/test/java/org/json/junit/MyEnumClass.java rename to src/test/java/org/json/junit/data/MyEnumClass.java index 8e71663..4d403c8 100644 --- a/src/test/java/org/json/junit/MyEnumClass.java +++ b/src/test/java/org/json/junit/data/MyEnumClass.java @@ -1,4 +1,4 @@ -package org.json.junit; +package org.json.junit.data; /** * this is simply a class that contains some enum instances diff --git a/src/test/java/org/json/junit/MyEnumField.java b/src/test/java/org/json/junit/data/MyEnumField.java similarity index 95% rename from src/test/java/org/json/junit/MyEnumField.java rename to src/test/java/org/json/junit/data/MyEnumField.java index f0833ef..60e89de 100644 --- a/src/test/java/org/json/junit/MyEnumField.java +++ b/src/test/java/org/json/junit/data/MyEnumField.java @@ -1,4 +1,4 @@ -package org.json.junit; +package org.json.junit.data; /** * An enum that contains getters and some internal fields diff --git a/src/test/java/org/json/junit/MyJsonString.java b/src/test/java/org/json/junit/data/MyJsonString.java similarity index 67% rename from src/test/java/org/json/junit/MyJsonString.java rename to src/test/java/org/json/junit/data/MyJsonString.java index 4e63693..4ddde53 100644 --- a/src/test/java/org/json/junit/MyJsonString.java +++ b/src/test/java/org/json/junit/data/MyJsonString.java @@ -1,11 +1,11 @@ -package org.json.junit; +package org.json.junit.data; import org.json.*; /** * Used in testing when a JSONString is needed */ -class MyJsonString implements JSONString { +public class MyJsonString implements JSONString { @Override public String toJSONString() { diff --git a/src/test/java/org/json/junit/MyLocaleBean.java b/src/test/java/org/json/junit/data/MyLocaleBean.java similarity index 88% rename from src/test/java/org/json/junit/MyLocaleBean.java rename to src/test/java/org/json/junit/data/MyLocaleBean.java index 0d68c39..846e1c5 100755 --- a/src/test/java/org/json/junit/MyLocaleBean.java +++ b/src/test/java/org/json/junit/data/MyLocaleBean.java @@ -1,4 +1,4 @@ -package org.json.junit; +package org.json.junit.data; public class MyLocaleBean { private final String id = "beanId"; diff --git a/src/test/java/org/json/junit/MyNumber.java b/src/test/java/org/json/junit/data/MyNumber.java similarity index 98% rename from src/test/java/org/json/junit/MyNumber.java rename to src/test/java/org/json/junit/data/MyNumber.java index 243a967..4b625af 100644 --- a/src/test/java/org/json/junit/MyNumber.java +++ b/src/test/java/org/json/junit/data/MyNumber.java @@ -1,4 +1,4 @@ -package org.json.junit; +package org.json.junit.data; import java.math.BigDecimal; diff --git a/src/test/java/org/json/junit/MyNumberContainer.java b/src/test/java/org/json/junit/data/MyNumberContainer.java similarity index 90% rename from src/test/java/org/json/junit/MyNumberContainer.java rename to src/test/java/org/json/junit/data/MyNumberContainer.java index 524f318..6527652 100644 --- a/src/test/java/org/json/junit/MyNumberContainer.java +++ b/src/test/java/org/json/junit/data/MyNumberContainer.java @@ -1,4 +1,4 @@ -package org.json.junit; +package org.json.junit.data; /** * Class that holds our MyNumber override as a property. diff --git a/src/test/java/org/json/junit/MyPublicClass.java b/src/test/java/org/json/junit/data/MyPublicClass.java similarity index 87% rename from src/test/java/org/json/junit/MyPublicClass.java rename to src/test/java/org/json/junit/data/MyPublicClass.java index e483d4c..1f30386 100644 --- a/src/test/java/org/json/junit/MyPublicClass.java +++ b/src/test/java/org/json/junit/data/MyPublicClass.java @@ -1,4 +1,4 @@ -package org.json.junit; +package org.json.junit.data; /** * Need a class with some public data members for testing diff --git a/src/test/java/org/json/junit/StringsResourceBundle.java b/src/test/java/org/json/junit/data/StringsResourceBundle.java similarity index 93% rename from src/test/java/org/json/junit/StringsResourceBundle.java rename to src/test/java/org/json/junit/data/StringsResourceBundle.java index d04aeaf..4479350 100644 --- a/src/test/java/org/json/junit/StringsResourceBundle.java +++ b/src/test/java/org/json/junit/data/StringsResourceBundle.java @@ -1,4 +1,4 @@ -package org.json.junit; +package org.json.junit.data; import java.util.*; From 49117f33dcf5ff5800a244799bc5fd4fd3f1e2ee Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Sun, 9 Jul 2017 17:35:46 -0400 Subject: [PATCH 55/99] Adds new tests for testing bean->JSONObject mapping --- .../java/org/json/junit/JSONObjectTest.java | 80 ++++++++++++++++++ .../java/org/json/junit/data/GenericBean.java | 72 +++++++++++++++++ .../org/json/junit/data/GenericBeanInt.java | 29 +++++++ .../java/org/json/junit/data/Singleton.java | 81 +++++++++++++++++++ .../org/json/junit/data/SingletonEnum.java | 49 +++++++++++ .../java/org/json/junit/data/WeirdList.java | 45 +++++++++++ 6 files changed, 356 insertions(+) create mode 100644 src/test/java/org/json/junit/data/GenericBean.java create mode 100644 src/test/java/org/json/junit/data/GenericBeanInt.java create mode 100644 src/test/java/org/json/junit/data/Singleton.java create mode 100644 src/test/java/org/json/junit/data/SingletonEnum.java create mode 100644 src/test/java/org/json/junit/data/WeirdList.java diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 372e362..ae6a8b6 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -32,6 +33,8 @@ import org.json.XML; import org.json.junit.data.BrokenToString; import org.json.junit.data.Fraction; +import org.json.junit.data.GenericBean; +import org.json.junit.data.GenericBeanInt; import org.json.junit.data.MyBean; import org.json.junit.data.MyBigNumberBean; import org.json.junit.data.MyEnum; @@ -40,6 +43,9 @@ import org.json.junit.data.MyNumber; import org.json.junit.data.MyNumberContainer; import org.json.junit.data.MyPublicClass; +import org.json.junit.data.Singleton; +import org.json.junit.data.SingletonEnum; +import org.json.junit.data.WeirdList; import org.junit.Test; import com.jayway.jsonpath.Configuration; @@ -2583,4 +2589,78 @@ public void toMap() { assertTrue("Removing a key should succeed", map.remove("key3") != null); assertTrue("Map should have 2 elements", map.size() == 2); } + + @Test + public void testSingletonBean() { + final JSONObject jo = new JSONObject(Singleton.getInstance()); + assertEquals(jo.keySet().toString(), 1, jo.length()); + assertEquals(0, jo.get("someInt")); + assertEquals(null, jo.opt("someString")); + + // Update the singleton values + Singleton.getInstance().setSomeInt(42); + Singleton.getInstance().setSomeString("Something"); + final JSONObject jo2 = new JSONObject(Singleton.getInstance()); + assertEquals(2, jo2.length()); + assertEquals(42, jo2.get("someInt")); + assertEquals("Something", jo2.get("someString")); + + // ensure our original jo hasn't changed. + assertEquals(0, jo.get("someInt")); + assertEquals(null, jo.opt("someString")); + } + @Test + public void testSingletonEnumBean() { + final JSONObject jo = new JSONObject(SingletonEnum.getInstance()); + assertEquals(jo.keySet().toString(), 1, jo.length()); + assertEquals(0, jo.get("someInt")); + assertEquals(null, jo.opt("someString")); + + // Update the singleton values + SingletonEnum.getInstance().setSomeInt(42); + SingletonEnum.getInstance().setSomeString("Something"); + final JSONObject jo2 = new JSONObject(SingletonEnum.getInstance()); + assertEquals(2, jo2.length()); + assertEquals(42, jo2.get("someInt")); + assertEquals("Something", jo2.get("someString")); + + // ensure our original jo hasn't changed. + assertEquals(0, jo.get("someInt")); + assertEquals(null, jo.opt("someString")); + } + + @Test + public void testGenericBean() { + GenericBean bean = new GenericBean<>(42); + final JSONObject jo = new JSONObject(bean); + assertEquals(jo.keySet().toString(), 8, jo.length()); + assertEquals(42, jo.get("genericValue")); + assertEquals("Expected the getter to only be called once", + 1, bean.genericGetCounter); + assertEquals(0, bean.genericSetCounter); + } + + @Test + public void testGenericIntBean() { + GenericBeanInt bean = new GenericBeanInt(42); + final JSONObject jo = new JSONObject(bean); + assertEquals(jo.keySet().toString(), 9, jo.length()); + assertEquals(42, jo.get("genericValue")); + assertEquals("Expected the getter to only be called once", + 1, bean.genericGetCounter); + assertEquals(0, bean.genericSetCounter); + } + + @Test + public void testWierdListBean() { + WeirdList bean = new WeirdList(42, 43, 44); + final JSONObject jo = new JSONObject(bean); + // get() should have a key of 0 length + // get(int) should be ignored base on parameter count + // getInt(int) should also be ignored based on parameter count + // add(Integer) should be ignore as it doesn't start with get/is and also has a parameter + // getALL should be mapped + assertEquals("Expected 1 key to mapped "+jo.keySet().toString(), 1, jo.length()); + assertNotNull(jo.get("ALL")); + } } diff --git a/src/test/java/org/json/junit/data/GenericBean.java b/src/test/java/org/json/junit/data/GenericBean.java new file mode 100644 index 0000000..17f6def --- /dev/null +++ b/src/test/java/org/json/junit/data/GenericBean.java @@ -0,0 +1,72 @@ +package org.json.junit.data; + +import java.io.StringReader; + +/** + * + * @author John Aylward + * + * @param + * generic number value + */ +public class GenericBean> implements MyBean { + public GenericBean(T genericValue) { + super(); + this.genericValue = genericValue; + } + + /** */ + private T genericValue; + /** to be used by the calling test to see how often the getter is called */ + public int genericGetCounter; + /** to be used by the calling test to see how often the setter is called */ + public int genericSetCounter; + + /** @return the genericValue */ + public T getGenericValue() { + this.genericGetCounter++; + return this.genericValue; + } + + /** sets the generic value */ + public void setGenericValue(T genericValue) { + this.genericSetCounter++; + this.genericValue = genericValue; + } + + @Override + public Integer getIntKey() { + return Integer.valueOf(42); + } + + @Override + public Double getDoubleKey() { + return Double.valueOf(4.2); + } + + @Override + public String getStringKey() { + return "MyString Key"; + } + + @Override + public String getEscapeStringKey() { + return "\"My String with \"s"; + } + + @Override + public Boolean isTrueKey() { + return Boolean.TRUE; + } + + @Override + public Boolean isFalseKey() { + return Boolean.FALSE; + } + + @Override + public StringReader getStringReaderKey() { + return new StringReader("Some String Value in a reader"); + } + +} diff --git a/src/test/java/org/json/junit/data/GenericBeanInt.java b/src/test/java/org/json/junit/data/GenericBeanInt.java new file mode 100644 index 0000000..70dfb28 --- /dev/null +++ b/src/test/java/org/json/junit/data/GenericBeanInt.java @@ -0,0 +1,29 @@ +/** + * + */ +package org.json.junit.data; + +/** + * @author john + * + */ +public class GenericBeanInt extends GenericBean { + /** */ + final char a = 'A'; + + /** return the a */ + public char getA() { + return a; + } + + /** return false. should not be beanable */ + public boolean getable() { + return false; + } + + /** */ + public GenericBeanInt(Integer genericValue) { + super(genericValue); + } + +} diff --git a/src/test/java/org/json/junit/data/Singleton.java b/src/test/java/org/json/junit/data/Singleton.java new file mode 100644 index 0000000..55b37f9 --- /dev/null +++ b/src/test/java/org/json/junit/data/Singleton.java @@ -0,0 +1,81 @@ +package org.json.junit.data; + +/** + * Sample singleton for use with bean testing. + * + * @author John Aylward + * + */ +public final class Singleton { + /** */ + private int someInt; + /** */ + private String someString; + /** single instance. */ + private static final Singleton INSTANCE = new Singleton(); + + /** @return the singleton instance. */ + public static final Singleton getInstance() { + return INSTANCE; + } + + /** */ + private Singleton() { + if (INSTANCE != null) { + throw new IllegalStateException("Already instantiated"); + } + } + + @Override + protected Object clone() throws CloneNotSupportedException { + return INSTANCE; + } + + /** @return someInt */ + public int getSomeInt() { + return someInt; + } + + /** sets someInt */ + public void setSomeInt(int someInt) { + this.someInt = someInt; + } + + /** @return someString */ + public String getSomeString() { + return someString; + } + + /** sets someString */ + public void setSomeString(String someString) { + this.someString = someString; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + someInt; + result = prime * result + ((someString == null) ? 0 : someString.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Singleton other = (Singleton) obj; + if (someInt != other.someInt) + return false; + if (someString == null) { + if (other.someString != null) + return false; + } else if (!someString.equals(other.someString)) + return false; + return true; + } +} diff --git a/src/test/java/org/json/junit/data/SingletonEnum.java b/src/test/java/org/json/junit/data/SingletonEnum.java new file mode 100644 index 0000000..55c0e6c --- /dev/null +++ b/src/test/java/org/json/junit/data/SingletonEnum.java @@ -0,0 +1,49 @@ +package org.json.junit.data; + +/** + * Sample singleton done as an Enum for use with bean testing. + * + * @author John Aylward + * + */ +public enum SingletonEnum { + INSTANCE; + /** */ + private int someInt; + /** */ + private String someString; + + /** single instance. */ + + /** + * @return the singleton instance. I a real application, I'd hope no one did + * this to an enum singleton. + */ + public static final SingletonEnum getInstance() { + return INSTANCE; + } + + /** */ + private SingletonEnum() { + } + + /** @return someInt */ + public int getSomeInt() { + return someInt; + } + + /** sets someInt */ + public void setSomeInt(int someInt) { + this.someInt = someInt; + } + + /** @return someString */ + public String getSomeString() { + return someString; + } + + /** sets someString */ + public void setSomeString(String someString) { + this.someString = someString; + } +} diff --git a/src/test/java/org/json/junit/data/WeirdList.java b/src/test/java/org/json/junit/data/WeirdList.java new file mode 100644 index 0000000..315c144 --- /dev/null +++ b/src/test/java/org/json/junit/data/WeirdList.java @@ -0,0 +1,45 @@ +/** + * + */ +package org.json.junit.data; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author John Aylward + */ +public class WeirdList { + /** */ + private final List list = new ArrayList<>(); + + public WeirdList(Integer... vals) { + this.list.addAll(Arrays.asList(vals)); + } + + /** gets a copy of the list */ + public List get() { + return new ArrayList<>(this.list); + } + + /** gets a copy of the list */ + public List getALL() { + return new ArrayList<>(this.list); + } + + /** get an index */ + public Integer get(int i) { + return this.list.get(i); + } + + /** get an index */ + public int getInt(int i) { + return this.list.get(i); + } + + /** adds a new value to the end of the list */ + public void add(Integer value) { + this.list.add(value); + } +} \ No newline at end of file From 7bc8f4102360c6d143f6ea826863c4840b3b1f07 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Sun, 9 Jul 2017 18:07:11 -0400 Subject: [PATCH 56/99] Add override of the generic getter to generate a Bridge method. --- src/test/java/org/json/junit/data/GenericBeanInt.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/org/json/junit/data/GenericBeanInt.java b/src/test/java/org/json/junit/data/GenericBeanInt.java index 70dfb28..8549f19 100644 --- a/src/test/java/org/json/junit/data/GenericBeanInt.java +++ b/src/test/java/org/json/junit/data/GenericBeanInt.java @@ -26,4 +26,10 @@ public GenericBeanInt(Integer genericValue) { super(genericValue); } + /** override to generate a bridge method */ + @Override + public Integer getGenericValue() { + return super.getGenericValue(); + } + } From e94783f91b5423d728a11c3323461481883bf209 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Sun, 9 Jul 2017 18:19:27 -0400 Subject: [PATCH 57/99] Updates javadocs --- .../java/org/json/junit/JSONObjectTest.java | 19 ++++++++++- .../java/org/json/junit/data/GenericBean.java | 9 +++++- .../org/json/junit/data/GenericBeanInt.java | 15 ++++++--- .../java/org/json/junit/data/Singleton.java | 14 ++++++-- .../org/json/junit/data/SingletonEnum.java | 17 ++++++++-- .../java/org/json/junit/data/WeirdList.java | 32 ++++++++++++++++--- 6 files changed, 91 insertions(+), 15 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index ae6a8b6..190f32a 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -2590,6 +2590,9 @@ public void toMap() { assertTrue("Map should have 2 elements", map.size() == 2); } + /** + * test that validates a singleton can be serialized as a bean. + */ @Test public void testSingletonBean() { final JSONObject jo = new JSONObject(Singleton.getInstance()); @@ -2609,6 +2612,10 @@ public void testSingletonBean() { assertEquals(0, jo.get("someInt")); assertEquals(null, jo.opt("someString")); } + + /** + * test that validates a singleton can be serialized as a bean. + */ @Test public void testSingletonEnumBean() { final JSONObject jo = new JSONObject(SingletonEnum.getInstance()); @@ -2629,6 +2636,9 @@ public void testSingletonEnumBean() { assertEquals(null, jo.opt("someString")); } + /** + * Test to validate that a generic class can be serialized as a bean. + */ @Test public void testGenericBean() { GenericBean bean = new GenericBean<>(42); @@ -2640,6 +2650,9 @@ public void testGenericBean() { assertEquals(0, bean.genericSetCounter); } + /** + * Test to validate that a generic class can be serialized as a bean. + */ @Test public void testGenericIntBean() { GenericBeanInt bean = new GenericBeanInt(42); @@ -2651,6 +2664,9 @@ public void testGenericIntBean() { assertEquals(0, bean.genericSetCounter); } + /** + * Test to verify key limitations in the JSONObject bean serializer. + */ @Test public void testWierdListBean() { WeirdList bean = new WeirdList(42, 43, 44); @@ -2660,7 +2676,8 @@ public void testWierdListBean() { // getInt(int) should also be ignored based on parameter count // add(Integer) should be ignore as it doesn't start with get/is and also has a parameter // getALL should be mapped - assertEquals("Expected 1 key to mapped "+jo.keySet().toString(), 1, jo.length()); + assertEquals("Expected 1 key to be mapped. Instead found: "+jo.keySet().toString(), + 1, jo.length()); assertNotNull(jo.get("ALL")); } } diff --git a/src/test/java/org/json/junit/data/GenericBean.java b/src/test/java/org/json/junit/data/GenericBean.java index 17f6def..4740030 100644 --- a/src/test/java/org/json/junit/data/GenericBean.java +++ b/src/test/java/org/json/junit/data/GenericBean.java @@ -10,6 +10,10 @@ * generic number value */ public class GenericBean> implements MyBean { + /** + * @param genericValue + * value to initiate with + */ public GenericBean(T genericValue) { super(); this.genericValue = genericValue; @@ -28,7 +32,10 @@ public T getGenericValue() { return this.genericValue; } - /** sets the generic value */ + /** + * @param genericValue + * generic value to set + */ public void setGenericValue(T genericValue) { this.genericSetCounter++; this.genericValue = genericValue; diff --git a/src/test/java/org/json/junit/data/GenericBeanInt.java b/src/test/java/org/json/junit/data/GenericBeanInt.java index 8549f19..8f0248d 100644 --- a/src/test/java/org/json/junit/data/GenericBeanInt.java +++ b/src/test/java/org/json/junit/data/GenericBeanInt.java @@ -11,17 +11,24 @@ public class GenericBeanInt extends GenericBean { /** */ final char a = 'A'; - /** return the a */ + /** @return the a */ public char getA() { return a; } - - /** return false. should not be beanable */ + + /** + * Should not be beanable + * + * @return false + */ public boolean getable() { return false; } - /** */ + /** + * @param genericValue + * the value to initiate with. + */ public GenericBeanInt(Integer genericValue) { super(genericValue); } diff --git a/src/test/java/org/json/junit/data/Singleton.java b/src/test/java/org/json/junit/data/Singleton.java index 55b37f9..36a9824 100644 --- a/src/test/java/org/json/junit/data/Singleton.java +++ b/src/test/java/org/json/junit/data/Singleton.java @@ -36,7 +36,12 @@ public int getSomeInt() { return someInt; } - /** sets someInt */ + /** + * sets someInt. + * + * @param someInt + * the someInt to set + */ public void setSomeInt(int someInt) { this.someInt = someInt; } @@ -46,7 +51,12 @@ public String getSomeString() { return someString; } - /** sets someString */ + /** + * sets someString. + * + * @param someString + * the someString to set + */ public void setSomeString(String someString) { this.someString = someString; } diff --git a/src/test/java/org/json/junit/data/SingletonEnum.java b/src/test/java/org/json/junit/data/SingletonEnum.java index 55c0e6c..8147cc6 100644 --- a/src/test/java/org/json/junit/data/SingletonEnum.java +++ b/src/test/java/org/json/junit/data/SingletonEnum.java @@ -7,6 +7,9 @@ * */ public enum SingletonEnum { + /** + * the singleton instance. + */ INSTANCE; /** */ private int someInt; @@ -32,7 +35,12 @@ public int getSomeInt() { return someInt; } - /** sets someInt */ + /** + * sets someInt. + * + * @param someInt + * the someInt to set + */ public void setSomeInt(int someInt) { this.someInt = someInt; } @@ -42,7 +50,12 @@ public String getSomeString() { return someString; } - /** sets someString */ + /** + * sets someString. + * + * @param someString + * the someString to set + */ public void setSomeString(String someString) { this.someString = someString; } diff --git a/src/test/java/org/json/junit/data/WeirdList.java b/src/test/java/org/json/junit/data/WeirdList.java index 315c144..77cd17f 100644 --- a/src/test/java/org/json/junit/data/WeirdList.java +++ b/src/test/java/org/json/junit/data/WeirdList.java @@ -14,31 +14,53 @@ public class WeirdList { /** */ private final List list = new ArrayList<>(); + /** + * @param vals + */ public WeirdList(Integer... vals) { this.list.addAll(Arrays.asList(vals)); } - /** gets a copy of the list */ + /** + * @return a copy of the list + */ public List get() { return new ArrayList<>(this.list); } - /** gets a copy of the list */ + /** + * @return a copy of the list + */ public List getALL() { return new ArrayList<>(this.list); } - /** get an index */ + /** + * get a value at an index. + * + * @param i + * index to get + * @return the value at the index + */ public Integer get(int i) { return this.list.get(i); } - /** get an index */ + /** + * get a value at an index. + * + * @param i + * index to get + * @return the value at the index + */ public int getInt(int i) { return this.list.get(i); } - /** adds a new value to the end of the list */ + /** + * @param value + * new value to add to the end of the list + */ public void add(Integer value) { this.list.add(value); } From 38d11227ee5608536b78af410e50d4af293626a8 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Sun, 9 Jul 2017 19:05:00 -0400 Subject: [PATCH 58/99] Adds exception tests --- .../java/org/json/junit/JSONObjectTest.java | 14 ++++ .../org/json/junit/data/ExceptionalBean.java | 69 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/test/java/org/json/junit/data/ExceptionalBean.java diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 190f32a..8e61c53 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -32,6 +32,7 @@ import org.json.JSONPointerException; import org.json.XML; import org.json.junit.data.BrokenToString; +import org.json.junit.data.ExceptionalBean; import org.json.junit.data.Fraction; import org.json.junit.data.GenericBean; import org.json.junit.data.GenericBeanInt; @@ -2680,4 +2681,17 @@ public void testWierdListBean() { 1, jo.length()); assertNotNull(jo.get("ALL")); } + + /** + * Tests the exception portions of populateMap. + */ + @Test + public void testExceptionalBean() { + ExceptionalBean bean = new ExceptionalBean(); + final JSONObject jo = new JSONObject(bean); + assertEquals("Expected 1 key to be mapped. Instead found: "+jo.keySet().toString(), + 1, jo.length()); + assertTrue(jo.get("closeable") instanceof JSONObject); + assertTrue(jo.getJSONObject("closeable").has("string")); + } } diff --git a/src/test/java/org/json/junit/data/ExceptionalBean.java b/src/test/java/org/json/junit/data/ExceptionalBean.java new file mode 100644 index 0000000..74d78a7 --- /dev/null +++ b/src/test/java/org/json/junit/data/ExceptionalBean.java @@ -0,0 +1,69 @@ +/** + * + */ +package org.json.junit.data; + +import java.io.Closeable; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import org.json.JSONObject; + +/** + * Object for testing the exception handling in {@link JSONObject#populateMap}. + * + * @author John Aylward + */ +public class ExceptionalBean { + /** + * @return a closeable. + */ + public Closeable getCloseable() { + // anonymous inner class did not work... + return new MyCloseable(); + } + + /** + * @return Nothing really. Just can't be void. + * @throws IllegalAccessException + * always thrown + */ + public int getIllegalAccessException() throws IllegalAccessException { + throw new IllegalAccessException("Yup, it's illegal"); + } + + /** + * @return Nothing really. Just can't be void. + * @throws IllegalArgumentException + * always thrown + */ + public int getIllegalArgumentException() throws IllegalArgumentException { + throw new IllegalArgumentException("Yup, it's illegal"); + } + + /** + * @return Nothing really. Just can't be void. + * @throws InvocationTargetException + * always thrown + */ + public int getInvocationTargetException() throws InvocationTargetException { + throw new InvocationTargetException(new Exception("Yup, it's illegal")); + } + + /** My closeable class. */ + public static final class MyCloseable implements Closeable { + + /** + * @return a string + */ + @SuppressWarnings("unused") + public String getString() { + return "Yup, it's closeable"; + } + + @Override + public void close() throws IOException { + throw new IOException("Closing is too hard!"); + } + } +} From aa562b5ec3d87f4f4f0bff8ac9fb4552c8d271f8 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Sat, 15 Jul 2017 12:19:02 -0400 Subject: [PATCH 59/99] Update test for issue https://github.com/stleary/JSON-java/issues/356 --- src/test/java/org/json/junit/JSONObjectTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index cabd41c..0e6a691 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1622,10 +1622,13 @@ public void jsonObjectToStringIndent() { " ]\n" + "}"; JSONObject jsonObject = new JSONObject(jsonObject0Str); - assertEquals(jsonObject0Str, jsonObject.toString()); - assertEquals(jsonObject0Str, jsonObject.toString(0)); - assertEquals(jsonObject1Str, jsonObject.toString(1)); - assertEquals(jsonObject4Str, jsonObject.toString(4)); + assertEquals("toString()",jsonObject0Str, jsonObject.toString()); + assertEquals("toString(0)",jsonObject0Str, jsonObject.toString(0)); + assertEquals("toString(1)",jsonObject1Str, jsonObject.toString(1)); + assertEquals("toString(4)",jsonObject4Str, jsonObject.toString(4)); + + JSONObject jo = new JSONObject().put("TABLE", new JSONObject().put("yhoo", new JSONObject())); + assertEquals("toString(2)","{\"TABLE\": {\"yhoo\": {}}}", jo.toString(2)); } /** From f2f6ad3b1f9324439489b5454811108faa3a3fd2 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 19 Jul 2017 20:34:59 -0400 Subject: [PATCH 60/99] * Fixes Gradle config so tests are only run once * Adds missing test to the test suite --- build.gradle | 5 ++++- src/test/java/org/json/junit/JunitTestSuite.java | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 58259f9..43656ae 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,10 @@ dependencies { // testCompile files('./JSON-Java.jar') } -test { finalizedBy jacocoTestReport } +test { + include "org/json/junit/JunitTestSuite.class" + finalizedBy jacocoTestReport +} jacocoTestReport{ additionalSourceDirs = files(sourceSets.main.allJava.srcDirs) reports { diff --git a/src/test/java/org/json/junit/JunitTestSuite.java b/src/test/java/org/json/junit/JunitTestSuite.java index 36bec60..9c9a325 100644 --- a/src/test/java/org/json/junit/JunitTestSuite.java +++ b/src/test/java/org/json/junit/JunitTestSuite.java @@ -17,7 +17,8 @@ JSONArrayTest.class, EnumTest.class, JSONPointerTest.class, - JSONStringTest.class + JSONStringTest.class, + JSONTokenerTest.class }) public class JunitTestSuite { } From fefd616d73c063de3ffb4749e6b46b363eea3e93 Mon Sep 17 00:00:00 2001 From: Miguel Date: Wed, 9 Aug 2017 21:51:46 -0400 Subject: [PATCH 61/99] Unit tests for JSONTokener --- build.gradle | 1 + .../java/org/json/junit/JSONObjectTest.java | 170 ++++++++++++++++++ 2 files changed, 171 insertions(+) diff --git a/build.gradle b/build.gradle index 43656ae..53fbdb3 100644 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,7 @@ dependencies { testCompile group: 'junit', name: 'junit', version: '4.+' testCompile group: 'com.jayway.jsonpath', name: 'json-path', version: '2.1.0' testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5' + testCompile group: 'slf4j.org', name: 'slf4j', version: '1.6.1' // Uncomment if you are testing against a JSON-Java release // testCompile 'org.json:json:20160212' // Uncomment if you have copied a local JSON-Java jar file into this project diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 1231ec9..35cf493 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1976,6 +1976,176 @@ public void jsonObjectParsingErrors() { } catch (JSONException e) { assertTrue("", true); } + try { + // test exception message when including a duplicate key (level 0) + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr03\":\"value-04\"\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); + } catch (JSONException e) { + assertEquals("Expecting an expection message", + "Duplicate key \"attr03\" at 90 [character 13 line 5]", + e.getMessage()); + } + try { + // test exception message when including a duplicate key (level 0) holding an object + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr03\": {" + +" \"attr04-01\":\"value-04-01\",n" + +" \"attr04-02\":\"value-04-02\",n" + +" \"attr04-03\":\"value-04-03\"n" + + " }\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); + } catch (JSONException e) { + assertEquals("Expecting an expection message", + "Duplicate key \"attr03\" at 90 [character 13 line 5]", + e.getMessage()); + } + try { + // test exception message when including a duplicate key (level 0) holding an array + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr03\": [\n" + +" {" + +" \"attr04-01\":\"value-04-01\",n" + +" \"attr04-02\":\"value-04-02\",n" + +" \"attr04-03\":\"value-04-03\"n" + +" }\n" + + " ]\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); + } catch (JSONException e) { + assertEquals("Expecting an expection message", + "Duplicate key \"attr03\" at 90 [character 13 line 5]", + e.getMessage()); + } + try { + // test exception message when including a duplicate key (level 1) + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr04\": {\n" + +" \"attr04-01\":\"value04-01\",\n" + +" \"attr04-02\":\"value04-02\",\n" + +" \"attr04-03\":\"value04-03\",\n" + +" \"attr04-03\":\"value04-04\"\n" + + " }\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); + } catch (JSONException e) { + assertEquals("Expecting an expection message", + "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", + e.getMessage()); + } + try { + // test exception message when including a duplicate key (level 1) holding an object + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr04\": {\n" + +" \"attr04-01\":\"value04-01\",\n" + +" \"attr04-02\":\"value04-02\",\n" + +" \"attr04-03\":\"value04-03\",\n" + +" \"attr04-03\": {\n" + +" \"attr04-04-01\":\"value04-04-01\",\n" + +" \"attr04-04-02\":\"value04-04-02\",\n" + +" \"attr04-04-03\":\"value04-04-03\",\n" + +" }\n" + +" }\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); + } catch (JSONException e) { + assertEquals("Expecting an expection message", + "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", + e.getMessage()); + } + try { + // test exception message when including a duplicate key (level 1) holding an array + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr04\": {\n" + +" \"attr04-01\":\"value04-01\",\n" + +" \"attr04-02\":\"value04-02\",\n" + +" \"attr04-03\":\"value04-03\",\n" + +" \"attr04-03\": [\n" + +" {\n" + +" \"attr04-04-01\":\"value04-04-01\",\n" + +" \"attr04-04-02\":\"value04-04-02\",\n" + +" \"attr04-04-03\":\"value04-04-03\",\n" + +" }\n" + +" ]\n" + +" }\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); + } catch (JSONException e) { + assertEquals("Expecting an expection message", + "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", + e.getMessage()); + } + try { + // test exception message when including a duplicate key in object (level 0) within an array + String str = "[\n" + +" {\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\"\n" + +" },\n" + +" {\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr01\":\"value-02\"\n" + +" }\n" + + "]"; + new JSONArray(str); + fail("Expected an exception"); + } catch (JSONException e) { + assertEquals("Expecting an expection message", + "Duplicate key \"attr01\" at 124 [character 17 line 8]", + e.getMessage()); + } + try { + // test exception message when including a duplicate key in object (level 1) within an array + String str = "[\n" + +" {\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\": {\n" + +" \"attr02-01\":\"value-02-01\",\n" + +" \"attr02-02\":\"value-02-02\"\n" + +" }\n" + +" },\n" + +" {\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\": {\n" + +" \"attr02-01\":\"value-02-01\",\n" + +" \"attr02-01\":\"value-02-02\"\n" + +" }\n" + +" }\n" + + "]"; + System.out.println(str); + new JSONArray(str); + fail("Expected an exception"); + } catch (JSONException e) { + assertEquals("Expecting an expection message", + "Duplicate key \"attr02-01\" at 269 [character 24 line 13]", + e.getMessage()); + } } /** From 1acb18091a7006fd8a113c474a912cfd4cc6a375 Mon Sep 17 00:00:00 2001 From: Miguel Date: Wed, 9 Aug 2017 21:57:10 -0400 Subject: [PATCH 62/99] Remove System.out.println --- src/test/java/org/json/junit/JSONObjectTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 35cf493..6470ebb 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -2138,7 +2138,6 @@ public void jsonObjectParsingErrors() { +" }\n" +" }\n" + "]"; - System.out.println(str); new JSONArray(str); fail("Expected an exception"); } catch (JSONException e) { From df466db7b9630e689813dd82de5f512ca0713273 Mon Sep 17 00:00:00 2001 From: Miguel Date: Wed, 9 Aug 2017 21:59:08 -0400 Subject: [PATCH 63/99] Replacing tabs with 4 spaces --- .../java/org/json/junit/JSONObjectTest.java | 290 +++++++++--------- 1 file changed, 145 insertions(+), 145 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 6470ebb..2dcebe4 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1977,173 +1977,173 @@ public void jsonObjectParsingErrors() { assertTrue("", true); } try { - // test exception message when including a duplicate key (level 0) - String str = "{\n" - +" \"attr01\":\"value-01\",\n" - +" \"attr02\":\"value-02\",\n" - +" \"attr03\":\"value-03\",\n" - +" \"attr03\":\"value-04\"\n" - + "}"; - new JSONObject(str); - fail("Expected an exception"); + // test exception message when including a duplicate key (level 0) + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr03\":\"value-04\"\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); } catch (JSONException e) { - assertEquals("Expecting an expection message", - "Duplicate key \"attr03\" at 90 [character 13 line 5]", - e.getMessage()); + assertEquals("Expecting an expection message", + "Duplicate key \"attr03\" at 90 [character 13 line 5]", + e.getMessage()); } try { - // test exception message when including a duplicate key (level 0) holding an object - String str = "{\n" - +" \"attr01\":\"value-01\",\n" - +" \"attr02\":\"value-02\",\n" - +" \"attr03\":\"value-03\",\n" - +" \"attr03\": {" - +" \"attr04-01\":\"value-04-01\",n" - +" \"attr04-02\":\"value-04-02\",n" - +" \"attr04-03\":\"value-04-03\"n" - + " }\n" - + "}"; - new JSONObject(str); - fail("Expected an exception"); + // test exception message when including a duplicate key (level 0) holding an object + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr03\": {" + +" \"attr04-01\":\"value-04-01\",n" + +" \"attr04-02\":\"value-04-02\",n" + +" \"attr04-03\":\"value-04-03\"n" + + " }\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); } catch (JSONException e) { - assertEquals("Expecting an expection message", - "Duplicate key \"attr03\" at 90 [character 13 line 5]", - e.getMessage()); + assertEquals("Expecting an expection message", + "Duplicate key \"attr03\" at 90 [character 13 line 5]", + e.getMessage()); } try { - // test exception message when including a duplicate key (level 0) holding an array - String str = "{\n" - +" \"attr01\":\"value-01\",\n" - +" \"attr02\":\"value-02\",\n" - +" \"attr03\":\"value-03\",\n" - +" \"attr03\": [\n" - +" {" - +" \"attr04-01\":\"value-04-01\",n" - +" \"attr04-02\":\"value-04-02\",n" - +" \"attr04-03\":\"value-04-03\"n" - +" }\n" - + " ]\n" - + "}"; - new JSONObject(str); - fail("Expected an exception"); + // test exception message when including a duplicate key (level 0) holding an array + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr03\": [\n" + +" {" + +" \"attr04-01\":\"value-04-01\",n" + +" \"attr04-02\":\"value-04-02\",n" + +" \"attr04-03\":\"value-04-03\"n" + +" }\n" + + " ]\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); } catch (JSONException e) { - assertEquals("Expecting an expection message", - "Duplicate key \"attr03\" at 90 [character 13 line 5]", - e.getMessage()); + assertEquals("Expecting an expection message", + "Duplicate key \"attr03\" at 90 [character 13 line 5]", + e.getMessage()); } try { - // test exception message when including a duplicate key (level 1) - String str = "{\n" - +" \"attr01\":\"value-01\",\n" - +" \"attr02\":\"value-02\",\n" - +" \"attr03\":\"value-03\",\n" - +" \"attr04\": {\n" - +" \"attr04-01\":\"value04-01\",\n" - +" \"attr04-02\":\"value04-02\",\n" - +" \"attr04-03\":\"value04-03\",\n" - +" \"attr04-03\":\"value04-04\"\n" - + " }\n" - + "}"; - new JSONObject(str); - fail("Expected an exception"); + // test exception message when including a duplicate key (level 1) + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr04\": {\n" + +" \"attr04-01\":\"value04-01\",\n" + +" \"attr04-02\":\"value04-02\",\n" + +" \"attr04-03\":\"value04-03\",\n" + +" \"attr04-03\":\"value04-04\"\n" + + " }\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); } catch (JSONException e) { - assertEquals("Expecting an expection message", - "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", - e.getMessage()); + assertEquals("Expecting an expection message", + "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", + e.getMessage()); } try { - // test exception message when including a duplicate key (level 1) holding an object - String str = "{\n" - +" \"attr01\":\"value-01\",\n" - +" \"attr02\":\"value-02\",\n" - +" \"attr03\":\"value-03\",\n" - +" \"attr04\": {\n" - +" \"attr04-01\":\"value04-01\",\n" - +" \"attr04-02\":\"value04-02\",\n" - +" \"attr04-03\":\"value04-03\",\n" - +" \"attr04-03\": {\n" - +" \"attr04-04-01\":\"value04-04-01\",\n" - +" \"attr04-04-02\":\"value04-04-02\",\n" - +" \"attr04-04-03\":\"value04-04-03\",\n" - +" }\n" - +" }\n" - + "}"; - new JSONObject(str); - fail("Expected an exception"); + // test exception message when including a duplicate key (level 1) holding an object + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr04\": {\n" + +" \"attr04-01\":\"value04-01\",\n" + +" \"attr04-02\":\"value04-02\",\n" + +" \"attr04-03\":\"value04-03\",\n" + +" \"attr04-03\": {\n" + +" \"attr04-04-01\":\"value04-04-01\",\n" + +" \"attr04-04-02\":\"value04-04-02\",\n" + +" \"attr04-04-03\":\"value04-04-03\",\n" + +" }\n" + +" }\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); } catch (JSONException e) { - assertEquals("Expecting an expection message", - "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", - e.getMessage()); + assertEquals("Expecting an expection message", + "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", + e.getMessage()); } try { - // test exception message when including a duplicate key (level 1) holding an array - String str = "{\n" - +" \"attr01\":\"value-01\",\n" - +" \"attr02\":\"value-02\",\n" - +" \"attr03\":\"value-03\",\n" - +" \"attr04\": {\n" - +" \"attr04-01\":\"value04-01\",\n" - +" \"attr04-02\":\"value04-02\",\n" - +" \"attr04-03\":\"value04-03\",\n" - +" \"attr04-03\": [\n" - +" {\n" - +" \"attr04-04-01\":\"value04-04-01\",\n" - +" \"attr04-04-02\":\"value04-04-02\",\n" - +" \"attr04-04-03\":\"value04-04-03\",\n" - +" }\n" - +" ]\n" - +" }\n" - + "}"; - new JSONObject(str); - fail("Expected an exception"); + // test exception message when including a duplicate key (level 1) holding an array + String str = "{\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\",\n" + +" \"attr03\":\"value-03\",\n" + +" \"attr04\": {\n" + +" \"attr04-01\":\"value04-01\",\n" + +" \"attr04-02\":\"value04-02\",\n" + +" \"attr04-03\":\"value04-03\",\n" + +" \"attr04-03\": [\n" + +" {\n" + +" \"attr04-04-01\":\"value04-04-01\",\n" + +" \"attr04-04-02\":\"value04-04-02\",\n" + +" \"attr04-04-03\":\"value04-04-03\",\n" + +" }\n" + +" ]\n" + +" }\n" + + "}"; + new JSONObject(str); + fail("Expected an exception"); } catch (JSONException e) { - assertEquals("Expecting an expection message", - "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", - e.getMessage()); + assertEquals("Expecting an expection message", + "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", + e.getMessage()); } try { - // test exception message when including a duplicate key in object (level 0) within an array - String str = "[\n" - +" {\n" - +" \"attr01\":\"value-01\",\n" - +" \"attr02\":\"value-02\"\n" - +" },\n" - +" {\n" - +" \"attr01\":\"value-01\",\n" - +" \"attr01\":\"value-02\"\n" - +" }\n" - + "]"; - new JSONArray(str); - fail("Expected an exception"); + // test exception message when including a duplicate key in object (level 0) within an array + String str = "[\n" + +" {\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\":\"value-02\"\n" + +" },\n" + +" {\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr01\":\"value-02\"\n" + +" }\n" + + "]"; + new JSONArray(str); + fail("Expected an exception"); } catch (JSONException e) { - assertEquals("Expecting an expection message", - "Duplicate key \"attr01\" at 124 [character 17 line 8]", - e.getMessage()); + assertEquals("Expecting an expection message", + "Duplicate key \"attr01\" at 124 [character 17 line 8]", + e.getMessage()); } try { - // test exception message when including a duplicate key in object (level 1) within an array - String str = "[\n" - +" {\n" - +" \"attr01\":\"value-01\",\n" - +" \"attr02\": {\n" - +" \"attr02-01\":\"value-02-01\",\n" - +" \"attr02-02\":\"value-02-02\"\n" - +" }\n" - +" },\n" - +" {\n" - +" \"attr01\":\"value-01\",\n" - +" \"attr02\": {\n" - +" \"attr02-01\":\"value-02-01\",\n" - +" \"attr02-01\":\"value-02-02\"\n" - +" }\n" - +" }\n" - + "]"; - new JSONArray(str); - fail("Expected an exception"); + // test exception message when including a duplicate key in object (level 1) within an array + String str = "[\n" + +" {\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\": {\n" + +" \"attr02-01\":\"value-02-01\",\n" + +" \"attr02-02\":\"value-02-02\"\n" + +" }\n" + +" },\n" + +" {\n" + +" \"attr01\":\"value-01\",\n" + +" \"attr02\": {\n" + +" \"attr02-01\":\"value-02-01\",\n" + +" \"attr02-01\":\"value-02-02\"\n" + +" }\n" + +" }\n" + + "]"; + new JSONArray(str); + fail("Expected an exception"); } catch (JSONException e) { - assertEquals("Expecting an expection message", - "Duplicate key \"attr02-01\" at 269 [character 24 line 13]", - e.getMessage()); + assertEquals("Expecting an expection message", + "Duplicate key \"attr02-01\" at 269 [character 24 line 13]", + e.getMessage()); } } From c365e2a774693a8bdf8b19c6ddcd039678856ed4 Mon Sep 17 00:00:00 2001 From: Miguel Date: Wed, 9 Aug 2017 22:03:09 -0400 Subject: [PATCH 64/99] Remov slf4j reference --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index 53fbdb3..43656ae 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,6 @@ dependencies { testCompile group: 'junit', name: 'junit', version: '4.+' testCompile group: 'com.jayway.jsonpath', name: 'json-path', version: '2.1.0' testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5' - testCompile group: 'slf4j.org', name: 'slf4j', version: '1.6.1' // Uncomment if you are testing against a JSON-Java release // testCompile 'org.json:json:20160212' // Uncomment if you have copied a local JSON-Java jar file into this project From 68b262914df7b3a98b2d970edb1adc9b72fed4fb Mon Sep 17 00:00:00 2001 From: Miguel Date: Thu, 10 Aug 2017 19:06:55 -0400 Subject: [PATCH 65/99] JSONObject(JSONTokener) now points to last character of duplicate key Updating exception message accordingly (position -1) --- src/test/java/org/json/junit/JSONObjectTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 2dcebe4..5d49daa 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1988,7 +1988,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr03\" at 90 [character 13 line 5]", + "Duplicate key \"attr03\" at 89 [character 12 line 5]", e.getMessage()); } try { @@ -2007,7 +2007,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr03\" at 90 [character 13 line 5]", + "Duplicate key \"attr03\" at 89 [character 12 line 5]", e.getMessage()); } try { @@ -2028,7 +2028,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr03\" at 90 [character 13 line 5]", + "Duplicate key \"attr03\" at 89 [character 12 line 5]", e.getMessage()); } try { @@ -2048,7 +2048,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", + "Duplicate key \"attr04-03\" at 214 [character 19 line 9]", e.getMessage()); } try { @@ -2072,7 +2072,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", + "Duplicate key \"attr04-03\" at 214 [character 19 line 9]", e.getMessage()); } try { @@ -2098,7 +2098,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", + "Duplicate key \"attr04-03\" at 214 [character 19 line 9]", e.getMessage()); } try { @@ -2117,7 +2117,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr01\" at 124 [character 17 line 8]", + "Duplicate key \"attr01\" at 123 [character 16 line 8]", e.getMessage()); } try { @@ -2142,7 +2142,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr02-01\" at 269 [character 24 line 13]", + "Duplicate key \"attr02-01\" at 268 [character 23 line 13]", e.getMessage()); } } From b90bee0f225e2502c8b62d494f571fd27ce5bea4 Mon Sep 17 00:00:00 2001 From: Miguel Date: Mon, 14 Aug 2017 13:05:23 -0400 Subject: [PATCH 66/99] Update error message location (+1) `JSONTokener.back()` call removed from `JSONObject(JSONTokener)` constructor. --- src/test/java/org/json/junit/JSONObjectTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 5d49daa..2dcebe4 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1988,7 +1988,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr03\" at 89 [character 12 line 5]", + "Duplicate key \"attr03\" at 90 [character 13 line 5]", e.getMessage()); } try { @@ -2007,7 +2007,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr03\" at 89 [character 12 line 5]", + "Duplicate key \"attr03\" at 90 [character 13 line 5]", e.getMessage()); } try { @@ -2028,7 +2028,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr03\" at 89 [character 12 line 5]", + "Duplicate key \"attr03\" at 90 [character 13 line 5]", e.getMessage()); } try { @@ -2048,7 +2048,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr04-03\" at 214 [character 19 line 9]", + "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", e.getMessage()); } try { @@ -2072,7 +2072,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr04-03\" at 214 [character 19 line 9]", + "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", e.getMessage()); } try { @@ -2098,7 +2098,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr04-03\" at 214 [character 19 line 9]", + "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", e.getMessage()); } try { @@ -2117,7 +2117,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr01\" at 123 [character 16 line 8]", + "Duplicate key \"attr01\" at 124 [character 17 line 8]", e.getMessage()); } try { @@ -2142,7 +2142,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an expection message", - "Duplicate key \"attr02-01\" at 268 [character 23 line 13]", + "Duplicate key \"attr02-01\" at 269 [character 24 line 13]", e.getMessage()); } } From cb61bbf720253b2d93832544b189d0a78501c604 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Sat, 19 Aug 2017 18:19:22 -0400 Subject: [PATCH 67/99] New tests for XML unescaping --- src/test/java/org/json/junit/XMLTest.java | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 244c9e9..5daca5c 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -764,5 +764,29 @@ public void testToJsonXML() { assertEquals(expectedReverseXml, reverseXml); } + + /** + * test to validate certain conditions of XML unescaping. + */ + @Test + public void testUnescape() { + assertEquals("{\"xml\":\"Can cope <;\"}", + XML.toJSONObject("Can cope <; ").toString()); + assertEquals("Can cope <; ", XML.unescape("Can cope <; ")); + + assertEquals("{\"xml\":\"Can cope & ;\"}", + XML.toJSONObject("Can cope & ; ").toString()); + assertEquals("Can cope & ; ", XML.unescape("Can cope & ; ")); + + assertEquals("{\"xml\":\"Can cope &;\"}", + XML.toJSONObject("Can cope &; ").toString()); + assertEquals("Can cope &; ", XML.unescape("Can cope &; ")); + + // double escaped + assertEquals("{\"xml\":\"Can cope <\"}", + XML.toJSONObject("Can cope &lt; ").toString()); + assertEquals("Can cope < ", XML.unescape("Can cope &lt; ")); + + } } \ No newline at end of file From 2713f2e2a4a5fa93cdf47b4f926ff5ea088abe68 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Sat, 19 Aug 2017 18:45:53 -0400 Subject: [PATCH 68/99] Adds testing for unicode entities --- src/test/java/org/json/junit/XMLTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 5daca5c..c34bf0f 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -782,11 +782,20 @@ public void testUnescape() { XML.toJSONObject("Can cope &; ").toString()); assertEquals("Can cope &; ", XML.unescape("Can cope &; ")); + // unicode entity + assertEquals("{\"xml\":\"Can cope 4;\"}", + XML.toJSONObject("Can cope 4; ").toString()); + assertEquals("Can cope 4; ", XML.unescape("Can cope 4; ")); + // double escaped assertEquals("{\"xml\":\"Can cope <\"}", XML.toJSONObject("Can cope &lt; ").toString()); assertEquals("Can cope < ", XML.unescape("Can cope &lt; ")); - } + assertEquals("{\"xml\":\"Can cope 4\"}", + XML.toJSONObject("Can cope &#x34; ").toString()); + assertEquals("Can cope 4 ", XML.unescape("Can cope &#x34; ")); + + } } \ No newline at end of file From 52ecc8970237e50f52632b42f4b30ef98e565b51 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 30 Oct 2017 07:27:42 -0400 Subject: [PATCH 69/99] New test to verify unclosed array --- src/test/java/org/json/junit/JSONArrayTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 0df7c5d..1c14774 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -79,6 +79,21 @@ public void emptStr() { e.getMessage()); } } + + /** + * Attempt to create a JSONArray with an unclosed array. + * Expects an exception + */ + @Test + public void unclosedArray() { + try { + assertNull("Should throw an exception", new JSONArray("[")); + } catch (JSONException e) { + assertEquals("Expected an exception message", + "A JSONArray text must start with '[' at 0 [character 1 line 1]", + e.getMessage()); + } + } /** * Attempt to create a JSONArray with a string as object that is From bde6ba1c52b1393526a24d51b04a2295e786ebfa Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 30 Oct 2017 07:41:11 -0400 Subject: [PATCH 70/99] Updates exception expected message --- src/test/java/org/json/junit/JSONArrayTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 1c14774..442fb0a 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -90,7 +90,7 @@ public void unclosedArray() { assertNull("Should throw an exception", new JSONArray("[")); } catch (JSONException e) { assertEquals("Expected an exception message", - "A JSONArray text must start with '[' at 0 [character 1 line 1]", + "Expected a ',' or ']' at 1 [character 2 line 1]", e.getMessage()); } } From dfa37a298f019516224fe1b563a4fec66253e103 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 30 Oct 2017 08:09:42 -0400 Subject: [PATCH 71/99] Add more tests for unclosed arrays --- .../java/org/json/junit/JSONArrayTest.java | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 442fb0a..4a0249d 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -30,7 +30,7 @@ * Tests for JSON-Java JSONArray.java */ public class JSONArrayTest { - String arrayStr = + private final String arrayStr = "["+ "true,"+ "false,"+ @@ -94,6 +94,36 @@ public void unclosedArray() { e.getMessage()); } } + + /** + * Attempt to create a JSONArray with an unclosed array. + * Expects an exception + */ + @Test + public void unclosedArray2() { + try { + assertNull("Should throw an exception", new JSONArray("[\"test\"")); + } catch (JSONException e) { + assertEquals("Expected an exception message", + "Expected a ',' or ']' at 7 [character 8 line 1]", + e.getMessage()); + } + } + + /** + * Attempt to create a JSONArray with an unclosed array. + * Expects an exception + */ + @Test + public void unclosedArray3() { + try { + assertNull("Should throw an exception", new JSONArray("[\"test\",")); + } catch (JSONException e) { + assertEquals("Expected an exception message", + "Expected a ',' or ']' at 8 [character 9 line 1]", + e.getMessage()); + } + } /** * Attempt to create a JSONArray with a string as object that is @@ -372,7 +402,7 @@ public void length() { assertTrue("expected empty JSONArray length 0", new JSONArray().length() == 0); JSONArray jsonArray = new JSONArray(this.arrayStr); - assertTrue("expected JSONArray length 13", jsonArray.length() == 13); + assertTrue("expected JSONArray length 13. instead found "+jsonArray.length(), jsonArray.length() == 13); JSONArray nestedJsonArray = jsonArray.getJSONArray(9); assertTrue("expected JSONArray length 1", nestedJsonArray.length() == 1); } From 578a442ef764691db51f2a0e880af9c86b675409 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Mon, 30 Oct 2017 08:43:56 -0500 Subject: [PATCH 72/99] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 79f8724..5f83c6c 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,11 @@ When adding a new unit test, don't forget to update JunitTestSuite.java. * If you have unit test results along with pull requests, the reviewer has an easier time understanding your code and determining if the it works as intended. When you start working on a test, add the empty file to the repository and update the readme, so that others will know that test is taken. +**Caveats:** +JSON-Java is Java 1.6-compatible, but JSON-Java-unit-tests requests Java 1.8. If you see this error, make sure you have 1.8 installed, on your path, and set in JAVA_HOME: +Execution failed for task ':compileJava'. +> invalid flag: -parameters + A unit test has the following stages: From ee3aa03da156e4f8d03eb40cf86c11810f2ac120 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Mon, 30 Oct 2017 08:44:21 -0500 Subject: [PATCH 73/99] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5f83c6c..86dd85c 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ When adding a new unit test, don't forget to update JunitTestSuite.java. * If you have unit test results along with pull requests, the reviewer has an easier time understanding your code and determining if the it works as intended. When you start working on a test, add the empty file to the repository and update the readme, so that others will know that test is taken. + **Caveats:** JSON-Java is Java 1.6-compatible, but JSON-Java-unit-tests requests Java 1.8. If you see this error, make sure you have 1.8 installed, on your path, and set in JAVA_HOME: Execution failed for task ':compileJava'. From e0801befe5981dfd2b93b04c4980d0fcf73c46cf Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Mon, 30 Oct 2017 08:45:41 -0500 Subject: [PATCH 74/99] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 86dd85c..07f9445 100644 --- a/README.md +++ b/README.md @@ -84,9 +84,10 @@ When you start working on a test, add the empty file to the repository and updat **Caveats:** JSON-Java is Java 1.6-compatible, but JSON-Java-unit-tests requests Java 1.8. If you see this error, make sure you have 1.8 installed, on your path, and set in JAVA_HOME: +``` Execution failed for task ':compileJava'. > invalid flag: -parameters - +``` A unit test has the following stages: From 936db93445a9481533494f0333738f1fc5198a7e Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Mon, 30 Oct 2017 08:46:43 -0500 Subject: [PATCH 75/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 07f9445..1ca5c64 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ When adding a new unit test, don't forget to update JunitTestSuite.java. When you start working on a test, add the empty file to the repository and update the readme, so that others will know that test is taken. **Caveats:** -JSON-Java is Java 1.6-compatible, but JSON-Java-unit-tests requests Java 1.8. If you see this error, make sure you have 1.8 installed, on your path, and set in JAVA_HOME: +JSON-Java is Java 1.6-compatible, but JSON-Java-unit-tests requires Java 1.8. If you see this error when building JSON-Java-unit-test, make sure you have 1.8 installed, on your path, and set in JAVA_HOME: ``` Execution failed for task ':compileJava'. > invalid flag: -parameters From 08d93f3eb5db5e3bde58fe3ca1da9da2acd4f1ed Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 6 Nov 2017 10:27:45 -0500 Subject: [PATCH 76/99] test cases for issue https://github.com/stleary/JSON-java/issues/379 --- .../java/org/json/junit/JSONArrayTest.java | 27 +++++++++++++++++++ .../java/org/json/junit/JSONObjectTest.java | 27 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 4a0249d..48050b9 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -1,6 +1,7 @@ package org.json.junit; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -54,6 +55,32 @@ public class JSONArrayTest { "\"-1\""+ "]"; + /** + * Tests that the similar method is working as expected. + */ + @Test + public void aaaVerifySimilar() { + final String string1 = "HasSameRef"; + JSONArray obj1 = new JSONArray() + .put("abc") + .put(string1) + .put(2); + + JSONArray obj2 = new JSONArray() + .put("abc") + .put(string1) + .put(3); + + JSONArray obj3 = new JSONArray() + .put("abc") + .put(new String(string1)) + .put(2); + + assertFalse("Should eval to false", obj1.similar(obj2)); + + assertTrue("Should eval to true", obj1.similar(obj3)); + } + /** * Attempt to create a JSONArray with a null string. * Expects a NullPointerException. diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 2dcebe4..6b248ad 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -58,6 +58,33 @@ * otherwise be impossible. */ public class JSONObjectTest { + + /** + * Tests that the similar method is working as expected. + */ + @Test + public void aaaVerifySimilar() { + final String string1 = "HasSameRef"; + JSONObject obj1 = new JSONObject() + .put("key1", "abc") + .put("key2", 2) + .put("key3", string1); + + JSONObject obj2 = new JSONObject() + .put("key1", "abc") + .put("key2", 3) + .put("key3", string1); + + JSONObject obj3 = new JSONObject() + .put("key1", "abc") + .put("key2", 2) + .put("key3", new String(string1)); + + assertFalse("Should eval to false", obj1.similar(obj2)); + + assertTrue("Should eval to true", obj1.similar(obj3)); + + } /** * JSONObject built from a bean, but only using a null value. From dae88d7c5cbf5569a28c5653d4d6d354d1fc2ce6 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 6 Nov 2017 10:35:49 -0500 Subject: [PATCH 77/99] fix method names --- src/test/java/org/json/junit/JSONArrayTest.java | 2 +- src/test/java/org/json/junit/JSONObjectTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 48050b9..8a31c87 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -59,7 +59,7 @@ public class JSONArrayTest { * Tests that the similar method is working as expected. */ @Test - public void aaaVerifySimilar() { + public void verifySimilar() { final String string1 = "HasSameRef"; JSONArray obj1 = new JSONArray() .put("abc") diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 6b248ad..85c37fd 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -63,7 +63,7 @@ public class JSONObjectTest { * Tests that the similar method is working as expected. */ @Test - public void aaaVerifySimilar() { + public void verifySimilar() { final String string1 = "HasSameRef"; JSONObject obj1 = new JSONObject() .put("key1", "abc") From cc2ed79e57dea53bb21418daaf3bbf39a68b1bed Mon Sep 17 00:00:00 2001 From: dengjianbao Date: Fri, 2 Feb 2018 22:54:08 +0800 Subject: [PATCH 78/99] Correct the message to match the function --- src/test/java/org/json/junit/JSONObjectTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 85c37fd..80283ae 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -266,7 +266,7 @@ public void verifyNumberOutput(){ JSONObject jsonObject = new JSONObject(new MyNumberContainer()); String actual = jsonObject.toString(); String expected = "{\"myNumber\":{\"number\":42}}"; - assertEquals("Not Equal", expected , actual); + assertEquals("Equal", expected , actual); /** * JSONObject.put() handles objects differently than the @@ -280,7 +280,7 @@ public void verifyNumberOutput(){ jsonObject.put("myNumber", new MyNumber()); actual = jsonObject.toString(); expected = "{\"myNumber\":42}"; - assertEquals("Not Equal", expected , actual); + assertEquals("Equal", expected , actual); /** * Calls the JSONObject(Map) ctor, which calls wrap() for values. @@ -293,7 +293,7 @@ public void verifyNumberOutput(){ jsonObject = new JSONObject(Collections.singletonMap("myNumber", new AtomicInteger(42))); actual = jsonObject.toString(); expected = "{\"myNumber\":\"42\"}"; - assertEquals("Not Equal", expected , actual); + assertEquals("Equal", expected , actual); /** * JSONObject.put() inserts the AtomicInteger directly into the @@ -305,7 +305,7 @@ public void verifyNumberOutput(){ jsonObject.put("myNumber", new AtomicInteger(42)); actual = jsonObject.toString(); expected = "{\"myNumber\":42}"; - assertEquals("Not Equal", expected , actual); + assertEquals("Equal", expected , actual); /** * Calls the JSONObject(Map) ctor, which calls wrap() for values. @@ -332,7 +332,7 @@ public void verifyNumberOutput(){ jsonObject.put("myNumber", new Fraction(4,2)); actual = jsonObject.toString(); expected = "{\"myNumber\":\"4/2\"}"; // valid JSON, bug fixed - assertEquals("Not Equal", expected , actual); + assertEquals("Equal", expected , actual); } /** From aa5e80bc8d694bf8a552401534d93d8938eaa665 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 7 Mar 2018 12:11:17 -0500 Subject: [PATCH 79/99] add test cases for null keys --- .../java/org/json/junit/JSONObjectTest.java | 72 ++++++++++++++++--- 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 80283ae..5ada98c 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1973,13 +1973,7 @@ public void jsonObjectParsingErrors() { "Null pointer", e.getMessage()); } - try { - // null put key - JSONObject jsonObject = new JSONObject("{}"); - jsonObject.put(null, 0); - fail("Expected an exception"); - } catch (NullPointerException ignored) { - } + try { // multiple putOnce key JSONObject jsonObject = new JSONObject("{}"); @@ -2182,6 +2176,10 @@ public void jsonObjectPutOnceNull() { JSONObject jsonObject = new JSONObject(); jsonObject.putOnce(null, null); assertTrue("jsonObject should be empty", jsonObject.length() == 0); + jsonObject.putOnce("", null); + assertTrue("jsonObject should be empty", jsonObject.length() == 0); + jsonObject.putOnce(null, ""); + assertTrue("jsonObject should be empty", jsonObject.length() == 0); } /** @@ -2453,7 +2451,7 @@ public void write() throws IOException { * Confirms that exceptions thrown when writing values are wrapped properly. */ @Test - public void testJSONWriterException() throws IOException { + public void testJSONWriterException() { final JSONObject jsonObject = new JSONObject(); jsonObject.put("someKey",new BrokenToString()); @@ -2893,4 +2891,62 @@ public void testExceptionalBean() { assertTrue(jo.get("closeable") instanceof JSONObject); assertTrue(jo.getJSONObject("closeable").has("string")); } + + @Test(expected=NullPointerException.class) + public void testPutNullBoolean() { + // null put key + JSONObject jsonObject = new JSONObject("{}"); + jsonObject.put(null, false); + fail("Expected an exception"); + } + @Test(expected=NullPointerException.class) + public void testPutNullCollection() { + // null put key + JSONObject jsonObject = new JSONObject("{}"); + jsonObject.put(null, Collections.emptySet()); + fail("Expected an exception"); + } + @Test(expected=NullPointerException.class) + public void testPutNullDouble() { + // null put key + JSONObject jsonObject = new JSONObject("{}"); + jsonObject.put(null, 0.0d); + fail("Expected an exception"); + } + @Test(expected=NullPointerException.class) + public void testPutNullFloat() { + // null put key + JSONObject jsonObject = new JSONObject("{}"); + jsonObject.put(null, 0.0f); + fail("Expected an exception"); + } + @Test(expected=NullPointerException.class) + public void testPutNullInt() { + // null put key + JSONObject jsonObject = new JSONObject("{}"); + jsonObject.put(null, 0); + fail("Expected an exception"); + } + @Test(expected=NullPointerException.class) + public void testPutNullLong() { + // null put key + JSONObject jsonObject = new JSONObject("{}"); + jsonObject.put(null, 0L); + fail("Expected an exception"); + } + @Test(expected=NullPointerException.class) + public void testPutNullMap() { + // null put key + JSONObject jsonObject = new JSONObject("{}"); + jsonObject.put(null, Collections.emptyMap()); + fail("Expected an exception"); + } + @Test(expected=NullPointerException.class) + public void testPutNullObject() { + // null put key + JSONObject jsonObject = new JSONObject("{}"); + jsonObject.put(null, new Object()); + fail("Expected an exception"); + } + } From 193a3823b53ad6684987671ee3da54f6d9a2705b Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 7 Mar 2018 14:52:50 -0500 Subject: [PATCH 80/99] new test cases to support bean annotation --- .../java/org/json/junit/JSONObjectTest.java | 77 ++++++++++++++++++- .../java/org/json/junit/data/GenericBean.java | 2 +- .../org/json/junit/data/GenericBeanInt.java | 29 ++++++- .../org/json/junit/data/MyBeanCustomName.java | 20 +++++ .../junit/data/MyBeanCustomNameInterface.java | 11 +++ .../junit/data/MyBeanCustomNameSubClass.java | 32 ++++++++ 6 files changed, 165 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/json/junit/data/MyBeanCustomName.java create mode 100644 src/test/java/org/json/junit/data/MyBeanCustomNameInterface.java create mode 100644 src/test/java/org/json/junit/data/MyBeanCustomNameSubClass.java diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 80283ae..0579acb 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -37,6 +37,8 @@ import org.json.junit.data.GenericBean; import org.json.junit.data.GenericBeanInt; import org.json.junit.data.MyBean; +import org.json.junit.data.MyBeanCustomName; +import org.json.junit.data.MyBeanCustomNameSubClass; import org.json.junit.data.MyBigNumberBean; import org.json.junit.data.MyEnum; import org.json.junit.data.MyEnumField; @@ -371,7 +373,7 @@ public void verifyPutCollection() { /** - * Verifies that the put Map has backwards compatability with RAW types pre-java5. + * Verifies that the put Map has backwards compatibility with RAW types pre-java5. */ @Test public void verifyPutMap() { @@ -467,7 +469,7 @@ public void jsonObjectByMapWithNullValue() { */ @SuppressWarnings("boxing") @Test - public void jsonObjectByBean() { + public void jsonObjectByBean1() { /** * Default access classes have to be mocked since JSONObject, which is * not in the same package, cannot call MyBean methods by reflection. @@ -501,6 +503,73 @@ public void jsonObjectByBean() { assertTrue("expected 0 callbacks[1] items", ((Map)(JsonPath.read(doc, "$.callbacks[1]"))).size() == 0); } + /** + * JSONObject built from a bean that has custom field names. + */ + @Test + public void jsonObjectByBean2() { + JSONObject jsonObject = new JSONObject(new MyBeanCustomName()); + assertNotNull(jsonObject); + assertEquals("Wrong number of keys found:", + 5, + jsonObject.keySet().size()); + assertFalse("Normal field name (someString) processing did not work", + jsonObject.has("someString")); + assertFalse("Normal field name (myDouble) processing did not work", + jsonObject.has("myDouble")); + assertFalse("Normal field name (someFloat) found", + jsonObject.has("someFloat")); + assertFalse("Ignored field found!", + jsonObject.has("ignoredInt")); + assertTrue("Normal field name (someInt) processing did not work", + jsonObject.has("someInt")); + assertTrue("Normal field name (someLong) processing did not work", + jsonObject.has("someLong")); + assertTrue("Overridden String field name (myStringField) not found", + jsonObject.has("myStringField")); + assertTrue("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) not found", + jsonObject.has("Some Weird NAme that Normally Wouldn't be possible!")); + assertTrue("Overridden String field name (InterfaceField) not found", + jsonObject.has("InterfaceField")); + } + + /** + * JSONObject built from a bean that has custom field names inherited from a parent class. + */ + @Test + public void jsonObjectByBean3() { + JSONObject jsonObject = new JSONObject(new MyBeanCustomNameSubClass()); + assertNotNull(jsonObject); + assertEquals("Wrong number of keys found:", + 7, + jsonObject.keySet().size()); + assertFalse("Normal int field name (someInt) found, but was overridden", + jsonObject.has("someInt")); + assertFalse("Normal field name (myDouble) processing did not work", + jsonObject.has("myDouble")); + assertFalse("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) FOUND!", + jsonObject.has("Some Weird NAme that Normally Wouldn't be possible!")); + assertFalse("Normal field name (someFloat) found", + jsonObject.has("someFloat")); + assertFalse("Ignored field found!", + jsonObject.has("ignoredInt")); + assertFalse("Ignored field at the same level as forced name found", + jsonObject.has("ShouldBeIgnored")); + assertTrue("Overridden int field name (newIntFieldName) not found", + jsonObject.has("newIntFieldName")); + assertTrue("Normal field name (someLong) processing did not work", + jsonObject.has("someLong")); + assertTrue("Overridden String field name (myStringField) not found", + jsonObject.has("myStringField")); + assertTrue(jsonObject.has("AMoreNormalName")); + assertTrue("Overridden String field name (InterfaceField) not found", + jsonObject.has("InterfaceField")); + assertTrue("Forced field not found!", + jsonObject.has("forcedInt")); + assertTrue("Normally ignored field (getable) with explicit property name not found", + jsonObject.has("Getable")); + } + /** * A bean is also an object. But in order to test the JSONObject * ctor that takes an object and a list of names, @@ -541,7 +610,7 @@ public void jsonObjectByResourceBundle() { assertTrue("expected \"later\":\"Later, \"", "Later, ".equals(jsonObject.query("/farewells/later"))); assertTrue("expected \"world\":\"World!\"", "Alligator!".equals(jsonObject.query("/farewells/gator"))); } - + /** * Exercise the JSONObject.accumulate() method */ @@ -2857,7 +2926,7 @@ public void testGenericBean() { public void testGenericIntBean() { GenericBeanInt bean = new GenericBeanInt(42); final JSONObject jo = new JSONObject(bean); - assertEquals(jo.keySet().toString(), 9, jo.length()); + assertEquals(jo.keySet().toString(), 10, jo.length()); assertEquals(42, jo.get("genericValue")); assertEquals("Expected the getter to only be called once", 1, bean.genericGetCounter); diff --git a/src/test/java/org/json/junit/data/GenericBean.java b/src/test/java/org/json/junit/data/GenericBean.java index 4740030..da6370d 100644 --- a/src/test/java/org/json/junit/data/GenericBean.java +++ b/src/test/java/org/json/junit/data/GenericBean.java @@ -20,7 +20,7 @@ public GenericBean(T genericValue) { } /** */ - private T genericValue; + protected T genericValue; /** to be used by the calling test to see how often the getter is called */ public int genericGetCounter; /** to be used by the calling test to see how often the setter is called */ diff --git a/src/test/java/org/json/junit/data/GenericBeanInt.java b/src/test/java/org/json/junit/data/GenericBeanInt.java index 8f0248d..5056611 100644 --- a/src/test/java/org/json/junit/data/GenericBeanInt.java +++ b/src/test/java/org/json/junit/data/GenericBeanInt.java @@ -13,7 +13,7 @@ public class GenericBeanInt extends GenericBean { /** @return the a */ public char getA() { - return a; + return this.a; } /** @@ -25,6 +25,33 @@ public boolean getable() { return false; } + /** + * Should not be beanable + * + * @return false + */ + public boolean get() { + return false; + } + + /** + * Should not be beanable + * + * @return false + */ + public boolean is() { + return false; + } + + /** + * Should be beanable + * + * @return false + */ + public boolean isB() { + return this.genericValue.equals((Integer.valueOf(this.a+1))); + } + /** * @param genericValue * the value to initiate with. diff --git a/src/test/java/org/json/junit/data/MyBeanCustomName.java b/src/test/java/org/json/junit/data/MyBeanCustomName.java new file mode 100644 index 0000000..56756c2 --- /dev/null +++ b/src/test/java/org/json/junit/data/MyBeanCustomName.java @@ -0,0 +1,20 @@ +package org.json.junit.data; + +import org.json.JSONPropertyName; + +/** + * Test bean for the {@link JSONPropertyName} annotation. + */ +public class MyBeanCustomName implements MyBeanCustomNameInterface { + public int getSomeInt() { return 42; } + @JSONPropertyName("") + public long getSomeLong() { return 42L; } + @JSONPropertyName("myStringField") + public String getSomeString() { return "someStringValue"; } + @JSONPropertyName("Some Weird NAme that Normally Wouldn't be possible!") + public double getMyDouble() { return 0.0d; } + @Override + public float getSomeFloat() { return 2.0f; } + @Override + public int getIgnoredInt() { return 40; } +} diff --git a/src/test/java/org/json/junit/data/MyBeanCustomNameInterface.java b/src/test/java/org/json/junit/data/MyBeanCustomNameInterface.java new file mode 100644 index 0000000..b25b578 --- /dev/null +++ b/src/test/java/org/json/junit/data/MyBeanCustomNameInterface.java @@ -0,0 +1,11 @@ +package org.json.junit.data; + +import org.json.JSONPropertyIgnore; +import org.json.JSONPropertyName; + +public interface MyBeanCustomNameInterface { + @JSONPropertyName("InterfaceField") + float getSomeFloat(); + @JSONPropertyIgnore + int getIgnoredInt(); +} \ No newline at end of file diff --git a/src/test/java/org/json/junit/data/MyBeanCustomNameSubClass.java b/src/test/java/org/json/junit/data/MyBeanCustomNameSubClass.java new file mode 100644 index 0000000..8f0500c --- /dev/null +++ b/src/test/java/org/json/junit/data/MyBeanCustomNameSubClass.java @@ -0,0 +1,32 @@ +/** + * + */ +package org.json.junit.data; + +import org.json.JSONPropertyIgnore; +import org.json.JSONPropertyName; + +/** + * Test bean to verify that the {@link org.json.JSONPropertyName} annotation + * is inherited. + */ +public class MyBeanCustomNameSubClass extends MyBeanCustomName { + @Override + @JSONPropertyName("forcedInt") + public int getIgnoredInt() { return 42*42; } + @Override + @JSONPropertyName("newIntFieldName") + public int getSomeInt() { return 43; } + @Override + public String getSomeString() { return "subClassString"; } + @Override + @JSONPropertyName("AMoreNormalName") + public double getMyDouble() { return 1.0d; } + @Override + public float getSomeFloat() { return 3.0f; } + @JSONPropertyIgnore + @JSONPropertyName("ShouldBeIgnored") + public boolean getShouldNotBeJSON() { return true; } + @JSONPropertyName("Getable") + public boolean getable() { return true; } +} From f4201cf318cff5fba56d1e1ef687ffb3f1a7d421 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 19 Mar 2018 09:34:13 -0400 Subject: [PATCH 81/99] Test cases for issue described in https://github.com/stleary/JSON-java/issues/410. --- src/test/java/org/json/junit/JSONPointerTest.java | 13 +++++++++++++ src/test/resources/jsonpointer-testdoc.json | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java index 19dac47..c4a8781 100644 --- a/src/test/java/org/json/junit/JSONPointerTest.java +++ b/src/test/java/org/json/junit/JSONPointerTest.java @@ -62,6 +62,19 @@ public void queryByEmptyKey() { assertSame(document.get(""), query("/")); } + @Test + public void queryByEmptyKeySubObject() { + assertSame(document.getJSONObject("obj").getJSONObject(""), query("/obj/")); + } + + @Test + public void queryByEmptyKeySubObjectSubOject() { + assertSame( + document.getJSONObject("obj").getJSONObject("").get(""), + query("/obj//") + ); + } + @Test public void slashEscaping() { assertSame(document.get("a/b"), query("/a~1b")); diff --git a/src/test/resources/jsonpointer-testdoc.json b/src/test/resources/jsonpointer-testdoc.json index d58fe82..6c1ce28 100644 --- a/src/test/resources/jsonpointer-testdoc.json +++ b/src/test/resources/jsonpointer-testdoc.json @@ -19,6 +19,7 @@ "another/key" : [ "val" ] - } + }, + "" : { "" : "empty key of an object with an empty key" } } } \ No newline at end of file From 43f3f5e80bb845db09e34ce467c38052b08866cf Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 19 Mar 2018 09:48:50 -0400 Subject: [PATCH 82/99] Add another test --- src/test/java/org/json/junit/JSONPointerTest.java | 8 ++++++++ src/test/resources/jsonpointer-testdoc.json | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java index c4a8781..5ddd089 100644 --- a/src/test/java/org/json/junit/JSONPointerTest.java +++ b/src/test/java/org/json/junit/JSONPointerTest.java @@ -74,6 +74,14 @@ public void queryByEmptyKeySubObjectSubOject() { query("/obj//") ); } + + @Test + public void queryByEmptyKeySubObjectValue() { + assertSame( + document.getJSONObject("obj").getJSONObject("").get("subKey"), + query("/obj//subKey") + ); + } @Test public void slashEscaping() { diff --git a/src/test/resources/jsonpointer-testdoc.json b/src/test/resources/jsonpointer-testdoc.json index 6c1ce28..657ccdd 100644 --- a/src/test/resources/jsonpointer-testdoc.json +++ b/src/test/resources/jsonpointer-testdoc.json @@ -20,6 +20,9 @@ "val" ] }, - "" : { "" : "empty key of an object with an empty key" } + "" : { + "" : "empty key of an object with an empty key", + "subKey" : "Some other value" + } } } \ No newline at end of file From 3fe4a767e6665d8290eb1359c4a9e2d7a13e4997 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Tue, 20 Mar 2018 22:15:25 -0400 Subject: [PATCH 83/99] Fixes incorrect syntax for JSONPointer in test. --- src/test/java/org/json/junit/JSONObjectTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 303a19a..5dc31c7 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -667,7 +667,7 @@ public void jsonObjectAppend() { assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); assertTrue("expected 6 myArray items", ((List)(JsonPath.read(doc, "$.myArray"))).size() == 6); assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/myArray/0"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/myArray/1/"))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/myArray/1"))); assertTrue("expected hello world!", "hello world!".equals(jsonObject.query("/myArray/2"))); assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/myArray/3"))); assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.query("/myArray/4"))); From d00501eabd9b60c8097fd466b99796b27fbdb7e9 Mon Sep 17 00:00:00 2001 From: Andrei Paikin Date: Fri, 25 May 2018 22:47:05 +0300 Subject: [PATCH 84/99] add usage of isEmpty method --- src/test/java/org/json/junit/CookieListTest.java | 2 +- src/test/java/org/json/junit/EnumTest.java | 2 +- src/test/java/org/json/junit/JSONArrayTest.java | 2 +- src/test/java/org/json/junit/JSONObjectTest.java | 16 ++++++++-------- src/test/java/org/json/junit/PropertyTest.java | 4 ++-- src/test/java/org/json/junit/XMLTest.java | 8 ++++---- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/test/java/org/json/junit/CookieListTest.java b/src/test/java/org/json/junit/CookieListTest.java index 80cbaa8..7149644 100644 --- a/src/test/java/org/json/junit/CookieListTest.java +++ b/src/test/java/org/json/junit/CookieListTest.java @@ -65,7 +65,7 @@ public void malFormedCookieListException() { public void emptyStringCookieList() { String cookieStr = ""; JSONObject jsonObject = CookieList.toJSONObject(cookieStr); - assertTrue(jsonObject.length() == 0); + assertTrue(jsonObject.isEmpty()); } /** diff --git a/src/test/java/org/json/junit/EnumTest.java b/src/test/java/org/json/junit/EnumTest.java index cd0d8c0..366643e 100644 --- a/src/test/java/org/json/junit/EnumTest.java +++ b/src/test/java/org/json/junit/EnumTest.java @@ -35,7 +35,7 @@ public void jsonObjectFromEnum() { // If there are no getters then the object is empty. MyEnum myEnum = MyEnum.VAL2; JSONObject jsonObject = new JSONObject(myEnum); - assertTrue("simple enum has no getters", jsonObject.length() == 0); + assertTrue("simple enum has no getters", jsonObject.isEmpty()); // enum with a getters should create a non-empty object MyEnumField myEnumField = MyEnumField.VAL2; diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 8a31c87..845f4e7 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -691,7 +691,7 @@ public void remove() { JSONArray jsonArray = new JSONArray(arrayStr1); jsonArray.remove(0); assertTrue("array should be empty", null == jsonArray.remove(5)); - assertTrue("jsonArray should be empty", jsonArray.length() == 0); + assertTrue("jsonArray should be empty", jsonArray.isEmpty()); } /** diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 5dc31c7..e3b9529 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -141,7 +141,7 @@ public void testLongFromString(){ @Test public void emptyJsonObject() { JSONObject jsonObject = new JSONObject(); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); + assertTrue("jsonObject should be empty", jsonObject.isEmpty()); } /** @@ -184,7 +184,7 @@ public void jsonObjectByNames() { public void jsonObjectByNullMap() { Map map = null; JSONObject jsonObject = new JSONObject(map); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); + assertTrue("jsonObject should be empty", jsonObject.isEmpty()); } /** @@ -1122,7 +1122,7 @@ public void bigNumberOperations() { BigDecimal bigDecimal = new BigDecimal( "123456789012345678901234567890.12345678901234567890123456789"); jsonObject = new JSONObject(bigDecimal); - assertTrue("large bigDecimal is not stored", jsonObject.length() == 0); + assertTrue("large bigDecimal is not stored", jsonObject.isEmpty()); /** * JSONObject put(String, Object) method stores and serializes @@ -2244,11 +2244,11 @@ public void jsonObjectParsingErrors() { public void jsonObjectPutOnceNull() { JSONObject jsonObject = new JSONObject(); jsonObject.putOnce(null, null); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); + assertTrue("jsonObject should be empty", jsonObject.isEmpty()); jsonObject.putOnce("", null); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); + assertTrue("jsonObject should be empty", jsonObject.isEmpty()); jsonObject.putOnce(null, ""); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); + assertTrue("jsonObject should be empty", jsonObject.isEmpty()); } /** @@ -2424,11 +2424,11 @@ public void jsonObjectputNull() { String str = "{\"myKey\": \"myval\"}"; JSONObject jsonObjectRemove = new JSONObject(str); jsonObjectRemove.remove("myKey"); - assertEquals("jsonObject should be empty",0 ,jsonObjectRemove.length()); + assertTrue("jsonObject should be empty", jsonObjectRemove.isEmpty()); JSONObject jsonObjectPutNull = new JSONObject(str); jsonObjectPutNull.put("myKey", (Object) null); - assertEquals("jsonObject should be empty",0 ,jsonObjectPutNull.length()); + assertTrue("jsonObject should be empty", jsonObjectPutNull.isEmpty()); } diff --git a/src/test/java/org/json/junit/PropertyTest.java b/src/test/java/org/json/junit/PropertyTest.java index 60d3eb5..8804284 100644 --- a/src/test/java/org/json/junit/PropertyTest.java +++ b/src/test/java/org/json/junit/PropertyTest.java @@ -21,7 +21,7 @@ public class PropertyTest { public void shouldHandleNullProperties() { Properties properties = null; JSONObject jsonObject = Property.toJSONObject(properties); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); + assertTrue("jsonObject should be empty", jsonObject.isEmpty()); } /** @@ -32,7 +32,7 @@ public void shouldHandleNullProperties() { public void shouldHandleEmptyProperties() { Properties properties = new Properties(); JSONObject jsonObject = Property.toJSONObject(properties); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); + assertTrue("jsonObject should be empty", jsonObject.isEmpty()); } /** diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index c34bf0f..651d1a7 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -34,7 +34,7 @@ public class XMLTest { public void shouldHandleNullXML() { String xmlStr = null; JSONObject jsonObject = XML.toJSONObject(xmlStr); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); + assertTrue("jsonObject should be empty", jsonObject.isEmpty()); } /** @@ -45,7 +45,7 @@ public void shouldHandleEmptyXML() { String xmlStr = ""; JSONObject jsonObject = XML.toJSONObject(xmlStr); - assertTrue("jsonObject should be empty", jsonObject.length() == 0); + assertTrue("jsonObject should be empty", jsonObject.isEmpty()); } /** @@ -55,7 +55,7 @@ public void shouldHandleEmptyXML() { public void shouldHandleNonXML() { String xmlStr = "{ \"this is\": \"not xml\"}"; JSONObject jsonObject = XML.toJSONObject(xmlStr); - assertTrue("xml string should be empty", jsonObject.length() == 0); + assertTrue("xml string should be empty", jsonObject.isEmpty()); } /** @@ -200,7 +200,7 @@ public void shouldHandleNullJSONXML() { public void shouldHandleEmptyJSONXML() { JSONObject jsonObject= new JSONObject(); String xmlStr = XML.toString(jsonObject); - assertTrue("xml string should be empty", xmlStr.length() == 0); + assertTrue("xml string should be empty", xmlStr.isEmpty()); } /** From 3b8b0a681c349f12ea83b490927c0da219a7550d Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Tue, 2 Oct 2018 12:38:17 -0400 Subject: [PATCH 85/99] Update test cases to verify performance change and verify opt/getBigDecimal match --- .../java/org/json/junit/JSONObjectTest.java | 95 +++++++++++++++++-- 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index e3b9529..63385a5 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -24,6 +24,7 @@ import java.util.Locale; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Pattern; import org.json.CDL; import org.json.JSONArray; @@ -60,7 +61,13 @@ * otherwise be impossible. */ public class JSONObjectTest { - + + /** + * Regular Expression Pattern that matches JSON Numbers. This is primarily used for + * output to guarantee that we are always writing valid JSON. + */ + static final Pattern NUMBER_PATTERN = Pattern.compile("-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?"); + /** * Tests that the similar method is working as expected. */ @@ -87,6 +94,67 @@ public void verifySimilar() { assertTrue("Should eval to true", obj1.similar(obj3)); } + + @Test + public void timeNumberParsing() { + // test data to use + final String[] testData = new String[] { + null, + "", + "100", + "-100", + "abc123", + "012345", + "100.5e199", + "-100.5e199", + "DEADBEEF", + "0xDEADBEEF", + "1234567890.1234567890", + "-1234567890.1234567890", + "adloghakuidghauiehgauioehgdkjfb nsruoh aeu noerty384 nkljfgh " + + "395h tdfn kdz8yt3 4hkls gn.ey85 4hzfhnz.o8y5a84 onvklt " + + "yh389thub nkz8y49lihv al4itlaithknty8hnbl" + // long (in length) number sequences with invalid data at the end of the + // string offer very poor performance for the REGEX. + ,"123467890123467890123467890123467890123467890123467890123467" + + "8901234678901234678901234678901234678901234678901234678" + + "9012346789012346789012346789012346789012346789012346789" + + "0a" + }; + final int testDataLength = testData.length; + final int iterations = 1000000; + + // 10 million iterations 1,000,000 * 10 + long startTime = System.nanoTime(); + for(int i = 0; i < iterations; i++) { + for(int j = 0; j < testDataLength; j++) { + try { + BigDecimal v1 = new BigDecimal(testData[j]); + v1.signum(); + } catch(Exception ignore) { + //do nothing + } + } + } + final long elapsedNano1 = System.nanoTime() - startTime; + System.out.println("new BigDecimal(testData[]) : " + elapsedNano1 / 1000000 + " ms"); + + startTime = System.nanoTime(); + for(int i = 0; i < iterations; i++) { + for(int j = 0; j < testDataLength; j++) { + try { + boolean v2 = NUMBER_PATTERN.matcher(testData[j]).matches(); + assert v2 == !!v2; + } catch(Exception ignore) { + //do nothing + } + } + } + final long elapsedNano2 = System.nanoTime() - startTime; + System.out.println("NUMBER_PATTERN.matcher(testData[]).matches() : " + elapsedNano2 / 1000000 + " ms"); + // don't assert normally as the testing is machine dependent. + // assertTrue("Expected Pattern matching to be faster than BigDecimal constructor",elapsedNano2 Date: Thu, 4 Oct 2018 16:02:50 -0400 Subject: [PATCH 86/99] update expected exception text in tests to match unified number getters --- .../java/org/json/junit/JSONArrayTest.java | 32 +++---- .../java/org/json/junit/JSONObjectTest.java | 94 +++++++++---------- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 845f4e7..3b70446 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -331,57 +331,57 @@ public void failedGetArrayValues() { jsonArray.getBoolean(4); assertTrue("expected getBoolean to fail", false); } catch (JSONException e) { - assertTrue("Expected an exception message", - "JSONArray[4] is not a boolean.".equals(e.getMessage())); + assertEquals("Expected an exception message", + "JSONArray[4] is not a boolean.",e.getMessage()); } try { jsonArray.get(-1); assertTrue("expected get to fail", false); } catch (JSONException e) { - assertTrue("Expected an exception message", - "JSONArray[-1] not found.".equals(e.getMessage())); + assertEquals("Expected an exception message", + "JSONArray[-1] not found.",e.getMessage()); } try { jsonArray.getDouble(4); assertTrue("expected getDouble to fail", false); } catch (JSONException e) { - assertTrue("Expected an exception message", - "JSONArray[4] is not a number.".equals(e.getMessage())); + assertEquals("Expected an exception message", + "JSONArray[4] is not a number.",e.getMessage()); } try { jsonArray.getInt(4); assertTrue("expected getInt to fail", false); } catch (JSONException e) { - assertTrue("Expected an exception message", - "JSONArray[4] is not a number.".equals(e.getMessage())); + assertEquals("Expected an exception message", + "JSONArray[4] is not a number.",e.getMessage()); } try { jsonArray.getJSONArray(4); assertTrue("expected getJSONArray to fail", false); } catch (JSONException e) { - assertTrue("Expected an exception message", - "JSONArray[4] is not a JSONArray.".equals(e.getMessage())); + assertEquals("Expected an exception message", + "JSONArray[4] is not a JSONArray.",e.getMessage()); } try { jsonArray.getJSONObject(4); assertTrue("expected getJSONObject to fail", false); } catch (JSONException e) { - assertTrue("Expected an exception message", - "JSONArray[4] is not a JSONObject.".equals(e.getMessage())); + assertEquals("Expected an exception message", + "JSONArray[4] is not a JSONObject.",e.getMessage()); } try { jsonArray.getLong(4); assertTrue("expected getLong to fail", false); } catch (JSONException e) { - assertTrue("Expected an exception message", - "JSONArray[4] is not a number.".equals(e.getMessage())); + assertEquals("Expected an exception message", + "JSONArray[4] is not a number.",e.getMessage()); } try { jsonArray.getString(5); assertTrue("expected getString to fail", false); } catch (JSONException e) { - assertTrue("Expected an exception message", - "JSONArray[5] not a string.".equals(e.getMessage())); + assertEquals("Expected an exception message", + "JSONArray[5] not a string.",e.getMessage()); } } diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 63385a5..c6cb580 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1013,128 +1013,128 @@ public void jsonObjectNonAndWrongValues() { jsonObject.getBoolean("nonKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("expecting an exception message", - "JSONObject[\"nonKey\"] not found.".equals(e.getMessage())); + assertEquals("expecting an exception message", + "JSONObject[\"nonKey\"] not found.", e.getMessage()); } try { jsonObject.getBoolean("stringKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a Boolean.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a Boolean.", + e.getMessage()); } try { jsonObject.getString("nonKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.", + e.getMessage()); } try { jsonObject.getString("trueKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"trueKey\"] not a string.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"trueKey\"] not a string.", + e.getMessage()); } try { jsonObject.getDouble("nonKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.", + e.getMessage()); } try { jsonObject.getDouble("stringKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a number.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a number.", + e.getMessage()); } try { jsonObject.getFloat("nonKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.", + e.getMessage()); } try { jsonObject.getFloat("stringKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a number.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a number.", + e.getMessage()); } try { jsonObject.getInt("nonKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.", + e.getMessage()); } try { jsonObject.getInt("stringKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not an int.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a number.", + e.getMessage()); } try { jsonObject.getLong("nonKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.", + e.getMessage()); } try { jsonObject.getLong("stringKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a long.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a number.", + e.getMessage()); } try { jsonObject.getJSONArray("nonKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.", + e.getMessage()); } try { jsonObject.getJSONArray("stringKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a JSONArray.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a JSONArray.", + e.getMessage()); } try { jsonObject.getJSONObject("nonKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"nonKey\"] not found.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"nonKey\"] not found.", + e.getMessage()); } try { jsonObject.getJSONObject("stringKey"); fail("Expected an exception"); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a JSONObject.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONObject[\"stringKey\"] is not a JSONObject.", + e.getMessage()); } } From e4186e072ad2407d5dee25eeacef68884154ec5b Mon Sep 17 00:00:00 2001 From: stleary Date: Sat, 8 Dec 2018 11:29:44 -0600 Subject: [PATCH 87/99] reduce number of iterations to shorten test time --- src/test/java/org/json/junit/JSONObjectTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index c6cb580..8d32649 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -122,9 +122,13 @@ public void timeNumberParsing() { + "0a" }; final int testDataLength = testData.length; - final int iterations = 1000000; + /** + * Changed to 1000 for faster test runs + */ + // final int iterations = 1000000; + final int iterations = 1000; - // 10 million iterations 1,000,000 * 10 + // 10 million iterations 1,000,000 * 10 (currently 100,000) long startTime = System.nanoTime(); for(int i = 0; i < iterations; i++) { for(int j = 0; j < testDataLength; j++) { From d0ea807884728782b2bc1722ca4a79e56e58e245 Mon Sep 17 00:00:00 2001 From: stleary Date: Sat, 8 Dec 2018 14:51:01 -0600 Subject: [PATCH 88/99] xml parser config tests --- README.md | 39 +- .../java/org/json/junit/JunitTestSuite.java | 3 +- .../org/json/junit/XMLConfigurationTest.java | 930 ++++++++++++++++++ 3 files changed, 934 insertions(+), 38 deletions(-) create mode 100755 src/test/java/org/json/junit/XMLConfigurationTest.java diff --git a/README.md b/README.md index 1ca5c64..e6e61b5 100644 --- a/README.md +++ b/README.md @@ -89,43 +89,8 @@ Execution failed for task ':compileJava'. > invalid flag: -parameters ``` -A unit test has the following stages: - -| Test phase |Description | -|----|----| -| No test | No test specifically for this class has been written, or the class contains no executable code. | -| In progress | Unit tests have been started for this class. | -| Coverage > 90% | Initial goal of 90% coverage has been reached. Test quality may be questionable | -| Reasonable test cases | 90% coverage. Functionality and behavior has been confirmed | -| Checked against previous unit tests | Historical unit tests have been checked in case something important was missed | -| Completed | The unit test is completed | - - -| Test file name | Coverage | Comments | -| ------------- | ------------- | ---- | -| Total coverage | 90.6% | | | -| | | | -| CDL.java | 98.8% | Reasonable test cases. | -| Cookie.java | 98.9% | Reasonable test cases. | -| CookieList.java |96.5% | Reasonable test cases. | -| HTTP.java | 98.8%| Coverage > 90% | -| HTTPTokener.java |93.2% | No test | -| JSONArray.java |88.3% | Reasonable test cases. Need new tests for newer API functions | -| JSONException.java | 100% | No test | -| JSONML.java | 84.4%| In progress | -| JSONObject | 96.7% | Reasonable test cases | -| JSONObject.Null | 77.8% | No test | -| JSONPointer | 96.3% | Reasonable test cases | -| JSONPointerException | 100% | No test | -| JSONString.java | | No test | -| JSONStringer.java | 93.8%| Coverage > 90% | -| JSONTokener.java | 87.5% | In progress | -| JSONWriter.java | 89.15% | No test | -| Property.java | 95.8% | Coverage > 90% | -| XML.java | 77.3% | In progress | -| XMLTokener.java| 82.4%| No test | - -| Files used in test | + +| Resource files used in test | | ------------- | | EnumTest.java | | MyBean.java | diff --git a/src/test/java/org/json/junit/JunitTestSuite.java b/src/test/java/org/json/junit/JunitTestSuite.java index 9c9a325..68b5acb 100644 --- a/src/test/java/org/json/junit/JunitTestSuite.java +++ b/src/test/java/org/json/junit/JunitTestSuite.java @@ -18,7 +18,8 @@ EnumTest.class, JSONPointerTest.class, JSONStringTest.class, - JSONTokenerTest.class + JSONTokenerTest.class, + XMLConfigurationTest.class }) public class JunitTestSuite { } diff --git a/src/test/java/org/json/junit/XMLConfigurationTest.java b/src/test/java/org/json/junit/XMLConfigurationTest.java new file mode 100755 index 0000000..a2d0b85 --- /dev/null +++ b/src/test/java/org/json/junit/XMLConfigurationTest.java @@ -0,0 +1,930 @@ +package org.json.junit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.XML; +import org.json.XMLParserConfiguration; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + + +/** + * Tests for JSON-Java XML.java with XMLParserConfiguration.java + */ +public class XMLConfigurationTest { + /** + * JUnit supports temporary files and folders that are cleaned up after the test. + * https://garygregory.wordpress.com/2010/01/20/junit-tip-use-rules-to-manage-temporary-files-and-folders/ + */ + @Rule + public TemporaryFolder testFolder = new TemporaryFolder(); + + /** + * JSONObject from a null XML string. + * Expects a NullPointerException + */ + @Test(expected=NullPointerException.class) + public void shouldHandleNullXML() { + String xmlStr = null; + JSONObject jsonObject = + XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); + assertTrue("jsonObject should be empty", jsonObject.isEmpty()); + } + + /** + * Empty JSONObject from an empty XML string. + */ + @Test + public void shouldHandleEmptyXML() { + + String xmlStr = ""; + JSONObject jsonObject = + XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); + assertTrue("jsonObject should be empty", jsonObject.isEmpty()); + } + + /** + * Empty JSONObject from a non-XML string. + */ + @Test + public void shouldHandleNonXML() { + String xmlStr = "{ \"this is\": \"not xml\"}"; + JSONObject jsonObject = + XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); + assertTrue("xml string should be empty", jsonObject.isEmpty()); + } + + /** + * Invalid XML string (tag contains a frontslash). + * Expects a JSONException + */ + @Test + public void shouldHandleInvalidSlashInTag() { + String xmlStr = + "\n"+ + "\n"+ + "
\n"+ + " \n"+ + " abc street\n"+ + "
\n"+ + "
"; + try { + XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); + fail("Expecting a JSONException"); + } catch (JSONException e) { + assertEquals("Expecting an exception message", + "Misshaped tag at 176 [character 14 line 4]", + e.getMessage()); + } + } + + /** + * Invalid XML string ('!' char in tag) + * Expects a JSONException + */ + @Test + public void shouldHandleInvalidBangInTag() { + String xmlStr = + "\n"+ + "\n"+ + "
\n"+ + " \n"+ + " \n"+ + "
\n"+ + "
"; + try { + XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); + fail("Expecting a JSONException"); + } catch (JSONException e) { + assertEquals("Expecting an exception message", + "Misshaped meta tag at 214 [character 12 line 7]", + e.getMessage()); + } + } + + /** + * Invalid XML string ('!' char and no closing tag brace) + * Expects a JSONException + */ + @Test + public void shouldHandleInvalidBangNoCloseInTag() { + String xmlStr = + "\n"+ + "\n"+ + "
\n"+ + " \n"+ + " \n"+ + ""; + try { + XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); + fail("Expecting a JSONException"); + } catch (JSONException e) { + assertEquals("Expecting an exception message", + "Misshaped meta tag at 213 [character 12 line 7]", + e.getMessage()); + } + } + + /** + * Invalid XML string (no end brace for tag) + * Expects JSONException + */ + @Test + public void shouldHandleNoCloseStartTag() { + String xmlStr = + "\n"+ + "\n"+ + "
\n"+ + " \n"+ + " \n"+ + ""; + try { + XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); + fail("Expecting a JSONException"); + } catch (JSONException e) { + assertEquals("Expecting an exception message", + "Misplaced '<' at 193 [character 4 line 6]", + e.getMessage()); + } + } + + /** + * Invalid XML string (partial CDATA chars in tag name) + * Expects JSONException + */ + @Test + public void shouldHandleInvalidCDATABangInTag() { + String xmlStr = + "\n"+ + "\n"+ + "
\n"+ + " Joe Tester\n"+ + " \n"+ + "
\n"+ + "
"; + try { + XMLParserConfiguration config = + new XMLParserConfiguration("altContent"); + XML.toJSONObject(xmlStr, config); + fail("Expecting a JSONException"); + } catch (JSONException e) { + assertEquals("Expecting an exception message", + "Expected 'CDATA[' at 204 [character 11 line 5]", + e.getMessage()); + } + } + + /** + * Null JSONObject in XML.toString() + */ + @Test + public void shouldHandleNullJSONXML() { + JSONObject jsonObject= null; + String actualXml = XML.toString(jsonObject, null, + XMLParserConfiguration.KEEP_STRINGS); + assertEquals("generated XML does not equal expected XML","\"null\"",actualXml); + } + + /** + * Empty JSONObject in XML.toString() + */ + @Test + public void shouldHandleEmptyJSONXML() { + JSONObject jsonObject= new JSONObject(); + String xmlStr = XML.toString(jsonObject, null, + XMLParserConfiguration.KEEP_STRINGS); + assertTrue("xml string should be empty", xmlStr.isEmpty()); + } + + /** + * No SML start tag. The ending tag ends up being treated as content. + */ + @Test + public void shouldHandleNoStartTag() { + String xmlStr = + "\n"+ + "\n"+ + "
\n"+ + " \n"+ + " >\n"+ + "
\n"+ + "
"; + String expectedStr = + "{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\",\""+ + "content\":\">\"},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+ + "xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}"; + JSONObject jsonObject = XML.toJSONObject(xmlStr, + XMLParserConfiguration.KEEP_STRINGS); + JSONObject expectedJsonObject = new JSONObject(expectedStr); + Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); + } + + /** + * Valid XML to JSONObject + */ + @Test + public void shouldHandleSimpleXML() { + String xmlStr = + "\n"+ + "\n"+ + "
\n"+ + " Joe Tester\n"+ + " [CDATA[Baker street 5]\n"+ + " \n"+ + " true\n"+ + " false\n"+ + " null\n"+ + " 42\n"+ + " -23\n"+ + " -23.45\n"+ + " -23x.45\n"+ + " 1, 2, 3, 4.1, 5.2\n"+ + "
\n"+ + "
"; + + String expectedStr = + "{\"addresses\":{\"address\":{\"street\":\"[CDATA[Baker street 5]\","+ + "\"name\":\"Joe Tester\",\"NothingHere\":\"\",TrueValue:true,\n"+ + "\"FalseValue\":false,\"NullValue\":null,\"PositiveValue\":42,\n"+ + "\"NegativeValue\":-23,\"DoubleValue\":-23.45,\"Nan\":-23x.45,\n"+ + "\"ArrayOfNum\":\"1, 2, 3, 4.1, 5.2\"\n"+ + "},\"xsi:noNamespaceSchemaLocation\":"+ + "\"test.xsd\",\"xmlns:xsi\":\"http://www.w3.org/2001/"+ + "XMLSchema-instance\"}}"; + + XMLParserConfiguration config = + new XMLParserConfiguration("altContent"); + compareStringToJSONObject(xmlStr, expectedStr, config); + compareReaderToJSONObject(xmlStr, expectedStr, config); + compareFileToJSONObject(xmlStr, expectedStr); + } + + /** + * Valid XML with comments to JSONObject + */ + @Test + public void shouldHandleCommentsInXML() { + + String xmlStr = + "\n"+ + "\n"+ + "\n"+ + "
\n"+ + " comment ]]>\n"+ + " Joe Tester\n"+ + " \n"+ + " Baker street 5\n"+ + "
\n"+ + "
"; + XMLParserConfiguration config = + new XMLParserConfiguration("altContent"); + JSONObject jsonObject = XML.toJSONObject(xmlStr, config); + String expectedStr = "{\"addresses\":{\"address\":{\"street\":\"Baker "+ + "street 5\",\"name\":\"Joe Tester\",\"altContent\":\" this is -- "+ + " comment \"}}}"; + JSONObject expectedJsonObject = new JSONObject(expectedStr); + Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); + } + + /** + * Valid XML to XML.toString() + */ + @Test + public void shouldHandleToString() { + String xmlStr = + "\n"+ + "\n"+ + "
\n"+ + " [CDATA[Joe & T > e < s " t ' er]]\n"+ + " Baker street 5\n"+ + " 1, 2, 3, 4.1, 5.2\n"+ + "
\n"+ + "
"; + + String expectedStr = + "{\"addresses\":{\"address\":{\"street\":\"Baker street 5\","+ + "\"name\":\"[CDATA[Joe & T > e < s \\\" t \\\' er]]\","+ + "\"ArrayOfNum\":\"1, 2, 3, 4.1, 5.2\"\n"+ + "},\"xsi:noNamespaceSchemaLocation\":"+ + "\"test.xsd\",\"xmlns:xsi\":\"http://www.w3.org/2001/"+ + "XMLSchema-instance\"}}"; + + JSONObject jsonObject = XML.toJSONObject(xmlStr, + XMLParserConfiguration.KEEP_STRINGS); + String xmlToStr = XML.toString(jsonObject, null, + XMLParserConfiguration.KEEP_STRINGS); + JSONObject finalJsonObject = XML.toJSONObject(xmlToStr, + XMLParserConfiguration.KEEP_STRINGS); + JSONObject expectedJsonObject = new JSONObject(expectedStr); + Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); + Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); + } + + /** + * Converting a JSON doc containing '>' content to JSONObject, then + * XML.toString() should result in valid XML. + */ + @Test + public void shouldHandleContentNoArraytoString() { + String expectedStr = + "{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\",\""+ + "altContent\":\">\"},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+ + "xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}"; + JSONObject expectedJsonObject = new JSONObject(expectedStr); + XMLParserConfiguration config = new XMLParserConfiguration("altContent"); + String finalStr = XML.toString(expectedJsonObject, null, config); + String expectedFinalStr = "
>"+ + "
test.xsdhttp://www.w3.org/2001/XMLSche"+ + "ma-instance
"; + assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+ + finalStr+"]", expectedFinalStr.equals(finalStr)); + } + + /** + * Converting a JSON doc containing a 'content' array to JSONObject, then + * XML.toString() should result in valid XML. + * TODO: This is probably an error in how the 'content' keyword is used. + */ + @Test + public void shouldHandleContentArraytoString() { + String expectedStr = + "{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\",\""+ + "altContent\":[1, 2, 3]},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+ + "xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}"; + JSONObject expectedJsonObject = new JSONObject(expectedStr); + XMLParserConfiguration config = new XMLParserConfiguration("altContent"); + String finalStr = XML.toString(expectedJsonObject, null, config); + String expectedFinalStr = "
"+ + "1\n2\n3"+ + "
test.xsdhttp://www.w3.org/2001/XMLSche"+ + "ma-instance
"; + assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+ + finalStr+"]", expectedFinalStr.equals(finalStr)); + } + + /** + * Converting a JSON doc containing a named array to JSONObject, then + * XML.toString() should result in valid XML. + */ + @Test + public void shouldHandleArraytoString() { + String expectedStr = + "{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\","+ + "\"something\":[1, 2, 3]},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+ + "xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}"; + JSONObject expectedJsonObject = new JSONObject(expectedStr); + String finalStr = XML.toString(expectedJsonObject, null, + XMLParserConfiguration.KEEP_STRINGS); + String expectedFinalStr = "
"+ + "123"+ + "
test.xsdhttp://www.w3.org/2001/XMLSche"+ + "ma-instance
"; + assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+ + finalStr+"]", expectedFinalStr.equals(finalStr)); + } + + /** + * Tests that the XML output for empty arrays is consistent. + */ + @Test + public void shouldHandleEmptyArray(){ + final JSONObject jo1 = new JSONObject(); + jo1.put("array",new Object[]{}); + final JSONObject jo2 = new JSONObject(); + jo2.put("array",new JSONArray()); + + final String expected = ""; + String output1 = XML.toString(jo1, "jo", + XMLParserConfiguration.KEEP_STRINGS); + assertEquals("Expected an empty root tag", expected, output1); + String output2 = XML.toString(jo2, "jo", + XMLParserConfiguration.KEEP_STRINGS); + assertEquals("Expected an empty root tag", expected, output2); + } + + /** + * Tests that the XML output for arrays is consistent when an internal array is empty. + */ + @Test + public void shouldHandleEmptyMultiArray(){ + final JSONObject jo1 = new JSONObject(); + jo1.put("arr",new Object[]{"One", new String[]{}, "Four"}); + final JSONObject jo2 = new JSONObject(); + jo2.put("arr",new JSONArray(new Object[]{"One", new JSONArray(new String[]{}), "Four"})); + + final String expected = "OneFour"; + String output1 = XML.toString(jo1, "jo", + XMLParserConfiguration.KEEP_STRINGS); + assertEquals("Expected a matching array", expected, output1); + String output2 = XML.toString(jo2, "jo", + XMLParserConfiguration.KEEP_STRINGS); + + assertEquals("Expected a matching array", expected, output2); + } + + /** + * Tests that the XML output for arrays is consistent when arrays are not empty. + */ + @Test + public void shouldHandleNonEmptyArray(){ + final JSONObject jo1 = new JSONObject(); + jo1.put("arr",new String[]{"One", "Two", "Three"}); + final JSONObject jo2 = new JSONObject(); + jo2.put("arr",new JSONArray(new String[]{"One", "Two", "Three"})); + + final String expected = "OneTwoThree"; + String output1 = XML.toString(jo1, "jo", + XMLParserConfiguration.KEEP_STRINGS); + assertEquals("Expected a non empty root tag", expected, output1); + String output2 = XML.toString(jo2, "jo", + XMLParserConfiguration.KEEP_STRINGS); + assertEquals("Expected a non empty root tag", expected, output2); + } + + /** + * Tests that the XML output for arrays is consistent when arrays are not empty and contain internal arrays. + */ + @Test + public void shouldHandleMultiArray(){ + final JSONObject jo1 = new JSONObject(); + jo1.put("arr",new Object[]{"One", new String[]{"Two", "Three"}, "Four"}); + final JSONObject jo2 = new JSONObject(); + jo2.put("arr",new JSONArray(new Object[]{"One", new JSONArray(new String[]{"Two", "Three"}), "Four"})); + + final String expected = "OneTwoThreeFour"; + String output1 = XML.toString(jo1, "jo", + XMLParserConfiguration.KEEP_STRINGS); + assertEquals("Expected a matching array", expected, output1); + String output2 = XML.toString(jo2, "jo", + XMLParserConfiguration.KEEP_STRINGS); + assertEquals("Expected a matching array", expected, output2); + } + + /** + * Converting a JSON doc containing a named array of nested arrays to + * JSONObject, then XML.toString() should result in valid XML. + */ + @Test + public void shouldHandleNestedArraytoString() { + String xmlStr = + "{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\","+ + "\"outer\":[[1], [2], [3]]},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+ + "xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}"; + JSONObject jsonObject = new JSONObject(xmlStr); + String finalStr = XML.toString(jsonObject, null, + XMLParserConfiguration.ORIGINAL); + JSONObject finalJsonObject = XML.toJSONObject(finalStr); + String expectedStr = "
"+ + "12"+ + "3"+ + "
test.xsdhttp://www.w3.org/2001/XMLSche"+ + "ma-instance
"; + JSONObject expectedJsonObject = XML.toJSONObject(expectedStr, + XMLParserConfiguration.ORIGINAL); + Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); + } + + + /** + * Possible bug: + * Illegal node-names must be converted to legal XML-node-names. + * The given example shows 2 nodes which are valid for JSON, but not for XML. + * Therefore illegal arguments should be converted to e.g. an underscore (_). + */ + @Test + public void shouldHandleIllegalJSONNodeNames() + { + JSONObject inputJSON = new JSONObject(); + inputJSON.append("123IllegalNode", "someValue1"); + inputJSON.append("Illegal@node", "someValue2"); + + String result = XML.toString(inputJSON, null, + XMLParserConfiguration.KEEP_STRINGS); + + /* + * This is invalid XML. Names should not begin with digits or contain + * certain values, including '@'. One possible solution is to replace + * illegal chars with '_', in which case the expected output would be: + * <___IllegalNode>someValue1someValue2 + */ + String expected = "<123IllegalNode>someValue1someValue2"; + + assertEquals(expected, result); + } + + /** + * JSONObject with NULL value, to XML.toString() + */ + @Test + public void shouldHandleNullNodeValue() + { + JSONObject inputJSON = new JSONObject(); + inputJSON.put("nullValue", JSONObject.NULL); + // This is a possible preferred result + // String expectedXML = ""; + /** + * This is the current behavior. JSONObject.NULL is emitted as + * the string, "null". + */ + String actualXML = "null"; + String resultXML = XML.toString(inputJSON, null, + XMLParserConfiguration.KEEP_STRINGS); + assertEquals(actualXML, resultXML); + } + + /** + * Investigate exactly how the "content" keyword works + */ + @Test + public void contentOperations() { + /* + * When a standalone 0) then return]]>"; + JSONObject jsonObject = XML.toJSONObject(xmlStr, + XMLParserConfiguration.KEEP_STRINGS); + assertTrue("1. 3 items", 3 == jsonObject.length()); + assertTrue("1. empty tag1", "".equals(jsonObject.get("tag1"))); + assertTrue("1. empty tag2", "".equals(jsonObject.get("tag2"))); + assertTrue("1. content found", "if (a < b && a > 0) then return".equals(jsonObject.get("content"))); + + // multiple consecutive standalone cdatas are accumulated into an array + xmlStr = " 0) then return]]>"; + jsonObject = XML.toJSONObject(xmlStr, + new XMLParserConfiguration(true, "altContent")); + assertTrue("2. 3 items", 3 == jsonObject.length()); + assertTrue("2. empty tag1", "".equals(jsonObject.get("tag1"))); + assertTrue("2. empty tag2", "".equals(jsonObject.get("tag2"))); + assertTrue("2. content array found", jsonObject.get("altContent") instanceof JSONArray); + JSONArray jsonArray = jsonObject.getJSONArray("altContent"); + assertTrue("2. array size", jsonArray.length() == 2); + assertTrue("2. content array entry 0", "if (a < b && a > 0) then return".equals(jsonArray.get(0))); + assertTrue("2. content array entry 1", "here is another cdata".equals(jsonArray.get(1))); + + /* + * text content is accumulated in a "content" inside a local JSONObject. + * If there is only one instance, it is saved in the context (a different JSONObject + * from the calling code. and the content element is discarded. + */ + xmlStr = "value 1"; + jsonObject = XML.toJSONObject(xmlStr, + new XMLParserConfiguration(true, "altContent")); + assertTrue("3. 2 items", 1 == jsonObject.length()); + assertTrue("3. value tag1", "value 1".equals(jsonObject.get("tag1"))); + + /* + * array-style text content (multiple tags with the same name) is + * accumulated in a local JSONObject with key="content" and value=JSONArray, + * saved in the context, and then the local JSONObject is discarded. + */ + xmlStr = "value 12true"; + jsonObject = XML.toJSONObject(xmlStr, + new XMLParserConfiguration(true, "altContent")); + assertTrue("4. 1 item", 1 == jsonObject.length()); + assertTrue("4. content array found", jsonObject.get("tag1") instanceof JSONArray); + jsonArray = jsonObject.getJSONArray("tag1"); + assertTrue("4. array size", jsonArray.length() == 3); + assertTrue("4. content array entry 0", "value 1".equals(jsonArray.get(0))); + assertTrue("4. content array entry 1", jsonArray.getInt(1) == 2); + assertTrue("4. content array entry 2", jsonArray.getBoolean(2) == true); + + /* + * Complex content is accumulated in a "content" field. For example, an element + * may contain a mix of child elements and text. Each text segment is + * accumulated to content. + */ + xmlStr = "val1val2"; + jsonObject = XML.toJSONObject(xmlStr, + new XMLParserConfiguration(true, "altContent")); + assertTrue("5. 1 item", 1 == jsonObject.length()); + assertTrue("5. jsonObject found", jsonObject.get("tag1") + instanceof JSONObject); + jsonObject = jsonObject.getJSONObject("tag1"); + assertTrue("5. 2 contained items", 2 == jsonObject.length()); + assertTrue("5. contained tag", "".equals(jsonObject.get("tag2"))); + assertTrue("5. contained content jsonArray found", + jsonObject.get("altContent") instanceof JSONArray); + jsonArray = jsonObject.getJSONArray("altContent"); + assertTrue("5. array size", jsonArray.length() == 2); + assertTrue("5. content array entry 0", "val1".equals(jsonArray.get(0))); + assertTrue("5. content array entry 1", "val2".equals(jsonArray.get(1))); + + /* + * If there is only 1 complex text content, then it is accumulated in a + * "content" field as a string. + */ + xmlStr = "val1"; + jsonObject = XML.toJSONObject(xmlStr, + new XMLParserConfiguration(true, "altContent")); + assertTrue("6. 1 item", 1 == jsonObject.length()); + assertTrue("6. jsonObject found", jsonObject.get("tag1") instanceof JSONObject); + jsonObject = jsonObject.getJSONObject("tag1"); + assertTrue("6. contained content found", + "val1".equals(jsonObject.get("altContent"))); + assertTrue("6. contained tag2", "".equals(jsonObject.get("tag2"))); + + /* + * In this corner case, the content sibling happens to have key=content + * We end up with an array within an array, and no content element. + * This is probably a bug. + */ + xmlStr = "val1"; + jsonObject = XML.toJSONObject(xmlStr, + new XMLParserConfiguration(true, "altContent")); + assertTrue("7. 1 item", 1 == jsonObject.length()); + assertTrue("7. jsonArray found", + jsonObject.get("tag1") instanceof JSONArray); + jsonArray = jsonObject.getJSONArray("tag1"); + assertTrue("array size 1", jsonArray.length() == 1); + assertTrue("7. contained array found", jsonArray.get(0) + instanceof JSONArray); + jsonArray = jsonArray.getJSONArray(0); + assertTrue("7. inner array size 2", jsonArray.length() == 2); + assertTrue("7. inner array item 0", "val1".equals(jsonArray.get(0))); + assertTrue("7. inner array item 1", "".equals(jsonArray.get(1))); + + /* + * Confirm behavior of original issue + */ + String jsonStr = + "{"+ + "\"Profile\": {"+ + "\"list\": {"+ + "\"history\": {"+ + "\"entries\": ["+ + "{"+ + "\"deviceId\": \"id\","+ + "\"altContent\": {"+ + "\"material\": ["+ + "{"+ + "\"stuff\": false"+ + "}"+ + "]"+ + "}"+ + "}"+ + "]"+ + "}"+ + "}"+ + "}"+ + "}"; + jsonObject = new JSONObject(jsonStr); + xmlStr = XML.toString(jsonObject, null, + new XMLParserConfiguration(true, "altContent")); + /* + * This is the created XML. Looks like content was mistaken for + * complex (child node + text) XML. + * + * + * + * + * id + * {"material":[{"stuff":false}]} + * + * + * + * + */ + assertTrue("nothing to test here, see comment on created XML, above", true); + } + + /** + * JSON string lost leading zero and converted "True" to true. + */ + @Test + public void testToJSONArray_jsonOutput() { + final String originalXml = "011000True"; + final String expectedJsonString = "{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0],\"title\":true}}"; + final JSONObject actualJsonOutput = XML.toJSONObject(originalXml, + new XMLParserConfiguration(false)); + assertEquals(expectedJsonString, actualJsonOutput.toString()); + } + + /** + * JSON string cannot be reverted to original xml. + */ + @Test + public void testToJSONArray_reversibility() { + final String originalXml = "011000True"; + XMLParserConfiguration config = new XMLParserConfiguration(false); + final String revertedXml = + XML.toString(XML.toJSONObject(originalXml, config), + null, config); + assertNotEquals(revertedXml, originalXml); + } + + /** + * test passes when using the new method toJsonArray. + */ + @Test + public void testToJsonXML() { + final String originalXml = "011000True"; + final String expectedJsonString = "{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\"],\"title\":\"True\"}}"; + + final JSONObject json = XML.toJSONObject(originalXml, + new XMLParserConfiguration(true)); + assertEquals(expectedJsonString, json.toString()); + + final String reverseXml = XML.toString(json); + // this reversal isn't exactly the same. use JSONML for an exact reversal + final String expectedReverseXml = "01011000True"; + + assertEquals(expectedReverseXml, reverseXml); + } + + /** + * test to validate certain conditions of XML unescaping. + */ + @Test + public void testUnescape() { + assertEquals("{\"xml\":\"Can cope <;\"}", + XML.toJSONObject("Can cope <; ", + XMLParserConfiguration.KEEP_STRINGS).toString()); + assertEquals("Can cope <; ", XML.unescape("Can cope <; ")); + + assertEquals("{\"xml\":\"Can cope & ;\"}", + XML.toJSONObject("Can cope & ; ", + XMLParserConfiguration.KEEP_STRINGS).toString()); + assertEquals("Can cope & ; ", XML.unescape("Can cope & ; ")); + + assertEquals("{\"xml\":\"Can cope &;\"}", + XML.toJSONObject("Can cope &; ", + XMLParserConfiguration.KEEP_STRINGS).toString()); + assertEquals("Can cope &; ", XML.unescape("Can cope &; ")); + + // unicode entity + assertEquals("{\"xml\":\"Can cope 4;\"}", + XML.toJSONObject("Can cope 4; ", + XMLParserConfiguration.KEEP_STRINGS).toString()); + assertEquals("Can cope 4; ", XML.unescape("Can cope 4; ")); + + // double escaped + assertEquals("{\"xml\":\"Can cope <\"}", + XML.toJSONObject("Can cope &lt; ", + XMLParserConfiguration.KEEP_STRINGS).toString()); + assertEquals("Can cope < ", XML.unescape("Can cope &lt; ")); + + assertEquals("{\"xml\":\"Can cope 4\"}", + XML.toJSONObject("Can cope &#x34; ", + XMLParserConfiguration.KEEP_STRINGS).toString()); + assertEquals("Can cope 4 ", XML.unescape("Can cope &#x34; ")); + + } + + /** + * Confirm XMLParserConfiguration functionality + */ + @Test + public void testConfig() { + /** + * 1st param is whether to keep the raw string, or call + * XML.stringToValue(), which may convert the token to + * boolean, null, or number. + * 2nd param is what JSON name to use for strings that are + * evaluated as xml content data in complex objects, e.g. + * + * value + * content data + * + */ + + String xmlStr = + "\n"+ + "\n"+ + "
\n"+ + " content 1\n"+ + " Sherlock Holmes\n"+ + " content 2\n"+ + " Baker street 5\n"+ + " content 3\n"+ + " 1\n"+ + "
\n"+ + "
"; + + // keep strings, use the altContent tag + XMLParserConfiguration config = + new XMLParserConfiguration(true, "altContent"); + JSONObject jsonObject = XML.toJSONObject(xmlStr, config); + // num is parsed as a string + assertEquals(jsonObject.getJSONObject("addresses"). + getJSONObject("address").getString("num"), "1"); + // complex content is collected in an 'altContent' array + JSONArray jsonArray = jsonObject.getJSONObject("addresses"). + getJSONObject("address").getJSONArray("altContent"); + String expectedStr = "[\"content 1\", \"content 2\", \"content 3\"]"; + JSONArray expectedJsonArray = new JSONArray(expectedStr); + Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); + + // keepstrings only + jsonObject = XML.toJSONObject(xmlStr, + XMLParserConfiguration.KEEP_STRINGS); + // num is parsed as a string + assertEquals(jsonObject.getJSONObject("addresses"). + getJSONObject("address").getString("num"), "1"); + // complex content is collected in an 'content' array + jsonArray = jsonObject.getJSONObject("addresses"). + getJSONObject("address").getJSONArray("content"); + expectedJsonArray = new JSONArray(expectedStr); + Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); + + // use alternate content name + config = new XMLParserConfiguration("altContent"); + jsonObject = XML.toJSONObject(xmlStr, config); + // num is parsed as a number + assertEquals(jsonObject.getJSONObject("addresses"). + getJSONObject("address").getInt("num"), 1); + // complex content is collected in an 'altContent' array + jsonArray = jsonObject.getJSONObject("addresses"). + getJSONObject("address").getJSONArray("altContent"); + expectedJsonArray = new JSONArray(expectedStr); + Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); + + } + + + /** + * Convenience method, given an input string and expected result, + * convert to JSONObject and compare actual to expected result. + * @param xmlStr the string to parse + * @param expectedStr the expected JSON string + * @param config provides more flexible XML parsing + * flexible XML parsing. + */ + private void compareStringToJSONObject(String xmlStr, String expectedStr, + XMLParserConfiguration config) { + JSONObject expectedJsonObject = new JSONObject(expectedStr); + JSONObject jsonObject = XML.toJSONObject(xmlStr, config); + Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); + } + + /** + * Convenience method, given an input string and expected result, + * convert to JSONObject via reader and compare actual to expected result. + * @param xmlStr the string to parse + * @param expectedStr the expected JSON string + * @param config provides more flexible XML parsing + */ + private void compareReaderToJSONObject(String xmlStr, String expectedStr, + XMLParserConfiguration config) { + /* + * Commenting out this method until the JSON-java code is updated + * to support XML.toJSONObject(reader) + JSONObject expectedJsonObject = new JSONObject(expectedStr); + Reader reader = new StringReader(xmlStr); + JSONObject jsonObject = XML.toJSONObject(reader); + Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); + */ + } + + /** + * Convenience method, given an input string and expected result, convert to + * JSONObject via file and compare actual to expected result. + * + * @param xmlStr + * the string to parse + * @param expectedStr + * the expected JSON string + * @throws IOException + */ + private void compareFileToJSONObject(String xmlStr, String expectedStr) { + /* + * Commenting out this method until the JSON-java code is updated + * to support XML.toJSONObject(reader) + try { + JSONObject expectedJsonObject = new JSONObject(expectedStr); + File tempFile = testFolder.newFile("fileToJSONObject.xml"); + FileWriter fileWriter = new FileWriter(tempFile); + fileWriter.write(xmlStr); + fileWriter.close(); + Reader reader = new FileReader(tempFile); + JSONObject jsonObject = XML.toJSONObject(reader); + Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); + } catch (IOException e) { + assertTrue("file writer error: " +e.getMessage(), false); + } + */ + } +} \ No newline at end of file From e7f7d348cd13e2e6d168e13398f6d7384294cc2a Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 10 Dec 2018 11:45:10 -0500 Subject: [PATCH 89/99] * updates tests to cover more cases of tokenizing * uncomments tests that should now work --- src/test/java/org/json/junit/CDLTest.java | 10 +- .../java/org/json/junit/JSONTokenerTest.java | 94 +++++++++++++++++++ src/test/java/org/json/junit/XMLTest.java | 32 +++---- 3 files changed, 115 insertions(+), 21 deletions(-) diff --git a/src/test/java/org/json/junit/CDLTest.java b/src/test/java/org/json/junit/CDLTest.java index b1f9561..721fd3c 100644 --- a/src/test/java/org/json/junit/CDLTest.java +++ b/src/test/java/org/json/junit/CDLTest.java @@ -30,7 +30,7 @@ public class CDLTest { ); /** - * CDL.toJSONArray() adds all values asstrings, with no filtering or + * CDL.toJSONArray() adds all values as strings, with no filtering or * conversions. For testing, this means that the expected JSONObject * values all must be quoted in the cases where the JSONObject parsing * might normally convert the value into a non-string. @@ -264,8 +264,8 @@ public void checkSpecialChars() { */ @Test public void textToJSONArray() { - JSONArray jsonArray = CDL.toJSONArray(lines); - JSONArray expectedJsonArray = new JSONArray(expectedLines); + JSONArray jsonArray = CDL.toJSONArray(this.lines); + JSONArray expectedJsonArray = new JSONArray(this.expectedLines); Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); } @@ -289,10 +289,10 @@ public void jsonArrayToJSONArray() { */ @Test public void textToJSONArrayAndBackToString() { - JSONArray jsonArray = CDL.toJSONArray(lines); + JSONArray jsonArray = CDL.toJSONArray(this.lines); String jsonStr = CDL.toString(jsonArray); JSONArray finalJsonArray = CDL.toJSONArray(jsonStr); - JSONArray expectedJsonArray = new JSONArray(expectedLines); + JSONArray expectedJsonArray = new JSONArray(this.expectedLines); Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray); } diff --git a/src/test/java/org/json/junit/JSONTokenerTest.java b/src/test/java/org/json/junit/JSONTokenerTest.java index dced89f..de1564d 100644 --- a/src/test/java/org/json/junit/JSONTokenerTest.java +++ b/src/test/java/org/json/junit/JSONTokenerTest.java @@ -12,7 +12,9 @@ import java.io.Reader; import java.io.StringReader; +import org.json.JSONArray; import org.json.JSONException; +import org.json.JSONObject; import org.json.JSONTokener; import org.junit.Test; @@ -64,7 +66,99 @@ public void verifyBackFailureDoubleBack() throws IOException { } } } + + @Test + public void testValid() { + checkValid("0",Number.class); + checkValid(" 0 ",Number.class); + checkValid("23",Number.class); + checkValid("23.5",Number.class); + checkValid(" 23.5 ",Number.class); + checkValid("null",null); + checkValid(" null ",null); + checkValid("true",Boolean.class); + checkValid(" true\n",Boolean.class); + checkValid("false",Boolean.class); + checkValid("\nfalse ",Boolean.class); + checkValid("{}",JSONObject.class); + checkValid(" {} ",JSONObject.class); + checkValid("{\"a\":1}",JSONObject.class); + checkValid(" {\"a\":1} ",JSONObject.class); + checkValid("[]",JSONArray.class); + checkValid(" [] ",JSONArray.class); + checkValid("[1,2]",JSONArray.class); + checkValid("\n\n[1,2]\n\n",JSONArray.class); + checkValid("1 2", String.class); + } + + @Test + public void testErrors() { + // Check that stream can detect that a value is found after + // the first one + checkError(" { \"a\":1 } 4 "); + checkError("null \"a\""); + checkError("{} true"); + } + + private Object checkValid(String testStr, Class aClass) { + Object result = nextValue(testStr); + // Check class of object returned + if( null == aClass ) { + if(JSONObject.NULL.equals(result)) { + // OK + } else { + throw new JSONException("Unexpected class: "+result.getClass().getSimpleName()); + } + } else { + if( null == result ) { + throw new JSONException("Unexpected null result"); + } else if(!aClass.isAssignableFrom(result.getClass()) ) { + throw new JSONException("Unexpected class: "+result.getClass().getSimpleName()); + } + } + + return result; + } + + private void checkError(String testStr) { + try { + nextValue(testStr); + + fail("Error should be triggered: (\""+testStr+"\")"); + } catch (JSONException e) { + // OK + } + } + + /** + * Verifies that JSONTokener can read a stream that contains a value. After + * the reading is done, check that the stream is left in the correct state + * by reading the characters after. All valid cases should reach end of stream. + * @param testStr + * @return + * @throws Exception + */ + private Object nextValue(String testStr) throws JSONException { + try(StringReader sr = new StringReader(testStr);){ + JSONTokener tokener = new JSONTokener(sr); + + Object result = tokener.nextValue(); + + if( result == null ) { + throw new JSONException("Unable to find value token in JSON stream: ("+tokener+"): "+testStr); + } + + char c = tokener.nextClean(); + if( 0 != c ) { + throw new JSONException("Unexpected character found at end of JSON stream: "+c+ " ("+tokener+"): "+testStr); + } + + return result; + } + + } + /** * Tests the failure of the skipTo method with a buffered reader. Preferably * we'd like this not to fail but at this time we don't have a good recovery. diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 1cff326..83a7cc2 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -6,6 +6,13 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -743,14 +750,10 @@ private void compareStringToJSONObject(String xmlStr, String expectedStr) { * @param expectedStr the expected JSON string */ private void compareReaderToJSONObject(String xmlStr, String expectedStr) { - /* - * Commenting out this method until the JSON-java code is updated - * to support XML.toJSONObject(reader) JSONObject expectedJsonObject = new JSONObject(expectedStr); Reader reader = new StringReader(xmlStr); JSONObject jsonObject = XML.toJSONObject(reader); Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - */ } /** @@ -764,22 +767,19 @@ private void compareReaderToJSONObject(String xmlStr, String expectedStr) { * @throws IOException */ private void compareFileToJSONObject(String xmlStr, String expectedStr) { - /* - * Commenting out this method until the JSON-java code is updated - * to support XML.toJSONObject(reader) try { JSONObject expectedJsonObject = new JSONObject(expectedStr); - File tempFile = testFolder.newFile("fileToJSONObject.xml"); - FileWriter fileWriter = new FileWriter(tempFile); - fileWriter.write(xmlStr); - fileWriter.close(); - Reader reader = new FileReader(tempFile); - JSONObject jsonObject = XML.toJSONObject(reader); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); + File tempFile = this.testFolder.newFile("fileToJSONObject.xml"); + try(FileWriter fileWriter = new FileWriter(tempFile);){ + fileWriter.write(xmlStr); + } + try(Reader reader = new FileReader(tempFile);){ + JSONObject jsonObject = XML.toJSONObject(reader); + Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); + } } catch (IOException e) { - assertTrue("file writer error: " +e.getMessage(), false); + fail("file writer error: " +e.getMessage()); } - */ } /** From 614e8359b91eb997142d313a0469aa69b707394e Mon Sep 17 00:00:00 2001 From: meiskalt7 Date: Thu, 18 Apr 2019 21:42:57 +0700 Subject: [PATCH 90/99] add test for xsi:nil to null conversion --- src/test/java/org/json/junit/XMLTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 83a7cc2..195f706 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -17,6 +17,7 @@ import org.json.JSONException; import org.json.JSONObject; import org.json.XML; +import org.json.XMLParserConfiguration; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -856,4 +857,15 @@ public void testUnescape() { } + /** + * test passes when xsi:nil="true" converting to null (JSON specification-like conversion) + */ + @Test + public void testToJsonWithNull() { + final String originalXml = ""; + final String expectedJsonString = "{\"root\":{\"id\":null}}"; + + final JSONObject json = XML.toJSONObject(originalXml,new XMLParserConfiguration(false, "content", true)); + assertEquals(expectedJsonString, json.toString()); + } } \ No newline at end of file From fa173fa51a61ba68c5c721c3170869f5ae93a927 Mon Sep 17 00:00:00 2001 From: meiskalt7 Date: Sun, 21 Apr 2019 00:53:39 +0700 Subject: [PATCH 91/99] add test for xsi:nil to null conversion disabled --- src/test/java/org/json/junit/XMLTest.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 195f706..b74daff 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -858,14 +858,26 @@ public void testUnescape() { } /** - * test passes when xsi:nil="true" converting to null (JSON specification-like conversion) + * test passes when xsi:nil="true" converting to null (JSON specification-like nil conversion enabled) */ @Test - public void testToJsonWithNull() { + public void testToJsonWithNullWhenNilConversionEnabled() { final String originalXml = ""; final String expectedJsonString = "{\"root\":{\"id\":null}}"; - final JSONObject json = XML.toJSONObject(originalXml,new XMLParserConfiguration(false, "content", true)); + final JSONObject json = XML.toJSONObject(originalXml, new XMLParserConfiguration(false, "content", true)); + assertEquals(expectedJsonString, json.toString()); + } + + /** + * test passes when xsi:nil="true" not converting to null (JSON specification-like nil conversion disabled) + */ + @Test + public void testToJsonWithNullWhenNilConversionDisabled() { + final String originalXml = ""; + final String expectedJsonString = "{\"root\":{\"id\":{\"xsi:nil\":true}}}"; + + final JSONObject json = XML.toJSONObject(originalXml, new XMLParserConfiguration()); assertEquals(expectedJsonString, json.toString()); } } \ No newline at end of file From 3e7a0b13d1c2ed0b18d5ba143ddaaf171c72932a Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Tue, 17 Sep 2019 10:36:48 -0400 Subject: [PATCH 92/99] new test case for issue 484 --- src/test/java/org/json/junit/JSONMLTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index 84b33ba..26f4f90 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -803,4 +803,16 @@ public void testToJSONObject_reversibility() { // // assertEquals(expectedJsonString, actualJsonString); // } + + @Test (timeout = 6000) + public void testIssue484InfinteLoop() { + try { + JSONML.toJSONObject("??*^M??|?CglR^F??`??>?w??PIlr^E??D^X^]?$?-^R?o??O?*??{OD?^FY??`2a????NM?b^Tq?:O?>S$^K?J?^FB.gUK?m^H??zE??^??!v]?^A???^[^A??^U?c??????h???s???g^Z???`?q^Dbi??:^QZl?)?}1^??k?0??:$V?$?Ovs(}J??^V????2;^QgQ?^_^A?^D?^U?Tg?K?`?h%c?hmGA? Date: Tue, 17 Sep 2019 10:47:16 -0400 Subject: [PATCH 93/99] Test cases updates for standardized exception messages --- src/test/java/org/json/junit/JSONArrayTest.java | 8 ++++---- src/test/java/org/json/junit/JSONMLTest.java | 6 +++--- src/test/java/org/json/junit/JSONObjectTest.java | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 3b70446..5aef340 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -346,14 +346,14 @@ public void failedGetArrayValues() { assertTrue("expected getDouble to fail", false); } catch (JSONException e) { assertEquals("Expected an exception message", - "JSONArray[4] is not a number.",e.getMessage()); + "JSONArray[4] is not a double.",e.getMessage()); } try { jsonArray.getInt(4); assertTrue("expected getInt to fail", false); } catch (JSONException e) { assertEquals("Expected an exception message", - "JSONArray[4] is not a number.",e.getMessage()); + "JSONArray[4] is not a int.",e.getMessage()); } try { jsonArray.getJSONArray(4); @@ -374,14 +374,14 @@ public void failedGetArrayValues() { assertTrue("expected getLong to fail", false); } catch (JSONException e) { assertEquals("Expected an exception message", - "JSONArray[4] is not a number.",e.getMessage()); + "JSONArray[4] is not a long.",e.getMessage()); } try { jsonArray.getString(5); assertTrue("expected getString to fail", false); } catch (JSONException e) { assertEquals("Expected an exception message", - "JSONArray[5] not a string.",e.getMessage()); + "JSONArray[5] is not a String.",e.getMessage()); } } diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index 84b33ba..fe3cd87 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -133,9 +133,9 @@ public void emptyTagException() { JSONML.toString(jsonArray); assertTrue("Expecting an exception", false); } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONArray[0] not a string.". - equals(e.getMessage())); + assertEquals("Expecting an exception message", + "JSONArray[0] is not a String.", + e.getMessage()); } } diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 8d32649..ac67980 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1041,7 +1041,7 @@ public void jsonObjectNonAndWrongValues() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "JSONObject[\"trueKey\"] not a string.", + "JSONObject[\"trueKey\"] is not a string.", e.getMessage()); } try { @@ -1057,7 +1057,7 @@ public void jsonObjectNonAndWrongValues() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a number.", + "JSONObject[\"stringKey\"] is not a double.", e.getMessage()); } try { @@ -1073,7 +1073,7 @@ public void jsonObjectNonAndWrongValues() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a number.", + "JSONObject[\"stringKey\"] is not a float.", e.getMessage()); } try { @@ -1089,7 +1089,7 @@ public void jsonObjectNonAndWrongValues() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a number.", + "JSONObject[\"stringKey\"] is not a int.", e.getMessage()); } try { @@ -1105,7 +1105,7 @@ public void jsonObjectNonAndWrongValues() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "JSONObject[\"stringKey\"] is not a number.", + "JSONObject[\"stringKey\"] is not a long.", e.getMessage()); } try { @@ -2087,7 +2087,7 @@ public void jsonObjectParsingErrors() { fail("Expected an exception"); } catch (JSONException e) { assertEquals("Expecting an exception message", - "JSONObject[myKey] is not a JSONArray.", + "JSONObject[\"myKey\"] is not a JSONArray (null).", e.getMessage()); } try { From 67e59888a2764d5b36fa133473563d70da4136ac Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Tue, 17 Sep 2019 11:14:41 -0400 Subject: [PATCH 94/99] add second case for data in #484 --- src/test/java/org/json/junit/JSONMLTest.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index 26f4f90..b7afe40 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -2,6 +2,8 @@ import static org.junit.Assert.*; +import java.util.Base64; + import org.json.*; import org.junit.Test; @@ -805,7 +807,7 @@ public void testToJSONObject_reversibility() { // } @Test (timeout = 6000) - public void testIssue484InfinteLoop() { + public void testIssue484InfinteLoop1() { try { JSONML.toJSONObject("??*^M??|?CglR^F??`??>?w??PIlr^E??D^X^]?$?-^R?o??O?*??{OD?^FY??`2a????NM?b^Tq?:O?>S$^K?J?^FB.gUK?m^H??zE??^??!v]?^A???^[^A??^U?c??????h???s???g^Z???`?q^Dbi??:^QZl?)?}1^??k?0??:$V?$?Ovs(}J??^V????2;^QgQ?^_^A?^D?^U?Tg?K?`?h%c?hmGA??w??PIlr??D?$?-?o??O?*??{OD?Y??`2a????NM?bq?:O?>S$ ?J?B.gUK?m\b??zE???!v]???????c??????h???s???g???`?qbi??:Zl?)?}1^??k?0??:$V?$?Ovs(}J??????2;gQ????Tg?K?`?h%c?hmGA? Date: Tue, 17 Sep 2019 11:15:25 -0400 Subject: [PATCH 95/99] remove unused import --- src/test/java/org/json/junit/JSONMLTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index b7afe40..3687fe5 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -2,8 +2,6 @@ import static org.junit.Assert.*; -import java.util.Base64; - import org.json.*; import org.junit.Test; From 16da56eb34b6036f145dea7e6bf638b6ad418b5e Mon Sep 17 00:00:00 2001 From: Alanscut Date: Sat, 28 Dec 2019 17:53:27 +0800 Subject: [PATCH 96/99] improve the confused assert message --- .../java/org/json/junit/JSONObjectTest.java | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index ac67980..438e55e 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -589,19 +589,19 @@ public void jsonObjectByBean2() { jsonObject.has("someString")); assertFalse("Normal field name (myDouble) processing did not work", jsonObject.has("myDouble")); - assertFalse("Normal field name (someFloat) found", + assertFalse("Normal field name (someFloat) processing did not work", jsonObject.has("someFloat")); - assertFalse("Ignored field found!", + assertFalse("Ignored field not found!", jsonObject.has("ignoredInt")); - assertTrue("Normal field name (someInt) processing did not work", + assertTrue("Normal field name (someInt) found", jsonObject.has("someInt")); - assertTrue("Normal field name (someLong) processing did not work", + assertTrue("Normal field name (someLong) found", jsonObject.has("someLong")); - assertTrue("Overridden String field name (myStringField) not found", + assertTrue("Overridden String field name (myStringField) found", jsonObject.has("myStringField")); - assertTrue("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) not found", + assertTrue("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) found", jsonObject.has("Some Weird NAme that Normally Wouldn't be possible!")); - assertTrue("Overridden String field name (InterfaceField) not found", + assertTrue("Overridden String field name (InterfaceField) found", jsonObject.has("InterfaceField")); } @@ -619,26 +619,29 @@ public void jsonObjectByBean3() { jsonObject.has("someInt")); assertFalse("Normal field name (myDouble) processing did not work", jsonObject.has("myDouble")); - assertFalse("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) FOUND!", + assertFalse("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) not FOUND!", jsonObject.has("Some Weird NAme that Normally Wouldn't be possible!")); - assertFalse("Normal field name (someFloat) found", + assertFalse("Normal field name (someFloat) found, but was overridden", jsonObject.has("someFloat")); - assertFalse("Ignored field found!", + assertFalse("Ignored field found! but was overridden", jsonObject.has("ignoredInt")); - assertFalse("Ignored field at the same level as forced name found", + assertFalse("Ignored field at the same level as forced name not found", jsonObject.has("ShouldBeIgnored")); - assertTrue("Overridden int field name (newIntFieldName) not found", + assertFalse("Normally ignored field (able) with explicit property name not found", + jsonObject.has("able")); + assertTrue("Overridden int field name (newIntFieldName) found", jsonObject.has("newIntFieldName")); - assertTrue("Normal field name (someLong) processing did not work", + assertTrue("Normal field name (someLong) found", jsonObject.has("someLong")); - assertTrue("Overridden String field name (myStringField) not found", + assertTrue("Overridden String field name (myStringField) found", jsonObject.has("myStringField")); - assertTrue(jsonObject.has("AMoreNormalName")); - assertTrue("Overridden String field name (InterfaceField) not found", + assertTrue("Overridden double field name (AMoreNormalName) found", + jsonObject.has("AMoreNormalName")); + assertTrue("Overridden String field name (InterfaceField) found", jsonObject.has("InterfaceField")); - assertTrue("Forced field not found!", + assertTrue("Forced field found!", jsonObject.has("forcedInt")); - assertTrue("Normally ignored field (getable) with explicit property name not found", + assertTrue("Overridden boolean field name (Getable) found", jsonObject.has("Getable")); } From 08719d4b3a6d73918631297030e8e03cc960de24 Mon Sep 17 00:00:00 2001 From: Alan Wang <948467222@qq.com> Date: Mon, 30 Dec 2019 09:51:08 +0800 Subject: [PATCH 97/99] Apply suggestions from code review Co-Authored-By: Sean Leary --- .../java/org/json/junit/JSONObjectTest.java | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 438e55e..b2f501e 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -593,15 +593,20 @@ public void jsonObjectByBean2() { jsonObject.has("someFloat")); assertFalse("Ignored field not found!", jsonObject.has("ignoredInt")); - assertTrue("Normal field name (someInt) found", + // getSomeInt() has no user-defined annotation + assertTrue("Normal field name (someInt) should have been found", jsonObject.has("someInt")); - assertTrue("Normal field name (someLong) found", + // the user-defined annotation does not replace any value, so someLong should be found + assertTrue("Normal field name (someLong) should have been found", jsonObject.has("someLong")); - assertTrue("Overridden String field name (myStringField) found", + // myStringField replaces someString property name via user-defined annotation + assertTrue("Overridden String field name (myStringField) should have been found", jsonObject.has("myStringField")); - assertTrue("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) found", + // weird name replaces myDouble property name via user-defined annotation + assertTrue("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) should have been found", jsonObject.has("Some Weird NAme that Normally Wouldn't be possible!")); - assertTrue("Overridden String field name (InterfaceField) found", + // InterfaceField replaces someFloat property name via user-defined annotation + assertTrue("Overridden String field name (InterfaceField) should have been found", jsonObject.has("InterfaceField")); } @@ -619,29 +624,39 @@ public void jsonObjectByBean3() { jsonObject.has("someInt")); assertFalse("Normal field name (myDouble) processing did not work", jsonObject.has("myDouble")); - assertFalse("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) not FOUND!", + // myDouble was replaced by weird name, and then replaced again by AMoreNormalName via user-defined annotation + assertFalse("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) should not be FOUND!", jsonObject.has("Some Weird NAme that Normally Wouldn't be possible!")); assertFalse("Normal field name (someFloat) found, but was overridden", jsonObject.has("someFloat")); assertFalse("Ignored field found! but was overridden", jsonObject.has("ignoredInt")); - assertFalse("Ignored field at the same level as forced name not found", + // shouldNotBeJSON property name was first ignored, then replaced by ShouldBeIgnored via user-defined annotations + assertFalse("Ignored field at the same level as forced name should not have been found", jsonObject.has("ShouldBeIgnored")); - assertFalse("Normally ignored field (able) with explicit property name not found", + // able property name was replaced by Getable via user-defined annotation + assertFalse("Normally ignored field (able) with explicit property name should not have been found", jsonObject.has("able")); - assertTrue("Overridden int field name (newIntFieldName) found", + // property name someInt was replaced by newIntFieldName via user-defined annotation + assertTrue("Overridden int field name (newIntFieldName) should have been found", jsonObject.has("newIntFieldName")); - assertTrue("Normal field name (someLong) found", + // property name someLong was not replaced via user-defined annotation + assertTrue("Normal field name (someLong) should have been found", jsonObject.has("someLong")); - assertTrue("Overridden String field name (myStringField) found", + // property name someString was replaced by myStringField via user-defined annotation + assertTrue("Overridden String field name (myStringField) should have been found", jsonObject.has("myStringField")); - assertTrue("Overridden double field name (AMoreNormalName) found", + // property name myDouble was replaced by a weird name, followed by AMoreNormalName via user-defined annotations + assertTrue("Overridden double field name (AMoreNormalName) should have been found", jsonObject.has("AMoreNormalName")); - assertTrue("Overridden String field name (InterfaceField) found", + // property name someFloat was replaced by InterfaceField via user-defined annotation + assertTrue("Overridden String field name (InterfaceField) should have been found", jsonObject.has("InterfaceField")); - assertTrue("Forced field found!", + // property name ignoredInt was replaced by none, followed by forcedInt via user-defined annotations + assertTrue("Forced field should have been found!", jsonObject.has("forcedInt")); - assertTrue("Overridden boolean field name (Getable) found", + // property name able was replaced by Getable via user-defined annotation + assertTrue("Overridden boolean field name (Getable) should have been found", jsonObject.has("Getable")); } From cd24543e6decdf360adf6bd53ee06fc12a4294c7 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sat, 23 May 2020 10:17:29 -0500 Subject: [PATCH 98/99] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e6e61b5..f27ec95 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # JSON-Java-unit-test + +# This project is no longer the source of truth for JSON-Java unit tests and it not accepting pull requests. The unit tests have been ported to [https://github.com/stleary/JSON-java](https://github.com/stleary/JSON-java) so that code and tests reside together. If this move works out, then future unit test changes will be performed there. + Unit tests to validate the JSON-Java GitHub project code
https://github.com/stleary/JSON-java
From 37294c45c1d61c224b6cb6b2b74a46b14b23eb11 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Wed, 29 Jul 2020 00:35:01 -0500 Subject: [PATCH 99/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f27ec95..63d0fd7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # JSON-Java-unit-test -# This project is no longer the source of truth for JSON-Java unit tests and it not accepting pull requests. The unit tests have been ported to [https://github.com/stleary/JSON-java](https://github.com/stleary/JSON-java) so that code and tests reside together. If this move works out, then future unit test changes will be performed there. +# This project is no longer accepting pull requests. It is not the source of truth for JSON-Java unit tests. The unit tests have been ported to [https://github.com/stleary/JSON-java](https://github.com/stleary/JSON-java) so that code and tests reside together. Please submit all pull requests to the new location. Unit tests to validate the JSON-Java GitHub project code