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,214 @@
1
+ require 'much-plugin'
2
+ require 'mr/read_model/query_expression'
3
+ require 'mr/record'
4
+ require 'mr/query'
5
+
6
+ module MR::ReadModel
7
+
8
+ module Querying
9
+ include MuchPlugin
10
+
11
+ plugin_included do
12
+ extend ClassMethods
13
+ end
14
+
15
+ module ClassMethods
16
+
17
+ def relation
18
+ @relation ||= Relation.new
19
+ end
20
+
21
+ def record_class
22
+ self.relation.from_record_class
23
+ end
24
+
25
+ def find(id, params = nil)
26
+ self.new(self.relation.build_for_find(id, params || {}).first!)
27
+ end
28
+
29
+ def query(params = nil)
30
+ MR::Query.new(self, self.relation.build_for_all(params || {}))
31
+ end
32
+
33
+ def count(*args)
34
+ self.query(*args).count
35
+ end
36
+
37
+ def build_sql(params = nil)
38
+ self.relation.build_sql(params)
39
+ end
40
+
41
+ def find_attr(column = nil)
42
+ self.relation.find_attr = column if !column.nil?
43
+ self.relation.find_attr
44
+ end
45
+
46
+ def select(*args, &block)
47
+ add_query_expression(:select, *args, &block)
48
+ rescue InvalidQueryExpressionError, ArgumentError => exception
49
+ raise ArgumentError, exception.message, caller
50
+ end
51
+
52
+ def from(record_class)
53
+ relation.from(record_class)
54
+ rescue ArgumentError => exception
55
+ raise ArgumentError, exception.message, caller
56
+ end
57
+
58
+ def from_subquery(&block)
59
+ relation.from_subquery(&block)
60
+ rescue ArgumentError => exception
61
+ raise ArgumentError, exception.message, caller
62
+ end
63
+
64
+ def joins(*args, &block)
65
+ add_query_expression(:joins, *args, &block)
66
+ rescue InvalidQueryExpressionError, ArgumentError => exception
67
+ raise ArgumentError, exception.message, caller
68
+ end
69
+
70
+ def inner_join_subquery(&block)
71
+ add_subquery_expression(:joins, :inner, &block)
72
+ rescue InvalidQueryExpressionError, ArgumentError => exception
73
+ raise ArgumentError, exception.message, caller
74
+ end
75
+
76
+ def left_outer_join_subquery(&block)
77
+ add_subquery_expression(:joins, :left, &block)
78
+ rescue InvalidQueryExpressionError, ArgumentError => exception
79
+ raise ArgumentError, exception.message, caller
80
+ end
81
+ alias :left_join_subquery :left_outer_join_subquery
82
+
83
+ def right_outer_join_subquery(&block)
84
+ add_subquery_expression(:joins, :right, &block)
85
+ rescue InvalidQueryExpressionError, ArgumentError => exception
86
+ raise ArgumentError, exception.message, caller
87
+ end
88
+ alias :right_join_subquery :right_outer_join_subquery
89
+
90
+ def full_outer_join_subquery(&block)
91
+ add_subquery_expression(:joins, :full, &block)
92
+ rescue InvalidQueryExpressionError, ArgumentError => exception
93
+ raise ArgumentError, exception.message, caller
94
+ end
95
+ alias :full_join_subquery :full_outer_join_subquery
96
+
97
+ def where(*args, &block)
98
+ add_merge_query_expression(:where, *args, &block)
99
+ rescue InvalidQueryExpressionError, ArgumentError => exception
100
+ raise ArgumentError, exception.message, caller
101
+ end
102
+
103
+ def order(*args, &block)
104
+ add_merge_query_expression(:order, *args, &block)
105
+ rescue InvalidQueryExpressionError, ArgumentError => exception
106
+ raise ArgumentError, exception.message, caller
107
+ end
108
+
109
+ def group(*args, &block)
110
+ add_query_expression(:group, *args, &block)
111
+ rescue InvalidQueryExpressionError, ArgumentError => exception
112
+ raise ArgumentError, exception.message, caller
113
+ end
114
+
115
+ def having(*args, &block)
116
+ add_query_expression(:having, *args, &block)
117
+ rescue InvalidQueryExpressionError, ArgumentError => exception
118
+ raise ArgumentError, exception.message, caller
119
+ end
120
+
121
+ def limit(*args, &block)
122
+ add_query_expression(:limit, *args, &block)
123
+ rescue InvalidQueryExpressionError, ArgumentError => exception
124
+ raise ArgumentError, exception.message, caller
125
+ end
126
+
127
+ def offset(*args, &block)
128
+ add_query_expression(:offset, *args, &block)
129
+ rescue InvalidQueryExpressionError, ArgumentError => exception
130
+ raise ArgumentError, exception.message, caller
131
+ end
132
+
133
+ def merge(*args, &block)
134
+ add_merge_query_expression(:merge, *args, &block)
135
+ rescue InvalidQueryExpressionError, ArgumentError => exception
136
+ raise ArgumentError, exception.message, caller
137
+ end
138
+
139
+ private
140
+
141
+ def add_query_expression(type, *args, &block)
142
+ QueryExpression.new(type, *args, &block).tap do |expression|
143
+ relation.query_expressions << expression
144
+ end
145
+ end
146
+
147
+ def add_merge_query_expression(type, *args, &block)
148
+ MergeQueryExpression.new(type, *args, &block).tap do |expression|
149
+ relation.query_expressions << expression
150
+ end
151
+ end
152
+
153
+ def add_subquery_expression(type, *args, &block)
154
+ SubqueryExpression.new(type, *args, &block).tap do |expression|
155
+ relation.query_expressions << expression
156
+ end
157
+ end
158
+
159
+ end
160
+
161
+ end
162
+
163
+ class Relation
164
+ attr_reader :from_expression, :query_expressions, :set_expressions
165
+ attr_writer :find_attr
166
+
167
+ def initialize
168
+ @from_expression = NullFromExpression.new
169
+ @query_expressions = []
170
+ @set_expressions = []
171
+ end
172
+
173
+ def from(record_class)
174
+ @from_expression = FromExpression.new(record_class)
175
+ end
176
+
177
+ def from_subquery(&block)
178
+ @from_expression = FromSubqueryExpression.new(&block)
179
+ end
180
+
181
+ def from_record_class
182
+ self.from_expression.record_class
183
+ end
184
+
185
+ def find_attr
186
+ @find_attr ||= self.from_expression.default_find_attr
187
+ end
188
+
189
+ FIND_EXCLUDED_TYPES = [:where, :limit, :offset].freeze
190
+ def build_for_find(id, params = nil)
191
+ query_expressions = self.query_expressions.reject do |e|
192
+ FIND_EXCLUDED_TYPES.include?(e.type)
193
+ end
194
+ ar_relation = build_ar_relation_for_all(query_expressions, params)
195
+ ar_relation.where(self.find_attr => id).limit(1)
196
+ end
197
+
198
+ def build_for_all(params = nil)
199
+ build_ar_relation_for_all(self.query_expressions, params)
200
+ end
201
+
202
+ def build_sql(params = nil)
203
+ self.build_for_all(params).to_sql.strip
204
+ end
205
+
206
+ private
207
+
208
+ def build_ar_relation_for_all(query_expressions, params)
209
+ ar_relation = self.from_expression.ar_relation(params)
210
+ query_expressions.inject(ar_relation){ |r, e| e.apply_to(r, params) }
211
+ end
212
+ end
213
+
214
+ end
@@ -0,0 +1,82 @@
1
+ require 'much-plugin'
2
+ require 'mr/read_model/querying'
3
+
4
+ module MR::ReadModel
5
+
6
+ module SetQuerying
7
+ include MuchPlugin
8
+
9
+ plugin_included do
10
+ include MR::ReadModel::Querying
11
+ extend ClassMethods
12
+ end
13
+
14
+ module ClassMethods
15
+
16
+ def relation
17
+ @relation ||= Relation.new
18
+ end
19
+
20
+ def union(&block)
21
+ add_set_expression(:union, &block)
22
+ rescue ArgumentError => exception
23
+ raise ArgumentError, exception.message, caller
24
+ end
25
+
26
+ def union_all(&block)
27
+ add_set_expression(:union_all, &block)
28
+ rescue ArgumentError => exception
29
+ raise ArgumentError, exception.message, caller
30
+ end
31
+
32
+ def intersect(&block)
33
+ add_set_expression(:intersect, &block)
34
+ rescue ArgumentError => exception
35
+ raise ArgumentError, exception.message, caller
36
+ end
37
+
38
+ def intersect_all(&block)
39
+ add_set_expression(:intersect_all, &block)
40
+ rescue ArgumentError => exception
41
+ raise ArgumentError, exception.message, caller
42
+ end
43
+
44
+ def except(&block)
45
+ add_set_expression(:except, &block)
46
+ rescue ArgumentError => exception
47
+ raise ArgumentError, exception.message, caller
48
+ end
49
+
50
+ def except_all(&block)
51
+ add_set_expression(:except_all, &block)
52
+ rescue ArgumentError => exception
53
+ raise ArgumentError, exception.message, caller
54
+ end
55
+
56
+ private
57
+
58
+ def add_set_expression(type, &block)
59
+ SetExpression.new(type, &block).tap do |expression|
60
+ relation.set_expressions << expression
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ class Relation < MR::ReadModel::Relation
67
+ attr_reader :set_expressions
68
+
69
+ def initialize
70
+ super
71
+ @set_expressions = []
72
+ end
73
+
74
+ def build_sql(params = nil)
75
+ sql = super(params)
76
+ self.set_expressions.inject(sql){ |s, e| e.combine_sql(s, params) }
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,98 @@
1
+ module MR; end
2
+ module MR::ReadModel
3
+
4
+ module Subquery
5
+ attr_reader :read_model_class
6
+
7
+ def initialize(&block)
8
+ self.instance_eval(&block)
9
+ if !self.read_model_class
10
+ raise ArgumentError, "invalid subquery - " \
11
+ "use `read_model` to define the subquery"
12
+ end
13
+ end
14
+
15
+ def read_model(&block)
16
+ @read_model_class = Class.new do
17
+ # TODO - fix circular require
18
+ require 'mr/read_model'
19
+ require 'mr/read_model/set_querying'
20
+ include MR::ReadModel
21
+ include MR::ReadModel::SetQuerying
22
+ end
23
+ @read_model_class.class_eval(&block)
24
+ end
25
+
26
+ def build_sql(params = nil)
27
+ "(#{self.read_model_class.build_sql(params)})"
28
+ end
29
+
30
+ end
31
+
32
+ module AliasSubquery
33
+ include Subquery
34
+
35
+ def alias_sql
36
+ @alias_sql ||= ""
37
+ end
38
+
39
+ def as(alias_name)
40
+ if alias_name.to_s.strip.empty?
41
+ raise ArgumentError, "alias can't be blank"
42
+ end
43
+ @alias_sql = "AS #{alias_name}"
44
+ end
45
+
46
+ def build_sql(params = nil)
47
+ if self.alias_sql.to_s.strip.empty?
48
+ raise InvalidSubqueryError, "subquery must have an alias"
49
+ end
50
+ "#{super} #{self.alias_sql}".strip
51
+ end
52
+
53
+ end
54
+
55
+ class FromSubquery
56
+ include AliasSubquery
57
+
58
+ def record_class
59
+ self.read_model_class.record_class
60
+ end
61
+
62
+ end
63
+
64
+ class JoinSubquery
65
+ include AliasSubquery
66
+
67
+ DEFAULT_JOIN_SQL = 'JOIN'.freeze
68
+ JOIN_SQL = Hash.new(DEFAULT_JOIN_SQL).tap do |h|
69
+ h[:inner] = 'INNER JOIN'.freeze
70
+ h[:left] = 'LEFT OUTER JOIN'.freeze
71
+ h[:right] = 'RIGHT OUTER JOIN'.freeze
72
+ h[:full] = 'FULL OUTER JOIN'.freeze
73
+ end.freeze
74
+
75
+ attr_reader :join_sql
76
+
77
+ def initialize(type, &block)
78
+ @join_sql = JOIN_SQL[type]
79
+ super(&block)
80
+ end
81
+
82
+ def conditions_sql
83
+ @conditions_sql ||= ""
84
+ end
85
+
86
+ def on(conditions)
87
+ @conditions_sql = "ON #{conditions}"
88
+ end
89
+
90
+ def build_sql(params = nil)
91
+ "#{self.join_sql} #{super} #{self.conditions_sql}".strip
92
+ end
93
+
94
+ end
95
+
96
+ InvalidSubqueryError = Class.new(RuntimeError)
97
+
98
+ end
@@ -0,0 +1,35 @@
1
+ require 'much-plugin'
2
+
3
+ module MR
4
+
5
+ module Record
6
+ include MuchPlugin
7
+
8
+ plugin_included do
9
+ extend ClassMethods
10
+ include InstanceMethods
11
+ end
12
+
13
+ module InstanceMethods
14
+
15
+ attr_writer :model
16
+
17
+ def model
18
+ @model ||= self.class.model_class.new(self)
19
+ end
20
+
21
+ def model_class
22
+ self.class.model_class
23
+ end
24
+
25
+ end
26
+
27
+ module ClassMethods
28
+
29
+ attr_accessor :model_class
30
+
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,229 @@
1
+ require 'mr/fake_record'
2
+ require 'mr/model'
3
+
4
+ module MR
5
+
6
+ module TestHelpers
7
+ module_function
8
+
9
+ def model_reset_save_called(model, &block)
10
+ fake_record = model.record
11
+ if !fake_record.kind_of?(MR::FakeRecord)
12
+ raise ArgumentError, "model must be using a fake record"
13
+ end
14
+ yield model if block
15
+ fake_record.reset_save_called
16
+ end
17
+
18
+ def assert_association_saved(model, association, expected_value)
19
+ with_backtrace(caller) do
20
+ AssociationSavedAssertion.new(model, association, expected_value).run(self)
21
+ end
22
+ end
23
+
24
+ def assert_not_association_saved(model, association, expected_value)
25
+ with_backtrace(caller) do
26
+ AssociationNotSavedAssertion.new(model, association, expected_value).run(self)
27
+ end
28
+ end
29
+
30
+ def assert_model_destroyed(model)
31
+ with_backtrace(caller) do
32
+ ModelDestroyedAssertion.new(model).run(self)
33
+ end
34
+ end
35
+
36
+ def assert_not_model_destroyed(model)
37
+ with_backtrace(caller) do
38
+ ModelNotDestroyedAssertion.new(model).run(self)
39
+ end
40
+ end
41
+
42
+ def assert_field_saved(model, field, expected_value)
43
+ with_backtrace(caller) do
44
+ FieldSavedAssertion.new(model, field, expected_value).run(self)
45
+ end
46
+ end
47
+
48
+ def assert_not_field_saved(model, field, expected_value)
49
+ with_backtrace(caller) do
50
+ FieldNotSavedAssertion.new(model, field, expected_value).run(self)
51
+ end
52
+ end
53
+
54
+ def assert_model_saved(model)
55
+ with_backtrace(caller) do
56
+ ModelSavedAssertion.new(model).run(self)
57
+ end
58
+ end
59
+
60
+ def assert_not_model_saved(model)
61
+ with_backtrace(caller) do
62
+ ModelNotSavedAssertion.new(model).run(self)
63
+ end
64
+ end
65
+
66
+ class AssociationSavedAssertionBase
67
+ def initialize(model, association, expected_value)
68
+ reflection = model.record.association(association).reflection
69
+ if reflection.macro != :belongs_to
70
+ raise ArgumentError, "association must be a belongs to"
71
+ end
72
+ @expected_value = expected_value || NULL_MODEL
73
+ # use `record.class` instead of `record_class` here, the configured
74
+ # `record_class` won't match the actual `record` class because `record` is
75
+ # a fake record
76
+ expected_foreign_type = @expected_value.record.class.to_s
77
+ expected_foreign_key = @expected_value.id
78
+ @assertions = [
79
+ build_assertion(model, reflection.foreign_type, expected_foreign_type),
80
+ build_assertion(model, reflection.foreign_key, expected_foreign_key)
81
+ ].compact
82
+ end
83
+
84
+ def run(context)
85
+ @assertions.each{ |a| a.run(context) }
86
+ end
87
+
88
+ private
89
+
90
+ def build_assertion(model, field, expected_value)
91
+ return unless field
92
+ self.field_assertion_class.new(model, field, expected_value)
93
+ end
94
+
95
+ NullModel = Struct.new(:id, :record)
96
+ NullRecord = Struct.new(:class)
97
+ NullRecordClass = Struct.new(:name)
98
+ NULL_MODEL = NullModel.new(nil, NullRecord.new(NullRecordClass.new))
99
+ end
100
+
101
+ class AssociationSavedAssertion < AssociationSavedAssertionBase
102
+ def field_assertion_class; FieldSavedAssertion; end
103
+ end
104
+
105
+ class AssociationNotSavedAssertion < AssociationSavedAssertionBase
106
+ def field_assertion_class; FieldNotSavedAssertion; end
107
+ end
108
+
109
+ class FieldSavedAssertionBase
110
+ def initialize(model, field, expected_value)
111
+ if !model.record.kind_of?(MR::FakeRecord)
112
+ raise ArgumentError, "model must be using a fake record"
113
+ end
114
+ @expected_value = expected_value
115
+ @field = field.to_s
116
+ @saved = model.record.saved_attributes.key?(@field)
117
+ @saved_as = model.record.saved_attributes[@field]
118
+ end
119
+ end
120
+
121
+ class FieldSavedAssertion < FieldSavedAssertionBase
122
+ def run(context)
123
+ if @saved
124
+ context.assert_equal @expected_value, @saved_as, saved_as_desc
125
+ else
126
+ context.assert_true @saved, saved_desc
127
+ end
128
+ end
129
+
130
+ private
131
+
132
+ def saved_desc
133
+ "Expected #{@field.inspect} field was saved."
134
+ end
135
+
136
+ def saved_as_desc
137
+ "Expected #{@field.inspect} field was saved as #{@expected_value.inspect}."
138
+ end
139
+ end
140
+
141
+ class FieldNotSavedAssertion < FieldSavedAssertionBase
142
+ def run(context)
143
+ if @saved
144
+ context.assert_not_equal @expected_value, @saved_as, saved_as_desc
145
+ else
146
+ context.assert_false @saved, saved_desc
147
+ end
148
+ end
149
+
150
+ private
151
+
152
+ def saved_desc
153
+ "Expected #{@field.inspect} field was not saved."
154
+ end
155
+
156
+ def saved_as_desc
157
+ "Expected #{@field.inspect} field was not saved as #{@expected_value.inspect}."
158
+ end
159
+ end
160
+
161
+ class ModelDestroyedAssertionBase
162
+ def initialize(model)
163
+ @model = model
164
+ @destroyed = @model.destroyed?
165
+ end
166
+ end
167
+
168
+ class ModelDestroyedAssertion < ModelDestroyedAssertionBase
169
+ def run(context)
170
+ context.assert_true(@destroyed){ destroyed_desc }
171
+ end
172
+
173
+ private
174
+
175
+ def destroyed_desc
176
+ "Expected #{@model.inspect} was destroyed."
177
+ end
178
+ end
179
+
180
+ class ModelNotDestroyedAssertion < ModelDestroyedAssertionBase
181
+ def run(context)
182
+ context.assert_false(@destroyed){ destroyed_desc }
183
+ end
184
+
185
+ private
186
+
187
+ def destroyed_desc
188
+ "Expected #{@model.inspect} was not destroyed."
189
+ end
190
+ end
191
+
192
+ class ModelSavedAssertionBase
193
+ def initialize(model)
194
+ @model = model
195
+ fake_record = model.record
196
+ if !fake_record.kind_of?(MR::FakeRecord)
197
+ raise ArgumentError, "model must be using a fake record"
198
+ end
199
+ @saved = fake_record.save_called
200
+ end
201
+ end
202
+
203
+ class ModelSavedAssertion < ModelSavedAssertionBase
204
+ def run(context)
205
+ context.assert_true(@saved){ saved_desc }
206
+ end
207
+
208
+ private
209
+
210
+ def saved_desc
211
+ "Expected #{@model.inspect} was saved."
212
+ end
213
+ end
214
+
215
+ class ModelNotSavedAssertion < ModelSavedAssertionBase
216
+ def run(context)
217
+ context.assert_false(@saved){ saved_desc }
218
+ end
219
+
220
+ private
221
+
222
+ def saved_desc
223
+ "Expected #{@model.inspect} was not saved."
224
+ end
225
+ end
226
+
227
+ end
228
+
229
+ end