pact 0.1.28 → 1.3.3

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 (285) hide show
  1. data/.gitignore +2 -1
  2. data/.ruby-version +1 -0
  3. data/.travis.yml +8 -0
  4. data/CHANGELOG.md +374 -0
  5. data/Gemfile +0 -1
  6. data/Gemfile.lock +58 -55
  7. data/README.md +214 -139
  8. data/Rakefile +4 -28
  9. data/bin/pact +2 -2
  10. data/config.ru +3 -0
  11. data/documentation/README.md +13 -0
  12. data/documentation/configuration.md +166 -0
  13. data/documentation/diff_formatter_embedded.png +0 -0
  14. data/documentation/diff_formatter_list.png +0 -0
  15. data/documentation/diff_formatter_unix.png +0 -0
  16. data/example/animal-service/Gemfile +14 -0
  17. data/example/animal-service/Gemfile.lock +69 -0
  18. data/example/animal-service/Rakefile +5 -0
  19. data/example/animal-service/config.ru +3 -0
  20. data/example/animal-service/db/animal_db.sqlite3 +0 -0
  21. data/example/animal-service/lib/animal_service/animal_repository.rb +12 -0
  22. data/example/animal-service/lib/animal_service/api.rb +28 -0
  23. data/example/animal-service/lib/animal_service/db.rb +5 -0
  24. data/example/animal-service/spec/service_consumers/pact_helper.rb +11 -0
  25. data/example/animal-service/spec/service_consumers/provider_states_for_zoo_app.rb +26 -0
  26. data/example/zoo-app/Gemfile +12 -0
  27. data/example/zoo-app/Gemfile.lock +63 -0
  28. data/example/zoo-app/Rakefile +5 -0
  29. data/example/zoo-app/doc/pacts/markdown/README.md +3 -0
  30. data/example/zoo-app/doc/pacts/markdown/Zoo App - Animal Service.md +75 -0
  31. data/example/zoo-app/lib/zoo_app/animal_service_client.rb +40 -0
  32. data/example/zoo-app/lib/zoo_app/models/alligator.rb +15 -0
  33. data/example/zoo-app/spec/pacts/zoo_app-animal_service.json +67 -0
  34. data/example/zoo-app/spec/service_providers/animal_service_client_spec.rb +71 -0
  35. data/example/zoo-app/spec/service_providers/pact_helper.rb +15 -0
  36. data/example/zoo-app/spec/spec_helper.rb +6 -0
  37. data/lib/pact/cli.rb +138 -0
  38. data/lib/pact/configuration.rb +169 -28
  39. data/lib/pact/consumer/app_manager.rb +10 -29
  40. data/lib/pact/consumer/configuration/configuration_extensions.rb +15 -0
  41. data/lib/pact/consumer/configuration/dsl.rb +12 -0
  42. data/lib/pact/consumer/configuration/mock_service.rb +91 -0
  43. data/lib/pact/consumer/configuration/service_consumer.rb +51 -0
  44. data/lib/pact/consumer/configuration/service_provider.rb +40 -0
  45. data/lib/pact/consumer/configuration.rb +11 -0
  46. data/lib/pact/consumer/consumer_contract_builder.rb +44 -47
  47. data/lib/pact/consumer/interaction_builder.rb +41 -0
  48. data/lib/pact/consumer/interactions_filter.rb +48 -0
  49. data/lib/pact/consumer/mock_service/app.rb +82 -0
  50. data/lib/pact/consumer/mock_service/interaction_delete.rb +33 -0
  51. data/lib/pact/consumer/mock_service/interaction_list.rb +76 -0
  52. data/lib/pact/consumer/mock_service/interaction_mismatch.rb +73 -0
  53. data/lib/pact/consumer/mock_service/interaction_post.rb +31 -0
  54. data/lib/pact/consumer/mock_service/interaction_replay.rb +139 -0
  55. data/lib/pact/consumer/mock_service/log_get.rb +28 -0
  56. data/lib/pact/consumer/mock_service/missing_interactions_get.rb +30 -0
  57. data/lib/pact/consumer/mock_service/mock_service_administration_endpoint.rb +31 -0
  58. data/lib/pact/consumer/mock_service/pact_post.rb +33 -0
  59. data/lib/pact/consumer/mock_service/rack_request_helper.rb +51 -0
  60. data/lib/pact/consumer/mock_service/verification_get.rb +68 -0
  61. data/lib/pact/consumer/mock_service.rb +1 -339
  62. data/lib/pact/consumer/mock_service_client.rb +65 -0
  63. data/lib/pact/consumer/mock_service_interaction_expectation.rb +37 -0
  64. data/lib/pact/consumer/request.rb +27 -0
  65. data/lib/pact/consumer/rspec.rb +9 -19
  66. data/lib/pact/consumer/server.rb +90 -0
  67. data/lib/pact/consumer/spec_hooks.rb +38 -0
  68. data/lib/pact/consumer/world.rb +37 -0
  69. data/lib/pact/consumer.rb +10 -7
  70. data/lib/pact/consumer_contract/consumer_contract.rb +115 -0
  71. data/lib/pact/consumer_contract/consumer_contract_writer.rb +84 -0
  72. data/lib/pact/consumer_contract/file_name.rb +19 -0
  73. data/lib/pact/consumer_contract/headers.rb +51 -0
  74. data/lib/pact/consumer_contract/interaction.rb +67 -0
  75. data/lib/pact/consumer_contract/pact_file.rb +24 -0
  76. data/lib/pact/consumer_contract/request.rb +73 -0
  77. data/lib/pact/consumer_contract/service_consumer.rb +28 -0
  78. data/lib/pact/consumer_contract/service_provider.rb +28 -0
  79. data/lib/pact/consumer_contract.rb +1 -110
  80. data/lib/pact/doc/doc_file.rb +40 -0
  81. data/lib/pact/doc/generate.rb +11 -0
  82. data/lib/pact/doc/generator.rb +82 -0
  83. data/lib/pact/doc/interaction_view_model.rb +114 -0
  84. data/lib/pact/doc/markdown/consumer_contract_renderer.rb +56 -0
  85. data/lib/pact/doc/markdown/generator.rb +26 -0
  86. data/lib/pact/doc/markdown/index_renderer.rb +41 -0
  87. data/lib/pact/doc/markdown/interaction.erb +14 -0
  88. data/lib/pact/doc/markdown/interaction_renderer.rb +38 -0
  89. data/lib/pact/doc/sort_interactions.rb +17 -0
  90. data/lib/pact/matchers/actual_type.rb +16 -0
  91. data/lib/pact/matchers/base_difference.rb +37 -0
  92. data/lib/pact/matchers/differ.rb +153 -0
  93. data/lib/pact/matchers/difference.rb +13 -0
  94. data/lib/pact/matchers/difference_indicator.rb +26 -0
  95. data/lib/pact/matchers/embedded_diff_formatter.rb +62 -0
  96. data/lib/pact/matchers/expected_type.rb +35 -0
  97. data/lib/pact/matchers/index_not_found.rb +15 -0
  98. data/lib/pact/matchers/list_diff_formatter.rb +101 -0
  99. data/lib/pact/matchers/matchers.rb +91 -37
  100. data/lib/pact/matchers/no_diff_indicator.rb +18 -0
  101. data/lib/pact/matchers/regexp_difference.rb +13 -0
  102. data/lib/pact/matchers/type_difference.rb +16 -0
  103. data/lib/pact/matchers/unexpected_index.rb +11 -0
  104. data/lib/pact/matchers/unexpected_key.rb +11 -0
  105. data/lib/pact/matchers/unix_diff_formatter.rb +114 -0
  106. data/lib/pact/project_root.rb +7 -0
  107. data/lib/pact/provider/configuration/configuration_extension.rb +58 -0
  108. data/lib/pact/provider/configuration/dsl.rb +13 -0
  109. data/lib/pact/provider/configuration/pact_verification.rb +46 -0
  110. data/lib/pact/provider/configuration/service_provider_config.rb +16 -0
  111. data/lib/pact/provider/configuration/service_provider_dsl.rb +59 -0
  112. data/lib/pact/provider/configuration.rb +7 -0
  113. data/lib/pact/provider/context.rb +0 -0
  114. data/lib/pact/provider/matchers/messages.rb +45 -0
  115. data/lib/pact/provider/pact_helper_locator.rb +22 -0
  116. data/lib/pact/provider/pact_spec_runner.rb +123 -0
  117. data/lib/pact/provider/pact_verification.rb +17 -0
  118. data/lib/pact/provider/print_missing_provider_states.rb +30 -0
  119. data/lib/pact/provider/request.rb +70 -0
  120. data/lib/pact/provider/rspec/backtrace_formatter.rb +43 -0
  121. data/lib/pact/provider/rspec/custom_options_file +0 -0
  122. data/lib/pact/provider/rspec/formatter_rspec_2.rb +65 -0
  123. data/lib/pact/provider/rspec/formatter_rspec_3.rb +96 -0
  124. data/lib/pact/provider/rspec/matchers.rb +97 -0
  125. data/lib/pact/provider/rspec.rb +181 -0
  126. data/lib/pact/provider/state/provider_state.rb +181 -0
  127. data/lib/pact/provider/state/provider_state_configured_modules.rb +13 -0
  128. data/lib/pact/provider/state/provider_state_manager.rb +42 -0
  129. data/lib/pact/provider/state/provider_state_proxy.rb +39 -0
  130. data/lib/pact/provider/test_methods.rb +47 -0
  131. data/lib/pact/provider/verification_report.rb +36 -0
  132. data/lib/pact/provider/world.rb +23 -0
  133. data/lib/pact/provider.rb +3 -0
  134. data/lib/pact/reification.rb +6 -4
  135. data/lib/pact/rspec.rb +53 -0
  136. data/lib/pact/shared/active_support_support.rb +51 -0
  137. data/lib/pact/shared/dsl.rb +76 -0
  138. data/lib/pact/shared/jruby_support.rb +18 -0
  139. data/lib/pact/shared/json_differ.rb +15 -0
  140. data/lib/pact/shared/key_not_found.rb +15 -0
  141. data/lib/pact/shared/null_expectation.rb +31 -0
  142. data/lib/pact/shared/request.rb +80 -0
  143. data/lib/pact/shared/text_differ.rb +14 -0
  144. data/lib/pact/something_like.rb +49 -0
  145. data/lib/pact/symbolize_keys.rb +12 -0
  146. data/lib/pact/tasks/task_helper.rb +36 -0
  147. data/lib/pact/tasks/verification_task.rb +87 -0
  148. data/lib/pact/tasks.rb +2 -0
  149. data/lib/pact/templates/provider_state.erb +14 -0
  150. data/lib/pact/term.rb +47 -2
  151. data/lib/pact/version.rb +1 -1
  152. data/lib/pact.rb +1 -1
  153. data/lib/tasks/pact.rake +25 -2
  154. data/pact.gemspec +13 -11
  155. data/{scratchpad.txt → scratchpad.rb} +18 -2
  156. data/spec/features/consumption_spec.rb +24 -56
  157. data/spec/features/production_spec.rb +19 -24
  158. data/spec/features/{producer_states → provider_states}/zebras.rb +3 -3
  159. data/spec/integration/consumer_spec.rb +212 -0
  160. data/spec/integration/pact/consumer_configuration_spec.rb +66 -0
  161. data/spec/integration/pact/provider_configuration_spec.rb +25 -0
  162. data/spec/lib/pact/cli_spec.rb +47 -0
  163. data/spec/lib/pact/configuration_spec.rb +269 -7
  164. data/spec/lib/pact/consumer/app_manager_spec.rb +3 -3
  165. data/spec/lib/pact/consumer/configuration_spec.rb +57 -0
  166. data/spec/lib/pact/consumer/consumer_contract_builder_spec.rb +52 -70
  167. data/spec/lib/pact/consumer/interaction_builder_spec.rb +91 -0
  168. data/spec/lib/pact/consumer/interactions_spec.rb +64 -0
  169. data/spec/lib/pact/consumer/mock_service/app_spec.rb +52 -0
  170. data/spec/lib/pact/consumer/mock_service/interaction_list_spec.rb +78 -0
  171. data/spec/lib/pact/consumer/mock_service/interaction_mismatch_spec.rb +70 -0
  172. data/spec/lib/pact/consumer/mock_service/interaction_replay_spec.rb +12 -0
  173. data/spec/lib/pact/consumer/mock_service/rack_request_helper_spec.rb +88 -0
  174. data/spec/lib/pact/consumer/mock_service/verification_get_spec.rb +142 -0
  175. data/spec/lib/pact/consumer/mock_service_client_spec.rb +88 -0
  176. data/spec/lib/pact/consumer/mock_service_interaction_expectation_spec.rb +54 -0
  177. data/spec/lib/pact/consumer/request_spec.rb +24 -0
  178. data/spec/lib/pact/consumer/service_consumer_spec.rb +1 -1
  179. data/spec/lib/pact/consumer_contract/active_support_support_spec.rb +58 -0
  180. data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +180 -0
  181. data/spec/lib/pact/consumer_contract/consumer_contract_writer_spec.rb +111 -0
  182. data/spec/lib/pact/consumer_contract/headers_spec.rb +107 -0
  183. data/spec/lib/pact/consumer_contract/interaction_spec.rb +107 -0
  184. data/spec/lib/pact/{request_spec.rb → consumer_contract/request_spec.rb} +80 -67
  185. data/spec/lib/pact/doc/generator_spec.rb +84 -0
  186. data/spec/lib/pact/doc/interaction_view_model_spec.rb +132 -0
  187. data/spec/lib/pact/doc/markdown/consumer_contract_renderer_spec.rb +29 -0
  188. data/spec/lib/pact/doc/markdown/index_renderer_spec.rb +29 -0
  189. data/spec/lib/pact/matchers/differ_spec.rb +214 -0
  190. data/spec/lib/pact/matchers/difference_spec.rb +22 -0
  191. data/spec/lib/pact/matchers/embedded_diff_formatter_spec.rb +90 -0
  192. data/spec/lib/pact/matchers/index_not_found_spec.rb +21 -0
  193. data/spec/lib/pact/matchers/list_diff_formatter_spec.rb +114 -0
  194. data/spec/lib/pact/matchers/matchers_spec.rb +400 -254
  195. data/spec/lib/pact/matchers/regexp_difference_spec.rb +20 -0
  196. data/spec/lib/pact/matchers/type_difference_spec.rb +34 -0
  197. data/spec/lib/pact/matchers/unexpected_index_spec.rb +20 -0
  198. data/spec/lib/pact/matchers/unexpected_key_spec.rb +20 -0
  199. data/spec/lib/pact/matchers/unix_diff_formatter_spec.rb +216 -0
  200. data/spec/lib/pact/provider/configuration/configuration_extension_spec.rb +30 -0
  201. data/spec/lib/pact/provider/configuration/pact_verification_spec.rb +43 -0
  202. data/spec/lib/pact/provider/configuration/service_provider_config_spec.rb +21 -0
  203. data/spec/lib/pact/provider/configuration/service_provider_dsl_spec.rb +108 -0
  204. data/spec/lib/pact/provider/configuration_spec.rb +50 -0
  205. data/spec/lib/pact/provider/matchers/messages_spec.rb +116 -0
  206. data/spec/lib/pact/provider/pact_helper_locator_spec.rb +54 -0
  207. data/spec/lib/pact/provider/print_missing_provider_states_spec.rb +19 -0
  208. data/spec/lib/pact/provider/request_spec.rb +78 -0
  209. data/spec/lib/pact/provider/rspec/formatter_rspec_2_spec.rb +68 -0
  210. data/spec/lib/pact/provider/rspec/formatter_rspec_3_spec.rb +72 -0
  211. data/spec/lib/pact/provider/rspec_spec.rb +55 -0
  212. data/spec/lib/pact/provider/state/provider_state_manager_spec.rb +89 -0
  213. data/spec/lib/pact/provider/state/provider_state_proxy_spec.rb +80 -0
  214. data/spec/lib/pact/provider/state/provider_state_spec.rb +213 -0
  215. data/spec/lib/pact/provider/world_spec.rb +41 -0
  216. data/spec/lib/pact/reification_spec.rb +24 -0
  217. data/spec/lib/pact/shared/dsl_spec.rb +86 -0
  218. data/spec/lib/pact/shared/json_differ_spec.rb +36 -0
  219. data/spec/lib/pact/shared/key_not_found_spec.rb +20 -0
  220. data/spec/lib/pact/shared/request_spec.rb +111 -0
  221. data/spec/lib/pact/shared/text_differ_spec.rb +54 -0
  222. data/spec/lib/pact/something_like_spec.rb +21 -0
  223. data/spec/lib/pact/tasks/task_helper_spec.rb +74 -0
  224. data/spec/lib/pact/tasks/verification_task_spec.rb +75 -0
  225. data/spec/lib/pact/term_spec.rb +57 -4
  226. data/spec/pact_specification/compliance-1.0.0.rb +47 -0
  227. data/spec/spec_helper.rb +17 -0
  228. data/spec/standalone/consumer_fail_test.rb +55 -0
  229. data/spec/standalone/consumer_pass_test.rb +51 -0
  230. data/spec/support/a_consumer-a_producer.json +2 -4
  231. data/spec/support/a_consumer-a_provider.json +32 -0
  232. data/spec/support/active_support_if_configured.rb +6 -0
  233. data/spec/support/app_for_config_ru.rb +4 -0
  234. data/spec/support/consumer_contract_template.json +24 -0
  235. data/spec/support/dsl_spec_support.rb +7 -0
  236. data/spec/support/factories.rb +82 -0
  237. data/spec/support/generated_index.md +4 -0
  238. data/spec/support/generated_markdown.md +55 -0
  239. data/spec/support/interaction_view_model.json +63 -0
  240. data/spec/support/interaction_view_model_with_terms.json +50 -0
  241. data/spec/support/markdown_pact.json +48 -0
  242. data/spec/support/missing_provider_states_output.txt +25 -0
  243. data/spec/support/options.json +21 -0
  244. data/spec/support/options_app.rb +15 -0
  245. data/spec/support/pact_helper.rb +57 -0
  246. data/spec/support/shared_examples_for_request.rb +94 -0
  247. data/spec/support/spec_support.rb +20 -0
  248. data/spec/support/stubbing.json +22 -0
  249. data/spec/support/stubbing_using_allow.rb +29 -0
  250. data/spec/support/term.json +48 -0
  251. data/spec/support/test_app_fail.json +41 -2
  252. data/spec/support/test_app_pass.json +19 -2
  253. data/spec/support/test_app_with_right_content_type_differ.json +23 -0
  254. data/tasks/pact-test.rake +98 -8
  255. data/tasks/spec.rake +8 -0
  256. metadata +393 -95
  257. data/lib/pact/app.rb +0 -32
  258. data/lib/pact/consumer/configuration_dsl.rb +0 -71
  259. data/lib/pact/consumer/dsl.rb +0 -98
  260. data/lib/pact/consumer/interaction.rb +0 -70
  261. data/lib/pact/consumer/run_condor.rb +0 -4
  262. data/lib/pact/consumer/run_mock_contract_service.rb +0 -13
  263. data/lib/pact/consumer/service_consumer.rb +0 -22
  264. data/lib/pact/consumer/service_producer.rb +0 -23
  265. data/lib/pact/json_warning.rb +0 -23
  266. data/lib/pact/producer/configuration_dsl.rb +0 -62
  267. data/lib/pact/producer/matchers.rb +0 -22
  268. data/lib/pact/producer/pact_spec_runner.rb +0 -57
  269. data/lib/pact/producer/producer_state.rb +0 -81
  270. data/lib/pact/producer/rspec.rb +0 -127
  271. data/lib/pact/producer/test_methods.rb +0 -89
  272. data/lib/pact/producer.rb +0 -1
  273. data/lib/pact/rake_task.rb +0 -64
  274. data/lib/pact/request.rb +0 -109
  275. data/lib/pact/verification_task.rb +0 -57
  276. data/spec/integration/pact/configuration_spec.rb +0 -65
  277. data/spec/lib/pact/consumer/dsl_spec.rb +0 -52
  278. data/spec/lib/pact/consumer/interaction_spec.rb +0 -108
  279. data/spec/lib/pact/consumer/mock_service_spec.rb +0 -147
  280. data/spec/lib/pact/consumer_contract_spec.rb +0 -125
  281. data/spec/lib/pact/producer/configuration_dsl_spec.rb +0 -101
  282. data/spec/lib/pact/producer/producer_state_spec.rb +0 -103
  283. data/spec/lib/pact/producer/rspec_spec.rb +0 -48
  284. data/spec/lib/pact/verification_task_spec.rb +0 -64
  285. data/spec/support/pact_rake_support.rb +0 -41
