Browse Source
tests, fixes, new feature and tests for some discovered but not yet fixed issuespull/148/head
kallestenflo
9 years ago
15 changed files with 557 additions and 45 deletions
@ -0,0 +1,118 @@ |
|||||||
|
package com.jayway.jsonpath; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
import static com.jayway.jsonpath.JsonPath.using; |
||||||
|
import static com.jayway.jsonpath.TestUtils.assertEvaluationThrows; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* Deep scan is indefinite, so certain "illegal" actions become a no-op instead of a path evaluation exception. |
||||||
|
*/ |
||||||
|
public class DeepScanTest extends BaseTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void when_deep_scanning_non_array_subscription_is_ignored() { |
||||||
|
Object result = JsonPath.parse("{\"x\": [0,1,[0,1,2,3,null],null]}").read("$..[2][3]"); |
||||||
|
assertThat(result).asList().containsOnly(3); |
||||||
|
result = JsonPath.parse("{\"x\": [0,1,[0,1,2,3,null],null], \"y\": [0,1,2]}").read("$..[2][3]"); |
||||||
|
assertThat(result).asList().containsOnly(3); |
||||||
|
|
||||||
|
result = JsonPath.parse("{\"x\": [0,1,[0,1,2],null], \"y\": [0,1,2]}").read("$..[2][3]"); |
||||||
|
assertThat(result).asList().isEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void when_deep_scanning_null_subscription_is_ignored() { |
||||||
|
Object result = JsonPath.parse("{\"x\": [null,null,[0,1,2,3,null],null]}").read("$..[2][3]"); |
||||||
|
assertThat(result).asList().containsOnly(3); |
||||||
|
result = JsonPath.parse("{\"x\": [null,null,[0,1,2,3,null],null], \"y\": [0,1,null]}").read("$..[2][3]"); |
||||||
|
assertThat(result).asList().containsOnly(3); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void when_deep_scanning_array_index_oob_is_ignored() { |
||||||
|
Object result = JsonPath.parse("{\"x\": [0,1,[0,1,2,3,10],null]}").read("$..[4]"); |
||||||
|
assertThat(result).asList().containsOnly(10); |
||||||
|
|
||||||
|
result = JsonPath.parse("{\"x\": [null,null,[0,1,2,3]], \"y\": [null,null,[0,1]]}").read("$..[2][3]"); |
||||||
|
assertThat(result).asList().containsOnly(3); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void definite_upstream_illegal_array_access_throws() { |
||||||
|
assertEvaluationThrows("{\"foo\": {\"bar\": null}}", "$.foo.bar.[5]", PathNotFoundException.class); |
||||||
|
assertEvaluationThrows("{\"foo\": {\"bar\": null}}", "$.foo.bar.[5, 10]", PathNotFoundException.class); |
||||||
|
|
||||||
|
assertEvaluationThrows("{\"foo\": {\"bar\": 4}}", "$.foo.bar.[5]", InvalidPathException.class); |
||||||
|
assertEvaluationThrows("{\"foo\": {\"bar\": 4}}", "$.foo.bar.[5, 10]", InvalidPathException.class); |
||||||
|
|
||||||
|
assertEvaluationThrows("{\"foo\": {\"bar\": []}}", "$.foo.bar.[5]", PathNotFoundException.class); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void when_deep_scanning_illegal_property_access_is_ignored() { |
||||||
|
Object result = JsonPath.parse("{\"x\": {\"foo\": {\"bar\": 4}}, \"y\": {\"foo\": 1}}").read("$..foo"); |
||||||
|
assertThat(result).asList().hasSize(2); |
||||||
|
|
||||||
|
result = JsonPath.parse("{\"x\": {\"foo\": {\"bar\": 4}}, \"y\": {\"foo\": 1}}").read("$..foo.bar"); |
||||||
|
assertThat(result).asList().containsOnly(4); |
||||||
|
result = JsonPath.parse("{\"x\": {\"foo\": {\"bar\": 4}}, \"y\": {\"foo\": 1}}").read("$..[*].foo.bar"); |
||||||
|
assertThat(result).asList().containsOnly(4); |
||||||
|
result = JsonPath.parse("{\"x\": {\"foo\": {\"baz\": 4}}, \"y\": {\"foo\": 1}}").read("$..[*].foo.bar"); |
||||||
|
assertThat(result).asList().isEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void when_deep_scanning_illegal_predicate_is_ignored() { |
||||||
|
Object result = JsonPath.parse("{\"x\": {\"foo\": {\"bar\": 4}}, \"y\": {\"foo\": 1}}").read( |
||||||
|
"$..foo[?(@.bar)].bar"); |
||||||
|
assertThat(result).asList().containsOnly(4); |
||||||
|
|
||||||
|
result = JsonPath.parse("{\"x\": {\"foo\": {\"bar\": 4}}, \"y\": {\"foo\": 1}}").read( |
||||||
|
"$..[*]foo[?(@.bar)].bar"); |
||||||
|
assertThat(result).asList().containsOnly(4); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void when_deep_scanning_require_properties_still_counts() { |
||||||
|
final Configuration conf = Configuration.defaultConfiguration().addOptions(Option.REQUIRE_PROPERTIES); |
||||||
|
|
||||||
|
Object result = JsonPath.parse("[{\"x\": {\"foo\": {\"x\": 4}, \"x\": null}, \"y\": {\"x\": 1}}, {\"x\": []}]").read( |
||||||
|
"$..x"); |
||||||
|
assertThat(result).asList().hasSize(5); |
||||||
|
|
||||||
|
// foo.bar must be found in every object node after deep scan (which is impossible)
|
||||||
|
assertEvaluationThrows("{\"foo\": {\"bar\": 4}}", "$..foo.bar", PathNotFoundException.class, conf); |
||||||
|
|
||||||
|
assertEvaluationThrows("{\"foo\": {\"bar\": 4}, \"baz\": 2}", "$..['foo', 'baz']", PathNotFoundException.class, conf); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void when_deep_scanning_leaf_multi_props_work() { |
||||||
|
Object result = JsonPath.parse("[{\"a\": \"a-val\", \"b\": \"b-val\", \"c\": \"c-val\"}, [1, 5], {\"a\": \"a-val\"}]").read( |
||||||
|
"$..['a', 'c']"); |
||||||
|
// This is current deep scan semantics: only objects containing all properties specified in multiprops token are
|
||||||
|
// considered.
|
||||||
|
assertThat(result).asList().hasSize(1); |
||||||
|
result = ((List)result).get(0); |
||||||
|
|
||||||
|
assertThat(result).isInstanceOf(Map.class); |
||||||
|
assertThat((Map)result).hasSize(2).containsEntry("a", "a-val").containsEntry("c", "c-val"); |
||||||
|
|
||||||
|
// But this semantics changes when DEFAULT_PATH_LEAF_TO_NULL comes into play.
|
||||||
|
Configuration conf = Configuration.defaultConfiguration().addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL); |
||||||
|
result = using(conf).parse("[{\"a\": \"a-val\", \"b\": \"b-val\", \"c\": \"c-val\"}, [1, 5], {\"a\": \"a-val\"}]").read( |
||||||
|
"$..['a', 'c']"); |
||||||
|
// todo: deep equality test, but not tied to any json provider
|
||||||
|
assertThat(result).asList().hasSize(2); |
||||||
|
for (final Object node : (List)result) { |
||||||
|
assertThat(node).isInstanceOf(Map.class); |
||||||
|
assertThat((Map)node).hasSize(2).containsEntry("a", "a-val"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
package com.jayway.jsonpath; |
||||||
|
|
||||||
|
import static com.jayway.jsonpath.JsonPath.using; |
||||||
|
import static org.assertj.core.api.Assertions.fail; |
||||||
|
|
||||||
|
public final class TestUtils { |
||||||
|
private TestUtils() {} |
||||||
|
|
||||||
|
public static void assertEvaluationThrows(final String json, final String path, |
||||||
|
Class<? extends JsonPathException> expected) { |
||||||
|
assertEvaluationThrows(json, path, expected, Configuration.defaultConfiguration()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Shortcut for expected exception testing during path evaluation. |
||||||
|
* |
||||||
|
* @param conf conf to use during evaluation |
||||||
|
* @param json json to parse |
||||||
|
* @param path jsonpath do evaluate |
||||||
|
* @param expected expected exception class (reference comparison, not an instanceof) |
||||||
|
*/ |
||||||
|
public static void assertEvaluationThrows(final String json, final String path, |
||||||
|
Class<? extends JsonPathException> expected, final Configuration conf) { |
||||||
|
try { |
||||||
|
using(conf).parse(json).read(path); |
||||||
|
fail("Should throw " + expected.getName()); |
||||||
|
} catch (JsonPathException exc) { |
||||||
|
if (exc.getClass() != expected) |
||||||
|
throw exc; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
package com.jayway.jsonpath.internal.token; |
||||||
|
|
||||||
|
import com.jayway.jsonpath.BaseTest; |
||||||
|
import com.jayway.jsonpath.internal.token.PathToken; |
||||||
|
import com.jayway.jsonpath.internal.token.PropertyPathToken; |
||||||
|
import com.jayway.jsonpath.internal.token.ScanPathToken; |
||||||
|
import com.jayway.jsonpath.internal.token.WildcardPathToken; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
import java.util.Arrays; |
||||||
|
|
||||||
|
public class PathTokenTest extends BaseTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void is_upstream_definite_in_simple_case() { |
||||||
|
assertThat(makePathReturningTail(makePPT("foo")).isUpstreamDefinite()).isTrue(); |
||||||
|
|
||||||
|
assertThat(makePathReturningTail(makePPT("foo"), makePPT("bar")).isUpstreamDefinite()).isTrue(); |
||||||
|
|
||||||
|
assertThat(makePathReturningTail(makePPT("foo", "foo2"), makePPT("bar")).isUpstreamDefinite()).isFalse(); |
||||||
|
|
||||||
|
assertThat(makePathReturningTail(new WildcardPathToken(), makePPT("bar")).isUpstreamDefinite()).isFalse(); |
||||||
|
|
||||||
|
assertThat(makePathReturningTail(new ScanPathToken(), makePPT("bar")).isUpstreamDefinite()).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void is_upstream_definite_in_complex_case() { |
||||||
|
assertThat(makePathReturningTail(makePPT("foo"), makePPT("bar"), makePPT("baz")).isUpstreamDefinite()).isTrue(); |
||||||
|
|
||||||
|
assertThat(makePathReturningTail(makePPT("foo"), new WildcardPathToken()).isUpstreamDefinite()).isTrue(); |
||||||
|
|
||||||
|
assertThat(makePathReturningTail(new WildcardPathToken(), makePPT("bar"), makePPT("baz")).isUpstreamDefinite()).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private PathToken makePPT(final String ... properties) { |
||||||
|
return new PropertyPathToken(Arrays.asList(properties)); |
||||||
|
} |
||||||
|
|
||||||
|
private PathToken makePathReturningTail(final PathToken ... tokens) { |
||||||
|
PathToken last = null; |
||||||
|
for (final PathToken token : tokens) { |
||||||
|
if (last != null) { |
||||||
|
last.appendTailToken(token); |
||||||
|
} |
||||||
|
last = token; |
||||||
|
} |
||||||
|
return last; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue