sbf-dm-types 1.3.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +45 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +468 -0
  5. data/.travis.yml +52 -0
  6. data/Gemfile +67 -0
  7. data/LICENSE +20 -0
  8. data/README.rdoc +3 -0
  9. data/Rakefile +4 -0
  10. data/dm-types.gemspec +26 -0
  11. data/lib/dm-types/api_key.rb +30 -0
  12. data/lib/dm-types/bcrypt_hash.rb +33 -0
  13. data/lib/dm-types/comma_separated_list.rb +28 -0
  14. data/lib/dm-types/csv.rb +34 -0
  15. data/lib/dm-types/enum.rb +55 -0
  16. data/lib/dm-types/epoch_time.rb +35 -0
  17. data/lib/dm-types/file_path.rb +24 -0
  18. data/lib/dm-types/flag.rb +64 -0
  19. data/lib/dm-types/ip_address.rb +34 -0
  20. data/lib/dm-types/json.rb +48 -0
  21. data/lib/dm-types/paranoid/base.rb +56 -0
  22. data/lib/dm-types/paranoid_boolean.rb +23 -0
  23. data/lib/dm-types/paranoid_datetime.rb +22 -0
  24. data/lib/dm-types/regexp.rb +21 -0
  25. data/lib/dm-types/slug.rb +28 -0
  26. data/lib/dm-types/support/dirty_minder.rb +168 -0
  27. data/lib/dm-types/support/flags.rb +41 -0
  28. data/lib/dm-types/uri.rb +27 -0
  29. data/lib/dm-types/uuid.rb +64 -0
  30. data/lib/dm-types/version.rb +5 -0
  31. data/lib/dm-types/yaml.rb +39 -0
  32. data/lib/dm-types.rb +23 -0
  33. data/spec/fixtures/api_user.rb +14 -0
  34. data/spec/fixtures/article.rb +35 -0
  35. data/spec/fixtures/bookmark.rb +23 -0
  36. data/spec/fixtures/invention.rb +7 -0
  37. data/spec/fixtures/network_node.rb +36 -0
  38. data/spec/fixtures/person.rb +25 -0
  39. data/spec/fixtures/software_package.rb +33 -0
  40. data/spec/fixtures/ticket.rb +21 -0
  41. data/spec/fixtures/tshirt.rb +24 -0
  42. data/spec/integration/api_key_spec.rb +27 -0
  43. data/spec/integration/bcrypt_hash_spec.rb +47 -0
  44. data/spec/integration/comma_separated_list_spec.rb +87 -0
  45. data/spec/integration/dirty_minder_spec.rb +197 -0
  46. data/spec/integration/enum_spec.rb +78 -0
  47. data/spec/integration/epoch_time_spec.rb +61 -0
  48. data/spec/integration/file_path_spec.rb +160 -0
  49. data/spec/integration/flag_spec.rb +72 -0
  50. data/spec/integration/ip_address_spec.rb +153 -0
  51. data/spec/integration/json_spec.rb +72 -0
  52. data/spec/integration/slug_spec.rb +67 -0
  53. data/spec/integration/uri_spec.rb +117 -0
  54. data/spec/integration/uuid_spec.rb +102 -0
  55. data/spec/integration/yaml_spec.rb +87 -0
  56. data/spec/shared/flags_shared_spec.rb +37 -0
  57. data/spec/shared/identity_function_group.rb +5 -0
  58. data/spec/spec_helper.rb +30 -0
  59. data/spec/unit/bcrypt_hash_spec.rb +155 -0
  60. data/spec/unit/csv_spec.rb +142 -0
  61. data/spec/unit/dirty_minder_spec.rb +65 -0
  62. data/spec/unit/enum_spec.rb +126 -0
  63. data/spec/unit/epoch_time_spec.rb +74 -0
  64. data/spec/unit/file_path_spec.rb +75 -0
  65. data/spec/unit/flag_spec.rb +114 -0
  66. data/spec/unit/ip_address_spec.rb +109 -0
  67. data/spec/unit/json_spec.rb +126 -0
  68. data/spec/unit/paranoid_boolean_spec.rb +149 -0
  69. data/spec/unit/paranoid_datetime_spec.rb +153 -0
  70. data/spec/unit/regexp_spec.rb +63 -0
  71. data/spec/unit/uri_spec.rb +83 -0
  72. data/spec/unit/yaml_spec.rb +111 -0
  73. data/tasks/spec.rake +21 -0
  74. data/tasks/yard.rake +9 -0
  75. data/tasks/yardstick.rake +19 -0
  76. metadata +229 -0