@@ -0,0 +1,35 @@
1
+ require 'pact/matchers/difference_indicator'
2
+
3
+ module Pact
4
+ class ExpectedType < Pact::DifferenceIndicator
5
+
6
+ def initialize value
7
+ @value = value
8
+ end
9
+
10
+ def type
11
+ @value.class.name
12
+ end
13
+
14
+ def to_json options = {}
15
+ type
16
+ end
17
+
18
+ def as_json options = {}
19
+ type
20
+ end
21
+
22
+ def eq? other
23
+ self.class == other.class && other.type == type
24
+ end
25
+
26
+ def == other
27
+ eq? other
28
+ end
29
+
30
+ def to_s
31
+ type
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ require 'pact/matchers/difference_indicator'
2
+
3
+ module Pact
4
+ class IndexNotFound < Pact::DifferenceIndicator
5
+
6
+ def to_s
7
+ "<index not found>"
8
+ end
9
+
10
+ def empty?
11
+ true
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,101 @@
1
+ module Pact
2
+ module Matchers
3
+ class ListDiffFormatter
4
+
5
+ attr_reader :diff
6
+
7
+ def initialize diff, options = {}
8
+ @diff = diff
9
+ end
10
+
11
+ def self.call diff, options = {}
12
+ new(diff, options).call
13
+ end
14
+
15
+ def to_hash
16
+ diff
17
+ end
18
+
19
+ def call
20
+ to_s
21
+ end
22
+
23
+ def to_s
24
+ diff_descriptions(diff).join("\n")
25
+ end
26
+
27
+ def diff_descriptions obj, path = [], descriptions = []
28
+ case obj
29
+ when Hash then handle_hash obj, path, descriptions
30
+ when Array then handle_array obj, path, descriptions
31
+ when Difference then handle_difference obj, path, descriptions
32
+ when TypeDifference then handle_mismatched_type obj, path, descriptions
33
+ when RegexpDifference then handle_mismatched_regexp obj, path, descriptions
34
+ when NoDiffIndicator then nil
35
+ else
36
+ raise "Invalid diff, expected Hash, Array, NoDiffIndicator or Difference, found #{obj.class}"
37
+ end
38
+ descriptions
39
+ end
40
+
41
+ def handle_hash hash, path, descriptions
42
+ hash.each_pair do | key, value |
43
+ diff_descriptions value, path + [key.inspect], descriptions
44
+ end
45
+ end
46
+
47
+ def handle_array array, path, descriptions
48
+ array.each_with_index do | obj, index |
49
+ diff_descriptions obj, path + [index], descriptions
50
+ end
51
+ end
52
+
53
+ def handle_difference difference, path, descriptions
54
+ case difference.expected
55
+ when Pact::UnexpectedKey then handle_unexpected_key(difference, path, descriptions)
56
+ when Pact::UnexpectedIndex then handle_unexpected_index(difference, path, descriptions)
57
+ else
58
+ case difference.actual
59
+ when Pact::KeyNotFound then handle_key_not_found(difference, path, descriptions)
60
+ when Pact::IndexNotFound then handle_index_not_found(difference, path, descriptions)
61
+ else
62
+ handle_mismatched_value(difference, path, descriptions)
63
+ end
64
+ end
65
+ end
66
+
67
+ def handle_unexpected_index difference, path, descriptions
68
+ descriptions << "\tAt:\n\t\t#{path_to_s(path)}\n\tArray contained unexpected item:\n\t\t#{difference.actual.ai}"
69
+ end
70
+
71
+ def handle_mismatched_value difference, path, descriptions
72
+ descriptions << "\tAt:\n\t\t#{path_to_s(path)}\n\tExpected:\n\t\t#{difference.expected.ai}\n\tActual:\n\t\t#{difference.actual.ai}"
73
+ end
74
+
75
+ def handle_mismatched_regexp difference, path, descriptions
76
+ descriptions << "\tAt:\n\t\t#{path_to_s(path)}\n\tExpected to match:\n\t\t#{difference.expected.inspect}\n\tActual:\n\t\t#{difference.actual.ai}"
77
+ end
78
+
79
+ def handle_mismatched_type difference, path, descriptions
80
+ descriptions << "\tAt:\n\t\t#{path_to_s(path)}\n\tExpected type:\n\t\t#{difference.expected}\n\tActual type:\n\t\t#{difference.actual}"
81
+ end
82
+
83
+ def handle_index_not_found difference, path, descriptions
84
+ descriptions << "\tAt:\n\t\t#{path_to_s(path)}\n\tMissing index with value:\n\t\t#{difference.expected.ai}"
85
+ end
86
+
87
+ def handle_key_not_found difference, path, descriptions
88
+ descriptions << "\tAt:\n\t\t#{path_to_s(path)}\n\tMissing key with value:\n\t\t#{difference.expected.ai}"
89
+ end
90
+
91
+ def handle_unexpected_key difference, path, descriptions
92
+ descriptions << "\tAt:\n\t\t#{path_to_s(path)}\n\tHash contained unexpected key with value:\n\t\t#{difference.actual.ai}"
93
+ end
94
+
95
+ def path_to_s path
96
+ "[" + path.join("][") + "]"
97
+ end
98
+
99
+ end
100
+ end
101
+ end
@@ -1,82 +1,136 @@
1
1
  require 'awesome_print'
