lib/soaspec/matchers.rb in soaspec-0.2.32 vs lib/soaspec/matchers.rb in soaspec-0.2.33

- old
+ new

@@ -1,118 +1,140 @@ -# frozen_string_literal: true - -require_relative 'core_ext/hash' -require_relative 'errors' - -# Whether response has any element with the provided value -RSpec::Matchers.define :contain_value do |expected| - match do |actual| - expect(actual.exchange_handler.include_value?(actual.response, expected)).to be true - end - - failure_message do |actual| - "expected that #{actual.exchange_handler.response_body(actual.response, format: :hash)} would contain value #{expected}" - end -end - -# Whether substring exists in body of response (more general than above) -RSpec::Matchers.define :include_in_body do |expected| - match do |actual| - expect(actual.exchange_handler.include_in_body?(actual.response, expected)).to be true - end - - failure_message do |actual| - "expected that #{actual.exchange_handler.response_body(actual.response, format: :raw)} would contain value #{expected}" - end -end - -# Whether an element exists at expected xpath -RSpec::Matchers.define :have_element_at_path do |xpath| - match do |object| - # Object like `response` returns the Exchange object from which a path can be obtained - exchange = object.respond_to?(:exchange) ? object.exchange : object - expect { exchange[xpath] }.to_not raise_error # Error will be raised if Path returns no value - end - - # TODO: Would be better to print failure message - failure_message do |object| - # Object like `response` returns the Exchange object from which a path can be obtained - exchange = object.respond_to?(:exchange) ? object.exchange : object - "expected that #{exchange.exchange_handler.response_body(exchange.response, format: :raw)} would have element at path '#{xpath}'" - end -end - -RSpec::Matchers.alias_matcher :have_element_at_xpath, :have_element_at_path -RSpec::Matchers.alias_matcher :contain_key, :have_element_at_path - -# Whether an element at xpath (defined by key) has value (defined by value). -# @param [Hash] expected_hash Xpath => Value pair (e.g. '//xmlns:GetWeatherResult' => 'Data Not Found') -RSpec::Matchers.define :have_xpath_value do |expected_hash| - match do |object| - # Object like `response` returns the Exchange object from which a path can be obtained - exchange = object.respond_to?(:exchange) ? object.exchange : object - expected_hash = Hash[*expected_hash.flatten] if expected_hash.is_a?(Array) # For some reason Array was occuring - expect(exchange[expected_hash.keys.first]).to eq expected_hash.values.first - end - - failure_message do |actual| - "expected that xpath '#{expected_hash.keys.first}' has value '#{expected_hash.values.first}' but was '#{actual[expected_hash.keys.first]}'" - end -end - -RSpec::Matchers.alias_matcher :have_jsonpath_value, :have_xpath_value - -RSpec::Matchers.define :be_found do - match do |exchange| - expect(exchange.exchange_handler.found?(exchange.response)).to be true - end - - failure_message do |exchange| - "expected result #{exchange.response} to be found. Status code is #{exchange.response.code}" - end -end - -# Whether response has successful status code and correct mandatory elements and values -RSpec::Matchers.define :be_successful do - # @param [Exchange, RestClient::Response] actual Object that returns Exchange or is Exchange - # @return [Exchange] Exchange to use - def exchange_from(actual) - actual.respond_to?(:exchange) ? actual.exchange : actual - end - - # @param [Exchange, RestClient::Response] exchange Object that returns Exchange or is Exchange - # @return [Array] List of errors when checking Exchange response is successful - def collect_errors(exchange) - failure_list = [] - failure_list << "#{exchange.status_code} not valid status code" unless exchange.successful_status_code? - exchange.exchange_handler.expected_mandatory_elements.each do |mandatory_element_path| - begin - exchange[mandatory_element_path] - rescue NoElementAtPath => e - failure_list << e.message - end - end - exchange.exchange_handler.expected_mandatory_xpath_values.each do |path, value| - failure_list << "Expected value at xpath '#{path}' to be '#{value}' but was '#{exchange[path]}'" unless exchange[path] == value - end - exchange.exchange_handler.expected_mandatory_json_values.each do |path, value| - failure_list << "Expected value at json '#{path}' to be '#{value}' but was '#{exchange[path]}'" unless exchange[path] == value - end - failure_list - end - - match do |actual| - exchange = exchange_from actual - failure_list = collect_errors exchange - raise failure_list.to_s unless failure_list.empty? - - true - end - - match_when_negated do |actual| - exchange = exchange_from actual - failure_list = collect_errors exchange - raise "Expected failure. Status code is #{exchange.status_code}" if failure_list.empty? - - true - end -end +# frozen_string_literal: true + +require_relative 'core_ext/hash' +require_relative 'errors' + +# Whether response has any element with the provided value +RSpec::Matchers.define :contain_value do |expected| + match do |actual| + expect(actual.exchange_handler.include_value?(actual.response, expected)).to be true + end + + failure_message do |actual| + "expected that #{actual.exchange_handler.response_body(actual.response, format: :hash)} would contain value #{expected}" + end +end + +# Whether substring exists in body of response (more general than above) +RSpec::Matchers.define :include_in_body do |expected| + match do |actual| + expect(actual.exchange_handler.include_in_body?(actual.response, expected)).to be true + end + + failure_message do |actual| + "expected that #{actual.exchange_handler.response_body(actual.response, format: :raw)} would contain value #{expected}" + end +end + +# Whether an element exists at expected xpath +RSpec::Matchers.define :have_element_at_path do |xpath| + match do |object| + # Object like `response` returns the Exchange object from which a path can be obtained + exchange = object.respond_to?(:exchange) ? object.exchange : object + expect { exchange[xpath] }.to_not raise_error # Error will be raised if Path returns no value + end + + # TODO: Would be better to print failure message + failure_message do |object| + # Object like `response` returns the Exchange object from which a path can be obtained + exchange = object.respond_to?(:exchange) ? object.exchange : object + "expected that #{exchange.exchange_handler.response_body(exchange.response, format: :raw)} would have element at path '#{xpath}'" + end +end + +RSpec::Matchers.alias_matcher :have_element_at_xpath, :have_element_at_path +RSpec::Matchers.alias_matcher :contain_key, :have_element_at_path + +# Whether an element at xpath (defined by key) has value (defined by value). +# @param [Hash] expected_hash Xpath => Value pair (e.g. '//xmlns:GetWeatherResult' => 'Data Not Found') +RSpec::Matchers.define :have_xpath_value do |expected_hash| + match do |object| + # Object like `response` returns the Exchange object from which a path can be obtained + exchange = object.respond_to?(:exchange) ? object.exchange : object + expected_hash = Hash[*expected_hash.flatten] if expected_hash.is_a?(Array) # For some reason Array was occuring + expect(exchange[expected_hash.keys.first]).to eq expected_hash.values.first + end + + failure_message do |actual| + "expected that xpath '#{expected_hash.keys.first}' has value '#{expected_hash.values.first}' but was '#{actual[expected_hash.keys.first]}'" + end +end + +RSpec::Matchers.alias_matcher :have_jsonpath_value, :have_xpath_value + +RSpec::Matchers.define :be_found do + match do |exchange| + expect(exchange.exchange_handler.found?(exchange.response)).to be true + end + + failure_message do |exchange| + "expected result #{exchange.response} to be found. Status code is #{exchange.response.code}" + end +end + +RSpec::Matchers.define :match_baseline do + + match do |exchange| + file = Soaspec::Baseline.file(exchange) + if File.exist?(file) + exchange.to_hash == YAML.load_file(file) + else + Soaspec::Baseline.create_file filename: file, + content: Psych.dump(exchange.to_hash) + raise Soaspec::BaselineError, + "Created baseline at #{file}. Inspect file to ensure it is + correct and rerun to ensure baseline is stable" + end + end + + failure_message do |exchange| + "#{exchange} did not match baseline. \n" \ + "Expected: #{YAML.load_file(Soaspec::Baseline.file(exchange))} \n" \ + " Actual: #{exchange.to_hash}" + end +end + +# Whether response has successful status code and correct mandatory elements and values +RSpec::Matchers.define :be_successful do + # @param [Exchange, RestClient::Response] actual Object that returns Exchange or is Exchange + # @return [Exchange] Exchange to use + def exchange_from(actual) + actual.respond_to?(:exchange) ? actual.exchange : actual + end + + # @param [Exchange, RestClient::Response] exchange Object that returns Exchange or is Exchange + # @return [Array] List of errors when checking Exchange response is successful + def collect_errors(exchange) + failure_list = [] + failure_list << "#{exchange.status_code} not valid status code" unless exchange.successful_status_code? + exchange.exchange_handler.expected_mandatory_elements.each do |mandatory_element_path| + begin + exchange[mandatory_element_path] + rescue NoElementAtPath => e + failure_list << e.message + end + end + exchange.exchange_handler.expected_mandatory_xpath_values.each do |path, value| + failure_list << "Expected value at xpath '#{path}' to be '#{value}' but was '#{exchange[path]}'" unless exchange[path] == value + end + exchange.exchange_handler.expected_mandatory_json_values.each do |path, value| + failure_list << "Expected value at json '#{path}' to be '#{value}' but was '#{exchange[path]}'" unless exchange[path] == value + end + failure_list + end + + match do |actual| + exchange = exchange_from actual + failure_list = collect_errors exchange + raise failure_list.to_s unless failure_list.empty? + + true + end + + match_when_negated do |actual| + exchange = exchange_from actual + failure_list = collect_errors exchange + raise "Expected failure. Status code is #{exchange.status_code}" if failure_list.empty? + + true + end +end