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,45 @@
1
+ require 'assert'
2
+ require 'mr/record'
3
+
4
+ require 'much-plugin'
5
+
6
+ module MR::Record
7
+
8
+ class UnitTests < Assert::Context
9
+ desc "MR::Record"
10
+ setup do
11
+ @record_class = Class.new do
12
+ include MR::Record
13
+ self.model_class = FakeTestModel
14
+ end
15
+ end
16
+ subject{ @record_class }
17
+
18
+ should have_accessors :model_class
19
+
20
+ should "use much-plugin" do
21
+ assert_includes MuchPlugin, MR::Record
22
+ end
23
+
24
+ end
25
+
26
+ class InstanceTests < UnitTests
27
+ desc "instance"
28
+ setup do
29
+ @record = @record_class.new
30
+ end
31
+ subject{ @record }
32
+
33
+ should have_accessors :model
34
+
35
+ should "build a model if one hasn't been set" do
36
+ assert_instance_of FakeTestModel, subject.model
37
+ end
38
+
39
+ end
40
+
41
+ class FakeTestModel
42
+ include MR::Model
43
+ end
44
+
45
+ end
@@ -0,0 +1,431 @@
1
+ require 'assert'
2
+ require 'mr/test_helpers'
3
+
4
+ require 'mr/factory'
5
+ require 'mr/model'
6
+
7
+ module MR::TestHelpers
8
+
9
+ class UnitTests < Assert::Context
10
+ desc "MR::TestHelpers"
11
+ subject{ MR::TestHelpers }
12
+
13
+ should have_imeths :model_reset_save_called
14
+ should have_imeths :assert_association_saved, :assert_not_association_saved
15
+ should have_imeths :assert_model_destroyed, :assert_not_model_destroyed
16
+ should have_imeths :assert_model_saved, :assert_not_model_saved
17
+ should have_imeths :assert_field_saved, :assert_not_field_saved
18
+
19
+ end
20
+
21
+ class WithModelTests < UnitTests
22
+ setup do
23
+ @associated_record = FakeTestRecord.new
24
+ @associated_model = FakeTestModel.new(@associated_record).tap(&:save)
25
+ @model = FakeTestModel.new({
26
+ :name => 'Test',
27
+ :area => @associated_model,
28
+ :parent => @associated_model
29
+ })
30
+ end
31
+ end
32
+
33
+ class TestingActualModelTests < WithModelTests
34
+ include MR::TestHelpers
35
+
36
+ desc "with an actual model"
37
+ subject{ @model }
38
+
39
+ should "be able to test if an association was saved or not" do
40
+ assert_not_model_saved subject
41
+ assert_not_association_saved subject, :parent, @associated_model
42
+ @model.save
43
+ assert_model_saved subject
44
+ assert_association_saved subject, :parent, @associated_model
45
+ @other_model = FakeTestModel.new.tap(&:save)
46
+ @model.parent = @other_model
47
+ @model.save
48
+ assert_association_saved subject, :parent, @other_model
49
+ end
50
+
51
+ should "be able to test if an polymorphic association was saved when " \
52
+ "the model `record_class` doesn't match it's actual record's class" do
53
+ associated_record = OtherFakeTestRecord.new
54
+ associated_model = FakeTestModel.new(associated_record).tap(&:save)
55
+ @model.parent = associated_model
56
+ @model.save
57
+ assert_model_saved subject
58
+ assert_association_saved subject, :parent, associated_model
59
+ end
60
+
61
+ should "be able to test if a field was saved or not" do
62
+ assert_not_model_saved subject
63
+ assert_not_field_saved subject, :name, 'Test'
64
+ @model.save
65
+ assert_model_saved subject
66
+ assert_field_saved subject, :name, 'Test'
67
+ @model.name = 'Joe'
68
+ @model.save
69
+ assert_field_saved subject, :name, 'Joe'
70
+ end
71
+
72
+ should "be able to test if a model was destroyed or not" do
73
+ assert_not_model_destroyed subject
74
+ @model.save
75
+ assert_not_model_destroyed subject
76
+ @model.destroy
77
+ assert_model_destroyed subject
78
+ end
79
+
80
+ should "reset a fake model's `save_called` state using `model_reset_save_called`" do
81
+ @model.save
82
+ model_reset_save_called @model
83
+ assert_not_model_saved @model
84
+ end
85
+
86
+ should "yield the model passed to it before resetting using `model_reset_save_called`" do
87
+ yielded = nil
88
+ model_reset_save_called(@model) do |m|
89
+ yielded = m
90
+ m.save
91
+ end
92
+ assert_equal @model, yielded
93
+ assert_not_model_saved @model
94
+ end
95
+
96
+ should "raise an ArgumentError when passed a model not using a fake record" do
97
+ record_class = Class.new{ include MR::Record }
98
+ model = FakeTestModel.new(record_class.new)
99
+ assert_raises(ArgumentError){ model_reset_save_called(model) }
100
+ end
101
+
102
+ end
103
+
104
+ class WithAssertContextSpyTests < WithModelTests
105
+ setup do
106
+ @model.save
107
+ @assert_context_spy = AssertContextSpy.new
108
+ end
109
+ end
110
+
111
+ class AssociationSavedAssertionBaseTests < WithAssertContextSpyTests
112
+ desc "AssociationSavedAssertionBase"
113
+
114
+ should "raise an ArgumentError when given a non belongs to association" do
115
+ assert_raises(ArgumentError) do
116
+ AssociationSavedAssertionBase.new(@model, :comments)
117
+ end
118
+ end
119
+
120
+ end
121
+
122
+ class AssociationSavedAssertionTests < WithAssertContextSpyTests
123
+ desc "AssociationSavedAssertion"
124
+ setup do
125
+ @assertion = AssociationSavedAssertion.new(
126
+ @model,
127
+ :area,
128
+ @associated_model
129
+ )
130
+ end
131
+ subject{ @assertion }
132
+
133
+ should have_imeths :run
134
+
135
+ should "assert that the association's foreign key was saved as " \
136
+ "the expected value when run" do
137
+ subject.run(@assert_context_spy)
138
+ assert_equal 1, @assert_context_spy.results.size
139
+ assert_equal [ true ], @assert_context_spy.results.map(&:value)
140
+ descriptions = @assert_context_spy.results.map(&:desc)
141
+ expected = "Expected \"area_id\" field was saved " \
142
+ "as #{@associated_model.id}."
143
+ assert_includes expected, descriptions
144
+ end
145
+
146
+ end
147
+
148
+ class AssociationSavedAssertionPolyTests < AssociationSavedAssertionTests
149
+ desc "run for a polymorphic belongs to"
150
+ setup do
151
+ @assertion = AssociationSavedAssertion.new(
152
+ @model,
153
+ :parent,
154
+ @associated_model
155
+ )
156
+ @assertion.run(@assert_context_spy)
157
+ end
158
+ subject{ @assert_context_spy.results }
159
+
160
+ should "have asserted that the association's foreign type and key " \
161
+ "were saved as the expected value" do
162
+ assert_equal 2, subject.size
163
+ assert_equal [ true, true ], subject.map(&:value)
164
+ descriptions = @assert_context_spy.results.map(&:desc)
165
+ expected = "Expected \"parent_type\" field was saved " \
166
+ "as #{@associated_record.class.name.inspect}."
167
+ assert_includes expected, descriptions
168
+ expected = "Expected \"parent_id\" field was saved " \
169
+ "as #{@associated_model.id}."
170
+ assert_includes expected, descriptions
171
+ end
172
+
173
+ end
174
+
175
+ class AssociationNotSavedAssertionTests < WithAssertContextSpyTests
176
+ desc "AssociationNotSavedAssertion"
177
+ setup do
178
+ @assertion = AssociationNotSavedAssertion.new(
179
+ @model,
180
+ :area,
181
+ @associated_model
182
+ )
183
+ end
184
+ subject{ @assertion }
185
+
186
+ should have_imeths :run
187
+
188
+ should "assert that the association's foreign key was not saved " \
189
+ "as the expected value when run" do
190
+ subject.run(@assert_context_spy)
191
+ assert_equal 1, @assert_context_spy.results.size
192
+ assert_equal [ false ], @assert_context_spy.results.map(&:value)
193
+ descriptions = @assert_context_spy.results.map(&:desc)
194
+ expected = "Expected \"area_id\" field was not saved " \
195
+ "as #{@associated_model.id}."
196
+ assert_includes expected, descriptions
197
+ end
198
+
199
+ end
200
+
201
+ class AssociationNotSavedAssertionPolyTests < AssociationNotSavedAssertionTests
202
+ desc "is run for a polymorphic belongs to"
203
+ setup do
204
+ @assertion = AssociationNotSavedAssertion.new(
205
+ @model,
206
+ :parent,
207
+ @associated_model
208
+ )
209
+ @assertion.run(@assert_context_spy)
210
+ end
211
+ subject{ @assert_context_spy.results }
212
+
213
+ should "have asserted that the association's foreign type was not saved " \
214
+ "as the expected value" do
215
+ assert_equal 2, subject.size
216
+ assert_equal [ false, false ], subject.map(&:value)
217
+ descriptions = @assert_context_spy.results.map(&:desc)
218
+ expected = "Expected \"parent_type\" field was not saved " \
219
+ "as #{@associated_record.class.name.inspect}."
220
+ assert_includes expected, descriptions
221
+ expected = "Expected \"parent_id\" field was not saved " \
222
+ "as #{@associated_model.id}."
223
+ assert_includes expected, descriptions
224
+ end
225
+
226
+ end
227
+
228
+ class FieldSavedAssertionBaseTests < WithAssertContextSpyTests
229
+ desc "FieldSavedAssertionBase"
230
+ setup do
231
+ @assertion = FieldSavedAssertionBase.new(@model, :name, 'Test')
232
+ end
233
+ subject{ @assertion }
234
+
235
+ should "raise an ArgumentError with a model not using a fake record" do
236
+ record_class = Class.new{ include MR::Record }
237
+ model = FakeTestModel.new(record_class.new)
238
+ assert_raises(ArgumentError){ FieldSavedAssertionBase.new(model, :name) }
239
+ end
240
+
241
+ end
242
+
243
+ class FieldSavedAssertionTests < WithAssertContextSpyTests
244
+ desc "FieldSavedAssertion"
245
+ setup do
246
+ @assertion = FieldSavedAssertion.new(@model, :name, 'Test')
247
+ end
248
+ subject{ @assertion }
249
+
250
+ should have_imeths :run
251
+
252
+ end
253
+
254
+ class FieldSavedAssertionSavedTests < FieldSavedAssertionTests
255
+ desc "when run for a field on a saved model"
256
+ setup do
257
+ @assertion = FieldSavedAssertion.new(@model, :name, 'Test')
258
+ @assertion.run(@assert_context_spy)
259
+ @results = @assert_context_spy.results
260
+ end
261
+
262
+ should "assert that the field was saved as the expected value when run" do
263
+ assert_equal 1, @results.size
264
+ assert_equal [ true ], @results.map(&:value)
265
+ expected = "Expected \"name\" field was saved as \"Test\"."
266
+ assert_includes expected, @results.map(&:desc)
267
+ end
268
+
269
+ end
270
+
271
+ class FieldSavedAssertionUnsavedTests < FieldSavedAssertionTests
272
+ desc "when run for a field on an unsaved model"
273
+ setup do
274
+ # this ensures that this test doesn't pass, a `nil` expected value would
275
+ # pass if the assertion class only used `assert_equal`
276
+ @assertion = FieldSavedAssertion.new(FakeTestModel.new, :name, nil)
277
+ @assertion.run(@assert_context_spy)
278
+ @results = @assert_context_spy.results
279
+ end
280
+
281
+ should "assert that the field was saved when run" do
282
+ assert_equal 1, @results.size
283
+ assert_equal [ false ], @results.map(&:value)
284
+ expected = "Expected \"name\" field was saved."
285
+ assert_includes expected, @results.map(&:desc)
286
+ end
287
+
288
+ end
289
+
290
+ class FieldNotSavedAssertionTests < WithAssertContextSpyTests
291
+ desc "FieldNotSavedAssertion"
292
+ setup do
293
+ @assertion = FieldNotSavedAssertion.new(@model, :other, 'Test')
294
+ end
295
+ subject{ @assertion }
296
+
297
+ should have_imeths :run
298
+
299
+ end
300
+
301
+ class FieldNotSavedAssertionSavedTests < FieldNotSavedAssertionTests
302
+ desc "when run for a field on a saved model"
303
+ setup do
304
+ @assertion = FieldNotSavedAssertion.new(@model, :name, 'Test')
305
+ @assertion.run(@assert_context_spy)
306
+ @results = @assert_context_spy.results
307
+ end
308
+
309
+ should "assert that the field was not saved as the expected value when run" do
310
+ assert_equal 1, @results.size
311
+ assert_equal [ false ], @results.map(&:value)
312
+ expected = "Expected \"name\" field was not saved as \"Test\"."
313
+ assert_includes expected, @results.map(&:desc)
314
+ end
315
+
316
+ end
317
+
318
+ class FieldNotSavedAssertionUnsavedTests < FieldNotSavedAssertionTests
319
+ desc "when run for a field on an unsaved model"
320
+ setup do
321
+ # this ensures that this test does pass, a non `nil` expected value would
322
+ # fail if the assertion class only used `assert_not_equal`
323
+ @assertion = FieldNotSavedAssertion.new(FakeTestModel.new, :name, 'Test')
324
+ @assertion.run(@assert_context_spy)
325
+ @results = @assert_context_spy.results
326
+ end
327
+
328
+ should "assert that the field was not saved when run" do
329
+ assert_equal 1, @results.size
330
+ assert_equal [ true ], @results.map(&:value)
331
+ expected = "Expected \"name\" field was not saved."
332
+ assert_includes expected, @results.map(&:desc)
333
+ end
334
+
335
+ end
336
+
337
+ class ModelDestroyedAssertionTests < WithAssertContextSpyTests
338
+ desc "ModelDestroyedAssertion"
339
+ setup do
340
+ @model.destroy
341
+ @assertion = ModelDestroyedAssertion.new(@model)
342
+ end
343
+ subject{ @assertion }
344
+
345
+ should have_imeths :run
346
+
347
+ should "assert that the model was destroyed using `run`" do
348
+ @assertion.run(@assert_context_spy)
349
+ result = @assert_context_spy.results.last
350
+ assert_true result.value
351
+ assert_equal "Expected #{@model.inspect} was destroyed.", result.block.call
352
+ end
353
+
354
+ end
355
+
356
+ class ModelNotDestroyedAssertionTests < WithAssertContextSpyTests
357
+ desc "ModelNotDestroyedAssertion"
358
+ setup do
359
+ @assertion = ModelNotDestroyedAssertion.new(@model)
360
+ end
361
+ subject{ @assertion }
362
+
363
+ should have_imeths :run
364
+
365
+ should "assert that the model was not destroyed using `run`" do
366
+ @assertion.run(@assert_context_spy)
367
+ result = @assert_context_spy.results.last
368
+ assert_true result.value
369
+ assert_equal "Expected #{@model.inspect} was not destroyed.", result.block.call
370
+ end
371
+
372
+ end
373
+
374
+ class AssertContextSpy
375
+ attr_reader :results
376
+
377
+ def initialize
378
+ @results = []
379
+ end
380
+
381
+ def assert_true(actual, desc = nil, &block)
382
+ self.assert_equal(true, actual, desc, &block)
383
+ end
384
+
385
+ def assert_false(actual, desc = nil, &block)
386
+ self.assert_equal(false, actual, desc, &block)
387
+ end
388
+
389
+ def assert_equal(expected, actual, desc = nil, &block)
390
+ self.assert(expected == actual, desc, &block)
391
+ end
392
+
393
+ def assert_not_equal(expected, actual, desc = nil, &block)
394
+ self.assert(expected != actual, desc)
395
+ end
396
+
397
+ def assert(value, desc = nil, &block)
398
+ @results << Result.new(value, desc, block)
399
+ end
400
+
401
+ class Result < Struct.new(:value, :desc, :block)
402
+ def what_failed; (block || proc{ }).call; end
403
+ end
404
+ end
405
+
406
+ class FakeTestRecord
407
+ include MR::FakeRecord
408
+ attribute :name, :string
409
+ attribute :active, :boolean
410
+ attribute :area_id, :integer
411
+ attribute :parent_type, :string
412
+ attribute :parent_id, :integer
413
+ belongs_to :parent, :polymorphic => true
414
+ belongs_to :area, :class_name => self.to_s
415
+ has_many :comments, :class_name => self.to_s
416
+ end
417
+
418
+ class OtherFakeTestRecord
419
+ include MR::FakeRecord
420
+ end
421
+
422
+ class FakeTestModel
423
+ include MR::Model
424
+ record_class FakeTestRecord
425
+ field_accessor :id, :name, :active, :parent_id, :parent_type
426
+ polymorphic_belongs_to :parent
427
+ belongs_to :area
428
+ has_many :comments
429
+ end
430
+
431
+ end