2
2
  require 'pact/term'
3
+ require 'pact/something_like'
4
+ require 'pact/shared/null_expectation'
5
+ require 'pact/shared/key_not_found'
6
+ require 'pact/matchers/unexpected_key'
7
+ require 'pact/matchers/unexpected_index'
8
+ require 'pact/matchers/index_not_found'
9
+ require 'pact/matchers/difference'
10
+ require 'pact/matchers/regexp_difference'
11
+ require 'pact/matchers/type_difference'
12
+ require 'pact/matchers/expected_type'
13
+ require 'pact/matchers/actual_type'
14
+ require 'pact/matchers/no_diff_indicator'
3
15
 
4
16
  module Pact
5
17
  module Matchers
6
18
 
7
- NO_DIFF_INDICATOR = 'no difference here!'
19
+ NO_DIFF_INDICATOR = NoDiffIndicator.new
20
+ DEFAULT_OPTIONS = {allow_unexpected_keys: true, type: false}.freeze
8
21
 
9
- def diff expected, actual, options = {}
22
+ def diff expected, actual, opts = {}
23
+ calculate_diff(Pact::Term.unpack_regexps(expected), actual, DEFAULT_OPTIONS.merge(opts))
24
+ end
25
+
26
+ def type_diff expected, actual, opts = {}
27
+ calculate_diff Pact::Term.unpack_regexps(expected), actual, DEFAULT_OPTIONS.merge(opts).merge(type: true)
28
+ end
29
+
30
+ private
31
+
32
+ def calculate_diff expected, actual, opts = {}
33
+ options = DEFAULT_OPTIONS.merge(opts)
10
34
  case expected
