package org.json.junit; /* Public Domain. */ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; 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 { private static final JSONObject document; private static final String EXPECTED_COMPLETE_DOCUMENT = "{\"\":0,\" \":7,\"g|h\":4,\"c%d\":2,\"k\\\"l\":6,\"a/b\":1,\"i\\\\j\":5," + "\"obj\":{\"\":{\"\":\"empty key of an object with an empty key\",\"subKey\":\"Some other value\"}," + "\"other~key\":{\"another/key\":[\"val\"]},\"key\":\"value\"},\"foo\":[\"bar\",\"baz\"],\"e^f\":3," + "\"m~n\":8}"; static { @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) { return new JSONPointer(pointer).queryFrom(document); } @Test public void emptyPointer() { assertTrue(new JSONObject(EXPECTED_COMPLETE_DOCUMENT).similar(query(""))); } @SuppressWarnings("unused") @Test(expected = NullPointerException.class) public void nullPointer() { new JSONPointer((String) null); } @Test public void objectPropertyQuery() { assertEquals("[\"bar\",\"baz\"]", query("/foo").toString()); } @Test public void arrayIndexQuery() { assertEquals("bar", query("/foo/0")); } @Test(expected = JSONPointerException.class) public void stringPropOfArrayFailure() { query("/foo/bar"); } @Test public void queryByEmptyKey() { assertEquals(0, query("/")); } @Test public void queryByEmptyKeySubObject() { JSONObject json = new JSONObject("{\"\":\"empty key of an object with an empty key\",\"subKey\":\"Some" + " other value\"}"); JSONObject obj = (JSONObject) query("/obj/"); assertTrue(json.similar(obj)); } @Test public void queryByEmptyKeySubObjectSubOject() { assertEquals("empty key of an object with an empty key", query("/obj//")); } @Test public void queryByEmptyKeySubObjectValue() { assertEquals("Some other value", query("/obj//subKey")); } @Test public void slashEscaping() { assertEquals(1, query("/a~1b")); } @Test public void tildeEscaping() { assertEquals(8, query("/m~0n")); } /** * We pass backslashes as-is * * @see rfc6901 section 3 */ @Test public void backslashHandling() { assertEquals(5, query("/i\\j")); } /** * We pass quotations as-is * * @see rfc6901 section 3 */ @Test public void quotationHandling() { assertEquals(6, query("/k\"l")); } @Test public void whitespaceKey() { assertEquals(7, query("/ ")); } @Test public void uriFragmentNotation() { assertEquals("[\"bar\",\"baz\"]", query("#/foo").toString()); } @Test public void uriFragmentNotationRoot() { assertTrue(new JSONObject(EXPECTED_COMPLETE_DOCUMENT).similar(query("#"))); } @Test public void uriFragmentPercentHandling() { assertEquals(2, query("#/c%25d")); assertEquals(3, query("#/e%5Ef")); assertEquals(4, query("#/g%7Ch")); assertEquals(8, query("#/m~0n")); } @SuppressWarnings("unused") @Test(expected = IllegalArgumentException.class) public void syntaxError() { new JSONPointer("key"); } @Test(expected = JSONPointerException.class) public void arrayIndexFailure() { query("/foo/2"); } @Test(expected = JSONPointerException.class) public void primitiveFailure() { query("/obj/key/failure"); } @Test public void builderTest() { JSONPointer pointer = JSONPointer.builder() .append("obj") .append("other~key").append("another/key") .append(0) .build(); assertEquals("val", pointer.queryFrom(document)); } @Test(expected = NullPointerException.class) public void nullToken() { JSONPointer.builder().append(null); } @Test public void toStringEscaping() { JSONPointer pointer = JSONPointer.builder() .append("obj") .append("other~key").append("another/key") .append("\"") .append(0) .build(); assertEquals("/obj/other~0key/another~1key/\"/0", pointer.toString()); } @Test public void emptyPointerToString() { assertEquals("", new JSONPointer("").toString()); } @Test public void toURIFragment() { assertEquals("#/c%25d", new JSONPointer("/c%d").toURIFragment()); assertEquals("#/e%5Ef", new JSONPointer("/e^f").toURIFragment()); assertEquals("#/g%7Ch", new JSONPointer("/g|h").toURIFragment()); assertEquals("#/m%7En", new JSONPointer("/m~n").toURIFragment()); } @Test public void tokenListIsCopiedInConstructor() { JSONPointer.Builder b = JSONPointer.builder().append("key1"); JSONPointer jp1 = b.build(); b.append("key2"); JSONPointer jp2 = b.build(); if(jp1.toString().equals(jp2.toString())) { fail("Oops, my pointers are sharing a backing array"); } } /** * Coverage for JSONObject query(String) */ @Test public void queryFromJSONObject() { String str = "{"+ "\"stringKey\":\"hello world!\","+ "\"arrayKey\":[0,1,2],"+ "\"objectKey\": {"+ "\"a\":\"aVal\","+ "\"b\":\"bVal\""+ "}"+ "}"; JSONObject jsonObject = new JSONObject(str); Object obj = jsonObject.query("/stringKey"); assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); obj = jsonObject.query("/arrayKey/1"); assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); obj = jsonObject.query("/objectKey/b"); assertTrue("Expected bVal", "bVal".equals(obj)); try { obj = jsonObject.query("/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 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() { String str = "["+ "\"hello world!\","+ "[0,1,2],"+ "{"+ "\"a\":\"aVal\","+ "\"b\":\"bVal\""+ "}"+ "]"; JSONArray jsonArray = new JSONArray(str); Object obj = jsonArray.query("/0"); assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); obj = jsonArray.query("/1/1"); assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); obj = jsonArray.query("/2/b"); assertTrue("Expected bVal", "bVal".equals(obj)); try { obj = jsonArray.query("/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 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); } /** * When creating a jsonObject we need to parse escaped characters "\\\\" * --> it's the string representation of "\\", so when query'ing via the JSONPointer * we DON'T escape them * */ @Test public void queryFromJSONObjectUsingPointer0() { String str = "{"+ "\"string\\\\\\\\Key\":\"hello world!\","+ "\"\\\\\":\"slash test\"," + "}"+ "}"; JSONObject jsonObject = new JSONObject(str); //Summary of issue: When a KEY in the jsonObject is "\\\\" --> it's held // as "\\" which means when querying, we need to use "\\" Object twoBackslahObj = jsonObject.optQuery(new JSONPointer("/\\")); assertEquals("slash test", twoBackslahObj); Object fourBackslashObj = jsonObject.optQuery(new JSONPointer("/string\\\\Key")); assertEquals("hello world!", fourBackslashObj); } }