shoulda-matchers 3.1.3 → 4.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.hound/ruby.yml +336 -316
  3. data/.python-version +1 -0
  4. data/.rubocop.yml +3 -1
  5. data/.travis.yml +7 -6
  6. data/Appraisals +76 -44
  7. data/CONTRIBUTING.md +137 -66
  8. data/Gemfile +5 -5
  9. data/Gemfile.lock +30 -35
  10. data/MAINTAINING.md +250 -0
  11. data/MIT-LICENSE +1 -1
  12. data/NEWS.md +176 -4
  13. data/README.md +138 -200
  14. data/Rakefile +7 -0
  15. data/bin/setup +190 -0
  16. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +4 -0
  17. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +0 -6
  18. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +0 -17
  19. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +27 -0
  20. data/gemfiles/4.2.gemfile +21 -20
  21. data/gemfiles/4.2.gemfile.lock +143 -140
  22. data/gemfiles/5.0.gemfile +37 -0
  23. data/gemfiles/5.0.gemfile.lock +238 -0
  24. data/gemfiles/5.1.gemfile +38 -0
  25. data/gemfiles/5.1.gemfile.lock +254 -0
  26. data/gemfiles/5.2.gemfile +40 -0
  27. data/gemfiles/5.2.gemfile.lock +273 -0
  28. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +18 -6
  29. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +6 -1
  30. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +1 -1
  31. data/lib/shoulda/matchers/action_controller/route_matcher.rb +87 -27
  32. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +1 -0
  33. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +0 -4
  34. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +5 -0
  35. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +5 -0
  36. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +26 -11
  37. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +39 -4
  38. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +116 -47
  39. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +127 -38
  40. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +55 -37
  41. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +30 -1
  42. data/lib/shoulda/matchers/active_model/validation_matcher.rb +11 -4
  43. data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +11 -6
  44. data/lib/shoulda/matchers/active_record.rb +3 -0
  45. data/lib/shoulda/matchers/active_record/association_matcher.rb +172 -22
  46. data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +1 -1
  47. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +11 -6
  48. data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +46 -0
  49. data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +51 -0
  50. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +268 -38
  51. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
  52. data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +111 -0
  53. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +207 -79
  54. data/lib/shoulda/matchers/doublespeak/object_double.rb +5 -1
  55. data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +100 -21
  56. data/lib/shoulda/matchers/rails_shim.rb +133 -52
  57. data/lib/shoulda/matchers/routing.rb +2 -2
  58. data/lib/shoulda/matchers/util.rb +23 -1
  59. data/lib/shoulda/matchers/util/word_wrap.rb +6 -2
  60. data/lib/shoulda/matchers/version.rb +1 -1
  61. data/script/install_gems_in_all_appraisals +3 -1
  62. data/script/run_all_tests +3 -1
  63. data/script/supported_ruby_versions +7 -0
  64. data/script/update_gem_in_all_appraisals +3 -1
  65. data/script/update_gems_in_all_appraisals +3 -1
  66. data/shoulda-matchers.gemspec +3 -3
  67. data/spec/acceptance/independent_matchers_spec.rb +2 -2
  68. data/spec/acceptance/multiple_libraries_integration_spec.rb +1 -1
  69. data/spec/acceptance/rails_integration_spec.rb +2 -2
  70. data/spec/spec_helper.rb +2 -3
  71. data/spec/support/acceptance/helpers.rb +2 -0
  72. data/spec/support/acceptance/helpers/command_helpers.rb +17 -4
  73. data/spec/support/acceptance/helpers/rails_migration_helpers.rb +21 -0
  74. data/spec/support/acceptance/helpers/step_helpers.rb +1 -1
  75. data/spec/support/tests/current_bundle.rb +3 -9
  76. data/spec/support/tests/filesystem.rb +2 -2
  77. data/spec/support/unit/attribute.rb +0 -2
  78. data/spec/support/unit/capture.rb +9 -3
  79. data/spec/support/unit/helpers/action_pack_versions.rb +22 -0
  80. data/spec/support/unit/helpers/active_model_versions.rb +4 -0
  81. data/spec/support/unit/helpers/active_record_versions.rb +22 -2
  82. data/spec/support/unit/helpers/active_resource_builder.rb +2 -2
  83. data/spec/support/unit/helpers/controller_builder.rb +1 -1
  84. data/spec/support/unit/helpers/message_helpers.rb +19 -0
  85. data/spec/support/unit/helpers/rails_versions.rb +14 -0
  86. data/spec/support/unit/matchers/fail_with_message_matcher.rb +7 -5
  87. data/spec/support/unit/matchers/print_warning_including.rb +21 -13
  88. data/spec/support/unit/model_creation_strategies/active_record.rb +1 -1
  89. data/spec/support/unit/model_creators/active_record.rb +0 -1
  90. data/spec/support/unit/model_creators/basic.rb +7 -2
  91. data/spec/support/unit/rails_application.rb +25 -0
  92. data/spec/support/unit/record_validating_confirmation_builder.rb +5 -2
  93. data/spec/support/unit/validation_matcher_scenario.rb +0 -2
  94. data/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb +18 -18
  95. data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +33 -5
  96. data/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb +1 -1
  97. data/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +80 -78
  98. data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +7 -9
  99. data/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +28 -4
  100. data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +19 -1
  101. data/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +27 -4
  102. data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +62 -5
  103. data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +52 -18
  104. data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +51 -4
  105. data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +99 -71
  106. data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +41 -15
  107. data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +445 -15
  108. data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +615 -93
  109. data/spec/unit/shoulda/matchers/active_record/have_secure_token_matcher_spec.rb +169 -0
  110. data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +167 -97
  111. data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +2 -4
  112. data/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb +152 -19
  113. data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +258 -94
  114. data/spec/unit_spec_helper.rb +9 -1
  115. data/zeus.json +1 -1
  116. metadata +31 -16
  117. data/gemfiles/4.0.0.gemfile +0 -38
  118. data/gemfiles/4.0.0.gemfile.lock +0 -223
  119. data/gemfiles/4.0.1.gemfile +0 -38
  120. data/gemfiles/4.0.1.gemfile.lock +0 -225
  121. data/gemfiles/4.1.gemfile +0 -38
  122. data/gemfiles/4.1.gemfile.lock +0 -220
  123. data/script/SUPPORTED_VERSIONS +0 -1
