Skip to content

Commit 07013de

Browse files
committed
feat: read matching rules from v3 format
1 parent caaa67b commit 07013de

File tree

3 files changed

+503
-0
lines changed

3 files changed

+503
-0
lines changed

lib/pact/matching_rules/v3/merge.rb

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
require 'pact/array_like'
2+
require 'pact/matching_rules/jsonpath'
3+
4+
module Pact
5+
module MatchingRules
6+
module V3
7+
class Merge
8+
9+
def self.call expected, matching_rules, root_path = '$'
10+
new(expected, matching_rules, root_path).call
11+
end
12+
13+
def initialize expected, matching_rules, root_path
14+
@expected = expected
15+
@matching_rules = standardise_paths(matching_rules)
16+
@root_path = JsonPath.new(root_path).to_s
17+
end
18+
19+
def call
20+
return @expected if @matching_rules.nil? || @matching_rules.empty?
21+
recurse @expected, @root_path
22+
end
23+
24+
private
25+
26+
def standardise_paths matching_rules
27+
return matching_rules if matching_rules.nil? || matching_rules.empty?
28+
matching_rules.each_with_object({}) do | (path, rule), new_matching_rules |
29+
new_matching_rules[JsonPath.new(path).to_s] = rule
30+
end
31+
end
32+
33+
def recurse expected, path
34+
case expected
35+
when Hash then recurse_hash(expected, path)
36+
when Array then recurse_array(expected, path)
37+
else
38+
expected
39+
end
40+
end
41+
42+
def recurse_hash hash, path
43+
hash.each_with_object({}) do | (k, v), new_hash |
44+
new_path = path + "['#{k}']"
45+
new_hash[k] = recurse(wrap(v, new_path), new_path)
46+
end
47+
end
48+
49+
def recurse_array array, path
50+
array_like_children_path = "#{path}[*]*"
51+
parent_match_rule = @matching_rules[path] && @matching_rules[path]['matchers'] && @matching_rules[path]['matchers'].first && @matching_rules[path]['matchers'].first['match']
52+
children_match_rule = @matching_rules[array_like_children_path] && @matching_rules[array_like_children_path]['matchers'] && @matching_rules[array_like_children_path]['matchers'].first && @matching_rules[array_like_children_path]['matchers'].first['match']
53+
min = @matching_rules[path] && @matching_rules[path]['matchers'] && @matching_rules[path]['matchers'].first && @matching_rules[path]['matchers'].first['min']
54+
55+
if min && (children_match_rule == 'type' || (children_match_rule.nil? && parent_match_rule == 'type'))
56+
warn_when_not_one_example_item(array, path)
57+
# log_ignored_rules(path, @matching_rules[path], {'min' => min})
58+
Pact::ArrayLike.new(recurse(array.first, "#{path}[*]"), min: min)
59+
else
60+
new_array = []
61+
array.each_with_index do | item, index |
62+
new_path = path + "[#{index}]"
63+
new_array << recurse(wrap(item, new_path), new_path)
64+
end
65+
new_array
66+
end
67+
end
68+
69+
def warn_when_not_one_example_item array, path
70+
unless array.size == 1
71+
Pact.configuration.error_stream.puts "WARN: Only the first item will be used to match the items in the array at #{path}"
72+
end
73+
end
74+
75+
def wrap object, path
76+
rules = @matching_rules[path] && @matching_rules[path]['matchers'] && @matching_rules[path]['matchers'].first
77+
array_rules = @matching_rules["#{path}[*]*"] && @matching_rules["#{path}[*]*"]['matchers'] && @matching_rules["#{path}[*]*"]['matchers'].first
78+
return object unless rules || array_rules
79+
80+
if rules['match'] == 'type' && !rules.has_key?('min')
81+
handle_match_type(object, path, rules)
82+
elsif rules['regex']
83+
handle_regex(object, path, rules)
84+
else
85+
log_ignored_rules(path, rules, {})
86+
object
87+
end
88+
end
89+
90+
def handle_match_type object, path, rules
91+
log_ignored_rules(path, rules, {'match' => 'type'})
92+
Pact::SomethingLike.new(object)
93+
end
94+
95+
def handle_regex object, path, rules
96+
log_ignored_rules(path, rules, {'match' => 'regex', 'regex' => rules['regex']})
97+
Pact::Term.new(generate: object, matcher: Regexp.new(rules['regex']))
98+
end
99+
100+
def log_ignored_rules path, rules, used_rules
101+
dup_rules = rules.dup
102+
used_rules.each_pair do | used_key, used_value |
103+
dup_rules.delete(used_key) if dup_rules[used_key] == used_value
104+
end
105+
if dup_rules.any?
106+
$stderr.puts "WARN: Ignoring unsupported matching rules #{dup_rules} for path #{path}"
107+
end
108+
end
109+
end
110+
end
111+
end
112+
end

spec/fixtures/pact-v3.json

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"consumer": {
3+
"name": "Consumer"
4+
},
5+
"provider": {
6+
"name": "Provider"
7+
},
8+
"messages": [
9+
{
10+
"contents": {
11+
"foo": "bar"
12+
},
13+
"description": "Published credit data",
14+
"metaData": {
15+
"contentType": "application/json"
16+
},
17+
"providerState": "or maybe 'scenario'? not sure about this",
18+
"matchingRules": {
19+
"body": {
20+
"$.foo": {
21+
"matchers": [{"match" : "type"}]
22+
}
23+
}
24+
}
25+
}
26+
]
27+
}

0 commit comments

Comments
 (0)