minitest-sequel 0.2.0 → 0.3.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.
@@ -0,0 +1,69 @@
1
+ require "minitest/sequel"
2
+
3
+ # reopening to add helpers functionality
4
+ class Minitest::Spec
5
+
6
+ # Enables quick tests to ensure that the basic CRUD functionality is working correctly for a Model
7
+ #
8
+ # let(:m) { User.make }
9
+ #
10
+ # ensure_working_CRUD(User, :username)
11
+ #
12
+ # NOTE!
13
+ #
14
+ # * the passed `_model` argument must be the actual Model class and NOT a string or symbol
15
+ # * the passed attribute `_attr` must be a String attribute or the tests will fail
16
+ #
17
+ # **DEPENDENCIES**
18
+ #
19
+ # this test depends upon being able to create a new model instance for each test via using
20
+ # Sequel Factory's `#make()` method
21
+ #
22
+ def self.ensure_working_CRUD(model, attr)
23
+
24
+ describe "a valid CRUD model" do
25
+
26
+ it "can create a #{model}" do
27
+ m = model.send(:make)
28
+ assert_instance_of(_model, m, "CRUD:create - expected #{m.class} to be an instance of #{model}")
29
+ assert_empty(m.errors, "CRUD:create - expected .errors to be empty, but was: [#{m.errors.inspect}]")
30
+ end
31
+
32
+ it "can read a #{model}" do
33
+ m = model.send(:make)
34
+ res = model.send :first
35
+ assert_instance_of(model, m, "CRUD:read - expected #{res.class} to be an instance of #{model}")
36
+ assert_equal(m, res, "CRUD:read - expected [#{m.inspect}] to equal [#{res.inspect}]")
37
+ end
38
+
39
+ it "can update a #{model}" do
40
+ m = model.send(:make)
41
+ tmp_str = "#{m.send(attr.to_sym)} Updated"
42
+ res = model.send(:first)
43
+
44
+ assert_equal(m, res, "CRUD:update - expected [#{m.inspect}] to equal [#{res.inspect}]")
45
+ res.send("#{attr}=", tmp_str)
46
+ res.save
47
+
48
+ res2 = model.send(:first)
49
+ assert_equal(tmp_str, res2.send(attr.to_sym), "CRUD:update - expected [#{res2.send(attr.to_sym)}] to equal the updated string: [#{tmp_str}]")
50
+ end
51
+
52
+ it "can destroy a #{model}" do
53
+ m = model.send(:make)
54
+ if m.respond_to?(:deleted_at)
55
+ assert_nil(m.deleted_at, "CRUD:delete - expected m.deleted_at to be nil, but was [#{m.deleted_at}]")
56
+ end
57
+ assert(m.destroy, "CRUD:delete - expected m.destroy to return true")
58
+ res = model.send(:first)
59
+ assert_nil(res, "CRUD:delete - expected #{model}.first to return nil, but was: [#{res.inspect}]")
60
+ if m.respond_to?(:deleted_at)
61
+ refute_nil(m.deleted_at, "CRUD:delete - expected m.deleted_at to be NOT be nil")
62
+ assert_instance_of(Time, m.deleted_at, "CRUD:delete - expected m.deleted_at to be an instance of Time")
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,166 @@
1
+ require "minitest/sequel"
2
+
3
+ # reopening to add validations functionality
4
+ module Minitest::Assertions
5
+
6
+ # Test if a model instance is timestamped via .plugin(:timestamps)
7
+ #
8
+ # let(:m) { Post.create(title: "Dummy") }
9
+ # proc { assert_timestamped_model_instance(m) }.wont_have_error
10
+ #
11
+ # You can also test if an updated record is correctly timestamped
12
+ #
13
+ # m.title = "Updated"
14
+ # m.save
15
+ # proc { assert_timestamped_model_instance(m, updated_record: true) }.wont_have_error
16
+ #
17
+ # Or alternatively test if an updated record is wrongly timestamped
18
+ #
19
+ # let(:m) { Post.create(title: "Dummy", updated_at: Time.now) }
20
+ # proc { assert_timestamped_model_instance(m, updated_record: false) }.must_have_error(/expected #.updated_at to be NIL on new record/)
21
+ #
22
+ #
23
+ def assert_timestamped_model_instance(model, opts = {})
24
+ model_class = model.class
25
+ # 1. test for Timestamps plugin
26
+ plugs = model_class.instance_variable_get("@plugins").map(&:to_s)
27
+ if plugs.include?("Sequel::Plugins::Timestamps")
28
+ # 2. test for created_at / :updated_at columns
29
+ assert_have_column(model, :created_at, {}, "AssertTimestampedModelInstance - expected model to have column :created_at, Debug: [#{model.inspect}]")
30
+ assert_have_column(model, :updated_at, {}, "AssertTimestampedModelInstance - expected model to have column :updated_at, Debug: [#{model.inspect}]")
31
+
32
+ if opts[:updated_record]
33
+ # 4. updated record
34
+ assert_instance_of(Time, model.created_at, "AssertTimestampedModelInstance:created_at - expected #created_at to be an instance of Time on updated record")
35
+ assert_instance_of(Time, model.updated_at, "AssertTimestampedModelInstance:updated_at - expected #updated_at to be an instance of Time on updated record")
36
+ else
37
+ # 3. initial record
38
+ assert_instance_of(Time, model.created_at, "AssertTimestampedModelInstance:created_at - expected #created_at to be an instance of Time on new record")
39
+ proc {
40
+ assert_nil(model.updated_at, "AssertTimestampedModelInstance:updated - expected #updated_at to be NIL on new record")
41
+ }.wont_have_error
42
+ end
43
+ else
44
+ raise(Minitest::Assertion, "Not a plugin(:timestamps) model, available plugins are: #{plugs.inspect}")
45
+ end
46
+ end
47
+
48
+ # Test if a model class is timestamped with .plugin(:timestamps)
49
+ #
50
+ # # Declared locally in the Model
51
+ # class Comment < Sequel::Model
52
+ # plugin(:timestamps)
53
+ # end
54
+ # proc { assert_timestamped_model(Comment) }.wont_have_error
55
+ #
56
+ # # on a non-timestamped model
57
+ # class Post < Sequel::Model; end
58
+ # proc { assert_timestamped_model(Post) }.must_have_error(/Not a \.plugin\(:timestamps\) model, available plugins are/)
59
+ #
60
+ #
61
+ # NOTE!
62
+ #
63
+ # You can also pass attributes to the created model in the tests via the `opts` hash like this:
64
+ #
65
+ # proc { assert_timestamped_model(Comment, {body: "I think...", email: "e@email.com"}) }.wont_have_error
66
+ #
67
+ #
68
+ def assert_timestamped_model(model, opts = {})
69
+ m = model.create(opts)
70
+ # 1. test for Timestamps plugin
71
+ plugs = model.instance_variable_get("@plugins").map(&:to_s)
72
+ if plugs.include?("Sequel::Plugins::Timestamps")
73
+ # 2. test for created_at / :updated_at columns
74
+ assert_have_column(m, :created_at, {}, "AssertTimestampedModel - expected model to have column :created_at. Debug: [#{m.inspect}]")
75
+ assert_have_column(m, :updated_at, {}, "AssertTimestampedModel - expected model to have column :updated_at. Debug: [#{m.inspect}]")
76
+
77
+ # 3. initial record
78
+ assert_instance_of(Time, m.created_at, "AssertTimestampedModel:created_at - expected #created_at to be an instance of Time on new record. Debug: [#{m.inspect}]")
79
+ assert_instance_of(NilClass, m.updated_at, "AssertTimestampedModel:updated_at - expected #updated_at to be an instance of NilClass on new record. Debug: [#{m.inspect}]")
80
+
81
+ # 4. updated record
82
+ # old_ts = m.created_at
83
+ # sleep 1 # TODO: could this be converted to timecop or similar?
84
+ m.title = "#{m.title} updated"
85
+ assert(m.save, "AssertTimestampedModel:#save - updated model failed. Debug: [#{m.inspect}]")
86
+ assert_instance_of(Time, m.created_at, "AssertTimestampedModel:created_at - expected #created_at to be an instance of Time on updated record. Debug: [#{m.inspect}]")
87
+ assert_instance_of(Time, m.updated_at, "AssertTimestampedModel:updated_at - expected #updated_at to be an instance of Time on updated record. Debug: [#{m.inspect}]")
88
+ # assert_equal(old_ts, m.created_at, "AssertTimestampedModel - expected the :created_at timestamp to be unchanged")
89
+ else
90
+ raise(Minitest::Assertion, "Not a plugin(:timestamps) model, available plugins are: #{plugs.inspect}")
91
+ end
92
+ end
93
+
94
+ # Test if a model class is paranoid with .plugin(:paranoid) via [Sequel-Paranoid](https://github.com/sdepold/sequel-paranoid)
95
+ #
96
+ # # Declared locally in the Model
97
+ # class Comment < Sequel::Model
98
+ # plugin(:paranoid)
99
+ # end
100
+ # proc { assert_paranoid_model(Comment) }.wont_have_error
101
+ #
102
+ # # on a non-paranoid model
103
+ # class Post < Sequel::Model; end
104
+ # proc { assert_paranoid_model(Post) }.must_have_error(/Not a plugin\(:paranoid\) model, available plugins are/)
105
+ #
106
+ #
107
+ # NOTE!
108
+ #
109
+ # You can also pass attributes to the created model in the tests via the `opts` hash like this:
110
+ #
111
+ # proc { assert_timestamped_model(Comment, {body: "I think...", email: "e@email.com"}) }.wont_have_error
112
+ #
113
+ #
114
+ def assert_paranoid_model(model, opts = {})
115
+ m = model.create(opts)
116
+ # 1. test for Paranoid plugin
117
+ plugs = model.instance_variable_get("@plugins").map(&:to_s)
118
+ if plugs.include?("Sequel::Plugins::Paranoid")
119
+ assert_nil(m.deleted_at, "AssertParanoidModel:deleted_at - expected #deleted_at to be NIL on new model")
120
+ # after update
121
+ assert(m.save, "AssertParanoidModel:save - updated model failed. Debug: [#{m.inspect}]")
122
+ assert_nil(m.deleted_at, "AssertParanoidModel:deleted_at - expected #deleted_at to be NIL on updated model")
123
+ # after destroy
124
+ assert(m.destroy, "AssertParanoidModel:destroy - destroy model failed. Debug: [#{m.inspect}]")
125
+ assert_instance_of(Time, m.deleted_at, "AssertParanoidModel:deleted_at - expected #deleted_at to be instance of Time on destroyed model, Debug: [#{m.inspect}]")
126
+ else
127
+ raise(Minitest::Assertion, "Not a plugin(:paranoid) model, available plugins are: #{plugs.inspect}")
128
+ end
129
+ end
130
+
131
+
132
+
133
+ # Test to ensure the current model is NOT a :timestamped model
134
+ #
135
+ # it { refute_timestamped_model(Post) }
136
+ #
137
+ def refute_timestamped_model(model, opts = {})
138
+ plugs = model.instance_variable_get("@plugins").map(&:to_s)
139
+ refute_includes(plugs, "Sequel::Plugins::Timestamps", "RefuteTimestampedModel - expected #{model} to NOT be a :timestamped model, but it was, Debug: [#{plugs.inspect}]")
140
+ end
141
+
142
+ # Test to ensure the current model is NOT a :paranoid model
143
+ #
144
+ # it { refute_paranoid_model(Post) }
145
+ #
146
+ def refute_paranoid_model(model)
147
+ plugs = model.instance_variable_get("@plugins").map(&:to_s)
148
+ refute_includes(plugs, "Sequel::Plugins::Paranoid", "RefuteParanoidModel - expected #{model} to NOT be a :paranoid model, but it was, Debug: [#{plugs.inspect}]")
149
+ end
150
+
151
+
152
+ end
153
+
154
+
155
+ # add support for Spec syntax
156
+ module Minitest::Expectations
157
+
158
+ infect_an_assertion :assert_timestamped_model, :must_be_timestamped_model, :reverse
159
+ infect_an_assertion :assert_paranoid_model, :must_be_paranoid_model, :reverse
160
+ infect_an_assertion :assert_paranoid_model, :must_be_a_paranoid_model, :reverse
161
+
162
+ infect_an_assertion :refute_timestamped_model, :wont_be_timestamped_model, :reverse
163
+ infect_an_assertion :refute_timestamped_model, :wont_be_a_timestamped_model, :reverse
164
+ infect_an_assertion :refute_paranoid_model, :wont_be_paranoid_model, :reverse
165
+ infect_an_assertion :refute_paranoid_model, :wont_be_a_paranoid_model, :reverse
166
+ end
@@ -1,212 +1,212 @@
1
- require 'minitest/sequel'
1
+ require "minitest/sequel"
2
2
 
3
3
  # reopening to add validations functionality
4
4
  module Minitest::Assertions
5
-
5
+
6
6
  # Test for validating presence of a model attribute
7
- #
7
+ #
8
8
  # it { assert_validates_presence(model, :title) }
9
9
  # it { model.must_validate_presence_of(:title, { message: '...' }) }
10
- #
10
+ #
11
11
  def assert_validates_presence(obj, attribute, opts = {}, msg = nil)
12
12
  assert_validates(obj, :presence, attribute, opts, msg)
13
13
  end
14
14
  alias_method :assert_validates_presence_of, :assert_validates_presence
15
-
15
+
16
16
  # Test for validating the length of a model's attribute.
17
- #
17
+ #
18
18
  # Available options:
19
- #
19
+ #
20
20
  # * :message - The message to use (no default, overrides :nil_message, :too_long, :too_short, and :wrong_length options if present)
21
21
  # * :nil_message - The message to use use if :maximum option is used and the value is nil (default: 'is not present')
22
- #
22
+ #
23
23
  # * :too_long - The message to use use if it the value is too long (default: 'is too long')
24
- #
24
+ #
25
25
  # * :too_short - The message to use use if it the value is too short (default: 'is too short')
26
- #
26
+ #
27
27
  # * :wrong_length - The message to use use if it the value is not valid (default: 'is the wrong length')
