active_record_doctor 1.9.0 → 1.11.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +83 -19
  3. data/lib/active_record_doctor/config/default.rb +17 -0
  4. data/lib/active_record_doctor/detectors/base.rb +216 -56
  5. data/lib/active_record_doctor/detectors/extraneous_indexes.rb +38 -56
  6. data/lib/active_record_doctor/detectors/incorrect_boolean_presence_validation.rb +2 -6
  7. data/lib/active_record_doctor/detectors/incorrect_dependent_option.rb +88 -15
  8. data/lib/active_record_doctor/detectors/incorrect_length_validation.rb +60 -0
  9. data/lib/active_record_doctor/detectors/mismatched_foreign_key_type.rb +16 -9
  10. data/lib/active_record_doctor/detectors/missing_foreign_keys.rb +2 -4
  11. data/lib/active_record_doctor/detectors/missing_non_null_constraint.rb +14 -11
  12. data/lib/active_record_doctor/detectors/missing_presence_validation.rb +16 -10
  13. data/lib/active_record_doctor/detectors/missing_unique_indexes.rb +61 -17
  14. data/lib/active_record_doctor/detectors/short_primary_key_type.rb +6 -2
  15. data/lib/active_record_doctor/detectors/undefined_table_references.rb +2 -4
  16. data/lib/active_record_doctor/detectors/unindexed_deleted_at.rb +6 -15
  17. data/lib/active_record_doctor/detectors/unindexed_foreign_keys.rb +2 -4
  18. data/lib/active_record_doctor/logger/dummy.rb +11 -0
  19. data/lib/active_record_doctor/logger/hierarchical.rb +22 -0
  20. data/lib/active_record_doctor/logger.rb +6 -0
  21. data/lib/active_record_doctor/rake/task.rb +10 -1
  22. data/lib/active_record_doctor/runner.rb +8 -3
  23. data/lib/active_record_doctor/version.rb +1 -1
  24. data/lib/active_record_doctor.rb +4 -0
  25. data/lib/generators/active_record_doctor/add_indexes/add_indexes_generator.rb +5 -5
  26. data/test/active_record_doctor/detectors/disable_test.rb +30 -0
  27. data/test/active_record_doctor/detectors/extraneous_indexes_test.rb +34 -0
  28. data/test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb +7 -7
  29. data/test/active_record_doctor/detectors/incorrect_dependent_option_test.rb +220 -43
  30. data/test/active_record_doctor/detectors/incorrect_length_validation_test.rb +107 -0
  31. data/test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb +35 -1
  32. data/test/active_record_doctor/detectors/missing_non_null_constraint_test.rb +78 -21
  33. data/test/active_record_doctor/detectors/missing_presence_validation_test.rb +89 -25
  34. data/test/active_record_doctor/detectors/missing_unique_indexes_test.rb +179 -15
  35. data/test/active_record_doctor/detectors/short_primary_key_type_test.rb +27 -19
  36. data/test/active_record_doctor/detectors/undefined_table_references_test.rb +11 -13
  37. data/test/active_record_doctor/detectors/unindexed_deleted_at_test.rb +9 -3
  38. data/test/active_record_doctor/runner_test.rb +18 -19
  39. data/test/setup.rb +15 -7
  40. metadata +25 -5
  41. data/test/model_factory.rb +0 -128
@@ -3,30 +3,30 @@
3
3
  class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Test
4
4
  def test_invoking_no_callbacks_suggests_delete_all
5
5
  create_table(:companies) do
6
- end.create_model do
6
+ end.define_model do
7
7
  has_many :users, dependent: :destroy
8
8
  end
9
9
 
10
10
  create_table(:users) do |t|
11
11
  t.references :companies
12
- end.create_model do
12
+ end.define_model do
13
13
  belongs_to :company
14
14
  end
15
15
 
16
16
  assert_problems(<<~OUTPUT)
17
- use `dependent: :delete_all` or similar on ModelFactory::Models::Company.users - associated models have no validations and can be deleted in bulk
17
+ use `dependent: :delete_all` or similar on TransientRecord::Models::Company.users - associated model TransientRecord::Models::User has no callbacks and can be deleted in bulk
18
18
  OUTPUT
19
19
  end
20
20
 
21
21
  def test_invoking_callbacks_does_not_suggest_delete_all
22
22
  create_table(:companies) do
23
- end.create_model do
23
+ end.define_model do
24
24
  has_many :users, dependent: :destroy
