Skip to content

Commit f75edfe

Browse files
elasti-roniNecas
authored andcommitted
refs supported in 'json_schema_for_method_response' and in swagger_dsl_spec
moved "match_field_structure" matcher into swagger_dsl_spec (the only spec using it) all specs pass
1 parent 15584d7 commit f75edfe

File tree

3 files changed

+82
-60
lines changed

3 files changed

+82
-60
lines changed

lib/apipie/swagger_generator.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,13 @@ def swagger_param_type(param_desc)
343343
#--------------------------------------------------------------------------
344344

345345
def json_schema_for_method_response(method, return_code, allow_nulls)
346+
@definitions = {}
346347
for response in method.returns
347-
return response_schema(response, allow_nulls) if response.code.to_s == return_code.to_s
348+
if response.code.to_s == return_code.to_s
349+
schema = response_schema(response, allow_nulls) if response.code.to_s == return_code.to_s
350+
schema[:definitions] = @definitions if @definitions != {}
351+
return schema
352+
end
348353
end
349354
nil
350355
end

spec/lib/swagger/swagger_dsl_spec.rb

+74-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,22 @@
1212

1313
let(:controller_class ) { described_class }
1414

15+
def get_ref(ref)
16+
name = ref.split('#/definitions/')[1].to_sym
17+
swagger[:definitions][name]
18+
end
19+
20+
def resolve_refs(schema)
21+
if schema['$ref']
22+
return get_ref(schema['$ref'])
23+
end
24+
schema
25+
end
26+
1527
def swagger_response_for(path, code=200, method='get')
16-
swagger[:paths][path][method][:responses][code]
28+
response = swagger[:paths][path][method][:responses][code]
29+
response[:schema] = resolve_refs(response[:schema])
30+
response
1731
end
1832

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

3347

3448

49+
50+
#
51+
# Matcher to validate the hierarchy of fields described in an internal 'returns' object (without checking their type)
52+
#
53+
# For example, code such as:
54+
# returns_obj = Apipie.get_resource_description(...)._methods.returns.detect{|e| e.code=200})
55+
# expect(returns_obj).to match_param_structure([:pet_name, :animal_type, :pet_measurements => [:weight, :height]])
56+
#
57+
# will verify that the payload structure described for the response of return code 200 is:
58+
# {
59+
# "pet_name": <any>,
60+
# "animal_type": <any>,
61+
# "pet_measurements": {
62+
# "weight": <any>,
63+
# "height": <any>
64+
# }
65+
# }
66+
#
67+
#
68+
RSpec::Matchers.define :match_field_structure do |expected|
69+
@last_message = nil
70+
71+
match do |actual|
72+
deep_match?(actual, expected)
73+
end
74+
75+
def deep_match?(actual, expected, breadcrumb=[])
76+
num = 0
77+
for pdesc in expected do
78+
if pdesc.is_a? Symbol
79+
return false unless fields_match?(actual.params_ordered[num], pdesc, breadcrumb)
80+
elsif pdesc.is_a? Hash
81+
return false unless fields_match?(actual.params_ordered[num], pdesc.keys[0], breadcrumb)
82+
return false unless deep_match?(actual.params_ordered[num].validator, pdesc.values[0], breadcrumb + [pdesc.keys[0]])
83+
end
84+
num+=1
85+
end
86+
@fail_message = "expected property count#{breadcrumb == [] ? '' : ' of ' + (breadcrumb).join('.')} (#{actual.params_ordered.count}) to be #{num}"
87+
actual.params_ordered.count == num
88+
end
89+
90+
def fields_match?(param, expected_name, breadcrumb)
91+
return false unless have_field?(param, expected_name, breadcrumb)
92+
@fail_message = "expected #{(breadcrumb + [param.name]).join('.')} to eq #{(breadcrumb + [expected_name]).join('.')}"
93+
param.name.to_s == expected_name.to_s
94+
end
95+
96+
def have_field?(field, expected_name, breadcrumb)
97+
@fail_message = "expected property #{(breadcrumb+[expected_name]).join('.')}"
98+
!field.nil?
99+
end
100+
101+
failure_message do |actual|
102+
@fail_message
103+
end
104+
end
105+
106+
35107
describe PetsController do
36108

37109

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

60-
a_schema = schema[:items]
132+
a_schema = resolve_refs(schema[:items])
61133
expect(a_schema).to have_field(:pet_name, 'string', {:description => 'Name of pet', :required => false})
62134
expect(a_schema).to have_field(:animal_type, 'string', {:description => 'Type of pet', :enum => ['dog','cat','iguana','kangaroo']})
63135
end

spec/spec_helper.rb

+2-57
Original file line numberDiff line numberDiff line change
@@ -34,62 +34,6 @@ def compatible_request(method, action, hash = {})
3434
end
3535

3636

37-
#
38-
# Matcher to validate the hierarchy of fields described in an internal 'returns' object (without checking their type)
39-
#
40-
# For example, code such as:
41-
# returns_obj = Apipie.get_resource_description(...)._methods.returns.detect{|e| e.code=200})
42-
# expect(returns_obj).to match_param_structure([:pet_name, :animal_type, :pet_measurements => [:weight, :height]])
43-
#
44-
# will verify that the payload structure described for the response of return code 200 is:
45-
# {
46-
# "pet_name": <any>,
47-
# "animal_type": <any>,
48-
# "pet_measurements": {
49-
# "weight": <any>,
50-
# "height": <any>
51-
# }
52-
# }
53-
#
54-
#
55-
RSpec::Matchers.define :match_field_structure do |expected|
56-
@last_message = nil
57-
58-
match do |actual|
59-
deep_match?(actual, expected)
60-
end
61-
62-
def deep_match?(actual, expected, breadcrumb=[])
63-
num = 0
64-
expected.each do |pdesc|
65-
if pdesc.is_a? Symbol
66-
return false unless matching_param(actual.params_ordered, pdesc, breadcrumb)
67-
elsif pdesc.is_a? Hash
68-
param = matching_param(actual.params_ordered, pdesc.keys[0], breadcrumb)
69-
return false unless param
70-
return false unless deep_match?(param.validator, pdesc.values[0], breadcrumb + [pdesc.keys[0]])
71-
end
72-
num+=1
73-
end
74-
@fail_message = "expected property count#{breadcrumb == [] ? '' : ' of ' + (breadcrumb).join('.')} (#{actual.params_ordered.count}) to be #{num}"
75-
actual.params_ordered.count == num
76-
end
77-
78-
def matching_param(params, expected_name, breadcrumb)
79-
param = params.find { |p| p.name.to_s == expected_name.to_s }
80-
unless param
81-
@fail_message = "expected [#{ params.map(&:name).join(', ') }] to include #{(breadcrumb + [expected_name]).join('.')}"
82-
end
83-
param
84-
end
85-
86-
failure_message do |actual|
87-
@fail_message
88-
end
89-
end
90-
91-
92-
9337
#
9438
# Matcher to validate the properties (name, type and options) of a single field in the
9539
# internal representation of a swagger schema
@@ -112,7 +56,8 @@ def fail(msg)
11256
@fail_message
11357
end
11458

115-
match do |actual|
59+
match do |unresolved|
60+
actual = resolve_refs(unresolved)
11661
return fail("expected schema to have type 'object' (got '#{actual[:type]}')") if (actual[:type]) != 'object'
11762
return fail("expected schema to include param named '#{name}' (got #{actual[:properties].keys})") if (prop = actual[:properties][name]).nil?
11863
return fail("expected param '#{name}' to have type '#{type}' (got '#{prop[:type]}')") if prop[:type] != type

0 commit comments

Comments
 (0)