Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions core/matching/matchers/matchers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ var Matchers = map[string]MatcherFunc{
// Default matcher
"": ExactMatch,

Exact: ExactMatch,
Glob: GlobMatch,
Json: JsonMatch,
JsonPath: JsonPathMatch,
JsonPartial: JsonPartialMatch,
Regex: RegexMatch,
Xml: XmlMatch,
Xpath: XpathMatch,
Exact: ExactMatch,
Glob: GlobMatch,
Json: JsonMatch,
JsonPath: JsonPathMatch,
JsonPartial: JsonPartialMatch,
Regex: RegexMatch,
Xml: XmlMatch,
Xpath: XpathMatch,
XmlTemplated: XmlTemplatedMatch,
}
102 changes: 102 additions & 0 deletions core/matching/matchers/xml_templated_match.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package matchers

import (
"regexp"

"github.com/beevik/etree"
)

var XmlTemplated = "xmltemplated"

var ignoreExpr = regexp.MustCompile("^\\s*\\{\\{\\s*ignore\\s*\\}\\}\\s*$")
var regExpr = regexp.MustCompile("^\\s*\\{\\{\\s*regex:(.*)\\}\\}\\s*$")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Hoverfly response template function is in this format: {{ function_name arg1, arg2.. }}
So I would suggest replacing the : with space as delimiter such as {{ regex your_regex_string_value }} for consistency.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for merged it, and sorry for long time no commits.
I am a little busy recently. After we finish our tasks, I will add a commit for this.

@tommysitu tommysitu Jun 17, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 whenever you have some time.


func XmlTemplatedMatch(match interface{}, toMatch string) bool {
matchString, ok := match.(string)
if !ok {
return false
}

// parse xml in mock data into dom tree
expected := etree.NewDocument()
if err := expected.ReadFromString(matchString); err != nil {
return false
}

// parse xml in actual request body into dom tree
actual := etree.NewDocument()
if err := actual.ReadFromString(toMatch); err != nil {
return false
}

// tree matching
return compareTree(expected.Root(), actual.Root())
}

func compareTree(expected *etree.Element, actual *etree.Element) bool {
// compare constructure
// step 1. compare tag name
if expected.Tag != actual.Tag {
return false
}
// step 2. compare node content
// case 1: leaf
if isLeaf(expected) {
// compare text content
return compareValue(expected.Text(), actual.Text())
}
// case 2: children element matching
actual_children := actual.ChildElements()
// for each expected tag
Comment thread
tommysitu marked this conversation as resolved.
for _, match := range expected.ChildElements() {
// find one in actual
matched := false
for i, ele := range actual_children {
if compareTree(match, ele) {
matched = true
// remove matched
actual_children = append(actual_children[:i], actual_children[i+1:]...)
break
}
}
// all elements in actual data is not matched
// or, too many elements in expected data
if matched == false {
return false
}
}
// too many elements in actual data
if len(actual_children) > 0 {
return false
}
Comment thread
tommysitu marked this conversation as resolved.
return true
}

// check element text content
func compareValue(expected string, actual string) bool {
// pattern 1: ignore value => always be true
if ignoreExpr.MatchString(expected) {
return true
}
// pattern 2: regex
// parse node content
group := regExpr.FindStringSubmatch(expected)
// if it matchs the grammer like {{regex: ... }} ==> otherwise, take it as plain text
if len(group) > 1 {
matcher, err := regexp.Compile(group[1])
// can not compile regular expression --> invalid regex --> false
if err != nil {
return false
}
// use regular expression to match actual value
return matcher.MatchString(actual)
}
// pattern 3: exact equal
return expected == actual
}

// check if an element is leaf
func isLeaf(expected *etree.Element) bool {
// it is a leaf node if it does not have any children
return len(expected.ChildElements()) == 0
}
Loading