hs-pact-support 1.17.1

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 (75) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +620 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +5 -0
  5. data/lib/pact/array_like.rb +49 -0
  6. data/lib/pact/configuration.rb +193 -0
  7. data/lib/pact/consumer/request.rb +27 -0
  8. data/lib/pact/consumer_contract/consumer_contract.rb +97 -0
  9. data/lib/pact/consumer_contract/file_name.rb +22 -0
  10. data/lib/pact/consumer_contract/headers.rb +51 -0
  11. data/lib/pact/consumer_contract/http_consumer_contract_parser.rb +37 -0
  12. data/lib/pact/consumer_contract/interaction.rb +81 -0
  13. data/lib/pact/consumer_contract/interaction_parser.rb +23 -0
  14. data/lib/pact/consumer_contract/interaction_v2_parser.rb +57 -0
  15. data/lib/pact/consumer_contract/interaction_v3_parser.rb +92 -0
  16. data/lib/pact/consumer_contract/pact_file.rb +157 -0
  17. data/lib/pact/consumer_contract/provider_state.rb +34 -0
  18. data/lib/pact/consumer_contract/query.rb +138 -0
  19. data/lib/pact/consumer_contract/query_hash.rb +89 -0
  20. data/lib/pact/consumer_contract/query_string.rb +51 -0
  21. data/lib/pact/consumer_contract/request.rb +83 -0
  22. data/lib/pact/consumer_contract/response.rb +58 -0
  23. data/lib/pact/consumer_contract/service_consumer.rb +28 -0
  24. data/lib/pact/consumer_contract/service_provider.rb +28 -0
  25. data/lib/pact/consumer_contract/string_with_matching_rules.rb +17 -0
  26. data/lib/pact/consumer_contract.rb +1 -0
  27. data/lib/pact/errors.rb +21 -0
  28. data/lib/pact/helpers.rb +60 -0
  29. data/lib/pact/http/authorization_header_redactor.rb +32 -0
  30. data/lib/pact/logging.rb +14 -0
  31. data/lib/pact/matchers/actual_type.rb +16 -0
  32. data/lib/pact/matchers/base_difference.rb +39 -0
  33. data/lib/pact/matchers/differ.rb +153 -0
  34. data/lib/pact/matchers/difference.rb +13 -0
  35. data/lib/pact/matchers/difference_indicator.rb +26 -0
  36. data/lib/pact/matchers/embedded_diff_formatter.rb +60 -0
  37. data/lib/pact/matchers/expected_type.rb +35 -0
  38. data/lib/pact/matchers/extract_diff_messages.rb +76 -0
  39. data/lib/pact/matchers/index_not_found.rb +15 -0
  40. data/lib/pact/matchers/list_diff_formatter.rb +103 -0
  41. data/lib/pact/matchers/matchers.rb +285 -0
  42. data/lib/pact/matchers/multipart_form_diff_formatter.rb +41 -0
  43. data/lib/pact/matchers/no_diff_at_index.rb +18 -0
  44. data/lib/pact/matchers/regexp_difference.rb +13 -0
  45. data/lib/pact/matchers/type_difference.rb +16 -0
  46. data/lib/pact/matchers/unexpected_index.rb +11 -0
  47. data/lib/pact/matchers/unexpected_key.rb +11 -0
  48. data/lib/pact/matchers/unix_diff_formatter.rb +157 -0
  49. data/lib/pact/matchers.rb +1 -0
  50. data/lib/pact/matching_rules/extract.rb +91 -0
  51. data/lib/pact/matching_rules/jsonpath.rb +58 -0
  52. data/lib/pact/matching_rules/merge.rb +125 -0
  53. data/lib/pact/matching_rules/v3/extract.rb +94 -0
  54. data/lib/pact/matching_rules/v3/merge.rb +141 -0
  55. data/lib/pact/matching_rules.rb +30 -0
  56. data/lib/pact/reification.rb +56 -0
  57. data/lib/pact/rspec.rb +51 -0
  58. data/lib/pact/shared/active_support_support.rb +65 -0
  59. data/lib/pact/shared/dsl.rb +76 -0
  60. data/lib/pact/shared/form_differ.rb +32 -0
  61. data/lib/pact/shared/jruby_support.rb +18 -0
  62. data/lib/pact/shared/json_differ.rb +10 -0
  63. data/lib/pact/shared/key_not_found.rb +15 -0
  64. data/lib/pact/shared/multipart_form_differ.rb +16 -0
  65. data/lib/pact/shared/null_expectation.rb +31 -0
  66. data/lib/pact/shared/request.rb +106 -0
  67. data/lib/pact/shared/text_differ.rb +11 -0
  68. data/lib/pact/something_like.rb +49 -0
  69. data/lib/pact/specification_version.rb +18 -0
  70. data/lib/pact/support/version.rb +5 -0
  71. data/lib/pact/support.rb +12 -0
  72. data/lib/pact/symbolize_keys.rb +13 -0
  73. data/lib/pact/term.rb +85 -0
  74. data/lib/tasks/pact.rake +29 -0
  75. metadata +327 -0
