pact-support 1.4.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +115 -0
  3. data/lib/pact/configuration.rb +4 -0
  4. data/lib/pact/consumer_contract/consumer_contract.rb +19 -8
  5. data/lib/pact/consumer_contract/http_consumer_contract_parser.rb +37 -0
  6. data/lib/pact/consumer_contract/interaction.rb +52 -57
  7. data/lib/pact/consumer_contract/interaction_parser.rb +23 -0
  8. data/lib/pact/consumer_contract/interaction_v2_parser.rb +28 -0
  9. data/lib/pact/consumer_contract/interaction_v3_parser.rb +61 -0
  10. data/lib/pact/consumer_contract/pact_file.rb +24 -24
  11. data/lib/pact/consumer_contract/query_hash.rb +2 -0
  12. data/lib/pact/consumer_contract/query_string.rb +2 -2
  13. data/lib/pact/consumer_contract/request.rb +1 -5
  14. data/lib/pact/consumer_contract/string_with_matching_rules.rb +17 -0
  15. data/lib/pact/matchers/multipart_form_diff_formatter.rb +41 -0
  16. data/lib/pact/matching_rules/merge.rb +30 -14
  17. data/lib/pact/matching_rules/v3/extract.rb +94 -0
  18. data/lib/pact/matching_rules/v3/merge.rb +128 -0
  19. data/lib/pact/matching_rules.rb +19 -6
  20. data/lib/pact/reification.rb +6 -3
  21. data/lib/pact/shared/multipart_form_differ.rb +14 -0
  22. data/lib/pact/specification_version.rb +18 -0
  23. data/lib/pact/support/version.rb +1 -1
  24. data/script/release.sh +1 -1
  25. data/spec/fixtures/multipart-form-diff.txt +9 -0
  26. data/spec/fixtures/not-a-pact.json +3 -0
  27. data/spec/fixtures/pact-http-v2.json +36 -0
  28. data/spec/fixtures/pact-http-v3.json +36 -0
  29. data/spec/integration/matching_rules_extract_and_merge_spec.rb +41 -4
  30. data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +54 -31
  31. data/spec/lib/pact/consumer_contract/http_consumer_contract_parser_spec.rb +25 -0
  32. data/spec/lib/pact/consumer_contract/interaction_parser_spec.rb +62 -0
  33. data/spec/lib/pact/consumer_contract/interaction_spec.rb +0 -23
  34. data/spec/lib/pact/consumer_contract/pact_file_spec.rb +9 -0
  35. data/spec/lib/pact/consumer_contract/query_hash_spec.rb +23 -0
  36. data/spec/lib/pact/matchers/multipart_form_diff_formatter_spec.rb +36 -0
  37. data/spec/lib/pact/matching_rules/merge_spec.rb +20 -7
  38. data/spec/lib/pact/matching_rules/v3/extract_spec.rb +238 -0
  39. data/spec/lib/pact/matching_rules/v3/merge_spec.rb +386 -0
  40. data/spec/lib/pact/matching_rules_spec.rb +82 -0
  41. data/spec/lib/pact/reification_spec.rb +18 -5
  42. data/spec/lib/pact/shared/multipart_form_differ_spec.rb +39 -0
  43. data/tasks/spec.rake +0 -1
  44. metadata +35 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d63ce6f1b637b9ec8c1aa7c097631c13134c8085
4
- data.tar.gz: e7f099a1364dd8e6ea4da06c5e6c15e6d1b83b38
3
+ metadata.gz: 2bbba1bbc7c4a2bf0c9bf83c335bca49f3911b33
4
+ data.tar.gz: 074b3a5fbf4ea09514e9a58d6af2d42d22739942
5
5
  SHA512:
