rswag/lib/swagger_rails/testing/test_case_builder.rb
2016-02-25 09:47:09 -08:00

116 lines
3.5 KiB
Ruby

module SwaggerRails
class TestCaseBuilder
def initialize(path_template, http_method, swagger)
@path_template = path_template
@http_method = http_method
@swagger = swagger
@param_values = {}
end
def set(param_values)
@param_values.merge!(param_values.stringify_keys)
end
def expect(status)
@expected_status = status.to_s
end
def test_data
operation = find_operation!
parameters = operation['parameters'] || []
responses = operation['responses']
{
path: build_path(parameters),
params: build_params(parameters),
headers: build_headers(parameters),
expected_response: build_expected_response(responses)
}
end
private
def find_operation!
keys = [ 'paths', @path_template, @http_method ]
operation = find_hash_item!(@swagger, keys)
operation || (raise MetadataError.new(keys))
end
def find_hash_item!(hash, keys)
item = hash[keys[0]] || (return nil)
keys.length == 1 ? item : find_hash_item!(item, keys.drop(1))
end
def build_path(parameters)
param_values = param_values_for(parameters, 'path')
@path_template.dup.tap do |template|
template.prepend(@swagger['basePath'].presence || '')
param_values.each { |name, value| template.sub!("\{#{name}\}", value.to_s) }
end
end
def build_params(parameters)
body_param_values = param_values_for(parameters, 'body')
return body_param_values.values.first.to_json if body_param_values.any?
param_values_for(parameters, 'query')
end
def build_headers(parameters)
param_values_for(parameters, 'header')
.merge({
'CONTENT_TYPE' => 'application/json',
'ACCEPT' => 'application/json'
})
end
def build_expected_response(responses)
status = @expected_status || responses.keys.find { |k| k.start_with?('2') }
response = responses[status] || (raise MetadataError.new('paths', @path_template, @http_method, 'responses', status))
{
status: status.to_i,
body: response_body_for(response)
}
end
def param_values_for(parameters, location)
applicable_parameters = parameters.select { |p| p['in'] == location }
Hash[applicable_parameters.map { |p| [ p['name'], param_value_for(p) ] }]
end
def param_value_for(parameter)
return @param_values[parameter['name']] if @param_values.has_key?(parameter['name'])
return parameter['default'] unless parameter['in'] == 'body'
schema = schema_for(parameter['schema'])
schema_example_for(schema)
end
def response_body_for(response)
return nil if response['schema'].nil?
schema = schema_for(response['schema'])
schema_example_for(schema)
end
def schema_for(schema_or_ref)
return schema_or_ref if schema_or_ref['$ref'].nil?
@swagger['definitions'][schema_or_ref['$ref'].sub('#/definitions/', '')]
end
def schema_example_for(schema)
return schema['example'] if schema['example'].present?
# If an array, try construct from the item example
if schema['type'] == 'array' && schema['item'].present?
item_schema = schema_for(schema['item'])
return [ schema_example_for(item_schema) ]
end
end
end
class MetadataError < StandardError
def initialize(*path_keys)
path = path_keys.map { |key| "['#{key}']" }.join('')
super("Swagger document is missing expected metadata at #{path}")
end
end
end