soaspec 0.2.33 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -15
  3. data/.gitlab-ci.yml +62 -62
  4. data/.rspec +3 -3
  5. data/.rubocop.yml +2 -2
  6. data/CODE_OF_CONDUCT.md +74 -74
  7. data/ChangeLog +643 -632
  8. data/Dockerfile +7 -7
  9. data/Gemfile +8 -8
  10. data/LICENSE.txt +21 -21
  11. data/README.md +253 -231
  12. data/Rakefile +52 -52
  13. data/Todo.md +16 -16
  14. data/exe/soaspec +140 -138
  15. data/exe/xml_to_yaml_file +43 -43
  16. data/lib/soaspec.rb +118 -106
  17. data/lib/soaspec/baseline.rb +82 -22
  18. data/lib/soaspec/core_ext/hash.rb +44 -44
  19. data/lib/soaspec/cucumber/generic_steps.rb +94 -94
  20. data/lib/soaspec/demo.rb +6 -6
  21. data/lib/soaspec/errors.rb +24 -24
  22. data/lib/soaspec/exchange/exchange.rb +131 -129
  23. data/lib/soaspec/exchange/exchange_extractor.rb +105 -90
  24. data/lib/soaspec/exchange/exchange_properties.rb +28 -28
  25. data/lib/soaspec/exchange/exchange_repeater.rb +21 -21
  26. data/lib/soaspec/exchange/request_builder.rb +108 -70
  27. data/lib/soaspec/exchange/variable_storer.rb +24 -24
  28. data/lib/soaspec/exchange_handlers/exchange_handler.rb +98 -98
  29. data/lib/soaspec/exchange_handlers/exchange_handler_defaults.rb +61 -61
  30. data/lib/soaspec/exchange_handlers/handler_accessors.rb +132 -132
  31. data/lib/soaspec/exchange_handlers/request/rest_request.rb +77 -59
  32. data/lib/soaspec/exchange_handlers/request/soap_request.rb +41 -41
  33. data/lib/soaspec/exchange_handlers/response_extractor.rb +84 -84
  34. data/lib/soaspec/exchange_handlers/rest_exchanger_factory.rb +111 -111
  35. data/lib/soaspec/exchange_handlers/rest_handler.rb +307 -307
  36. data/lib/soaspec/exchange_handlers/rest_methods.rb +65 -65
  37. data/lib/soaspec/exchange_handlers/rest_parameters.rb +112 -112
  38. data/lib/soaspec/exchange_handlers/rest_parameters_defaults.rb +42 -42
  39. data/lib/soaspec/exchange_handlers/soap_handler.rb +241 -241
  40. data/lib/soaspec/exe_helpers.rb +94 -94
  41. data/lib/soaspec/generate_server.rb +48 -48
  42. data/lib/soaspec/generator/.rspec.erb +5 -5
  43. data/lib/soaspec/generator/.travis.yml.erb +5 -5
  44. data/lib/soaspec/generator/Gemfile.erb +8 -8
  45. data/lib/soaspec/generator/README.md.erb +29 -29
  46. data/lib/soaspec/generator/Rakefile.erb +20 -19
  47. data/lib/soaspec/generator/config/data/default.yml.erb +2 -2
  48. data/lib/soaspec/generator/css/bootstrap.css +6833 -6833
  49. data/lib/soaspec/generator/features/support/env.rb.erb +3 -3
  50. data/lib/soaspec/generator/generate_exchange.html.erb +47 -47
  51. data/lib/soaspec/generator/lib/blz_service.rb.erb +26 -26
  52. data/lib/soaspec/generator/lib/dynamic_class_content.rb.erb +12 -12
  53. data/lib/soaspec/generator/lib/new_rest_service.rb.erb +56 -56
  54. data/lib/soaspec/generator/lib/new_soap_service.rb.erb +29 -29
  55. data/lib/soaspec/generator/lib/package_service.rb.erb +2 -2
  56. data/lib/soaspec/generator/lib/shared_example.rb.erb +8 -8
  57. data/lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb +12 -12
  58. data/lib/soaspec/generator/spec/rest_spec.rb.erb +9 -9
  59. data/lib/soaspec/generator/spec/soap_spec.rb.erb +51 -51
  60. data/lib/soaspec/generator/spec/spec_helper.rb.erb +23 -23
  61. data/lib/soaspec/generator/template/soap_template.xml +6 -6
  62. data/lib/soaspec/indifferent_hash.rb +9 -9
  63. data/lib/soaspec/interpreter.rb +70 -70
  64. data/lib/soaspec/matchers.rb +136 -140
  65. data/lib/soaspec/o_auth2.rb +142 -142
  66. data/lib/soaspec/soaspec_shared_examples.rb +26 -26
  67. data/lib/soaspec/spec_logger.rb +143 -143
  68. data/lib/soaspec/template_reader.rb +30 -30
  69. data/lib/soaspec/test_server/bank.wsdl +90 -90
  70. data/lib/soaspec/test_server/get_bank.rb +166 -166
  71. data/lib/soaspec/test_server/id_manager.rb +41 -41
  72. data/lib/soaspec/test_server/invoices.rb +29 -29
  73. data/lib/soaspec/test_server/namespace.xml +14 -14
  74. data/lib/soaspec/test_server/note.xml +5 -5
  75. data/lib/soaspec/test_server/puppy_service.rb +21 -21
  76. data/lib/soaspec/test_server/test_attribute.rb +14 -14
  77. data/lib/soaspec/test_server/test_namespace.rb +14 -14
  78. data/lib/soaspec/version.rb +6 -6
  79. data/lib/soaspec/virtual_server.rb +193 -190
  80. data/lib/soaspec/wait.rb +43 -43
  81. data/lib/soaspec/wsdl_generator.rb +215 -215
  82. data/soaspec.gemspec +58 -58
  83. data/test.wsdl +116 -116
  84. data/test.xml +10 -10
  85. data/test_wsdl.rb +43 -43
  86. metadata +3 -3
