Skip to content

Commit

Permalink
fix: correctly handle Pact.like and Pact.each_like at top level of body
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed Aug 9, 2018
1 parent cdfbb70 commit f37c283
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 15 deletions.
27 changes: 17 additions & 10 deletions lib/pact/matching_rules/v3/merge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,44 @@ def standardise_paths matching_rules
end

def recurse expected, path
case expected
recursed = case expected
when Hash then recurse_hash(expected, path)
when Array then recurse_array(expected, path)
else
expected
end
wrap(recursed, path)
end

def recurse_hash hash, path
hash.each_with_object({}) do | (k, v), new_hash |
new_path = path + "['#{k}']"
new_hash[k] = recurse(wrap(v, new_path), new_path)
new_hash[k] = recurse(v, new_path)
end
end

def recurse_array array, path

parent_match_rule = @matching_rules[path] && @matching_rules[path]['matchers'] && @matching_rules[path]['matchers'].first && @matching_rules[path]['matchers'].first.delete('match')
# This assumes there is only one rule! TODO make this find the appropriate rule.
parent_match_rule = @matching_rules[path]['matchers'].first['match'] rescue nil
array_like_children_path = "#{path}[*]*"
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.delete('match')
min = @matching_rules[path] && @matching_rules[path]['matchers'] && @matching_rules[path]['matchers'].first && @matching_rules[path]['matchers'].first.delete('min')
children_match_rule = @matching_rules[array_like_children_path]['matchers'].first['match'] rescue nil
min = @matching_rules[path]['matchers'].first['min'] rescue nil

if min && (children_match_rule == 'type' || (children_match_rule.nil? && parent_match_rule == 'type'))
if min && children_match_rule == 'type'
@matching_rules[path]['matchers'].first.delete('min')
@matching_rules[array_like_children_path]['matchers'].first.delete('match')
warn_when_not_one_example_item(array, path)
Pact::ArrayLike.new(recurse(array.first, "#{path}[*]"), min: min)
elsif min && parent_match_rule == 'type'
@matching_rules[path]['matchers'].first.delete('min')
@matching_rules[path]['matchers'].first.delete('match')
warn_when_not_one_example_item(array, path)
Pact::ArrayLike.new(recurse(array.first, "#{path}[*]"), min: min)
else
new_array = []
array.each_with_index do | item, index |
new_path = path + "[#{index}]"
new_array << recurse(wrap(item, new_path), new_path)
new_array << recurse(item, new_path)
end
new_array
end
Expand All @@ -82,14 +90,13 @@ def wrap object, path
elsif rules['regex']
handle_regex(object, path, rules)
else
#log_ignored_rules(path, rules, {})
object
end
end

def handle_match_type object, path, rules
rules.delete('match')
Pact::SomethingLike.new(recurse(object, path))
Pact::SomethingLike.new(object)
end

def handle_regex object, path, rules
Expand Down
67 changes: 62 additions & 5 deletions spec/lib/pact/matching_rules/v3/merge_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ module V3
end

it "it logs the rules it has ignored" do
expect($stderr).to receive(:puts).with(/ignored.*matchingrule/)
expect($stderr).to receive(:puts).once.with(/ignored.*matchingrule/)
subject
end

Expand All @@ -105,6 +105,61 @@ module V3
end
end

describe "when a Pact.like is nested inside a Pact.each_like which is nested inside a Pact.like" do
let(:original_definition) do
Pact.like('foos' => Pact.each_like(Pact.like('name' => "foo1")))
end

let(:expected) do
Pact::Reification.from_term(original_definition)
end

let(:matching_rules) do
Extract.call(original_definition)
end

it "creates a Pact::SomethingLike containing a Pact::ArrayLike containing a Pact::SomethingLike" do
expect(subject.to_hash).to eq original_definition.to_hash
end
end

describe "when a Pact.array_like is the top level object" do
let(:original_definition) do
Pact.each_like('foos')
end

let(:expected) do
Pact::Reification.from_term(original_definition)
end

let(:matching_rules) do
Extract.call(original_definition)
end

it "creates a Pact::ArrayLike" do
expect(subject.to_hash).to eq original_definition.to_hash
end
end

describe "when a Pact.like containing an array is the top level object" do
let(:original_definition) do
Pact.like(['foos'])
end

let(:expected) do
Pact::Reification.from_term(original_definition).tap { |it| puts it }
end

let(:matching_rules) do
Extract.call(original_definition).tap { |it| puts it }
end

it "creates a Pact::SomethingLike" do
expect(subject).to be_a(Pact::SomethingLike)
expect(subject.to_hash).to eq original_definition.to_hash
end
end

describe "regular expressions" do
describe "in a hash" do
before do
Expand Down Expand Up @@ -203,7 +258,7 @@ module V3
let(:matching_rules) do
{
"$.alligators" => {
"matchers" => [{ 'min' => 2, 'match' => 'type' }]
"matchers" => [{ 'min' => 2}]
},
"$.alligators[*].*" => {
"matchers" => [{ 'match' => 'type'}]
Expand Down Expand Up @@ -236,9 +291,10 @@ module V3
end

it "creates a Pact::ArrayLike at the appropriate path" do
expect(subject["alligators"]).to be_instance_of(Pact::ArrayLike)
expect(subject["alligators"].contents).to eq 'name' => 'Mary'
expect(subject["alligators"].min).to eq 2
expect(subject["alligators"]).to be_instance_of(Pact::SomethingLike)
expect(subject["alligators"].contents).to be_instance_of(Pact::ArrayLike)
expect(subject["alligators"].contents.contents).to eq 'name' => 'Mary'
expect(subject["alligators"].contents.min).to eq 2
end
end

Expand Down Expand Up @@ -380,6 +436,7 @@ module V3
expect(subject['@name']).to be_instance_of(Pact::SomethingLike)
end
end

end
end
end
Expand Down

0 comments on commit f37c283

Please sign in to comment.