forme 2.1.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 }