forked from ManageIQ/manageiq
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsupports_feature_mixin_spec.rb
312 lines (256 loc) · 9.05 KB
/
supports_feature_mixin_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
describe SupportsFeatureMixin do
before do
stub_const('SupportsFeatureMixin::QUERYABLE_FEATURES',
SupportsFeatureMixin::QUERYABLE_FEATURES.merge(
:publish => 'publish the post',
:archive => 'archive the post',
:fake => 'fake it',
:nuke => 'nuke it'
))
stub_const('Post::Operations::Publishing', Module.new do
extend ActiveSupport::Concern
included do
supports :publish
end
end)
stub_const('Post::Operations', Module.new do
extend ActiveSupport::Concern
include Post::Operations::Publishing
included do
supports :archive
supports_not :delete
supports_not :fake, :reason => 'We keep it real!'
end
end)
stub_const('Post', Class.new do
include SupportsFeatureMixin
include Post::Operations
end)
stub_const('SpecialPost::Operations', Module.new do
extend ActiveSupport::Concern
included do
supports :fake do
unsupported_reason_add(:fake, 'Need more money') unless bribe
end
end
end)
stub_const('SpecialPost', Class.new(Post) do
include SupportsFeatureMixin
include SpecialPost::Operations
attr_accessor :bribe
def initialize(options = {})
self.bribe = options[:bribe]
end
end)
end
context "defines method" do
it "supports_feature? on the class" do
expect(Post.respond_to?(:supports_publish?)).to be true
end
it "supports_feature? on the instance" do
expect(Post.new.respond_to?(:supports_publish?)).to be true
end
it "unsupported_reason on the class" do
expect(Post.respond_to?(:unsupported_reason)).to be true
end
it "unsupported_reason on the instance" do
expect(Post.new.respond_to?(:unsupported_reason)).to be true
end
end
context "for a supported feature" do
it ".supports_feature? is true" do
expect(Post.supports_publish?).to be true
end
it ".supports?(feature) is true" do
expect(Post.supports?(:publish)).to be true
end
it "#supports_feature? is true" do
expect(Post.new.supports_publish?).to be true
end
it "#unsupported_reason(:feature) is nil" do
expect(Post.new.unsupported_reason(:publish)).to be nil
end
it ".unsupported_reason(:feature) is nil" do
expect(Post.unsupported_reason(:publish)).to be nil
end
end
context "for an unsupported feature" do
it ".supports_feature? is false" do
expect(Post.supports_fake?).to be false
end
it "#supports_feature? is false" do
expect(Post.new.supports_fake?).to be false
end
it "#unsupported_reason(:feature) returns a reason" do
expect(Post.new.unsupported_reason(:fake)).to eq "We keep it real!"
end
it ".unsupported_reason(:feature) returns a reason" do
expect(Post.unsupported_reason(:fake)).to eq "We keep it real!"
end
end
context "for an unsupported feature without a reason" do
it ".supports_feature? is false" do
expect(Post.supports_delete?).to be false
end
it "#supports_feature? is false" do
expect(Post.new.supports_delete?).to be false
end
it "#unsupported_reason(:feature) returns some default reason" do
expect(Post.new.unsupported_reason(:delete)).not_to be_blank
end
it ".unsupported_reason(:feature) returns no reason" do
expect(Post.unsupported_reason(:delete)).not_to be_blank
end
end
context "definition in nested modules" do
it "defines a class method on the model" do
expect(Post.respond_to?(:supports_archive?)).to be true
end
it "defines an instance method" do
expect(Post.new.respond_to?(:supports_archive?)).to be true
end
end
context "a feature defined on the base class" do
it "defines supports_feature? on the subclass" do
expect(SpecialPost.respond_to?(:supports_publish?)).to be true
end
it "defines supports_feature? on an instance of the subclass" do
expect(SpecialPost.new.respond_to?(:supports_publish?)).to be true
end
it "can be overriden on the subclass" do
expect(SpecialPost.supports_fake?).to be true
end
end
context "conditionally supported feature" do
context "when the condition is met" do
it "is supported on the class" do
expect(SpecialPost.supports_fake?).to be true
end
it "is supported on the instance" do
expect(SpecialPost.new(:bribe => true).supports_fake?).to be true
end
it "gives no reason on the class" do
expect(SpecialPost.unsupported_reason(:fake)).to be nil
end
it "gives no reason on the instance" do
expect(SpecialPost.new(:bribe => true).unsupported_reason(:fake)).to be nil
end
end
context "when the condition is not met" do
it "gives a reason on the instance" do
special_post = SpecialPost.new
expect(special_post.supports_fake?).to be false
expect(special_post.unsupported_reason(:fake)).to eq "Need more money"
end
it "gives a reason without calling supports_feature? first" do
expect(SpecialPost.new.unsupported_reason(:fake)).to eq "Need more money"
end
end
context "when the condition changes on the instance" do
it "is checks the current condition" do
special_post = SpecialPost.new
expect(special_post.supports_fake?).to be false
expect(special_post.unsupported_reason(:fake)).to eq "Need more money"
special_post.bribe = true
expect(special_post.supports_fake?).to be true
expect(special_post.unsupported_reason(:fake)).to be nil
end
end
end
context "guards against unqueriable features" do
it "when defining a class with :supports_not" do
stub_const("MegaPost", Class.new)
expect do
class MegaPost
include SupportsFeatureMixin
supports_not :mega
end
end.to raise_error(SupportsFeatureMixin::UnknownFeatureError)
end
it "when defining a class with :supports" do
stub_const("MegaPost", Class.new)
expect do
class MegaPost
include SupportsFeatureMixin
supports :mega
end
end.to raise_error(SupportsFeatureMixin::UnknownFeatureError)
end
it "when querying a feature on the class" do
expect do
SpecialPost.supports?('mega')
end.to raise_error(SupportsFeatureMixin::UnknownFeatureError)
end
it "when querying a feature on the instance" do
expect do
SpecialPost.new.supports?('mega')
end.to raise_error(SupportsFeatureMixin::UnknownFeatureError)
end
it "when querying a reason on the class" do
expect do
SpecialPost.unsupported_reason(:mega)
end.to raise_error(SupportsFeatureMixin::UnknownFeatureError)
end
it "when querying a reason on the instance" do
expect do
SpecialPost.new.unsupported_reason(:mega)
end.to raise_error(SupportsFeatureMixin::UnknownFeatureError)
end
end
context "can be queried for features" do
it "that are known on the class" do
expect(Post.feature_known?("fake")).to be true
end
it "that are unknown on the class" do
expect(Post.feature_known?("lobotomize")).to be false
end
it "that are known on the instance" do
expect(Post.new.feature_known?("fake")).to be true
end
it "that are unknown on the instance" do
expect(Post.new.feature_known?("lobotomize")).to be false
end
end
context "feature that is implicitly unsupported" do
it "is unsupported by a class" do
expect(Post.supports_nuke?).to be false
end
it "is unsupported by an instance of the class" do
expect(Post.new.supports_nuke?).to be false
end
it "can be supported by the class" do
stub_const("NukeablePost", Class.new(SpecialPost) do
supports :nuke do
unsupported_reason_add(:nuke, "dont nuke the bribe") if bribe
end
end)
expect(NukeablePost.new(:bribe => true).supports_nuke?).to be false
expect(NukeablePost.new(:bribe => false).supports_nuke?).to be true
end
end
context 'included in a module' do
before do
stub_const('MyModule', Module.new do
include SupportsFeatureMixin
supports_not :publish # supported in base class Post
supports :fake do # unsupported in base class Post
unsupported_reason_add(:fake, "We never fake")
end
end)
stub_const('SomePost', Class.new(Post) do
include MyModule
end)
end
it "does not affect undefined features" do
expect(SomePost.new.supports_delete?).to be false
expect(SomePost.supports_delete?).to be false
end
it "overrides features defined on the class with those in the module" do
expect(SomePost.new.supports_publish?).to be false
expect(SomePost.supports_publish?).to be false
expect(SomePost.supports_fake?).to be true
expect(SomePost.new.supports_fake?).to be false
expect(SomePost.new.unsupported_reason(:fake)).to eq('We never fake')
end
end
end