@@ -1,168 +1,690 @@
1
- require "unit_spec_helper"
1
+ require 'unit_spec_helper'
2
2
 
3
3
  describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do
4
- if active_record_supports_enum?
5
- context 'if the attribute is given in plural form accidentally' do
6
- it 'rejects' do
7
- record = record_with_array_values
8
- plural_enum_attribute = enum_attribute.to_s.pluralize
9
- message = "Expected #{record.class} to define :#{plural_enum_attribute} as an enum and store the value in a column with an integer type"
4
+ context 'if the attribute is given in plural form accidentally' do
5
+ it 'rejects with an appropriate failure message' do
6
+ record = build_record_with_array_values(
7
+ model_name: 'Example',
8
+ attribute_name: :attr,
9
+ column_type: :integer,
10
+ )
11
+ message = format_message(<<-MESSAGE)
12
+ Expected Example to define :attrs as an enum, backed by an integer.
13
+ However, no such enum exists in Example.
14
+ MESSAGE
15
+
16
+ assertion = lambda do
17
+ expect(record).to define_enum_for(:attrs)
18
+ end
19
+
20
+ expect(&assertion).to fail_with_message(message)
21
+ end
22
+ end
23
+
24
+ context 'if a method to hold enum values exists on the model but was not created via the enum macro' do
25
+ it 'rejects with an appropriate failure message' do
26
+ model = define_model 'Example' do
27
+ def self.statuses; end
28
+ end
29
+
30
+ message = format_message(<<-MESSAGE)
31
+ Expected Example to define :attr as an enum, backed by an integer.
32
+ However, no such enum exists in Example.
33
+ MESSAGE
34
+
35
+ assertion = lambda do
36
+ expect(model.new).to define_enum_for(:attr)
37
+ end
38
+
39
+ expect(&assertion).to fail_with_message(message)
40
+ end
41
+ end
42
+
43
+ describe 'with only the attribute name specified' do
44
+ context 'if the attribute is not defined as an enum' do
45
+ it 'rejects with an appropriate failure message' do
46
+ record = build_record_with_non_enum_attribute(
47
+ model_name: 'Example',
48
+ attribute_name: :attr,
49
+ )
50
+ message = format_message(<<-MESSAGE)
51
+ Expected Example to define :attr as an enum, backed by an integer.
52
+ However, no such enum exists in Example.
53
+ MESSAGE
10
54
 
