apipie-rails 1.1.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +12 -48
  3. data/.github/workflows/rubocop-challenger.yml +2 -2
  4. data/.github/workflows/rubocop.yml +2 -4
  5. data/.rubocop.yml +39 -38
  6. data/.rubocop_todo.yml +55 -65
  7. data/.vscode/settings.json +3 -0
  8. data/CHANGELOG.md +19 -2
  9. data/Gemfile +20 -0
  10. data/README.rst +12 -9
  11. data/app/controllers/apipie/apipies_controller.rb +3 -17
  12. data/gemfiles/Gemfile.tools +9 -0
  13. data/lib/apipie/application.rb +18 -7
  14. data/lib/apipie/dsl_definition.rb +6 -5
  15. data/lib/apipie/errors.rb +14 -0
  16. data/lib/apipie/extractor/collector.rb +1 -1
  17. data/lib/apipie/extractor/recorder.rb +1 -1
  18. data/lib/apipie/extractor.rb +6 -3
  19. data/lib/apipie/generator/swagger/config.rb +3 -1
  20. data/lib/apipie/generator/swagger/method_description/api_schema_service.rb +6 -3
  21. data/lib/apipie/generator/swagger/warning.rb +1 -1
  22. data/lib/apipie/resource_description.rb +28 -3
  23. data/lib/apipie/validator.rb +20 -6
  24. data/lib/apipie/version.rb +1 -1
  25. data/spec/controllers/api/v2/architectures_controller_spec.rb +10 -3
  26. data/spec/controllers/api/v2/empty_middle_controller_spec.rb +23 -0
  27. data/spec/controllers/api/v2/nested/resources_controller_spec.rb +16 -0
  28. data/spec/controllers/api/v2/sub/footguns_controller_spec.rb +19 -0
  29. data/spec/controllers/users_controller_spec.rb +10 -0
  30. data/spec/dummy/app/controllers/api/v2/base_controller.rb +6 -0
  31. data/spec/dummy/app/controllers/api/v2/empty_middle_controller.rb +14 -0
  32. data/spec/dummy/app/controllers/api/v2/nested/resources_controller.rb +2 -2
  33. data/spec/dummy/app/controllers/api/v2/sub/footguns_controller.rb +30 -0
  34. data/spec/dummy/app/controllers/users_controller.rb +6 -0
  35. data/spec/dummy/config/routes.rb +1 -0
  36. data/spec/lib/apipie/apipies_controller_spec.rb +63 -19
  37. data/spec/lib/apipie/extractor/collector_spec.rb +57 -0
  38. data/spec/lib/apipie/generator/swagger/method_description/api_schema_service_spec.rb +13 -0
  39. data/spec/test_engine/memes_controller_spec.rb +1 -1
  40. metadata +11 -9
  41. data/gemfiles/Gemfile.rails50 +0 -10
  42. data/gemfiles/Gemfile.rails51 +0 -10
  43. data/gemfiles/Gemfile.rails52 +0 -10
  44. data/gemfiles/Gemfile.rails60 +0 -17
  45. data/gemfiles/Gemfile.rails61 +0 -17
  46. data/gemfiles/Gemfile.rails70 +0 -17
@@ -241,9 +241,11 @@ module Apipie
241
241
  method_params = self.class._apipie_get_method_params(action_name)
242
242
 
243
243
  if Apipie.configuration.validate_presence?
244
- method_params.each do |_, param|
245
- # check if required parameters are present
246
- raise ParamMissing.new(param) if param.required && !params.key?(param.name)
244
+ Validator::BaseValidator.raise_if_missing_params do |missing|
245
+ method_params.each do |_, param|
246
+ # check if required parameters are present
247
+ missing << param if param.required && !params.key?(param.name)
248
+ end
247
249
  end
248
250
  end
249
251
 
@@ -259,7 +261,7 @@ module Apipie
259
261
  if Apipie.configuration.validate_key?
260
262
  params.reject{|k,_| %w[format controller action].include?(k.to_s) }.each_pair do |param, _|
261
263
  # params allowed
262
- if method_params.select {|_,p| p.name.to_s == param.to_s}.empty?
264
+ if method_params.none? {|_,p| p.name.to_s == param.to_s}
263
265
  self.class._apipie_handle_validate_key_error params, param
264
266
  end
265
267
  end
@@ -285,7 +287,6 @@ module Apipie
285
287
  old_method.bind(self).call(*args)
286
288
  end
287
289
  end
288
-
289
290
  end
290
291
  end
291
292
 
data/lib/apipie/errors.rb CHANGED
@@ -24,6 +24,20 @@ module Apipie
24
24
  end
25
25
  end
26
26
 
27
+ class ParamMultipleMissing < ParamError
28
+ attr_accessor :params
29
+
30
+ def initialize(params)
31
+ @params = params
32
+ end
33
+
34
+ def to_s
35
+ params.map do |param|
36
+ ParamMissing.new(param).to_s
37
+ end.join("\n")
38
+ end
39
+ end
40
+
27
41
  class ParamMissing < DefinedParamError
28
42
  def to_s
29
43
  unless @param.options[:missing_message].nil?
@@ -19,7 +19,7 @@ module Apipie
19
19
  def ignore_call?(record)
20
20
  return true unless record[:controller]
21
21
  return true if @ignored.include?(record[:controller].name)
22
- return true if @ignored.include?("#{Apipie.resource_id(record[:controller].name)}##{record[:action]}")
22
+ return true if @ignored.include?("#{Apipie.get_resource_id(record[:controller].name)}##{record[:action]}")
23
23
  return true unless @api_controllers_paths.include?(controller_full_path(record[:controller]))
24
24
  end
25
25
 
@@ -48,7 +48,7 @@ module Apipie
48
48
  else
49
49
  @query = request.query_string
50
50
  end
51
- if response.content_type != 'application/pdf'
51
+ if response.media_type != 'application/pdf'
52
52
  @response_data = parse_data(response.body)
53
53
  end
54
54
  @code = response.code
@@ -15,10 +15,13 @@ class Apipie::Railtie
15
15
  end
16
16
  end
17
17
  end
18
- app.middleware.use ::Apipie::Extractor::Recorder::Middleware
19
18
 
20
- ActionController::TestCase.send(:prepend, Apipie::Extractor::Recorder::FunctionalTestRecording)
21
- ActionController::TestCase::Behavior.send(:prepend, Apipie::Extractor::Recorder::FunctionalTestRecording)
19
+ if Apipie.configuration.record
20
+ app.middleware.use ::Apipie::Extractor::Recorder::Middleware
21
+
22
+ ActionController::TestCase.send(:prepend, Apipie::Extractor::Recorder::FunctionalTestRecording)
23
+ ActionController::TestCase::Behavior.send(:prepend, Apipie::Extractor::Recorder::FunctionalTestRecording)
24
+ end
22
25
  end
23
26
  end
24
27
 
@@ -10,7 +10,7 @@ module Apipie
10
10
  :json_input_uses_refs, :suppress_warnings, :api_host,
11
11
  :generate_x_computed_id_field, :allow_additional_properties_in_response,
12
12
  :responses_use_refs, :schemes, :security_definitions,
13
- :global_security].freeze
13
+ :global_security, :skip_default_tags].freeze
14
14
 
15
15
  attr_accessor(*CONFIG_ATTRIBUTES)
16
16
 
@@ -43,6 +43,7 @@ module Apipie
43
43
  alias include_warning_tags? include_warning_tags
44
44
  alias json_input_uses_refs? json_input_uses_refs
45
45
  alias responses_use_refs? responses_use_refs
46
+ alias skip_default_tags? skip_default_tags
46
47
  alias generate_x_computed_id_field? generate_x_computed_id_field
47
48
  alias swagger_include_warning_tags? swagger_include_warning_tags
48
49
  alias swagger_json_input_uses_refs? swagger_json_input_uses_refs
@@ -61,6 +62,7 @@ module Apipie
61
62
  @schemes = [:https]
62
63
  @security_definitions = {}
63
64
  @global_security = []
65
+ @skip_default_tags = false
64
66
  end
65
67
 
66
68
  def self.deprecated_methods
@@ -47,9 +47,12 @@ class Apipie::Generator::Swagger::MethodDescription::ApiSchemaService
47
47
  end
