Browse Source

improved path parsing

pull/1/merge
kalle 14 years ago
parent
commit
8f695ae262
  1. 8
      changelog.txt
  2. 12
      json-path-assert/src/main/java/com/jayway/jsonassert/JsonAsserter.java
  3. 28
      json-path-assert/src/main/java/com/jayway/jsonassert/impl/JsonAsserterImpl.java
  4. 47
      json-path-assert/src/test/java/com/jayway/jsonassert/JsonAssertTest.java
  5. 49
      json-path-assert/src/test/resources/links.json
  6. 3
      json-path/src/main/java/com/jayway/jsonpath/PathUtil.java
  7. 10
      json-path/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterFactory.java
  8. 14
      json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java
  9. 8
      json-path/src/test/java/com/jayway/jsonpath/PathUtilTest.java
  10. 2
      json-path/src/test/java/com/jayway/jsonpath/SplitPathFragmentsTest.java

8
changelog.txt

@ -0,0 +1,8 @@
------------------------------------------
0.5.2
------------------------------------------
- Fixed issue that path was never considered definite if containing a ':'
- Bracket notation is now first class citizen $.foo.bar == $.['foo'].['bar']
- Added JsonAsserter.assertNotDefined(String path) to allow checks for negative existence of a path

12
json-path-assert/src/main/java/com/jayway/jsonassert/JsonAsserter.java

