Skip to content

Commit

Permalink
refs supported in 'json_schema_for_method_response' and in swagger_ds…
Browse files Browse the repository at this point in the history
…l_spec

moved "match_field_structure" matcher into swagger_dsl_spec (the only spec using it)
all specs pass
  • Loading branch information
elasti-ron authored and abenari committed May 8, 2018
1 parent df64d4d commit 9254cfc
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 57 deletions.
6 changes: 6 additions & 0 deletions lib/apipie/swagger_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,12 @@ def swagger_param_type(param_desc)
#--------------------------------------------------------------------------

def response_schema(response)
@definitions = {}
if response.code.to_s == return_code.to_s
schema = response_schema(response, allow_nulls) if response.code.to_s == return_code.to_s
schema[:definitions] = @definitions if @definitions != {}
return schema
end
begin
# no need to warn about "missing default value for optional param" when processing response definitions
prev_value = @disable_default_value_warning
Expand Down
76 changes: 74 additions & 2 deletions spec/lib/swagger/swagger_dsl_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,22 @@

let(:controller_class ) { described_class }

def get_ref(ref)
name = ref.split('#/definitions/')[1].to_sym
swagger[:definitions][name]
end

def resolve_refs(schema)
if schema['$ref']
return get_ref(schema['$ref'])
end
schema
end

def swagger_response_for(path, code=200, method='get')
swagger[:paths][path][method][:responses][code]
response = swagger[:paths][path][method][:responses][code]
response[:schema] = resolve_refs(response[:schema])
response
end

def swagger_params_for(path, method='get')
Expand All @@ -32,6 +46,64 @@ def swagger_param_by_name(param_name, path, method='get')




#
# Matcher to validate the hierarchy of fields described in an internal 'returns' object (without checking their type)
#
# For example, code such as:
# returns_obj = Apipie.get_resource_description(...)._methods.returns.detect{|e| e.code=200})
# expect(returns_obj).to match_param_structure([:pet_name, :animal_type, :pet_measurements => [:weight, :height]])
#
# will verify that the payload structure described for the response of return code 200 is:
# {
# "pet_name": <any>,
# "animal_type": <any>,
# "pet_measurements": {
# "weight": <any>,
# "height": <any>
# }
# }
#
#
RSpec::Matchers.define :match_field_structure do |expected|
@last_message = nil

match do |actual|
deep_match?(actual, expected)
end

def deep_match?(actual, expected, breadcrumb=[])
num = 0
for pdesc in expected do
if pdesc.is_a? Symbol
return false unless fields_match?(actual.params_ordered[num], pdesc, breadcrumb)
elsif pdesc.is_a? Hash
return false unless fields_match?(actual.params_ordered[num], pdesc.keys[0], breadcrumb)
return false unless deep_match?(actual.params_ordered[num].validator, pdesc.values[0], breadcrumb + [pdesc.keys[0]])
end
num+=1
end
@fail_message = "expected property count#{breadcrumb == [] ? '' : ' of ' + (breadcrumb).join('.')} (#{actual.params_ordered.count}) to be #{num}"
actual.params_ordered.count == num
end

def fields_match?(param, expected_name, breadcrumb)
return false unless have_field?(param, expected_name, breadcrumb)
@fail_message = "expected #{(breadcrumb + [param.name]).join('.')} to eq #{(breadcrumb + [expected_name]).join('.')}"
param.name.to_s == expected_name.to_s
end

def have_field?(field, expected_name, breadcrumb)
@fail_message = "expected property #{(breadcrumb+[expected_name]).join('.')}"
!field.nil?
end

failure_message do |actual|
@fail_message
end
end


describe PetsController do


Expand All @@ -57,7 +129,7 @@ def swagger_param_by_name(param_name, path, method='get')
schema = response[:schema]
expect(schema[:type]).to eq("array")

a_schema = schema[:items]
a_schema = resolve_refs(schema[:items])
expect(a_schema).to have_field(:pet_name, 'string', {:description => 'Name of pet', :required => false})
expect(a_schema).to have_field(:animal_type, 'string', {:description => 'Type of pet', :enum => ['dog','cat','iguana','kangaroo']})
end
Expand Down
57 changes: 2 additions & 55 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,61 +34,7 @@ def compatible_request(method, action, hash = {})
end


#
# Matcher to validate the hierarchy of fields described in an internal 'returns' object (without checking their type)
#
# For example, code such as:
# returns_obj = Apipie.get_resource_description(...)._methods.returns.detect{|e| e.code=200})
# expect(returns_obj).to match_param_structure([:pet_name, :animal_type, :pet_measurements => [:weight, :height]])
#
# will verify that the payload structure described for the response of return code 200 is:
# {
# "pet_name": <any>,
# "animal_type": <any>,
# "pet_measurements": {
# "weight": <any>,
# "height": <any>
# }
# }
#
#
RSpec::Matchers.define :match_field_structure do |expected|
@last_message = nil

match do |actual|
deep_match?(actual, expected)
end

def deep_match?(actual, expected, breadcrumb=[])
num = 0
expected.each do |pdesc|
if pdesc.is_a? Symbol
return false unless matching_param(actual.params_ordered, pdesc, breadcrumb)
elsif pdesc.is_a? Hash
param = matching_param(actual.params_ordered, pdesc.keys[0], breadcrumb)
return false unless param
return false unless deep_match?(param.validator, pdesc.values[0], breadcrumb + [pdesc.keys[0]])
end
num+=1
end
@fail_message = "expected property count#{breadcrumb == [] ? '' : ' of ' + (breadcrumb).join('.')} (#{actual.params_ordered.count}) to be #{num}"
actual.params_ordered.count == num
end

def matching_param(params, expected_name, breadcrumb)
param = params.find { |p| p.name.to_s == expected_name.to_s }
unless param
@fail_message = "expected [#{ params.map(&:name).join(', ') }] to include #{(breadcrumb + [expected_name]).join('.')}"
end
param
end

failure_message do |actual|
@fail_message
end
end



#
# Matcher to validate the properties (name, type and options) of a single field in the
Expand All @@ -112,7 +58,8 @@ def fail(msg)
@fail_message
end

match do |actual|
match do |unresolved|
actual = resolve_refs(unresolved)
return fail("expected schema to have type 'object' (got '#{actual[:type]}')") if (actual[:type]) != 'object'
return fail("expected schema to include param named '#{name}' (got #{actual[:properties].keys})") if (prop = actual[:properties][name]).nil?
return fail("expected param '#{name}' to have type '#{type}' (got '#{prop[:type]}')") if prop[:type] != type
Expand Down

0 comments on commit 9254cfc

Please sign in to comment.