11
35
  when Hash then hash_diff(expected, actual, options)
12
36
  when Array then array_diff(expected, actual, options)
13
- when Pact::Term then diff(expected.matcher, actual, options)
14
37
  when Regexp then regexp_diff(expected, actual, options)
38
+ when Pact::SomethingLike then calculate_diff(expected.contents, actual, options.merge(:type => true))
15
39
  else object_diff(expected, actual, options)
16
40
  end
17
41
  end
18
42
 
19
- def structure_diff expected, actual
20
- diff expected, actual, {structure: true}
21
- end
43
+ alias_method :structure_diff, :type_diff # Backwards compatibility
22
44
 
23
45
  def regexp_diff regexp, actual, options
24
- if actual != nil && regexp.match(actual)
46
+ if actual.is_a?(String) && regexp.match(actual)
25
47
  {}
26
48
  else
27
- {expected: regexp, actual: actual}
49
+ RegexpDifference.new regexp, actual
28
50
  end
29
51
  end
30
52
 
31
53
  def array_diff expected, actual, options
32
54
  if actual.is_a? Array
33
- if expected.length == actual.length
34
- difference = []
35
- diff_found = false
36
- expected.each_with_index do | item, index|
37
- if (item_diff = diff(item, actual[index], options)).any?
38
- diff_found = true
39
- difference << item_diff
40
- else
41
- difference << NO_DIFF_INDICATOR
42
- end
43
- end
44
- diff_found ? difference : {}
55
+ actual_array_diff expected, actual, options
56
+ else
57
+ Difference.new expected, actual
58
+ end
59
+ end
60
+
61
+ def actual_array_diff expected, actual, options
62
+ difference = []
63
+ diff_found = false
64
+ length = [expected.length, actual.length].max
65
+ length.times do | index|
66
+ expected_item = expected.fetch(index, Pact::UnexpectedIndex.new)
67
+ actual_item = actual.fetch(index, Pact::IndexNotFound.new)
68
+ if (item_diff = calculate_diff(expected_item, actual_item, options)).any?
69
+ diff_found = true
70
+ difference << item_diff
45
71
  else
