pact 1.66.2 → 1.67.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/lib/pact/v2/configuration.rb +23 -0
  4. data/lib/pact/v2/consumer/grpc_interaction_builder.rb +194 -0
  5. data/lib/pact/v2/consumer/http_interaction_builder.rb +162 -0
  6. data/lib/pact/v2/consumer/interaction_contents.rb +62 -0
  7. data/lib/pact/v2/consumer/message_interaction_builder.rb +287 -0
  8. data/lib/pact/v2/consumer/mock_server.rb +100 -0
  9. data/lib/pact/v2/consumer/pact_config/base.rb +24 -0
  10. data/lib/pact/v2/consumer/pact_config/grpc.rb +26 -0
  11. data/lib/pact/v2/consumer/pact_config/http.rb +55 -0
  12. data/lib/pact/v2/consumer/pact_config/message.rb +17 -0
  13. data/lib/pact/v2/consumer/pact_config/plugin_async_message.rb +26 -0
  14. data/lib/pact/v2/consumer/pact_config/plugin_http.rb +26 -0
  15. data/lib/pact/v2/consumer/pact_config/plugin_sync_message.rb +26 -0
  16. data/lib/pact/v2/consumer/pact_config.rb +30 -0
  17. data/lib/pact/v2/consumer/plugin_async_message_interaction_builder.rb +171 -0
  18. data/lib/pact/v2/consumer/plugin_http_interaction_builder.rb +201 -0
  19. data/lib/pact/v2/consumer/plugin_sync_message_interaction_builder.rb +180 -0
  20. data/lib/pact/v2/consumer.rb +8 -0
  21. data/lib/pact/v2/generators/base.rb +287 -0
  22. data/lib/pact/v2/generators.rb +49 -0
  23. data/lib/pact/v2/matchers/base.rb +74 -0
  24. data/lib/pact/v2/matchers/v1/equality.rb +19 -0
  25. data/lib/pact/v2/matchers/v2/regex.rb +19 -0
  26. data/lib/pact/v2/matchers/v2/type.rb +17 -0
  27. data/lib/pact/v2/matchers/v3/boolean.rb +17 -0
  28. data/lib/pact/v2/matchers/v3/content_type.rb +32 -0
  29. data/lib/pact/v2/matchers/v3/date.rb +18 -0
  30. data/lib/pact/v2/matchers/v3/date_time.rb +18 -0
  31. data/lib/pact/v2/matchers/v3/decimal.rb +17 -0
  32. data/lib/pact/v2/matchers/v3/each.rb +42 -0
  33. data/lib/pact/v2/matchers/v3/include.rb +17 -0
  34. data/lib/pact/v2/matchers/v3/integer.rb +17 -0
  35. data/lib/pact/v2/matchers/v3/null.rb +16 -0
  36. data/lib/pact/v2/matchers/v3/number.rb +17 -0
  37. data/lib/pact/v2/matchers/v3/semver.rb +23 -0
  38. data/lib/pact/v2/matchers/v3/time.rb +18 -0
  39. data/lib/pact/v2/matchers/v3/values.rb +16 -0
  40. data/lib/pact/v2/matchers/v4/each_key.rb +26 -0
  41. data/lib/pact/v2/matchers/v4/each_key_value.rb +32 -0
  42. data/lib/pact/v2/matchers/v4/each_value.rb +33 -0
  43. data/lib/pact/v2/matchers/v4/not_empty.rb +24 -0
  44. data/lib/pact/v2/matchers/v4/status_code.rb +17 -0
  45. data/lib/pact/v2/matchers.rb +110 -0
  46. data/lib/pact/v2/native/blocking_verifier.rb +17 -0
  47. data/lib/pact/v2/native/logger.rb +25 -0
  48. data/lib/pact/v2/provider/async_message_verifier.rb +28 -0
  49. data/lib/pact/v2/provider/base_verifier.rb +242 -0
  50. data/lib/pact/v2/provider/grpc_verifier.rb +38 -0
  51. data/lib/pact/v2/provider/gruf_server.rb +75 -0
  52. data/lib/pact/v2/provider/http_server.rb +79 -0
  53. data/lib/pact/v2/provider/http_verifier.rb +43 -0
  54. data/lib/pact/v2/provider/message_provider_servlet.rb +79 -0
  55. data/lib/pact/v2/provider/mixed_verifier.rb +22 -0
  56. data/lib/pact/v2/provider/pact_broker_proxy.rb +66 -0
  57. data/lib/pact/v2/provider/pact_broker_proxy_runner.rb +77 -0
  58. data/lib/pact/v2/provider/pact_config/async.rb +29 -0
  59. data/lib/pact/v2/provider/pact_config/base.rb +101 -0
  60. data/lib/pact/v2/provider/pact_config/grpc.rb +26 -0
  61. data/lib/pact/v2/provider/pact_config/http.rb +27 -0
  62. data/lib/pact/v2/provider/pact_config/mixed.rb +39 -0
  63. data/lib/pact/v2/provider/pact_config.rb +26 -0
  64. data/lib/pact/v2/provider/provider_server_runner.rb +89 -0
  65. data/lib/pact/v2/provider/provider_state_configuration.rb +32 -0
  66. data/lib/pact/v2/provider/provider_state_servlet.rb +86 -0
  67. data/lib/pact/v2/provider.rb +8 -0
  68. data/lib/pact/v2/railtie.rb +13 -0
  69. data/lib/pact/v2/rspec/support/pact_consumer_helpers.rb +93 -0
  70. data/lib/pact/v2/rspec/support/pact_message_helpers.rb +42 -0
  71. data/lib/pact/v2/rspec/support/pact_provider_helpers.rb +129 -0
  72. data/lib/pact/v2/rspec/support/waterdrop/pact_waterdrop_client.rb +27 -0
  73. data/lib/pact/v2/rspec/support/webmock/webmock_helpers.rb +30 -0
  74. data/lib/pact/v2/rspec.rb +17 -0
  75. data/lib/pact/v2/tasks/pact.rake +13 -0
  76. data/lib/pact/v2.rb +71 -0
  77. data/lib/pact/version.rb +1 -1
  78. data/lib/pact.rb +1 -0
  79. data/pact.gemspec +52 -7
  80. metadata +419 -65
