sbf-dm-core 1.3.0.beta

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.
Files changed (259) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +29 -0
  3. data/.document +5 -0
  4. data/.gitignore +44 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +468 -0
  7. data/.travis.yml +57 -0
  8. data/.yardopts +1 -0
  9. data/Gemfile +70 -0
  10. data/LICENSE +20 -0
  11. data/README.md +269 -0
  12. data/Rakefile +4 -0
  13. data/dm-core.gemspec +21 -0
  14. data/lib/dm-core/adapters/abstract_adapter.rb +233 -0
  15. data/lib/dm-core/adapters/in_memory_adapter.rb +110 -0
  16. data/lib/dm-core/adapters.rb +249 -0
  17. data/lib/dm-core/associations/many_to_many.rb +477 -0
  18. data/lib/dm-core/associations/many_to_one.rb +282 -0
  19. data/lib/dm-core/associations/one_to_many.rb +332 -0
  20. data/lib/dm-core/associations/one_to_one.rb +84 -0
  21. data/lib/dm-core/associations/relationship.rb +650 -0
  22. data/lib/dm-core/backwards.rb +11 -0
  23. data/lib/dm-core/collection.rb +1486 -0
  24. data/lib/dm-core/core_ext/kernel.rb +21 -0
  25. data/lib/dm-core/core_ext/pathname.rb +4 -0
  26. data/lib/dm-core/core_ext/symbol.rb +10 -0
  27. data/lib/dm-core/identity_map.rb +6 -0
  28. data/lib/dm-core/model/hook.rb +99 -0
  29. data/lib/dm-core/model/is.rb +30 -0
  30. data/lib/dm-core/model/property.rb +244 -0
  31. data/lib/dm-core/model/relationship.rb +366 -0
  32. data/lib/dm-core/model/scope.rb +87 -0
  33. data/lib/dm-core/model.rb +876 -0
  34. data/lib/dm-core/property/binary.rb +19 -0
  35. data/lib/dm-core/property/boolean.rb +35 -0
  36. data/lib/dm-core/property/class.rb +23 -0
  37. data/lib/dm-core/property/date.rb +45 -0
  38. data/lib/dm-core/property/date_time.rb +44 -0
  39. data/lib/dm-core/property/decimal.rb +47 -0
  40. data/lib/dm-core/property/discriminator.rb +40 -0
  41. data/lib/dm-core/property/float.rb +27 -0
  42. data/lib/dm-core/property/integer.rb +32 -0
  43. data/lib/dm-core/property/invalid_value_error.rb +17 -0
  44. data/lib/dm-core/property/lookup.rb +26 -0
  45. data/lib/dm-core/property/numeric.rb +35 -0
  46. data/lib/dm-core/property/object.rb +33 -0
  47. data/lib/dm-core/property/serial.rb +13 -0
  48. data/lib/dm-core/property/string.rb +47 -0
  49. data/lib/dm-core/property/text.rb +12 -0
  50. data/lib/dm-core/property/time.rb +46 -0
  51. data/lib/dm-core/property/typecast/numeric.rb +32 -0
  52. data/lib/dm-core/property/typecast/time.rb +33 -0
  53. data/lib/dm-core/property.rb +856 -0
  54. data/lib/dm-core/property_set.rb +177 -0
  55. data/lib/dm-core/query/conditions/comparison.rb +886 -0
  56. data/lib/dm-core/query/conditions/operation.rb +710 -0
  57. data/lib/dm-core/query/direction.rb +33 -0
  58. data/lib/dm-core/query/operator.rb +34 -0
  59. data/lib/dm-core/query/path.rb +113 -0
  60. data/lib/dm-core/query/sort.rb +38 -0
  61. data/lib/dm-core/query.rb +1352 -0
  62. data/lib/dm-core/relationship_set.rb +69 -0
  63. data/lib/dm-core/repository.rb +226 -0
  64. data/lib/dm-core/resource/persistence_state/clean.rb +36 -0
  65. data/lib/dm-core/resource/persistence_state/deleted.rb +26 -0
  66. data/lib/dm-core/resource/persistence_state/dirty.rb +91 -0
  67. data/lib/dm-core/resource/persistence_state/immutable.rb +32 -0
  68. data/lib/dm-core/resource/persistence_state/persisted.rb +25 -0
  69. data/lib/dm-core/resource/persistence_state/transient.rb +87 -0
  70. data/lib/dm-core/resource/persistence_state.rb +70 -0
  71. data/lib/dm-core/resource.rb +1220 -0
  72. data/lib/dm-core/spec/lib/adapter_helpers.rb +63 -0
  73. data/lib/dm-core/spec/lib/collection_helpers.rb +21 -0
  74. data/lib/dm-core/spec/lib/counter_adapter.rb +38 -0
  75. data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
  76. data/lib/dm-core/spec/lib/spec_helper.rb +74 -0
  77. data/lib/dm-core/spec/setup.rb +164 -0
  78. data/lib/dm-core/spec/shared/adapter_spec.rb +366 -0
  79. data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
  80. data/lib/dm-core/spec/shared/resource_spec.rb +1221 -0
  81. data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
  82. data/lib/dm-core/spec/shared/semipublic/property_spec.rb +184 -0
  83. data/lib/dm-core/spec/shared/semipublic/query/conditions/abstract_comparison_spec.rb +261 -0
  84. data/lib/dm-core/support/assertions.rb +8 -0
  85. data/lib/dm-core/support/chainable.rb +18 -0
  86. data/lib/dm-core/support/deprecate.rb +12 -0
  87. data/lib/dm-core/support/descendant_set.rb +89 -0
  88. data/lib/dm-core/support/equalizer.rb +48 -0
  89. data/lib/dm-core/support/ext/array.rb +22 -0
  90. data/lib/dm-core/support/ext/blank.rb +25 -0
  91. data/lib/dm-core/support/ext/hash.rb +67 -0
  92. data/lib/dm-core/support/ext/module.rb +47 -0
  93. data/lib/dm-core/support/ext/object.rb +57 -0
  94. data/lib/dm-core/support/ext/string.rb +24 -0
  95. data/lib/dm-core/support/ext/try_dup.rb +12 -0
  96. data/lib/dm-core/support/hook.rb +388 -0
  97. data/lib/dm-core/support/inflections.rb +60 -0
  98. data/lib/dm-core/support/inflector/inflections.rb +211 -0
  99. data/lib/dm-core/support/inflector/methods.rb +151 -0
  100. data/lib/dm-core/support/lazy_array.rb +451 -0
  101. data/lib/dm-core/support/local_object_space.rb +13 -0
  102. data/lib/dm-core/support/logger.rb +201 -0
  103. data/lib/dm-core/support/mash.rb +176 -0
  104. data/lib/dm-core/support/naming_conventions.rb +109 -0
  105. data/lib/dm-core/support/ordered_set.rb +381 -0
  106. data/lib/dm-core/support/subject.rb +33 -0
  107. data/lib/dm-core/support/subject_set.rb +251 -0
  108. data/lib/dm-core/version.rb +3 -0
  109. data/lib/dm-core.rb +274 -0
  110. data/script/performance.rb +275 -0
  111. data/script/profile.rb +218 -0
  112. data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
  113. data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +69 -0
  114. data/spec/public/associations/many_to_many_spec.rb +197 -0
  115. data/spec/public/associations/many_to_one_spec.rb +83 -0
  116. data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +40 -0
  117. data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
  118. data/spec/public/associations/one_to_many_spec.rb +81 -0
  119. data/spec/public/associations/one_to_one_spec.rb +176 -0
  120. data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +46 -0
  121. data/spec/public/collection_spec.rb +69 -0
  122. data/spec/public/finalize_spec.rb +77 -0
  123. data/spec/public/model/hook_spec.rb +245 -0
  124. data/spec/public/model/property_spec.rb +91 -0
  125. data/spec/public/model/relationship_spec.rb +1040 -0
  126. data/spec/public/model_spec.rb +456 -0
  127. data/spec/public/property/binary_spec.rb +43 -0
  128. data/spec/public/property/boolean_spec.rb +21 -0
  129. data/spec/public/property/class_spec.rb +27 -0
  130. data/spec/public/property/date_spec.rb +21 -0
  131. data/spec/public/property/date_time_spec.rb +21 -0
  132. data/spec/public/property/decimal_spec.rb +23 -0
  133. data/spec/public/property/discriminator_spec.rb +134 -0
  134. data/spec/public/property/float_spec.rb +22 -0
  135. data/spec/public/property/integer_spec.rb +22 -0
  136. data/spec/public/property/object_spec.rb +117 -0
  137. data/spec/public/property/serial_spec.rb +22 -0
  138. data/spec/public/property/string_spec.rb +21 -0
  139. data/spec/public/property/text_spec.rb +62 -0
  140. data/spec/public/property/time_spec.rb +21 -0
  141. data/spec/public/property_spec.rb +333 -0
  142. data/spec/public/resource/state_spec.rb +72 -0
  143. data/spec/public/resource_spec.rb +289 -0
  144. data/spec/public/sel_spec.rb +53 -0
  145. data/spec/public/setup_spec.rb +145 -0
  146. data/spec/public/shared/association_collection_shared_spec.rb +309 -0
  147. data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
  148. data/spec/public/shared/collection_shared_spec.rb +1637 -0
  149. data/spec/public/shared/finder_shared_spec.rb +1647 -0
  150. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  151. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +13 -0
  152. data/spec/semipublic/associations/many_to_many_spec.rb +94 -0
  153. data/spec/semipublic/associations/many_to_one_spec.rb +63 -0
  154. data/spec/semipublic/associations/one_to_many_spec.rb +55 -0
  155. data/spec/semipublic/associations/one_to_one_spec.rb +53 -0
  156. data/spec/semipublic/associations/relationship_spec.rb +200 -0
  157. data/spec/semipublic/associations_spec.rb +177 -0
  158. data/spec/semipublic/collection_spec.rb +110 -0
  159. data/spec/semipublic/model_spec.rb +96 -0
  160. data/spec/semipublic/property/binary_spec.rb +13 -0
  161. data/spec/semipublic/property/boolean_spec.rb +47 -0
  162. data/spec/semipublic/property/class_spec.rb +33 -0
  163. data/spec/semipublic/property/date_spec.rb +43 -0
  164. data/spec/semipublic/property/date_time_spec.rb +46 -0
  165. data/spec/semipublic/property/decimal_spec.rb +83 -0
  166. data/spec/semipublic/property/discriminator_spec.rb +19 -0
  167. data/spec/semipublic/property/float_spec.rb +82 -0
  168. data/spec/semipublic/property/integer_spec.rb +82 -0
  169. data/spec/semipublic/property/lookup_spec.rb +29 -0
  170. data/spec/semipublic/property/serial_spec.rb +13 -0
  171. data/spec/semipublic/property/string_spec.rb +13 -0
  172. data/spec/semipublic/property/text_spec.rb +31 -0
  173. data/spec/semipublic/property/time_spec.rb +50 -0
  174. data/spec/semipublic/property_spec.rb +114 -0
  175. data/spec/semipublic/query/conditions/comparison_spec.rb +1502 -0
  176. data/spec/semipublic/query/conditions/operation_spec.rb +1296 -0
  177. data/spec/semipublic/query/path_spec.rb +471 -0
  178. data/spec/semipublic/query_spec.rb +3665 -0
  179. data/spec/semipublic/resource/state/clean_spec.rb +89 -0
  180. data/spec/semipublic/resource/state/deleted_spec.rb +79 -0
  181. data/spec/semipublic/resource/state/dirty_spec.rb +163 -0
  182. data/spec/semipublic/resource/state/immutable_spec.rb +107 -0
  183. data/spec/semipublic/resource/state/transient_spec.rb +163 -0
  184. data/spec/semipublic/resource/state_spec.rb +230 -0
  185. data/spec/semipublic/resource_spec.rb +23 -0
  186. data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
  187. data/spec/semipublic/shared/resource_shared_spec.rb +198 -0
  188. data/spec/semipublic/shared/resource_state_shared_spec.rb +91 -0
  189. data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
  190. data/spec/spec_helper.rb +34 -0
  191. data/spec/support/core_ext/hash.rb +10 -0
  192. data/spec/support/core_ext/inheritable_attributes.rb +46 -0
  193. data/spec/support/properties/huge_integer.rb +17 -0
  194. data/spec/unit/array_spec.rb +23 -0
  195. data/spec/unit/blank_spec.rb +73 -0
  196. data/spec/unit/data_mapper/ordered_set/append_spec.rb +26 -0
  197. data/spec/unit/data_mapper/ordered_set/clear_spec.rb +24 -0
  198. data/spec/unit/data_mapper/ordered_set/delete_spec.rb +28 -0
  199. data/spec/unit/data_mapper/ordered_set/each_spec.rb +19 -0
  200. data/spec/unit/data_mapper/ordered_set/empty_spec.rb +20 -0
  201. data/spec/unit/data_mapper/ordered_set/entries_spec.rb +22 -0
  202. data/spec/unit/data_mapper/ordered_set/eql_spec.rb +51 -0
  203. data/spec/unit/data_mapper/ordered_set/equal_value_spec.rb +84 -0
  204. data/spec/unit/data_mapper/ordered_set/hash_spec.rb +12 -0
  205. data/spec/unit/data_mapper/ordered_set/include_spec.rb +23 -0
  206. data/spec/unit/data_mapper/ordered_set/index_spec.rb +28 -0
  207. data/spec/unit/data_mapper/ordered_set/initialize_spec.rb +32 -0
  208. data/spec/unit/data_mapper/ordered_set/merge_spec.rb +36 -0
  209. data/spec/unit/data_mapper/ordered_set/shared/append_spec.rb +24 -0
  210. data/spec/unit/data_mapper/ordered_set/shared/clear_spec.rb +9 -0
  211. data/spec/unit/data_mapper/ordered_set/shared/delete_spec.rb +25 -0
  212. data/spec/unit/data_mapper/ordered_set/shared/each_spec.rb +17 -0
  213. data/spec/unit/data_mapper/ordered_set/shared/empty_spec.rb +9 -0
  214. data/spec/unit/data_mapper/ordered_set/shared/entries_spec.rb +9 -0
  215. data/spec/unit/data_mapper/ordered_set/shared/include_spec.rb +9 -0
  216. data/spec/unit/data_mapper/ordered_set/shared/index_spec.rb +13 -0
  217. data/spec/unit/data_mapper/ordered_set/shared/initialize_spec.rb +28 -0
  218. data/spec/unit/data_mapper/ordered_set/shared/merge_spec.rb +28 -0
  219. data/spec/unit/data_mapper/ordered_set/shared/size_spec.rb +13 -0
  220. data/spec/unit/data_mapper/ordered_set/shared/to_ary_spec.rb +11 -0
  221. data/spec/unit/data_mapper/ordered_set/size_spec.rb +27 -0
  222. data/spec/unit/data_mapper/ordered_set/to_ary_spec.rb +23 -0
  223. data/spec/unit/data_mapper/subject_set/append_spec.rb +47 -0
  224. data/spec/unit/data_mapper/subject_set/clear_spec.rb +34 -0
  225. data/spec/unit/data_mapper/subject_set/delete_spec.rb +40 -0
  226. data/spec/unit/data_mapper/subject_set/each_spec.rb +30 -0
  227. data/spec/unit/data_mapper/subject_set/empty_spec.rb +31 -0
  228. data/spec/unit/data_mapper/subject_set/entries_spec.rb +31 -0
  229. data/spec/unit/data_mapper/subject_set/get_spec.rb +34 -0
  230. data/spec/unit/data_mapper/subject_set/include_spec.rb +32 -0
  231. data/spec/unit/data_mapper/subject_set/named_spec.rb +33 -0
  232. data/spec/unit/data_mapper/subject_set/shared/append_spec.rb +18 -0
  233. data/spec/unit/data_mapper/subject_set/shared/clear_spec.rb +9 -0
  234. data/spec/unit/data_mapper/subject_set/shared/delete_spec.rb +9 -0
  235. data/spec/unit/data_mapper/subject_set/shared/each_spec.rb +9 -0
  236. data/spec/unit/data_mapper/subject_set/shared/empty_spec.rb +9 -0
  237. data/spec/unit/data_mapper/subject_set/shared/entries_spec.rb +9 -0
  238. data/spec/unit/data_mapper/subject_set/shared/get_spec.rb +9 -0
  239. data/spec/unit/data_mapper/subject_set/shared/include_spec.rb +9 -0
  240. data/spec/unit/data_mapper/subject_set/shared/named_spec.rb +9 -0
  241. data/spec/unit/data_mapper/subject_set/shared/size_spec.rb +13 -0
  242. data/spec/unit/data_mapper/subject_set/shared/to_ary_spec.rb +9 -0
  243. data/spec/unit/data_mapper/subject_set/shared/values_at_spec.rb +44 -0
  244. data/spec/unit/data_mapper/subject_set/size_spec.rb +42 -0
  245. data/spec/unit/data_mapper/subject_set/to_ary_spec.rb +34 -0
  246. data/spec/unit/data_mapper/subject_set/values_at_spec.rb +57 -0
  247. data/spec/unit/hash_spec.rb +27 -0
  248. data/spec/unit/hook_spec.rb +1216 -0
  249. data/spec/unit/inflections_spec.rb +14 -0
  250. data/spec/unit/lazy_array_spec.rb +1949 -0
  251. data/spec/unit/mash_spec.rb +289 -0
  252. data/spec/unit/module_spec.rb +70 -0
  253. data/spec/unit/object_spec.rb +38 -0
  254. data/spec/unit/try_dup_spec.rb +46 -0
  255. data/tasks/ci.rake +1 -0
  256. data/tasks/spec.rake +18 -0
  257. data/tasks/yard.rake +9 -0
  258. data/tasks/yardstick.rake +19 -0
  259. metadata +323 -0
