modelish 0.3.0 → 1.0.0.pre.1
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.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rspec +3 -1
- data/.ruby-version +1 -1
- data/.travis.yml +14 -0
- data/Appraisals +11 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +5 -1
- data/README.md +5 -0
- data/gemfiles/hashie_1.gemfile +7 -0
- data/gemfiles/hashie_2.gemfile +7 -0
- data/gemfiles/hashie_3.gemfile +7 -0
- data/lib/modelish/base.rb +108 -72
- data/lib/modelish/configuration.rb +9 -8
- data/lib/modelish/property_translations.rb +23 -11
- data/lib/modelish/property_types.rb +67 -50
- data/lib/modelish/validations.rb +70 -51
- data/lib/modelish/version.rb +3 -1
- data/lib/modelish.rb +3 -1
- data/modelish.gemspec +20 -15
- data/spec/modelish/base_spec.rb +203 -182
- data/spec/modelish/configuration_spec.rb +26 -19
- data/spec/modelish/property_translations_spec.rb +47 -39
- data/spec/modelish/property_types_spec.rb +53 -45
- data/spec/modelish/validations_spec.rb +296 -256
- data/spec/modelish_spec.rb +5 -3
- data/spec/spec_helper.rb +97 -2
- data/spec/support/property_examples.rb +15 -12
- data/spec/support/typed_property_examples.rb +39 -35
- data/spec/support/unknown_property_examples.rb +6 -4
- data/spec/support/validation_examples.rb +29 -23
- metadata +136 -103
- data/.ruby-gemset +0 -1
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
|
-
describe Modelish::Validations do
|
5
|
+
RSpec.describe Modelish::Validations do
|
4
6
|
let(:model_class) { Class.new { include Modelish::Validations } }
|
5
7
|
|
6
8
|
let(:property_name) { :validated_property }
|
@@ -9,543 +11,564 @@ describe Modelish::Validations do
|
|
9
11
|
|
10
12
|
subject { model_class }
|
11
13
|
|
12
|
-
it {
|
14
|
+
it { is_expected.to respond_to(:validate_required?) }
|
13
15
|
|
14
|
-
describe
|
16
|
+
describe '.validate_required?' do
|
15
17
|
subject { model_class.validate_required?(property_name => value) }
|
16
18
|
|
17
|
-
context
|
19
|
+
context 'when value is nil' do
|
18
20
|
let(:value) { nil }
|
19
21
|
|
20
|
-
it {
|
22
|
+
it { is_expected.to eq(false) }
|
21
23
|
end
|
22
24
|
|
23
|
-
context
|
25
|
+
context 'when value is blank' do
|
24
26
|
let(:value) { ' ' }
|
25
27
|
|
26
|
-
it {
|
28
|
+
it { is_expected.to eq(false) }
|
27
29
|
end
|
28
30
|
|
29
|
-
context
|
31
|
+
context 'when value is not blank' do
|
30
32
|
let(:value) { Object.new }
|
31
33
|
|
32
|
-
it {
|
34
|
+
it { is_expected.to eq(true) }
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
|
-
it {
|
38
|
+
it { is_expected.to respond_to(:validate_required) }
|
37
39
|
|
38
|
-
describe
|
40
|
+
describe '.validate_required' do
|
39
41
|
subject { errors }
|
40
42
|
let(:errors) { model_class.validate_required(property_name => value) }
|
41
43
|
|
42
|
-
context
|
44
|
+
context 'when value is nil' do
|
43
45
|
let(:value) { nil }
|
44
46
|
|
45
|
-
it {
|
47
|
+
it { is_expected.to_not be_empty }
|
46
48
|
|
47
|
-
describe
|
49
|
+
describe 'first error' do
|
48
50
|
subject { errors.first }
|
49
51
|
|
50
|
-
it {
|
51
|
-
its(:message) {
|
52
|
+
it { is_expected.to be_an ArgumentError }
|
53
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
55
|
-
context
|
57
|
+
context 'when value is blank' do
|
56
58
|
let(:value) { ' ' }
|
57
59
|
|
58
|
-
it {
|
60
|
+
it { is_expected.to_not be_empty }
|
59
61
|
|
60
|
-
describe
|
62
|
+
describe 'first error' do
|
61
63
|
subject { errors.first }
|
62
64
|
|
63
|
-
it {
|
64
|
-
its(:message) {
|
65
|
+
it { is_expected.to be_an ArgumentError }
|
66
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
68
|
-
context
|
70
|
+
context 'when value is not blank' do
|
69
71
|
let(:value) { Object.new }
|
70
72
|
|
71
|
-
it {
|
73
|
+
it { is_expected.to be_empty }
|
72
74
|
end
|
73
75
|
end
|
74
76
|
|
75
|
-
it {
|
77
|
+
it { is_expected.to respond_to(:validate_required!) }
|
76
78
|
|
77
|
-
describe
|
79
|
+
describe '.validate_required!' do
|
78
80
|
subject { model_class.validate_required!(property_name => value) }
|
79
81
|
|
80
|
-
context
|
82
|
+
context 'when value is nil' do
|
81
83
|
let(:value) { nil }
|
82
84
|
|
83
|
-
it
|
85
|
+
it 'raises an ArgumentError' do
|
84
86
|
expect { subject }.to raise_error(ArgumentError)
|
85
87
|
end
|
86
88
|
|
87
|
-
it
|
88
|
-
expect { subject }.to raise_error
|
89
|
+
it 'includes the name in the error message' do
|
90
|
+
expect { subject }.to raise_error do |e|
|
91
|
+
expect(e.message).to match(/#{property_name}/i)
|
92
|
+
end
|
89
93
|
end
|
90
94
|
end
|
91
95
|
|
92
|
-
context
|
96
|
+
context 'when value is blank' do
|
93
97
|
let(:value) { ' ' }
|
94
98
|
|
95
|
-
it
|
99
|
+
it 'raises an ArgumentError' do
|
96
100
|
expect { subject }.to raise_error(ArgumentError)
|
97
101
|
end
|
98
102
|
|
99
|
-
it
|
100
|
-
expect { subject }.to raise_error
|
103
|
+
it 'includes the name in the error message' do
|
104
|
+
expect { subject }.to raise_error do |e|
|
105
|
+
expect(e.message).to match(/#{property_name}/i)
|
106
|
+
end
|
101
107
|
end
|
102
108
|
end
|
103
109
|
|
104
|
-
context
|
110
|
+
context 'when value is not blank' do
|
105
111
|
let(:value) { 'valid value' }
|
106
112
|
|
107
|
-
it
|
113
|
+
it 'does not raise any errors' do
|
108
114
|
expect { subject }.to_not raise_error
|
109
115
|
end
|
110
116
|
end
|
111
117
|
end
|
112
118
|
|
113
|
-
it {
|
119
|
+
it { is_expected.to respond_to(:validate_length) }
|
114
120
|
|
115
|
-
describe
|
121
|
+
describe '.validate_length' do
|
116
122
|
subject { model_class.validate_length(property_name, value, max_length) }
|
117
123
|
let(:max_length) { 10 }
|
118
124
|
|
119
|
-
context
|
125
|
+
context 'when value is longer than max_length' do
|
120
126
|
let(:value) { 'a' * (max_length + 1) }
|
121
127
|
|
122
|
-
it {
|
123
|
-
its(:message) {
|
124
|
-
its(:message) {
|
128
|
+
it { is_expected.to be_an ArgumentError }
|
129
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
130
|
+
its(:message) { is_expected.to match(/#{max_length}/) }
|
125
131
|
end
|
126
132
|
|
127
|
-
context
|
133
|
+
context 'when value is shorter than max_length' do
|
128
134
|
let(:value) { 'a' * (max_length - 1) }
|
129
135
|
|
130
|
-
it {
|
136
|
+
it { is_expected.to be_nil }
|
131
137
|
end
|
132
138
|
|
133
|
-
context
|
139
|
+
context 'when value is the same length as max_length' do
|
134
140
|
let(:value) { 'a' * max_length }
|
135
141
|
|
136
|
-
it {
|
142
|
+
it { is_expected.to be_nil }
|
137
143
|
end
|
138
144
|
|
139
|
-
context
|
145
|
+
context 'when value is nil' do
|
140
146
|
let(:value) { nil }
|
141
147
|
|
142
|
-
it {
|
148
|
+
it { is_expected.to be_nil }
|
143
149
|
end
|
144
150
|
|
145
|
-
context
|
146
|
-
let(:value) { double(:
|
151
|
+
context 'when max_length is nil' do
|
152
|
+
let(:value) { double(length: 50) }
|
147
153
|
let(:max_length) { nil }
|
148
154
|
|
149
|
-
it {
|
155
|
+
it { is_expected.to be_nil }
|
150
156
|
end
|
151
157
|
end
|
152
158
|
|
153
|
-
it {
|
159
|
+
it { is_expected.to respond_to(:validate_length?) }
|
154
160
|
|
155
|
-
describe
|
161
|
+
describe '.validate_length?' do
|
156
162
|
subject { model_class.validate_length?(property_name, value, max_length) }
|
157
163
|
let(:max_length) { 16 }
|
158
164
|
|
159
|
-
context
|
165
|
+
context 'when value is longer than max_length' do
|
160
166
|
let(:value) { 'a' * (max_length + 1) }
|
161
167
|
|
162
|
-
it {
|
168
|
+
it { is_expected.to eq(false) }
|
163
169
|
end
|
164
170
|
|
165
|
-
context
|
171
|
+
context 'when value is shorter than max_length' do
|
166
172
|
let(:value) { 'a' * (max_length - 1) }
|
167
173
|
|
168
|
-
it {
|
174
|
+
it { is_expected.to eq(true) }
|
169
175
|
end
|
170
176
|
|
171
|
-
context
|
177
|
+
context 'when value is the same length as max_length' do
|
172
178
|
let(:value) { 'a' * max_length }
|
173
179
|
|
174
|
-
it {
|
180
|
+
it { is_expected.to eq(true) }
|
175
181
|
end
|
176
182
|
|
177
|
-
context
|
183
|
+
context 'when value is nil' do
|
178
184
|
let(:value) { nil }
|
179
185
|
|
180
|
-
it {
|
186
|
+
it { is_expected.to eq(true) }
|
181
187
|
end
|
182
188
|
|
183
|
-
context
|
189
|
+
context 'when max_length is nil' do
|
184
190
|
let(:value) { Object.new }
|
185
191
|
let(:max_length) { nil }
|
186
192
|
|
187
|
-
it {
|
193
|
+
it { is_expected.to eq(true) }
|
188
194
|
end
|
189
195
|
end
|
190
196
|
|
191
|
-
it {
|
197
|
+
it { is_expected.to respond_to(:validate_length!) }
|
192
198
|
|
193
|
-
describe
|
199
|
+
describe '.validate_length!' do
|
194
200
|
subject { model_class.validate_length!(property_name, value, max_length) }
|
195
201
|
let(:max_length) { 8 }
|
196
202
|
|
197
|
-
context
|
203
|
+
context 'when value is longer than max_length' do
|
198
204
|
let(:value) { 'a' * (max_length + 1) }
|
199
205
|
|
200
|
-
it
|
206
|
+
it 'raises an ArgumentError' do
|
201
207
|
expect { subject }.to raise_error(ArgumentError)
|
202
208
|
end
|
203
209
|
|
204
|
-
it
|
205
|
-
expect { subject }.to raise_error
|
210
|
+
it 'includes the name in the error message' do
|
211
|
+
expect { subject }.to raise_error do |e|
|
212
|
+
expect(e.message).to match(/#{property_name}/i)
|
213
|
+
end
|
206
214
|
end
|
207
215
|
|
208
|
-
it
|
209
|
-
expect { subject }.to raise_error
|
216
|
+
it 'includes the max length in the error message' do
|
217
|
+
expect { subject }.to raise_error do |e|
|
218
|
+
expect(e.message).to match(/#{max_length}/)
|
219
|
+
end
|
210
220
|
end
|
211
221
|
end
|
212
222
|
|
213
|
-
context
|
223
|
+
context 'when value is shorter than max_length' do
|
214
224
|
let(:value) { 'a' * (max_length - 1) }
|
215
225
|
|
216
|
-
it
|
226
|
+
it 'does not raise an error' do
|
217
227
|
expect { subject }.to_not raise_error
|
218
228
|
end
|
219
229
|
end
|
220
230
|
|
221
|
-
context
|
231
|
+
context 'when value is nil' do
|
222
232
|
let(:value) { nil }
|
223
233
|
|
224
|
-
it
|
234
|
+
it 'does not raise an error' do
|
225
235
|
expect { subject }.to_not raise_error
|
226
236
|
end
|
227
237
|
end
|
228
238
|
|
229
|
-
context
|
239
|
+
context 'when max_length is nil' do
|
230
240
|
let(:max_length) { nil }
|
231
241
|
let(:value) { 'aaaaaaaaaaa' }
|
232
242
|
|
233
|
-
it
|
243
|
+
it 'does not raise an error' do
|
234
244
|
expect { subject }.to_not raise_error
|
235
245
|
end
|
236
246
|
end
|
237
247
|
end
|
238
248
|
|
239
|
-
it {
|
249
|
+
it { is_expected.to respond_to(:validate_type) }
|
240
250
|
|
241
|
-
describe
|
242
|
-
subject
|
251
|
+
describe '.validate_type' do
|
252
|
+
subject do
|
253
|
+
model_class.validate_type(property_name, property_value, property_type)
|
254
|
+
end
|
243
255
|
|
244
|
-
context
|
256
|
+
context 'for type Integer' do
|
245
257
|
let(:property_type) { Integer }
|
246
258
|
|
247
|
-
context
|
259
|
+
context 'with nil value' do
|
248
260
|
let(:property_value) { nil }
|
249
261
|
|
250
|
-
it {
|
262
|
+
it { is_expected.to be_nil }
|
251
263
|
end
|
252
264
|
|
253
|
-
context
|
265
|
+
context 'with valid int' do
|
254
266
|
let(:property_value) { 42 }
|
255
267
|
|
256
|
-
it {
|
268
|
+
it { is_expected.to be_nil }
|
257
269
|
end
|
258
270
|
|
259
|
-
context
|
271
|
+
context 'with valid string' do
|
260
272
|
let(:property_value) { '42' }
|
261
273
|
|
262
|
-
it {
|
274
|
+
it { is_expected.to be_nil }
|
263
275
|
end
|
264
276
|
|
265
|
-
context
|
277
|
+
context 'with invalid value' do
|
266
278
|
let(:property_value) { 42.99 }
|
267
279
|
|
268
|
-
it {
|
269
|
-
its(:message) {
|
270
|
-
its(:message) {
|
271
|
-
its(:message) {
|
280
|
+
it { is_expected.to be_an ArgumentError }
|
281
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
282
|
+
its(:message) { is_expected.to match(/#{property_value.inspect}/i) }
|
283
|
+
its(:message) { is_expected.to match(/#{property_type}/i) }
|
272
284
|
end
|
273
285
|
end
|
274
286
|
|
275
|
-
context
|
287
|
+
context 'for type Float' do
|
276
288
|
let(:property_type) { Float }
|
277
289
|
|
278
|
-
context
|
290
|
+
context 'with nil value' do
|
279
291
|
let(:property_value) { nil }
|
280
292
|
|
281
|
-
it {
|
293
|
+
it { is_expected.to be_nil }
|
282
294
|
end
|
283
295
|
|
284
|
-
context
|
296
|
+
context 'with valid float value' do
|
285
297
|
let(:property_value) { 42.5 }
|
286
298
|
|
287
|
-
it {
|
299
|
+
it { is_expected.to be_nil }
|
288
300
|
end
|
289
301
|
|
290
|
-
context
|
302
|
+
context 'with valid string' do
|
291
303
|
let(:property_value) { '42.5' }
|
292
304
|
|
293
|
-
it {
|
305
|
+
it { is_expected.to be_nil }
|
294
306
|
end
|
295
307
|
|
296
|
-
context
|
308
|
+
context 'with valid type that can be upcast' do
|
297
309
|
let(:property_value) { 42 }
|
298
310
|
|
299
|
-
it {
|
311
|
+
it { is_expected.to be_nil }
|
300
312
|
end
|
301
313
|
|
302
|
-
context
|
314
|
+
context 'with invalid value' do
|
303
315
|
let(:property_value) { 'forty-two' }
|
304
316
|
|
305
|
-
it {
|
306
|
-
its(:message) {
|
307
|
-
its(:message) {
|
308
|
-
its(:message) {
|
317
|
+
it { is_expected.to be_an ArgumentError }
|
318
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
319
|
+
its(:message) { is_expected.to match(/#{property_value.inspect}/i) }
|
320
|
+
its(:message) { is_expected.to match(/#{property_type}/i) }
|
309
321
|
end
|
310
322
|
end
|
311
323
|
|
312
|
-
context
|
324
|
+
context 'for type Array' do
|
313
325
|
let(:property_type) { Array }
|
314
326
|
|
315
|
-
context
|
327
|
+
context 'with nil' do
|
316
328
|
let(:property_value) { nil }
|
317
329
|
|
318
|
-
it {
|
330
|
+
it { is_expected.to be_nil }
|
319
331
|
end
|
320
|
-
context
|
321
|
-
let(:property_value) { [1,2,3] }
|
332
|
+
context 'with a valid array' do
|
333
|
+
let(:property_value) { [1, 2, 3] }
|
322
334
|
|
323
|
-
it {
|
335
|
+
it { is_expected.to be_nil }
|
324
336
|
end
|
325
337
|
|
326
|
-
context
|
327
|
-
let(:property_value) { {1 => 2, 3 => 4} }
|
338
|
+
context 'with an invalid value' do
|
339
|
+
let(:property_value) { { 1 => 2, 3 => 4 } }
|
340
|
+
let(:property_value_regex) do
|
341
|
+
property_value.inspect.gsub('{', '\{').gsub('}', '\}')
|
342
|
+
end
|
328
343
|
|
329
|
-
it {
|
330
|
-
its(:message) {
|
331
|
-
its(:message) {
|
332
|
-
its(:message) {
|
344
|
+
it { is_expected.to be_an ArgumentError }
|
345
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
346
|
+
its(:message) { is_expected.to match(/#{property_value_regex}/i) }
|
347
|
+
its(:message) { is_expected.to match(/#{property_type}/i) }
|
333
348
|
end
|
334
349
|
end
|
335
350
|
|
336
|
-
context
|
351
|
+
context 'for an arbitrary class' do
|
337
352
|
let(:property_type) { Hash }
|
338
353
|
|
339
|
-
context
|
354
|
+
context 'with nil value' do
|
340
355
|
let(:property_value) { nil }
|
341
356
|
|
342
|
-
it {
|
357
|
+
it { is_expected.to be_nil }
|
343
358
|
end
|
344
359
|
|
345
|
-
context
|
346
|
-
let(:property_value) { {1 => 2} }
|
360
|
+
context 'with valid hash value' do
|
361
|
+
let(:property_value) { { 1 => 2 } }
|
347
362
|
|
348
|
-
it {
|
363
|
+
it { is_expected.to be_nil }
|
349
364
|
end
|
350
365
|
|
351
|
-
context
|
352
|
-
let(:property_value) { [1,2] }
|
366
|
+
context 'with invalid value' do
|
367
|
+
let(:property_value) { [1, 2] }
|
353
368
|
|
354
|
-
it {
|
355
|
-
its(:message) {
|
356
|
-
its(:message) {
|
357
|
-
its(:message) {
|
369
|
+
it { is_expected.to be_an ArgumentError }
|
370
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
371
|
+
its(:message) { is_expected.to match(/#{property_value.inspect}/i) }
|
372
|
+
its(:message) { is_expected.to match(/#{property_type}/i) }
|
358
373
|
end
|
359
374
|
end
|
360
375
|
|
361
|
-
context
|
376
|
+
context 'for type Date' do
|
362
377
|
let(:property_type) { Date }
|
363
378
|
|
364
|
-
context
|
379
|
+
context 'with nil value' do
|
365
380
|
let(:property_value) { nil }
|
366
381
|
|
367
|
-
it {
|
382
|
+
it { is_expected.to be_nil }
|
368
383
|
end
|
369
384
|
|
370
|
-
context
|
385
|
+
context 'with valid string' do
|
371
386
|
let(:property_value) { '2011-03-10' }
|
372
387
|
|
373
|
-
it {
|
388
|
+
it { is_expected.to be_nil }
|
374
389
|
end
|
375
390
|
|
376
|
-
context
|
391
|
+
context 'with valid Date' do
|
377
392
|
let(:property_value) { Date.civil(2011, 3, 10) }
|
378
393
|
|
379
|
-
it {
|
394
|
+
it { is_expected.to be_nil }
|
380
395
|
end
|
381
396
|
|
382
|
-
context
|
397
|
+
context 'with invalid value' do
|
383
398
|
let(:property_value) { 'this is not a date' }
|
384
399
|
|
385
|
-
it {
|
386
|
-
its(:message) {
|
387
|
-
its(:message) {
|
388
|
-
its(:message) {
|
400
|
+
it { is_expected.to be_an ArgumentError }
|
401
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
402
|
+
its(:message) { is_expected.to match(/#{property_value.inspect}/i) }
|
403
|
+
its(:message) { is_expected.to match(/#{property_type}/i) }
|
389
404
|
end
|
390
405
|
end
|
391
406
|
|
392
|
-
context
|
407
|
+
context 'for type DateTime' do
|
393
408
|
let(:property_type) { DateTime }
|
394
409
|
|
395
|
-
context
|
410
|
+
context 'with nil value' do
|
396
411
|
let(:property_value) { nil }
|
397
412
|
|
398
|
-
it {
|
413
|
+
it { is_expected.to be_nil }
|
399
414
|
end
|
400
415
|
|
401
|
-
context
|
416
|
+
context 'with valid string' do
|
402
417
|
let(:property_value) { '2011-03-10T03:15:23-05:00' }
|
403
418
|
|
404
|
-
it {
|
419
|
+
it { is_expected.to be_nil }
|
405
420
|
end
|
406
421
|
|
407
|
-
context
|
408
|
-
let(:property_value)
|
422
|
+
context 'with valid DateTime' do
|
423
|
+
let(:property_value) do
|
424
|
+
DateTime.civil(2011, 3, 10, 3, 15, 23, Rational(-5, 24))
|
425
|
+
end
|
409
426
|
|
410
|
-
it {
|
427
|
+
it { is_expected.to be_nil }
|
411
428
|
end
|
412
429
|
|
413
|
-
context
|
430
|
+
context 'with invalid value' do
|
414
431
|
let(:property_value) { 'this is not a date time' }
|
415
432
|
|
416
|
-
it {
|
417
|
-
its(:message) {
|
418
|
-
its(:message) {
|
419
|
-
its(:message) {
|
433
|
+
it { is_expected.to be_an ArgumentError }
|
434
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
435
|
+
its(:message) { is_expected.to match(/#{property_value.inspect}/i) }
|
436
|
+
its(:message) { is_expected.to match(/#{property_type}/i) }
|
420
437
|
end
|
421
438
|
end
|
422
439
|
|
423
|
-
context
|
440
|
+
context 'for a Symbol type' do
|
424
441
|
let(:property_type) { Symbol }
|
425
442
|
|
426
|
-
context
|
443
|
+
context 'with nil value' do
|
427
444
|
let(:property_value) { nil }
|
428
445
|
|
429
|
-
it {
|
446
|
+
it { is_expected.to be_nil }
|
430
447
|
end
|
431
448
|
|
432
|
-
context
|
449
|
+
context 'with a valid string' do
|
433
450
|
let(:property_value) { 'my string' }
|
434
451
|
|
435
|
-
it {
|
452
|
+
it { is_expected.to be_nil }
|
436
453
|
end
|
437
454
|
|
438
|
-
context
|
455
|
+
context 'with a valid symbol' do
|
439
456
|
let(:property_value) { :my_symbol }
|
440
457
|
|
441
|
-
it {
|
458
|
+
it { is_expected.to be_nil }
|
442
459
|
end
|
443
460
|
|
444
|
-
context
|
461
|
+
context 'with an invalid value' do
|
445
462
|
let(:property_value) { Object.new }
|
446
463
|
|
447
|
-
it {
|
448
|
-
its(:message) {
|
449
|
-
its(:message) {
|
450
|
-
its(:message) {
|
464
|
+
it { is_expected.to be_an ArgumentError }
|
465
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
466
|
+
its(:message) { is_expected.to match(/#{property_value.inspect}/i) }
|
467
|
+
its(:message) { is_expected.to match(/#{property_type}/i) }
|
451
468
|
end
|
452
469
|
end
|
453
470
|
|
454
|
-
context
|
471
|
+
context 'when type is nil' do
|
455
472
|
let(:property_type) { nil }
|
456
473
|
|
457
|
-
context
|
458
|
-
let(:property_value) { 'foo' }
|
474
|
+
context 'with any value' do
|
475
|
+
let(:property_value) { 'foo' }
|
459
476
|
|
460
|
-
it {
|
477
|
+
it { is_expected.to be_nil }
|
461
478
|
end
|
462
479
|
end
|
463
480
|
end
|
464
481
|
|
465
|
-
it {
|
482
|
+
it { is_expected.to respond_to(:validate_type!) }
|
466
483
|
|
467
|
-
describe
|
468
|
-
subject
|
484
|
+
describe '.validate_type!' do
|
485
|
+
subject do
|
486
|
+
model_class.validate_type!(property_name, property_value, property_type)
|
487
|
+
end
|
469
488
|
|
470
|
-
context
|
489
|
+
context 'for type Integer' do
|
471
490
|
let(:property_type) { Integer }
|
472
491
|
|
473
|
-
context
|
492
|
+
context 'with nil value' do
|
474
493
|
let(:property_value) { nil }
|
475
494
|
|
476
|
-
it
|
495
|
+
it 'does not raise any errors' do
|
477
496
|
expect { subject }.to_not raise_error
|
478
497
|
end
|
479
498
|
end
|
480
499
|
|
481
|
-
context
|
500
|
+
context 'with valid int' do
|
482
501
|
let(:property_value) { 42 }
|
483
502
|
|
484
|
-
it
|
503
|
+
it 'does not raise any errors' do
|
485
504
|
expect { subject }.to_not raise_error
|
486
505
|
end
|
487
506
|
end
|
488
507
|
|
489
|
-
context
|
508
|
+
context 'with valid string' do
|
490
509
|
let(:property_value) { '42' }
|
491
510
|
|
492
|
-
it
|
511
|
+
it 'does not raise any errors' do
|
493
512
|
expect { subject }.to_not raise_error
|
494
513
|
end
|
495
514
|
end
|
496
515
|
|
497
|
-
context
|
516
|
+
context 'with invalid value' do
|
498
517
|
let(:property_value) { 42.99 }
|
499
518
|
|
500
|
-
it
|
519
|
+
it 'raises an ArgumentError' do
|
501
520
|
expect { subject }.to raise_error(ArgumentError)
|
502
521
|
end
|
503
522
|
|
504
|
-
it
|
505
|
-
expect { subject }.to raise_error
|
523
|
+
it 'references the property name in the error message' do
|
524
|
+
expect { subject }.to raise_error do |e|
|
525
|
+
expect(e.message).to match(/#{property_name}/i)
|
526
|
+
end
|
506
527
|
end
|
507
528
|
end
|
508
529
|
end
|
509
530
|
end
|
510
531
|
|
511
|
-
it {
|
532
|
+
it { is_expected.to respond_to(:validate_type?) }
|
512
533
|
|
513
|
-
describe
|
514
|
-
subject
|
534
|
+
describe '.validate_type?' do
|
535
|
+
subject do
|
536
|
+
model_class.validate_type?(property_name, property_value, property_type)
|
537
|
+
end
|
515
538
|
|
516
|
-
context
|
539
|
+
context 'for type Integer' do
|
517
540
|
let(:property_type) { Integer }
|
518
541
|
|
519
|
-
context
|
542
|
+
context 'with nil value' do
|
520
543
|
let(:property_value) { nil }
|
521
544
|
|
522
|
-
it {
|
545
|
+
it { is_expected.to eq(true) }
|
523
546
|
end
|
524
547
|
|
525
|
-
context
|
548
|
+
context 'with valid int' do
|
526
549
|
let(:property_value) { 42 }
|
527
550
|
|
528
|
-
it {
|
551
|
+
it { is_expected.to eq(true) }
|
529
552
|
end
|
530
553
|
|
531
|
-
context
|
554
|
+
context 'with valid string' do
|
532
555
|
let(:property_value) { '42' }
|
533
556
|
|
534
|
-
it {
|
557
|
+
it { is_expected.to eq(true) }
|
535
558
|
end
|
536
559
|
|
537
|
-
context
|
560
|
+
context 'with invalid value' do
|
538
561
|
let(:property_value) { 42.99 }
|
539
562
|
|
540
|
-
it {
|
563
|
+
it { is_expected.to eq(false) }
|
541
564
|
end
|
542
565
|
end
|
543
566
|
end
|
544
567
|
|
545
|
-
it {
|
568
|
+
it { is_expected.to respond_to(:add_validator) }
|
546
569
|
|
547
|
-
context
|
548
|
-
before do
|
570
|
+
context 'with simple validated property' do
|
571
|
+
before do
|
549
572
|
model_class.add_validator(property_name, &validator_block)
|
550
573
|
model.send("#{property_name}=", property_value)
|
551
574
|
end
|
@@ -554,68 +577,75 @@ describe Modelish::Validations do
|
|
554
577
|
|
555
578
|
let(:property_value) { '42' }
|
556
579
|
|
557
|
-
let(:message_validator)
|
558
|
-
|
580
|
+
let(:message_validator) do
|
581
|
+
->(val) { val.to_i != 42 ? "#{property_name} must be 42" : nil }
|
582
|
+
end
|
583
|
+
|
584
|
+
let(:error_validator) do
|
585
|
+
lambda do |val|
|
586
|
+
val.to_i != 42 ? ArgumentError.new("#{property_name} must be 42") : nil
|
587
|
+
end
|
588
|
+
end
|
559
589
|
|
560
|
-
describe
|
590
|
+
describe '.validators' do
|
561
591
|
let(:validator_block) { message_validator }
|
562
592
|
|
563
593
|
subject { validators }
|
564
594
|
let(:validators) { model_class.validators }
|
565
595
|
|
566
|
-
|
596
|
+
its(:size) { is_expected.to eq(1) }
|
567
597
|
|
568
|
-
describe
|
598
|
+
describe '[property_name]' do
|
569
599
|
subject { prop_validators }
|
570
600
|
let(:prop_validators) { validators[property_name] }
|
571
601
|
|
572
|
-
|
602
|
+
its(:size) { is_expected.to eq(1) }
|
573
603
|
|
574
|
-
describe
|
604
|
+
describe '#first' do
|
575
605
|
subject { prop_validators.first }
|
576
606
|
|
577
|
-
it {
|
578
|
-
it {
|
607
|
+
it { is_expected.to respond_to(:call) }
|
608
|
+
it { is_expected.to eq(validator_block) }
|
579
609
|
end
|
580
610
|
end
|
581
611
|
end
|
582
612
|
|
583
|
-
context
|
584
|
-
context
|
613
|
+
context 'with valid value' do
|
614
|
+
context 'with validator that returns an error message' do
|
585
615
|
let(:validator_block) { message_validator }
|
586
616
|
|
587
|
-
|
617
|
+
it_behaves_like 'a valid model'
|
588
618
|
end
|
589
619
|
|
590
|
-
context
|
620
|
+
context 'with validator that returns an error' do
|
591
621
|
let(:validator_block) { error_validator }
|
592
622
|
|
593
|
-
|
623
|
+
it_behaves_like 'a valid model'
|
594
624
|
end
|
595
625
|
end
|
596
626
|
|
597
|
-
context
|
627
|
+
context 'with invalid value' do
|
598
628
|
let(:property_value) { 'not valid' }
|
599
629
|
|
600
|
-
context
|
630
|
+
context 'with validator that returns an error message' do
|
601
631
|
let(:validator_block) { message_validator }
|
602
632
|
|
603
|
-
|
633
|
+
it_behaves_like 'a model with an invalid property' do
|
604
634
|
let(:error_count) { 1 }
|
605
635
|
end
|
606
636
|
end
|
607
637
|
|
608
|
-
context
|
638
|
+
context 'with validator that returns an error' do
|
609
639
|
let(:validator_block) { error_validator }
|
610
640
|
|
611
|
-
|
641
|
+
it_behaves_like 'a model with an invalid property' do
|
612
642
|
let(:error_count) { 1 }
|
613
643
|
end
|
614
644
|
end
|
615
645
|
end
|
616
646
|
end
|
617
647
|
|
618
|
-
context
|
648
|
+
context 'with property that has multiple validations' do
|
619
649
|
before do
|
620
650
|
model_class.add_validator(property_name, &nil_validator)
|
621
651
|
model_class.add_validator(property_name, &int_validator)
|
@@ -624,101 +654,111 @@ describe Modelish::Validations do
|
|
624
654
|
|
625
655
|
subject { model }
|
626
656
|
|
627
|
-
let(:nil_validator)
|
628
|
-
|
657
|
+
let(:nil_validator) do
|
658
|
+
lambda do |val|
|
659
|
+
val.nil? ? "#{property_name} is_expected.to not be nil" : nil
|
660
|
+
end
|
661
|
+
end
|
662
|
+
let(:int_validator) do
|
663
|
+
lambda do |val|
|
664
|
+
"#{property_name} must represent the integer 42" unless val.to_i == 42
|
665
|
+
end
|
666
|
+
end
|
629
667
|
|
630
668
|
let(:property_value) { '42' }
|
631
669
|
|
632
|
-
describe
|
670
|
+
describe '.validators' do
|
633
671
|
subject { validators }
|
634
672
|
let(:validators) { model_class.validators }
|
635
673
|
|
636
|
-
|
674
|
+
its(:size) { is_expected.to eq(1) }
|
637
675
|
|
638
|
-
describe
|
676
|
+
describe '[property_name]' do
|
639
677
|
subject { prop_validators }
|
640
678
|
let(:prop_validators) { validators[property_name] }
|
641
679
|
|
642
|
-
|
680
|
+
its(:size) { is_expected.to eq(2) }
|
643
681
|
|
644
|
-
describe
|
682
|
+
describe '#first' do
|
645
683
|
subject { prop_validators.first }
|
646
|
-
it {
|
647
|
-
it {
|
684
|
+
it { is_expected.to respond_to(:call) }
|
685
|
+
it { is_expected.to eq(nil_validator) }
|
648
686
|
end
|
649
687
|
|
650
|
-
describe
|
688
|
+
describe '#last' do
|
651
689
|
subject { prop_validators.last }
|
652
|
-
it {
|
653
|
-
it {
|
690
|
+
it { is_expected.to respond_to(:call) }
|
691
|
+
it { is_expected.to eq(int_validator) }
|
654
692
|
end
|
655
693
|
end
|
656
694
|
end
|
657
695
|
|
658
|
-
context
|
659
|
-
it {
|
696
|
+
context 'with valid value' do
|
697
|
+
it { is_expected.to be_valid }
|
660
698
|
|
661
|
-
describe
|
699
|
+
describe '#validate' do
|
662
700
|
subject { model.validate }
|
663
701
|
|
664
|
-
it {
|
702
|
+
it { is_expected.to be_empty }
|
665
703
|
end
|
666
704
|
|
667
|
-
describe
|
705
|
+
describe '#validate!' do
|
668
706
|
subject { model.validate! }
|
669
707
|
|
670
|
-
it
|
708
|
+
it 'does not raise any errors' do
|
671
709
|
expect { subject }.to_not raise_error
|
672
710
|
end
|
673
711
|
end
|
674
712
|
end
|
675
713
|
|
676
|
-
context
|
714
|
+
context 'with nil value' do
|
677
715
|
let(:property_value) { nil }
|
678
716
|
|
679
|
-
it {
|
717
|
+
it { is_expected.to_not be_valid }
|
680
718
|
|
681
|
-
describe
|
719
|
+
describe '#validate' do
|
682
720
|
subject { errors }
|
683
721
|
let(:errors) { model.validate }
|
684
722
|
|
685
|
-
|
723
|
+
its(:size) { is_expected.to eq(1) }
|
686
724
|
|
687
|
-
it {
|
725
|
+
it { is_expected.to have_key(property_name) }
|
688
726
|
|
689
|
-
describe
|
727
|
+
describe '[property_name]' do
|
690
728
|
subject { prop_errors }
|
691
729
|
let(:prop_errors) { errors[property_name] }
|
692
730
|
|
693
|
-
|
731
|
+
its(:size) { is_expected.to eq(2) }
|
694
732
|
|
695
|
-
describe
|
733
|
+
describe '#first' do
|
696
734
|
subject { prop_errors.first }
|
697
735
|
|
698
|
-
it {
|
699
|
-
its(:message) {
|
700
|
-
its(:message) {
|
736
|
+
it { is_expected.to be_a ArgumentError }
|
737
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
738
|
+
its(:message) { is_expected.to match(/nil/i) }
|
701
739
|
end
|
702
740
|
|
703
|
-
describe
|
741
|
+
describe '#last' do
|
704
742
|
subject { prop_errors.last }
|
705
743
|
|
706
|
-
it {
|
707
|
-
its(:message) {
|
708
|
-
its(:message) {
|
744
|
+
it { is_expected.to be_a ArgumentError }
|
745
|
+
its(:message) { is_expected.to match(/#{property_name}/i) }
|
746
|
+
its(:message) { is_expected.to match(/integer/i) }
|
709
747
|
end
|
710
748
|
end
|
711
749
|
end
|
712
750
|
|
713
|
-
describe
|
751
|
+
describe '#validate!' do
|
714
752
|
subject { model.validate! }
|
715
753
|
|
716
|
-
it
|
754
|
+
it 'raises an ArgumentError' do
|
717
755
|
expect { subject }.to raise_error(ArgumentError)
|
718
756
|
end
|
719
757
|
|
720
|
-
it
|
721
|
-
expect { subject }.to raise_error
|
758
|
+
it 'references the property name in the error message' do
|
759
|
+
expect { subject }.to raise_error do |e|
|
760
|
+
expect(e.message).to match(/#{property_name}/i)
|
761
|
+
end
|
722
762
|
end
|
723
763
|
end
|
724
764
|
end
|