@@ -0,0 +1,87 @@
1
+ require_relative '../spec_helper'
2
+
3
+ try_spec do
4
+
5
+ require_relative '../fixtures/person'
6
+
7
+ describe DataMapper::TypesFixtures::Person do
8
+ supported_by :all do
9
+ before :all do
10
+ @resource = DataMapper::TypesFixtures::Person.new(:name => '')
11
+ end
12
+
13
+ describe 'with no interests information' do
14
+ before :all do
15
+ @resource.interests = nil
16
+ end
17
+
18
+ describe 'when dumped and loaded again' do
19
+ before :all do
20
+ expect(@resource.save).to be(true)
21
+ @resource.reload
22
+ end
23
+
24
+ it 'has no interests' do
25
+ expect(@resource.interests).to eq nil
26
+ end
27
+ end
28
+ end
29
+
30
+ describe 'with no interests information' do
31
+ before :all do
32
+ @resource.interests = []
33
+ end
34
+
35
+ describe 'when dumped and loaded again' do
36
+ before :all do
37
+ expect(@resource.save).to be(true)
38
+ @resource.reload
39
+ end
40
+
41
+ it 'has empty interests list' do
42
+ expect(@resource.interests).to eq []
43
+ end
44
+ end
45
+ end
46
+
47
+ describe 'with interests information given as a Hash' do
48
+ it 'raises ArgumentError' do
49
+ expect do
50
+ @resource.interests = { :hash => 'value' }
51
+ @resource.save
52
+ end.to raise_error(ArgumentError, /must be a string, an array or nil/)
53
+ end
54
+ end
55
+
56
+ describe 'with a few items on the interests list' do
57
+ before :all do
58
+ @input = 'fire, water, fire, a whole lot of other interesting things, ,,,'
59
+ @resource.interests = @input
60
+ end
61
+
62
+ describe 'when dumped and loaded again' do
63
+ before :all do
64
+ expect(@resource.save).to be(true)
65
+ @resource.reload
66
+ end
67
+
68
+ it 'includes "fire" in interests' do
69
+ expect(@resource.interests).to include('fire')
70
+ end
71
+
72
+ it 'includes "water" in interests' do
73
+ expect(@resource.interests).to include('water')
74
+ end
75
+
76
+ it 'includes "a whole lot of other interesting things" in interests' do
77
+ expect(@resource.interests).to include('a whole lot of other interesting things')
78
+ end
79
+
80
+ it 'has blank entries removed' do
81
+ expect(@resource.interests.any? { |i| DataMapper::Ext.blank?(i) }).to be(false)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,197 @@
1
+ require_relative '../spec_helper'
2
+
3
+ try_spec do
4
+
5
+ # FIXME: DirtyMinder is currently unsupported on RBX, because unlike the other
6
+ # supported Rubies, RBX core class (e.g. Array, Hash) methods use #send(). In
7
+ # other words, the other Rubies don't use #send() (they map directly to their
8
+ # C functions).
9
+ #
10
+ # The current methodology takes advantage of this by using #send() to forward
11
+ # method invocations we've hooked. Supporting RBX will require finding
12
+ # another way, possibly for all Rubies. In the meantime, something is better
13
+ # than nothing.
14
+ next if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'rbx'
15
+
16
+ require_relative '../fixtures/person'
17
+
18
+ describe DataMapper::TypesFixtures::Person do
19
+ supported_by :all do
20
+ before :all do
21
+ @resource = DataMapper::TypesFixtures::Person.new(:name => 'Thomas Edison')
22
+ end
23
+
24
+ describe 'with positions indirectly mutated as a hash' do
25
+ before :all do
26
+ @resource.positions = {
27
+ 'company' => "Soon To Be Dirty, LLC",
28
+ 'title' => "Layperson",
29
+ 'details' => { 'awesome' => true },
30
+ }
31
+ @resource.save
32
+ @resource.reload
33
+ expect(@resource.positions['title']).to eq 'Layperson'
34
+ end
35
+
36
+ describe 'when I change positions' do
37
+ before :all do
38
+ expect(@resource.clean?).to eq true
39
+ @resource.positions['title'] = 'Chief Layer of People'
40
+ @resource.save
41
+ @resource.reload
42
+ end
43
+
44
+ it 'remembers the new position' do
45
+ expect(@resource.positions['title']).to eq 'Chief Layer of People'
46
+ end
47
+ end
48
+
49
+ describe 'when I add a new attribute of the position' do
50
+ before :all do
51
+ expect(@resource.clean?).to eq true
52
+ @resource.positions['pays_buttloads_of_money'] = true
53
+ @resource.save
54
+ @resource.reload
55
+ end
56
+
57
+ it 'remembers the new attribute' do
58
+ expect(@resource.positions['pays_buttloads_of_money']).to be(true)
59
+ end
60
+ end
61
+
62
+ describe 'when I change the details of the position' do
63
+ before :all do
64
+ expect(@resource.clean?).to eq true
65
+ @resource.positions['details'].merge!('awesome' => "VERY TRUE")
66
+ @resource.save
67
+ @resource.reload
68
+ end
69
+
70
+ it 'remembers the changed detail' do
71
+ pending 'not supported (YET)'
72
+
73
+ # TODO: Not supported (yet?) -- this is a much harder problem to
74
+ # solve: using mutating accessors of nested objects. We could
75
+ # detect it from #dirty? (using the #hash method), but #dirty?
76
+ # only returns the status of known-mutated properties (not full,
77
+ # on-demand scan of object dirty-ness).
78
+ expect(@resource.positions['details']['awesome']).to eq 'VERY TRUE'
79
+ end
80
+ end
81
+
82
+ describe 'when I reload the resource while the property is dirty' do
83
+ before :all do
84
+ @resource.positions['title'] = 'Chief Layer of People'
85
+ @resource.reload
86
+ end
87
+
88
+ it 'reflects the previously set/persisted value' do
89
+ expect(@resource.positions).not_to be_nil
90
+ expect(@resource.positions['title']).to eq 'Layperson'
91
+ end
92
+ end
93
+
94
+ end # positions indirectly mutated as a hash
95
+
96
+ describe 'with positions indirectly mutated as an array' do
97
+ before :all do
98
+ @resource.positions = [
99
+ { 'company' => "Soon To Be Dirty, LLC",
100
+ 'title' => "Layperson",
101
+ 'details' => { 'awesome' => true },
102
+ },
103
+ ]
104
+ @resource.save
105
+ @resource.reload
106
+ expect(@resource.positions.first['title']).to eq 'Layperson'
107
+ end
108
+
109
+ describe 'when I remove the position' do
110
+ before :all do
111
+ expect(@resource.clean?).to eq true
112
+ @resource.positions.pop
113
+ @resource.save
114
+ @resource.reload
115
+ end
116
+
117
+ it "knows there aren't any positions" do
118
+ expect(@resource.positions).to eq []
119
+ end
120
+ end
121
+
122
+ describe "when I add a new position" do
123
+ before :all do
124
+ expect(@resource.clean?).to eq true
125
+ @resource.positions << {
126
+ 'company' => "Down and Dirty, LP",
127
+ 'title' => "Porn Star",
128
+ 'details' => { 'awesome' => "also true" },
129
+ }
130
+ @resource.save
131
+ @resource.reload
132
+ end
133
+
134
+ it "knows there's two positions" do
135
+ expect(@resource.positions.length).to eq 2
136
+ end
137
+
138
+ it 'knows which position is which' do
139
+ expect(@resource.positions.first['title']).to eq 'Layperson'
140
+ expect(@resource.positions.last['title']).to eq 'Porn Star'
141
+ end
142
+
143
+ describe 'when I change the details of one of the positions' do
144
+ before :all do
145
+ @resource.positions.last['details'].merge!('high_risk' => true)
146
+ @resource.save
147
+ @resource.reload
148
+ end
149
+
150
+ it 'remembers the changed detail' do
151
+ pending 'not supported (YET)'
152
+
153
+ # TODO: Not supported (yet?) -- this is a much harder problem to
154
+ # solve: using mutating accessors of nested objects. We could
155
+ # detect it from #dirty? (using the #hash method), but #dirty?
156
+ # only returns the status of known-mutated properties (not full,
157
+ # on-demand scan of object dirty-ness).
158
+ expect(@resource.positions.last['details']['high_risk']).to eq true
159
+ end
160
+ end
161
+ end # when I add a new position
162
+
163
+ describe 'when I remove the position with a block-based mutator' do
164
+ before :all do
165
+ expect(@resource.clean?).to eq true
166
+ @resource.positions.reject! { |_| true }
167
+ @resource.save
168
+ @resource.reload
169
+ end
170
+
171
+ it "knows there aren't any positions" do
172
+ expect(@resource.positions).to eq []
173
+ end
174
+ end
175
+
176
+ describe 'when I mutate positions through a reference' do
177
+ before :all do
178
+ expect(@resource.clean?).to eq true
179
+ @positions = @resource.positions
180
+ @positions << {
181
+ 'company' => "Ooga Booga, Inc",
182
+ 'title' => "Rocker",
183
+ }
184
+ end
185
+
186
+ it 'reflects the change in both the property and the reference' do
187
+ expect(@resource.positions.length).to eq 2
188
+ expect(@resource.positions.last['title']).to eq 'Rocker'
189
+ expect(@positions.last['title']).to eq 'Rocker'
190
+ end
191
+ end
192
+
193
+ end # positions indirectly mutated as an array
194
+
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,78 @@
1
+ require_relative '../spec_helper'
2
+
3
+ try_spec do
4
+
5
+ require_relative '../fixtures/ticket'
6
+
7
+ describe DataMapper::TypesFixtures::Ticket do
8
+ supported_by :all do
9
+ describe 'that is dumped and then loaded' do
10
+ before :all do
11
+ @resource = DataMapper::TypesFixtures::Ticket.new(
12
+ :title => "Can't order by aggregated fields",
13
+ :id => 789,
14
+ :body => "I'm trying to use the aggregate method and sort the results by a summed field, but it doesn't work.",
15
+ :status => 'confirmed'
16
+ )
17
+
18
+ expect(@resource.save).to be(true)
19
+ @resource.reload
20
+ end
21
+
22
+ it 'preserves property value' do
23
+ expect(@resource.status).to eq :confirmed
24
+ end
25
+ end
26
+
27
+ describe 'that is supplied a matching enumeration value' do
28
+ before :all do
29
+ @resource = DataMapper::TypesFixtures::Ticket.new(:status => :assigned)
30
+ end
31
+
32
+ it 'typecasts it for outside reader' do
33
+ expect(@resource.status).to eq :assigned
34
+ end
35
+ end
36
+
37
+ describe '#get' do
38
+ before :all do
39
+ @resource = DataMapper::TypesFixtures::Ticket.new(
40
+ :title => '"sudo make install" of drizzle fails because it tries to chown mysql',
41
+ :id => 257497,
42
+ :body => "Note that at the very least, there should be a check to see whether or not the user is created before chown'ing a file to the user.",
43
+ :status => 'confirmed'
44
+ )
45
+ expect(@resource.save).to be(true)
46
+ end
47
+
48
+ it 'supports queries with equality operator on enumeration property' do
49
+ expect(DataMapper::TypesFixtures::Ticket.all(:status => :confirmed)).to include(@resource)
50
+ end
51
+
52
+ it 'supports queries with inequality operator on enumeration property' do
53
+ expect(DataMapper::TypesFixtures::Ticket.all(:status.not => :confirmed)).not_to include(@resource)
54
+ end
55
+ end
56
+
57
+ describe 'with value unknown to enumeration property' do
58
+ before :all do
59
+ @resource = DataMapper::TypesFixtures::Ticket.new(:status => :undecided)
60
+ end
61
+
62
+ # TODO: consider sharing shared spec exampels with dm-validations,
63
+ # which has 'invalid model' shared group
64
+ it 'is invalid (auto validation for :within kicks in)' do
65
+ expect(@resource).not_to be_valid
66
+ end
67
+
68
+ it 'has errors' do
69
+ expect(@resource.errors).not_to be_empty
70
+ end
71
+
72
+ it 'has a meaningful error message on invalid property' do
73
+ expect(@resource.errors.on(:status)).to include('Status must be one of unconfirmed, confirmed, assigned, resolved, not_applicable')
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,61 @@
1
+ require_relative '../spec_helper'
2
+
3
+ try_spec do
4
+
5
+ require_relative '../fixtures/person'
6
+
7
+ describe DataMapper::TypesFixtures::Person do
8
+ supported_by :all do
9
+ before :all do
10
+ @resource = DataMapper::TypesFixtures::Person.new(:name => '')
11
+ end
12
+
13
+ describe 'with a birthday' do
14
+ before :all do
15
+ @resource.birthday = '1983-05-03'
16
+ end
17
+
18
+ describe 'after typecasting string input' do
19
+ it 'has a valid birthday' do
20
+ expect(@resource.birthday).to eq ::Time.parse('1983-05-03')
21
+ end
22
+ end
23
+
24
+ describe 'when dumped and loaded again' do
25
+ before :all do
26
+ expect(@resource.save).to be(true)
27
+ @resource.reload
28
+ end
29
+
30
+ it 'has a valid birthday' do
31
+ expect(@resource.birthday).to eq ::Time.parse('1983-05-03')
32
+ end
33
+ end
34
+ end
35
+
36
+ describe 'without a birthday' do
37
+ before :all do
38
+ @resource.birthday = nil
39
+ end
40
+
41
+ describe 'after typecasting nil' do
42
+ it 'has a nil value for birthday' do
43
+ expect(@resource.birthday).to be_nil
44
+ end
45
+ end
46
+
47
+ describe 'when dumped and loaded again' do
48
+ before :all do
49
+ expect(@resource.save).to be(true)
50
+ @resource.reload
51
+ end
52
+
53
+ it 'has a nil value for birthday' do
54
+ expect(@resource.birthday).to be_nil
55
+ end
56
+ end
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,160 @@
1
+ require_relative '../spec_helper'
2
+
3
+ try_spec do
4
+
5
+ require_relative '../fixtures/software_package'
6
+
7
+ describe DataMapper::TypesFixtures::SoftwarePackage do
8
+ supported_by :all do
9
+ describe 'with source path at /var/cache/apt/archives/linux-libc-dev_2.6.28-11.40_i386.deb' do
10
+ before :all do
11
+ @source_path = '/var/cache/apt/archives/linux-libc-dev_2.6.28-11.40_i386.deb'
12
+ @resource = DataMapper::TypesFixtures::SoftwarePackage.new(:source_path => @source_path)
13
+ end
14
+
15
+ describe 'when is a new record' do
16
+ before :all do
17
+ end
18
+
19
+ it 'points to original path' do
20
+ expect(@resource.source_path.to_s).to eq @source_path
21
+ end
22
+
23
+ it 'responds to :directory?' do
24
+ expect(@resource.source_path).to respond_to(:directory?)
25
+ end
26
+
27
+ it 'responds to :file?' do
28
+ expect(@resource.source_path).to respond_to(:file?)
29
+ end
30
+
31
+ it 'responds to :dirname' do
32
+ expect(@resource.source_path).to respond_to(:dirname)
33
+ end
34
+
35
+ it 'responds to :absolute?' do
36
+ expect(@resource.source_path).to respond_to(:absolute?)
37
+ end
38
+
39
+ it 'responds to :readable?' do
40
+ expect(@resource.source_path).to respond_to(:readable?)
41
+ end
42
+
43
+ it 'responds to :size' do
44
+ expect(@resource.source_path).to respond_to(:size)
45
+ end
46
+ end
47
+ end
48
+
49
+ describe 'with destination path at /usr/local' do
50
+ before :all do
51
+ @destination_path = '/usr/local'
52
+ @resource = DataMapper::TypesFixtures::SoftwarePackage.new(:destination_path => @destination_path)
53
+ end
54
+
55
+ describe 'when saved and reloaded' do
56
+ before :all do
57
+ expect(@resource.save).to be(true)
58
+ @resource.reload
59
+ end
60
+
61
+ it 'points to original path' do
62
+ expect(@resource.destination_path.to_s).to eq @destination_path
63
+ end
64
+
65
+ it 'responds to :directory?' do
66
+ expect(@resource.destination_path).to respond_to(:directory?)
67
+ end
68
+
69
+ it 'responds to :file?' do
70
+ expect(@resource.destination_path).to respond_to(:file?)
71
+ end
72
+
73
+ it 'responds to :dirname' do
74
+ expect(@resource.destination_path).to respond_to(:dirname)
75
+ end
76
+
77
+ it 'responds to :absolute?' do
78
+ expect(@resource.destination_path).to respond_to(:absolute?)
79
+ end
80
+
81
+ it 'responds to :readable?' do
82
+ expect(@resource.destination_path).to respond_to(:readable?)
83
+ end
84
+
85
+ it 'responds to :size' do
86
+ expect(@resource.destination_path).to respond_to(:size)
87
+ end
88
+ end
89
+ end
90
+
91
+ describe 'with no (nil) source path' do
92
+ before :all do
93
+ @source_path = nil
94
+ @resource = DataMapper::TypesFixtures::SoftwarePackage.new(:source_path => @source_path)
95
+ end
96
+
97
+ describe 'when saved and reloaded' do
98
+ before :all do
99
+ expect(@resource.save).to be(true)
100
+ @resource.reload
101
+ end
102
+
103
+ it 'has nil source path' do
104
+ expect(@resource.source_path).to be_nil
105
+ end
106
+ end
107
+ end
108
+
109
+ describe 'with a blank source path' do
110
+ before :all do
111
+ @source_path = ''
112
+ @resource = DataMapper::TypesFixtures::SoftwarePackage.new(:source_path => @source_path)
113
+ end
114
+
115
+ describe 'when saved and reloaded' do
116
+ before :all do
117
+ expect(@resource.save).to be(true)
118
+ @resource.reload
119
+ end
120
+
121
+ it 'has nil source path' do
122
+ expect(@resource.source_path).to be_nil
123
+ end
124
+ end
125
+ end
126
+
127
+ describe 'with a source path assigned to an empty array' do
128
+ before :all do
129
+ @source_path = []
130
+ @resource = DataMapper::TypesFixtures::SoftwarePackage.new(:source_path => @source_path)
131
+ end
132
+
133
+ describe 'when saved and reloaded' do
134
+ before :all do
135
+ expect(@resource.save).to be(true)
136
+ @resource.reload
137
+ end
138
+
139
+ it 'has nil source path' do
140
+ expect(@resource.source_path).to be_nil
141
+ end
142
+ end
143
+ end
144
+
145
+ describe 'with a source path assigned to a Hash' do
146
+ before :all do
147
+ @source_path = { :guitar => 'Joe Satriani' }
148
+ end
149
+
150
+ describe 'when instantiated' do
151
+ it 'raises an exception' do
152
+ expect do
153
+ DataMapper::TypesFixtures::SoftwarePackage.new(:source_path => @source_path)
154
+ end.to raise_error(TypeError)
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,72 @@
1
+ require_relative '../spec_helper'
2
+
3
+ try_spec do
4
+
5
+ require_relative '../fixtures/tshirt'
6
+
7
+ describe DataMapper::TypesFixtures::TShirt do
8
+ supported_by :all do
9
+ before do
10
+ @resource = DataMapper::TypesFixtures::TShirt.new(
11
+ :writing => 'Fork you',
12
+ :has_picture => true,
13
+ :picture => :octocat,
14
+ :color => :white
15
+ )
16
+ end
17
+
18
+ describe 'with the default value' do
19
+ it 'returns it as an array' do
20
+ expect(@resource.size).to eql(DataMapper::TypesFixtures::TShirt.properties[:size].default)
21
+ end
22
+ end
23
+
24
+ describe 'with multiple sizes' do
25
+ describe 'dumped and loaded' do
26
+ before do
27
+ @resource.size = [ :xs, :medium ]
28
+ expect(@resource.save).to be(true)
29
+ @resource.reload
30
+ end
31
+
32
+ it 'returns size as array' do
33
+ expect(@resource.size).to eq [ :xs, :medium ]
34
+ end
35
+ end
36
+ end
37
+
38
+ describe 'with a single size' do
39
+ before do
40
+ @resource.size = :large
41
+ end
42
+
43
+ describe 'dumped and loaded' do
44
+ before do
45
+ expect(@resource.save).to be(true)
46
+ @resource.reload
47
+ end
48
+
49
+ it 'returns size as array with a single value' do
50
+ expect(@resource.size).to eq [:large]
51
+ end
52
+ end
53
+ end
54
+
55
+ # Flag does not add any auto validations
56
+ describe 'without size' do
57
+ before do
58
+ expect(@resource).to be_valid
59
+ @resource.size = nil
60
+ end
61
+
62
+ it 'is valid' do
63
+ expect(@resource).to be_valid
64
+ end
65
+
66
+ it 'has no errors' do
67
+ expect(@resource.errors).to be_empty
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end