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
@@ -5,7 +5,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
5
5
  create_table(:users) do |t|
6
6
  t.string :email
7
7
  t.index :email
8
- end.create_model do
8
+ end.define_model do
9
9
  validates :email, uniqueness: true
10
10
  end
11
11
 
@@ -14,24 +14,70 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
14
14
  OUTPUT
15
15
  end
16
16
 
17
+ def test_missing_unique_index_on_functional_index
18
+ skip if !(ActiveRecord::VERSION::STRING >= "5.0" && postgresql?)
19
+
20
+ create_table(:users) do |t|
21
+ t.string :email
22
+ t.index "lower(email)"
23
+ end.define_model do
24
+ validates :email, uniqueness: true
25
+ end
26
+
27
+ # Running the detector should NOT raise an error when a functional index
28
+ # is present. No need to assert anything -- the test is successful if no
29
+ # exception was raised.
30
+ run_detector
31
+ end
32
+
33
+ def test_validates_multiple_attributes
34
+ create_table(:users) do |t|
35
+ t.string :email
36
+ t.string :ref_token
37
+ end.define_model do
38
+ validates :email, :ref_token, uniqueness: true
39
+ end
40
+
41
+ assert_problems(<<~OUTPUT)
42
+ add a unique index on users(email) - validating uniqueness in the model without an index can lead to duplicates
43
+ add a unique index on users(ref_token) - validating uniqueness in the model without an index can lead to duplicates
44
+ OUTPUT
45
+ end
46
+
17
47
  def test_present_unique_index
18
48
  create_table(:users) do |t|
19
49
  t.string :email
20
50
  t.index :email, unique: true
21
- end.create_model do
51
+ end.define_model do
22
52
  validates :email, uniqueness: true
23
53
  end
24
54
 
25
55
  refute_problems
26
56
  end
27
57
 
28
- def test_missing_unique_index_with_scope
58
+ def test_present_partial_unique_index
59
+ skip("MySQL doesn't support partial indexes") if mysql?
60
+
61
+ create_table(:users) do |t|
62
+ t.string :email
63
+ t.boolean :active
64
+ t.index :email, unique: true, where: "active"
65
+ end.define_model do
66
+ validates :email, uniqueness: true
67
+ end
68
+
69
+ assert_problems(<<~OUTPUT)
70
+ add a unique index on users(email) - validating uniqueness in the model without an index can lead to duplicates
71
+ OUTPUT
72
+ end
73
+
74
+ def test_unique_index_with_extra_columns_with_scope
29
75
  create_table(:users) do |t|
30
76
  t.string :email
31
77
  t.integer :company_id
32
78
  t.integer :department_id
33
79
  t.index [:company_id, :department_id, :email]
34
- end.create_model do
80
+ end.define_model do
35
81
  validates :email, uniqueness: { scope: [:company_id, :department_id] }
36
82
  end
37
83
 
@@ -40,26 +86,93 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
40
86
  OUTPUT
41
87
  end
42
88
 
43
- def test_present_unique_index_with_scope
89
+ def test_unique_index_with_exact_columns_with_scope
44
90
  create_table(:users) do |t|
45
91
  t.string :email
46
92
  t.integer :company_id
47
93
  t.integer :department_id
48
94
  t.index [:company_id, :department_id, :email], unique: true
49
- end.create_model do
95
+ end.define_model do
50
96
  validates :email, uniqueness: { scope: [:company_id, :department_id] }
51
97
  end
52
98
 
53
99
  refute_problems
54
100
  end
55
101
 
102
+ def test_unique_index_with_fewer_columns_with_scope
103
+ create_table(:users) do |t|
104
+ t.string :email
105
+ t.integer :company_id
106
+ t.integer :department_id
107
+ t.index [:company_id, :department_id], unique: true
108
+ end.define_model do
109
+ validates :email, uniqueness: { scope: [:company_id, :department_id] }
110
+ end
111
+
112
+ refute_problems
113
+ end
114
+
115
+ def test_missing_unique_index_with_association_attribute
116
+ create_table(:users) do |t|
117
+ t.integer :account_id
118
+ end.define_model do
119
+ belongs_to :account
120
+ validates :account, uniqueness: true
121
+ end
122
+
123
+ assert_problems(<<~OUTPUT)
124
+ add a unique index on users(account_id) - validating uniqueness in the model without an index can lead to duplicates
125
+ OUTPUT
126
+ end
127
+
128
+ def test_present_unique_index_with_association_attribute
129
+ create_table(:users) do |t|
130
+ t.integer :account_id
131
+ t.index :account_id, unique: true
132
+ end.define_model do
133
+ belongs_to :account
134
+ validates :account, uniqueness: true
135
+ end
136
+
137
+ refute_problems
138
+ end
139
+
140
+ def test_missing_unique_index_with_association_scope
141
+ create_table(:comments) do |t|
142
+ t.string :title
143
+ t.integer :commentable_id
144
+ t.string :commentable_type
145
+ end.define_model do
146
+ belongs_to :commentable, polymorphic: true
147
+ validates :title, uniqueness: { scope: :commentable }
148
+ end
149
+
150
+ assert_problems(<<~OUTPUT)
151
+ add a unique index on comments(commentable_type, commentable_id, title) - validating uniqueness in the model without an index can lead to duplicates
152
+ OUTPUT
153
+ end
154
+
155
+ def test_present_unique_index_with_association_scope
156
+ create_table(:comments) do |t|
157
+ t.string :title
158
+ t.integer :commentable_id
159
+ t.string :commentable_type
160
+ t.index [:commentable_id, :commentable_type, :title], unique: true
161
+ end.define_model do
162
+ belongs_to :commentable, polymorphic: true
163
+ validates :title, uniqueness: { scope: :commentable }
164
+ end
165
+
166
+ refute_problems
167
+ end
168
+
56
169
  def test_column_order_is_ignored
57
170
  create_table(:users) do |t|
58
171
  t.string :email
59
172
  t.integer :organization_id
60
173
 
61
174
  t.index [:email, :organization_id], unique: true
62
- end.create_model do
175
+ end.define_model do
63
176
  validates :email, uniqueness: { scope: :organization_id }
64
177
  end
65
178
 
@@ -86,24 +199,75 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
86
199
  create_table(:users) do |t|
87
200
  t.string :email
88
201
  t.index :email
89
- end.create_model do
202
+ end.define_model do
90
203
  validates_with DummyValidator
91
204
  end
92
205
 
93
206
  refute_problems
94
207
  end
95
208
 
209
+ def test_has_one_without_index
210
+ create_table(:users)
211
+ .define_model do
212
+ has_one :account, class_name: "TransientRecord::Models::Account"
213
+ has_one :account_history, through: :account, class_name: "TransientRecord::Models::Account"
214
+ end
215
+
216
+ create_table(:accounts) do |t|
217
+ t.integer :user_id
218
+ end.define_model do
219
+ has_one :account_history, class_name: "TransientRecord::Models::AccountHistory"
220
+ end
221
+
222
+ create_table(:account_histories) do |t|
223
+ t.integer :account_id
224
+ end.define_model do
225
+ belongs_to :account, class_name: "TransientRecord::Models::Account"
226
+ end
227
+
228
+ assert_problems(<<~OUTPUT)
229
+ add a unique index on accounts(user_id) - using `has_one` in the TransientRecord::Models::User model without an index can lead to duplicates
230
+ add a unique index on account_histories(account_id) - using `has_one` in the TransientRecord::Models::Account model without an index can lead to duplicates
231
+ OUTPUT
232
+ end
233
+
234
+ def test_has_one_with_scope_and_without_index
235
+ create_table(:users)
236
+ .define_model do
237
+ has_one :last_comment, -> { order(created_at: :desc) }, class_name: "TransientRecord::Models::Comment"
238
+ end
239
+
240
+ create_table(:comments) do |t|
241
+ t.integer :user_id
242
+ end.define_model
243
+
244
+ refute_problems
245
+ end
246
+
247
+ def test_has_one_with_index
248
+ create_table(:users)
249
+ .define_model do
250
+ has_one :account, class_name: "TransientRecord::Models::Account"
251
+ end
252
+
253
+ create_table(:accounts) do |t|
254
+ t.integer :user_id, index: { unique: true }
255
+ end.define_model
256
+
257
+ refute_problems
258
+ end
259
+
96
260
  def test_config_ignore_models
