diff --git a/lib/pact/consumer_contract/interaction_v2_parser.rb b/lib/pact/consumer_contract/interaction_v2_parser.rb index cfc208c..fbc8b97 100644 --- a/lib/pact/consumer_contract/interaction_v2_parser.rb +++ b/lib/pact/consumer_contract/interaction_v2_parser.rb @@ -23,12 +23,22 @@ def self.call hash, options end def self.parse_request request_hash, options - if request_hash['query'].is_a?(String) + original_query_string = request_hash['query'] + query_is_string = original_query_string.is_a?(String) + if query_is_string request_hash = request_hash.dup request_hash['query'] = Pact::Query.parse_string(request_hash['query']) end + # The query has to be a hash at this stage for the matching rules to be applied request_hash = Pact::MatchingRules.merge(request_hash, request_hash['matchingRules'], options) - Pact::Request::Expected.from_hash(request_hash) + # The original query string needs to be passed in to the constructor so it can be used + # when the request is replayed. Otherwise, we loose the square brackets because they get lost + # in the translation between string => structured object, as we don't know/store which + # query string convention was used. + if query_is_string + request_hash['query'] = Pact::QueryHash.new(request_hash['query'], original_query_string) + end + request = Pact::Request::Expected.from_hash(request_hash) end def self.parse_response response_hash, options diff --git a/lib/pact/consumer_contract/query.rb b/lib/pact/consumer_contract/query.rb index f8a78d5..ee7c6de 100644 --- a/lib/pact/consumer_contract/query.rb +++ b/lib/pact/consumer_contract/query.rb @@ -14,6 +14,10 @@ def self.create query end end + def self.is_a_query_object?(object) + object.is_a?(Pact::QueryHash) || object.is_a?(Pact::QueryString) + end + def self.parse_string query_string parsed_query = parse_query(query_string) diff --git a/lib/pact/consumer_contract/query_hash.rb b/lib/pact/consumer_contract/query_hash.rb index e447d3c..e8e63de 100644 --- a/lib/pact/consumer_contract/query_hash.rb +++ b/lib/pact/consumer_contract/query_hash.rb @@ -8,8 +8,11 @@ class QueryHash include ActiveSupportSupport include SymbolizeKeys - def initialize(query) + attr_reader :original_string + + def initialize(query, original_string = nil) @hash = query.nil? ? query : convert_to_hash_of_arrays(query) + @original_string = original_string end def as_json(opts = {}) diff --git a/lib/pact/reification.rb b/lib/pact/reification.rb index bbfbc2c..a731dfe 100644 --- a/lib/pact/reification.rb +++ b/lib/pact/reification.rb @@ -27,15 +27,19 @@ def self.from_term(term) when Pact::QueryString from_term(term.query) when Pact::QueryHash - from_term(term.query).map { |k, v| - if v.nil? - k - elsif v.is_a?(Array) #For cases where there are multiple instance of the same parameter - v.map { |x| "#{k}=#{escape(x)}"}.join('&') - else - "#{k}=#{escape(v)}" - end - }.join('&') + if term.original_string + term.original_string + else + from_term(term.query).map { |k, v| + if v.nil? + k + elsif v.is_a?(Array) #For cases where there are multiple instance of the same parameter + v.map { |x| "#{k}=#{escape(x)}"}.join('&') + else + "#{k}=#{escape(v)}" + end + }.join('&') + end when Pact::StringWithMatchingRules String.new(term) else diff --git a/lib/pact/shared/request.rb b/lib/pact/shared/request.rb index ff74e0b..66f343d 100644 --- a/lib/pact/shared/request.rb +++ b/lib/pact/shared/request.rb @@ -14,7 +14,7 @@ def initialize(method, path, headers, body, query) @path = path @headers = Hash === headers ? Headers.new(headers) : headers # Could be a NullExpectation - TODO make this more elegant @body = body - @query = is_unspecified?(query) ? query : Pact::Query.create(query) + set_query(query) end def to_hash @@ -89,6 +89,18 @@ def display_path def display_query (query.nil? || query.empty?) ? '' : "?#{Pact::Reification.from_term(query)}" end + + def set_query(query) + @query = if is_unspecified?(query) + query + else + if Pact::Query.is_a_query_object?(query) + query + else + Pact::Query.create(query) + end + end + end end end end diff --git a/spec/lib/pact/reification_spec.rb b/spec/lib/pact/reification_spec.rb index f609b1c..d3545c7 100644 --- a/spec/lib/pact/reification_spec.rb +++ b/spec/lib/pact/reification_spec.rb @@ -108,6 +108,16 @@ module Pact end end + context "when Hash Query with an original_string" do + let(:query) { QueryHash.new( {param: 'hello', extra: 'world'}, "foo=bar")} + + subject { Reification.from_term(query)} + + it "returns the original string" do + expect(subject).to eq("foo=bar") + end + end + context "when Hash Query with UTF-8 string" do subject { Reification.from_term(query)} diff --git a/spec/lib/pact/shared/request_spec.rb b/spec/lib/pact/shared/request_spec.rb index f27795e..a91c186 100644 --- a/spec/lib/pact/shared/request_spec.rb +++ b/spec/lib/pact/shared/request_spec.rb @@ -56,6 +56,14 @@ def self.key_not_found expect(subject).to eq("/something") end end + + context "with a pre-parsed query that has an original_string" do + let(:query) { Pact::QueryHash.new({ "foo" => "bar", "meep" => "moop" }, "foo=bar") } + + it "uses the original string" do + expect(subject).to eq ("/something?foo=bar") + end + end end describe "#method_and_path" do