11
55
  assertion = lambda do
12
- expect(record).to define_enum_for(plural_enum_attribute)
56
+ expect(record).to define_enum_for(:attr)
13
57
  end
14
58
 
15
59
  expect(&assertion).to fail_with_message(message)
16
60
  end
17
61
  end
18
62
 
19
- context 'if a method to hold enum values exists on the model but was not created via the enum macro' do
20
- it 'rejects' do
21
- model = define_model :example do
22
- def self.statuses; end
23
- end
24
-
25
- message = "Expected #{model} to define :statuses as an enum and store the value in a column with an integer type"
63
+ context 'if the column storing the attribute is not an integer type' do
64
+ it 'rejects with an appropriate failure message' do
65
+ record = build_record_with_array_values(
66
+ model_name: 'Example',
67
+ attribute_name: :attr,
68
+ column_type: :string,
69
+ )
70
+ message = format_message(<<-MESSAGE)
71
+ Expected Example to define :attr as an enum, backed by an integer.
72
+ However, :attr is a string column.
73
+ MESSAGE
26
74
 
27
75
  assertion = lambda do
28
- expect(model.new).to define_enum_for(:statuses)
76
+ expect(record).to define_enum_for(:attr)
29
77
  end
30
78
 
31
79
  expect(&assertion).to fail_with_message(message)
32
80
  end
33
81
  end
34
82
 
35
- describe "with only the attribute name specified" do
36
- it "accepts a record where the attribute is defined as an enum" do
37
- expect(record_with_array_values).to define_enum_for(enum_attribute)
83
+ context 'if the attribute is defined as an enum' do
84
+ it 'accepts' do
85
+ record = build_record_with_array_values(attribute_name: :attr)
86
+
87
+ expect(record).to define_enum_for(:attr)
38
88
  end
39
89
 
40
- it "rejects a record where the attribute is not defined as an enum" do
41
- message = "Expected #{record_with_array_values.class} to define :#{non_enum_attribute} as an enum and store the value in a column with an integer type"
90
+ context 'and the matcher is negated' do
91
+ it 'rejects with an appropriate failure message' do
92
+ record = build_record_with_array_values(
93
+ model_name: 'Example',
94
+ attribute_name: :attr,
95
+ column_type: :integer,
96
+ )
97
+ message = format_message(<<-MESSAGE)
98
+ Expected Example not to define :attr as an enum, backed by an integer,
99
+ but it did.
100
+ MESSAGE
42
101
 
43
- assertion = lambda do
44
- expect(record_with_array_values).
45
- to define_enum_for(non_enum_attribute)
46
- end
102
+ assertion = lambda do
103
+ expect(record).not_to define_enum_for(:attr)
104
+ end
47
105
 
48
- expect(&assertion).to fail_with_message(message)
106
+ expect(&assertion).to fail_with_message(message)
107
+ end
49
108
  end
109
+ end
110
+ end
50
111
 
51
- it "rejects a record where the attribute is not defined as an enum with should not" do
52
- message = "Did not expect #{record_with_array_values.class} to define :#{enum_attribute} as an enum and store the value in a column with an integer type"
112
+ describe 'with both attribute name and enum values specified' do
113
+ context 'when the actual enum values are an array' do
114
+ context 'if the attribute is not defined as an enum' do
115
+ it 'rejects with an appropriate failure message' do
116
+ record = build_record_with_non_enum_attribute(
117
+ model_name: 'Example',
118
+ attribute_name: :attr,
119
+ )
120
+ message = format_message(<<-MESSAGE)
121
+ Expected Example to define :attr as an enum, backed by an integer,
122
+ with possible values ‹["open", "close"]›. However, no such enum
123
+ exists in Example.
124
+ MESSAGE
53
125
 
54
- assertion = lambda do
55
- expect(record_with_array_values).
56
- not_to define_enum_for(enum_attribute)
126
+ assertion = lambda do
127
+ expect(record).
128
+ to define_enum_for(:attr).
129
+ with_values(['open', 'close'])
130
+ end
131
+
132
+ expect(&assertion).to fail_with_message(message)
57
133
  end
134
+ end
58
135
 
