grape 1.3.3 → 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +111 -2
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +135 -23
  5. data/UPGRADING.md +237 -46
  6. data/grape.gemspec +5 -5
  7. data/lib/grape/api/instance.rb +34 -42
  8. data/lib/grape/api.rb +21 -16
  9. data/lib/grape/cookies.rb +2 -0
  10. data/lib/grape/dsl/callbacks.rb +1 -1
  11. data/lib/grape/dsl/desc.rb +3 -5
  12. data/lib/grape/dsl/headers.rb +5 -2
  13. data/lib/grape/dsl/helpers.rb +8 -5
  14. data/lib/grape/dsl/inside_route.rb +72 -53
  15. data/lib/grape/dsl/middleware.rb +4 -4
  16. data/lib/grape/dsl/parameters.rb +11 -7
  17. data/lib/grape/dsl/request_response.rb +9 -6
  18. data/lib/grape/dsl/routing.rb +8 -9
  19. data/lib/grape/dsl/settings.rb +5 -5
  20. data/lib/grape/dsl/validations.rb +18 -1
  21. data/lib/grape/eager_load.rb +1 -1
  22. data/lib/grape/endpoint.rb +29 -42
  23. data/lib/grape/error_formatter/json.rb +2 -6
  24. data/lib/grape/error_formatter/xml.rb +2 -6
  25. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  26. data/lib/grape/exceptions/validation.rb +2 -3
  27. data/lib/grape/exceptions/validation_errors.rb +1 -1
  28. data/lib/grape/formatter/json.rb +1 -0
  29. data/lib/grape/formatter/serializable_hash.rb +2 -1
  30. data/lib/grape/formatter/xml.rb +1 -0
  31. data/lib/grape/locale/en.yml +1 -1
  32. data/lib/grape/middleware/auth/base.rb +3 -3
  33. data/lib/grape/middleware/auth/dsl.rb +7 -1
  34. data/lib/grape/middleware/base.rb +6 -3
  35. data/lib/grape/middleware/error.rb +11 -13
  36. data/lib/grape/middleware/formatter.rb +7 -7
  37. data/lib/grape/middleware/stack.rb +10 -3
  38. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  39. data/lib/grape/middleware/versioner/header.rb +6 -4
  40. data/lib/grape/middleware/versioner/param.rb +1 -0
  41. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  42. data/lib/grape/middleware/versioner/path.rb +2 -0
  43. data/lib/grape/parser/json.rb +1 -1
  44. data/lib/grape/parser/xml.rb +1 -1
  45. data/lib/grape/path.rb +1 -0
  46. data/lib/grape/request.rb +4 -1
  47. data/lib/grape/router/attribute_translator.rb +3 -3
  48. data/lib/grape/router/pattern.rb +1 -1
  49. data/lib/grape/router/route.rb +2 -2
  50. data/lib/grape/router.rb +31 -30
  51. data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
  52. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
  53. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
  54. data/lib/grape/util/base_inheritable.rb +2 -2
  55. data/lib/grape/util/inheritable_setting.rb +1 -3
  56. data/lib/grape/util/lazy_value.rb +4 -2
  57. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  58. data/lib/grape/validations/attributes_iterator.rb +8 -0
  59. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  60. data/lib/grape/validations/params_scope.rb +97 -62
  61. data/lib/grape/validations/single_attribute_iterator.rb +1 -1
  62. data/lib/grape/validations/types/custom_type_coercer.rb +16 -3
  63. data/lib/grape/validations/types/dry_type_coercer.rb +1 -1
  64. data/lib/grape/validations/types/invalid_value.rb +24 -0
  65. data/lib/grape/validations/types/json.rb +2 -1
  66. data/lib/grape/validations/types/primitive_coercer.rb +4 -5
  67. data/lib/grape/validations/types.rb +1 -4
  68. data/lib/grape/validations/validator_factory.rb +1 -1
  69. data/lib/grape/validations/validators/all_or_none.rb +8 -5
  70. data/lib/grape/validations/validators/allow_blank.rb +9 -7
  71. data/lib/grape/validations/validators/as.rb +6 -8
  72. data/lib/grape/validations/validators/at_least_one_of.rb +7 -4
  73. data/lib/grape/validations/validators/base.rb +74 -69
  74. data/lib/grape/validations/validators/coerce.rb +63 -76
  75. data/lib/grape/validations/validators/default.rb +36 -34
  76. data/lib/grape/validations/validators/exactly_one_of.rb +9 -6
  77. data/lib/grape/validations/validators/except_values.rb +13 -11
  78. data/lib/grape/validations/validators/multiple_params_base.rb +24 -19
  79. data/lib/grape/validations/validators/mutual_exclusion.rb +8 -5
  80. data/lib/grape/validations/validators/presence.rb +7 -4
  81. data/lib/grape/validations/validators/regexp.rb +8 -5
  82. data/lib/grape/validations/validators/same_as.rb +18 -15
  83. data/lib/grape/validations/validators/values.rb +61 -56
  84. data/lib/grape/validations.rb +6 -0
  85. data/lib/grape/version.rb +1 -1
  86. data/lib/grape.rb +7 -3
  87. data/spec/grape/api/custom_validations_spec.rb +77 -45
  88. data/spec/grape/api/deeply_included_options_spec.rb +3 -3
  89. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
  90. data/spec/grape/api/invalid_format_spec.rb +2 -0
  91. data/spec/grape/api/recognize_path_spec.rb +1 -1
  92. data/spec/grape/api/routes_with_requirements_spec.rb +8 -8
  93. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
  94. data/spec/grape/api_remount_spec.rb +25 -19
  95. data/spec/grape/api_spec.rb +576 -211
  96. data/spec/grape/dsl/callbacks_spec.rb +2 -1
  97. data/spec/grape/dsl/headers_spec.rb +39 -9
  98. data/spec/grape/dsl/helpers_spec.rb +3 -2
  99. data/spec/grape/dsl/inside_route_spec.rb +185 -34
  100. data/spec/grape/dsl/logger_spec.rb +16 -18
  101. data/spec/grape/dsl/middleware_spec.rb +2 -1
  102. data/spec/grape/dsl/parameters_spec.rb +2 -0
  103. data/spec/grape/dsl/request_response_spec.rb +1 -0
  104. data/spec/grape/dsl/routing_spec.rb +10 -7
  105. data/spec/grape/endpoint/declared_spec.rb +848 -0
  106. data/spec/grape/endpoint_spec.rb +77 -589
  107. data/spec/grape/entity_spec.rb +29 -23
  108. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
  109. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
  110. data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
  111. data/spec/grape/exceptions/validation_spec.rb +5 -3
  112. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
  113. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
  114. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
  115. data/spec/grape/integration/rack_sendfile_spec.rb +13 -9
  116. data/spec/grape/loading_spec.rb +8 -8
  117. data/spec/grape/middleware/auth/dsl_spec.rb +15 -6
  118. data/spec/grape/middleware/auth/strategies_spec.rb +61 -21
  119. data/spec/grape/middleware/base_spec.rb +24 -15
  120. data/spec/grape/middleware/error_spec.rb +3 -3
  121. data/spec/grape/middleware/exception_spec.rb +111 -161
  122. data/spec/grape/middleware/formatter_spec.rb +28 -7
  123. data/spec/grape/middleware/globals_spec.rb +7 -4
  124. data/spec/grape/middleware/stack_spec.rb +15 -12
  125. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
  126. data/spec/grape/middleware/versioner/header_spec.rb +14 -13
  127. data/spec/grape/middleware/versioner/param_spec.rb +7 -1
  128. data/spec/grape/middleware/versioner/path_spec.rb +5 -1
  129. data/spec/grape/middleware/versioner_spec.rb +1 -1
  130. data/spec/grape/parser_spec.rb +4 -0
  131. data/spec/grape/path_spec.rb +52 -52
  132. data/spec/grape/presenters/presenter_spec.rb +7 -6
  133. data/spec/grape/request_spec.rb +6 -4
  134. data/spec/grape/util/inheritable_setting_spec.rb +7 -7
  135. data/spec/grape/util/inheritable_values_spec.rb +3 -2
  136. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
  137. data/spec/grape/util/stackable_values_spec.rb +7 -5
  138. data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
  139. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +14 -3
  140. data/spec/grape/validations/params_scope_spec.rb +72 -10
  141. data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -6
  142. data/spec/grape/validations/types/primitive_coercer_spec.rb +63 -7
  143. data/spec/grape/validations/types_spec.rb +8 -8
  144. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
  145. data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
  146. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
  147. data/spec/grape/validations/validators/coerce_spec.rb +248 -33
  148. data/spec/grape/validations/validators/default_spec.rb +121 -78
  149. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
  150. data/spec/grape/validations/validators/except_values_spec.rb +4 -3
  151. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
  152. data/spec/grape/validations/validators/presence_spec.rb +16 -1
  153. data/spec/grape/validations/validators/regexp_spec.rb +25 -31
  154. data/spec/grape/validations/validators/same_as_spec.rb +14 -20
  155. data/spec/grape/validations/validators/values_spec.rb +183 -178
  156. data/spec/grape/validations_spec.rb +342 -29
  157. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  158. data/spec/integration/multi_json/json_spec.rb +1 -1
  159. data/spec/integration/multi_xml/xml_spec.rb +1 -1
  160. data/spec/shared/versioning_examples.rb +32 -29
  161. data/spec/spec_helper.rb +12 -12
  162. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  163. data/spec/support/chunks.rb +14 -0
  164. data/spec/support/versioned_helpers.rb +4 -6
  165. metadata +110 -102
@@ -10,10 +10,10 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
10
10
  end
11
11
 
12
12
  describe 'in an endpoint' do
13
- context '#params' do
13
+ describe '#params' do
14
14
  before do
15
15
  subject.params do
16
- build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
16
+ build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder # rubocop:disable RSpec/DescribedClass
17
17
  end
18
18
 
19
19
  subject.get do
@@ -21,7 +21,7 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
21
21
  end
22
22
  end
23
23
 
24
- it 'should be of type Hash' do
24
+ it 'is of type Hash' do
25
25
  get '/'
26
26
  expect(last_response.status).to eq(200)
27
27
  expect(last_response.body).to eq('ActiveSupport::HashWithIndifferentAccess')
@@ -31,10 +31,10 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
31
31
 
32
32
  describe 'in an api' do
33
33
  before do
34
- subject.send(:include, Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder)
34
+ subject.send(:include, Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder) # rubocop:disable RSpec/DescribedClass
35
35
  end
36
36
 
37
- context '#params' do
37
+ describe '#params' do
38
38
  before do
39
39
  subject.get do
40
40
  params.class
@@ -49,7 +49,7 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
49
49
 
50
50
  it 'parses sub hash params' do
51
51
  subject.params do
52
- build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
52
+ build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder # rubocop:disable RSpec/DescribedClass
53
53
 
54
54
  optional :a, type: Hash do
55
55
  optional :b, type: Hash do
@@ -70,7 +70,7 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
70
70
 
71
71
  it 'params are indifferent to symbol or string keys' do
72
72
  subject.params do
73
- build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
73
+ build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder # rubocop:disable RSpec/DescribedClass
74
74
  optional :a, type: Hash do
75
75
  optional :b, type: Hash do
76
76
  optional :c, type: String
@@ -90,7 +90,7 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
90
90
 
91
91
  it 'responds to string keys' do
92
92
  subject.params do
93
- build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
93
+ build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder # rubocop:disable RSpec/DescribedClass
94
94
  requires :a, type: String
95
95
  end
96
96
 
@@ -10,10 +10,10 @@ describe Grape::Extensions::Hashie::Mash::ParamBuilder do
10
10
  end
11
11
 
12
12
  describe 'in an endpoint' do
13
- context '#params' do
13
+ describe '#params' do
14
14
  before do
15
15
  subject.params do
16
- build_with Grape::Extensions::Hashie::Mash::ParamBuilder
16
+ build_with Grape::Extensions::Hashie::Mash::ParamBuilder # rubocop:disable RSpec/DescribedClass
17
17
  end
18
18
 
19
19
  subject.get do
@@ -21,7 +21,7 @@ describe Grape::Extensions::Hashie::Mash::ParamBuilder do
21
21
  end
22
22
  end
23
23
 
24
- it 'should be of type Hashie::Mash' do
24
+ it 'is of type Hashie::Mash' do
25
25
  get '/'
26
26
  expect(last_response.status).to eq(200)
27
27
  expect(last_response.body).to eq('Hashie::Mash')
@@ -31,17 +31,17 @@ describe Grape::Extensions::Hashie::Mash::ParamBuilder do
31
31
 
32
32
  describe 'in an api' do
33
33
  before do
34
- subject.send(:include, Grape::Extensions::Hashie::Mash::ParamBuilder)
34
+ subject.send(:include, Grape::Extensions::Hashie::Mash::ParamBuilder) # rubocop:disable RSpec/DescribedClass
35
35
  end
36
36
 
37
- context '#params' do
37
+ describe '#params' do
38
38
  before do
39
39
  subject.get do
40
40
  params.class
41
41
  end
42
42
  end
43
43
 
44
- it 'should be Hashie::Mash' do
44
+ it 'is Hashie::Mash' do
45
45
  get '/'
46
46
  expect(last_response.status).to eq(200)
47
47
  expect(last_response.body).to eq('Hashie::Mash')
@@ -57,7 +57,7 @@ describe Grape::Extensions::Hashie::Mash::ParamBuilder do
57
57
  end
58
58
  end
59
59
 
60
- it 'should be Hashie::Mash' do
60
+ it 'is Hashie::Mash' do
61
61
  get '/foo'
62
62
  expect(last_response.status).to eq(200)
63
63
  expect(last_response.body).to eq('Hashie::Mash')
@@ -66,7 +66,7 @@ describe Grape::Extensions::Hashie::Mash::ParamBuilder do
66
66
 
67
67
  it 'is indifferent to key or symbol access' do
68
68
  subject.params do
69
- build_with Grape::Extensions::Hashie::Mash::ParamBuilder
69
+ build_with Grape::Extensions::Hashie::Mash::ParamBuilder # rubocop:disable RSpec/DescribedClass
70
70
  requires :a, type: String
71
71
  end
72
72
  subject.get '/foo' do
@@ -4,12 +4,16 @@ require 'spec_helper'
4
4
 
5
5
  describe Rack::Sendfile do
6
6
  subject do
7
- send_file = file_streamer
7
+ content_object = file_object
8
8
  app = Class.new(Grape::API) do
9
9
  use Rack::Sendfile
10
10
  format :json
11
11
  get do
12
- file send_file
12
+ if content_object.is_a?(String)
13
+ sendfile content_object
14
+ else
15
+ stream content_object
16
+ end
13
17
  end
14
18
  end
15
19
 
@@ -22,9 +26,9 @@ describe Rack::Sendfile do
22
26
  app.call(env)
23
27
  end
24
28
 
25
- context do
26
- let(:file_streamer) do
27
- double(:file_streamer, to_path: '/accel/mapping/some/path')
29
+ context 'when calling sendfile' do
30
+ let(:file_object) do
31
+ '/accel/mapping/some/path'
28
32
  end
29
33
 
30
34
  it 'contains Sendfile headers' do
@@ -33,14 +37,14 @@ describe Rack::Sendfile do
33
37
  end
34
38
  end
35
39
 
36
- context do
37
- let(:file_streamer) do
38
- double(:file_streamer)
40
+ context 'when streaming non file content' do
41
+ let(:file_object) do
42
+ double(:file_object, each: nil)
39
43
  end
40
44
 
41
45
  it 'not contains Sendfile headers' do
42
46
  headers = subject[1]
43
- expect(headers).to_not include('X-Accel-Redirect')
47
+ expect(headers).not_to include('X-Accel-Redirect')
44
48
  end
45
49
  end
46
50
  end
@@ -3,6 +3,14 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Grape::API do
6
+ subject do
7
+ CombinedApi = combined_api
8
+ Class.new(Grape::API) do
9
+ format :json
10
+ mount CombinedApi => '/'
11
+ end
12
+ end
13
+
6
14
  let(:jobs_api) do
7
15
  Class.new(Grape::API) do
8
16
  namespace :one do
@@ -26,14 +34,6 @@ describe Grape::API do
26
34
  end
27
35
  end
28
36
 
29
- subject do
30
- CombinedApi = combined_api
31
- Class.new(Grape::API) do
32
- format :json
33
- mount CombinedApi => '/'
34
- end
35
- end
36
-
37
37
  def app
38
38
  subject
39
39
  end
@@ -5,7 +5,7 @@ require 'spec_helper'
5
5
  describe Grape::Middleware::Auth::DSL do
6
6
  subject { Class.new(Grape::API) }
7
7
 
8
- let(:block) { ->() {} }
8
+ let(:block) { -> {} }
9
9
  let(:settings) do
10
10
  {
11
11
  opaque: 'secret',
@@ -16,7 +16,7 @@ describe Grape::Middleware::Auth::DSL do
16
16
  end
17
17
 
18
18
  describe '.auth' do
19
- it 'stets auth parameters' do
19
+ it 'sets auth parameters' do
20
20
  expect(subject.base_instance).to receive(:use).with(Grape::Middleware::Auth::Base, settings)
21
21
 
22
22
  subject.auth :http_digest, realm: settings[:realm], opaque: settings[:opaque], &settings[:proc]
@@ -38,16 +38,25 @@ describe Grape::Middleware::Auth::DSL do
38
38
  end
39
39
 
40
40
  describe '.http_basic' do
41
- it 'stets auth parameters' do
41
+ it 'sets auth parameters' do
42
42
  subject.http_basic realm: 'my_realm', &settings[:proc]
43
43
  expect(subject.auth).to eq(realm: 'my_realm', type: :http_basic, proc: block)
44
44
  end
45
45
  end
46
46
 
47
47
  describe '.http_digest' do
48
- it 'stets auth parameters' do
49
- subject.http_digest realm: 'my_realm', opaque: 'my_opaque', &settings[:proc]
50
- expect(subject.auth).to eq(realm: 'my_realm', type: :http_digest, proc: block, opaque: 'my_opaque')
48
+ context 'when realm is a hash' do
49
+ it 'sets auth parameters' do
50
+ subject.http_digest realm: { realm: 'my_realm', opaque: 'my_opaque' }, &settings[:proc]
51
+ expect(subject.auth).to eq(realm: { realm: 'my_realm', opaque: 'my_opaque' }, type: :http_digest, proc: block)
52
+ end
53
+ end
54
+
55
+ context 'when realm is not hash' do
56
+ it 'sets auth parameters' do
57
+ subject.http_digest realm: 'my_realm', opaque: 'my_opaque', &settings[:proc]
58
+ expect(subject.auth).to eq(realm: 'my_realm', type: :http_digest, proc: block, opaque: 'my_opaque')
59
+ end
51
60
  end
52
61
  end
53
62
  end
@@ -36,13 +36,23 @@ describe Grape::Middleware::Auth::Strategies do
36
36
  RSpec::Matchers.define :be_challenge do
37
37
  match do |actual_response|
38
38
  actual_response.status == 401 &&
39
- actual_response['WWW-Authenticate'] =~ /^Digest / &&
39
+ actual_response['WWW-Authenticate'].start_with?('Digest ') &&
40
40
  actual_response.body.empty?
41
41
  end
42
42
  end
43
43
 
44
44
  module StrategiesSpec
45
- class Test < Grape::API
45
+ class PasswordHashed < Grape::API
46
+ http_digest(realm: { realm: 'Test Api', opaque: 'secret', passwords_hashed: true }) do |username|
47
+ { 'foo' => Digest::MD5.hexdigest(['foo', 'Test Api', 'bar'].join(':')) }[username]
48
+ end
49
+
50
+ get '/test' do
51
+ [{ hey: 'you' }, { there: 'bar' }, { foo: 'baz' }]
52
+ end
53
+ end
54
+
55
+ class PasswordIsNotHashed < Grape::API
46
56
  http_digest(realm: 'Test Api', opaque: 'secret') do |username|
47
57
  { 'foo' => 'bar' }[username]
48
58
  end
@@ -53,30 +63,60 @@ describe Grape::Middleware::Auth::Strategies do
53
63
  end
54
64
  end
55
65
 
56
- def app
57
- StrategiesSpec::Test
58
- end
66
+ context 'when password is hashed' do
67
+ def app
68
+ StrategiesSpec::PasswordHashed
69
+ end
59
70
 
60
- it 'is a digest authentication challenge' do
61
- get '/test'
62
- expect(last_response).to be_challenge
63
- end
71
+ it 'is a digest authentication challenge' do
72
+ get '/test'
73
+ expect(last_response).to be_challenge
74
+ end
64
75
 
65
- it 'throws a 401 if no auth is given' do
66
- get '/test'
67
- expect(last_response.status).to eq(401)
68
- end
76
+ it 'throws a 401 if no auth is given' do
77
+ get '/test'
78
+ expect(last_response.status).to eq(401)
79
+ end
69
80
 
70
- it 'authenticates if given valid creds' do
71
- digest_authorize 'foo', 'bar'
72
- get '/test'
73
- expect(last_response.status).to eq(200)
81
+ it 'authenticates if given valid creds' do
82
+ digest_authorize 'foo', 'bar'
83
+ get '/test'
84
+ expect(last_response.status).to eq(200)
85
+ end
86
+
87
+ it 'throws a 401 if given invalid creds' do
88
+ digest_authorize 'bar', 'foo'
89
+ get '/test'
90
+ expect(last_response.status).to eq(401)
91
+ end
74
92
  end
75
93
 
76
- it 'throws a 401 if given invalid creds' do
77
- digest_authorize 'bar', 'foo'
78
- get '/test'
79
- expect(last_response.status).to eq(401)
94
+ context 'when password is not hashed' do
95
+ def app
96
+ StrategiesSpec::PasswordIsNotHashed
97
+ end
98
+
99
+ it 'is a digest authentication challenge' do
100
+ get '/test'
101
+ expect(last_response).to be_challenge
102
+ end
103
+
104
+ it 'throws a 401 if no auth is given' do
105
+ get '/test'
106
+ expect(last_response.status).to eq(401)
107
+ end
108
+
109
+ it 'authenticates if given valid creds' do
110
+ digest_authorize 'foo', 'bar'
111
+ get '/test'
112
+ expect(last_response.status).to eq(200)
113
+ end
114
+
115
+ it 'throws a 401 if given invalid creds' do
116
+ digest_authorize 'bar', 'foo'
117
+ get '/test'
118
+ expect(last_response.status).to eq(401)
119
+ end
80
120
  end
81
121
  end
82
122
  end
@@ -3,7 +3,8 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Grape::Middleware::Base do
6
- subject { Grape::Middleware::Base.new(blank_app) }
6
+ subject { described_class.new(blank_app) }
7
+
7
8
  let(:blank_app) { ->(_) { [200, {}, 'Hi there.'] } }
8
9
 
9
10
  before do
@@ -20,6 +21,8 @@ describe Grape::Middleware::Base do
20
21
  end
21
22
 
22
23
  context 'callbacks' do
24
+ after { subject.call!({}) }
25
+
23
26
  it 'calls #before' do
24
27
  expect(subject).to receive(:before)
25
28
  end
@@ -27,8 +30,6 @@ describe Grape::Middleware::Base do
27
30
  it 'calls #after' do
28
31
  expect(subject).to receive(:after)
29
32
  end
30
-
31
- after { subject.call!({}) }
32
33
  end
33
34
 
34
35
  context 'callbacks on error' do
@@ -58,7 +59,7 @@ describe Grape::Middleware::Base do
58
59
  context 'with patched warnings' do
59
60
  before do
60
61
  @warnings = warnings = []
61
- allow_any_instance_of(Grape::Middleware::Base).to receive(:warn) { |m| warnings << m }
62
+ allow_any_instance_of(described_class).to receive(:warn) { |m| warnings << m }
62
63
  allow(subject).to receive(:after).and_raise(StandardError)
63
64
  end
64
65
 
@@ -75,49 +76,57 @@ describe Grape::Middleware::Base do
75
76
  end
76
77
 
77
78
  describe '#response' do
78
- subject { Grape::Middleware::Base.new(response) }
79
+ subject do
80
+ puts described_class
81
+ described_class.new(response)
82
+ end
79
83
 
80
- context Array do
84
+ before { subject.call({}) }
85
+
86
+ context 'when Array' do
81
87
  let(:response) { ->(_) { [204, { abc: 1 }, 'test'] } }
82
88
 
83
89
  it 'status' do
84
- subject.call({})
85
90
  expect(subject.response.status).to eq(204)
86
91
  end
87
92
 
88
93
  it 'body' do
89
- subject.call({})
90
94
  expect(subject.response.body).to eq(['test'])
91
95
  end
92
96
 
93
97
  it 'header' do
94
- subject.call({})
95
98
  expect(subject.response.header).to have_key(:abc)
96
99
  end
100
+
101
+ it 'returns the memoized Rack::Response instance' do
102
+ expect(subject.response).to be(subject.response)
103
+ end
97
104
  end
98
105
 
99
- context Rack::Response do
106
+ context 'when Rack::Response' do
100
107
  let(:response) { ->(_) { Rack::Response.new('test', 204, abc: 1) } }
101
108
 
102
109
  it 'status' do
103
- subject.call({})
104
110
  expect(subject.response.status).to eq(204)
105
111
  end
106
112
 
107
113
  it 'body' do
108
- subject.call({})
109
114
  expect(subject.response.body).to eq(['test'])
110
115
  end
111
116
 
112
117
  it 'header' do
113
- subject.call({})
114
118
  expect(subject.response.header).to have_key(:abc)
115
119
  end
120
+
121
+ it 'returns the memoized Rack::Response instance' do
122
+ expect(subject.response).to be(subject.response)
123
+ end
116
124
  end
117
125
  end
118
126
 
119
127
  describe '#context' do
120
- subject { Grape::Middleware::Base.new(blank_app) }
128
+ subject { described_class.new(blank_app) }
129
+
121
130
  it 'allows access to response context' do
122
131
  subject.call(Grape::Env::API_ENDPOINT => { header: 'some header' })
123
132
  expect(subject.context).to eq(header: 'some header')
@@ -126,7 +135,7 @@ describe Grape::Middleware::Base do
126
135
 
127
136
  context 'options' do
128
137
  it 'persists options passed at initialization' do
129
- expect(Grape::Middleware::Base.new(blank_app, abc: true).options[:abc]).to be true
138
+ expect(described_class.new(blank_app, abc: true).options[:abc]).to be true
130
139
  end
131
140
 
132
141
  context 'defaults' do
@@ -16,8 +16,7 @@ describe Grape::Middleware::Error do
16
16
 
17
17
  class ErrApp
18
18
  class << self
19
- attr_accessor :error
20
- attr_accessor :format
19
+ attr_accessor :error, :format
21
20
 
22
21
  def call(_env)
23
22
  throw :error, error
@@ -30,7 +29,7 @@ describe Grape::Middleware::Error do
30
29
  opts = options
31
30
  Rack::Builder.app do
32
31
  use Spec::Support::EndpointFaker
33
- use Grape::Middleware::Error, opts
32
+ use Grape::Middleware::Error, **opts
34
33
  run ErrorSpec::ErrApp
35
34
  end
36
35
  end
@@ -63,6 +62,7 @@ describe Grape::Middleware::Error do
63
62
 
64
63
  context 'with http code' do
65
64
  let(:options) { { default_message: 'Aww, hamburgers.' } }
65
+
66
66
  it 'adds the status code if wanted' do
67
67
  ErrorSpec::ErrApp.error = { message: { code: 200 } }
68
68
  get '/'