Commit 53254556 by andrew morton

Move towards supporting multiple documents

parent 7e77096a
require 'rspec/core'
require 'rspec/swagger/configuration'
require 'rspec/swagger/document'
require 'rspec/swagger/formatter'
require 'rspec/swagger/helpers'
require 'rspec/swagger/version'
......
module RSpec
module Swagger
class Document
attr_accessor :data
def initialize(data)
@data = data.deep_symbolize_keys
end
def resolve_ref(ref)
unless %r{#/(?<location>parameters|definitions)/(?<name>.+)} =~ ref
raise ArgumentError, "Invalid reference: #{ref}"
end
result = data.fetch(location.to_sym, {})[name.to_sym]
raise ArgumentError, "Reference value does not exist: #{ref}" unless result
if location == 'parameters'
result.merge(name: name)
end
result
end
end
end
end
......@@ -20,7 +20,7 @@ module RSpec
return unless notification.example.metadata[:swagger_object] == :response
data = notification.example.metadata[:swagger_data]
document = document_for(nil)
document = document_for(data[:document])
path_item = path_item_for(document, data[:path])
# TODO output path_item's parameters
operation = operation_for(path_item, data[:operation])
......@@ -42,7 +42,7 @@ module RSpec
puts JSON.pretty_generate(document)
end
def document_for doc_name = nil
def document_for(doc_name = nil)
if doc_name
documents.fetch(doc_name)
else
......@@ -50,21 +50,21 @@ module RSpec
end
end
def path_item_for document, path_name
def path_item_for(document, path_name)
document[:paths] ||= {}
document[:paths][path_name] ||= {}
end
def operation_for path, operation_name
def operation_for(path, operation_name)
path[operation_name] ||= {responses: {}}
end
def response_for operation, status_code
def response_for(operation, status_code)
operation[:responses][status_code] ||= {}
end
def prepare_example example
def prepare_example(example)
mime_type = example[:content_type]
body = example[:body]
if mime_type == 'application/json'
......
......@@ -42,15 +42,20 @@ paths: (Paths)
description: Invalid input
=end
module Paths
def path template, &block
def path template, attributes = {}, &block
attributes.symbolize_keys!
raise ArgumentError, "Path must start with a /" unless template.starts_with?('/')
#TODO template might be a $ref
meta = {
swagger_object: :path_item,
swagger_data: {path: template}
swagger_data: {
document: attributes[:swagger_document] || RSpec.configuration.swagger_docs.keys.first,
path: template
}
}
describe("path #{template}", meta, &block)
describe(template, meta, &block)
end
end
......
......@@ -12,6 +12,7 @@ Gem::Specification.new do |s|
s.files = [
'lib/rspec/swagger.rb',
'lib/rspec/swagger/configuration.rb',
'lib/rspec/swagger/document.rb',
'lib/rspec/swagger/formatter.rb',
'lib/rspec/swagger/helpers.rb',
'lib/rspec/swagger/version.rb',
......
---
swagger: '2.0'
info:
version: 0.0.0
title: Simple API
paths:
/:
get:
responses:
200:
description: OK
require 'swagger_helper'
RSpec.describe RSpec::Swagger::Document do
subject { described_class.new(data) }
let(:data) { minimial_example }
it "stores the data" do
expect(subject.data[:swagger]).to eq('2.0')
end
describe "#resolve_ref" do
context 'with nothing to reference' do
let(:data) { minimial_example }
it 'errors' do
expect{ subject.resolve_ref('#/parameters/user-id') }.to raise_exception(ArgumentError)
expect{ subject.resolve_ref('#/definitions/Tag') }.to raise_exception(ArgumentError)
end
end
context 'with data to reference' do
let(:data) { instagram_example }
it "errors on invalid references" do
expect{ subject.resolve_ref('parameters/user-id') }.to raise_exception(ArgumentError)
expect{ subject.resolve_ref('definitions/user-id') }.to raise_exception(ArgumentError)
end
it "finds parameter references" do
expect(subject.resolve_ref('#/parameters/user-id')).to eq({
name: 'user-id',
in: 'path',
description: 'The user identifier number',
type: 'number',
required: true,
})
end
it "finds valid schema references" do
expect(subject.resolve_ref('#/definitions/Tag')).to eq({
type: 'object',
properties: {
media_count: {
type: 'integer',
},
name: {
type: 'string',
},
}
})
end
end
end
def minimial_example
YAML.load_file(File.expand_path('../../../fixtures/files/minimal.yml', __FILE__))
end
def instagram_example
YAML.load_file(File.expand_path('../../../fixtures/files/instagram.yml', __FILE__))
end
end
......@@ -3,15 +3,14 @@ require "spec_helper"
RSpec.describe RSpec::Swagger::Formatter do
let(:output) { StringIO.new }
let(:formatter) { described_class.new(output) }
let(:documents) do
let(:documents) { {'minimal.json' => minimal} }
# Make this a method to bypass rspec's memoization.
def minimal
{
'minimal.json' => {
swagger: '2.0',
info: {
version: '0.0.0',
title: 'Simple API'
}
swagger: '2.0',
info: {
version: '0.0.0',
title: 'Simple API'
}
}
end
......@@ -24,11 +23,17 @@ RSpec.describe RSpec::Swagger::Formatter do
let(:example_notification) { double('Notification', example: double('Example', metadata: metadata)) }
let(:metadata) { {} }
context "minimal" do
context "with a single document" do
let(:metadata) do
{
swagger_object: :response,
swagger_data: {path: "/ping", operation: :put, status_code: 200, response_description: 'OK', example: nil}
swagger_data: {
path: "/ping",
operation: :put,
status_code: 200,
response_description: 'OK',
example: nil
}
}
end
......@@ -51,6 +56,28 @@ RSpec.describe RSpec::Swagger::Formatter do
})
end
end
context "with multiple documents" do
let(:documents) { {'doc1.json' => minimal, 'doc2.json' => minimal} }
let(:metadata) do
{
swagger_object: :response,
swagger_data: {
document: 'doc2.json',
path: "/ping",
operation: :put,
status_code: 200
}
}
end
it "puts the response on the right document" do
formatter.example_finished(example_notification)
expect(formatter.documents['doc1.json'][:paths]).to be_blank
expect(formatter.documents['doc2.json'][:paths].length).to eq(1)
end
end
end
describe "#close" do
......@@ -91,6 +118,5 @@ RSpec.describe RSpec::Swagger::Formatter do
formatter.close(blank_notification)
end
end
end
end
......@@ -14,6 +14,31 @@ RSpec.describe RSpec::Swagger::Helpers::Paths do
expect{ subject.path("foo") }.to raise_exception(ArgumentError)
expect{ subject.path("/foo") }.not_to raise_exception
end
it "defaults to the first swagger document if not specified" do
expect(subject).to receive(:describe).with("/ping", {
swagger_object: :path_item,
swagger_data: {
document: RSpec.configuration.swagger_docs.keys.first,
path: '/ping'
}
})
subject.path('/ping')
end
it "accepts specified swagger document name" do
expect(subject).to receive(:describe).with("/ping", {
swagger_object: :path_item,
swagger_data: {
document: 'hello_swagger.json',
path: '/ping'
}
})
subject.path('/ping', swagger_document: 'hello_swagger.json')
end
end
RSpec.describe RSpec::Swagger::Helpers::Parameters do
......@@ -109,7 +134,7 @@ RSpec.describe RSpec::Swagger::Helpers::Resolver do
end
end
describe("#resolve_params", swagger_object: :something) do
describe("#resolve_path", 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)
......
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