48
48
 
49
49
  def tags
50
- [@method_description.resource._id] +
51
- warning_tags +
52
- @method_description.tag_list.tags
50
+ tags = if Apipie.configuration.generator.swagger.skip_default_tags?
51
+ []
52
+ else
53
+ [@method_description.resource._id]
54
+ end
55
+ tags + warning_tags + @method_description.tag_list.tags
53
56
  end
54
57
 
55
58
  def warning_tags
@@ -59,7 +59,7 @@ class Apipie::Generator::Swagger::Warning
59
59
  #
60
60
  # @return [Apipie::Generator::Swagger::Warning]
61
61
  def self.for_code(code, method_id, message_attributes = {})
62
- if !CODES.values.include?(code)
62
+ if !CODES.value?(code)
63
63
  raise ArgumentError, 'Unknown warning code'
64
64
  end
65
65
 
@@ -26,7 +26,9 @@ module Apipie
26
26
  @controller = controller
27
27
  @_id = id
28
28
  @_version = version || Apipie.configuration.default_version
29
- @_parent = Apipie.get_resource_description(controller.superclass, version)
29
+ @_parent = Apipie.value_from_parents(controller.superclass, version) do |parent, ver|
30
+ Apipie.get_resource_description(parent, ver)
31
+ end
30
32
 
31
33
  update_from_dsl_data(dsl_data) if dsl_data
32
34
  end
@@ -60,7 +62,16 @@ module Apipie
60
62
  end
61
63
 
62
64
  def name
63
- @name ||= @_resource_name.presence || @_id.split('-').map(&:capitalize).join('::')
65
+ @name ||= case resource_name
66
+ when Proc
67
+ resource_name.call(controller)
68
+ when Symbol
69
+ controller.public_send(resource_name)
70
+ when String
71
+ resource_name
72
+ else
73
+ default_name
74
+ end
64
75
  end
65
76
  alias _name name
66
77
 
@@ -90,7 +101,9 @@ module Apipie
90
101
  Apipie.full_url crumbs.join('/')
91
102
  end
92
103
 
93
- def api_url; "#{Apipie.api_base_url(_version)}#{@_path}"; end
104
+ def api_url
105
+ "#{Apipie.api_base_url(_version)}#{@_path}"
106
+ end
94
107
 
95
108
  def valid_method_name?(method_name)
96
109
  @_methods.keys.map(&:to_s).include?(method_name.to_s)
@@ -123,5 +136,17 @@ module Apipie
123
136
  }
124
137
  end
125
138
 
139
+ protected
140
+
141
+ def resource_name
142
+ @_resource_name.presence || @_parent&.resource_name
143
+ end
144
+
145
+ private
146
+
147
+ def default_name
148
+ @_id.split('-').map(&:capitalize).join('::')
149
+ end
150
+
126
151
  end
127
152
  end
@@ -38,6 +38,16 @@ module Apipie
38
38
  return nil
39
39
  end
40
40
 
41
+ def self.raise_if_missing_params
42
+ missing_params = []
43
+ yield missing_params
44
+ if missing_params.size > 1
45
+ raise ParamMultipleMissing.new(missing_params)
46
+ elsif missing_params.size == 1
47
+ raise ParamMissing.new(missing_params.first)
48
+ end
49
+ end
50
+
41
51
  # check if value is valid
42
52
  def valid?(value)
43
53
  if self.validate(value)
@@ -345,14 +355,18 @@ module Apipie
345
355
 
346
356
  def validate(value)
347
357
  return false if !value.is_a? Hash
348
- @hash_params&.each do |k, p|
349
- if Apipie.configuration.validate_presence?
350
- raise ParamMissing.new(p) if p.required && !value.key?(k)
351
- end
352
- if Apipie.configuration.validate_value?
353
- p.validate(value[k]) if value.key?(k)
358
+
359
+ BaseValidator.raise_if_missing_params do |missing|
360
+ @hash_params&.each do |k, p|
361
+ if Apipie.configuration.validate_presence?
362
+ missing << p if p.required && !value.key?(k)
363
+ end
364
+ if Apipie.configuration.validate_value?
365
+ p.validate(value[k]) if value.key?(k)
366
+ end
354
367
  end