28
- #
28
+ #
29
29
  # Size related options:
30
- #
30
+ #
31
31
  # * :is - The exact size required for the value to be valid (no default)
32
- #
32
+ #
33
33
  # * :minimum - The minimum size allowed for the value (no default)
34
- #
34
+ #
35
35
  # * :maximum - The maximum size allowed for the value (no default)
36
36
  #
37
37
  # * :within - The array/range that must include the size of the value for it to be valid (no default)
38
- #
39
- #
38
+ #
39
+ #
40
40
  # it { assert_validates_length(model, :title, { maximum: 12 }) }
41
41
  # it { model.must_validate_length_of(:title, { within: 4..12 }) }
42
- #
42
+ #
43
43
  def assert_validates_length(obj, attribute, opts = {}, msg = nil)
44
44
  assert_validates(obj, :length, attribute, opts, msg)
45
45
  end
46
46
  alias_method :assert_validates_length_of, :assert_validates_length
47
-
47
+
48
48
  # Test for validating the exact length of a model's attribute.
49
- #
49
+ #
50
50
  # it { assert_validates_exact_length(model, :title, 12, { message: '...' }) }
51
51
  # it { model.must_validate_exact_length_of(:title, 12, { message: '...' }) }
52
- #
52
+ #
53
53
  def assert_validates_exact_length(obj, attribute, exact_length, opts = {}, msg = nil)
54
- opts.merge!({ is: exact_length })
54
+ opts.merge!(is: exact_length)
55
55
  assert_validates(obj, :length, attribute, opts, msg)
56
56
  end
57
57
  alias_method :assert_validates_exact_length_of, :assert_validates_exact_length
58
-
58
+
59
59
  # Test for validating the exact length of a model's attribute.
60
- #
60
+ #
61
61
  # it { assert_validates_length_range(model, :title, 4..12, { message: '...' }) }
62
62
  # it { model.must_validate_length_range_of(:title, 4..12, { message: '...' }) }
63
- #
63
+ #
64
64
  def assert_validates_length_range(obj, attribute, range, opts = {}, msg = nil)
65
- opts.merge!({ within: range })
65
+ opts.merge!(within: range)
66
66
  assert_validates(obj, :length, attribute, opts, msg)
67
67
  end
68
68
  alias_method :assert_validates_length_range_of, :assert_validates_length_range
69
-
69
+
70
70
  # Test for validating the maximum length of a model's attribute.
71
- #
71
+ #
72
72
  # it { assert_validates_max_length(model, :title, 12, { message: '...' }) }