97
261
  create_table(:users) do |t|
98
262
  t.string :email
99
- end.create_model do
263
+ end.define_model do
100
264
  validates :email, uniqueness: true
101
265
  end
102
266
 
103
267
  config_file(<<-CONFIG)
104
268
  ActiveRecordDoctor.configure do |config|
105
269
  config.detector :missing_unique_indexes,
106
- ignore_models: ["ModelFactory::Models::User"]
270
+ ignore_models: ["TransientRecord::Models::User"]
107
271
  end
108
272
  CONFIG
109
273
 
@@ -113,13 +277,13 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
113
277
  def test_global_ignore_models
114
278
  create_table(:users) do |t|
115
279
  t.string :email
116
- end.create_model do
280
+ end.define_model do
117
281
  validates :email, uniqueness: true
118
282
  end
119
283
 
120
284
  config_file(<<-CONFIG)
121
285
  ActiveRecordDoctor.configure do |config|
122
- config.global :ignore_models, ["ModelFactory::Models::User"]
286
+ config.global :ignore_models, ["TransientRecord::Models::User"]
123
287
  end
124
288
  CONFIG
125
289
 
@@ -130,14 +294,14 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
130
294
  create_table(:users) do |t|
131
295
  t.string :email
132
296
  t.integer :role
133
- end.create_model do
297
+ end.define_model do
134
298
  validates :email, :role, uniqueness: { scope: :organization_id }
135
299
  end
136
300
 
137
301
  config_file(<<-CONFIG)
138
302
  ActiveRecordDoctor.configure do |config|
139
303
  config.detector :missing_unique_indexes,
140
- ignore_columns: ["ModelFactory::Models::User(organization_id, email, role)"]
304
+ ignore_columns: ["TransientRecord::Models::User(organization_id, email)", "TransientRecord::Models::User(organization_id, role)"]
141
305
  end
142
306
  CONFIG
143
307
 
@@ -154,7 +318,7 @@ class ActiveRecordDoctor::Detectors::MissingUniqueIndexesTest < Minitest::Test
154
318
  def assert_skipped(options)
155
319
  create_table(:users) do |t|
156
320
  t.string :email
157
- end.create_model do
321
+ end.define_model do
158
322
  validates :email, uniqueness: options
159
323
  end
160
324
 
@@ -1,32 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ActiveRecordDoctor::Detectors::ShortPrimaryKeyTypeTest < Minitest::Test
4
+ def setup
5
+ @connection = ActiveRecord::Base.connection
6
+ @connection.enable_extension("uuid-ossp") if postgresql?
7
+ super
8
+ end
9
+
10
+ def teardown
11
+ @connection.disable_extension("uuid-ossp") if postgresql?
12
+ super
13
+ end
14
+
4
15
  def test_short_integer_primary_key_is_reported
5
- if mysql?
6
- create_table(:companies, id: :int)
7
-
8
- assert_problems(<<~OUTPUT)
9
- change the type of companies.id to bigint
10
- OUTPUT
11
- elsif postgresql?
12
- create_table(:companies, id: :integer)
13
-
14
- assert_problems(<<~OUTPUT)
15
- change the type of companies.id to bigint
16
- OUTPUT
16
+ create_table(:companies, id: :int)
17
+
18
+ # In Rails 4.2 and MySQL primary key is not created due to a bug
19
+ if mysql? && ActiveRecord::VERSION::STRING < "5.0"
20
+ @connection.execute("ALTER TABLE companies ADD PRIMARY KEY(id)")
17
21
  end