@ -16,7 +16,7 @@ public interface JsonAsserter {
* <p/> * <p/>
* <code> * <code>
* with(json).assertThat("items[0].name", equalTo("Bobby")) * with(json).assertThat("items[0].name", equalTo("Bobby"))
* .assertThat("items[0].age" , equalTo(24L)) * .assertThat("items[0].age" , equalTo(24L))
* </code> * </code>
* *
* @param path the json path specifying the value being compared * @param path the json path specifying the value being compared
@ -37,6 +37,16 @@ public interface JsonAsserter {
*/ */
<T> JsonAsserter assertEquals(String path, T expected); <T> JsonAsserter assertEquals(String path, T expected);
/**
* Checks that a path is not defined within a document. If the document contains the
* given path, an AssertionError is thrown
*
* @param path the path to make sure not exists
* @return this
*/
JsonAsserter assertNotDefined(String path);
/** /**
* Asserts that object specified by path is null. If it is not, an AssertionError * Asserts that object specified by path is null. If it is not, an AssertionError
* is thrown with the given message. * is thrown with the given message.

28
json-path-assert/src/main/java/com/jayway/jsonassert/impl/JsonAsserterImpl.java

@ -4,13 +4,10 @@ package com.jayway.jsonassert.impl;
import com.jayway.jsonassert.JsonAsserter; import com.jayway.jsonassert.JsonAsserter;
import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathUtil; import com.jayway.jsonpath.PathUtil;
import org.hamcrest.Description;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import org.hamcrest.MatcherAssert; import org.hamcrest.MatcherAssert;
import java.text.ParseException; import static java.lang.String.format;
import java.util.List;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
/** /**
@ -21,7 +18,6 @@ import static org.hamcrest.Matchers.*;
public class JsonAsserterImpl implements JsonAsserter { public class JsonAsserterImpl implements JsonAsserter {
private final Object jsonObject; private final Object jsonObject;
@ -35,20 +31,18 @@ public class JsonAsserterImpl implements JsonAsserter {
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> JsonAsserter assertThat(String path, Matcher<T> matcher) { public <T> JsonAsserter assertThat(String path, Matcher<T> matcher) {
String reason = "When processing json path: " + path; String reason = "When processing json path: " + path;
if(PathUtil.isPathDefinite(path)){ if (PathUtil.isPathDefinite(path)) {
MatcherAssert.assertThat(reason, JsonPath.<T>readOne(jsonObject, path), matcher); MatcherAssert.assertThat(reason, JsonPath.<T>readOne(jsonObject, path), matcher);
} } else {
else { MatcherAssert.assertThat(reason, (T) JsonPath.<T>read(jsonObject, path), matcher);
MatcherAssert.assertThat(reason, (T) JsonPath.<T>read(jsonObject, path), matcher);
} }
return this; return this;
} }
@ -60,6 +54,18 @@ public class JsonAsserterImpl implements JsonAsserter {
return assertThat(path, equalTo(expected)); return assertThat(path, equalTo(expected));
} }
/**
* {@inheritDoc}
*/
public JsonAsserter assertNotDefined(String path) {
Object o = JsonPath.readOne(jsonObject, path);
if(o != null){
throw new AssertionError(format("Document contains the path <%s> but was expected not to.", path));
}
return this;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */

47
json-path-assert/src/test/java/com/jayway/jsonassert/JsonAssertTest.java

@ -3,6 +3,8 @@ package com.jayway.jsonassert;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.Test; import org.junit.Test;
import java.io.InputStream;
import static com.jayway.jsonassert.JsonAssert.*; import static com.jayway.jsonassert.JsonAssert.*;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
@ -41,11 +43,40 @@ public class JsonAssertTest {
" ],\n" + " ],\n" +
" \"bicycle\": {\n" + " \"bicycle\": {\n" +
" \"color\": \"red\",\n" + " \"color\": \"red\",\n" +
" \"price\": 19.95\n" + " \"price\": 19.95\n," +
" \"nullValue\": null\n" +
" }\n" + " }\n" +
" }\n" + " }\n" +
"}"; "}";
@Test
public void links_document() throws Exception {
with(getResourceAsStream("links.json")).assertEquals("count", 2L)
.assertThat("links.gc:this.href", endsWith("?pageNumber=1&pageSize=2"))
.assertNotDefined("links.gc:prev")
.assertNotDefined("links.gc:next")
.assertThat("rows", collectionWithSize(equalTo(2)));
}
@Test
public void a_document_can_be_expected_not_to_contain_a_path() throws Exception {
with(JSON).assertNotDefined("$.store.bicycle.cool");
}
@Test
public void a_value_can_asserted_to_be_null() throws Exception {
with(JSON).assertNull("$.store.bicycle.nullValue");
}
@Test
public void ends_with_evalueates() throws Exception {
with(JSON).assertThat("$.store.book[0].category", endsWith("nce"));
}
@Test @Test
public void a_path_can_be_asserted_with_matcher() throws Exception { public void a_path_can_be_asserted_with_matcher() throws Exception {
@ -78,6 +109,15 @@ public class JsonAssertTest {
.assertThat("$.store.book[0]", mapContainingKey(equalTo("category"))) .assertThat("$.store.book[0]", mapContainingKey(equalTo("category")))
.and() .and()
.assertThat("$.store.book[0]", mapContainingValue(equalTo("reference"))); .assertThat("$.store.book[0]", mapContainingValue(equalTo("reference")));
with(JSON).assertThat("$.['store'].['book'][0]", hasEntry("category", "reference"))
.assertThat("$.['store'].['book'][0]", hasEntry("title", "Sayings of the Century"))
.and()
.assertThat("$..['book'][0]", hasItems(hasEntry("category", "reference")))
.and()
.assertThat("$.['store'].['book'][0]", mapContainingKey(equalTo("category")))
.and()
.assertThat("$.['store'].['book'][0]", mapContainingValue(equalTo("reference")));
} }
@Test @Test
@ -102,4 +142,9 @@ public class JsonAssertTest {
with(JSON).assertThat("$.store.book[*].fooBar", emptyCollection()); with(JSON).assertThat("$.store.book[*].fooBar", emptyCollection());
} }
private InputStream getResourceAsStream(String resourceName) {
return getClass().getClassLoader().getResourceAsStream(resourceName);
}
} }

49
json-path-assert/src/test/resources/links.json

@ -0,0 +1,49 @@
{
"links": {
"gc:this": {
"rel": "gc:this",
"href": "/rest/account/market/incentives?pageNumber=1&pageSize=2"
}
},
"count": 2,
"pageNumber": 1,
"pageSize": 2,
"rows": [{
"id": "cd646745-5834-4244-9126-fa631c32693c",
"price": 10,
"title": "A TITLE",
"description": "description",
"smallIcon": "small.ico",
"categories": ["cd646745-5834-4244-9126-fa631c32693c"],
"brand": {
"id": "8d0280ae-8ea3-4ae1-b46c-f0fc0b293066",
"name": "brand.name",
"picture": "brand.picture"
},
"links": {
"gc:market:incentive": {
"rel": "gc:market:incentive",
"href": "/rest/account/market/incentives/cd646745-5834-4244-9126-fa631c32693c"
}
}
},
{
"id": "cd646745-5834-4244-9126-fa631c32693c2",
"price": 10,
"title": "B TITLE",
"description": "description",
"smallIcon": "small.ico",
"categories": ["cd646745-5834-4244-9126-fa631c32693c"],
"brand": {
"id": "8d0280ae-8ea3-4ae1-b46c-f0fc0b293066",
"name": "brand.name",
"picture": "brand.picture"
},
"links": {
"gc:market:incentive": {
"rel": "gc:market:incentive",
"href": "/rest/account/market/incentives/cd646745-5834-4244-9126-fa631c32693c2"
}
}
}]
}

3
json-path/src/main/java/com/jayway/jsonpath/PathUtil.java

@ -32,7 +32,8 @@ public class PathUtil {
* @return true if path is definite (points to single item) * @return true if path is definite (points to single item)
*/ */
public static boolean isPathDefinite(String jsonPath) { public static boolean isPathDefinite(String jsonPath) {
return !jsonPath.replaceAll("\"[^\"\\\\\\n\r]*\"", "").matches(".*(\\.\\.|\\*|\\[[\\\\/]|\\?|,|:|>|\\(|<|=|\\+).*"); //return !jsonPath.replaceAll("\"[^\"\\\\\\n\r]*\"", "").matches(".*(\\.\\.|\\*|\\[[\\\\/]|\\?|,|:|>|\\(|<|=|\\+).*");
return !jsonPath.replaceAll("\"[^\"\\\\\\n\r]*\"", "").matches(".*(\\.\\.|\\*|\\[[\\\\/]|\\?|,|:\\s?\\]|\\[\\s?:|>|\\(|<|=|\\+).*");
} }
/** /**

10
json-path/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterFactory.java

@ -10,8 +10,8 @@ import java.util.regex.Pattern;
public class JsonPathFilterFactory { public class JsonPathFilterFactory {
private final static Pattern ROOT_FILTER_PATTERN = Pattern.compile("\\$"); private final static Pattern ROOT_FILTER_PATTERN = Pattern.compile("\\$");
private final static Pattern PROPERTY_FILTER_PATTERN = Pattern.compile("(\\w+)|\\['(\\w+)'\\]"); //private final static Pattern PROPERTY_FILTER_PATTERN = Pattern.compile("(\\w+)|\\['(\\w+)'\\]");
//private final static Pattern PROPERTY_FILTER_PATTERN = Pattern.compile("\\w+"); private final static Pattern PROPERTY_FILTER_PATTERN = Pattern.compile("(.*)|\\['(.*?)'\\]");
private final static Pattern WILDCARD_PROPERTY_FILTER_PATTERN = Pattern.compile("\\*"); private final static Pattern WILDCARD_PROPERTY_FILTER_PATTERN = Pattern.compile("\\*");
private final static Pattern LIST_FILTER_PATTERN = Pattern.compile("\\[.*?\\]"); private final static Pattern LIST_FILTER_PATTERN = Pattern.compile("\\[.*?\\]");
private final static Pattern TRAVERSE_FILTER_PATTERN = Pattern.compile("\\.\\."); private final static Pattern TRAVERSE_FILTER_PATTERN = Pattern.compile("\\.\\.");
@ -26,15 +26,15 @@ public class JsonPathFilterFactory {
if(ROOT_FILTER_PATTERN.matcher(pathFragment).matches()){ if(ROOT_FILTER_PATTERN.matcher(pathFragment).matches()){
return ROOT_FILTER; return ROOT_FILTER;
} }
else if(PROPERTY_FILTER_PATTERN.matcher(pathFragment).matches() || WILDCARD_PROPERTY_FILTER_PATTERN.matcher(pathFragment).matches() ){
return new PropertyFilter(pathFragment);
}
else if(LIST_FILTER_PATTERN.matcher(pathFragment).matches()){ else if(LIST_FILTER_PATTERN.matcher(pathFragment).matches()){
return new ListFilter(pathFragment); return new ListFilter(pathFragment);
} }
else if(TRAVERSE_FILTER_PATTERN.matcher(pathFragment).matches()){ else if(TRAVERSE_FILTER_PATTERN.matcher(pathFragment).matches()){
return TRAVERSE_FILTER; return TRAVERSE_FILTER;
} }
else if(PROPERTY_FILTER_PATTERN.matcher(pathFragment).matches() || WILDCARD_PROPERTY_FILTER_PATTERN.matcher(pathFragment).matches() ){
return new PropertyFilter(pathFragment);
}
return null; return null;
} }

14
json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java

@ -1,6 +1,5 @@
package com.jayway.jsonpath; package com.jayway.jsonpath;
import org.apache.commons.lang.StringUtils;
import org.junit.Test; import org.junit.Test;
import java.util.List; import java.util.List;
@ -46,11 +45,19 @@ public class JsonPathTest {
" ],\n" + " ],\n" +
" \"bicycle\": {\n" + " \"bicycle\": {\n" +
" \"color\": \"red\",\n" + " \"color\": \"red\",\n" +
" \"price\": 19.95\n" + " \"price\": 19.95,\n" +
" \"foo:bar\": \"fooBar\"\n" +
" }\n" + " }\n" +
" }\n" + " }\n" +
"}"; "}";
@Test
public void read_path_with_colon() throws Exception {
assertEquals(JsonPath.readOne(DOCUMENT, "$.store.bicycle.foo:bar"), "fooBar");
assertEquals(JsonPath.readOne(DOCUMENT, "$.['store'].['bicycle'].['foo:bar']"), "fooBar");
}
@Test @Test
public void read_document_from_root() throws Exception { public void read_document_from_root() throws Exception {
@ -165,11 +172,12 @@ public class JsonPathTest {
assertTrue(res.isEmpty()); assertTrue(res.isEmpty());
} }
/*
@Test(expected = InvalidPathException.class) @Test(expected = InvalidPathException.class)
public void invalid_space_path_throws_exception() throws Exception { public void invalid_space_path_throws_exception() throws Exception {
JsonPath.read(DOCUMENT, "space is not good"); JsonPath.read(DOCUMENT, "space is not good");
} }
*/
@Test(expected = InvalidPathException.class) @Test(expected = InvalidPathException.class)
public void invalid_new_path_throws_exception() throws Exception { public void invalid_new_path_throws_exception() throws Exception {

8
json-path/src/test/java/com/jayway/jsonpath/PathUtilTest.java

@ -3,6 +3,7 @@ package com.jayway.jsonpath;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/** /**
* Created by IntelliJ IDEA. * Created by IntelliJ IDEA.
@ -18,5 +19,12 @@ public class PathUtilTest {
assertFalse(PathUtil.isPathDefinite("$..book[0]")); assertFalse(PathUtil.isPathDefinite("$..book[0]"));
} }
@Test
public void is_definite() throws Exception {
assertTrue(PathUtil.isPathDefinite("$.definite.this.is"));
assertTrue(PathUtil.isPathDefinite("$.definite:this.is"));
assertTrue(PathUtil.isPathDefinite("rows[0].id"));
}
} }

2
json-path/src/test/java/com/jayway/jsonpath/SplitPathFragmentsTest.java

@ -60,6 +60,8 @@ public class SplitPathFragmentsTest {
assertThat(PathUtil.splitPath("$.[0][1].author"), hasItems("$", "[0]", "[1]", "author")); assertThat(PathUtil.splitPath("$.[0][1].author"), hasItems("$", "[0]", "[1]", "author"));
assertThat(PathUtil.splitPath("$.[0].[1].author"), hasItems("$", "[0]", "[1]", "author")); assertThat(PathUtil.splitPath("$.[0].[1].author"), hasItems("$", "[0]", "[1]", "author"));
assertThat(PathUtil.splitPath("$.foo:bar.author"), hasItems("$", "foo:bar", "author"));
} }

Loading…
Cancel
Save