6
- metadata.gz: 6fab573b4105cb73ab146e406cfddbb56508160324e639b35a287f823a1b8c1570347768ef0198dbcf7454ea9dbfef7f0a53f9e3b48c9e22f430c5cd4d45548e
7
- data.tar.gz: 424fdc09077746fda17301499934ef326c6f1af664baac0cc08e5f3d3c318d1047a3a7a95db7b90cf82d6139da774cb579fedb0a56929aba6fdc66dbaf15ca0d
6
+ metadata.gz: d15ba35784d2b6a93feeae4f77fd43f32ae2b07d3ece6b1b1a0367d9d05702a6a6dca9696e65287ba782c2ccfc495fc7fb3c8e8a34c57f525ddaf0702acdf6b2
7
+ data.tar.gz: 58ebf78d2b351442c2d3ac0ce8a2874949939acb51ca94b5aa7f0b261b1674da0ddd73db983e643267e9dd3b8c0117a80277090ac36690ff71ece9fbb694c118
data/CHANGELOG.md CHANGED
@@ -1,3 +1,118 @@
1
+ <a name="v1.7.0"></a>
2
+ ### v1.7.0 (2018-08-07)
3
+
4
+
5
+ #### Features
6
+
7
+ * add support for multipart/form ([8ed4332](/../../commit/8ed4332))
8
+
9
+
10
+ <a name="v1.6.6"></a>
11
+ ### v1.6.6 (2018-07-25)
12
+
13
+
14
+ #### Bug Fixes
15
+
16
+ * correctly handle an 'each like' inside a 'like' ([7dc76dc](/../../commit/7dc76dc))
17
+
18
+
19
+ <a name="v1.6.5"></a>
20
+ ### v1.6.5 (2018-07-23)
21
+
22
+
23
+ #### Features
24
+
25
+ * use 0 as the nil pact specification version ([88e4750](/../../commit/88e4750))
26
+ * reify StringWithMatchingRules to a String ([a025dd3](/../../commit/a025dd3))
27
+ * parse String response and request bodies to StringWithMatchingRules to support pact-xml ([a9fbb58](/../../commit/a9fbb58))
28
+ * add custom contract parsers to front of pact parsers list so that customised parsers are tried first ([babc319](/../../commit/babc319))
29
+
30
+
31
+ #### Bug Fixes
32
+
33
+ * show a more helpful error when attempting to parse a URI that is not a pact ([a8ba1ed](/../../commit/a8ba1ed))
34
+
35
+
36
+ <a name="v1.6.4"></a>
37
+ ### v1.6.4 (2018-07-14)
38
+
39
+
40
+ #### Bug Fixes
41
+
42
+ * correctly serialize query params that use a Pact.each_like in pact file ([b3414dd](/../../commit/b3414dd))
43
+
44
+
45
+ <a name="v1.6.3"></a>
46
+ ### v1.6.3 (2018-07-12)
47
+
48
+
49
+ #### Bug Fixes
50
+
51
+ * remove incorrect warning about ignoring unsupported matching rules for min => x ([50d5f6d](/../../commit/50d5f6d))
52
+ * serialize ArrayLike in query params without wrapping another array around it ([b4a9ec7](/../../commit/b4a9ec7))
53
+
54
+
55
+ <a name="v1.6.2"></a>
56
+ ### v1.6.2 (2018-05-31)
57
+
58
+
59
+ #### Bug Fixes
60
+
61
+ * **windows-path**
62
+ * prevent locale file paths to be parsed by URI to stop errors in windows paths like spaces in paths ([ecf64d6](/../../commit/ecf64d6))
63
+
64
+
65
+ <a name="v1.6.1"></a>
66
+ ### v1.6.1 (2018-05-21)
67
+
68
+
69
+ #### Bug Fixes
70
+
71
+ * correctly read local windows pact file paths with backslashes ([e27bd38](/../../commit/e27bd38))
72
+
73
+
74
+ <a name="v1.6.0"></a>
75
+ ### v1.6.0 (2018-04-03)
76
+
77
+
78
+ #### Features
79
+
80
+ * add support for writing v3 matching rules ([fc89696](/../../commit/fc89696))
81
+
82
+
83
+ <a name="v1.5.2"></a>
84
+ ### v1.5.2 (2018-03-23)
85
+
86
+ #### Bug Fixes
87
+
88
+ * remove include of pact matchers in query string ([c478dff](/../../commit/c478dff))
89
+
90
+
91
+ <a name="v1.5.1"></a>
92
+ ### v1.5.1 (2018-03-23)
93
+
94
+ #### Bug Fixes
95
+
96
+ * add missing require for pact matchers in query ([927d3b9](/../../commit/927d3b9))
97
+
98
+
99
+ <a name="v1.5.0"></a>
100
+ ### v1.5.0 (2018-03-23)
101
+
102
+ #### Features
103
+
104
+ * parse pacts without a specification version as v2 ([a69b5e6](/../../commit/a69b5e6))
105
+ * locate matching rules correctly for v3 pacts ([0f22db2](/../../commit/0f22db2))
106
+ * read matching rules from v3 format ([07013de](/../../commit/07013de))
107
+ * allow different consumer contract parsers to be registered ([531ab3a](/../../commit/531ab3a))
108
+ * update message classes to support pact-message ([2e48892](/../../commit/2e48892))
109
+ * add request and response to message ([93839cf](/../../commit/93839cf))
110
+
111
+ * **message contracts**
112
+ * dynamically mix in new and from_hash into Pact::Message ([c0c3ad5](/../../commit/c0c3ad5))
113
+ * read message pact into Ruby object ([6573bd4](/../../commit/6573bd4))
114
+
115
+
1
116
  <a name="v1.3.1"></a>