46
- {expected: expected, actual: actual}
72
+ difference << NO_DIFF_INDICATOR
73
+ end
74
+ end
75
+ diff_found ? difference : {}
76
+ end
77
+
78
+ def actual_hash_diff expected, actual, options
79
+ difference = expected.keys.inject({}) do |calculate_diff, key|
80
+ if (diff_at_key = calculate_diff(expected[key], actual.fetch(key, Pact::KeyNotFound.new), options)).any?
81
+ calculate_diff[key] = diff_at_key
47
82
  end
83
+ calculate_diff
84
+ end
85
+ difference.merge(check_for_unexpected_keys(expected, actual, options))
86
+ end
87
+
88
+ def check_for_unexpected_keys expected, actual, options
89
+ if options[:allow_unexpected_keys]
90
+ {}
48
91
  else
49
- {expected: expected, actual: actual}
92
+ (actual.keys - expected.keys).inject({}) do | calculate_diff, key |
93
+ calculate_diff[key] = Difference.new(UnexpectedKey.new, actual[key])
94
+ calculate_diff
95
+ end
50
96
  end
51
97
  end
52
98
 
53
99
  def hash_diff expected, actual, options
54
100
  if actual.is_a? Hash
55
- expected.keys.inject({}) do |diff, key|
56
- if (diff_at_key = diff(expected[key], actual[key], options)).any?
57
- diff[key] = diff_at_key
58
- end
59
- diff
60
- end
101
+ actual_hash_diff expected, actual, options
61
102
  else