@@ -0,0 +1,287 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Generators
6
+ module Base
7
+ def as_basic
8
+ raise NotImplementedError, "Subclasses must implement the as_basic method"
9
+ end
10
+ end
11
+
12
+ class RandomIntGenerator
13
+ include Base
14
+
15
+ def initialize(min:, max:)
16
+ @min = min
17
+ @max = max
18
+ end
19
+
20
+ def as_basic
21
+ {
22
+ "pact:matcher:type" => "integer",
23
+ "pact:generator:type" => "RandomInt",
24
+ "min" => @min,
25
+ "max" => @max,
26
+ "value" => rand(@min..@max)
27
+ }
28
+ end
29
+ end
30
+
31
+ class RandomDecimalGenerator
32
+ include Base
33
+
34
+ def initialize(digits:)
35
+ @digits = digits
36
+ end
37
+
38
+ def as_basic
39
+ {
40
+ 'pact:matcher:type' => 'decimal',
41
+ "pact:generator:type" => "RandomDecimal",
42
+ "digits" => @digits,
43
+ "value" => rand.round(@digits)
44
+ }
45
+ end
46
+ end
47
+
48
+ class RandomHexadecimalGenerator
49
+ include Base
50
+
51
+ def initialize(digits:)
52
+ @digits = digits
53
+ end
54
+
55
+ def as_basic
56
+ {
57
+ "pact:matcher:type" => "decimal",
58
+ "pact:generator:type" => "RandomHexadecimal",
59
+ "digits" => @digits,
60
+ "value" => SecureRandom.hex((@digits / 2.0).ceil)[0...@digits]
61
+ }
62
+ end
63
+ end
64
+
65
+ class RandomStringGenerator
66
+ include Base
67
+
68
+ def initialize(size:, example: nil)
69
+ @size = size
70
+ @example = example
71
+ end
72
+
73
+ def as_basic
74
+ {
75
+ "pact:matcher:type" => "type",
76
+ "pact:generator:type" => "RandomString",
77
+ "size" => @size,
78
+ "value" => @example || SecureRandom.alphanumeric(@size)
79
+ }
80
+ end
81
+ end
82
+
83
+ class UuidGenerator
84
+ include Base
85
+
86
+
87
+ def initialize(example: nil)
88
+ @example = example
89
+ @regexStr = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}';
90
+ if @example
91
+ regex = Regexp.new("^#{@regexStr}$")
92
+ unless @example.match?(regex)
93
+ raise ArgumentError, "regex: Example value '#{@example}' does not match the UUID regular expression '#{@regexStr}'"
94
+ end
95
+ end
96
+ end
97
+
98
+ def as_basic
99
+ {
100
+ "pact:matcher:type" => "regex",
101
+ "pact:generator:type" => "Uuid",
102
+ "regex" => @regexStr,
103
+ "value" => @example || SecureRandom.uuid
104
+ }
105
+ end
106
+ end
107
+
108
+ class DateGenerator
109
+ include Base
110
+
111
+ def initialize(format: nil, example: nil)
112
+ @format = format || default_format
113
+ @example = example || Time.now.strftime(convert_from_java_simple_date_format(@format))
114
+ end
115
+
116
+ def as_basic
117
+ h = { "pact:generator:type" => type }
118
+ h["pact:matcher:type"] = matcher_type
119
+ h["format"] = @format if @format
120
+ h["value"] = @example
121
+ h
122
+ end
123
+
124
+ def type
125
+ 'Date'
126
+ end
127
+
128
+ def matcher_type
129
+ 'date'
130
+ end
131
+
132
+ def default_format
133
+ 'yyyy-MM-dd'
134
+ end
135
+
136
+ # Converts Java SimpleDateFormat to Ruby strftime format
137
+ def convert_from_java_simple_date_format(format)
138
+ f = format.dup
139
+ # Year
140
+ f.gsub!(/(?<!%)y{4,}/, '%Y')
141
+ f.gsub!(/(?<!%)y{1,3}/, '%y')
142
+ # Month
143
+ f.gsub!(/(?<!%)M{4,}/, '%B')
144
+ f.gsub!(/(?<!%)M{3}/, '%b')
145
+ f.gsub!(/(?<!%)M{1,2}/, '%m')
146
+ # Week
147
+ f.gsub!(/(?<!%)w{1,}/, '%W')
148
+ # Day
149
+ f.gsub!(/(?<!%)D{1,}/, '%j')
150
+ f.gsub!(/(?<!%)d{1,}/, '%d')
151
+ f.gsub!(/(?<!%)E{4,}/, '%A')
152
+ f.gsub!(/(?<!%)E{1,3}/, '%a')
153
+ f.gsub!(/(?<!%)u{1,}/, '%u')
154
+ # Time
155
+ f.gsub!(/(?<!%)a{1,}/, '%p')
156
+ f.gsub!(/(?<!%)k{1,}/, '%H')
157
+ f.gsub!(/(?<!%)n{1,}/, '%M')
158
+ f.gsub!(/(?<!%)s{1,}/, '%S')
159
+ f.gsub!(/(?<!%)S{1,}/, '%L')
160
+ # Timezone
161
+ f.gsub!(/(?<!%)z{1,}/, '%z')
162
+ f.gsub!(/(?<!%)Z{1,}/, '%z')
163
+ f.gsub!(/(?<!%)X{1,}/, '%Z')
164
+ # Java 'H' (hour in day, 0-23) to Ruby '%H'
165
+ f.gsub!(/(?<!%)H{2}/, '%H')
166
+ f.gsub!(/(?<!%)H{1}/, '%k')
167
+ # Java 'm' (minute in hour) to Ruby '%M'
168
+ f.gsub!(/(?<!%)m{2}/, '%M')
169
+ f.gsub!(/(?<!%)m{1}/, '%-M')
170
+ # Java 'h' (hour in am/pm, 1-12) to Ruby '%I'
171
+ f.gsub!(/(?<!%)h{2}/, '%I')
172
+ f.gsub!(/(?<!%)h{1}/, '%-I')
173
+ # Java 's' (second in minute) to Ruby '%S'
174
+ f.gsub!(/(?<!%)s{1,}/, '%S')
175
+ # Java 'a' (am/pm marker) to Ruby '%p'
176
+ f.gsub!(/(?<!%)a/, '%p')
177
+ # Java 'K' (hour in am/pm, 0-11) to Ruby '%l'
178
+ f.gsub!(/(?<!%)K{2}/, '%l')
179
+ f.gsub!(/(?<!%)K{1}/, '%-l')
180
+ # Java 'S' (fractional seconds, milliseconds) to Ruby '%L'
181
+ f.gsub!(/(?<!%)S{1,}/, '%L')
182
+ # Java 'z' (general time zone) to Ruby '%Z'
183
+ f.gsub!(/(?<!%)z{1,}/, '%Z')
184
+ # Java 'Z' (RFC 822 time zone) to Ruby '%z'
185
+ f.gsub!(/(?<!%)Z{1,}/, '%z')
186
+ # Java 'X' (ISO 8601 time zone) to Ruby '%z'
187
+ f.gsub!(/(?<!%)X{1,}/, '%z')
188
+ # Java 'G' (era designator) - no direct Ruby equivalent, remove or leave as is
189
+ f.gsub!(/(?<!%)G+/, '%G')
190
+ # Java 'Q' (quarter) - no direct Ruby equivalent, remove or leave as is
191
+ f.gsub!(/(?<!%)Q+/, '')
192
+ # Java 'F' (day of week in month) - no direct Ruby equivalent, remove or leave as is
193
+ f.gsub!(/(?<!%)F+/, '')
194
+ # Java 'c' (stand-alone day of week) - no direct Ruby equivalent, remove or leave as is
195
+ f.gsub!(/(?<!%)c+/, '')
196
+ # Java 'L' (stand-alone month) - treat as month
197
+ f.gsub!(/(?<!%)L{4,}/, '%B')
198
+ f.gsub!(/(?<!%)L{3}/, '%b')
199
+ f.gsub!(/(?<!%)L{1,2}/, '%m')
200
+ f
201
+ end
202
+ end
203
+
204
+ # Time provides the time generator which will give the current time in the defined format
205
+ class TimeGenerator < DateGenerator
206
+ def type
207
+ 'Time'
208
+ end
209
+
210
+ def matcher_type
211
+ 'time'
212
+ end
213
+
214
+ def default_format
215
+ 'HH:mm'
216
+ end
217
+ end
218
+
219
+ class DateTimeGenerator < DateGenerator
220
+ def type
221
+ 'DateTime'
222
+ end
223
+
224
+ def matcher_type
225
+ 'datetime'
226
+ end
227
+
228
+ def default_format
229
+ 'yyyy-MM-dd HH:mm'
230
+ end
231
+ end
232
+
233
+ class RandomBooleanGenerator
234
+ include Base
235
+
236
+ def initialize(example: nil)
237
+ @example = example
238
+ end
239
+
240
+ def as_basic
241
+ {
242
+ "pact:matcher:type" => "boolean",
243
+ "pact:generator:type" => "RandomBoolean",
244
+ "value" => @example.nil? ? [true, false].sample : @example
245
+ }
246
+ end
247
+ end
248
+
249
+ class ProviderStateGenerator
250
+ include Base
251
+
252
+ def initialize(expression:, example:)
253
+ @expression = expression
254
+ @value = example
255
+ end
256
+
257
+ def as_basic
258
+ {
259
+ 'pact:matcher:type': 'type',
260
+ "pact:generator:type" => "ProviderState",
261
+ "expression" => @expression,
262
+ "value" => @value
263
+ }
264
+ end
265
+ end
266
+
267
+ class MockServerURLGenerator
268
+ include Base
269
+
270
+ def initialize(regex:, example:)
271
+ @regex = regex
272
+ @example = example
273
+ end
274
+
275
+ def as_basic
276
+ {
277
+ "pact:generator:type" => "MockServerURL",
278
+ "pact:matcher:type" => "regex",
279
+ "regex" => @regex,
280
+ "example" => @example,
281
+ "value" => @example
282
+ }
283
+ end
284
+ end
285
+ end
286
+ end
287
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Generators
6
+
7
+ def generate_random_int(min:, max:)
8
+ Pact::V2::Generators::RandomIntGenerator.new(min: min, max: max)
9
+ end
10
+ def generate_random_decimal(digits:)
11
+ Pact::V2::Generators::RandomDecimalGenerator.new(digits: digits)
12
+ end
13
+ def generate_random_hexadecimal(digits:)
14
+ Pact::V2::Generators::RandomHexadecimalGenerator.new(digits: digits)
15
+ end
16
+ def generate_random_string(size:)
17
+ Pact::V2::Generators::RandomStringGenerator.new(size: size)
18
+ end
19
+
20
+ def generate_uuid(example: nil)
21
+ Pact::V2::Generators::UuidGenerator.new(example: example)
22
+ end
23
+
24
+ def generate_date(format: nil, example: nil)
25
+ Pact::V2::Generators::DateGenerator.new(format: format, example: example)
26
+ end
27
+
28
+ def generate_time(format: nil)
29
+ Pact::V2::Generators::TimeGenerator.new(format: format)
30
+ end
31
+
32
+ def generate_datetime(format: nil)
33
+ Pact::V2::Generators::DateTimeGenerator.new(format: format)
34
+ end
35
+
36
+ def generate_random_boolean
37
+ Pact::V2::Generators::RandomBooleanGenerator.new
38
+ end
39
+
40
+ def generate_from_provider_state(expression:, example:)
41
+ Pact::V2::Generators::ProviderStateGenerator.new(expression: expression, example: example).as_basic
42
+ end
43
+
44
+ def generate_mock_server_url(regex: nil, example: nil)
45
+ Pact::V2::Generators::MockServerURLGenerator.new(regex: regex, example: example)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ # see https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md
7
+ class Base
8
+ attr_reader :spec_version, :kind, :template, :opts
9
+
10
+ class MatcherInitializationError < Pact::V2::Error; end
11
+
12
+ def initialize(spec_version:, kind:, template: nil, opts: {})
13
+ @spec_version = spec_version
14
+ @kind = kind
15
+ @template = template
16
+ @opts = opts
17
+ end
18
+
19
+ def as_basic
20
+ result = {
21
+ "pact:matcher:type" => serialize!(@kind.deep_dup, :basic)
22
+ }
23
+ result["status"] = serialize!(@opts[:status].deep_dup, :basic) if @opts[:status]
24
+ result["value"] = serialize!(@template.deep_dup, :basic) unless @template.nil?
25
+ result.merge!(serialize!(@opts.deep_dup, :basic))
26
+ result
27
+ end
28
+
29
+ def as_plugin
30
+ params = @opts.values.map { |v| format_primitive(v) }.join(",")
31
+ value = format_primitive(@template) unless @template.nil?
32
+
33
+ if @template.nil?
34
+ return "matching(#{@kind}#{params.present? ? ", #{params}" : ""})"
35
+ end
36
+
37
+ return "matching(#{@kind}, #{params}, #{value})" if params.present?
38
+
39
+ "matching(#{@kind}, #{value})"
40
+ end
41
+
42
+ private
43
+
44
+ def serialize!(data, format)
45
+ # serialize complex types recursively
46
+ case data
47
+ when TrueClass, FalseClass, Numeric, String
48
+ data
49
+ when Array
50
+ data.map { |v| serialize!(v, format) }
51
+ when Hash
52
+ data.transform_values { |v| serialize!(v, format) }
53
+ when Pact::V2::Matchers::Base
54
+ return data.as_basic if format == :basic
55
+ data.as_plugin if format == :plugin
56
+ else
57
+ data
58
+ end
59
+ end
60
+
61
+ def format_primitive(arg)
62
+ case arg
63
+ when TrueClass, FalseClass, Numeric
64
+ arg.to_s
65
+ when String
66
+ "'#{arg}'"
67
+ else
68
+ raise "#{arg.class} is not a primitive"
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V1
7
+ class Equality < Pact::V2::Matchers::Base
8
+ def initialize(template)
9
+ super(spec_version: Pact::V2::Matchers::PACT_SPEC_V1, kind: "equality", template: template)
10
+ end
11
+
12
+ def as_plugin
13
+ "matching(equalTo, #{format_primitive(@template)})"
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V2
7
+ class Regex < Pact::V2::Matchers::Base
8
+ def initialize(regex, template)
9
+ raise MatcherInitializationError, "#{self.class}: #{regex} should be an instance of Regexp" unless regex.is_a?(Regexp)
10
+ raise MatcherInitializationError, "#{self.class}: #{template} should be an instance of String or Array" unless template.is_a?(String) || template.is_a?(Array)
11
+ raise MatcherInitializationError, "#{self.class}: #{template} array values should be strings" if template.is_a?(Array) && !template.all?(String)
12
+
13
+ super(spec_version: Pact::V2::Matchers::PACT_SPEC_V2, kind: "regex", template: template, opts: {regex: regex.to_s})
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V2
7
+ class Type < Pact::V2::Matchers::Base
8
+ def initialize(template)
9
+ raise MatcherInitializationError, "#{self.class}: template is not a primitive" unless template.is_a?(TrueClass) || template.is_a?(FalseClass) || template.is_a?(Numeric) || template.is_a?(String) || template.is_a?(Array) || template.is_a?(Hash)
10
+
11
+ super(spec_version: Pact::V2::Matchers::PACT_SPEC_V2, kind: "type", template: template)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V3
7
+ class Boolean < Pact::V2::Matchers::Base
8
+ def initialize(template)
9
+ raise MatcherInitializationError, "#{self.class}: #{template} should be an instance of Boolean" unless template.is_a?(TrueClass) || template.is_a?(FalseClass)
10
+
11
+ super(spec_version: Pact::V2::Matchers::PACT_SPEC_V3, kind: "boolean", template: template)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V3
7
+ class ContentType < Pact::V2::Matchers::Base
8
+ def initialize(content_type, template: nil)
9
+ @content_type = content_type
10
+ @template = template
11
+ @opts = {}
12
+ @opts[:plugin_template] = template unless template.nil?
13
+ unless content_type.is_a?(String) && !content_type.empty?
14
+ raise MatcherInitializationError, "#{self.class}: content_type must be a non-empty String"
15
+ end
16
+
17
+ super(
18
+ spec_version: Pact::V2::Matchers::PACT_SPEC_V3,
19
+ kind: "contentType",
20
+ template: content_type,
21
+ opts: @opts
22
+ )
23
+ end
24
+
25
+ def as_plugin
26
+ "matching(contentType, '#{@content_type}', '#{@opts[:plugin_template]}')"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V3
7
+ class Date < Pact::V2::Matchers::Base
8
+ def initialize(format, template)
9
+ raise MatcherInitializationError, "#{self.class}: #{format} should be an instance of String" unless template.is_a?(String)
10
+ raise MatcherInitializationError, "#{self.class}: #{template} should be an instance of String" unless template.is_a?(String)
11
+
12
+ super(spec_version: Pact::V2::Matchers::PACT_SPEC_V3, kind: "date", template: template, opts: {format: format})
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V3
7
+ class DateTime < Pact::V2::Matchers::Base
8
+ def initialize(format, template)
9
+ raise MatcherInitializationError, "#{self.class}: #{format} should be an instance of String" unless template.is_a?(String)
10
+ raise MatcherInitializationError, "#{self.class}: #{template} should be an instance of String" unless template.is_a?(String)
11
+
12
+ super(spec_version: Pact::V2::Matchers::PACT_SPEC_V3, kind: "datetime", template: template, opts: {format: format})
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V3
7
+ class Decimal < Pact::V2::Matchers::Base
8
+ def initialize(template)
9
+ raise MatcherInitializationError, "#{self.class}: #{template} should be an instance of Float" unless template.is_a?(Float)
10
+
11
+ super(spec_version: Pact::V2::Matchers::PACT_SPEC_V3, kind: "decimal", template: template)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V3
7
+ class Each < Pact::V2::Matchers::Base
8
+ def initialize(template, min)
9
+ raise MatcherInitializationError, "#{self.class}: #{min} should be greater than 0" if min.present? && min < 1
10
+
11
+ min_array_size = min.presence || 1
12
+ val = template.is_a?(Array) ? template : [template] * min_array_size
13
+
14
+ raise MatcherInitializationError, "#{self.class}: #{min} is invalid: template size is #{val.size}" if min_array_size != val.size
15
+
16
+ super(
17
+ spec_version: Pact::V2::Matchers::PACT_SPEC_V3,
18
+ kind: "type",
19
+ template: val,
20
+ opts: {min: min_array_size})
21
+ end
22
+
23
+ def as_plugin
24
+ if @template.first.is_a?(Hash)
25
+ return {
26
+ "pact:match" => "eachValue(matching($'SAMPLE'))",
27
+ "SAMPLE" => serialize!(@template.first.deep_dup, :plugin)
28
+ }
29
+ end
30
+
31
+ params = @opts.except(:min).values.map { |v| format_primitive(v) }.join(",")
32
+ value = format_primitive(@template.first)
33
+
34
+ return "eachValue(matching(#{@kind}, #{params}, #{value}))" if params.present?
35
+
36
+ "eachValue(matching(#{@kind}, #{value}))"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V3
7
+ class Include < Pact::V2::Matchers::Base
8
+ def initialize(template)
9
+ raise MatcherInitializationError, "#{self.class}: #{template} should be an instance of String" unless template.is_a?(String)
10
+
11
+ super(spec_version: Pact::V2::Matchers::PACT_SPEC_V3, kind: "include", template: template)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V3
7
+ class Integer < Pact::V2::Matchers::Base
8
+ def initialize(template)
9
+ raise MatcherInitializationError, "#{self.class}: #{template} should be an instance of Integer" unless template.is_a?(::Integer)
10
+
11
+ super(spec_version: Pact::V2::Matchers::PACT_SPEC_V3, kind: "integer", template: template)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V3
7
+ class Null < Pact::V2::Matchers::Base
8
+ def initialize
9
+ super(spec_version: Pact::V2::Matchers::PACT_SPEC_V3, kind: "null", template: nil)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pact
4
+ module V2
5
+ module Matchers
6
+ module V3
7
+ class Number < Pact::V2::Matchers::Base
8
+ def initialize(template)
9
+ raise MatcherInitializationError, "#{self.class}: #{template} should be an instance of Numeric" unless template.is_a?(Numeric)
10
+
11
+ super(spec_version: Pact::V2::Matchers::PACT_SPEC_V3, kind: "number", template: template)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end