73
73
  # it { model.must_validate_max_length_of(:title, 12, { message: '...' }) }
74
- #
74
+ #
75
75
  def assert_validates_max_length(obj, attribute, max_length, opts = {}, msg = nil)
76
- opts.merge!({ maximum: max_length })
76
+ opts.merge!(maximum: max_length)
77
77
  assert_validates(obj, :length, attribute, opts, msg)
78
78
  end
79
79
  alias_method :assert_validates_max_length_of, :assert_validates_max_length
80
80
 
81
81
  # Test for validating the minimum length of a model's attribute.
82
- #
82
+ #
83
83
  # it { assert_validates_min_length(model, :title, 12, { message: '...' }) }
84
84
  # it { model.must_validate_min_length_of(:title, 12, { message: '...' }) }
85
- #
85
+ #
86
86
  def assert_validates_min_length(obj, attribute, min_length, opts = {}, msg = nil)
87
- opts.merge!({ minimum: min_length })
87
+ opts.merge!(minimum: min_length)
88
88
  assert_validates(obj, :length, attribute, opts, msg)
89
89
  end
90
90
  alias_method :assert_validates_min_length_of, :assert_validates_min_length
91
-
91
+
92
92
  # Test for validating the format of a model's attribute with a regexp.
93
- #
93
+ #
94
94
  # it { assert_validates_format(model, :title, 12, { with: /[a-z+]/ }) }
95
95
  # it { model.must_validate_format_of(:title, 12, { with: /[a-z]+/ }) }
96
- #
96
+ #
97
97
  def assert_validates_format(obj, attribute, opts = {}, msg = nil)
98
98
  assert_validates(obj, :format, attribute, opts, msg)
99
99
  end
100
100
  alias_method :assert_validates_format_of, :assert_validates_format
101
-
101
+
102
102
  # Test for validating that a model's attribute is within a specified range or set of values.
103
- #
103
+ #
104
104
  # it { assert_validates_inclusion(model, :status, { in: [:a, :b, :c] }) }
105
105
  # it { model.must_validate_inclusion_of(:status, { in: [:a, :b, :c] }) }
106
- #
106
+ #
107
107
  def assert_validates_inclusion(obj, attribute, opts = {}, msg = nil)
108
108
  assert_validates(obj, :inclusion, attribute, opts, msg)
109
109
  end
110
110
  alias_method :assert_validates_inclusion_of, :assert_validates_inclusion
111
-
111
+
112
112
  # Test for validating that a a model's attribute is an integer.
113
- #
113
+ #
114
114
  # it { assert_validates_integer(model, :author_id, { message: '...' }) }
115
115
  # it { model.must_validate_integer_of(:author_id, { message: '...' }) }
116
- #
116
+ #
117
117
  def assert_validates_integer(obj, attribute, opts = {}, msg = nil)
118
- opts.merge!({ only_integer: true })
118
+ opts.merge!(only_integer: true)
119
119
  assert_validates(obj, :numericality, attribute, opts, msg)
120
120
  end
121
-
121
+
122
122
  # Test for validating that a model's attribute is numeric (number).
123
- #
123
+ #
124
124
  # it { assert_validates_numericality(model, :author_id, { message: '...' }) }
125
125
  # it { model.must_validate_numericality_of(:author_id, { message: '...' }) }
126
- #
126
+ #
127
127
  def assert_validates_numericality(obj, attribute, opts = {}, msg = nil)
128
128
  assert_validates(obj, :numericality, attribute, opts, msg)
129
129
  end
130
130
  alias_method :assert_validates_numericality_of, :assert_validates_numericality
131
-
131
+
132
132
  # Test for validating that a model's attribute is unique.
133
- #
133
+ #
134
134
  # it { assert_validates_uniqueness(model, :urlslug, { message: '...' }) }
135
135
  # it { model.must_validate_uniqueness_of(:urlslug, { message: '...' }) }
136
- #
136
+ #
137
137
  def assert_validates_uniqueness(obj, attribute, opts = {}, msg = nil)
138
138
  assert_validates(obj, :uniqueness, attribute, opts, msg)
139
139
  end
140
140
  alias_method :assert_validates_uniqueness_of, :assert_validates_uniqueness
141
-
141
+
142
142
  # Validates acceptance of an attribute. Just checks that the value is equal to the :accept option. This method is unique in that :allow_nil is assumed to be true instead of false.
143
-
143
+
144
144
  # Test for validating the acceptance of a model's attribute.
145
- #
145
+ #
146
146
  # it { assert_validates_acceptance(Order.new, :toc, { message: '...' }) }
147
147
  # it { model.must_validate_acceptance_of(:toc, { message: '...' }) }
148
- #
148
+ #
149
149
  def assert_validates_acceptance(obj, attribute, opts = {}, msg = nil)
150
150
  assert_validates(obj, :acceptance, attribute, opts, msg)
151
151
  end
152
152
  alias_method :assert_validates_acceptance_of, :assert_validates_acceptance
153
-
153
+
154
154
  # Test for validating the confirmation of a model's attribute.
155
- #
155
+ #
156
156
  # it { assert_validates_confirmation(User.new, :password, { message: '...' }) }
157
157
  # it { User.new.must_validate_confirmation_of(:password, { message: '...' }) }
158
- #
158
+ #
159
159
  def assert_validates_confirmation(obj, attribute, opts = {}, msg = nil)
160
160
  assert_validates(obj, :confirmation, attribute, opts, msg)
161
161
  end
162
162
  alias_method :assert_validates_confirmation_of, :assert_validates_confirmation
163
-
163
+
164
164
  # Base test for validations of a model, used mainly as a shortcut for other assertions