62
- {expected: expected, actual: actual}
103
+ Difference.new expected, actual
63
104
  end
64
105
  end
65
106
 
66
- def class_diff expected, actual
67
- if expected.class != actual.class
68
- actual_display = actual.nil? ? nil : {:class => actual.class, :value => actual }
69
- expected_display = expected.nil? ? nil : {:class => expected.class, eg: expected}
70
- {:expected => expected_display, :actual => actual_display}
71
- else
107
+ def type_difference expected, actual
108
+ if types_match? expected, actual
72
109
  {}
110
+ else
111
+ TypeDifference.new type_diff_expected_display(expected), type_diff_actual_display(actual)
73
112
  end
74
113
  end
75
114
 
115
+ def type_diff_actual_display actual
116
+ actual.is_a?(KeyNotFound) ? actual : ActualType.new(actual)
117
+ end
118
+
119
+ def type_diff_expected_display expected
120
+ ExpectedType.new(expected)
121
+ end
122
+
123
+ def types_match? expected, actual
124
+ #There must be a more elegant way to do this
125
+ expected.class == actual.class ||
126
+ (expected.is_a?(TrueClass) && actual.is_a?(FalseClass)) ||
127
+ (expected.is_a?(FalseClass) && actual.is_a?(TrueClass))
128
+ end
129
+
76
130
  def object_diff expected, actual, options