22
+
23
+ assert_problems(<<~OUTPUT)
24
+ change the type of companies.id to bigint
25
+ OUTPUT
18
26
  end
19
27
 
20
28
  def test_long_integer_primary_key_is_not_reported
21
- if mysql?
22
- create_table(:companies, id: :bigint)
29
+ create_table(:companies, id: :bigint)
30
+ refute_problems
31
+ end
23
32
 
24
- refute_problems
25
- elsif postgresql?
26
- create_table(:companies, id: :bigserial)
33
+ def test_uuid_primary_key_is_not_reported
34
+ skip unless postgresql?
27
35
 
28
- refute_problems
29
- end
36
+ create_table(:companies, id: :uuid)
37
+ refute_problems
30
38
  end
31
39
 
32
40
  def test_no_primary_key_is_not_reported
@@ -3,17 +3,17 @@
3
3
  class ActiveRecordDoctor::Detectors::UndefinedTableReferencesTest < Minitest::Test
4
4
  def test_model_backed_by_table
5
5
  create_table(:users) do
6
- end.create_model do
6
+ end.define_model do
7
7
  end
8
8
 
9
9
  refute_problems
10
10
  end
11
11
 
12
12
  def test_model_backed_by_non_existent_table
13
- create_model(:User)
13
+ define_model(:User)
14
14
 
15
15
  assert_problems(<<~OUTPUT)
16
- ModelFactory::Models::User references a non-existent table or view named users
16
+ TransientRecord::Models::User references a non-existent table or view named users
17
17
  OUTPUT
18
18
  end
19
19
 
@@ -21,22 +21,20 @@ class ActiveRecordDoctor::Detectors::UndefinedTableReferencesTest < Minitest::Te
21
21
  # We replace the underlying table with a view. The view doesn't have to be
22
22
  # backed by an actual table - it can simply return a predefined tuple.
23
23
  ActiveRecord::Base.connection.execute("CREATE VIEW users AS SELECT 1")
24
- create_model(:User)
24
+ define_model(:User)
25
25
 
26
- begin
27
- refute_problems
28
- ensure
29
- ActiveRecord::Base.connection.execute("DROP VIEW users")
30
- end
26
+ refute_problems
27
+ ensure
28
+ ActiveRecord::Base.connection.execute("DROP VIEW users")
31
29
  end
32
30
 
33
31
  def test_config_ignore_tables
34
- create_model(:User)
32
+ define_model(:User)
35
33
 
36
34
  config_file(<<-CONFIG)
37
35
  ActiveRecordDoctor.configure do |config|
38
36
  config.detector :undefined_table_references,
39
- ignore_models: ["ModelFactory::Models::User"]
37
+ ignore_models: ["TransientRecord::Models::User"]
40
38
  end
41
39
  CONFIG
42
40
 
@@ -44,11 +42,11 @@ class ActiveRecordDoctor::Detectors::UndefinedTableReferencesTest < Minitest::Te
44
42
  end
45
43
 
46
44
  def test_global_ignore_tables
47
- create_model(:User)
45
+ define_model(:User)
48
46
 
49
47
  config_file(<<-CONFIG)
50
48
  ActiveRecordDoctor.configure do |config|
51
- config.global :ignore_models, ["ModelFactory::Models::User"]
49
+ config.global :ignore_models, ["TransientRecord::Models::User"]
52
50
  end
53
51
  CONFIG
54
52
 
@@ -11,6 +11,9 @@ class ActiveRecordDoctor::Detectors::UnindexedDeletedAtTest < Minitest::Test
11
11
  t.index [:first_name, :last_name],
