Skip to content

Commit

Permalink
contains only deep implemented #2093
Browse files Browse the repository at this point in the history
  • Loading branch information
ptrthomas committed Nov 1, 2022
1 parent 9ebe9d6 commit b33fa80
Show file tree
Hide file tree
Showing 6 changed files with 489 additions and 448 deletions.
5 changes: 5 additions & 0 deletions karate-core/src/main/java/com/intuit/karate/Match.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public static enum Type {
CONTAINS_ONLY,
CONTAINS_ANY,
CONTAINS_DEEP,
CONTAINS_ONLY_DEEP,
CONTAINS_ANY_DEEP,
EACH_EQUALS,
EACH_NOT_EQUALS,
Expand Down Expand Up @@ -391,6 +392,10 @@ public Result containsDeep(Object expected) {
public Result containsOnly(Object expected) {
return is(Type.CONTAINS_ONLY, expected);
}

public Result containsOnlyDeep(Object expected) {
return is(Type.CONTAINS_ONLY_DEEP, expected);
}

public Result containsAny(Object expected) {
return is(Type.CONTAINS_ANY, expected);
Expand Down
25 changes: 19 additions & 6 deletions karate-core/src/main/java/com/intuit/karate/MatchOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ boolean execute() {
case CONTAINS_ANY:
case CONTAINS_ONLY:
case CONTAINS_DEEP:
case CONTAINS_ONLY_DEEP:
case CONTAINS_ANY_DEEP:
// don't tamper with strings on the RHS that represent arrays or objects
if (!expected.isList() && !(expected.isString() && expected.isArrayObjectOrReference())) {
Expand Down Expand Up @@ -239,6 +240,7 @@ boolean execute() {
case CONTAINS_ANY:
case CONTAINS_ONLY:
case CONTAINS_DEEP:
case CONTAINS_ONLY_DEEP:
case CONTAINS_ANY_DEEP:
return actualContainsExpected() ? pass() : fail("actual does not contain expected");
case NOT_CONTAINS:
Expand All @@ -262,10 +264,16 @@ private boolean macroEqualsExpected(String expStr) {
int startPos = matchTypeToStartPos(nestedType);
macro = macro.substring(startPos);
if (actual.isList()) { // special case, look for partial maps within list
if (nestedType == Match.Type.CONTAINS) {
nestedType = Match.Type.CONTAINS_DEEP;
} else if (nestedType == Match.Type.CONTAINS_ANY) {
nestedType = Match.Type.CONTAINS_ANY_DEEP;
switch (nestedType) {
case CONTAINS:
nestedType = Match.Type.CONTAINS_DEEP;
break;
case CONTAINS_ONLY:
nestedType = Match.Type.CONTAINS_ONLY_DEEP;
break;
case CONTAINS_ANY:
nestedType = Match.Type.CONTAINS_ANY_DEEP;
break;
}
}
context.JS.put("$", context.root.actual.getValue());
Expand Down Expand Up @@ -457,7 +465,7 @@ private boolean actualEqualsExpected() {
}

private boolean matchMapValues(Map<String, Object> actMap, Map<String, Object> expMap) { // combined logic for equals and contains
if (actMap.size() > expMap.size() && (type == Match.Type.EQUALS || type == Match.Type.CONTAINS_ONLY)) {
if (actMap.size() > expMap.size() && (type == Match.Type.EQUALS || type == Match.Type.CONTAINS_ONLY || type == Match.Type.CONTAINS_ONLY_DEEP)) {
int sizeDiff = actMap.size() - expMap.size();
Map<String, Object> diffMap = new LinkedHashMap(actMap);
for (String key : expMap.keySet()) {
Expand Down Expand Up @@ -494,6 +502,8 @@ private boolean matchMapValues(Map<String, Object> actMap, Map<String, Object> e
Match.Type childMatchType;
if (type == Match.Type.CONTAINS_DEEP) {
childMatchType = childActValue.isMapOrListOrXml() ? Match.Type.CONTAINS_DEEP : Match.Type.EQUALS;
} else if (type == Match.Type.CONTAINS_ONLY_DEEP) {
childMatchType = childActValue.isMapOrListOrXml() ? Match.Type.CONTAINS_ONLY_DEEP : Match.Type.EQUALS;
} else {
childMatchType = Match.Type.EQUALS;
}
Expand Down Expand Up @@ -550,7 +560,7 @@ private boolean actualContainsExpected() {
if (type != Match.Type.CONTAINS_ANY && type != Match.Type.CONTAINS_ANY_DEEP && expListCount > actListCount) {
return fail("actual array length is less than expected - " + actListCount + ":" + expListCount);
}
if (type == Match.Type.CONTAINS_ONLY && expListCount != actListCount) {
if ((type == Match.Type.CONTAINS_ONLY || type == Match.Type.CONTAINS_ONLY_DEEP) && expListCount != actListCount) {
return fail("actual array length is not equal to expected - " + actListCount + ":" + expListCount);
}
for (Object exp : expList) { // for each item in the expected list
Expand All @@ -563,6 +573,9 @@ private boolean actualContainsExpected() {
case CONTAINS_DEEP:
childMatchType = actListValue.isMapOrListOrXml() ? Match.Type.CONTAINS_DEEP : Match.Type.EQUALS;
break;
case CONTAINS_ONLY_DEEP:
childMatchType = actListValue.isMapOrListOrXml() ? Match.Type.CONTAINS_ONLY_DEEP : Match.Type.EQUALS;
break;
case CONTAINS_ANY_DEEP:
childMatchType = actListValue.isMapOrListOrXml() ? Match.Type.CONTAINS_ANY : Match.Type.EQUALS;
break;
Expand Down
9 changes: 7 additions & 2 deletions karate-core/src/main/java/com/intuit/karate/MatchStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ public MatchStep(String raw) {
not = raw.charAt(lhsEndPos + 1) == '!';
searchPos = lhsEndPos + (not ? 10 : 9);
String anyOrOnlyOrDeep = raw.substring(searchPos).trim();
if (anyOrOnlyOrDeep.startsWith("only")) {
if (anyOrOnlyOrDeep.startsWith("only deep")) {
int onlyPos = raw.indexOf(" only deep", searchPos);
only = true;
deep = true;
searchPos = onlyPos + 10;
} else if (anyOrOnlyOrDeep.startsWith("only")) {
int onlyPos = raw.indexOf(" only", searchPos);
only = true;
searchPos = onlyPos + 5;
Expand Down Expand Up @@ -140,7 +145,7 @@ private static Match.Type getType(boolean each, boolean not, boolean contains, b
}
if (contains) {
if (only) {
return Match.Type.CONTAINS_ONLY;
return deep ? Match.Type.CONTAINS_ONLY_DEEP : Match.Type.CONTAINS_ONLY;
}
if (any) {
return Match.Type.CONTAINS_ANY;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ void testMatchStep() {
test("aXml //active == '#regex (false|true)'", EQUALS, "aXml", "//active", "'#regex (false|true)'");
test("hello ==", EQUALS, "hello", null, null);
test("hello world == foo", EQUALS, "hello", "world", "foo");
test("hello world contains only deep foo", CONTAINS_ONLY_DEEP, "hello", "world", "foo");
test("each hello world == foo", EACH_EQUALS, "hello", "world", "foo");
test("{\"a\":1,\"b\":2} == '#object'", EQUALS, "({\"a\":1,\"b\":2})", null, "'#object'");
test("hello.foo(bar) != blah", NOT_EQUALS, "hello.foo(bar)", null, "blah");
Expand Down
Loading

0 comments on commit b33fa80

Please sign in to comment.