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