2
117
  ### v1.3.1 (2018-03-19)
3
118
 
@@ -1,9 +1,11 @@
1
1
  require 'pact/matchers/embedded_diff_formatter'
2
2
  require 'pact/matchers/unix_diff_formatter'
3
3
  require 'pact/matchers/list_diff_formatter'
4
+ require 'pact/matchers/multipart_form_diff_formatter'
4
5
  require 'pact/shared/json_differ'
5
6
  require 'pact/shared/text_differ'
6
7
  require 'pact/shared/form_differ'
8
+ require 'pact/shared/multipart_form_differ'
7
9
 
8
10
 
9
11
  module Pact
@@ -24,6 +26,7 @@ module Pact
24
26
  end
25
27
 
26
28
  DIFF_FORMATTER_REGISTRATIONS = [
29
+ [/multipart\/form-data/, Pact::Matchers::MultipartFormDiffFormatter],
27
30
  [/.*/, Pact::Matchers::UnixDiffFormatter],
28
31
  [NilMatcher, Pact::Matchers::UnixDiffFormatter]
29
32
  ]
@@ -31,6 +34,7 @@ module Pact
31
34
  DIFFERS = [
32
35
  [/json/, Pact::JsonDiffer],
33
36
  [/application\/x\-www\-form\-urlencoded/, Pact::FormDiffer],
37
+ [/multipart\/form-data/, Pact::MultipartFormDiffer],
34
38
  [NilMatcher, Pact::TextDiffer],
35
39
  [/.*/, Pact::TextDiffer]
36
40
  ]
@@ -10,9 +10,12 @@ require 'pact/consumer_contract/service_consumer'
10
10
  require 'pact/consumer_contract/service_provider'
11
11
  require 'pact/consumer_contract/interaction'
12
12
  require 'pact/consumer_contract/pact_file'
13
+ require 'pact/consumer_contract/http_consumer_contract_parser'
13
14
 
14
15
  module Pact
15
16
 
17
+ class UnrecognizePactFormatError < ::Pact::Error; end
18
+
16
19
  class ConsumerContract
17
20
 
18
21
  include SymbolizeKeys
@@ -29,13 +32,19 @@ module Pact
29
32
  @provider = attributes[:provider]
30
33
  end
31
34
 
35
+ def self.add_parser consumer_contract_parser
36
+ parsers.unshift(consumer_contract_parser)
37
+ end
38
+
39
+ def self.parsers
40
+ @parsers ||= [Pact::HttpConsumerContractParser.new]
41
+ end
42
+
32
43
  def self.from_hash(hash)
33
- hash = symbolize_keys(hash)
34
- new(
35
- :consumer => ServiceConsumer.from_hash(hash[:consumer]),
36
- :provider => ServiceProvider.from_hash(hash[:provider]),
37
- :interactions => hash[:interactions].collect { |h| Interaction.from_hash(h)}
38
- )
44
+ parsers.each do | parser |
45
+ return parser.call(hash) if parser.can_parse?(hash)
46
+ end
47
+ raise Pact::UnrecognizePactFormatError.new("This document does not use a recognised Pact format: #{hash}")
39
48
  end
40
49
 
41
50
  def self.from_json string
@@ -45,6 +54,8 @@ module Pact
45
54
 
46
55
  def self.from_uri uri, options = {}
47
56
  from_json(Pact::PactFile.read(uri, options))
