Skip to content

Commit

Permalink
fix: Matching rules for query strings with square brackets were not b…
Browse files Browse the repository at this point in the history
…ing written in V2 format correctly #1766
  • Loading branch information
rholshausen committed Feb 16, 2024
1 parent 9480fdc commit 2dd6271
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import au.com.dius.pact.core.model.annotations.Pact;
import org.apache.hc.client5.http.fluent.Request;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

Expand All @@ -18,7 +17,6 @@

@ExtendWith(PactConsumerTestExt.class)
@PactTestFor(providerName = "QueryWithSquareBrackets", pactVersion = PactSpecVersion.V2)
@Disabled
public class QueryWithSquareBracketsTest {

@Pact(consumer="test_consumer")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ const val PATH_SPECIAL_CHARS = "'[].@ \t\n"
const val EXP_ALLOWED_SPECIAL_CHARS = "-_:#@"

sealed class PathToken {
abstract fun rawString(): String

object Root : PathToken() {
override fun toString() = "$"

override fun rawString() = "$"
}

data class Field(val name: String) : PathToken() {
Expand All @@ -19,20 +23,28 @@ sealed class PathToken {
this.name
}
}

override fun rawString() = this.name
}

data class Index(val index: Int) : PathToken() {
override fun toString(): String {
return "[${this.index}]"
}

override fun rawString() = this.index.toString()
}

object Star : PathToken() {
override fun toString() = "*"

override fun rawString() = "*"
}

object StarIndex : PathToken() {
override fun toString() = "[*]"

override fun rawString() = "[*]"
}
}

Expand Down Expand Up @@ -196,10 +208,10 @@ fun constructValidPath(segment: String, rootPath: String): String {
segment.isEmpty() -> rootPath
else -> {
val root = StringUtils.stripEnd(rootPath, ".")
if (segment.any { !validPathCharacter(it) }) {
"$root['$segment']"
} else if (segment.all { it.isDigit() }) {
if (segment.all { it.isDigit() }) {
"$root[$segment]"
} else if (segment.any { !validPathCharacter(it) }) {
"$root['$segment']"
} else {
"$root.$segment"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package au.com.dius.pact.core.model.matchingrules

import au.com.dius.pact.core.model.PactSpecVersion
import au.com.dius.pact.core.model.atLeast
import au.com.dius.pact.core.model.*
import au.com.dius.pact.core.model.generators.Generator
import au.com.dius.pact.core.support.json.JsonValue
import io.github.oshai.kotlinlogging.KLogging
Expand Down Expand Up @@ -153,10 +152,15 @@ data class MatchingRuleCategory @JvmOverloads constructor(
"header" -> "\$.headers"
else -> "\$.$name"
}
val keySuffix = when (name) {
"body" -> it.key
"header", "headers", "query" -> PathToken.Field(it.key).toString()
else -> it.key
}
val key = when {
it.key.startsWith('$') -> keyBase + it.key.substring(1)
it.key.isNotEmpty() && !it.key.startsWith('[') -> keyBase + '.' + it.key
it.key.isNotEmpty() -> keyBase + it.key
keySuffix.startsWith('$') -> keyBase + keySuffix.substring(1)
keySuffix.isNotEmpty() && !keySuffix.startsWith('[') -> "$keyBase.$keySuffix"
keySuffix.isNotEmpty() -> keyBase + keySuffix
else -> keyBase
}
Pair(key, it.value.toMap(pactSpecVersion))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,17 @@ class MatchingRulesImpl : MatchingRules {
addV2Rule("body", "$${key.substring(6)}", Json.toMap(value))
}
} else if (key.startsWith("$.headers")) {
addV2Rule("header", pathFromTokens(path.drop(2)), Json.toMap(value))
val headerValue = if (path.size > 3) {
pathFromTokens(path.drop(2))
} else path[2].rawString()
addV2Rule("header", headerValue, Json.toMap(value))
} else {
addV2Rule(path[1].toString(), if (path.size > 2) pathFromTokens(path.drop(2)) else null, Json.toMap(value))
val ruleValue = if (path.size > 3) {
pathFromTokens(path.drop(2))
}
else if (path.size == 3) path[2].rawString()
else null
addV2Rule(path[1].toString(), ruleValue, Json.toMap(value))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,4 +371,63 @@ class MatchingRulesSpec extends Specification {
new TimeMatcher().toMap(PactSpecVersion.V3) == [match: 'time', format: 'HH:mm:ss']
new TimeMatcher('hh').toMap(PactSpecVersion.V3) == [match: 'time', format: 'hh']
}

@Issue('#1766')
def 'With V2 format, matching rules for queries should be encoded correctly'() {
given:
def matchingRules = new MatchingRulesImpl()
matchingRules
.addCategory('query')
.addRule('X', new RegexMatcher('1'))
.addRule('principal_identifier[account_id]', new RegexMatcher('2'))

expect:
matchingRules.toV2Map() == [
'$.query.X': [match: 'regex', regex: '1'],
'$.query[\'principal_identifier[account_id]\']': [match: 'regex', regex: '2']
]
}

@Issue('#1766')
def 'loads V2 query matching rules that are encoded'() {
given:
def matchingRulesMap = [
'$.query.Q1': ['match': 'regex', 'regex': '1'],
'$.query[\'principal_identifier[account_id]\']': ['match': 'regex', 'regex': '2']
]

when:
def matchingRules = MatchingRulesImpl.fromJson(Json.INSTANCE.toJson(matchingRulesMap))

then:
!matchingRules.empty
matchingRules.rulesForCategory('query') == new MatchingRuleCategory('query', [
Q1: new MatchingRuleGroup([ new RegexMatcher('1') ]),
'principal_identifier[account_id]': new MatchingRuleGroup([ new RegexMatcher('2') ])
])
}

@Issue('#1766')
def 'With V3 format, matching rules for queries should not be encoded'() {
given:
def matchingRules = new MatchingRulesImpl()
matchingRules
.addCategory('query')
.addRule('X', new RegexMatcher('1'))
.addRule('principal_identifier[account_id]', new RegexMatcher('2'))

expect:
matchingRules.toV3Map(PactSpecVersion.V3) == [
query: [
X: [
matchers: [[match: 'regex', regex: '1']],
combine: 'AND'
],
'principal_identifier[account_id]': [
matchers: [[match: 'regex', regex: '2']],
combine: 'AND'
]
]
]
}
}

0 comments on commit 2dd6271

Please sign in to comment.