shoulda-matchers 3.0.0.rc1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -3
  3. data/Gemfile.lock +12 -41
  4. data/NEWS.md +118 -26
  5. data/README.md +34 -11
  6. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +0 -0
  7. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +4 -0
  8. data/gemfiles/4.0.0.gemfile +2 -3
  9. data/gemfiles/4.0.0.gemfile.lock +47 -77
  10. data/gemfiles/4.0.1.gemfile +2 -3
  11. data/gemfiles/4.0.1.gemfile.lock +51 -79
  12. data/gemfiles/4.1.gemfile +2 -3
  13. data/gemfiles/4.1.gemfile.lock +73 -103
  14. data/gemfiles/4.2.gemfile +2 -3
  15. data/gemfiles/4.2.gemfile.lock +90 -124
  16. data/lib/shoulda/matchers.rb +1 -0
  17. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +6 -8
  18. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +1 -3
  19. data/lib/shoulda/matchers/action_controller/flash_store.rb +1 -8
  20. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +140 -88
  21. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +2 -5
  22. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +5 -10
  23. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +2 -4
  24. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +1 -3
  25. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +3 -5
  26. data/lib/shoulda/matchers/action_controller/route_matcher.rb +5 -7
  27. data/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +35 -9
  28. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +3 -3
  29. data/lib/shoulda/matchers/active_model.rb +57 -1
  30. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +2 -5
  31. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +162 -54
  32. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +5 -2
  33. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +1 -3
  34. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +24 -11
  35. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +4 -3
  36. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +0 -2
  37. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +4 -3
  38. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +2 -1
  39. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +15 -13
  40. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +3 -3
  41. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +3 -3
  42. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +4 -4
  43. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +8 -8
  44. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +8 -8
  45. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +12 -14
  46. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +10 -4
  47. data/lib/shoulda/matchers/active_model/validation_matcher.rb +0 -3
  48. data/lib/shoulda/matchers/active_model/validator.rb +0 -8
  49. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +4 -6
  50. data/lib/shoulda/matchers/active_record/association_matcher.rb +58 -43
  51. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +2 -2
  52. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +3 -5
  53. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +3 -5
  54. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +1 -4
  55. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +3 -5
  56. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +7 -7
  57. data/lib/shoulda/matchers/doublespeak/double.rb +10 -1
  58. data/lib/shoulda/matchers/doublespeak/double_collection.rb +13 -5
  59. data/lib/shoulda/matchers/doublespeak/method_call.rb +10 -1
  60. data/lib/shoulda/matchers/doublespeak/object_double.rb +2 -1
  61. data/lib/shoulda/matchers/doublespeak/world.rb +10 -0
  62. data/lib/shoulda/matchers/error.rb +4 -0
  63. data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +11 -10
  64. data/lib/shoulda/matchers/integrations/libraries.rb +1 -0
  65. data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +1 -1
  66. data/lib/shoulda/matchers/integrations/libraries/active_model.rb +1 -1
  67. data/lib/shoulda/matchers/integrations/libraries/active_record.rb +1 -1
  68. data/lib/shoulda/matchers/integrations/libraries/rails.rb +2 -1
  69. data/lib/shoulda/matchers/integrations/libraries/routing.rb +27 -0
  70. data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +1 -1
  71. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +1 -1
  72. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +1 -1
  73. data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +1 -1
  74. data/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb +2 -2
  75. data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +1 -1
  76. data/lib/shoulda/matchers/routing.rb +10 -0
  77. data/lib/shoulda/matchers/version.rb +1 -1
  78. data/script/SUPPORTED_VERSIONS +1 -1
  79. data/spec/acceptance/independent_matchers_spec.rb +103 -42
  80. data/spec/doublespeak_spec_helper.rb +5 -1
  81. data/spec/support/acceptance/adds_shoulda_matchers_to_project.rb +34 -11
  82. data/spec/support/acceptance/helpers/rspec_helpers.rb +9 -13
  83. data/spec/support/acceptance/helpers/step_helpers.rb +13 -0
  84. data/spec/support/acceptance/matchers/have_output.rb +1 -1
  85. data/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +1 -1
  86. data/spec/support/tests/command_runner.rb +5 -1
  87. data/spec/support/unit/helpers/active_record_versions.rb +0 -4
  88. data/spec/support/unit/shared_examples/set_session_or_flash.rb +8 -3
  89. data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +198 -39
  90. data/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +269 -102
  91. data/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +24 -0
  92. data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +118 -101
  93. data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +0 -82
  94. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +148 -121
  95. data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +20 -8
  96. data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +64 -183
  97. data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +14 -0
  98. data/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +60 -0
  99. data/spec/unit/shoulda/matchers/doublespeak/double_spec.rb +23 -7
  100. data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +242 -0
  101. data/spec/unit_spec_helper.rb +4 -0
  102. data/tasks/documentation.rb +35 -0
  103. metadata +9 -8
  104. data/Guardfile +0 -5
  105. data/cucumber.yml +0 -1
  106. data/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb +0 -12
@@ -26,6 +26,36 @@ module Shoulda::Matchers::Doublespeak
26
26
  to have_received(:new).
27
27
  with(world, :klass, :a_method, :implementation)
28
28
  end
29
+
30
+ context 'if a double has already been registered for the method' do
31
+ it 'does not call Double.new again' do
32
+ world = build_world
33
+ allow(DoubleImplementationRegistry).
34
+ to receive(:find).
35
+ and_return(:implementation)
36
+ allow(Double).to receive(:new)
37
+ double_collection = described_class.new(world, :klass)
38
+
39
+ double_collection.register_stub(:a_method)
40
+ double_collection.register_stub(:a_method)
41
+
42
+ expect(Double).to have_received(:new).once
43
+ end
44
+
45
+ it 'returns the same Double' do
46
+ world = build_world
47
+ allow(DoubleImplementationRegistry).
48
+ to receive(:find).
49
+ and_return(:implementation)
50
+ allow(Double).to receive(:new)
51
+ double_collection = described_class.new(world, :klass)
52
+
53
+ double1 = double_collection.register_stub(:a_method)
54
+ double2 = double_collection.register_stub(:a_method)
55
+
56
+ expect(double1).to equal(double2)
57
+ end
58
+ end
29
59
  end
30
60
 
31
61
  describe '#register_proxy' do
@@ -54,6 +84,36 @@ module Shoulda::Matchers::Doublespeak
54
84
  to have_received(:new).
55
85
  with(world, :klass, :a_method, :implementation)
56
86
  end
87
+
88
+ context 'if a double has already been registered for the method' do
89
+ it 'does not call Double.new again' do
90
+ world = build_world
91
+ allow(DoubleImplementationRegistry).
92
+ to receive(:find).
93
+ and_return(:implementation)
94
+ allow(Double).to receive(:new)
95
+ double_collection = described_class.new(world, :klass)
96
+
97
+ double_collection.register_proxy(:a_method)
98
+ double_collection.register_proxy(:a_method)
99
+
100
+ expect(Double).to have_received(:new).once
101
+ end
102
+
103
+ it 'returns the same Double' do
104
+ world = build_world
105
+ allow(DoubleImplementationRegistry).
106
+ to receive(:find).
107
+ and_return(:implementation)
108
+ allow(Double).to receive(:new)
109
+ double_collection = described_class.new(world, :klass)
110
+
111
+ double1 = double_collection.register_proxy(:a_method)
112
+ double2 = double_collection.register_proxy(:a_method)
113
+
114
+ expect(double1).to equal(double2)
115
+ end
116
+ end
57
117
  end
58
118
 
59
119
  describe '#activate' do
@@ -2,6 +2,20 @@ require 'doublespeak_spec_helper'
2
2
 
3
3
  module Shoulda::Matchers::Doublespeak
4
4
  describe Double do
5
+ describe 'initializer' do
6
+ context 'if doubles are currently activated on the world level' do
7
+ it 'immediately activates the new Double' do
8
+ world = build_world(doubles_activated?: true)
9
+ klass = create_class(a_method_name: nil)
10
+ implementation = build_implementation
11
+
12
+ double = described_class.new(world, klass, :a_method_name, implementation)
13
+
14
+ expect(double).to be_activated
15
+ end
16
+ end
17
+ end
18
+
5
19
  describe '#to_return' do
6
20
  it 'tells its implementation to call the given block' do
7
21
  sent_block = -> { }
@@ -12,7 +26,7 @@ module Shoulda::Matchers::Doublespeak
12
26
  actual_block = block
13
27
  end
14
28
  double = described_class.new(
15
- :a_world,
29
+ build_world,
16
30
  :klass,
17
31
  :a_method,
18
32
  implementation
@@ -24,7 +38,7 @@ module Shoulda::Matchers::Doublespeak
24
38
  it 'tells its implementation to return the given value' do
25
39
  implementation = build_implementation
26
40
  double = described_class.new(
27
- :a_world,
41
+ build_world,
28
42
  :klass,
29
43
  :a_method,
30
44
  implementation
@@ -43,7 +57,7 @@ module Shoulda::Matchers::Doublespeak
43
57
  actual_block = block
44
58
  end
45
59
  double = described_class.new(
46
- :a_world,
60
+ build_world,
47
61
  :klass,
48
62
  :a_method,
49
63
  implementation
@@ -72,7 +86,8 @@ module Shoulda::Matchers::Doublespeak
72
86
  object: instance,
73
87
  method_name: method_name,
74
88
  args: args,
75
- block: block
89
+ block: block,
90
+ caller: :some_caller
76
91
  )
77
92
 
78
93
  double.activate
@@ -127,7 +142,7 @@ module Shoulda::Matchers::Doublespeak
127
142
  klass = create_class(a_method: 42)
128
143
  instance = klass.new
129
144
  double = described_class.new(
130
- :a_world,
145
+ build_world,
131
146
  klass,
132
147
  :a_method,
133
148
  build_implementation
@@ -141,7 +156,7 @@ module Shoulda::Matchers::Doublespeak
141
156
  describe '#record_call' do
142
157
  it 'adds the given call to the list of calls' do
143
158
  double = described_class.new(
144
- :a_world,
159
+ build_world,
145
160
  :a_klass,
146
161
  :a_method,
147
162
  :an_implementation
@@ -247,7 +262,8 @@ module Shoulda::Matchers::Doublespeak
247
262
  def build_world(methods = {})
248
263
  defaults = {
249
264
  original_method_for: nil,
250
- store_original_method_for: nil
265
+ store_original_method_for: nil,
266
+ doubles_activated?: nil
251
267
  }
252
268
  double('world', defaults.merge(methods))
253
269
  end
@@ -0,0 +1,242 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe 'Shoulda::Matchers::Routing::RouteMatcher', type: :routing do
4
+ before do
5
+ define_controller('ThingsController')
6
+ end
7
+
8
+ shared_examples_for 'core tests' do
9
+ context 'when the given method, path, controller, and action match an existing route' do
10
+ it 'accepts' do
11
+ define_routes { get '/', to: 'things#index' }
12
+
13
+ assert_accepts add_target_to(
14
+ route(:get, '/'),
15
+ controller: 'things',
16
+ action: 'index'
17
+ )
18
+ end
19
+
20
+ context 'and the expected controller is specified as a symbol' do
21
+ it 'accepts' do
22
+ define_routes { get '/', to: 'things#index' }
23
+
24
+ assert_accepts add_target_to(
25
+ route(:get, '/'),
26
+ controller: :things,
27
+ action: 'index'
28
+ )
29
+ end
30
+ end
31
+
32
+ context 'and the expected action is specified as a symbol' do
33
+ it 'accepts' do
34
+ define_routes { get '/', to: 'things#index' }
35
+
36
+ assert_accepts add_target_to(
37
+ route(:get, '/'),
38
+ controller: 'things',
39
+ action: :index
40
+ )
41
+ end
42
+ end
43
+ end
44
+
45
+ context 'when the given method, path, controller, and action do not match an existing route' do
46
+ it 'rejects' do
47
+ assert_rejects add_target_to(
48
+ route(:get, '/non_existent_route'),
49
+ controller: 'no_controller',
50
+ action: 'no_action'
51
+ )
52
+ end
53
+ end
54
+
55
+ context 'when the given path, controller, and action match an existing route but the method does not' do
56
+ it 'rejects' do
57
+ define_routes { post '/', to: 'things#index' }
58
+
59
+ assert_rejects add_target_to(
60
+ route(:get, '/'),
61
+ controller: 'things',
62
+ action: 'index'
63
+ )
64
+ end
65
+ end
66
+
67
+ context 'when the given method, controller, and action match an existing route but the path does not' do
68
+ it 'rejects' do
69
+ define_routes { get '/', to: 'things#index' }
70
+
71
+ assert_rejects add_target_to(
72
+ route(:get, '/different_path'),
73
+ controller: 'things',
74
+ action: 'index'
75
+ )
76
+ end
77
+ end
78
+
79
+ context 'when the given method and path match an existing route but the controller does not' do
80
+ it 'rejects' do
81
+ define_routes { get '/', to: 'another_controller#index' }
82
+
83
+ assert_rejects add_target_to(
84
+ route(:get, '/'),
85
+ controller: 'things',
86
+ action: 'index'
87
+ )
88
+ end
89
+ end
90
+
91
+ context 'when the given method, path, and controller match an existing route but the action does not' do
92
+ it 'rejects' do
93
+ define_routes { get '/', to: 'things#index' }
94
+
95
+ assert_rejects add_target_to(
96
+ route(:get, '/'),
97
+ controller: 'things',
98
+ action: 'another_action'
99
+ )
100
+ end
101
+ end
102
+
103
+ context 'when the actual route has a param' do
104
+ context 'and the expected params include that param' do
105
+ it 'accepts' do
106
+ define_routes { get '/things/:id', to: 'things#show' }
107
+
108
+ assert_accepts add_target_to(
109
+ route(:get, '/things/1'),
110
+ controller: 'things',
111
+ action: 'show',
112
+ id: '1'
113
+ )
114
+ end
115
+
116
+ context 'but its value was not specified as a string' do
117
+ it 'accepts, treating it as a string' do
118
+ define_routes { get '/things/:id', to: 'things#show' }
119
+
120
+ assert_accepts add_target_to(
121
+ route(:get, '/things/1'),
122
+ controller: 'things',
123
+ action: 'show',
124
+ id: 1
125
+ )
126
+ end
127
+ end
128
+ end
129
+
130
+ context 'and the expected params do not match the actual params' do
131
+ it 'rejects' do
132
+ define_routes { get '/things/:id', to: 'things#show' }
133
+
134
+ params = {
135
+ controller: 'things',
136
+ action: 'show',
137
+ some: 'other',
138
+ params: 'here'
139
+ }
140
+ assert_rejects add_target_to(
141
+ route(:get, '/things/:id'),
142
+ params
143
+ )
144
+ end
145
+ end
146
+ end
147
+
148
+ context 'when the actual route has a default param whose value is a symbol' do
149
+ context 'and the expected params include a value for it' do
150
+ context 'as a symbol' do
151
+ it 'accepts' do
152
+ define_routes do
153
+ post '/things(.:format)',
154
+ to: 'things#create',
155
+ defaults: { format: :json }
156
+ end
157
+
158
+ assert_accepts add_target_to(
159
+ route(:post, '/things'),
160
+ controller: 'things',
161
+ action: 'create',
162
+ format: :json
163
+ )
164
+ end
165
+ end
166
+
167
+ context 'as a string' do
168
+ it 'accepts' do
169
+ define_routes do
170
+ post '/things(.:format)',
171
+ to: 'things#create',
172
+ defaults: { format: :json }
173
+ end
174
+
175
+ assert_accepts add_target_to(
176
+ route(:post, '/things'),
177
+ controller: 'things',
178
+ action: 'create',
179
+ format: 'json'
180
+ )
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ context 'when the existing route has a glob segment' do
187
+ context 'and a param is given which represents the segment' do
188
+ it 'accepts' do
189
+ define_routes { get '/things/*id', to: 'things#whatever' }
190
+
191
+ assert_accepts add_target_to(
192
+ route(:get, '/things/foo/bar'),
193
+ controller: 'things',
194
+ action: 'whatever',
195
+ id: 'foo/bar'
196
+ )
197
+ end
198
+ end
199
+
200
+ context 'and no param is given which represents the segment' do
201
+ it 'rejects' do
202
+ define_routes { get '/things/*id', to: 'things#whatever' }
203
+
204
+ assert_rejects add_target_to(
205
+ route(:get, '/things'),
206
+ controller: 'things',
207
+ action: 'whatever'
208
+ )
209
+ end
210
+ end
211
+ end
212
+ end
213
+
214
+ context 'given a controller and action specified as individual options' do
215
+ include_examples 'core tests'
216
+
217
+ def add_target_to(route_matcher, params)
218
+ route_matcher.to(params)
219
+ end
220
+ end
221
+
222
+ context 'given a controller and action joined together in a string' do
223
+ include_examples 'core tests'
224
+
225
+ def add_target_to(route_matcher, args)
226
+ controller = args.fetch(:controller)
227
+ action = args.fetch(:action)
228
+ route_matcher.to(
229
+ "#{controller}##{action}",
230
+ args.except(:controller, :action)
231
+ )
232
+ end
233
+ end
234
+
235
+ def assert_accepts(matcher)
236
+ should(matcher)
237
+ end
238
+
239
+ def assert_rejects(matcher)
240
+ should_not(matcher)
241
+ end
242
+ end
@@ -30,6 +30,10 @@ RSpec.configure do |config|
30
30
  c.syntax = :expect
31
31
  end
32
32
 
33
+ if config.files_to_run.one?
34
+ config.default_formatter = 'doc'
35
+ end
36
+
33
37
  config.mock_with :rspec
34
38
 
35
39
  if config.respond_to?(:infer_spec_type_from_file_location!)
@@ -33,6 +33,41 @@ module Shoulda
33
33
  publisher.generate_docs_for(args.version, latest_version: args.latest_version)
34
34
  end
35
35
 
36
+ desc 'Watch source files for this project for changes and autogenerate docs accordingly'
37
+ task :autogenerate do
38
+ require 'fssm'
39
+
40
+ project_directory = File.expand_path(File.dirname(__FILE__) + "/..")
41
+
42
+ regenerate_docs = -> (base, relative) {
43
+ print 'Regenerating docs... '
44
+ system('bundle exec yard doc &>/dev/null')
45
+ puts 'done!'
46
+ }
47
+
48
+ puts 'Waiting for documentation files to change...'
49
+
50
+ FSSM.monitor do
51
+ path project_directory do
52
+ glob 'README.md'
53
+ create(&regenerate_docs)
54
+ update(&regenerate_docs)
55
+ end
56
+
57
+ path File.join(project_directory, 'doc_config/yard') do
58
+ glob '**/*.rb'
59
+ create(&regenerate_docs)
60
+ update(&regenerate_docs)
61
+ end
62
+
63
+ path File.join(project_directory, 'lib') do
64
+ glob '**/*.rb'
65
+ create(&regenerate_docs)
66
+ update(&regenerate_docs)
67
+ end
68
+ end
69
+ end
70
+
36
71
  desc 'Generate docs for a particular version and push them to GitHub'
37
72
  task :publish, [:version, :latest_version] => :setup do |t, args|
38
73
  unless args.version