shoulda 3.4.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -7
  3. data/.hound.yml +3 -0
  4. data/.rubocop.yml +192 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +33 -2
  7. data/Appraisals +109 -8
  8. data/CHANGELOG.md +10 -0
  9. data/CONTRIBUTING.md +6 -1
  10. data/Gemfile +13 -0
  11. data/README.md +67 -74
  12. data/Rakefile +24 -10
  13. data/gemfiles/rails_4_2.gemfile +34 -0
  14. data/gemfiles/rails_4_2.gemfile.lock +240 -0
  15. data/gemfiles/rails_5_0.gemfile +32 -0
  16. data/gemfiles/rails_5_0.gemfile.lock +232 -0
  17. data/gemfiles/rails_5_1.gemfile +33 -0
  18. data/gemfiles/rails_5_1.gemfile.lock +247 -0
  19. data/gemfiles/rails_5_2.gemfile +35 -0
  20. data/gemfiles/rails_5_2.gemfile.lock +266 -0
  21. data/gemfiles/rails_6_0.gemfile +37 -0
  22. data/gemfiles/rails_6_0.gemfile.lock +291 -0
  23. data/lib/shoulda/version.rb +1 -1
  24. data/script/install_gems_in_all_appraisals +16 -0
  25. data/script/run_all_tests +16 -0
  26. data/script/supported_ruby_versions +7 -0
  27. data/script/update_gem_in_all_appraisals +17 -0
  28. data/script/update_gems_in_all_appraisals +16 -0
  29. data/shoulda.gemspec +23 -23
  30. data/test/acceptance/integrates_with_rails_test.rb +580 -0
  31. data/test/acceptance_test_helper.rb +43 -0
  32. data/test/support/acceptance/add_shoulda_to_project.rb +73 -0
  33. data/test/support/acceptance/helpers/array_helpers.rb +13 -0
  34. data/test/support/acceptance/helpers/pluralization_helpers.rb +13 -0
  35. data/test/support/acceptance/matchers/have_output.rb +33 -0
  36. data/test/support/acceptance/matchers/indicate_that_tests_were_run.rb +109 -0
  37. data/test/support/acceptance/rails_application_with_shoulda.rb +47 -0
  38. data/test/support/current_bundle.rb +61 -0
  39. data/test/support/snowglobe.rb +5 -0
  40. data/test/test_helper.rb +23 -0
  41. metadata +61 -153
  42. data/features/rails_integration.feature +0 -87
  43. data/features/step_definitions/rails_steps.rb +0 -77
  44. data/features/support/env.rb +0 -14
  45. data/gemfiles/3.0.gemfile +0 -7
  46. data/gemfiles/3.0.gemfile.lock +0 -127
  47. data/gemfiles/3.1.gemfile +0 -9
  48. data/gemfiles/3.1.gemfile.lock +0 -149
  49. data/gemfiles/3.2.gemfile +0 -9
  50. data/gemfiles/3.2.gemfile.lock +0 -146
