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,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