JSONObjectTest.java
/**
* The MIT License
*
* Copyright for portions of unirest-java are held by Kong Inc (c) 2013.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package kong.unirest.modules.jackson;
import kong.unirest.core.UnirestException;
import kong.unirest.core.json.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.skyscreamer.jsonassert.JSONAssert;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Map;
import java.util.Set;
import static com.google.common.collect.ImmutableMap.of;
import static com.google.common.collect.Sets.newHashSet;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.*;
class JSONObjectTest {
@Test
void canSimpleSerializeAnObject() {
var test = new TestMe(true, "Wakk Wakka", 42, new TestMe());
var o = new JSONObject(test);
assertEquals(true, o.optBoolean("aBoolean"));
assertEquals("Wakk Wakka", o.optString("aSillyString"));
assertEquals(42, o.optNumber("aNumber"));
assertNotNull(o.optJSONObject("aSub"));
}
@Test
void isEmpty() {
var o = new JSONObject();
assertTrue(o.isEmpty());
o.put("foo", "bar");
assertFalse(o.isEmpty());
}
@Test
void isNull() {
var o = new JSONObject();
assertTrue(o.isNull("foo"));
o.put("foo", (Object)null);
assertTrue(o.isNull("foo"));
o.put("foo", 42);
assertFalse(o.isNull("foo"));
}
@Test
void contructInvalid() {
JSONException ex = assertThrows(JSONException.class, () -> new JSONObject("foo"));
assertEquals("Invalid JSON", ex.getMessage());
}
@Test
void simpleConvert() {
String str = "{\"foo\": {\"baz\": 42}}";
JSONObject obj = new JSONObject(str);
assertTrue(obj.has("foo"));
assertEquals(1, obj.length());
assertEquals(42, obj.getJSONObject("foo").getInt("baz"));
}
@Test
void doubles() {
JSONObject obj = new JSONObject();
obj.put("key", 33.5d);
obj.put("not", "nan");
assertEquals(33.5d, obj.getDouble("key"), 4);
assertNotFound(() -> obj.getDouble("boo"));
assertJSONEx(() -> obj.getDouble("not"), "JSONObject[\"not\"] is not a number.");
isTypeAndValue(33.5, Double.class, obj.get("key"));
assertEquals(33.5d, obj.optDouble("key"), 4);
assertEquals(66.6d, obj.optDouble("boo", 66.6d), 4);
assertEquals(Double.NaN, obj.optDouble("boo"), 4);
}
@Test
void nullsAreSerialized() {
JSONObject obj = new JSONObject("{\"key1\": \"value\", \"key2\": null}");
assertEquals("{\"key1\":\"value\",\"key2\":null}", obj.toString());
}
@Test
void issue_366() {
JSONObject jsonObject = new JSONObject("{\"status\":\"OK\",\"message\":\"hive_1597818501335\"}");
assertEquals("{\"status\":\"OK\",\"message\":\"hive_1597818501335\"}", jsonObject.toString());
}
@Test
void nullsAreSerializedOnPretty() {
JSONObject obj = new JSONObject("{\"key1\": \"value\", \"key2\": null}");
assertEquals("{\n" +
" \"key1\" : \"value\",\n" +
" \"key2\" : null\n" +
"}", obj.toString(3));
}
@Test
void floats() {
JSONObject obj = new JSONObject();
obj.put("key", 33.5f);
obj.put("not", "nan");
assertEquals(33.5f, obj.getFloat("key"), 4);
assertNotFound(() -> obj.getFloat("boo"));
assertJSONEx(() -> obj.getFloat("not"), "JSONObject[\"not\"] is not a number.");
isTypeAndValue(33.5, Double.class, obj.get("key"));
assertEquals(33.5f, obj.optFloat("key"), 4);
assertEquals(66.6f, obj.optFloat("boo", 66.6f), 4);
assertEquals(Float.NaN, obj.optFloat("boo"), 4);
}
@Test
void longs() {
JSONObject obj = new JSONObject();
obj.put("key", Long.MAX_VALUE);
obj.put("not", "nan");
assertEquals(Long.MAX_VALUE, obj.getLong("key"));
assertNotFound(() -> obj.getLong("boo"));
assertJSONEx(() -> obj.getLong("not"), "JSONObject[\"not\"] is not a number.");
isTypeAndValue(Long.MAX_VALUE, Long.class, obj.get("key"));
assertEquals(Long.MAX_VALUE, obj.optLong("key"));
assertEquals(66L, obj.optLong("boo", 66));
assertEquals(0L, obj.optLong("boo"));
}
@Test
void booleans() {
JSONObject obj = new JSONObject();
obj.put("key", true);
obj.put("not", "nan");
assertTrue(obj.getBoolean("key"));
assertNotFound(() -> obj.getBoolean("boo"));
assertJSONEx(() -> obj.getBoolean("not"), "JSONObject[\"not\"] is not a boolean.");
isTypeAndValue(true, Boolean.class, obj.get("key"));
assertTrue(obj.optBoolean("key"));
assertTrue(obj.optBoolean("boo", true));
assertFalse(obj.optBoolean("boo"));
}
@Test
void ints() {
JSONObject obj = new JSONObject();
obj.put("key", 33);
obj.put("not", "nan");
assertEquals(33, obj.getInt("key"));
assertNotFound(() -> obj.getInt("boo"));
assertJSONEx(() -> obj.getInt("not"), "JSONObject[\"not\"] is not a number.");
isTypeAndValue(33, Integer.class, obj.get("key"));
assertEquals(33, obj.optInt("key"));
assertEquals(66, obj.optInt("boo", 66));
assertEquals(0, obj.optInt("boo"));
}
@Test
void numbers() {
Number tt = 33;
JSONObject obj = new JSONObject();
obj.put("key", tt);
obj.put("not", "nan");
assertEquals(tt, obj.getNumber("key"));
assertNotFound(() -> obj.getNumber("boo"));
assertJSONEx(() -> obj.getNumber("not"), "JSONObject[\"not\"] is not a number.");
isTypeAndValue(tt, Number.class, obj.getNumber("key"));
assertEquals(tt, obj.optNumber("key"));
assertEquals(66, obj.optNumber("boo", 66));
assertEquals(0, obj.optNumber("boo"));
}
@Test
void bigInts() {
JSONObject obj = new JSONObject();
obj.put("key", BigInteger.valueOf(33));
obj.put("not", "nan");
assertEquals(BigInteger.valueOf(33), obj.getBigInteger("key"));
assertNotFound(() -> obj.getBigInteger("boo"));
assertJSONEx(() -> obj.getBigInteger("not"), "JSONObject[\"not\"] is not a number.");
assertEquals(BigInteger.valueOf(33), obj.optBigInteger("key", BigInteger.TEN));
assertEquals(BigInteger.TEN, obj.optBigInteger("boo", BigInteger.TEN));
isTypeAndValue(33, Integer.class, obj.get("key"));
}
@Test
void bigDecimal() {
BigDecimal value = BigDecimal.valueOf(33.5);
JSONObject obj = new JSONObject();
obj.put("key", value);
obj.put("not", "nan");
assertEquals(value, obj.getBigDecimal("key"));
assertNotFound(() -> obj.getBigDecimal("boo"));
assertJSONEx(() -> obj.getBigDecimal("not"), "JSONObject[\"not\"] is not a number.");
assertEquals(value, obj.optBigDecimal("key", BigDecimal.TEN));
assertEquals(BigDecimal.TEN, obj.optBigDecimal("boo", BigDecimal.TEN));
isTypeAndValue(33.5, Double.class, obj.get("key"));
}
@Test
void strings() {
JSONObject obj = new JSONObject();
obj.put("key", "cheese");
obj.put("not", 45);
assertEquals("cheese", obj.getString("key"));
assertNotFound(() -> obj.getString("boo"));
assertEquals("45", obj.getString("not"));
assertEquals("cheese", obj.optString("key"));
assertEquals("logs", obj.optString("boo", "logs"));
assertEquals("", obj.optString("boo"));
isTypeAndValue("cheese", String.class, obj.get("key"));
}
@Test
void jsonObjects() throws Exception {
JSONObject subObj = new JSONObject("{\"derp\": 42}");
JSONObject obj = new JSONObject();
obj.put("key", subObj);
obj.put("not", 45);
assertEqualJson(subObj, obj.getJSONObject("key"));
assertNotFound(() -> obj.getJSONObject("boo"));
assertJSONEx(() -> obj.getJSONObject("not"), "JSONObject[\"not\"] is not a JSONObject.");
assertEqualJson(subObj, obj.optJSONObject("key"));
assertNull(obj.optJSONObject("boo"));
assertTrue(subObj.similar(obj.get("key")));
}
@Test
void jsonArrays() throws Exception {
var subObj = new JSONArray("[42]");
JSONObject obj = new JSONObject();
obj.put("key", subObj);
obj.put("not", 45);
assertEqualJson(subObj, obj.getJSONArray("key"));
assertNotFound(() -> obj.getJSONArray("boo"));
assertJSONEx(() -> obj.getJSONArray("not"), "JSONObject[\"not\"] is not a JSONArray.");
assertEqualJson(subObj, obj.optJSONArray("key"));
assertNull(obj.optJSONArray("boo"));
assertTrue(subObj.similar(obj.get("key")));
}
@Test
void enums() {
JSONObject obj = new JSONObject();
obj.put("key", fruit.orange);
obj.put("not", "nan");
assertEquals(fruit.orange, obj.getEnum(fruit.class, "key"));
assertJSONEx(() -> obj.getEnum(fruit.class, "not"), "JSONObject[\"not\"] is not an enum of type \"fruit\".");
assertEquals(fruit.orange, obj.optEnum(fruit.class, "key"));
assertEquals(fruit.apple, obj.optEnum(fruit.class, "boo", fruit.apple));
assertNull(obj.optEnum(fruit.class, "boo"));
isTypeAndValue(obj.get("key"), String.class, "orange");
}
@Test
void toStringIt() {
String str = "{\"foo\": 42}";
JSONObject obj = new JSONObject(str);
assertEquals("{\"foo\":42}", obj.toString());
}
@Test
void toStringItIndent() {
String str = "{\"foo\": 42, \"bar\": true}";
JSONObject obj = new JSONObject(str);
assertEquals("{\n" +
" \"foo\" : 42,\n" +
" \"bar\" : true\n" +
"}", obj.toString(3));
}
@Test
void objProperties() {
String str = "{\"foos\": [6,7,8]}";
JSONObject obj = new JSONObject(str);
assertEquals(7, obj.getJSONArray("foos").get(1));
assertEquals(7, obj.optJSONArray("foos").get(1));
assertNull(obj.optJSONArray("bars"));
}
@Test
void writer() {
String str = "{\"foo\":42}";
JSONObject obj = new JSONObject(str);
StringWriter sw = new StringWriter();
obj.write(sw);
assertEquals(str, sw.toString());
}
@Test
void writerIndent() {
String str = "{\"foo\": 42, \"bar\": true}";
JSONObject obj = new JSONObject(str);
StringWriter sw = new StringWriter();
obj.write(sw, 3, 3);
assertEquals("{\n" +
" \"foo\" : 42,\n" +
" \"bar\" : true\n" +
"}", sw.toString());
}
@Test
void remove() {
JSONObject obj = new JSONObject("{\"foo\": 42, \"bar\": true}");
assertEquals(42, obj.remove("foo"));
assertNull(obj.remove("nothing"));
assertEquals("{\"bar\":true}", obj.toString());
}
@Test
void removeAThingThatDoesntExist() {
JSONObject obj = new JSONObject();
obj.remove("foo");
assertEquals(0, obj.length());
}
@Test
void putReplace() {
JSONObject obj = new JSONObject("{\"bar\": 42}");
assertEquals(42, obj.get("bar"));
assertSame(obj, obj.put("bar", 33));
assertEquals(33, obj.get("bar"));
NullPointerException ex = assertThrows(NullPointerException.class, () -> obj.put(null, "hi"));
assertEquals("key == null", ex.getMessage());
}
@Test
void accumulateDoesNotCreate() {
JSONObject obj = new JSONObject();
assertSame(obj, obj.accumulate("bar", 42));
assertEquals(0, obj.length());
}
@Test
void accumulate() {
JSONObject obj = new JSONObject("{\"bar\": 42}");
assertSame(obj, obj.accumulate("bar", 33));
assertEquals(2, obj.getJSONArray("bar").length());
assertEquals(42, obj.getJSONArray("bar").get(0));
assertEquals(33, obj.getJSONArray("bar").get(1));
}
@Test
void accumulateNullKey() {
NullPointerException ex = assertThrows(NullPointerException.class, () -> new JSONObject().accumulate(null, "hi"));
assertEquals("Null key.", ex.getMessage());
}
@Test
void append() {
JSONObject obj = new JSONObject();
assertSame(obj, obj.append("bar", 42));
obj.append("bar", 33);
assertEquals(2, obj.getJSONArray("bar").length());
assertEquals(42, obj.getJSONArray("bar").get(0));
assertEquals(33, obj.getJSONArray("bar").get(1));
}
@Test
void appendNullKey() {
NullPointerException ex = assertThrows(NullPointerException.class, () -> new JSONObject().append(null, "hi"));
assertEquals("Null key.", ex.getMessage());
}
@Test
void appendToNotAnArrary() {
JSONObject obj = new JSONObject();
assertSame(obj, obj.put("bar", "not"));
JSONException ex = assertThrows(JSONException.class, () -> obj.append("bar", 33));
assertEquals("JSONObject[\"bar\"] is not a JSONArray.", ex.getMessage());
}
@Test
void increment() {
JSONObject obj = new JSONObject();
assertSame(obj, obj.increment("cool-beans"));
assertEquals(1, obj.get("cool-beans"));
obj.increment("cool-beans")
.increment("cool-beans")
.increment("cool-beans");
assertEquals(4, obj.get("cool-beans"));
}
@Test
void incrementDouble() {
JSONObject obj = new JSONObject();
assertSame(obj, obj.put("cool-beans", 1.5));
obj.increment("cool-beans");
assertEquals(2.5, obj.get("cool-beans"));
}
@Test
void putOnce() {
JSONObject obj = new JSONObject();
assertSame(obj, obj.putOnce("foo", "bar"));
assertJSONEx(() -> obj.putOnce("foo", "baz"), "Duplicate key \"foo\"");
assertEquals("bar", obj.getString("foo"));
}
@Test
void optPut() {
JSONObject obj = new JSONObject();
assertSame(obj, obj.putOpt("foo", "bar"));
obj.putOpt(null, "bar");
obj.putOpt("foo", null);
assertEquals("bar", obj.get("foo"));
obj.putOpt("foo", "qux");
assertEquals("qux", obj.get("foo"));
}
@Test
void keySet() {
JSONObject obj = new JSONObject();
obj.put("one", "a");
obj.put("two", "b");
Set<String> exp = newHashSet("one", "two");
assertEquals(exp, obj.keySet());
assertEquals(exp, newHashSet(obj.keys()));
}
@Test
void similar() {
JSONObject obj1 = new JSONObject("{\"foo\":42}");
JSONObject obj2 = new JSONObject("{\"foo\":42}");
assertTrue(obj1.similar(obj2));
obj1.put("foo", -9);
assertFalse(obj1.similar(obj2));
}
@Test
void query() {
JSONObject obj = new JSONObject("{\"a\":{\"b\": 42}}");
assertEquals(42, obj.query("/a/b"));
}
@Test
void maps() {
JSONObject obj = new JSONObject("{\"foo\": {\"bar\": 42}, \"qux\": 21474836475, \"baz\": 55}");
Map<String, Object> map = obj.toMap();
assertEquals(55, map.get("baz"));
assertEquals(21474836475L, map.get("qux"));
JSONObject sub = (JSONObject) obj.get("foo");
assertEquals(42, sub.get("bar"));
}
@Test
void names() {
JSONObject obj = new JSONObject(of("foo", 1, "bar", 2, "baz", 3));
var names = obj.names();
assertEquals(
newHashSet("foo", "bar", "baz"),
newHashSet(names.toList())
);
}
@Test
void toJSONArray() {
var o = new JSONObject(of("foo","bar","baz",42));
assertNull(o.toJSONArray(new JSONArray()));
assertEquals(new JSONArray(asList("bar", 42)),
o.toJSONArray(new JSONArray(asList("foo", "baz"))));
assertEquals(new JSONArray(asList(null, null)),
new JSONObject().toJSONArray(new JSONArray(asList("foo", "baz"))));
}
@Test
void putCollection() {
var o = new JSONObject();
o.put("foo", asList(1,2,3));
assertEquals("{\"foo\":[1,2,3]}", o.toString());
}
@Test
void putObjectAsMap() {
var o = new JSONObject();
o.put("foo", of("baz", 42));
assertEquals("{\"foo\":{\"baz\":42}}", o.toString());
}
@Test
@SuppressWarnings("ConstantConditions")
void stringToValue() {
assertSame(JSONObject.NULL, JSONObject.stringToValue("null"));
assertEquals(true, JSONObject.stringToValue("true"));
assertEquals(false, JSONObject.stringToValue("false"));
assertEquals(42, JSONObject.stringToValue("42"));
assertEquals(45.25, JSONObject.stringToValue("45.25"));
assertEquals(-45.25, JSONObject.stringToValue("-45.25"));
NullPointerException ex = assertThrows(NullPointerException.class, () -> JSONObject.stringToValue(null));
}
@Test
void quote() {
assertEquals("\"\\\"foo\\\"hoo\"", JSONObject.quote("\"foo\"hoo"));
}
@Test
void quoteWriter() throws IOException {
StringWriter w = new StringWriter();
Writer quote = JSONObject.quote("\"foo\"hoo", w);
assertEquals("\"\\\"foo\\\"hoo\"", quote.toString());
}
@Test
void wrapPrimitives() {
assertEquals(42, JSONObject.wrap(42));
assertEquals(42.5, JSONObject.wrap(42.5));
assertSame(JSONObject.NULL, JSONObject.wrap(null));
assertEquals(true, JSONObject.wrap(true));
}
@Test
void wrapObjects() {
assertTrue(new JSONArray(asList(1,2,3)).similar(JSONObject.wrap(asList(1,2,3))));
assertTrue(new JSONArray(asList(1,2,3)).similar(JSONObject.wrap(new int[]{1,2,3})));
assertTrue(new JSONObject(of("f",1)).similar(JSONObject.wrap(of("f",1))));
assertTrue(new JSONObject().similar(JSONObject.wrap(new Foo("hi"))));
}
@Test
void doubleToString() {
assertEquals("42", JSONObject.doubleToString(42));
assertEquals("42.5643", JSONObject.doubleToString(42.5643));
}
@Test
void numberToString() {
assertEquals("42", JSONObject.numberToString(42));
assertEquals("42.5643", JSONObject.numberToString(42.5643f));
}
@Test
void valueToString() {
assertEquals("null", JSONObject.valueToString(null));
assertEquals("42", JSONObject.valueToString(42));
assertEquals("42.5643", JSONObject.valueToString(42.5643f));
assertEquals("\"Hello World\"", JSONObject.valueToString("Hello World"));
assertEquals("{\"bar\":\"me\"}", JSONObject.valueToString(new Foo("me")));
assertEquals("{}", JSONObject.valueToString(new JSONObject()));
assertEquals("[]", JSONObject.valueToString(new JSONArray()));
}
@Test
void getNames() {
assertArrayEquals(null, JSONObject.getNames(new JSONObject()));
assertArrayEquals(new String[]{"a","b"}, JSONObject.getNames(new JSONObject(of("a",1,"b",2))));
}
private void assertNotFound(Executable exRunnable) {
assertJSONEx(exRunnable, "JSONObject[\"boo\"] not found.");
}
public static void assertJSONEx(Executable exRunnable, String message) {
JSONException ex = assertThrows(JSONException.class, exRunnable);
assertEquals(message, ex.getMessage());
}
public static void assertEqualJson(Object subObj, Object value){
try {
JSONAssert.assertEquals(subObj.toString(), value.toString(), true);
} catch (org.json.JSONException e) {
throw new UnirestException(e);
}
}
public static void isTypeAndValue(Object o, Class<?> type, Object value) {
assertEquals(o, value);
assertTrue(type.isInstance(o));
}
public enum fruit {orange, apple}
public static class TestMe {
private boolean aBoolean;
private String aSillyString;
private Integer aNumber;
private TestMe aSub;
public TestMe(){ }
public TestMe(boolean bool, String aString, int aNumber, TestMe aSub){
this.aBoolean = bool;
this.aSillyString = aString;
this.aNumber = aNumber;
this.aSub = aSub;
}
public boolean isaBoolean() {
return aBoolean;
}
public void setaBoolean(boolean aBoolean) {
this.aBoolean = aBoolean;
}
public String getaSillyString() {
return aSillyString;
}
public void setaSillyString(String aSillyString) {
this.aSillyString = aSillyString;
}
public Integer getaNumber() {
return aNumber;
}
public void setaNumber(Integer aNumber) {
this.aNumber = aNumber;
}
public TestMe getaSub() {
return aSub;
}
public void setaSub(TestMe aSub) {
this.aSub = aSub;
}
}
}