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,651 @@
1
+ require 'assert'
2
+ require 'mr/factory/config'
3
+
4
+ require 'mr/factory/model_factory'
5
+ require 'mr/factory/record_factory'
6
+ require 'mr/fake_record'
7
+ require 'mr/model'
8
+
9
+ module MR::Factory::Config
10
+
11
+ class UnitTests < Assert::Context
12
+ desc "MR::Factory::Config"
13
+ setup do
14
+ @config_class = Class.new do
15
+ include MR::Factory::Config
16
+ end
17
+ end
18
+ subject{ @config_class }
19
+
20
+ end
21
+
22
+ class InitTests < UnitTests
23
+ desc "when init"
24
+ setup do
25
+ @object_class = Factory.boolean ? FakeTwoRecord : TestReadModel
26
+
27
+ @config = @config_class.new(@object_class)
28
+ end
29
+ subject{ @config }
30
+
31
+ should have_readers :object_class
32
+ should have_imeths :apply_args, :set_default_args
33
+
34
+ should "know its object class" do
35
+ assert_equal @object_class, subject.object_class
36
+ end
37
+
38
+ should "know its object builder class" do
39
+ exp = MR::Factory::Config::ObjectBuilder
40
+ assert_equal exp, subject.instance_eval{ object_builder_class }
41
+ end
42
+
43
+ should "know how to apply args" do
44
+ object = @object_class.new
45
+
46
+ call_order = 0
47
+ apply_hash_called_at = nil
48
+ apply_hash_called_with = nil
49
+ Assert.stub(ObjectBuilder, :apply_hash) do |*args|
50
+ apply_hash_called_at = call_order += 1
51
+ apply_hash_called_with = args
52
+ end
53
+
54
+ apply_proc_called_at = nil
55
+ apply_proc_called_with = nil
56
+ Assert.stub(ObjectBuilder, :apply_proc) do |*args, &block|
57
+ apply_proc_called_at = call_order += 1
58
+ apply_proc_called_with = args + [block]
59
+ end
60
+
61
+ args_hash = { :name => Factory.string }
62
+ subject.apply_args(object, args_hash)
63
+
64
+ assert_equal 1, apply_hash_called_at
65
+ exp = [object, subject, args_hash]
66
+ assert_equal exp, apply_hash_called_with
67
+
68
+ assert_nil apply_proc_called_at
69
+ assert_nil apply_proc_called_with
70
+
71
+ call_order = 0
72
+ apply_hash_called_at = nil
73
+ apply_hash_called_with = nil
74
+
75
+ # should use a default args proc if one is set
76
+ default_args_proc = proc{ set :name, Factory.string }
77
+ subject.set_default_args(&default_args_proc)
78
+
79
+ subject.apply_args(object, args_hash)
80
+
81
+ assert_equal 1, apply_proc_called_at
82
+ exp = [object, subject, default_args_proc]
83
+ assert_equal exp, apply_proc_called_with
84
+
85
+ assert_equal 2, apply_hash_called_at
86
+ exp = [object, subject, args_hash]
87
+ assert_equal exp, apply_hash_called_with
88
+ end
89
+
90
+ end
91
+
92
+ class ObjectBuilderTests < UnitTests
93
+ desc "ObjectBuilder"
94
+ setup do
95
+ @object_class = [FakeTwoRecord, FakeTwoModel].sample
96
+
97
+ @object = @object_class.new
98
+ @config = @config_class.new(@object_class)
99
+
100
+ @object_builder_class = ObjectBuilder
101
+ end
102
+ subject{ @object_builder_class }
103
+
104
+ should have_imeths :apply_hash, :apply_proc
105
+
106
+ should "know how to apply a hash and proc" do
107
+ set_names_and_values = []
108
+ Assert.stub(@object_builder_class, :new).with(@object, @config) do |*args|
109
+ object_builder = Assert.stub_send(@object_builder_class, :new, @object, @config)
110
+ Assert.stub(object_builder, :set) do |key, value|
111
+ set_names_and_values << [key, value]
112
+ end
113
+ object_builder
114
+ end
115
+
116
+ hash = Factory.integer(3).times.inject({}) do |h, _|
117
+ h.merge!(Factory.string => Factory.string)
118
+ end
119
+
120
+ subject.apply_hash(@object, @config, hash)
121
+
122
+ exp = hash.map{ |(k, v)| [k, v] }.sort
123
+ assert_equal exp, set_names_and_values.sort
124
+
125
+ set_names_and_values = []
126
+
127
+ subject.apply_proc(@object, @config) do
128
+ hash.each{ |key, value| set(key, value) }
129
+ end
130
+
131
+ exp = hash.map{ |(k, v)| [k, v] }.sort
132
+ assert_equal exp, set_names_and_values.sort
133
+ end
134
+
135
+ end
136
+
137
+ class ObjectBuilderInitTests < ObjectBuilderTests
138
+ desc "when init"
139
+ setup do
140
+ @object_builder = @object_builder_class.new(@object, @config)
141
+ end
142
+ subject{ @object_builder }
143
+
144
+ should have_imeths :set
145
+
146
+ should "know how to set an attribute on its object" do
147
+ @object.name = Factory.string
148
+
149
+ value = [Factory.string, nil].sample
150
+ subject.set(:name, value)
151
+
152
+ assert_equal value, @object.name
153
+ end
154
+
155
+ end
156
+
157
+ class WithAssociationsConfigTests < Assert::Context
158
+ desc "MR::Factory::WithAssociationsConfig"
159
+ setup do
160
+ @factory_class, @build_factory_proc = if Factory.boolean
161
+ [ MR::Factory::RecordFactory,
162
+ proc{ |rc| MR::Factory::RecordFactory.new(rc) }
163
+ ]
164
+ else
165
+ [ MR::Factory::ModelFactory,
166
+ proc{ |rc| MR::Factory::ModelFactory.new(rc.model_class, rc) }
167
+ ]
168
+ end
169
+
170
+ build_factory_proc = @build_factory_proc
171
+ @config_class = Class.new do
172
+ include MR::Factory::WithAssociationsConfig
173
+ define_method(:build_factory_for_record_class) do |record_class|
174
+ build_factory_proc.call(record_class)
175
+ end
176
+ private :build_factory_for_record_class
177
+ end
178
+ end
179
+ subject{ @config_class }
180
+
181
+ should "be a factory config" do
182
+ assert_includes MR::Factory::Config, subject
183
+ end
184
+
185
+ end
186
+
187
+ class WithAssociationsConfigInitTests < WithAssociationsConfigTests
188
+ desc "when init"
189
+ setup do
190
+ @record_class = FakeTwoRecord
191
+ @config = @config_class.new(@record_class)
192
+ end
193
+ subject{ @config }
194
+
195
+ should have_imeths :record_class
196
+ should have_imeths :force_in_stack_association_names, :force_in_stack_association?
197
+ should have_imeths :default_factories, :association_factories
198
+ should have_imeths :factories_for, :factory_for, :factory_config_for
199
+ should have_imeths :record_classes_for, :build_associated_record
200
+ should have_imeths :add_association_factory
201
+
202
+ should "know its record class" do
203
+ assert_equal @record_class, subject.record_class
204
+ end
205
+
206
+ should "know its force walk association names" do
207
+ assert_equal [], subject.force_in_stack_association_names
208
+ end
209
+
210
+ should "know if it should force walk an association" do
211
+ association_name = Factory.string
212
+ assert_false subject.force_in_stack_association?(association_name)
213
+
214
+ subject.force_in_stack_association_names << association_name
215
+
216
+ assert_true subject.force_in_stack_association?(association_name)
217
+ end
218
+
219
+ should "know its object builder class" do
220
+ exp = MR::Factory::WithAssociationsConfig::ObjectBuilder
221
+ assert_equal exp, subject.instance_eval{ object_builder_class }
222
+ end
223
+
224
+ should "know its default factories" do
225
+ assert_equal({}, subject.default_factories)
226
+
227
+ factory_built_with = []
228
+ Assert.stub(@factory_class, :new) do |*args|
229
+ factory_built_with = args
230
+ Assert.stub_send(@factory_class, :new, *args)
231
+ end
232
+
233
+ factory = subject.default_factories[FakeOneRecord]
234
+ assert_instance_of @factory_class, factory
235
+ if @factory_class == MR::Factory::RecordFactory
236
+ assert_equal [FakeOneRecord], factory_built_with
237
+ else
238
+ assert_equal [FakeOneModel, FakeOneRecord], factory_built_with
239
+ end
240
+
241
+ # should cache the factories it builds
242
+ assert_equal 1, subject.default_factories.size
243
+ assert_same factory, subject.default_factories[FakeOneRecord]
244
+
245
+ # should raise a no record class error if given a `nil` record class
246
+ assert_raises(MR::Factory::NoRecordClassError) do
247
+ subject.default_factories[nil]
248
+ end
249
+ end
250
+
251
+ should "know its association factories" do
252
+ assert_equal({}, subject.association_factories)
253
+ end
254
+
255
+ should "know how to add an association factory" do
256
+ fake_one_factory = @build_factory_proc.call(FakeOneRecord)
257
+ subject.add_association_factory(:fake_one, fake_one_factory)
258
+
259
+ assert_true subject.default_factories.key?(FakeOneRecord)
260
+ assert_equal fake_one_factory, subject.default_factories[FakeOneRecord]
261
+
262
+ key = @config_class::AssociationFactoriesKey.new(:fake_one, FakeOneRecord)
263
+ assert_true subject.association_factories.key?(key)
264
+ assert_equal [fake_one_factory], subject.association_factories[key]
265
+ end
266
+
267
+ should "configure an association to be force walked when adding a factory for it" do
268
+ fake_one_factory = @build_factory_proc.call(FakeOneRecord)
269
+ subject.add_association_factory(:fake_one, fake_one_factory)
270
+
271
+ assert_not_includes :fake_one, subject.force_in_stack_association_names
272
+
273
+ subject.add_association_factory(:fake_one, fake_one_factory, :force_in_stack => true)
274
+ assert_includes :fake_one, subject.force_in_stack_association_names
275
+ end
276
+
277
+ should "not duplicate force walk associations when adding a factory for it" do
278
+ fake_one_factory = @build_factory_proc.call(FakeOneRecord)
279
+ assert_empty subject.force_in_stack_association_names
280
+
281
+ subject.add_association_factory(:fake_one, fake_one_factory, :force_in_stack => true)
282
+ assert_equal 1, subject.force_in_stack_association_names.size
283
+
284
+ subject.add_association_factory(:fake_one, fake_one_factory, :force_in_stack => true)
285
+ assert_equal 1, subject.force_in_stack_association_names.size
286
+ end
287
+
288
+ should "not change a default once its set when adding an association factory" do
289
+ fake_one_factory = @build_factory_proc.call(FakeOneRecord)
290
+ subject.add_association_factory(:fake_one, fake_one_factory)
291
+
292
+ other_fake_one_factory = @build_factory_proc.call(FakeOneRecord)
293
+ subject.add_association_factory(:fake_one, other_fake_one_factory)
294
+
295
+ default_factory = subject.default_factories[FakeOneRecord]
296
+ assert_not_equal other_fake_one_factory, default_factory
297
+ assert_equal fake_one_factory, default_factory
298
+ end
299
+
300
+ should "store all factories added for an association" do
301
+ fake_one_factory = @build_factory_proc.call(FakeOneRecord)
302
+ subject.add_association_factory(:fake_one, fake_one_factory)
303
+
304
+ other_fake_one_factory = @build_factory_proc.call(FakeOneRecord)
305
+ subject.add_association_factory(:fake_one, other_fake_one_factory)
306
+
307
+ key = @config_class::AssociationFactoriesKey.new(:fake_one, FakeOneRecord)
308
+ assert_equal 2, subject.association_factories[key].size
309
+ assert_includes fake_one_factory, subject.association_factories[key]
310
+ assert_includes other_fake_one_factory, subject.association_factories[key]
311
+ end
312
+
313
+ should "know how to add a factory for a polymorphic association" do
314
+ fake_one_factory = @build_factory_proc.call(FakeOneRecord)
315
+ subject.add_association_factory(:fake_poly, fake_one_factory)
316
+
317
+ assert_true subject.default_factories.key?(FakeOneRecord)
318
+ assert_equal fake_one_factory, subject.default_factories[FakeOneRecord]
319
+
320
+ # should add a `nil` record class association factory key
321
+ key = @config_class::AssociationFactoriesKey.new(:fake_poly)
322
+ assert_true subject.association_factories.key?(key)
323
+ assert_equal [fake_one_factory], subject.association_factories[key]
324
+
325
+ key = @config_class::AssociationFactoriesKey.new(:fake_poly, FakeOneRecord)
326
+ assert_true subject.association_factories.key?(key)
327
+ assert_equal [fake_one_factory], subject.association_factories[key]
328
+ end
329
+
330
+ should "error if adding a factory for an unknown association" do
331
+ factory = @build_factory_proc.call(FakeOneRecord)
332
+
333
+ assert_raises(MR::Factory::NoAssociationError) do
334
+ subject.add_association_factory(Factory.string, factory)
335
+ end
336
+ end
337
+
338
+ should "know how to get factories for an association and record class" do
339
+ association_name = Factory.boolean ? :fake_one : :fake_poly
340
+
341
+ factory = @build_factory_proc.call(FakeOneRecord)
342
+ subject.add_association_factory(association_name, factory)
343
+
344
+ assert_equal [factory], subject.factories_for(association_name, FakeOneRecord)
345
+
346
+ other_factory = @build_factory_proc.call(FakeOneRecord)
347
+ subject.add_association_factory(association_name, other_factory)
348
+
349
+ factories = subject.factories_for(association_name, FakeOneRecord)
350
+
351
+ assert_equal 2, factories.size
352
+ assert_includes factory, factories
353
+ assert_includes other_factory, factories
354
+ end
355
+
356
+ should "return a default factory for an association if one isn't configured" do
357
+ association_name = Factory.boolean ? :fake_one : :fake_poly
358
+
359
+ exp = [subject.default_factories[FakeOneRecord]]
360
+ assert_equal exp, subject.factories_for(association_name, FakeOneRecord)
361
+ end
362
+
363
+ should "know how to get a factory for an association and record class" do
364
+ association_name = Factory.boolean ? :fake_one : :fake_poly
365
+
366
+ factories = Factory.integer(3).times.map do
367
+ @build_factory_proc.call(FakeOneRecord)
368
+ end
369
+ Assert.stub(subject, :factories_for).with(
370
+ association_name,
371
+ FakeOneRecord
372
+ ){ factories }
373
+
374
+ factory = factories.sample
375
+ Assert.stub(factories, :sample){ factory }
376
+
377
+ assert_same factory, subject.factory_for(association_name, FakeOneRecord)
378
+ end
379
+
380
+ should "know how to get record classes for an association" do
381
+ association_name = Factory.boolean ? :fake_one : :fake_poly
382
+
383
+ factories = [
384
+ @build_factory_proc.call(FakeOneRecord),
385
+ @build_factory_proc.call(FakeThreeRecord)
386
+ ]
387
+ Assert.stub(subject, :factories_for).with(association_name, nil){ factories }
388
+
389
+ exp = factories.map(&:record_class)
390
+ assert_equal exp, subject.record_classes_for(association_name)
391
+ end
392
+
393
+ end
394
+
395
+ class WithAssociationsConfigObjectBuilderTests < WithAssociationsConfigTests
396
+ desc "ObjectBuilder"
397
+ setup do
398
+ @object_builder_class = MR::Factory::WithAssociationsConfig::ObjectBuilder
399
+ end
400
+ subject{ @object_builder_class }
401
+
402
+ should "be a factory config object builder" do
403
+ assert subject < MR::Factory::Config::ObjectBuilder
404
+ end
405
+
406
+ end
407
+
408
+ class RecordObjectBuilderInitTests < WithAssociationsConfigObjectBuilderTests
409
+ desc "when init with a record"
410
+ setup do
411
+ @config_class.class_eval do
412
+ define_method(:ar_association_for) do |record, name|
413
+ if (reflection = record.class.reflect_on_association(name))
414
+ record.association(reflection.name)
415
+ end
416
+ end
417
+ define_method(:build_factory_for_record_class) do |record_class|
418
+ MR::Factory::RecordFactory.new(record_class)
419
+ end
420
+ end
421
+
422
+ @record_class = FakeTwoRecord
423
+ @record = @record_class.new
424
+ @config = @config_class.new(@record_class)
425
+ @object_builder = @object_builder_class.new(@record, @config)
426
+ end
427
+ subject{ @object_builder }
428
+
429
+ should "know how to set an association on its record" do
430
+ @record.fake_one = FakeOneRecord.new
431
+
432
+ value = [FakeOneRecord.new, nil].sample
433
+ subject.set(:fake_one, value)
434
+
435
+ assert_equal value, @record.fake_one
436
+
437
+ @record.fake_poly = FakeOneRecord.new
438
+
439
+ value = [FakeOneRecord.new, nil].sample
440
+ subject.set(:fake_poly, value)
441
+
442
+ assert_equal value, @record.fake_poly
443
+ end
444
+
445
+ should "know how to set an association when given a hash" do
446
+ associated_record_class = FakeOneRecord
447
+ association_name = Factory.boolean ? :fake_one : :fake_poly
448
+ associated_factory = MR::Factory::RecordFactory.new(associated_record_class)
449
+ if Factory.boolean
450
+ @config.add_association_factory(association_name, associated_factory)
451
+ else
452
+ @config.default_factories[associated_record_class] = associated_factory
453
+ end
454
+
455
+ apply_hash_called_with = nil
456
+ Assert.stub(@object_builder_class, :apply_hash) do |*args|
457
+ apply_hash_called_with = args
458
+ Assert.stub_send(@object_builder_class, :apply_hash, *args)
459
+ end
460
+
461
+ # when the association is already set
462
+ associated_record = associated_factory.record
463
+ @record.send("#{association_name}=", associated_record)
464
+
465
+ association_args = { :name => Factory.string }
466
+ subject.set(association_name, association_args)
467
+
468
+ assert_equal associated_record, @record.send(association_name)
469
+ assert_equal association_args[:name], associated_record.name
470
+
471
+ exp = [associated_record, associated_factory.config, association_args]
472
+ assert_equal exp, apply_hash_called_with
473
+
474
+ # when the association isn't already set
475
+ @record.send("#{association_name}=", nil)
476
+ if association_name == :fake_poly
477
+ # set the fake poly type attribute so it can find a factory for it
478
+ @record.fake_poly_type = associated_record_class.to_s
479
+ end
480
+
481
+ associated_record = associated_factory.record
482
+ Assert.stub(associated_factory, :instance){ associated_record }
483
+
484
+ association_args = { :name => Factory.string }
485
+ subject.set(association_name, association_args)
486
+
487
+ assert_equal associated_record, @record.send(association_name)
488
+ assert_equal association_args[:name], associated_record.name
489
+
490
+ exp = [associated_record, associated_factory.config, association_args]
491
+ assert_equal exp, apply_hash_called_with
492
+ end
493
+
494
+ should "raise a record class error if it can't build an association" do
495
+ assert_raises(MR::Factory::NoRecordClassError) do
496
+ subject.set(:fake_poly, {})
497
+ end
498
+ end
499
+
500
+ end
501
+
502
+ class ModelObjectBuilderInitTests < WithAssociationsConfigObjectBuilderTests
503
+ desc "when init with a model"
504
+ setup do
505
+ @config_class.class_eval do
506
+ define_method(:ar_association_for) do |model, name|
507
+ if (reflection = model.record_class.reflect_on_association(name))
508
+ model.record.association(reflection.name)
509
+ end
510
+ end
511
+ define_method(:build_factory_for_record_class) do |record_class|
512
+ MR::Factory::ModelFactory.new(record_class.model_class, record_class)
513
+ end
514
+ end
515
+
516
+ @model_class = FakeTwoModel
517
+ @model = @model_class.new
518
+ @config = @config_class.new(@model_class.record_class)
519
+ @object_builder = @object_builder_class.new(@model, @config)
520
+ end
521
+ subject{ @object_builder }
522
+
523
+ should "know how to set an association on its model" do
524
+ @model.fake_one = FakeOneModel.new
525
+
526
+ value = [FakeOneModel.new, nil].sample
527
+ subject.set(:fake_one, value)
528
+
529
+ assert_equal value, @model.fake_one
530
+
531
+ @model.fake_poly = FakeOneModel.new
532
+
533
+ value = [FakeOneModel.new, nil].sample
534
+ subject.set(:fake_poly, value)
535
+
536
+ assert_equal value, @model.fake_poly
537
+ end
538
+
539
+ should "know how to set an association when given a hash" do
540
+ associated_model_class = FakeOneModel
541
+ association_name = Factory.boolean ? :fake_one : :fake_poly
542
+ associated_factory = MR::Factory::ModelFactory.new(
543
+ associated_model_class,
544
+ associated_model_class.record_class
545
+ )
546
+ if Factory.boolean
547
+ @config.add_association_factory(association_name, associated_factory)
548
+ else
549
+ record_class = associated_model_class.record_class
550
+ @config.default_factories[record_class] = associated_factory
551
+ end
552
+
553
+ apply_hash_called_with = nil
554
+ Assert.stub(@object_builder_class, :apply_hash) do |*args|
555
+ apply_hash_called_with = args
556
+ Assert.stub_send(@object_builder_class, :apply_hash, *args)
557
+ end
558
+
559
+ # when the association is already set
560
+ associated_model = associated_factory.model
561
+ @model.send("#{association_name}=", associated_model)
562
+
563
+ association_args = { :name => Factory.string }
564
+ subject.set(association_name, association_args)
565
+
566
+ assert_equal associated_model, @model.send(association_name)
567
+ assert_equal association_args[:name], associated_model.name
568
+
569
+ exp = [associated_model, associated_factory.config, association_args]
570
+ assert_equal exp, apply_hash_called_with
571
+
572
+ # when the association isn't already set
573
+ @model.send("#{association_name}=", nil)
574
+ if association_name == :fake_poly
575
+ # set the fake poly type attribute so it can find a factory for it
576
+ @model.fake_poly_type = associated_model_class.record_class.to_s
577
+ end
578
+
579
+ associated_model = associated_factory.model
580
+ Assert.stub(associated_factory, :instance){ associated_model }
581
+
582
+ association_args = { :name => Factory.string }
583
+ subject.set(association_name, association_args)
584
+
585
+ assert_equal associated_model, @model.send(association_name)
586
+ assert_equal association_args[:name], associated_model.name
587
+
588
+ exp = [associated_model, associated_factory.config, association_args]
589
+ assert_equal exp, apply_hash_called_with
590
+ end
591
+
592
+ should "raise a record class error if it can't build an association" do
593
+ assert_raises(MR::Factory::NoRecordClassError) do
594
+ subject.set(:fake_poly, {})
595
+ end
596
+ end
597
+
598
+ end
599
+
600
+ class FakeOneRecord
601
+ include MR::FakeRecord
602
+
603
+ attribute :name, :string
604
+ end
605
+
606
+ class FakeTwoRecord
607
+ include MR::FakeRecord
608
+
609
+ attribute :name, :string
610
+ attribute :fake_poly_type, :string
611
+ attribute :fake_poly_id, :integer
612
+ attribute :fake_one_id, :integer
613
+
614
+ belongs_to :fake_poly, :polymorphic => true
615
+ belongs_to :fake_one, :class_name => FakeOneRecord.to_s
616
+ end
617
+
618
+ class FakeThreeRecord
619
+ include MR::FakeRecord
620
+
621
+ attribute :fake_one_id, :integer
622
+ attribute :fake_two_id, :integer
623
+
624
+ belongs_to :fake_one, :class_name => FakeOneRecord.to_s
625
+ belongs_to :fake_two, :class_name => FakeTwoRecord.to_s
626
+ end
627
+
628
+ class FakeOneModel
629
+ include MR::Model
630
+ record_class FakeOneRecord
631
+
632
+ field_accessor :name
633
+ end
634
+
635
+ class FakeTwoModel
636
+ include MR::Model
637
+ record_class FakeTwoRecord
638
+
639
+ field_accessor :name, :fake_poly_type, :fake_poly_id, :fake_one_id
640
+
641
+ polymorphic_belongs_to :fake_poly
642
+ belongs_to :fake_one
643
+ end
644
+
645
+ class TestReadModel
646
+ include MR::ReadModel
647
+
648
+ field :name, :string
649
+ end
650
+
651
+ end