165
- def assert_validates(obj, validation_type, attribute, opts = {}, msg = nil, &blk)
166
- msg = msg.nil? ? '' : "#{msg}\n"
165
+ def assert_validates(obj, validation_type, attribute, opts = {}, msg = nil)
166
+ msg = msg.nil? ? "" : "#{msg}\n"
167
167
  err_msg = []
168
168
  conf_msg = []
169
169
  unless obj.respond_to?(attribute)
170
- assert(false, "Column :#{attribute} is not defined in #{obj.class.to_s}")
170
+ assert(false, "Column :#{attribute} is not defined in #{obj.class}")
171
171
  end
172
-
172
+
173
173
  msg << "Expected #{obj.class} to validate :#{validation_type} for :#{attribute} column"
174
-
174
+
175
175
  if _validated_model?(obj)
176
-
176
+
177
177
  if _validated_column?(obj, attribute)
178
-
179
- # checks if the model column is validated by the validation type
178
+
179
+ # checks if the model column is validated by the validation type
180
180
  if _validated_with_validation_type?(obj, attribute, validation_type)
181
181
  matching = true
182
-
182
+
183
183
  # bail out if options provided are invalid
184
184
  val_opts = _valid_validation_options(validation_type)
185
-
186
- invalid_opts = opts.keys.reject { |o| val_opts.include?(o) }
185
+
186
+ invalid_opts = opts.keys.reject { |o| val_opts.include?(o) }
187
187
  unless invalid_opts.empty?
188
188
  msg << ", but the following invalid option(s) was found: { "
189
189
  invalid_opts.each { |o| msg << "#{o.inspect}; " }
190
190
  msg << " }. Valid options are: #{val_opts.inspect}"
191
191
  assert(false, msg)
192
192
  end
193
-
193
+
194
194
  h = _validation_types_hash_for_column(obj, attribute)
195
195
  _available_validation_options.each do |ov|
196
196
  unless opts[ov].nil?
197
197
  expected = (h[validation_type][ov].to_s == opts[ov].to_s)
198
- conf_msg << "#{ov}: '#{opts[ov]}'"
198
+ conf_msg << "#{ov}: '#{opts[ov]}'"
199
199
  unless expected
200
200
  err_msg << "#{ov}: '#{h[validation_type][ov]}'"
201
201
  end
202
202
  matching &&= expected
203
203
  end
204
204
  end
205
-
205
+
206
206
  msg = msg << " with: { #{conf_msg.join(', ')} }" unless conf_msg.empty?
207
207
  msg << " but found: { #{err_msg.join(', ')} }" unless err_msg.empty?
208
208
  assert(matching, msg)
209
-
209
+
210
210
  else
211
211
  msg << ", but no :#{validation_type} validation is defined for :#{attribute}"
212
212
  assert(false, msg)
@@ -216,184 +216,179 @@ module Minitest::Assertions
216
216
  assert(false, msg)
217
217
  end
218
218
  else
219
- assert(false, "No validations defined in #{obj.class.to_s}")
219
+ assert(false, "No validations defined in #{obj.class}")
220
220
  end
221
221
  end
222
-
223
-
222
+
223
+
224
224
  # Test for validating presence of a model attribute
225
- #
225
+ #
226
226
  # it { refute_validates_presence(model, :title) }
227
227
  # it { model.must_validate_presence_of(:title, { message: '...' }) }
228
- #
228
+ #
229
229
  def refute_validates_presence(obj, attribute, opts = {}, msg = nil)
230
230
  refute_validates(obj, :presence, attribute, opts, msg)
231
231
  end
232
232
  alias_method :refute_validates_presence_of, :refute_validates_presence
233
-
233
+
234
234
  # Test for validating the length of a model's attribute.
235
- #
235
+ #
236
236
  # Available options:
237
- #
238
- # :message :: The message to use (no default, overrides :nil_message, :too_long,
237
+ #
238
+ # :message :: The message to use (no default, overrides :nil_message, :too_long,
239
239
  # :too_short, and :wrong_length options if present)
240
- #
241
- # :nil_message :: The message to use use if :maximum option is used and the value is nil
240
+ #
241
+ # :nil_message :: The message to use use if :maximum option is used and the value is nil
242
242
  # (default: 'is not present')
243
- #
243
+ #
244
244
  # :too_long :: The message to use use if it the value is too long (default: 'is too long')
245
- #
246
- # :too_short :: The message to use use if it the value is too short
245
+ #
246
+ # :too_short :: The message to use use if it the value is too short
247
247
  # (default: 'is too short')
248
- #
249
- # :wrong_length :: The message to use use if it the value is not valid
248
+ #
249
+ # :wrong_length :: The message to use use if it the value is not valid
250
250
  # (default: 'is the wrong length')
251
- #
251
+ #
252
252
  # SIZE RELATED OPTIONS:
253
- #
253
+ #
254
254
  # :is :: The exact size required for the value to be valid (no default)
255
255
  # :minimum :: The minimum size allowed for the value (no default)
256
256
  # :maximum :: The maximum size allowed for the value (no default)
257
- # :within :: The array/range that must include the size of the value for it to be valid
257
+ # :within :: The array/range that must include the size of the value for it to be valid
258
258
  # (no default)
259
- #
259
+ #
260
260
  # it { refute_validates_length(model, :title, { maximum: 12 }) }
261
261
  # it { model.must_validate_length_of(:title, { within: 4..12 }) }
262
- #
262
+ #
263
263
  def refute_validates_length(obj, attribute, opts = {}, msg = nil)
264
264
  refute_validates(obj, :length, attribute, opts, msg)
265
265
  end
