forme 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,541 +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
- handle_params = hash.delete(:handle_params)
176
- orig_hash.each{|k,v| hash[k.to_s] = v}
177
- album = obj
178
- ret, _, data, hmac = nil
179
-
180
- @app.route do |r|
181
- r.get do
182
- if @block = env[:block]
183
- render(:inline=>'<% form(*env[:args]) do |f| %><%= @block.call(f) %><% end %>')
184
- else
185
- form(*env[:args])
186
- end
187
- end
188
- r.post do
189
- r.params.replace(env[:params])
190
- ret = send(meth, album, &forme_set_block)
191
- nil
192
- end
193
- end
194
- body = @app.call('REQUEST_METHOD'=>'GET', :args=>[album, *form_args], :block=>block)[2].join
195
- 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
196
- csrf = $1
197
- data = $2
198
- hmac = $3
199
- data.gsub!("&quot;", '"') if data
200
- h = {"album"=>hash, "_forme_set_data"=>data, "_forme_set_data_hmac"=>hmac, "_csrf"=>csrf, "body"=>body}
201
- if data && hmac
202
- h = handle_params.call(h) if handle_params
203
- forme_call(h)
204
- end
205
- meth == :forme_parse ? ret : h
206
- end
207
-
208
- it "should have subform work correctly" do
209
- @app.route do |r|
210
- @album = Album.load(:name=>'N', :copies_sold=>2, :id=>1)
211
- @album.associations[:artist] = Artist.load(:name=>'A', :id=>2)
212
- erb <<END
213
- 0
214
- <% form(@album, {:action=>'/baz'}, :button=>'Sub') do |f| %>
215
- 1
216
- <%= f.subform(:artist, :inputs=>[:name], :legend=>'Foo', :grid=>true, :labels=>%w'Name') %>
217
- 2
218
- <% end %>
219
- 3
220
- END
221
- end
222
-
223
- body = @app.call('REQUEST_METHOD'=>'GET')[2].join.gsub("\n", ' ').gsub(/ +/, ' ').chomp(' ')
224
- 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'
225
- end
226
-
227
- it "#forme_set should include HMAC values if form includes inputs for obj" do
228
- h = forme_set(@ab, :name=>'Foo')
229
- proc{forme_call(h)}.must_raise Roda::RodaPlugins::FormeSet::Error
230
- @ab.name.must_be_nil
231
- @ab.copies_sold.must_be_nil
232
-
233
- h = forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
234
- hmac = h.delete("_forme_set_data_hmac")
235
- proc{forme_call(h)}.must_raise Roda::RodaPlugins::FormeSet::Error
236
- proc{forme_call(h.merge("_forme_set_data_hmac"=>hmac+'1'))}.must_raise Roda::RodaPlugins::FormeSet::Error
237
- data = h["_forme_set_data"]
238
- data.sub!(/"csrf":\["_csrf","./, "\"csrf\":[\"_csrf\",\"|")
239
- hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA512.new, '1'*64, data)
240
- proc{forme_call(h.merge("_forme_set_data_hmac"=>hmac))}.must_raise Roda::RodaPlugins::FormeSet::Error
241
- @ab.name.must_equal 'Foo'
242
- @ab.copies_sold.must_be_nil
243
-
244
- forme_set(@ab, :copies_sold=>100){|f| f.input(:name)}
245
- @ab.name.must_be_nil
246
- @ab.copies_sold.must_be_nil
247
- end
248
-
249
- it "#forme_set handle missing csrf" do
250
- h = forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
251
- @ab.name = nil
252
- data = JSON.parse(h["_forme_set_data"])
253
- data.delete('csrf')
254
- data = data.to_json
255
- hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA512.new, '1'*64, data)
256
- forme_call(h.merge("_forme_set_data_hmac"=>hmac, "_forme_set_data"=>data))
257
- @ab.name.must_equal 'Foo'
258
- @ab.copies_sold.must_be_nil
259
- end
260
-
261
- it "#forme_set should handle custom form namespaces" do
262
- forme_set(@ab, {"album"=>{"name"=>'Foo', 'copies_sold'=>'100'}}, {}, :namespace=>'album'){|f| f.input(:name); f.input(:copies_sold)}
263
- @ab.name.must_equal 'Foo'
264
- @ab.copies_sold.must_equal 100
265
-
266
- proc{forme_set(@ab, {"a"=>{"name"=>'Foo'}}, {}, :namespace=>'album'){|f| f.input(:name); f.input(:copies_sold)}}.must_raise Roda::RodaPlugins::FormeSet::Error
267
- end
268
-
269
- it "#forme_set should call plugin block if there is an error with the form submission hmac not matching data" do
270
- @app.plugin :forme_set do |error_type, _|
271
- request.on{error_type.to_s}
272
- end
273
-
274
- h = forme_set(@ab, :name=>'Foo')
275
- forme_call(h)[2].must_equal ['missing_data']
276
-
277
- h = forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
278
- hmac = h.delete("_forme_set_data_hmac")
279
- forme_call(h)[2].must_equal ['missing_hmac']
280
-
281
- forme_call(h.merge("_forme_set_data_hmac"=>hmac+'1'))[2].must_equal ['hmac_mismatch']
282
-
283
- data = h["_forme_set_data"]
284
- data.sub!(/"csrf":\["_csrf","./, "\"csrf\":[\"_csrf\",\"|")
285
- hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA512.new, '1'*64, data)
286
- forme_call(h.merge("_forme_set_data_hmac"=>hmac))[2].must_equal ['csrf_mismatch']
287
-
288
- h = forme_set(@ab, :name=>'Foo')
289
- h.delete('album')
290
- forme_call(h)[2].must_equal ['missing_namespace']
291
- end
292
-
293
- it "#forme_set should raise if plugin block does not raise or throw" do
294
- @app.plugin :forme_set do |_, obj|
295
- obj
296
- end
297
- h = forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
298
- h.delete("_forme_set_data_hmac")
299
- proc{forme_call(h)}.must_raise Roda::RodaPlugins::FormeSet::Error
300
- end
301
-
302
- it "#forme_set should only set values in the form" do
303
- forme_set(@ab, :name=>'Foo')
304
- @ab.name.must_be_nil
305
-
306
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name)}
307
- @ab.name.must_equal 'Foo'
308
-
309
- forme_set(@ab, 'copies_sold'=>'1'){|f| f.input(:name)}
310
- @ab.name.must_be_nil
311
- @ab.copies_sold.must_be_nil
312
-
313
- forme_set(@ab, 'name'=>'Bar', 'copies_sold'=>'1'){|f| f.input(:name); f.input(:copies_sold)}
314
- @ab.name.must_equal 'Bar'
315
- @ab.copies_sold.must_equal 1
316
- end
317
-
318
- it "#forme_set should handle form_versions" do
319
- h = forme_set(@ab, {:name=>'Foo'}){|f| f.input(:name)}
320
- @ab.name.must_equal 'Foo'
321
-
322
- obj = nil
323
- version = nil
324
- name = nil
325
- forme_set_block = proc do |v, o|
326
- obj = o
327
- name = o.name
328
- version = v
329
- end
330
- h2 = forme_set(@ab, {:name=>'Foo', :forme_set_block=>forme_set_block}, {}, :form_version=>1){|f| f.input(:name)}
331
- obj.must_be_same_as @ab
332
- name.must_equal 'Foo'
333
- version.must_equal 1
334
-
335
- forme_call(h)
336
- obj.must_be_same_as @ab
337
- version.must_be_nil
338
-
339
- forme_set(@ab, {:name=>'Bar', :forme_set_block=>forme_set_block}, {}, :form_version=>2){|f| f.input(:name)}
340
- obj.must_be_same_as @ab
341
- name.must_equal 'Bar'
342
- version.must_equal 2
343
-
344
- h['album']['name'] = 'Baz'
345
- forme_call(h)
346
- obj.must_be_same_as @ab
347
- name.must_equal 'Baz'
348
- version.must_be_nil
349
-
350
- forme_call(h2)
351
- obj.must_be_same_as @ab
352
- version.must_equal 1
353
- end
354
-
355
- it "#forme_set should work for forms without blocks" do
356
- forme_set(@ab, {:name=>'Foo'}, {}, :inputs=>[:name])
357
- @ab.name.must_equal 'Foo'
358
- end
359
-
360
- it "#forme_set should handle different ways to specify parameter names" do
361
- [{:attr=>{:name=>'foo'}}, {:attr=>{'name'=>:foo}}, {:name=>'foo'}, {:name=>'bar[foo]'}, {:key=>:foo}].each do |opts|
362
- forme_set(@ab, name=>'Foo'){|f| f.input(:name, opts)}
363
- @ab.name.must_be_nil
364
-
365
- forme_set(@ab, 'foo'=>'Foo'){|f| f.input(:name, opts)}
366
- @ab.name.must_equal 'Foo'
367
- end
368
- end
369
-
370
- it "#forme_set should ignore values where key is explicitly set to nil" do
371
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name, :key=>nil)}
372
- @ab.forme_set(:name=>'Foo')
373
- @ab.name.must_be_nil
374
- @ab.forme_set(nil=>'Foo')
375
- @ab.name.must_be_nil
376
- end
377
-
378
- it "#forme_set should skip inputs with disabled/readonly formatter set on input" do
379
- [:disabled, :readonly, ::Forme::Formatter::Disabled, ::Forme::Formatter::ReadOnly].each do |formatter|
380
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name, :formatter=>formatter)}
381
- @ab.name.must_be_nil
382
- end
383
-
384
- forme_set(@ab, :name=>'Foo'){|f| f.input(:name, :formatter=>:default)}
385
- @ab.name.must_equal 'Foo'
386
- end
387
-
388
- it "#forme_set should skip inputs with disabled/readonly formatter set on Form" do
389
- [:disabled, :readonly, ::Forme::Formatter::Disabled, ::Forme::Formatter::ReadOnly].each do |formatter|
390
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:disabled){|f| f.input(:name)}
391
- @ab.name.must_be_nil
392
- end
393
-
394
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:default){|f| f.input(:name)}
395
- @ab.name.must_equal 'Foo'
396
- end
397
-
398
- it "#forme_set should skip inputs with disabled/readonly formatter set using with_opts" do
399
- [:disabled, :readonly, ::Forme::Formatter::Disabled, ::Forme::Formatter::ReadOnly].each do |formatter|
400
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>formatter){f.input(:name)}}
401
- @ab.name.must_be_nil
402
- end
403
-
404
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>:default){f.input(:name)}}
405
- @ab.name.must_equal 'Foo'
406
- end
407
-
408
- it "#forme_set should prefer input formatter to with_opts formatter" do
409
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>:default){f.input(:name, :formatter=>:readonly)}}
410
- @ab.name.must_be_nil
411
-
412
- forme_set(@ab, :name=>'Foo'){|f| f.with_opts(:formatter=>:readonly){f.input(:name, :formatter=>:default)}}
413
- @ab.name.must_equal 'Foo'
414
- end
415
-
416
- it "#forme_set should prefer with_opts formatter to form formatter" do
417
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:default){|f| f.with_opts(:formatter=>:readonly){f.input(:name)}}
418
- @ab.name.must_be_nil
419
-
420
- forme_set(@ab, {:name=>'Foo'}, {}, :formatter=>:readonly){|f| f.with_opts(:formatter=>:default){f.input(:name)}}
421
- @ab.name.must_equal 'Foo'
422
- end
423
-
424
- it "#forme_set should handle setting values for associated objects" do
425
- forme_set(@ab, :artist_id=>'1')
426
- @ab.artist_id.must_be_nil
427
-
428
- forme_set(@ab, :artist_id=>'1'){|f| f.input(:artist)}
429
- @ab.artist_id.must_equal 1
430
-
431
- forme_set(@ab, 'tag_pks'=>%w'1 2'){|f| f.input(:artist)}
432
- @ab.artist_id.must_be_nil
433
- @ab.tag_pks.must_equal []
434
-
435
- forme_set(@ab, 'artist_id'=>'1', 'tag_pks'=>%w'1 2'){|f| f.input(:artist); f.input(:tags)}
436
- @ab.artist_id.must_equal 1
437
- @ab.tag_pks.must_equal [1, 2]
438
- end
439
-
440
- it "#forme_set should handle validations for filtered associations" do
441
- [
442
- [{:dataset=>proc{|ds| ds.exclude(:id=>1)}},
443
- {:dataset=>proc{|ds| ds.exclude(:id=>1)}}],
444
- [{:options=>Artist.exclude(:id=>1).select_order_map([:name, :id])},
445
- {:options=>Tag.exclude(:id=>1).select_order_map(:id), :name=>'tag_pks[]'}],
446
- [{:options=>Artist.exclude(:id=>1).all, :text_method=>:name, :value_method=>:id},
447
- {:options=>Tag.exclude(:id=>1).all, :text_method=>:name, :value_method=>:id}],
448
- ].each do |artist_opts, tag_opts|
449
- @ab.forme_validations.clear
450
- forme_set(@ab, 'artist_id'=>'1', 'tag_pks'=>%w'1 2'){|f| f.input(:artist, artist_opts); f.input(:tags, tag_opts)}
451
- @ab.artist_id.must_equal 1
452
- @ab.tag_pks.must_equal [1, 2]
453
- @ab.valid?.must_equal false
454
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
455
- @ab.errors[:tag_pks].must_equal ['invalid value submitted']
456
-
457
- @ab.forme_validations.clear
458
- forme_set(@ab, 'artist_id'=>'1', 'tag_pks'=>%w'2'){|f| f.input(:artist, artist_opts); f.input(:tags, tag_opts)}
459
- @ab.forme_set('artist_id'=>'1', 'tag_pks'=>['2'])
460
- @ab.artist_id.must_equal 1
461
- @ab.tag_pks.must_equal [2]
462
- @ab.valid?.must_equal false
463
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
464
- @ab.errors[:tag_pks].must_be_nil
465
-
466
- @ab.forme_validations.clear
467
- forme_set(@ab, 'artist_id'=>'2', 'tag_pks'=>%w'2'){|f| f.input(:artist, artist_opts); f.input(:tags, tag_opts)}
468
- @ab.valid?.must_equal true
469
- end
470
- end
471
-
472
- it "#forme_set should not require associated values for many_to_one association with select boxes" do
473
- forme_set(@ab, {}){|f| f.input(:artist)}
474
- @ab.valid?.must_equal true
475
-
476
- forme_set(@ab, {'artist_id'=>nil}){|f| f.input(:artist)}
477
- @ab.valid?.must_equal true
478
-
479
- forme_set(@ab, {'artist_id'=>''}){|f| f.input(:artist)}
480
- @ab.valid?.must_equal true
481
- end
482
-
483
- it "#forme_set should not require associated values for many_to_one association with radio buttons" do
484
- forme_set(@ab, {}){|f| f.input(:artist, :as=>:radio)}
485
- @ab.valid?.must_equal true
486
- end
487
-
488
- it "#forme_set should require associated values for many_to_one association with select boxes when :required is used" do
489
- forme_set(@ab, {}){|f| f.input(:artist, :required=>true)}
490
- @ab.valid?.must_equal false
491
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
492
- end
493
-
494
- it "#forme_set should require associated values for many_to_one association with radio buttons when :required is used" do
495
- forme_set(@ab, {}){|f| f.input(:artist, :as=>:radio, :required=>true)}
496
- @ab.valid?.must_equal false
497
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
498
- end
499
-
500
- it "#forme_set should handle cases where currently associated values is nil" do
501
- def @ab.tag_pks; nil; end
502
- forme_set(@ab, :tag_pks=>['1']){|f| f.input(:tags)}
503
- @ab.valid?.must_equal true
504
- end
505
-
506
- it "#forme_parse should return hash with values and validations" do
507
- forme_parse(@ab, :name=>'Foo'){|f| f.input(:name)}.must_equal(:values=>{:name=>'Foo'}, :validations=>{}, :form_version=>nil)
508
-
509
- hash = forme_parse(@ab, :name=>'Foo', 'artist_id'=>'1') do |f|
510
- f.input(:name)
511
- f.input(:artist, :dataset=>proc{|ds| ds.exclude(:id=>1)})
512
- end
513
- hash.must_equal(:values=>{:name=>'Foo', :artist_id=>'1'}, :validations=>{:artist_id=>[:valid, false]}, :form_version=>nil)
514
-
515
- @ab.set(hash[:values])
516
- @ab.valid?.must_equal true
517
-
518
- @ab.forme_validations.merge!(hash[:validations])
519
- @ab.valid?.must_equal false
520
- @ab.errors[:artist_id].must_equal ['invalid value submitted']
521
-
522
- @ab = Album.new
523
- hash = forme_parse(@ab, {:name=>'Foo', 'artist_id'=>'1'}, {}, :form_version=>1) do |f|
524
- f.input(:name)
525
- f.input(:artist, :dataset=>proc{|ds| ds.exclude(:id=>2)})
526
- end
527
- hash.must_equal(:values=>{:name=>'Foo', :artist_id=>'1'}, :validations=>{:artist_id=>[:valid, true]}, :form_version=>1)
528
- @ab.set(hash[:values])
529
- @ab.valid?.must_equal true
530
-
531
- @ab.forme_validations.merge!(hash[:validations])
532
- @ab.valid?.must_equal true
533
- end
534
-
535
- it "should handle forms with objects that don't support forme_inputs" do
536
- forme_set(String, {:name=>'Foo'}, {}, :inputs=>[:name])['body'].must_equal '<form><fieldset class="inputs"><input id="name" name="name" type="text" value="String"/></fieldset></form>'
537
- end
538
- end
539
- end
540
- end
541
- end
@@ -1,103 +0,0 @@
1
- require 'sequel'
2
-
3
- db_url = 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
- Float :fl
21
- BigDecimal :bd
22
- end
23
- DB.create_table(:album_infos) do
24
- primary_key :id
25
- foreign_key :album_id, :albums
26
- String :info
27
- end
28
- DB.create_table(:tracks) do
29
- primary_key :id
30
- foreign_key :album_id, :albums
31
- String :name
32
- end
33
- DB.create_table(:tags) do
34
- primary_key :id
35
- String :name
36
- end
37
- DB.create_table(:albums_tags) do
38
- foreign_key :album_id, :albums
39
- foreign_key :tag_id, :tags
40
- end
41
-
42
- a = DB[:artists].insert(:name=>'a')
43
- d = DB[:artists].insert(:name=>'d')
44
- 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)
45
- DB[:tracks].insert(:name=>'m', :album_id=>b)
46
- DB[:tracks].insert(:name=>'n', :album_id=>b)
47
- c = DB[:albums].insert(:name=>'c', :artist_id=>d, :gold=>true, :platinum=>true)
48
- DB[:tracks].insert(:name=>'o', :album_id=>c)
49
- s = DB[:tags].insert(:name=>'s')
50
- t = DB[:tags].insert(:name=>'t')
51
- DB[:tags].insert(:name=>'u')
52
- [[b, s], [b, t], [c, t]].each{|k, v| DB[:albums_tags].insert(k, v)}
53
-
54
- # Allow loading of pg_array extension even when not on PostgreSQL
55
- def DB.add_conversion_proc(*)
56
- super if defined?(super)
57
- end
58
- def DB.conversion_procs_updated(*)
59
- super if defined?(super)
60
- end
61
- def DB.conversion_procs
62
- return super if defined?(super)
63
- {}
64
- end
65
-
66
- Sequel::Model.plugin :forme
67
- class Album < Sequel::Model
68
- plugin :association_pks
69
- plugin :forme_set
70
-
71
- many_to_one :artist, :order=>:name
72
- one_to_one :album_info
73
- one_to_many :tracks
74
- many_to_many :tags, :delay_pks=>:always
75
-
76
- plugin :pg_array_associations
77
- pg_array_to_many :atags, :class=>:Tag
78
-
79
- def atag_ids
80
- @atag_ids ||= [1,2]
81
- end
82
-
83
- def artist_name
84
- artist.name if artist
85
- end
86
-
87
- alias foo= name=
88
-
89
- if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
90
- # Add workaround for no boolean handling in jdbc-sqlite3
91
- plugin :typecast_on_load, :gold, :platinum, :release_date, :created_at
92
- end
93
- end
94
- class Artist < Sequel::Model
95
- one_to_many :albums
96
- def idname() "#{id}#{name}" end
97
- def name2() "#{name}2" end
98
- def name3() "#{name}3" end
99
- end
100
- class Track < Sequel::Model; end
101
- class Tag < Sequel::Model; end
102
- class AlbumInfo < Sequel::Model; end
103
-
@@ -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 }