reform 2.3.0.rc1 → 2.3.0.rc2
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 +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +30 -0
- data/.rubocop_todo.yml +460 -0
- data/.travis.yml +26 -11
- data/CHANGES.md +25 -2
- data/Gemfile +6 -3
- data/ISSUE_TEMPLATE.md +1 -1
- data/README.md +2 -4
- data/Rakefile +18 -9
- data/lib/reform/contract.rb +7 -7
- data/lib/reform/contract/custom_error.rb +41 -0
- data/lib/reform/contract/validate.rb +9 -5
- data/lib/reform/errors.rb +27 -15
- data/lib/reform/form.rb +22 -11
- data/lib/reform/form/call.rb +1 -1
- data/lib/reform/form/composition.rb +2 -2
- data/lib/reform/form/dry.rb +10 -86
- data/lib/reform/form/dry/input_hash.rb +37 -0
- data/lib/reform/form/dry/new_api.rb +58 -0
- data/lib/reform/form/dry/old_api.rb +61 -0
- data/lib/reform/form/populator.rb +9 -11
- data/lib/reform/form/prepopulate.rb +3 -2
- data/lib/reform/form/validate.rb +19 -12
- data/lib/reform/result.rb +36 -9
- data/lib/reform/validation.rb +10 -8
- data/lib/reform/validation/groups.rb +2 -3
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +10 -9
- data/test/benchmarking.rb +10 -11
- data/test/call_new_api.rb +23 -0
- data/test/{call_test.rb → call_old_api.rb} +3 -3
- data/test/changed_test.rb +7 -7
- data/test/coercion_test.rb +50 -18
- data/test/composition_new_api.rb +186 -0
- data/test/{composition_test.rb → composition_old_api.rb} +23 -26
- data/test/contract/custom_error_test.rb +55 -0
- data/test/contract_new_api.rb +77 -0
- data/test/{contract_test.rb → contract_old_api.rb} +8 -8
- data/test/default_test.rb +1 -1
- data/test/deserialize_test.rb +8 -11
- data/test/errors_new_api.rb +225 -0
- data/test/errors_old_api.rb +230 -0
- data/test/feature_test.rb +7 -9
- data/test/fixtures/dry_error_messages.yml +5 -2
- data/test/fixtures/dry_new_api_error_messages.yml +104 -0
- data/test/form_new_api.rb +57 -0
- data/test/{form_test.rb → form_old_api.rb} +2 -2
- data/test/form_option_new_api.rb +24 -0
- data/test/{form_option_test.rb → form_option_old_api.rb} +1 -1
- data/test/from_test.rb +8 -12
- data/test/inherit_new_api.rb +105 -0
- data/test/{inherit_test.rb → inherit_old_api.rb} +10 -17
- data/test/module_new_api.rb +137 -0
- data/test/{module_test.rb → module_old_api.rb} +19 -15
- data/test/parse_option_test.rb +5 -5
- data/test/parse_pipeline_test.rb +2 -2
- data/test/populate_new_api.rb +304 -0
- data/test/{populate_test.rb → populate_old_api.rb} +28 -34
- data/test/populator_skip_test.rb +1 -2
- data/test/prepopulator_test.rb +5 -6
- data/test/read_only_test.rb +12 -1
- data/test/readable_test.rb +5 -5
- data/test/reform_new_api.rb +204 -0
- data/test/{reform_test.rb → reform_old_api.rb} +17 -23
- data/test/save_new_api.rb +101 -0
- data/test/{save_test.rb → save_old_api.rb} +10 -13
- data/test/setup_test.rb +6 -6
- data/test/{skip_if_test.rb → skip_if_new_api.rb} +20 -9
- data/test/skip_if_old_api.rb +92 -0
- data/test/skip_setter_and_getter_test.rb +2 -3
- data/test/test_helper.rb +13 -5
- data/test/validate_new_api.rb +408 -0
- data/test/{validate_test.rb → validate_old_api.rb} +43 -53
- data/test/validation/dry_validation_new_api.rb +826 -0
- data/test/validation/{dry_validation_test.rb → dry_validation_old_api.rb} +223 -116
- data/test/validation/result_test.rb +20 -22
- data/test/validation_library_provided_test.rb +3 -3
- data/test/virtual_test.rb +46 -6
- data/test/writeable_test.rb +7 -7
- metadata +101 -51
- data/test/errors_test.rb +0 -180
- data/test/readonly_test.rb +0 -14
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
1
|
require "test_helper"
|
|
3
2
|
require "reform/form/dry"
|
|
4
3
|
require "reform/form/coercion"
|
|
@@ -41,74 +40,73 @@ class DryValidationErrorsAPITest < Minitest::Spec
|
|
|
41
40
|
|
|
42
41
|
validation do
|
|
43
42
|
configure do
|
|
44
|
-
config.messages_file =
|
|
43
|
+
config.messages_file = "test/fixtures/dry_error_messages.yml"
|
|
45
44
|
end
|
|
46
45
|
|
|
47
46
|
required(:title).filled
|
|
48
47
|
end
|
|
49
48
|
end
|
|
50
|
-
|
|
51
49
|
end
|
|
52
50
|
|
|
53
|
-
let
|
|
51
|
+
let(:form) { AlbumForm.new(Album.new(nil, Artist.new(nil, Label.new), [Song.new(nil), Song.new(nil)])) }
|
|
54
52
|
|
|
55
53
|
it "everything wrong" do
|
|
56
|
-
result = form.(
|
|
54
|
+
result = form.(title: nil, artist: {email: ""}, songs: [{title: "Clams have feelings too"}, {title: ""}])
|
|
57
55
|
|
|
58
56
|
result.success?.must_equal false
|
|
59
57
|
|
|
60
58
|
# errors.messages
|
|
61
|
-
form.errors.messages.must_equal(
|
|
62
|
-
form.artist.errors.messages.must_equal(
|
|
63
|
-
form.artist.label.errors.messages.must_equal(
|
|
59
|
+
form.errors.messages.must_equal(title: ["must be filled", "size cannot be less than 2"], "artist.email": ["must be filled"], "artist.label.location": ["must be filled"], "songs.title": ["must be filled"])
|
|
60
|
+
form.artist.errors.messages.must_equal(email: ["must be filled"], "label.location": ["must be filled"])
|
|
61
|
+
form.artist.label.errors.messages.must_equal(location: ["must be filled"])
|
|
64
62
|
form.songs[0].errors.messages.must_equal({})
|
|
65
|
-
form.songs[1].errors.messages.must_equal(
|
|
63
|
+
form.songs[1].errors.messages.must_equal(title: ["must be filled"])
|
|
66
64
|
|
|
67
65
|
# #errors[]
|
|
68
|
-
form.errors[:nonsense].
|
|
66
|
+
form.errors[:nonsense].must_equal []
|
|
69
67
|
form.errors[:title].must_equal ["must be filled", "size cannot be less than 2"]
|
|
70
68
|
form.artist.errors[:email].must_equal ["must be filled"]
|
|
71
69
|
form.artist.label.errors[:location].must_equal ["must be filled"]
|
|
72
|
-
form.songs[0].errors[:title].
|
|
70
|
+
form.songs[0].errors[:title].must_equal []
|
|
73
71
|
form.songs[1].errors[:title].must_equal ["must be filled"]
|
|
74
72
|
|
|
75
73
|
# #to_result
|
|
76
|
-
form.to_result.errors.must_equal(
|
|
77
|
-
form.to_result.messages.must_equal(
|
|
78
|
-
form.to_result.hints.must_equal(
|
|
79
|
-
form.artist.to_result.errors.must_equal(
|
|
80
|
-
form.artist.to_result.messages.must_equal(
|
|
81
|
-
form.artist.to_result.hints.must_equal(
|
|
82
|
-
form.artist.label.to_result.errors.must_equal(
|
|
83
|
-
form.artist.label.to_result.messages.must_equal(
|
|
84
|
-
form.artist.label.to_result.hints.must_equal(
|
|
74
|
+
form.to_result.errors.must_equal(title: ["must be filled"])
|
|
75
|
+
form.to_result.messages.must_equal(title: ["must be filled", "size cannot be less than 2"])
|
|
76
|
+
form.to_result.hints.must_equal(title: ["size cannot be less than 2"])
|
|
77
|
+
form.artist.to_result.errors.must_equal(email: ["must be filled"])
|
|
78
|
+
form.artist.to_result.messages.must_equal(email: ["must be filled"])
|
|
79
|
+
form.artist.to_result.hints.must_equal(email: [])
|
|
80
|
+
form.artist.label.to_result.errors.must_equal(location: ["must be filled"])
|
|
81
|
+
form.artist.label.to_result.messages.must_equal(location: ["must be filled"])
|
|
82
|
+
form.artist.label.to_result.hints.must_equal(location: [])
|
|
85
83
|
form.songs[0].to_result.errors.must_equal({})
|
|
86
84
|
form.songs[0].to_result.messages.must_equal({})
|
|
87
85
|
form.songs[0].to_result.hints.must_equal({})
|
|
88
|
-
form.songs[1].to_result.errors.must_equal(
|
|
89
|
-
form.songs[1].to_result.messages.must_equal(
|
|
90
|
-
form.songs[1].to_result.hints.must_equal(
|
|
91
|
-
form.songs[1].to_result.errors(locale: :de).must_equal(
|
|
92
|
-
form.songs[1].to_result.messages(locale: :de).must_equal(
|
|
93
|
-
form.songs[1].to_result.hints(locale: :de).must_equal(
|
|
86
|
+
form.songs[1].to_result.errors.must_equal(title: ["must be filled"])
|
|
87
|
+
form.songs[1].to_result.messages.must_equal(title: ["must be filled"])
|
|
88
|
+
form.songs[1].to_result.hints.must_equal(title: [])
|
|
89
|
+
form.songs[1].to_result.errors(locale: :de).must_equal(title: ["muss abgefüllt sein"])
|
|
90
|
+
form.songs[1].to_result.messages(locale: :de).must_equal(title: ["muss abgefüllt sein"])
|
|
91
|
+
form.songs[1].to_result.hints(locale: :de).must_equal(title: [])
|
|
94
92
|
end
|
|
95
93
|
|
|
96
94
|
it "only nested property is invalid." do
|
|
97
|
-
result = form.(
|
|
95
|
+
result = form.(title: "Black Star", artist: {email: ""})
|
|
98
96
|
|
|
99
97
|
result.success?.must_equal false
|
|
100
98
|
|
|
101
99
|
# errors.messages
|
|
102
|
-
form.errors.messages.must_equal(
|
|
103
|
-
form.artist.errors.messages.must_equal(
|
|
104
|
-
form.artist.label.errors.messages.must_equal(
|
|
100
|
+
form.errors.messages.must_equal("artist.email": ["must be filled"], "artist.label.location": ["must be filled"], "songs.title": ["must be filled"])
|
|
101
|
+
form.artist.errors.messages.must_equal(email: ["must be filled"], "label.location": ["must be filled"])
|
|
102
|
+
form.artist.label.errors.messages.must_equal(location: ["must be filled"])
|
|
105
103
|
end
|
|
106
104
|
|
|
107
105
|
it "nested collection invalid" do
|
|
108
|
-
result = form.(
|
|
106
|
+
result = form.(title: "Black Star", artist: {email: "uhm", label: {location: "Hannover"}}, songs: [{title: ""}])
|
|
109
107
|
|
|
110
108
|
result.success?.must_equal false
|
|
111
|
-
form.errors.messages.must_equal(
|
|
109
|
+
form.errors.messages.must_equal("songs.title": ["must be filled"])
|
|
112
110
|
end
|
|
113
111
|
|
|
114
112
|
#---
|
|
@@ -129,11 +127,11 @@ class DryValidationErrorsAPITest < Minitest::Spec
|
|
|
129
127
|
|
|
130
128
|
it do
|
|
131
129
|
form = CollectionExternalValidationsForm.new(Album.new(nil, nil, [Song.new, Song.new]))
|
|
132
|
-
form.validate(songs: [
|
|
130
|
+
form.validate(songs: [{title: "Liar"}, {title: ""}])
|
|
133
131
|
|
|
134
|
-
form.errors.messages.must_equal(
|
|
132
|
+
form.errors.messages.must_equal("songs.title": ["must be filled"])
|
|
135
133
|
form.songs[0].errors.messages.must_equal({})
|
|
136
|
-
form.songs[1].errors.messages.must_equal(
|
|
134
|
+
form.songs[1].errors.messages.must_equal(title: ["must be filled"])
|
|
137
135
|
end
|
|
138
136
|
end
|
|
139
137
|
|
|
@@ -153,7 +151,7 @@ class DryValidationExplicitSchemaTest < Minitest::Spec
|
|
|
153
151
|
validation schema: SessionSchema
|
|
154
152
|
end
|
|
155
153
|
|
|
156
|
-
let
|
|
154
|
+
let(:form) { SessionForm.new(Session.new) }
|
|
157
155
|
|
|
158
156
|
# valid.
|
|
159
157
|
it do
|
|
@@ -177,8 +175,8 @@ class DryValidationDefaultGroupTest < Minitest::Spec
|
|
|
177
175
|
property :email
|
|
178
176
|
property :password
|
|
179
177
|
property :confirm_password
|
|
180
|
-
property :starts_at, type:
|
|
181
|
-
property :active, type:
|
|
178
|
+
property :starts_at, type: DRY_TYPES_CONSTANT::DateTime
|
|
179
|
+
property :active, type: DRY_TYPES_CONSTANT::Bool
|
|
182
180
|
property :color
|
|
183
181
|
|
|
184
182
|
validation do
|
|
@@ -192,7 +190,7 @@ class DryValidationDefaultGroupTest < Minitest::Spec
|
|
|
192
190
|
required(:confirm_password).filled
|
|
193
191
|
end
|
|
194
192
|
|
|
195
|
-
validation name: :dynamic_args, with: {
|
|
193
|
+
validation name: :dynamic_args, with: {form: true} do
|
|
196
194
|
configure do
|
|
197
195
|
def colors
|
|
198
196
|
form.colors
|
|
@@ -206,7 +204,7 @@ class DryValidationDefaultGroupTest < Minitest::Spec
|
|
|
206
204
|
end
|
|
207
205
|
end
|
|
208
206
|
|
|
209
|
-
let
|
|
207
|
+
let(:form) { SessionForm.new(Session.new) }
|
|
210
208
|
|
|
211
209
|
# valid.
|
|
212
210
|
it do
|
|
@@ -214,16 +212,16 @@ class DryValidationDefaultGroupTest < Minitest::Spec
|
|
|
214
212
|
email: "yep",
|
|
215
213
|
starts_at: "01/01/2000 - 11:00",
|
|
216
214
|
active: "true",
|
|
217
|
-
confirm_password:
|
|
215
|
+
confirm_password: "pA55w0rd").must_equal true
|
|
218
216
|
form.errors.messages.inspect.must_equal "{}"
|
|
219
217
|
end
|
|
220
218
|
|
|
221
219
|
it "invalid" do
|
|
222
220
|
form.validate(username: "Helloween",
|
|
223
221
|
email: "yep",
|
|
224
|
-
active:
|
|
222
|
+
active: "hello",
|
|
225
223
|
starts_at: "01/01/2000 - 11:00",
|
|
226
|
-
color:
|
|
224
|
+
color: "purple").must_equal false
|
|
227
225
|
form.errors.messages.inspect.must_equal "{:active=>[\"must be boolean\"], :confirm_password=>[\"must be filled\"], :color=>[\"must be one of: red orange green\"]}"
|
|
228
226
|
end
|
|
229
227
|
end
|
|
@@ -231,10 +229,9 @@ end
|
|
|
231
229
|
class ValidationGroupsTest < MiniTest::Spec
|
|
232
230
|
describe "basic validations" do
|
|
233
231
|
Session = Struct.new(:username, :email, :password, :confirm_password, :special_class)
|
|
234
|
-
SomeClass= Struct.new(:id)
|
|
232
|
+
SomeClass = Struct.new(:id)
|
|
235
233
|
|
|
236
234
|
class SessionForm < TestForm
|
|
237
|
-
|
|
238
235
|
property :username
|
|
239
236
|
property :email
|
|
240
237
|
property :password
|
|
@@ -251,7 +248,7 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
251
248
|
required(:email).filled(min_size?: 3)
|
|
252
249
|
end
|
|
253
250
|
|
|
254
|
-
validation name: :
|
|
251
|
+
validation name: :password, if: :email do
|
|
255
252
|
required(:password).filled(min_size?: 2)
|
|
256
253
|
end
|
|
257
254
|
|
|
@@ -260,35 +257,35 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
260
257
|
end
|
|
261
258
|
end
|
|
262
259
|
|
|
263
|
-
let
|
|
260
|
+
let(:form) { SessionForm.new(Session.new) }
|
|
264
261
|
|
|
265
262
|
# valid.
|
|
266
263
|
it do
|
|
267
|
-
form.validate(
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
264
|
+
form.validate(username: "Helloween",
|
|
265
|
+
special_class: SomeClass.new(id: 15),
|
|
266
|
+
email: "yep",
|
|
267
|
+
password: "99",
|
|
268
|
+
confirm_password: "99").must_equal true
|
|
272
269
|
form.errors.messages.inspect.must_equal "{}"
|
|
273
270
|
end
|
|
274
271
|
|
|
275
272
|
# invalid.
|
|
276
273
|
it do
|
|
277
274
|
form.validate({}).must_equal false
|
|
278
|
-
form.errors.messages.must_equal({:
|
|
275
|
+
form.errors.messages.must_equal({username: ["must be filled"], email: ["must be filled"], special_class: ["must be filled", "must be ValidationGroupsTest::SomeClass"]})
|
|
279
276
|
end
|
|
280
277
|
|
|
281
278
|
# partially invalid.
|
|
282
279
|
# 2nd group fails.
|
|
283
280
|
it do
|
|
284
|
-
form.validate(username: "Helloween", email: "yo", confirm_password:"9", special_class: SomeClass.new(id: 15)).must_equal false
|
|
285
|
-
form.errors.messages.inspect.must_equal "{:email=>[\"size cannot be less than 3\"], :confirm_password=>[\"size cannot be less than 2\"]
|
|
281
|
+
form.validate(username: "Helloween", email: "yo", confirm_password: "9", special_class: SomeClass.new(id: 15)).must_equal false
|
|
282
|
+
form.errors.messages.inspect.must_equal "{:email=>[\"size cannot be less than 3\"], :confirm_password=>[\"size cannot be less than 2\"]}"
|
|
286
283
|
end
|
|
287
284
|
# 3rd group fails.
|
|
288
285
|
it do
|
|
289
|
-
form.validate(username: "Helloween", email: "yo!", confirm_password:"9", special_class: SomeClass.new(id: 15)).must_equal false
|
|
286
|
+
form.validate(username: "Helloween", email: "yo!", confirm_password: "9", special_class: SomeClass.new(id: 15)).must_equal false
|
|
290
287
|
form.errors.messages.inspect
|
|
291
|
-
|
|
288
|
+
.must_equal "{:confirm_password=>[\"size cannot be less than 2\"], :password=>[\"must be filled\", \"size cannot be less than 2\"]}"
|
|
292
289
|
end
|
|
293
290
|
# 4th group with after: fails.
|
|
294
291
|
it do
|
|
@@ -303,7 +300,7 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
303
300
|
class SessionForm < TestForm
|
|
304
301
|
property :username
|
|
305
302
|
|
|
306
|
-
validation name: :default, with: {
|
|
303
|
+
validation name: :default, with: {user: OpenStruct.new(name: "Nick")} do
|
|
307
304
|
configure do
|
|
308
305
|
def users_name
|
|
309
306
|
user.name
|
|
@@ -313,17 +310,17 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
313
310
|
end
|
|
314
311
|
end
|
|
315
312
|
|
|
316
|
-
let
|
|
313
|
+
let(:form) { SessionForm.new(Session.new) }
|
|
317
314
|
|
|
318
315
|
# valid.
|
|
319
316
|
it do
|
|
320
|
-
form.validate(
|
|
317
|
+
form.validate(username: "Nick").must_equal true
|
|
321
318
|
form.errors.messages.inspect.must_equal "{}"
|
|
322
319
|
end
|
|
323
320
|
|
|
324
321
|
# invalid.
|
|
325
322
|
it do
|
|
326
|
-
form.validate(
|
|
323
|
+
form.validate(username: "Fred").must_equal false
|
|
327
324
|
form.errors.messages.inspect.must_equal "{:username=>[\"must be equal to Nick\"]}"
|
|
328
325
|
end
|
|
329
326
|
end
|
|
@@ -336,15 +333,14 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
336
333
|
|
|
337
334
|
MySchema = Dry::Validation.Schema do
|
|
338
335
|
configure do
|
|
339
|
-
config.messages_file =
|
|
336
|
+
config.messages_file = "test/fixtures/dry_error_messages.yml"
|
|
340
337
|
|
|
341
338
|
def good_musical_taste?(val)
|
|
342
339
|
val.is_a? String
|
|
343
340
|
end
|
|
344
|
-
|
|
345
341
|
end
|
|
346
342
|
|
|
347
|
-
required(:password).filled(
|
|
343
|
+
required(:password).filled(min_size?: 6)
|
|
348
344
|
end
|
|
349
345
|
|
|
350
346
|
class Session2Form < TestForm
|
|
@@ -358,22 +354,22 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
358
354
|
end
|
|
359
355
|
end
|
|
360
356
|
|
|
361
|
-
let
|
|
357
|
+
let(:form) { Session2Form.new(Session2.new) }
|
|
362
358
|
|
|
363
359
|
# valid.
|
|
364
360
|
it do
|
|
365
|
-
form.validate(
|
|
361
|
+
form.validate(username: "Helloween", email: "yep", password: "extrasafe").must_equal true
|
|
366
362
|
form.errors.messages.inspect.must_equal "{}"
|
|
367
363
|
end
|
|
368
364
|
|
|
369
365
|
# invalid.
|
|
370
366
|
it do
|
|
371
367
|
form.validate({}).must_equal false
|
|
372
|
-
form.errors.messages.must_equal(
|
|
368
|
+
form.errors.messages.must_equal(password: ["must be filled", "size cannot be less than 6"], username: ["must be filled"], email: ["must be filled", "you're a bad person"])
|
|
373
369
|
end
|
|
374
370
|
|
|
375
371
|
it do
|
|
376
|
-
form.validate(
|
|
372
|
+
form.validate(email: 1).must_equal false
|
|
377
373
|
form.errors.messages.inspect.must_equal "{:password=>[\"must be filled\", \"size cannot be less than 6\"], :username=>[\"must be filled\"], :email=>[\"you're a bad person\"]}"
|
|
378
374
|
end
|
|
379
375
|
end
|
|
@@ -416,7 +412,7 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
416
412
|
# message need to be defined on fixtures/dry_error_messages
|
|
417
413
|
# d-v expects you to define your custome messages on the .yml file
|
|
418
414
|
def good_musical_taste?(value)
|
|
419
|
-
value !=
|
|
415
|
+
value != "Nickelback"
|
|
420
416
|
end
|
|
421
417
|
end
|
|
422
418
|
|
|
@@ -434,46 +430,45 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
434
430
|
required(:name).filled
|
|
435
431
|
end
|
|
436
432
|
end
|
|
437
|
-
|
|
438
433
|
end
|
|
439
434
|
end
|
|
440
435
|
|
|
441
|
-
let
|
|
436
|
+
let(:album) do
|
|
442
437
|
OpenStruct.new(
|
|
443
|
-
:
|
|
444
|
-
:
|
|
445
|
-
:
|
|
446
|
-
:
|
|
438
|
+
hit: OpenStruct.new,
|
|
439
|
+
songs: [OpenStruct.new, OpenStruct.new],
|
|
440
|
+
band: Struct.new(:name, :label).new("", OpenStruct.new),
|
|
441
|
+
producers: [OpenStruct.new, OpenStruct.new, OpenStruct.new],
|
|
447
442
|
)
|
|
448
443
|
end
|
|
449
444
|
|
|
450
|
-
let
|
|
445
|
+
let(:form) { AlbumForm.new(album) }
|
|
451
446
|
|
|
452
447
|
it "maps errors to form objects correctly" do
|
|
453
448
|
result = form.validate(
|
|
454
449
|
"title" => "Nickelback",
|
|
455
|
-
"songs" => [
|
|
450
|
+
"songs" => [{"title" => ""}, {"title" => ""}],
|
|
456
451
|
"band" => {"size" => "", "label" => {"location" => ""}},
|
|
457
|
-
"producers" => [{"name" =>
|
|
452
|
+
"producers" => [{"name" => ""}, {"name" => "something lovely"}]
|
|
458
453
|
)
|
|
459
454
|
|
|
460
455
|
result.must_equal false
|
|
461
456
|
# from nested validation
|
|
462
|
-
form.errors.messages.must_equal(
|
|
457
|
+
form.errors.messages.must_equal(title: ["you're a bad person"], "hit.title": ["must be filled"], "songs.title": ["must be filled"], "producers.name": ["must be filled"], "band.name": ["must be filled"], "band.label.location": ["must be filled"])
|
|
463
458
|
|
|
464
459
|
# songs have their own validation.
|
|
465
|
-
form.songs[0].errors.messages.must_equal(
|
|
460
|
+
form.songs[0].errors.messages.must_equal(title: ["must be filled"])
|
|
466
461
|
# hit got its own validation group.
|
|
467
|
-
form.hit.errors.messages.must_equal(
|
|
462
|
+
form.hit.errors.messages.must_equal(title: ["must be filled"])
|
|
468
463
|
|
|
469
|
-
form.band.label.errors.messages.must_equal(
|
|
470
|
-
form.band.errors.messages.must_equal(
|
|
471
|
-
form.producers[0].errors.messages.must_equal(
|
|
464
|
+
form.band.label.errors.messages.must_equal(location: ["must be filled"])
|
|
465
|
+
form.band.errors.messages.must_equal(name: ["must be filled"], "label.location": ["must be filled"])
|
|
466
|
+
form.producers[0].errors.messages.must_equal(name: ["must be filled"])
|
|
472
467
|
|
|
473
468
|
# TODO: use the same form structure as the top one and do the same test against messages, errors and hints.
|
|
474
|
-
form.producers[0].to_result.errors.must_equal(
|
|
475
|
-
form.producers[0].to_result.messages.must_equal(
|
|
476
|
-
form.producers[0].to_result.hints.must_equal(
|
|
469
|
+
form.producers[0].to_result.errors.must_equal(name: ["must be filled"])
|
|
470
|
+
form.producers[0].to_result.messages.must_equal(name: ["must be filled"])
|
|
471
|
+
form.producers[0].to_result.hints.must_equal(name: [])
|
|
477
472
|
end
|
|
478
473
|
|
|
479
474
|
# FIXME: fix the "must be filled error"
|
|
@@ -481,9 +476,9 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
481
476
|
it "renders full messages correctly" do
|
|
482
477
|
result = form.validate(
|
|
483
478
|
"title" => "",
|
|
484
|
-
"songs" => [
|
|
479
|
+
"songs" => [{"title" => ""}, {"title" => ""}],
|
|
485
480
|
"band" => {"size" => "", "label" => {"name" => ""}},
|
|
486
|
-
"producers" => [{"name" =>
|
|
481
|
+
"producers" => [{"name" => ""}, {"name" => ""}, {"name" => "something lovely"}]
|
|
487
482
|
)
|
|
488
483
|
|
|
489
484
|
result.must_equal false
|
|
@@ -505,7 +500,7 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
505
500
|
|
|
506
501
|
validation do
|
|
507
502
|
configure do
|
|
508
|
-
config.messages_file =
|
|
503
|
+
config.messages_file = "test/fixtures/dry_error_messages.yml"
|
|
509
504
|
end
|
|
510
505
|
|
|
511
506
|
required(:title).filled
|
|
@@ -519,24 +514,24 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
519
514
|
end
|
|
520
515
|
end
|
|
521
516
|
|
|
522
|
-
let
|
|
517
|
+
let(:form) { AlbumFormWith1NestedVal.new(album) }
|
|
523
518
|
|
|
524
519
|
it "allows to access dry's result semantics per nested form" do
|
|
525
|
-
|
|
520
|
+
form.validate(
|
|
526
521
|
"title" => "",
|
|
527
|
-
"songs" => [
|
|
522
|
+
"songs" => [{"title" => ""}, {"title" => ""}],
|
|
528
523
|
"band" => {"size" => "", "label" => {"name" => ""}},
|
|
529
|
-
"producers" => [{"name" =>
|
|
524
|
+
"producers" => [{"name" => ""}, {"name" => ""}, {"name" => "something lovely"}]
|
|
530
525
|
)
|
|
531
526
|
|
|
532
|
-
form.to_result.errors.must_equal(
|
|
533
|
-
form.band.to_result.errors.must_equal(
|
|
534
|
-
form.band.label.to_result.errors.must_equal(
|
|
527
|
+
form.to_result.errors.must_equal(title: ["must be filled"])
|
|
528
|
+
form.band.to_result.errors.must_equal(name: ["must be filled"])
|
|
529
|
+
form.band.label.to_result.errors.must_equal(location: ["must be filled"])
|
|
535
530
|
|
|
536
531
|
# with locale: "de"
|
|
537
|
-
form.to_result.errors(locale: :de).must_equal(
|
|
538
|
-
form.band.to_result.errors(locale: :de).must_equal(
|
|
539
|
-
form.band.label.to_result.errors(locale: :de).must_equal(
|
|
532
|
+
form.to_result.errors(locale: :de).must_equal(title: ["muss abgefüllt sein"])
|
|
533
|
+
form.band.to_result.errors(locale: :de).must_equal(name: ["muss abgefüllt sein"])
|
|
534
|
+
form.band.label.to_result.errors(locale: :de).must_equal(location: ["muss abgefüllt sein"])
|
|
540
535
|
end
|
|
541
536
|
end
|
|
542
537
|
end
|
|
@@ -557,7 +552,7 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
557
552
|
# end
|
|
558
553
|
# end
|
|
559
554
|
|
|
560
|
-
# let
|
|
555
|
+
# let(:form) { OverwritingForm.new(Session.new) }
|
|
561
556
|
|
|
562
557
|
# # valid.
|
|
563
558
|
# it do
|
|
@@ -571,36 +566,41 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
571
566
|
# end
|
|
572
567
|
# end
|
|
573
568
|
|
|
574
|
-
|
|
575
569
|
describe "inherit: true in same group" do
|
|
576
570
|
class InheritSameGroupForm < TestForm
|
|
577
571
|
property :username
|
|
578
572
|
property :email
|
|
573
|
+
property :full_name, virtual: true
|
|
579
574
|
|
|
580
|
-
validation name: :
|
|
581
|
-
|
|
582
|
-
|
|
575
|
+
validation name: :username do
|
|
576
|
+
configure do
|
|
577
|
+
config.messages_file = "test/fixtures/dry_error_messages.yml"
|
|
578
|
+
end
|
|
583
579
|
|
|
584
|
-
validation name: :email, inherit: true do # extends the above.
|
|
585
580
|
required(:username).filled
|
|
581
|
+
required(:full_name).filled
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
validation name: :username, inherit: true do # overrides and extends the above.
|
|
585
|
+
optional(:username).maybe
|
|
586
|
+
required(:email).filled
|
|
586
587
|
end
|
|
587
588
|
end
|
|
588
589
|
|
|
589
|
-
let
|
|
590
|
+
let(:form) { InheritSameGroupForm.new(Session.new) }
|
|
590
591
|
|
|
591
592
|
# valid.
|
|
592
593
|
it do
|
|
593
|
-
form.validate(
|
|
594
|
+
form.validate(full_name: "My name", email: 9).must_equal true
|
|
594
595
|
end
|
|
595
596
|
|
|
596
597
|
# invalid.
|
|
597
598
|
it do
|
|
598
599
|
form.validate({}).must_equal false
|
|
599
|
-
form.errors.messages.
|
|
600
|
+
form.errors.messages.must_equal email: ["must be filled"], full_name: ["must be filled"]
|
|
600
601
|
end
|
|
601
602
|
end
|
|
602
603
|
|
|
603
|
-
|
|
604
604
|
describe "if: with lambda" do
|
|
605
605
|
class IfWithLambdaForm < TestForm
|
|
606
606
|
property :username
|
|
@@ -612,30 +612,137 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
612
612
|
end
|
|
613
613
|
|
|
614
614
|
# run this is :email group is true.
|
|
615
|
-
validation name: :after_email, if:
|
|
615
|
+
validation name: :after_email, if: ->(results) { results[:email].success? } do # extends the above.
|
|
616
616
|
required(:username).filled
|
|
617
617
|
end
|
|
618
618
|
|
|
619
619
|
# block gets evaled in form instance context.
|
|
620
|
-
validation name: :password, if:
|
|
620
|
+
validation name: :password, if: ->(results) { email == "john@trb.org" } do
|
|
621
621
|
required(:password).filled
|
|
622
622
|
end
|
|
623
623
|
end
|
|
624
624
|
|
|
625
|
-
let
|
|
625
|
+
let(:form) { IfWithLambdaForm.new(Session.new) }
|
|
626
626
|
|
|
627
627
|
# valid.
|
|
628
628
|
it do
|
|
629
|
-
form.validate(
|
|
629
|
+
form.validate(username: "Strung Out", email: 9).must_equal true
|
|
630
630
|
end
|
|
631
631
|
|
|
632
632
|
# invalid.
|
|
633
633
|
it do
|
|
634
|
-
form.validate(
|
|
634
|
+
form.validate(email: 9).must_equal false
|
|
635
635
|
form.errors.messages.inspect.must_equal "{:username=>[\"must be filled\"]}"
|
|
636
636
|
end
|
|
637
637
|
end
|
|
638
638
|
|
|
639
|
+
class NestedSchemaValidationTest < MiniTest::Spec
|
|
640
|
+
AddressSchema = Dry::Validation.Schema do
|
|
641
|
+
required(:company).filled(:int?)
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
class OrderForm < TestForm
|
|
645
|
+
property :delivery_address do
|
|
646
|
+
property :company
|
|
647
|
+
end
|
|
648
|
+
|
|
649
|
+
validation do
|
|
650
|
+
required(:delivery_address).schema(AddressSchema)
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
let(:company) { Struct.new(:company) }
|
|
655
|
+
let(:order) { Struct.new(:delivery_address) }
|
|
656
|
+
let(:form) { OrderForm.new(order.new(company.new)) }
|
|
657
|
+
|
|
658
|
+
it "has company error" do
|
|
659
|
+
form.validate(delivery_address: {company: "not int"}).must_equal false
|
|
660
|
+
form.errors.messages.must_equal(:"delivery_address.company" => ["must be an integer"])
|
|
661
|
+
end
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
class NestedSchemaValidationWithFormTest < MiniTest::Spec
|
|
665
|
+
class CompanyForm < TestForm
|
|
666
|
+
property :company
|
|
667
|
+
|
|
668
|
+
validation do
|
|
669
|
+
required(:company).filled(:int?)
|
|
670
|
+
end
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
class OrderFormWithForm < TestForm
|
|
674
|
+
property :delivery_address, form: CompanyForm
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
let(:company) { Struct.new(:company) }
|
|
678
|
+
let(:order) { Struct.new(:delivery_address) }
|
|
679
|
+
let(:form) { OrderFormWithForm.new(order.new(company.new)) }
|
|
680
|
+
|
|
681
|
+
it "has company error" do
|
|
682
|
+
form.validate(delivery_address: {company: "not int"}).must_equal false
|
|
683
|
+
form.errors.messages.must_equal(:"delivery_address.company" => ["must be an integer"])
|
|
684
|
+
end
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
class CollectionPropertyWithCustomRuleTest < MiniTest::Spec
|
|
688
|
+
Artist = Struct.new(:first_name, :last_name)
|
|
689
|
+
Song = Struct.new(:title, :enabled)
|
|
690
|
+
Album = Struct.new(:title, :songs, :artist)
|
|
691
|
+
|
|
692
|
+
class AlbumForm < TestForm
|
|
693
|
+
property :title
|
|
694
|
+
|
|
695
|
+
collection :songs, virtual: true, populate_if_empty: Song do
|
|
696
|
+
property :title
|
|
697
|
+
property :enabled
|
|
698
|
+
|
|
699
|
+
validation do
|
|
700
|
+
required(:title).filled
|
|
701
|
+
end
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
property :artist, populate_if_empty: Artist do
|
|
705
|
+
property :first_name
|
|
706
|
+
property :last_name
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
validation do
|
|
710
|
+
configure do
|
|
711
|
+
config.messages_file = "test/fixtures/dry_error_messages.yml"
|
|
712
|
+
|
|
713
|
+
def a_song?(value)
|
|
714
|
+
value.any? { |el| el && el[:enabled] }
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
def with_last_name?(value)
|
|
718
|
+
!value[:last_name].nil?
|
|
719
|
+
end
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
required(:songs).filled(:a_song?)
|
|
723
|
+
required(:artist).filled(:with_last_name?)
|
|
724
|
+
end
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
it "validates fails and shows the correct errors" do
|
|
728
|
+
form = AlbumForm.new(Album.new(nil, [], nil))
|
|
729
|
+
form.validate(
|
|
730
|
+
"songs" => [
|
|
731
|
+
{"title" => "One", "enabled" => false},
|
|
732
|
+
{"title" => nil, "enabled" => false},
|
|
733
|
+
{"title" => "Three", "enabled" => false}
|
|
734
|
+
],
|
|
735
|
+
"artist" => {"last_name" => nil}
|
|
736
|
+
).must_equal false
|
|
737
|
+
form.songs.size.must_equal 3
|
|
738
|
+
|
|
739
|
+
form.errors.messages.must_equal(
|
|
740
|
+
:songs => ["must have at least one enabled song"],
|
|
741
|
+
:artist => ["must have last name"],
|
|
742
|
+
:"songs.title" => ["must be filled"]
|
|
743
|
+
)
|
|
744
|
+
end
|
|
745
|
+
end
|
|
639
746
|
|
|
640
747
|
# Currenty dry-v don't support that option, it doesn't make sense
|
|
641
748
|
# I've talked to @solnic and he plans to add a "hint" feature to show
|
|
@@ -654,7 +761,7 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
654
761
|
# end
|
|
655
762
|
# end
|
|
656
763
|
|
|
657
|
-
# let
|
|
764
|
+
# let(:form) { MultipleErrorsForPropertyForm.new(Session.new) }
|
|
658
765
|
|
|
659
766
|
# # valid.
|
|
660
767
|
# it do
|