25
25
  end
26
26
 
27
27
  create_table(:users) do |t|
28
28
  t.references :companies
29
- end.create_model do
29
+ end.define_model do
30
30
  belongs_to :company
31
31
 
32
32
  before_destroy :log
@@ -40,13 +40,13 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
40
40
 
41
41
  def test_skipping_callbacks_suggests_destroy
42
42
  create_table(:companies) do
43
- end.create_model do
43
+ end.define_model do
44
44
  has_many :users, dependent: :delete_all
45
45
  end
46
46
 
47
47
  create_table(:users) do |t|
48
48
  t.references :companies
49
- end.create_model do
49
+ end.define_model do
50
50
  belongs_to :company
51
51
 
52
52
  before_destroy :log
@@ -56,19 +56,19 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
56
56
  end
57
57
 
58
58
  assert_problems(<<~OUTPUT)
59
- use `dependent: :destroy` or similar on ModelFactory::Models::Company.users - the associated model has callbacks that are currently skipped
59
+ use `dependent: :destroy` or similar on TransientRecord::Models::Company.users - associated model TransientRecord::Models::User has callbacks that are currently skipped
60
60
  OUTPUT
61
61
  end
62
62
 
63
63
  def test_invoking_callbacks_does_not_suggest_destroy
64
64
  create_table(:companies) do
65
- end.create_model do
65
+ end.define_model do
66
66
  has_many :users, dependent: :destroy
67
67
  end
68
68
 
69
69
  create_table(:users) do |t|
70
70
  t.references :companies
71
- end.create_model do
71
+ end.define_model do
72
72
  belongs_to :company
73
73
 
74
74
  before_destroy :log
@@ -82,102 +82,102 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
82
82
 
83
83
  def test_works_on_has_one
84
84
  create_table(:companies) do
85
- end.create_model do
86
- has_one :owner, class_name: "ModelFactory::Models::User", dependent: :destroy
85
+ end.define_model do
86
+ has_one :owner, class_name: "TransientRecord::Models::User", dependent: :destroy
87
87
  end
88
88
 
89
89
  create_table(:users) do |t|
90
90
  t.references :companies
91
- end.create_model do
91
+ end.define_model do
92
92
  belongs_to :company
93
93
  end
94
94
 
95
95
  assert_problems(<<~OUTPUT)
96
- use `dependent: :delete` or similar on ModelFactory::Models::Company.owner - the associated model has no callbacks and can be deleted without loading
96
+ use `dependent: :delete` or similar on TransientRecord::Models::Company.owner - associated model TransientRecord::Models::User has no callbacks and can be deleted without loading
97
97
  OUTPUT
98
98
  end
99
99
 
100
100
  def test_works_on_belongs_to
101
101
  create_table(:companies) do
102
- end.create_model do
102
+ end.define_model do
103
103
  has_many :users
104
104
  end
105
105
 
106
106
  create_table(:users) do |t|
107
107
  t.references :company
108
- end.create_model do
108
+ end.define_model do
109
109
  belongs_to :company, dependent: :destroy
110
110
  end
111
111
 
112
112
  assert_problems(<<~OUTPUT)
113
- use `dependent: :delete` or similar on ModelFactory::Models::User.company - the associated model has no callbacks and can be deleted without loading
113
+ use `dependent: :delete` or similar on TransientRecord::Models::User.company - associated model TransientRecord::Models::Company has no callbacks and can be deleted without loading
114
114
  OUTPUT
115
115
  end
116
116
 
117
117
  def test_no_foreign_key_on_second_level_association
118
118
  create_table(:companies) do
119
- end.create_model do
119
+ end.define_model do
120
120
  has_many :users
121
121
  has_many :projects
122
122
  end
123
123
 
124
124
  create_table(:users) do |t|
125
125
  t.references :company
126
- end.create_model do
126
+ end.define_model do
127
127
  belongs_to :company, dependent: :destroy
128
128
  end
129
129
 
130
130
  create_table(:projects) do |t|
131
131
  t.references :company
132
- end.create_model do
132
+ end.define_model do
133
133
  belongs_to :company
134
134
  end
135
135
 
136
136
  assert_problems(<<~OUTPUT)
137
- use `dependent: :delete` or similar on ModelFactory::Models::User.company - the associated model has no callbacks and can be deleted without loading
137
+ use `dependent: :delete` or similar on TransientRecord::Models::User.company - associated model TransientRecord::Models::Company has no callbacks and can be deleted without loading
138
138
  OUTPUT