355
368
  end
369
+
356
370
  return true
357
371
  end
358
372
 
@@ -1,3 +1,3 @@
1
1
  module Apipie
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.1"
3
3
  end
@@ -1,12 +1,19 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Api::V2::ArchitecturesController do
4
+ let(:resource_description) { Apipie.get_resource_description(described_class, "2.0") }
5
+
4
6
  describe "resource description" do
5
- subject { Apipie.get_resource_description(Api::V2::ArchitecturesController, "2.0") }
7
+ describe 'version' do
8
+ subject { resource_description._version }
6
9
 
7
- it "should be version 2.0" do
8
- expect(subject._version).to eq('2.0')
10
+ it { is_expected.to eq('2.0') }
9
11
  end
10
12
 
13
+ describe 'name' do
14
+ subject { resource_description.name }
15
+
16
+ it { is_expected.to eq('Architectures') }
17
+ end
11
18
  end
12
19
  end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Api::V2::EmptyMiddleController do
4
+ let(:resource_description) { Apipie.get_resource_description(described_class, '2.0') }
5
+
6
+ describe 'resource description' do
7
+ subject { resource_description }
8
+
9
+ context 'when namespaced resources are enabled' do
10
+ before { Apipie.configuration.namespaced_resources = true }
11
+ after { Apipie.configuration.namespaced_resources = false }
12
+
13
+ # we don't actually expect the resource description to be nil, but resource IDs
14
+ # are computed at file load time, and altering the value of namespaced_resources
15
+ # after the fact doesn't change the resource ID, so it can't be found
16
+ it { is_expected.to be_nil }
17
+ end
18
+
19
+ context 'when namespaced resources are disabled' do
20
+ it { is_expected.to be_nil }
21
+ end
22
+ end
23
+ end
@@ -1,6 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Api::V2::Nested::ResourcesController do
4
+ let(:resource_description) { Apipie.get_resource_description(described_class, "2.0") }
5
+
6
+ describe "resource description" do
7
+ describe 'version' do
8
+ subject { resource_description._version }
9
+
10
+ it { is_expected.to eq('2.0') }
11
+ end
12
+
13
+ describe 'name' do
14
+ subject { resource_description.name }
15
+
16
+ it { is_expected.to eq('Rsrcs') }
17
+ end
18
+ end
19
+
4
20
  describe '.get_resource_id' do
5
21
  subject { Apipie.get_resource_id(Api::V2::Nested::ResourcesController) }
6
22
 
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Api::V2::Sub::FootgunsController do
4
+ let(:resource_description) { Apipie.get_resource_description(described_class, '2.0') }
5
+
6
+ describe 'resource description' do
7
+ describe 'version' do
8
+ subject { resource_description._version }
9
+
10
+ it { is_expected.to eq('2.0') }
11
+ end
12
+
13
+ describe 'name' do
14
+ subject { resource_description.name }
15
+
16
+ it { is_expected.to eq('snugtooF') }
17
+ end
18
+ end
19
+ end
@@ -37,6 +37,7 @@ describe UsersController do
37
37
  expect(methods.keys).to include(:update)
38
38
  expect(methods.keys).to include(:two_urls)
39
39
  expect(methods.keys).to include(:action_with_headers)
40
+ expect(methods.keys).to include(:multiple_required_params)
40
41
  end
41
42
 
42
43
  it "should contain info about resource" do
@@ -101,6 +102,10 @@ describe UsersController do
101
102
  expect { get :show, :params => { :id => 5 }}.to raise_error(Apipie::ParamMissing, /session_parameter_is_required/)
102
103
  end
103
104
 
105
+ it "should fail if multiple required parameters are missing" do
106
+ expect { get :multiple_required_params }.to raise_error(Apipie::ParamMultipleMissing, /required_param1.*\n.*required_param2|required_param2.*\n.*required_parameter1/)
107
+ end
108
+
104
109
  it "should pass if required parameter has wrong type" do
105
110
  expect { get :show, :params => { :id => 5 , :session => "secret_hash" }}.not_to raise_error
