reform 2.3.2 → 2.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +17 -0
  3. data/.gitignore +1 -1
  4. data/CHANGES.md +23 -0
  5. data/Gemfile +1 -1
  6. data/LICENSE.txt +1 -1
  7. data/README.md +5 -5
  8. data/Rakefile +1 -12
  9. data/lib/reform/contract/validate.rb +1 -1
  10. data/lib/reform/form/dry.rb +47 -9
  11. data/lib/reform/form/populator.rb +13 -3
  12. data/lib/reform/form/prepopulate.rb +1 -1
  13. data/lib/reform/form/validate.rb +3 -3
  14. data/lib/reform/validation/groups.rb +0 -1
  15. data/lib/reform/version.rb +1 -1
  16. data/reform.gemspec +2 -2
  17. data/test/call_test.rb +23 -0
  18. data/test/changed_test.rb +6 -6
  19. data/test/coercion_test.rb +17 -17
  20. data/test/{composition_new_api.rb → composition_test.rb} +27 -28
  21. data/test/{contract_new_api.rb → contract_test.rb} +8 -8
  22. data/test/default_test.rb +2 -2
  23. data/test/deserialize_test.rb +8 -8
  24. data/test/docs/validation_test.rb +134 -0
  25. data/test/{errors_new_api.rb → errors_test.rb} +41 -41
  26. data/test/feature_test.rb +2 -2
  27. data/test/fixtures/dry_error_messages.yml +64 -54
  28. data/test/{form_option_new_api.rb → form_option_test.rb} +1 -1
  29. data/test/{form_new_api.rb → form_test.rb} +3 -3
  30. data/test/from_test.rb +10 -10
  31. data/test/{inherit_new_api.rb → inherit_test.rb} +17 -17
  32. data/test/{module_new_api.rb → module_test.rb} +10 -10
  33. data/test/parse_option_test.rb +7 -7
  34. data/test/parse_pipeline_test.rb +1 -1
  35. data/test/{populate_new_api.rb → populate_test.rb} +136 -53
  36. data/test/populator_skip_test.rb +2 -2
  37. data/test/prepopulator_test.rb +16 -16
  38. data/test/read_only_test.rb +2 -2
  39. data/test/readable_test.rb +3 -3
  40. data/test/{reform_new_api.rb → reform_test.rb} +19 -19
  41. data/test/{save_new_api.rb → save_test.rb} +4 -4
  42. data/test/setup_test.rb +9 -9
  43. data/test/{skip_if_new_api.rb → skip_if_test.rb} +12 -12
  44. data/test/skip_setter_and_getter_test.rb +6 -6
  45. data/test/test_helper.rb +5 -6
  46. data/test/{validate_new_api.rb → validate_test.rb} +65 -78
  47. data/test/validation/{dry_validation_new_api.rb → dry_validation_test.rb} +128 -128
  48. data/test/validation/result_test.rb +14 -14
  49. data/test/virtual_test.rb +7 -7
  50. data/test/writeable_test.rb +8 -8
  51. metadata +42 -75
  52. data/.travis.yml +0 -16
  53. data/Appraisals +0 -8
  54. data/gemfiles/0.13.0.gemfile +0 -8
  55. data/gemfiles/1.5.0.gemfile +0 -9
  56. data/lib/reform/form/dry/new_api.rb +0 -47
  57. data/lib/reform/form/dry/old_api.rb +0 -61
  58. data/test/call_new_api.rb +0 -23
  59. data/test/call_old_api.rb +0 -23
  60. data/test/composition_old_api.rb +0 -184
  61. data/test/contract_old_api.rb +0 -77
  62. data/test/errors_old_api.rb +0 -230
  63. data/test/fixtures/dry_new_api_error_messages.yml +0 -104
  64. data/test/form_old_api.rb +0 -57
  65. data/test/form_option_old_api.rb +0 -24
  66. data/test/inherit_old_api.rb +0 -105
  67. data/test/module_old_api.rb +0 -146
  68. data/test/populate_old_api.rb +0 -304
  69. data/test/reform_old_api.rb +0 -202
  70. data/test/save_old_api.rb +0 -101
  71. data/test/skip_if_old_api.rb +0 -92
  72. data/test/validate_old_api.rb +0 -410
  73. data/test/validation/dry_validation_old_api.rb +0 -772