@@ -1,23 +1,23 @@
1
-
2
- require 'soaspec'
3
- require 'require_all'
4
- require_all 'lib'
5
- require 'data_magic'
6
-
7
- include DataMagic # Used as example of loading data smartly. Use 'data_for' method to load yml data
8
- <% if @type == 'rest' %>
9
- include Soaspec::RestMethods
10
- <% end %>
11
-
12
- RSpec.configure do |config|
13
- # This will make backtrace much shorter by removing many lines from rspec failure message
14
- config.backtrace_exclusion_patterns = [
15
- /rspec/
16
- ]
17
- <% if @virtual %>
18
- # Close test server after all RSpec tests have run
19
- config.after(:suite) do
20
- Process.kill(:QUIT, ENV['test_server_pid'].to_i) if ENV['test_server_pid'] && !ENV['leave_server_running']
21
- end
22
- <% end %>
23
- end
1
+
2
+ require 'soaspec'
3
+ require 'require_all'
4
+ require_all 'lib'
5
+ require 'data_magic'
6
+
7
+ include DataMagic # Used as example of loading data smartly. Use 'data_for' method to load yml data
8
+ <% if @type == 'rest' %>
9
+ include Soaspec::RestMethods
10
+ <% end %>
11
+
12
+ RSpec.configure do |config|
13
+ # This will make backtrace much shorter by removing many lines from rspec failure message
14
+ config.backtrace_exclusion_patterns = [
15
+ /rspec/
16
+ ]
17
+ <% if @virtual %>
18
+ # Close test server after all RSpec tests have run
19
+ config.after(:suite) do
20
+ Process.kill(:QUIT, ENV['test_server_pid'].to_i) if ENV['test_server_pid'] && !ENV['leave_server_running']
21
+ end
22
+ <% end %>
23
+ end
@@ -1,7 +1,7 @@
1
- <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://thomas-bayer.com/blz/" xmlns:env="http://www.w3.org/2003/05/soap-envelope">
2
- <env:Body>
3
- <tns:getBank>
4
- <tns:blz><%= test_values[:blz] || '70070010' %></tns:blz>
5
- </tns:getBank>
6
- </env:Body>
1
+ <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://thomas-bayer.com/blz/" xmlns:env="http://www.w3.org/2003/05/soap-envelope">
2
+ <env:Body>
3
+ <tns:getBank>
4
+ <tns:blz><%= test_values[:blz] || '70070010' %></tns:blz>
5
+ </tns:getBank>
6
+ </env:Body>
7
7
  </env:Envelope>