106
111
  expect { get :show, :params => { :id => "ten" , :session => "secret_hash" }}.not_to raise_error
@@ -246,6 +251,11 @@ describe UsersController do
246
251
  post :create, :params => { :user => { :name => "root", :pass => "12345", :membership => "____" } }
247
252
  }.to raise_error(Apipie::ParamInvalid, /membership/)
248
253
 
254
+ # Should include both pass and name
255
+ expect {
256
+ post :create, :params => { :user => { :membership => "standard" } }
257
+ }.to raise_error(Apipie::ParamMultipleMissing, /pass.*\n.*name|name.*\n.*pass/)
258
+
249
259
  expect {
250
260
  post :create, :params => { :user => { :name => "root" } }
251
261
  }.to raise_error(Apipie::ParamMissing, /pass/)
@@ -5,6 +5,12 @@ module Api
5
5
  api_version '2.0'
6
6
  app_info 'Version 2.0 description'
7
7
  api_base_url '/api/v2'
8
+
9
+ name :reversed_name
10
+ end
11
+
12
+ def self.reversed_name
13
+ controller_name.capitalize.reverse
8
14
  end
9
15
  end
10
16
  end
@@ -0,0 +1,14 @@
1
+ module Api
2
+ module V2
3
+ class EmptyMiddleController < V2::BaseController
4
+ # This is an empty controller, used to test cases where controllers
5
+ # may inherit from a middle controler that does not define a resource_description,
6
+ # but the middle controller's parent does.
7
+
8
+ def inconsequential_method
9
+ # This method is here to ensure that the controller is not empty.
10
+ # It triggers method_added, which is used to add the resource description.
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,8 +1,8 @@
1
1
  module Api
2
2
  module V2
3
3
  class Nested::ResourcesController < V2::BaseController
4
- resource_description do
5
- name 'Resources'
4
+ resource_description do
5
+ name ->(controller) { controller.controller_name.delete('aeiou').capitalize }
6
6
  resource_id "resource"
7
7
  end
8
8
  api :GET, "/nested/resources/", "List all nested resources."
@@ -0,0 +1,30 @@
1
+ module Api
2
+ module V2
3
+ module Sub
4
+ class FootgunsController < V2::EmptyMiddleController
5
+ resource_description do
6
+ short 'Footguns are bad'
7
+ end
8
+
9
+ api :GET, '/footguns/', 'List all footguns.'
10
+ def index; end
11
+
12
+ api :GET, '/footguns/:id/', 'Show a footgun.'
13
+ def show; end
14
+
15
+ api :POST, '/footguns/', 'Create a footgun.'
16
+ def create; end
17
+
18
+ api :PUT, '/footguns/:id/', 'Update a footgun.'
19
+ param :footgun, Hash, :required => true do
20
+ param :name, String
21
+ end
22
+ def update; end
23
+
24
+ api! 'Delete a footgun.'
25
+ api_version '2.0' # forces removal of the method description
26
+ def destroy; end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -301,4 +301,10 @@ class UsersController < ApplicationController
301
301
  header :HeaderNameWithDefaultValue, 'Header with default value', required: true, default: 'default value'
302
302
  def action_with_headers
303
303
  end
304
+
305
+ api :GET, '/users/multiple_required_params'
306
+ param :required_param1, String, required: true
307
+ param :required_param2, String, required: true
308
+ def multiple_required_params
309
+ end
304
310
  end
@@ -8,6 +8,7 @@ Dummy::Application.routes.draw do
8
8
  resources :users do
9
9
  collection do
10
10
  post :create_route
11
+ get :multiple_required_params
11
12
  end
12
13
  end
13
14
  resources :concerns, :only => [:index, :show]
@@ -258,12 +258,12 @@ describe Apipie::ApipiesController, type: :controller do
258
258
 
259
259
  before do
260
260
  FileUtils.rm_r(cache_dir) if File.exist?(cache_dir)
261
- FileUtils.mkdir_p(File.join(cache_dir, "apidoc", "v1", "resource"))
261
+ FileUtils.mkdir_p(File.join(cache_dir, "apidoc", "v1", "resource-with-namespace"))
262
262
  File.open(File.join(cache_dir, "apidoc", "v1.html"), "w") { |f| f << "apidoc.html cache v1" }
