datamapper-dm-core 0.9.11 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +17 -14
- data/.gitignore +3 -1
- data/FAQ +6 -5
- data/History.txt +5 -39
- data/Manifest.txt +67 -76
- data/QUICKLINKS +1 -1
- data/README.txt +21 -15
- data/Rakefile +16 -15
- data/SPECS +2 -29
- data/TODO +1 -1
- data/dm-core.gemspec +11 -15
- data/lib/dm-core/adapters/abstract_adapter.rb +182 -185
- data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
- data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
- data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
- data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
- data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
- data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
- data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
- data/lib/dm-core/adapters.rb +135 -16
- data/lib/dm-core/associations/many_to_many.rb +372 -90
- data/lib/dm-core/associations/many_to_one.rb +220 -73
- data/lib/dm-core/associations/one_to_many.rb +319 -255
- data/lib/dm-core/associations/one_to_one.rb +66 -53
- data/lib/dm-core/associations/relationship.rb +560 -158
- data/lib/dm-core/collection.rb +1104 -381
- data/lib/dm-core/core_ext/kernel.rb +12 -0
- data/lib/dm-core/core_ext/symbol.rb +10 -0
- data/lib/dm-core/identity_map.rb +4 -34
- data/lib/dm-core/migrations.rb +1283 -0
- data/lib/dm-core/model/descendant_set.rb +81 -0
- data/lib/dm-core/model/hook.rb +45 -0
- data/lib/dm-core/model/is.rb +32 -0
- data/lib/dm-core/model/property.rb +248 -0
- data/lib/dm-core/model/relationship.rb +335 -0
- data/lib/dm-core/model/scope.rb +90 -0
- data/lib/dm-core/model.rb +570 -369
- data/lib/dm-core/property.rb +753 -280
- data/lib/dm-core/property_set.rb +141 -98
- data/lib/dm-core/query/conditions/comparison.rb +814 -0
- data/lib/dm-core/query/conditions/operation.rb +247 -0
- data/lib/dm-core/query/direction.rb +43 -0
- data/lib/dm-core/query/operator.rb +42 -0
- data/lib/dm-core/query/path.rb +102 -0
- data/lib/dm-core/query/sort.rb +45 -0
- data/lib/dm-core/query.rb +974 -492
- data/lib/dm-core/repository.rb +147 -107
- data/lib/dm-core/resource.rb +644 -429
- data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
- data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
- data/lib/dm-core/support/chainable.rb +20 -0
- data/lib/dm-core/support/deprecate.rb +12 -0
- data/lib/dm-core/support/equalizer.rb +23 -0
- data/lib/dm-core/support/logger.rb +13 -0
- data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
- data/lib/dm-core/transaction.rb +333 -92
- data/lib/dm-core/type.rb +98 -60
- data/lib/dm-core/types/boolean.rb +1 -1
- data/lib/dm-core/types/discriminator.rb +34 -20
- data/lib/dm-core/types/object.rb +7 -4
- data/lib/dm-core/types/paranoid_boolean.rb +11 -9
- data/lib/dm-core/types/paranoid_datetime.rb +11 -9
- data/lib/dm-core/types/serial.rb +3 -3
- data/lib/dm-core/types/text.rb +3 -4
- data/lib/dm-core/version.rb +1 -1
- data/lib/dm-core.rb +106 -110
- data/script/performance.rb +102 -109
- data/script/profile.rb +169 -38
- data/spec/lib/adapter_helpers.rb +105 -0
- data/spec/lib/collection_helpers.rb +18 -0
- data/spec/lib/counter_adapter.rb +34 -0
- data/spec/lib/pending_helpers.rb +27 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
- data/spec/public/associations/many_to_many_spec.rb +193 -0
- data/spec/public/associations/many_to_one_spec.rb +73 -0
- data/spec/public/associations/one_to_many_spec.rb +77 -0
- data/spec/public/associations/one_to_one_spec.rb +156 -0
- data/spec/public/collection_spec.rb +65 -0
- data/spec/public/model/relationship_spec.rb +924 -0
- data/spec/public/model_spec.rb +159 -0
- data/spec/public/property_spec.rb +829 -0
- data/spec/public/resource_spec.rb +71 -0
- data/spec/public/sel_spec.rb +44 -0
- data/spec/public/setup_spec.rb +145 -0
- data/spec/public/shared/association_collection_shared_spec.rb +317 -0
- data/spec/public/shared/collection_shared_spec.rb +1723 -0
- data/spec/public/shared/finder_shared_spec.rb +1619 -0
- data/spec/public/shared/resource_shared_spec.rb +924 -0
- data/spec/public/shared/sel_shared_spec.rb +112 -0
- data/spec/public/transaction_spec.rb +129 -0
- data/spec/public/types/discriminator_spec.rb +130 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
- data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
- data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
- data/spec/semipublic/associations/relationship_spec.rb +194 -0
- data/spec/semipublic/associations_spec.rb +177 -0
- data/spec/semipublic/collection_spec.rb +142 -0
- data/spec/semipublic/property_spec.rb +61 -0
- data/spec/semipublic/query/conditions_spec.rb +528 -0
- data/spec/semipublic/query/path_spec.rb +443 -0
- data/spec/semipublic/query_spec.rb +2626 -0
- data/spec/semipublic/resource_spec.rb +47 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
- data/spec/spec.opts +3 -1
- data/spec/spec_helper.rb +80 -57
- data/tasks/ci.rb +19 -31
- data/tasks/dm.rb +43 -48
- data/tasks/doc.rb +8 -11
- data/tasks/gemspec.rb +5 -5
- data/tasks/hoe.rb +15 -16
- data/tasks/install.rb +8 -10
- metadata +72 -93
- data/lib/dm-core/associations/relationship_chain.rb +0 -81
- data/lib/dm-core/associations.rb +0 -207
- data/lib/dm-core/auto_migrations.rb +0 -105
- data/lib/dm-core/dependency_queue.rb +0 -32
- data/lib/dm-core/hook.rb +0 -11
- data/lib/dm-core/is.rb +0 -16
- data/lib/dm-core/logger.rb +0 -232
- data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
- data/lib/dm-core/migrator.rb +0 -29
- data/lib/dm-core/scope.rb +0 -58
- data/lib/dm-core/support/array.rb +0 -13
- data/lib/dm-core/support/assertions.rb +0 -8
- data/lib/dm-core/support/errors.rb +0 -23
- data/lib/dm-core/support/kernel.rb +0 -11
- data/lib/dm-core/support/symbol.rb +0 -41
- data/lib/dm-core/support.rb +0 -7
- data/lib/dm-core/type_map.rb +0 -80
- data/lib/dm-core/types.rb +0 -19
- data/script/all +0 -4
- data/spec/integration/association_spec.rb +0 -1382
- data/spec/integration/association_through_spec.rb +0 -203
- data/spec/integration/associations/many_to_many_spec.rb +0 -449
- data/spec/integration/associations/many_to_one_spec.rb +0 -163
- data/spec/integration/associations/one_to_many_spec.rb +0 -188
- data/spec/integration/auto_migrations_spec.rb +0 -413
- data/spec/integration/collection_spec.rb +0 -1073
- data/spec/integration/data_objects_adapter_spec.rb +0 -32
- data/spec/integration/dependency_queue_spec.rb +0 -46
- data/spec/integration/model_spec.rb +0 -197
- data/spec/integration/mysql_adapter_spec.rb +0 -85
- data/spec/integration/postgres_adapter_spec.rb +0 -731
- data/spec/integration/property_spec.rb +0 -253
- data/spec/integration/query_spec.rb +0 -514
- data/spec/integration/repository_spec.rb +0 -61
- data/spec/integration/resource_spec.rb +0 -513
- data/spec/integration/sqlite3_adapter_spec.rb +0 -352
- data/spec/integration/sti_spec.rb +0 -273
- data/spec/integration/strategic_eager_loading_spec.rb +0 -156
- data/spec/integration/transaction_spec.rb +0 -75
- data/spec/integration/type_spec.rb +0 -275
- data/spec/lib/logging_helper.rb +0 -18
- data/spec/lib/mock_adapter.rb +0 -27
- data/spec/lib/model_loader.rb +0 -100
- data/spec/lib/publicize_methods.rb +0 -28
- data/spec/models/content.rb +0 -16
- data/spec/models/vehicles.rb +0 -34
- data/spec/models/zoo.rb +0 -48
- data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
- data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
- data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
- data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
- data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
- data/spec/unit/associations/many_to_many_spec.rb +0 -32
- data/spec/unit/associations/many_to_one_spec.rb +0 -159
- data/spec/unit/associations/one_to_many_spec.rb +0 -393
- data/spec/unit/associations/one_to_one_spec.rb +0 -7
- data/spec/unit/associations/relationship_spec.rb +0 -71
- data/spec/unit/associations_spec.rb +0 -242
- data/spec/unit/auto_migrations_spec.rb +0 -111
- data/spec/unit/collection_spec.rb +0 -182
- data/spec/unit/data_mapper_spec.rb +0 -35
- data/spec/unit/identity_map_spec.rb +0 -126
- data/spec/unit/is_spec.rb +0 -80
- data/spec/unit/migrator_spec.rb +0 -33
- data/spec/unit/model_spec.rb +0 -321
- data/spec/unit/naming_conventions_spec.rb +0 -36
- data/spec/unit/property_set_spec.rb +0 -90
- data/spec/unit/property_spec.rb +0 -753
- data/spec/unit/query_spec.rb +0 -571
- data/spec/unit/repository_spec.rb +0 -93
- data/spec/unit/resource_spec.rb +0 -649
- data/spec/unit/scope_spec.rb +0 -142
- data/spec/unit/transaction_spec.rb +0 -493
- data/spec/unit/type_map_spec.rb +0 -114
- data/spec/unit/type_spec.rb +0 -119
|
@@ -0,0 +1,829 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
|
3
|
+
|
|
4
|
+
describe DataMapper::Property do
|
|
5
|
+
|
|
6
|
+
# define the model prior to supported_by
|
|
7
|
+
before :all do
|
|
8
|
+
class ::Track
|
|
9
|
+
include DataMapper::Resource
|
|
10
|
+
|
|
11
|
+
property :id, Serial
|
|
12
|
+
property :artist, String, :lazy => false, :index => :artist_album
|
|
13
|
+
property :title, String, :field => 'name', :index => true
|
|
14
|
+
property :album, String, :index => :artist_album
|
|
15
|
+
property :musicbrainz_hash, String, :unique => true, :unique_index => true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class ::Image
|
|
19
|
+
include DataMapper::Resource
|
|
20
|
+
|
|
21
|
+
property :md5hash, String, :key => true, :length => 32
|
|
22
|
+
property :title, String, :nullable => false, :unique => true
|
|
23
|
+
property :description, Text, :length => 1..1024, :lazy => [ :detail ]
|
|
24
|
+
|
|
25
|
+
property :format, String, :default => 'jpeg'
|
|
26
|
+
# WxH, stored as a dumped Ruby pair
|
|
27
|
+
property :size, Object
|
|
28
|
+
property :filesize, Float
|
|
29
|
+
property :width, Integer
|
|
30
|
+
property :quality, BigDecimal
|
|
31
|
+
|
|
32
|
+
property :taken_on, Date
|
|
33
|
+
property :taken_at, Time, :default => lambda { |resource, property| Time.now }
|
|
34
|
+
property :retouched_at, DateTime
|
|
35
|
+
property :type, Class
|
|
36
|
+
property :visible, Boolean, :default => true
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
supported_by :all do
|
|
41
|
+
describe '#field' do
|
|
42
|
+
it 'returns @field value if it is present' do
|
|
43
|
+
Track.properties[:title].field.should eql('name')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'returns field for specific repository when it is present'
|
|
47
|
+
|
|
48
|
+
it 'sets field value using field naming convention on first reference'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe '#custom?' do
|
|
52
|
+
it 'is true for custom type fields (not provided by dm-core)'
|
|
53
|
+
|
|
54
|
+
it 'is false for core type fields (provided by dm-core)'
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe '#default_for' do
|
|
58
|
+
it 'returns default value for non-callables' do
|
|
59
|
+
Image.properties[:format].default_for(Image.new).should == 'jpeg'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'returns result of a call for callable values' do
|
|
63
|
+
Image.properties[:taken_at].default_for(Image.new).year.should == Time.now.year
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe '#eql?' do
|
|
68
|
+
it 'is true for properties with the same model and name' do
|
|
69
|
+
Track.properties[:title].should eql(Track.properties[:title])
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
it 'is false for properties of different models' do
|
|
74
|
+
Track.properties[:title].should_not eql(Image.properties[:title])
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'is false for properties with different names' do
|
|
78
|
+
Track.properties[:title].should_not eql(Track.properties[:id])
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe '#get' do
|
|
83
|
+
before :all do
|
|
84
|
+
@image = Image.create(:md5hash => '5268f0f3f452844c79843e820f998869',
|
|
85
|
+
:title => 'Rome at the sunset',
|
|
86
|
+
:description => 'Just wow')
|
|
87
|
+
|
|
88
|
+
@image.should be_saved
|
|
89
|
+
|
|
90
|
+
@image = Image.first(:fields => [ :md5hash, :title ], :md5hash => @image.md5hash)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'triggers loading for lazy loaded properties' do
|
|
94
|
+
Image.properties[:description].get(@image)
|
|
95
|
+
Image.properties[:description].loaded?(@image).should be(true)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'assigns loaded value to @ivar' do
|
|
99
|
+
Image.properties[:description].get(@image)
|
|
100
|
+
@image.instance_variable_get(:@description).should == 'Just wow'
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'sets default value for new records with nil value' do
|
|
104
|
+
Image.properties[:format].get(@image).should == 'jpeg'
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'returns property value' do
|
|
108
|
+
Image.properties[:description].get(@image).should == 'Just wow'
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe '#get!' do
|
|
113
|
+
before :all do
|
|
114
|
+
@image = Image.new
|
|
115
|
+
|
|
116
|
+
# now some dark Ruby magic
|
|
117
|
+
@image.instance_variable_set(:@description, 'Is set by magic')
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'gets instance variable value from the resource directly' do
|
|
121
|
+
# if you know a better way to test direct instance variable access,
|
|
122
|
+
# go ahead and make changes to this example
|
|
123
|
+
Image.properties[:description].get!(@image).should == 'Is set by magic'
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe '#index' do
|
|
128
|
+
it 'returns true when property has an index' do
|
|
129
|
+
Track.properties[:title].index.should be_true
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it 'returns index name when property has a named index' do
|
|
133
|
+
Track.properties[:album].index.should eql(:artist_album)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'returns nil when property has no index' do
|
|
137
|
+
Track.properties[:musicbrainz_hash].index.should be_nil
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe '#initialize' do
|
|
142
|
+
describe 'when tracking strategy is explicitly given' do
|
|
143
|
+
it 'uses tracking strategy from options'
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
describe 'when custom type has tracking stragegy' do
|
|
147
|
+
it 'uses tracking strategy from type'
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
describe '#inspect' do
|
|
152
|
+
before :all do
|
|
153
|
+
@str = Track.properties[:title].inspect
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it 'features model name' do
|
|
157
|
+
@str.should =~ /@model=Track/
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it 'features property name' do
|
|
161
|
+
@str.should =~ /@name=:title/
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
describe '#key?' do
|
|
166
|
+
describe 'returns true when property is a ' do
|
|
167
|
+
it 'serial key' do
|
|
168
|
+
Track.properties[:id].key?.should be_true
|
|
169
|
+
end
|
|
170
|
+
it 'natural key' do
|
|
171
|
+
Image.properties[:md5hash].key?.should be_true
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it 'returns true when property is a part of composite key'
|
|
176
|
+
|
|
177
|
+
it 'returns false when property does not relate to a key' do
|
|
178
|
+
Track.properties[:title].key?.should be_false
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
describe '#lazy?' do
|
|
183
|
+
it 'returns true when property is lazy loaded' do
|
|
184
|
+
Image.properties[:description].lazy?.should be_true
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it 'returns false when property is not lazy loaded' do
|
|
188
|
+
Track.properties[:artist].lazy?.should be_false
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
describe '#length' do
|
|
193
|
+
it 'returns upper bound for Range values' do
|
|
194
|
+
Image.properties[:description].length.should eql(1024)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it 'returns value as is for integer values' do
|
|
198
|
+
Image.properties[:md5hash].length.should eql(32)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
describe '#min' do
|
|
203
|
+
describe 'when :min and :max options not provided to constructor' do
|
|
204
|
+
before do
|
|
205
|
+
@property = Image.property(:integer_with_nil_min, Integer)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
it 'should be nil' do
|
|
209
|
+
@property.min.should be_nil
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
describe 'when :min option not provided to constructor, but :max is provided' do
|
|
214
|
+
before do
|
|
215
|
+
@property = Image.property(:integer_with_default_min, Integer, :max => 1)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
it 'should be the default value' do
|
|
219
|
+
@property.min.should == 0
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
describe 'when :min and :max options provided to constructor' do
|
|
224
|
+
before do
|
|
225
|
+
@min = 1
|
|
226
|
+
@property = Image.property(:integer_with_explicit_min, Integer, :min => @min, :max => 2)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
it 'should be the expected value' do
|
|
230
|
+
@property.min.should == @min
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
describe '#max' do
|
|
236
|
+
describe 'when :min and :max options not provided to constructor' do
|
|
237
|
+
before do
|
|
238
|
+
@property = Image.property(:integer_with_nil_max, Integer)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
it 'should be nil' do
|
|
242
|
+
@property.max.should be_nil
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
describe 'when :max option not provided to constructor, but :min is provided' do
|
|
247
|
+
before do
|
|
248
|
+
@property = Image.property(:integer_with_default_max, Integer, :min => 1)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it 'should be the default value' do
|
|
252
|
+
@property.max.should == 2**31-1
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
describe 'when :min and :max options provided to constructor' do
|
|
257
|
+
before do
|
|
258
|
+
@max = 2
|
|
259
|
+
@property = Image.property(:integer_with_explicit_max, Integer, :min => 1, :max => @max)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it 'should be the expected value' do
|
|
263
|
+
@property.max.should == @max
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
describe '#nullable?' do
|
|
269
|
+
it 'returns true when property can accept nil as its value' do
|
|
270
|
+
Track.properties[:artist].nullable?.should be_true
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
it 'returns false when property nil value is prohibited for this property' do
|
|
274
|
+
Image.properties[:title].nullable?.should be_false
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
describe '#serial?' do
|
|
279
|
+
it 'returns true when property is serial (auto incrementing)' do
|
|
280
|
+
Track.properties[:id].serial?.should be_true
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
it 'returns false when property is NOT serial (auto incrementing)' do
|
|
284
|
+
Image.properties[:md5hash].serial?.should be_false
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# What's going on here:
|
|
289
|
+
#
|
|
290
|
+
# we first set original value and make an assertion on it
|
|
291
|
+
# then we try to set it again, which clears original value
|
|
292
|
+
# (since original value is set, property is no longer dirty)
|
|
293
|
+
describe '#set_original_value' do
|
|
294
|
+
before :all do
|
|
295
|
+
@image = Image.create(:md5hash => '5268f0f3f452844c79843e820f998869',
|
|
296
|
+
:title => 'Rome at the sunset',
|
|
297
|
+
:description => 'Just wow')
|
|
298
|
+
@image.reload
|
|
299
|
+
@property = Image.properties[:title]
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
describe 'when value changes' do
|
|
303
|
+
before :all do
|
|
304
|
+
@property.set_original_value(@image, 'Rome at the sunset')
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
it 'sets original value of the property' do
|
|
308
|
+
@image.original_attributes[@property].should == 'Rome at the sunset'
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
describe 'when value stays the same' do
|
|
313
|
+
before :all do
|
|
314
|
+
@property.set_original_value(@image, 'Rome at the sunset')
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
it 'only sets original value when it has changed' do
|
|
318
|
+
@property.set_original_value(@image, 'Rome at the sunset')
|
|
319
|
+
@image.original_attributes[@property].should be_blank
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
describe '#set' do
|
|
325
|
+
before :all do
|
|
326
|
+
# keep in mind we must run these examples with a
|
|
327
|
+
# saved model instance
|
|
328
|
+
@image = Image.create(:md5hash => '5268f0f3f452844c79843e820f998869',
|
|
329
|
+
:title => 'Rome at the sunset',
|
|
330
|
+
:description => 'Just wow')
|
|
331
|
+
@image.reload
|
|
332
|
+
@property = Image.properties[:title]
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
it 'triggers lazy loading for given resource'
|
|
336
|
+
|
|
337
|
+
it 'type casts given value' do
|
|
338
|
+
# set it to a float
|
|
339
|
+
@property.set(@image, 1.0)
|
|
340
|
+
# get a string that has been typecasted
|
|
341
|
+
@image.title.should == '1.0'
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
it 'stores original value' do
|
|
345
|
+
@property.set(@image, 'Updated value')
|
|
346
|
+
@image.original_attributes[@property].should == 'Rome at the sunset'
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
it 'sets new property value' do
|
|
350
|
+
@property.set(@image, 'Updated value')
|
|
351
|
+
@image.title.should == 'Updated value'
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
describe '#set!' do
|
|
356
|
+
before :all do
|
|
357
|
+
@image = Image.new(:md5hash => '5268f0f3f452844c79843e820f998869',
|
|
358
|
+
:title => 'Rome at the sunset',
|
|
359
|
+
:description => 'Just wow')
|
|
360
|
+
|
|
361
|
+
@property = Image.properties[:title]
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
it 'directly sets instance variable on given resource' do
|
|
365
|
+
@property.set!(@image, 'Set with dark Ruby magic')
|
|
366
|
+
@image.title.should == 'Set with dark Ruby magic'
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
describe '#typecast' do
|
|
371
|
+
describe "when type is able to do typecasting on it's own" do
|
|
372
|
+
it 'delegates all the work to the type'
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
describe 'when value is nil' do
|
|
376
|
+
it 'returns value unchanged' do
|
|
377
|
+
Image.properties[:size].typecast(nil).should be(nil)
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
describe 'when value is a Ruby primitive' do
|
|
382
|
+
it 'returns value unchanged' do
|
|
383
|
+
Image.properties[:size].typecast([3200, 2400]).should == [3200, 2400]
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
describe 'when type primitive is a String' do
|
|
388
|
+
before :all do
|
|
389
|
+
@property = Image.properties[:title]
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
it 'returns same value if a string' do
|
|
393
|
+
@value = '1.0'
|
|
394
|
+
@property.typecast(@value).should equal(@value)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
it 'returns string representation of the new value' do
|
|
398
|
+
@property.typecast(1.0).should eql('1.0')
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
describe 'when type primitive is a Float' do
|
|
403
|
+
before :all do
|
|
404
|
+
@property = Image.properties[:filesize]
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
it 'returns same value if a float' do
|
|
408
|
+
@value = 24.0
|
|
409
|
+
@property.typecast(@value).should equal(@value)
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
it 'returns float representation of a zero string integer' do
|
|
413
|
+
@property.typecast('0').should eql(0.0)
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
it 'returns float representation of a positive string integer' do
|
|
417
|
+
@property.typecast('24').should eql(24.0)
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
it 'returns float representation of a negative string integer' do
|
|
421
|
+
@property.typecast('-24').should eql(-24.0)
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
it 'returns float representation of a zero string float' do
|
|
425
|
+
@property.typecast('0.0').should eql(0.0)
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
it 'returns float representation of a positive string float' do
|
|
429
|
+
@property.typecast('24.35').should eql(24.35)
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
it 'returns float representation of a negative string float' do
|
|
433
|
+
@property.typecast('-24.35').should eql(-24.35)
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
it 'returns float representation of a zero string float, with no leading digits' do
|
|
437
|
+
@property.typecast('.0').should eql(0.0)
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
it 'returns float representation of a positive string float, with no leading digits' do
|
|
441
|
+
@property.typecast('.41').should eql(0.41)
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
it 'returns float representation of a zero integer' do
|
|
445
|
+
@property.typecast(0).should eql(0.0)
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
it 'returns float representation of a positive integer' do
|
|
449
|
+
@property.typecast(24).should eql(24.0)
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
it 'returns float representation of a negative integer' do
|
|
453
|
+
@property.typecast(-24).should eql(-24.0)
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
it 'returns float representation of a zero decimal' do
|
|
457
|
+
@property.typecast(BigDecimal('0.0')).should eql(0.0)
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
it 'returns float representation of a positive decimal' do
|
|
461
|
+
@property.typecast(BigDecimal('24.35')).should eql(24.35)
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
it 'returns float representation of a negative decimal' do
|
|
465
|
+
@property.typecast(BigDecimal('-24.35')).should eql(-24.35)
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
[ Object.new, true, '00.0', '0.', '-.0', 'string' ].each do |value|
|
|
469
|
+
it "does not typecast non-numeric value #{value.inspect}" do
|
|
470
|
+
@property.typecast(value).should equal(value)
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
describe 'when type primitive is a Integer' do
|
|
476
|
+
before :all do
|
|
477
|
+
@property = Image.properties[:width]
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
it 'returns same value if an integer' do
|
|
481
|
+
@value = 24
|
|
482
|
+
@property.typecast(@value).should equal(@value)
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
it 'returns integer representation of a zero string integer' do
|
|
486
|
+
@property.typecast('0').should eql(0)
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
it 'returns integer representation of a positive string integer' do
|
|
490
|
+
@property.typecast('24').should eql(24)
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
it 'returns integer representation of a negative string integer' do
|
|
494
|
+
@property.typecast('-24').should eql(-24)
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
it 'returns integer representation of a zero string float' do
|
|
498
|
+
@property.typecast('0.0').should eql(0)
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
it 'returns integer representation of a positive string float' do
|
|
502
|
+
@property.typecast('24.35').should eql(24)
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
it 'returns integer representation of a negative string float' do
|
|
506
|
+
@property.typecast('-24.35').should eql(-24)
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
it 'returns integer representation of a zero string float, with no leading digits' do
|
|
510
|
+
@property.typecast('.0').should eql(0)
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
it 'returns integer representation of a positive string float, with no leading digits' do
|
|
514
|
+
@property.typecast('.41').should eql(0)
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
it 'returns integer representation of a zero float' do
|
|
518
|
+
@property.typecast(0.0).should eql(0)
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
it 'returns integer representation of a positive float' do
|
|
522
|
+
@property.typecast(24.35).should eql(24)
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
it 'returns integer representation of a negative float' do
|
|
526
|
+
@property.typecast(-24.35).should eql(-24)
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
it 'returns integer representation of a zero decimal' do
|
|
530
|
+
@property.typecast(BigDecimal('0.0')).should eql(0)
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
it 'returns integer representation of a positive decimal' do
|
|
534
|
+
@property.typecast(BigDecimal('24.35')).should eql(24)
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
it 'returns integer representation of a negative decimal' do
|
|
538
|
+
@property.typecast(BigDecimal('-24.35')).should eql(-24)
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
[ Object.new, true, '00.0', '0.', '-.0', 'string' ].each do |value|
|
|
542
|
+
it "does not typecast non-numeric value #{value.inspect}" do
|
|
543
|
+
@property.typecast(value).should equal(value)
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
describe 'when type primitive is a BigDecimal' do
|
|
549
|
+
before :all do
|
|
550
|
+
@property = Image.properties[:quality]
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
it 'returns same value if a decimal' do
|
|
554
|
+
@value = BigDecimal('24.0')
|
|
555
|
+
@property.typecast(@value).should equal(@value)
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
it 'returns decimal representation of a zero string integer' do
|
|
559
|
+
@property.typecast('0').should eql(BigDecimal('0.0'))
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
it 'returns decimal representation of a positive string integer' do
|
|
563
|
+
@property.typecast('24').should eql(BigDecimal('24.0'))
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
it 'returns decimal representation of a negative string integer' do
|
|
567
|
+
@property.typecast('-24').should eql(BigDecimal('-24.0'))
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
it 'returns decimal representation of a zero string float' do
|
|
571
|
+
@property.typecast('0.0').should eql(BigDecimal('0.0'))
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
it 'returns decimal representation of a positive string float' do
|
|
575
|
+
@property.typecast('24.35').should eql(BigDecimal('24.35'))
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
it 'returns decimal representation of a negative string float' do
|
|
579
|
+
@property.typecast('-24.35').should eql(BigDecimal('-24.35'))
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
it 'returns decimal representation of a zero string float, with no leading digits' do
|
|
583
|
+
@property.typecast('.0').should eql(BigDecimal('0.0'))
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
it 'returns decimal representation of a positive string float, with no leading digits' do
|
|
587
|
+
@property.typecast('.41').should eql(BigDecimal('0.41'))
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
it 'returns decimal representation of a zero integer' do
|
|
591
|
+
@property.typecast(0).should eql(BigDecimal('0.0'))
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
it 'returns decimal representation of a positive integer' do
|
|
595
|
+
@property.typecast(24).should eql(BigDecimal('24.0'))
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
it 'returns decimal representation of a negative integer' do
|
|
599
|
+
@property.typecast(-24).should eql(BigDecimal('-24.0'))
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
it 'returns decimal representation of a zero float' do
|
|
603
|
+
@property.typecast(0.0).should eql(BigDecimal('0.0'))
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
it 'returns decimal representation of a positive float' do
|
|
607
|
+
@property.typecast(24.35).should eql(BigDecimal('24.35'))
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
it 'returns decimal representation of a negative float' do
|
|
611
|
+
@property.typecast(-24.35).should eql(BigDecimal('-24.35'))
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
[ Object.new, true, '00.0', '0.', '-.0', 'string' ].each do |value|
|
|
615
|
+
it "does not typecast non-numeric value #{value.inspect}" do
|
|
616
|
+
@property.typecast(value).should equal(value)
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
describe 'when type primitive is a DateTime' do
|
|
622
|
+
before do
|
|
623
|
+
@property = Image.properties[:retouched_at]
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
describe 'and value given as a hash with keys like :year, :month, etc' do
|
|
627
|
+
it 'builds a DateTime instance from hash values' do
|
|
628
|
+
result = @property.typecast(
|
|
629
|
+
'year' => '2006',
|
|
630
|
+
'month' => '11',
|
|
631
|
+
'day' => '23',
|
|
632
|
+
'hour' => '12',
|
|
633
|
+
'min' => '0',
|
|
634
|
+
'sec' => '0'
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
result.should be_kind_of(DateTime)
|
|
638
|
+
result.year.should eql(2006)
|
|
639
|
+
result.month.should eql(11)
|
|
640
|
+
result.day.should eql(23)
|
|
641
|
+
result.hour.should eql(12)
|
|
642
|
+
result.min.should eql(0)
|
|
643
|
+
result.sec.should eql(0)
|
|
644
|
+
end
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
describe 'and value is a string' do
|
|
648
|
+
it 'parses the string' do
|
|
649
|
+
Image.properties[:retouched_at].typecast('Dec, 2006').month.should == 12
|
|
650
|
+
end
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
it 'does not typecast non-datetime values' do
|
|
654
|
+
@property.typecast('not-datetime').should eql('not-datetime')
|
|
655
|
+
end
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
describe 'when type primitive is a Date' do
|
|
659
|
+
before do
|
|
660
|
+
@property = Image.properties[:taken_on]
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
describe 'and value given as a hash with keys like :year, :month, etc' do
|
|
664
|
+
it 'builds a Date instance from hash values' do
|
|
665
|
+
result = @property.typecast(
|
|
666
|
+
'year' => '2007',
|
|
667
|
+
'month' => '3',
|
|
668
|
+
'day' => '25'
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
result.should be_kind_of(Date)
|
|
672
|
+
result.year.should eql(2007)
|
|
673
|
+
result.month.should eql(3)
|
|
674
|
+
result.day.should eql(25)
|
|
675
|
+
end
|
|
676
|
+
end
|
|
677
|
+
|
|
678
|
+
describe 'and value is a string' do
|
|
679
|
+
it 'parses the string' do
|
|
680
|
+
result = @property.typecast('Dec 20th, 2006')
|
|
681
|
+
result.month.should == 12
|
|
682
|
+
result.day.should == 20
|
|
683
|
+
result.year.should == 2006
|
|
684
|
+
end
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
it 'does not typecast non-date values' do
|
|
688
|
+
@property.typecast('not-date').should eql('not-date')
|
|
689
|
+
end
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
describe 'when type primitive is a Time' do
|
|
693
|
+
before do
|
|
694
|
+
@property = Image.properties[:taken_at]
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
describe 'and value given as a hash with keys like :year, :month, etc' do
|
|
698
|
+
it 'builds a Time instance from hash values' do
|
|
699
|
+
result = @property.typecast(
|
|
700
|
+
'year' => '2006',
|
|
701
|
+
'month' => '11',
|
|
702
|
+
'day' => '23',
|
|
703
|
+
'hour' => '12',
|
|
704
|
+
'min' => '0',
|
|
705
|
+
'sec' => '0'
|
|
706
|
+
)
|
|
707
|
+
|
|
708
|
+
result.should be_kind_of(Time)
|
|
709
|
+
result.year.should eql(2006)
|
|
710
|
+
result.month.should eql(11)
|
|
711
|
+
result.day.should eql(23)
|
|
712
|
+
result.hour.should eql(12)
|
|
713
|
+
result.min.should eql(0)
|
|
714
|
+
result.sec.should eql(0)
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
describe 'and value is a string' do
|
|
719
|
+
it 'parses the string' do
|
|
720
|
+
result = @property.typecast('22:24')
|
|
721
|
+
result.hour.should eql(22)
|
|
722
|
+
result.min.should eql(24)
|
|
723
|
+
end
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
it 'does not typecast non-time values' do
|
|
727
|
+
pending 'Time#parse is too permissive' do
|
|
728
|
+
@property.typecast('not-time').should eql('not-time')
|
|
729
|
+
end
|
|
730
|
+
end
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
describe 'when type primitive is a Class' do
|
|
734
|
+
before do
|
|
735
|
+
@property = Image.properties[:type]
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
it 'returns same value if a class' do
|
|
739
|
+
@value = Image
|
|
740
|
+
@property.typecast(@value).should equal(@value)
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
it 'returns the class if found' do
|
|
744
|
+
@property.typecast('Image').should eql(Image)
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
it 'does not typecast non-class values' do
|
|
748
|
+
@property.typecast('NoClass').should eql('NoClass')
|
|
749
|
+
end
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
describe 'when type primitive is a Boolean' do
|
|
753
|
+
before do
|
|
754
|
+
@property = Image.properties[:visible]
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
[ true, 'true', 'TRUE', '1', 1, 't', 'T' ].each do |value|
|
|
758
|
+
it "returns true when value is #{value.inspect}" do
|
|
759
|
+
@property.typecast(value).should be_true
|
|
760
|
+
end
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
[ false, 'false', 'FALSE', '0', 0, 'f', 'F' ].each do |value|
|
|
764
|
+
it "returns false when value is #{value.inspect}" do
|
|
765
|
+
@property.typecast(value).should be_false
|
|
766
|
+
end
|
|
767
|
+
end
|
|
768
|
+
|
|
769
|
+
[ 'string', 2, 1.0, BigDecimal('1.0'), DateTime.now, Time.now, Date.today, Class, Object.new, ].each do |value|
|
|
770
|
+
it "does not typecast value #{value.inspect}" do
|
|
771
|
+
@property.typecast(value).should equal(value)
|
|
772
|
+
end
|
|
773
|
+
end
|
|
774
|
+
end
|
|
775
|
+
end # #typecase
|
|
776
|
+
|
|
777
|
+
describe '#unique?' do
|
|
778
|
+
it 'is true for fields that explicitly given uniq index' do
|
|
779
|
+
Track.properties[:musicbrainz_hash].unique?.should be_true
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
it 'is true for serial fields' do
|
|
783
|
+
pending do
|
|
784
|
+
Track.properties[:title].unique?.should be_true
|
|
785
|
+
end
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
it 'is true for keys' do
|
|
789
|
+
Image.properties[:md5hash].unique?.should be_true
|
|
790
|
+
end
|
|
791
|
+
end
|
|
792
|
+
|
|
793
|
+
describe '#unique_index' do
|
|
794
|
+
it 'returns true when property has unique index' do
|
|
795
|
+
Track.properties[:musicbrainz_hash].unique_index.should be_true
|
|
796
|
+
end
|
|
797
|
+
|
|
798
|
+
it 'returns nil when property has no unique index' do
|
|
799
|
+
Image.properties[:title].unique_index.should be_nil
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
describe '#valid?' do
|
|
804
|
+
describe 'when type primitive is a Boolean' do
|
|
805
|
+
before do
|
|
806
|
+
@property = Image.properties[:visible]
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
[ true, false ].each do |value|
|
|
810
|
+
it "returns true when value is #{value.inspect}" do
|
|
811
|
+
@property.valid?(value).should be_true
|
|
812
|
+
end
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
[ 'true', 'TRUE', '1', 1, 't', 'T', 'false', 'FALSE', '0', 0, 'f', 'F' ].each do |value|
|
|
816
|
+
it "returns false for #{value.inspect}" do
|
|
817
|
+
@property.valid?(value).should be_false
|
|
818
|
+
end
|
|
819
|
+
end
|
|
820
|
+
end
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
describe '#value' do
|
|
824
|
+
it 'returns value for core types'
|
|
825
|
+
|
|
826
|
+
it 'triggers dump operation for custom types'
|
|
827
|
+
end
|
|
828
|
+
end
|
|
829
|
+
end # DataMapper::Property
|