@@ -0,0 +1,333 @@
1
+ require_relative '../spec_helper'
2
+
3
+ # instance methods
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, :required => true, :unique => true
23
+ property :description, Text, :length => 1..1024, :lazy => [ :detail ]
24
+ property :width, Integer, :lazy => [:dimensions]
25
+ property :height, Integer, :lazy => [:dimensions]
26
+ property :format, String, :default => 'jpeg'
27
+ property :taken_at, Time, :default => proc { Time.now }
28
+ end
29
+ DataMapper.finalize
30
+ end
31
+
32
+ supported_by :all do
33
+ describe '#field' do
34
+ it 'returns @field value if it is present' do
35
+ expect(Track.properties[:title].field).to eql('name')
36
+ end
37
+
38
+ it 'returns field for specific repository when it is present'
39
+
40
+ it 'sets field value using field naming convention on first reference'
41
+ end
42
+
43
+ describe '#default_for' do
44
+ it 'returns default value for non-callables' do
45
+ expect(Image.properties[:format].default_for(Image.new)).to eq 'jpeg'
46
+ end
47
+
48
+ it 'returns result of a call for callable values' do
49
+ expect(Image.properties[:taken_at].default_for(Image.new).year).to eq Time.now.year
50
+ end
51
+ end
52
+
53
+ describe '#eql?' do
54
+ it 'is true for properties with the same model and name' do
55
+ expect(Track.properties[:title]).to eql(Track.properties[:title])
56
+ end
57
+
58
+ it 'is false for properties of different models' do
59
+ expect(Track.properties[:title]).not_to eql(Image.properties[:title])
60
+ end
61
+
62
+ it 'is false for properties with different names' do
63
+ expect(Track.properties[:title]).not_to eql(Track.properties[:id])
64
+ end
65
+ end
66
+
67
+ describe '#get!' do
68
+ before :all do
69
+ @image = Image.new
70
+
71
+ # now some dark Ruby magic
72
+ @image.instance_variable_set(:@description, 'Is set by magic')
73
+ end
74
+
75
+ it 'gets instance variable value from the resource directly' do
76
+ # if you know a better way to test direct instance variable access,
77
+ # go ahead and make changes to this example
78
+ expect(Image.properties[:description].get!(@image)).to eq 'Is set by magic'
79
+ end
80
+ end
81
+
82
+ describe '#index' do
83
+ it 'returns true when property has an index' do
84
+ expect(Track.properties[:title].index).to be(true)
85
+ end
86
+
87
+ it 'returns index name when property has a named index' do
88
+ expect(Track.properties[:album].index).to eql(:artist_album)
89
+ end
90
+
91
+ it 'returns false when property has no index' do
92
+ expect(Track.properties[:musicbrainz_hash].index).to be(false)
93
+ end
94
+ end
95
+
96
+ describe '#initialize' do
97
+ describe 'when tracking strategy is explicitly given' do
98
+ it 'uses tracking strategy from options'
99
+ end
100
+ end
101
+
102
+ describe '#inspect' do
103
+ before :all do
104
+ @str = Track.properties[:title].inspect
105
+ end
106
+
107
+ it 'features model name' do
108
+ expect(@str).to match(/@model=Track/)
109
+ end
110
+
111
+ it 'features property name' do
112
+ expect(@str).to match(/@name=:title/)
113
+ end
114
+ end
115
+
116
+ describe '#key?' do
117
+ describe 'returns true when property is a ' do
118
+ it 'serial key' do
119
+ expect(Track.properties[:id].key?).to be(true)
120
+ end
121
+ it 'natural key' do
122
+ expect(Image.properties[:md5hash].key?).to be(true)
123
+ end
124
+ end
125
+
126
+ it 'returns true when property is a part of composite key'
127
+
128
+ it 'returns false when property does not relate to a key' do
129
+ expect(Track.properties[:title].key?).to be(false)
130
+ end
131
+ end
132
+
133
+ describe '#lazy?' do
134
+ it 'returns true when property is lazy loaded' do
135
+ expect(Image.properties[:description].lazy?).to be(true)
136
+ end
137
+
138
+ it 'returns false when property is not lazy loaded' do
139
+ expect(Track.properties[:artist].lazy?).to be(false)
140
+ end
141
+ end
142
+
143
+ describe '#lazy_load_properties' do
144
+ it 'returns all lazy properties in the same context' do
145
+ expect(Image.properties[:width].__send__(:lazy_load_properties)).to eq Image.properties.values_at(:width, :height)
146
+ end
147
+
148
+ it 'returns all properties by default' do
149
+ expect(Track.properties[:artist].__send__(:lazy_load_properties)).to eq Track.properties
150
+ end
151
+ end
152
+
153
+ describe '#length' do
154
+ it 'returns upper bound for Range values' do
155
+ expect(Image.properties[:description].length).to eql(1024)
156
+ end
157
+
158
+ it 'returns value as is for integer values' do
159
+ expect(Image.properties[:md5hash].length).to eql(32)
160
+ end
161
+ end
162
+
163
+ describe '#min' do
164
+ describe 'when :min and :max options not provided to constructor' do
165
+ before do
166
+ @property = Image.property(:integer_with_nil_min, Integer)
167
+ end
168
+
169
+ it 'Is nil' do
170
+ expect(@property.min).to be_nil
171
+ end
172
+ end
173
+
174
+ describe 'when :min option not provided to constructor, but :max is provided' do
175
+ before do
176
+ @property = Image.property(:integer_with_default_min, Integer, :max => 1)
177
+ end
178
+
179
+ it 'is the default value' do
180
+ expect(@property.min).to eq 0
181
+ end
182
+ end
183
+
184
+ describe 'when :min and :max options provided to constructor' do
185
+ before do
186
+ @min = 1
187
+ @property = Image.property(:integer_with_explicit_min, Integer, :min => @min, :max => 2)
188
+ end
189
+
190
+ it 'is the expected value' do
191
+ expect(@property.min).to eq @min
192
+ end
193
+ end
194
+ end
195
+
196
+ describe '#max' do
197
+ describe 'when :min and :max options not provided to constructor' do
198
+ before do
199
+ @property = Image.property(:integer_with_nil_max, Integer)
200
+ end
201
+
202
+ it 'Is nil' do
203
+ expect(@property.max).to be_nil
204
+ end
205
+ end
206
+
207
+ describe 'when :max option not provided to constructor, but :min is provided' do
208
+ before do
209
+ @property = Image.property(:integer_with_default_max, Integer, :min => 1)
210
+ end
211
+
212
+ it 'is the default value' do
213
+ expect(@property.max).to eq 2**31 - 1
214
+ end
215
+ end
216
+
217
+ describe 'when :min and :max options provided to constructor' do
218
+ before do
219
+ @max = 2
220
+ @property = Image.property(:integer_with_explicit_max, Integer, min: 1, max: @max)
221
+ end
222
+
223
+ it 'Is the expected value' do
224
+ expect(@property.max).to eq @max
225
+ end
226
+ end
227
+ end
228
+
229
+ describe '#allow_nil?' do
230
+ it 'returns true when property can accept nil as its value' do
231
+ expect(Track.properties[:artist].allow_nil?).to be(true)
232
+ end
233
+
234
+ it 'returns false when property nil value is prohibited for this property' do
235
+ expect(Image.properties[:title].allow_nil?).to be(false)
236
+ end
237
+ end
238
+
239
+ describe '#serial?' do
240
+ it 'returns true when property is serial (auto incrementing)' do
241
+ expect(Track.properties[:id].serial?).to be(true)
242
+ end
243
+
244
+ it 'returns false when property is NOT serial (auto incrementing)' do
245
+ expect(Image.properties[:md5hash].serial?).to be(false)
246
+ end
247
+ end
248
+
249
+ describe '#set' do
250
+ before :all do
251
+ # keep in mind we must run these examples with a
252
+ # saved model instance
253
+ @image = Image.create(
254
+ :md5hash => '5268f0f3f452844c79843e820f998869',
255
+ :title => 'Rome at the sunset',
256
+ :description => 'Just wow'
257
+ )
258
+
259
+ @property = Image.properties[:title]
260
+ end
261
+
262
+ it 'triggers lazy loading for given resource'
263
+
264
+ it 'sets new property value' do
265
+ @property.set(@image, 'Updated value')
266
+ expect(@image.title).to eq 'Updated value'
267
+ end
268
+ end
269
+
270
+ describe '#set!' do
271
+ before :all do
272
+ @image = Image.new(:md5hash => '5268f0f3f452844c79843e820f998869',
273
+ :title => 'Rome at the sunset',
274
+ :description => 'Just wow')
275
+
276
+ @property = Image.properties[:title]
277
+ end
278
+
279
+ it 'directly sets instance variable on given resource' do
280
+ @property.set!(@image, 'Set with dark Ruby magic')
281
+ expect(@image.title).to eq 'Set with dark Ruby magic'
282
+ end
283
+ end
284
+
285
+ describe '#unique?' do
286
+ it 'is true for fields that explicitly given uniq index' do
287
+ expect(Track.properties[:musicbrainz_hash].unique?).to be(true)
288
+ end
289
+
290
+ it 'is true for serial fields' do
291
+ pending
292
+
293
+ expect(Track.properties[:title].unique?).to be(true)
294
+ end
295
+
296
+ it 'is true for keys' do
297
+ expect(Image.properties[:md5hash].unique?).to be(true)
298
+ end
299
+ end
300
+
301
+ describe '#unique_index' do
302
+ it 'returns true when property has unique index' do
303
+ expect(Track.properties[:musicbrainz_hash].unique_index).to be(true)
304
+ end
305
+
306
+ it 'returns false when property has no unique index' do
307
+ expect(Track.properties[:title].unique_index).to be(false)
308
+ end
309
+
310
+ it 'returns true when property is unique' do
311
+ expect(Image.properties[:title].unique_index).to be(true)
312
+ end
313
+
314
+ it 'returns :key when property is a key' do
315
+ expect(Track.properties[:id].unique_index).to eq :key
316
+ end
317
+ end
318
+
319
+ describe 'exception on bad property names' do
320
+ it "is raised for 'model'" do
321
+ expect {
322
+ Track.property :model, String
323
+ }.to raise_error(ArgumentError)
324
+ end
325
+
326
+ it "is raised for 'repository_name'" do
327
+ expect {
328
+ Track.property :repository_name, String
329
+ }.to raise_error(ArgumentError)
330
+ end
331
+ end
332
+ end
333
+ end # DataMapper::Property
@@ -0,0 +1,72 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
+
3
+ describe 'DataMapper::Resource' do
4
+ before :all do
5
+ class ::Author
6
+ include DataMapper::Resource
7
+
8
+ property :id, Serial
9
+ property :string_, String
10
+ property :bool_, Boolean
11
+ property :float_, Float
12
+ property :integer_, Integer
13
+ property :decimal_, Decimal
14
+ property :datetime_, DateTime
15
+ property :date_, Date
16
+ property :time_, Time
17
+ end
18
+
19
+ DataMapper.finalize
20
+
21
+ @model = Author
22
+ end
23
+
24
+ supported_by :all do
25
+ before do
26
+ @values = {
27
+ :string_ => Addressable::URI.parse('http://test.example/'),
28
+ :bool_ => true,
29
+ :float_ => 2.5,
30
+ :integer_ => 10,
31
+ :decimal_ => BigDecimal("999.95"),
32
+ :datetime_ => DateTime.parse('2010-10-11 12:13:14+0'),
33
+ :date_ => Date.parse('2010-10-11 12:13:14+0'),
34
+ :time_ => Time.parse('2010-10-11 12:13:14+0'),
35
+ }
36
+ @string_values = {
37
+ :string_ => 'http://test.example/',
38
+ :decimal_ => '999.95',
39
+ }
40
+
41
+ @resource = @model.create(@values)
42
+ end
43
+
44
+ describe '.new' do
45
+ subject { @resource }
46
+
47
+ it { is_expected.not_to be_dirty }
48
+ end
49
+
50
+ [:string_, :bool_, :float_, :integer_, :decimal_, :datetime_, :date_, :time_].each do |property|
51
+ describe "#{property.to_s[0...-1]} property mutator" do
52
+ before do
53
+ @resource.send("#{property}=", @string_values[property] || @values[property].to_s)
54
+ end
55
+
56
+ it 'type casts given equal value so resource remains clean' do
57
+ expect(@resource).not_to be_dirty
58
+ end
59
+ end
60
+
61
+ describe "#attribute_set for #{property.to_s[0...-1]} property" do
62
+ before do
63
+ @resource.attribute_set(property, @string_values[property] || @values[property].to_s)
64
+ end
65
+
66
+ it 'type casts given equal value so resource remains clean' do
67
+ expect(@resource).not_to be_dirty
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,289 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe DataMapper::Resource do
4
+ before :all do
5
+ module ::Blog
6
+ class User
7
+ include DataMapper::Resource
8
+
9
+ property :name, String, :key => true
10
+ property :age, Integer
11
+ property :summary, Text
12
+ property :description, Text
13
+ property :admin, Boolean, :accessor => :private
14
+
15
+ belongs_to :parent, self, :required => false
16
+ has n, :children, self, :inverse => :parent
17
+
18
+ belongs_to :referrer, self, :required => false
19
+ has n, :comments
20
+
21
+ # FIXME: figure out a different approach than stubbing things out
22
+ def comment=(*)
23
+ # do nothing with comment
24
+ end
25
+ end
26
+
27
+ class Author < User; end
28
+
29
+ class Comment
30
+ include DataMapper::Resource
31
+
32
+ property :id, Serial
33
+ property :body, Text
34
+
35
+ belongs_to :user
36
+ end
37
+
38
+ class Article
39
+ include DataMapper::Resource
40
+
41
+ property :id, Serial
42
+ property :body, Text
43
+
44
+ has n, :paragraphs
45
+ end
46
+
47
+ class Paragraph
48
+ include DataMapper::Resource
49
+
50
+ property :id, Serial
51
+ property :text, String
52
+
53
+ belongs_to :article
54
+ end
55
+ end
56
+
57
+ class ::Default
58
+ include DataMapper::Resource
59
+
60
+ property :name, String, :key => true, :default => 'a default value'
61
+ end
62
+ DataMapper.finalize
63
+
64
+ @user_model = Blog::User
65
+ @author_model = Blog::Author
66
+ @comment_model = Blog::Comment
67
+ @article_model = Blog::Article
68
+ @paragraph_model = Blog::Paragraph
69
+ end
70
+
71
+ supported_by :all do
72
+ before :all do
73
+ user = @user_model.create(:name => 'dbussink', :age => 25, :description => 'Test')
74
+
75
+ @user = @user_model.get!(*user.key)
76
+ end
77
+
78
+ it_behaves_like 'A public Resource'
79
+ it_behaves_like 'A Resource supporting Strategic Eager Loading'
80
+
81
+ it 'A resource responds to raise_on_save_failure' do
82
+ expect(@user).to respond_to(:raise_on_save_failure)
83
+ end
84
+
85
+ describe '#raise_on_save_failure' do
86
+ after do
87
+ # reset to the default value
88
+ reset_raise_on_save_failure(@user_model)
89
+ reset_raise_on_save_failure(@user)
90
+ end
91
+
92
+ subject { @user.raise_on_save_failure }
93
+
94
+ describe 'when model.raise_on_save_failure has not been set' do
95
+ it { is_expected.to be(false) }
96
+ end
97
+
98
+ describe 'when model.raise_on_save_failure has been set to true' do
99
+ before do
100
+ @user_model.raise_on_save_failure = true
101
+ end
102
+
103
+ it { is_expected.to be(true) }
104
+ end
105
+
106
+ describe 'when resource.raise_on_save_failure has been set to true' do
107
+ before do
108
+ @user.raise_on_save_failure = true
109
+ end
110
+
111
+ it { is_expected.to be(true) }
112
+ end
113
+ end
114
+
115
+ it 'A model responds to raise_on_save_failure=' do
116
+ expect(@user_model).to respond_to(:raise_on_save_failure=)
117
+ end
118
+
119
+ describe '#raise_on_save_failure=' do
120
+ after do
121
+ # reset to the default value
122
+ @user_model.raise_on_save_failure = false
123
+ end
124
+
125
+ subject { @user_model.raise_on_save_failure = @value }
126
+
127
+ describe 'with a true value' do
128
+ before do
129
+ @value = true
130
+ end
131
+
132
+ it { is_expected.to be(true) }
133
+
134
+ it 'Sets raise_on_save_failure' do
135
+ expect { method(:subject) }.to change {
136
+ @user_model.raise_on_save_failure
137
+ }.from(false).to(true)
138
+ end
139
+ end
140
+
141
+ describe 'with a false value' do
142
+ before do
143
+ @value = false
144
+ end
145
+
146
+ it { is_expected.to be(false) }
147
+
148
+ it 'Sets raise_on_save_failure' do
149
+ expect { method(:subject) }.not_to change {
150
+ @user_model.raise_on_save_failure
151
+ }
152
+ end
153
+ end
154
+ end
155
+
156
+ [ :save, :save! ].each do |method|
157
+ describe "##{method}" do
158
+ subject { @user.__send__(method) }
159
+
160
+ describe 'when raise_on_save_failure is true' do
161
+ before do
162
+ @user.raise_on_save_failure = true
163
+ end
164
+
165
+ describe 'and it is a savable resource' do
166
+ it { is_expected.to be(true) }
167
+ end
168
+
169
+ # FIXME: We cannot trigger a failing save with invalid properties anymore.
170
+ # Invalid properties will result in their own exception.
171
+ # So Im mocking here, but a better approach is needed.
172
+
173
+ describe 'and it is an invalid resource' do
174
+ before do
175
+ expect(@user).to receive(:save_self).and_return(false)
176
+ end
177
+
178
+ it 'Raises an exception' do
179
+ expect { method(:subject) }.to raise_error(DataMapper::SaveFailureError,
180
+ "Blog::User##{method} returned false, Blog::User was not saved") { |error|
181
+ expect(error.resource).to equal(@user)
182
+ }
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end
188
+
189
+ [ :update, :update! ].each do |method|
190
+ describe 'with attributes where one is a foreign key' do
191
+ before :all do
192
+ rescue_if @skip do
193
+ @dkubb = @user.referrer = @user_model.create(:name => 'dkubb', :age => 33)
194
+ @user.save
195
+ @user = @user_model.get!(*@user.key)
196
+ expect(@user.referrer).to
197
+
198
+ @solnic = @user_model.create(:name => 'solnic', :age => 28)
199
+
200
+ @attributes = {}
201
+
202
+ relationship = @user_model.relationships[:referrer]
203
+ relationship.child_key.to_a.each_with_index do |k, i|
204
+ @attributes[k.name] = relationship.parent_key.to_a[i].get!(@solnic)
205
+ end
206
+
207
+ @return = @user.__send__(method, @attributes)
208
+ end
209
+ end
210
+
211
+ it 'Returns true' do
212
+ expect(@return).to be(true)
213
+ end
214
+
215
+ it 'Updates attributes of Resource' do
216
+ @attributes.each { |key, value| expect(@user.__send__(key)).to eq value }
217
+ end
218
+
219
+ it 'Persists the changes' do
220
+ resource = @user_model.get!(*@user.key)
221
+ @attributes.each { |key, value| expect(resource.__send__(key)).to eq value }
222
+ end
223
+
224
+ it 'Returns correct parent' do
225
+ resource = @user_model.get!(*@user.key)
226
+ expect(resource.referrer).to eq @solnic
227
+ end
228
+ end
229
+ end
230
+
231
+ describe '#attribute_get' do
232
+ subject { object.attribute_get(name) }
233
+
234
+ let(:object) { @user }
235
+
236
+ context 'with a known property' do
237
+ let(:name) { :name }
238
+
239
+ it 'returns the attribute value' do
240
+ is_expected.to eq 'dbussink'
241
+ end
242
+ end
243
+
244
+ context 'with an unknown property' do
245
+ let(:name) { :unknown }
246
+
247
+ it 'returns nil' do
248
+ is_expected.to be_nil
249
+ end
250
+ end
251
+ end
252
+
253
+ describe '#attribute_set' do
254
+ subject { object.attribute_set(name, value) }
255
+
256
+ let(:object) { @user.dup }
257
+
258
+ context 'with a known property' do
259
+ let(:name) { :name }
260
+ let(:value) { 'dkubb' }
261
+
262
+ it 'sets the attribute' do
263
+ expect { subject }.to change { object.name }
264
+ .from('dbussink')
265
+ .to('dkubb')
266
+ end
267
+
268
+ it 'makes the object dirty' do
269
+ expect { subject }.to change { object.dirty? }
270
+ .from(false)
271
+ .to(true)
272
+ end
273
+ end
274
+
275
+ context 'with an unknown property' do
276
+ let(:name) { :unknown }
277
+ let(:value) { mock('Unknown Value') }
278
+
279
+ it 'does not set the attribute' do
280
+ expect { subject }.to_not change { object.attributes.dup }
281
+ end
282
+
283
+ it 'does not make the object dirty' do
284
+ expect { subject }.to_not change { object.dirty? }
285
+ end
286
+ end
287
+ end
288
+ end
289
+ end