57
+ rescue UnrecognizePactFormatError
58
+ raise Pact::UnrecognizePactFormatError.new("This document does not use a recognised Pact format. Please check that #{uri} is a valid pact file.")
48
59
  end
49
60
 
50
61
  def self.maintain_backwards_compatiblity_with_producer_keys string
@@ -54,9 +65,9 @@ module Pact
54
65
  def find_interaction criteria
55
66
  interactions = find_interactions criteria
56
67
  if interactions.size == 0
57
- raise "Could not find interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}."
68
+ raise Pact::Error.new("Could not find interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}.")
58
69
  elsif interactions.size > 1
59
- raise "Found more than 1 interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}."
70
+ raise Pact::Error.new("Found more than 1 interaction matching #{criteria} in pact file between #{consumer.name} and #{provider.name}.")
60
71
  end
61
72
  interactions.first
62
73
  end
@@ -0,0 +1,37 @@
1
+ require 'pact/specification_version'
2
+
3
+ module Pact
4
+ class HttpConsumerContractParser
5
+ include SymbolizeKeys
6
+
7
+ def call(hash)
8
+ hash = symbolize_keys(hash)
9
+ v = pact_specification_version(hash)
10
+ options = { pact_specification_version: v }
11
+
12
+ if v.after? 3
13
+ Pact.configuration.error_stream.puts "WARN: This code only knows how to parse v3 pacts, attempting to parse v#{options[:pact_specification_version]} pact using v3 code."
14
+ end
15
+
16
+ interactions = hash[:interactions].collect { |hash| Interaction.from_hash(hash, options) }
17
+ ConsumerContract.new(
18
+ :consumer => ServiceConsumer.from_hash(hash[:consumer]),
19
+ :provider => ServiceProvider.from_hash(hash[:provider]),
20
+ :interactions => interactions
21
+ )
22
+ end
23
+
24
+ def pact_specification_version hash
25
+ # TODO handle all 3 ways of defining this...
26
+ # metadata.pactSpecificationVersion
27
+ maybe_pact_specification_version_1 = hash[:metadata] && hash[:metadata]['pactSpecification'] && hash[:metadata]['pactSpecification']['version']
28
+ maybe_pact_specification_version_2 = hash[:metadata] && hash[:metadata]['pactSpecificationVersion']
29
+ pact_specification_version = maybe_pact_specification_version_1 || maybe_pact_specification_version_2
30
+ pact_specification_version ? Pact::SpecificationVersion.new(pact_specification_version) : Pact::SpecificationVersion::NIL_VERSION
31
+ end
32
+
33
+ def can_parse?(hash)
34
+ hash.key?('interactions') || hash.key?(:interactions)
35
+ end
36
+ end
37
+ end
@@ -1,76 +1,71 @@
1
- require 'pact/consumer_contract/request'
2
- require 'pact/consumer_contract/response'
3
- require 'pact/symbolize_keys'
4
1
  require 'pact/shared/active_support_support'
5
- require 'pact/matching_rules'
6
- require 'pact/errors'
2
+ require 'pact/consumer_contract/interaction_parser'
7
3
 
8
4
  module Pact
9
- class Interaction
5
+ class Interaction
10
6
  include ActiveSupportSupport
11
- include SymbolizeKeys
12
7
 
13
- attr_accessor :description, :request, :response, :provider_state
8
+ attr_accessor :description, :request, :response, :provider_state
14
9
 
15
- def initialize attributes = {}
16
- @description = attributes[:description]
17
- @request = attributes[:request]
18
- @response = attributes[:response]
19
- @provider_state = attributes[:provider_state] || attributes[:providerState]
20
- end
10
+ def initialize attributes = {}
11
+ @description = attributes[:description]
12
+ @request = attributes[:request]
13
+ @response = attributes[:response]
14
+ @provider_state = attributes[:provider_state] || attributes[:providerState]
15
+ end
21
16
 
22
- def self.from_hash hash
23
- request_hash = Pact::MatchingRules.merge(hash['request'], hash['request']['matchingRules'])
24
- request = Pact::Request::Expected.from_hash(request_hash)
25
- response_hash = Pact::MatchingRules.merge(hash['response'], hash['response']['matchingRules'])
26
- response = Pact::Response.from_hash(response_hash)
27
- new(symbolize_keys(hash).merge(request: request, response: response))
28
- end
17
+ def self.from_hash hash, options = {}
18
+ InteractionParser.call(hash, options)
19
+ end
29
20
 