263
263
  File.open(File.join(cache_dir, "apidoc", "v2.html"), "w") { |f| f << "apidoc.html cache v2" }
264
264
  File.open(File.join(cache_dir, "apidoc", "v1.json"), "w") { |f| f << "apidoc.json cache" }
265
- File.open(File.join(cache_dir, "apidoc", "v1", "resource.html"), "w") { |f| f << "resource.html cache" }
266
- File.open(File.join(cache_dir, "apidoc", "v1", "resource", "method.html"), "w") { |f| f << "method.html cache" }
265
+ File.open(File.join(cache_dir, "apidoc", "v1", "resource-with-namespace.html"), "w") { |f| f << "resource-with-namespace.html cache" }
266
+ File.open(File.join(cache_dir, "apidoc", "v1", "resource-with-namespace", "method.html"), "w") { |f| f << "method.html cache" }
267
267
 
268
268
  Apipie.configuration.use_cache = true
269
269
  @orig_cache_dir = Apipie.configuration.cache_dir
@@ -279,24 +279,68 @@ describe Apipie::ApipiesController, type: :controller do
279
279
  # FileUtils.rm_r(cache_dir) if File.exist?(cache_dir)
280
280
  end
281
281
 
282
- it "uses the file in cache dir instead of generating the content on runtime" do
283
- get :index
284
- expect(response.body).to eq("apidoc.html cache v1")
285
- get :index, :params => { :version => 'v1' }
286
- expect(response.body).to eq("apidoc.html cache v1")
287
- get :index, :params => { :version => 'v2' }
288
- expect(response.body).to eq("apidoc.html cache v2")
289
- get :index, :params => { :version => 'v1', :format => "html" }
290
- expect(response.body).to eq("apidoc.html cache v1")
291
- get :index, :params => { :version => 'v1', :format => "json" }
292
- expect(response.body).to eq("apidoc.json cache")
293
- get :index, :params => { :version => 'v1', :format => "html", :resource => "resource" }
294
- expect(response.body).to eq("resource.html cache")
295
- get :index, :params => { :version => 'v1', :format => "html", :resource => "resource", :method => "method" }
296
- expect(response.body).to eq("method.html cache")
282
+ context 'when the file exists' do
283
+ it "uses the file in cache dir instead of generating the content on runtime" do
284
+ get :index
285
+ expect(response.body).to eq("apidoc.html cache v1")
286
+
287
+ get :index, :params => { :version => 'v1' }
288
+ expect(response.body).to eq("apidoc.html cache v1")
289
+
290
+ get :index, :params => { :version => 'v2' }
291
+ expect(response.body).to eq("apidoc.html cache v2")
292
+
293
+ get :index, :params => { :version => 'v1', :format => "html" }
294
+ expect(response.body).to eq("apidoc.html cache v1")
295
+
296
+ get :index, :params => { :version => 'v1', :format => "json" }
297
+ expect(response.body).to eq("apidoc.json cache")
298
+
299
+ get :index, :params => { :version => 'v1', :format => "html", :resource => "resource-with-namespace" }
300
+ expect(response.body).to eq("resource-with-namespace.html cache")
301
+
302
+ get :index, :params => { :version => 'v1', :format => "html", :resource => "resource-with-namespace", :method => "method" }
303
+ expect(response.body).to eq("method.html cache")
304
+ end
297
305
  end
298
306
 
299
- end
307
+ context 'when the file does not exist' do
308
+ it 'returns a not found' do
309
+ get :index, :params => { :version => 'v3-does-not-exist' }
310
+ expect(response).to have_http_status(:not_found)
311
+ end
312
+ end
313
+
314
+ context 'preventing path traversal' do
315
+ context 'when resource contains ..' do
316
+ it "returns a not found" do
317
+ get :index, :params => { :version => 'v1', :format => "html", :resource => "../resource-with-namespace", :method => "method" }
318
+ expect(response).to have_http_status(:not_found)
319
+ end
320
+ end
300
321
 
