active_record_doctor 1.11.0 → 1.13.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -14
  3. data/lib/active_record_doctor/config/loader.rb +1 -1
  4. data/lib/active_record_doctor/detectors/base.rb +30 -15
  5. data/lib/active_record_doctor/detectors/extraneous_indexes.rb +14 -9
  6. data/lib/active_record_doctor/detectors/incorrect_boolean_presence_validation.rb +1 -1
  7. data/lib/active_record_doctor/detectors/incorrect_dependent_option.rb +44 -31
  8. data/lib/active_record_doctor/detectors/mismatched_foreign_key_type.rb +1 -1
  9. data/lib/active_record_doctor/detectors/missing_non_null_constraint.rb +2 -2
  10. data/lib/active_record_doctor/detectors/missing_unique_indexes.rb +73 -23
  11. data/lib/active_record_doctor/detectors/short_primary_key_type.rb +3 -3
  12. data/lib/active_record_doctor/detectors/unindexed_foreign_keys.rb +34 -7
  13. data/lib/active_record_doctor/logger/hierarchical.rb +1 -1
  14. data/lib/active_record_doctor/railtie.rb +1 -1
  15. data/lib/active_record_doctor/runner.rb +1 -1
  16. data/lib/active_record_doctor/utils.rb +21 -0
  17. data/lib/active_record_doctor/version.rb +1 -1
  18. data/lib/active_record_doctor.rb +2 -0
  19. data/lib/generators/active_record_doctor/add_indexes/add_indexes_generator.rb +14 -14
  20. data/lib/tasks/active_record_doctor.rake +2 -2
  21. metadata +11 -47
  22. data/test/active_record_doctor/config/loader_test.rb +0 -120
  23. data/test/active_record_doctor/config_test.rb +0 -116
  24. data/test/active_record_doctor/detectors/disable_test.rb +0 -30
  25. data/test/active_record_doctor/detectors/extraneous_indexes_test.rb +0 -224
  26. data/test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb +0 -79
  27. data/test/active_record_doctor/detectors/incorrect_dependent_option_test.rb +0 -472
  28. data/test/active_record_doctor/detectors/incorrect_length_validation_test.rb +0 -107
  29. data/test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb +0 -116
  30. data/test/active_record_doctor/detectors/missing_foreign_keys_test.rb +0 -70
  31. data/test/active_record_doctor/detectors/missing_non_null_constraint_test.rb +0 -273
  32. data/test/active_record_doctor/detectors/missing_presence_validation_test.rb +0 -232
  33. data/test/active_record_doctor/detectors/missing_unique_indexes_test.rb +0 -327
  34. data/test/active_record_doctor/detectors/short_primary_key_type_test.rb +0 -72
  35. data/test/active_record_doctor/detectors/undefined_table_references_test.rb +0 -55
  36. data/test/active_record_doctor/detectors/unindexed_deleted_at_test.rb +0 -177
  37. data/test/active_record_doctor/detectors/unindexed_foreign_keys_test.rb +0 -78
  38. data/test/active_record_doctor/runner_test.rb +0 -41
  39. data/test/generators/active_record_doctor/add_indexes/add_indexes_generator_test.rb +0 -131
  40. data/test/setup.rb +0 -124