59
- expect(&assertion).to fail_with_message(message)
136
+ context 'if the attribute is defined as an enum' do
137
+ context 'but the enum values do not match' do
138
+ it 'rejects with an appropriate failure message' do
139
+ record = build_record_with_array_values(
140
+ model_name: 'Example',
141
+ attribute_name: :attr,
142
+ values: ['published', 'unpublished', 'draft'],
143
+ )
144
+ message = format_message(<<-MESSAGE)
145
+ Expected Example to define :attr as an enum, backed by an integer,
146
+ with possible values ‹["open", "close"]›. However, the actual
147
+ enum values for :attr are ‹["published", "unpublished", "draft"]›.
148
+ MESSAGE
149
+
150
+ assertion = lambda do
151
+ expect(record).
152
+ to define_enum_for(:attr).
153
+ with_values(['open', 'close'])
154
+ end
155
+
156
+ expect(&assertion).to fail_with_message(message)
157
+ end
158
+ end
159
+
160
+ context 'and the enum values match' do
161
+ it 'accepts' do
162
+ record = build_record_with_array_values(
163
+ attribute_name: :attr,
164
+ values: ['published', 'unpublished', 'draft'],
165
+ )
166
+
167
+ expect(record).to define_enum_for(:attr).
168
+ with_values(['published', 'unpublished', 'draft'])
169
+ end
170
+ end
60
171
  end
172
+ end
61
173
 
62
- context 'if the column storing the attribute is not an integer type' do
63
- it 'rejects' do
64
- record = record_with_array_values(column_type: :string)
65
- message = "Expected #{record.class} to define :statuses as an enum and store the value in a column with an integer type"
174
+ context 'when the actual enum values are a hash' do
175
+ context 'if the attribute is not defined as an enum' do
176
+ it 'rejects with an appropriate failure message' do
177
+ record = build_record_with_non_enum_attribute(
178
+ model_name: 'Example',
179
+ attribute_name: :attr,
180
+ )
181
+ message = format_message(<<-MESSAGE)
182
+ Expected Example to define :attr as an enum, backed by an integer,
183
+ with possible values ‹{active: 5, archived: 10}›. However, no such
184
+ enum exists in Example.
185
+ MESSAGE
66
186
 
67
187
  assertion = lambda do
68
- expect(record).to define_enum_for(:statuses)
188
+ expect(record).
189
+ to define_enum_for(:attr).
190
+ with_values(active: 5, archived: 10)
69
191
  end
70
192
 
71
193
  expect(&assertion).to fail_with_message(message)
72
194
  end
73
195
  end
196
+
197
+ context 'if the attribute is defined as an enum' do
198
+ context 'but the enum values do not match' do
199
+ it 'rejects with an appropriate failure message' do
200
+ record = build_record_with_hash_values(
201
+ model_name: 'Example',
202
+ attribute_name: :attr,
203
+ values: { active: 0, archived: 1 },
204
+ )
205
+ message = format_message(<<-MESSAGE)
206
+ Expected Example to define :attr as an enum, backed by an integer,
207
+ with possible values ‹{active: 5, archived: 10}›. However, the
208
+ actual enum values for :attr are ‹{active: 0, archived: 1}›.
209
+ MESSAGE
210
+
211
+ assertion = lambda do
212
+ expect(record).
213
+ to define_enum_for(:attr).
214
+ with_values(active: 5, archived: 10)
215
+ end
216
+
217
+ expect(&assertion).to fail_with_message(message)
218
+ end
219
+ end
220
+
221
+ context 'and the enum values match' do
222
+ context 'when expected enum values are a hash' do
223
+ it 'accepts' do
224
+ record = build_record_with_hash_values(
225
+ attribute_name: :attr,
226
+ values: { active: 0, archived: 1 },
227
+ )
228
+
229
+ expect(record).
230
+ to define_enum_for(:attr).
231
+ with_values(active: 0, archived: 1)
232
+ end
233
+ end
234
+
235
+ context 'when expected enum values are an array' do
236
+ it 'accepts' do
237
+ record = build_record_with_hash_values(
238
+ attribute_name: :attr,
239
+ values: { active: 0, archived: 1 },
240
+ )
241
+
242
+ expect(record).
243
+ to define_enum_for(:attr).
244
+ with_values(['active', 'archived'])
245
+ end
246
+ end
247
+ end
248
+ end
74
249
  end
250
+ end
251
+
252
+ context 'with values specified using #with' do
253
+ it 'produces a warning' do
254
+ record = build_record_with_array_values(
255
+ attribute_name: :attr,
256
+ values: [:foo, :bar],
257
+ )
258
+
259
+ assertion = lambda do
260
+ expect(record).to define_enum_for(:attr).with([:foo, :bar])
261
+ end
75
262
 