12
12
  name: "index_profiles_on_first_name_and_last_name",
13
13
  where: "deleted_at IS NULL"
14
+ t.index [:last_name],
15
+ name: "index_deleted_profiles_on_last_name",
16
+ where: "deleted_at IS NOT NULL"
14
17
  end
15
18
 
16
19
  refute_problems
@@ -28,7 +31,7 @@ class ActiveRecordDoctor::Detectors::UnindexedDeletedAtTest < Minitest::Test
28
31
  end
29
32
 
30
33
  assert_problems(<<~OUTPUT)
31
- consider adding `WHERE deleted_at IS NULL` to index_profiles_on_first_name_and_last_name - a partial index can speed lookups of soft-deletable models
34
+ consider adding `WHERE deleted_at IS NULL` or `WHERE deleted_at IS NOT NULL` to index_profiles_on_first_name_and_last_name - a partial index can speed lookups of soft-deletable models
32
35
  OUTPUT
33
36
  end
34
37
 
@@ -42,6 +45,9 @@ class ActiveRecordDoctor::Detectors::UnindexedDeletedAtTest < Minitest::Test
42
45
  t.index [:first_name, :last_name],
43
46
  name: "index_profiles_on_first_name_and_last_name",
44
47
  where: "discarded_at IS NULL"
48
+ t.index [:last_name],
49
+ name: "index_discarded_profiles_on_last_name",
50
+ where: "discarded_at IS NOT NULL"
45
51
  end
46
52
 
47
53
  refute_problems
@@ -59,7 +65,7 @@ class ActiveRecordDoctor::Detectors::UnindexedDeletedAtTest < Minitest::Test
59
65
  end
60
66
 
61
67
  assert_problems(<<~OUTPUT)
62
- consider adding `WHERE discarded_at IS NULL` to index_profiles_on_first_name_and_last_name - a partial index can speed lookups of soft-deletable models
68
+ consider adding `WHERE discarded_at IS NULL` or `WHERE discarded_at IS NOT NULL` to index_profiles_on_first_name_and_last_name - a partial index can speed lookups of soft-deletable models
63
69
  OUTPUT
64
70
  end
65
71
 
@@ -165,7 +171,7 @@ class ActiveRecordDoctor::Detectors::UnindexedDeletedAtTest < Minitest::Test
165
171
  CONFIG
166
172
 
167
173
  assert_problems(<<~OUTPUT)
168
- consider adding `WHERE obliverated_at IS NULL` to index_profiles_on_first_name_and_last_name - a partial index can speed lookups of soft-deletable models
174
+ consider adding `WHERE obliverated_at IS NULL` or `WHERE obliverated_at IS NOT NULL` to index_profiles_on_first_name_and_last_name - a partial index can speed lookups of soft-deletable models
169
175
  OUTPUT
170
176
  end
171
177
  end
@@ -1,42 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ActiveRecordDoctor::RunnerTest < Minitest::Test
4
- def test_run_one_raises_on_unknown_detectors
5
- io = StringIO.new
6
- runner = ActiveRecordDoctor::Runner.new(load_config, io)
4
+ def setup
5
+ @io = StringIO.new
6
+ @runner = ActiveRecordDoctor::Runner.new(
7
+ config: load_config,
8
+ logger: ActiveRecordDoctor::Logger::Dummy.new,
9
+ io: @io
10
+ )
11
+ end
7
12
 
13
+ def test_run_one_raises_on_unknown_detectors
8
14
  assert_raises(KeyError) do
9
- runner.run_one(:performance_issues)
15
+ @runner.run_one(:performance_issues)
10
16
  end
11
17
  end
12
18
 
13
19
  def test_run_all_returns_true_when_no_errors
14
- io = StringIO.new
15
- runner = ActiveRecordDoctor::Runner.new(load_config, io)
16
-
17
- assert(runner.run_all)
18
- assert(io.string.blank?)
20
+ assert(@runner.run_all)
21
+ assert(@io.string.blank?)
19
22
  end