266
266
  alias_method :refute_validates_length_of, :refute_validates_length
267
-
267
+
268
268
  # Test for validating the exact length of a model's attribute.
269
- #
269
+ #
270
270
  # it { refute_validates_exact_length(model, :title, 12, { message: '...' }) }
271
271
  # it { model.must_validate_exact_length_of(:title, 12, { message: '...' }) }
272
- #
272
+ #
273
273
  def refute_validates_exact_length(obj, attribute, exact_length, opts = {}, msg = nil)
274
- opts.merge!({ is: exact_length })
274
+ opts.merge!(is: exact_length)
275
275
  refute_validates(obj, :length, attribute, opts, msg)
276
276
  end
277
277
  alias_method :refute_validates_exact_length_of, :refute_validates_exact_length
278
-
278
+
279
279
  # Test for validating the exact length of a model's attribute.
280
- #
280
+ #
281
281
  # it { refute_validates_length_range(model, :title, 4..12, { message: '...' }) }
282
282
  # it { model.must_validate_length_range_of(:title, 4..12, { message: '...' }) }
283
- #
283
+ #
284
284
  def refute_validates_length_range(obj, attribute, range, opts = {}, msg = nil)
285
- opts.merge!({ within: range })
285
+ opts.merge!(within: range)
286
286
  refute_validates(obj, :length, attribute, opts, msg)
287
287
  end
288
288
  alias_method :refute_validates_length_range_of, :refute_validates_length_range
289
-
289
+
290
290
  # Test for validating the maximum length of a model's attribute.
291
- #
291
+ #
292
292
  # it { refute_validates_max_length(model, :title, 12, { message: '...' }) }
293
293
  # it { model.must_validate_max_length_of(:title, 12, { message: '...' }) }
294
- #
294
+ #
295
295
  def refute_validates_max_length(obj, attribute, max_length, opts = {}, msg = nil)
296
- opts.merge!({ maximum: max_length })
296
+ opts.merge!(maximum: max_length)
297
297
  refute_validates(obj, :length, attribute, opts, msg)
298
298
  end
299
299
  alias_method :refute_validates_max_length_of, :refute_validates_max_length
300
300
 
301
301
  # Test for validating the minimum length of a model's attribute.
302
- #
302
+ #
303
303
  # it { refute_validates_min_length(model, :title, 12, { message: '...' }) }
304
304
  # it { model.must_validate_min_length_of(:title, 12, { message: '...' }) }
305
- #
305
+ #
306
306
  def refute_validates_min_length(obj, attribute, min_length, opts = {}, msg = nil)
307
- opts.merge!({ minimum: min_length })
307
+ opts.merge!(minimum: min_length)
308
308
  refute_validates(obj, :length, attribute, opts, msg)
309
309
  end
310
310
  alias_method :refute_validates_min_length_of, :refute_validates_min_length
311
-
311
+
312
312
  # Test for validating the format of a model's attribute with a regexp.
313
- #
313
+ #
314
314
  # it { refute_validates_format(model, :title, 12, { with: /[a-z+]/ }) }
315
315
  # it { model.must_validate_format_of(:title, 12, { with: /[a-z]+/ }) }
316
- #
316
+ #
317
317
  def refute_validates_format(obj, attribute, opts = {}, msg = nil)
318
318
  refute_validates(obj, :format, attribute, opts, msg)
319
319
  end
320
320
  alias_method :refute_validates_format_of, :refute_validates_format
321
-
321
+
322
322
  # Test for validating that a model's attribute is within a specified range or set of values.
323
- #
323
+ #
324
324
  # it { refute_validates_inclusion(model, :status, { in: [:a, :b, :c] }) }
325
325
  # it { model.must_validate_inclusion_of(:status, { in: [:a, :b, :c] }) }
326
- #
326
+ #
327
327
  def refute_validates_inclusion(obj, attribute, opts = {}, msg = nil)
328
328
  refute_validates(obj, :inclusion, attribute, opts, msg)
329
329
  end
330
330
  alias_method :refute_validates_inclusion_of, :refute_validates_inclusion
331
-
331
+
332
332
  # Test for validating that a a model's attribute is an integer.
333
- #
333
+ #
334
334
  # it { refute_validates_integer(model, :author_id, { message: '...' }) }
335
335
  # it { model.must_validate_integer_of(:author_id, { message: '...' }) }
336
- #
336
+ #
337
337
  def refute_validates_integer(obj, attribute, opts = {}, msg = nil)
338
- opts.merge!({ only_integer: true })
338
+ opts.merge!(only_integer: true)
339
339
  refute_validates(obj, :numericality, attribute, opts, msg)
340
340
  end
341
-
341
+
342
342
  # Test for validating that a model's attribute is numeric (number).
343
- #
343
+ #
344
344
  # it { refute_validates_numericality(model, :author_id, { message: '...' }) }
345
345
  # it { model.must_validate_numericality_of(:author_id, { message: '...' }) }
346
- #
346
+ #
347
347
  def refute_validates_numericality(obj, attribute, opts = {}, msg = nil)
348
348
  refute_validates(obj, :numericality, attribute, opts, msg)
349
349
  end
350
350
  alias_method :refute_validates_numericality_of, :refute_validates_numericality
351
-
351
+
352
352
  # Test for validating that a model's attribute is unique.
353
- #
353
+ #
354
354
  # it { refute_validates_uniqueness(model, :urlslug, { message: '...' }) }
355
355
  # it { model.must_validate_uniqueness_of(:urlslug, { message: '...' }) }
356
- #
356
+ #
357
357
  def refute_validates_uniqueness(obj, attribute, opts = {}, msg = nil)
