hocon 0.9.5 → 1.0.1
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 +4 -4
- data/CHANGELOG.md +14 -2
- data/README.md +22 -10
- data/lib/hocon.rb +9 -3
- data/lib/hocon/config_factory.rb +4 -0
- data/lib/hocon/config_value_factory.rb +13 -2
- data/lib/hocon/impl/config_reference.rb +5 -2
- data/lib/hocon/impl/simple_config_origin.rb +1 -1
- data/spec/fixtures/parse_render/example1/input.conf +21 -0
- data/spec/fixtures/parse_render/example1/output.conf +26 -0
- data/spec/fixtures/parse_render/example1/output_nocomments.conf +17 -0
- data/spec/fixtures/parse_render/example2/input.conf +10 -0
- data/spec/fixtures/parse_render/example2/output.conf +17 -0
- data/spec/fixtures/parse_render/example2/output_nocomments.conf +17 -0
- data/spec/fixtures/parse_render/example3/input.conf +2 -0
- data/spec/fixtures/parse_render/example3/output.conf +2 -0
- data/spec/fixtures/parse_render/example4/input.json +6 -0
- data/spec/fixtures/parse_render/example4/output.conf +6 -0
- data/spec/fixtures/test_utils/resources/bom.conf +2 -0
- data/spec/fixtures/test_utils/resources/cycle.conf +1 -0
- data/spec/fixtures/test_utils/resources/file-include.conf +5 -0
- data/spec/fixtures/test_utils/resources/include-from-list.conf +4 -0
- data/spec/fixtures/test_utils/resources/subdir/bar.conf +1 -0
- data/spec/fixtures/test_utils/resources/subdir/baz.conf +1 -0
- data/spec/fixtures/test_utils/resources/subdir/foo.conf +5 -0
- data/spec/fixtures/test_utils/resources/test01.conf +80 -0
- data/spec/fixtures/test_utils/resources/test01.json +4 -0
- data/spec/fixtures/test_utils/resources/test03.conf +36 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/test_utils.rb +757 -0
- data/spec/unit/typesafe/config/concatenation_spec.rb +417 -0
- data/spec/unit/typesafe/config/conf_parser_spec.rb +822 -0
- data/spec/unit/typesafe/config/config_document_parser_spec.rb +494 -0
- data/spec/unit/typesafe/config/config_document_spec.rb +576 -0
- data/spec/unit/typesafe/config/config_factory_spec.rb +120 -0
- data/spec/unit/typesafe/config/config_node_spec.rb +552 -0
- data/spec/unit/typesafe/config/config_value_factory_spec.rb +85 -0
- data/spec/unit/typesafe/config/config_value_spec.rb +935 -0
- data/spec/unit/typesafe/config/hocon_spec.rb +54 -0
- data/spec/unit/typesafe/config/path_spec.rb +261 -0
- data/spec/unit/typesafe/config/public_api_spec.rb +520 -0
- data/spec/unit/typesafe/config/simple_config_spec.rb +112 -0
- data/spec/unit/typesafe/config/token_spec.rb +188 -0
- data/spec/unit/typesafe/config/tokenizer_spec.rb +801 -0
- metadata +39 -3
@@ -0,0 +1,85 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'hocon/config_value_factory'
|
5
|
+
require 'hocon/config_render_options'
|
6
|
+
require 'hocon/config_error'
|
7
|
+
|
8
|
+
describe Hocon::ConfigValueFactory do
|
9
|
+
let(:render_options) { Hocon::ConfigRenderOptions.defaults }
|
10
|
+
|
11
|
+
before do
|
12
|
+
render_options.origin_comments = false
|
13
|
+
render_options.json = false
|
14
|
+
end
|
15
|
+
|
16
|
+
context "converting objects to ConfigValue using ConfigValueFactory" do
|
17
|
+
it "should convert true into a ConfigBoolean" do
|
18
|
+
value = Hocon::ConfigValueFactory.from_any_ref(true, nil)
|
19
|
+
expect(value).to be_instance_of(Hocon::Impl::ConfigBoolean)
|
20
|
+
expect(value.unwrapped).to eql(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should convert false into a ConfigBoolean" do
|
24
|
+
value = Hocon::ConfigValueFactory.from_any_ref(false, nil)
|
25
|
+
expect(value).to be_instance_of(Hocon::Impl::ConfigBoolean)
|
26
|
+
expect(value.unwrapped).to eql(false)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should convert nil into a ConfigNull object" do
|
30
|
+
value = Hocon::ConfigValueFactory.from_any_ref(nil, nil)
|
31
|
+
expect(value).to be_instance_of(Hocon::Impl::ConfigNull)
|
32
|
+
expect(value.unwrapped).to be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should convert an string into a ConfigString object" do
|
36
|
+
value = Hocon::ConfigValueFactory.from_any_ref("Hello, World!", nil)
|
37
|
+
expect(value).to be_a(Hocon::Impl::ConfigString)
|
38
|
+
expect(value.unwrapped).to eq("Hello, World!")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should convert an integer into a ConfigInt object" do
|
42
|
+
value = Hocon::ConfigValueFactory.from_any_ref(123, nil)
|
43
|
+
expect(value).to be_instance_of(Hocon::Impl::ConfigInt)
|
44
|
+
expect(value.unwrapped).to eq(123)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should convert a double into a ConfigDouble object" do
|
48
|
+
value = Hocon::ConfigValueFactory.from_any_ref(123.456, nil)
|
49
|
+
expect(value).to be_instance_of(Hocon::Impl::ConfigDouble)
|
50
|
+
expect(value.unwrapped).to eq(123.456)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should convert a map into a SimpleConfigObject" do
|
54
|
+
map = {"a" => 1, "b" => 2, "c" => 3}
|
55
|
+
value = Hocon::ConfigValueFactory.from_any_ref(map, nil)
|
56
|
+
expect(value).to be_instance_of(Hocon::Impl::SimpleConfigObject)
|
57
|
+
expect(value.unwrapped).to eq(map)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should convert symbol keys in a map to string keys" do
|
61
|
+
orig_map = {a: 1, b: 2, c: {a: 1, b: 2, c: {a: 1}}}
|
62
|
+
map = {"a" => 1, "b" => 2, "c"=>{"a"=>1, "b"=>2, "c"=>{"a"=>1}}}
|
63
|
+
value = Hocon::ConfigValueFactory.from_any_ref(orig_map, nil)
|
64
|
+
expect(value).to be_instance_of(Hocon::Impl::SimpleConfigObject)
|
65
|
+
expect(value.unwrapped).to eq(map)
|
66
|
+
|
67
|
+
value = Hocon::ConfigValueFactory.from_map(orig_map, nil)
|
68
|
+
expect(value).to be_instance_of(Hocon::Impl::SimpleConfigObject)
|
69
|
+
expect(value.unwrapped).to eq(map)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should not parse maps with non-string and non-symbol keys" do
|
73
|
+
map = {1 => "a", 2 => "b"}
|
74
|
+
expect{ Hocon::ConfigValueFactory.from_any_ref(map, nil) }.to raise_error(Hocon::ConfigError::ConfigBugOrBrokenError)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should convert an Enumerable into a SimpleConfigList" do
|
78
|
+
list = [1, 2, 3, 4, 5]
|
79
|
+
value = Hocon::ConfigValueFactory.from_any_ref(list, nil)
|
80
|
+
expect(value).to be_instance_of(Hocon::Impl::SimpleConfigList)
|
81
|
+
expect(value.unwrapped).to eq(list)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,935 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'hocon'
|
3
|
+
require 'test_utils'
|
4
|
+
|
5
|
+
require 'hocon/impl/config_delayed_merge'
|
6
|
+
require 'hocon/impl/config_delayed_merge_object'
|
7
|
+
require 'hocon/config_error'
|
8
|
+
require 'hocon/impl/unsupported_operation_error'
|
9
|
+
require 'hocon/config_value_factory'
|
10
|
+
require 'hocon/config_render_options'
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
SimpleConfigOrigin = Hocon::Impl::SimpleConfigOrigin
|
15
|
+
SimpleConfigObject = Hocon::Impl::SimpleConfigObject
|
16
|
+
SimpleConfigList = Hocon::Impl::SimpleConfigList
|
17
|
+
SubstitutionExpression = Hocon::Impl::SubstitutionExpression
|
18
|
+
ConfigReference = Hocon::Impl::ConfigReference
|
19
|
+
ConfigConcatenation = Hocon::Impl::ConfigConcatenation
|
20
|
+
ConfigDelayedMerge = Hocon::Impl::ConfigDelayedMerge
|
21
|
+
ConfigDelayedMergeObject = Hocon::Impl::ConfigDelayedMergeObject
|
22
|
+
ConfigNotResolvedError = Hocon::ConfigError::ConfigNotResolvedError
|
23
|
+
UnresolvedSubstitutionError = Hocon::ConfigError::UnresolvedSubstitutionError
|
24
|
+
ConfigBugOrBrokenError = Hocon::ConfigError::ConfigBugOrBrokenError
|
25
|
+
AbstractConfigObject = Hocon::Impl::AbstractConfigObject
|
26
|
+
ConfigValueFactory = Hocon::ConfigValueFactory
|
27
|
+
ConfigFactory = Hocon::ConfigFactory
|
28
|
+
UnsupportedOperationError = Hocon::Impl::UnsupportedOperationError
|
29
|
+
ConfigNumber = Hocon::Impl::ConfigNumber
|
30
|
+
ConfigRenderOptions = Hocon::ConfigRenderOptions
|
31
|
+
|
32
|
+
describe "SimpleConfigOrigin equality" do
|
33
|
+
context "different origins with the same name should be equal" do
|
34
|
+
let(:a) { SimpleConfigOrigin.new_simple("foo") }
|
35
|
+
let(:same_as_a) { SimpleConfigOrigin.new_simple("foo") }
|
36
|
+
let(:b) { SimpleConfigOrigin.new_simple("bar") }
|
37
|
+
|
38
|
+
context "a equals a" do
|
39
|
+
let(:first_object) { a }
|
40
|
+
let(:second_object) { a }
|
41
|
+
include_examples "object_equality"
|
42
|
+
end
|
43
|
+
|
44
|
+
context "a equals same_as_a" do
|
45
|
+
let(:first_object) { a }
|
46
|
+
let(:second_object) { same_as_a }
|
47
|
+
include_examples "object_equality"
|
48
|
+
end
|
49
|
+
|
50
|
+
context "a does not equal b" do
|
51
|
+
let(:first_object) { a }
|
52
|
+
let(:second_object) { b }
|
53
|
+
include_examples "object_inequality"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "ConfigInt equality" do
|
59
|
+
context "different ConfigInts with the same value should be equal" do
|
60
|
+
a = TestUtils.int_value(42)
|
61
|
+
same_as_a = TestUtils.int_value(42)
|
62
|
+
b = TestUtils.int_value(43)
|
63
|
+
|
64
|
+
context "a equals a" do
|
65
|
+
let(:first_object) { a }
|
66
|
+
let(:second_object) { a }
|
67
|
+
include_examples "object_equality"
|
68
|
+
end
|
69
|
+
|
70
|
+
context "a equals same_as_a" do
|
71
|
+
let(:first_object) { a }
|
72
|
+
let(:second_object) { same_as_a }
|
73
|
+
include_examples "object_equality"
|
74
|
+
end
|
75
|
+
|
76
|
+
context "a does not equal b" do
|
77
|
+
let(:first_object) { a }
|
78
|
+
let(:second_object) { b }
|
79
|
+
include_examples "object_inequality"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "ConfigFloat equality" do
|
85
|
+
context "different ConfigFloats with the same value should be equal" do
|
86
|
+
a = TestUtils.double_value(3.14)
|
87
|
+
same_as_a = TestUtils.double_value(3.14)
|
88
|
+
b = TestUtils.double_value(4.14)
|
89
|
+
|
90
|
+
context "a equals a" do
|
91
|
+
let(:first_object) { a }
|
92
|
+
let(:second_object) { a }
|
93
|
+
include_examples "object_equality"
|
94
|
+
end
|
95
|
+
|
96
|
+
context "a equals same_as_a" do
|
97
|
+
let(:first_object) { a }
|
98
|
+
let(:second_object) { same_as_a }
|
99
|
+
include_examples "object_equality"
|
100
|
+
end
|
101
|
+
|
102
|
+
context "a does not equal b" do
|
103
|
+
let(:first_object) { a }
|
104
|
+
let(:second_object) { b }
|
105
|
+
include_examples "object_inequality"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "ConfigFloat and ConfigInt equality" do
|
111
|
+
context "different ConfigInts with the same value should be equal" do
|
112
|
+
double_val = TestUtils.double_value(3.0)
|
113
|
+
int_value = TestUtils.int_value(3)
|
114
|
+
double_value_b = TestUtils.double_value(4.0)
|
115
|
+
int_value_b = TestUtils.double_value(4)
|
116
|
+
|
117
|
+
context "int equals double" do
|
118
|
+
let(:first_object) { double_val }
|
119
|
+
let(:second_object) { int_value }
|
120
|
+
include_examples "object_equality"
|
121
|
+
end
|
122
|
+
|
123
|
+
context "ConfigFloat made from int equals double" do
|
124
|
+
let(:first_object) { double_value_b }
|
125
|
+
let(:second_object) { int_value_b }
|
126
|
+
include_examples "object_equality"
|
127
|
+
end
|
128
|
+
|
129
|
+
context "3 doesn't equal 4.0" do
|
130
|
+
let(:first_object) { int_value }
|
131
|
+
let(:second_object) { double_value_b }
|
132
|
+
include_examples "object_inequality"
|
133
|
+
end
|
134
|
+
|
135
|
+
context "4.0 doesn't equal 3.0" do
|
136
|
+
let(:first_object) { int_value_b }
|
137
|
+
let(:second_object) { double_val }
|
138
|
+
include_examples "object_inequality"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "SimpleConfigObject equality" do
|
144
|
+
context "SimpleConfigObjects made from hash maps" do
|
145
|
+
a_map = TestUtils.config_map({a: 1, b: 2, c: 3})
|
146
|
+
same_as_a_map = TestUtils.config_map({a: 1, b: 2, c: 3})
|
147
|
+
b_map = TestUtils.config_map({a: 3, b: 4, c: 5})
|
148
|
+
|
149
|
+
# different keys is a different case in the equals implementation
|
150
|
+
c_map = TestUtils.config_map({x: 3, y: 4, z: 5})
|
151
|
+
|
152
|
+
a = SimpleConfigObject.new(TestUtils.fake_origin, a_map)
|
153
|
+
same_as_a = SimpleConfigObject.new(TestUtils.fake_origin, same_as_a_map)
|
154
|
+
b = SimpleConfigObject.new(TestUtils.fake_origin, b_map)
|
155
|
+
c = SimpleConfigObject.new(TestUtils.fake_origin, c_map)
|
156
|
+
|
157
|
+
# the config for an equal object is also equal
|
158
|
+
config = a.to_config
|
159
|
+
|
160
|
+
context "a equals a" do
|
161
|
+
let(:first_object) { a }
|
162
|
+
let(:second_object) { a }
|
163
|
+
include_examples "object_equality"
|
164
|
+
end
|
165
|
+
|
166
|
+
context "a equals same_as_a" do
|
167
|
+
let(:first_object) { a }
|
168
|
+
let(:second_object) { same_as_a }
|
169
|
+
include_examples "object_equality"
|
170
|
+
end
|
171
|
+
|
172
|
+
context "b equals b" do
|
173
|
+
let(:first_object) { b }
|
174
|
+
let(:second_object) { b }
|
175
|
+
include_examples "object_equality"
|
176
|
+
end
|
177
|
+
|
178
|
+
context "c equals c" do
|
179
|
+
let(:first_object) { c }
|
180
|
+
let(:second_object) { c }
|
181
|
+
include_examples "object_equality"
|
182
|
+
end
|
183
|
+
|
184
|
+
context "a doesn't equal b" do
|
185
|
+
let(:first_object) { a }
|
186
|
+
let(:second_object) { b }
|
187
|
+
include_examples "object_inequality"
|
188
|
+
end
|
189
|
+
|
190
|
+
context "a doesn't equal c" do
|
191
|
+
let(:first_object) { a }
|
192
|
+
let(:second_object) { c }
|
193
|
+
include_examples "object_inequality"
|
194
|
+
end
|
195
|
+
|
196
|
+
context "b doesn't equal c" do
|
197
|
+
let(:first_object) { b }
|
198
|
+
let(:second_object) { c }
|
199
|
+
include_examples "object_inequality"
|
200
|
+
end
|
201
|
+
|
202
|
+
context "a's config equals a's config" do
|
203
|
+
let(:first_object) { config }
|
204
|
+
let(:second_object) { config }
|
205
|
+
include_examples "object_equality"
|
206
|
+
end
|
207
|
+
|
208
|
+
context "a's config equals same_as_a's config" do
|
209
|
+
let(:first_object) { config }
|
210
|
+
let(:second_object) { same_as_a.to_config }
|
211
|
+
include_examples "object_equality"
|
212
|
+
end
|
213
|
+
|
214
|
+
context "a's config equals a's config computed again" do
|
215
|
+
let(:first_object) { config }
|
216
|
+
let(:second_object) { a.to_config }
|
217
|
+
include_examples "object_equality"
|
218
|
+
end
|
219
|
+
|
220
|
+
context "a's config doesn't equal b's config" do
|
221
|
+
let(:first_object) { config }
|
222
|
+
let(:second_object) { b.to_config }
|
223
|
+
include_examples "object_inequality"
|
224
|
+
end
|
225
|
+
|
226
|
+
context "a's config doesn't equal c's config" do
|
227
|
+
let(:first_object) { config }
|
228
|
+
let(:second_object) { c.to_config }
|
229
|
+
include_examples "object_inequality"
|
230
|
+
end
|
231
|
+
|
232
|
+
context "a doesn't equal a's config" do
|
233
|
+
let(:first_object) { a }
|
234
|
+
let(:second_object) { config }
|
235
|
+
include_examples "object_inequality"
|
236
|
+
end
|
237
|
+
|
238
|
+
context "b doesn't equal b's config" do
|
239
|
+
let(:first_object) { b }
|
240
|
+
let(:second_object) { b.to_config }
|
241
|
+
include_examples "object_inequality"
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe "SimpleConfigList equality" do
|
247
|
+
a_values = [1, 2, 3].map { |i| TestUtils.int_value(i) }
|
248
|
+
a_list = SimpleConfigList.new(TestUtils.fake_origin, a_values)
|
249
|
+
|
250
|
+
same_as_a_values = [1, 2, 3].map { |i| TestUtils.int_value(i) }
|
251
|
+
same_as_a_list = SimpleConfigList.new(TestUtils.fake_origin, same_as_a_values)
|
252
|
+
|
253
|
+
b_values = [4, 5, 6].map { |i| TestUtils.int_value(i) }
|
254
|
+
b_list = SimpleConfigList.new(TestUtils.fake_origin, b_values)
|
255
|
+
|
256
|
+
context "a_list equals a_list" do
|
257
|
+
let(:first_object) { a_list }
|
258
|
+
let(:second_object) { a_list }
|
259
|
+
include_examples "object_equality"
|
260
|
+
end
|
261
|
+
|
262
|
+
context "a_list equals same_as_a_list" do
|
263
|
+
let(:first_object) { a_list }
|
264
|
+
let(:second_object) { same_as_a_list }
|
265
|
+
include_examples "object_equality"
|
266
|
+
end
|
267
|
+
|
268
|
+
context "a_list doesn't equal b_list" do
|
269
|
+
let(:first_object) { a_list }
|
270
|
+
let(:second_object) { b_list }
|
271
|
+
include_examples "object_inequality"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
describe "ConfigReference equality" do
|
276
|
+
a = TestUtils.subst("foo")
|
277
|
+
same_as_a = TestUtils.subst("foo")
|
278
|
+
b = TestUtils.subst("bar")
|
279
|
+
c = TestUtils.subst("foo", true)
|
280
|
+
|
281
|
+
specify "testing values are of the right type" do
|
282
|
+
expect(a).to be_instance_of(ConfigReference)
|
283
|
+
expect(b).to be_instance_of(ConfigReference)
|
284
|
+
expect(c).to be_instance_of(ConfigReference)
|
285
|
+
end
|
286
|
+
|
287
|
+
context "a equals a" do
|
288
|
+
let(:first_object) { a }
|
289
|
+
let(:second_object) { a }
|
290
|
+
include_examples "object_equality"
|
291
|
+
end
|
292
|
+
|
293
|
+
context "a equals same_as_a" do
|
294
|
+
let(:first_object) { a }
|
295
|
+
let(:second_object) { same_as_a }
|
296
|
+
include_examples "object_equality"
|
297
|
+
end
|
298
|
+
|
299
|
+
context "a doesn't equal b" do
|
300
|
+
let(:first_object) { a }
|
301
|
+
let(:second_object) { b }
|
302
|
+
include_examples "object_inequality"
|
303
|
+
end
|
304
|
+
|
305
|
+
context "a doesn't equal c, an optional substitution" do
|
306
|
+
let(:first_object) { a }
|
307
|
+
let(:second_object) { c }
|
308
|
+
include_examples "object_inequality"
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
describe "ConfigConcatenation equality" do
|
313
|
+
a = TestUtils.subst_in_string("foo")
|
314
|
+
same_as_a = TestUtils.subst_in_string("foo")
|
315
|
+
b = TestUtils.subst_in_string("bar")
|
316
|
+
c = TestUtils.subst_in_string("foo", true)
|
317
|
+
|
318
|
+
specify "testing values are of the right type" do
|
319
|
+
expect(a).to be_instance_of(ConfigConcatenation)
|
320
|
+
expect(b).to be_instance_of(ConfigConcatenation)
|
321
|
+
expect(c).to be_instance_of(ConfigConcatenation)
|
322
|
+
end
|
323
|
+
|
324
|
+
context "a equals a" do
|
325
|
+
let(:first_object) { a }
|
326
|
+
let(:second_object) { a }
|
327
|
+
include_examples "object_equality"
|
328
|
+
end
|
329
|
+
|
330
|
+
context "a equals same_as_a" do
|
331
|
+
let(:first_object) { a }
|
332
|
+
let(:second_object) { same_as_a }
|
333
|
+
include_examples "object_equality"
|
334
|
+
end
|
335
|
+
|
336
|
+
context "a doesn't equal b" do
|
337
|
+
let(:first_object) { a }
|
338
|
+
let(:second_object) { b }
|
339
|
+
include_examples "object_inequality"
|
340
|
+
end
|
341
|
+
|
342
|
+
context "a doesn't equal c, an optional substitution" do
|
343
|
+
let(:first_object) { a }
|
344
|
+
let(:second_object) { c }
|
345
|
+
include_examples "object_inequality"
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
describe "ConfigDelayedMerge equality" do
|
350
|
+
s1 = TestUtils.subst("foo")
|
351
|
+
s2 = TestUtils.subst("bar")
|
352
|
+
a = ConfigDelayedMerge.new(TestUtils.fake_origin, [s1, s2])
|
353
|
+
same_as_a = ConfigDelayedMerge.new(TestUtils.fake_origin, [s1, s2])
|
354
|
+
b = ConfigDelayedMerge.new(TestUtils.fake_origin, [s2, s1])
|
355
|
+
|
356
|
+
context "a equals a" do
|
357
|
+
let(:first_object) { a }
|
358
|
+
let(:second_object) { a }
|
359
|
+
include_examples "object_equality"
|
360
|
+
end
|
361
|
+
|
362
|
+
context "a equals same_as_a" do
|
363
|
+
let(:first_object) { a }
|
364
|
+
let(:second_object) { same_as_a }
|
365
|
+
include_examples "object_equality"
|
366
|
+
end
|
367
|
+
|
368
|
+
context "a doesn't equal b" do
|
369
|
+
let(:first_object) { a }
|
370
|
+
let(:second_object) { b }
|
371
|
+
include_examples "object_inequality"
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
describe "ConfigDelayedMergeObject equality" do
|
376
|
+
empty = SimpleConfigObject.empty
|
377
|
+
s1 = TestUtils.subst("foo")
|
378
|
+
s2 = TestUtils.subst("bar")
|
379
|
+
a = ConfigDelayedMergeObject.new(TestUtils.fake_origin, [empty, s1, s2])
|
380
|
+
same_as_a = ConfigDelayedMergeObject.new(TestUtils.fake_origin, [empty, s1, s2])
|
381
|
+
b = ConfigDelayedMergeObject.new(TestUtils.fake_origin, [empty, s2, s1])
|
382
|
+
|
383
|
+
context "a equals a" do
|
384
|
+
let(:first_object) { a }
|
385
|
+
let(:second_object) { a }
|
386
|
+
include_examples "object_equality"
|
387
|
+
end
|
388
|
+
|
389
|
+
context "a equals same_as_a" do
|
390
|
+
let(:first_object) { a }
|
391
|
+
let(:second_object) { same_as_a }
|
392
|
+
include_examples "object_equality"
|
393
|
+
end
|
394
|
+
|
395
|
+
context "a doesn't equal b" do
|
396
|
+
let(:first_object) { a }
|
397
|
+
let(:second_object) { b }
|
398
|
+
include_examples "object_inequality"
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
describe "Values' to_s methods" do
|
403
|
+
# just check that these don't throw, the exact output
|
404
|
+
# isn't super important since it's just for debugging
|
405
|
+
|
406
|
+
specify "to_s doesn't throw error" do
|
407
|
+
TestUtils.int_value(10).to_s
|
408
|
+
TestUtils.double_value(3.14).to_s
|
409
|
+
TestUtils.string_value("hi").to_s
|
410
|
+
TestUtils.null_value.to_s
|
411
|
+
TestUtils.bool_value(true).to_s
|
412
|
+
empty_object = SimpleConfigObject.empty
|
413
|
+
empty_object.to_s
|
414
|
+
|
415
|
+
SimpleConfigList.new(TestUtils.fake_origin, []).to_s
|
416
|
+
TestUtils.subst("a").to_s
|
417
|
+
TestUtils.subst_in_string("b").to_s
|
418
|
+
dm = ConfigDelayedMerge.new(TestUtils.fake_origin, [TestUtils.subst("a"), TestUtils.subst("b")])
|
419
|
+
dm.to_s
|
420
|
+
|
421
|
+
dmo = ConfigDelayedMergeObject.new(TestUtils.fake_origin, [empty_object, TestUtils.subst("a"), TestUtils.subst("b")])
|
422
|
+
dmo.to_s
|
423
|
+
|
424
|
+
TestUtils.fake_origin.to_s
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
describe "ConfigObject" do
|
429
|
+
specify "should unwrap correctly" do
|
430
|
+
m = SimpleConfigObject.new(TestUtils.fake_origin, TestUtils.config_map({a: 1, b: 2, c: 3}))
|
431
|
+
|
432
|
+
expect({a: 1, b: 2, c: 3}).to eq(m.unwrapped)
|
433
|
+
end
|
434
|
+
|
435
|
+
specify "should implement read only map" do
|
436
|
+
m = SimpleConfigObject.new(TestUtils.fake_origin, TestUtils.config_map({a: 1, b: 2, c: 3}))
|
437
|
+
|
438
|
+
expect(TestUtils.int_value(1)).to eq(m[:a])
|
439
|
+
expect(TestUtils.int_value(2)).to eq(m[:b])
|
440
|
+
expect(TestUtils.int_value(3)).to eq(m[:c])
|
441
|
+
expect(m[:d]).to be_nil
|
442
|
+
# [] can take a non-string
|
443
|
+
expect(m[[]]).to be_nil
|
444
|
+
|
445
|
+
expect(m.has_key? :a).to be_truthy
|
446
|
+
expect(m.has_key? :z).to be_falsey
|
447
|
+
# has_key? can take a non-string
|
448
|
+
expect(m.has_key? []).to be_falsey
|
449
|
+
|
450
|
+
expect(m.has_value? TestUtils.int_value(1)).to be_truthy
|
451
|
+
expect(m.has_value? TestUtils.int_value(10)).to be_falsey
|
452
|
+
# has_value? can take a non-string
|
453
|
+
expect(m.has_value? []).to be_falsey
|
454
|
+
|
455
|
+
expect(m.empty?).to be_falsey
|
456
|
+
|
457
|
+
expect(m.size).to eq(3)
|
458
|
+
|
459
|
+
values = [TestUtils.int_value(1), TestUtils.int_value(2), TestUtils.int_value(3)]
|
460
|
+
expect(values).to eq(m.values)
|
461
|
+
|
462
|
+
keys = [:a, :b, :c]
|
463
|
+
expect(keys).to eq(m.keys)
|
464
|
+
|
465
|
+
expect { m["hello"] = TestUtils.int_value(41) }.to raise_error(UnsupportedOperationError)
|
466
|
+
expect { m.delete(:a) }.to raise_error(UnsupportedOperationError)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
describe "ConfigList" do
|
471
|
+
specify "should implement read only list" do
|
472
|
+
values = ["a", "b", "c"].map { |i| TestUtils.string_value(i) }
|
473
|
+
l = SimpleConfigList.new(TestUtils.fake_origin, values)
|
474
|
+
|
475
|
+
expect(values[0]).to eq(l[0])
|
476
|
+
expect(values[1]).to eq(l[1])
|
477
|
+
expect(values[2]).to eq(l[2])
|
478
|
+
|
479
|
+
expect(l.include? TestUtils.string_value("a")).to be_truthy
|
480
|
+
expect(l.include_all?([TestUtils.string_value("a")])).to be_truthy
|
481
|
+
expect(l.include_all?([TestUtils.string_value("b")])).to be_truthy
|
482
|
+
expect(l.include_all?(values)).to be_truthy
|
483
|
+
|
484
|
+
expect(l.index(values[1])).to eq(1)
|
485
|
+
|
486
|
+
expect(l.empty?).to be_falsey
|
487
|
+
|
488
|
+
expect(l.map { |v| v }).to eq(values.map { |v| v })
|
489
|
+
|
490
|
+
expect(l.rindex(values[1])).to eq(1)
|
491
|
+
|
492
|
+
expect(l.size).to eq(3)
|
493
|
+
|
494
|
+
expect { l.push(TestUtils.int_value(3)) }.to raise_error(UnsupportedOperationError)
|
495
|
+
expect { l << TestUtils.int_value(3) }.to raise_error(UnsupportedOperationError)
|
496
|
+
expect { l.clear }.to raise_error(UnsupportedOperationError)
|
497
|
+
expect { l.delete(TestUtils.int_value(2)) }.to raise_error(UnsupportedOperationError)
|
498
|
+
expect { l.delete(1) }.to raise_error(UnsupportedOperationError)
|
499
|
+
expect { l[0] = TestUtils.int_value(42) }.to raise_error(UnsupportedOperationError)
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
describe "Objects throwing ConfigNotResolvedError" do
|
504
|
+
context "ConfigSubstitution" do
|
505
|
+
specify "should throw ConfigNotResolvedError" do
|
506
|
+
expect{ TestUtils.subst("foo").value_type }.to raise_error(ConfigNotResolvedError)
|
507
|
+
expect{ TestUtils.subst("foo").unwrapped }.to raise_error(ConfigNotResolvedError)
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
context "ConfigDelayedMerge" do
|
512
|
+
let(:dm) { ConfigDelayedMerge.new(TestUtils.fake_origin, [TestUtils.subst("a"), TestUtils.subst("b")]) }
|
513
|
+
|
514
|
+
specify "should throw ConfigNotResolvedError" do
|
515
|
+
expect{ dm.value_type }.to raise_error(ConfigNotResolvedError)
|
516
|
+
expect{ dm.unwrapped }.to raise_error(ConfigNotResolvedError)
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
context "ConfigDelayedMergeObject" do
|
521
|
+
empty_object = SimpleConfigObject.empty
|
522
|
+
objects = [empty_object, TestUtils.subst("a"), TestUtils.subst("b")]
|
523
|
+
|
524
|
+
let(:dmo) { ConfigDelayedMergeObject.new(TestUtils.fake_origin, objects) }
|
525
|
+
|
526
|
+
specify "should have value type of OBJECT" do
|
527
|
+
expect(dmo.value_type).to eq(Hocon::ConfigValueType::OBJECT)
|
528
|
+
end
|
529
|
+
|
530
|
+
specify "should throw ConfigNotResolvedError" do
|
531
|
+
expect{ dmo.unwrapped }.to raise_error(ConfigNotResolvedError)
|
532
|
+
expect{ dmo["foo"] }.to raise_error(ConfigNotResolvedError)
|
533
|
+
expect{ dmo.has_key?(nil) }.to raise_error(ConfigNotResolvedError)
|
534
|
+
expect{ dmo.has_value?(nil) }.to raise_error(ConfigNotResolvedError)
|
535
|
+
expect{ dmo.each }.to raise_error(ConfigNotResolvedError)
|
536
|
+
expect{ dmo.empty? }.to raise_error(ConfigNotResolvedError)
|
537
|
+
expect{ dmo.keys }.to raise_error(ConfigNotResolvedError)
|
538
|
+
expect{ dmo.size }.to raise_error(ConfigNotResolvedError)
|
539
|
+
expect{ dmo.values }.to raise_error(ConfigNotResolvedError)
|
540
|
+
expect{ dmo.to_config.get_int("foo") }.to raise_error(ConfigNotResolvedError)
|
541
|
+
end
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
describe "Round tripping numbers through parse_string" do
|
546
|
+
specify "should get the same numbers back out" do
|
547
|
+
# formats rounded off with E notation
|
548
|
+
a = "132454454354353245.3254652656454808909932874873298473298472"
|
549
|
+
# formats as 100000.0
|
550
|
+
b = "1e6"
|
551
|
+
# formats as 5.0E-5
|
552
|
+
c = "0.00005"
|
553
|
+
# formats as 1E100 (capital E)
|
554
|
+
d = "1e100"
|
555
|
+
|
556
|
+
object = TestUtils.parse_config("{ a : #{a}, b : #{b}, c : #{c}, d : #{d}}")
|
557
|
+
expect([a, b, c, d]).to eq(["a", "b", "c", "d"].map { |x| object.get_string(x) })
|
558
|
+
|
559
|
+
object2 = TestUtils.parse_config("{ a : xx #{a} yy, b : xx #{b} yy, c : xx #{c} yy, d : xx #{d} yy}")
|
560
|
+
expected2 = [a, b, c, d].map { |x| "xx #{x} yy"}
|
561
|
+
expect(["a", "b", "c", "d"].map { |x| object2.get_string(x) }).to eq(expected2)
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
|
566
|
+
|
567
|
+
describe "AbstractConfigObject#merge_origins" do
|
568
|
+
def o(desc, empty)
|
569
|
+
values = {}
|
570
|
+
|
571
|
+
if !empty
|
572
|
+
values["hello"] = TestUtils.int_value(37)
|
573
|
+
end
|
574
|
+
|
575
|
+
SimpleConfigObject.new(SimpleConfigOrigin.new_simple(desc), values)
|
576
|
+
end
|
577
|
+
|
578
|
+
def m(*values)
|
579
|
+
AbstractConfigObject.merge_origins(values).description
|
580
|
+
end
|
581
|
+
|
582
|
+
specify "should merge origins correctly" do
|
583
|
+
# simplest case
|
584
|
+
expect(m(o("a", false), o("b", false))).to eq("merge of a,b")
|
585
|
+
|
586
|
+
# combine duplicate "merge of"
|
587
|
+
expect(m(o("a", false), o("merge of x,y", false))).to eq("merge of a,x,y")
|
588
|
+
expect(m(o("merge of a,b", false), o("merge of x,y", false))).to eq("merge of a,b,x,y")
|
589
|
+
# ignore empty objects
|
590
|
+
expect(m(o("foo", true), o("a", false))).to eq("a")
|
591
|
+
# unless they are all empty, pick the first one
|
592
|
+
expect(m(o("foo", true), o("a", true))).to eq("foo")
|
593
|
+
# merge just one
|
594
|
+
expect(m(o("foo", false))).to eq("foo")
|
595
|
+
# merge three
|
596
|
+
expect(m(o("a", false), o("b", false), o("c", false))).to eq("merge of a,b,c")
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
describe "SimpleConfig#has_path?" do
|
601
|
+
specify "should work in various contexts" do
|
602
|
+
empty = TestUtils.parse_config("{}")
|
603
|
+
|
604
|
+
expect(empty.has_path?("foo")).to be_falsey
|
605
|
+
|
606
|
+
object = TestUtils.parse_config("a=null, b.c.d=11, foo=bar")
|
607
|
+
|
608
|
+
# returns true for the non-null values
|
609
|
+
expect(object.has_path?("foo")).to be_truthy
|
610
|
+
expect(object.has_path?("b.c.d")).to be_truthy
|
611
|
+
expect(object.has_path?("b.c")).to be_truthy
|
612
|
+
expect(object.has_path?("b")).to be_truthy
|
613
|
+
|
614
|
+
# has_path is false for null values but contains_key is true
|
615
|
+
expect(object.root["a"]).to eq(TestUtils.null_value)
|
616
|
+
expect(object.root.has_key?("a")).to be_truthy
|
617
|
+
expect(object.has_path?("a")).to be_falsey
|
618
|
+
|
619
|
+
# false for totally absent values
|
620
|
+
expect(object.root.has_key?("notinhere")).to be_falsey
|
621
|
+
expect(object.has_path?("notinhere")).to be_falsey
|
622
|
+
|
623
|
+
# throws proper exceptions
|
624
|
+
expect { empty.has_path?("a.") }.to raise_error(Hocon::ConfigError::ConfigBadPathError)
|
625
|
+
expect { empty.has_path?("..") }.to raise_error(Hocon::ConfigError::ConfigBadPathError)
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
describe "ConfigNumber::new_number" do
|
630
|
+
specify "should create new objects correctly" do
|
631
|
+
def n(v)
|
632
|
+
ConfigNumber.new_number(TestUtils.fake_origin, v, nil)
|
633
|
+
end
|
634
|
+
|
635
|
+
expect(n(3.14).unwrapped).to eq(3.14)
|
636
|
+
expect(n(1).unwrapped).to eq(1)
|
637
|
+
expect(n(1).unwrapped).to eq(1.0)
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
describe "Boolean conversions" do
|
642
|
+
specify "true, yes, and on all convert to true" do
|
643
|
+
trues = TestUtils.parse_object("{ a=true, b=yes, c=on }").to_config
|
644
|
+
["a", "b", "c"].map { |x| expect(trues.get_boolean(x)).to be true }
|
645
|
+
|
646
|
+
falses = TestUtils.parse_object("{ a=false, b=no, c=off }").to_config
|
647
|
+
["a", "b", "c"].map { |x| expect(falses.get_boolean(x)).to be false }
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
describe "SimpleConfigOrigin" do
|
652
|
+
let(:has_filename) { SimpleConfigOrigin.new_file("foo") }
|
653
|
+
let(:no_filename) { SimpleConfigOrigin.new_simple("bar") }
|
654
|
+
let(:filename_with_line) { has_filename.with_line_number(3) }
|
655
|
+
let(:no_filename_with_line) { no_filename.with_line_number(4) }
|
656
|
+
|
657
|
+
specify "filename matches what was specified" do
|
658
|
+
expect(has_filename.filename).to eq("foo")
|
659
|
+
expect(filename_with_line.filename).to eq("foo")
|
660
|
+
expect(no_filename.filename).to be nil
|
661
|
+
expect(no_filename_with_line.filename).to be nil
|
662
|
+
end
|
663
|
+
|
664
|
+
specify "description matches correctly" do
|
665
|
+
expect(has_filename.description).to eq("foo")
|
666
|
+
expect(no_filename.description).to eq("bar")
|
667
|
+
expect(filename_with_line.description).to eq("foo: 3")
|
668
|
+
expect(no_filename_with_line.description).to eq("bar: 4")
|
669
|
+
end
|
670
|
+
|
671
|
+
specify "origins with no line number should have line number of -1" do
|
672
|
+
expect(has_filename.line_number).to eq(-1)
|
673
|
+
expect(no_filename.line_number).to eq(-1)
|
674
|
+
end
|
675
|
+
|
676
|
+
specify "line_number returns the right line number" do
|
677
|
+
expect(filename_with_line.line_number).to eq(3)
|
678
|
+
expect(no_filename_with_line.line_number).to eq(4)
|
679
|
+
end
|
680
|
+
|
681
|
+
# Note: skipping tests related to URLs since we aren't implementing that
|
682
|
+
end
|
683
|
+
|
684
|
+
|
685
|
+
describe "Config#with_only_key and with_only_path" do
|
686
|
+
context "should keep the correct data" do
|
687
|
+
object = TestUtils.parse_object("{ a=1, b=2, c.d.y=3, e.f.g=4, c.d.z=5 }")
|
688
|
+
|
689
|
+
it "should keep only a" do
|
690
|
+
expect(object.with_only_key("a")).to eq(TestUtils.parse_object("{ a=1 }"))
|
691
|
+
end
|
692
|
+
|
693
|
+
it "should keep only e" do
|
694
|
+
expect(object.with_only_key("e")).to eq(TestUtils.parse_object("{ e.f.g=4 }"))
|
695
|
+
end
|
696
|
+
|
697
|
+
it "should keep only c.d" do
|
698
|
+
expect(object.to_config.with_only_path("c.d").root).to eq(TestUtils.parse_object("{ c.d.y=3, c.d.z=5 }"))
|
699
|
+
end
|
700
|
+
|
701
|
+
it "should keep only c.d.z" do
|
702
|
+
expect(object.to_config.with_only_path("c.d.z").root).to eq(TestUtils.parse_object("{ c.d.z=5 }"))
|
703
|
+
end
|
704
|
+
|
705
|
+
it "should keep nonexistent key" do
|
706
|
+
expect(object.with_only_key("nope")).to eq(TestUtils.parse_object("{ }"))
|
707
|
+
end
|
708
|
+
|
709
|
+
it "should keep nonexistent path" do
|
710
|
+
expect(object.to_config.with_only_path("q.w.e.r.t.y").root).to eq(TestUtils.parse_object("{ }"))
|
711
|
+
end
|
712
|
+
|
713
|
+
it "should keep only nonexistent underneath non-object" do
|
714
|
+
expect(object.to_config.with_only_path("a.nonextistent").root).to eq(TestUtils.parse_object("{ }"))
|
715
|
+
end
|
716
|
+
|
717
|
+
it "should keep only nonexistent underneath nested non-object" do
|
718
|
+
expect(object.to_config.with_only_path("c.d.z.nonexistent").root).to eq(TestUtils.parse_object("{ }"))
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
722
|
+
specify "should handle unresolved correctly" do
|
723
|
+
object = TestUtils.parse_object("{ a = {}, a=${x}, b=${y}, b=${z}, x={asf:1}, y=2, z=3 }")
|
724
|
+
|
725
|
+
expect(object.to_config.resolve.with_only_path("a.asf").root).to eq(TestUtils.parse_object("{ a={asf:1} }"))
|
726
|
+
|
727
|
+
TestUtils.intercept(UnresolvedSubstitutionError) do
|
728
|
+
object.with_only_key("a").to_config.resolve
|
729
|
+
end
|
730
|
+
|
731
|
+
TestUtils.intercept(UnresolvedSubstitutionError) do
|
732
|
+
object.with_only_key("b").to_config.resolve
|
733
|
+
end
|
734
|
+
|
735
|
+
expect(object.resolve_status).to eq(Hocon::Impl::ResolveStatus::UNRESOLVED)
|
736
|
+
expect(object.with_only_key("z").resolve_status).to eq(Hocon::Impl::ResolveStatus::RESOLVED)
|
737
|
+
end
|
738
|
+
end
|
739
|
+
|
740
|
+
describe "Config#without_key/path" do
|
741
|
+
|
742
|
+
context "should remove keys correctly" do
|
743
|
+
object = TestUtils.parse_object("{ a=1, b=2, c.d.y=3, e.f.g=4, c.d.z=5 }")
|
744
|
+
|
745
|
+
it "should not have a" do
|
746
|
+
expect(object.without_key("a")).to eq(TestUtils.parse_object("{ b=2, c.d.y=3, e.f.g=4, c.d.z=5 }"))
|
747
|
+
end
|
748
|
+
|
749
|
+
it "should not have c" do
|
750
|
+
expect(object.without_key("c")).to eq(TestUtils.parse_object("{ a=1, b=2, e.f.g=4 }"))
|
751
|
+
end
|
752
|
+
|
753
|
+
it "should not have c.d" do
|
754
|
+
expect(object.to_config.without_path("c.d").root).to eq(TestUtils.parse_object("{ a=1, b=2, e.f.g=4, c={} }"))
|
755
|
+
end
|
756
|
+
|
757
|
+
it "should not have c.d.z" do
|
758
|
+
expect(object.to_config.without_path("c.d.z").root).to eq(TestUtils.parse_object("{ a=1, b=2, c.d.y=3, e.f.g=4 }"))
|
759
|
+
end
|
760
|
+
|
761
|
+
it "should not change without nonexistent key" do
|
762
|
+
expect(object.without_key("nonexistent")).to eq(TestUtils.parse_object("{ a=1, b=2, c.d.y=3, e.f.g=4, c.d.z=5 }"))
|
763
|
+
end
|
764
|
+
|
765
|
+
it "should not change without nonexistent path" do
|
766
|
+
expect(object.to_config.without_path("q.w.e.r.t.y").root).to eq(TestUtils.parse_object("{ a=1, b=2, c.d.y=3, e.f.g=4, c.d.z=5 }"))
|
767
|
+
end
|
768
|
+
|
769
|
+
it "should not change without nonexistent path with existing prefix" do
|
770
|
+
expect(object.to_config.without_path("a.foo").root).to eq(TestUtils.parse_object("{ a=1, b=2, c.d.y=3, e.f.g=4, c.d.z=5 }"))
|
771
|
+
end
|
772
|
+
end
|
773
|
+
end
|
774
|
+
|
775
|
+
describe "Config#without_key/path involving unresolved" do
|
776
|
+
|
777
|
+
specify "should handle unresolved correctly" do
|
778
|
+
object = TestUtils.parse_object("{ a = {}, a=${x}, b=${y}, b=${z}, x={asf:1}, y=2, z=3 }")
|
779
|
+
|
780
|
+
expect(object.to_config.resolve.without_path("a.asf").root).to eq(TestUtils.parse_object("{ a={}, b=3, x={asf:1}, y=2, z=3 }"))
|
781
|
+
|
782
|
+
TestUtils.intercept(UnresolvedSubstitutionError) do
|
783
|
+
object.without_key("x").to_config.resolve
|
784
|
+
end
|
785
|
+
|
786
|
+
TestUtils.intercept(UnresolvedSubstitutionError) do
|
787
|
+
object.without_key("z").to_config.resolve
|
788
|
+
end
|
789
|
+
|
790
|
+
expect(object.resolve_status).to eq(Hocon::Impl::ResolveStatus::UNRESOLVED)
|
791
|
+
expect(object.without_key("a").resolve_status).to eq(Hocon::Impl::ResolveStatus::UNRESOLVED)
|
792
|
+
expect(object.without_key("a").without_key("b").resolve_status).to eq(Hocon::Impl::ResolveStatus::RESOLVED)
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|
796
|
+
describe "Config#at_path" do
|
797
|
+
specify "works with one element" do
|
798
|
+
v = ConfigValueFactory.from_any_ref(42)
|
799
|
+
config = v.at_path("a")
|
800
|
+
|
801
|
+
expect(config).to eq(TestUtils.parse_config("a=42"))
|
802
|
+
expect(v).to eq(config.get_value("a"))
|
803
|
+
expect(config.origin.description).to include("at_path")
|
804
|
+
end
|
805
|
+
|
806
|
+
specify "works with two elements" do
|
807
|
+
v = ConfigValueFactory.from_any_ref(42)
|
808
|
+
config = v.at_path("a.b")
|
809
|
+
|
810
|
+
expect(config).to eq(TestUtils.parse_config("a.b=42"))
|
811
|
+
expect(v).to eq(config.get_value("a.b"))
|
812
|
+
expect(config.origin.description).to include("at_path")
|
813
|
+
end
|
814
|
+
|
815
|
+
specify "works with four elements" do
|
816
|
+
v = ConfigValueFactory.from_any_ref(42)
|
817
|
+
config = v.at_path("a.b.c.d")
|
818
|
+
|
819
|
+
expect(config).to eq(TestUtils.parse_config("a.b.c.d=42"))
|
820
|
+
expect(v).to eq(config.get_value("a.b.c.d"))
|
821
|
+
expect(config.origin.description).to include("at_path")
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
describe "Config#at_key" do
|
826
|
+
specify "at_key works" do
|
827
|
+
v = ConfigValueFactory.from_any_ref(42)
|
828
|
+
config = v.at_key("a")
|
829
|
+
|
830
|
+
expect(config).to eq(TestUtils.parse_config("a=42"))
|
831
|
+
expect(v).to eq(config.get_value("a"))
|
832
|
+
expect(config.origin.description).to include("at_key")
|
833
|
+
end
|
834
|
+
|
835
|
+
specify "works with value depth 1 from empty" do
|
836
|
+
v = ConfigValueFactory.from_any_ref(42)
|
837
|
+
config = ConfigFactory.empty.with_value("a", v)
|
838
|
+
|
839
|
+
expect(config).to eq(TestUtils.parse_config("a=42"))
|
840
|
+
expect(v).to eq(config.get_value("a"))
|
841
|
+
end
|
842
|
+
|
843
|
+
specify "works with value depth 2 from empty" do
|
844
|
+
v = ConfigValueFactory.from_any_ref(42)
|
845
|
+
config = ConfigFactory.empty.with_value("a.b", v)
|
846
|
+
|
847
|
+
expect(config).to eq(TestUtils.parse_config("a.b=42"))
|
848
|
+
expect(v).to eq(config.get_value("a.b"))
|
849
|
+
end
|
850
|
+
|
851
|
+
specify "works with value depth 3 from empty" do
|
852
|
+
v = ConfigValueFactory.from_any_ref(42)
|
853
|
+
config = ConfigFactory.empty.with_value("a.b.c", v)
|
854
|
+
|
855
|
+
expect(config).to eq(TestUtils.parse_config("a.b.c=42"))
|
856
|
+
expect(v).to eq(config.get_value("a.b.c"))
|
857
|
+
end
|
858
|
+
|
859
|
+
specify "with value depth 1 overwrites existing" do
|
860
|
+
v = ConfigValueFactory.from_any_ref(47)
|
861
|
+
old = v.at_path("a")
|
862
|
+
config = old.with_value("a", ConfigValueFactory.from_any_ref(42))
|
863
|
+
|
864
|
+
expect(config).to eq(TestUtils.parse_config("a=42"))
|
865
|
+
expect(config.get_int("a")).to eq(42)
|
866
|
+
end
|
867
|
+
|
868
|
+
specify "with value depth 2 overwrites existing" do
|
869
|
+
v = ConfigValueFactory.from_any_ref(47)
|
870
|
+
old = v.at_path("a.b")
|
871
|
+
config = old.with_value("a.b", ConfigValueFactory.from_any_ref(42))
|
872
|
+
|
873
|
+
expect(config).to eq(TestUtils.parse_config("a.b=42"))
|
874
|
+
expect(config.get_int("a.b")).to eq(42)
|
875
|
+
end
|
876
|
+
|
877
|
+
specify "with value inside existing object" do
|
878
|
+
v = ConfigValueFactory.from_any_ref(47)
|
879
|
+
old = v.at_path("a.c")
|
880
|
+
config = old.with_value("a.b", ConfigValueFactory.from_any_ref(42))
|
881
|
+
|
882
|
+
expect(config).to eq(TestUtils.parse_config("a.b=42,a.c=47"))
|
883
|
+
expect(config.get_int("a.b")).to eq(42)
|
884
|
+
expect(config.get_int("a.c")).to eq(47)
|
885
|
+
end
|
886
|
+
|
887
|
+
specify "with value build complex config" do
|
888
|
+
v1 = ConfigValueFactory.from_any_ref(1)
|
889
|
+
v2 = ConfigValueFactory.from_any_ref(2)
|
890
|
+
v3 = ConfigValueFactory.from_any_ref(3)
|
891
|
+
v4 = ConfigValueFactory.from_any_ref(4)
|
892
|
+
|
893
|
+
config = ConfigFactory.empty.with_value("a", v1)
|
894
|
+
.with_value("b.c", v2)
|
895
|
+
.with_value("b.d", v3)
|
896
|
+
.with_value("x.y.z", v4)
|
897
|
+
|
898
|
+
expect(config).to eq(TestUtils.parse_config("a=1,b.c=2,b.d=3,x.y.z=4"))
|
899
|
+
end
|
900
|
+
end
|
901
|
+
|
902
|
+
describe "#render" do
|
903
|
+
context "has newlines in description" do
|
904
|
+
v = ConfigValueFactory.from_any_ref(89, "this is a description\nwith some\nnewlines")
|
905
|
+
|
906
|
+
list = SimpleConfigList.new(SimpleConfigOrigin.new_simple("\n5\n6\n7\n"), [v])
|
907
|
+
|
908
|
+
conf = ConfigFactory.empty.with_value("bar", list)
|
909
|
+
|
910
|
+
rendered = conf.root.render
|
911
|
+
|
912
|
+
specify "rendered config should have all the lines that were added, with newlines" do
|
913
|
+
expect(rendered).to include("is a description\n")
|
914
|
+
expect(rendered).to include("with some\n")
|
915
|
+
expect(rendered).to include("newlines\n")
|
916
|
+
expect(rendered).to include("#\n")
|
917
|
+
expect(rendered).to include("5\n")
|
918
|
+
expect(rendered).to include("6\n")
|
919
|
+
expect(rendered).to include("7\n")
|
920
|
+
end
|
921
|
+
|
922
|
+
specify "the rendered config should give back the original config" do
|
923
|
+
parsed = ConfigFactory.parse_string(rendered)
|
924
|
+
|
925
|
+
expect(parsed).to eq(conf)
|
926
|
+
end
|
927
|
+
end
|
928
|
+
|
929
|
+
specify "should sort properly" do
|
930
|
+
config = TestUtils.parse_config('0=a,1=b,2=c,3=d,10=e,20=f,30=g')
|
931
|
+
rendered = config.root.render(ConfigRenderOptions.concise)
|
932
|
+
|
933
|
+
expect(rendered).to eq('{"0":"a","1":"b","2":"c","3":"d","10":"e","20":"f","30":"g"}')
|
934
|
+
end
|
935
|
+
end
|