mr 0.35.2

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 (115) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/Gemfile +13 -0
  4. data/LICENSE +22 -0
  5. data/README.md +29 -0
  6. data/bench/all.rb +4 -0
  7. data/bench/factory.rb +68 -0
  8. data/bench/fake_record.rb +174 -0
  9. data/bench/model.rb +201 -0
  10. data/bench/read_model.rb +191 -0
  11. data/bench/results/factory.txt +21 -0
  12. data/bench/results/fake_record.txt +37 -0
  13. data/bench/results/model.txt +44 -0
  14. data/bench/results/read_model.txt +46 -0
  15. data/bench/setup.rb +132 -0
  16. data/lib/mr.rb +11 -0
  17. data/lib/mr/after_commit.rb +49 -0
  18. data/lib/mr/after_commit/fake_record.rb +39 -0
  19. data/lib/mr/after_commit/record.rb +48 -0
  20. data/lib/mr/after_commit/record_procs_methods.rb +82 -0
  21. data/lib/mr/factory.rb +82 -0
  22. data/lib/mr/factory/config.rb +240 -0
  23. data/lib/mr/factory/model_factory.rb +103 -0
  24. data/lib/mr/factory/model_stack.rb +28 -0
  25. data/lib/mr/factory/read_model_factory.rb +104 -0
  26. data/lib/mr/factory/record_factory.rb +130 -0
  27. data/lib/mr/factory/record_stack.rb +219 -0
  28. data/lib/mr/fake_query.rb +53 -0
  29. data/lib/mr/fake_record.rb +58 -0
  30. data/lib/mr/fake_record/associations.rb +257 -0
  31. data/lib/mr/fake_record/attributes.rb +168 -0
  32. data/lib/mr/fake_record/persistence.rb +116 -0
  33. data/lib/mr/json_field.rb +180 -0
  34. data/lib/mr/json_field/fake_record.rb +31 -0
  35. data/lib/mr/json_field/record.rb +38 -0
  36. data/lib/mr/model.rb +67 -0
  37. data/lib/mr/model/associations.rb +161 -0
  38. data/lib/mr/model/configuration.rb +67 -0
  39. data/lib/mr/model/fields.rb +177 -0
  40. data/lib/mr/model/persistence.rb +79 -0
  41. data/lib/mr/query.rb +126 -0
  42. data/lib/mr/read_model.rb +83 -0
  43. data/lib/mr/read_model/data.rb +38 -0
  44. data/lib/mr/read_model/fields.rb +218 -0
  45. data/lib/mr/read_model/query_expression.rb +188 -0
  46. data/lib/mr/read_model/querying.rb +214 -0
  47. data/lib/mr/read_model/set_querying.rb +82 -0
  48. data/lib/mr/read_model/subquery.rb +98 -0
  49. data/lib/mr/record.rb +35 -0
  50. data/lib/mr/test_helpers.rb +229 -0
  51. data/lib/mr/type_converter.rb +85 -0
  52. data/lib/mr/version.rb +3 -0
  53. data/log/.gitkeep +0 -0
  54. data/mr.gemspec +29 -0
  55. data/test/helper.rb +21 -0
  56. data/test/support/db.rb +10 -0
  57. data/test/support/factory.rb +13 -0
  58. data/test/support/factory/area.rb +6 -0
  59. data/test/support/factory/comment.rb +14 -0
  60. data/test/support/factory/image.rb +6 -0
  61. data/test/support/factory/user.rb +6 -0
  62. data/test/support/models/area.rb +58 -0
  63. data/test/support/models/comment.rb +60 -0
  64. data/test/support/models/image.rb +53 -0
  65. data/test/support/models/user.rb +96 -0
  66. data/test/support/read_model/querying.rb +150 -0
  67. data/test/support/read_models/comment_with_user_data.rb +27 -0
  68. data/test/support/read_models/set_data.rb +49 -0
  69. data/test/support/read_models/subquery_data.rb +41 -0
  70. data/test/support/read_models/user_with_area_data.rb +15 -0
  71. data/test/support/schema.rb +39 -0
  72. data/test/support/setup_test_db.rb +10 -0
  73. data/test/system/factory/model_factory_tests.rb +87 -0
  74. data/test/system/factory/model_stack_tests.rb +30 -0
  75. data/test/system/factory/record_factory_tests.rb +84 -0
  76. data/test/system/factory/record_stack_tests.rb +51 -0
  77. data/test/system/factory_tests.rb +32 -0
  78. data/test/system/read_model_tests.rb +199 -0
  79. data/test/system/with_model_tests.rb +275 -0
  80. data/test/unit/after_commit/fake_record_tests.rb +110 -0
  81. data/test/unit/after_commit/record_procs_methods_tests.rb +177 -0
  82. data/test/unit/after_commit/record_tests.rb +134 -0
  83. data/test/unit/after_commit_tests.rb +113 -0
  84. data/test/unit/factory/config_tests.rb +651 -0
  85. data/test/unit/factory/model_factory_tests.rb +473 -0
  86. data/test/unit/factory/model_stack_tests.rb +97 -0
  87. data/test/unit/factory/read_model_factory_tests.rb +195 -0
  88. data/test/unit/factory/record_factory_tests.rb +446 -0
  89. data/test/unit/factory/record_stack_tests.rb +549 -0
  90. data/test/unit/factory_tests.rb +213 -0
  91. data/test/unit/fake_query_tests.rb +137 -0
  92. data/test/unit/fake_record/associations_tests.rb +585 -0
  93. data/test/unit/fake_record/attributes_tests.rb +265 -0
  94. data/test/unit/fake_record/persistence_tests.rb +239 -0
  95. data/test/unit/fake_record_tests.rb +106 -0
  96. data/test/unit/json_field/fake_record_tests.rb +75 -0
  97. data/test/unit/json_field/record_tests.rb +80 -0
  98. data/test/unit/json_field_tests.rb +302 -0
  99. data/test/unit/model/associations_tests.rb +346 -0
  100. data/test/unit/model/configuration_tests.rb +92 -0
  101. data/test/unit/model/fields_tests.rb +278 -0
  102. data/test/unit/model/persistence_tests.rb +114 -0
  103. data/test/unit/model_tests.rb +137 -0
  104. data/test/unit/query_tests.rb +300 -0
  105. data/test/unit/read_model/data_tests.rb +56 -0
  106. data/test/unit/read_model/fields_tests.rb +416 -0
  107. data/test/unit/read_model/query_expression_tests.rb +381 -0
  108. data/test/unit/read_model/querying_tests.rb +613 -0
  109. data/test/unit/read_model/set_querying_tests.rb +149 -0
  110. data/test/unit/read_model/subquery_tests.rb +242 -0
  111. data/test/unit/read_model_tests.rb +187 -0
  112. data/test/unit/record_tests.rb +45 -0
  113. data/test/unit/test_helpers_tests.rb +431 -0
  114. data/test/unit/type_converter_tests.rb +207 -0
  115. metadata +285 -0
