diff --git a/consumer/src/main/java/au/com/dius/pact/consumer/dsl/PactDslJsonBody.java b/consumer/src/main/java/au/com/dius/pact/consumer/dsl/PactDslJsonBody.java index 34b295bc83..37e432c582 100755 --- a/consumer/src/main/java/au/com/dius/pact/consumer/dsl/PactDslJsonBody.java +++ b/consumer/src/main/java/au/com/dius/pact/consumer/dsl/PactDslJsonBody.java @@ -24,24 +24,23 @@ import au.com.dius.pact.core.model.matchingrules.ValuesMatcher; import au.com.dius.pact.core.support.expressions.DataType; import com.mifmif.common.regex.Generex; - -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.TimeZone; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateFormatUtils; import org.apache.commons.lang3.time.FastDateFormat; import org.json.JSONObject; import java.math.BigDecimal; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.Date; +import java.util.TimeZone; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static au.com.dius.pact.core.model.PathExpressionsKt.PATH_SPECIAL_CHARS; +import static au.com.dius.pact.consumer.dsl.Dsl.matcherKey; /** * DSL to define a JSON Object @@ -164,7 +163,7 @@ public PactDslJsonBody booleanValue(String name, Boolean value) { * @param name attribute name */ public PactDslJsonBody stringType(String name) { - generators.addGenerator(Category.BODY, matcherKey(name), new RandomStringGenerator(20)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new RandomStringGenerator(20)); return stringType(name, "string"); } @@ -186,24 +185,16 @@ public PactDslJsonBody stringType(String... names) { */ public PactDslJsonBody stringType(String name, String example) { body.put(name, example); - matchers.addRule(matcherKey(name), TypeMatcher.INSTANCE); + matchers.addRule(matcherKey(name, rootPath), TypeMatcher.INSTANCE); return this; } - private String matcherKey(String name) { - String key = rootPath + name; - if (StringUtils.containsAny(name, PATH_SPECIAL_CHARS)) { - key = StringUtils.stripEnd(rootPath, ".") + "['" + name + "']"; - } - return key; - } - /** * Attribute that can be any number * @param name attribute name */ public PactDslJsonBody numberType(String name) { - generators.addGenerator(Category.BODY, matcherKey(name), new RandomIntGenerator(0, Integer.MAX_VALUE)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new RandomIntGenerator(0, Integer.MAX_VALUE)); return numberType(name, 100); } @@ -225,7 +216,7 @@ public PactDslJsonBody numberType(String... names) { */ public PactDslJsonBody numberType(String name, Number number) { body.put(name, number); - matchers.addRule(matcherKey(name), new NumberTypeMatcher(NumberTypeMatcher.NumberType.NUMBER)); + matchers.addRule(matcherKey(name, rootPath), new NumberTypeMatcher(NumberTypeMatcher.NumberType.NUMBER)); return this; } @@ -234,7 +225,7 @@ public PactDslJsonBody numberType(String name, Number number) { * @param name attribute name */ public PactDslJsonBody integerType(String name) { - generators.addGenerator(Category.BODY, matcherKey(name), new RandomIntGenerator(0, Integer.MAX_VALUE)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new RandomIntGenerator(0, Integer.MAX_VALUE)); return integerType(name, 100); } @@ -256,7 +247,7 @@ public PactDslJsonBody integerType(String... names) { */ public PactDslJsonBody integerType(String name, Long number) { body.put(name, number); - matchers.addRule(matcherKey(name), new NumberTypeMatcher(NumberTypeMatcher.NumberType.INTEGER)); + matchers.addRule(matcherKey(name, rootPath), new NumberTypeMatcher(NumberTypeMatcher.NumberType.INTEGER)); return this; } @@ -267,7 +258,7 @@ public PactDslJsonBody integerType(String name, Long number) { */ public PactDslJsonBody integerType(String name, Integer number) { body.put(name, number); - matchers.addRule(matcherKey(name), new NumberTypeMatcher(NumberTypeMatcher.NumberType.INTEGER)); + matchers.addRule(matcherKey(name, rootPath), new NumberTypeMatcher(NumberTypeMatcher.NumberType.INTEGER)); return this; } @@ -276,7 +267,7 @@ public PactDslJsonBody integerType(String name, Integer number) { * @param name attribute name */ public PactDslJsonBody decimalType(String name) { - generators.addGenerator(Category.BODY, matcherKey(name), new RandomDecimalGenerator(10)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new RandomDecimalGenerator(10)); return decimalType(name, 100.0); } @@ -298,7 +289,7 @@ public PactDslJsonBody decimalType(String... names) { */ public PactDslJsonBody decimalType(String name, BigDecimal number) { body.put(name, number); - matchers.addRule(matcherKey(name), new NumberTypeMatcher(NumberTypeMatcher.NumberType.DECIMAL)); + matchers.addRule(matcherKey(name, rootPath), new NumberTypeMatcher(NumberTypeMatcher.NumberType.DECIMAL)); return this; } @@ -309,7 +300,7 @@ public PactDslJsonBody decimalType(String name, BigDecimal number) { */ public PactDslJsonBody decimalType(String name, Double number) { body.put(name, number); - matchers.addRule(matcherKey(name), new NumberTypeMatcher(NumberTypeMatcher.NumberType.DECIMAL)); + matchers.addRule(matcherKey(name, rootPath), new NumberTypeMatcher(NumberTypeMatcher.NumberType.DECIMAL)); return this; } @@ -339,7 +330,7 @@ public PactDslJsonBody booleanType(String... names) { */ public PactDslJsonBody booleanType(String name, Boolean example) { body.put(name, example); - matchers.addRule(matcherKey(name), TypeMatcher.INSTANCE); + matchers.addRule(matcherKey(name, rootPath), TypeMatcher.INSTANCE); return this; } @@ -355,7 +346,7 @@ public PactDslJsonBody stringMatcher(String name, String regex, String value) { regex + "\""); } body.put(name, value); - matchers.addRule(matcherKey(name), regexp(regex)); + matchers.addRule(matcherKey(name, rootPath), regexp(regex)); return this; } @@ -365,7 +356,7 @@ public PactDslJsonBody stringMatcher(String name, String regex, String value) { * @param regex regular expression */ public PactDslJsonBody stringMatcher(String name, String regex) { - generators.addGenerator(Category.BODY, matcherKey(name), new RegexGenerator(regex)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new RegexGenerator(regex)); stringMatcher(name, regex, new Generex(regex).random()); return this; } @@ -458,9 +449,9 @@ public PactDslJsonBody timestamp(String name, String format, Instant example, Ti */ public PactDslJsonBody datetime(String name) { String pattern = DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(); - generators.addGenerator(Category.BODY, matcherKey(name), new DateTimeGenerator(pattern, null)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new DateTimeGenerator(pattern, null)); body.put(name, DateFormatUtils.ISO_DATETIME_FORMAT.format(new Date(DATE_2000))); - matchers.addRule(matcherKey(name), matchTimestamp(pattern)); + matchers.addRule(matcherKey(name, rootPath), matchTimestamp(pattern)); return this; } @@ -470,10 +461,10 @@ public PactDslJsonBody datetime(String name) { * @param format datetime format */ public PactDslJsonBody datetime(String name, String format) { - generators.addGenerator(Category.BODY, matcherKey(name), new DateTimeGenerator(format, null)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new DateTimeGenerator(format, null)); DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format).withZone(ZoneId.systemDefault()); body.put(name, formatter.format(new Date(DATE_2000).toInstant())); - matchers.addRule(matcherKey(name), matchTimestamp(format)); + matchers.addRule(matcherKey(name, rootPath), matchTimestamp(format)); return this; } @@ -497,7 +488,7 @@ public PactDslJsonBody datetime(String name, String format, Date example) { public PactDslJsonBody datetime(String name, String format, Date example, TimeZone timeZone) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format).withZone(timeZone.toZoneId()); body.put(name, formatter.format(example.toInstant())); - matchers.addRule(matcherKey(name), matchTimestamp(format)); + matchers.addRule(matcherKey(name, rootPath), matchTimestamp(format)); return this; } @@ -521,7 +512,7 @@ public PactDslJsonBody datetime(String name, String format, Instant example) { public PactDslJsonBody datetime(String name, String format, Instant example, TimeZone timeZone) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format).withZone(timeZone.toZoneId()); body.put(name, formatter.format(example)); - matchers.addRule(matcherKey(name), matchTimestamp(format)); + matchers.addRule(matcherKey(name, rootPath), matchTimestamp(format)); return this; } @@ -538,9 +529,9 @@ public PactDslJsonBody date() { */ public PactDslJsonBody date(String name) { String pattern = DateFormatUtils.ISO_DATE_FORMAT.getPattern(); - generators.addGenerator(Category.BODY, matcherKey(name), new DateGenerator(pattern, null)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new DateGenerator(pattern, null)); body.put(name, DateFormatUtils.ISO_DATE_FORMAT.format(new Date(DATE_2000))); - matchers.addRule(matcherKey(name), matchDate(pattern)); + matchers.addRule(matcherKey(name, rootPath), matchDate(pattern)); return this; } @@ -550,10 +541,10 @@ public PactDslJsonBody date(String name) { * @param format date format to match */ public PactDslJsonBody date(String name, String format) { - generators.addGenerator(Category.BODY, matcherKey(name), new DateGenerator(format, null)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new DateGenerator(format, null)); FastDateFormat instance = FastDateFormat.getInstance(format); body.put(name, instance.format(new Date(DATE_2000))); - matchers.addRule(matcherKey(name), matchDate(format)); + matchers.addRule(matcherKey(name, rootPath), matchDate(format)); return this; } @@ -577,7 +568,7 @@ public PactDslJsonBody date(String name, String format, Date example) { public PactDslJsonBody date(String name, String format, Date example, TimeZone timeZone) { FastDateFormat instance = FastDateFormat.getInstance(format, timeZone); body.put(name, instance.format(example)); - matchers.addRule(matcherKey(name), matchDate(format)); + matchers.addRule(matcherKey(name, rootPath), matchDate(format)); return this; } @@ -594,9 +585,9 @@ public PactDslJsonBody time() { */ public PactDslJsonBody time(String name) { String pattern = DateFormatUtils.ISO_TIME_FORMAT.getPattern(); - generators.addGenerator(Category.BODY, matcherKey(name), new TimeGenerator(pattern, null)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new TimeGenerator(pattern, null)); body.put(name, DateFormatUtils.ISO_TIME_FORMAT.format(new Date(DATE_2000))); - matchers.addRule(matcherKey(name), matchTime(pattern)); + matchers.addRule(matcherKey(name, rootPath), matchTime(pattern)); return this; } @@ -606,10 +597,10 @@ public PactDslJsonBody time(String name) { * @param format time format to match */ public PactDslJsonBody time(String name, String format) { - generators.addGenerator(Category.BODY, matcherKey(name), new TimeGenerator(format, null)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new TimeGenerator(format, null)); FastDateFormat instance = FastDateFormat.getInstance(format); body.put(name, instance.format(new Date(DATE_2000))); - matchers.addRule(matcherKey(name), matchTime(format)); + matchers.addRule(matcherKey(name, rootPath), matchTime(format)); return this; } @@ -633,7 +624,7 @@ public PactDslJsonBody time(String name, String format, Date example) { public PactDslJsonBody time(String name, String format, Date example, TimeZone timeZone) { FastDateFormat instance = FastDateFormat.getInstance(format, timeZone); body.put(name, instance.format(example)); - matchers.addRule(matcherKey(name), matchTime(format)); + matchers.addRule(matcherKey(name, rootPath), matchTime(format)); return this; } @@ -643,7 +634,7 @@ public PactDslJsonBody time(String name, String format, Date example, TimeZone t */ public PactDslJsonBody ipAddress(String name) { body.put(name, "127.0.0.1"); - matchers.addRule(matcherKey(name), regexp("(\\d{1,3}\\.)+\\d{1,3}")); + matchers.addRule(matcherKey(name, rootPath), regexp("(\\d{1,3}\\.)+\\d{1,3}")); return this; } @@ -652,11 +643,7 @@ public PactDslJsonBody ipAddress(String name) { * @param name field name */ public PactDslJsonBody object(String name) { - String base = rootPath + name; - if (StringUtils.containsAny(name, PATH_SPECIAL_CHARS)) { - base = StringUtils.substringBeforeLast(rootPath, ".") + "['" + name + "']"; - } - return new PactDslJsonBody(base + ".", "", this); + return new PactDslJsonBody(matcherKey(name, rootPath) + ".", "", this); } public PactDslJsonBody object() { @@ -669,10 +656,7 @@ public PactDslJsonBody object() { * @param value DSL Part to set the value as */ public PactDslJsonBody object(String name, DslPart value) { - String base = rootPath + name; - if (StringUtils.containsAny(name, PATH_SPECIAL_CHARS)) { - base = StringUtils.substringBeforeLast(rootPath, ".") + "['" + name + "']"; - } + String base = matcherKey(name, rootPath); if (value instanceof PactDslJsonBody) { PactDslJsonBody object = new PactDslJsonBody(base, "", this, (PactDslJsonBody) value); putObject(object); @@ -721,7 +705,7 @@ public DslPart close() { * @param name field name */ public PactDslJsonArray array(String name) { - return new PactDslJsonArray(matcherKey(name), name, this); + return new PactDslJsonArray(matcherKey(name, rootPath), name, this); } public PactDslJsonArray array() { @@ -762,8 +746,8 @@ public PactDslJsonBody eachLike() { */ @Override public PactDslJsonBody eachLike(String name, int numberExamples) { - matchers.addRule(matcherKey(name), matchMin(0)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), "", this, true); + matchers.addRule(matcherKey(name, rootPath), matchMin(0)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), "", this, true); parent.setNumberExamples(numberExamples); return new PactDslJsonBody(".", ".", parent); } @@ -789,8 +773,8 @@ public PactDslJsonBody eachLike(String name, PactDslJsonRootValue value) { * @param numberExamples number of examples to generate */ public PactDslJsonBody eachLike(String name, PactDslJsonRootValue value, int numberExamples) { - matchers.addRule(matcherKey(name), matchMin(0)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), "", this, true); + matchers.addRule(matcherKey(name, rootPath), matchMin(0)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), "", this, true); parent.setNumberExamples(numberExamples); parent.putObject(value); return (PactDslJsonBody) parent.closeArray(); @@ -823,8 +807,8 @@ public PactDslJsonBody minArrayLike(String name, Integer size, int numberExample throw new IllegalArgumentException(String.format("Number of example %d is less than the minimum size of %d", numberExamples, size)); } - matchers.addRule(matcherKey(name), matchMin(size)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), "", this, true); + matchers.addRule(matcherKey(name, rootPath), matchMin(size)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), "", this, true); parent.setNumberExamples(numberExamples); return new PactDslJsonBody(".", "", parent); } @@ -856,8 +840,8 @@ public PactDslJsonBody minArrayLike(String name, Integer size, PactDslJsonRootVa throw new IllegalArgumentException(String.format("Number of example %d is less than the minimum size of %d", numberExamples, size)); } - matchers.addRule(matcherKey(name), matchMin(size)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), "", this, true); + matchers.addRule(matcherKey(name, rootPath), matchMin(size)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), "", this, true); parent.setNumberExamples(numberExamples); parent.putObject(value); return (PactDslJsonBody) parent.closeArray(); @@ -890,8 +874,8 @@ public PactDslJsonBody maxArrayLike(String name, Integer size, int numberExample throw new IllegalArgumentException(String.format("Number of example %d is more than the maximum size of %d", numberExamples, size)); } - matchers.addRule(matcherKey(name), matchMax(size)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), "", this, true); + matchers.addRule(matcherKey(name, rootPath), matchMax(size)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), "", this, true); parent.setNumberExamples(numberExamples); return new PactDslJsonBody(".", "", parent); } @@ -923,8 +907,8 @@ public PactDslJsonBody maxArrayLike(String name, Integer size, PactDslJsonRootVa throw new IllegalArgumentException(String.format("Number of example %d is more than the maximum size of %d", numberExamples, size)); } - matchers.addRule(matcherKey(name), matchMax(size)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), "", this, true); + matchers.addRule(matcherKey(name, rootPath), matchMax(size)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), "", this, true); parent.setNumberExamples(numberExamples); parent.putObject(value); return (PactDslJsonBody) parent.closeArray(); @@ -942,9 +926,9 @@ public PactDslJsonBody id() { * @param name attribute name */ public PactDslJsonBody id(String name) { - generators.addGenerator(Category.BODY, matcherKey(name), new RandomIntGenerator(0, Integer.MAX_VALUE)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new RandomIntGenerator(0, Integer.MAX_VALUE)); body.put(name, 1234567890L); - matchers.addRule(matcherKey(name), TypeMatcher.INSTANCE); + matchers.addRule(matcherKey(name, rootPath), TypeMatcher.INSTANCE); return this; } @@ -955,7 +939,7 @@ public PactDslJsonBody id(String name) { */ public PactDslJsonBody id(String name, Long id) { body.put(name, id); - matchers.addRule(matcherKey(name), TypeMatcher.INSTANCE); + matchers.addRule(matcherKey(name, rootPath), TypeMatcher.INSTANCE); return this; } @@ -964,7 +948,7 @@ public PactDslJsonBody id(String name, Long id) { * @param name attribute name */ public PactDslJsonBody hexValue(String name) { - generators.addGenerator(Category.BODY, matcherKey(name), new RandomHexadecimalGenerator(10)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new RandomHexadecimalGenerator(10)); return hexValue(name, "1234a"); } @@ -978,7 +962,7 @@ public PactDslJsonBody hexValue(String name, String hexValue) { throw new InvalidMatcherException(EXAMPLE + hexValue + "\" is not a hexadecimal value"); } body.put(name, hexValue); - matchers.addRule(matcherKey(name), regexp("[0-9a-fA-F]+")); + matchers.addRule(matcherKey(name, rootPath), regexp("[0-9a-fA-F]+")); return this; } @@ -987,7 +971,7 @@ public PactDslJsonBody hexValue(String name, String hexValue) { * @param name attribute name */ public PactDslJsonBody uuid(String name) { - generators.addGenerator(Category.BODY, matcherKey(name), UuidGenerator.INSTANCE); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), UuidGenerator.INSTANCE); return uuid(name, "e2490de5-5bd3-43d5-b7c4-526e33f71304"); } @@ -1010,7 +994,7 @@ public PactDslJsonBody uuid(String name, String uuid) { throw new InvalidMatcherException(EXAMPLE + uuid + "\" is not an UUID"); } body.put(name, uuid); - matchers.addRule(matcherKey(name), regexp(UUID_REGEX)); + matchers.addRule(matcherKey(name, rootPath), regexp(UUID_REGEX)); return this; } @@ -1035,8 +1019,8 @@ public PactDslJsonArray eachArrayLike() { @Override public PactDslJsonArray eachArrayLike(String name, int numberExamples) { - matchers.addRule(matcherKey(name), matchMin(0)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), name, this, true); + matchers.addRule(matcherKey(name, rootPath), matchMin(0)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), name, this, true); parent.setNumberExamples(numberExamples); return new PactDslJsonArray("", "", parent); } @@ -1062,8 +1046,8 @@ public PactDslJsonArray eachArrayWithMaxLike(String name, int numberExamples, In throw new IllegalArgumentException(String.format("Number of example %d is more than the maximum size of %d", numberExamples, size)); } - matchers.addRule(matcherKey(name), matchMax(size)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), name, this, true); + matchers.addRule(matcherKey(name, rootPath), matchMax(size)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), name, this, true); parent.setNumberExamples(numberExamples); return new PactDslJsonArray("", "", parent); } @@ -1089,8 +1073,8 @@ public PactDslJsonArray eachArrayWithMinLike(String name, int numberExamples, In throw new IllegalArgumentException(String.format("Number of example %d is less than the minimum size of %d", numberExamples, size)); } - matchers.addRule(matcherKey(name), matchMin(size)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), name, this, true); + matchers.addRule(matcherKey(name, rootPath), matchMin(size)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), name, this, true); parent.setNumberExamples(numberExamples); return new PactDslJsonArray("", "", parent); } @@ -1153,7 +1137,7 @@ public PactDslJsonBody eachKeyLike(String exampleKey, PactDslJsonRootValue value */ public PactDslJsonBody includesStr(String name, String value) { body.put(name, value); - matchers.addRule(matcherKey(name), includesMatcher(value)); + matchers.addRule(matcherKey(name, rootPath), includesMatcher(value)); return this; } @@ -1164,7 +1148,7 @@ public PactDslJsonBody includesStr(String name, String value) { */ public PactDslJsonBody equalTo(String name, Object value) { body.put(name, value); - matchers.addRule(matcherKey(name), EqualsMatcher.INSTANCE); + matchers.addRule(matcherKey(name, rootPath), EqualsMatcher.INSTANCE); return this; } @@ -1180,7 +1164,7 @@ public PactDslJsonBody and(String name, Object value, MatchingRule... rules) { } else { body.put(name, JSONObject.NULL); } - matchers.setRules(matcherKey(name), new MatchingRuleGroup(Arrays.asList(rules), RuleLogic.AND)); + matchers.setRules(matcherKey(name, rootPath), new MatchingRuleGroup(Arrays.asList(rules), RuleLogic.AND)); return this; } @@ -1196,7 +1180,7 @@ public PactDslJsonBody or(String name, Object value, MatchingRule... rules) { } else { body.put(name, JSONObject.NULL); } - matchers.setRules(matcherKey(name), new MatchingRuleGroup(Arrays.asList(rules), RuleLogic.OR)); + matchers.setRules(matcherKey(name, rootPath), new MatchingRuleGroup(Arrays.asList(rules), RuleLogic.OR)); return this; } @@ -1209,7 +1193,7 @@ public PactDslJsonBody or(String name, Object value, MatchingRule... rules) { public PactDslJsonBody matchUrl(String name, String basePath, Object... pathFragments) { UrlMatcherSupport urlMatcher = new UrlMatcherSupport(basePath, Arrays.asList(pathFragments)); body.put(name, urlMatcher.getExampleValue()); - matchers.addRule(matcherKey(name), regexp(urlMatcher.getRegexExpression())); + matchers.addRule(matcherKey(name, rootPath), regexp(urlMatcher.getRegexExpression())); return this; } @@ -1226,8 +1210,8 @@ public PactDslJsonBody minMaxArrayLike(Integer minSize, Integer maxSize) { @Override public PactDslJsonBody minMaxArrayLike(String name, Integer minSize, Integer maxSize, int numberExamples) { validateMinAndMaxAndExamples(minSize, maxSize, numberExamples); - matchers.addRule(matcherKey(name), matchMinMax(minSize, maxSize)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), "", this, true); + matchers.addRule(matcherKey(name, rootPath), matchMinMax(minSize, maxSize)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), "", this, true); parent.setNumberExamples(numberExamples); return new PactDslJsonBody(".", "", parent); } @@ -1263,8 +1247,8 @@ public PactDslJsonArray eachArrayWithMinMaxLike(Integer minSize, Integer maxSize @Override public PactDslJsonArray eachArrayWithMinMaxLike(String name, int numberExamples, Integer minSize, Integer maxSize) { validateMinAndMaxAndExamples(minSize, maxSize, numberExamples); - matchers.addRule(matcherKey(name), matchMinMax(minSize, maxSize)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), name, this, true); + matchers.addRule(matcherKey(name, rootPath), matchMinMax(minSize, maxSize)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), name, this, true); parent.setNumberExamples(numberExamples); return new PactDslJsonArray("", "", parent); } @@ -1286,8 +1270,8 @@ public PactDslJsonArray eachArrayWithMinMaxLike(int numberExamples, Integer minS public PactDslJsonBody minMaxArrayLike(String name, Integer minSize, Integer maxSize, PactDslJsonRootValue value, int numberExamples) { validateMinAndMaxAndExamples(minSize, maxSize, numberExamples); - matchers.addRule(matcherKey(name), matchMinMax(minSize, maxSize)); - PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name), "", this, true); + matchers.addRule(matcherKey(name, rootPath), matchMinMax(minSize, maxSize)); + PactDslJsonArray parent = new PactDslJsonArray(matcherKey(name, rootPath), "", this, true); parent.setNumberExamples(numberExamples); parent.putObject(value); return (PactDslJsonBody) parent.closeArray(); @@ -1300,9 +1284,9 @@ public PactDslJsonBody minMaxArrayLike(String name, Integer minSize, Integer max * @param example Example value to be used in the consumer test */ public PactDslJsonBody valueFromProviderState(String name, String expression, Object example) { - generators.addGenerator(Category.BODY, matcherKey(name), new ProviderStateGenerator(expression, DataType.from(example))); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new ProviderStateGenerator(expression, DataType.from(example))); body.put(name, example); - matchers.addRule(matcherKey(name), TypeMatcher.INSTANCE); + matchers.addRule(matcherKey(name, rootPath), TypeMatcher.INSTANCE); return this; } @@ -1322,10 +1306,10 @@ public PactDslJsonBody dateExpression(String name, String expression) { * @param format Date format to use */ public PactDslJsonBody dateExpression(String name, String expression, String format) { - generators.addGenerator(Category.BODY, matcherKey(name), new DateGenerator(format, expression)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new DateGenerator(format, expression)); FastDateFormat instance = FastDateFormat.getInstance(format); body.put(name, instance.format(new Date(DATE_2000))); - matchers.addRule(matcherKey(name), matchDate(format)); + matchers.addRule(matcherKey(name, rootPath), matchDate(format)); return this; } @@ -1345,10 +1329,10 @@ public PactDslJsonBody timeExpression(String name, String expression) { * @param format Time format to use */ public PactDslJsonBody timeExpression(String name, String expression, String format) { - generators.addGenerator(Category.BODY, matcherKey(name), new TimeGenerator(format, expression)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new TimeGenerator(format, expression)); FastDateFormat instance = FastDateFormat.getInstance(format); body.put(name, instance.format(new Date(DATE_2000))); - matchers.addRule(matcherKey(name), matchTime(format)); + matchers.addRule(matcherKey(name, rootPath), matchTime(format)); return this; } @@ -1368,10 +1352,10 @@ public PactDslJsonBody datetimeExpression(String name, String expression) { * @param format Datetime format to use */ public PactDslJsonBody datetimeExpression(String name, String expression, String format) { - generators.addGenerator(Category.BODY, matcherKey(name), new DateTimeGenerator(format, expression)); + generators.addGenerator(Category.BODY, matcherKey(name, rootPath), new DateTimeGenerator(format, expression)); FastDateFormat instance = FastDateFormat.getInstance(format); body.put(name, instance.format(new Date(DATE_2000))); - matchers.addRule(matcherKey(name), matchTimestamp(format)); + matchers.addRule(matcherKey(name, rootPath), matchTimestamp(format)); return this; } } diff --git a/consumer/src/main/kotlin/au/com/dius/pact/consumer/dsl/Dsl.kt b/consumer/src/main/kotlin/au/com/dius/pact/consumer/dsl/Dsl.kt index 954c21e357..d0f1d386e2 100644 --- a/consumer/src/main/kotlin/au/com/dius/pact/consumer/dsl/Dsl.kt +++ b/consumer/src/main/kotlin/au/com/dius/pact/consumer/dsl/Dsl.kt @@ -1,9 +1,24 @@ package au.com.dius.pact.consumer.dsl +import au.com.dius.pact.core.model.validPathCharacter +import org.apache.commons.lang3.StringUtils + object Dsl { /** * Creates a builder to define the matchers on an array of JSON primitives */ @JvmStatic fun arrayOfPrimitives() = ArrayOfPrimitivesBuilder() + + /** + * Returns a safe matcher key for the attribute name + */ + @JvmStatic + fun matcherKey(name: String, rootPath: String): String { + return if (name.any { !validPathCharacter(it) }) { + "${StringUtils.stripEnd(rootPath, ".")}['$name']" + } else { + rootPath + name + } + } } diff --git a/consumer/src/test/groovy/au/com/dius/pact/consumer/dsl/DslSpec.groovy b/consumer/src/test/groovy/au/com/dius/pact/consumer/dsl/DslSpec.groovy new file mode 100644 index 0000000000..a4dc5fb1de --- /dev/null +++ b/consumer/src/test/groovy/au/com/dius/pact/consumer/dsl/DslSpec.groovy @@ -0,0 +1,26 @@ +package au.com.dius.pact.consumer.dsl + +import spock.lang.Specification +import spock.lang.Unroll + +class DslSpec extends Specification { + + @Unroll + def 'correctly generates a key for an attribute name'() { + expect: + Dsl.matcherKey(name, 'a.b.c.') == result + + where: + + name | result + 'a' | 'a.b.c.a' + 'a1' | 'a.b.c.a1' + '_a' | 'a.b.c._a' + '@a' | 'a.b.c.@a' + '#a' | 'a.b.c.#a' + 'b-a' | 'a.b.c.b-a' + 'b:a' | 'a.b.c.b:a' + '01/01/2001' | "a.b.c['01/01/2001']" + 'a[' | "a.b.c['a[']" + } +} diff --git a/consumer/src/test/java/au/com/dius/pact/consumer/PactDslJsonBodyTest.java b/consumer/src/test/java/au/com/dius/pact/consumer/PactDslJsonBodyTest.java index 289991e6c9..aec9c7a831 100644 --- a/consumer/src/test/java/au/com/dius/pact/consumer/PactDslJsonBodyTest.java +++ b/consumer/src/test/java/au/com/dius/pact/consumer/PactDslJsonBodyTest.java @@ -31,7 +31,7 @@ public class PactDslJsonBodyTest { private static final String THIRD = "@third"; @Test - public void noSpecialHandlingForObjectNamesFormerlyNotConformingToGatling() { + public void noSpecialHandlingForObjectNames() { DslPart body = new PactDslJsonBody() .id() .object("2") @@ -71,20 +71,20 @@ public void noSpecialHandlingForObjectNamesFormerlyNotConformingToGatling() { } @Test - public void guardAgainstFieldNamesThatDontConformToGatlingFields() { - DslPart body = new PactDslJsonBody() - .id("1") - .stringType("@field") - .hexValue("200", "abc") - .integerType(K_DEPRECIATION_BIPS); - - Set expectedMatchers = new HashSet(Arrays.asList( - ".200", ".1", "['@field']", ".10k-depreciation-bips" - )); - assertThat(body.getMatchers().getMatchingRules().keySet(), is(equalTo(expectedMatchers))); - - assertThat(((JSONObject) body.getBody()).keySet(), is(equalTo((Set) - new HashSet(Arrays.asList("200", K_DEPRECIATION_BIPS, "1", "@field"))))); + public void matcherPathTest() { + DslPart body = new PactDslJsonBody() + .id("1") + .stringType("@field") + .hexValue("200", "abc") + .integerType(K_DEPRECIATION_BIPS); + + Set expectedMatchers = new HashSet(Arrays.asList( + ".200", ".1", ".@field", ".10k-depreciation-bips" + )); + assertThat(body.getMatchers().getMatchingRules().keySet(), is(equalTo(expectedMatchers))); + + assertThat(((JSONObject) body.getBody()).keySet(), is(equalTo((Set) + new HashSet(Arrays.asList("200", K_DEPRECIATION_BIPS, "1", "@field"))))); } @Test @@ -123,11 +123,11 @@ public void nestedObjectMatcherTest() { .closeObject(); Set expectedMatchers = new HashSet<>(Arrays.asList( - ".first.second['@third'].fourth.level4", - ".first.second['@third'].level3", + ".first.second.@third.fourth.level4", + ".first.second.@third.level3", ".first.second.level2", ".first.level1", - ".first['@level1']" + ".first.@level1" )); assertThat(body.getMatchers().getMatchingRules().keySet(), is(equalTo(expectedMatchers))); diff --git a/core/model/src/main/kotlin/au/com/dius/pact/core/model/PathExpressions.kt b/core/model/src/main/kotlin/au/com/dius/pact/core/model/PathExpressions.kt index 1cdd387dc4..9def0b113b 100755 --- a/core/model/src/main/kotlin/au/com/dius/pact/core/model/PathExpressions.kt +++ b/core/model/src/main/kotlin/au/com/dius/pact/core/model/PathExpressions.kt @@ -68,7 +68,7 @@ fun identifier(ch: Char, chars: PushbackIterator>, tokens: Mu var id = String() + ch while (chars.hasNext()) { val c = chars.next() - if (c.value.isLetterOrDigit() || EXP_ALLOWED_SPECIAL_CHARS.contains(c.value)) { + if (validPathCharacter(c.value)) { id += c.value } else if (c.value == '.' || c.value == '\'' || c.value == '[') { chars.pushback(c) @@ -92,7 +92,7 @@ fun pathIdentifier( val ch = chars.next() when { ch.value == '*' -> tokens.add(PathToken.Star) - ch.value.isLetterOrDigit() || EXP_ALLOWED_SPECIAL_CHARS.contains(ch.value) -> + validPathCharacter(ch.value) -> identifier(ch.value, chars, tokens, path) else -> throw InvalidPathExpression("Expected either a \"*\" or path identifier in path expression \"$path\"" + " at index ${ch.index}") @@ -102,6 +102,8 @@ fun pathIdentifier( } } +fun validPathCharacter(c: Char) = c.isLetterOrDigit() || EXP_ALLOWED_SPECIAL_CHARS.contains(c) + // bracket_path -> (string_path | index | *) ] fun bracketPath(chars: PushbackIterator>, tokens: MutableList, path: String, index: Int) { if (chars.hasNext()) {