data/test/save_old_api.rb DELETED
@@ -1,101 +0,0 @@
1
- require "test_helper"
2
-
3
- class SaveTest < BaseTest
4
- Song = Struct.new(:title, :album, :composer)
5
- Album = Struct.new(:name, :songs, :artist)
6
- Artist = Struct.new(:name)
7
-
8
- class AlbumForm < TestForm
9
- property :name
10
- validation do
11
- required(:name).filled
12
- end
13
-
14
- collection :songs do
15
- property :title
16
- validation do
17
- required(:title).filled
18
- end
19
-
20
- property :composer do
21
- property :name
22
- validation do
23
- required(:name).filled
24
- end
25
- end
26
- end
27
-
28
- property :artist, save: false do
29
- property :name
30
- end
31
- end
32
-
33
- module Saveable
34
- def save
35
- @saved = true
36
- end
37
-
38
- def saved?
39
- defined?(@saved) && @saved
40
- end
41
- end
42
-
43
- let(:song) { Song.new("Broken").extend(Saveable) }
44
- # let(:song_with_composer) { Song.new("Resist Stance", nil, composer).extend(Saveable) }
45
- let(:composer) { Artist.new("Greg Graffin").extend(Saveable) }
46
- let(:artist) { Artist.new("Bad Religion").extend(Saveable).extend(Saveable) }
47
- let(:album) { Album.new("The Dissent Of Man", [song], artist).extend(Saveable) }
48
-
49
- let(:form) { AlbumForm.new(album) }
50
-
51
- it do
52
- form.validate("songs" => [{"title" => "Fixed"}])
53
-
54
- form.save
55
-
56
- album.saved?.must_equal true
57
- album.songs[0].title.must_equal "Fixed"
58
- album.songs[0].saved?.must_equal true
59
- assert_nil album.artist.saved?
60
- end
61
-
62
- describe "#sync with block" do
63
- it do
64
- form = AlbumForm.new(Album.new("Greatest Hits"))
65
-
66
- form.validate(name: nil) # nil-out the title.
67
-
68
- nested_hash = nil
69
- form.sync do |hash|
70
- nested_hash = hash
71
- end
72
-
73
- nested_hash.must_equal({"name" => nil, "artist" => nil})
74
- end
75
- end
76
- end
77
-
78
- # class SaveWithDynamicOptionsTest < MiniTest::Spec
79
- # Song = Struct.new(:id, :title, :length) do
80
- # include Saveable
81
- # end
82
-
83
- # class SongForm < TestForm
84
- # property :title#, save: false
85
- # property :length, virtual: true
86
- # end
87
-
88
- # let(:song) { Song.new }
89
- # let(:form) { SongForm.new(song) }
90
-
91
- # # we have access to original input value and outside parameters.
92
- # it "xxx" do
93
- # form.validate("title" => "A Poor Man's Memory", "length" => 10)
94
- # length_seconds = 120
95
- # form.save(length: lambda { |value, options| form.model.id = "#{value}: #{length_seconds}" })
96
-
97
- # song.title.must_equal "A Poor Man's Memory"
98
- # assert_nil song.length
99
- # song.id.must_equal "10: 120"
100
- # end
101
- # end
@@ -1,92 +0,0 @@
1
- require "test_helper"
2
-
3
- class SkipIfTest < BaseTest
4
- let(:hit) { Song.new }
5
- let(:album) { Album.new(nil, hit, [], nil) }
6
-
7
- class AlbumForm < TestForm
8
- property :title
9
-
10
- property :hit, skip_if: ->(options) { options[:fragment]["title"] == "" } do
11
- property :title
12
- validation do
13
- required(:title).filled
14
- end
15
- end
16
-
17
- collection :songs, skip_if: :skip_song?, populate_if_empty: BaseTest::Song do
18
- property :title
19
- end
20
-
21
- def skip_song?(options)
22
- options[:fragment]["title"].nil?
23
- end
24
- end
25
-
26
- # deserializes when present.
27
- it do
28
- form = AlbumForm.new(album)
29
- form.validate("hit" => {"title" => "Altar Of Sacrifice"}).must_equal true
30
- form.hit.title.must_equal "Altar Of Sacrifice"
31
- end
32
-
33
- # skips deserialization when not present.
34
- it do
35
- form = AlbumForm.new(Album.new)
36
- form.validate("hit" => {"title" => ""}).must_equal true
37
- assert_nil form.hit # hit hasn't been deserialised.
38
- end
39
-
40
- # skips deserialization when not present.
41
- it do
42
- form = AlbumForm.new(Album.new(nil, nil, []))
43
- form.validate("songs" => [{"title" => "Waste Of Breath"}, {"title" => nil}]).must_equal true
44
- form.songs.size.must_equal 1
45
- form.songs[0].title.must_equal "Waste Of Breath"
46
- end
47
- end
48
-
49
- class SkipIfAllBlankTest < BaseTest
50
- # skip_if: :all_blank"
51
- class AlbumForm < TestForm
52
- collection :songs, skip_if: :all_blank, populate_if_empty: BaseTest::Song do
53
- property :title
54
- property :length
55
- end
56
- end
57
-
58
- # create only one object.
59
- it do
60
- form = AlbumForm.new(OpenStruct.new(songs: []))
61
- form.validate("songs" => [{"title" => "Apathy"}, {"title" => "", "length" => ""}]).must_equal true
62
- form.songs.size.must_equal 1
63
- form.songs[0].title.must_equal "Apathy"
64
- end
65
-
66
- it do
67
- form = AlbumForm.new(OpenStruct.new(songs: []))
68
- form.validate("songs" => [{"title" => "", "length" => ""}, {"title" => "Apathy"}]).must_equal true
69
- form.songs.size.must_equal 1
70
- form.songs[0].title.must_equal "Apathy"
71
- end
72
-
73
- it do
74
- form = AlbumForm.new(OpenStruct.new(songs: []))
75
- form.validate(:songs => [{:title=>"", :length => ""}, {:title=>"Apathy"}]).must_equal true
76
- form.songs.size.must_equal 1
77
- form.songs[0].title.must_equal "Apathy"
78
- end
79
- end
80
-
81
- class InvalidOptionsCombinationTest < BaseTest
82
- it do
83
- assert_raises(Reform::Form::InvalidOptionsCombinationError) do
84
- class AlbumForm < TestForm
85
- collection :songs, skip_if: :all_blank, populator: -> {} do
86
- property :title
87
- property :length
88
- end
89
- end
90
- end
91
- end
92
- end
@@ -1,410 +0,0 @@
1
- require "test_helper"
2
-
3
- class ContractValidateTest < MiniTest::Spec
4
- Song = Struct.new(:title, :album, :composer)
5
- Album = Struct.new(:name, :songs, :artist)
6
- Artist = Struct.new(:name)
7
-
8
- class AlbumForm < TestContract
9
- property :name
10
- validation do
11
- required(:name).filled
12
- end
13
-
14
- collection :songs do
15
- property :title
16
- validation do
17
- required(:title).filled
18
- end
19
-
20
- property :composer do
21
- validation do
22
- required(:name).filled
23
- end
24
- property :name
25
- end
26
- end
27
-
28
- property :artist do
29
- property :name
30
- end
31
- end
32
-
33
- let(:song) { Song.new("Broken") }
34
- let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
35
- let(:composer) { Artist.new("Greg Graffin") }
36
- let(:artist) { Artist.new("Bad Religion") }
37
- let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
38
-
39
- let(:form) { AlbumForm.new(album) }
40
-
41
- # valid
42
- it do
43
- form.validate.must_equal true
44
- form.errors.messages.inspect.must_equal "{}"
45
- end
46
-
47
- # invalid
48
- it do
49
- album.songs[1].composer.name = nil
50
- album.name = nil
51
-
52
- form.validate.must_equal false
53
- form.errors.messages.inspect.must_equal "{:name=>[\"must be filled\"], :\"songs.composer.name\"=>[\"must be filled\"]}"
54
- end
55
- end
56
-
57
- # no configuration results in "sync" (formerly known as parse_strategy: :sync).
58
- class ValidateWithoutConfigurationTest < MiniTest::Spec
59
- Song = Struct.new(:title, :album, :composer)
60
- Album = Struct.new(:name, :songs, :artist)
61
- Artist = Struct.new(:name)
62
-
63
- class AlbumForm < TestForm
64
- property :name
65
- validation do
66
- required(:name).filled
67
- end
68
-
69
- collection :songs do
70
- property :title
71
- validation do
72
- required(:title).filled
73
- end
74
-
75
- property :composer do
76
- property :name
77
- validation do
78
- required(:name).filled
79
- end
80
- end
81
- end
82
-
83
- property :artist do
84
- property :name
85
- end
86
- end
87
-
88
- let(:song) { Song.new("Broken") }
89
- let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
90
- let(:composer) { Artist.new("Greg Graffin") }
91
- let(:artist) { Artist.new("Bad Religion") }
92
- let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
93
-
94
- let(:form) { AlbumForm.new(album) }
95
-
96
- # valid.
97
- it do
98
- object_ids = {
99
- song: form.songs[0].object_id, song_with_composer: form.songs[1].object_id,
100
- artist: form.artist.object_id, composer: form.songs[1].composer.object_id
101
- }
102
-
103
- form.validate(
104
- "name" => "Best Of",
105
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne", "composer" => {"name" => "Sting"}}],
106
- "artist" => {"name" => "The Police"}
107
- ).must_equal true
108
-
109
- form.errors.messages.inspect.must_equal "{}"
110
-
111
- # form has updated.
112
- form.name.must_equal "Best Of"
113
- form.songs[0].title.must_equal "Fallout"
114
- form.songs[1].title.must_equal "Roxanne"
115
- form.songs[1].composer.name.must_equal "Sting"
116
- form.artist.name.must_equal "The Police"
117
-
118
- # objects are still the same.
119
- form.songs[0].object_id.must_equal object_ids[:song]
120
- form.songs[1].object_id.must_equal object_ids[:song_with_composer]
121
- form.songs[1].composer.object_id.must_equal object_ids[:composer]
122
- form.artist.object_id.must_equal object_ids[:artist]
123
-
124
- # model has not changed, yet.
125
- album.name.must_equal "The Dissent Of Man"
126
- album.songs[0].title.must_equal "Broken"
127
- album.songs[1].title.must_equal "Resist Stance"
128
- album.songs[1].composer.name.must_equal "Greg Graffin"
129
- album.artist.name.must_equal "Bad Religion"
130
- end
131
-
132
- # with symbols.
133
- it do
134
- form.validate(
135
- name: "Best Of",
136
- songs: [{title: "The X-Creep"}, {title: "Trudging", composer: {name: "SNFU"}}],
137
- artist: {name: "The Police"}
138
- ).must_equal true
139
-
140
- form.name.must_equal "Best Of"
141
- form.songs[0].title.must_equal "The X-Creep"
142
- form.songs[1].title.must_equal "Trudging"
143
- form.songs[1].composer.name.must_equal "SNFU"
144
- form.artist.name.must_equal "The Police"
145
- end
146
-
147
- # throws exception when no populators.
148
- it do
149
- album = Album.new("The Dissent Of Man", [])
150
-
151
- assert_raises RuntimeError do
152
- AlbumForm.new(album).validate(songs: {title: "Resist-Stance"})
153
- end
154
- end
155
- end
156
-
157
- class ValidateWithInternalPopulatorOptionTest < MiniTest::Spec
158
- Song = Struct.new(:title, :album, :composer)
159
- Album = Struct.new(:name, :songs, :artist)
160
- Artist = Struct.new(:name)
161
-
162
- class AlbumForm < TestForm
163
- property :name
164
- validation do
165
- required(:name).filled
166
- end
167
-
168
- collection :songs,
169
- internal_populator: ->(input, options) {
170
- collection = options[:represented].songs
171
- (item = collection[options[:index]]) ? item : collection.insert(options[:index], Song.new)
172
- } do
173
- property :title
174
- validation do
175
- required(:title).filled
176
- end
177
-
178
- property :composer, internal_populator: ->(input, options) { (item = options[:represented].composer) ? item : Artist.new } do
179
- property :name
180
- validation do
181
- required(:name).filled
182
- end
183
- end
184
- end
185
-
186
- property :artist, internal_populator: ->(input, options) { (item = options[:represented].artist) ? item : Artist.new } do
187
- property :name
188
- validation do
189
- required(:name).filled
190
- end
191
- end
192
- end
193
-
194
- let(:song) { Song.new("Broken") }
195
- let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
196
- let(:composer) { Artist.new("Greg Graffin") }
197
- let(:artist) { Artist.new("Bad Religion") }
198
- let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
199
-
200
- let(:form) { AlbumForm.new(album) }
201
-
202
- # valid.
203
- it("xxx") do
204
- form.validate(
205
- "name" => "Best Of",
206
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne", "composer" => {"name" => "Sting"}}],
207
- "artist" => {"name" => "The Police"},
208
- ).must_equal true
209
- form.valid?.must_equal true
210
-
211
- form.errors.messages.inspect.must_equal "{}"
212
-
213
- # form has updated.
214
- form.name.must_equal "Best Of"
215
- form.songs[0].title.must_equal "Fallout"
216
- form.songs[1].title.must_equal "Roxanne"
217
- form.songs[1].composer.name.must_equal "Sting"
218
- form.artist.name.must_equal "The Police"
219
-
220
- # model has not changed, yet.
221
- album.name.must_equal "The Dissent Of Man"
222
- album.songs[0].title.must_equal "Broken"
223
- album.songs[1].title.must_equal "Resist Stance"
224
- album.songs[1].composer.name.must_equal "Greg Graffin"
225
- album.artist.name.must_equal "Bad Religion"
226
- end
227
-
228
- # invalid.
229
- it do
230
- form.validate(
231
- "name" => "",
232
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne", "composer" => {"name" => ""}}],
233
- "artist" => {"name" => ""},
234
- ).must_equal false
235
- form.valid?.must_equal false
236
-
237
- form.errors.messages.inspect.must_equal "{:name=>[\"must be filled\"], :\"songs.composer.name\"=>[\"must be filled\"], :\"artist.name\"=>[\"must be filled\"]}"
238
- end
239
-
240
- # adding to collection via :instance.
241
- # valid.
242
- it do
243
- form.validate(
244
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}, {"title" => "Rime Of The Ancient Mariner"}],
245
- ).must_equal true
246
-
247
- form.errors.messages.inspect.must_equal "{}"
248
-
249
- # form has updated.
250
- form.name.must_equal "The Dissent Of Man"
251
- form.songs[0].title.must_equal "Fallout"
252
- form.songs[1].title.must_equal "Roxanne"
253
- form.songs[1].composer.name.must_equal "Greg Graffin"
254
- form.songs[1].title.must_equal "Roxanne"
255
- form.songs[2].title.must_equal "Rime Of The Ancient Mariner" # new song added.
256
- form.songs.size.must_equal 3
257
- form.artist.name.must_equal "Bad Religion"
258
-
259
- # model has not changed, yet.
260
- album.name.must_equal "The Dissent Of Man"
261
- album.songs[0].title.must_equal "Broken"
262
- album.songs[1].title.must_equal "Resist Stance"
263
- album.songs[1].composer.name.must_equal "Greg Graffin"
264
- album.songs.size.must_equal 2
265
- album.artist.name.must_equal "Bad Religion"
266
- end
267
-
268
- # allow writeable: false even in the deserializer.
269
- class SongForm < TestForm
270
- property :title, deserializer: {writeable: false}
271
- end
272
-
273
- it do
274
- form = SongForm.new(song = Song.new)
275
- form.validate("title" => "Ignore me!")
276
- assert_nil form.title
277
- form.title = "Unopened"
278
- form.sync # only the deserializer is marked as not-writeable.
279
- song.title.must_equal "Unopened"
280
- end
281
- end
282
-
283
- # # not sure if we should catch that in Reform or rather do that in disposable. this is https://github.com/trailblazer/reform/pull/104
284
- # # describe ":populator with :empty" do
285
- # # let(:form) {
286
- # # Class.new(Reform::Form) do
287
- # # collection :songs, :empty => true, :populator => lambda { |fragment, index, args|
288
- # # songs[index] = args.binding[:form].new(Song.new)
289
- # # } do
290
- # # property :title
291
- # # end
292
- # # end
293
- # # }
294
-
295
- # # let(:params) {
296
- # # {
297
- # # "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}]
298
- # # }
299
- # # }
300
-
301
- # # subject { form.new(Album.new("Hits", [], [])) }
302
-
303
- # # before { subject.validate(params) }
304
-
305
- # # it { subject.songs[0].title.must_equal "Fallout" }
306
- # # it { subject.songs[1].title.must_equal "Roxanne" }
307
- # # end
308
-
309
- # # test cardinalities.
310
- # describe "with empty collection and cardinality" do
311
- # let(:album) { Album.new }
312
-
313
- # subject { Class.new(Reform::Form) do
314
- # include Reform::Form::ActiveModel
315
- # model :album
316
-
317
- # collection :songs do
318
- # property :title
319
- # end
320
-
321
- # property :hit do
322
- # property :title
323
- # end
324
-
325
- # validates :songs, :length => {:minimum => 1}
326
- # validates :hit, :presence => true
327
- # end.new(album) }
328
-
329
- # describe "invalid" do
330
- # before { subject.validate({}).must_equal false }
331
-
332
- # it do
333
- # # ensure that only hit and songs keys are present
334
- # subject.errors.messages.keys.sort.must_equal([:hit, :songs])
335
- # # validate content of hit and songs keys
336
- # subject.errors.messages[:hit].must_equal(["must be filled"])
337
- # subject.errors.messages[:songs].first.must_match(/\Ais too short \(minimum is 1 characters?\)\z/)
338
- # end
339
- # end
340
-
341
- # describe "valid" do
342
- # let(:album) { Album.new(nil, Song.new, [Song.new("Urban Myth")]) }
343
-
344
- # before {
345
- # subject.validate({"songs" => [{"title"=>"Daddy, Brother, Lover, Little Boy"}], "hit" => {"title"=>"The Horse"}}).
346
- # must_equal true
347
- # }
348
-
349
- # it { subject.errors.messages.must_equal({}) }
350
- # end
351
- # end
352
-
353
- # # providing manual validator method allows accessing form's API.
354
- # describe "with ::validate" do
355
- # let(:form) {
356
- # Class.new(Reform::Form) do
357
- # property :title
358
-
359
- # validate :title?
360
-
361
- # def title?
362
- # errors.add :title, "not lowercase" if title == "Fallout"
363
- # end
364
- # end
365
- # }
366
-
367
- # let(:params) { {"title" => "Fallout"} }
368
- # let(:song) { Song.new("Englishman") }
369
-
370
- # subject { form.new(song) }
371
-
372
- # before { @res = subject.validate(params) }
373
-
374
- # it { @res.must_equal false }
375
- # it { subject.errors.messages.must_equal({:title=>["not lowercase"]}) }
376
- # end
377
-
378
- # # overriding the reader for a nested form should only be considered when rendering.
379
- # describe "with overridden reader for nested form" do
380
- # let(:form) {
381
- # Class.new(Reform::Form) do
382
- # property :band, :populate_if_empty => lambda { |*| Band.new } do
383
- # property :label
384
- # end
385
-
386
- # collection :songs, :populate_if_empty => lambda { |*| Song.new } do
387
- # property :title
388
- # end
389
-
390
- # def band
391
- # raise "only call me when rendering the form!"
392
- # end
393
-
394
- # def songs
395
- # raise "only call me when rendering the form!"
396
- # end
397
- # end.new(album)
398
- # }
399
-
400
- # let(:album) { Album.new }
401
-
402
- # # don't use #artist when validating!
403
- # it do
404
- # form.validate("band" => {"label" => "Hellcat"}, "songs" => [{"title" => "Stand Your Ground"}, {"title" => "Otherside"}])
405
- # form.sync
406
- # album.band.label.must_equal "Hellcat"
407
- # album.songs.first.title.must_equal "Stand Your Ground"
408
- # end
409
- # end
410
- # end