76
- describe "with both attribute name and enum values specified" do
77
- context "when the actual enum values are an array" do
78
- it "accepts a record where the attribute is defined as an enum and the enum values match" do
79
- expect(record_with_array_values).to define_enum_for(enum_attribute).
80
- with(["published", "unpublished", "draft"])
263
+ expect(&assertion).to deprecate(
264
+ 'The `with` qualifier on `define_enum_for`',
265
+ '`with_values`',
266
+ )
267
+ end
268
+ end
269
+
270
+ describe 'with the backing column specified to be of some type' do
271
+ context 'if the column storing the attribute is of a different type' do
272
+ it 'rejects with an appropriate failure message' do
273
+ record = build_record_with_array_values(
274
+ model_name: 'Example',
275
+ attribute_name: :attr,
276
+ column_type: :integer,
277
+ )
278
+ message = format_message(<<-MESSAGE)
279
+ Expected Example to define :attr as an enum, backed by a string.
280
+ However, :attr is an integer column.
281
+ MESSAGE
282
+
283
+ assertion = lambda do
284
+ expect(record).
285
+ to define_enum_for(:attr).
286
+ backed_by_column_of_type(:string)
81
287
  end
82
288
 
83
- it "accepts a record where the attribute is not defined as an enum" do
84
- message = %{Expected #{record_with_array_values.class} to define :#{non_enum_attribute} as an enum with ["open", "close"] and store the value in a column with an integer type}
289
+ expect(&assertion).to fail_with_message(message)
290
+ end
291
+ end
292
+
293
+ context 'if the column storing the attribute is of the same type' do
294
+ it 'accepts' do
295
+ record = build_record_with_array_values(
296
+ attribute_name: :attr,
297
+ column_type: :string,
298
+ )
85
299
 
86
- assertion = lambda do
87
- expect(record_with_array_values).
88
- to define_enum_for(non_enum_attribute).with(['open', 'close'])
300
+ expect(record).
301
+ to define_enum_for(:attr).
302
+ backed_by_column_of_type(:string)
303
+ end
304
+ end
305
+ end
306
+
307
+ if active_record_enum_supports_prefix_and_suffix?
308
+ context 'qualified with #with_prefix' do
309
+ context 'when the prefix is explicit' do
310
+ context 'if the attribute was not defined with a prefix' do
311
+ it 'rejects with an appropriate failure message' do
312
+ record = build_record_with_array_values(
313
+ model_name: 'Example',
314
+ attribute_name: :attr,
315
+ column_type: :integer,
316
+ values: [:active, :archived],
317
+ )
318
+
319
+ assertion = lambda do
320
+ expect(record).
321
+ to define_enum_for(:attr).
322
+ with_values([:active, :archived]).
323
+ with_prefix(:foo)
324
+ end
325
+
326
+ message = format_message(<<-MESSAGE)
327
+ Expected Example to define :attr as an enum, backed by an integer,
328
+ using a prefix of :foo, with possible values ‹[:active,
329
+ :archived]›. However, it was defined with either a different
330
+ prefix or none at all.
331
+ MESSAGE
332
+
333
+ expect(&assertion).to fail_with_message(message)
89
334
  end
335
+ end
90
336
 
91
- expect(&assertion).to fail_with_message(message)
337
+ context 'if the attribute was defined with a different prefix' do
338
+ it 'rejects with an appropriate failure message' do
339
+ record = build_record_with_array_values(
340
+ model_name: 'Example',
341
+ attribute_name: :attr,
342
+ column_type: :integer,
343
+ values: [:active, :archived],
344
+ prefix: :foo,
345
+ )
346
+
347
+ assertion = lambda do
348
+ expect(record).
349
+ to define_enum_for(:attr).
350
+ with_values([:active, :archived]).
351
+ with_prefix(:bar)
352
+ end
353
+
354
+ message = format_message(<<-MESSAGE)
355
+ Expected Example to define :attr as an enum, backed by an integer,
356
+ using a prefix of :bar, with possible values ‹[:active,
357
+ :archived]›. However, it was defined with either a different
358
+ prefix or none at all.
359
+ MESSAGE
360
+
361
+ expect(&assertion).to fail_with_message(message)
362
+ end
92
363
  end
93
364
 
94
- it "accepts a record where the attribute is defined as an enum but the enum values do not match" do
95
- message = %{Expected #{record_with_array_values.class} to define :#{enum_attribute} as an enum with ["open", "close"] and store the value in a column with an integer type}
365
+ context 'if the attribute was defined with the same prefix' do
366
+ it 'accepts' do
367
+ record = build_record_with_array_values(
368
+ model_name: 'Example',
369
+ attribute_name: :attr,
370
+ values: [:active, :archived],
371
+ prefix: :foo,
372
+ )
373
+
374
+ expect(record).
375
+ to define_enum_for(:attr).
376
+ with_values([:active, :archived]).
377
+ with_prefix(:foo)
378
+ end
379
+ end
380
+ end
96
381
 
97
- assertion = lambda do
98
- expect(record_with_array_values).
99
- to define_enum_for(enum_attribute).
100
- with(["open", "close"])
382
+ context 'when the prefix is implicit' do
383
+ context 'if the attribute was not defined with a prefix' do
384
+ it 'rejects with an appropriate failure message' do
385
+ record = build_record_with_array_values(
386
+ model_name: 'Example',
387
+ attribute_name: :attr,
388
+ column_type: :integer,
389
+ values: [:active, :archived],
390
+ )
391
+
392
+ assertion = lambda do
393
+ expect(record).
394
+ to define_enum_for(:attr).
395
+ with_values([:active, :archived]).
396
+ with_prefix
397
+ end
398
+
399
+ message = format_message(<<-MESSAGE)
400
+ Expected Example to define :attr as an enum, backed by an integer,
401
+ using a prefix of :attr, with possible values ‹[:active,
402
+ :archived]›. However, it was defined with either a different
403
+ prefix or none at all.
404
+ MESSAGE
405
+
406
+ expect(&assertion).to fail_with_message(message)
101
407
  end
408
+ end
102
409
 
103
- expect(&assertion).to fail_with_message(message)
410
+ context 'if the attribute was defined with a prefix' do
411
+ it 'accepts' do
412
+ record = build_record_with_array_values(
413
+ model_name: 'Example',
414
+ attribute_name: :attr,
415
+ values: [:active, :archived],
416
+ prefix: true,
417
+ )
418
+
419
+ expect(record).
420
+ to define_enum_for(:attr).
421
+ with_values([:active, :archived]).
422
+ with_prefix
423
+ end
104
424
  end
105
425
  end
426
+ end
106
427
 
107
- context "when the actual enum values are a hash" do
108
- it "accepts a record where the attribute is defined as an enum and the enum values match" do
109
- expect(record_with_hash_values).to define_enum_for(enum_attribute).with(active: 0, archived: 1)
428
+ context 'qualified with #with_suffix' do
429
+ context 'when the suffix is explicit' do
430
+ context 'if the attribute was not defined with a suffix' do
431
+ it 'rejects with an appropriate failure message' do
432
+ record = build_record_with_array_values(
433
+ model_name: 'Example',
434
+ attribute_name: :attr,
435
+ column_type: :integer,
436
+ values: [:active, :archived],
437
+ )
438
+
439
+ assertion = lambda do
440
+ expect(record).
441
+ to define_enum_for(:attr).
442
+ with_values([:active, :archived]).
443
+ with_suffix(:foo)
444
+ end
445
+
446
+ message = format_message(<<-MESSAGE)
447
+ Expected Example to define :attr as an enum, backed by an integer,
448
+ using a suffix of :foo, with possible values ‹[:active,
449
+ :archived]›. However, it was defined with either a different
450
+ suffix or none at all.
451
+ MESSAGE
452
+
453
+ expect(&assertion).to fail_with_message(message)
454
+ end
110
455
  end
111
456
 
112
- it "accepts a record where the enum values match when expected enum values are given as an array" do
113
- expect(record_with_hash_values).to define_enum_for(enum_attribute).with(["active", "archived"])
457
+ context 'if the attribute was defined with a different suffix' do
458
+ it 'rejects with an appropriate failure message' do
459
+ record = build_record_with_array_values(
460
+ model_name: 'Example',
461
+ attribute_name: :attr,
462
+ column_type: :integer,
463
+ values: [:active, :archived],
464
+ suffix: :foo,
465
+ )
466
+
467
+ assertion = lambda do
468
+ expect(record).
469
+ to define_enum_for(:attr).
470
+ with_values([:active, :archived]).
471
+ with_suffix(:bar)
472
+ end
473
+
474
+ message = format_message(<<-MESSAGE)
475
+ Expected Example to define :attr as an enum, backed by an integer,
476
+ using a suffix of :bar, with possible values ‹[:active,
477
+ :archived]›. However, it was defined with either a different
478
+ suffix or none at all.
479
+ MESSAGE
480
+
481
+ expect(&assertion).to fail_with_message(message)
482
+ end
114
483
  end
115
484
 
116
- it "accepts a record where the attribute is defined as an enum but the enum values do not match" do
117
- message = %{Expected #{record_with_hash_values.class} to define :#{enum_attribute} as an enum with {:active=>5, :archived=>10} and store the value in a column with an integer type}
485
+ context 'if the attribute was defined with the same suffix' do
486
+ it 'accepts' do
487
+ record = build_record_with_array_values(
488
+ model_name: 'Example',
489
+ attribute_name: :attr,
490
+ values: [:active, :archived],
491
+ suffix: :foo,
492
+ )
493
+
494
+ expect(record).
495
+ to define_enum_for(:attr).
496
+ with_values([:active, :archived]).
497
+ with_suffix(:foo)
498
+ end
499
+ end
500
+ end
118
501
 
119
- assertion = lambda do
120
- expect(record_with_hash_values).
121
- to define_enum_for(enum_attribute).
122
- with(active: 5, archived: 10)
502
+ context 'when the suffix is implicit' do
503
+ context 'if the attribute was not defined with a suffix' do
504
+ it 'rejects with an appropriate failure message' do
505
+ record = build_record_with_array_values(
506
+ model_name: 'Example',
507
+ attribute_name: :attr,
508
+ column_type: :integer,
509
+ values: [:active, :archived],
510
+ )
511
+
512
+ assertion = lambda do
513
+ expect(record).
514
+ to define_enum_for(:attr).
515
+ with_values([:active, :archived]).
516
+ with_suffix
517
+ end
518
+
519
+ message = format_message(<<-MESSAGE)
520
+ Expected Example to define :attr as an enum, backed by an integer,
521
+ using a suffix of :attr, with possible values ‹[:active,
522
+ :archived]›. However, it was defined with either a different
523
+ suffix or none at all.
524
+ MESSAGE
525
+
526
+ expect(&assertion).to fail_with_message(message)
123
527
  end
528
+ end
124
529
 
125
- expect(&assertion).to fail_with_message(message)
530
+ context 'if the attribute was defined with a suffix' do
531
+ it 'accepts' do
532
+ record = build_record_with_array_values(
533
+ model_name: 'Example',
534
+ attribute_name: :attr,
535
+ values: [:active, :archived],
536
+ suffix: true,
537
+ )
538
+
539
+ expect(record).
540
+ to define_enum_for(:attr).
541
+ with_values([:active, :archived]).
542
+ with_suffix
543
+ end
126
544
  end
545
+ end
546
+ end
127
547
 
128
- it "rejects a record where the attribute is not defined as an enum" do
129
- message = %{Expected #{record_with_hash_values.class} to define :record_with_hash_values as an enum with {:active=>5, :archived=>10} and store the value in a column with an integer type}
548
+ context 'qualified with both #with_prefix and #with_suffix' do
549
+ context 'if the attribute was not defined with a different prefix' do
550
+ it 'rejects with an appropriate failure message' do
551
+ record = build_record_with_array_values(
552
+ model_name: 'Example',
553
+ attribute_name: :attr,
554
+ column_type: :integer,
555
+ values: [:active, :archived],
556
+ prefix: :foo,
557
+ suffix: :bar,
558
+ )
130
559
 
131
560
  assertion = lambda do
132
- expect(record_with_hash_values).
133
- to define_enum_for(:record_with_hash_values).
134
- with(active: 5, archived: 10)
561
+ expect(record).
562
+ to define_enum_for(:attr).
563
+ with_values([:active, :archived]).
564
+ with_prefix(:whatever).
565
+ with_suffix(:bar)
135
566
  end
136
567
 
568
+ message = format_message(<<-MESSAGE)
569
+ Expected Example to define :attr as an enum, backed by an integer,
570
+ using a prefix of :whatever and a suffix of :bar, with possible
571
+ values ‹[:active, :archived]›. However, it was defined with either
572
+ a different prefix, a different suffix, or neither one at all.
573
+ MESSAGE
574
+
137
575
  expect(&assertion).to fail_with_message(message)
138
576
  end
577
+
578
+ context 'if the attribute was defined with a different suffix' do
579
+ it 'rejects with an appropriate failure message' do
580
+ record = build_record_with_array_values(
581
+ model_name: 'Example',
582
+ attribute_name: :attr,
583
+ column_type: :integer,
584
+ values: [:active, :archived],
585
+ prefix: :foo,
586
+ suffix: :bar,
587
+ )
588
+
589
+ assertion = lambda do
590
+ expect(record).
591
+ to define_enum_for(:attr).
592
+ with_values([:active, :archived]).
593
+ with_prefix(:foo).
594
+ with_suffix(:whatever)
595
+ end
596
+
597
+ message = format_message(<<-MESSAGE)
598
+ Expected Example to define :attr as an enum, backed by an integer,
599
+ using a prefix of :foo and a suffix of :whatever, with possible
600
+ values ‹[:active, :archived]›. However, it was defined with
601
+ either a different prefix, a different suffix, or neither one at
602
+ all.
603
+ MESSAGE
604
+
605
+ expect(&assertion).to fail_with_message(message)
606
+ end
607
+ end
608
+
609
+ context 'if the attribute was defined with the same prefix and suffix' do
610
+ it 'accepts' do
611
+ record = build_record_with_array_values(
612
+ model_name: 'Example',
613
+ attribute_name: :attr,
614
+ values: [:active, :archived],
615
+ prefix: :foo,
616
+ suffix: :bar,
617
+ )
618
+
619
+ expect(record).
620
+ to define_enum_for(:attr).
621
+ with_values([:active, :archived]).
622
+ with_prefix(:foo).
623
+ with_suffix(:bar)
624
+ end
625
+ end
139
626
  end
140
627
  end
628
+ end
141
629
 
142
- def enum_attribute
143
- :status
144
- end
630
+ def build_record_with_array_values(
631
+ model_name: 'Example',
632
+ attribute_name: :attr,
633
+ column_type: :integer,
634
+ values: ['published', 'unpublished', 'draft'],
635
+ prefix: false,
636
+ suffix: false
637
+ )
638
+ build_record_with_enum_attribute(
639
+ model_name: model_name,
640
+ attribute_name: attribute_name,
641
+ column_type: column_type,
642
+ values: values,
643
+ prefix: prefix,
644
+ suffix: suffix,
645
+ )
646
+ end
145
647
 
146
- def non_enum_attribute
147
- :condition
148
- end
648
+ def build_record_with_hash_values(
649
+ model_name: 'Example',
650
+ attribute_name: :attr,
651
+ values: { active: 0, archived: 1 },
652
+ prefix: false,
653
+ suffix: false
654
+ )
655
+ build_record_with_enum_attribute(
656
+ model_name: model_name,
657
+ attribute_name: attribute_name,
658
+ column_type: :integer,
659
+ values: values,
660
+ prefix: prefix,
661
+ suffix: suffix,
662
+ )
663
+ end
149
664
 
150
- def record_with_array_values(column_type: :integer)
151
- model = define_model(
152
- :record_with_array_values,
153
- enum_attribute => { type: column_type },
154
- )
155
- model.enum(enum_attribute => ['published', 'unpublished', 'draft'])
156
- model.new
665
+ def build_record_with_enum_attribute(
666
+ model_name:,
667
+ attribute_name:,
668
+ column_type:,
669
+ values:,
670
+ prefix: false,
671
+ suffix: false
672
+ )
673
+ model = define_model(
674
+ model_name,
675
+ attribute_name => { type: column_type },
676
+ )
677
+
678
+ if active_record_enum_supports_prefix_and_suffix?
679
+ model.enum(attribute_name => values, _prefix: prefix, _suffix: suffix)
680
+ else
681
+ model.enum(attribute_name => values)
157
682
  end
158
683
 
159
- def record_with_hash_values
160
- model = define_model(
161
- :record_with_hash_values,
162
- enum_attribute => { type: :integer },
163
- )
164
- model.enum(enum_attribute => { active: 0, archived: 1 })
165
- model.new
166
- end
684
+ model.new
685
+ end
686
+
687
+ def build_record_with_non_enum_attribute(model_name:, attribute_name:)
688
+ define_model(model_name, attribute_name => :integer).new
167
689
  end
168
690
  end