358
358
  refute_validates(obj, :uniqueness, attribute, opts, msg)
359
359
  end
360
360
  alias_method :refute_validates_uniqueness_of, :refute_validates_uniqueness
361
-
361
+
362
362
  # Validates acceptance of an attribute. Just checks that the value is equal to the :accept option. This method is unique in that :allow_nil is assumed to be true instead of false.
363
-
363
+
364
364
  # Test for validating the acceptance of a model's attribute.
365
- #
365
+ #
366
366
  # it { refute_validates_acceptance(Order.new, :toc, { message: '...' }) }
367
367
  # it { model.must_validate_acceptance_of(:toc, { message: '...' }) }
368
- #
368
+ #
369
369
  def refute_validates_acceptance(obj, attribute, opts = {}, msg = nil)
370
370
  refute_validates(obj, :acceptance, attribute, opts, msg)
371
371
  end
372
372
  alias_method :refute_validates_acceptance_of, :refute_validates_acceptance
373
-
373
+
374
374
  # Test for validating the confirmation of a model's attribute.
375
- #
375
+ #
376
376
  # it { refute_validates_confirmation(User.new, :password, { message: '...' }) }
377
377
  # it { User.new.must_validate_confirmation_of(:password, { message: '...' }) }
378
- #
378
+ #
379
379
  def refute_validates_confirmation(obj, attribute, opts = {}, msg = nil)
380
380
  refute_validates(obj, :confirmation, attribute, opts, msg)
381
381
  end
382
382
  alias_method :refute_validates_confirmation_of, :refute_validates_confirmation
383
-
383
+
384
384
  # Base test for validations of a model, used mainly as a shortcut for other assertions
385
- def refute_validates(obj, validation_type, attribute, opts = {}, msg = nil, &blk)
386
- msg = msg.nil? ? '' : "#{msg}\n"
387
- err_msg = []
388
- conf_msg = []
385
+ def refute_validates(obj, validation_type, attribute, opts = {}, msg = nil)
386
+ msg = msg.nil? ? "" : "#{msg}\n"
389
387
  unless obj.respond_to?(attribute)
390
- assert(false, "Column :#{attribute} is not defined in #{obj.class.to_s}, so cannot be validated")
388
+ assert(false, "Column :#{attribute} is not defined in #{obj.class}, so cannot be validated")
391
389
  end
392
-
393
390
  msg << "Expected #{obj.class} NOT to validate :#{attribute} with :#{validation_type}"
394
-
395
391
  if _validated_model?(obj)
396
-
397
392
  if _validated_column?(obj, attribute)
398
393
  msg << ", but the column :#{attribute} was validated with :#{validation_type}"
399
394
  assert(false, msg)
@@ -401,65 +396,73 @@ module Minitest::Assertions
401
396
  assert(true, msg)
402
397
  end
403
398
  else
404
- assert(false, "No validations defined in #{obj.class.to_s}")
399
+ assert(false, "No validations defined in #{obj.class}")
405
400
  end
406
401
  end
407
-
408
-
409
- #
402
+
403
+ #
410
404
  def assert_raises_validation_failed(obj)
411
405
  assert_raises(::Sequel::ValidationFailed) { obj.save }
412
406
  end
413
407
  alias_method :assert_fails_validation, :assert_raises_validation_failed
414
-
415
-
408
+
409
+ # #
410
+ # #
411
+ # def assert_presence(obj, attr, value)
412
+ # obj.send("#{attr}=", value)
413
+ # assert(obj.valid?)
414
+ # end
415
+ #
416
+ # [nil, '', ' '].each { |x| }
417
+ #
418
+ # end
419
+
416
420
  private
417
-
418
-
419
- #
421
+
422
+ #
420
423
  def _validated_model?(model)
421
- return (model.class.respond_to?(:has_validations?) && model.class.has_validations?)
424
+ (model.class.respond_to?(:has_validations?) && model.class.has_validations?)
422
425
  end
423
-
424
- #
426
+
427
+ #
425
428
  def _validated_column?(model, attribute)
426
429
  return false unless _validated_model?(model)
427
- return model.class.validation_reflections.keys.include?(attribute.to_sym)
430
+ model.class.validation_reflections.keys.include?(attribute.to_sym)
428
431
  end
429
-
430
- #
432
+
433
+ #
431
434
  def _validated_with_validation_type?(model, attribute, validation_type)
432
435
  return false unless _validated_column?(model, attribute)
433
- return _validation_types_hash_for_column(model, attribute).keys.include?(validation_type)
436
+ _validation_types_hash_for_column(model, attribute).keys.include?(validation_type)
434
437
  end
435
-
436
- #
438
+
439
+ #
437
440
  def _validation_types_hash_for_column(model, attribute)
438
441
  h = {}
439
442
  model.class.validation_reflections[attribute].each { |c| h[c[0]] = c[1] }
440
443
  h
441
444
  end
442
-
443
- #
445
+
446
+ #
444
447
  def _available_validation_types
445
448
  [:format, :length, :presence, :numericality, :confirmation, :acceptance, :inclusion, :uniqueness]
446
449
  end
447
-
448
- #
450
+
451
+ #
449
452
  def _available_validation_options
450
453
  [
451
454
  :message, :if, :is, :in, :allow_blank, :allow_missing, :allow_nil, :accept, :with, :within,
452
455
  :only_integer, :maximum, :minimum, :nil_message, :too_long, :too_short, :wrong_length
453
456
  ]
454
457
  end
455
-
456
- #
458
+
459
+ #
457
460
  def _valid_validation_options(type = nil)
458
461
  arr = [:message]
459
462
  case type.to_sym
460
463
  when :each
