minitest-sequel 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/dependabot.yml +24 -0
- data/.github/workflows/ruby.yml +45 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +48 -0
- data/.rubocop_todo.yml +7 -0
- data/CODE_OF_CONDUCT.md +17 -10
- data/Gemfile +81 -2
- data/Guardfile +26 -0
- data/README.md +368 -243
- data/Rakefile +16 -24
- data/lib/minitest/sequel/associations.rb +353 -163
- data/lib/minitest/sequel/columns.rb +204 -140
- data/lib/minitest/sequel/helpers.rb +190 -21
- data/lib/minitest/sequel/plugins.rb +409 -129
- data/lib/minitest/sequel/validations.rb +1122 -504
- data/lib/minitest/sequel/version.rb +4 -3
- data/lib/minitest/sequel.rb +27 -23
- data/minitest-sequel.gemspec +28 -27
- metadata +49 -143
data/README.md
CHANGED
@@ -1,19 +1,26 @@
|
|
1
|
+
<!-- markdownlint-disable MD013 MD033 -->
|
2
|
+
|
1
3
|
# Minitest-Sequel
|
2
4
|
|
3
|
-
[
|
4
|
-
|
5
|
+
[![Ruby](https://github.com/kematzy/minitest-sequel/actions/workflows/ruby.yml/badge.svg?branch=master)](https://github.com/kematzy/minitest-sequel/actions/workflows/ruby.yml) - [![Gem Version](https://badge.fury.io/rb/minitest-sequel.svg)](https://badge.fury.io/rb/minitest-sequel) - [![Minitest Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop-minitest)
|
6
|
+
|
7
|
+
Coverage: Currently at **99.1%**
|
8
|
+
|
9
|
+
[Minitest](https://github.com/seattlerb/minitest) assertions to speed-up development and testing
|
10
|
+
of [Sequel](http://sequel.jeremyevans.net/) database setups.
|
5
11
|
|
6
|
-
The general hope is that this gem will contain a variety of useful assertions in all areas of
|
7
|
-
code within your apps, gems, etc.
|
12
|
+
The general hope is that this gem will contain a variety of useful assertions in all areas of
|
13
|
+
testing Sequel database code within your apps, gems, etc.
|
8
14
|
|
9
15
|
Please help out with missing features / functionality.
|
10
16
|
|
11
|
-
|
17
|
+
---
|
12
18
|
|
13
19
|
## Model Definitions
|
14
20
|
|
21
|
+
### `#assert_have_column (:model, :attribute, :opts, :msg)`
|
15
22
|
|
16
|
-
|
23
|
+
spec: `_(model).must_have_column(:attribute, :opts, :msg)`
|
17
24
|
|
18
25
|
Conveniently test your Model definitions as follows:
|
19
26
|
|
@@ -22,9 +29,9 @@ let(:m) { Post.first }
|
|
22
29
|
|
23
30
|
it { assert_have_column(m, :title, type: :string, db_type: 'varchar(250)', allow_null: :false) }
|
24
31
|
|
25
|
-
it { m.must_have_column(:title, type: :string, allow_null: :false) }
|
32
|
+
it { _(m).must_have_column(:title, type: :string, allow_null: :false) }
|
26
33
|
|
27
|
-
it { m.must_have_column(:title, { type: :string, allow_null: :false }, "Custom messsage
|
34
|
+
it { _(m).must_have_column(:title, { type: :string, allow_null: :false }, "Custom messsage") }
|
28
35
|
|
29
36
|
# definition of args
|
30
37
|
# assert_have_column(
|
@@ -35,81 +42,72 @@ it { m.must_have_column(:title, { type: :string, allow_null: :false }, "Custom m
|
|
35
42
|
# )
|
36
43
|
```
|
37
44
|
|
38
|
-
The
|
39
|
-
|
45
|
+
The `#assert_have_column()` method first tests if the column name is defined in the Model and then
|
46
|
+
checks all passed options.
|
40
47
|
|
41
48
|
The following options are valid and checked:
|
42
49
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
50
|
+
- `:type`
|
51
|
+
- `:db_type`
|
52
|
+
- `:allow_null`
|
53
|
+
- `:max_length`
|
54
|
+
- `:default`
|
55
|
+
- `:primary_key`
|
56
|
+
- `:auto_increment`
|
51
57
|
|
52
|
-
In the event the specs differ from the actual database implementation an extensive error message
|
53
|
-
differing option(s) is provided to help speed up debugging the issue:
|
58
|
+
In the event the specs differ from the actual database implementation an extensive error message
|
59
|
+
with the differing option(s) is provided to help speed up debugging the issue:
|
54
60
|
|
55
|
-
```
|
61
|
+
```bash
|
56
62
|
Expected Post model to have column: :title with: \
|
57
|
-
{
|
63
|
+
{
|
64
|
+
type: 'string',
|
65
|
+
db_type: 'varchar(250)',
|
66
|
+
allow_null: 'false'
|
67
|
+
}
|
58
68
|
but found: { db_type: 'varchar(255)' }
|
59
69
|
```
|
60
70
|
|
61
|
-
|
71
|
+
> [!NOTE]
|
72
|
+
> To test options with a value that is either `nil`, `true` or `false`, please use `:nil`, `:false`
|
73
|
+
> or `:true` and provide numbers as 'strings' instead, ie: `'1'` instead of `1`.
|
62
74
|
|
63
|
-
To test options with a value that is either `nil`, `true` or `false`, please use `:nil`, `:false` or `:true` and provide
|
64
|
-
numbers as 'strings' instead, ie: `'1'` instead of `1`.
|
65
|
-
|
66
|
-
|
67
|
-
<br>
|
68
75
|
<br>
|
69
76
|
|
70
|
-
|
77
|
+
---
|
71
78
|
|
72
79
|
<br>
|
73
80
|
|
74
|
-
|
75
|
-
## Associations
|
81
|
+
## Model Associations
|
76
82
|
|
77
83
|
Conveniently test model associations quickly and easily with these Minitest assertions:
|
78
84
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
* `assert_association_many_to_many`
|
86
|
-
|
87
|
-
* `assert_association`
|
85
|
+
- `#assert_association_one_to_one`
|
86
|
+
- `#assert_association_one_to_many`
|
87
|
+
- `#assert_association_many_to_one`
|
88
|
+
- `#assert_association_many_to_many`
|
89
|
+
- `#assert_association`
|
88
90
|
|
89
91
|
<br>
|
90
|
-
<br>
|
91
|
-
|
92
92
|
|
93
93
|
### `:one_to_one` association
|
94
94
|
|
95
|
-
|
96
95
|
A model defined with an association like this:
|
97
96
|
|
98
|
-
|
99
97
|
```ruby
|
100
98
|
class Post < Sequel::Model
|
101
99
|
one_to_one :first_comment, class: :Comment, order: :id
|
102
100
|
end
|
103
101
|
```
|
104
102
|
|
105
|
-
Can be easily and quickly tested with
|
103
|
+
Can be easily and quickly tested with `#assert_association_one_to_one()` like this:
|
106
104
|
|
107
105
|
```ruby
|
108
106
|
let(:m) { Post.first }
|
109
107
|
|
110
108
|
it { assert_association_one_to_one(m, :first_comment)
|
111
109
|
# or
|
112
|
-
it { m.must_have_one_to_one_association(:first_comment) }
|
110
|
+
it { _(m).must_have_one_to_one_association(:first_comment) }
|
113
111
|
|
114
112
|
|
115
113
|
# definition of args
|
@@ -123,18 +121,28 @@ assert_association_one_to_one(
|
|
123
121
|
|
124
122
|
In the event of errors an extensive error message is provided:
|
125
123
|
|
126
|
-
```
|
124
|
+
```bash
|
127
125
|
# example error message
|
128
126
|
|
129
|
-
Expected Author to have a :one_to_one association :key_posts but no association \
|
130
|
-
|
131
|
-
{
|
132
|
-
|
127
|
+
Expected Author to have a :one_to_one association :key_posts but no association ':key_posts' \
|
128
|
+
was found - available associations are: [ \
|
129
|
+
{
|
130
|
+
:attribute=>:posts,
|
131
|
+
:type=>:one_to_many,
|
132
|
+
:class=>:Post,
|
133
|
+
:keys=>[:author_id]},
|
134
|
+
{
|
135
|
+
:attribute=>:key_post,
|
136
|
+
:type=>:one_to_one,
|
137
|
+
:class=>:Post,
|
138
|
+
:keys=>[:author_id]
|
139
|
+
}
|
133
140
|
]
|
134
141
|
```
|
135
142
|
|
136
143
|
<br>
|
137
|
-
|
144
|
+
|
145
|
+
---
|
138
146
|
|
139
147
|
### `:one_to_many` association
|
140
148
|
|
@@ -146,22 +154,23 @@ class Post < Sequel::Model
|
|
146
154
|
end
|
147
155
|
```
|
148
156
|
|
149
|
-
Can be easily and quickly tested with
|
157
|
+
Can be easily and quickly tested with `#assert_association_one_to_many()` like this:
|
150
158
|
|
151
159
|
```ruby
|
152
|
-
let(:
|
160
|
+
let(:m) { Post.first }
|
153
161
|
|
154
|
-
it { assert_association_one_to_many(
|
162
|
+
it { assert_association_one_to_many(m, :comments) }
|
155
163
|
# or
|
156
|
-
it { m.must_have_one_to_many_association(:comments) }
|
157
|
-
```
|
164
|
+
it { _(m).must_have_one_to_many_association(:comments) }
|
165
|
+
```
|
158
166
|
|
159
167
|
As above the assertion provides an extensive error message if something is wrong.
|
160
168
|
|
161
169
|
<br>
|
162
|
-
<br>
|
163
170
|
|
164
|
-
|
171
|
+
---
|
172
|
+
|
173
|
+
### `:many_to_one` association
|
165
174
|
|
166
175
|
A model defined with an association like this:
|
167
176
|
|
@@ -171,23 +180,23 @@ class Post < Sequel::Model
|
|
171
180
|
end
|
172
181
|
```
|
173
182
|
|
174
|
-
Can be easily and quickly tested with
|
183
|
+
Can be easily and quickly tested with `#assert_association_many_to_one()` like this:
|
175
184
|
|
176
185
|
```ruby
|
177
|
-
let(:
|
186
|
+
let(:m) { Post.first }
|
178
187
|
|
179
|
-
it { assert_association_many_to_one(
|
188
|
+
it { assert_association_many_to_one(m, :author) }
|
180
189
|
# or
|
181
|
-
it { m.must_have_many_to_one_association(:author) }
|
182
|
-
```
|
183
|
-
|
190
|
+
it { _(m).must_have_many_to_one_association(:author) }
|
191
|
+
```
|
184
192
|
|
185
193
|
As above the assertion provides an extensive error message if something is wrong.
|
186
194
|
|
187
195
|
<br>
|
188
|
-
<br>
|
189
196
|
|
190
|
-
|
197
|
+
---
|
198
|
+
|
199
|
+
### `:many_to_many` association
|
191
200
|
|
192
201
|
A model defined with an association like this:
|
193
202
|
|
@@ -197,47 +206,55 @@ class Post < Sequel::Model
|
|
197
206
|
end
|
198
207
|
```
|
199
208
|
|
200
|
-
Can be easily and quickly tested with
|
209
|
+
Can be easily and quickly tested with `#assert_association_many_to_many()` like this:
|
201
210
|
|
202
211
|
```ruby
|
203
|
-
let(:
|
212
|
+
let(:m) { Post.first }
|
204
213
|
|
205
|
-
it { assert_association_many_to_many(
|
214
|
+
it { assert_association_many_to_many(m, :categories) }
|
206
215
|
# or
|
207
|
-
it { m.must_have_many_to_many_association(:categories) }
|
208
|
-
```
|
216
|
+
it { _(m).must_have_many_to_many_association(:categories) }
|
217
|
+
```
|
209
218
|
|
210
219
|
If something is wrong an extensive error message is provided:
|
211
220
|
|
212
|
-
```
|
221
|
+
```bash
|
213
222
|
Expected Category to have a :many_to_many association :posts with given options: \
|
214
223
|
{:class_name=>'Posts'} but should be {:class_name=>'Post' }
|
215
224
|
```
|
216
225
|
|
217
226
|
or
|
218
227
|
|
219
|
-
```
|
220
|
-
Expected Category to have a :many_to_many association :post but no association \
|
221
|
-
|
222
|
-
{
|
223
|
-
:
|
228
|
+
```bash
|
229
|
+
Expected Category to have a :many_to_many association :post but no association ':post' was found \
|
230
|
+
- available associations are: [ \
|
231
|
+
{
|
232
|
+
:attribute=>:posts,
|
233
|
+
:type=>:many_to_many,
|
234
|
+
:class=>:Post,
|
235
|
+
:join_table=>:categories_posts,
|
236
|
+
:left_keys=>[:category_id],
|
237
|
+
:right_keys=>[:post_id]
|
224
238
|
}
|
225
239
|
]
|
226
240
|
```
|
227
241
|
|
228
242
|
<br>
|
229
|
-
<br>
|
230
243
|
|
231
|
-
|
232
|
-
|
244
|
+
---
|
245
|
+
|
246
|
+
### `#assert_association(:model, :type, :attribute, :options, :msg)`
|
247
|
+
|
248
|
+
spec: `_(model).must_have_association(:type, :attribute, :options, :msg)`
|
233
249
|
|
234
|
-
if the above assertion methods are insufficient, you can use the base
|
250
|
+
if the above assertion methods are insufficient, you can use the base
|
251
|
+
`assert_association` method instead.
|
235
252
|
|
236
253
|
```ruby
|
237
254
|
it "should have a :one_through_one association" do
|
238
255
|
assert_association(Post, :one_through_one, :author)
|
239
256
|
# or
|
240
|
-
Post.must_have_association(:one_through_one, :author)
|
257
|
+
_(Post).must_have_association(:one_through_one, :author)
|
241
258
|
end
|
242
259
|
|
243
260
|
# definition of args
|
@@ -253,234 +270,302 @@ assert_association(
|
|
253
270
|
<br>
|
254
271
|
<br>
|
255
272
|
|
256
|
-
|
273
|
+
---
|
257
274
|
|
258
275
|
<br>
|
259
276
|
|
260
|
-
## Validations
|
261
|
-
|
262
|
-
If you are using the recommended `:validation_class_methods` plugin in your app, the following instance validation methods are supported:
|
263
|
-
|
264
|
-
* `assert_validates_presence()`
|
265
|
-
|
266
|
-
* `assert_validates_exact_length()`
|
267
|
-
|
268
|
-
* `assert_validates_length_range()`
|
269
|
-
|
270
|
-
* `assert_validates_max_length()`
|
271
|
-
|
272
|
-
* `assert_validates_min_length()`
|
273
|
-
|
274
|
-
* `assert_validates_format()`
|
275
|
-
|
276
|
-
* `assert_validates_inclusion()`
|
277
|
-
|
278
|
-
* `assert_validates_integer()`
|
277
|
+
## Model Validations
|
279
278
|
|
280
|
-
|
279
|
+
If you are using the recommended `:validation_class_methods` plugin in your app, the following
|
280
|
+
instance validation methods are supported:
|
281
281
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
282
|
+
- `#assert_validates_presence()`
|
283
|
+
- `#assert_validates_exact_length()`
|
284
|
+
- `#assert_validates_length_range()`
|
285
|
+
- `#assert_validates_max_length()`
|
286
|
+
- `#assert_validates_min_length()`
|
287
|
+
- `#assert_validates_format()`
|
288
|
+
- `#assert_validates_inclusion()`
|
289
|
+
- `#assert_validates_integer()`
|
290
|
+
- `#assert_validates_numericality()`
|
291
|
+
- `#assert_validates_uniqueness()`
|
292
|
+
- `#assert_validates_acceptance()`
|
293
|
+
- `#assert_validates_confirmation()`
|
287
294
|
|
288
295
|
With all valid options checked
|
289
296
|
|
297
|
+
<br>
|
298
|
+
|
290
299
|
---
|
291
300
|
|
292
|
-
|
293
|
-
|
301
|
+
### `#assert_validates_presence(:model, :attribute, :opts, :msg)`
|
302
|
+
|
303
|
+
alias: `#assert_validates_presence_of(:attribute, :opts, :msg)`
|
294
304
|
|
295
305
|
Test for validating presence of a model attribute
|
296
306
|
|
297
307
|
```ruby
|
298
|
-
|
299
|
-
|
308
|
+
let(:m) { Post.first }
|
309
|
+
|
310
|
+
it { assert_validates_presence(m, :title) }
|
311
|
+
# or
|
312
|
+
it { _(m).must_validate_presence_of(:title, { message: '...' }) }
|
300
313
|
```
|
314
|
+
|
301
315
|
<br>
|
302
316
|
|
317
|
+
---
|
318
|
+
|
319
|
+
### `#assert_validates_length(:model, :attribute, :opts, :msg)`
|
303
320
|
|
304
|
-
|
305
|
-
alias `:assert_validates_length_of`
|
321
|
+
alias `#assert_validates_length_of`
|
306
322
|
|
307
323
|
Test for validating the length of a model's attribute.
|
308
324
|
|
309
325
|
Available options:
|
310
326
|
|
311
|
-
|
327
|
+
- :message - The message to use (no default, overrides :nil_message, :too_long,
|
328
|
+
:too_short, and :wrong_length options if present)
|
312
329
|
|
313
|
-
|
330
|
+
- :nil_message - The message to use use if :maximum option is used and the
|
331
|
+
value is nil (default: 'is not present')
|
314
332
|
|
315
|
-
|
333
|
+
- :too_long - The message to use use if it the value is too long
|
334
|
+
(default: 'is too long')
|
316
335
|
|
317
|
-
|
336
|
+
- :too_short - The message to use use if it the value is too short
|
337
|
+
(default: 'is too short')
|
318
338
|
|
319
|
-
|
339
|
+
- :wrong_length - The message to use use if it the value is not valid
|
340
|
+
(default: 'is the wrong length')
|
320
341
|
|
321
342
|
Size related options:
|
322
343
|
|
323
|
-
|
344
|
+
- :is - The exact size required for the value to be valid (no default)
|
324
345
|
|
325
|
-
|
346
|
+
- :minimum - The minimum size allowed for the value (no default)
|
326
347
|
|
327
|
-
|
348
|
+
- :maximum - The maximum size allowed for the value (no default)
|
328
349
|
|
329
|
-
|
350
|
+
- :within - The array/range that must include the size of the value for it to
|
351
|
+
be valid (no default)
|
330
352
|
|
331
353
|
```ruby
|
332
|
-
|
333
|
-
|
354
|
+
let(:m) { Post.first }
|
355
|
+
|
356
|
+
it { assert_validates_length(m, :title, { maximum: 12 }) }
|
357
|
+
# or
|
358
|
+
it { _(m).must_validate_length_of(:title, { within: 4..12 }) }
|
334
359
|
```
|
360
|
+
|
335
361
|
<br>
|
336
362
|
|
363
|
+
---
|
364
|
+
|
365
|
+
### `#assert_validates_exact_length(:model, :attribute, :exact_length, :opts, :msg)`
|
337
366
|
|
338
|
-
|
339
|
-
alias: `:assert_validates_exact_length_of`
|
367
|
+
alias: `#assert_validates_exact_length_of`
|
340
368
|
|
341
369
|
Test for validating the exact length of a model's attribute.
|
342
370
|
|
343
371
|
```ruby
|
344
|
-
|
345
|
-
|
372
|
+
let(:m) { Post.first }
|
373
|
+
|
374
|
+
it { assert_validates_exact_length(m, :title, 12, { message: '...' }) }
|
375
|
+
# or
|
376
|
+
it { _(m).must_validate_exact_length_of(:title, 12, { message: '...' }) }
|
346
377
|
```
|
378
|
+
|
347
379
|
<br>
|
348
380
|
|
381
|
+
---
|
382
|
+
|
383
|
+
### `#assert_validates_length_range(:model, :attribute, :range, :opts, :msg)`
|
349
384
|
|
350
|
-
|
351
|
-
alias: `:assert_validates_length_range_of`
|
385
|
+
alias: `#assert_validates_length_range_of`
|
352
386
|
|
353
387
|
Test for validating the exact length of a model's attribute.
|
354
388
|
|
355
389
|
```ruby
|
356
|
-
|
357
|
-
|
390
|
+
let(:m) { Post.first }
|
391
|
+
|
392
|
+
it { assert_validates_length_range(m, :title, 4..12, { message: '...' }) }
|
393
|
+
# or
|
394
|
+
it { _(m).must_validate_length_range_of(:title, 4..12, { message: '...' }) }
|
358
395
|
```
|
359
396
|
|
360
397
|
<br>
|
361
398
|
|
399
|
+
---
|
400
|
+
|
401
|
+
### `#assert_validates_max_length(:model, :attribute, :max_length, :opts, :msg)`
|
362
402
|
|
363
|
-
|
364
|
-
alias: `:assert_validates_max_length_of`
|
403
|
+
alias: `#assert_validates_max_length_of`
|
365
404
|
|
366
405
|
Test for validating the maximum length of a model's attribute.
|
367
406
|
|
368
407
|
```ruby
|
369
|
-
|
370
|
-
|
408
|
+
let(:m) { Post.first }
|
409
|
+
|
410
|
+
it { assert_validates_max_length(m, :title, 12, { message: '...' }) }
|
411
|
+
# or
|
412
|
+
it { _(m).must_validate_max_length_of(:title, 12, { message: '...' }) }
|
371
413
|
```
|
372
414
|
|
373
415
|
<br>
|
374
416
|
|
417
|
+
---
|
375
418
|
|
376
|
-
|
377
|
-
|
419
|
+
### `#assert_validates_min_length(:model, :attribute, :min_length, :opts, :msg)`
|
420
|
+
|
421
|
+
alias: `#assert_validates_min_length_of`
|
378
422
|
|
379
423
|
Test for validating the minimum length of a model's attribute.
|
380
424
|
|
381
425
|
```ruby
|
382
|
-
|
383
|
-
|
426
|
+
let(:m) { Post.first }
|
427
|
+
|
428
|
+
it { assert_validates_min_length(m, :title, 12, { message: '...' }) }
|
429
|
+
# or
|
430
|
+
it { _(m).must_validate_min_length_of(:title, 12, { message: '...' }) }
|
384
431
|
```
|
385
432
|
|
386
433
|
<br>
|
387
434
|
|
435
|
+
---
|
436
|
+
|
437
|
+
### `#assert_validates_format(:model, :attribute, :opts, :msg)`
|
388
438
|
|
389
|
-
|
390
|
-
alias: `:assert_validates_format_of`
|
439
|
+
alias: `#assert_validates_format_of`
|
391
440
|
|
392
441
|
Test for validating the format of a model's attribute with a regexp.
|
393
442
|
|
394
443
|
```ruby
|
395
|
-
|
396
|
-
|
444
|
+
let(:m) { Post.first }
|
445
|
+
|
446
|
+
it { assert_validates_format(m, :title, { with: /[a-z+]/ }) }
|
447
|
+
# or
|
448
|
+
it { _(m).must_validate_format_of(:title, { with: /[a-z]+/ }) }
|
397
449
|
```
|
398
450
|
|
399
451
|
<br>
|
400
452
|
|
453
|
+
---
|
454
|
+
|
455
|
+
### `#assert_validates_inclusion(:model, :attribute, :opts, :msg)`
|
401
456
|
|
402
|
-
|
403
|
-
alias: `:assert_validates_inclusion_of`
|
457
|
+
alias: `#assert_validates_inclusion_of`
|
404
458
|
|
405
|
-
Test for validating that a model's attribute is within a specified range or
|
459
|
+
Test for validating that a model's attribute is within a specified range or
|
460
|
+
set of values.
|
406
461
|
|
407
462
|
```ruby
|
408
|
-
|
409
|
-
|
463
|
+
let(:m) { Post.first }
|
464
|
+
|
465
|
+
it { assert_validates_inclusion(m, :status, { in: [:a, :b, :c] }) }
|
466
|
+
# or
|
467
|
+
it { _(m).must_validate_inclusion_of(:status, { in: [:a, :b, :c] }) }
|
410
468
|
```
|
411
469
|
|
412
470
|
<br>
|
413
471
|
|
472
|
+
---
|
473
|
+
|
474
|
+
### `#assert_validates_integer(:model, :attribute, :opts, :msg)`
|
414
475
|
|
415
|
-
#### `assert_validates_integer(obj, attribute, opts = {}, msg = nil)`
|
416
476
|
alias: none
|
417
477
|
|
418
478
|
Test for validating that a a model's attribute is an integer.
|
419
479
|
|
420
480
|
```ruby
|
421
|
-
|
422
|
-
|
481
|
+
let(:m) { Post.first }
|
482
|
+
|
483
|
+
it { assert_validates_integer(m, :author_id, { message: '...' }) }
|
484
|
+
# or
|
485
|
+
it { _(m).must_validate_integer_of(:author_id, { message: '...' }) }
|
423
486
|
```
|
424
487
|
|
425
488
|
<br>
|
426
489
|
|
490
|
+
---
|
427
491
|
|
428
|
-
|
429
|
-
|
492
|
+
### `#assert_validates_numericality(:model, :attribute, :opts, :msg)`
|
493
|
+
|
494
|
+
alias: `#assert_validates_numericality_of`
|
430
495
|
|
431
496
|
Test for validating that a model's attribute is numeric (number).
|
432
497
|
|
433
498
|
```ruby
|
434
|
-
|
435
|
-
|
499
|
+
let(:m) { Post.first }
|
500
|
+
|
501
|
+
it { assert_validates_numericality(m, :author_id, { message: '...' }) }
|
502
|
+
# or
|
503
|
+
it { _(m).must_validate_numericality_of(:author_id, { message: '...' }) }
|
436
504
|
```
|
437
505
|
|
438
506
|
<br>
|
439
507
|
|
508
|
+
---
|
509
|
+
|
510
|
+
### `#assert_validates_uniqueness(:model, :attribute, :opts, :msg)`
|
440
511
|
|
441
|
-
|
442
|
-
alias: `:assert_validates_uniqueness_of`
|
512
|
+
alias: `#assert_validates_uniqueness_of`
|
443
513
|
|
444
514
|
Test for validating that a model's attribute is unique.
|
445
515
|
|
446
516
|
```ruby
|
447
|
-
|
448
|
-
|
517
|
+
let(:m) { Post.first }
|
518
|
+
|
519
|
+
it { assert_validates_uniqueness(m, :urlslug, { message: '...' }) }
|
520
|
+
# or
|
521
|
+
it { _(m).must_validate_uniqueness_of(:urlslug, { message: '...' }) }
|
449
522
|
```
|
450
523
|
|
451
524
|
<br>
|
452
525
|
|
526
|
+
---
|
527
|
+
|
528
|
+
### `#assert_validates_acceptance(:model, :attribute, :opts, :msg)`
|
453
529
|
|
454
|
-
|
455
|
-
alias: `assert_validates_acceptance_of`
|
530
|
+
alias: `#assert_validates_acceptance_of`
|
456
531
|
|
457
532
|
Test for validating the acceptance of a model's attribute.
|
458
533
|
|
459
534
|
```ruby
|
460
|
-
|
461
|
-
|
535
|
+
let(:m) { Order.new }
|
536
|
+
|
537
|
+
it { assert_validates_acceptance(m, :toc, { message: '...' }) }
|
538
|
+
# or
|
539
|
+
it { _(m).must_validate_acceptance_of(:toc, { message: '...' }) }
|
462
540
|
```
|
463
541
|
|
464
542
|
<br>
|
465
543
|
|
544
|
+
---
|
545
|
+
|
546
|
+
### `#assert_validates_confirmation(:model, :attribute, :opts, :msg)`
|
466
547
|
|
467
|
-
|
468
|
-
alias: `:assert_validates_confirmation_of`
|
548
|
+
alias: `#assert_validates_confirmation_of`
|
469
549
|
|
470
550
|
Test for validating the confirmation of a model's attribute.
|
471
551
|
|
472
552
|
```ruby
|
473
|
-
|
474
|
-
|
553
|
+
let(:m) { User.new }
|
554
|
+
|
555
|
+
it { assert_validates_confirmation(m, :password, { message: '...' }) }
|
556
|
+
# or
|
557
|
+
it { _(m).must_validate_confirmation_of(:password, { message: '...' }) }
|
475
558
|
```
|
476
559
|
|
477
560
|
<br>
|
478
561
|
|
562
|
+
---
|
479
563
|
|
480
564
|
Each validation assertion have a responding negative test, ie: `refute_validate_presence()`
|
481
565
|
|
566
|
+
<br>
|
482
567
|
|
483
|
-
### Usage
|
568
|
+
### Usage Example
|
484
569
|
|
485
570
|
A model defined with validations like this:
|
486
571
|
|
@@ -505,17 +590,20 @@ let(:m) { Post.first }
|
|
505
590
|
|
506
591
|
it "should validate presence of :title column" do
|
507
592
|
assert_validates_presence(m, :title)
|
593
|
+
# or
|
594
|
+
_(m).must_validate_presence_of(:title)
|
508
595
|
end
|
509
596
|
|
510
597
|
it "should validate format of :title column with regexp" do
|
511
598
|
assert_validates_format(m, :title, /\w+/)
|
599
|
+
# or
|
600
|
+
_(m).must_validate_format_of(:title, /\w+/)
|
512
601
|
end
|
513
602
|
```
|
514
603
|
|
515
|
-
<br>
|
516
604
|
<br>
|
517
605
|
|
518
|
-
|
606
|
+
---
|
519
607
|
|
520
608
|
<br>
|
521
609
|
|
@@ -523,10 +611,13 @@ end
|
|
523
611
|
|
524
612
|
This gem also contains a collection of "helpers" that aid working with Sequel models:
|
525
613
|
|
614
|
+
### `#assert_timestamped_model(:model, :opts, :msg)`
|
526
615
|
|
527
|
-
|
616
|
+
Quickly test if a model class is timestamped with `.plugin(:timestamps)` with
|
617
|
+
[Sequel-Timestamps](http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/Timestamps.html)
|
528
618
|
|
529
|
-
|
619
|
+
> [!NOTE]
|
620
|
+
> The test examples below uses the [minitest-assert_errors](https://github.com/kematzy/minitest-assert_errors) package.
|
530
621
|
|
531
622
|
|
532
623
|
```ruby
|
@@ -534,123 +625,157 @@ Quickly test if a model class is timestamped with .plugin(:timestamps) with [Seq
|
|
534
625
|
class Comment < Sequel::Model
|
535
626
|
plugin(:timestamps)
|
536
627
|
end
|
537
|
-
|
628
|
+
|
629
|
+
assert_no_error { assert_timestamped_model(Comment) }
|
538
630
|
|
539
631
|
# on a non-timestamped model
|
540
632
|
class Post < Sequel::Model; end
|
541
|
-
proc { assert_timestamped_model(Post) }.must_have_error(/Not a \.plugin\(:timestamps\) model, available plugins are/)
|
542
|
-
```
|
543
633
|
|
544
|
-
|
634
|
+
msg = /Not a \.plugin\(:timestamps\) model, available plugins are/
|
545
635
|
|
546
|
-
|
636
|
+
assert_error_raised(msg) { assert_timestamped_model(Post) }
|
637
|
+
```
|
638
|
+
|
639
|
+
> [!TIP]
|
640
|
+
> You can also pass attributes to the created model in the tests via the `opts` hash like this:
|
547
641
|
|
548
642
|
```ruby
|
549
|
-
|
643
|
+
assert_no_error do
|
644
|
+
assert_timestamped_model(Comment, {body: "I think...", email: "e@email.com"})
|
645
|
+
end
|
550
646
|
```
|
551
|
-
|
552
|
-
Timestamps can be declared globally for all models via `Sequel::Model.plugin(:timestamps)` before the models are migrated.
|
553
647
|
|
648
|
+
Timestamps can be declared globally for all models via `Sequel::Model.plugin(:timestamps)` before
|
649
|
+
the models are migrated.
|
650
|
+
|
651
|
+
<br>
|
652
|
+
|
653
|
+
---
|
554
654
|
|
555
|
-
|
655
|
+
### `#assert_timestamped_model_instance(:model, :opts, :msg)`
|
556
656
|
|
557
|
-
Test if a model instance is timestamped with the .plugin(:timestamps) via
|
657
|
+
Test if a model instance is timestamped with the .plugin(:timestamps) via
|
658
|
+
[Sequel-Timestamps](http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/Timestamps.html)
|
558
659
|
|
559
660
|
```ruby
|
560
661
|
let(:m) { Post.create(title: "Dummy") }
|
561
|
-
proc { assert_timestamped_model_instance(m) }.wont_have_error
|
562
|
-
```
|
563
662
|
|
663
|
+
assert_no_error { assert_timestamped_model_instance(m) }
|
664
|
+
```
|
564
665
|
|
565
666
|
You can also test if an updated record is correctly timestamped
|
566
667
|
|
567
668
|
```ruby
|
568
669
|
m.title = "Updated"
|
569
670
|
m.save
|
570
|
-
|
671
|
+
|
672
|
+
assert_no_error do
|
673
|
+
assert_timestamped_model_instance(m, updated_record: true)
|
674
|
+
end
|
571
675
|
```
|
572
676
|
|
573
677
|
Or alternatively test if an updated record is wrongly timestamped
|
574
678
|
|
575
679
|
```ruby
|
576
680
|
let(:m) { Post.create(title: "Dummy", updated_at: Time.now) }
|
577
|
-
proc { assert_timestamped_model_instance(m, updated_record: false) }.must_have_error(/expected #.updated_at to be NIL on new record/)
|
578
|
-
```
|
579
681
|
|
682
|
+
msg = /expected #.updated_at to be NIL on new record/
|
683
|
+
|
684
|
+
assert_error_raised(msg) do
|
685
|
+
assert_timestamped_model_instance(m, updated_record: false)
|
686
|
+
end
|
687
|
+
```
|
580
688
|
|
581
689
|
<br>
|
582
690
|
|
583
|
-
|
691
|
+
---
|
692
|
+
|
693
|
+
### `#assert_paranoid_model(:model, :opts, :msg)`
|
584
694
|
|
585
|
-
Test if a model class is paranoid with .plugin(:paranoid) via
|
695
|
+
Test if a model class is paranoid with .plugin(:paranoid) via
|
696
|
+
[Sequel-Paranoid](https://github.com/sdepold/sequel-paranoid)
|
586
697
|
|
587
698
|
```ruby
|
588
699
|
# Declared locally in the Model
|
589
700
|
class Comment < Sequel::Model
|
590
701
|
plugin(:paranoid)
|
591
702
|
end
|
592
|
-
|
703
|
+
|
704
|
+
assert_no_error { assert_paranoid_model(Comment) }
|
593
705
|
|
594
706
|
# on a non-paranoid model
|
595
707
|
class Post < Sequel::Model; end
|
596
|
-
proc { assert_paranoid_model(Post) }.must_have_error(/Not a plugin\(:paranoid\) model, available plugins are/)
|
597
|
-
```
|
598
708
|
|
599
|
-
|
709
|
+
msg = /Not a plugin\(:paranoid\) model, available plugins are/
|
710
|
+
|
711
|
+
assert_error_raised(msg) { assert_paranoid_model(Post) }
|
712
|
+
```
|
600
713
|
|
601
|
-
|
714
|
+
> [!TIP]
|
715
|
+
> You can also pass attributes to the created model in the tests via the `opts` hash like this:
|
602
716
|
|
603
717
|
```ruby
|
604
|
-
|
718
|
+
assert_no_error do
|
719
|
+
assert_timestamped_model(Comment, { body: "I think...", email: "e@email.com" })
|
720
|
+
end
|
605
721
|
```
|
606
722
|
|
607
|
-
|
608
723
|
<br>
|
609
724
|
|
610
|
-
|
725
|
+
---
|
611
726
|
|
612
|
-
|
727
|
+
### `#refute_timestamped_model(:model, :msg)`
|
613
728
|
|
729
|
+
Test to ensure a model is NOT declared with .plugin(:timestamps) using
|
730
|
+
[Sequel-Timestamps](http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/Timestamps.html)
|
614
731
|
|
615
|
-
Test if a model class is paranoid with .plugin(:paranoid) via
|
732
|
+
Test if a model class is paranoid with .plugin(:paranoid) via
|
733
|
+
[Sequel-Paranoid](https://github.com/sdepold/sequel-paranoid)
|
616
734
|
|
617
735
|
```ruby
|
618
736
|
class Comment < Sequel::Model
|
619
737
|
plugin(:timestamps)
|
620
738
|
end
|
621
|
-
|
739
|
+
|
740
|
+
msg = /expected Comment to NOT be a :timestamped model, but it was/
|
741
|
+
|
742
|
+
assert_error_raised(msg) do
|
743
|
+
refute_timestamped_model(Comment)
|
744
|
+
end
|
622
745
|
|
623
746
|
# on a non-timestamped model
|
624
747
|
class Post < Sequel::Model; end
|
748
|
+
|
625
749
|
it { refute_timestamped_model(Post) }
|
626
750
|
```
|
627
751
|
|
628
752
|
<br>
|
629
753
|
|
630
|
-
|
754
|
+
---
|
755
|
+
|
756
|
+
### `#refute_paranoid_model(:model, :msg)`
|
631
757
|
|
632
|
-
Test to ensure a model is NOT declared with .plugin(:paranoid) using
|
758
|
+
Test to ensure a model is NOT declared with .plugin(:paranoid) using
|
759
|
+
[Sequel-Paranoid](https://github.com/sdepold/sequel-paranoid)
|
633
760
|
|
634
761
|
```ruby
|
635
762
|
class Comment < Sequel::Model
|
636
763
|
plugin(:paranoid)
|
637
764
|
end
|
638
|
-
|
765
|
+
|
766
|
+
msg = /expected Comment to NOT be a :paranoid model, but it was/
|
767
|
+
|
768
|
+
assert_error_raised(msg) { refute_paranoid_model(Comment) }
|
639
769
|
|
640
770
|
# on a non-paranoid model
|
641
771
|
class Post < Sequel::Model; end
|
772
|
+
|
642
773
|
it { refute_paranoid_model(Post) }
|
643
774
|
```
|
644
775
|
|
645
|
-
|
646
776
|
<br>
|
647
777
|
|
648
|
-
|
649
|
-
<br>
|
650
|
-
|
651
|
-
----
|
652
|
-
|
653
|
-
<br>
|
778
|
+
---
|
654
779
|
|
655
780
|
## Miscellaneous Helpers
|
656
781
|
|
@@ -658,7 +783,7 @@ This gem also contains a collection of "helpers" that aid working with Sequel mo
|
|
658
783
|
|
659
784
|
<br>
|
660
785
|
|
661
|
-
|
786
|
+
### `#ensure_working_CRUD(:model, :attribute)`
|
662
787
|
|
663
788
|
Enables quick tests to ensure that the basic CRUD functionality is working correctly for a Model
|
664
789
|
|
@@ -666,20 +791,21 @@ Enables quick tests to ensure that the basic CRUD functionality is working corre
|
|
666
791
|
ensure_working_CRUD(User, :name)
|
667
792
|
```
|
668
793
|
|
669
|
-
|
670
|
-
|
671
|
-
|
794
|
+
> [!NOTE]
|
795
|
+
> - the passed `:model` argument must be the actual Model class and NOT a string or symbol
|
796
|
+
> - the passed attribute `:attribute` must be a String attribute or the tests will fail
|
672
797
|
|
673
|
-
|
798
|
+
<br>
|
799
|
+
|
800
|
+
## Dependencies
|
674
801
|
|
675
802
|
This test depends upon being able to create a new model instance for each test via using
|
676
803
|
[Sequel Factory's](https://github.com/mjackson/sequel-factory) `#make()` method
|
677
804
|
|
678
|
-
|
679
805
|
<br>
|
680
806
|
<br>
|
681
807
|
|
682
|
-
|
808
|
+
---
|
683
809
|
|
684
810
|
<br>
|
685
811
|
|
@@ -694,67 +820,66 @@ gem 'minitest-sequel'
|
|
694
820
|
And then execute:
|
695
821
|
|
696
822
|
```bash
|
697
|
-
|
823
|
+
bundle
|
698
824
|
```
|
699
825
|
|
700
826
|
Or install it yourself as:
|
701
827
|
|
702
828
|
```bash
|
703
|
-
|
829
|
+
gem install minitest-sequel
|
704
830
|
```
|
705
831
|
|
706
|
-
##
|
707
|
-
|
708
|
-
In your project's `spec/spec_helper.rb` or `test/test_helper.rb` file ensure the following code is present:
|
832
|
+
## Within Your Project
|
709
833
|
|
834
|
+
In your project's `spec/spec_helper.rb` or `test/test_helper.rb` file ensure
|
835
|
+
the following code is present:
|
710
836
|
|
711
|
-
```ruby
|
837
|
+
```ruby
|
712
838
|
gem 'minitest'
|
713
839
|
|
714
840
|
require 'minitest/autorun'
|
715
|
-
require 'minitest/sequel' # NB!!
|
841
|
+
require 'minitest/sequel' # NB!! must be loaded after minitest/autorun
|
716
842
|
|
717
843
|
require 'sqlite3' # using sqlite for tests
|
718
844
|
|
719
|
-
|
845
|
+
# The preferred default validations plugin, which uses class-level methods.
|
720
846
|
Sequel::Model.plugin(:validation_class_methods)
|
721
847
|
|
722
|
-
|
848
|
+
# connect to database
|
723
849
|
DB = Sequel.sqlite # :memory
|
724
850
|
|
725
|
-
|
851
|
+
## add migrations and seeds below
|
726
852
|
|
727
853
|
DB.create_table(:posts) do
|
728
854
|
primary_key :id
|
729
855
|
# <snip...>
|
730
856
|
end
|
731
857
|
|
732
|
-
|
858
|
+
# <snip...>
|
733
859
|
```
|
734
860
|
|
735
861
|
Then in your tests you should be good to go when using the sequel assertions.
|
736
862
|
|
737
|
-
|
738
|
-
|
739
863
|
## Development
|
740
864
|
|
741
|
-
After checking out the repo, run `bundle install` to install all dependencies.
|
865
|
+
After checking out the repo, run `bundle install` to install all dependencies.
|
866
|
+
Then, run `rake spec` to run the tests.
|
742
867
|
|
743
868
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
744
869
|
|
745
|
-
To release a new version, update the version number in `version.rb`, and then run
|
746
|
-
which will create a git tag for the version, push git commits and
|
747
|
-
[rubygems.org](https://rubygems.org).
|
748
|
-
|
870
|
+
To release a new version, update the version number in `version.rb`, and then run
|
871
|
+
`bundle exec rake release`, which will create a git tag for the version, push git commits and
|
872
|
+
tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
749
873
|
|
750
874
|
## Contributing
|
751
875
|
|
752
|
-
Bug reports and pull requests are welcome on GitHub at
|
753
|
-
|
754
|
-
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere
|
755
|
-
to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
876
|
+
Bug reports and pull requests are welcome on GitHub at
|
877
|
+
[Issues](https://github.com/kematzy/minitest-sequel/issues).
|
756
878
|
|
879
|
+
This project is intended to be a safe, welcoming space for collaboration, and contributors are
|
880
|
+
expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
757
881
|
|
758
882
|
## License
|
759
883
|
|
760
|
-
The gem is available as open source under the terms of the
|
884
|
+
The gem is available as open source under the terms of the
|
885
|
+
[MIT License](http://opensource.org/licenses/MIT).
|