322
+ context 'when method contains ..' do
323
+ it "returns a not found" do
324
+ get :index, :params => { :version => 'v1', :format => "html", :resource => "resource-with-namespace", :method => "../method" }
325
+ expect(response).to have_http_status(:not_found)
326
+ end
327
+ end
328
+
329
+ context 'when version contains ..' do
330
+ it "returns a not found" do
331
+ get :index, :params => { :version => '../v1', :format => "html", :resource => "resource-with-namespace", :method => "method" }
332
+ expect(response).to have_http_status(:not_found)
333
+ end
334
+ end
335
+
336
+ context 'when format contains ..' do
337
+ it "returns a not found" do
338
+ get :index, :params => { :version => 'v1', :format => "../html", :resource => "resource-with-namespace", :method => "method" }
339
+ expect(response).to have_http_status(:not_found)
340
+ end
341
+ end
342
+ end
343
+
344
+ end
301
345
 
302
346
  end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Apipie::Extractor::Collector do
6
+ let(:recorder) { described_class.new }
7
+
8
+ describe '#ignore_call?' do
9
+ subject { recorder.ignore_call?(record) }
10
+
11
+ let(:record) { { controller: controller, action: action } }
12
+ let(:controller) { ActionController::Base }
13
+ let(:action) { nil }
14
+
15
+ context 'when controller is nil' do
16
+ let(:controller) { nil }
17
+
18
+ it { is_expected.to be true }
19
+ end
20
+
21
+ context 'when controller is ignored' do
22
+ before do
23
+ allow(Apipie.configuration).to receive(:ignored_by_recorder).and_return(['ActionController::Bas'])
24
+ end
25
+
26
+ it { is_expected.to be true }
27
+ end
28
+
29
+ context 'when resource#method is ignored' do
30
+ let(:action) { 'ignored_action' }
31
+
32
+ before do
33
+ allow(Apipie.configuration).to receive(:ignored_by_recorder).and_return(['ActionController::Bas#ignored_action'])
34
+ end
35
+
36
+ it { is_expected.to be true }
37
+ end
38
+
39
+ context 'when controller is not an API controller' do
40
+ before do
41
+ allow(Apipie::Extractor).to receive(:controller_path).with('action_controller/base').and_return('foo')
42
+ allow(Apipie).to receive(:api_controllers_paths).and_return([])
43
+ end
44
+
45
+ it { is_expected.to be true }
46
+ end
47
+
48
+ context 'when controller is an API controller' do
49
+ before do
50
+ allow(Apipie::Extractor).to receive(:controller_path).with('action_controller/base').and_return('foo')
51
+ allow(Apipie).to receive(:api_controllers_paths).and_return(['foo'])
52
+ end
53
+
54
+ it { is_expected.to be_falsey }
55
+ end
56
+ end
57
+ end
@@ -64,6 +64,19 @@ describe Apipie::Generator::Swagger::MethodDescription::ApiSchemaService do
64
64
  it { is_expected.to include(*tags) }
65
65
  end
66
66
 
67
+ context 'when Apipie.configuration.generator.swagger.skip_default_tags is enabled' do
68
+ before { Apipie.configuration.generator.swagger.skip_default_tags = true }
69
+ after { Apipie.configuration.generator.swagger.skip_default_tags = false }
70
+
71
+ it { is_expected.to be_empty }
72
+
73
+ context 'when tags are available' do
74
+ let(:tags) { ['Tag 1', 'Tag 2'] }
75
+
76
+ it { is_expected.to eq(tags) }
77
+ end
78
+ end
79
+
67
80
  context 'when Apipie.configuration.generator.swagger.include_warning_tags is enabled' do
68
81
  before { Apipie.configuration.generator.swagger.include_warning_tags = true }
69
82
 
@@ -4,7 +4,7 @@ describe TestEngine::MemesController do
4
4
 
5
5
  describe "#index" do
6
6
  it "should have the full mounted path of engine" do
7
- Apipie.routes_for_action(TestEngine::MemesController, :index, {}).first[:path].should eq("/test/memes")
7
+ expect(Apipie.routes_for_action(TestEngine::MemesController, :index, {}).first[:path]).to eq("/test/memes")
8
8
  end
9
9
  end
10
10
  end