iknow_view_models 3.2.0 → 3.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -0
- data/Appraisals +6 -6
- data/Rakefile +5 -5
- data/gemfiles/rails_5_2.gemfile +5 -5
- data/gemfiles/rails_6_0.gemfile +5 -5
- data/iknow_view_models.gemspec +40 -39
- data/lib/iknow_view_models.rb +9 -7
- data/lib/iknow_view_models/version.rb +1 -1
- data/lib/view_model.rb +17 -14
- data/lib/view_model/access_control.rb +5 -2
- data/lib/view_model/access_control/composed.rb +10 -9
- data/lib/view_model/access_control/open.rb +2 -0
- data/lib/view_model/access_control/read_only.rb +2 -0
- data/lib/view_model/access_control/tree.rb +11 -6
- data/lib/view_model/access_control_error.rb +4 -1
- data/lib/view_model/active_record.rb +12 -11
- data/lib/view_model/active_record/association_data.rb +2 -1
- data/lib/view_model/active_record/association_manipulation.rb +6 -4
- data/lib/view_model/active_record/cache.rb +4 -2
- data/lib/view_model/active_record/collection_nested_controller.rb +3 -3
- data/lib/view_model/active_record/controller_base.rb +4 -1
- data/lib/view_model/active_record/nested_controller_base.rb +1 -0
- data/lib/view_model/active_record/update_context.rb +8 -6
- data/lib/view_model/active_record/update_data.rb +32 -30
- data/lib/view_model/active_record/update_operation.rb +17 -13
- data/lib/view_model/active_record/visitor.rb +0 -1
- data/lib/view_model/after_transaction_runner.rb +0 -1
- data/lib/view_model/callbacks.rb +3 -1
- data/lib/view_model/controller.rb +13 -3
- data/lib/view_model/deserialization_error.rb +15 -12
- data/lib/view_model/error.rb +12 -10
- data/lib/view_model/error_view.rb +3 -1
- data/lib/view_model/migration/no_path_error.rb +1 -0
- data/lib/view_model/migration/one_way_error.rb +1 -0
- data/lib/view_model/migration/unspecified_version_error.rb +1 -0
- data/lib/view_model/record.rb +11 -13
- data/lib/view_model/reference.rb +3 -1
- data/lib/view_model/references.rb +8 -5
- data/lib/view_model/registry.rb +1 -1
- data/lib/view_model/schemas.rb +9 -4
- data/lib/view_model/serialization_error.rb +4 -1
- data/lib/view_model/serialize_context.rb +4 -4
- data/lib/view_model/test_helpers.rb +8 -3
- data/lib/view_model/test_helpers/arvm_builder.rb +19 -14
- data/lib/view_model/traversal_context.rb +2 -1
- data/test/.rubocop.yml +14 -0
- data/test/helpers/arvm_test_models.rb +12 -9
- data/test/helpers/arvm_test_utilities.rb +5 -3
- data/test/helpers/controller_test_helpers.rb +31 -29
- data/test/helpers/match_enumerator.rb +1 -0
- data/test/helpers/query_logging.rb +2 -1
- data/test/helpers/test_access_control.rb +5 -3
- data/test/helpers/viewmodel_spec_helpers.rb +21 -20
- data/test/unit/view_model/access_control_test.rb +144 -144
- data/test/unit/view_model/active_record/alias_test.rb +15 -13
- data/test/unit/view_model/active_record/belongs_to_test.rb +40 -39
- data/test/unit/view_model/active_record/cache_test.rb +27 -26
- data/test/unit/view_model/active_record/cloner_test.rb +67 -63
- data/test/unit/view_model/active_record/controller_test.rb +37 -38
- data/test/unit/view_model/active_record/counter_test.rb +10 -9
- data/test/unit/view_model/active_record/customization_test.rb +59 -58
- data/test/unit/view_model/active_record/has_many_test.rb +112 -111
- data/test/unit/view_model/active_record/has_many_through_poly_test.rb +15 -14
- data/test/unit/view_model/active_record/has_many_through_test.rb +33 -38
- data/test/unit/view_model/active_record/has_one_test.rb +37 -36
- data/test/unit/view_model/active_record/migration_test.rb +13 -13
- data/test/unit/view_model/active_record/namespacing_test.rb +19 -17
- data/test/unit/view_model/active_record/poly_test.rb +44 -45
- data/test/unit/view_model/active_record/shared_test.rb +30 -28
- data/test/unit/view_model/active_record/version_test.rb +9 -7
- data/test/unit/view_model/active_record_test.rb +72 -72
- data/test/unit/view_model/callbacks_test.rb +19 -15
- data/test/unit/view_model/controller_test.rb +4 -2
- data/test/unit/view_model/record_test.rb +92 -97
- data/test/unit/view_model/traversal_context_test.rb +4 -5
- data/test/unit/view_model_test.rb +18 -16
- metadata +7 -5
@@ -1,10 +1,12 @@
|
|
1
|
-
|
2
|
-
require_relative "../../../helpers/arvm_test_models.rb"
|
3
|
-
require_relative "../../../helpers/viewmodel_spec_helpers.rb"
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
3
|
+
require_relative '../../../helpers/arvm_test_utilities'
|
4
|
+
require_relative '../../../helpers/arvm_test_models'
|
5
|
+
require_relative '../../../helpers/viewmodel_spec_helpers'
|
6
6
|
|
7
|
-
require
|
7
|
+
require 'minitest/autorun'
|
8
|
+
|
9
|
+
require 'view_model/active_record'
|
8
10
|
|
9
11
|
class ViewModel::ActiveRecord::Alias < ActiveSupport::TestCase
|
10
12
|
include ARVMTestUtilities
|
@@ -14,18 +16,18 @@ class ViewModel::ActiveRecord::Alias < ActiveSupport::TestCase
|
|
14
16
|
|
15
17
|
def child_attributes
|
16
18
|
super.merge(
|
17
|
-
viewmodel: ->(
|
18
|
-
add_view_alias
|
19
|
-
add_view_alias
|
20
|
-
end
|
19
|
+
viewmodel: ->(_v) do
|
20
|
+
add_view_alias 'ChildA'
|
21
|
+
add_view_alias 'ChildB'
|
22
|
+
end,
|
21
23
|
)
|
22
24
|
end
|
23
25
|
|
24
|
-
it
|
25
|
-
%w
|
26
|
+
it 'permits association types to be aliased' do
|
27
|
+
%w[Child ChildA ChildB].each do |view_alias|
|
26
28
|
view = {
|
27
|
-
|
28
|
-
|
29
|
+
'_type' => viewmodel_class.view_name,
|
30
|
+
'child' => { '_type' => view_alias },
|
29
31
|
}
|
30
32
|
|
31
33
|
parent = viewmodel_class.deserialize_from_view(view).model
|
@@ -1,10 +1,12 @@
|
|
1
|
-
|
2
|
-
require_relative "../../../helpers/arvm_test_models.rb"
|
3
|
-
require_relative '../../../helpers/viewmodel_spec_helpers.rb'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
3
|
+
require_relative '../../../helpers/arvm_test_utilities'
|
4
|
+
require_relative '../../../helpers/arvm_test_models'
|
5
|
+
require_relative '../../../helpers/viewmodel_spec_helpers'
|
6
6
|
|
7
|
-
require
|
7
|
+
require 'minitest/autorun'
|
8
|
+
|
9
|
+
require 'view_model/active_record'
|
8
10
|
|
9
11
|
class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
10
12
|
include ARVMTestUtilities
|
@@ -14,13 +16,13 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
14
16
|
def setup
|
15
17
|
super
|
16
18
|
|
17
|
-
# TODO make a `has_list?` that allows a parent to set all children as an array
|
18
|
-
@model1 = model_class.new(name:
|
19
|
-
child: child_model_class.new(name:
|
19
|
+
# TODO: make a `has_list?` that allows a parent to set all children as an array
|
20
|
+
@model1 = model_class.new(name: 'p1',
|
21
|
+
child: child_model_class.new(name: 'p1l'))
|
20
22
|
@model1.save!
|
21
23
|
|
22
|
-
@model2 = model_class.new(name:
|
23
|
-
child: child_model_class.new(name:
|
24
|
+
@model2 = model_class.new(name: 'p2',
|
25
|
+
child: child_model_class.new(name: 'p2l'))
|
24
26
|
|
25
27
|
@model2.save!
|
26
28
|
|
@@ -30,14 +32,14 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
30
32
|
def test_serialize_view
|
31
33
|
view, _refs = serialize_with_references(ModelView.new(@model1))
|
32
34
|
|
33
|
-
assert_equal({
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
assert_equal({ '_type' => 'Model',
|
36
|
+
'_version' => 1,
|
37
|
+
'id' => @model1.id,
|
38
|
+
'name' => @model1.name,
|
39
|
+
'child' => { '_type' => 'Child',
|
40
|
+
'_version' => 1,
|
41
|
+
'id' => @model1.child.id,
|
42
|
+
'name' => @model1.child.name },
|
41
43
|
},
|
42
44
|
view)
|
43
45
|
end
|
@@ -53,9 +55,9 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
53
55
|
|
54
56
|
def test_create_from_view
|
55
57
|
view = {
|
56
|
-
|
57
|
-
|
58
|
-
|
58
|
+
'_type' => 'Model',
|
59
|
+
'name' => 'p',
|
60
|
+
'child' => { '_type' => 'Child', 'name' => 'l' },
|
59
61
|
}
|
60
62
|
|
61
63
|
pv = ModelView.deserialize_from_view(view)
|
@@ -64,10 +66,10 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
64
66
|
assert(!p.changed?)
|
65
67
|
assert(!p.new_record?)
|
66
68
|
|
67
|
-
assert_equal(
|
69
|
+
assert_equal('p', p.name)
|
68
70
|
|
69
71
|
assert(p.child.present?)
|
70
|
-
assert_equal(
|
72
|
+
assert_equal('l', p.child.name)
|
71
73
|
end
|
72
74
|
|
73
75
|
def test_create_belongs_to_nil
|
@@ -86,7 +88,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
86
88
|
def test_belongs_to_create
|
87
89
|
@model1.update(child: nil)
|
88
90
|
|
89
|
-
alter_by_view!(ModelView, @model1) do |view,
|
91
|
+
alter_by_view!(ModelView, @model1) do |view, _refs|
|
90
92
|
view['child'] = { '_type' => 'Child', 'name' => 'cheese' }
|
91
93
|
end
|
92
94
|
|
@@ -96,7 +98,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
96
98
|
def test_belongs_to_replace
|
97
99
|
old_child = @model1.child
|
98
100
|
|
99
|
-
alter_by_view!(ModelView, @model1) do |view,
|
101
|
+
alter_by_view!(ModelView, @model1) do |view, _refs|
|
100
102
|
view['child'] = { '_type' => 'Child', 'name' => 'cheese' }
|
101
103
|
end
|
102
104
|
|
@@ -108,7 +110,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
108
110
|
old_p1_child = @model1.child
|
109
111
|
old_p2_child = @model2.child
|
110
112
|
|
111
|
-
set_by_view!(ModelView, [@model1, @model2]) do |(p1, p2),
|
113
|
+
set_by_view!(ModelView, [@model1, @model2]) do |(p1, p2), _refs|
|
112
114
|
p1['child'] = nil
|
113
115
|
p2['child'] = update_hash_for(ChildView, old_p1_child)
|
114
116
|
end
|
@@ -122,7 +124,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
122
124
|
old_p1_child = @model1.child
|
123
125
|
old_p2_child = @model2.child
|
124
126
|
|
125
|
-
alter_by_view!(ModelView, [@model1, @model2]) do |(p1, p2),
|
127
|
+
alter_by_view!(ModelView, [@model1, @model2]) do |(p1, p2), _refs|
|
126
128
|
p1['child'] = update_hash_for(ChildView, old_p2_child)
|
127
129
|
p2['child'] = update_hash_for(ChildView, old_p1_child)
|
128
130
|
end
|
@@ -136,22 +138,22 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
136
138
|
d_context = ModelView.new_deserialize_context
|
137
139
|
|
138
140
|
target_child = Child.create
|
139
|
-
from_model
|
140
|
-
to_model
|
141
|
+
from_model = Model.create(name: 'from', child: target_child)
|
142
|
+
to_model = Model.create(name: 'p3')
|
141
143
|
|
142
144
|
alter_by_view!(
|
143
145
|
ModelView, [from_model, to_model],
|
144
146
|
deserialize_context: d_context
|
145
|
-
) do |(from, to),
|
147
|
+
) do |(from, to), _refs|
|
146
148
|
from['child'] = nil
|
147
149
|
to['child'] = update_hash_for(ChildView, target_child)
|
148
150
|
end
|
149
151
|
|
150
152
|
assert_equal(target_child, to_model.child, 'target child moved')
|
151
153
|
assert_equal([ViewModel::Reference.new(ModelView, from_model.id),
|
152
|
-
ViewModel::Reference.new(ModelView, to_model.id)],
|
154
|
+
ViewModel::Reference.new(ModelView, to_model.id),],
|
153
155
|
d_context.valid_edit_refs,
|
154
|
-
|
156
|
+
'only models are checked for change; child was not')
|
155
157
|
end
|
156
158
|
|
157
159
|
def test_implicit_release_invalid_belongs_to
|
@@ -174,11 +176,11 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
174
176
|
t.integer :deleted_child_id
|
175
177
|
t.integer :ignored_child_id
|
176
178
|
end,
|
177
|
-
model: ->(
|
179
|
+
model: ->(_m) do
|
178
180
|
belongs_to :deleted_child, class_name: Child.name, dependent: :delete
|
179
181
|
belongs_to :ignored_child, class_name: Child.name
|
180
182
|
end,
|
181
|
-
viewmodel: ->(
|
183
|
+
viewmodel: ->(_v) do
|
182
184
|
associations :deleted_child, :ignored_child
|
183
185
|
end)
|
184
186
|
end
|
@@ -198,7 +200,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
198
200
|
end
|
199
201
|
|
200
202
|
def test_no_gc_dependent_ignore
|
201
|
-
model = model_class.create(ignored_child: Child.new(name:
|
203
|
+
model = model_class.create(ignored_child: Child.new(name: 'one'))
|
202
204
|
old_child = model.ignored_child
|
203
205
|
|
204
206
|
alter_by_view!(ModelView, model) do |ov, _refs|
|
@@ -232,7 +234,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
232
234
|
end
|
233
235
|
|
234
236
|
def test_renamed_roundtrip
|
235
|
-
alter_by_view!(ModelView, @model) do |view,
|
237
|
+
alter_by_view!(ModelView, @model) do |view, _refs|
|
236
238
|
assert_equal({ 'id' => @model.child.id,
|
237
239
|
'_type' => 'Child',
|
238
240
|
'_version' => 1,
|
@@ -284,7 +286,6 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
284
286
|
end
|
285
287
|
end
|
286
288
|
|
287
|
-
|
288
289
|
# Do we support replacing a node in the tree and remodeling its children
|
289
290
|
# back to it? In theory we want to, but currently we don't: the child node
|
290
291
|
# is unresolvable.
|
@@ -299,8 +300,8 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
299
300
|
def test_move
|
300
301
|
model = Aye.create(bee: Bee.new(cee: Cee.new))
|
301
302
|
assert_raises(ViewModel::DeserializationError::ParentNotFound) do
|
302
|
-
alter_by_view!(AyeView, model) do |view,
|
303
|
-
view['bee'].delete(
|
303
|
+
alter_by_view!(AyeView, model) do |view, _refs|
|
304
|
+
view['bee'].delete('id')
|
304
305
|
end
|
305
306
|
end
|
306
307
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/unit'
|
5
|
+
require 'minitest/hooks'
|
6
6
|
|
7
|
-
require_relative
|
8
|
-
require_relative
|
9
|
-
require_relative
|
7
|
+
require_relative '../../../helpers/arvm_test_models'
|
8
|
+
require_relative '../../../helpers/arvm_test_utilities'
|
9
|
+
require_relative '../../../helpers/viewmodel_spec_helpers'
|
10
10
|
|
11
|
-
require
|
12
|
-
require
|
11
|
+
require 'view_model'
|
12
|
+
require 'view_model/active_record'
|
13
13
|
|
14
14
|
# IknowCache uses Rails.cache: create a dummy cache.
|
15
15
|
|
@@ -91,8 +91,8 @@ class ViewModel::ActiveRecord
|
|
91
91
|
end
|
92
92
|
|
93
93
|
included do
|
94
|
-
let(:shared) { shared_model_class.create!(name:
|
95
|
-
let(:root) { model_class.create!(name:
|
94
|
+
let(:shared) { shared_model_class.create!(name: 'shared1') }
|
95
|
+
let(:root) { model_class.create!(name: 'root1', child: Child.new(name: 'owned1'), shared: shared) }
|
96
96
|
let(:root_view) { viewmodel_class.new(root) }
|
97
97
|
end
|
98
98
|
end
|
@@ -183,13 +183,14 @@ class ViewModel::ActiveRecord
|
|
183
183
|
|
184
184
|
# The cached reference must correspond to the returned data.
|
185
185
|
parsed_data = JSON.parse(ref_data)
|
186
|
-
value(parsed_data[
|
187
|
-
value(parsed_data[
|
186
|
+
value(parsed_data['id']).must_equal(id)
|
187
|
+
value(parsed_data['_type']).must_equal(view_name)
|
188
188
|
|
189
189
|
# When the cached reference is to independently cached data
|
190
190
|
# (SharedView in this test), make sure that data is correctly
|
191
191
|
# cached.
|
192
|
-
next unless view_name ==
|
192
|
+
next unless view_name == 'Shared'
|
193
|
+
|
193
194
|
value(id).must_equal(shared.id)
|
194
195
|
cached_shared = read_cache(shared_viewmodel_class, id)
|
195
196
|
value(cached_shared).must_be(:present?)
|
@@ -224,8 +225,8 @@ class ViewModel::ActiveRecord
|
|
224
225
|
end
|
225
226
|
|
226
227
|
def change_in_database
|
227
|
-
root.update_attribute(:name,
|
228
|
-
shared.update_attribute(:name,
|
228
|
+
root.update_attribute(:name, 'CHANGEDROOT')
|
229
|
+
shared.update_attribute(:name, 'CHANGEDSHARED')
|
229
230
|
end
|
230
231
|
|
231
232
|
it 'resolves from the cache' do
|
@@ -243,7 +244,7 @@ class ViewModel::ActiveRecord
|
|
243
244
|
viewmodel_class.viewmodel_cache.clear
|
244
245
|
|
245
246
|
cache_data, cache_refs = serialize_with_cache
|
246
|
-
value(cache_data[0][
|
247
|
+
value(cache_data[0]['name']).must_equal('CHANGEDROOT') # Root view invalidated
|
247
248
|
value(cache_refs).must_equal(before_refs) # Shared view not invalidated
|
248
249
|
end
|
249
250
|
|
@@ -301,7 +302,7 @@ class ViewModel::ActiveRecord
|
|
301
302
|
viewmodel_class.viewmodel_cache.delete(root.id)
|
302
303
|
|
303
304
|
cache_data, cache_refs = serialize_with_cache
|
304
|
-
value(cache_data[0][
|
305
|
+
value(cache_data[0]['name']).must_equal('CHANGEDROOT')
|
305
306
|
value(cache_refs).must_equal(before_refs)
|
306
307
|
end
|
307
308
|
|
@@ -311,8 +312,8 @@ class ViewModel::ActiveRecord
|
|
311
312
|
|
312
313
|
# Shared view invalidated, but root view not
|
313
314
|
cache_data, cache_hrefs = serialize_with_cache
|
314
|
-
value(cache_data[0][
|
315
|
-
value(cache_hrefs.values[0][
|
315
|
+
value(cache_data[0]['name']).must_equal('root1')
|
316
|
+
value(cache_hrefs.values[0]['name']).must_equal('CHANGEDSHARED')
|
316
317
|
end
|
317
318
|
|
318
319
|
it 'can clear a cache via its external cache group' do
|
@@ -321,12 +322,12 @@ class ViewModel::ActiveRecord
|
|
321
322
|
|
322
323
|
# Shared view invalidated, but root view not
|
323
324
|
cache_data, cache_hrefs = serialize_with_cache
|
324
|
-
value(cache_data[0][
|
325
|
-
value(cache_hrefs.values[0][
|
325
|
+
value(cache_data[0]['name']).must_equal('root1')
|
326
|
+
value(cache_hrefs.values[0]['name']).must_equal('CHANGEDSHARED')
|
326
327
|
end
|
327
328
|
|
328
329
|
describe 'and a record not in the cache' do
|
329
|
-
let(:root2) { model_class.create!(name:
|
330
|
+
let(:root2) { model_class.create!(name: 'root2', child: Child.new(name: 'owned2'), shared: shared) }
|
330
331
|
|
331
332
|
def serialize_from_database
|
332
333
|
views = model_class.find(root.id, root2.id).map { |r| viewmodel_class.new(r) }
|
@@ -354,21 +355,21 @@ class ViewModel::ActiveRecord
|
|
354
355
|
change_in_database
|
355
356
|
|
356
357
|
cache_data, cache_refs = serialize_with_cache
|
357
|
-
value(cache_data[0][
|
358
|
-
value(cache_data[1][
|
358
|
+
value(cache_data[0]['name']).must_equal('root1')
|
359
|
+
value(cache_data[1]['name']).must_equal('root2')
|
359
360
|
value(cache_refs).must_equal(refs)
|
360
361
|
end
|
361
362
|
end
|
362
363
|
end
|
363
364
|
end
|
364
365
|
|
365
|
-
describe
|
366
|
+
describe 'with a non-cacheable shared child' do
|
366
367
|
include ViewModelSpecHelpers::ParentAndSharedBelongsToChild
|
367
368
|
def model_attributes
|
368
369
|
super.merge(viewmodel: ->(_) { cacheable! })
|
369
370
|
end
|
370
371
|
|
371
|
-
let(:root) { model_class.create!(name:
|
372
|
+
let(:root) { model_class.create!(name: 'root1', child: Child.new(name: 'owned1')) }
|
372
373
|
let(:root_view) { viewmodel_class.new(root) }
|
373
374
|
|
374
375
|
include BehavesLikeACache
|
@@ -1,14 +1,16 @@
|
|
1
|
-
|
2
|
-
require "minitest/unit"
|
3
|
-
require "minitest/hooks"
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/unit'
|
5
|
+
require 'minitest/hooks'
|
6
|
+
|
7
|
+
require_relative '../../../helpers/arvm_test_models'
|
8
|
+
require_relative '../../../helpers/viewmodel_spec_helpers'
|
7
9
|
|
8
10
|
# MiniTest::Spec.register_spec_type(/./, Minitest::HooksSpec)
|
9
11
|
|
10
|
-
require
|
11
|
-
require
|
12
|
+
require 'view_model'
|
13
|
+
require 'view_model/active_record'
|
12
14
|
|
13
15
|
class ViewModel::ActiveRecord
|
14
16
|
class ClonerTest < ActiveSupport::TestCase
|
@@ -18,7 +20,7 @@ class ViewModel::ActiveRecord
|
|
18
20
|
let(:viewmodel) { create_viewmodel! }
|
19
21
|
let(:model) { viewmodel.model }
|
20
22
|
|
21
|
-
describe
|
23
|
+
describe 'with single model' do
|
22
24
|
include ViewModelSpecHelpers::Single
|
23
25
|
|
24
26
|
def model_attributes
|
@@ -26,15 +28,15 @@ class ViewModel::ActiveRecord
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def new_model
|
29
|
-
model_class.new(name:
|
31
|
+
model_class.new(name: 'a', nonview: 'b')
|
30
32
|
end
|
31
33
|
|
32
|
-
it
|
34
|
+
it 'persists the test setup' do
|
33
35
|
assert(viewmodel.model.persisted?)
|
34
36
|
refute(viewmodel.model.new_record?)
|
35
37
|
end
|
36
38
|
|
37
|
-
it
|
39
|
+
it 'can clone the model' do
|
38
40
|
clone_model = Cloner.new.clone(viewmodel)
|
39
41
|
assert(clone_model.new_record?)
|
40
42
|
assert_nil(clone_model.id)
|
@@ -45,75 +47,75 @@ class ViewModel::ActiveRecord
|
|
45
47
|
end
|
46
48
|
|
47
49
|
class IgnoreParentCloner < Cloner
|
48
|
-
def visit_model_view(
|
50
|
+
def visit_model_view(_node, _model)
|
49
51
|
ignore!
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
|
-
it
|
55
|
+
it 'can ignore a model' do
|
54
56
|
clone_model = IgnoreParentCloner.new.clone(viewmodel)
|
55
57
|
assert_nil(clone_model)
|
56
58
|
end
|
57
59
|
|
58
60
|
class IgnoreAllCloner < Cloner
|
59
|
-
def pre_visit(
|
61
|
+
def pre_visit(_node, _model)
|
60
62
|
ignore!
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
64
|
-
it
|
66
|
+
it 'can ignore a model in pre-visit' do
|
65
67
|
clone_model = IgnoreAllCloner.new.clone(viewmodel)
|
66
68
|
assert_nil(clone_model)
|
67
69
|
end
|
68
70
|
|
69
71
|
class AlterAttributeCloner < Cloner
|
70
|
-
def visit_model_view(
|
71
|
-
model.name =
|
72
|
+
def visit_model_view(_node, model)
|
73
|
+
model.name = 'changed'
|
72
74
|
end
|
73
75
|
end
|
74
76
|
|
75
|
-
it
|
77
|
+
it 'can alter a model attribute' do
|
76
78
|
clone_model = AlterAttributeCloner.new.clone(viewmodel)
|
77
79
|
assert(clone_model.new_record?)
|
78
80
|
assert_nil(clone_model.id)
|
79
|
-
assert_equal(
|
80
|
-
refute_equal(
|
81
|
+
assert_equal('changed', clone_model.name)
|
82
|
+
refute_equal('changed', model.name)
|
81
83
|
assert_equal(model.nonview, clone_model.nonview)
|
82
84
|
clone_model.save!
|
83
85
|
refute_equal(model, clone_model)
|
84
86
|
end
|
85
87
|
|
86
88
|
class PostAlterAttributeCloner < Cloner
|
87
|
-
def end_visit_model_view(
|
88
|
-
model.name =
|
89
|
+
def end_visit_model_view(_node, model)
|
90
|
+
model.name = 'changed'
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
92
|
-
it
|
94
|
+
it 'can alter a model attribute post-visit' do
|
93
95
|
clone_model = PostAlterAttributeCloner.new.clone(viewmodel)
|
94
96
|
assert(clone_model.new_record?)
|
95
97
|
assert_nil(clone_model.id)
|
96
|
-
assert_equal(
|
97
|
-
refute_equal(
|
98
|
+
assert_equal('changed', clone_model.name)
|
99
|
+
refute_equal('changed', model.name)
|
98
100
|
assert_equal(model.nonview, clone_model.nonview)
|
99
101
|
clone_model.save!
|
100
102
|
refute_equal(model, clone_model)
|
101
103
|
end
|
102
104
|
end
|
103
105
|
|
104
|
-
describe
|
106
|
+
describe 'with a child' do
|
105
107
|
def new_child_model
|
106
|
-
child_model_class.new(name:
|
108
|
+
child_model_class.new(name: 'b')
|
107
109
|
end
|
108
110
|
|
109
111
|
def new_model
|
110
|
-
model_class.new(name:
|
112
|
+
model_class.new(name: 'a', child: new_child_model)
|
111
113
|
end
|
112
114
|
|
113
115
|
module BehavesLikeConstructingAChild
|
114
116
|
extend ActiveSupport::Concern
|
115
117
|
included do
|
116
|
-
it
|
118
|
+
it 'persists the test setup' do
|
117
119
|
assert(viewmodel.model.persisted?)
|
118
120
|
refute(viewmodel.model.new_record?)
|
119
121
|
assert(viewmodel.model.child.persisted?)
|
@@ -123,7 +125,7 @@ class ViewModel::ActiveRecord
|
|
123
125
|
end
|
124
126
|
|
125
127
|
class IgnoreChildAssociationCloner < Cloner
|
126
|
-
def visit_model_view(
|
128
|
+
def visit_model_view(_node, _model)
|
127
129
|
ignore_association!(:child)
|
128
130
|
end
|
129
131
|
end
|
@@ -131,7 +133,7 @@ class ViewModel::ActiveRecord
|
|
131
133
|
module BehavesLikeCloningAChild
|
132
134
|
extend ActiveSupport::Concern
|
133
135
|
included do
|
134
|
-
it
|
136
|
+
it 'can clone the model and child' do
|
135
137
|
clone_model = Cloner.new.clone(viewmodel)
|
136
138
|
|
137
139
|
assert(clone_model.new_record?)
|
@@ -148,7 +150,7 @@ class ViewModel::ActiveRecord
|
|
148
150
|
refute_equal(model.child, clone_model.child)
|
149
151
|
end
|
150
152
|
|
151
|
-
it
|
153
|
+
it 'can ignore the child association' do
|
152
154
|
clone_model = IgnoreChildAssociationCloner.new.clone(viewmodel)
|
153
155
|
|
154
156
|
assert(clone_model.new_record?)
|
@@ -160,66 +162,67 @@ class ViewModel::ActiveRecord
|
|
160
162
|
end
|
161
163
|
end
|
162
164
|
|
163
|
-
describe
|
165
|
+
describe 'as belongs_to' do
|
164
166
|
include ViewModelSpecHelpers::ParentAndBelongsToChild
|
165
167
|
include BehavesLikeConstructingAChild
|
166
168
|
include BehavesLikeCloningAChild
|
167
169
|
end
|
168
170
|
|
169
|
-
describe
|
171
|
+
describe 'as has_one' do
|
170
172
|
include ViewModelSpecHelpers::ParentAndHasOneChild
|
171
173
|
include BehavesLikeConstructingAChild
|
172
174
|
include BehavesLikeCloningAChild
|
173
175
|
end
|
174
176
|
|
175
|
-
describe
|
177
|
+
describe 'as belongs_to shared child' do
|
176
178
|
include ViewModelSpecHelpers::ParentAndSharedBelongsToChild
|
177
179
|
include BehavesLikeConstructingAChild
|
178
|
-
it "can clone the model but not the child" do
|
179
|
-
clone_model = Cloner.new.clone(viewmodel)
|
180
180
|
|
181
|
-
|
182
|
-
|
183
|
-
assert_equal(model.name, clone_model.name)
|
181
|
+
it 'can clone the model but not the child' do
|
182
|
+
clone_model = Cloner.new.clone(viewmodel)
|
184
183
|
|
185
|
-
|
186
|
-
|
187
|
-
|
184
|
+
assert(clone_model.new_record?)
|
185
|
+
assert_nil(clone_model.id)
|
186
|
+
assert_equal(model.name, clone_model.name)
|
188
187
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
188
|
+
clone_child = clone_model.child
|
189
|
+
refute(clone_child.new_record?)
|
190
|
+
assert_equal(model.child, clone_child)
|
191
|
+
|
192
|
+
clone_model.save!
|
193
|
+
refute_equal(model, clone_model)
|
194
|
+
assert_equal(model.child, clone_model.child)
|
195
|
+
end
|
193
196
|
end
|
194
197
|
end
|
195
198
|
|
196
199
|
class IgnoreChildrenAssociationCloner < Cloner
|
197
|
-
def visit_model_view(
|
200
|
+
def visit_model_view(_node, _model)
|
198
201
|
ignore_association!(:children)
|
199
202
|
end
|
200
203
|
end
|
201
204
|
|
202
|
-
describe
|
205
|
+
describe 'with has_many children' do
|
203
206
|
include ViewModelSpecHelpers::ParentAndHasManyChildren
|
204
207
|
def new_child_models
|
205
|
-
[
|
208
|
+
['b', 'c'].map { |n| child_model_class.new(name: n) }
|
206
209
|
end
|
207
210
|
|
208
211
|
def new_model
|
209
|
-
model_class.new(name:
|
212
|
+
model_class.new(name: 'a', children: new_child_models)
|
210
213
|
end
|
211
214
|
|
212
|
-
it
|
215
|
+
it 'persists the test setup' do
|
213
216
|
assert(viewmodel.model.persisted?)
|
214
217
|
refute(viewmodel.model.new_record?)
|
215
218
|
assert_equal(2, viewmodel.model.children.size)
|
216
|
-
viewmodel.model.children.each do |
|
219
|
+
viewmodel.model.children.each do |child|
|
217
220
|
assert(child.persisted?)
|
218
221
|
refute(child.new_record?)
|
219
222
|
end
|
220
223
|
end
|
221
224
|
|
222
|
-
it
|
225
|
+
it 'can clone the model' do
|
223
226
|
clone_model = Cloner.new.clone(viewmodel)
|
224
227
|
|
225
228
|
assert(clone_model.new_record?)
|
@@ -244,9 +247,10 @@ class ViewModel::ActiveRecord
|
|
244
247
|
class IgnoreFirstChildCloner < Cloner
|
245
248
|
def initialize
|
246
249
|
@ignored_first = false
|
250
|
+
super
|
247
251
|
end
|
248
252
|
|
249
|
-
def visit_child_view(
|
253
|
+
def visit_child_view(_node, _model)
|
250
254
|
unless @ignored_first
|
251
255
|
@ignored_first = true
|
252
256
|
ignore!
|
@@ -254,7 +258,7 @@ class ViewModel::ActiveRecord
|
|
254
258
|
end
|
255
259
|
end
|
256
260
|
|
257
|
-
it
|
261
|
+
it 'can ignore subset of children' do
|
258
262
|
clone_model = IgnoreFirstChildCloner.new.clone(viewmodel)
|
259
263
|
|
260
264
|
assert(clone_model.new_record?)
|
@@ -265,7 +269,7 @@ class ViewModel::ActiveRecord
|
|
265
269
|
assert_equal(model.children[1].name, clone_model.children[0].name)
|
266
270
|
end
|
267
271
|
|
268
|
-
it
|
272
|
+
it 'can ignore the children association' do
|
269
273
|
clone_model = IgnoreChildrenAssociationCloner.new.clone(viewmodel)
|
270
274
|
|
271
275
|
assert(clone_model.new_record?)
|
@@ -276,19 +280,19 @@ class ViewModel::ActiveRecord
|
|
276
280
|
end
|
277
281
|
end
|
278
282
|
|
279
|
-
describe
|
283
|
+
describe 'with has_many_through shared children' do
|
280
284
|
include ViewModelSpecHelpers::ParentAndHasManyThroughChildren
|
281
285
|
def new_model_children
|
282
|
-
[
|
286
|
+
['b', 'c'].map.with_index do |n, i|
|
283
287
|
join_model_class.new(child: child_model_class.new(name: n), position: i)
|
284
288
|
end
|
285
289
|
end
|
286
290
|
|
287
291
|
def new_model
|
288
|
-
model_class.new(
|
292
|
+
model_class.new(name: 'a', model_children: new_model_children)
|
289
293
|
end
|
290
294
|
|
291
|
-
it
|
295
|
+
it 'persists the test setup' do
|
292
296
|
assert(viewmodel.model.persisted?)
|
293
297
|
refute(viewmodel.model.new_record?)
|
294
298
|
assert_equal(2, viewmodel.model.model_children.size)
|
@@ -301,7 +305,7 @@ class ViewModel::ActiveRecord
|
|
301
305
|
end
|
302
306
|
end
|
303
307
|
|
304
|
-
it
|
308
|
+
it 'can clone the model and join model but not the child' do
|
305
309
|
clone_model = Cloner.new.clone(viewmodel)
|
306
310
|
|
307
311
|
assert(clone_model.new_record?)
|
@@ -325,7 +329,7 @@ class ViewModel::ActiveRecord
|
|
325
329
|
end
|
326
330
|
end
|
327
331
|
|
328
|
-
it
|
332
|
+
it 'can ignore the children association' do
|
329
333
|
clone_model = IgnoreChildrenAssociationCloner.new.clone(viewmodel)
|
330
334
|
|
331
335
|
assert(clone_model.new_record?)
|