20
23
 
21
24
  def test_run_all_returns_false_when_errors
22
25
  # Create a model without its underlying table to trigger an error.
23
- create_model(:User)
24
-
25
- io = StringIO.new
26
- runner = ActiveRecordDoctor::Runner.new(load_config, io)
26
+ define_model(:User)
27
27
 
28
- refute(runner.run_all)
29
- refute(io.string.blank?)
28
+ refute(@runner.run_all)
29
+ refute(@io.string.blank?)
30
30
  end
31
31
 
32
32
  def test_help_prints_help
33
33
  ActiveRecordDoctor.detectors.each do |name, _|
34
- io = StringIO.new
35
- runner = ActiveRecordDoctor::Runner.new(load_config, io)
34
+ @io.truncate(0)
36
35
 
37
- runner.help(name)
36
+ @runner.help(name)
38
37
 
39
- refute(io.string.blank?, "expected help for #{name}")
38
+ refute(@io.string.blank?, "expected help for #{name}")
40
39
  end
41
40
  end
42
41
  end
data/test/setup.rb CHANGED
@@ -33,7 +33,7 @@ require "active_record_doctor"
33
33
  require "minitest"
34
34
  require "minitest/autorun"
35
35
  require "minitest/fork_executor"
36
- require_relative "model_factory"
36
+ require "transient_record"
37
37
 
38
38
  # Filter out Minitest backtrace while allowing backtrace from other libraries
39
39
  # to be shown.
@@ -44,11 +44,11 @@ Minitest.parallel_executor = Minitest::ForkExecutor.new
44
44
 
45
45
  # Prepare the test class.
46
46
  class Minitest::Test
47
- include ModelFactory
47
+ include TransientRecord
48
48
 
49
49
  def setup
50
50
  # Delete remnants (models and tables) of previous test case runs.
51
- cleanup_models
51
+ TransientRecord.cleanup
52
52
  end
53
53
 
54
54
  def teardown
@@ -61,7 +61,7 @@ class Minitest::Test
61
61
 
62
62
  # Ensure all remnants of previous test runs, most likely in form of tables,
63
63
  # are removed.
64
- cleanup_models
64
+ TransientRecord.cleanup
65
65
  end
66
66
 
67
67
  private
@@ -93,7 +93,11 @@ class Minitest::Test
93
93
 
94
94
  def run_detector
95
95
  io = StringIO.new
96
- runner = ActiveRecordDoctor::Runner.new(load_config, io)
96
+ runner = ActiveRecordDoctor::Runner.new(
97
+ config: load_config,
98
+ logger: ActiveRecordDoctor::Logger::Dummy.new,
99
+ io: io
100
+ )
97
101
  success = runner.run_one(detector_name)
98
102
  [success, io.string]
99
103
  end
@@ -104,13 +108,17 @@ class Minitest::Test
104
108
 
105
109
  def assert_problems(expected_output)
106
110
  success, output = run_detector
107
- assert_equal(expected_output, output)
111
+ assert_equal(sort_lines(expected_output), sort_lines(output))
108
112
  refute(success, "Expected the detector to return failure.")
109
113
  end
110
114
 
111
115
  def refute_problems(expected_output = "")
112
116
  success, output = run_detector
113
- assert_equal(expected_output, output)
117
+ assert_equal(sort_lines(expected_output), sort_lines(output))
114
118
  assert(success, "Expected the detector to return success.")
115
119
  end
120
+
121
+ def sort_lines(string)
122
+ string.split("\n").sort
123
+ end
116
124
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_doctor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Navis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-03 00:00:00.000000000 Z
11
+ date: 2023-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: 12.3.3
97
+ - !ruby/object:Gem::Dependency
98
+ name: transient_record
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 1.0.0.rc1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 1.0.0.rc1
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: rubocop
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -126,6 +140,7 @@ files:
126
140
  - lib/active_record_doctor/detectors/extraneous_indexes.rb