139
139
  end
140
140
 
141
141
  def test_nullify_foreign_key_on_second_level_association
142
142
  create_table(:companies) do
143
- end.create_model do
143
+ end.define_model do
144
144
  has_many :users
145
145
  has_many :projects
146
146
  end
147
147
 
148
148
  create_table(:users) do |t|
149
149
  t.references :company
150
- end.create_model do
150
+ end.define_model do
151
151
  belongs_to :company, dependent: :destroy
152
152
  end
153
153
 
154
154
  create_table(:projects) do |t|
155
155
  t.references :company, foreign_key: { on_delete: :nullify }
156
- end.create_model do
156
+ end.define_model do
157
157
  belongs_to :company
158
158
  end
159
159
 
160
160
  assert_problems(<<~OUTPUT)
161
- use `dependent: :delete` or similar on ModelFactory::Models::User.company - the associated model has no callbacks and can be deleted without loading
161
+ use `dependent: :delete` or similar on TransientRecord::Models::User.company - associated model TransientRecord::Models::Company has no callbacks and can be deleted without loading
162
162
  OUTPUT
163
163
  end
164
164
 
165
165
  def test_cascade_foreign_key_and_callbacks_on_second_level_association
166
166
  create_table(:companies) do
167
- end.create_model do
167
+ end.define_model do
168
168
  has_many :users
169
169
  has_many :projects
170
170
  end
171
171
 
172
172
  create_table(:users) do |t|
173
173
  t.references :company
174
- end.create_model do
174
+ end.define_model do
175
175
  belongs_to :company, dependent: :delete
176
176
  end
177
177
 
178
178
  create_table(:projects) do |t|
179
179
  t.references :company, foreign_key: { on_delete: :cascade }
180
- end.create_model do
180
+ end.define_model do
181
181
  belongs_to :company
182
182
 
183
183
  before_destroy :log
@@ -187,26 +187,26 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
187
187
  end
188
188
 
189
189
  assert_problems(<<~OUTPUT)
190
- use `dependent: :destroy` or similar on ModelFactory::Models::User.company - the associated model has callbacks that are currently skipped
190
+ use `dependent: :destroy` or similar on TransientRecord::Models::User.company - associated model TransientRecord::Models::Company has callbacks that are currently skipped
191
191
  OUTPUT
192
192
  end
193
193
 
194
194
  def test_cascade_foreign_key_and_no_callbacks_on_second_level_association
195
195
  create_table(:companies) do
196
- end.create_model do
196
+ end.define_model do
197
197
  has_many :users
198
198
  has_many :projects
199
199
  end
200
200
 
201
201
  create_table(:users) do |t|
202
202
  t.references :company
203
- end.create_model do
203
+ end.define_model do
204
204
  belongs_to :company, dependent: :delete
205
205
  end
206
206
 
207
207
  create_table(:projects) do |t|
208
208
  t.references :company, foreign_key: { on_delete: :cascade }
209
- end.create_model do
209
+ end.define_model do
210
210
  belongs_to :company
211
211
  end
212
212
 
@@ -215,35 +215,212 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
215
215
 
216
216
  def test_no_dependent_suggests_nothing
217
217
  create_table(:companies) do
218
- end.create_model do
218
+ end.define_model do
219
219
  has_many :users
220
220
  end
221
221
 
222
222
  create_table(:users) do |t|
223
223
  t.references :companies
224
- end.create_model do
224
+ end.define_model do
225
225
  belongs_to :company
226
226
  end
227
227
 
228
228
  refute_problems
229
229
  end
230
230
 