@@ -1,224 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class ActiveRecordDoctor::Detectors::ExtraneousIndexesTest < Minitest::Test
4
- def test_index_on_primary_key_is_duplicate
5
- create_table(:users) do |t|
6
- t.index :id
7
- end
8
-
9
- assert_problems(<<OUTPUT)
10
- remove index_users_on_id - coincides with the primary key on the table
11
- OUTPUT
12
- end
13
-
14
- def test_partial_index_on_primary_key
15
- skip("MySQL doesn't support partial indexes") if mysql?
16
-
17
- create_table(:users) do |t|
18
- t.boolean :admin
19
- t.index :id, where: "admin"
20
- end
21
-
22
- refute_problems
23
- end
24
-
25
- def test_index_on_non_standard_primary_key
26
- create_table(:profiles, primary_key: :user_id) do |t|
27
- t.index :user_id
28
- end
29
-
30
- assert_problems(<<OUTPUT)
31
- remove index_profiles_on_user_id - coincides with the primary key on the table
32
- OUTPUT
33
- end
34
-
35
- def test_non_unique_version_of_index_is_duplicate
36
- create_table(:users) do |t|
37
- t.string :email
38
- t.index :email, unique: true, name: "unique_index_on_users_email"
39
- end
40
-
41
- # Rails 4.2 compatibility - can't be pulled into the block above.
42
- ActiveRecord::Base.connection.add_index :users, :email, name: "index_users_on_email"
43
-
44
- assert_problems(<<OUTPUT)
45
- remove index_users_on_email - can be replaced by unique_index_on_users_email
46
- OUTPUT
47
- end
48
-
49
- def test_single_column_covered_by_unique_and_non_unique_multi_column_is_duplicate
50
- create_table(:users) do |t|
51
- t.string :first_name
52
- t.string :last_name
53
- t.string :email
54
- t.index [:last_name, :first_name, :email]
55
- t.index [:last_name, :first_name],
56
- unique: true,
57
- name: "unique_index_on_users_last_name_and_first_name"
58
- t.index :last_name
59
- end
60
-
61
- assert_problems(<<OUTPUT)
62
- remove index_users_on_last_name - can be replaced by index_users_on_last_name_and_first_name_and_email or unique_index_on_users_last_name_and_first_name
63
- OUTPUT
64
- end
65
-
66
- def test_multi_column_covered_by_unique_and_non_unique_multi_column_is_duplicate
67
- create_table(:users) do |t|
68
- t.string :first_name
69
- t.string :last_name
70
- t.string :email
71
- t.index [:last_name, :first_name, :email]
72
- t.index [:last_name, :first_name],
73
- unique: true,
74
- name: "unique_index_on_users_last_name_and_first_name"
75
- end
76
-
77
- # Rails 4.2 compatibility - can't be pulled into the block above.
78
- ActiveRecord::Base.connection.add_index :users, [:last_name, :first_name]
79
-
80
- assert_problems(<<OUTPUT)
81
- remove index_users_on_last_name_and_first_name - can be replaced by index_users_on_last_name_and_first_name_and_email or unique_index_on_users_last_name_and_first_name
82
- OUTPUT
83
- end
84
-
85
- def test_unique_index_with_fewer_columns
86
- create_table(:users) do |t|
87
- t.string :first_name
88
- t.string :last_name
89
- t.index :first_name, unique: true
90
- t.index [:last_name, :first_name], unique: true
91
- end
92
-
93
- assert_problems(<<OUTPUT)
94
- remove index_users_on_last_name_and_first_name - can be replaced by index_users_on_first_name
95
- OUTPUT
96
- end
97
-
98
- def test_not_covered_by_different_index_type
99
- create_table(:users) do |t|
100
- t.string :first_name
101
- t.string :last_name
102
- t.index [:last_name, :first_name], using: :btree
103
-
104
- if mysql?
105
- t.index :last_name, type: :fulltext
106
- else
107
- t.index :last_name, using: :hash
108
- end
109
- end
110
-
111
- refute_problems
112
- end
113
-
114
- def test_not_covered_by_partial_index
115
- skip("MySQL doesn't support partial indexes") if mysql?
116
-
117
- create_table(:users) do |t|
118
- t.string :first_name
119
- t.string :last_name
120
- t.boolean :active
121
- t.index [:last_name, :first_name], where: "active"
122
- t.index :last_name
123
- end
124
-
125
- refute_problems
126
- end
127
-
128
- def test_not_covered_with_different_opclasses
129
- skip("ActiveRecord < 5.2 doesn't support operator classes") if ActiveRecord::VERSION::STRING < "5.2"
130
- skip("MySQL doesn't support operator classes") if mysql?
131
-
132
- create_table(:users) do |t|
133
- t.string :first_name
134
- t.string :last_name
135
- t.index [:last_name, :first_name], opclass: :varchar_pattern_ops
136
- t.index :last_name
137
- end
138
-
139
- refute_problems
140
- end
141
-
142
- def test_config_ignore_tables
143
- # The detector recognizes two kinds of errors and both must take
144
- # ignore_tables into account. We trigger those errors by indexing the
145
- # primary key (the first extraneous index) and then indexing email twice
146
- # (index2... is the other extraneous index).
147
- create_table(:users) do |t|
148
- t.index :id
149
- t.string :email
150
-
151
- t.index :email, name: "index1_on_users_email"
152
- t.index :email, name: "index2_on_users_email"
153
- end
154
-
155
- config_file(<<-CONFIG)
156
- ActiveRecordDoctor.configure do |config|
157
- config.detector :extraneous_indexes,
158
- ignore_tables: ["users"]
159
- end
160
- CONFIG
161
-
162
- refute_problems
163
- end
164
-
165
- def test_config_global_ignore_tables
166
- create_table(:users) do |t|
167
- t.index :id
168
- t.string :email
169
-
170
- t.index :email, name: "index1_on_users_email"
171
- t.index :email, name: "index2_on_users_email"
172
- end
173
-
174
- config_file(<<-CONFIG)
175
- ActiveRecordDoctor.configure do |config|
176
- config.global :ignore_tables, ["users"]
177
- end
178
- CONFIG
179
-
180
- refute_problems
181
- end
182
-
183
- def test_config_global_ignore_indexes
184
- create_table(:users) do |t|
185
- t.index :id
186
- t.string :email
187
-
188
- t.index :email, name: "index1_on_users_email"
189
- t.index :email, name: "index2_on_users_email"
190
- end
191
-
192
- config_file(<<-CONFIG)
193
- ActiveRecordDoctor.configure do |config|
194
- config.global :ignore_indexes, [
195
- "index1_on_users_email",
196
- "index2_on_users_email",
197
- "index_users_on_id",
198
- ]
199
- end
200
- CONFIG
201
-
202
- refute_problems
203
- end
204
-
205
- def test_config_detector_ignore_indexes
206
- create_table(:users) do |t|
207
- t.index :id
208
- t.string :email
209
- t.string :api_key
210
-
211
- t.index :email, name: "index_on_users_email"
212
- t.index [:email, :api_key], name: "index_on_users_email_and_api_key"
213
- end
214
-
215
- config_file(<<-CONFIG)
216
- ActiveRecordDoctor.configure do |config|
217
- config.detector :extraneous_indexes,
218
- ignore_indexes: ["index_users_on_id", "index_on_users_email"]
219
- end
220
- CONFIG
221
-
222
- refute_problems
223
- end
224
- end
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class ActiveRecordDoctor::Detectors::IncorrectBooleanPresenceValidationTest < Minitest::Test
4
- def test_presence_true_is_reported_on_boolean_only
5
- create_table(:users) do |t|
6
- t.string :email, null: false
7
- t.boolean :active, null: false
8
- end.define_model do
9
- # email is a non-boolean column whose presence CAN be validated in the
10
- # usual way. We include it in the test model to ensure the detector reports
11
- # only boolean columns.
12
- validates :email, :active, presence: true
13
- end
14
-
15
- assert_problems(<<~OUTPUT)
16
- replace the `presence` validator on TransientRecord::Models::User.active with `inclusion` - `presence` can't be used on booleans
17
- OUTPUT
18
- end
19
-
20
- def test_inclusion_is_not_reported
21
- create_table(:users) do |t|
22
- t.boolean :active, null: false
23
- end.define_model do
24
- validates :active, inclusion: { in: [true, false] }
25
- end
26
-
27
- refute_problems
28
- end
29
-
30
- def test_models_with_non_existent_tables_are_skipped
31
- define_model(:User)
32
-
33
- refute_problems
34
- end
35
-
36
- def test_config_ignore_models
37
- create_table(:users) do |t|
38
- t.string :email, null: false
39
- end.define_model
40
-
41
- config_file(<<-CONFIG)
42
- ActiveRecordDoctor.configure do |config|
43
- config.detector :incorrect_boolean_presence_validation,
44
- ignore_models: ["ModelFactory.User"]
45
- end
46
- CONFIG
47
-
48
- refute_problems
49
- end
50
-
51
- def test_global_ignore_models
52
- create_table(:users) do |t|
53
- t.string :email, null: false
54
- end.define_model
55
-
56
- config_file(<<-CONFIG)
57
- ActiveRecordDoctor.configure do |config|
58
- config.global :ignore_models, ["ModelFactory.User"]
59
- end
60
- CONFIG
61
-
62
- refute_problems
63
- end
64
-
65
- def test_config_ignore_attributes
66
- create_table(:users) do |t|
67
- t.string :email, null: false
68
- end.define_model
69
-
70
- config_file(<<-CONFIG)
71
- ActiveRecordDoctor.configure do |config|
72
- config.detector :incorrect_boolean_presence_validation,
73
- ignore_attributes: ["ModelFactory.User.email"]
74
- end
75
- CONFIG
76
-
77
- refute_problems
78
- end
79
- end