pact 1.3.0 → 1.3.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.
- data/.travis.yml +1 -1
- data/CHANGELOG.md +14 -0
- data/Gemfile.lock +5 -5
- data/README.md +25 -29
- data/documentation/README.md +9 -7
- data/lib/pact/configuration.rb +83 -12
- data/lib/pact/consumer/mock_service/interaction_mismatch.rb +5 -1
- data/lib/pact/consumer/spec_hooks.rb +7 -4
- data/lib/pact/consumer/world.rb +12 -0
- data/lib/pact/consumer_contract/headers.rb +51 -0
- data/lib/pact/consumer_contract/request.rb +6 -1
- data/lib/pact/provider/configuration/service_provider_dsl.rb +6 -1
- data/lib/pact/provider/matchers/messages.rb +2 -2
- data/lib/pact/provider/rspec.rb +7 -1
- data/lib/pact/provider/rspec/backtrace_formatter.rb +30 -6
- data/lib/pact/provider/rspec/matchers.rb +9 -6
- data/lib/pact/shared/json_differ.rb +15 -0
- data/lib/pact/shared/request.rb +11 -2
- data/lib/pact/shared/text_differ.rb +14 -0
- data/lib/pact/version.rb +1 -1
- data/spec/lib/pact/configuration_spec.rb +127 -5
- data/spec/lib/pact/consumer/mock_service/interaction_mismatch_spec.rb +8 -5
- data/spec/lib/pact/consumer_contract/headers_spec.rb +107 -0
- data/spec/lib/pact/consumer_contract/request_spec.rb +9 -0
- data/spec/lib/pact/matchers/matchers_spec.rb +35 -0
- data/spec/lib/pact/provider/configuration/service_provider_dsl_spec.rb +16 -0
- data/spec/lib/pact/provider/matchers/messages_spec.rb +5 -4
- data/spec/lib/pact/provider/rspec_spec.rb +15 -11
- data/spec/lib/pact/shared/json_differ_spec.rb +36 -0
- data/spec/lib/pact/shared/request_spec.rb +25 -1
- data/spec/lib/pact/shared/text_differ_spec.rb +54 -0
- data/spec/support/pact_helper.rb +2 -0
- data/spec/support/test_app_with_right_content_type_differ.json +23 -0
- data/tasks/pact-test.rake +6 -0
- metadata +72 -30
- checksums.yaml +0 -7
- data/documentation/Testing with pact.png +0 -0
- data/documentation/best-practices.md +0 -33
- data/documentation/development-workflow.md +0 -22
- data/documentation/faq.md +0 -81
- data/documentation/provider-states.md +0 -178
- data/documentation/raq.md +0 -39
- data/documentation/terminology.md +0 -25
- data/documentation/troubleshooting.md +0 -4
- data/documentation/verifying-pacts.md +0 -106
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,20 @@ Do this to generate your change history
|
|
2
2
|
|
3
3
|
git log --pretty=format:' * %h - %s (%an, %ad)'
|
4
4
|
|
5
|
+
### 1.3.1 (11 August 2014)
|
6
|
+
|
7
|
+
* 3432259 - Fixed 'pact:verify broken with rspec-core 3.0.3' https://github.com/realestate-com-au/pact/issues/44 (bethesque, Mon Aug 11 10:14:42 2014 +1000)
|
8
|
+
* e2e8eff - Deleted documentation that has been moved to the wiki (bethesque, Thu Jul 24 15:20:07 2014 +1000)
|
9
|
+
* bcc3143 - Fixing bug 'Method case should not matter when matching requests' https://github.com/realestate-com-au/pact/issues/41 (bethesque, Tue Jul 22 16:51:48 2014 +1000)
|
10
|
+
* d4bfab9 - Adding ability to configure DiffFormatter based on content-type (bethesque, Mon Jun 23 21:22:47 2014 +1000)
|
11
|
+
* eb330ea - Ensured content-type header works in a case insensitive way when looking up the right differ (bethesque, Mon Jun 23 17:23:04 2014 +1000)
|
12
|
+
* 2733e8e - Made header matching case insensitive for requests. Fixing issue https://github.com/realestate-com-au/pact/issues/20 (bethesque, Mon May 26 19:15:48 2014 +1000)
|
13
|
+
* 2b8355d - Added nicer error message for scenario when a service provider app has not been configured, and there is no config.ru (bethesque, Mon Jun 23 09:42:18 2014 +1000)
|
14
|
+
* 1e774bb - Defaulting to TextDiffer if response has no content-type (bethesque, Sat Jun 21 10:34:44 2014 +1000)
|
15
|
+
* 863b093 - Added support for documents without content types (bethesque, Sat Jun 21 10:32:08 2014 +1000)
|
16
|
+
* b21900b - Enabling differs to be configured based on Content-Type (bethesque, Sat Jun 21 10:21:37 2014 +1000)
|
17
|
+
* 527b5d5 - Modified after hook to only write pacts when one or more 'pact => true' examples have run (bethesque, Wed Jun 18 15:15:55 2014 +1000)
|
18
|
+
|
5
19
|
### 1.3.0 (18 June 2014)
|
6
20
|
|
7
21
|
* ea79190 - Modifying (cough*monkeypatching*cough) RSpec::Core::BacktraceFormatter as RSpec3 has some hardcoded exclusion patterns that result in *all* the backtrace lines being shown when pact:verify fails. (bethesque, Wed Jun 18 13:02:38 2014 +1000)
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pact (1.3.
|
4
|
+
pact (1.3.1)
|
5
5
|
awesome_print (~> 1.1)
|
6
6
|
find_a_port (~> 1.0.1)
|
7
7
|
json
|
@@ -50,14 +50,14 @@ GEM
|
|
50
50
|
rspec-core (~> 3.0.0)
|
51
51
|
rspec-expectations (~> 3.0.0)
|
52
52
|
rspec-mocks (~> 3.0.0)
|
53
|
-
rspec-core (3.0.
|
53
|
+
rspec-core (3.0.3)
|
54
54
|
rspec-support (~> 3.0.0)
|
55
|
-
rspec-expectations (3.0.
|
55
|
+
rspec-expectations (3.0.3)
|
56
56
|
diff-lcs (>= 1.2.0, < 2.0)
|
57
57
|
rspec-support (~> 3.0.0)
|
58
|
-
rspec-mocks (3.0.
|
58
|
+
rspec-mocks (3.0.3)
|
59
59
|
rspec-support (~> 3.0.0)
|
60
|
-
rspec-support (3.0.
|
60
|
+
rspec-support (3.0.3)
|
61
61
|
safe_yaml (1.0.3)
|
62
62
|
slop (3.5.0)
|
63
63
|
term-ansicolor (1.3.0)
|
data/README.md
CHANGED
@@ -14,6 +14,12 @@ Travis CI Status: [ control the development of both the consumer and the provider. It is fantastic tool for intra-organsation microservices.
|
16
16
|
|
17
|
+
## What is it not good for?
|
18
|
+
|
19
|
+
* Performance and load testing.
|
20
|
+
* Functional testing of the provider - that is what the provider's own tests should do. Pact is about checking the contents and format of requests and responses.
|
21
|
+
* Situations where you cannot load data into the provider without using the API that you're actually testing.
|
22
|
+
|
17
23
|
## Features
|
18
24
|
|
19
25
|
* A service is mocked using an actual process running on a specified port, so javascript clients can be tested as easily as backend clients.
|
@@ -27,7 +33,7 @@ Pact is most valuable for designing and testing integrations where you (or your
|
|
27
33
|
## How does it work?
|
28
34
|
|
29
35
|
1. In the specs for the provider facing code in the consumer project, expectations are set up on a mock service provider.
|
30
|
-
1. When the specs are run, the requests, and their expected responses, are written to a "pact" file.
|
36
|
+
1. When the specs are run, the mock service returns the expected responses. The requests, and their expected responses, are then written to a "pact" file.
|
31
37
|
1. The requests in the pact file are later replayed against the provider, and the actual responses are checked to make sure they match the expected responses.
|
32
38
|
|
33
39
|
## Why is developing and testing with Pact better than using traditional system integration tests?
|
@@ -37,6 +43,7 @@ Pact is most valuable for designing and testing integrations where you (or your
|
|
37
43
|
* Causes of failure are easier to identify as only one component is being tested at a time.
|
38
44
|
* Design of service provider is improved by considering first how the data is actually going to be used, rather than how it is most easily retrieved and serialised.
|
39
45
|
* No separate integration environment required for automated integration tests - pact tests run in standalone CI builds.
|
46
|
+
* Integration flows that would traditionally require running multiple services at the same time can be broken down and each integration point tested separately.
|
40
47
|
|
41
48
|
## Contact
|
42
49
|
|
@@ -180,7 +187,7 @@ require 'pact/tasks'
|
|
180
187
|
|
181
188
|
Create a `pact_helper.rb` in your service provider project. The recommended place is `spec/service_consumers/pact_helper.rb`.
|
182
189
|
|
183
|
-
See [Verifying Pacts](
|
190
|
+
See [Verifying Pacts](https://github.com/realestate-com-au/pact/wiki/Verifying-pacts) and the [Provider](documentation/configuration.md#provider) section of the Configuration documentation for more information.
|
184
191
|
|
185
192
|
```ruby
|
186
193
|
# In specs/service_consumers/pact_helper.rb
|
@@ -220,29 +227,8 @@ Yay! Your provider now honours the pact it has with your consumer. You can now h
|
|
220
227
|
|
221
228
|
### Using provider states
|
222
229
|
|
223
|
-
|
224
|
-
|
225
|
-
Read more about provider states [here](/documentation/provider-states.md).
|
226
|
-
|
227
|
-
### Verifying pacts
|
230
|
+
Each interaction in a pact is verified in isolation, with no context maintained from the previous interactions. So how do you test a request that requires data to already exist on the provider? Read about provider states [here](https://github.com/realestate-com-au/pact/wiki/Provider-states).
|
228
231
|
|
229
|
-
You can verify a pact at an arbitrary local or remote URL
|
230
|
-
|
231
|
-
$ rake pact:verify:at[../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json]
|
232
|
-
$ rake pact:verify:at[http://build-box/MyConsumerBuild/latestSuccessful/artifacts/my_consumer-my_provider.json]
|
233
|
-
|
234
|
-
To make a shortcut task for pact at an arbitrary URL, add the following to your Rakefile. The pact.uri may be a local file system path or a remote URL.
|
235
|
-
|
236
|
-
```ruby
|
237
|
-
# In Rakefile or /tasks/pact.rake
|
238
|
-
|
239
|
-
# This creates a rake task that can be executed by running
|
240
|
-
# $ rake pact:verify:dev
|
241
|
-
|
242
|
-
Pact::VerificationTask.new(:dev) do | pact |
|
243
|
-
pact.uri '../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json'
|
244
|
-
end
|
245
|
-
```
|
246
232
|
|
247
233
|
## Configuration
|
248
234
|
|
@@ -250,15 +236,20 @@ See the [Configuration](/documentation/configuration.md) section of the document
|
|
250
236
|
|
251
237
|
## Pact best practices
|
252
238
|
|
253
|
-
As in all things, there are good ways to implement Pacts, and there are not so good ways. Check out the [Best practices](/
|
239
|
+
As in all things, there are good ways to implement Pacts, and there are not so good ways. Check out the [Best practices](https://github.com/realestate-com-au/pact/wiki/Best-practices) section of the documentation to make sure you're not Pacting it Wrong.
|
254
240
|
|
255
241
|
## Docs
|
256
242
|
|
257
243
|
* [Example](example)
|
258
|
-
* [
|
259
|
-
* [
|
260
|
-
* [
|
261
|
-
* [
|
244
|
+
* [Configuration](documentation/configuration.md)
|
245
|
+
* [Terminology](https://github.com/realestate-com-au/pact/wiki/Terminology)
|
246
|
+
* [Provider States](https://github.com/realestate-com-au/pact/wiki/Provider-states)
|
247
|
+
* [Verifying pacts](https://github.com/realestate-com-au/pact/wiki/Verifying-pacts)
|
248
|
+
* [Frequently asked questions](https://github.com/realestate-com-au/pact/wiki/FAQ)
|
249
|
+
* [Rarely asked questions](https://github.com/realestate-com-au/pact/wiki/RAQ)
|
250
|
+
* [Best practices](https://github.com/realestate-com-au/pact/wiki/Best-practices)
|
251
|
+
* [Troubleshooting](https://github.com/realestate-com-au/pact/wiki/Troubleshooting)
|
252
|
+
* [Testing with pact diagram](https://github.com/realestate-com-au/pact/wiki/Testing with pact.png)
|
262
253
|
|
263
254
|
## Related libraries
|
264
255
|
|
@@ -270,6 +261,8 @@ As in all things, there are good ways to implement Pacts, and there are not so g
|
|
270
261
|
|
271
262
|
[Pact JVM](https://github.com/DiUS/pact-jvm) - A Pact implementation for the JVM (Java and Scala). It generates pact files that are compatible with the Ruby implementation.
|
272
263
|
|
264
|
+
[Pact .NET](https://github.com/SEEK-Jobs/pact-net) - A Pact implementation for .NET.
|
265
|
+
|
273
266
|
[Shokkenki](https://github.com/brentsnook/shokkenki) - Another Consumer Driven Contract gem written by one of Pact's original authors, Brent Snook. Shokkenki allows matchers to be composed using jsonpath expressions and allows auto-generation of mock response values based on regular expressions.
|
274
267
|
|
275
268
|
## Links
|
@@ -301,3 +294,6 @@ Long term:
|
|
301
294
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
302
295
|
4. Push to the branch (`git push origin my-new-feature`)
|
303
296
|
5. Create new Pull Request
|
297
|
+
|
298
|
+
If you would like to implement pact in another language, please check out the [Pact specification](https://github.com/bethesque/pact-specification) and have a chat to one of us on the [pact-dev Google group](https://groups.google.com/forum/#!forum/pact-dev). The vision is to have a compatible pact implementation in all the commonly used languages, your help would be greatly appreciated!
|
299
|
+
|
data/documentation/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
### Pact Documentation
|
2
2
|
|
3
3
|
* Step by step instructions for getting started with pacts can be found in the project [README.md](/README.md#usage)
|
4
|
-
* [Terminology](
|
4
|
+
* [Terminology](https://github.com/realestate-com-au/pact/wiki/Terminology)
|
5
5
|
* [Configuration](configuration.md)
|
6
|
-
* [Provider States](
|
7
|
-
* [
|
8
|
-
* [
|
9
|
-
* [
|
10
|
-
* [
|
11
|
-
* [
|
6
|
+
* [Provider States](https://github.com/realestate-com-au/pact/wiki/Provider-states)
|
7
|
+
* [Verifying pacts](https://github.com/realestate-com-au/pact/wiki/Verifying-pacts)
|
8
|
+
* [Frequently asked questions](https://github.com/realestate-com-au/pact/wiki/FAQ)
|
9
|
+
* [Rarely asked questions](https://github.com/realestate-com-au/pact/wiki/RAQ)
|
10
|
+
* [Best practices](https://github.com/realestate-com-au/pact/wiki/Best-practices)
|
11
|
+
* [Troubleshooting](https://github.com/realestate-com-au/pact/wiki/Troubleshooting)
|
12
|
+
* [Testing with pact diagram](https://github.com/realestate-com-au/pact/wiki/Testing with pact.png)
|
13
|
+
* [Development workflow](https://github.com/realestate-com-au/pact/wiki/Development-workflow)
|
data/lib/pact/configuration.rb
CHANGED
@@ -4,6 +4,8 @@ require 'pact/doc/markdown/generator'
|
|
4
4
|
require 'pact/matchers/unix_diff_formatter'
|
5
5
|
require 'pact/matchers/embedded_diff_formatter'
|
6
6
|
require 'pact/matchers/list_diff_formatter'
|
7
|
+
require 'pact/shared/json_differ'
|
8
|
+
require 'pact/shared/text_differ'
|
7
9
|
|
8
10
|
module Pact
|
9
11
|
|
@@ -17,6 +19,27 @@ module Pact
|
|
17
19
|
:list => Pact::Matchers::ListDiffFormatter
|
18
20
|
}
|
19
21
|
|
22
|
+
|
23
|
+
class NilMatcher
|
24
|
+
def self.=~ other
|
25
|
+
other == nil ? 0 : nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
DIFF_FORMATTER_REGISTRATIONS = [
|
30
|
+
[/.*/, Pact::Matchers::UnixDiffFormatter],
|
31
|
+
[NilMatcher, Pact::Matchers::UnixDiffFormatter]
|
32
|
+
]
|
33
|
+
|
34
|
+
DIFFERS = [
|
35
|
+
[/json/, Pact::JsonDiffer],
|
36
|
+
[NilMatcher, Pact::TextDiffer],
|
37
|
+
[/.*/, Pact::TextDiffer]
|
38
|
+
]
|
39
|
+
|
40
|
+
|
41
|
+
DEFAULT_DIFFER = Pact::TextDiffer
|
42
|
+
|
20
43
|
attr_accessor :pact_dir
|
21
44
|
attr_accessor :log_dir
|
22
45
|
attr_accessor :doc_dir
|
@@ -41,6 +64,11 @@ module Pact
|
|
41
64
|
c
|
42
65
|
end
|
43
66
|
|
67
|
+
def initialize
|
68
|
+
@differ_registrations = []
|
69
|
+
@diff_formatter_registrations = []
|
70
|
+
end
|
71
|
+
|
44
72
|
def logger
|
45
73
|
@logger ||= create_logger
|
46
74
|
end
|
@@ -61,20 +89,29 @@ module Pact
|
|
61
89
|
@doc_generators ||= []
|
62
90
|
end
|
63
91
|
|
64
|
-
|
65
|
-
|
92
|
+
# Should this be deprecated in favour of register_diff_formatter???
|
93
|
+
def diff_formatter= diff_formatter
|
94
|
+
register_diff_formatter /.*/, diff_formatter
|
95
|
+
register_diff_formatter nil, diff_formatter
|
66
96
|
end
|
67
97
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
98
|
+
def register_diff_formatter content_type, diff_formatter
|
99
|
+
key = content_type_regexp_for content_type
|
100
|
+
@diff_formatter_registrations << [key, diff_formatter_for(diff_formatter)]
|
101
|
+
end
|
102
|
+
|
103
|
+
def diff_formatter_for_content_type content_type
|
104
|
+
diff_formatter_registrations.find{ | registration | registration.first =~ content_type }.last
|
105
|
+
end
|
106
|
+
|
107
|
+
def register_body_differ content_type, differ
|
108
|
+
key = content_type_regexp_for content_type
|
109
|
+
validate_differ differ
|
110
|
+
@differ_registrations << [key, differ]
|
111
|
+
end
|
112
|
+
|
113
|
+
def body_differ_for_content_type content_type
|
114
|
+
differ_registrations.find{ | registration | registration.first =~ content_type }.last
|
78
115
|
end
|
79
116
|
|
80
117
|
def log_path
|
@@ -91,6 +128,40 @@ module Pact
|
|
91
128
|
|
92
129
|
private
|
93
130
|
|
131
|
+
def diff_formatter_for input
|
132
|
+
if DIFF_FORMATTERS[input]
|
133
|
+
DIFF_FORMATTERS[input]
|
134
|
+
elsif input.respond_to?(:call)
|
135
|
+
input
|
136
|
+
else
|
137
|
+
raise "Pact diff_formatter needs to respond to call, or be in the preconfigured list: #{DIFF_FORMATTERS.keys}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def validate_differ differ
|
142
|
+
if !differ.respond_to?(:call)
|
143
|
+
raise "Pact.configuration.register_body_differ expects a differ that is a lamda or a class/object that responds to call."
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def content_type_regexp_for content_type
|
148
|
+
case content_type
|
149
|
+
when String then Regexp.new(/^#{Regexp.escape(content_type)}$/)
|
150
|
+
when Regexp then content_type
|
151
|
+
when nil then NilMatcher
|
152
|
+
else
|
153
|
+
raise "Invalid content type used to register a differ (#{content_type.inspect}). Please use a Regexp or a String."
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def differ_registrations
|
158
|
+
@differ_registrations + DIFFERS
|
159
|
+
end
|
160
|
+
|
161
|
+
def diff_formatter_registrations
|
162
|
+
@diff_formatter_registrations + DIFF_FORMATTER_REGISTRATIONS
|
163
|
+
end
|
164
|
+
|
94
165
|
def self.default_log_dir
|
95
166
|
File.expand_path("./log")
|
96
167
|
end
|
@@ -56,10 +56,14 @@ module Pact
|
|
56
56
|
def to_s
|
57
57
|
[
|
58
58
|
"Diff with interaction: #{candidate_interaction.description_with_provider_state_quoted}",
|
59
|
-
|
59
|
+
diff_formatter.call(diff, {colour: false})
|
60
60
|
].join("\n")
|
61
61
|
end
|
62
62
|
|
63
|
+
def diff_formatter
|
64
|
+
Pact.configuration.diff_formatter_for_content_type(candidate_interaction.request.content_type)
|
65
|
+
end
|
66
|
+
|
63
67
|
def diff
|
64
68
|
@diff ||= candidate_interaction.request.difference(actual_request)
|
65
69
|
end
|
@@ -11,6 +11,7 @@ module Pact
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def before_each example_description
|
14
|
+
Pact.consumer_world.register_pact_example_ran
|
14
15
|
Pact.configuration.logger.info "Clearing all expectations"
|
15
16
|
Pact::Consumer::AppManager.instance.ports_of_mock_services.each do | port |
|
16
17
|
Pact::Consumer::MockServiceClient.clear_interactions port, example_description
|
@@ -25,10 +26,12 @@ module Pact
|
|
25
26
|
end
|
26
27
|
|
27
28
|
def after_suite
|
28
|
-
Pact.consumer_world.
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
if Pact.consumer_world.any_pact_examples_ran?
|
30
|
+
Pact.consumer_world.consumer_contract_builders.each { | c | c.write_pact }
|
31
|
+
Pact::Doc::Generate.call
|
32
|
+
Pact::Consumer::AppManager.instance.kill_all
|
33
|
+
Pact::Consumer::AppManager.instance.clear_all
|
34
|
+
end
|
32
35
|
end
|
33
36
|
end
|
34
37
|
end
|
data/lib/pact/consumer/world.rb
CHANGED
@@ -12,6 +12,10 @@ module Pact
|
|
12
12
|
module Consumer
|
13
13
|
class World
|
14
14
|
|
15
|
+
def initialize
|
16
|
+
@any_pact_examples_ran = false
|
17
|
+
end
|
18
|
+
|
15
19
|
def consumer_contract_builders
|
16
20
|
@consumer_contract_builders ||= []
|
17
21
|
end
|
@@ -20,6 +24,14 @@ module Pact
|
|
20
24
|
consumer_contract_builders << consumer_contract_builder
|
21
25
|
end
|
22
26
|
|
27
|
+
def register_pact_example_ran
|
28
|
+
@any_pact_examples_ran = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def any_pact_examples_ran?
|
32
|
+
@any_pact_examples_ran
|
33
|
+
end
|
34
|
+
|
23
35
|
end
|
24
36
|
end
|
25
37
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Pact
|
2
|
+
|
3
|
+
class DuplicateHeaderError < StandardError; end
|
4
|
+
class InvalidHeaderNameTypeError < StandardError; end
|
5
|
+
|
6
|
+
class Headers < Hash
|
7
|
+
|
8
|
+
def initialize hash = {}
|
9
|
+
hash.each_pair do | key, value |
|
10
|
+
check_for_invalid key
|
11
|
+
self[find_matching_key(key)] = value
|
12
|
+
end
|
13
|
+
self.freeze
|
14
|
+
end
|
15
|
+
|
16
|
+
def [] key
|
17
|
+
super(find_matching_key(key))
|
18
|
+
end
|
19
|
+
|
20
|
+
def fetch *args, &block
|
21
|
+
args[0] = find_matching_key(args[0]) if args.first
|
22
|
+
super(*args, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def key? key
|
26
|
+
super(find_matching_key(key))
|
27
|
+
end
|
28
|
+
|
29
|
+
alias_method :has_key?, :key?
|
30
|
+
alias_method :include?, :key?
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def find_matching_key key
|
35
|
+
key = key.to_s
|
36
|
+
match = keys.find { |k| k.downcase == key.downcase }
|
37
|
+
match.nil? ? key : match
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_for_invalid key
|
41
|
+
unless (String === key || Symbol === key)
|
42
|
+
raise InvalidHeaderNameTypeError.new "Header name (#{key}) must be a String or a Symbol."
|
43
|
+
end
|
44
|
+
if key? key
|
45
|
+
raise DuplicateHeaderError.new "Duplicate header found (#{find_matching_key(key)} and #{key}. Please use a comma separated single value when multiple headers with the same name are required."
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -60,8 +60,13 @@ module Pact
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def body_difference(actual_body)
|
63
|
-
|
63
|
+
body_differ.call({:body => body}, {body: actual_body}, allow_unexpected_keys: runtime_options[:allow_unexpected_keys_in_body])
|
64
64
|
end
|
65
|
+
|
66
|
+
def body_differ
|
67
|
+
Pact.configuration.body_differ_for_content_type content_type
|
68
|
+
end
|
69
|
+
|
65
70
|
end
|
66
71
|
|
67
72
|
end
|