231
+ def test_polymorphic_destroy_reported_when_all_associations_deletable
232
+ create_table(:images) do |t|
233
+ t.bigint :imageable_id, null: false
234
+ t.string :imageable_type, null: true
235
+ end.define_model do
236
+ belongs_to :imageable, polymorphic: true, dependent: :destroy
237
+ end
238
+
239
+ create_table(:users) do
240
+ end.define_model do
241
+ has_one :image, as: :imageable
242
+ end
243
+
244
+ create_table(:companies) do
245
+ end.define_model do
246
+ has_one :image, as: :imageable
247
+ end
248
+
249
+ assert_problems(<<~OUTPUT)
250
+ use `dependent: :delete` or similar on TransientRecord::Models::Image.imageable - associated models TransientRecord::Models::Company, TransientRecord::Models::User have no callbacks and can be deleted without loading
251
+ OUTPUT
252
+ end
253
+
254
+ def test_polymorphic_destroy_not_reported_when_some_associations_not_deletable
255
+ create_table(:images) do |t|
256
+ t.bigint :imageable_id, null: false
257
+ t.string :imageable_type, null: true
258
+ end.define_model do
259
+ belongs_to :imageable, polymorphic: true, dependent: :destroy
260
+ end
261
+
262
+ create_table(:users) do
263
+ end.define_model do
264
+ has_one :image, as: :imageable
265
+
266
+ before_destroy :log
267
+
268
+ def log
269
+ end
270
+ end
271
+
272
+ create_table(:companies) do
273
+ end.define_model do
274
+ has_one :image, as: :imageable
275
+ end
276
+
277
+ refute_problems
278
+ end
279
+
280
+ def test_polymorphic_delete_reported_when_some_associations_not_deletable
281
+ create_table(:images) do |t|
282
+ t.bigint :imageable_id, null: false
283
+ t.string :imageable_type, null: true
284
+ end.define_model do
285
+ belongs_to :imageable, polymorphic: true, dependent: :delete
286
+ end
287
+
288
+ create_table(:users) do
289
+ end.define_model do
290
+ has_one :image, as: :imageable
291
+
292
+ before_destroy :log
293
+
294
+ def log
295
+ end
296
+ end
297
+
298
+ create_table(:companies) do
299
+ end.define_model do
300
+ has_one :image, as: :imageable
301
+ end
302
+
303
+ assert_problems(<<~OUTPUT)
304
+ use `dependent: :destroy` or similar on TransientRecord::Models::Image.imageable - associated model TransientRecord::Models::User has callbacks that are currently skipped
305
+ OUTPUT
306
+ end
307
+
308
+ def test_polymorphic_delete_not_reported_when_all_associations_deletable
309
+ create_table(:images) do |t|
310
+ t.bigint :imageable_id, null: false
311
+ t.string :imageable_type, null: true
312
+ end.define_model do
313
+ belongs_to :imageable, polymorphic: true, dependent: :delete
314
+ end
315
+
316
+ create_table(:users) do
317
+ end.define_model do
318
+ has_one :image, as: :imageable
319
+ end
320
+
321
+ create_table(:companies) do
322
+ end.define_model do
323
+ has_one :image, as: :imageable
324
+ end
325
+
326
+ refute_problems
327
+ end
328
+
329
+ def test_works_on_has_through_associations_with_destroy
330
+ create_table(:users) do
331
+ end.define_model do
332
+ has_many :posts
333
+ has_many :comments, through: :posts, dependent: :destroy
334
+ end
335
+
336
+ create_table(:posts) do |t|
337
+ t.references :users
338
+ end.define_model do
339
+ belongs_to :user
340
+ has_many :comments
341
+ end
342
+
343
+ create_table(:comments) do |t|
344
+ t.references :posts
345
+ end.define_model do
346
+ belongs_to :post
347
+ end
348
+
349
+ assert_problems(<<~OUTPUT)
350
+ use `dependent: :delete_all` or similar on TransientRecord::Models::User.comments - associated join model TransientRecord::Models::Post has no callbacks and can be deleted in bulk
351
+ OUTPUT
352
+ end
353
+
354
+ def test_works_on_has_through_associations_with_delete_all
355
+ create_table(:users) do
356
+ end.define_model do
357
+ has_many :posts
358
+ has_many :comments, through: :posts, dependent: :delete_all
359
+ end
360
+
361
+ create_table(:posts) do |t|
362
+ t.references :users
363
+ end.define_model do
364
+ belongs_to :user
365
+ has_many :comments
366
+
367
+ before_destroy :log
368
+
369
+ def log
370
+ end
371
+ end
372
+
373
+ create_table(:comments) do |t|
374
+ t.references :posts
375
+ end.define_model do
376
+ belongs_to :post
377
+ end
378
+
379
+ assert_problems(<<~OUTPUT)
380
+ use `dependent: :destroy` or similar on TransientRecord::Models::User.comments - associated join model TransientRecord::Models::Post has callbacks that are currently skipped
381
+ OUTPUT
382
+ end
383
+
384
+ def test_has_through_associations_when_join_model_incomplete
385
+ create_table(:users) do
386
+ end.define_model do
387
+ has_many :posts
388
+ has_many :comments, through: :posts
389
+ end
390
+
391
+ create_table(:posts) do |t|
392
+ t.references :users
393
+ end.define_model do
394
+ # The join model should define has_many :comments, but intentionally skips
395
+ # it for this test case's purpose.
396
+ end
397
+
398
+ create_table(:comments) do |t|
399
+ t.references :posts
400
+ end.define_model do
401
+ end
402
+
403
+ assert_problems(<<~OUTPUT)
404
+ ensure TransientRecord::Models::User.comments is configured correctly - TransientRecord::Models::Post.comments may be undefined
405
+ OUTPUT
406
+ end
407
+
231
408
  def test_config_ignore_models
