forme 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,523 +0,0 @@
1
- require_relative 'spec_helper'
2
- require_relative 'sequel_helper'
3
- require_relative 'erb_helper'
4
-
5
- begin
6
- require 'roda'
7
- require 'tilt'
8
- rescue LoadError
9
- warn "unable to load roda or tilt, skipping roda specs"
10
- else
11
- begin
12
- require 'tilt/erubi'
13
- rescue LoadError
14
- begin
15
- require 'tilt/erubis'
16
- rescue LoadError
17
- require 'tilt/erb'
18
- end
19
- else
20
- begin
21
- require 'erubi/capture_end'
22
- require_relative 'erubi_capture_helper'
23
- rescue LoadError
24
- end
25
- end
26
-
27
- def FormeRodaTest(block=ERB_BLOCK)
28
- Class.new(Roda) do
29
- opts[:check_dynamic_arity] = opts[:check_arity] = :warn
30
-
31
- if defined?(Roda::RodaVersionNumber) && Roda::RodaVersionNumber >= 30100
32
- require 'roda/session_middleware'
33
- opts[:sessions_convert_symbols] = true
34
- use RodaSessionMiddleware, :secret=>SecureRandom.random_bytes(64), :key=>'rack.session'
35
- else
36
- use Rack::Session::Cookie, :secret => "__a_very_long_string__"
37
- end
38
-
39
- def erb(s, opts={})
40
- render(opts.merge(:inline=>s))
41
- end
42
-
43
- route do |r|
44
- r.get 'use_request_specific_token', :use do |use|
45
- render :inline=>"[#{Base64.strict_encode64(send(:csrf_secret))}]<%= form({:method=>:post}, {:use_request_specific_token=>#{use == '1'}}) %>"
46
- end
47
- r.get 'csrf', :use do |use|
48
- render :inline=>"<%= form({:method=>:post}, {:csrf=>#{use == '1'}}) %>"
49
- end
50
- instance_exec(r, &block)
51
- end
52
- end
53
- end
54
-
55
- begin
56
- require 'rack/csrf'
57
- rescue LoadError
58
- warn "unable to load rack/csrf, skipping roda csrf plugin spec"
59
- else
60
- describe "Forme Roda ERB integration with roda forme and csrf plugins" do
61
- app = FormeRodaCSRFTest = FormeRodaTest()
62
- app.plugin :csrf
63
- app.plugin :forme
64
-
65
- def sin_get(path)
66
- s = String.new
67
- FormeRodaCSRFTest.app.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
68
- s.gsub(/\s+/, ' ').strip
69
- end
70
-
71
- include FormeErbSpecs
72
- end
73
- end
74
-
75
- module FormeRouteCsrfSpecs
76
- extend Minitest::Spec::DSL
77
- include FormeErbSpecs
78
-
79
- it "should have a valid CSRF tag" do
80
- output = sin_get('/use_request_specific_token/1')
81
- output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
82
- secret = $1
83
- token = $2
84
- app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/1', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal true
85
- app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/2', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal false
86
- end
87
-
88
- it "should handle the :use_request_specific_token => true option" do
89
- output = sin_get('/use_request_specific_token/1')
90
- output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
91
- secret = $1
92
- token = $2
93
- app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/1', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal true
94
- app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/2', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal false
95
- end
96
-
97
- it "should handle the :use_request_specific_token => false option" do
98
- output = sin_get('/use_request_specific_token/0')
99
- output =~ /\[([^\]]+)\].*?value=\"([^\"]+)\"/
100
- secret = $1
101
- token = $2
102
- app.new({'SCRIPT_NAME'=>'', 'PATH_INFO'=>'/use_request_specific_token/0', 'REQUEST_METHOD'=>'POST', 'rack.session'=>{'_roda_csrf_secret'=>secret}, 'rack.input'=>StringIO.new}).valid_csrf?(:token=>token).must_equal(plugin_opts.empty? ? false : true)
103
- end
104
-
105
- it "should handle the :csrf option" do
106
- sin_get('/csrf/1').must_include '<input name="_csrf" type="hidden" value="'
107
- sin_get('/csrf/0').wont_include '<input name="_csrf" type="hidden" value="'
108
- end
109
- end
110
-
111
- begin
112
- require 'roda/plugins/route_csrf'
113
- require 'roda/plugins/capture_erb'
114
- require 'roda/plugins/inject_erb'
115
- rescue LoadError
116
- warn "unable to load necessary Roda plugins, skipping forme_erubi_capture plugin spec"
117
- else
118
- describe "Forme Roda Erubi::CaptureEnd integration with roda forme_route_csrf" do
119
- app = FormeRodaTest(ERUBI_CAPTURE_BLOCK)
120
- app.plugin :forme_erubi_capture
121
- app.plugin :render, :engine_opts=>{'erb'=>{:engine_class=>Erubi::CaptureEndEngine}}
122
-
123
- define_method(:app){app}
124
- define_method(:plugin_opts){{}}
125
- define_method(:sin_get) do |path|
126
- s = String.new
127
- app.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
128
- s.gsub(/\s+/, ' ').strip
129
- end
130
-
131
- include FormeRouteCsrfSpecs
132
- end if defined?(ERUBI_CAPTURE_BLOCK)
133
-
134
- [{}, {:require_request_specific_tokens=>false}].each do |plugin_opts|
135
- describe "Forme Roda ERB integration with roda forme_route_csrf and route_csrf plugin with #{plugin_opts}" do
136
- app = FormeRodaTest()
137
- app.plugin :forme_route_csrf
138
- app.plugin :route_csrf, plugin_opts
139
-
140
- define_method(:app){app}
141
- define_method(:plugin_opts){plugin_opts}
142
- define_method(:sin_get) do |path|
143
- s = String.new
144
- app.call(@rack.merge('PATH_INFO'=>path))[2].each{|str| s << str}
145
- s.gsub(/\s+/, ' ').strip
146
- end
147
-
148
- include FormeRouteCsrfSpecs
149
- end
150
-
151
- describe "Forme Roda ERB Sequel integration with roda forme_set plugin and route_csrf plugin with #{plugin_opts}" do
152
- before do
153
- @app = FormeRodaTest()
154
- @app.plugin :route_csrf, plugin_opts
155
- @app.plugin(:forme_set, :secret=>'1'*64)
156
-
157
- @ab = Album.new
158
- end
159
-
160
- def forme_parse(*args, &block)
161
- _forme_set(:forme_parse, *args, &block)
162
- end
163
-
164
- def forme_set(*args, &block)
165
- _forme_set(:forme_set, *args, &block)
166
- end
167
-
168
- def forme_call(params)
169
- @app.call('REQUEST_METHOD'=>'POST', 'rack.input'=>StringIO.new, :params=>params)
170
- end
171
-
172
- def _forme_set(meth, obj, orig_hash, *form_args, &block)
173
- hash = {}
174
- forme_set_block = orig_hash.delete(:forme_set_block)
175
- orig_hash.each{|k,v| hash[k.to_s] = v}
176
- album = @ab
177
- ret, _, data, hmac = nil
178
-
179
- @app.route do |r|
180
- r.get do
181
- if @block = env[:block]
182
- render(:inline=>'<% form(*env[:args]) do |f| %><%= @block.call(f) %><% end %>')
183
- else
184
- form(*env[:args])
185
- end
186
- end
187
- r.post do
188
- r.params.replace(env[:params])
189
- ret = send(meth, album, &forme_set_block)
190
- nil
191
- end
192
- end
193
- body = @app.call('REQUEST_METHOD'=>'GET', :args=>[album, *form_args], :block=>block)[2].join
194
- body =~ %r|<input name="_csrf" type="hidden" value="([^"]+)"/>.*<input name="_forme_set_data" type="hidden" value="([^"]+)"/><input name="_forme_set_data_hmac" type="hidden" value="([^"]+)"/>|n
195
- csrf = $1
196
- data = $2
197
- hmac = $3
198
- data.gsub!("&quot;", '"') if data
199
- h = {"album"=>hash, "_forme_set_data"=>data, "_forme_set_data_hmac"=>hmac, "_csrf"=>csrf}
200
- if data && hmac
201
- forme_call(h)
202
- end
203
- meth == :forme_parse ? ret : h
204
- end
205
-
206
- it "should have subform work correctly" do
207
- @app.route do |r|
208
- @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
209
- @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
210
- erb <<END
211
- 0
212
- <% form(@album, {:action=>'/baz'}, :button=>'Sub') do |f| %>
213
- 1
214
- <%= f.subform(:artist, :inputs=>[:name], :legend=>'Foo', :grid=>true, :labels=>%w'Name') %>
215
- 2
216
- <% end %>
217
- 3
218
- END
219
- end
220
-
221
- body = @app.call('REQUEST_METHOD'=>'GET')[2].join.gsub("\n", ' ').gsub(/ +/, ' ').chomp(' ')
222
- body.sub(%r{<input name="_csrf" type="hidden" value="([^"]+)"/>}, '<input name="_csrf" type="hidden" value="csrf"/>').must_equal '0 <form action="/baz" class="forme album" method="post"><input name="_csrf" type="hidden" value="csrf"/> 1 <input id="album_artist_attributes_id" name="album[artist_attributes][id]" type="hidden" value="2"/><table><caption>Foo</caption><thead><tr><th>Name</th></tr></thead><tbody><tr><td class="string"><input id="album_artist_attributes_name" maxlength="255" name="album[artist_attributes][name]" type="text" value="A"/></td></tr></tbody></table> 2 <input type="submit" value="Sub"/></form>3'
223
- end
224
-
225
- it "#forme_set should include HMAC values if form includes inputs for obj" do
226
- h = forme_set(@ab, :name=>'Foo')
227
- proc{forme_call(h)}.must_raise Roda::RodaPlugins::FormeSet::Error
228
- @ab.name.must_be_nil
229
- @ab.copies_sold.must_be_nil
230
-
231
- h = forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
232
- hmac = h.delete("_forme_set_data_hmac")
233
- proc{forme_call(h)}.must_raise Roda::RodaPlugins::FormeSet::Error
234
- proc{forme_call(h.merge("_forme_set_data_hmac"=>hmac+'1'))}.must_raise Roda::RodaPlugins::FormeSet::Error
235
- data = h["_forme_set_data"]
236
- data.sub!(/"csrf":\["_csrf","./, "\"csrf\":[\"_csrf\",\"|")
237
- hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA512.new, '1'*64, data)
238
- proc{forme_call(h.merge("_forme_set_data_hmac"=>hmac))}.must_raise Roda::RodaPlugins::FormeSet::Error
239
- @ab.name.must_equal 'Foo'
240
- @ab.copies_sold.must_be_nil
241
-
242
- forme_set(@ab, :copies_sold=>100){|f| f.input(:name)}
243
- @ab.name.must_be_nil
244
- @ab.copies_sold.must_be_nil
245
- end
246
-
247
- it "#forme_set should handle custom form namespaces" do
248
- forme_set(@ab, {"album"=>{"name"=>'Foo', 'copies_sold'=>'100'}}, {}, :namespace=>'album'){|f| f.input(:name); f.input(:copies_sold)}
249
- @ab.name.must_equal 'Foo'
250
- @ab.copies_sold.must_equal 100
251
-
252
- proc{forme_set(@ab, {"a"=>{"name"=>'Foo'}}, {}, :namespace=>'album'){|f| f.input(:name); f.input(:copies_sold)}}.must_raise Roda::RodaPlugins::FormeSet::Error
253
- end
254
-
255
- it "#forme_set should call plugin block if there is an error with the form submission hmac not matching data" do
256
- @app.plugin :forme_set do |error_type, _|
257
- request.on{error_type.to_s}
258
- end
259
-
260
- h = forme_set(@ab, :name=>'Foo')
261
- forme_call(h)[2].must_equal ['missing_data']
262
-
263
- h = forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
264
- hmac = h.delete("_forme_set_data_hmac")
265
- forme_call(h)[2].must_equal ['missing_hmac']
266
-
267
- forme_call(h.merge("_forme_set_data_hmac"=>hmac+'1'))[2].must_equal ['hmac_mismatch']
268
-
269
- data = h["_forme_set_data"]
270
- data.sub!(/"csrf":\["_csrf","./, "\"csrf\":[\"_csrf\",\"|")
271
- hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA512.new, '1'*64, data)
272
- forme_call(h.merge("_forme_set_data_hmac"=>hmac))[2].must_equal ['csrf_mismatch']
273
-
274
- h = forme_set(@ab, :name=>'Foo')
275
- h.delete('album')
276
- forme_call(h)[2].must_equal ['missing_namespace']
277
- end
278
-
279
- it "#forme_set should raise if plugin block does not raise or throw" do
280
- @app.plugin :forme_set do |_, obj|
281
- obj
282
- end
283
- h = forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
284
- h.delete("_forme_set_data_hmac")
285
- proc{forme_call(h)}.must_raise Roda::RodaPlugins::FormeSet::Error
286
- end
287
-
288
- it "#forme_set should only set values in the form" do
289
- forme_set(@ab, :name=>'Foo')
290
- @ab.name.must_be_nil
291
-
292
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
293
- @ab.name.must_equal 'Foo'
294
-
295
- forme_set(@ab, 'copies_sold'=>'1'){|f| f.input(:name)}
296
- @ab.name.must_be_nil
297
- @ab.copies_sold.must_be_nil
298
-
299
- forme_set(@ab, 'name'=>'Bar', 'copies_sold'=>'1'){|f| f.input(:name); f.input(:copies_sold)}
300
- @ab.name.must_equal 'Bar'
301
- @ab.copies_sold.must_equal 1
302
- end
303
-
304
- it "#forme_set should handle form_versions" do
305
- h = forme_set(@ab, {:name=>'Foo'}){|f| f.input(:name)}
306
- @ab.name.must_equal 'Foo'
307
-
308
- obj = nil
309
- version = nil
310
- name = nil
311
- forme_set_block = proc do |v, o|
312
- obj = o
313
- name = o.name
314
- version = v
315
- end
316
- h2 = forme_set(@ab, {:name=>'Foo', :forme_set_block=>forme_set_block}, {}, :form_version=>1){|f| f.input(:name)}
317
- obj.must_be_same_as @ab
318
- name.must_equal 'Foo'
319
- version.must_equal 1
320
-
321
- forme_call(h)
322
- obj.must_be_same_as @ab
323
- version.must_be_nil
324
-
325
- forme_set(@ab, {:name=>'Bar', :forme_set_block=>forme_set_block}, {}, :form_version=>2){|f| f.input(:name)}
326
- obj.must_be_same_as @ab
327
- name.must_equal 'Bar'
328
- version.must_equal 2
329
-
330
- h['album']['name'] = 'Baz'
331
- forme_call(h)
332
- obj.must_be_same_as @ab
333
- name.must_equal 'Baz'
334
- version.must_be_nil
335
-
336
- forme_call(h2)
337
- obj.must_be_same_as @ab
338
- version.must_equal 1
339
- end
340
-
341
- it "#forme_set should work for forms without blocks" do
342
- forme_set(@ab, {:name=>'Foo'}, {}, :inputs=>[:name])
343
- @ab.name.must_equal 'Foo'
344
- end
345
-
346
- it "#forme_set should handle different ways to specify parameter names" do
347
- [{:attr=>{:name=>'foo'}}, {:attr=>{'name'=>:foo}}, {:name=>'foo'}, {:name=>'bar[foo]'}, {:key=>:foo}].each do |opts|
348
- forme_set(@ab, name=>'Foo'){|f| f.input(:name, opts)}
349
- @ab.name.must_be_nil
350
-
351
- forme_set(@ab, 'foo'=>'Foo'){|f| f.input(:name, opts)}
352
- @ab.name.must_equal 'Foo'
353
- end
354
- end
355
-
356
- it "#forme_set should ignore values where key is explicitly set to nil" do
357
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name, :key=>nil)}
358
- @ab.forme_set(:name=>'Foo')
359
- @ab.name.must_be_nil
360
- @ab.forme_set(nil=>'Foo')
361
- @ab.name.must_be_nil
362
- end
363
-
364
- it "#forme_set should skip inputs with disabled/readonly formatter set on input" do
365
- [:disabled, :readonly, ::Forme::Formatter::Disabled, ::Forme::Formatter::ReadOnly].each do |formatter|
366
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name, :formatter=>formatter)}
367
- @ab.name.must_be_nil
368
- end
369
-
370
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name, :formatter=>:default)}
371
- @ab.name.must_equal 'Foo'
372
- end
373
-
374
- it "#forme_set should skip inputs with disabled/readonly formatter set on Form" do
375
- [:disabled, :readonly, ::Forme::Formatter::Disabled, ::Forme::Formatter::ReadOnly].each do |formatter|
376
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:disabled){|f| f.input(:name)}
377
- @ab.name.must_be_nil
378
- end
379
-
380
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:default){|f| f.input(:name)}
381
- @ab.name.must_equal 'Foo'
382
- end
383
-
384
- it "#forme_set should skip inputs with disabled/readonly formatter set using with_opts" do
385
- [:disabled, :readonly, ::Forme::Formatter::Disabled, ::Forme::Formatter::ReadOnly].each do |formatter|
386
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>formatter){f.input(:name)}}
387
- @ab.name.must_be_nil
388
- end
389
-
390
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>:default){f.input(:name)}}
391
- @ab.name.must_equal 'Foo'
392
- end
393
-
394
- it "#forme_set should prefer input formatter to with_opts formatter" do
395
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>:default){f.input(:name, :formatter=>:readonly)}}
396
- @ab.name.must_be_nil
397
-
398
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>:readonly){f.input(:name, :formatter=>:default)}}
399
- @ab.name.must_equal 'Foo'
400
- end
401
-
402
- it "#forme_set should prefer with_opts formatter to form formatter" do
403
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:default){|f| f.with_opts(:formatter=>:readonly){f.input(:name)}}
404
- @ab.name.must_be_nil
405
-
406
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:readonly){|f| f.with_opts(:formatter=>:default){f.input(:name)}}
407
- @ab.name.must_equal 'Foo'
408
- end
409
-
410
- it "#forme_set should handle setting values for associated objects" do
411
- forme_set(@ab, :artist_id=>'1')
412
- @ab.artist_id.must_be_nil
413
-
414
- forme_set(@ab, :artist_id=>'1'){|f| f.input(:artist)}
415
- @ab.artist_id.must_equal 1
416
-
417
- forme_set(@ab, 'tag_pks'=>%w'1 2'){|f| f.input(:artist)}
418
- @ab.artist_id.must_be_nil
419
- @ab.tag_pks.must_equal []
420
-
421
- forme_set(@ab, 'artist_id'=>'1', 'tag_pks'=>%w'1 2'){|f| f.input(:artist); f.input(:tags)}
422
- @ab.artist_id.must_equal 1
423
- @ab.tag_pks.must_equal [1, 2]
424
- end
425
-
426
- it "#forme_set should handle validations for filtered associations" do
427
- [
428
- [{:dataset=>proc{|ds| ds.exclude(:id=>1)}},
429
- {:dataset=>proc{|ds| ds.exclude(:id=>1)}}],
430
- [{:options=>Artist.exclude(:id=>1).select_order_map([:name, :id])},
431
- {:options=>Tag.exclude(:id=>1).select_order_map(:id), :name=>'tag_pks[]'}],
432
- [{:options=>Artist.exclude(:id=>1).all, :text_method=>:name, :value_method=>:id},
433
- {:options=>Tag.exclude(:id=>1).all, :text_method=>:name, :value_method=>:id}],
434
- ].each do |artist_opts, tag_opts|
435
- @ab.forme_validations.clear
436
- forme_set(@ab, 'artist_id'=>'1', 'tag_pks'=>%w'1 2'){|f| f.input(:artist, artist_opts); f.input(:tags, tag_opts)}
437
- @ab.artist_id.must_equal 1
438
- @ab.tag_pks.must_equal [1, 2]
439
- @ab.valid?.must_equal false
440
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
441
- @ab.errors[:tag_pks].must_equal ['invalid value submitted']
442
-
443
- @ab.forme_validations.clear
444
- forme_set(@ab, 'artist_id'=>'1', 'tag_pks'=>%w'2'){|f| f.input(:artist, artist_opts); f.input(:tags, tag_opts)}
445
- @ab.forme_set('artist_id'=>'1', 'tag_pks'=>['2'])
446
- @ab.artist_id.must_equal 1
447
- @ab.tag_pks.must_equal [2]
448
- @ab.valid?.must_equal false
449
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
450
- @ab.errors[:tag_pks].must_be_nil
451
-
452
- @ab.forme_validations.clear
453
- forme_set(@ab, 'artist_id'=>'2', 'tag_pks'=>%w'2'){|f| f.input(:artist, artist_opts); f.input(:tags, tag_opts)}
454
- @ab.valid?.must_equal true
455
- end
456
- end
457
-
458
- it "#forme_set should not require associated values for many_to_one association with select boxes" do
459
- forme_set(@ab, {}){|f| f.input(:artist)}
460
- @ab.valid?.must_equal true
461
-
462
- forme_set(@ab, {'artist_id'=>nil}){|f| f.input(:artist)}
463
- @ab.valid?.must_equal true
464
-
465
- forme_set(@ab, {'artist_id'=>''}){|f| f.input(:artist)}
466
- @ab.valid?.must_equal true
467
- end
468
-
469
- it "#forme_set should not require associated values for many_to_one association with radio buttons" do
470
- forme_set(@ab, {}){|f| f.input(:artist, :as=>:radio)}
471
- @ab.valid?.must_equal true
472
- end
473
-
474
- it "#forme_set should require associated values for many_to_one association with select boxes when :required is used" do
475
- forme_set(@ab, {}){|f| f.input(:artist, :required=>true)}
476
- @ab.valid?.must_equal false
477
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
478
- end
479
-
480
- it "#forme_set should require associated values for many_to_one association with radio buttons when :required is used" do
481
- forme_set(@ab, {}){|f| f.input(:artist, :as=>:radio, :required=>true)}
482
- @ab.valid?.must_equal false
483
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
484
- end
485
-
486
- it "#forme_set should handle cases where currently associated values is nil" do
487
- def @ab.tag_pks; nil; end
488
- forme_set(@ab, :tag_pks=>['1']){|f| f.input(:tags)}
489
- @ab.valid?.must_equal true
490
- end
491
-
492
- it "#forme_parse should return hash with values and validations" do
493
- forme_parse(@ab, :name=>'Foo'){|f| f.input(:name)}.must_equal(:values=>{:name=>'Foo'}, :validations=>{}, :form_version=>nil)
494
-
495
- hash = forme_parse(@ab, :name=>'Foo', 'artist_id'=>'1') do |f|
496
- f.input(:name)
497
- f.input(:artist, :dataset=>proc{|ds| ds.exclude(:id=>1)})
498
- end
499
- hash.must_equal(:values=>{:name=>'Foo', :artist_id=>'1'}, :validations=>{:artist_id=>[:valid, false]}, :form_version=>nil)
500
-
501
- @ab.set(hash[:values])
502
- @ab.valid?.must_equal true
503
-
504
- @ab.forme_validations.merge!(hash[:validations])
505
- @ab.valid?.must_equal false
506
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
507
-
508
- @ab = Album.new
509
- hash = forme_parse(@ab, {:name=>'Foo', 'artist_id'=>'1'}, {}, :form_version=>1) do |f|
510
- f.input(:name)
511
- f.input(:artist, :dataset=>proc{|ds| ds.exclude(:id=>2)})
512
- end
513
- hash.must_equal(:values=>{:name=>'Foo', :artist_id=>'1'}, :validations=>{:artist_id=>[:valid, true]}, :form_version=>1)
514
- @ab.set(hash[:values])
515
- @ab.valid?.must_equal true
516
-
517
- @ab.forme_validations.merge!(hash[:validations])
518
- @ab.valid?.must_equal true
519
- end
520
- end
521
- end
522
- end
523
- end
@@ -1,101 +0,0 @@
1
- require 'sequel'
2
-
3
- db_url = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby' ? 'jdbc:sqlite::memory:' : 'sqlite:/'
4
- DB = Sequel.connect(db_url, :identifier_mangling=>false)
5
- DB.extension(:freeze_datasets)
6
- Sequel.default_timezone = :utc
7
- DB.create_table(:artists) do
8
- primary_key :id
9
- String :name
10
- end
11
- DB.create_table(:albums) do
12
- primary_key :id
13
- foreign_key :artist_id, :artists
14
- String :name
15
- TrueClass :gold
16
- TrueClass :platinum, :null=>false, :default=>false
17
- Date :release_date
18
- DateTime :created_at
19
- Integer :copies_sold
20
- end
21
- DB.create_table(:album_infos) do
22
- primary_key :id
23
- foreign_key :album_id, :albums
24
- String :info
25
- end
26
- DB.create_table(:tracks) do
27
- primary_key :id
28
- foreign_key :album_id, :albums
29
- String :name
30
- end
31
- DB.create_table(:tags) do
32
- primary_key :id
33
- String :name
34
- end
35
- DB.create_table(:albums_tags) do
36
- foreign_key :album_id, :albums
37
- foreign_key :tag_id, :tags
38
- end
39
-
40
- a = DB[:artists].insert(:name=>'a')
41
- d = DB[:artists].insert(:name=>'d')
42
- b = DB[:albums].insert(:name=>'b', :artist_id=>a, :gold=>false, :release_date=>Date.new(2011, 6, 5), :created_at=>Date.new(2011, 6, 5), :copies_sold=>10)
43
- DB[:tracks].insert(:name=>'m', :album_id=>b)
44
- DB[:tracks].insert(:name=>'n', :album_id=>b)
45
- c = DB[:albums].insert(:name=>'c', :artist_id=>d, :gold=>true, :platinum=>true)
46
- DB[:tracks].insert(:name=>'o', :album_id=>c)
47
- s = DB[:tags].insert(:name=>'s')
48
- t = DB[:tags].insert(:name=>'t')
49
- DB[:tags].insert(:name=>'u')
50
- [[b, s], [b, t], [c, t]].each{|k, v| DB[:albums_tags].insert(k, v)}
51
-
52
- # Allow loading of pg_array extension even when not on PostgreSQL
53
- def DB.add_conversion_proc(*)
54
- super if defined?(super)
55
- end
56
- def DB.conversion_procs_updated(*)
57
- super if defined?(super)
58
- end
59
- def DB.conversion_procs
60
- return super if defined?(super)
61
- {}
62
- end
63
-
64
- Sequel::Model.plugin :forme
65
- class Album < Sequel::Model
66
- plugin :association_pks
67
- plugin :forme_set
68
-
69
- many_to_one :artist, :order=>:name
70
- one_to_one :album_info
71
- one_to_many :tracks
72
- many_to_many :tags, :delay_pks=>:always
73
-
74
- plugin :pg_array_associations
75
- pg_array_to_many :atags, :class=>:Tag
76
-
77
- def atag_ids
78
- @atag_ids ||= [1,2]
79
- end
80
-
81
- def artist_name
82
- artist.name if artist
83
- end
84
-
85
- alias foo= name=
86
-
87
- if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
88
- # Add workaround for no boolean handling in jdbc-sqlite3
89
- plugin :typecast_on_load, :gold, :platinum, :release_date, :created_at
90
- end
91
- end
92
- class Artist < Sequel::Model
93
- one_to_many :albums
94
- def idname() "#{id}#{name}" end
95
- def name2() "#{name}2" end
96
- def name3() "#{name}3" end
97
- end
98
- class Track < Sequel::Model; end
99
- class Tag < Sequel::Model; end
100
- class AlbumInfo < Sequel::Model; end
101
-
@@ -1,40 +0,0 @@
1
- require_relative 'sequel_helper'
2
-
3
- gem 'i18n', '>= 0.7.0'
4
- require 'i18n'
5
- I18n.load_path = [File.join(File.dirname(File.expand_path(__FILE__)), 'i18n_helper.yml')]
6
-
7
- DB.create_table(:firms) do
8
- primary_key :id
9
- String :name
10
- end
11
- DB.create_table(:invoices) do
12
- primary_key :id
13
- foreign_key :firm_id, :firms
14
- String :name
15
- String :summary
16
- end
17
- DB.create_table(:clients) do
18
- primary_key :id
19
- foreign_key :firm_id, :firms
20
- String :name
21
- end
22
-
23
- a = DB[:firms].insert(:name=>'a')
24
- DB[:invoices].insert(:name=>'b', :firm_id=>a, :summary=>'a brief summary')
25
- DB[:clients].insert(:name=>'a great client', :firm_id=>a)
26
-
27
- class Firm < Sequel::Model
28
- one_to_many :invoices
29
- one_to_many :clients
30
- end
31
-
32
- class Invoice < Sequel::Model
33
- many_to_one :firm
34
- end
35
-
36
- class Client < Sequel::Model
37
- many_to_one :firm
38
- end
39
-
40
- [Firm, Invoice, Client].each{|c| c.plugin :forme_i18n }