@@ -1,9 +1,9 @@
1
- # frozen_string_literal: true
2
-
3
- require 'hashie'
4
-
5
- # Hash that allows accessing hash with either string or Hash
6
- class IndifferentHash < Hash
7
- include Hashie::Extensions::MergeInitializer
8
- include Hashie::Extensions::IndifferentAccess
9
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'hashie'
4
+
5
+ # Hash that allows accessing hash with either string or Hash
6
+ class IndifferentHash < Hash
7
+ include Hashie::Extensions::MergeInitializer
8
+ include Hashie::Extensions::IndifferentAccess
9
+ end
@@ -1,70 +1,70 @@
1
- # frozen_string_literal: true
2
-
3
- # Help interpret the general type of a particular object
4
- class Interpreter
5
- class << self
6
- # @return [Error] XML Errors found in interpreting response
7
- attr_accessor :xml_errors
8
-
9
- # @return [Error] JSON Errors found in interpreting response
10
- attr_accessor :json_errors
11
-
12
- # @param [Object] response API response
13
- # @return [Symbol] Type of provided response
14
- def response_type_for(response)
15
- @xml_errors = nil
16
- @json_errors = nil
17
- @response = response
18
- if @response.is_a? String
19
- if xml?
20
- :xml
21
- elsif json?
22
- :json
23
- else
24
- :string
25
- end
26
- elsif response.is_a? Hash
27
- :hash
28
- elsif response.is_a?(Nokogiri::XML::NodeSet) || response.is_a?(Nokogiri::XML::Document)
29
- :xml
30
- else
31
- :unknown
32
- end
33
- end
34
-
35
- # @return [Boolean] Whether response has tag like syntax similar to XML. Could be a syntax error occurred
36
- def looks_like_xml?
37
- @response[0] == '<' && @response[-1] == '>'
38
- end
39
-
40
- # @return [Boolean] Whether response has bracket like syntax similar to JSON. Could be a syntax error occurred
41
- def looks_like_json?
42
- @response[0] == '{' && @response[-1] == '}'
43
- end
44
-
45
- # @return [String] Description of error
46
- def diagnose_error
47
- return xml_errors if looks_like_xml?
48
-
49
- return json_errors if looks_like_json?
50
-
51
- ''
52
- end
53
-
54
- # @return [Boolean] Whether valid XML
55
- def xml?
56
- Nokogiri::XML(@response) { |config| config.options = Nokogiri::XML::ParseOptions::STRICT }
57
- rescue Nokogiri::XML::SyntaxError => e
58
- self.xml_errors = e
59
- false
60
- end
61
-
62
- # @return [Boolean] Whether valid JSON
63
- def json?
64
- JSON.parse(@response)
65
- rescue JSON::ParserError => e
66
- self.json_errors = e
67
- false
68
- end
69
- end
70
- end
1
+ # frozen_string_literal: true
2
+
3
+ # Help interpret the general type of a particular object
4
+ class Interpreter
5
+ class << self
6
+ # @return [Error] XML Errors found in interpreting response
7
+ attr_accessor :xml_errors
8
+
9
+ # @return [Error] JSON Errors found in interpreting response
10
+ attr_accessor :json_errors
11
+
12
+ # @param [Object] response API response
13
+ # @return [Symbol] Type of provided response
14
+ def response_type_for(response)
15
+ @xml_errors = nil
16
+ @json_errors = nil
17
+ @response = response
18
+ if @response.is_a? String
19
+ if xml?
20
+ :xml
21
+ elsif json?
22
+ :json
23
+ else
24
+ :string
25
+ end
26
+ elsif response.is_a? Hash
27
+ :hash
28
+ elsif response.is_a?(Nokogiri::XML::NodeSet) || response.is_a?(Nokogiri::XML::Document)
29
+ :xml
30
+ else
31
+ :unknown
32
+ end
33
+ end
34
+
35
+ # @return [Boolean] Whether response has tag like syntax similar to XML. Could be a syntax error occurred
36
+ def looks_like_xml?
37
+ @response[0] == '<' && @response[-1] == '>'
38
+ end
39
+
40
+ # @return [Boolean] Whether response has bracket like syntax similar to JSON. Could be a syntax error occurred
41
+ def looks_like_json?
42
+ @response[0] == '{' && @response[-1] == '}'
43
+ end
44
+
45
+ # @return [String] Description of error
46
+ def diagnose_error
47
+ return xml_errors if looks_like_xml?
48
+
49
+ return json_errors if looks_like_json?
50
+
51
+ ''
52
+ end
53
+
54
+ # @return [Boolean] Whether valid XML
55
+ def xml?
56
+ Nokogiri::XML(@response) { |config| config.options = Nokogiri::XML::ParseOptions::STRICT }
57
+ rescue Nokogiri::XML::SyntaxError => e
58
+ self.xml_errors = e
59
+ false
60
+ end
61
+
62
+ # @return [Boolean] Whether valid JSON
63
+ def json?
64
+ JSON.parse(@response)
65
+ rescue JSON::ParserError => e
66
+ self.json_errors = e
67
+ false
68
+ end
69
+ end
70
+ end
@@ -1,140 +1,136 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'core_ext/hash'
4
- require_relative 'errors'
5
-
6
- # Whether response has any element with the provided value
7
- RSpec::Matchers.define :contain_value do |expected|
8
- match do |actual|
9
- expect(actual.exchange_handler.include_value?(actual.response, expected)).to be true
10
- end
11
-
12
- failure_message do |actual|
13
- "expected that #{actual.exchange_handler.response_body(actual.response, format: :hash)} would contain value #{expected}"
14
- end
15
- end
16
-
17
- # Whether substring exists in body of response (more general than above)
18
- RSpec::Matchers.define :include_in_body do |expected|
19
- match do |actual|
20
- expect(actual.exchange_handler.include_in_body?(actual.response, expected)).to be true
21
- end
22
-
23
- failure_message do |actual|
24
- "expected that #{actual.exchange_handler.response_body(actual.response, format: :raw)} would contain value #{expected}"
25
- end
26
- end
27
-
28
- # Whether an element exists at expected xpath
29
- RSpec::Matchers.define :have_element_at_path do |xpath|
30
- match do |object|
31
- # Object like `response` returns the Exchange object from which a path can be obtained
32
- exchange = object.respond_to?(:exchange) ? object.exchange : object
33
- expect { exchange[xpath] }.to_not raise_error # Error will be raised if Path returns no value
34
- end
35
-
36
- # TODO: Would be better to print failure message
37
- failure_message do |object|
38
- # Object like `response` returns the Exchange object from which a path can be obtained
39
- exchange = object.respond_to?(:exchange) ? object.exchange : object
40
- "expected that #{exchange.exchange_handler.response_body(exchange.response, format: :raw)} would have element at path '#{xpath}'"
41
- end
42
- end
43
-
44
- RSpec::Matchers.alias_matcher :have_element_at_xpath, :have_element_at_path
45
- RSpec::Matchers.alias_matcher :contain_key, :have_element_at_path
46
-
47
- # Whether an element at xpath (defined by key) has value (defined by value).
48
- # @param [Hash] expected_hash Xpath => Value pair (e.g. '//xmlns:GetWeatherResult' => 'Data Not Found')
49
- RSpec::Matchers.define :have_xpath_value do |expected_hash|
50
- match do |object|
51
- # Object like `response` returns the Exchange object from which a path can be obtained
52
- exchange = object.respond_to?(:exchange) ? object.exchange : object
53
- expected_hash = Hash[*expected_hash.flatten] if expected_hash.is_a?(Array) # For some reason Array was occuring
54
- expect(exchange[expected_hash.keys.first]).to eq expected_hash.values.first
55
- end
56
-
57
- failure_message do |actual|
58
- "expected that xpath '#{expected_hash.keys.first}' has value '#{expected_hash.values.first}' but was '#{actual[expected_hash.keys.first]}'"
59
- end
60
- end
61
-
62
- RSpec::Matchers.alias_matcher :have_jsonpath_value, :have_xpath_value
63
-
64
- RSpec::Matchers.define :be_found do
65
- match do |exchange|
66
- expect(exchange.exchange_handler.found?(exchange.response)).to be true
67
- end
68
-
69
- failure_message do |exchange|
70
- "expected result #{exchange.response} to be found. Status code is #{exchange.response.code}"
71
- end
72
- end
73
-
74
- RSpec::Matchers.define :match_baseline do
75
-
76
- match do |exchange|
77
- file = Soaspec::Baseline.file(exchange)
78
- if File.exist?(file)
79
- exchange.to_hash == YAML.load_file(file)
80
- else
81
- Soaspec::Baseline.create_file filename: file,
82
- content: Psych.dump(exchange.to_hash)
83
- raise Soaspec::BaselineError,
84
- "Created baseline at #{file}. Inspect file to ensure it is
85
- correct and rerun to ensure baseline is stable"
86
- end
87
- end
88
-
89
- failure_message do |exchange|
90
- "#{exchange} did not match baseline. \n" \
91
- "Expected: #{YAML.load_file(Soaspec::Baseline.file(exchange))} \n" \
92
- " Actual: #{exchange.to_hash}"
93
- end
94
- end
95
-
96
- # Whether response has successful status code and correct mandatory elements and values
97
- RSpec::Matchers.define :be_successful do
98
- # @param [Exchange, RestClient::Response] actual Object that returns Exchange or is Exchange
99
- # @return [Exchange] Exchange to use
100
- def exchange_from(actual)
101
- actual.respond_to?(:exchange) ? actual.exchange : actual
102
- end
103
-
104
- # @param [Exchange, RestClient::Response] exchange Object that returns Exchange or is Exchange
105
- # @return [Array] List of errors when checking Exchange response is successful
106
- def collect_errors(exchange)
107
- failure_list = []
108
- failure_list << "#{exchange.status_code} not valid status code" unless exchange.successful_status_code?
109
- exchange.exchange_handler.expected_mandatory_elements.each do |mandatory_element_path|
110
- begin
111
- exchange[mandatory_element_path]
112
- rescue NoElementAtPath => e
113
- failure_list << e.message
114
- end
115
- end
116
- exchange.exchange_handler.expected_mandatory_xpath_values.each do |path, value|
117
- failure_list << "Expected value at xpath '#{path}' to be '#{value}' but was '#{exchange[path]}'" unless exchange[path] == value
118
- end
119
- exchange.exchange_handler.expected_mandatory_json_values.each do |path, value|
120
- failure_list << "Expected value at json '#{path}' to be '#{value}' but was '#{exchange[path]}'" unless exchange[path] == value
121
- end
122
- failure_list
123
- end
124
-
125
- match do |actual|
126
- exchange = exchange_from actual
127
- failure_list = collect_errors exchange
128
- raise failure_list.to_s unless failure_list.empty?
129
-
130
- true
131
- end
132
-
133
- match_when_negated do |actual|
134
- exchange = exchange_from actual
135
- failure_list = collect_errors exchange
136
- raise "Expected failure. Status code is #{exchange.status_code}" if failure_list.empty?
137
-
138
- true
139
- end
140
- end
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'core_ext/hash'
4
+ require_relative 'errors'
5
+
6
+ # Whether response has any element with the provided value
7
+ RSpec::Matchers.define :contain_value do |expected|
8
+ match do |actual|
9
+ expect(actual.exchange_handler.include_value?(actual.response, expected)).to be true
10
+ end
11
+
12
+ failure_message do |actual|
13
+ "expected that #{actual.exchange_handler.response_body(actual.response, format: :hash)} would contain value #{expected}"
14
+ end
15
+ end
16
+
17
+ # Whether substring exists in body of response (more general than above)
18
+ RSpec::Matchers.define :include_in_body do |expected|
19
+ match do |actual|
20
+ expect(actual.exchange_handler.include_in_body?(actual.response, expected)).to be true
21
+ end
22
+
23
+ failure_message do |actual|
24
+ "expected that #{actual.exchange_handler.response_body(actual.response, format: :raw)} would contain value #{expected}"
25
+ end
26
+ end
27
+
28
+ # Whether an element exists at expected xpath
29
+ RSpec::Matchers.define :have_element_at_path do |xpath|
30
+ match do |object|
31
+ # Object like `response` returns the Exchange object from which a path can be obtained
32
+ exchange = object.respond_to?(:exchange) ? object.exchange : object
33
+ expect { exchange[xpath] }.to_not raise_error # Error will be raised if Path returns no value
34
+ end
35
+
36
+ # TODO: Would be better to print failure message
37
+ failure_message do |object|
38
+ # Object like `response` returns the Exchange object from which a path can be obtained
39
+ exchange = object.respond_to?(:exchange) ? object.exchange : object
40
+ "expected that #{exchange.exchange_handler.response_body(exchange.response, format: :raw)} would have element at path '#{xpath}'"
41
+ end
42
+ end
43
+
44
+ RSpec::Matchers.alias_matcher :have_element_at_xpath, :have_element_at_path
45
+ RSpec::Matchers.alias_matcher :contain_key, :have_element_at_path
46
+
47
+ # Whether an element at xpath (defined by key) has value (defined by value).
48
+ # @param [Hash] expected_hash Xpath => Value pair (e.g. '//xmlns:GetWeatherResult' => 'Data Not Found')
49
+ RSpec::Matchers.define :have_xpath_value do |expected_hash|
50
+ match do |object|
51
+ # Object like `response` returns the Exchange object from which a path can be obtained
52
+ exchange = object.respond_to?(:exchange) ? object.exchange : object
53
+ expected_hash = Hash[*expected_hash.flatten] if expected_hash.is_a?(Array) # For some reason Array was occuring
54
+ expect(exchange[expected_hash.keys.first]).to eq expected_hash.values.first
55
+ end
56
+
57
+ failure_message do |actual|
58
+ "expected that xpath '#{expected_hash.keys.first}' has value '#{expected_hash.values.first}' but was '#{actual[expected_hash.keys.first]}'"
59
+ end
60
+ end
61
+
62
+ RSpec::Matchers.alias_matcher :have_jsonpath_value, :have_xpath_value
63
+
64
+ RSpec::Matchers.define :be_found do
65
+ match do |exchange|
66
+ expect(exchange.exchange_handler.found?(exchange.response)).to be true
67
+ end
68
+
69
+ failure_message do |exchange|
70
+ "expected result #{exchange.response} to be found. Status code is #{exchange.response.code}"
71
+ end
72
+ end
73
+
74
+ # Record response first time this is run. It will fail. Next time, compare it
75
+ # is the same
76
+ # @param [Symbol] format Format to save the baseline as. Default is :raw. Use :hash
77
+ # to store as hash which will ignore order in comparison
78
+ RSpec::Matchers.define :match_baseline do |format = :raw|
79
+
80
+ match do |exchange|
81
+ Soaspec::Baseline.new(exchange, format).matches?
82
+ end
83
+
84
+ failure_message do |exchange|
85
+ baseline = Soaspec::Baseline.new(exchange, format)
86
+ "#{exchange} did not match baseline. \n" \
87
+ "Expected: #{baseline.read_baseline} \n" \
88
+ "Actual: #{baseline.actual_content}"
89
+ end
90
+ end
91
+
92
+ # Whether response has successful status code and correct mandatory elements and values
93
+ RSpec::Matchers.define :be_successful do
94
+ # @param [Exchange, RestClient::Response] actual Object that returns Exchange or is Exchange
95
+ # @return [Exchange] Exchange to use
96
+ def exchange_from(actual)
97
+ actual.respond_to?(:exchange) ? actual.exchange : actual
98
+ end
99
+
100
+ # @param [Exchange, RestClient::Response] exchange Object that returns Exchange or is Exchange
101
+ # @return [Array] List of errors when checking Exchange response is successful
102
+ def collect_errors(exchange)
103
+ failure_list = []
104
+ failure_list << "#{exchange.status_code} not valid status code" unless exchange.successful_status_code?
105
+ exchange.exchange_handler.expected_mandatory_elements.each do |mandatory_element_path|
106
+ begin
107
+ exchange[mandatory_element_path]
108
+ rescue NoElementAtPath => e
109
+ failure_list << e.message
110
+ end
111
+ end
112
+ exchange.exchange_handler.expected_mandatory_xpath_values.each do |path, value|
113
+ failure_list << "Expected value at xpath '#{path}' to be '#{value}' but was '#{exchange[path]}'" unless exchange[path] == value
114
+ end
115
+ exchange.exchange_handler.expected_mandatory_json_values.each do |path, value|
116
+ failure_list << "Expected value at json '#{path}' to be '#{value}' but was '#{exchange[path]}'" unless exchange[path] == value
117
+ end
118
+ failure_list
119
+ end
120
+
121
+ match do |actual|
122
+ exchange = exchange_from actual
123
+ failure_list = collect_errors exchange
124
+ raise failure_list.to_s unless failure_list.empty?
125
+
126
+ true
127
+ end
128
+
129
+ match_when_negated do |actual|
130
+ exchange = exchange_from actual
131
+ failure_list = collect_errors exchange
132
+ raise "Expected failure. Status code is #{exchange.status_code}" if failure_list.empty?
133
+
134
+ true
135
+ end
136
+ end