From aa1707d6e2bb1039af3cbb6dede4359a72390d0a Mon Sep 17 00:00:00 2001 From: andrew morton Date: Wed, 5 Oct 2016 00:00:09 -0600 Subject: [PATCH 1/2] Don't require optional parameters to have value Fixes #20 Also starts adding some rdocs. --- lib/rspec/rails/swagger/document.rb | 2 + lib/rspec/rails/swagger/request_builder.rb | 20 +++-- .../rails/swagger/request_builder_spec.rb | 76 ++++++++++++++++--- 3 files changed, 81 insertions(+), 17 deletions(-) diff --git a/lib/rspec/rails/swagger/document.rb b/lib/rspec/rails/swagger/document.rb index bd3bf0b..573cbcf 100644 --- a/lib/rspec/rails/swagger/document.rb +++ b/lib/rspec/rails/swagger/document.rb @@ -12,6 +12,8 @@ def [](value) data[value] end + ## + # Look up parameter or definition references. def resolve_ref(ref) unless %r{#/(?parameters|definitions)/(?.+)} =~ ref raise ArgumentError, "Invalid reference: #{ref}" diff --git a/lib/rspec/rails/swagger/request_builder.rb b/lib/rspec/rails/swagger/request_builder.rb index 65992c0..a2d27a2 100644 --- a/lib/rspec/rails/swagger/request_builder.rb +++ b/lib/rspec/rails/swagger/request_builder.rb @@ -4,10 +4,17 @@ module Swagger class RequestBuilder attr_reader :metadata, :instance + ## + # Creates a new RequestBuilder from the Example class's +metadata+ hash + # and a test +instance+ that we can use to populate the parameter + # values. def initialize(metadata, instance) @metadata, @instance = metadata, instance end + ## + # Finds the Document associated with this request so things like schema + # and parameter references can be resolved. def document @document ||= begin name = metadata[:swagger_document] @@ -27,6 +34,9 @@ def consumes Array(metadata[:swagger_operation][:consumes]).presence || Array(document[:consumes]) end + ## + # Returns parameters defined in the operation and path item. Providing + # a +location+ will limit the parameters by their `in` value. def parameters location = nil path_item = metadata[:swagger_path_item] || {} operation = metadata[:swagger_operation] || {} @@ -39,12 +49,10 @@ def parameters location = nil end def parameter_values location - # Don't bother looking at the full parameter bodies since all we need - # are location and name which are in the key. - values = parameters(location) - .keys - .map{ |k| k.split('&').last } - .map{ |name| [name, instance.send(name)] } + values = parameters(location). + map{ |_, p| p['$ref'] ? document.resolve_ref(p['$ref']) : p }. + select{ |p| p[:required] || instance.respond_to?(p[:name]) }. + map{ |p| [p[:name], instance.send(p[:name])] } Hash[values] end diff --git a/spec/rspec/rails/swagger/request_builder_spec.rb b/spec/rspec/rails/swagger/request_builder_spec.rb index 0ebcc89..4393a36 100644 --- a/spec/rspec/rails/swagger/request_builder_spec.rb +++ b/spec/rspec/rails/swagger/request_builder_spec.rb @@ -98,15 +98,19 @@ describe '#parameters' do subject { described_class.new(metadata, double('instance')) } - let(:metadata) { { - swagger_path_item: { parameters: { - 'path&petId' => { name: 'petId', in: :path, description: 'path' }, - 'query&site' => { name: 'site', in: :query } - } }, - swagger_operation: { parameters: { - 'path&petId' => { name: 'petId', in: :path, description: 'op' } - } }, - } } + let(:metadata) do + { + swagger_path_item: { + parameters: { + 'path&petId' => { name: 'petId', in: :path, description: 'path' }, + 'query&site' => { name: 'site', in: :query } + } + }, + swagger_operation: { + parameters: { 'path&petId' => { name: 'petId', in: :path, description: 'op' } } + } + } + end it 'merges values from the path and operation' do expect(subject.parameters).to eq({ @@ -116,6 +120,56 @@ end end + describe '#parameter_values' do + subject { described_class.new(metadata, instance) } + let(:metadata) do + { + swagger_operation: { + parameters: { + "query&date" => { "$ref" => "#/parameters/filter_date" }, + "query&subscriber" => { name: "subscriber", type: :string, in: :query, required: required } + } + } + } + end + let(:instance) { double('instance') } + before do + expect(subject).to receive_message_chain(:document, :resolve_ref) do + { name: "date", type: :integer, in: :query, required: required } + end + end + + context 'required parameters' do + let(:required) { true } + + it 'includes defined values' do + allow(instance).to receive(:date) { 10 } + allow(instance).to receive(:subscriber) { false } + + expect(subject.parameter_values(:query)).to eq({ 'date' => 10, 'subscriber' => false }) + end + + it 'undefined cause errors' do + expect{ subject.parameter_values(:query) }.to raise_exception(RSpec::Mocks::MockExpectationError) + end + end + + context 'optional parameters' do + let(:required) { false } + + it 'includes defined values' do + allow(instance).to receive(:date) { 27 } + allow(instance).to receive(:subscriber) { true } + + expect(subject.parameter_values(:query)).to eq({ 'date' => 27, 'subscriber' => true }) + end + + it 'ommits undefined values' do + expect(subject.parameter_values(:query)).to eq({}) + end + end + end + describe '#headers' do subject { described_class.new(double('metadata'), instance) } let(:instance) { double('instance') } @@ -170,7 +224,7 @@ context 'with header params' do it 'returns them in a string' do expect(subject).to receive(:parameters).with(:header) { { - 'header&X-Magic' => { same: :here } + 'header&X-Magic' => { name: 'X-Magic', in: :header } } } expect(instance).to receive('X-Magic'.to_sym) { :pickles } @@ -221,7 +275,7 @@ context 'with query params' do it 'returns them in a string' do expect(subject).to receive(:parameters).with(:query) { { - 'query&site' => { same: :here } + 'query&site' => { name: 'site', in: :query } } } expect(instance).to receive(:site) { :pickles } From 160af2e8d57a055a63343944f8e86fdbed2e947e Mon Sep 17 00:00:00 2001 From: andrew morton Date: Wed, 5 Oct 2016 00:03:18 -0600 Subject: [PATCH 2/2] Bump version to 0.1.3 --- lib/rspec/rails/swagger/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rspec/rails/swagger/version.rb b/lib/rspec/rails/swagger/version.rb index 5d9ac22..1920525 100644 --- a/lib/rspec/rails/swagger/version.rb +++ b/lib/rspec/rails/swagger/version.rb @@ -3,7 +3,7 @@ module Rails # Version information for RSpec Swagger. module Swagger module Version - STRING = '0.1.2' + STRING = '0.1.3' end end end