diff --git a/README.md b/README.md
index faf400a..63d0fd7 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,11 @@
# JSON-Java-unit-test
+
+# 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
-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.
@@ -82,43 +85,17 @@ 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.
-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. |
-| EnumTest.java | n/a | Just documenting how enums are handled. |
-| HTTP.java | 98.7%| 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 |
-| 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 |
-
-| Files used in test |
+**Caveats:**
+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
+```
+
+
+| Resource files used in test |
| ------------- |
+| EnumTest.java |
| MyBean.java |
| MyBigNumberBean.java |
| MyEnum.java |
diff --git a/build.gradle b/build.gradle
index d2969d4..43656ae 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
@@ -22,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/CDLTest.java b/src/test/java/org/json/junit/CDLTest.java
index a40b014..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.
@@ -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 2]",
+ 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 2]",
+ 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 2]",
+ 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);
}
/**
@@ -249,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);
}
@@ -274,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/CookieListTest.java b/src/test/java/org/json/junit/CookieListTest.java
index 7a710db..7149644 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());
}
}
@@ -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/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/EnumTest.java b/src/test/java/org/json/junit/EnumTest.java
index ab4a1e5..366643e 100644
--- a/src/test/java/org/json/junit/EnumTest.java
+++ b/src/test/java/org/json/junit/EnumTest.java
@@ -1,14 +1,18 @@
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;
import java.util.List;
import java.util.Map;
-import java.util.Set;
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;
@@ -31,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;
@@ -92,7 +96,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")));
}
/**
@@ -194,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);
@@ -326,6 +330,7 @@ public void enumAPI() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("strKey", "value");
+ jsonObject.put("strKey2", "VAL1");
jsonObject.put("enumKey", myEnumField);
jsonObject.put("enumClassKey", myEnumClass);
@@ -361,11 +366,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/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java
index 244a693..5aef340 100644
--- a/src/test/java/org/json/junit/JSONArrayTest.java
+++ b/src/test/java/org/json/junit/JSONArrayTest.java
@@ -1,11 +1,12 @@
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 java.io.IOException;
import java.io.StringWriter;
-import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
@@ -30,7 +31,7 @@
* Tests for JSON-Java JSONArray.java
*/
public class JSONArrayTest {
- String arrayStr =
+ private final String arrayStr =
"["+
"true,"+
"false,"+
@@ -54,6 +55,32 @@ public class JSONArrayTest {
"\"-1\""+
"]";
+ /**
+ * Tests that the similar method is working as expected.
+ */
+ @Test
+ public void verifySimilar() {
+ 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.
@@ -61,7 +88,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,12 +99,56 @@ 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]".
- equals(e.getMessage()));
+ 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 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",
+ "Expected a ',' or ']' at 1 [character 2 line 1]",
+ 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());
}
}
@@ -90,8 +161,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 +170,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 +200,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 +234,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 +279,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,62 +326,62 @@ 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);
} 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 double.",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 int.",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 long.",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] is not a String.",e.getMessage());
}
}
@@ -321,7 +392,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,8 +428,8 @@ public void join() {
public void length() {
assertTrue("expected empty JSONArray length 0",
new JSONArray().length() == 0);
- JSONArray jsonArray = new JSONArray(arrayStr);
- assertTrue("expected JSONArray length 13", jsonArray.length() == 13);
+ JSONArray jsonArray = new JSONArray(this.arrayStr);
+ 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);
}
@@ -368,9 +439,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",
@@ -393,6 +465,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",
@@ -441,6 +527,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 +603,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,14 +684,14 @@ 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);
+ assertTrue("jsonArray should be empty", jsonArray.isEmpty());
}
/**
@@ -612,11 +700,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 +833,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 +892,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 +930,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 +945,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 +1015,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..6f04fd5 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());
}
}
@@ -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());
}
}
@@ -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 215 [character 12 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 214 [character 12 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());
}
}
@@ -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 = "01 1 00 0 True ";
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,98 @@ 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);
+ }
+
+// 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
+// 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. 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 = "#5D28D1 Example text here #AF44EF 127310656 #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.
+// */
+// @Test
+// public void testAttributeConversionReversabilityXML() {
+// final String originalXml = "#5D28D1 Example text here #AF44EF 127310656 #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);
+// }
+
+ @Test (timeout = 6000)
+ 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?)(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 = "";
- quotedStr = JSONObject.quote(str);
- assertTrue("quote() expected escaped frontslash, found "+quotedStr,
- "\"<\\/\"".equals(quotedStr));
- str = "AB\bC";
- quotedStr = JSONObject.quote(str);
- assertTrue("quote() expected escaped backspace, found "+quotedStr,
- "\"AB\\bC\"".equals(quotedStr));
- str = "ABC\n";
- quotedStr = JSONObject.quote(str);
- assertTrue("quote() expected escaped newline, found "+quotedStr,
- "\"ABC\\n\"".equals(quotedStr));
- str = "AB\fC";
- quotedStr = JSONObject.quote(str);
- assertTrue("quote() expected escaped formfeed, found "+quotedStr,
- "\"AB\\fC\"".equals(quotedStr));
- str = "\r";
- quotedStr = JSONObject.quote(str);
- assertTrue("quote() expected escaped return, found "+quotedStr,
- "\"\\r\"".equals(quotedStr));
- str = "\u1234\u0088";
- quotedStr = JSONObject.quote(str);
- assertTrue("quote() expected escaped unicode, found "+quotedStr,
- "\"\u1234\\u0088\"".equals(quotedStr));
- }
-
- /**
- * Confirm behavior when JSONObject stringToValue() is called for an
- * empty string
- */
- @Test
- public void stringToValue() {
- String str = "";
- String valueStr = (String)(JSONObject.stringToValue(str));
- assertTrue("stringToValue() expected empty String, found "+valueStr,
- "".equals(valueStr));
- }
-
- /**
- * Confirm behavior when toJSONArray is called with a null value
- */
- @Test
- public void toJSONArray() {
- assertTrue("toJSONArray() with null names should be null",
- null == new JSONObject().toJSONArray(null));
- }
-
- /**
- * Exercise the JSONObject write() method
- */
- @Test
- public void write() {
- String str = "{\"key1\":\"value1\",\"key2\":[1,2,3]}";
- String expectedStr = str;
- JSONObject jsonObject = new JSONObject(str);
- StringWriter stringWriter = new StringWriter();
- Writer writer = jsonObject.write(stringWriter);
- String actualStr = writer.toString();
- assertTrue("write() expected " +expectedStr+
- " 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);
- String actualStr = appendable.toString();
- assertTrue("write() expected " +expectedStr+
- " but found " +actualStr,
- expectedStr.equals(actualStr));
- }
-*/
-
- /**
- * Exercise the JSONObject write(Writer, 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" +
- " }";
- 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 = 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);
- 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
- */
- @Test
- public void equals() {
- String str = "{\"key\":\"value\"}";
- JSONObject aJsonObject = new JSONObject(str);
- assertTrue("Same JSONObject should be equal to itself",
- aJsonObject.equals(aJsonObject));
- }
-
- /**
- * JSON null is not the same as Java null. This test examines the differences
- * in how they are handled by JSON-java.
- */
- @Test
- public void jsonObjectNullOperations() {
- /**
- * The Javadoc for JSONObject.NULL states:
- * "JSONObject.NULL is equivalent to the value that JavaScript calls null,
- * whilst Java's null is equivalent to the value that JavaScript calls
- * undefined."
- *
- * Standard ECMA-262 6th Edition / June 2015 (included to help explain the javadoc):
- * undefined value: primitive value used when a variable has not been assigned a value
- * Undefined type: type whose sole value is the undefined value
- * null value: primitive value that represents the intentional absence of any object value
- * Null type: type whose sole value is the null value
- * Java SE8 language spec (included to help explain the javadoc):
- * The Kinds of Types and Values ...
- * There is also a special null type, the type of the expression null, which has no name.
- * Because the null type has no name, it is impossible to declare a variable of the null
- * type or to cast to the null type. The null reference is the only possible value of an
- * expression of null type. The null reference can always be assigned or cast to any reference type.
- * In practice, the programmer can ignore the null type and just pretend that null is merely
- * a special literal that can be of any reference type.
- * Extensible Markup Language (XML) 1.0 Fifth Edition / 26 November 2008
- * No mention of null
- * ECMA-404 1st Edition / October 2013:
- * JSON Text ...
- * These are three literal name tokens: ...
- * null
- *
- * There seems to be no best practice to follow, it's all about what we
- * want the code to do.
- */
-
- // add JSONObject.NULL then convert to string in the manner of XML.toString()
- JSONObject jsonObjectJONull = new JSONObject();
- Object obj = JSONObject.NULL;
- jsonObjectJONull.put("key", obj);
- Object value = jsonObjectJONull.opt("key");
- assertTrue("opt() JSONObject.NULL should find JSONObject.NULL",
- obj.equals(value));
- value = jsonObjectJONull.get("key");
- assertTrue("get() JSONObject.NULL should find JSONObject.NULL",
- obj.equals(value));
- if (value == null) {
- value = "";
- }
- String string = value instanceof String ? (String)value : null;
- assertTrue("XML toString() should convert JSONObject.NULL to null",
- string == null);
-
- // now try it with null
- JSONObject jsonObjectNull = new JSONObject();
- obj = null;
- jsonObjectNull.put("key", obj);
- value = jsonObjectNull.opt("key");
- assertTrue("opt() null should find null", value == null);
- if (value == null) {
- value = "";
- }
- string = value instanceof String ? (String)value : null;
- assertTrue("should convert null to empty string", "".equals(string));
- try {
- value = jsonObjectNull.get("key");
- assertTrue("get() null should throw exception", false);
- } catch (Exception ignored) {}
-
- /**
- * XML.toString() then goes on to do something with the value
- * if the key val is "content", then value.toString() will be
- * called. This will evaluate to "null" for JSONObject.NULL,
- * and the empty string for null.
- * But if the key is anything else, then JSONObject.NULL will be emitted
- * as 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.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;
+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 java.util.regex.Pattern;
+
+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.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;
+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;
+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.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;
+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 {
+
+ /**
+ * 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.
+ */
+ @Test
+ public void verifySimilar() {
+ 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));
+
+ }
+
+ @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;
+ /**
+ * Changed to 1000 for faster test runs
+ */
+ // final int iterations = 1000000;
+ final int iterations = 1000;
+
+ // 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++) {
+ 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)(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.isEmpty());
+ }
+
+ /**
+ * 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("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("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("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("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("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 compatibility 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 jsonObjectByBean1() {
+ /**
+ * 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);
+ }
+
+ /**
+ * 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) processing did not work",
+ jsonObject.has("someFloat"));
+ assertFalse("Ignored field not found!",
+ jsonObject.has("ignoredInt"));
+ // getSomeInt() has no user-defined annotation
+ assertTrue("Normal field name (someInt) should have been found",
+ jsonObject.has("someInt"));
+ // 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"));
+ // myStringField replaces someString property name via user-defined annotation
+ assertTrue("Overridden String field name (myStringField) should have been found",
+ jsonObject.has("myStringField"));
+ // 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!"));
+ // InterfaceField replaces someFloat property name via user-defined annotation
+ assertTrue("Overridden String field name (InterfaceField) should have been 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"));
+ // 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"));
+ // 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"));
+ // 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"));
+ // property name someInt was replaced by newIntFieldName via user-defined annotation
+ assertTrue("Overridden int field name (newIntFieldName) should have been found",
+ jsonObject.has("newIntFieldName"));
+ // property name someLong was not replaced via user-defined annotation
+ assertTrue("Normal field name (someLong) should have been found",
+ jsonObject.has("someLong"));
+ // property name someString was replaced by myStringField via user-defined annotation
+ assertTrue("Overridden String field name (myStringField) should have been found",
+ jsonObject.has("myStringField"));
+ // 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"));
+ // property name someFloat was replaced by InterfaceField via user-defined annotation
+ assertTrue("Overridden String field name (InterfaceField) should have been found",
+ jsonObject.has("InterfaceField"));
+ // property name ignoredInt was replaced by none, followed by forcedInt via user-defined annotations
+ assertTrue("Forced field should have been found!",
+ jsonObject.has("forcedInt"));
+ // property name able was replaced by Getable via user-defined annotation
+ assertTrue("Overridden boolean field name (Getable) should have been 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,
+ * 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.data.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);
+ fail("Expected exception");
+ } 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);
+ fail("Expected exception");
+ } 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\","+
+ "\"BigDecimalStrKey\":\"19007199254740993.35481234487103587486413587843213584\","+
+ "\"negZeroKey\":-0.0,"+
+ "\"negZeroStrKey\":\"-0.0\","+
+ "\"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("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 a Double",
+ jsonObject.opt("negZeroKey") instanceof Double);
+ assertTrue("get negZeroKey should be a Double",
+ jsonObject.get("negZeroKey") instanceof Double);
+ assertTrue("optNumber negZeroKey should return Double",
+ jsonObject.optNumber("negZeroKey") instanceof Double);
+ assertTrue("optNumber negZeroStrKey should return Double",
+ jsonObject.optNumber("negZeroStrKey") instanceof Double);
+ 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 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",
+ jsonObject.optFloat("doubleStrKey", Float.NaN) == 1f);
+ 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("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 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",
+ 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 double 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");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("expecting an exception message",
+ "JSONObject[\"nonKey\"] not found.", e.getMessage());
+ }
+ try {
+ jsonObject.getBoolean("stringKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"stringKey\"] is not a Boolean.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getString("nonKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"nonKey\"] not found.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getString("trueKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"trueKey\"] is not a string.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getDouble("nonKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"nonKey\"] not found.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getDouble("stringKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"stringKey\"] is not a double.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getFloat("nonKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"nonKey\"] not found.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getFloat("stringKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"stringKey\"] is not a float.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getInt("nonKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"nonKey\"] not found.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getInt("stringKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"stringKey\"] is not a int.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getLong("nonKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"nonKey\"] not found.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getLong("stringKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"stringKey\"] is not a long.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getJSONArray("nonKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"nonKey\"] not found.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getJSONArray("stringKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"stringKey\"] is not a JSONArray.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getJSONObject("nonKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"nonKey\"] not found.",
+ e.getMessage());
+ }
+ try {
+ jsonObject.getJSONObject("stringKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"stringKey\"] is not a JSONObject.",
+ 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.isEmpty());
+
+ /**
+ * 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}"));
+ assertTrue("BigInteger as BigDecimal",
+ jsonObject.getBigDecimal("bigInt").equals(new BigDecimal(bigInteger)));
+
+
+ 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}"));
+
+ assertTrue("BigDecimal as BigInteger",
+ jsonObject.getBigInteger("bigDec").equals(bigDecimal.toBigInteger()));
+ /**
+ * exercise some exceptions
+ */
+ try {
+ // bigInt key does not exist
+ jsonObject.getBigDecimal("bigInt");
+ fail("expected an exeption");
+ } catch (JSONException ignored) {}
+ obj = jsonObject.optBigDecimal("bigInt", BigDecimal.ONE);
+ assertTrue("expected BigDecimal", obj.equals(BigDecimal.ONE));
+ jsonObject.put("stringKey", "abc");
+ try {
+ jsonObject.getBigDecimal("stringKey");
+ fail("expected an exeption");
+ } catch (JSONException ignored) {}
+ obj = jsonObject.optBigInteger("bigDec", BigInteger.ONE);
+ assertTrue("expected BigInteger", obj instanceof BigInteger);
+ assertEquals(bigDecimal.toBigInteger(), obj);
+
+ /**
+ * 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);
+ fail("should not be able to get big int");
+ } catch (Exception ignored) {}
+ try {
+ jsonArray.getBigDecimal(2);
+ 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));
+
+ // 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", 1.1f);
+ 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!
+ */
+ assertEquals(Float.valueOf(3.1f), 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 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
+ // 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("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));
+ }
+
+ /**
+ * 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) {
+ 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) {
+ 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) {
+ 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) {
+ assertEquals("Expecting an exception message",
+ "Expected a ',' or '}' at 15 [character 16 line 1]",
+ e.getMessage());
+ }
+ try {
+ // append to wrong key
+ String str = "{\"myKey\":true, \"myOtherKey\":false}";
+ JSONObject jsonObject = new JSONObject(str);
+ jsonObject.append("myKey", "hello");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "JSONObject[\"myKey\"] is not a JSONArray (null).",
+ e.getMessage());
+ }
+ try {
+ // increment wrong key
+ String str = "{\"myKey\":true, \"myOtherKey\":false}";
+ JSONObject jsonObject = new JSONObject(str);
+ jsonObject.increment("myKey");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Unable to increment [\"myKey\"].",
+ e.getMessage());
+ }
+ try {
+ // invalid key
+ String str = "{\"myKey\":true, \"myOtherKey\":false}";
+ JSONObject jsonObject = new JSONObject(str);
+ jsonObject.get(null);
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Null key.",
+ e.getMessage());
+ }
+ try {
+ // invalid numberToString()
+ JSONObject.numberToString((Number)null);
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Null pointer",
+ e.getMessage());
+ }
+
+ try {
+ // multiple putOnce key
+ JSONObject jsonObject = new JSONObject("{}");
+ jsonObject.putOnce("hello", "world");
+ jsonObject.putOnce("hello", "world!");
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertTrue("", true);
+ }
+ try {
+ // test validity of invalid double
+ JSONObject.testValidity(Double.NaN);
+ fail("Expected an exception");
+ } catch (JSONException e) {
+ assertTrue("", true);
+ }
+ try {
+ // test validity of invalid float
+ JSONObject.testValidity(Float.NEGATIVE_INFINITY);
+ fail("Expected an exception");
+ } 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"
+ + "]";
+ 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());
+ }
+ }
+
+ /**
+ * 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.isEmpty());
+ jsonObject.putOnce("", null);
+ assertTrue("jsonObject should be empty", jsonObject.isEmpty());
+ jsonObject.putOnce(null, "");
+ assertTrue("jsonObject should be empty", jsonObject.isEmpty());
+ }
+
+ /**
+ * 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",
+ 42l == jsonObject.optLong("myKey", 42l));
+ assertTrue("optDouble() should return default double",
+ 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")));
+ }
+
+ /**
+ * Exercise JSONObject opt(key, default) method when the key doesn't exist.
+ */
+ @Test
+ 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);
+ 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",
+ 42l == jsonObject.optLong("myKey", 42l));
+ assertTrue("optDouble() should return default double",
+ 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")));
+ }
+
+ /**
+ * 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)==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);
+ }
+
+ /**
+ * 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"));
+ }
+
+ /**
+ * 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));
+ assertEquals(jo.optBigDecimal("float", null),jo.getBigDecimal("float"));
+ assertEquals(jo.optBigDecimal("double", null),jo.getBigDecimal("double"));
+ }
+
+ /**
+ * 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
+ */
+ @Test
+ public void jsonObjectputNull() {
+
+ // put null should remove the item.
+ String str = "{\"myKey\": \"myval\"}";
+ JSONObject jsonObjectRemove = new JSONObject(str);
+ jsonObjectRemove.remove("myKey");
+ assertTrue("jsonObject should be empty", jsonObjectRemove.isEmpty());
+
+ JSONObject jsonObjectPutNull = new JSONObject(str);
+ jsonObjectPutNull.put("myKey", (Object) null);
+ assertTrue("jsonObject should be empty", jsonObjectPutNull.isEmpty());
+
+
+ }
+
+ /**
+ * 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 = "";
+ quotedStr = JSONObject.quote(str);
+ assertTrue("quote() expected escaped frontslash, found "+quotedStr,
+ "\"<\\/\"".equals(quotedStr));
+ str = "AB\bC";
+ quotedStr = JSONObject.quote(str);
+ assertTrue("quote() expected escaped backspace, found "+quotedStr,
+ "\"AB\\bC\"".equals(quotedStr));
+ str = "ABC\n";
+ quotedStr = JSONObject.quote(str);
+ assertTrue("quote() expected escaped newline, found "+quotedStr,
+ "\"ABC\\n\"".equals(quotedStr));
+ str = "AB\fC";
+ quotedStr = JSONObject.quote(str);
+ assertTrue("quote() expected escaped formfeed, found "+quotedStr,
+ "\"AB\\fC\"".equals(quotedStr));
+ str = "\r";
+ quotedStr = JSONObject.quote(str);
+ assertTrue("quote() expected escaped return, found "+quotedStr,
+ "\"\\r\"".equals(quotedStr));
+ str = "\u1234\u0088";
+ quotedStr = JSONObject.quote(str);
+ assertTrue("quote() expected escaped unicode, found "+quotedStr,
+ "\"\u1234\\u0088\"".equals(quotedStr));
+ }
+
+ /**
+ * Confirm behavior when JSONObject stringToValue() is called for an
+ * empty string
+ */
+ @Test
+ public void stringToValue() {
+ String str = "";
+ String valueStr = (String)(JSONObject.stringToValue(str));
+ assertTrue("stringToValue() expected empty String, found "+valueStr,
+ "".equals(valueStr));
+ }
+
+ /**
+ * Confirm behavior when toJSONArray is called with a null value
+ */
+ @Test
+ public void toJSONArray() {
+ assertTrue("toJSONArray() with null names should be null",
+ null == new JSONObject().toJSONArray(null));
+ }
+
+ /**
+ * Exercise the JSONObject write() method
+ */
+ @Test
+ public void write() throws IOException {
+ String str = "{\"key1\":\"value1\",\"key2\":[1,2,3]}";
+ String expectedStr = str;
+ JSONObject jsonObject = new JSONObject(str);
+ StringWriter stringWriter = new StringWriter();
+ try {
+ String actualStr = jsonObject.write(stringWriter).toString();
+ assertTrue("write() expected " +expectedStr+
+ " but found " +actualStr,
+ expectedStr.equals(actualStr));
+ } finally {
+ stringWriter.close();
+ }
+ }
+
+ /**
+ * Confirms that exceptions thrown when writing values are wrapped properly.
+ */
+ @Test
+ public void testJSONWriterException() {
+ 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
+ */
+/*
+ @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);
+ String actualStr = appendable.toString();
+ assertTrue("write() expected " +expectedStr+
+ " but found " +actualStr,
+ expectedStr.equals(actualStr));
+ }
+*/
+
+ /**
+ * Exercise the JSONObject write(Writer, int, int) method
+ */
+ @Test
+ public void write3Param() throws IOException {
+ 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;
+ StringWriter stringWriter = new StringWriter();
+ try {
+ String actualStr = jsonObject.write(stringWriter,0,0).toString();
+ assertEquals(expectedStr, actualStr);
+ } finally {
+ stringWriter.close();
+ }
+
+ expectedStr = str2;
+ stringWriter = new StringWriter();
+ try {
+ String actualStr = jsonObject.write(stringWriter,2,1).toString();
+ assertEquals(expectedStr, actualStr);
+ } finally {
+ stringWriter.close();
+ }
+ }
+
+ /**
+ * 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);
+ 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
+ */
+ @Test
+ public void equals() {
+ String str = "{\"key\":\"value\"}";
+ JSONObject aJsonObject = new JSONObject(str);
+ assertTrue("Same JSONObject should be equal to itself",
+ aJsonObject.equals(aJsonObject));
+ }
+
+ /**
+ * JSON null is not the same as Java null. This test examines the differences
+ * in how they are handled by JSON-java.
+ */
+ @Test
+ public void jsonObjectNullOperations() {
+ /**
+ * The Javadoc for JSONObject.NULL states:
+ * "JSONObject.NULL is equivalent to the value that JavaScript calls null,
+ * whilst Java's null is equivalent to the value that JavaScript calls
+ * undefined."
+ *
+ * Standard ECMA-262 6th Edition / June 2015 (included to help explain the javadoc):
+ * undefined value: primitive value used when a variable has not been assigned a value
+ * Undefined type: type whose sole value is the undefined value
+ * null value: primitive value that represents the intentional absence of any object value
+ * Null type: type whose sole value is the null value
+ * Java SE8 language spec (included to help explain the javadoc):
+ * The Kinds of Types and Values ...
+ * There is also a special null type, the type of the expression null, which has no name.
+ * Because the null type has no name, it is impossible to declare a variable of the null
+ * type or to cast to the null type. The null reference is the only possible value of an
+ * expression of null type. The null reference can always be assigned or cast to any reference type.
+ * In practice, the programmer can ignore the null type and just pretend that null is merely
+ * a special literal that can be of any reference type.
+ * Extensible Markup Language (XML) 1.0 Fifth Edition / 26 November 2008
+ * No mention of null
+ * ECMA-404 1st Edition / October 2013:
+ * JSON Text ...
+ * These are three literal name tokens: ...
+ * null
+ *
+ * There seems to be no best practice to follow, it's all about what we
+ * want the code to do.
+ */
+
+ // add JSONObject.NULL then convert to string in the manner of XML.toString()
+ JSONObject jsonObjectJONull = new JSONObject();
+ Object obj = JSONObject.NULL;
+ jsonObjectJONull.put("key", obj);
+ Object value = jsonObjectJONull.opt("key");
+ assertTrue("opt() JSONObject.NULL should find JSONObject.NULL",
+ obj.equals(value));
+ value = jsonObjectJONull.get("key");
+ assertTrue("get() JSONObject.NULL should find JSONObject.NULL",
+ obj.equals(value));
+ if (value == null) {
+ value = "";
+ }
+ String string = value instanceof String ? (String)value : null;
+ assertTrue("XML toString() should convert JSONObject.NULL to null",
+ string == null);
+
+ // now try it with null
+ JSONObject jsonObjectNull = new JSONObject();
+ obj = null;
+ jsonObjectNull.put("key", obj);
+ value = jsonObjectNull.opt("key");
+ assertNull("opt() null should find null", value);
+ // what is this trying to do? It appears to test absolutely nothing...
+// if (value == null) {
+// value = "";
+// }
+// string = value instanceof String ? (String)value : null;
+// assertTrue("should convert null to empty string", "".equals(string));
+ try {
+ value = jsonObjectNull.get("key");
+ fail("get() null should throw exception");
+ } catch (Exception ignored) {}
+
+ /**
+ * XML.toString() then goes on to do something with the value
+ * if the key val is "content", then value.toString() will be
+ * called. This will evaluate to "null" for JSONObject.NULL,
+ * and the empty string for null.
+ * But if the key is anything else, then JSONObject.NULL will be emitted
+ * as 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);
+ }
+
+ /**
+ * test that validates a singleton can be serialized as a bean.
+ */
+ @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 that validates a singleton can be serialized as a bean.
+ */
+ @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 to validate that a generic class can be serialized as a bean.
+ */
+ @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 to validate that a generic class can be serialized as a bean.
+ */
+ @Test
+ public void testGenericIntBean() {
+ GenericBeanInt bean = new GenericBeanInt(42);
+ final JSONObject jo = new JSONObject(bean);
+ assertEquals(jo.keySet().toString(), 10, jo.length());
+ assertEquals(42, jo.get("genericValue"));
+ assertEquals("Expected the getter to only be called once",
+ 1, bean.genericGetCounter);
+ 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);
+ 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 be mapped. Instead found: "+jo.keySet().toString(),
+ 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"));
+ }
+
+ @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");
+ }
+
+}
diff --git a/src/test/java/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java
index 75f4ea8..5ddd089 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) {
@@ -48,6 +62,27 @@ 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 queryByEmptyKeySubObjectValue() {
+ assertSame(
+ document.getJSONObject("obj").getJSONObject("").get("subKey"),
+ query("/obj//subKey")
+ );
+ }
+
@Test
public void slashEscaping() {
assertSame(document.get("a/b"), query("/a~1b"));
@@ -157,7 +192,7 @@ public void tokenListIsCopiedInConstructor() {
}
/**
- * Coverage for JSONObject queryFrom()
+ * Coverage for JSONObject query(String)
*/
@Test
public void queryFromJSONObject() {
@@ -187,7 +222,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 +303,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);
+ }
}
diff --git a/src/test/java/org/json/junit/JSONStringTest.java b/src/test/java/org/json/junit/JSONStringTest.java
index cba5d09..ec40dbb 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) {
+ assertEquals("Unable to write JSONArray value at index: 0", 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/JSONTokenerTest.java b/src/test/java/org/json/junit/JSONTokenerTest.java
new file mode 100644
index 0000000..de1564d
--- /dev/null
+++ b/src/test/java/org/json/junit/JSONTokenerTest.java
@@ -0,0 +1,295 @@
+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;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+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;
+
+/**
+ * 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());
+ }
+ }
+ }
+
+ @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.
+ *
+ * @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\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 = " "+
+ "1 2 3 "+
+ "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 = "One Four ";
+ 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 = "One Two Three ";
+ 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 = "One Two Three Four ";
+ 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 = " "+
+ "1 2 "+
+ "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>someValue1123IllegalNode>someValue2 ";
+
+ 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 1 2 true ";
+ 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 = "val1 val2 ";
+ 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 = "01 1 00 0 True ";
+ 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 = "01 1 00 0 True ";
+ 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 = "01 1 00 0 True ";
+ 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 = "01 01 1 00 0 True ";
+
+ 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 < ",
+ XMLParserConfiguration.KEEP_STRINGS).toString());
+ assertEquals("Can cope < ", XML.unescape("Can cope < "));
+
+ assertEquals("{\"xml\":\"Can cope 4\"}",
+ XML.toJSONObject("Can cope 4 ",
+ XMLParserConfiguration.KEEP_STRINGS).toString());
+ assertEquals("Can cope 4 ", XML.unescape("Can cope 4 "));
+
+ }
+
+ /**
+ * 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
diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java
index 2f3fea7..b74daff 100644
--- a/src/test/java/org/json/junit/XMLTest.java
+++ b/src/test/java/org/json/junit/XMLTest.java
@@ -1,16 +1,23 @@
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;
+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.JSONML;
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;
@@ -36,7 +43,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());
}
/**
@@ -47,7 +54,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());
}
/**
@@ -57,7 +64,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());
}
/**
@@ -77,11 +84,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());
}
}
@@ -102,11 +109,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 214 [character 12 line 7]",
+ e.getMessage());
}
}
@@ -127,11 +134,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 213 [character 12 line 7]",
+ e.getMessage());
}
}
@@ -152,11 +159,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());
}
}
@@ -177,11 +184,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());
}
}
@@ -202,7 +209,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());
}
/**
@@ -267,6 +274,63 @@ 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\":\"\\\" \\\" & ' < >\"," +
+ "\"high\":\"𝄢 𐅥\""+
+ "}}";
+
+ compareStringToJSONObject(xmlStr, expectedStr);
+ compareReaderToJSONObject(xmlStr, expectedStr);
+ compareFileToJSONObject(xmlStr, expectedStr);
+ }
+
+ /**
+ * Tests that control characters are escaped.
+ */
+ @Test
+ public void testJsonToXmlEscape(){
+ final String jsonSrc = "{\"amount\":\"10,00 €\","
+ + "\"description\":\"Ação Válida\u0085\","
+ + "\"xmlEntities\":\"\\\" ' & < >\""
+ + "}";
+ JSONObject json = new JSONObject(jsonSrc);
+ String xml = XML.toString(json);
+ //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(">"));
+ }
+
/**
* Valid XML with comments to JSONObject
*/
@@ -400,9 +464,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);
}
/**
@@ -417,9 +481,9 @@ public void shouldHandleEmptyMultiArray(){
final String expected = "One Four ";
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);
}
/**
@@ -434,9 +498,9 @@ public void shouldHandleNonEmptyArray(){
final String expected = "One Two Three ";
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);
}
/**
@@ -451,9 +515,9 @@ public void shouldHandleMultiArray(){
final String expected = "One Two Three Four ";
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);
}
/**
@@ -675,8 +739,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);
}
@@ -687,14 +751,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);
- */
}
/**
@@ -708,22 +768,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());
}
- */
}
/**
@@ -766,5 +823,61 @@ 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 &; "));
+
+ // 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 < ").toString());
+ assertEquals("Can cope < ", XML.unescape("Can cope < "));
+
+ assertEquals("{\"xml\":\"Can cope 4\"}",
+ XML.toJSONObject("Can cope 4 ").toString());
+ assertEquals("Can cope 4 ", XML.unescape("Can cope 4 "));
+
+ }
+
+ /**
+ * test passes when xsi:nil="true" converting to null (JSON specification-like nil conversion enabled)
+ */
+ @Test
+ public void testToJsonWithNullWhenNilConversionEnabled() {
+ final String originalXml = " ";
+ final String expectedJsonString = "{\"root\":{\"id\":null}}";
+
+ 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
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/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!");
+ }
+ }
+}
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/data/GenericBean.java b/src/test/java/org/json/junit/data/GenericBean.java
new file mode 100644
index 0000000..da6370d
--- /dev/null
+++ b/src/test/java/org/json/junit/data/GenericBean.java
@@ -0,0 +1,79 @@
+package org.json.junit.data;
+
+import java.io.StringReader;
+
+/**
+ *
+ * @author John Aylward
+ *
+ * @param
+ * generic number value
+ */
+public class GenericBean> implements MyBean {
+ /**
+ * @param genericValue
+ * value to initiate with
+ */
+ public GenericBean(T genericValue) {
+ super();
+ this.genericValue = 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 */
+ public int genericSetCounter;
+
+ /** @return the genericValue */
+ public T getGenericValue() {
+ this.genericGetCounter++;
+ return this.genericValue;
+ }
+
+ /**
+ * @param genericValue
+ * generic value to set
+ */
+ 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..5056611
--- /dev/null
+++ b/src/test/java/org/json/junit/data/GenericBeanInt.java
@@ -0,0 +1,69 @@
+/**
+ *
+ */
+package org.json.junit.data;
+
+/**
+ * @author john
+ *
+ */
+public class GenericBeanInt extends GenericBean {
+ /** */
+ final char a = 'A';
+
+ /** @return the a */
+ public char getA() {
+ return this.a;
+ }
+
+ /**
+ * Should not be beanable
+ *
+ * @return false
+ */
+ 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.
+ */
+ public GenericBeanInt(Integer genericValue) {
+ super(genericValue);
+ }
+
+ /** override to generate a bridge method */
+ @Override
+ public Integer getGenericValue() {
+ return super.getGenericValue();
+ }
+
+}
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/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; }
+}
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 74%
rename from src/test/java/org/json/junit/MyEnumField.java
rename to src/test/java/org/json/junit/data/MyEnumField.java
index 8f2c633..60e89de 100644
--- a/src/test/java/org/json/junit/MyEnumField.java
+++ b/src/test/java/org/json/junit/data/MyEnumField.java
@@ -1,8 +1,9 @@
-package org.json.junit;
+package org.json.junit.data;
/**
* 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/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/data/MyLocaleBean.java b/src/test/java/org/json/junit/data/MyLocaleBean.java
new file mode 100755
index 0000000..846e1c5
--- /dev/null
+++ b/src/test/java/org/json/junit/data/MyLocaleBean.java
@@ -0,0 +1,12 @@
+package org.json.junit.data;
+
+public class MyLocaleBean {
+ private final String id = "beanId";
+ private final String i = "beanI";
+ public String getId() {
+ return id;
+ }
+ public String getI() {
+ return i;
+ }
+}
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 75%
rename from src/test/java/org/json/junit/MyPublicClass.java
rename to src/test/java/org/json/junit/data/MyPublicClass.java
index 1f55e3e..1f30386 100644
--- a/src/test/java/org/json/junit/MyPublicClass.java
+++ b/src/test/java/org/json/junit/data/MyPublicClass.java
@@ -1,8 +1,9 @@
-package org.json.junit;
+package org.json.junit.data;
/**
* 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/data/Singleton.java b/src/test/java/org/json/junit/data/Singleton.java
new file mode 100644
index 0000000..36a9824
--- /dev/null
+++ b/src/test/java/org/json/junit/data/Singleton.java
@@ -0,0 +1,91 @@
+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.
+ *
+ * @param someInt
+ * the someInt to set
+ */
+ public void setSomeInt(int someInt) {
+ this.someInt = someInt;
+ }
+
+ /** @return someString */
+ public String getSomeString() {
+ return someString;
+ }
+
+ /**
+ * sets someString.
+ *
+ * @param someString
+ * the someString to set
+ */
+ 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..8147cc6
--- /dev/null
+++ b/src/test/java/org/json/junit/data/SingletonEnum.java
@@ -0,0 +1,62 @@
+package org.json.junit.data;
+
+/**
+ * Sample singleton done as an Enum for use with bean testing.
+ *
+ * @author John Aylward
+ *
+ */
+public enum SingletonEnum {
+ /**
+ * the singleton instance.
+ */
+ 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.
+ *
+ * @param someInt
+ * the someInt to set
+ */
+ public void setSomeInt(int someInt) {
+ this.someInt = someInt;
+ }
+
+ /** @return someString */
+ public String getSomeString() {
+ return 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/StringsResourceBundle.java b/src/test/java/org/json/junit/data/StringsResourceBundle.java
similarity index 90%
rename from src/test/java/org/json/junit/StringsResourceBundle.java
rename to src/test/java/org/json/junit/data/StringsResourceBundle.java
index 83d9322..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.*;
@@ -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/data/WeirdList.java b/src/test/java/org/json/junit/data/WeirdList.java
new file mode 100644
index 0000000..77cd17f
--- /dev/null
+++ b/src/test/java/org/json/junit/data/WeirdList.java
@@ -0,0 +1,67 @@
+/**
+ *
+ */
+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<>();
+
+ /**
+ * @param vals
+ */
+ public WeirdList(Integer... vals) {
+ this.list.addAll(Arrays.asList(vals));
+ }
+
+ /**
+ * @return a copy of the list
+ */
+ public List get() {
+ return new ArrayList<>(this.list);
+ }
+
+ /**
+ * @return a copy of the list
+ */
+ public List getALL() {
+ return new ArrayList<>(this.list);
+ }
+
+ /**
+ * 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 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);
+ }
+
+ /**
+ * @param value
+ * new value to add to the end of the list
+ */
+ public void add(Integer value) {
+ this.list.add(value);
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/jsonpointer-testdoc.json b/src/test/resources/jsonpointer-testdoc.json
index d58fe82..657ccdd 100644
--- a/src/test/resources/jsonpointer-testdoc.json
+++ b/src/test/resources/jsonpointer-testdoc.json
@@ -19,6 +19,10 @@
"another/key" : [
"val"
]
+ },
+ "" : {
+ "" : "empty key of an object with an empty key",
+ "subKey" : "Some other value"
}
}
}
\ No newline at end of file