@@ -0,0 +1,580 @@
1
+ require 'acceptance_test_helper'
2
+
3
+ class ShouldaIntegratesWithRailsTest < AcceptanceTest
4
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
5
+ def setup
6
+ app.create
7
+
8
+ app.write_file 'db/migrate/1_create_users.rb', <<-FILE
9
+ class CreateUsers < #{app.migration_class_name}
10
+ def self.up
11
+ create_table :categories_users do |t|
12
+ t.integer :category_id
13
+ t.integer :user_id
14
+ end
15
+
16
+ create_table :categories do |t|
17
+ end
18
+
19
+ create_table :cities do |t|
20
+ end
21
+
22
+ create_table :lives do |t|
23
+ t.integer :user_id
24
+ end
25
+
26
+ create_table :issues do |t|
27
+ t.integer :user_id
28
+ end
29
+
30
+ create_table :users do |t|
31
+ t.integer :account_id
32
+ t.integer :city_id
33
+ t.string :email
34
+ t.integer :age
35
+ t.integer :status
36
+ t.string :aspects
37
+ end
38
+
39
+ add_index :users, :account_id
40
+ end
41
+ end
42
+ FILE
43
+
44
+ app.run_migrations!
45
+
46
+ app.write_file 'app/models/category.rb', <<-FILE
47
+ class Category < ActiveRecord::Base
48
+ end
49
+ FILE
50
+
51
+ app.write_file 'app/models/city.rb', <<-FILE
52
+ class City < ActiveRecord::Base
53
+ end
54
+ FILE
55
+
56
+ app.write_file 'app/models/issue.rb', <<-FILE
57
+ class Issue < ActiveRecord::Base
58
+ end
59
+ FILE
60
+
61
+ app.write_file 'app/models/life.rb', <<-FILE
62
+ class Life < ActiveRecord::Base
63
+ end
64
+ FILE
65
+
66
+ app.write_file 'app/models/person.rb', <<-FILE
67
+ class Person
68
+ # Note: All of these validations are listed in the same order as what's
69
+ # defined in the test (see below)
70
+
71
+ include ActiveModel::Model
72
+ include ActiveModel::SecurePassword
73
+
74
+ attr_accessor(
75
+ :age,
76
+ :card_number,
77
+ :email,
78
+ :foods,
79
+ :nothing,
80
+ :password_digest,
81
+ :some_other_attribute,
82
+ :some_other_attribute_confirmation,
83
+ :something,
84
+ :terms_of_service,
85
+ :workouts,
86
+ :some_other_attribute,
87
+ )
88
+
89
+ validate :email_looks_like_an_email
90
+
91
+ delegate :a_method, to: :some_delegate_object
92
+
93
+ has_secure_password
94
+
95
+ validates_absence_of :nothing
96
+ validates_acceptance_of :terms_of_service
97
+ validates_confirmation_of :password
98
+ validates_exclusion_of :workouts, in: ["biceps"]
99
+ validates_inclusion_of :foods, in: ["spaghetti"]
100
+ validates_length_of :card_number, maximum: 16
101
+ validates_numericality_of :age
102
+ validates_presence_of :something
103
+
104
+ def some_delegate_object
105
+ Object.new.instance_eval do
106
+ def a_method; end
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+ def email_looks_like_an_email
113
+ if email !~ /@/
114
+ errors.add :email, "invalid"
115
+ end
116
+ end
117
+ end
118
+ FILE
119
+
120
+ app.write_file 'app/models/user.rb', <<-FILE
121
+ class User < ActiveRecord::Base
122
+ # Note: All of these validations are listed in the same order as what's
123
+ # defined in the test (see below)
124
+
125
+ belongs_to :city
126
+ enum status: { inactive: 0, active: 1 }
127
+ attr_readonly :username
128
+ has_and_belongs_to_many :categories
129
+ has_many :issues
130
+ has_one :life
131
+ serialize :aspects
132
+ validates_uniqueness_of :email
133
+ accepts_nested_attributes_for :issues
134
+ end
135
+ FILE
136
+
137
+ app.write_file 'app/controllers/examples_controller.rb', <<-FILE
138
+ class ExamplesController < ApplicationController
139
+ # Note: All of these validations are listed in the same order as what's
140
+ # defined in the test (see below)
141
+
142
+ before_action :some_before_action
143
+ after_action :some_after_action
144
+ around_action :some_around_action
145
+
146
+ rescue_from ActiveRecord::RecordNotFound, with: :handle_not_found
147
+
148
+ layout "application"
149
+
150
+ def index
151
+ render :index
152
+ head :ok
153
+ end
154
+
155
+ def create
156
+ create_params
157
+ flash[:success] = "Example created"
158
+ session[:some_key] = "some value"
159
+ redirect_to action: :index
160
+ end
161
+
162
+ def handle_not_found
163
+ end
164
+
165
+ private
166
+
167
+ def some_before_action
168
+ end
169
+
170
+ def some_after_action
171
+ end
172
+
173
+ def some_around_action
174
+ yield
175
+ end
176
+
177
+ def create_params
178
+ params.require(:user).permit(:email, :password)
179
+ end
180
+ end
181
+ FILE
182
+
183
+ app.write_file 'app/views/examples/index.html.erb', <<-FILE
184
+ Some content here
185
+ FILE
186
+
187
+ app.write_file 'config/routes.rb', <<-FILE
188
+ Rails.application.routes.draw do
189
+ resources :examples, only: [:index, :create]
190
+ end
191
+ FILE
192
+ end
193
+
194
+ def test_succeeding_assertions_for_active_model
195
+ app.write_file 'test/models/person_test.rb', <<-FILE
196
+ require 'test_helper'
197
+
198
+ class PersonTest < ActiveSupport::TestCase
199
+ # Note: All of these matchers are listed in alphabetical order so we can
200
+ # compare with what is listed inside of the shoulda-matchers README
201
+
202
+ should allow_value("john@smith.com").for(:email)
203
+ should_not allow_value("john").for(:email)
204
+
205
+ should delegate_method(:a_method).to(:some_delegate_object)
206
+ should_not delegate_method(:some_other_method).to(:some_other_object)
207
+
208
+ should have_secure_password
209
+
210
+ should validate_absence_of(:nothing)
211
+ should_not validate_absence_of(:some_other_attribute)
212
+
213
+ should validate_acceptance_of(:terms_of_service)
214
+ should_not validate_acceptance_of(:some_other_attribute)
215
+
216
+ should validate_confirmation_of(:password)
217
+ should_not validate_confirmation_of(:some_other_attribute)
218
+
219
+ should validate_exclusion_of(:workouts).in_array(["biceps"])
220
+ should_not validate_exclusion_of(:some_other_attribute).
221
+ in_array(["whatever"])
222
+
223
+ should validate_inclusion_of(:foods).in_array(["spaghetti"])
224
+ should_not validate_inclusion_of(:some_other_attribute).
225
+ in_array(["whatever"])
226
+
227
+ should validate_length_of(:card_number).is_at_most(16)
228
+ should_not validate_length_of(:some_other_attribute).is_at_most(16)
229
+
230
+ should validate_numericality_of(:age)
231
+ should_not validate_numericality_of(:some_other_attribute)
232
+
233
+ should validate_presence_of(:something)
234
+ should_not validate_presence_of(:some_other_attribute)
235
+ end
236
+ FILE
237
+
238
+ result = app.run_n_unit_test_suite
239
+
240
+ assert_accepts indicate_that_tests_were_run(failures: 0), result
241
+ end
242
+
243
+ def test_succeeding_assertions_for_active_record
244
+ app.write_file 'test/models/user_test.rb', <<-FILE
245
+ require 'test_helper'
246
+
247
+ class UserTest < ActiveSupport::TestCase
248
+ # Note: All of these matchers are listed in alphabetical order so we can
249
+ # compare with what is listed inside of the shoulda-matchers README
250
+
251
+ should belong_to(:city)
252
+ should_not belong_to(:some_other_attribute)
253
+
254
+ should define_enum_for(:status).with_values(inactive: 0, active: 1)
255
+ should_not define_enum_for(:status).with_values(foo: "bar")
256
+
257
+ should have_db_column(:age)
258
+ should_not have_db_column(:some_other_attribute)
259
+
260
+ should have_db_index(:account_id)
261
+ should_not have_db_index(:some_other_attribute)
262
+
263
+ should have_readonly_attribute(:username)
264
+ should_not have_readonly_attribute(:some_other_attribute)
265
+
266
+ should have_and_belong_to_many(:categories)
267
+ should_not have_and_belong_to_many(:whatevers)
268
+
269
+ should have_many(:issues)
270
+ should_not have_many(:whatevers)
271
+
272
+ should have_one(:life)
273
+ should_not have_one(:whatever)
274
+
275
+ should serialize(:aspects)
276
+ should_not serialize(:age)
277
+
278
+ should validate_uniqueness_of(:email)
279
+ should_not validate_uniqueness_of(:some_other_attribute)
280
+
281
+ should accept_nested_attributes_for(:issues)
282
+ should_not accept_nested_attributes_for(:some_other_attribute)
283
+ end
284
+ FILE
285
+
286
+ result = app.run_n_unit_test_suite
287
+
288
+ assert_accepts indicate_that_tests_were_run(failures: 0), result
289
+ end
290
+
291
+ def test_succeeding_assertions_for_action_controller
292
+ app.write_file 'test/controllers/examples_controller_test.rb', <<-FILE
293
+ require 'test_helper'
294
+
295
+ class ExamplesControllerTest < ActionController::TestCase
296
+ context "GET #index" do
297
+ setup do
298
+ get :index
299
+ end
300
+
301
+ # Note: All of these matchers are listed in alphabetical order so we
302
+ # can compare with what is listed inside of the shoulda-matchers
303
+ # README
304
+
305
+ should use_before_action(:some_before_action)
306
+ should_not use_before_action(:some_other_before_action)
307
+ should use_after_action(:some_after_action)
308
+ should_not use_after_action(:some_other_after_action)
309
+ should use_around_action(:some_around_action)
310
+ should_not use_around_action(:some_other_around_action)
311
+
312
+ # This is one of the defaults for Rails
313
+ should filter_param(:password)
314
+ should_not filter_param(:some_other_param)
315
+
316
+ should rescue_from(ActiveRecord::RecordNotFound).
317
+ with(:handle_not_found)
318
+ should_not rescue_from(ActiveRecord::RecordNotFound).
319
+ with(:some_other_method)
320
+
321
+ should render_template(:index)
322
+ should_not render_template(:some_other_action)
323
+
324
+ should render_with_layout("application")
325
+ should_not render_with_layout("some_other_layout")
326
+
327
+ should respond_with(:ok)
328
+ should_not respond_with(:some_other_status)
329
+
330
+ should route(:get, "/examples").to(action: :index)
331
+ should_not route(:get, "/examples").to(action: :something_else)
332
+ end
333
+
334
+ context "POST #create" do
335
+ setup do
336
+ if ActionPack::VERSION::STRING.start_with?("4.")
337
+ post :create, {
338
+ user: {
339
+ email: "some@email.com",
340
+ password: "somepassword"
341
+ }
342
+ }
343
+ else
344
+ post :create, params: {
345
+ user: {
346
+ email: "some@email.com",
347
+ password: "somepassword"
348
+ }
349
+ }
350
+ end
351
+ end
352
+
353
+ should permit(:email, :password).
354
+ for(:create, params: {
355
+ user: {
356
+ email: "some@email.com",
357
+ password: "somepassword"
358
+ }
359
+ }).
360
+ on(:user)
361
+ should_not permit(:foo, :bar).
362
+ for(:create, params: {
363
+ user: {
364
+ email: "some@email.com",
365
+ password: "somepassword"
366
+ }
367
+ }).
368
+ on(:user)
369
+
370
+ should redirect_to("/examples")
371
+ should_not redirect_to("/something_else")
372
+
373
+ should set_flash[:success].to("Example created")
374
+ should_not set_flash[:success].to("Something else")
375
+
376
+ should set_session[:some_key].to("some value")
377
+ should_not set_session[:some_key].to("some other value")
378
+ end
379
+ end
380
+ FILE
381
+
382
+ result = app.run_n_unit_test_suite
383
+
384
+ assert_accepts indicate_that_tests_were_run(failures: 0), result
385
+ end
386
+
387
+ def test_failing_assertions_for_active_model
388
+ app.write_file 'test/models/person_test.rb', <<-FILE
389
+ require 'test_helper'
390
+
391
+ class PersonTest < ActiveSupport::TestCase
392
+ # Note: All of these matchers are listed in alphabetical order so we can
393
+ # compare with what is listed inside of the shoulda-matchers README
394
+
395
+ should_not allow_value("john@smith.com").for(:email)
396
+ should allow_value("john").for(:email)
397
+
398
+ # FIXME: See #1187 in shoulda-matchers
399
+ #should_not have_secure_password
400
+
401
+ should_not validate_absence_of(:nothing)
402
+ should validate_absence_of(:some_other_attribute)
403
+
404
+ should_not validate_acceptance_of(:terms_of_service)
405
+ should validate_acceptance_of(:some_other_attribute)
406
+
407
+ should_not validate_confirmation_of(:password)
408
+ should validate_confirmation_of(:some_other_attribute)
409
+
410
+ should_not validate_exclusion_of(:workouts).in_array(["biceps"])
411
+ should validate_exclusion_of(:some_other_attribute).
412
+ in_array(["whatever"])
413
+
414
+ should_not validate_inclusion_of(:foods).in_array(["spaghetti"])
415
+ should validate_inclusion_of(:some_other_attribute).
416
+ in_array(["whatever"])
417
+
418
+ should_not validate_length_of(:card_number).is_at_most(16)
419
+ should validate_length_of(:some_other_attribute).is_at_most(16)
420
+
421
+ should_not validate_numericality_of(:age)
422
+ should validate_numericality_of(:some_other_attribute)
423
+
424
+ should_not validate_presence_of(:something)
425
+ should validate_presence_of(:some_other_attribute)
426
+
427
+ should_not delegate_method(:a_method).to(:some_delegate_object)
428
+ should delegate_method(:some_other_method).to(:some_other_object)
429
+ end
430
+ FILE
431
+
432
+ result = app.run_n_unit_test_suite
433
+
434
+ assert_accepts indicate_that_tests_were_run(failures: 20), result
435
+ end
436
+
437
+ def test_failing_assertions_for_active_record
438
+ app.write_file 'test/models/user_test.rb', <<-FILE
439
+ require 'test_helper'
440
+
441
+ class UserTest < ActiveSupport::TestCase
442
+ # Note: All of these matchers are listed in alphabetical order so we can
443
+ # compare with what is listed inside of the shoulda-matchers README
444
+
445
+ should_not belong_to(:city)
446
+ should belong_to(:some_other_attribute)
447
+
448
+ should_not define_enum_for(:status).with_values(inactive: 0, active: 1)
449
+ should define_enum_for(:status).with_values(foo: "bar")
450
+
451
+ should_not have_db_column(:age)
452
+ should have_db_column(:some_other_attribute)
453
+
454
+ should_not have_db_index(:account_id)
455
+ should have_db_index(:some_other_attribute)
456
+
457
+ should_not have_readonly_attribute(:username)
458
+ should have_readonly_attribute(:some_other_attribute)
459
+
460
+ should_not have_and_belong_to_many(:categories)
461
+ should have_and_belong_to_many(:whatevers)
462
+
463
+ should_not have_many(:issues)
464
+ should have_many(:whatevers)
465
+
466
+ should_not have_one(:life)
467
+ should have_one(:whatever)
468
+
469
+ should_not serialize(:aspects)
470
+ should serialize(:age)
471
+
472
+ should_not validate_uniqueness_of(:email)
473
+ should validate_uniqueness_of(:some_other_attribute)
474
+
475
+ should_not accept_nested_attributes_for(:issues)
476
+ should accept_nested_attributes_for(:some_other_attribute)
477
+ end
478
+ FILE
479
+
480
+ result = app.run_n_unit_test_suite
481
+
482
+ assert_accepts indicate_that_tests_were_run(failures: 22), result
483
+ end
484
+
485
+ def test_failing_assertions_for_action_controller
486
+ app.write_file 'test/controllers/examples_controller_test.rb', <<-FILE
487
+ require 'test_helper'
488
+
489
+ class ExamplesControllerTest < ActionController::TestCase
490
+ context "GET #index" do
491
+ setup do
492
+ get :index
493
+ end
494
+
495
+ # Note: All of these matchers are listed in alphabetical order so we
496
+ # can compare with what is listed inside of the shoulda-matchers
497
+ # README
498
+
499
+ should_not use_before_action(:some_before_action)
500
+ should use_before_action(:some_other_before_action)
501
+ should_not use_after_action(:some_after_action)
502
+ should use_after_action(:some_other_after_action)
503
+ should_not use_around_action(:some_around_action)
504
+ should use_around_action(:some_other_around_action)
505
+
506
+ should_not filter_param(:password)
507
+ should filter_param(:some_other_param)
508
+
509
+ should_not rescue_from(ActiveRecord::RecordNotFound).
510
+ with(:handle_not_found)
511
+ should rescue_from(ActiveRecord::RecordNotFound).
512
+ with(:some_other_method)
513
+
514
+ should_not render_template(:index)
515
+ should render_template(:some_other_action)
516
+
517
+ should_not render_with_layout("application")
518
+ should render_with_layout("some_other_layout")
519
+
520
+ should_not respond_with(:ok)
521
+ should respond_with(:some_other_status)
522
+
523
+ should_not route(:get, "/examples").to(action: :index)
524
+ should route(:get, "/examples").to(action: :something_else)
525
+ end
526
+
527
+ context "POST #create" do
528
+ setup do
529
+ if ActionPack::VERSION::STRING.start_with?("4.")
530
+ post :create, {
531
+ user: {
532
+ email: "some@email.com",
533
+ password: "somepassword"
534
+ }
535
+ }
536
+ else
537
+ post :create, params: {
538
+ user: {
539
+ email: "some@email.com",
540
+ password: "somepassword"
541
+ }
542
+ }
543
+ end
544
+ end
545
+
546
+ should_not permit(:email, :password).
547
+ for(:create, params: {
548
+ user: {
549
+ email: "some@email.com",
550
+ password: "somepassword"
551
+ }
552
+ }).
553
+ on(:user)
554
+ should permit(:foo, :bar).
555
+ for(:create, params: {
556
+ user: {
557
+ email: "some@email.com",
558
+ password: "somepassword"
559
+ }
560
+ }).
561
+ on(:user)
562
+
563
+ should_not redirect_to("/examples")
564
+ should redirect_to("/something_else")
565
+
566
+ should_not set_flash[:success].to("Example created")
567
+ should set_flash[:success].to("Something else")
568
+
569
+ should_not set_session[:some_key].to("some value")
570
+ should set_session[:some_key].to("some other value")
571
+ end
572
+ end
573
+ FILE
574
+
575
+ result = app.run_n_unit_test_suite
576
+
577
+ assert_accepts indicate_that_tests_were_run(failures: 26), result
578
+ end
579
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
580
+ end