@@ -0,0 +1,91 @@
1
+ require 'pact/something_like'
2
+ require 'pact/array_like'
3
+ require 'pact/term'
4
+
5
+ module Pact
6
+ module MatchingRules
7
+ class Extract
8
+
9
+ def self.call matchable
10
+ new(matchable).call
11
+ end
12
+
13
+ def initialize matchable
14
+ @matchable = matchable
15
+ @rules = Hash.new
16
+ end
17
+
18
+ def call
19
+ recurse matchable, "$", nil
20
+ rules
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :matchable, :rules
26
+
27
+ def recurse object, path, match_type
28
+ case object
29
+ when Hash then recurse_hash(object, path, match_type)
30
+ when Array then recurse_array(object, path, match_type)
31
+ when Pact::SomethingLike then handle_something_like(object, path, match_type)
32
+ when Pact::ArrayLike then handle_array_like(object, path, match_type)
33
+ when Pact::Term then record_regex_rule object, path
34
+ when Pact::QueryString then recurse(object.query, path, match_type)
35
+ when Pact::QueryHash then recurse_hash(object.query, path, match_type)
36
+ end
37
+ end
38
+
39
+ def recurse_hash hash, path, match_type
40
+ hash.each do | (key, value) |
41
+ recurse value, "#{path}#{next_path_part(key)}", match_type
42
+ end
43
+ end
44
+
45
+ def recurse_array new_array, path, match_type
46
+ new_array.each_with_index do | value, index |
47
+ recurse value, "#{path}[#{index}]", match_type
48
+ end
49
+ end
50
+
51
+ def handle_something_like something_like, path, match_type
52
+ record_match_type_rule path, "type"
53
+ recurse something_like.contents, path, "type"
54
+ end
55
+
56
+ def handle_array_like array_like, path, match_type
57
+ record_rule "#{path}", 'min' => array_like.min
58
+ record_match_type_rule "#{path}[*].*", 'type'
59
+ recurse array_like.contents, "#{path}[*]", :array_like
60
+ end
61
+
62
+ def record_rule path, rule
63
+ rules[path] ||= {}
64
+ rules[path] = rules[path].merge(rule)
65
+ end
66
+
67
+ def record_regex_rule term, path
68
+ rules[path] ||= {}
69
+ rules[path]['match'] = 'regex'
70
+ rules[path]['regex'] = term.matcher.inspect[1..-2]
71
+ end
72
+
73
+ def record_match_type_rule path, match_type
74
+ unless match_type == :array_like || match_type.nil?
75
+ rules[path] ||= {}
76
+ rules[path]['match'] = match_type
77
+ end
78
+ end
79
+
80
+ # Beth: there's a potential bug if the key contains a dot and a single quote.
81
+ # Not sure what to do then.
82
+ def next_path_part key
83
+ if key.to_s.include?('.')
84
+ "['#{key}']"
85
+ else
86
+ ".#{key}"
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,58 @@
1
+ require 'strscan'
2
+
3
+ # Ripped with appreciation from Joshua Hull's useful JsonPath gem
4
+ # https://github.com/joshbuddy/jsonpath/blob/792ff9a928998f4252692cd3c1ba378ed931a5aa/lib/jsonpath.rb
5
+ # Only including the code that Pact needs, to reduce dependencies and potential gem version clashes.
6
+
7
+ module Pact
8
+ module MatchingRules
9
+ class JsonPath
10
+
11
+ attr_reader :path
12
+
13
+ def initialize(path)
14
+ scanner = StringScanner.new(path)
15
+ @path = []
16
+ while not scanner.eos?
17
+ if token = scanner.scan(/\$/)
18
+ @path << token
19
+ elsif token = scanner.scan(/@/)
20
+ @path << token
21
+ elsif token = scanner.scan(/[:a-zA-Z0-9_-]+/)
22
+ @path << "['#{token}']"
23
+ elsif token = scanner.scan(/'(.*?)'/)
24
+ @path << "[#{token}]"
25
+ elsif token = scanner.scan(/\[/)
26
+ count = 1
27
+ while !count.zero?
28
+ if t = scanner.scan(/\[/)
29
+ token << t
30
+ count += 1
31
+ elsif t = scanner.scan(/\]/)
32
+ token << t
33
+ count -= 1
34
+ elsif t = scanner.scan(/[^\[\]]*/)
35
+ token << t
36
+ end
37
+ end
38
+ @path << token
39
+ elsif token = scanner.scan(/\.\./)
40
+ @path << token
41
+ elsif scanner.scan(/\./)
42
+ nil
43
+ elsif token = scanner.scan(/\*/)
44
+ @path << token
45
+ elsif token = scanner.scan(/[><=] \d+/)
46
+ @path.last << token
47
+ elsif token = scanner.scan(/./)
48
+ @path.last << token
49
+ end
50
+ end
51
+ end
52
+
53
+ def to_s
54
+ path.join
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,125 @@
1
+ require 'pact/array_like'
2
+ require 'pact/matching_rules/jsonpath'
3
+
4
+ module Pact
5
+ module MatchingRules
6
+ class Merge
7
+
8
+ def self.call expected, matching_rules, root_path = '$'
9
+ new(expected, matching_rules, root_path).call
10
+ end
11
+
12
+ def initialize expected, matching_rules, root_path
13
+ @expected = expected
14
+ @matching_rules = standardise_paths(matching_rules)
15
+ @root_path = JsonPath.new(root_path).to_s
16
+ @used_rules = []
17
+ end
18
+
19
+ def call
20
+ return @expected if @matching_rules.nil? || @matching_rules.empty?
21
+ recurse(@expected, @root_path).tap { log_ignored_rules }
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
+ recursed = 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
+
41
+ wrap(recursed, path)
42
+ end
43
+
44
+ def recurse_hash hash, path
45
+ recursed = hash.each_with_object({}) do | (k, v), new_hash |
46
+ new_path = path + "['#{k}']"
47
+ new_hash[k] = recurse(v, new_path)
48
+ end
49
+ end
50
+
51
+ def recurse_array array, path
52
+ parent_match_rule = find_rule(path, 'match')
53
+ log_used_rule(path, 'match', parent_match_rule) if parent_match_rule
54
+
55
+ array_like_children_path = "#{path}[*]*"
56
+ children_match_rule = find_rule(array_like_children_path, 'match')
57
+ log_used_rule(array_like_children_path, 'match', children_match_rule) if children_match_rule
58
+
59
+ min = find_rule(path, 'min')
60
+ log_used_rule(path, 'min', min) if min
61
+
62
+ if min && (children_match_rule == 'type' || (children_match_rule.nil? && parent_match_rule == 'type'))
63
+ warn_when_not_one_example_item(array, path)
64
+ Pact::ArrayLike.new(recurse(array.first, "#{path}[*]"), min: min)
65
+ else
66
+ new_array = []
67
+ array.each_with_index do | item, index |
68
+ new_path = path + "[#{index}]"
69
+ new_array << recurse(item, new_path)
70
+ end
71
+ new_array
72
+ end
73
+ end
74
+
75
+ def warn_when_not_one_example_item array, path
76
+ unless array.size == 1
77
+ Pact.configuration.error_stream.puts "WARN: Only the first item will be used to match the items in the array at #{path}"
78
+ end
79
+ end
80
+
81
+ def wrap object, path
82
+ if find_rule(path, 'match') == 'type' && !find_rule(path, 'min')
83
+ handle_match_type(object, path)
84
+ elsif find_rule(path, 'regex')
85
+ handle_regex(object, path)
86
+ else
87
+ object
88
+ end
89
+ end
90
+
91
+ def handle_match_type object, path
92
+ log_used_rule(path, 'match', 'type')
93
+ Pact::SomethingLike.new(object)
94
+ end
95
+
96
+ def handle_regex object, path
97
+ regex = find_rule(path, 'regex')
98
+ log_used_rule(path, 'match', 'regex') # assumed to be present
99
+ log_used_rule(path, 'regex', regex)
100
+ Pact::Term.new(generate: object, matcher: Regexp.new(regex))
101
+ end
102
+
103
+ def log_ignored_rules
104
+ dup_rules = @matching_rules.dup
105
+ @used_rules.each do | (path, key, value) |
106
+ dup_rules[path].delete(key) if dup_rules[path][key] == value
107
+ end
108
+
109
+ if dup_rules.any?
110
+ dup_rules.each do | path, rules |
111
+ $stderr.puts "WARN: Ignoring unsupported matching rules #{rules} for path #{path}" if rules.any?
112
+ end
113
+ end
114
+ end
115
+
116
+ def find_rule(path, key)
117
+ @matching_rules[path] && @matching_rules[path][key]
118
+ end
119
+
120
+ def log_used_rule path, key, value
121
+ @used_rules << [path, key, value]
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,94 @@
1
+ require 'pact/something_like'
2
+ require 'pact/array_like'
3
+ require 'pact/term'
4
+
5
+ module Pact
6
+ module MatchingRules::V3
7
+ class Extract
8
+
9
+ def self.call matchable
10
+ new(matchable).call
11
+ end
12
+
13
+ def initialize matchable
14
+ @matchable = matchable
15
+ @rules = Hash.new
16
+ end
17
+
18
+ def call
19
+ recurse matchable, "$", nil
20
+ rules
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :matchable, :rules
26
+
27
+ def recurse object, path, match_type
28
+ case object
29
+ when Hash then recurse_hash(object, path, match_type)
30
+ when Array then recurse_array(object, path, match_type)
31
+ when Pact::SomethingLike then handle_something_like(object, path, match_type)
32
+ when Pact::ArrayLike then handle_array_like(object, path, match_type)
33
+ when Pact::Term then record_regex_rule object, path
34
+ when Pact::QueryString then recurse(object.query, path, match_type)
35
+ when Pact::QueryHash then recurse_hash(object.query, path, match_type)
36
+ end
37
+ end
38
+
39
+ def recurse_hash hash, path, match_type
40
+ hash.each do | (key, value) |
41
+ recurse value, "#{path}#{next_path_part(key)}", match_type
42
+ end
43
+ end
44
+
45
+ def recurse_array new_array, path, match_type
46
+ new_array.each_with_index do | value, index |
47
+ recurse value, "#{path}[#{index}]", match_type
48
+ end
49
+ end
50
+
51
+ def handle_something_like something_like, path, match_type
52
+ record_match_type_rule path, "type"
53
+ recurse something_like.contents, path, "type"
54
+ end
55
+
56
+ def handle_array_like array_like, path, match_type
57
+ record_rule "#{path}", 'min' => array_like.min
58
+ record_match_type_rule "#{path}[*].*", 'type'
59
+ recurse array_like.contents, "#{path}[*]", :array_like
60
+ end
61
+
62
+ def record_rule path, rule
63
+ rules[path] ||= {}
64
+ rules[path]['matchers'] ||= []
65
+ rules[path]['matchers'] << rule
66
+ end
67
+
68
+ def record_regex_rule term, path
69
+ rules[path] ||= {}
70
+ rules[path]['matchers'] ||= []
71
+ rule = { 'match' => 'regex', 'regex' => term.matcher.inspect[1..-2]}
72
+ rules[path]['matchers'] << rule
73
+ end
74
+
75
+ def record_match_type_rule path, match_type
76
+ unless match_type == :array_like || match_type.nil?
77
+ rules[path] ||= {}
78
+ rules[path]['matchers'] ||= []
79
+ rules[path]['matchers'] << { 'match' => match_type }
80
+ end
81
+ end
82
+
83
+ # Beth: there's a potential bug if the key contains a dot and a single quote.
84
+ # Not sure what to do then.
85
+ def next_path_part key
86
+ if key.to_s.include?('.')
87
+ "['#{key}']"
88
+ else
89
+ ".#{key}"
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,141 @@
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).tap { log_ignored_rules }
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, rules), new_matching_rules |
29
+ new_matching_rules[JsonPath.new(path).to_s] = Marshal.load(Marshal.dump(rules)) # simplest way to deep clone
30
+ end
31
+ end
32
+
33
+ def recurse expected, path
34
+ recursed = 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
+ wrap(recursed, path)
41
+ end
42
+
43
+ def recurse_hash hash, path
44
+ hash.each_with_object({}) do | (k, v), new_hash |
45
+ new_path = path + "['#{k}']"
46
+ new_hash[k] = recurse(v, new_path)
47
+ end
48
+ end
49
+
50
+ def recurse_array array, path
51
+ # This assumes there is only one rule! TODO make this find the appropriate rule.
52
+ parent_match_rule = @matching_rules[path]['matchers'].first['match'] rescue nil
53
+ array_like_children_path = "#{path}[*]*"
54
+ children_match_rule = @matching_rules[array_like_children_path]['matchers'].first['match'] rescue nil
55
+ min = @matching_rules[path]['matchers'].first['min'] rescue nil
56
+
57
+ if min && children_match_rule == 'type'
58
+ @matching_rules[path]['matchers'].first.delete('min')
59
+ @matching_rules[array_like_children_path]['matchers'].first.delete('match')
60
+ warn_when_not_one_example_item(array, path)
61
+ Pact::ArrayLike.new(recurse(array.first, "#{path}[*]"), min: min)
62
+ elsif min && parent_match_rule == 'type'
63
+ @matching_rules[path]['matchers'].first.delete('min')
64
+ @matching_rules[path]['matchers'].first.delete('match')
65
+ warn_when_not_one_example_item(array, path)
66
+ Pact::ArrayLike.new(recurse(array.first, "#{path}[*]"), min: min)
67
+ else
68
+ new_array = []
69
+ array.each_with_index do | item, index |
70
+ new_path = path + "[#{index}]"
71
+ new_array << recurse(item, new_path)
72
+ end
73
+ new_array
74
+ end
75
+ end
76
+
77
+ def warn_when_not_one_example_item array, path
78
+ unless array.size == 1
79
+ Pact.configuration.error_stream.puts "WARN: Only the first item will be used to match the items in the array at #{path}"
80
+ end
81
+ end
82
+
83
+ def wrap object, path
84
+ rules = @matching_rules[path] && @matching_rules[path]['matchers'] && @matching_rules[path]['matchers'].first
85
+ array_rules = @matching_rules["#{path}[*]*"] && @matching_rules["#{path}[*]*"]['matchers'] && @matching_rules["#{path}[*]*"]['matchers'].first
86
+ return object unless rules || array_rules
87
+
88
+ if rules['match'] == 'type' && !rules.has_key?('min')
89
+ handle_match_type(object, path, rules)
90
+ elsif rules['regex']
91
+ handle_regex(object, path, rules)
92
+ else
93
+ object
94
+ end
95
+ end
96
+
97
+ def handle_match_type object, path, rules
98
+ rules.delete('match')
99
+ Pact::SomethingLike.new(object)
100
+ end
101
+
102
+ def handle_regex object, path, rules
103
+ rules.delete('match')
104
+ regex = rules.delete('regex')
105
+ Pact::Term.new(generate: object, matcher: Regexp.new(regex))
106
+ end
107
+
108
+ def log_ignored_rules
109
+ @matching_rules.each do | jsonpath, rules_hash |
110
+ rules_array = rules_hash["matchers"]
111
+ if rules_array
112
+ ((rules_array.length - 1)..0).each do | index |
113
+ rules_array.delete_at(index) if rules_array[index].empty?
114
+ end
115
+ end
116
+ end
117
+
118
+ if @matching_rules.any?
119
+ @matching_rules.each do | path, rules_hash |
120
+ rules_hash.each do | key, value |
121
+ $stderr.puts "WARN: Ignoring unsupported #{key} #{value} for path #{path}" if value_present?(value)
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ def find_rule(path, key)
128
+ @matching_rules[path] && @matching_rules[path][key]
129
+ end
130
+
131
+ def log_used_rule path, key, value
132
+ @used_rules << [path, key, value]
133
+ end
134
+
135
+ def value_present? value
136
+ value.respond_to?(:any?) ? value.any? : true
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,30 @@
1
+ require 'pact/matching_rules/extract'
2
+ require 'pact/matching_rules/v3/extract'
3
+ require 'pact/matching_rules/merge'
4
+ require 'pact/matching_rules/v3/merge'
5
+
6
+ module Pact
7
+ module MatchingRules
8
+
9
+ # @api public Used by pact-mock_service
10
+ def self.extract object_graph, options = {}
11
+ pact_specification_version = options[:pact_specification_version] || Pact::SpecificationVersion::NIL_VERSION
12
+ case pact_specification_version.major
13
+ when nil, 0, 1, 2
14
+ Extract.(object_graph)
15
+ else
16
+ V3::Extract.(object_graph)
17
+ end
18
+ end
19
+
20
+ def self.merge object_graph, matching_rules, options = {}
21
+ pact_specification_version = options[:pact_specification_version] || Pact::SpecificationVersion::NIL_VERSION
22
+ case pact_specification_version.major
23
+ when nil, 0, 1, 2
24
+ Merge.(object_graph, matching_rules)
25
+ else
26
+ V3::Merge.(object_graph, matching_rules)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,56 @@
1
+ require 'expgen'
2
+ require 'pact/term'
3
+ require 'pact/something_like'
4
+ require 'pact/array_like'
5
+ require 'pact/shared/request'
6
+ require 'pact/consumer_contract/query_hash'
7
+ require 'pact/consumer_contract/query_string'
8
+ require 'pact/consumer_contract/string_with_matching_rules'
9
+
10
+ module Pact
11
+ module Reification
12
+ include ActiveSupportSupport
13
+
14
+ def self.from_term(term)
15
+ case term
16
+ when Pact::Term, Pact::SomethingLike, Pact::ArrayLike
17
+ from_term(term.generate)
18
+ when Regexp
19
+ from_term(Expgen.gen(term))
20
+ when Hash
21
+ term.inject({}) do |mem, (key,t)|
22
+ mem[key] = from_term(t)
23
+ mem
24
+ end
25
+ when Array
26
+ term.map{ |t| from_term(t)}
27
+ when Pact::Request::Base
28
+ from_term(term.to_hash)
29
+ when Pact::QueryString
30
+ from_term(term.query)
31
+ when Pact::QueryHash
32
+ if term.original_string
33
+ term.original_string
34
+ else
35
+ from_term(term.query).map { |k, v|
36
+ if v.nil?
37
+ k
38
+ elsif v.is_a?(Array) #For cases where there are multiple instance of the same parameter
39
+ v.map { |x| "#{k}=#{escape(x)}"}.join('&')
40
+ else
41
+ "#{k}=#{escape(v)}"
42
+ end
43
+ }.join('&')
44
+ end
45
+ when Pact::StringWithMatchingRules
46
+ String.new(term)
47
+ else
48
+ term
49
+ end
50
+ end
51
+
52
+ def self.escape(str)
53
+ URI.encode_www_form_component(str)
54
+ end
55
+ end
56
+ end
data/lib/pact/rspec.rb ADDED
@@ -0,0 +1,51 @@
1
+ # This is horrible, must work out a better way of doing this
2
+ module Pact
3
+ module RSpec
4
+
5
+ def self.color_enabled?
6
+ if ::RSpec.configuration.respond_to?(:color_enabled?)
7
+ ::RSpec.configuration.color_enabled?(::RSpec.configuration.output_stream)
8
+ else
9
+ ::RSpec.configuration.color_enabled?
10
+ end
11
+ end
12
+
13
+ def self.formatter_class
14
+ if ::RSpec::Core::Formatters.respond_to?(:register)
15
+ require 'pact/provider/rspec/formatter_rspec_3'
16
+ Pact::Provider::RSpec::Formatter
17
+ else
18
+ require 'pact/provider/rspec/formatter_rspec_2'
19
+ Pact::Provider::RSpec::Formatter2
20
+ end
21
+ end
22
+
23
+ def self.full_description example
24
+ example.respond_to?(:full_description) ? example.full_description : example.example.full_description
25
+ end
26
+
27
+ def self.runner_defined?
28
+ defined?(::RSpec::Core::Runner)
29
+ end
30
+
31
+ def self.is_rspec_3
32
+ defined?(::RSpec) && ::RSpec::Core::Formatters.respond_to?(:register)
33
+ end
34
+
35
+ def self.is_rspec_2
36
+ defined?(::RSpec) && !is_rspec_3
37
+ end
38
+
39
+ def self.with_rspec_3
40
+ if is_rspec_3
41
+ yield
42
+ end
43
+ end
44
+
45
+ def self.with_rspec_2
46
+ if is_rspec_2
47
+ yield
48
+ end
49
+ end
50
+ end
51
+ end