30
- def to_hash
31
- {
32
- description: description,
33
- provider_state: provider_state,
34
- request: request.to_hash,
35
- response: response.to_hash
36
- }
37
- end
21
+ def to_hash
22
+ {
23
+ description: description,
24
+ provider_state: provider_state,
25
+ request: request.to_hash,
26
+ response: response.to_hash
27
+ }
28
+ end
38
29
 
39
- def validate!
40
- raise Pact::InvalidInteractionError.new(self) unless description && request && response
41
- end
30
+ def http?
31
+ true
32
+ end
33
+
34
+ def validate!
35
+ raise Pact::InvalidInteractionError.new(self) unless description && request && response
36
+ end
42
37
 
43
- def matches_criteria? criteria
44
- criteria.each do | key, value |
45
- unless match_criterion self.send(key.to_s), value
46
- return false
47
- end
38
+ def matches_criteria? criteria
39
+ criteria.each do | key, value |
40
+ unless match_criterion self.send(key.to_s), value
41
+ return false
48
42
  end
49
- true
50
43
  end
44
+ true
45
+ end
51
46
 
52
- def match_criterion target, criterion
53
- target == criterion || (criterion.is_a?(Regexp) && criterion.match(target))
54
- end
47
+ def match_criterion target, criterion
48
+ target == criterion || (criterion.is_a?(Regexp) && criterion.match(target))
49
+ end
55
50
 
56
- def == other
57
- other.is_a?(Interaction) && to_hash == other.to_hash
58
- end
51
+ def == other
52
+ other.is_a?(Interaction) && to_hash == other.to_hash
53
+ end
59
54
 
60
- def eq? other
61
- self == other
62
- end
55
+ def eq? other
56
+ self == other
57
+ end
63
58
 
64
- def description_with_provider_state_quoted
65
- provider_state ? "\"#{description}\" given \"#{provider_state}\"" : "\"#{description}\""
66
- end
59
+ def description_with_provider_state_quoted
60
+ provider_state ? "\"#{description}\" given \"#{provider_state}\"" : "\"#{description}\""
61
+ end
67
62
 
68
- def request_modifies_resource_without_checking_response_body?
69
- request.modifies_resource? && response.body_allows_any_value?
70
- end
63
+ def request_modifies_resource_without_checking_response_body?
64
+ request.modifies_resource? && response.body_allows_any_value?
65
+ end
71
66
 
72
- def to_s
73
- to_hash.to_s
74
- end
75
- end
67
+ def to_s
68
+ to_hash.to_s
69
+ end
70
+ end
76
71
  end
