Commit db6e3635 by andrew morton

Start resolving parameters

parent f37dda8c
......@@ -11,6 +11,7 @@ module RSpec
config.extend Operation, swagger_object: :operation
config.extend Parameters, swagger_object: :operation
config.extend Response, swagger_object: :status_code
config.include Common, :swagger_object
end
......@@ -42,6 +43,8 @@ paths: (Paths)
=end
module Paths
def path template, &block
raise ArgumentError, "Path must start with a /" unless template.starts_with?('/')
#TODO template might be a $ref
meta = {
swagger_object: :path_item,
......@@ -53,6 +56,8 @@ paths: (Paths)
module PathItem
def operation verb, desc, &block
# TODO, check verbs against a whitelist
verb = verb.to_s.downcase
meta = {
swagger_object: :operation,
......@@ -72,12 +77,14 @@ paths: (Paths)
raise ArgumentError, "Invalid 'in' parameter, must be one of #{locations}"
end
# Path attributes are always required
attributes[:required] = true if attributes[:in] == :path
# if name.respond_to?(:has_key?)
# param = { '$ref' => name.delete(:ref) || name.delete('ref') }
# end
params_key = "#{metadata[:swagger_object]}_params".to_sym
params = metadata[:swagger_data][params_key] ||= {}
params = metadata[:swagger_data][:params] ||= {}
param = { name: name.to_s }.merge(attributes)
# Params should be unique based on the 'name' and 'in' values.
......@@ -89,9 +96,8 @@ paths: (Paths)
module Operation
def response status_code, desc, params = {}, headers = {}, &block
unless status_code == :default || (100..599).cover?(status_code)
raise ArgumentError, "status_code must be between 100 and 599 or :default"
raise ArgumentError, "status_code must be an integer 100 to 599, or :default"
end
meta = {
swagger_object: :status_code,
swagger_data: metadata[:swagger_data].merge(status_code: status_code, response_description: desc)
......@@ -99,30 +105,29 @@ paths: (Paths)
describe("#{status_code}", meta) do
self.module_exec(&block) if block_given?
method = metadata[:swagger_data][:operation]
path = metadata[:swagger_data][:path]
args = if ::Rails::VERSION::MAJOR >= 5
[path, {params: params, headers: headers}]
else
[path, params, headers]
end
# TODO: this needs a better mechanism
if metadata[:capture_example]
example = metadata[:swagger_data][:example] = {}
end
meta = {
swagger_object: :response
# response: metadata[:swagger_data][:response].merge()
}
it("matches", meta) do
before do |example|
method = example.metadata[:swagger_data][:operation]
path = resolve_path(example.metadata[:swagger_data][:path], self)
args = if ::Rails::VERSION::MAJOR >= 5
[path, {params: params, headers: headers}]
else
[path, params, headers]
end
self.send(method, *args)
if response && example
example.merge!( body: response.body, content_type: response.content_type.to_s)
end
# TODO fix the naming collision
# if example
# example.merge!(body: response.body, content_type: response.content_type.to_s)
# end
end
it("matches", { swagger_object: :response }) do
expect(response).to have_http_status(status_code)
end
end
......@@ -134,6 +139,21 @@ paths: (Paths)
metadata[:capture_example] = true
end
end
module Common
def resolve_params swagger_data, group_instance
# TODO resolve $refs
# TODO there should only be one body param
# TODO there should not be both body and formData params
swagger_data[:params].values.map do |p|
p.slice(:name, :in).merge(value: group_instance.send(p[:name]))
end
end
def resolve_path template, group_instance
template.gsub(/(\{.*?\})/){|match| group_instance.send(match[1...-1]) }
end
end
end
end
end
......@@ -15,8 +15,10 @@ RSpec.describe "Requestsing", type: :request do
end
end
path '/posts/1' do
parameter "path-param", {in: :path}
path '/posts/{post_id}' do
parameter "post_id", {in: :path}
let(:post_id) { 1 }
operation "GET", "fetch item" do
before { Post.new.save }
parameter "op-param", {in: :query}
......
require "spec_helper"
RSpec.describe RSpec::Swagger::Helpers::Paths do
let(:klass) do
Class.new do
include RSpec::Swagger::Helpers::Paths
attr_accessor :metadata
def describe *args ; end
end
end
subject { klass.new }
it "requires the path start with a /" do
expect{ subject.path("foo") }.to raise_exception(ArgumentError)
expect{ subject.path("/foo") }.not_to raise_exception
end
end
RSpec.describe RSpec::Swagger::Helpers::Parameters do
let(:klass) do
Class.new do
......@@ -13,39 +29,28 @@ RSpec.describe RSpec::Swagger::Helpers::Parameters do
before { subject.metadata = {swagger_object: :path_item, swagger_data: {}} }
it "requires 'in' parameter" do
expect{ subject.parameter "name", foo: :bar }.to raise_exception(ArgumentError)
expect{ subject.parameter("name", foo: :bar) }.to raise_exception(ArgumentError)
end
it "validates 'in' parameter" do
expect{ subject.parameter "name", in: :form_data }.to raise_exception(ArgumentError)
expect{ subject.parameter "name", in: "formData" }.to raise_exception(ArgumentError)
expect{ subject.parameter "name", in: :formData }.not_to raise_exception
expect{ subject.parameter("name", in: :form_data) }.to raise_exception(ArgumentError)
expect{ subject.parameter("name", in: "formData") }.to raise_exception(ArgumentError)
expect{ subject.parameter("name", in: :formData) }.not_to raise_exception
end
context "on a path_item" do
before { subject.metadata = {swagger_object: :path_item, swagger_data: {}} }
it "marks path parameters as required" do
subject.parameter("name", in: :path)
it "keeps parameters unique by name and in" do
subject.parameter('foo', in: :path)
subject.parameter('foo', in: :path)
subject.parameter('bar', in: :query)
subject.parameter('baz', in: :query)
expect(subject.metadata[:swagger_data][:path_item_params].length).to eq 3
end
expect(subject.metadata[:swagger_data][:params].values.first).to include(required: true)
end
context "on an operation" do
before { subject.metadata = {swagger_object: :operation, swagger_data: {}} }
it "keeps parameters unique by name and in" do
subject.parameter('foo', in: :path)
subject.parameter('foo', in: :path)
subject.parameter('bar', in: :query)
subject.parameter('baz', in: :query)
it "keeps parameters unique by name and location" do
subject.parameter('foo', in: :path)
subject.parameter('foo', in: :path)
subject.parameter('bar', in: :query)
subject.parameter('baz', in: :query)
expect(subject.metadata[:swagger_data][:operation_params].length).to eq 3
end
expect(subject.metadata[:swagger_data][:params].length).to eq 3
end
end
end
......@@ -76,3 +81,54 @@ RSpec.describe RSpec::Swagger::Helpers::Operation do
end
end
end
RSpec.describe RSpec::Swagger::Helpers::Common do
# Tthis helper is an include rather than an extend we can get it pulled into
# the test just by matching the filter metadata.
describe("#resolve_params", swagger_object: :something) do
let(:swagger_data) { { params: params } }
describe "with a missing value" do
let(:params) { {"path&post_id" => {name: "post_id", in: :path}} }
# TODO best thing would be to lazily evaulate the params so we'd only
# hit this if something was trying to use it.
it "raises an error" do
expect{resolve_params(swagger_data, self)}.to raise_exception(NoMethodError)
end
end
describe "with a valid value" do
let(:params) { {"path&post_id" => {name: "post_id", in: :path, description: "long"}} }
let(:post_id) { 123 }
it "returns it" do
expect(resolve_params(swagger_data, self)).to eq([{name: "post_id", in: :path, value: 123}])
end
end
end
describe("#resolve_params", swagger_object: :something) do
describe "with a missing value" do
it "raises an error" do
expect{ resolve_path('/sites/{site_id}', self) }.to raise_exception(NoMethodError)
end
end
describe "with values" do
let(:site_id) { 1001 }
let(:accountId) { "pickles" }
it "substitutes them into the path" do
expect(resolve_path('/sites/{site_id}/accounts/{accountId}', self)).to eq('/sites/1001/accounts/pickles')
end
end
describe "with a base path" do
xit "prefixes the path" do
end
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment