shoulda-matchers 3.0.0.rc1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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