@@ -0,0 +1,23 @@
1
+ require 'pact/specification_version'
2
+ require 'pact/consumer_contract/interaction_v2_parser'
3
+ require 'pact/consumer_contract/interaction_v3_parser'
4
+
5
+ module Pact
6
+ class InteractionParser
7
+ def self.call hash, options = {}
8
+ pact_specification_version = options[:pact_specification_version] || Pact::SpecificationVersion::NIL_VERSION
9
+ case pact_specification_version.major
10
+ when nil, 0, 1, 2 then parse_v2_interaction(hash, pact_specification_version: pact_specification_version)
11
+ else parse_v3_interaction(hash, pact_specification_version: pact_specification_version)
12
+ end
13
+ end
14
+
15
+ def self.parse_v2_interaction hash, options
16
+ InteractionV2Parser.call(hash, options)
17
+ end
18
+
19
+ def self.parse_v3_interaction hash, options
20
+ InteractionV3Parser.call(hash, options)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ require 'pact/consumer_contract/request'
2
+ require 'pact/consumer_contract/response'
3
+ require 'pact/symbolize_keys'
4
+ require 'pact/matching_rules'
5
+ require 'pact/errors'
6
+
7
+ module Pact
8
+ class InteractionV2Parser
9
+
10
+ include SymbolizeKeys
11
+
12
+ def self.call hash, options
13
+ request = parse_request(hash['request'], options)
14
+ response = parse_response(hash['response'], options)
15
+ Interaction.new(symbolize_keys(hash).merge(request: request, response: response))
16
+ end
17
+
18
+ def self.parse_request request_hash, options
19
+ request_hash = Pact::MatchingRules.merge(request_hash, request_hash['matchingRules'], options)
20
+ Pact::Request::Expected.from_hash(request_hash)
21
+ end
22
+
23
+ def self.parse_response response_hash, options
24
+ response_hash = Pact::MatchingRules.merge(response_hash, response_hash['matchingRules'], options)
25
+ Pact::Response.from_hash(response_hash)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,61 @@
1
+ require 'pact/consumer_contract/request'
2
+ require 'pact/consumer_contract/response'
3
+ require 'pact/symbolize_keys'
4
+ require 'pact/matching_rules'
5
+ require 'pact/errors'
6
+ require 'pact/consumer_contract/string_with_matching_rules'
7
+
8
+ module Pact
9
+ class InteractionV3Parser
10
+
11
+ include SymbolizeKeys
12
+
13
+ def self.call hash, options
14
+ request = parse_request(hash['request'], options)
15
+ response = parse_response(hash['response'], options)
16
+ Interaction.new(symbolize_keys(hash).merge(request: request, response: response))
17
+ end
18
+
19
+ def self.parse_request request_hash, options
20
+ request_matching_rules = request_hash['matchingRules'] || {}
21
+ if request_hash['body'].is_a?(String)
22
+ parse_request_with_string_body(request_hash, request_matching_rules['body'] || {}, options)
23
+ else
24
+ parse_request_with_non_string_body(request_hash, request_matching_rules, options)
25
+ end
26
+ end
27
+
28
+ def self.parse_response response_hash, options
29
+ response_matching_rules = response_hash['matchingRules'] || {}
30
+ if response_hash['body'].is_a?(String)
31
+ parse_response_with_string_body(response_hash, response_matching_rules['body'] || {}, options)
32
+ else
33
+ parse_response_with_non_string_body(response_hash, response_matching_rules, options)
34
+ end
35
+ end
36
+
37
+ def self.parse_request_with_non_string_body request_hash, request_matching_rules, options
38
+ request_hash = request_hash.keys.each_with_object({}) do | key, new_hash |
39
+ new_hash[key] = Pact::MatchingRules.merge(request_hash[key], request_matching_rules[key], options)
40
+ end
41
+ Pact::Request::Expected.from_hash(request_hash)
42
+ end
43
+
44
+ def self.parse_response_with_non_string_body response_hash, response_matching_rules, options
45
+ response_hash = response_hash.keys.each_with_object({}) do | key, new_hash |
46
+ new_hash[key] = Pact::MatchingRules.merge(response_hash[key], response_matching_rules[key], options)
47
+ end
48
+ Pact::Response.from_hash(response_hash)
49
+ end
50
+
51
+ def self.parse_request_with_string_body request_hash, request_matching_rules, options
52
+ string_with_matching_rules = StringWithMatchingRules.new(request_hash['body'], options[:pact_specification_version], request_matching_rules)
53
+ Pact::Request::Expected.from_hash(request_hash.merge('body' => string_with_matching_rules))
54
+ end
55
+
56
+ def self.parse_response_with_string_body response_hash, response_matching_rules, options
57
+ string_with_matching_rules = StringWithMatchingRules.new(response_hash['body'], options[:pact_specification_version], response_matching_rules)
58
+ Pact::Response.from_hash(response_hash.merge('body' => string_with_matching_rules))
59
+ end
60
+ end
61
+ end
@@ -36,39 +36,25 @@ module Pact
36
36
  end
37
37
 
38
38
  def render_pact(uri_string, options)
39
- uri_obj = URI(uri_string)
40
- if uri_obj.userinfo
41
- options[:username] = uri_obj.user unless options[:username]
42
- options[:password] = uri_obj.password unless options[:password]
43
- end
44
- get(uri_obj, options)
39
+ local?(uri_string) ? get_local(uri_string, options) : get_remote_with_retry(uri_string, options)
45
40
  end
46
41
 
47
42
  private
48
43
 
49
- def get(uri, options)
50
- local?(uri) ? get_local(uri, options) : get_remote_with_retry(uri, options)
51
- end
52
-
53
44
  def local? uri
54
- !uri.host
45
+ !uri.start_with?("http://", "https://")
55
46
  end