461
464
  # validates_each (*atts, &block)
462
- # Adds a validation for each of the given attributes using the supplied block.
465
+ # Adds a validation for each of the given attributes using the supplied block.
463
466
  [:allow_blank, :allow_missing, :allow_nil].each { |a| arr << a }
464
467
  when :acceptance
465
468
  # The value required for the object to be valid (default: '1')
@@ -474,76 +477,73 @@ module Minitest::Assertions
474
477
  # Whether only integers are valid values (default: false)
475
478
  arr << :only_integer
476
479
  when :length
477
- #
478
- # :message :: The message to use (no default, overrides :nil_message, :too_long,
480
+ #
481
+ # :message :: The message to use (no default, overrides :nil_message, :too_long,
479
482
  # :too_short, and :wrong_length options if present)
480
- #
481
- # :nil_message :: The message to use use if :maximum option is used and the value is nil
483
+ #
484
+ # :nil_message :: The message to use use if :maximum option is used and the value is nil
482
485
  # (default: 'is not present')
483
- #
486
+ #
484
487
  # :too_long :: The message to use use if it the value is too long (default: 'is too long')
485
- #
486
- # :too_short :: The message to use use if it the value is too short
488
+ #
489
+ # :too_short :: The message to use use if it the value is too short
487
490
  # (default: 'is too short')
488
- #
489
- # :wrong_length :: The message to use use if it the value is not valid
491
+ #
492
+ # :wrong_length :: The message to use use if it the value is not valid
490
493
  # (default: 'is the wrong length')
491
- #
494
+ #
492
495
  # SIZE
493
496
  # :is :: The exact size required for the value to be valid (no default)
494
497
  # :minimum :: The minimum size allowed for the value (no default)
495
498
  # :maximum :: The maximum size allowed for the value (no default)
496
- # :within :: The array/range that must include the size of the value for it to be valid
499
+ # :within :: The array/range that must include the size of the value for it to be valid
497
500
  # (no default)
498
-
499
- [ :is, :maximum, :minimum, :nil_message, :too_long, :too_short, :within, :wrong_length ]
500
- .each { |a| arr << a }
501
+
502
+ [:is, :maximum, :minimum, :nil_message, :too_long, :too_short, :within, :wrong_length].each { |a| arr << a }
501
503
  else
502
504
  arr
503
505
  end unless type.nil?
504
506
  arr
505
507
  end
506
-
507
- end
508
508
 
509
+ end
509
510
 
510
511
  # add support for Spec syntax
511
512
  module Minitest::Expectations
512
513
  infect_an_assertion :assert_validates, :must_validate, :reverse
513
514
  infect_an_assertion :assert_validates_presence, :must_validate_presence_of, :reverse
514
515
  infect_an_assertion :assert_validates_format, :must_validate_format_of, :reverse
515
-
516
+
516
517
  infect_an_assertion :assert_validates_length, :must_validate_length_of, :reverse
517
518
  infect_an_assertion :assert_validates_exact_length, :must_validate_exact_length_of, :reverse
518
519
  infect_an_assertion :assert_validates_min_length, :must_validate_min_length_of, :reverse
519
520
  infect_an_assertion :assert_validates_max_length, :must_validate_max_length_of, :reverse
520
521
  infect_an_assertion :assert_validates_length_range, :must_validate_length_range_of, :reverse
521
-
522
+
522
523
  infect_an_assertion :assert_validates_integer, :must_validate_integer_of, :reverse
523
524
  infect_an_assertion :assert_validates_numericality, :must_validate_numericality_of, :reverse
524
525
  infect_an_assertion :assert_validates_confirmation, :must_validate_confirmation_of, :reverse
525
526
  infect_an_assertion :assert_validates_acceptance, :must_validate_acceptance_of, :reverse
526
527
  infect_an_assertion :assert_validates_inclusion, :must_validate_inclusion_of, :reverse
527
528
  infect_an_assertion :assert_validates_uniqueness, :must_validate_uniqueness_of, :reverse
528
-
529
+
529
530
  infect_an_assertion :assert_fails_validation, :must_fail_validation, :reverse
530
-
531
-
531
+
532
+
532
533
  infect_an_assertion :refute_validates, :wont_validate, :reverse
533
534
  infect_an_assertion :refute_validates_presence, :wont_validate_presence_of, :reverse
534
535
  infect_an_assertion :refute_validates_format, :wont_validate_format_of, :reverse
535
-
536
+
536
537
  infect_an_assertion :refute_validates_length, :wont_validate_length_of, :reverse
537
538
  infect_an_assertion :refute_validates_exact_length, :wont_validate_exact_length_of, :reverse
538
539
  infect_an_assertion :refute_validates_min_length, :wont_validate_min_length_of, :reverse
539
540
  infect_an_assertion :refute_validates_max_length, :wont_validate_max_length_of, :reverse
540
541
  infect_an_assertion :refute_validates_length_range, :wont_validate_length_range_of, :reverse
541
-
542
+
542
543
  infect_an_assertion :refute_validates_integer, :wont_validate_integer_of, :reverse
543
544
  infect_an_assertion :refute_validates_numericality, :wont_validate_numericality_of, :reverse
544
545
  infect_an_assertion :refute_validates_confirmation, :wont_validate_confirmation_of, :reverse
545
546
  infect_an_assertion :refute_validates_acceptance, :wont_validate_acceptance_of, :reverse
546
547
  infect_an_assertion :refute_validates_inclusion, :wont_validate_inclusion_of, :reverse
547
548
  infect_an_assertion :refute_validates_uniqueness, :wont_validate_uniqueness_of, :reverse
548
-
549
549
  end