pact-support 1.4.0 → 1.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +143 -0
- data/lib/pact/configuration.rb +4 -0
- data/lib/pact/consumer_contract/consumer_contract.rb +19 -8
- data/lib/pact/consumer_contract/http_consumer_contract_parser.rb +37 -0
- data/lib/pact/consumer_contract/interaction.rb +57 -56
- data/lib/pact/consumer_contract/interaction_parser.rb +23 -0
- data/lib/pact/consumer_contract/interaction_v2_parser.rb +34 -0
- data/lib/pact/consumer_contract/interaction_v3_parser.rb +73 -0
- data/lib/pact/consumer_contract/pact_file.rb +24 -24
- data/lib/pact/consumer_contract/provider_state.rb +34 -0
- data/lib/pact/consumer_contract/query.rb +0 -2
- data/lib/pact/consumer_contract/query_hash.rb +6 -0
- data/lib/pact/consumer_contract/query_string.rb +2 -2
- data/lib/pact/consumer_contract/request.rb +1 -5
- data/lib/pact/consumer_contract/string_with_matching_rules.rb +17 -0
- data/lib/pact/matchers/multipart_form_diff_formatter.rb +41 -0
- data/lib/pact/matching_rules/merge.rb +43 -28
- data/lib/pact/matching_rules/v3/extract.rb +94 -0
- data/lib/pact/matching_rules/v3/merge.rb +135 -0
- data/lib/pact/matching_rules.rb +19 -6
- data/lib/pact/reification.rb +6 -3
- data/lib/pact/shared/multipart_form_differ.rb +14 -0
- data/lib/pact/specification_version.rb +18 -0
- data/lib/pact/support/version.rb +1 -1
- data/script/release.sh +1 -1
- data/spec/fixtures/multipart-form-diff.txt +9 -0
- data/spec/fixtures/not-a-pact.json +3 -0
- data/spec/fixtures/pact-http-v2.json +36 -0
- data/spec/fixtures/pact-http-v3.json +36 -0
- data/spec/integration/matching_rules_extract_and_merge_spec.rb +41 -4
- data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +54 -31
- data/spec/lib/pact/consumer_contract/http_consumer_contract_parser_spec.rb +25 -0
- data/spec/lib/pact/consumer_contract/interaction_parser_spec.rb +62 -0
- data/spec/lib/pact/consumer_contract/interaction_spec.rb +2 -26
- data/spec/lib/pact/consumer_contract/interaction_v2_parser_spec.rb +54 -0
- data/spec/lib/pact/consumer_contract/interaction_v3_parser_spec.rb +48 -0
- data/spec/lib/pact/consumer_contract/pact_file_spec.rb +9 -0
- data/spec/lib/pact/consumer_contract/query_hash_spec.rb +23 -0
- data/spec/lib/pact/matchers/multipart_form_diff_formatter_spec.rb +36 -0
- data/spec/lib/pact/matching_rules/merge_spec.rb +198 -110
- data/spec/lib/pact/matching_rules/v3/extract_spec.rb +238 -0
- data/spec/lib/pact/matching_rules/v3/merge_spec.rb +462 -0
- data/spec/lib/pact/matching_rules_spec.rb +82 -0
- data/spec/lib/pact/reification_spec.rb +18 -5
- data/spec/lib/pact/shared/multipart_form_differ_spec.rb +39 -0
- data/spec/support/factories.rb +5 -0
- data/tasks/spec.rake +0 -1
- metadata +40 -3
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
require 'pact/matching_rules/v3/merge'
|
|
2
|
+
|
|
3
|
+
module Pact
|
|
4
|
+
module MatchingRules
|
|
5
|
+
module V3
|
|
6
|
+
describe Merge do
|
|
7
|
+
subject { Merge.(expected, matching_rules) }
|
|
8
|
+
|
|
9
|
+
before do
|
|
10
|
+
allow($stderr).to receive(:puts) do | message |
|
|
11
|
+
raise "Was not expecting stderr to receive #{message.inspect} in this spec. This may be because of a missed rule deletion in Merge."
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe "no recognised rules" do
|
|
16
|
+
before do
|
|
17
|
+
allow($stderr).to receive(:puts)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
let(:expected) do
|
|
21
|
+
{
|
|
22
|
+
"_links" => {
|
|
23
|
+
"self" => {
|
|
24
|
+
"href" => "http://localhost:1234/thing"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
let(:matching_rules) do
|
|
31
|
+
{
|
|
32
|
+
"$._links.self.href" => {
|
|
33
|
+
"matchers" => [{ "type" => "unknown" }]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "returns the object at that path unaltered" do
|
|
39
|
+
expect(subject["_links"]["self"]["href"]).to eq "http://localhost:1234/thing"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "it logs the rules it has ignored" do
|
|
43
|
+
expect($stderr).to receive(:puts) do | message |
|
|
44
|
+
expect(message).to include("WARN")
|
|
45
|
+
expect(message).to include("type")
|
|
46
|
+
expect(message).to include("unknown")
|
|
47
|
+
expect(message).to include("$['_links']")
|
|
48
|
+
end
|
|
49
|
+
subject
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe "with nil rules" do
|
|
55
|
+
let(:expected) do
|
|
56
|
+
{
|
|
57
|
+
"_links" => {
|
|
58
|
+
"self" => {
|
|
59
|
+
"href" => "http://localhost:1234/thing"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
let(:matching_rules) { nil }
|
|
66
|
+
|
|
67
|
+
it "returns the example unaltered" do
|
|
68
|
+
expect(subject["_links"]["self"]["href"]).to eq "http://localhost:1234/thing"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe "type based matching" do
|
|
74
|
+
before do
|
|
75
|
+
allow($stderr).to receive(:puts)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
let(:expected) do
|
|
79
|
+
{
|
|
80
|
+
"name" => "Mary"
|
|
81
|
+
}
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
let(:matching_rules) do
|
|
85
|
+
{
|
|
86
|
+
"$.name" => {
|
|
87
|
+
"matchers" => [{ "match" => "type", "ignored" => "matchingrule" }]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "creates a SomethingLike at the appropriate path" do
|
|
93
|
+
expect(subject['name']).to be_instance_of(Pact::SomethingLike)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "it logs the rules it has ignored" do
|
|
97
|
+
expect($stderr).to receive(:puts).once.with(/ignored.*matchingrule/)
|
|
98
|
+
subject
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "does not alter the passed in rules hash" do
|
|
102
|
+
original_matching_rules = JSON.parse(matching_rules.to_json)
|
|
103
|
+
subject
|
|
104
|
+
expect(matching_rules).to eq original_matching_rules
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
describe "when a Pact.like is nested inside a Pact.each_like which is nested inside a Pact.like" do
|
|
109
|
+
let(:original_definition) do
|
|
110
|
+
Pact.like('foos' => Pact.each_like(Pact.like('name' => "foo1")))
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
let(:expected) do
|
|
114
|
+
Pact::Reification.from_term(original_definition)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
let(:matching_rules) do
|
|
118
|
+
Extract.call(original_definition)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "creates a Pact::SomethingLike containing a Pact::ArrayLike containing a Pact::SomethingLike" do
|
|
122
|
+
expect(subject.to_hash).to eq original_definition.to_hash
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
describe "when a Pact.array_like is the top level object" do
|
|
127
|
+
let(:original_definition) do
|
|
128
|
+
Pact.each_like('foos')
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
let(:expected) do
|
|
132
|
+
Pact::Reification.from_term(original_definition)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
let(:matching_rules) do
|
|
136
|
+
Extract.call(original_definition)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "creates a Pact::ArrayLike" do
|
|
140
|
+
expect(subject.to_hash).to eq original_definition.to_hash
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
describe "when a Pact.like containing an array is the top level object" do
|
|
145
|
+
let(:original_definition) do
|
|
146
|
+
Pact.like(['foos'])
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
let(:expected) do
|
|
150
|
+
Pact::Reification.from_term(original_definition).tap { |it| puts it }
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
let(:matching_rules) do
|
|
154
|
+
Extract.call(original_definition).tap { |it| puts it }
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "creates a Pact::SomethingLike" do
|
|
158
|
+
expect(subject).to be_a(Pact::SomethingLike)
|
|
159
|
+
expect(subject.to_hash).to eq original_definition.to_hash
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
describe "regular expressions" do
|
|
164
|
+
describe "in a hash" do
|
|
165
|
+
before do
|
|
166
|
+
allow($stderr).to receive(:puts)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
let(:expected) do
|
|
170
|
+
{
|
|
171
|
+
"_links" => {
|
|
172
|
+
"self" => {
|
|
173
|
+
"href" => "http://localhost:1234/thing"
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
let(:matching_rules) do
|
|
180
|
+
{
|
|
181
|
+
"$._links.self.href" => {
|
|
182
|
+
"matchers" => [{ "regex" => "http:\\/\\/.*\\/thing", "match" => "regex", "ignored" => "somerule" }]
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it "creates a Pact::Term at the appropriate path" do
|
|
188
|
+
expect(subject["_links"]["self"]["href"]).to be_instance_of(Pact::Term)
|
|
189
|
+
expect(subject["_links"]["self"]["href"].generate).to eq "http://localhost:1234/thing"
|
|
190
|
+
expect(subject["_links"]["self"]["href"].matcher.inspect).to eq "/http:\\/\\/.*\\/thing/"
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it "it logs the rules it has ignored" do
|
|
194
|
+
expect($stderr).to receive(:puts) do | message |
|
|
195
|
+
expect(message).to match /ignored.*"somerule"/
|
|
196
|
+
expect(message).to_not match /regex/
|
|
197
|
+
expect(message).to_not match /"match"/
|
|
198
|
+
end
|
|
199
|
+
subject
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
describe "with an array" do
|
|
204
|
+
|
|
205
|
+
let(:expected) do
|
|
206
|
+
{
|
|
207
|
+
"_links" => {
|
|
208
|
+
"self" => [{
|
|
209
|
+
"href" => "http://localhost:1234/thing"
|
|
210
|
+
}]
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
let(:matching_rules) do
|
|
216
|
+
{
|
|
217
|
+
"$._links.self[0].href" => {
|
|
218
|
+
"matchers" => [{ "regex" => "http:\\/\\/.*\\/thing" }]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it "creates a Pact::Term at the appropriate path" do
|
|
224
|
+
expect(subject["_links"]["self"][0]["href"]).to be_instance_of(Pact::Term)
|
|
225
|
+
expect(subject["_links"]["self"][0]["href"].generate).to eq "http://localhost:1234/thing"
|
|
226
|
+
expect(subject["_links"]["self"][0]["href"].matcher.inspect).to eq "/http:\\/\\/.*\\/thing/"
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
describe "with an ArrayLike containing a Term" do
|
|
231
|
+
let(:expected) do
|
|
232
|
+
["foo"]
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
let(:matching_rules) do
|
|
236
|
+
{
|
|
237
|
+
"$" => {"matchers" => [{"min" => 1}]},
|
|
238
|
+
"$[*].*" => {"matchers" => [{"match" => "type"}]},
|
|
239
|
+
"$[*]" => {"matchers" => [{"match" => "regex", "regex"=>"f"}]}
|
|
240
|
+
}
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
it "it creates an ArrayLike with a Pact::Term as the contents" do
|
|
244
|
+
expect(subject).to be_a(Pact::ArrayLike)
|
|
245
|
+
expect(subject.contents).to be_a(Pact::Term)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
describe "with an array where all elements should match by type and the rule is specified on the parent element and there is no min specified" do
|
|
251
|
+
let(:expected) do
|
|
252
|
+
{
|
|
253
|
+
'alligators' => [{'name' => 'Mary'}]
|
|
254
|
+
}
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
let(:matching_rules) do
|
|
258
|
+
{
|
|
259
|
+
"$.alligators" => {
|
|
260
|
+
"matchers" => [{ 'match' => 'type' }]
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
it "creates a Pact::SomethingLike at the appropriate path" do
|
|
266
|
+
expect(subject["alligators"]).to be_instance_of(Pact::SomethingLike)
|
|
267
|
+
expect(subject["alligators"].contents).to eq ['name' => 'Mary']
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
describe "with an array where all elements should match by type and the rule is specified on the child elements" do
|
|
272
|
+
let(:expected) do
|
|
273
|
+
{
|
|
274
|
+
'alligators' => [{'name' => 'Mary'}]
|
|
275
|
+
}
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
let(:matching_rules) do
|
|
279
|
+
{
|
|
280
|
+
"$.alligators" => {
|
|
281
|
+
"matchers" => [{ 'min' => 2}]
|
|
282
|
+
},
|
|
283
|
+
"$.alligators[*].*" => {
|
|
284
|
+
"matchers" => [{ 'match' => 'type'}]
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
end
|
|
288
|
+
it "creates a Pact::ArrayLike at the appropriate path" do
|
|
289
|
+
expect(subject["alligators"]).to be_instance_of(Pact::ArrayLike)
|
|
290
|
+
expect(subject["alligators"].contents).to eq 'name' => 'Mary'
|
|
291
|
+
expect(subject["alligators"].min).to eq 2
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
describe "with an array where all elements should match by type and the rule is specified on both the parent element and the child elements" do
|
|
296
|
+
let(:expected) do
|
|
297
|
+
{
|
|
298
|
+
'alligators' => [{'name' => 'Mary'}]
|
|
299
|
+
}
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
let(:matching_rules) do
|
|
303
|
+
{
|
|
304
|
+
"$.alligators" => {
|
|
305
|
+
"matchers" => [{ 'min' => 2, 'match' => 'type' }]
|
|
306
|
+
},
|
|
307
|
+
"$.alligators[*].*" => {
|
|
308
|
+
"matchers" => [{ 'match' => 'type' }]
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
it "creates a Pact::ArrayLike at the appropriate path" do
|
|
314
|
+
expect(subject["alligators"]).to be_instance_of(Pact::SomethingLike)
|
|
315
|
+
expect(subject["alligators"].contents).to be_instance_of(Pact::ArrayLike)
|
|
316
|
+
expect(subject["alligators"].contents.contents).to eq 'name' => 'Mary'
|
|
317
|
+
expect(subject["alligators"].contents.min).to eq 2
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
describe "with an array where all elements should match by type and there is only a match:type on the parent element" do
|
|
322
|
+
let(:expected) do
|
|
323
|
+
{
|
|
324
|
+
'alligators' => [{'name' => 'Mary'}]
|
|
325
|
+
}
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
let(:matching_rules) do
|
|
329
|
+
{
|
|
330
|
+
"$.alligators" => { 'matchers' => [{'min' => 2, 'match' => 'type'}] },
|
|
331
|
+
}
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
it "creates a Pact::ArrayLike at the appropriate path" do
|
|
335
|
+
expect(subject["alligators"]).to be_instance_of(Pact::ArrayLike)
|
|
336
|
+
expect(subject["alligators"].contents).to eq 'name' => 'Mary'
|
|
337
|
+
expect(subject["alligators"].min).to eq 2
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
describe "with an array where all elements should match by type nested inside another array where all elements should match by type" do
|
|
342
|
+
let(:expected) do
|
|
343
|
+
{
|
|
344
|
+
|
|
345
|
+
'alligators' => [
|
|
346
|
+
{
|
|
347
|
+
'name' => 'Mary',
|
|
348
|
+
'children' => [
|
|
349
|
+
'age' => 9
|
|
350
|
+
]
|
|
351
|
+
}
|
|
352
|
+
]
|
|
353
|
+
|
|
354
|
+
}
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
let(:matching_rules) do
|
|
358
|
+
{
|
|
359
|
+
"$.alligators" => { "matchers" => [{ 'min' => 2, 'match' => 'type' }] },
|
|
360
|
+
"$.alligators[*].children" => { "matchers" => [{ 'min' => 1, 'match' => 'type' }]},
|
|
361
|
+
}
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
it "creates a Pact::ArrayLike at the appropriate path" do
|
|
365
|
+
expect(subject["alligators"].contents['children']).to be_instance_of(Pact::ArrayLike)
|
|
366
|
+
expect(subject["alligators"].contents['children'].contents).to eq 'age' => 9
|
|
367
|
+
expect(subject["alligators"].contents['children'].min).to eq 1
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
describe "with an example array with more than one item" do
|
|
372
|
+
before do
|
|
373
|
+
allow($stderr).to receive(:puts)
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
let(:expected) do
|
|
377
|
+
{
|
|
378
|
+
|
|
379
|
+
'alligators' => [
|
|
380
|
+
{'name' => 'Mary'},
|
|
381
|
+
{'name' => 'Joe'}
|
|
382
|
+
]
|
|
383
|
+
|
|
384
|
+
}
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
let(:matching_rules) do
|
|
388
|
+
{
|
|
389
|
+
"$.alligators" => { "matchers" => [{'min' => 2, 'match' => 'type'}] }
|
|
390
|
+
}
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
it "doesn't warn about the min size being ignored" do
|
|
394
|
+
expect(Pact.configuration.error_stream).to receive(:puts).once
|
|
395
|
+
subject
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
it "warns that the other items will be ignored" do
|
|
399
|
+
allow(Pact.configuration.error_stream).to receive(:puts)
|
|
400
|
+
expect(Pact.configuration.error_stream).to receive(:puts).with(/WARN: Only the first item/)
|
|
401
|
+
subject
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
describe "using bracket notation for a Hash" do
|
|
406
|
+
let(:expected) do
|
|
407
|
+
{
|
|
408
|
+
"name" => "Mary"
|
|
409
|
+
}
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
let(:matching_rules) do
|
|
413
|
+
{
|
|
414
|
+
"$['name']" => { "matchers" => [{"match" => "type"}] }
|
|
415
|
+
}
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
it "applies the rule" do
|
|
419
|
+
expect(subject['name']).to be_instance_of(Pact::SomethingLike)
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
describe "with a dot in the path" do
|
|
424
|
+
let(:expected) do
|
|
425
|
+
{
|
|
426
|
+
"first.name" => "Mary"
|
|
427
|
+
}
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
let(:matching_rules) do
|
|
431
|
+
{
|
|
432
|
+
"$['first.name']" => { "matchers" => [{ "match" => "type" }] }
|
|
433
|
+
}
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
it "applies the rule" do
|
|
437
|
+
expect(subject['first.name']).to be_instance_of(Pact::SomethingLike)
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
describe "with an @ in the path" do
|
|
442
|
+
let(:expected) do
|
|
443
|
+
{
|
|
444
|
+
"@name" => "Mary"
|
|
445
|
+
}
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
let(:matching_rules) do
|
|
449
|
+
{
|
|
450
|
+
"$['@name']" => { "matchers" => [ { "match" => "type" }] }
|
|
451
|
+
}
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
it "applies the rule" do
|
|
455
|
+
expect(subject['@name']).to be_instance_of(Pact::SomethingLike)
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'pact/matching_rules'
|
|
2
|
+
|
|
3
|
+
module Pact
|
|
4
|
+
module MatchingRules
|
|
5
|
+
describe ".merge" do
|
|
6
|
+
before do
|
|
7
|
+
allow(V3::Merge).to receive(:call)
|
|
8
|
+
allow(Merge).to receive(:call)
|
|
9
|
+
allow(Pact.configuration.error_stream).to receive(:puts)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:object) { double('object') }
|
|
13
|
+
let(:rules) { double('rules') }
|
|
14
|
+
let(:options) { { pact_specification_version: Pact::SpecificationVersion.new(pact_specification_version) } }
|
|
15
|
+
|
|
16
|
+
subject { MatchingRules.merge(object, rules, options)}
|
|
17
|
+
|
|
18
|
+
context "when the pact_specification_version is nil" do
|
|
19
|
+
let(:options) { { pact_specification_version: nil } }
|
|
20
|
+
|
|
21
|
+
it "calls Merge" do
|
|
22
|
+
expect(Merge).to receive(:call)
|
|
23
|
+
subject
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context "when the pact_specification_version starts with '1.'" do
|
|
28
|
+
let(:pact_specification_version) { "1.0" }
|
|
29
|
+
|
|
30
|
+
it "calls Merge" do
|
|
31
|
+
expect(Merge).to receive(:call)
|
|
32
|
+
subject
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context "when the pact_specification_version is with '1'" do
|
|
37
|
+
let(:pact_specification_version) { "1" }
|
|
38
|
+
|
|
39
|
+
it "calls Merge" do
|
|
40
|
+
expect(Merge).to receive(:call)
|
|
41
|
+
subject
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context "when the pact_specification_version starts with '2.'" do
|
|
46
|
+
let(:pact_specification_version) { "2.0" }
|
|
47
|
+
|
|
48
|
+
it "calls Merge" do
|
|
49
|
+
expect(Merge).to receive(:call)
|
|
50
|
+
subject
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "when the pact_specification_version starts with '3.'" do
|
|
55
|
+
let(:pact_specification_version) { "3.0" }
|
|
56
|
+
|
|
57
|
+
it "calls V3::Merge" do
|
|
58
|
+
expect(V3::Merge).to receive(:call)
|
|
59
|
+
subject
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context "when the pact_specification_version starts with '4.'" do
|
|
64
|
+
let(:pact_specification_version) { "4.0" }
|
|
65
|
+
|
|
66
|
+
it "calls V3::Merge" do
|
|
67
|
+
expect(V3::Merge).to receive(:call)
|
|
68
|
+
subject
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context "when the pact_specification_version is with '11'" do
|
|
73
|
+
let(:pact_specification_version) { "11" }
|
|
74
|
+
|
|
75
|
+
it "calls V3::Merge" do
|
|
76
|
+
expect(V3::Merge).to receive(:call)
|
|
77
|
+
subject
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -122,10 +122,9 @@ module Pact
|
|
|
122
122
|
end
|
|
123
123
|
|
|
124
124
|
context "when Hash Query with UTF-8 string" do
|
|
125
|
-
|
|
126
125
|
subject { Reification.from_term(query)}
|
|
127
126
|
|
|
128
|
-
let(:query) { QueryHash.new(
|
|
127
|
+
let(:query) { QueryHash.new(param: 'ILove', extra: '寿司') }
|
|
129
128
|
|
|
130
129
|
it "returns the hash with escaping UTF-8 string" do
|
|
131
130
|
expect(subject).to eq("param=ILove&extra=%E5%AF%BF%E5%8F%B8")
|
|
@@ -133,7 +132,6 @@ module Pact
|
|
|
133
132
|
end
|
|
134
133
|
|
|
135
134
|
context "when Hash Query with embeded terms" do
|
|
136
|
-
|
|
137
135
|
subject { Reification.from_term(query)}
|
|
138
136
|
|
|
139
137
|
let(:query) { QueryHash.new( {param: 'hello', extra: Pact::Term.new(generate: "wonderworld", matcher: /\w+world/)})}
|
|
@@ -141,10 +139,9 @@ module Pact
|
|
|
141
139
|
it "returns the hash in the natural order, and fills in Terms appropriately" do
|
|
142
140
|
expect(subject).to eq("param=hello&extra=wonderworld")
|
|
143
141
|
end
|
|
144
|
-
|
|
145
142
|
end
|
|
146
|
-
context "when Hash Query with Arrays and multiple params with the same name" do
|
|
147
143
|
|
|
144
|
+
context "when Hash Query with Arrays and multiple params with the same name" do
|
|
148
145
|
subject { Reification.from_term(query)}
|
|
149
146
|
|
|
150
147
|
let(:query) { QueryHash.new( {param: 'hello', double: [Pact::Term.new(generate: "wonder", matcher: /\w+/), 'world'], simple: 'bye'})}
|
|
@@ -152,8 +149,24 @@ module Pact
|
|
|
152
149
|
it "returns the hash in the natural order, and fills in Terms appropriately" do
|
|
153
150
|
expect(subject).to eq("param=hello&double=wonder&double=world&simple=bye")
|
|
154
151
|
end
|
|
152
|
+
end
|
|
155
153
|
|
|
154
|
+
context "when Hash Query with an ArrayLike" do
|
|
155
|
+
subject { Reification.from_term(query)}
|
|
156
|
+
|
|
157
|
+
let(:query) { QueryHash.new(param: Pact.each_like("1", min: 2)) }
|
|
158
|
+
|
|
159
|
+
it "turns the hash into a string with the right number of params" do
|
|
160
|
+
expect(subject).to eq("param=1¶m=1")
|
|
161
|
+
end
|
|
156
162
|
end
|
|
157
163
|
|
|
164
|
+
context "with a StringWithMatchingRules" do
|
|
165
|
+
subject { Reification.from_term(StringWithMatchingRules.new("foo", Pact::SpecificationVersion.new("3"), {}))}
|
|
166
|
+
|
|
167
|
+
it "returns a String" do
|
|
168
|
+
expect(subject.class).to be String
|
|
169
|
+
end
|
|
170
|
+
end
|
|
158
171
|
end
|
|
159
172
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'pact/shared/multipart_form_differ'
|
|
2
|
+
|
|
3
|
+
module Pact
|
|
4
|
+
describe MultipartFormDiffer do
|
|
5
|
+
|
|
6
|
+
describe ".call" do
|
|
7
|
+
|
|
8
|
+
let(:expected_body) do
|
|
9
|
+
"-------------RubyMultipartPost-1e4912957c7bb64de3c444568326663b\r\nContent-Disposition: form-data; name=\"file\"; filename=\"text.txt\"\r\nContent-Length: 14\r\nContent-Type: text/plain\r\nContent-Transfer-Encoding: binary\r\n\r\nThis is a file\r\n-------------RubyMultipartPost-1e4912957c7bb64de3c444568326663b--\r\n\r\n"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:actual_body) do
|
|
13
|
+
"-------------RubyMultipartPost-1e4912957c7bb64de3c4445683266XXX\r\nContent-Disposition: form-data; name=\"file\"; filename=\"text.txt\"\r\nContent-Length: 14\r\nContent-Type: text/plain\r\nContent-Transfer-Encoding: binary\r\n\r\nThis is a file\r\n-------------RubyMultipartPost-1e4912957c7bb64de3c4445683266XXX--\r\n\r\n"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
let(:options) do
|
|
17
|
+
{}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
subject { MultipartFormDiffer.call(expected_body, actual_body, options) }
|
|
21
|
+
|
|
22
|
+
context "when the bodies are the same apart from the boundary" do
|
|
23
|
+
it "returns an empty diff" do
|
|
24
|
+
expect(subject).to eq({})
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "when the bodies are not the same" do
|
|
29
|
+
let(:actual_body) do
|
|
30
|
+
"-------------RubyMultipartPost-1e4912957c7bb64de3c4445683266XXX\r\nContent-Disposition: form-data; name=\"file\"; filename=\"bar.txt\"\r\nContent-Length: 14\r\nContent-Type: text/plain\r\nContent-Transfer-Encoding: binary\r\n\r\nThis is a file\r\n-------------RubyMultipartPost-1e4912957c7bb64de3c4445683266XXX--\r\n\r\n"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "returns a text diff" do
|
|
34
|
+
expect(subject).to_not eq({})
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/spec/support/factories.rb
CHANGED
|
@@ -40,6 +40,11 @@ class InteractionFactory
|
|
|
40
40
|
'body' => {a: 'response body'}
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
|
|
44
|
+
if hash.key?(:provider_states) || hash.key?('provider_states')
|
|
45
|
+
defaults.delete('provider_state')
|
|
46
|
+
end
|
|
47
|
+
|
|
43
48
|
Pact::Interaction.from_hash(stringify_keys(deep_merge(defaults, stringify_keys(hash))))
|
|
44
49
|
end
|
|
45
50
|
end
|
data/tasks/spec.rake
CHANGED