232
409
  create_table(:companies) do
233
- end.create_model do
410
+ end.define_model do
234
411
  has_many :users, dependent: :destroy
235
412
  end
236
413
 
237
414
  create_table(:users) do |t|
238
415
  t.references :companies
239
- end.create_model do
416
+ end.define_model do
240
417
  belongs_to :company
241
418
  end
242
419
 
243
420
  config_file(<<-CONFIG)
244
421
  ActiveRecordDoctor.configure do |config|
245
422
  config.detector :incorrect_dependent_option,
246
- ignore_models: ["ModelFactory::Models::Company"]
423
+ ignore_models: ["TransientRecord::Models::Company"]
247
424
  end
248
425
  CONFIG
249
426
 
@@ -252,19 +429,19 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
252
429
 
253
430
  def test_global_ignore_models
254
431
  create_table(:companies) do
255
- end.create_model do
432
+ end.define_model do
256
433
  has_many :users, dependent: :destroy
257
434
  end
258
435
 
259
436
  create_table(:users) do |t|
260
437
  t.references :companies
261
- end.create_model do
438
+ end.define_model do
262
439
  belongs_to :company
263
440
  end
264
441
 
265
442
  config_file(<<-CONFIG)
266
443
  ActiveRecordDoctor.configure do |config|
267
- config.global :ignore_models, ["ModelFactory::Models::Company"]
444
+ config.global :ignore_models, ["TransientRecord::Models::Company"]
268
445
  end
269
446
  CONFIG
270
447
 
@@ -273,20 +450,20 @@ class ActiveRecordDoctor::Detectors::IncorrectDependentOptionTest < Minitest::Te
273
450
 
274
451
  def test_config_ignore_associations
275
452
  create_table(:companies) do
276
- end.create_model do
453
+ end.define_model do
277
454
  has_many :users, dependent: :destroy
278
455
  end
279
456
 
280
457
  create_table(:users) do |t|
281
458
  t.references :companies
282
- end.create_model do
459
+ end.define_model do
283
460
  belongs_to :company
284
461
  end
285
462
 
286
463
  config_file(<<-CONFIG)
287
464
  ActiveRecordDoctor.configure do |config|
288
465
  config.detector :incorrect_dependent_option,
289
- ignore_associations: ["ModelFactory::Models::Company.users"]
466
+ ignore_associations: ["TransientRecord::Models::Company.users"]
290
467
  end
291
468
  CONFIG