@@ -0,0 +1,346 @@
1
+ require 'assert'
2
+ require 'mr/model/associations'
3
+
4
+ require 'much-plugin'
5
+ require 'mr/fake_record'
6
+ require 'mr/model'
7
+
8
+ module MR::Model::Associations
9
+
10
+ class UnitTests < Assert::Context
11
+ desc "MR::Model::Associations"
12
+ setup do
13
+ @model_class = Class.new do
14
+ include MR::Model::Associations
15
+ record_class FakeRecordWithAssociations
16
+ def initialize(record); set_record record; end
17
+ end
18
+ @record = FakeRecordWithAssociations.new
19
+ end
20
+ subject{ @model_class }
21
+
22
+ should have_imeths :associations
23
+ should have_imeths :belongs_to, :polymorphic_belongs_to
24
+ should have_imeths :has_one, :has_many
25
+
26
+ should "use much-plugin" do
27
+ assert_includes MuchPlugin, MR::Model::Associations
28
+ end
29
+
30
+ should "include Model::Configuration mixin" do
31
+ assert_includes MR::Model::Configuration, subject.included_modules
32
+ end
33
+
34
+ should "return an instance of a AssociationSet using `associations`" do
35
+ associations = subject.associations
36
+ assert_instance_of MR::Model::AssociationSet, associations
37
+ assert_same associations, subject.associations
38
+ end
39
+
40
+ should "add accessors methods for a belongs to association using `belongs_to`" do
41
+ subject.belongs_to :area
42
+ model = subject.new(@record)
43
+ new_record = FakeTestRecord.new
44
+ new_model = FakeTestModel.new(new_record)
45
+
46
+ assert_respond_to :area, model
47
+ assert_respond_to :area=, model
48
+ model.area = new_model
49
+ assert_instance_of FakeTestModel, model.area
50
+ assert_equal new_record, @record.area
51
+ end
52
+
53
+ should "add accessors methods for a polymorphic belongs to association " \
54
+ "using `polymorphic_belongs_to`" do
55
+ subject.polymorphic_belongs_to :parent
56
+ model = subject.new(@record)
57
+ new_record = FakeTestRecord.new
58
+ new_model = FakeTestModel.new(new_record)
59
+
60
+ assert_respond_to :parent, model
61
+ assert_respond_to :parent=, model
62
+ model.parent = new_model
63
+ assert_instance_of FakeTestModel, model.parent
64
+ assert_equal new_record, @record.parent
65
+ end
66
+
67
+ should "add accessors methods for a has one association using `has_one`" do
68
+ subject.has_one :image
69
+ model = subject.new(@record)
70
+ new_record = FakeTestRecord.new
71
+ new_model = FakeTestModel.new(new_record)
72
+
73
+ assert_respond_to :image, model
74
+ assert_respond_to :image=, model
75
+ model.image = new_model
76
+ assert_instance_of FakeTestModel, model.image
77
+ assert_equal new_record, @record.image
78
+ end
79
+
80
+ should "add accessors methods for a has many association using `has_many`" do
81
+ subject.has_many :comments
82
+ model = subject.new(@record)
83
+ first_record = FakeTestRecord.new
84
+ first_model = FakeTestModel.new(first_record)
85
+ second_record = FakeTestRecord.new
86
+ second_model = FakeTestModel.new(second_record)
87
+
88
+ assert_respond_to :comments, model
89
+ assert_respond_to :comments=, model
90
+ model.comments = [ first_model, second_model ]
91
+ assert_instance_of Array, model.comments
92
+ assert_includes first_record, @record.comments
93
+ assert_includes second_record, @record.comments
94
+ end
95
+
96
+ end
97
+
98
+ class InstanceTests < UnitTests
99
+ desc "for a model instance"
100
+ setup do
101
+ @model_class.class_eval do
102
+ belongs_to :area
103
+ polymorphic_belongs_to :parent
104
+ has_one :image
105
+ has_many :comments
106
+ end
107
+ @model = @model_class.new(@record)
108
+ end
109
+ subject{ @model }
110
+
111
+ should "raise an ArgumentError if writing non MR::Model values to associations" do
112
+ assert_raises(ArgumentError){ subject.area = 'test' }
113
+ assert_raises(ArgumentError){ subject.parent = 'test' }
114
+ assert_raises(ArgumentError){ subject.image = 'test' }
115
+ assert_raises(ArgumentError){ subject.comments = [ 'test' ] }
116
+ end
117
+
118
+ end
119
+
120
+ class AssociationSetTests < UnitTests
121
+ desc "AssociationSet"
122
+ setup do
123
+ @association_set = MR::Model::AssociationSet.new
124
+ end
125
+ subject{ @association_set }
126
+
127
+ should have_readers :belongs_to, :polymorphic_belongs_to
128
+ should have_readers :has_one, :has_many
129
+ should have_imeths :add_belongs_to, :add_polymorphic_belongs_to
130
+ should have_imeths :add_has_one, :add_has_many
131
+
132
+ end
133
+
134
+ class AssociationTests < UnitTests
135
+ desc "Association"
136
+ setup do
137
+ @association = MR::Model::Association.new(:test)
138
+ end
139
+ subject{ @association }
140
+
141
+ should have_readers :name
142
+ should have_readers :reader_method_name, :writer_method_name
143
+
144
+ should "know it's name and method names" do
145
+ assert_equal 'test', subject.name
146
+ assert_equal 'test', subject.reader_method_name
147
+ assert_equal 'test=', subject.writer_method_name
148
+ end
149
+
150
+ end
151
+
152
+ class OneToOneAssociationTests < UnitTests
153
+ desc "OneToOneAssociation"
154
+ setup do
155
+ @test_record = FakeTestRecord.new.tap{ |r| r.save! }
156
+ @test_model = FakeTestModel.new(@test_record)
157
+ @other_record = FakeTestRecord.new.tap{ |r| r.save! }
158
+ @other_model = FakeTestModel.new(@other_record)
159
+
160
+ @association = MR::Model::OneToOneAssociation.new(:area)
161
+ end
162
+ subject{ @association }
163
+
164
+ should have_imeths :read, :write
165
+
166
+ should "be a kind of Association" do
167
+ assert_kind_of MR::Model::Association, subject
168
+ end
169
+
170
+ should "allow reading the record's association using `read`" do
171
+ @test_record.area = @other_record
172
+ assert_equal @other_model, subject.read(@test_record)
173
+ end
174
+
175
+ should "allow reading `nil` values for the record's association using `read`" do
176
+ @test_record.area = nil
177
+ assert_nil subject.read(@test_record)
178
+ end
179
+
180
+ should "allow writing the record's association using `write`" do
181
+ record = @other_record
182
+ yielded = nil
183
+ result = subject.write(@other_model, @test_model, @test_record) do |object|
184
+ yielded = object; record
185
+ end
186
+
187
+ assert_equal @other_model, yielded
188
+ assert_equal @other_record, @test_record.area
189
+ assert_equal @test_model.send(subject.name), result
190
+ end
191
+
192
+ should "allow writing `nil` values to the record's association using `write`" do
193
+ subject.write(nil, @test_model, @test_record){ raise 'test' }
194
+ assert_nil @test_record.area
195
+ end
196
+
197
+ should "raise a bad association value error when writing a non MR::Model" do
198
+ assert_raises(MR::Model::BadAssociationValueError) do
199
+ subject.write('test', @test_model, @test_record){ }
200
+ end
201
+ end
202
+
203
+ end
204
+
205
+ class OneToManyAssociationTests < UnitTests
206
+ desc "OneToManyAssociation"
207
+ setup do
208
+ @test_record = FakeTestRecord.new.tap{ |r| r.save! }
209
+ @test_model = FakeTestModel.new(@test_record)
210
+ @first_record = FakeTestRecord.new.tap{ |r| r.save! }
211
+ @first_model = FakeTestModel.new(@first_record)
212
+ @second_record = FakeTestRecord.new.tap{ |r| r.save! }
213
+ @second_model = FakeTestModel.new(@second_record)
214
+
215
+ @association = MR::Model::OneToManyAssociation.new(:comments)
216
+ end
217
+ subject{ @association }
218
+
219
+ should have_imeths :read, :write
220
+
221
+ should "be a kind of Association" do
222
+ assert_kind_of MR::Model::Association, subject
223
+ end
224
+
225
+ should "allow reading the record's association using `read`" do
226
+ @test_record.comments = [ @first_record ]
227
+ expected = [ @first_model ]
228
+ assert_equal expected, subject.read(@test_record)
229
+ end
230
+
231
+ should "allow reading `nil` values for the record's association using `read`" do
232
+ @test_record.comments = []
233
+ assert_equal [], subject.read(@test_record)
234
+ end
235
+
236
+ should "allow writing the record's association using `write`" do
237
+ models = [ @first_model, @second_model ]
238
+ yielded = []
239
+ results = subject.write(models, @test_model, @test_record) do |object|
240
+ yielded << object; object.record
241
+ end
242
+
243
+ assert_equal models, yielded
244
+ records = [ @first_record, @second_record ]
245
+ assert_equal records, @test_record.comments
246
+ assert_equal @test_model.send(subject.name), results
247
+ end
248
+
249
+ should "allow writing a single value to the record's association using `write`" do
250
+ subject.write(@second_model, @test_model, @test_record) do |object|
251
+ object.record
252
+ end
253
+ assert_equal [ @second_record ], @test_record.comments
254
+ end
255
+
256
+ should "allow writing `nil` values to the record's association using `write`" do
257
+ subject.write(nil, @test_model, @test_record){ raise 'test' }
258
+ assert_equal [], @test_record.comments
259
+ end
260
+
261
+ should "raise a bad association value error when writing a non MR::Model" do
262
+ assert_raises(MR::Model::BadAssociationValueError) do
263
+ subject.write('test', @test_model, @test_record){ }
264
+ end
265
+ end
266
+
267
+ end
268
+
269
+ class BelongsToAssociationTests < UnitTests
270
+ desc "BelongsToAssociation"
271
+ setup do
272
+ @association = MR::Model::BelongsToAssociation.new(:test)
273
+ end
274
+ subject{ @association }
275
+
276
+ should "be a kind of OneToOneAssociation" do
277
+ assert_kind_of MR::Model::OneToOneAssociation, subject
278
+ end
279
+
280
+ end
281
+
282
+ class HasOneAssociationTests < UnitTests
283
+ desc "HasOneAssociation"
284
+ setup do
285
+ @association = MR::Model::HasOneAssociation.new(:test)
286
+ end
287
+ subject{ @association }
288
+
289
+ should "be a kind of OneToOneAssociation" do
290
+ assert_kind_of MR::Model::OneToOneAssociation, subject
291
+ end
292
+
293
+ end
294
+
295
+ class HasManyAssociationTests < UnitTests
296
+ desc "HasManyAssociation"
297
+ setup do
298
+ @association = MR::Model::HasManyAssociation.new(:test)
299
+ end
300
+ subject{ @association }
301
+
302
+ should "be a kind of OneToManyAssociation" do
303
+ assert_kind_of MR::Model::OneToManyAssociation, subject
304
+ end
305
+
306
+ end
307
+
308
+ class PolymorphicBelongsToAssociationTests < UnitTests
309
+ desc "PolymorphicBelongsToAssociation"
310
+ setup do
311
+ @association = MR::Model::PolymorphicBelongsToAssociation.new(:test)
312
+ end
313
+ subject{ @association }
314
+
315
+ should "be a kind of BelongsToAssociation" do
316
+ assert_kind_of MR::Model::BelongsToAssociation, subject
317
+ end
318
+
319
+ end
320
+
321
+ class FakeRecordWithAssociations
322
+ include MR::FakeRecord
323
+ attribute :area_id, :integer
324
+ attribute :parent_type, :string
325
+ attribute :parent_id, :integer
326
+ belongs_to :area, :class_name => 'MR::Model::Associations::FakeRecordWithAssociations'
327
+ belongs_to :parent, :polymorphic => true
328
+ has_one :image, :class_name => 'MR::Model::Associations::FakeRecordWithAssociations'
329
+ has_many :comments, :class_name => 'MR::Model::Associations::FakeRecordWithAssociations'
330
+ end
331
+
332
+ class FakeTestRecord
333
+ include MR::FakeRecord
334
+ attribute :area_id, :integer
335
+ belongs_to :area, :class_name => 'MR::Model::Associations::FakeTestRecord'
336
+ has_many :comments, :class_name => 'MR::Model::Associations::FakeTestRecord'
337
+ end
338
+
339
+ class FakeTestModel
340
+ include MR::Model
341
+ record_class FakeTestRecord
342
+ belongs_to :area
343
+ has_many :comments
344
+ end
345
+
346
+ end
@@ -0,0 +1,92 @@
1
+ require 'assert'
2
+ require 'mr/model/configuration'
3
+
4
+ require 'much-plugin'
5
+ require 'mr/fake_record'
6
+
7
+ module MR::Model::Configuration
8
+
9
+ class UnitTests < Assert::Context
10
+ desc "MR::Model::Configuration"
11
+ setup do
12
+ @model_class = Class.new do
13
+ include MR::Model::Configuration
14
+ end
15
+ end
16
+ subject{ @model_class }
17
+
18
+ should have_imeths :record_class
19
+
20
+ should "use much-plugin" do
21
+ assert_includes MuchPlugin, MR::Model::Configuration
22
+ end
23
+
24
+ should "allow reading and writing it's record class with `record_class`" do
25
+ subject.record_class FakeTestRecord
26
+ assert_equal FakeTestRecord, subject.record_class
27
+ end
28
+
29
+ should "raise a no record class error if a record class hasn't been set" do
30
+ assert_raises(MR::Model::NoRecordClassError){ subject.record_class }
31
+ end
32
+
33
+ should "raise an ArgumentError when a non MR::Record `record_class` is written" do
34
+ assert_raises(ArgumentError){ subject.record_class('fake-class') }
35
+ end
36
+
37
+ end
38
+
39
+ class InstanceTests < UnitTests
40
+
41
+ # These private methods are tested because they are an interace to the other
42
+ # mixins.
43
+
44
+ desc "for a model instance"
45
+ setup do
46
+ @model_class.class_eval do
47
+ record_class FakeTestRecord
48
+
49
+ def read_record
50
+ record
51
+ end
52
+
53
+ def write_record(record)
54
+ set_record(record)
55
+ end
56
+ end
57
+ @record = FakeTestRecord.new
58
+ @model = @model_class.new
59
+ end
60
+ subject{ @model }
61
+
62
+ should have_imeths :record_class
63
+
64
+ should "allow reading the model class' record class using `record_class`" do
65
+ assert_equal @model_class.record_class, subject.record_class
66
+ end
67
+
68
+ should "allow reading the `record` through the protected method" do
69
+ subject.write_record(@record)
70
+ assert_equal @record, subject.read_record
71
+ end
72
+
73
+ should "set the record's model when `set_record` is called" do
74
+ subject.write_record(@record)
75
+ assert_equal @model, @record.model
76
+ end
77
+
78
+ should "raise a no record error if a record hasn't been set" do
79
+ assert_raises(MR::Model::NoRecordError){ subject.read_record }
80
+ end
81
+
82
+ should "raise an invalid record error when setting record without an MR::Record" do
83
+ assert_raises(MR::Model::InvalidRecordError){ subject.write_record('fake') }
84
+ end
85
+
86
+ end
87
+
88
+ class FakeTestRecord
89
+ include MR::FakeRecord
90
+ end
91
+
92
+ end
@@ -0,0 +1,278 @@
1
+ require 'assert'
2
+ require 'mr/model/fields'
3
+
4
+ require 'much-plugin'
5
+ require 'mr/fake_record'
6
+
7
+ module MR::Model::Fields
8
+
9
+ class UnitTests < Assert::Context
10
+ desc "MR::Model::Fields"
11
+ setup do
12
+ @model_class = Class.new do
13
+ include MR::Model::Fields
14
+ def initialize(record); set_record record; end
15
+ end
16
+ @record = FakeTestRecord.new
17
+ end
18
+ subject{ @model_class }
19
+
20
+ should have_imeths :fields, :field_reader, :field_writer, :field_accessor
21
+ should have_imeths :field_names
22
+
23
+ should "use much-plugin" do
24
+ assert_includes MuchPlugin, MR::Model::Fields
25
+ end
26
+
27
+ should "include Model::Configuration mixin" do
28
+ assert_includes MR::Model::Configuration, subject
29
+ end
30
+
31
+ should "return an instance of a FieldSet using `fields`" do
32
+ fields = subject.fields
33
+ assert_instance_of MR::Model::FieldSet, fields
34
+ assert_same fields, subject.fields
35
+ end
36
+
37
+ should "add reader methods for a field using `field_reader`" do
38
+ subject.field_reader :name
39
+ @record.name = 'test'
40
+ model = subject.new(@record)
41
+
42
+ assert_respond_to :name, model
43
+ assert_respond_to :name_was, model
44
+ assert_respond_to :name_changed?, model
45
+ assert_equal @record.name, model.name
46
+ assert_equal @record.name_was, model.name_was
47
+ assert_equal @record.name_changed?, model.name_changed?
48
+ end
49
+
50
+ should "add writer methods for a field using `field_writer`" do
51
+ subject.field_writer :name
52
+ model = subject.new(@record)
53
+
54
+ assert_respond_to :name=, model
55
+ model.name = 'test'
56
+ assert_equal 'test', @record.name
57
+ end
58
+
59
+ should "add accessor methods for a field using `field_accessor`" do
60
+ subject.field_accessor :name
61
+ model = subject.new(@record)
62
+
63
+ assert_respond_to :name, model
64
+ assert_respond_to :name_changed?, model
65
+ assert_respond_to :name=, model
66
+ model.name = 'test'
67
+ assert_equal 'test', @record.name
68
+ assert_equal @record.name, model.name
69
+ assert_equal @record.name_changed?, model.name_changed?
70
+ end
71
+
72
+ should "know its field names" do
73
+ assert_equal [], subject.field_names
74
+
75
+ subject.field_reader :field1
76
+ subject.field_writer :field2
77
+ subject.field_accessor :field3
78
+
79
+ result = subject.field_names
80
+ assert_equal subject.fields.names, result
81
+ end
82
+
83
+ end
84
+
85
+ class InstanceTests < UnitTests
86
+ desc "for a model instance"
87
+ setup do
88
+ @model_class.class_eval do
89
+ field_accessor :name, :active, :description
90
+ end
91
+ @model = @model_class.new(@record)
92
+ end
93
+ subject{ @model }
94
+
95
+ should have_imeths :fields, :fields=
96
+
97
+ should "allow reading all the fields using `fields`" do
98
+ subject.name = 'test'
99
+ subject.active = true
100
+ subject.description = 'desc'
101
+
102
+ expected = {
103
+ 'name' => 'test',
104
+ 'active' => true,
105
+ 'description' => 'desc'
106
+ }
107
+ assert_equal expected, subject.fields
108
+ end
109
+
110
+ should "allow writing multiple fields using `fields=`" do
111
+ subject.fields = {
112
+ 'name' => 'test',
113
+ 'active' => true,
114
+ 'description' => 'desc'
115
+ }
116
+ assert_equal 'test', subject.name
117
+ assert_equal true, subject.active
118
+ assert_equal 'desc', subject.description
119
+ end
120
+
121
+ should "raise an ArgumentError when a non-Hash is passed to `fields=`" do
122
+ assert_raises(ArgumentError){ subject.fields = 'test' }
123
+ end
124
+
125
+ should "raise a no field error when writing a bad field using `fields=`" do
126
+ assert_raises(MR::Model::NoFieldError) do
127
+ subject.fields = { :not_valid => 'test' }
128
+ end
129
+ end
130
+
131
+ end
132
+
133
+ class FieldSetTests < UnitTests
134
+ desc "FieldSet"
135
+ setup do
136
+ @fields_set = MR::Model::FieldSet.new
137
+ end
138
+ subject{ @fields_set }
139
+
140
+ should have_imeths :names, :find, :get
141
+ should have_imeths :read_all, :batch_write
142
+ should have_imeths :add_reader, :add_writer
143
+
144
+ should "know its field names" do
145
+ assert_equal [], subject.names
146
+
147
+ subject.add_reader(:field1, @model_class)
148
+ subject.add_writer(:field2, @model_class)
149
+
150
+ assert_equal 2, subject.names.size
151
+ assert_includes 'field1', subject.names
152
+ assert_includes 'field2', subject.names
153
+ end
154
+
155
+ should "return an existing field or raise a no field error using `find`" do
156
+ subject.get('name')
157
+ field = subject.find('name')
158
+ assert_instance_of MR::Model::Field, field
159
+ assert_equal 'name', field.name
160
+
161
+ assert_raises(MR::Model::NoFieldError){ subject.find('not_valid') }
162
+ end
163
+
164
+ should "return an existing field or build a new field using `get`" do
165
+ field = subject.get('name')
166
+ assert_instance_of MR::Model::Field, field
167
+ assert_equal 'name', field.name
168
+ assert_same field, subject.get('name')
169
+ end
170
+
171
+ should "return a hash of field names and values using `read_all`" do
172
+ assert_equal({}, subject.read_all(@record))
173
+ subject.get('name')
174
+ @record.name = 'test'
175
+ assert_equal({ 'name' => 'test' }, subject.read_all(@record))
176
+ end
177
+
178
+ should "set multiple field values using `batch_write`" do
179
+ subject.get('name')
180
+ subject.get('active')
181
+ values = { :name => 'test', :active => true }
182
+ subject.batch_write(values, @record)
183
+
184
+ assert_equal 'test', @record.name
185
+ assert_equal true, @record.active
186
+ end
187
+
188
+ should "add a field and define reader methods for it using `add_reader`" do
189
+ subject.add_reader('name', @model_class)
190
+
191
+ assert_instance_of MR::Model::Field, subject.find('name')
192
+ model = @model_class.new(@record)
193
+ assert_respond_to :name, model
194
+ assert_respond_to :name_changed?, model
195
+ end
196
+
197
+ should "add a field and define writer methods for it using `add_writer`" do
198
+ subject.add_writer('name', @model_class)
199
+
200
+ assert_instance_of MR::Model::Field, subject.find('name')
201
+ model = @model_class.new(@record)
202
+ assert_respond_to :name=, model
203
+ end
204
+
205
+ end
206
+
207
+ class FieldTests < UnitTests
208
+ desc "Field"
209
+ setup do
210
+ @field = MR::Model::Field.new('name')
211
+ end
212
+ subject{ @field }
213
+
214
+ should have_readers :name
215
+ should have_readers :reader_method_name, :writer_method_name
216
+ should have_readers :was_method_name, :changed_method_name
217
+
218
+ should have_imeths :read, :write, :was, :changed?
219
+ should have_imeths :define_reader_on, :define_writer_on
220
+
221
+ should "know it's name and method names" do
222
+ assert_equal 'name', subject.name
223
+ assert_equal 'name', subject.reader_method_name
224
+ assert_equal 'name_was', subject.was_method_name
225
+ assert_equal 'name_changed?', subject.changed_method_name
226
+ assert_equal 'name=', subject.writer_method_name
227
+ end
228
+
229
+ should "read a record's attribute using `read`" do
230
+ @record.name = 'test'
231
+ assert_equal 'test', subject.read(@record)
232
+ end
233
+
234
+ should "write a record's attribute using `write`" do
235
+ subject.write('test', @record)
236
+ assert_equal 'test', @record.name
237
+ end
238
+
239
+ should "read a record attribute's prevous value using `was`" do
240
+ assert_nil subject.was(@record)
241
+ @record.name = 'Test'
242
+ assert_nil subject.was(@record)
243
+ @record.save!
244
+ assert_equal 'Test', subject.was(@record)
245
+ @record.name = 'New test'
246
+ assert_equal 'Test', subject.was(@record)
247
+ end
248
+
249
+ should "return if a record's attribute has changed using `changed`" do
250
+ assert_equal false, subject.changed?(@record)
251
+ subject.write('test', @record)
252
+ assert_equal true, subject.changed?(@record)
253
+ end
254
+
255
+ should "define reader methods using `define_reader_on`" do
256
+ subject.define_reader_on(@model_class)
257
+ model = @model_class.new(@record)
258
+ assert_respond_to :name, model
259
+ assert_respond_to :name_was, model
260
+ assert_respond_to :name_changed?, model
261
+ end
262
+
263
+ should "define writer methods using `define_writer_on`" do
264
+ subject.define_writer_on(@model_class)
265
+ model = @model_class.new(@record)
266
+ assert_respond_to :name=, model
267
+ end
268
+
269
+ end
270
+
271
+ class FakeTestRecord
272
+ include MR::FakeRecord
273
+ attribute :name, :string
274
+ attribute :active, :boolean
275
+ attribute :description, :text
276
+ end
277
+
278
+ end