127
141
  - lib/active_record_doctor/detectors/incorrect_boolean_presence_validation.rb
128
142
  - lib/active_record_doctor/detectors/incorrect_dependent_option.rb
143
+ - lib/active_record_doctor/detectors/incorrect_length_validation.rb
129
144
  - lib/active_record_doctor/detectors/mismatched_foreign_key_type.rb
130
145
  - lib/active_record_doctor/detectors/missing_foreign_keys.rb
131
146
  - lib/active_record_doctor/detectors/missing_non_null_constraint.rb
@@ -137,6 +152,9 @@ files:
137
152
  - lib/active_record_doctor/detectors/unindexed_foreign_keys.rb
138
153
  - lib/active_record_doctor/errors.rb
139
154
  - lib/active_record_doctor/help.rb
155
+ - lib/active_record_doctor/logger.rb
156
+ - lib/active_record_doctor/logger/dummy.rb
157
+ - lib/active_record_doctor/logger/hierarchical.rb
140
158
  - lib/active_record_doctor/printers.rb
141
159
  - lib/active_record_doctor/railtie.rb
142
160
  - lib/active_record_doctor/rake/task.rb
@@ -147,9 +165,11 @@ files:
147
165
  - lib/tasks/active_record_doctor.rake
148
166
  - test/active_record_doctor/config/loader_test.rb
149
167
  - test/active_record_doctor/config_test.rb
168
+ - test/active_record_doctor/detectors/disable_test.rb
150
169
  - test/active_record_doctor/detectors/extraneous_indexes_test.rb
151
170
  - test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb
152
171
  - test/active_record_doctor/detectors/incorrect_dependent_option_test.rb
172
+ - test/active_record_doctor/detectors/incorrect_length_validation_test.rb
153
173
  - test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb
154
174
  - test/active_record_doctor/detectors/missing_foreign_keys_test.rb
155
175
  - test/active_record_doctor/detectors/missing_non_null_constraint_test.rb
@@ -161,7 +181,6 @@ files:
161
181
  - test/active_record_doctor/detectors/unindexed_foreign_keys_test.rb
162
182
  - test/active_record_doctor/runner_test.rb
163
183
  - test/generators/active_record_doctor/add_indexes/add_indexes_generator_test.rb
164
- - test/model_factory.rb
165
184
  - test/setup.rb
166
185
  homepage: https://github.com/gregnavis/active_record_doctor
167
186
  licenses:
@@ -182,16 +201,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
201
  - !ruby/object:Gem::Version
183
202
  version: '0'
184
203
  requirements: []
185
- rubygems_version: 3.2.32
204
+ rubygems_version: 3.2.33
186
205
  signing_key:
187
206
  specification_version: 4
188
207
  summary: Identify database issues before they hit production.
189
208
  test_files:
190
209
  - test/active_record_doctor/config/loader_test.rb
191
210
  - test/active_record_doctor/config_test.rb
211
+ - test/active_record_doctor/detectors/disable_test.rb
192
212
  - test/active_record_doctor/detectors/extraneous_indexes_test.rb
193
213
  - test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb
194
214
  - test/active_record_doctor/detectors/incorrect_dependent_option_test.rb
215
+ - test/active_record_doctor/detectors/incorrect_length_validation_test.rb
195
216
  - test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb
196
217
  - test/active_record_doctor/detectors/missing_foreign_keys_test.rb
197
218
  - test/active_record_doctor/detectors/missing_non_null_constraint_test.rb
@@ -203,5 +224,4 @@ test_files:
203
224
  - test/active_record_doctor/detectors/unindexed_foreign_keys_test.rb
204
225
  - test/active_record_doctor/runner_test.rb
205
226
  - test/generators/active_record_doctor/add_indexes/add_indexes_generator_test.rb
206
- - test/model_factory.rb
207
227
  - test/setup.rb