56
47
 
57
- def get_local(uri, _)
58
- File.read uri.to_s
59
- end
60
-
61
- def get_remote(uri, options)
62
- request = Net::HTTP::Get.new(uri)
63
- request.basic_auth(options[:username], options[:password]) if options[:username]
64
- Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
65
- http.open_timeout = options[:open_timeout] || OPEN_TIMEOUT
66
- http.read_timeout = options[:read_timeout] || READ_TIMEOUT
67
- http.request(request)
68
- end
48
+ def get_local(filepath, _)
49
+ File.read windows_safe(filepath)
69
50
  end
70
51
 
71
- def get_remote_with_retry(uri, options)
52
+ def get_remote_with_retry(uri_string, options)
53
+ uri = URI(uri_string)
54
+ if uri.userinfo
55
+ options[:username] = uri.user unless options[:username]
56
+ options[:password] = uri.password unless options[:password]
57
+ end
72
58
  ((options[:retry_limit] || RETRY_LIMIT) + 1).times do |i|
73
59
  begin
74
60
  response = get_remote(uri, options)
@@ -89,6 +75,16 @@ module Pact
89
75
  end
90
76
  end
91
77
 
78
+ def get_remote(uri, options)
79
+ request = Net::HTTP::Get.new(uri)
80
+ request.basic_auth(options[:username], options[:password]) if options[:username]
81
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
82
+ http.open_timeout = options[:open_timeout] || OPEN_TIMEOUT
83
+ http.read_timeout = options[:read_timeout] || READ_TIMEOUT
84
+ http.request(request)
85
+ end
86
+ end
87
+
92
88
  def success?(response)
93
89
  response.code.to_i == 200
94
90
  end
@@ -104,5 +100,9 @@ module Pact
104
100
  def delay_retry(count)
105
101
  Kernel.sleep(2 ** count * 0.3)
106
102
  end
103
+
104
+ def windows_safe(uri)
105
+ uri.start_with?("http") ? uri : uri.gsub("\\", File::SEPARATOR)
106
+ end
107
107
  end
108
108
  end
@@ -56,6 +56,8 @@ module Pact
56
56
  def insert(hash, k, v)
57
57
  if Hash === v
58
58
  v.each {|k2, v2| insert(hash, :"#{k}[#{k2}]", v2) }
59
+ elsif Pact::ArrayLike === v
60
+ hash[k.to_sym] = v
59
61
  else
60
62
  hash[k.to_sym] = [*v]
61
63
  end
@@ -4,7 +4,6 @@ module Pact
4
4
  class QueryString
5
5
 
6
6
  include ActiveSupportSupport
7
- include Pact::Matchers
8
7
 
9
8
  def initialize query
10
9
  @query = query.nil? ? query : query.dup
@@ -27,7 +26,8 @@ module Pact
27
26
  end
28
27
 
29
28
  def difference(other)
30
- diff(query, other.query)
29
+ require 'pact/matchers' # avoid recursive loop between this file and pact/matchers
30
+ Pact::Matchers.diff(query, other.query)
31
31
  end
32
32
 
33
33
  def query
@@ -2,9 +2,7 @@ require 'pact/shared/request'
2
2
  require 'pact/shared/null_expectation'
3
3
 
4
4
  module Pact
5
-
6
5
  module Request
7
-
8
6
  class Expected < Pact::Request::Base
9
7
 
10
8
  DEFAULT_OPTIONS = {:allow_unexpected_keys => false}.freeze
@@ -80,8 +78,6 @@ module Pact
80
78
  def body_differ
81
79
  Pact.configuration.body_differ_for_content_type content_type
82
80
  end
83
-
84
81
  end
85
-
86
82
  end
87
- end
83
+ end
@@ -0,0 +1,17 @@
1
+ module Pact
2
+ class StringWithMatchingRules < String
3
+ attr_reader :matching_rules
4
+ attr_reader :pact_specification_version
5
+
6
+ def initialize string, pact_specification_version, matching_rules = {}
7
+ super(string)
8
+ @matching_rules = matching_rules
9
+ @pact_specification_version = pact_specification_version
10
+ end
11
+
12
+ # How can we show the matching rules too?
13
+ def to_s
14
+ super
15
+ end
16
+ end
17
+ end