const_conf 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/LICENSE +19 -0
- data/README.md +789 -0
- data/Rakefile +35 -0
- data/const_conf.gemspec +35 -0
- data/lib/const_conf/dir_plugin.rb +175 -0
- data/lib/const_conf/env_dir_extension.rb +83 -0
- data/lib/const_conf/errors.rb +93 -0
- data/lib/const_conf/file_plugin.rb +33 -0
- data/lib/const_conf/json_plugin.rb +12 -0
- data/lib/const_conf/railtie.rb +13 -0
- data/lib/const_conf/setting.rb +382 -0
- data/lib/const_conf/setting_accessor.rb +103 -0
- data/lib/const_conf/tree.rb +265 -0
- data/lib/const_conf/version.rb +8 -0
- data/lib/const_conf/yaml_plugin.rb +30 -0
- data/lib/const_conf.rb +401 -0
- data/spec/assets/.env/API_KEY +1 -0
- data/spec/assets/config.json +3 -0
- data/spec/assets/config.yml +1 -0
- data/spec/assets/config_env.yml +7 -0
- data/spec/const_conf/dir_plugin_spec.rb +249 -0
- data/spec/const_conf/env_dir_extension_spec.rb +59 -0
- data/spec/const_conf/file_plugin_spec.rb +173 -0
- data/spec/const_conf/json_plugin_spec.rb +64 -0
- data/spec/const_conf/setting_accessor_spec.rb +114 -0
- data/spec/const_conf/setting_spec.rb +628 -0
- data/spec/const_conf/tree_spec.rb +185 -0
- data/spec/const_conf/yaml_plugin_spec.rb +84 -0
- data/spec/const_conf_spec.rb +216 -0
- data/spec/spec_helper.rb +140 -0
- metadata +240 -0
@@ -0,0 +1,628 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ConstConf::Setting, protect_env: true do
|
4
|
+
let(:parent_namespace) do
|
5
|
+
Module.new do
|
6
|
+
include ConstConf
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
it "creates a setting with name and prefix" do
|
12
|
+
setting = parent_namespace.module_eval do
|
13
|
+
ConstConf::Setting.new(name: "DATABASE_URL", prefix: "APP") do
|
14
|
+
end
|
15
|
+
end
|
16
|
+
expect(setting.name).to eq "DATABASE_URL"
|
17
|
+
expect(setting.prefix).to eq "APP"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "constructs env var name from prefix and name" do
|
21
|
+
setting = parent_namespace.module_eval do
|
22
|
+
ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
23
|
+
end
|
24
|
+
end
|
25
|
+
expect(setting.env_var_name).to eq "APP_DATABASE_URL"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#env_var_name" do
|
30
|
+
it "handles nested module names with double colons" do
|
31
|
+
setting = parent_namespace.module_eval do
|
32
|
+
ConstConf::Setting.new(name: ["APP", "EMAIL", "NOTIFY_USER"], prefix: "APP") do
|
33
|
+
end
|
34
|
+
end
|
35
|
+
expect(setting.env_var_name).to eq "APP_EMAIL_NOTIFY_USER"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "uses empty prefix when none provided" do
|
39
|
+
setting = ConstConf::Setting.new(name: ["APP", "SERVICE", "DATABASE_URL"], prefix: '')
|
40
|
+
allow(setting).to receive(:parent_namespace).and_return('APP::SERVICE')
|
41
|
+
expect(setting.env_var_name).to eq "DATABASE_URL"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#value" do
|
46
|
+
before do
|
47
|
+
ENV['APP_DATABASE_URL'] = "postgres://localhost/test"
|
48
|
+
ENV['APP_HOSTNAMES'] = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
it "returns environment variable value when present" do
|
52
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
53
|
+
description 'nope'
|
54
|
+
default "sqlite3://default.db"
|
55
|
+
end
|
56
|
+
expect(setting.value).to eq "postgres://localhost/test"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns default value when env var is not set" do
|
60
|
+
ENV['APP_DATABASE_URL'] = nil
|
61
|
+
|
62
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
63
|
+
default "sqlite3://default.db"
|
64
|
+
end
|
65
|
+
expect(setting.value).to eq "sqlite3://default.db"
|
66
|
+
end
|
67
|
+
|
68
|
+
it "applies decode logic when present" do
|
69
|
+
setting = ConstConf::Setting.new(name: ["APP", "HOSTNAMES"], prefix: "APP") do
|
70
|
+
default "foo,bar,baz"
|
71
|
+
decode ->(val) { val.split(",") }
|
72
|
+
end
|
73
|
+
expect(setting.value).to eq ["foo", "bar", "baz"]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#active?" do
|
78
|
+
it "returns true when activated with non-nil value" do
|
79
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
80
|
+
activated true
|
81
|
+
default "sqlite3://default.db"
|
82
|
+
end
|
83
|
+
expect(setting.active?).to be true
|
84
|
+
end
|
85
|
+
|
86
|
+
it "returns false when not activated" do
|
87
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
88
|
+
activated false
|
89
|
+
end
|
90
|
+
expect(setting.active?).to be false
|
91
|
+
end
|
92
|
+
|
93
|
+
it "evaluates Proc with value when activated is a Proc (arity 1)" do
|
94
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
95
|
+
activated ->(value) { value.present? }
|
96
|
+
default "test_value"
|
97
|
+
end
|
98
|
+
expect(setting.active?).to be true
|
99
|
+
end
|
100
|
+
|
101
|
+
it "evaluates Proc without arguments when activated is a Proc (arity 0)" do
|
102
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
103
|
+
activated -> { true }
|
104
|
+
default "test_value"
|
105
|
+
end
|
106
|
+
expect(setting.active?).to be true
|
107
|
+
end
|
108
|
+
|
109
|
+
it "returns false when Proc evaluation returns false (arity 1)" do
|
110
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
111
|
+
activated ->(value) { value.nil? }
|
112
|
+
default "test_value"
|
113
|
+
end
|
114
|
+
expect(setting.active?).to be false
|
115
|
+
end
|
116
|
+
|
117
|
+
it "returns false when Proc evaluation returns false (arity 0)" do
|
118
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
119
|
+
activated -> { false }
|
120
|
+
default "test_value"
|
121
|
+
end
|
122
|
+
expect(setting.active?).to be false
|
123
|
+
end
|
124
|
+
|
125
|
+
it "calls method on value when activated is a Symbol" do
|
126
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
127
|
+
activated :present?
|
128
|
+
default "test_value"
|
129
|
+
end
|
130
|
+
expect(setting.active?).to be true
|
131
|
+
end
|
132
|
+
|
133
|
+
it "returns false when Symbol method returns false on value" do
|
134
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
135
|
+
activated :empty?
|
136
|
+
default "test_value"
|
137
|
+
end
|
138
|
+
expect(setting.active?).to be false
|
139
|
+
end
|
140
|
+
|
141
|
+
it "returns false when Symbol method returns false on nil value" do
|
142
|
+
ENV['APP_DATABASE_URL'] = nil
|
143
|
+
|
144
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
145
|
+
activated :present?
|
146
|
+
default nil
|
147
|
+
end
|
148
|
+
expect(setting.active?).to be false
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "#configured?" do
|
153
|
+
it "returns true when environment variable is set" do
|
154
|
+
ENV['APP_TEST_VAR'] = 'value'
|
155
|
+
|
156
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
157
|
+
default "default"
|
158
|
+
end
|
159
|
+
|
160
|
+
expect(setting.configured?).to be true
|
161
|
+
end
|
162
|
+
|
163
|
+
it "returns false when environment variable is not set" do
|
164
|
+
ENV['APP_TEST_VAR'] = nil
|
165
|
+
|
166
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
167
|
+
default "default"
|
168
|
+
end
|
169
|
+
|
170
|
+
expect(setting.configured?).to be false
|
171
|
+
end
|
172
|
+
|
173
|
+
it "returns false when ignored and environment variable is set" do
|
174
|
+
ENV['APP_TEST_VAR'] = 'value'
|
175
|
+
|
176
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
177
|
+
ignored true
|
178
|
+
default "default"
|
179
|
+
end
|
180
|
+
|
181
|
+
expect(setting.configured?).to be false
|
182
|
+
end
|
183
|
+
|
184
|
+
it "returns false when configured value is nil and no default" do
|
185
|
+
ENV['APP_TEST_VAR'] = nil
|
186
|
+
|
187
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
188
|
+
# No default specified
|
189
|
+
end
|
190
|
+
|
191
|
+
expect(setting.configured?).to be false
|
192
|
+
end
|
193
|
+
|
194
|
+
it "returns true when configured value is present" do
|
195
|
+
ENV['APP_TEST_VAR'] = 'some_value'
|
196
|
+
|
197
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
198
|
+
default nil
|
199
|
+
end
|
200
|
+
|
201
|
+
expect(setting.configured?).to be true
|
202
|
+
end
|
203
|
+
|
204
|
+
it "returns false when configured value is an empty string" do
|
205
|
+
ENV['APP_TEST_VAR'] = ''
|
206
|
+
|
207
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
208
|
+
default "default"
|
209
|
+
end
|
210
|
+
|
211
|
+
expect(setting.configured?).to be true
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe "#required?" do
|
216
|
+
it "returns true when required is set to true" do
|
217
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
218
|
+
required true
|
219
|
+
end
|
220
|
+
expect(setting.required?).to be true
|
221
|
+
end
|
222
|
+
|
223
|
+
it "returns false when required is not set" do
|
224
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP")
|
225
|
+
expect(setting.required?).to be false
|
226
|
+
end
|
227
|
+
|
228
|
+
it "returns true when required is a proc that returns true (arity 1)" do
|
229
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
230
|
+
required ->(value) { value.present? }
|
231
|
+
end
|
232
|
+
allow(setting).to receive(:configured_value_or_default_value).and_return("test_value")
|
233
|
+
expect(setting.required?).to be true
|
234
|
+
end
|
235
|
+
|
236
|
+
it "returns false when required is a proc that returns false (arity 1)" do
|
237
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
238
|
+
required ->(value) { value.nil? }
|
239
|
+
end
|
240
|
+
allow(setting).to receive(:configured_value_or_default_value).and_return("test_value")
|
241
|
+
expect(setting.required?).to be false
|
242
|
+
end
|
243
|
+
|
244
|
+
it "returns true when required is a proc that returns true (arity 0)" do
|
245
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
246
|
+
required -> { true }
|
247
|
+
end
|
248
|
+
expect(setting.required?).to be true
|
249
|
+
end
|
250
|
+
|
251
|
+
it "returns false when required is a proc that returns false (arity 0)" do
|
252
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
253
|
+
required -> { false }
|
254
|
+
end
|
255
|
+
expect(setting.required?).to be false
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
describe "#confirm!" do
|
260
|
+
it "raises RequiredValueNotConfigured when required but not configured" do
|
261
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
262
|
+
description 'nope'
|
263
|
+
required true
|
264
|
+
end
|
265
|
+
expect { setting.confirm! }.to raise_error(ConstConf::RequiredValueNotConfigured)
|
266
|
+
end
|
267
|
+
|
268
|
+
it "raises RequiredDescriptionNotConfigured if description is missing" do
|
269
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
270
|
+
required true
|
271
|
+
activated true
|
272
|
+
end
|
273
|
+
expect { setting.confirm! }.to raise_error(ConstConf::RequiredDescriptionNotConfigured)
|
274
|
+
end
|
275
|
+
|
276
|
+
it "does not raise error when required and configured" do
|
277
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
278
|
+
description 'nope'
|
279
|
+
required true
|
280
|
+
activated true
|
281
|
+
end
|
282
|
+
allow(setting).to receive(:configured_value).and_return('was set')
|
283
|
+
expect { setting.confirm! }.not_to raise_error
|
284
|
+
end
|
285
|
+
|
286
|
+
context "when check fails" do
|
287
|
+
it "raises SettingCheckFailed error" do
|
288
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
289
|
+
description 'Test setting'
|
290
|
+
check ->(setting) { false } # Always fail
|
291
|
+
end
|
292
|
+
expect { setting.confirm! }.to raise_error(ConstConf::SettingCheckFailed)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
context "when check passes" do
|
297
|
+
it "does not raise error" do
|
298
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
299
|
+
description 'Test setting'
|
300
|
+
check ->(setting) { true } # Always pass
|
301
|
+
end
|
302
|
+
expect { setting.confirm! }.not_to raise_error
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
describe "#ignored?" do
|
308
|
+
it "returns true when ignored is set to true" do
|
309
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP") do
|
310
|
+
description 'nope'
|
311
|
+
ignored true
|
312
|
+
end
|
313
|
+
expect(setting.ignored?).to be true
|
314
|
+
end
|
315
|
+
|
316
|
+
it "returns false when ignored is not set" do
|
317
|
+
setting = ConstConf::Setting.new(name: ["APP", "DATABASE_URL"], prefix: "APP")
|
318
|
+
expect(setting.ignored?).to be false
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "#value_provided?" do
|
323
|
+
it "returns true when configured value exists" do
|
324
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
325
|
+
default "default"
|
326
|
+
end
|
327
|
+
|
328
|
+
allow(setting).to receive(:configured_value_or_default_value).and_return("value")
|
329
|
+
|
330
|
+
expect(setting.value_provided?).to be true
|
331
|
+
end
|
332
|
+
|
333
|
+
it "returns false when no configured value or default exists" do
|
334
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
335
|
+
default nil
|
336
|
+
end
|
337
|
+
|
338
|
+
allow(setting).to receive(:configured_value_or_default_value).and_return(nil)
|
339
|
+
|
340
|
+
expect(setting.value_provided?).to be false
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
describe "#default_value" do
|
345
|
+
it "returns the default value when it's not a proc" do
|
346
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
347
|
+
default "test_default"
|
348
|
+
end
|
349
|
+
|
350
|
+
expect(setting.default_value).to eq "test_default"
|
351
|
+
end
|
352
|
+
|
353
|
+
it "evaluates the default when it's a proc" do
|
354
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
355
|
+
default -> { "computed_default" }
|
356
|
+
end
|
357
|
+
|
358
|
+
expect(setting.default_value).to eq "computed_default"
|
359
|
+
end
|
360
|
+
|
361
|
+
it "handles nil defaults properly" do
|
362
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
363
|
+
default nil
|
364
|
+
end
|
365
|
+
|
366
|
+
expect(setting.default_value).to be_nil
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
describe "#configured_value_or_default_value" do
|
371
|
+
it "returns configured value when present" do
|
372
|
+
ENV['APP_TEST_VAR'] = 'configured_value'
|
373
|
+
|
374
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
375
|
+
default "default_value"
|
376
|
+
end
|
377
|
+
|
378
|
+
expect(setting.configured_value_or_default_value).to eq "configured_value"
|
379
|
+
end
|
380
|
+
|
381
|
+
it "returns default value when configured value is nil" do
|
382
|
+
ENV['APP_TEST_VAR'] = nil
|
383
|
+
|
384
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
385
|
+
default "default_value"
|
386
|
+
end
|
387
|
+
|
388
|
+
expect(setting.configured_value_or_default_value).to eq "default_value"
|
389
|
+
end
|
390
|
+
|
391
|
+
it "returns nil when both configured and default values are nil" do
|
392
|
+
ENV['APP_TEST_VAR'] = nil
|
393
|
+
|
394
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
395
|
+
default nil
|
396
|
+
end
|
397
|
+
|
398
|
+
expect(setting.configured_value_or_default_value).to be_nil
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
describe "#configured_value" do
|
403
|
+
it "returns env var value when set and not ignored" do
|
404
|
+
ENV['APP_TEST_VAR'] = 'value'
|
405
|
+
|
406
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
407
|
+
default "default"
|
408
|
+
end
|
409
|
+
|
410
|
+
expect(setting.configured_value).to eq "value"
|
411
|
+
end
|
412
|
+
|
413
|
+
it "returns nil when env var is not set" do
|
414
|
+
ENV['APP_TEST_VAR'] = nil
|
415
|
+
|
416
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
417
|
+
default "default"
|
418
|
+
end
|
419
|
+
|
420
|
+
expect(setting.configured_value).to be_nil
|
421
|
+
end
|
422
|
+
|
423
|
+
it "returns nil when ignored" do
|
424
|
+
ENV['APP_TEST_VAR'] = 'value'
|
425
|
+
|
426
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
427
|
+
ignored true
|
428
|
+
default "default"
|
429
|
+
end
|
430
|
+
|
431
|
+
expect(setting.configured_value).to be_nil
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
describe "#checked?" do
|
436
|
+
context "with default check (always passes)" do
|
437
|
+
it "returns :unchecked_true by default" do
|
438
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
439
|
+
description 'Test setting'
|
440
|
+
end
|
441
|
+
expect(setting.checked?).to be :unchecked_true
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
context "with custom check that passes" do
|
446
|
+
it "returns true when custom check passes" do
|
447
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
448
|
+
description 'Test setting'
|
449
|
+
check ->(setting) { true } # Always pass
|
450
|
+
end
|
451
|
+
expect(setting.checked?).to be true
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
context "with custom check that fails" do
|
456
|
+
it "returns false when custom check fails" do
|
457
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
458
|
+
description 'Test setting'
|
459
|
+
check ->(setting) { false } # Always fail
|
460
|
+
end
|
461
|
+
expect(setting.checked?).to be false
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
context "with custom check that uses setting value" do
|
466
|
+
it "returns true when check validates value properly" do
|
467
|
+
ENV['APP_TEST_VAR'] = 'valid_value'
|
468
|
+
|
469
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
470
|
+
description 'Test setting'
|
471
|
+
check ->(setting) {
|
472
|
+
value = setting.value
|
473
|
+
!value.nil? && value.length > 5 # Only pass if value length > 5
|
474
|
+
}
|
475
|
+
end
|
476
|
+
expect(setting.checked?).to be true
|
477
|
+
end
|
478
|
+
|
479
|
+
it "returns false when check validates value improperly" do
|
480
|
+
ENV['APP_TEST_VAR'] = 'short'
|
481
|
+
|
482
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
483
|
+
description 'Test setting'
|
484
|
+
check ->(setting) {
|
485
|
+
value = setting.value
|
486
|
+
!value.nil? && value.length > 5 # Only pass if value length > 5
|
487
|
+
}
|
488
|
+
end
|
489
|
+
expect(setting.checked?).to be false
|
490
|
+
end
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
describe "#decoded_value" do
|
495
|
+
it "applies decoding when proc is present" do
|
496
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
497
|
+
decode ->(val) { val.upcase }
|
498
|
+
end
|
499
|
+
expect(setting).to be_decoding
|
500
|
+
expect(setting.send(:decoded_value, "test")).to eq "TEST"
|
501
|
+
end
|
502
|
+
|
503
|
+
it "returns value unchanged when no decoding is present" do
|
504
|
+
setting = ConstConf::Setting.new(name: ["APP", "TEST_VAR"], prefix: "APP") do
|
505
|
+
decode nil
|
506
|
+
end
|
507
|
+
|
508
|
+
expect(setting.send(:decoded_value, "test")).to eq "test"
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
context 'with parent namespace' do
|
513
|
+
module TestParentNamespace
|
514
|
+
include ConstConf
|
515
|
+
end
|
516
|
+
|
517
|
+
describe "#view" do
|
518
|
+
it "generates tree structure for setting" do
|
519
|
+
setting = TestParentNamespace.module_eval do
|
520
|
+
ConstConf::Setting.new(name: ["APP", "VIEW_TEST"], prefix: "APP") do
|
521
|
+
description 'View test variable'
|
522
|
+
default 'view_default'
|
523
|
+
required true
|
524
|
+
sensitive true
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
# Test that view works with StringIO
|
529
|
+
io = StringIO.new
|
530
|
+
setting.view(io: io)
|
531
|
+
output = io.string
|
532
|
+
|
533
|
+
expect(output).to include('VIEW_TEST')
|
534
|
+
expect(output).to include('View test variable')
|
535
|
+
expect(output).to include('APP_VIEW_TEST')
|
536
|
+
expect(output).not_to include('view_default')
|
537
|
+
expect(output).to include('required 🔴')
|
538
|
+
expect(output).to include('sensitive 🔒')
|
539
|
+
end
|
540
|
+
|
541
|
+
it "shows check status in view output" do
|
542
|
+
setting = TestParentNamespace.module_eval do
|
543
|
+
ConstConf::Setting.new(name: ["APP", "CHECK_VAR"], prefix: "APP") do
|
544
|
+
description 'Check test variable'
|
545
|
+
check ->(setting) { true }
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
io = StringIO.new
|
550
|
+
setting.view(io: io)
|
551
|
+
output = io.string
|
552
|
+
|
553
|
+
expect(output).to include('checked ✅')
|
554
|
+
end
|
555
|
+
|
556
|
+
it "shows failed check in view output" do
|
557
|
+
setting = TestParentNamespace.module_eval do
|
558
|
+
ConstConf::Setting.new(name: ["APP", "FAILED_VAR"], prefix: "APP") do
|
559
|
+
description 'Failed check variable'
|
560
|
+
check ->(setting) { false }
|
561
|
+
end
|
562
|
+
end
|
563
|
+
|
564
|
+
io = StringIO.new
|
565
|
+
setting.view(io: io)
|
566
|
+
output = io.string
|
567
|
+
|
568
|
+
expect(output).to include('checked ❌')
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
describe "#to_s" do
|
573
|
+
it "returns string representation with all metadata" do
|
574
|
+
setting = TestParentNamespace.module_eval do
|
575
|
+
ConstConf::Setting.new(name: ["APP", "TO_S_TEST"], prefix: "APP") do
|
576
|
+
description 'To string test'
|
577
|
+
default 'to_string_default'
|
578
|
+
required true
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
output = setting.to_s
|
583
|
+
expect(output).to be_a(String)
|
584
|
+
expect(output).to include('TO_S_TEST')
|
585
|
+
expect(output).to include('To string test')
|
586
|
+
expect(output).to include('default "to_string_default"')
|
587
|
+
expect(output).to include('required 🔴')
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
describe "#inspect" do
|
592
|
+
it "returns same format as to_s" do
|
593
|
+
setting = TestParentNamespace.module_eval do
|
594
|
+
ConstConf::Setting.new(name: ["APP", "INSPECT_TEST"], prefix: "APP") do
|
595
|
+
description 'Inspect test'
|
596
|
+
default 'inspect_default'
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
inspect_output = setting.inspect
|
601
|
+
to_s_output = setting.to_s
|
602
|
+
|
603
|
+
expect(inspect_output).to be_a(String)
|
604
|
+
expect(to_s_output).to be_a(String)
|
605
|
+
expect(inspect_output).to eq to_s_output
|
606
|
+
end
|
607
|
+
|
608
|
+
it "returns same format as to_s without colors" do
|
609
|
+
require 'irb'
|
610
|
+
allow(IRB.conf).to receive(:[]).with(:USE_COLORIZE).and_return true
|
611
|
+
|
612
|
+
setting = TestParentNamespace.module_eval do
|
613
|
+
ConstConf::Setting.new(name: ["APP", "INSPECT_TEST"], prefix: "APP") do
|
614
|
+
description 'Inspect test'
|
615
|
+
default 'inspect_default'
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
inspect_output = setting.inspect
|
620
|
+
to_s_output = setting.to_s
|
621
|
+
|
622
|
+
expect(inspect_output).to be_a(String)
|
623
|
+
expect(to_s_output).to be_a(String)
|
624
|
+
expect(inspect_output).to eq Term::ANSIColor.uncolor(to_s_output)
|
625
|
+
end
|
626
|
+
end
|
627
|
+
end
|
628
|
+
end
|