77
- return class_diff(expected, actual) if options[:structure]
131
+ return type_difference(expected, actual) if options[:type]
78
132
  if expected != actual
79
- {:expected => expected, :actual => actual}
133
+ Difference.new expected, actual
80
134
  else
81
135
  {}
82
136
  end
@@ -0,0 +1,18 @@
1
+ module Pact
2
+ module Matchers
3
+ class NoDiffIndicator
4
+
5
+ def to_json options = {}
6
+ to_s
7
+ end
8
+
9
+ def to_s
10
+ 'no difference here!'
11
+ end
12
+
13
+ def == other
14
+ other.is_a? NoDiffIndicator
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ require 'pact/matchers/base_difference'
2
+
3
+ module Pact
4
+ module Matchers
5
+ class RegexpDifference < BaseDifference
6
+
7
+ def as_json options = {}
8
+ {:EXPECTED_TO_MATCH => expected.inspect, :ACTUAL => actual}
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ require 'pact/matchers/base_difference'
2
+
3
+ module Pact
4
+ module Matchers
5
+ class TypeDifference < BaseDifference
6
+
7
+ def as_json options = {}
8
+ if KeyNotFound === actual
9
+ {:EXPECTED_TYPE => expected.as_json, :ACTUAL => actual.as_json }
10
+ else
11
+ {:EXPECTED_TYPE => expected.as_json, :ACTUAL_TYPE => actual.as_json }
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ require 'pact/matchers/difference_indicator'
2
+
3
+ module Pact
4
+ class UnexpectedIndex < Pact::DifferenceIndicator
5
+
6
+ def to_s
7
+ '<index not to exist>'
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'pact/matchers/difference_indicator'
2
+
3
+ module Pact
4
+ class UnexpectedKey < Pact::DifferenceIndicator
5
+
6
+ def to_s
7
+ '<key not to exist>'
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,114 @@
1
+ require 'pact/shared/jruby_support'
2
+ require 'pact/matchers/differ'
3
+
4
+ module Pact
5
+ module Matchers
6
+
7
+ class UnixDiffFormatter
8
+
9
+ include JRubySupport
10
+
11
+ def initialize diff, options = {}
12
+ @diff = diff
13
+ @colour = options.fetch(:colour, false)
14
+ @differ = Pact::Matchers::Differ.new(@colour)
15
+ end
16
+
17
+ def self.call diff, options = {colour: Pact.configuration.color_enabled}
18
+ new(diff, options).call
19
+ end
20
+
21
+ def call
22
+ to_s
23
+ end
24
+
25
+ def to_s
26
+ expected = generate_string(diff, :expected)
27
+ actual = generate_string(diff, :actual)
28
+ @differ.diff_as_string(actual, expected).lstrip + "\n" + key
29
+ end
30
+
31
+ private
32
+
33
+ def handle thing, target
34
+ case thing
35
+ when Hash then copy_hash(thing, target)
36
+ when Array then copy_array(thing, target)
37
+ when Difference then copy_diff(thing, target)
38
+ when TypeDifference then copy_diff(thing, target)
39
+ when RegexpDifference then copy_diff(thing, target)
40
+ when NoDiffIndicator then copy_no_diff(thing, target)
41
+ else copy_object(thing, target)
42
+ end
43
+ end
44
+
45
+ def generate_string diff, target
46
+ comparable = handle(diff, target)
47
+ begin
48
+ # Can't think of an elegant way to check if we can pretty generate other than to try it and maybe fail
49
+ fix_blank_lines_in_empty_hashes JSON.pretty_generate(comparable)
50
+ rescue JSON::GeneratorError
51
+ comparable.to_s
52
+ end
53
+ end
54
+
55
+ def copy_hash hash, target
56
+ hash.keys.each_with_object({}) do | key, new_hash |
57
+ value = handle hash[key], target
58
+ new_hash[key] = value unless (KeyNotFound === value || UnexpectedKey === value)
59
+ end
60
+ end
61
+
62
+ def copy_array array, target
63
+ array.each_index.each_with_object([]) do | index, new_array |
64
+ value = handle array[index], target
65
+ new_array[index] = value unless (UnexpectedIndex === value || IndexNotFound === value)
66
+ end
67
+ end
68
+
69
+ def copy_no_diff(thing, target)
70
+ thing
71
+ end
72
+
73
+ def copy_diff difference, target
74
+ if target == :actual
75
+ handle difference.actual, target
76
+ else
77
+ handle difference.expected, target
78
+ end
79
+ end
80
+
81
+ def copy_object object, target
82
+ if Regexp === object
83
+ RegexpDecorator.new(object)
84
+ else
85
+ object
86
+ end
87
+ end
88
+
89
+ def key
90
+ "Key: " + @differ.red("-") + @differ.red(" means \"expected, but was not found\". \n") +
91
+ @differ.green(" +") + @differ.green(" means \"actual, should not be found\". \n") +
92
+ " Values where the expected matches the actual are not shown.\n"
93
+ end
94
+
95
+ class RegexpDecorator
96
+
97
+ def initialize regexp
98
+ @regexp = regexp
99
+ end
100
+
101
+ def to_json options={}
102
+ @regexp.inspect
103
+ end
104
+
105
+ def as_json
106
+ @regexp.inspect
107
+ end
108
+ end
109
+
110
+ attr_reader :diff
111
+ end
112
+
113
+ end
114
+ end
@@ -0,0 +1,7 @@
1
+ require 'pathname'
2
+
3
+ module Pact
4
+ def self.project_root
5
+ @project_root ||= Pathname.new(File.expand_path('../../../',__FILE__)).freeze
6
+ end
7
+ end
@@ -0,0 +1,58 @@
1
+ require 'pact/provider/state/provider_state'
2
+ require 'pact/provider/state/provider_state_configured_modules'
3
+
4
+ module Pact
5
+
6
+ module Provider
7
+
8
+ module Configuration
9
+
10
+ module ConfigurationExtension
11
+
12
+ def provider= provider
13
+ @provider = provider
14
+ end
15
+
16
+ def provider
17
+ if defined? @provider
18
+ @provider
19
+ else
20
+ raise "Please configure your provider. See the Provider section in the README for examples."
21
+ end
22
+ end
23
+
24
+ def add_pact_verification verification
25
+ pact_verifications << verification
26
+ end
27
+
28
+ def pact_verifications
29
+ @pact_verifications ||= []
30
+ end
31
+
32
+ def config_ru_path
33
+ @config_ru_path ||= './config.ru'
34
+ end
35
+
36
+ def config_ru_path= config_ru_path
37
+ @config_ru_path = config_ru_path
38
+ end
39
+
40
+ def color_enabled
41
+ # Can't use ||= when the variable might be false, it will execute the expression if it's false
42
+ defined?(@color_enabled) ? @color_enabled : true
43
+ end
44
+
45
+ def color_enabled= color_enabled
46
+ @color_enabled = color_enabled
47
+ end
48
+
49
+ def include mod
50
+ Pact::Provider::State::ProviderStateConfiguredModules.instance_eval do
51
+ include mod
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,13 @@
1
+ require 'pact/provider/configuration/service_provider_dsl'
2
+
3
+ module Pact
4
+
5
+ module Provider
6
+
7
+ module DSL
8
+ def service_provider name, &block
9
+ Configuration::ServiceProviderDSL.build(name, &block)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,46 @@
1
+ require 'pact/provider/pact_verification'
2
+ require 'pact/shared/dsl'
3
+
4
+ module Pact
5
+ module Provider
6
+
7
+ module Configuration
8
+
9
+ class PactVerification
10
+
11
+ extend Pact::DSL
12
+
13
+ attr_accessor :consumer_name, :pact_uri, :ref
14
+
15
+ def initialize consumer_name, options = {}
16
+ @consumer_name = consumer_name
17
+ @ref = options.fetch(:ref, :head)
18
+ @pact_uri = nil
19
+ end
20
+
21
+ dsl do
22
+ def pact_uri pact_uri
23
+ self.pact_uri = pact_uri
24
+ end
25
+ end
26
+
27
+ def finalize
28
+ validate
29
+ create_pact_verification
30
+ end
31
+
32
+ private
33
+
34
+ def create_pact_verification
35
+ verification = Pact::Provider::PactVerification.new(consumer_name, pact_uri, ref)
36
+ Pact.configuration.add_pact_verification verification
37
+ end
38
+
39
+ def validate
40
+ raise "Please provide a pact_uri for the verification" unless pact_uri
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,16 @@
1
+ module Pact
2
+ module Provider
3
+ module Configuration
4
+ class ServiceProviderConfig
5
+
6
+ def initialize &app_block
7
+ @app_block = app_block
8
+ end
9
+
10
+ def app
11
+ @app_block.call
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end