qonfig 0.25.0 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -2
  3. data/.rubocop.yml +19 -1
  4. data/.travis.yml +7 -2
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile.lock +102 -0
  7. data/README.md +2 -0
  8. data/gemfiles/with_external_deps.gemfile.lock +112 -0
  9. data/gemfiles/without_external_deps.gemfile.lock +102 -0
  10. data/lib/qonfig.rb +1 -1
  11. data/lib/qonfig/commands/definition/load_from_env.rb +2 -0
  12. data/lib/qonfig/commands/definition/load_from_env/value_converter.rb +2 -0
  13. data/lib/qonfig/imports/direct_key.rb +8 -2
  14. data/lib/qonfig/imports/mappings.rb +8 -2
  15. data/lib/qonfig/loaders/basic.rb +2 -0
  16. data/lib/qonfig/loaders/json.rb +2 -1
  17. data/lib/qonfig/settings.rb +5 -1
  18. data/lib/qonfig/settings/key_matcher.rb +1 -1
  19. data/lib/qonfig/uploaders/base.rb +2 -0
  20. data/lib/qonfig/uploaders/yaml.rb +2 -0
  21. data/lib/qonfig/version.rb +1 -1
  22. data/qonfig.gemspec +4 -6
  23. data/sig/.keep +0 -0
  24. data/spec/features/clear_options_spec.rb +92 -0
  25. data/spec/features/compacted_config_spec.rb +308 -0
  26. data/spec/features/composition_spec.rb +207 -0
  27. data/spec/features/config_definition_and_representation_spec.rb +535 -0
  28. data/spec/features/definition_order_spec.rb +69 -0
  29. data/spec/features/dig_functionality_spec.rb +47 -0
  30. data/spec/features/dot_notation_spec.rb +159 -0
  31. data/spec/features/export_settings_spec.rb +138 -0
  32. data/spec/features/expose_json_spec.rb +281 -0
  33. data/spec/features/expose_self/format_option_dynamic_spec.rb +69 -0
  34. data/spec/features/expose_self/format_option_json_spec.rb +74 -0
  35. data/spec/features/expose_self/format_option_unsupported_spec.rb +27 -0
  36. data/spec/features/expose_self/format_option_yaml_spec.rb +77 -0
  37. data/spec/features/expose_self_spec.rb +97 -0
  38. data/spec/features/expose_yaml_spec.rb +263 -0
  39. data/spec/features/freeze_state_spec.rb +122 -0
  40. data/spec/features/get_config_keys_spec.rb +62 -0
  41. data/spec/features/get_config_values_spec.rb +41 -0
  42. data/spec/features/has_a_key_spec.rb +48 -0
  43. data/spec/features/import_settings_spec.rb +323 -0
  44. data/spec/features/indifferent_access_spec.rb +57 -0
  45. data/spec/features/inheritance_spec.rb +110 -0
  46. data/spec/features/instantiation_without_class_definition_spec.rb +59 -0
  47. data/spec/features/iteration_over_setting_keys_spec.rb +48 -0
  48. data/spec/features/load_from_env_spec.rb +240 -0
  49. data/spec/features/load_from_json_spec.rb +97 -0
  50. data/spec/features/load_from_self/format_option_json_spec.rb +31 -0
  51. data/spec/features/load_from_self/format_option_unsupported_spec.rb +27 -0
  52. data/spec/features/load_from_self/format_option_yaml_spec.rb +49 -0
  53. data/spec/features/load_from_self/with_erb_instructions_spec.rb +33 -0
  54. data/spec/features/load_from_self/with_hash_like_data_representation_spec.rb +66 -0
  55. data/spec/features/load_from_self/with_non_hash_like_data_representation_spec.rb +19 -0
  56. data/spec/features/load_from_self/without_end_data_spec.rb +11 -0
  57. data/spec/features/load_from_yaml_spec.rb +110 -0
  58. data/spec/features/load_setting_values_from_file/by_instance_method_examples.rb +171 -0
  59. data/spec/features/load_setting_values_from_file/by_macros_examples.rb +165 -0
  60. data/spec/features/load_setting_values_from_file/load_from_json_spec.rb +21 -0
  61. data/spec/features/load_setting_values_from_file/load_from_self/json_format/end_data_with_env_spec.rb +100 -0
  62. data/spec/features/load_setting_values_from_file/load_from_self/json_format/with_end_data_spec.rb +129 -0
  63. data/spec/features/load_setting_values_from_file/load_from_self/json_format/with_incorrect_end_data_spec.rb +34 -0
  64. data/spec/features/load_setting_values_from_file/load_from_self/json_format/without_end_data_spec.rb +65 -0
  65. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/end_data_with_env_spec.rb +94 -0
  66. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/with_end_data_spec.rb +126 -0
  67. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/with_incorrect_end_data_spec.rb +32 -0
  68. data/spec/features/load_setting_values_from_file/load_from_self/yaml_format/without_end_data_spec.rb +65 -0
  69. data/spec/features/load_setting_values_from_file/load_from_yaml_spec.rb +21 -0
  70. data/spec/features/load_setting_values_from_file/shared_behavior_spec.rb +33 -0
  71. data/spec/features/mixin_spec.rb +387 -0
  72. data/spec/features/non_redefineable_core_methods_spec.rb +29 -0
  73. data/spec/features/plugins/pretty_print_spec.rb +86 -0
  74. data/spec/features/plugins/toml/expose_self/format_option_toml_spec.rb +71 -0
  75. data/spec/features/plugins/toml/expose_toml_spec.rb +221 -0
  76. data/spec/features/plugins/toml/load_from_self/format_option_toml_spec.rb +27 -0
  77. data/spec/features/plugins/toml/load_from_toml_spec.rb +109 -0
  78. data/spec/features/plugins/toml/load_setting_values_from_file/load_from_toml_spec.rb +27 -0
  79. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/end_data_with_env_spec.rb +95 -0
  80. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/with_end_data_spec.rb +125 -0
  81. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/with_incorrect_end_data_spec.rb +34 -0
  82. data/spec/features/plugins/toml/load_setting_values_from_file/load_toml_from_self/without_end_data_spec.rb +65 -0
  83. data/spec/features/plugins/toml/load_setting_values_from_file/shared_behavior_spec.rb +34 -0
  84. data/spec/features/plugins/toml/save_to_toml_spec.rb +149 -0
  85. data/spec/features/plugins/vault/expose_vault_spec.rb +117 -0
  86. data/spec/features/plugins/vault/load_from_vault_spec.rb +80 -0
  87. data/spec/features/plugins_spec.rb +89 -0
  88. data/spec/features/reload_spec.rb +75 -0
  89. data/spec/features/run_code_with_temporary_settings_spec.rb +104 -0
  90. data/spec/features/save_to_file/save_to_json_spec.rb +157 -0
  91. data/spec/features/save_to_file/save_to_yaml_spec.rb +189 -0
  92. data/spec/features/settings_as_predicates_spec.rb +47 -0
  93. data/spec/features/settings_redefinition_spec.rb +30 -0
  94. data/spec/features/slice_functionality_spec.rb +69 -0
  95. data/spec/features/subset_functionality_spec.rb +49 -0
  96. data/spec/features/validation_spec.rb +916 -0
  97. data/spec/fixtures/array_settings.yml +3 -0
  98. data/spec/fixtures/expose_json/incompatible_root_structure.json +6 -0
  99. data/spec/fixtures/expose_json/incompatible_structure.json +4 -0
  100. data/spec/fixtures/expose_json/project.development.json +7 -0
  101. data/spec/fixtures/expose_json/project.json +30 -0
  102. data/spec/fixtures/expose_json/project.production.json +7 -0
  103. data/spec/fixtures/expose_json/project.staging.json +7 -0
  104. data/spec/fixtures/expose_json/project.test.json +7 -0
  105. data/spec/fixtures/expose_yaml/incompatible_structure.yml +2 -0
  106. data/spec/fixtures/expose_yaml/project.development.yml +4 -0
  107. data/spec/fixtures/expose_yaml/project.production.yml +4 -0
  108. data/spec/fixtures/expose_yaml/project.staging.yml +4 -0
  109. data/spec/fixtures/expose_yaml/project.test.yml +4 -0
  110. data/spec/fixtures/expose_yaml/project.yml +25 -0
  111. data/spec/fixtures/json_array_sample.json +14 -0
  112. data/spec/fixtures/json_object_sample.json +9 -0
  113. data/spec/fixtures/json_with_empty_object.json +6 -0
  114. data/spec/fixtures/json_with_erb.json +6 -0
  115. data/spec/fixtures/plugins/toml/expose_toml/project.development.toml +4 -0
  116. data/spec/fixtures/plugins/toml/expose_toml/project.production.toml +4 -0
  117. data/spec/fixtures/plugins/toml/expose_toml/project.staging.toml +4 -0
  118. data/spec/fixtures/plugins/toml/expose_toml/project.test.toml +4 -0
  119. data/spec/fixtures/plugins/toml/expose_toml/project.toml +27 -0
  120. data/spec/fixtures/plugins/toml/mini_file.toml +6 -0
  121. data/spec/fixtures/plugins/toml/toml_sample_with_all_types.toml +72 -0
  122. data/spec/fixtures/plugins/toml/values_file/with_env.toml +13 -0
  123. data/spec/fixtures/plugins/toml/values_file/without_env.toml +6 -0
  124. data/spec/fixtures/rubocop_settings.yml +12 -0
  125. data/spec/fixtures/shared_settings_with_aliases.yml +10 -0
  126. data/spec/fixtures/travis_settings.yml +6 -0
  127. data/spec/fixtures/values_file/with_env.json +19 -0
  128. data/spec/fixtures/values_file/with_env.yml +17 -0
  129. data/spec/fixtures/values_file/without_env.json +8 -0
  130. data/spec/fixtures/values_file/without_env.yml +5 -0
  131. data/spec/fixtures/with_empty_hash.yml +4 -0
  132. data/spec/fixtures/with_erb_instructions.yml +3 -0
  133. data/spec/spec_helper.rb +27 -0
  134. data/spec/support/meta_scopes.rb +20 -0
  135. data/spec/support/spec_support.rb +42 -0
  136. metadata +128 -11
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe '(#subset)-functionality' do
4
+ specify '#subset functionality works as expected :)' do
5
+ class SubsetableConfig < Qonfig::DataSet
6
+ setting :db do
7
+ setting :creds do
8
+ setting :user, 'D@iVeR'
9
+ setting :data, test: false
10
+ end
11
+ end
12
+
13
+ setting :adapter, :sidekiq
14
+ end
15
+
16
+ config = SubsetableConfig.new
17
+
18
+ # access to the subset (with indifferent keys type)
19
+ expect(config.subset(:db, ['db', :creds], ['db', 'creds', :user], 'adapter')).to match(
20
+ 'db' => { 'creds' => { 'user' => 'D@iVeR', 'data' => { test: false } } }, # :db
21
+ 'creds' => { 'user' => 'D@iVeR', 'data' => { test: false } }, # ['db', :creds]
22
+ 'user' => 'D@iVeR', # ['db', 'creds', :user]
23
+ 'adapter' => :sidekiq # 'adepter'
24
+ )
25
+
26
+ # try to use subset with with unexistent keys
27
+ # NOTE: :megazavr key does not exist
28
+ expect { config.subset(%i[db creds megazavr]) }.to raise_error(Qonfig::UnknownSettingError)
29
+ # NOTE: :test key does not exist
30
+ expect { config.subset(:db, :test) }.to raise_error(Qonfig::UnknownSettingError)
31
+
32
+ # you cant use subset operation over setting values - you can do it only over the setting keys!
33
+ expect { config.subset(%i[db creds data test]) }.to raise_error(Qonfig::UnknownSettingError)
34
+
35
+ # subset invokation with empty key list
36
+ # rubocop:disable Lint/RedundantSplatExpansion
37
+ expect(config.subset(*[])).to eq({})
38
+ expect(config.subset).to eq({})
39
+ # rubocop:enable Lint/RedundantSplatExpansion
40
+
41
+ # subset invokation over unexistent option
42
+ expect { config.subset(%i[db creds session]) }.to raise_error(Qonfig::UnknownSettingError)
43
+ expect { config.subset(%i[a b c d]) }.to raise_error(Qonfig::UnknownSettingError)
44
+
45
+ # invokation with incorret subset key attributes
46
+ expect { config.subset([:db, :creds, Object.new]) }.to raise_error(Qonfig::ArgumentError)
47
+ expect { config.subset(:db, 123) }.to raise_error(Qonfig::ArgumentError)
48
+ end
49
+ end
@@ -0,0 +1,916 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'Validation' do
4
+ describe 'DSL' do
5
+ specify 'fails when validation method isnt chosen' do
6
+ expect do
7
+ # NOTE: no validation block, no dataset method
8
+ Class.new(Qonfig::DataSet) { validate }
9
+ end.to raise_error(Qonfig::ValidatorArgumentError)
10
+ end
11
+
12
+ specify 'fails when you try to use both block validation and method validation' do
13
+ expect do
14
+ Class.new(Qonfig::DataSet) do
15
+ validate '*', by: :test do # NOTE: dataset mtehod
16
+ true
17
+ end # NOTE: block
18
+ end
19
+ end.to raise_error(Qonfig::ValidatorArgumentError)
20
+ end
21
+
22
+ specify 'fails when you try to use both predefined validator and any validation method' do
23
+ expect do
24
+ Class.new(Qonfig::DataSet) do
25
+ validate '*', :integer do
26
+ true
27
+ end
28
+ end
29
+ end.to raise_error(Qonfig::ValidatorArgumentError)
30
+
31
+ expect do
32
+ Class.new(Qonfig::DataSet) do
33
+ validate '*', :integer, by: :check
34
+ end
35
+ end.to raise_error(Qonfig::ValidatorArgumentError)
36
+
37
+ expect do
38
+ Class.new(Qonfig::DataSet) do
39
+ validate '*', :integer, by: :check do
40
+ true
41
+ end
42
+ end
43
+ end.to raise_error(Qonfig::ValidatorArgumentError)
44
+ end
45
+
46
+ specify 'fails when required predefined validator does not exist' do
47
+ # NOTE: incorrect name => error
48
+ expect do
49
+ Class.new(Qonfig::DataSet) do
50
+ validate '*', 1923923
51
+ end
52
+ end.to raise_error(Qonfig::ValidatorArgumentError)
53
+
54
+ # NOTE: nonexistent predefined validator => error
55
+ expect do
56
+ Class.new(Qonfig::DataSet) do
57
+ validate '*', :abracadabra
58
+ end
59
+ end.to raise_error(Qonfig::ValidatorArgumentError)
60
+
61
+ # NOTE: existent predefined validator => ok
62
+ expect do
63
+ Class.new(Qonfig::DataSet) do
64
+ validate '*', :integer
65
+ validate '*', :float
66
+ validate '*', :string
67
+ validate '*', :symbol
68
+ validate '*', :numeric
69
+ validate '*', :hash, strict: true
70
+ validate '*', :array, strict: true
71
+ validate '*', :big_decimal, strict: true
72
+ validate '*', :boolean, strict: true
73
+ end
74
+ end.not_to raise_error
75
+ end
76
+
77
+ specify 'predefned validatiors can be selected by string and symbols' do
78
+ expect do
79
+ Class.new(Qonfig::DataSet) do
80
+ validate 'a', :integer
81
+ validate 'b', 'integer', strict: true
82
+ end
83
+ end.not_to raise_error
84
+ end
85
+
86
+ specify 'dataset method validation (by:): fails on incorrect method name' do
87
+ expect do
88
+ # NOTE: only strings and symbols are supported
89
+ Class.new(Qonfig::DataSet) { validate by: 123 }
90
+ end.to raise_error(Qonfig::ValidatorArgumentError)
91
+
92
+ expect do
93
+ # NOTE: only strings and symbols are supported
94
+ Class.new(Qonfig::DataSet) { validate by: '123' }
95
+ end.not_to raise_error
96
+
97
+ expect do
98
+ # NOTE: only strings and symbols are supported
99
+ Class.new(Qonfig::DataSet) { validate by: :my_method }
100
+ end.not_to raise_error
101
+ end
102
+
103
+ specify 'you can set validation method that is not defined yet' do
104
+ expect do
105
+ Class.new(Qonfig::DataSet) do
106
+ validate by: :my_method # NOTE: not defined method
107
+ validate by: 'another_method' # NOTE: not defined method
108
+ end
109
+ end.not_to raise_error
110
+ end
111
+
112
+ specify 'correct setting key patterns' do
113
+ expect do
114
+ Class.new(Qonfig::DataSet) do
115
+ validate :db do # NOTE: symbol => correct
116
+ end
117
+
118
+ validate 'db.creds' do # NOTE: string => correct
119
+ end
120
+
121
+ validate :user, by: :my_method # NOTE: symbol => correct
122
+ validate 'password', by: :my_method # NOTE: string => correct
123
+ end
124
+ end.not_to raise_error
125
+ end
126
+
127
+ specify 'incorrect setting key patterns' do
128
+ expect do
129
+ Class.new(Qonfig::DataSet) do
130
+ validate 123, by: :my_method
131
+ end
132
+ end.to raise_error(Qonfig::ValidatorArgumentError)
133
+
134
+ expect do
135
+ Class.new(Qonfig::DataSet) do
136
+ validate 123 do
137
+ true
138
+ end
139
+ end
140
+ end.to raise_error(Qonfig::ValidatorArgumentError)
141
+ end
142
+
143
+ specify ':strict and non-strict both can be used' do
144
+ expect do
145
+ Class.new(Qonfig::DataSet) do
146
+ validate(:kek, strict: true) {}
147
+ validate(:pek, strict: false) {}
148
+ end
149
+ end.not_to raise_error
150
+ end
151
+
152
+ specify 'fails with error on non-boolean values of :strict attribute' do
153
+ expect do
154
+ Class.new(Qonfig::DataSet) do
155
+ validate(:check, strict: Object.new) {}
156
+ end
157
+ end.to raise_error(Qonfig::ValidatorArgumentError)
158
+
159
+ expect do
160
+ Class.new(Qonfig::DataSet) do
161
+ validate(:check, strict: nil) {}
162
+ end
163
+ end.to raise_error(Qonfig::ValidatorArgumentError)
164
+ end
165
+ end
166
+
167
+ describe 'validations' do
168
+ let(:config_klass) do
169
+ Class.new(Qonfig::DataSet) do
170
+ setting :telegraf_url, 'test' # NOTE: all right
171
+
172
+ # NOTE: check that telegraf_url is a string value
173
+ validate('telegraf_url', strict: true) do |value|
174
+ value.is_a?(String)
175
+ end
176
+ end
177
+ end
178
+
179
+ specify 'validates invalid settings on instnation' do
180
+ config_klass = Class.new(Qonfig::DataSet) do
181
+ setting :telegraf_url, 12345 # NOTE: should be a string
182
+ validate 'telegraf_url' do |value|
183
+ value.is_a?(String)
184
+ end
185
+ end
186
+
187
+ expect { config_klass.new }.to raise_error(Qonfig::ValidationError)
188
+ end
189
+
190
+ specify 'validates settings defined by configuration options on instantiation' do
191
+ expect { config_klass.new(telegraf_url: '123') }.not_to raise_error
192
+ expect { config_klass.new(telegraf_url: 123) }.to raise_error(Qonfig::ValidationError)
193
+ end
194
+
195
+ specify 'validates settings defined by configuration block' do
196
+ expect do
197
+ config_klass.new.configure do |config|
198
+ config.telegraf_url = 123 # NOTE: should be a string
199
+ end
200
+ end.to raise_error(Qonfig::ValidationError)
201
+ end
202
+
203
+ specify 'validates settings setted in runtime' do
204
+ config = config_klass.new
205
+
206
+ expect { config.settings.telegraf_url = 1234 }.to raise_error(Qonfig::ValidationError)
207
+ expect { config.settings.telegraf_url = '55' }.not_to raise_error
208
+ end
209
+
210
+ specify 'invokes validations on config reload' do
211
+ # reload with hash
212
+ expect do
213
+ config_klass.new.reload!(telegraf_url: 123) # NOTE: should be a string
214
+ end.to raise_error(Qonfig::ValidationError)
215
+
216
+ # reload with configuration block
217
+ expect do
218
+ config_klass.new.reload! do |conf|
219
+ conf.telegraf_url = 123 # NOTE: should be a string
220
+ end
221
+ end.to raise_error(Qonfig::ValidationError)
222
+ end
223
+
224
+ specify 'invokes validations on config clearing' do
225
+ # NOTE:
226
+ # before #clear!: telegraf_config => 'test' (correct value)
227
+ # after #clear!: telegraf_config => nil (incorrect value)
228
+
229
+ expect { config_klass.new.clear! }.to raise_error(Qonfig::ValidationError)
230
+ end
231
+
232
+ specify 'config state after exception interception (#valid? / #validate!)' do
233
+ config = config_klass.new
234
+ expect(config.valid?).to eq(true)
235
+
236
+ begin
237
+ config.clear! # NOTE: set telegraf_url to nil (to incorrect value)
238
+ rescue Qonfig::ValidationError
239
+ end
240
+
241
+ expect(config.valid?).to eq(false)
242
+ end
243
+
244
+ specify 'deeply nested settings validation' do
245
+ deep_config_klass = Class.new(Qonfig::DataSet) do
246
+ setting :db do
247
+ setting :user, 'D@iVeR'
248
+ setting :password, 'test123'
249
+ end
250
+
251
+ # NOTE: setting key pattern :)
252
+ validate('db.user') { |value| value.is_a?(String) }
253
+ end
254
+
255
+ # NOTE: all right (originally)
256
+ expect { deep_config_klass.new }.not_to raise_error
257
+
258
+ # NOTE: change validated setting to incorrect value
259
+ # rubocop:disable Layout/LineLength
260
+ expect { deep_config_klass.new(db: { user: 123 }) }.to raise_error(Qonfig::ValidationError)
261
+ expect { deep_config_klass.new.settings.db.user = 123 }.to raise_error(Qonfig::ValidationError)
262
+ # rubocop:enable Layout/LineLength
263
+
264
+ # NOTE: change non-validated setting to any value
265
+ expect { deep_config_klass.new(db: { password: 123 }) }.not_to raise_error
266
+ expect { deep_config_klass.new.settings.db.password = 555 }.not_to raise_error
267
+ end
268
+
269
+ specify 'child class inherits the base class validations' do
270
+ base_config_klass = Class.new(Qonfig::DataSet) do
271
+ setting :adapter, 'sidekiq'
272
+ validate(:adapter, strict: true) { |value| value.is_a?(String) }
273
+ end
274
+
275
+ child_config_klass = Class.new(base_config_klass) do
276
+ setting :enabled, false
277
+ validate('enabled') { |value| value.is_a?(TrueClass) || value.is_a?(FalseClass) }
278
+
279
+ # NOTE: should inherit :adapter valdations
280
+ end
281
+
282
+ # NOTE: all right (originally)
283
+ expect { child_config_klass.new }.not_to raise_error
284
+ expect do
285
+ config = child_config_klass.new
286
+ config.settings.adapter = 'resque'
287
+ config.settings.enabled = true
288
+ end.not_to raise_error
289
+
290
+ # NOTE: inherited validations
291
+ # rubocop:disable Layout/LineLength
292
+ expect { child_config_klass.new(adapter: 123) }.to raise_error(Qonfig::ValidationError)
293
+ expect { child_config_klass.new.settings.adapter = 123 }.to raise_error(Qonfig::ValidationError)
294
+ expect { child_config_klass.new { |conf| conf.adapter = 123 } }.to raise_error(Qonfig::ValidationError)
295
+ expect { child_config_klass.new.reload!(adapter: 123) }.to raise_error(Qonfig::ValidationError)
296
+ # rubocop:enable Layout/LineLength
297
+
298
+ config = child_config_klass.new
299
+ expect(config.valid?).to eq(true)
300
+ begin
301
+ config.settings.adapter = 123
302
+ rescue Qonfig::ValidationError
303
+ end
304
+ expect(config.valid?).to eq(false)
305
+ expect(config.settings.adapter).to eq(123)
306
+
307
+ # NOTE: own validations
308
+ # rubocop:disable Layout/LineLength
309
+ expect { child_config_klass.new(enabled: '123') }.to raise_error(Qonfig::ValidationError)
310
+ expect { child_config_klass.new.settings.enabled = '123' }.to raise_error(Qonfig::ValidationError)
311
+ expect { child_config_klass.new { |conf| conf.enabled = '123' } }.to raise_error(Qonfig::ValidationError)
312
+ expect { child_config_klass.new.reload!(enabled: '123') }.to raise_error(Qonfig::ValidationError)
313
+ expect { child_config_klass.new.clear! }.to raise_error(Qonfig::ValidationError)
314
+ # rubocop:enable Layout/LineLength
315
+
316
+ config = child_config_klass.new
317
+ expect(config.valid?).to eq(true)
318
+ begin
319
+ config.settings.enabled = '123'
320
+ rescue Qonfig::ValidationError
321
+ end
322
+ expect(config.valid?).to eq(false)
323
+ expect(config.settings.enabled).to eq('123')
324
+ end
325
+
326
+ specify 'config composition inherits validators' do
327
+ config_klass = Class.new(Qonfig::DataSet) do
328
+ setting :telegraf_url, 'udp://localhost:9094'
329
+ validate(:telegraf_url) { |value| value.is_a?(String) }
330
+ end
331
+
332
+ composed_config_klass = Class.new(Qonfig::DataSet) do
333
+ # NOTE: root configs
334
+ compose(config_klass)
335
+
336
+ # NOTE: nested configs
337
+ setting(:nested) { compose(config_klass) }
338
+ end
339
+
340
+ # NOTE: all right
341
+ expect { composed_config_klass.new }.not_to raise_error
342
+ expect do
343
+ config = composed_config_klass.new
344
+ config.settings.telegraf_url = '123'
345
+ config.settings.nested.telegraf_url = '123'
346
+ end.not_to raise_error
347
+
348
+ expect do # NOTE: check root config validation
349
+ composed_config_klass.new.settings.telegraf_url = 123 # NOTE: should be a string
350
+ end.to raise_error(Qonfig::ValidationError)
351
+
352
+ expect do # NOTE: check nested config validation
353
+ composed_config_klass.new.settings.nested.telegraf_url = 123
354
+ end.to raise_error(Qonfig::ValidationError)
355
+ end
356
+
357
+ specify 'setting patterns (validation of a set of configs chosen by setting pattern)' do
358
+ config_klass = Class.new(Qonfig::DataSet) do
359
+ setting :db do
360
+ setting :creds do
361
+ setting :user, 'D@iVeR'
362
+ setting :password, 'test123'
363
+ end
364
+ end
365
+
366
+ setting :sidekiq do
367
+ setting :admin do
368
+ setting :user, 'D@iVeR'
369
+ setting :password, '123test'
370
+ end
371
+
372
+ setting :logger_level, 'info'
373
+ end
374
+
375
+ setting :adapter, :resque
376
+ setting :port, 1019
377
+
378
+ # only the root setting key
379
+ # (port)
380
+ validate('port', strict: true) do |value|
381
+ value.is_a?(Numeric)
382
+ end
383
+
384
+ # all .user setting keys
385
+ # (db.creds.user, sidekiq.admin.user)
386
+ validate('#.user', strict: true) do |value|
387
+ value.is_a?(String)
388
+ end
389
+
390
+ # one level inside db AND all password setting keys there
391
+ # (db.creds.password)
392
+ validate('db.*.password', strict: true) do |value|
393
+ value.is_a?(String)
394
+ end
395
+
396
+ # all .adapter setting keys
397
+ # (adapter)
398
+ validate('#.adapter', strict: true) do |value|
399
+ value.is_a?(Symbol)
400
+ end
401
+
402
+ # all keys inside sidekiq setting group
403
+ # (sidekiq.admin.user, sidekiq.admin.password, sidekiq.logger_level)
404
+ validate('sidekiq.#', strict: true) do |value|
405
+ value.is_a?(String)
406
+ end
407
+ end
408
+
409
+ # NOTE: all right (originally)
410
+ expect { config_klass.new }.not_to raise_error
411
+
412
+ # rubocop:disable Layout/LineLength
413
+ expect { config_klass.new.settings.db.creds.user = 123 }.to raise_error(Qonfig::ValidationError)
414
+ expect { config_klass.new.settings.sidekiq.admin.user = 123 }.to raise_error(Qonfig::ValidationError)
415
+ expect { config_klass.new.settings.sidekiq.admin.password = 123 }.to raise_error(Qonfig::ValidationError)
416
+ expect { config_klass.new.settings.sidekiq.logger_level = nil }.to raise_error(Qonfig::ValidationError)
417
+ expect { config_klass.new.settings.db.creds.password = 123 }.to raise_error(Qonfig::ValidationError)
418
+ expect { config_klass.new.settings.adapter = 'que' }.to raise_error(Qonfig::ValidationError)
419
+ expect { config_klass.new.settings.port = '555' }.to raise_error(Qonfig::ValidationError)
420
+ # rubocop:enable Layout/LineLength
421
+
422
+ expect { config_klass.new.settings.db.creds.user = '123' }.not_to raise_error
423
+ expect { config_klass.new.settings.sidekiq.admin.user = '123' }.not_to raise_error
424
+ expect { config_klass.new.settings.sidekiq.admin.password = '123' }.not_to raise_error
425
+ expect { config_klass.new.settings.sidekiq.logger_level = 'warn' }.not_to raise_error
426
+ expect { config_klass.new.settings.db.creds.password = '123' }.not_to raise_error
427
+ expect { config_klass.new.settings.adapter = :que }.not_to raise_error
428
+ expect { config_klass.new.settings.port = 5599 }.not_to raise_error
429
+ end
430
+
431
+ specify 'proc-based validation wokrs inside dataset instance context' do
432
+ config_klass = Class.new(Qonfig::DataSet) do
433
+ setting :some_key, 555
434
+
435
+ validate 'some_key' do |value|
436
+ value > some_method
437
+ end
438
+
439
+ def some_method
440
+ 123
441
+ end
442
+ end
443
+
444
+ # NOTE: all right (originally)
445
+ expect { config_klass.new }.not_to raise_error
446
+
447
+ # NOTE: invalid value
448
+ expect { config_klass.new(some_key: 122) }.to raise_error(Qonfig::ValidationError)
449
+ # NOTE: valid value
450
+ expect { config_klass.new(some_key: 1234) }.not_to raise_error
451
+ end
452
+
453
+ specify 'setting key validation by custom method defined directly on dataset' do
454
+ config_klass = Class.new(Qonfig::DataSet) do
455
+ setting :db do
456
+ setting :enabled, false
457
+ end
458
+
459
+ # NOTE: validate setting keys by custom dataset method
460
+ validate 'db.#', by: :check_credentials
461
+
462
+ def check_credentials(setting_key_value)
463
+ setting_key_value.is_a?(TrueClass) || setting_key_value.is_a?(FalseClass)
464
+ end
465
+ end
466
+
467
+ # NOTE: all right (orginally)
468
+ expect { config_klass.new }.not_to raise_error
469
+
470
+ # NOTE: invalid values
471
+ expect { config_klass.new.settings.db.enabled = 123 }.to raise_error(Qonfig::ValidationError)
472
+ expect { config_klass.new(db: { enabled: 123 }) }.to raise_error(Qonfig::ValidationError)
473
+
474
+ # NOTE: valid values
475
+ expect { config_klass.new.settings.db.enabled = true }.not_to raise_error
476
+ expect { config_klass.new(db: { enabled: true }) }.not_to raise_error
477
+ end
478
+
479
+ specify 'full data set object validation via #validate' do
480
+ # валидация всего сеттингса скопом (синтаксис "validate { |settings| } / validate by:")
481
+ config_klass = Class.new(Qonfig::DataSet) do
482
+ setting :namespace do
483
+ setting :enabled, :true
484
+ end
485
+
486
+ setting :go_for_cybersport, 'NO'
487
+
488
+ # NOTE: no setting key pattern => full dataset object validation
489
+ validate { settings.namespace.enabled.is_a?(Symbol) }
490
+
491
+ # NOTE: no setting key pattern => full dataset object validation
492
+ validate by: :check_all
493
+
494
+ def check_all
495
+ settings.go_for_cybersport == 'NO'
496
+ end
497
+ end
498
+
499
+ # NOTE: all right (originally)
500
+ expect { config_klass.new }.not_to raise_error
501
+
502
+ # NOTE: invalid values
503
+ # (namespace.enabled should be a symbol)
504
+ expect do
505
+ config_klass.new.settings.namespace.enabled = 123
506
+ end.to raise_error(Qonfig::ValidationError)
507
+ # (go_for_cybersport should have the 'NO' string value)
508
+ expect do
509
+ config_klass.new.settings.go_for_cybersport = 'YES'
510
+ end.to raise_error(Qonfig::ValidationError)
511
+
512
+ # NOTE: valid values
513
+ expect { config_klass.new.settings.namespace.enabled = :false }.not_to raise_error
514
+ expect { config_klass.new.settings.go_for_cybersport = 'NO' }.not_to raise_error
515
+ end
516
+ end
517
+
518
+ describe 'strict behaviour' do
519
+ specify 'non-strict by default (validation ignores nil values)' do
520
+ config = Qonfig::DataSet.build do
521
+ setting :login, 'D@iVeR'
522
+ setting :password, 'atata123'
523
+ setting :enabled, true
524
+
525
+ validate :login, :string
526
+ validate(:password) { |value| value.is_a?(String) }
527
+ validate :enabled, by: :check_enabled_setting
528
+
529
+ def check_enabled_setting(value)
530
+ value.is_a?(FalseClass) || value.is_a?(TrueClass)
531
+ end
532
+ end
533
+
534
+ expect(config.valid?).to eq(true)
535
+ expect { config.settings.login = nil }.not_to raise_error
536
+ expect { config.settings.password = nil }.not_to raise_error
537
+ expect { config.settings.enabled = nil }.not_to raise_error
538
+ expect(config.valid?).to eq(true)
539
+ end
540
+
541
+ specify 'strict validation does not ignore nil value' do
542
+ config = Qonfig::DataSet.build do
543
+ setting :login, '0exp'
544
+ setting :password, 'test123'
545
+ setting :enabled, false
546
+
547
+ validate :login, :string, strict: true
548
+ validate(:password, strict: true) { |value| value.is_a?(String) }
549
+ validate :enabled, by: :check_enabled_setting, strict: true
550
+
551
+ def check_enabled_setting(value)
552
+ value.is_a?(FalseClass) || value.is_a?(TrueClass)
553
+ end
554
+ end
555
+
556
+ expect(config.valid?).to eq(true)
557
+ expect { config.settings.login = nil }.to raise_error(Qonfig::ValidationError)
558
+ expect { config.settings.password = nil }.to raise_error(Qonfig::ValidationError)
559
+ expect { config.settings.enabled = nil }.to raise_error(Qonfig::ValidationError)
560
+ expect(config.valid?).to eq(false)
561
+ end
562
+ end
563
+
564
+ describe 'predefined validators' do
565
+ specify 'common behaviour (strict)' do
566
+ config_klass = Class.new(Qonfig::DataSet) do
567
+ setting :enabled, false
568
+ setting :count, 123
569
+ setting :amount, 23.55
570
+ setting :adapter, 'sidekiq'
571
+ setting :switcher, :on
572
+ setting :data, [1, 2, 3]
573
+ setting :mappings, a: 1, b: 2
574
+ setting :age, 20
575
+
576
+ validate :enabled, :boolean, strict: true
577
+ validate :count, :integer, strict: true
578
+ validate :amount, :float, strict: true
579
+ validate :adapter, :string, strict: true
580
+ validate :switcher, :symbol, strict: true
581
+ validate :data, :array, strict: true
582
+ validate :mappings, :hash, strict: true
583
+ validate :age, :numeric, strict: true
584
+ end
585
+
586
+ # NOTE: all right (originally)
587
+ expect { config_klass.new }.not_to raise_error
588
+
589
+ # NOTE: invalid values
590
+ expect { config_klass.new.settings.enabled = nil }.to raise_error(Qonfig::ValidationError)
591
+ expect { config_klass.new.settings.count = '5' }.to raise_error(Qonfig::ValidationError)
592
+ expect { config_klass.new.settings.amount = 22 }.to raise_error(Qonfig::ValidationError)
593
+ expect { config_klass.new.settings.adapter = :resque }.to raise_error(Qonfig::ValidationError)
594
+ expect { config_klass.new.settings.switcher = 'off' }.to raise_error(Qonfig::ValidationError)
595
+ expect { config_klass.new.settings.data = {} }.to raise_error(Qonfig::ValidationError)
596
+ expect { config_klass.new.settings.mappings = [] }.to raise_error(Qonfig::ValidationError)
597
+ expect { config_klass.new.settings.age = nil }.to raise_error(Qonfig::ValidationError)
598
+
599
+ # NOTE: valid values
600
+ expect { config_klass.new.settings.enabled = true }.not_to raise_error
601
+ expect { config_klass.new.settings.count = 5 }.not_to raise_error
602
+ expect { config_klass.new.settings.amount = 22.0 }.not_to raise_error
603
+ expect { config_klass.new.settings.adapter = 'resque' }.not_to raise_error
604
+ expect { config_klass.new.settings.switcher = :off }.not_to raise_error
605
+ expect { config_klass.new.settings.data = [] }.not_to raise_error
606
+ expect { config_klass.new.settings.mappings = {} }.not_to raise_error
607
+ expect { config_klass.new.settings.age = 20.1 }.not_to raise_error
608
+ end
609
+
610
+ specify 'common behaviour (non-strict)' do
611
+ config_klass = Class.new(Qonfig::DataSet) do
612
+ setting :enabled, false
613
+ setting :count, 123
614
+ setting :amount, 23.55
615
+ setting :adapter, 'sidekiq'
616
+ setting :switcher, :on
617
+ setting :data, [1, 2, 3]
618
+ setting :mappings, a: 1, b: 2
619
+ setting :age, 20
620
+
621
+ validate :enabled, :boolean
622
+ validate :count, :integer
623
+ validate :amount, :float
624
+ validate :adapter, :string
625
+ validate :switcher, :symbol
626
+ validate :data, :array
627
+ validate :mappings, :hash
628
+ validate :age, :numeric
629
+ end
630
+
631
+ # NOTE: all right (originally)
632
+ expect { config_klass.new }.not_to raise_error
633
+
634
+ # NOTE: invalid values
635
+ expect { config_klass.new.settings.count = '5' }.to raise_error(Qonfig::ValidationError)
636
+ expect { config_klass.new.settings.amount = 22 }.to raise_error(Qonfig::ValidationError)
637
+ expect { config_klass.new.settings.adapter = :resque }.to raise_error(Qonfig::ValidationError)
638
+ expect { config_klass.new.settings.switcher = 'off' }.to raise_error(Qonfig::ValidationError)
639
+ expect { config_klass.new.settings.data = {} }.to raise_error(Qonfig::ValidationError)
640
+ expect { config_klass.new.settings.mappings = [] }.to raise_error(Qonfig::ValidationError)
641
+
642
+ # NOTE: non-strict values (validation ignores nil values)
643
+ expect { config_klass.new.settings.age = nil }.not_to raise_error
644
+ expect { config_klass.new.settings.enabled = nil }.not_to raise_error
645
+
646
+ # NOTE: valid values
647
+ expect { config_klass.new.settings.enabled = true }.not_to raise_error
648
+ expect { config_klass.new.settings.count = 5 }.not_to raise_error
649
+ expect { config_klass.new.settings.amount = 22.0 }.not_to raise_error
650
+ expect { config_klass.new.settings.adapter = 'resque' }.not_to raise_error
651
+ expect { config_klass.new.settings.switcher = :off }.not_to raise_error
652
+ expect { config_klass.new.settings.data = [] }.not_to raise_error
653
+ expect { config_klass.new.settings.mappings = {} }.not_to raise_error
654
+ expect { config_klass.new.settings.age = 20.1 }.not_to raise_error
655
+ end
656
+
657
+ describe 'valid_with?' do
658
+ specify '(#valid_with?): config object is valid or invalid with new potenital configs' do
659
+ config = Qonfig::DataSet.build do
660
+ setting :enabled, false
661
+ setting :count, 123
662
+ setting :amount, 23.55
663
+ setting :level, 100_500
664
+ setting :sound do
665
+ setting :genre, 'death-metal'
666
+ end
667
+
668
+ validate :enabled, :boolean
669
+ validate :count, :integer, strict: true
670
+
671
+ validate by: :check_level
672
+ validate 'sound.#' do |value|
673
+ value.is_a?(String)
674
+ end
675
+
676
+ def check_level
677
+ settings.level.is_a?(Numeric)
678
+ end
679
+ end
680
+
681
+ expect(config.valid_with?(
682
+ enabled: true,
683
+ count: 444,
684
+ amount: 66.21,
685
+ level: 123.55,
686
+ sound: { genre: 'melodic-death-metal' }
687
+ )).to eq(true)
688
+
689
+ expect(config.valid_with?(enabled: '123')).to eq(false)
690
+ expect(config.valid_with?(sound: { genre: false })).to eq(false)
691
+ expect(config.valid_with?(level: '2')).to eq(false)
692
+ expect(config.valid_with?(count: nil)).to eq(false)
693
+ expect(config.valid_with?(level: '7', count: nil, enabled: 123)).to eq(false)
694
+
695
+ # NOTE: check that original config does not mutated after validation checking
696
+ expect(config.settings.enabled).to eq(false)
697
+ expect(config.settings.count).to eq(123)
698
+ expect(config.settings.amount).to eq(23.55)
699
+ expect(config.settings.level).to eq(100_500)
700
+ expect(config.settings.sound.genre).to eq('death-metal')
701
+ end
702
+ end
703
+
704
+ specify '(.valid_with?/#valid_with?) support for do-config notation :)' do
705
+ config_klass = Class.new(Qonfig::DataSet) do
706
+ setting :enabled, false
707
+ setting(:db) { setting :user, 'D@iVeR' }
708
+ validate :enabled, :boolean, strict: true
709
+ validate 'db.#', :text, strict: true
710
+ end
711
+
712
+ config = config_klass.new
713
+
714
+ # class-level checker
715
+ expect(
716
+ (config_klass.valid_with?(enabled: true) do |conf|
717
+ conf.db.user = '0exp'
718
+ end)
719
+ ).to eq(true)
720
+ expect(
721
+ (config_klass.valid_with?(enabled: false) do |conf|
722
+ conf.db.user = 123
723
+ end)
724
+ ).to eq(false)
725
+ expect(
726
+ (config_klass.valid_with?(enabled: nil) do |conf|
727
+ conf.db.user = 'test'
728
+ end)
729
+ ).to eq(false)
730
+
731
+ # instance-level checker
732
+ expect(
733
+ (config.valid_with?(enabled: true) do |conf|
734
+ conf.db.user = '0exp'
735
+ end)
736
+ ).to eq(true)
737
+ expect(
738
+ (config.valid_with?(enabled: false) do |conf|
739
+ conf.db.user = 123
740
+ end)
741
+ ).to eq(false)
742
+ expect(
743
+ (config.valid_with?(enabled: nil) do |conf|
744
+ conf.db.user = 'test'
745
+ end)
746
+ ).to eq(false)
747
+
748
+ # original instance is not changed
749
+ expect(config.settings.enabled).to eq(false)
750
+ expect(config.settings.db.user).to eq('D@iVeR')
751
+ end
752
+
753
+ specify '(.valid_with?) potential config instances will be valid or invalid with new configs' do
754
+ config_klass = Class.new(Qonfig::DataSet) do
755
+ setting :enabled, false
756
+ setting :count, 123
757
+ setting :amount, 23.55
758
+ setting :level, 100_500
759
+ setting :sound do
760
+ setting :genre, 'death-metal'
761
+ end
762
+
763
+ validate :enabled, :boolean
764
+ validate :count, :integer, strict: true
765
+
766
+ validate by: :check_level
767
+ validate 'sound.#' do |value|
768
+ value.is_a?(String)
769
+ end
770
+
771
+ def check_level
772
+ settings.level.is_a?(Numeric)
773
+ end
774
+ end
775
+
776
+ expect(config_klass.valid_with?(
777
+ enabled: true,
778
+ count: 444,
779
+ amount: 66.21,
780
+ level: 123.55,
781
+ sound: { genre: 'melodic-death-metal' }
782
+ )).to eq(true)
783
+
784
+ expect(config_klass.valid_with?(enabled: '123')).to eq(false)
785
+ expect(config_klass.valid_with?(sound: { genre: false })).to eq(false)
786
+ expect(config_klass.valid_with?(level: '2')).to eq(false)
787
+ expect(config_klass.valid_with?(count: nil)).to eq(false)
788
+ expect(config_klass.valid_with?(level: '7', count: nil, enabled: 123)).to eq(false)
789
+ end
790
+ end
791
+
792
+ describe 'custom validators' do
793
+ specify 'you can define your own global validators and concrete-class-related validators' do
794
+ # custom global validator
795
+ Qonfig::DataSet.define_validator(:globality) do |value|
796
+ value == 'global'
797
+ end
798
+
799
+ config_klass = Class.new(Qonfig::DataSet) do
800
+ # custom class-related validator
801
+ define_validator(:int_or_sym) do |value|
802
+ value.is_a?(Integer) || value.is_a?(Symbol)
803
+ end
804
+
805
+ # custom class-related validator
806
+ define_validator(:queue_adapter) do |value|
807
+ value == :que || value == :sidekiq
808
+ end
809
+
810
+ setting :some_value, 123
811
+ setting :adapter, :sidekiq
812
+ setting :global, 'global'
813
+
814
+ validate :some_value, :int_or_sym # class-related validator
815
+ validate :adapter, :queue_adapter # class-related validator
816
+ validate :global, :globality, strict: true # global validator + srict cheker
817
+ end
818
+
819
+ expect { config_klass.new }.not_to raise_error
820
+
821
+ # invalid :global setting values
822
+ expect { config_klass.new(global: 123) }.to raise_error(Qonfig::ValidationError)
823
+ expect { config_klass.new(global: nil) }.to raise_error(Qonfig::ValidationError)
824
+ # invalid :some_value setting value
825
+ expect { config_klass.new(some_value: 123.456) }.to raise_error(Qonfig::ValidationError)
826
+ # invalid :adaper setting value
827
+ expect { config_klass.new(adapter: :sneakers) }.to raise_error(Qonfig::ValidationError)
828
+ end
829
+
830
+ specify 'fails when validation logic is not provided at definition step' do
831
+ config_klass = Class.new(Qonfig::DataSet)
832
+
833
+ expect do
834
+ config_klass.define_validator(:simple_validator)
835
+ end.to raise_error(Qonfig::ValidatorArgumentError)
836
+
837
+ expect do
838
+ config_klass.define_validator(:simple_validator) {}
839
+ end.not_to raise_error
840
+ end
841
+
842
+ specify 'inheritance works as expeced' do
843
+ Qonfig::DataSet.define_validator(:global_inheritable) do |value|
844
+ value == 0
845
+ end
846
+
847
+ first_klass = Class.new(Qonfig::DataSet) do
848
+ define_validator(:first_validator) { |value| value == 1 }
849
+ setting :a
850
+ end
851
+
852
+ second_klass = Class.new(first_klass) do
853
+ define_validator(:second_validator) { |value| value == 2 }
854
+ setting :b
855
+ end
856
+
857
+ third_klass = Class.new(second_klass) do
858
+ define_validator(:third_validator) { |value| value == 3 }
859
+ setting :c
860
+ setting :d
861
+
862
+ validate :a, :first_validator
863
+ validate :b, :second_validator
864
+ validate :c, :third_validator
865
+ validate :d, :global_inheritable
866
+ end
867
+
868
+ expect { third_klass.new(a: 1, b: 2, c: 3, d: 0) }.not_to raise_error
869
+ expect { third_klass.new }.not_to raise_error
870
+
871
+ expect { third_klass.new(a: '1') }.to raise_error(Qonfig::ValidationError)
872
+ expect { third_klass.new(b: '2') }.to raise_error(Qonfig::ValidationError)
873
+ expect { third_klass.new(c: '3') }.to raise_error(Qonfig::ValidationError)
874
+ expect { third_klass.new(d: '0') }.to raise_error(Qonfig::ValidationError)
875
+ end
876
+
877
+ specify 'predefined validators can be redefined' do
878
+ # custom global predefined validator
879
+ Qonfig::DataSet.define_validator(:global_predefined) do |value|
880
+ value == :predefined
881
+ end
882
+
883
+ config_klass_with_redefinition = Class.new(Qonfig::DataSet) do
884
+ define_validator(:global_predefined) do |value|
885
+ value == :class_level_predefined
886
+ end
887
+
888
+ setting :some_option
889
+ validate :some_option, :global_predefined
890
+ end
891
+
892
+ config_klass_without_redefinition = Class.new(Qonfig::DataSet) do
893
+ setting :some_option
894
+ validate :some_option, :global_predefined
895
+ end
896
+
897
+ # NOTE: config with redefined validator
898
+ expect do
899
+ # check that redefined validator is used
900
+ config_klass_with_redefinition.new(some_option: :class_level_predefined)
901
+ end.not_to raise_error
902
+ expect do
903
+ # check that global validator is not reached
904
+ config_klass_with_redefinition.new(some_option: :predefined)
905
+ end.to raise_error(Qonfig::ValidationError)
906
+
907
+ # NOTE: config without redefined validator
908
+ expect do
909
+ config_klass_without_redefinition.new(some_option: :class_level_predefined)
910
+ end.to raise_error(Qonfig::ValidationError)
911
+ expect do
912
+ config_klass_without_redefinition.new(some_option: :predefined)
913
+ end.not_to raise_error
914
+ end
915
+ end
916
+ end