mr 0.35.2

Sign up to get free protection for your applications and to get access to all the features.
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