1
0
Fork 0
mirror of https://github.com/ethauvin/JSON-java.git synced 2025-06-17 07:50:52 -07:00

Verify exception messages. Move method comments so JavaDoc will pick them up.

This commit is contained in:
stleary 2015-08-09 18:19:32 -05:00
parent 8e48caeb3d
commit 58d72fe20f
2 changed files with 498 additions and 208 deletions

View file

@ -12,7 +12,7 @@ import org.json.*;
import org.junit.*; import org.junit.*;
/** /**
* These classes will be used for testing * Used in testing when a JSONString is needed
*/ */
class MyJsonString implements JSONString { class MyJsonString implements JSONString {
@ -22,6 +22,9 @@ class MyJsonString implements JSONString {
} }
} }
/**
* Used in testing when Bean behavior is needed
*/
interface MyBean { interface MyBean {
public Integer getIntKey(); public Integer getIntKey();
public Double getDoubleKey(); public Double getDoubleKey();
@ -32,6 +35,9 @@ interface MyBean {
public StringReader getStringReaderKey(); public StringReader getStringReaderKey();
}; };
/**
* Used in testing when a Bean containing big numbers is needed
*/
interface MyBigNumberBean { interface MyBigNumberBean {
public BigInteger getBigInteger(); public BigInteger getBigInteger();
public BigDecimal getBigDecimal(); public BigDecimal getBigDecimal();
@ -39,34 +45,45 @@ interface MyBigNumberBean {
/** /**
* JSONObject, along with JSONArray, are the central classes of the reference app. * JSONObject, along with JSONArray, are the central classes of the reference app.
* All of the other classes interact with it and JSON functionality would be * All of the other classes interact with them, and JSON functionality would
* impossible without it. * otherwise be impossible.
*/ */
public class JSONObjectTest { public class JSONObjectTest {
/** /**
* Need a class with some public data members for testing, so * Need a class with some public data members for testing, so
* JSONObjectTest is chosen. * JSONObjectTest itself will be used for this purpose.
* TODO: Why not use MyBigNumberBean or MyBean?
*/ */
public Integer publicInt = 42; public Integer publicInt = 42;
public String publicString = "abc"; public String publicString = "abc";
/**
* JSONObject built from a bean, but only using a null value.
* Nothing good is expected to happen.
* Expects NullPointerException
*/
@Test(expected=NullPointerException.class)
public void jsonObjectByNullBean() {
MyBean myBean = null;
new JSONObject(myBean);
}
/**
* A JSONObject can be created with no content
*/
@Test @Test
public void emptyJsonObject() { public void emptyJsonObject() {
/**
* A JSONObject can be created with no content
*/
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
assertTrue("jsonObject should be empty", jsonObject.length() == 0); assertTrue("jsonObject should be empty", jsonObject.length() == 0);
} }
/**
* A JSONObject can be created from another JSONObject plus a list of names.
* In this test, some of the starting JSONObject keys are not in the
* names list.
*/
@Test @Test
public void jsonObjectByNames() { public void jsonObjectByNames() {
/**
* A JSONObject can be created from another JSONObject plus a list of names.
* In this test, some of the starting JSONObject keys are not in the
* names list.
*/
String str = String str =
"{"+ "{"+
"\"trueKey\":true,"+ "\"trueKey\":true,"+
@ -92,28 +109,25 @@ public class JSONObjectTest {
} }
/** /**
* JSONObjects can be built from a Map<String, Object>.
* In this test the map is null.
* the JSONObject(JsonTokener) ctor is not tested directly since it already * the JSONObject(JsonTokener) ctor is not tested directly since it already
* has full coverage from other tests. * has full coverage from other tests.
*/ */
@Test @Test
public void jsonObjectByNullMap() { public void jsonObjectByNullMap() {
/**
* JSONObjects can be built from a Map<String, Object>.
* In this test the map is null.
*/
Map<String, Object> map = null; Map<String, Object> map = null;
JSONObject jsonObject = new JSONObject(map); JSONObject jsonObject = new JSONObject(map);
JSONObject expectedJsonObject = new JSONObject(); JSONObject expectedJsonObject = new JSONObject();
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
} }
/**
* JSONObjects can be built from a Map<String, Object>.
* In this test all of the map entries are valid JSON types.
*/
@Test @Test
public void jsonObjectByMap() { public void jsonObjectByMap() {
/**
* JSONObjects can be built from a Map<String, Object>.
* In this test all of the map entries are valid JSON types.
*/
String expectedStr = String expectedStr =
"{"+ "{"+
"\"trueKey\":true,"+ "\"trueKey\":true,"+
@ -136,13 +150,13 @@ public class JSONObjectTest {
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
} }
/**
* JSONObjects can be built from a Map<String, Object>.
* In this test the map entries are not valid JSON types.
* The actual conversion is kind of interesting.
*/
@Test @Test
public void jsonObjectByMapWithUnsupportedValues() { public void jsonObjectByMapWithUnsupportedValues() {
/**
* JSONObjects can be built from a Map<String, Object>.
* In this test the map entries are not valid JSON types.
* The actual conversion is kind of interesting.
*/
String expectedStr = String expectedStr =
"{"+ "{"+
"\"key1\":{},"+ "\"key1\":{},"+
@ -158,12 +172,12 @@ public class JSONObjectTest {
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
} }
/**
* JSONObjects can be built from a Map<String, Object>.
* In this test one of the map values is null
*/
@Test @Test
public void jsonObjectByMapWithNullValue() { public void jsonObjectByMapWithNullValue() {
/**
* JSONObjects can be built from a Map<String, Object>.
* In this test one of the map values is null
*/
String expectedStr = String expectedStr =
"{"+ "{"+
"\"trueKey\":true,"+ "\"trueKey\":true,"+
@ -187,22 +201,12 @@ public class JSONObjectTest {
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
} }
@Test(expected=NullPointerException.class) /**
public void jsonObjectByNullBean() { * JSONObject built from a bean. In this case all but one of the
/** * bean getters return valid JSON types
* JSONObject built from a bean, but only using a null value. */
* Nothing good is expected to happen.
*/
MyBean myBean = null;
new JSONObject(myBean);
}
@Test @Test
public void jsonObjectByBean() { public void jsonObjectByBean() {
/**
* JSONObject built from a bean. In this case all but one of the
* bean getters return valid JSON types
*/
String expectedStr = String expectedStr =
"{"+ "{"+
"\"trueKey\":true,"+ "\"trueKey\":true,"+
@ -244,14 +248,14 @@ public class JSONObjectTest {
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
} }
/**
* 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 @Test
public void jsonObjectByObjectAndNames() { public void jsonObjectByObjectAndNames() {
/**
* 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.
*/
String expectedStr = String expectedStr =
"{"+ "{"+
"\"publicString\":\"abc\","+ "\"publicString\":\"abc\","+
@ -265,6 +269,9 @@ public class JSONObjectTest {
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
} }
/**
* Exercise the JSONObject from resource bundle functionality
*/
@Test @Test
public void jsonObjectByResourceBundle() { public void jsonObjectByResourceBundle() {
// TODO: how to improve resource bundle testing? // TODO: how to improve resource bundle testing?
@ -286,6 +293,9 @@ public class JSONObjectTest {
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
} }
/**
* Exercise the JSONObject.accumulate() method
*/
@Test @Test
public void jsonObjectAccumulate() { public void jsonObjectAccumulate() {
// TODO: should include an unsupported object // TODO: should include an unsupported object
@ -311,6 +321,9 @@ public class JSONObjectTest {
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
} }
/**
* Exercise the JSONObject append() functionality
*/
@Test @Test
public void jsonObjectAppend() { public void jsonObjectAppend() {
// TODO: should include an unsupported object // TODO: should include an unsupported object
@ -336,6 +349,9 @@ public class JSONObjectTest {
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
} }
/**
* Exercise the JSONObject doubleToString() method
*/
@Test @Test
public void jsonObjectDoubleToString() { public void jsonObjectDoubleToString() {
String [] expectedStrs = {"1", "1", "-23.4", "-2.345E68", "null", "null" }; String [] expectedStrs = {"1", "1", "-23.4", "-2.345E68", "null", "null" };
@ -349,6 +365,9 @@ public class JSONObjectTest {
} }
} }
/**
* Exercise some JSONObject get[type] and opt[type] methods
*/
@Test @Test
public void jsonObjectValues() { public void jsonObjectValues() {
String str = String str =
@ -423,9 +442,12 @@ public class JSONObjectTest {
jsonObjectInner.get("myKey").equals("myVal")); jsonObjectInner.get("myKey").equals("myVal"));
} }
/**
* Check whether JSONObject handles large or high precision numbers correctly
*/
@Test @Test
public void stringToValueNumbersTest() { public void stringToValueNumbersTest() {
// Check if library handles large or high precision numbers correctly
assertTrue( "0.2 should be a Double!", assertTrue( "0.2 should be a Double!",
JSONObject.stringToValue( "0.2" ) instanceof Double ); JSONObject.stringToValue( "0.2" ) instanceof Double );
assertTrue( "Doubles should be Doubles, even when incorrectly converting floats!", assertTrue( "Doubles should be Doubles, even when incorrectly converting floats!",
@ -528,6 +550,9 @@ public class JSONObjectTest {
jsonObject.get("doubleIdentifier").equals(new Double(0.1))); jsonObject.get("doubleIdentifier").equals(new Double(0.1)));
} }
/**
* Tests how JSONObject get[type] handles incorrect types
*/
@Test @Test
public void jsonObjectNonAndWrongValues() { public void jsonObjectNonAndWrongValues() {
String str = String str =
@ -547,75 +572,126 @@ public class JSONObjectTest {
"\"objectKey\":{\"myKey\":\"myVal\"}"+ "\"objectKey\":{\"myKey\":\"myVal\"}"+
"}"; "}";
JSONObject jsonObject = new JSONObject(str); JSONObject jsonObject = new JSONObject(str);
int tryCount = 0;
int exceptionCount = 0;
try { try {
++tryCount;
jsonObject.getBoolean("nonKey"); jsonObject.getBoolean("nonKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("expecting an exception message",
"JSONObject[\"nonKey\"] not found.".equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getBoolean("stringKey"); jsonObject.getBoolean("stringKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"stringKey\"] is not a Boolean.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getString("nonKey"); jsonObject.getString("nonKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"nonKey\"] not found.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getString("trueKey"); jsonObject.getString("trueKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"trueKey\"] not a string.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getDouble("nonKey"); jsonObject.getDouble("nonKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"nonKey\"] not found.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getDouble("stringKey"); jsonObject.getDouble("stringKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"stringKey\"] is not a number.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getInt("nonKey"); jsonObject.getInt("nonKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"nonKey\"] not found.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getInt("stringKey"); jsonObject.getInt("stringKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"stringKey\"] is not an int.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getLong("nonKey"); jsonObject.getLong("nonKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"nonKey\"] not found.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getLong("stringKey"); jsonObject.getLong("stringKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"stringKey\"] is not a long.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getJSONArray("nonKey"); jsonObject.getJSONArray("nonKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"nonKey\"] not found.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getJSONArray("stringKey"); jsonObject.getJSONArray("stringKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"stringKey\"] is not a JSONArray.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getJSONObject("nonKey"); jsonObject.getJSONObject("nonKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[\"nonKey\"] not found.".
equals(e.getMessage()));
}
try { try {
++tryCount;
jsonObject.getJSONObject("stringKey"); jsonObject.getJSONObject("stringKey");
} catch (JSONException ignore) { ++exceptionCount; } assertTrue("Expected an exception", false);
assertTrue("all get calls should have failed", } catch (JSONException e) {
exceptionCount == tryCount); 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 @Test
public void unexpectedDoubleToIntConversion() { public void unexpectedDoubleToIntConversion() {
/**
* 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.
*/
String key30 = "key30"; String key30 = "key30";
String key31 = "key31"; String key31 = "key31";
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
@ -636,11 +712,11 @@ public class JSONObjectTest {
assertTrue("3.1 remains a double", deserialized.getDouble(key31) == 3.1); assertTrue("3.1 remains a double", deserialized.getDouble(key31) == 3.1);
} }
@Test
/** /**
* Important behaviors of big numbers. Includes both JSONObject * Document behaviors of big numbers. Includes both JSONObject
* and JSONArray tests * and JSONArray tests
*/ */
@Test
public void bigNumberOperations() { public void bigNumberOperations() {
/** /**
* JSONObject tries to parse BigInteger as a bean, but it only has * JSONObject tries to parse BigInteger as a bean, but it only has
@ -874,6 +950,10 @@ public class JSONObjectTest {
Util.compareActualVsExpectedStringArrays(names, jsonObjectTestExpectedNames); Util.compareActualVsExpectedStringArrays(names, jsonObjectTestExpectedNames);
} }
/**
* Populate a JSONArray from an empty JSONObject names() method.
* It should be empty.
*/
@Test @Test
public void emptyJsonObjectNamesToJsonAray() { public void emptyJsonObjectNamesToJsonAray() {
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
@ -881,6 +961,10 @@ public class JSONObjectTest {
assertTrue("jsonArray should be null", jsonArray == null); assertTrue("jsonArray should be null", jsonArray == null);
} }
/**
* Populate a JSONArray from a JSONObject names() method.
* Confirm that it contains the expected names.
*/
@Test @Test
public void jsonObjectNamesToJsonAray() { public void jsonObjectNamesToJsonAray() {
String str = String str =
@ -907,6 +991,9 @@ public class JSONObjectTest {
Util.compareActualVsExpectedStringArrays(names, expectedNames); Util.compareActualVsExpectedStringArrays(names, expectedNames);
} }
/**
* Exercise the JSONObject increment() method.
*/
@Test @Test
public void jsonObjectIncrement() { public void jsonObjectIncrement() {
String str = String str =
@ -919,19 +1006,31 @@ public class JSONObjectTest {
"\"keyInt\":3,"+ "\"keyInt\":3,"+
"\"keyLong\":9999999993,"+ "\"keyLong\":9999999993,"+
"\"keyDouble\":3.1,"+ "\"keyDouble\":3.1,"+
// 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 * Should work the same way on any platform! @see
// converting 32-bit into double-precision 64-bit. * https://docs.oracle
// Java type-casts float to double. A 32 bit float is type-casted to 64 bit double by simply appending zero-bits to the * .com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.3 This is
// mantissa (and extended the signed exponent by 3 bits.) and there is no way to obtain more information than it is * the effect of a float to double conversion and is inherent to
// stored in the 32-bits float. * the shortcomings of the IEEE 754 format, when converting
* 32-bit into double-precision 64-bit. Java type-casts float to
// Like 1/3 cannot be represented as base10 number because it is periodically, 1/5 (for example) cannot be represented * double. A 32 bit float is type-casted to 64 bit double by
// as base2 number since it is periodically in base2 (take a look at http://www.h-schmidt.net/FloatConverter/) * simply appending zero-bits to the mantissa (and extended the
// The same happens to 3.1, that decimal number (base10 representation) is periodic in base2 representation, therefore * signed exponent by 3 bits.) and there is no way to obtain
// appending zero-bits is inaccurate. Only repeating the periodically occuring bits (0110) would be a proper conversion. * more information than it is stored in the 32-bits float.
// 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! * 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!
*/
"\"keyFloat\":3.0999999046325684,"+ "\"keyFloat\":3.0999999046325684,"+
"}"; "}";
JSONObject jsonObject = new JSONObject(str); JSONObject jsonObject = new JSONObject(str);
@ -948,24 +1047,28 @@ public class JSONObjectTest {
JSONObject expectedJsonObject = new JSONObject(expectedStr); JSONObject expectedJsonObject = new JSONObject(expectedStr);
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
/* /**
float f = 3.1f; * float f = 3.1f;
double df = (double) f; * double df = (double) f;
double d = 3.1d; * double d = 3.1d;
System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f))); * System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(df))); * System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(df)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d))); * System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d)));
*
* - Float:
* seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm
* 1000000010001100110011001100110
* - Double
* seeeeeeeeeeemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
* 10000000 10001100110011001100110
* 100000000001000110011001100110011000000000000000000000000000000
* 100000000001000110011001100110011001100110011001100110011001101
*/
- Float: /**
seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm * Examples of well documented but probably unexpected behavior in
1000000010001100110011001100110 * java / with 32-bit float to 64-bit float conversion.
- 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 explicit type-casting float as double!", (double)0.2f == 0.2d );
assertFalse("Document unexpected behaviour with implicit type-cast!", 0.2f == 0.2d ); assertFalse("Document unexpected behaviour with implicit type-cast!", 0.2f == 0.2d );
Double d1 = new Double( 1.1f ); Double d1 = new Double( 1.1f );
@ -997,7 +1100,9 @@ public class JSONObjectTest {
} }
/**
* Exercise JSONObject numberToString() method
*/
@Test @Test
public void jsonObjectNumberToString() { public void jsonObjectNumberToString() {
String str; String str;
@ -1017,6 +1122,9 @@ public class JSONObjectTest {
assertTrue("expected 5000000 actual "+str, str.equals("5000000")); assertTrue("expected 5000000 actual "+str, str.equals("5000000"));
} }
/**
* Exercise JSONObject put() and similar() methods
*/
@Test @Test
public void jsonObjectPut() { public void jsonObjectPut() {
String expectedStr = String expectedStr =
@ -1090,6 +1198,9 @@ public class JSONObjectTest {
!aCompareArrayJsonObject.similar(bCompareArrayJsonObject)); !aCompareArrayJsonObject.similar(bCompareArrayJsonObject));
} }
/**
* Exercise JSONObject toString() method
*/
@Test @Test
public void jsonObjectToString() { public void jsonObjectToString() {
String str = String str =
@ -1110,6 +1221,13 @@ public class JSONObjectTest {
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
} }
/**
* 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 @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void jsonObjectToStringSuppressWarningOnCastToMap() { public void jsonObjectToStringSuppressWarningOnCastToMap() {
@ -1124,7 +1242,8 @@ public class JSONObjectTest {
expectedJsonObject.keySet().iterator().next())); expectedJsonObject.keySet().iterator().next()));
/** /**
* Can't do a Util compare because although they look the same * Can't do a Util compare because although they look the same
* in the debugger, one is a map and the other is a JSONObject. * in the debugger, one is a map and the other is a JSONObject.
* TODO: write a util method for such comparisons
*/ */
map = (Map<String, String>)jsonObject.get("key"); map = (Map<String, String>)jsonObject.get("key");
JSONObject mapJsonObject = expectedJsonObject.getJSONObject("key"); JSONObject mapJsonObject = expectedJsonObject.getJSONObject("key");
@ -1137,6 +1256,13 @@ public class JSONObjectTest {
map.get(map.keySet().iterator().next()))); map.get(map.keySet().iterator().next())));
} }
/**
* 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 @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void jsonObjectToStringSuppressWarningOnCastToCollection() { public void jsonObjectToStringSuppressWarningOnCastToCollection() {
@ -1166,6 +1292,9 @@ public class JSONObjectTest {
} }
} }
/**
* Exercises the JSONObject.valueToString() method for various types
*/
@Test @Test
public void valueToString() { public void valueToString() {
@ -1211,6 +1340,12 @@ public class JSONObjectTest {
jsonArray.toString().equals(JSONObject.valueToString(array))); jsonArray.toString().equals(JSONObject.valueToString(array)));
} }
/**
* 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 @Test
public void wrapObject() { public void wrapObject() {
// wrap(null) returns NULL // wrap(null) returns NULL
@ -1224,8 +1359,9 @@ public class JSONObjectTest {
/** /**
* This test is to document the preferred behavior if BigDecimal is * This test is to document the preferred behavior if BigDecimal is
* supported. At the present time, bd returns as a string, since it * supported. Previously bd returned as a string, since it
* is recognized as being a Java package class. * 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); Object bdWrap = JSONObject.wrap(BigDecimal.ONE);
assertTrue("BigDecimal.ONE evaluates to ONE", assertTrue("BigDecimal.ONE evaluates to ONE",
@ -1273,88 +1409,128 @@ public class JSONObjectTest {
// TODO test wrap(package) // TODO test wrap(package)
} }
/**
* Explore how JSONObject handles parsing errors.
*/
@Test @Test
public void jsonObjectParsingErrors() { public void jsonObjectParsingErrors() {
int tryCount = 0;
int exceptionCount = 0;
try { try {
// does not start with '{' // does not start with '{'
++tryCount;
String str = "abc"; String str = "abc";
new JSONObject(str); new JSONObject(str);
} catch (JSONException ignore) {++exceptionCount; } 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 { try {
// does not end with '}' // does not end with '}'
++tryCount;
String str = "{"; String str = "{";
new JSONObject(str); new JSONObject(str);
} catch (JSONException ignore) {++exceptionCount; } 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 { try {
// key with no ':' // key with no ':'
++tryCount;
String str = "{\"myKey\" = true}"; String str = "{\"myKey\" = true}";
new JSONObject(str); new JSONObject(str);
} catch (JSONException ignore) {++exceptionCount; } 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 { try {
// entries with no ',' separator // entries with no ',' separator
++tryCount;
String str = "{\"myKey\":true \"myOtherKey\":false}"; String str = "{\"myKey\":true \"myOtherKey\":false}";
new JSONObject(str); new JSONObject(str);
} catch (JSONException ignore) {++exceptionCount; } 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 { try {
// append to wrong key // append to wrong key
++tryCount;
String str = "{\"myKey\":true, \"myOtherKey\":false}"; String str = "{\"myKey\":true, \"myOtherKey\":false}";
JSONObject jsonObject = new JSONObject(str); JSONObject jsonObject = new JSONObject(str);
jsonObject.append("myKey", "hello"); jsonObject.append("myKey", "hello");
} catch (JSONException ignore) {++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"JSONObject[myKey] is not a JSONArray.".
equals(e.getMessage()));
}
try { try {
// increment wrong key // increment wrong key
++tryCount;
String str = "{\"myKey\":true, \"myOtherKey\":false}"; String str = "{\"myKey\":true, \"myOtherKey\":false}";
JSONObject jsonObject = new JSONObject(str); JSONObject jsonObject = new JSONObject(str);
jsonObject.increment("myKey"); jsonObject.increment("myKey");
} catch (JSONException ignore) {++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"Unable to increment [\"myKey\"].".
equals(e.getMessage()));
}
try { try {
// invalid key // invalid key
++tryCount;
String str = "{\"myKey\":true, \"myOtherKey\":false}"; String str = "{\"myKey\":true, \"myOtherKey\":false}";
JSONObject jsonObject = new JSONObject(str); JSONObject jsonObject = new JSONObject(str);
jsonObject.get(null); jsonObject.get(null);
} catch (JSONException ignore) {++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"Null key.".
equals(e.getMessage()));
}
try { try {
// invalid numberToString() // invalid numberToString()
++tryCount;
JSONObject.numberToString((Number)null); JSONObject.numberToString((Number)null);
} catch (JSONException ignore) {++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expecting an exception message",
"Null pointer".
equals(e.getMessage()));
}
try { try {
// null put key // null put key
++tryCount;
JSONObject jsonObject = new JSONObject("{}"); JSONObject jsonObject = new JSONObject("{}");
jsonObject.put(null, 0); jsonObject.put(null, 0);
} catch (NullPointerException ignore) {++exceptionCount; } assertTrue("Expected an exception", false);
} catch (NullPointerException ignored) {
}
try { try {
// multiple putOnce key // multiple putOnce key
++tryCount;
JSONObject jsonObject = new JSONObject("{}"); JSONObject jsonObject = new JSONObject("{}");
jsonObject.putOnce("hello", "world"); jsonObject.putOnce("hello", "world");
jsonObject.putOnce("hello", "world!"); jsonObject.putOnce("hello", "world!");
} catch (JSONException ignore) {++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("", true);
}
try { try {
// test validity of invalid double // test validity of invalid double
++tryCount;
JSONObject.testValidity(Double.NaN); JSONObject.testValidity(Double.NaN);
} catch (JSONException ignore) {++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("", true);
}
try { try {
// test validity of invalid float // test validity of invalid float
++tryCount;
JSONObject.testValidity(Float.NEGATIVE_INFINITY); JSONObject.testValidity(Float.NEGATIVE_INFINITY);
} catch (JSONException ignore) {++exceptionCount; } assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("all tries should have failed", assertTrue("", true);
exceptionCount == tryCount); }
} }
/**
* Confirm behavior when putOnce() is called with null parameters
*/
@Test @Test
public void jsonObjectPutOnceNull() { public void jsonObjectPutOnceNull() {
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
@ -1362,6 +1538,9 @@ public class JSONObjectTest {
assertTrue("jsonObject should be empty", jsonObject.length() == 0); assertTrue("jsonObject should be empty", jsonObject.length() == 0);
} }
/**
* Exercise JSONObject opt(key, default) method
*/
@Test @Test
public void jsonObjectOptDefault() { public void jsonObjectOptDefault() {
@ -1382,6 +1561,9 @@ public class JSONObjectTest {
"hi".equals(jsonObject.optString("hiKey", "hi"))); "hi".equals(jsonObject.optString("hiKey", "hi")));
} }
/**
* Confirm behavior when JSONObject put(key, null object) is called
*/
@Test @Test
public void jsonObjectputNull() { public void jsonObjectputNull() {
@ -1397,6 +1579,11 @@ public class JSONObjectTest {
jsonObjectPutNull.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 @Test
public void jsonObjectQuote() { public void jsonObjectQuote() {
String str; String str;
@ -1435,6 +1622,10 @@ public class JSONObjectTest {
"\"\u1234\\u0088\"".equals(quotedStr)); "\"\u1234\\u0088\"".equals(quotedStr));
} }
/**
* Confirm behavior when JSONObject stringToValue() is called for an
* empty string
*/
@Test @Test
public void stringToValue() { public void stringToValue() {
String str = ""; String str = "";
@ -1443,12 +1634,18 @@ public class JSONObjectTest {
"".equals(valueStr)); "".equals(valueStr));
} }
/**
* Confirm behavior when toJSONArray is called with a null value
*/
@Test @Test
public void toJSONArray() { public void toJSONArray() {
assertTrue("toJSONArray() with null names should be null", assertTrue("toJSONArray() with null names should be null",
null == new JSONObject().toJSONArray(null)); null == new JSONObject().toJSONArray(null));
} }
/**
* Exercise the JSONObject write() method
*/
@Test @Test
public void write() { public void write() {
String str = "{\"key\":\"value\"}"; String str = "{\"key\":\"value\"}";
@ -1462,6 +1659,9 @@ public class JSONObjectTest {
expectedStr.equals(actualStr)); expectedStr.equals(actualStr));
} }
/**
* Exercise the JSONObject equals() method
*/
@Test @Test
public void equals() { public void equals() {
String str = "{\"key\":\"value\"}"; String str = "{\"key\":\"value\"}";
@ -1470,6 +1670,10 @@ public class JSONObjectTest {
aJsonObject.equals(aJsonObject)); 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 @Test
public void jsonObjectNullOperations() { public void jsonObjectNullOperations() {
/** /**

View file

@ -1,100 +1,178 @@
package org.json.junit; package org.json.junit;
import static org.junit.Assert.*;
import org.json.*; import org.json.*;
import org.junit.Test; import org.junit.Test;
/** /**
* Tests for JSON-Java JSONStringer.java * Tests for JSON-Java JSONStringer.
* TODO: Could use a lot more testing. For example, cascade-style productions.
*/ */
public class JSONStringerTest { public class JSONStringerTest {
@Test(expected=JSONException.class) /**
* Object with a null key.
* Expects a JSONException.
*/
@Test
public void nullKeyException() { public void nullKeyException() {
JSONStringer jsonStringer = new JSONStringer(); JSONStringer jsonStringer = new JSONStringer();
jsonStringer.object(); jsonStringer.object();
jsonStringer.key(null); try {
jsonStringer.key(null);
assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expected an exception message",
"Null key.".
equals(e.getMessage()));
}
} }
@Test(expected=JSONException.class) /**
* Add a key with no object.
* Expects a JSONException.
*/
@Test
public void outOfSequenceException() { public void outOfSequenceException() {
JSONStringer jsonStringer = new JSONStringer(); JSONStringer jsonStringer = new JSONStringer();
jsonStringer.key("hi"); try {
jsonStringer.key("hi");
assertTrue("Expected an exception", false);
} catch (JSONException e) {
assertTrue("Expected an exception message",
"Misplaced key.".
equals(e.getMessage()));
}
} }
@Test(expected=JSONException.class) /**
* Missplace an array.
* Expects a JSONException
*/
@Test
public void missplacedArrayException() { public void missplacedArrayException() {
JSONStringer jsonStringer = new JSONStringer(); JSONStringer jsonStringer = new JSONStringer();
jsonStringer.object().endObject(); jsonStringer.object().endObject();
jsonStringer.array(); try {
jsonStringer.array();
} catch (JSONException e) {
assertTrue("Expected an exception message",
"Misplaced array.".
equals(e.getMessage()));
}
} }
@Test(expected=JSONException.class) /**
* Missplace an endErray.
* Expects a JSONException
*/
@Test
public void missplacedEndArrayException() { public void missplacedEndArrayException() {
JSONStringer jsonStringer = new JSONStringer(); JSONStringer jsonStringer = new JSONStringer();
jsonStringer.object(); jsonStringer.object();
jsonStringer.endArray(); try {
jsonStringer.endArray();
} catch (JSONException e) {
assertTrue("Expected an exception message",
"Misplaced endArray.".
equals(e.getMessage()));
}
} }
@Test(expected=JSONException.class) /**
* Missplace an endObject.
* Expects a JSONException
*/
@Test
public void missplacedEndObjectException() { public void missplacedEndObjectException() {
JSONStringer jsonStringer = new JSONStringer(); JSONStringer jsonStringer = new JSONStringer();
jsonStringer.array(); jsonStringer.array();
jsonStringer.endObject(); try {
jsonStringer.endObject();
} catch (JSONException e) {
assertTrue("Expected an exception message",
"Misplaced endObject.".
equals(e.getMessage()));
}
} }
@Test(expected=JSONException.class) /**
* Missplace an object.
* Expects a JSONException.
*/
@Test
public void missplacedObjectException() { public void missplacedObjectException() {
JSONStringer jsonStringer = new JSONStringer(); JSONStringer jsonStringer = new JSONStringer();
jsonStringer.object().endObject(); jsonStringer.object().endObject();
jsonStringer.object(); try {
jsonStringer.object();
} catch (JSONException e) {
assertTrue("Expected an exception message",
"Misplaced object.".
equals(e.getMessage()));
}
} }
@Test(expected=JSONException.class) /**
* Exceeds implementation max nesting depth.
* Expects a JSONException
*/
@Test
public void exceedNestDepthException() { public void exceedNestDepthException() {
new JSONStringer().object(). try {
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). new JSONStringer().object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object().
key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(); key("k").object().key("k").object().key("k").object().key("k").object().key("k").object();
} catch (JSONException e) {
assertTrue("Expected an exception message",
"".
equals(e.getMessage()));
}
} }
/**
* Build a JSON doc using JSONString API calls,
* then convert to JSONObject
*/
@Test @Test
public void simpleObjectString() { public void simpleObjectString() {
String expectedStr = String expectedStr =
@ -123,6 +201,10 @@ public class JSONStringerTest {
Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject); Util.compareActualVsExpectedJsonObjects(jsonObject, expectedJsonObject);
} }
/**
* Build a JSON doc using JSONString API calls,
* then convert to JSONArray
*/
@Test @Test
public void simpleArrayString() { public void simpleArrayString() {
String expectedStr = String expectedStr =
@ -149,6 +231,10 @@ public class JSONStringerTest {
Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
} }
/**
* Build a nested JSON doc using JSONString API calls,
* then convert to JSONObject
*/
@Test @Test
public void complexObjectString() { public void complexObjectString() {
String expectedStr = String expectedStr =