292
469
 
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ActiveRecordDoctor::Detectors::IncorrectLengthValidationTest < Minitest::Test
4
+ def test_validation_and_limit_equal_is_ok
5
+ create_table(:users) do |t|
6
+ t.string :email, limit: 64
7
+ t.string :name, limit: 32
8
+ end.define_model do
9
+ validates :email, length: { maximum: 64 }
10
+ validates :name, length: { maximum: 32 }
11
+ end
12
+
13
+ refute_problems
14
+ end
15
+
16
+ def test_validation_and_limit_different_is_error
17
+ create_table(:users) do |t|
18
+ t.string :email, limit: 64
19
+ end.define_model do
20
+ validates :email, length: { maximum: 32 }
21
+ end
22
+
23
+ assert_problems(<<~OUTPUT)
24
+ the schema limits users.email to 64 characters but the length validator on TransientRecord::Models::User.email enforces a maximum of 32 characters - set both limits to the same value or remove both
25
+ OUTPUT
26
+ end
27
+
28
+ def test_validation_and_no_limit_is_error
29
+ skip("MySQL always sets a limit on text columns") if mysql?
30
+
31
+ create_table(:users) do |t|
32
+ t.string :email
33
+ end.define_model do
34
+ validates :email, length: { maximum: 32 }
35
+ end
36
+
37
+ assert_problems(<<~OUTPUT)
38
+ the length validator on TransientRecord::Models::User.email enforces a maximum of 32 characters but there's no schema limit on users.email - remove the validator or the schema length limit
39
+ OUTPUT
40
+ end
41
+
42
+ def test_no_validation_and_limit_is_error
43
+ create_table(:users) do |t|
44
+ t.string :email, limit: 64
45
+ end.define_model do
46
+ end
47
+
48
+ assert_problems(<<~OUTPUT)
49
+ the schema limits users.email to 64 characters but there's no length validator on TransientRecord::Models::User.email - remove the database limit or add the validator
50
+ OUTPUT
51
+ end
52
+
53
+ def test_no_validation_and_no_limit_is_ok
54
+ skip("MySQL always sets a limit on text columns") if mysql?
55
+
56
+ create_table(:users) do |t|
57
+ t.string :email
58
+ end.define_model do
59
+ end
60
+
61
+ refute_problems
62
+ end
63
+
64
+ def test_config_ignore_models
65
+ create_table(:users) do |t|
66
+ t.string :email, limit: 64
67
+ end.define_model
68
+
69
+ config_file(<<-CONFIG)
70
+ ActiveRecordDoctor.configure do |config|
71
+ config.detector :incorrect_length_validation,
72
+ ignore_models: ["TransientRecord::Models::User"]
73
+ end
74
+ CONFIG
75
+
76
+ refute_problems
77
+ end
78
+
79
+ def test_global_ignore_models
80
+ create_table(:users) do |t|
81
+ t.string :email, limit: 64
82
+ end.define_model
83
+
84
+ config_file(<<-CONFIG)
85
+ ActiveRecordDoctor.configure do |config|
86
+ config.global :ignore_models, ["TransientRecord::Models::User"]
87
+ end
88
+ CONFIG
89
+
90
+ refute_problems
91
+ end
92
+
93
+ def test_config_ignore_attributes
94
+ create_table(:users) do |t|
95
+ t.string :email, limit: 64
96
+ end.define_model
97
+
98
+ config_file(<<-CONFIG)
99
+ ActiveRecordDoctor.configure do |config|
100
+ config.detector :incorrect_length_validation,
101
+ ignore_attributes: ["TransientRecord::Models::User.email"]
102
+ end
103
+ CONFIG
104
+
105
+ refute_problems
106
+ end
107
+ end
@@ -11,7 +11,7 @@ class ActiveRecordDoctor::Detectors::MismatchedForeignKeyTypeTest < Minitest::Te
11
11
  end
12
12
 
13
13
  assert_problems(<<~OUTPUT)
14
- users.company_id references a column of different type - foreign keys should be of the same type as the referenced column
14
+ users.company_id is a foreign key of type integer and references companies.id of type bigint - foreign keys should be of the same type as the referenced column
15
15
  OUTPUT
16
16
  end
17
17
 
@@ -24,6 +24,40 @@ class ActiveRecordDoctor::Detectors::MismatchedForeignKeyTypeTest < Minitest::Te
24
24
  refute_problems
25
25
  end
26
26
 
27
+ def test_mismatched_foreign_key_with_non_primary_key_type_is_reported
28
+ # MySQL does not allow foreign keys to have different type than paired primary keys
29
+ return if mysql?
30
+
31
+ create_table(:companies, id: :bigint) do |t|
32
+ t.string :code
33
+ t.index :code, unique: true
34
+ end
35
+ create_table(:users) do |t|
36
+ t.text :code
37
+ t.foreign_key :companies, table: :companies, column: :code, primary_key: :code
38
+ end
39
+
40
+ assert_problems(<<~OUTPUT)
41
+ users.code is a foreign key of type text and references companies.code of type character varying - foreign keys should be of the same type as the referenced column
42
+ OUTPUT
43
+ end
44
+
45
+ def test_matched_foreign_key_with_non_primary_key_type_is_not_reported
46
+ # MySQL does not allow foreign keys to have different type than paired primary keys
47
+ return if mysql?
48
+
49
+ create_table(:companies, id: :bigint) do |t|
50
+ t.string :code
51
+ t.index :code, unique: true
52
+ end
53
+ create_table(:users) do |t|
54
+ t.string :code
55
+ t.foreign_key :companies, table: :companies, column: :code, primary_key: :code
56
+ end
57
+
58
+ refute_problems
59
+ end
60
+
27
61
  def test_config_ignore_tables
28
62
  # MySQL does not allow foreign keys to have different type than paired primary keys
29
63
  return if mysql?