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,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'hocon'
|
5
|
+
require 'hocon/config_render_options'
|
6
|
+
|
7
|
+
describe Hocon do
|
8
|
+
let(:render_options) { Hocon::ConfigRenderOptions.defaults }
|
9
|
+
|
10
|
+
before do
|
11
|
+
render_options.origin_comments = false
|
12
|
+
render_options.json = false
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec.shared_examples "hocon_parsing" do
|
16
|
+
|
17
|
+
it "should make the config data available as a map" do
|
18
|
+
expect(conf).to eq(expected)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
[EXAMPLE1, EXAMPLE2].each do |example|
|
24
|
+
let(:input_file) { "#{FIXTURE_DIR}/parse_render/#{example[:name]}/input.conf" }
|
25
|
+
let(:output_file) { "#{FIXTURE_DIR}/parse_render/#{example[:name]}/output.conf" }
|
26
|
+
let(:output) { File.read("#{output_file}") }
|
27
|
+
let(:output_nocomments_file) { "#{FIXTURE_DIR}/parse_render/#{example[:name]}/output_nocomments.conf" }
|
28
|
+
let(:output_nocomments) { File.read("#{output_nocomments_file}") }
|
29
|
+
let(:expected) { example[:hash] }
|
30
|
+
# TODO 'reparsed' appears to be unused
|
31
|
+
let(:reparsed) { Hocon::ConfigFactory.parse_file("#{FIXTURE_DIR}/parse_render/#{example[:name]}/output.conf") }
|
32
|
+
|
33
|
+
context "loading a HOCON file" do
|
34
|
+
let(:conf) { Hocon.load(input_file) }
|
35
|
+
include_examples "hocon_parsing"
|
36
|
+
end
|
37
|
+
|
38
|
+
context "parsing a HOCON string" do
|
39
|
+
let(:string) { File.open(input_file).read }
|
40
|
+
let(:conf) { Hocon.parse(string) }
|
41
|
+
include_examples "hocon_parsing"
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
context "loading a HOCON file with a substitution" do
|
47
|
+
conf = Hocon.load("#{FIXTURE_DIR}/parse_render/#{EXAMPLE3[:name]}/input.conf")
|
48
|
+
expected = EXAMPLE3[:hash]
|
49
|
+
it "should successfully resolve the substitution" do
|
50
|
+
expect(conf).to eq(expected)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,261 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'hocon'
|
5
|
+
require 'test_utils'
|
6
|
+
|
7
|
+
|
8
|
+
describe Hocon::Impl::Path do
|
9
|
+
Path = Hocon::Impl::Path
|
10
|
+
|
11
|
+
####################
|
12
|
+
# Path Equality
|
13
|
+
####################
|
14
|
+
context "Check path equality" do
|
15
|
+
# note: foo.bar is a single key here
|
16
|
+
let(:key_a) { Path.new_key("foo.bar") }
|
17
|
+
let(:same_as_key_a) { Path.new_key("foo.bar") }
|
18
|
+
let(:different_key) { Path.new_key("hello") }
|
19
|
+
|
20
|
+
# Here foo.bar is two elements
|
21
|
+
let(:two_elements) { Path.new_path("foo.bar") }
|
22
|
+
let(:same_as_two_elements) { Path.new_path("foo.bar") }
|
23
|
+
|
24
|
+
context "key_a equals a path of the same name" do
|
25
|
+
let(:first_object) { key_a }
|
26
|
+
let(:second_object) { TestUtils.path("foo.bar") }
|
27
|
+
include_examples "object_equality"
|
28
|
+
end
|
29
|
+
|
30
|
+
context "two_elements equals a path with those two elements" do
|
31
|
+
let(:first_object) { two_elements}
|
32
|
+
let(:second_object) { TestUtils.path("foo", "bar") }
|
33
|
+
include_examples "object_equality"
|
34
|
+
end
|
35
|
+
|
36
|
+
context "key_a equals key_a" do
|
37
|
+
let(:first_object) { key_a }
|
38
|
+
let(:second_object) { key_a }
|
39
|
+
include_examples "object_equality"
|
40
|
+
end
|
41
|
+
|
42
|
+
context "key_a equals same_as_key_a" do
|
43
|
+
let(:first_object) { key_a }
|
44
|
+
let(:second_object) { same_as_key_a }
|
45
|
+
include_examples "object_equality"
|
46
|
+
end
|
47
|
+
|
48
|
+
context "key_a not equal to different_key" do
|
49
|
+
let(:first_object) { key_a }
|
50
|
+
let(:second_object) { different_key }
|
51
|
+
include_examples "object_inequality"
|
52
|
+
end
|
53
|
+
|
54
|
+
context "key_a not equal to the two_elements path" do
|
55
|
+
let(:first_object) { key_a }
|
56
|
+
let(:second_object) { two_elements }
|
57
|
+
include_examples "object_inequality"
|
58
|
+
end
|
59
|
+
|
60
|
+
context "two_elements path equals same_as_two_elements path" do
|
61
|
+
let(:first_object) { two_elements}
|
62
|
+
let(:second_object) { same_as_two_elements }
|
63
|
+
include_examples "object_equality"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
####################
|
68
|
+
# Testing to_s
|
69
|
+
####################
|
70
|
+
context "testing to_s" do
|
71
|
+
it "should find to_s returning the correct strings" do
|
72
|
+
expect("Path(foo)").to eq(TestUtils.path("foo").to_s)
|
73
|
+
expect("Path(foo.bar)").to eq(TestUtils.path("foo", "bar").to_s)
|
74
|
+
expect('Path(foo."bar*")').to eq(TestUtils.path("foo", "bar*").to_s)
|
75
|
+
expect('Path("foo.bar")').to eq(TestUtils.path("foo.bar").to_s)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
####################
|
80
|
+
# Render
|
81
|
+
####################
|
82
|
+
context "testing .render" do
|
83
|
+
context "rendering simple one element case" do
|
84
|
+
let(:expected) { "foo" }
|
85
|
+
let(:path) { TestUtils.path("foo") }
|
86
|
+
include_examples "path_render_test"
|
87
|
+
end
|
88
|
+
|
89
|
+
context "rendering simple two element case" do
|
90
|
+
let(:expected) { "foo.bar" }
|
91
|
+
let(:path) { TestUtils.path("foo", "bar") }
|
92
|
+
include_examples "path_render_test"
|
93
|
+
end
|
94
|
+
|
95
|
+
context "rendering non safe char in an element" do
|
96
|
+
let(:expected) { 'foo."bar*"' }
|
97
|
+
let(:path) { TestUtils.path("foo", "bar*") }
|
98
|
+
include_examples "path_render_test"
|
99
|
+
end
|
100
|
+
|
101
|
+
context "rendering period in an element" do
|
102
|
+
let(:expected) { '"foo.bar"' }
|
103
|
+
let(:path) { TestUtils.path("foo.bar") }
|
104
|
+
include_examples "path_render_test"
|
105
|
+
end
|
106
|
+
|
107
|
+
context "rendering hyphen in element" do
|
108
|
+
let(:expected) { "foo-bar" }
|
109
|
+
let(:path) { TestUtils.path("foo-bar") }
|
110
|
+
include_examples "path_render_test"
|
111
|
+
end
|
112
|
+
|
113
|
+
context "rendering hyphen in element" do
|
114
|
+
let(:expected) { "foo_bar" }
|
115
|
+
let(:path) { TestUtils.path("foo_bar") }
|
116
|
+
include_examples "path_render_test"
|
117
|
+
end
|
118
|
+
|
119
|
+
context "rendering element starting with a hyphen" do
|
120
|
+
let(:expected) { "-foo" }
|
121
|
+
let(:path) { TestUtils.path("-foo") }
|
122
|
+
include_examples "path_render_test"
|
123
|
+
end
|
124
|
+
|
125
|
+
context "rendering element starting with a number" do
|
126
|
+
let(:expected) { "10foo" }
|
127
|
+
let(:path) { TestUtils.path("10foo") }
|
128
|
+
include_examples "path_render_test"
|
129
|
+
end
|
130
|
+
|
131
|
+
context "rendering empty elements" do
|
132
|
+
let(:expected) { '"".""' }
|
133
|
+
let(:path) { TestUtils.path("", "") }
|
134
|
+
include_examples "path_render_test"
|
135
|
+
end
|
136
|
+
|
137
|
+
context "rendering element with internal space" do
|
138
|
+
let(:expected) { '"foo bar"' }
|
139
|
+
let(:path) { TestUtils.path("foo bar") }
|
140
|
+
include_examples "path_render_test"
|
141
|
+
end
|
142
|
+
|
143
|
+
context "rendering leading and trailing spaces" do
|
144
|
+
let(:expected) { '" foo "' }
|
145
|
+
let(:path) { TestUtils.path(" foo ") }
|
146
|
+
include_examples "path_render_test"
|
147
|
+
end
|
148
|
+
|
149
|
+
context "rendering trailing space only" do
|
150
|
+
let(:expected) { '"foo "' }
|
151
|
+
let(:path) { TestUtils.path("foo ") }
|
152
|
+
include_examples "path_render_test"
|
153
|
+
end
|
154
|
+
|
155
|
+
context "rendering number with decimal point" do
|
156
|
+
let(:expected) { "1.2" }
|
157
|
+
let(:path) { TestUtils.path("1", "2") }
|
158
|
+
include_examples "path_render_test"
|
159
|
+
end
|
160
|
+
|
161
|
+
context "rendering number with multiple decimal points" do
|
162
|
+
let(:expected) { "1.2.3.4" }
|
163
|
+
let(:path) { TestUtils.path("1", "2", "3", "4") }
|
164
|
+
include_examples "path_render_test"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "test that paths made from a list of Path objects equal paths made from a list of strings" do
|
169
|
+
it "should find a path made from a list of one path equal to a path from one string" do
|
170
|
+
path_from_path_list = Path.from_path_list([TestUtils.path("foo")])
|
171
|
+
expected_path = TestUtils.path("foo")
|
172
|
+
|
173
|
+
expect(path_from_path_list).to eq(expected_path)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should find a path made from a list of multiple paths equal to that list of strings" do
|
177
|
+
path_from_path_list = Path.from_path_list([TestUtils.path("foo", "bar"),
|
178
|
+
TestUtils.path("baz", "boo")])
|
179
|
+
expected_path = TestUtils.path("foo", "bar", "baz", "boo")
|
180
|
+
|
181
|
+
expect(path_from_path_list).to eq(expected_path)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context "prepending paths" do
|
186
|
+
it "should find prepending a single path works" do
|
187
|
+
prepended_path = TestUtils.path("bar").prepend(TestUtils.path("foo"))
|
188
|
+
expected_path = TestUtils.path("foo", "bar")
|
189
|
+
|
190
|
+
expect(prepended_path).to eq(expected_path)
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should find prepending multiple paths works" do
|
194
|
+
prepended_path = TestUtils.path("c", "d").prepend(TestUtils.path("a", "b"))
|
195
|
+
expected_path = TestUtils.path("a", "b", "c", "d")
|
196
|
+
|
197
|
+
expect(prepended_path).to eq(expected_path)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
context "path length" do
|
202
|
+
it "should find length of single part path to be 1" do
|
203
|
+
path = TestUtils.path("food")
|
204
|
+
expect(path.length).to eq(1)
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should find length of two part path to be 2" do
|
208
|
+
path = TestUtils.path("foo", "bar")
|
209
|
+
expect(path.length).to eq(2)
|
210
|
+
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
context "parent paths" do
|
215
|
+
it "should find parent of single level path to be nil" do
|
216
|
+
path = TestUtils.path("a")
|
217
|
+
|
218
|
+
expect(path.parent).to be_nil
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should find parent of a.b to be a" do
|
222
|
+
path = TestUtils.path("a", "b")
|
223
|
+
parent = TestUtils.path("a")
|
224
|
+
|
225
|
+
expect(path.parent).to eq(parent)
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should find parent of a.b.c to be a.b" do
|
229
|
+
path = TestUtils.path("a", "b", "c")
|
230
|
+
parent = TestUtils.path("a", "b")
|
231
|
+
|
232
|
+
expect(path.parent).to eq(parent)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context "path last method" do
|
237
|
+
it "should find last of single level path to be itself" do
|
238
|
+
path = TestUtils.path("a")
|
239
|
+
|
240
|
+
expect(path.last).to eq("a")
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should find last of a.b to be b" do
|
244
|
+
path = TestUtils.path("a", "b")
|
245
|
+
|
246
|
+
expect(path.last).to eq("b")
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context "invalid paths" do
|
251
|
+
it "should catch exception from empty path" do
|
252
|
+
bad_path = ""
|
253
|
+
expect { Path.new_path(bad_path) }.to raise_error(Hocon::ConfigError::ConfigBadPathError)
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should catch exception from path '..'" do
|
257
|
+
bad_path = ".."
|
258
|
+
expect { Path.new_path(bad_path) }.to raise_error(Hocon::ConfigError::ConfigBadPathError)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
@@ -0,0 +1,520 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'test_utils'
|
5
|
+
require 'hocon'
|
6
|
+
require 'hocon/config_factory'
|
7
|
+
require 'hocon/config_value_factory'
|
8
|
+
require 'hocon/impl/config_delayed_merge_object'
|
9
|
+
require 'hocon/impl/replaceable_merge_stack'
|
10
|
+
require 'hocon/config_util'
|
11
|
+
|
12
|
+
# Note: Skipping many tests that rely on java's System.getProperties functionality,
|
13
|
+
# which lets you access things like "os.name", "java.vendor", and "user.home"
|
14
|
+
# Also skipping
|
15
|
+
|
16
|
+
ConfigFactory = Hocon::ConfigFactory
|
17
|
+
ConfigValueFactory = Hocon::ConfigValueFactory
|
18
|
+
SimpleConfigObject = Hocon::Impl::SimpleConfigObject
|
19
|
+
SimpleConfigList = Hocon::Impl::SimpleConfigList
|
20
|
+
ConfigUtil = Hocon::ConfigUtil
|
21
|
+
|
22
|
+
shared_examples_for "test_from_value" do
|
23
|
+
default_value_description = "hardcoded value"
|
24
|
+
|
25
|
+
specify "create_from made into a config value should equal the expected value" do
|
26
|
+
expect(Hocon::ConfigValueFactory.from_any_ref(create_from)).to eq(expected_value)
|
27
|
+
end
|
28
|
+
|
29
|
+
specify "create_from made into a config value with origin description should equal the expected value" do
|
30
|
+
expect(Hocon::ConfigValueFactory.from_any_ref(create_from, "foo")).to eq(expected_value)
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "descriptions match" do
|
34
|
+
if create_from.is_a?(Hocon::ConfigValue)
|
35
|
+
# description is ignored for createFrom that is already a ConfigValue
|
36
|
+
expect(Hocon::ConfigValueFactory.from_any_ref(create_from).origin.description).to eq(create_from.origin.description)
|
37
|
+
else
|
38
|
+
expect(Hocon::ConfigValueFactory.from_any_ref(create_from).origin.description).to eq(default_value_description)
|
39
|
+
expect(Hocon::ConfigValueFactory.from_any_ref(create_from, "foo").origin.description).to eq("foo")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "basic load and get" do
|
45
|
+
conf = ConfigFactory.load_file(TestUtils.resource_file("test01"))
|
46
|
+
|
47
|
+
specify "should be able to see some values in the config object" do
|
48
|
+
expect(conf.get_int("ints.fortyTwo")).to eq(42)
|
49
|
+
child = conf.get_config("ints")
|
50
|
+
|
51
|
+
expect(child.get_int("fortyTwo")).to eq(42)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "loading JSON only" do
|
56
|
+
options = Hocon::ConfigParseOptions.defaults.set_syntax(Hocon::ConfigSyntax::JSON)
|
57
|
+
conf = ConfigFactory.load_file_with_parse_options(TestUtils.resource_file("test01"), options)
|
58
|
+
|
59
|
+
specify "should be missing value specific to CONF files" do
|
60
|
+
TestUtils.intercept(Hocon::ConfigError::ConfigMissingError) do
|
61
|
+
conf.get_int("ints.fortyTwo")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
specify "should find value specific to the JSON file" do
|
66
|
+
expect(conf.get_int("fromJson1")).to eq(1)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "loading CONF only" do
|
71
|
+
options = Hocon::ConfigParseOptions.defaults.set_syntax(Hocon::ConfigSyntax::CONF)
|
72
|
+
conf = ConfigFactory.load_file_with_parse_options(TestUtils.resource_file("test01"), options)
|
73
|
+
|
74
|
+
specify "should be missing value specific to JSON files" do
|
75
|
+
TestUtils.intercept(Hocon::ConfigError::ConfigMissingError) do
|
76
|
+
conf.get_int("fromJson1")
|
77
|
+
end
|
78
|
+
|
79
|
+
TestUtils.intercept(Hocon::ConfigError::ConfigMissingError) do
|
80
|
+
conf.get_int("fromProps.one")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
specify "should find value specific to the CONF file" do
|
85
|
+
expect(conf.get_int("ints.fortyTwo")).to eq(42)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "ConfigFactory#load_file_with_resolve_options" do
|
90
|
+
options = Hocon::ConfigResolveOptions.defaults
|
91
|
+
conf = ConfigFactory.load_file_with_resolve_options(TestUtils.resource_file("test01"), options)
|
92
|
+
|
93
|
+
specify "sanity check to make sure load_file_with_resolve_options act strange" do
|
94
|
+
expect(conf.get_int("ints.fortyTwo")).to eq(42)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "empty configs" do
|
99
|
+
empty = ConfigFactory.empty
|
100
|
+
empty_foo = ConfigFactory.empty("foo")
|
101
|
+
|
102
|
+
specify "empty config is empty" do
|
103
|
+
expect(empty.empty?).to be true
|
104
|
+
end
|
105
|
+
|
106
|
+
specify "empty config's origin should be 'empty config'" do
|
107
|
+
expect(empty.origin.description).to eq("empty config")
|
108
|
+
end
|
109
|
+
|
110
|
+
specify "empty config with origin description is empty" do
|
111
|
+
expect(empty_foo.empty?).to be true
|
112
|
+
end
|
113
|
+
|
114
|
+
specify "empty config with origin description 'foo' is having it's description set" do
|
115
|
+
expect(empty_foo.origin.description).to eq("foo")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "Creating objects with ConfigValueFactory" do
|
120
|
+
context "from true" do
|
121
|
+
let(:expected_value) { TestUtils.bool_value(true) }
|
122
|
+
let(:create_from) { true }
|
123
|
+
|
124
|
+
include_examples "test_from_value"
|
125
|
+
end
|
126
|
+
|
127
|
+
context "from false" do
|
128
|
+
let(:expected_value) { TestUtils.bool_value(false) }
|
129
|
+
let(:create_from) { false }
|
130
|
+
|
131
|
+
include_examples "test_from_value"
|
132
|
+
end
|
133
|
+
|
134
|
+
context "from nil" do
|
135
|
+
let(:expected_value) { TestUtils.null_value }
|
136
|
+
let(:create_from) { nil }
|
137
|
+
|
138
|
+
include_examples "test_from_value"
|
139
|
+
end
|
140
|
+
|
141
|
+
context "from int" do
|
142
|
+
let(:expected_value) { TestUtils.int_value(5) }
|
143
|
+
let(:create_from) { 5 }
|
144
|
+
|
145
|
+
include_examples "test_from_value"
|
146
|
+
end
|
147
|
+
|
148
|
+
context "from float" do
|
149
|
+
let(:expected_value) { TestUtils.double_value(3.14) }
|
150
|
+
let(:create_from) { 3.14 }
|
151
|
+
|
152
|
+
include_examples "test_from_value"
|
153
|
+
end
|
154
|
+
|
155
|
+
context "from string" do
|
156
|
+
let(:expected_value) { TestUtils.string_value("hello world") }
|
157
|
+
let(:create_from) { "hello world" }
|
158
|
+
|
159
|
+
include_examples "test_from_value"
|
160
|
+
end
|
161
|
+
|
162
|
+
context "from empty hash" do
|
163
|
+
let(:expected_value) { SimpleConfigObject.new(TestUtils.fake_origin, {}) }
|
164
|
+
let(:create_from) { {} }
|
165
|
+
|
166
|
+
include_examples "test_from_value"
|
167
|
+
end
|
168
|
+
|
169
|
+
context "from populated hash" do
|
170
|
+
value_hash = TestUtils.config_map({"a" => 1, "b" => 2, "c" => 3})
|
171
|
+
|
172
|
+
let(:expected_value) { SimpleConfigObject.new(TestUtils.fake_origin, value_hash) }
|
173
|
+
let(:create_from) { {"a" => 1, "b" => 2, "c" => 3} }
|
174
|
+
|
175
|
+
include_examples "test_from_value"
|
176
|
+
|
177
|
+
specify "from_map should also work" do
|
178
|
+
# from_map is just a wrapper around from_any_ref
|
179
|
+
expect(ConfigValueFactory.from_map({"a" => 1, "b" => 2, "c" => 3}).origin.description).to eq("hardcoded value")
|
180
|
+
expect(ConfigValueFactory.from_map({"a" => 1, "b" => 2, "c" => 3}, "foo").origin.description).to eq("foo")
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context "from empty array" do
|
185
|
+
let(:expected_value) { SimpleConfigList.new(TestUtils.fake_origin, []) }
|
186
|
+
let(:create_from) { [] }
|
187
|
+
|
188
|
+
include_examples "test_from_value"
|
189
|
+
end
|
190
|
+
|
191
|
+
context "from populated array" do
|
192
|
+
value_array = [1, 2, 3].map { |v| TestUtils.int_value(v) }
|
193
|
+
|
194
|
+
let(:expected_value) { SimpleConfigList.new(TestUtils.fake_origin, value_array) }
|
195
|
+
let(:create_from) { [1, 2, 3] }
|
196
|
+
|
197
|
+
include_examples "test_from_value"
|
198
|
+
end
|
199
|
+
|
200
|
+
# Omitting tests that involve trees and iterators
|
201
|
+
# Omitting tests using units (memory size, duration, etc)
|
202
|
+
|
203
|
+
context "from existing Config values" do
|
204
|
+
context "from int" do
|
205
|
+
let(:expected_value) { TestUtils.int_value(1000) }
|
206
|
+
let(:create_from) { TestUtils.int_value(1000) }
|
207
|
+
|
208
|
+
include_examples "test_from_value"
|
209
|
+
end
|
210
|
+
|
211
|
+
context "from string" do
|
212
|
+
let(:expected_value) { TestUtils.string_value("foo") }
|
213
|
+
let(:create_from) { TestUtils.string_value("foo") }
|
214
|
+
|
215
|
+
include_examples "test_from_value"
|
216
|
+
end
|
217
|
+
|
218
|
+
context "from hash" do
|
219
|
+
int_map = {"a" => 1, "b" => 2, "c" => 3}
|
220
|
+
let(:expected_value) { SimpleConfigObject.new(TestUtils.fake_origin, TestUtils.config_map(int_map)) }
|
221
|
+
let(:create_from) { SimpleConfigObject.new(TestUtils.fake_origin, TestUtils.config_map(int_map)) }
|
222
|
+
|
223
|
+
include_examples "test_from_value"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
context "from existing list of Config values" do
|
228
|
+
int_list = [1, 2, 3].map { |v| TestUtils.int_value(v) }
|
229
|
+
|
230
|
+
let(:expected_value) { SimpleConfigList.new(TestUtils.fake_origin, int_list) }
|
231
|
+
let(:create_from) { int_list }
|
232
|
+
|
233
|
+
include_examples "test_from_value"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "round tripping unwrap" do
|
238
|
+
conf = ConfigFactory.load_file(TestUtils.resource_file("test01"))
|
239
|
+
|
240
|
+
unwrapped = conf.root.unwrapped
|
241
|
+
|
242
|
+
rewrapped = ConfigValueFactory.from_map(unwrapped, conf.origin.description)
|
243
|
+
reunwrapped = rewrapped.unwrapped
|
244
|
+
|
245
|
+
specify "conf has a lot of stuff in it" do
|
246
|
+
expect(conf.root.size).to be > 4
|
247
|
+
end
|
248
|
+
|
249
|
+
specify "rewrapped conf equals conf" do
|
250
|
+
expect(rewrapped).to eq(conf.root)
|
251
|
+
end
|
252
|
+
|
253
|
+
specify "reunwrapped conf equals unwrapped conf" do
|
254
|
+
expect(unwrapped).to eq(reunwrapped)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
# Omitting Tests (and functionality) for ConfigFactory.parse_map until I know if it's
|
259
|
+
# a priority
|
260
|
+
|
261
|
+
describe "default parse options" do
|
262
|
+
def check_not_found(e)
|
263
|
+
["No such", "not found", "were found"].any? { |string| e.message.include?(string)}
|
264
|
+
end
|
265
|
+
|
266
|
+
let(:defaults) { Hocon::ConfigParseOptions::defaults }
|
267
|
+
|
268
|
+
specify "allow missing == true" do
|
269
|
+
expect(defaults.allow_missing?).to be true
|
270
|
+
end
|
271
|
+
|
272
|
+
specify "includer == nil" do
|
273
|
+
expect(defaults.includer).to be_nil
|
274
|
+
end
|
275
|
+
|
276
|
+
specify "origin description == nil" do
|
277
|
+
expect(defaults.origin_description).to be_nil
|
278
|
+
end
|
279
|
+
|
280
|
+
specify "syntax == nil" do
|
281
|
+
expect(defaults.syntax).to be_nil
|
282
|
+
end
|
283
|
+
|
284
|
+
context "allow missing with ConfigFactory#parse_file" do
|
285
|
+
specify "nonexistant conf throws error when allow_missing? == false" do
|
286
|
+
allow_missing_false = Hocon::ConfigParseOptions::defaults.set_allow_missing(false)
|
287
|
+
|
288
|
+
e = TestUtils.intercept(Hocon::ConfigError::ConfigIOError) do
|
289
|
+
ConfigFactory.parse_file(TestUtils.resource_file("nonexistant.conf"), allow_missing_false)
|
290
|
+
end
|
291
|
+
|
292
|
+
expect(check_not_found(e)).to be true
|
293
|
+
end
|
294
|
+
|
295
|
+
specify "nonexistant conf returns empty conf when allow_missing? == false" do
|
296
|
+
allow_missing_true = Hocon::ConfigParseOptions::defaults.set_allow_missing(true)
|
297
|
+
|
298
|
+
conf = ConfigFactory.parse_file(TestUtils.resource_file("nonexistant.conf"), allow_missing_true)
|
299
|
+
|
300
|
+
expect(conf.empty?).to be true
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context "allow missing with ConfigFactory#parse_file_any_syntax" do
|
305
|
+
specify "nonexistant conf throws error when allow_missing? == false" do
|
306
|
+
allow_missing_false = Hocon::ConfigParseOptions::defaults.set_allow_missing(false)
|
307
|
+
|
308
|
+
e = TestUtils.intercept(Hocon::ConfigError::ConfigIOError) do
|
309
|
+
ConfigFactory.parse_file_any_syntax(TestUtils.resource_file("nonexistant"), allow_missing_false)
|
310
|
+
end
|
311
|
+
|
312
|
+
expect(check_not_found(e)).to be true
|
313
|
+
end
|
314
|
+
|
315
|
+
specify "nonexistant conf returns empty conf when allow_missing? == false" do
|
316
|
+
allow_missing_true = Hocon::ConfigParseOptions::defaults.set_allow_missing(true)
|
317
|
+
|
318
|
+
conf = ConfigFactory.parse_file_any_syntax(TestUtils.resource_file("nonexistant"), allow_missing_true)
|
319
|
+
|
320
|
+
expect(conf.empty?).to be true
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# Omitting ConfigFactory.prase_resources_any_syntax since we're not supporting it
|
325
|
+
context "allow missing shouldn't mess up includes" do
|
326
|
+
# test03.conf contains some nonexistent includes. check that
|
327
|
+
# setAllowMissing on the file (which is not missing) doesn't
|
328
|
+
# change that the includes are allowed to be missing.
|
329
|
+
# This can break because some options might "propagate" through
|
330
|
+
# to includes, but we don't want them all to do so.
|
331
|
+
|
332
|
+
allow_missing_true = Hocon::ConfigParseOptions::defaults.set_allow_missing(true)
|
333
|
+
allow_missing_false = Hocon::ConfigParseOptions::defaults.set_allow_missing(false)
|
334
|
+
|
335
|
+
conf = ConfigFactory.parse_file(TestUtils.resource_file("test03.conf"), allow_missing_false)
|
336
|
+
conf2 = ConfigFactory.parse_file(TestUtils.resource_file("test03.conf"), allow_missing_true)
|
337
|
+
|
338
|
+
specify "conf should have stuff from test01.conf" do
|
339
|
+
expect(conf.get_int("test01.booleans")).to eq(42)
|
340
|
+
end
|
341
|
+
|
342
|
+
specify "both confs should be equal regardless of allow_missing being true or false" do
|
343
|
+
expect(conf).to eq(conf2)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
# Omitting test that creates a subclass of ConfigIncluder to record everything that's
|
349
|
+
# included by a .conf file. It's complex and we've decided the functionality is well
|
350
|
+
# tested elsewhere and right now it isn't worth the effort.
|
351
|
+
|
352
|
+
describe "string parsing" do
|
353
|
+
specify "should parse correctly" do
|
354
|
+
conf = ConfigFactory.parse_string("{ a : b }", Hocon::ConfigParseOptions.defaults)
|
355
|
+
|
356
|
+
expect(conf.get_string("a")).to eq("b")
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
|
361
|
+
# Omitting tests for parse_file_any_syntax in the interests of time since this has already
|
362
|
+
# been tested above
|
363
|
+
|
364
|
+
# Omitting classpath tests
|
365
|
+
|
366
|
+
describe "config_utils" do
|
367
|
+
# This is to test the public wrappers around ConfigImplUtils
|
368
|
+
|
369
|
+
specify "can join and split paths" do
|
370
|
+
expect(ConfigUtil.join_path("", "a", "b", "$")).to eq("\"\".a.b.\"$\"")
|
371
|
+
expect(ConfigUtil.join_path_from_list(["", "a", "b", "$"])).to eq("\"\".a.b.\"$\"")
|
372
|
+
expect(ConfigUtil.split_path("\"\".a.b.\"$\"")).to eq(["", "a", "b", "$"])
|
373
|
+
end
|
374
|
+
|
375
|
+
specify "should throw errors on invalid paths" do
|
376
|
+
TestUtils.intercept(Hocon::ConfigError) do
|
377
|
+
ConfigUtil.split_path("$")
|
378
|
+
end
|
379
|
+
|
380
|
+
TestUtils.intercept(Hocon::ConfigError) do
|
381
|
+
# no args
|
382
|
+
ConfigUtil.join_path
|
383
|
+
end
|
384
|
+
|
385
|
+
TestUtils.intercept(Hocon::ConfigError) do
|
386
|
+
# empty list
|
387
|
+
ConfigUtil.join_path_from_list([])
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
specify "should quote strings correctly" do
|
392
|
+
expect(ConfigUtil.quote_string("")).to eq("\"\"")
|
393
|
+
expect(ConfigUtil.quote_string("a")).to eq("\"a\"")
|
394
|
+
expect(ConfigUtil.quote_string("\n")).to eq("\"\\n\"")
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
# Omitting tests that use class loaders
|
399
|
+
|
400
|
+
describe "detecting cycles" do
|
401
|
+
specify "should detect a cycle" do
|
402
|
+
e = TestUtils.intercept(Hocon::ConfigError::ConfigParseError) do
|
403
|
+
ConfigFactory.load_file(TestUtils.resource_file("cycle.conf"))
|
404
|
+
end
|
405
|
+
|
406
|
+
# Message mentioning cycle
|
407
|
+
expect(e.message).to include("include statements nested")
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
describe "including from list" do
|
412
|
+
# We would ideally make this case NOT throw an exception but we need to do some work
|
413
|
+
# to get there, see https://github.com/typesafehub/config/issues/160
|
414
|
+
specify "should throw error when trying to include from list" do
|
415
|
+
e = TestUtils.intercept(Hocon::ConfigError::ConfigParseError) do
|
416
|
+
ConfigFactory.load_file(TestUtils.resource_file("include-from-list.conf"))
|
417
|
+
end
|
418
|
+
|
419
|
+
# Message mentioning current implementation limitations
|
420
|
+
expect(e.message).to include("limitation")
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
# Omitting tests using System.getProperty since it's java specific
|
425
|
+
|
426
|
+
# Omitting serialization tests since we aren't supporting it
|
427
|
+
|
428
|
+
describe "using some values without resolving" do
|
429
|
+
conf = ConfigFactory.parse_string("a=42,b=${NOPE}")
|
430
|
+
|
431
|
+
specify "should be able to use some values without resolving" do
|
432
|
+
expect(conf.get_int("a")).to eq(42)
|
433
|
+
end
|
434
|
+
|
435
|
+
specify "unresolved value should throw error" do
|
436
|
+
TestUtils.intercept(Hocon::ConfigError::ConfigNotResolvedError) do
|
437
|
+
conf.get_int("b")
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
describe "include file statements" do
|
443
|
+
conf = ConfigFactory.parse_file(TestUtils.resource_file("file-include.conf"))
|
444
|
+
|
445
|
+
specify "should find values from each included file" do
|
446
|
+
expect(conf.get_int("base")).to eq(41)
|
447
|
+
expect(conf.get_int("foo")).to eq(42)
|
448
|
+
expect(conf.get_int("bar")).to eq(43)
|
449
|
+
# these two do not work right now, because we do not
|
450
|
+
# treat the filename as relative to the including file
|
451
|
+
# if file() is specified, so `include file("bar-file.conf")`
|
452
|
+
# fails.
|
453
|
+
#assertEquals("got bar-file.conf", 44, conf.getInt("bar-file"))
|
454
|
+
#assertEquals("got subdir/baz.conf", 45, conf.getInt("baz"))
|
455
|
+
end
|
456
|
+
|
457
|
+
specify "should not find certain paths" do
|
458
|
+
expect(conf.has_path?("bar-file")).to be false
|
459
|
+
expect(conf.has_path?("baz")).to be false
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
describe "Config#has_path_or_null" do
|
464
|
+
conf = ConfigFactory.parse_string("x.a=null,x.b=42")
|
465
|
+
|
466
|
+
specify "has_path_or_null returns correctly" do
|
467
|
+
# hasPath says false for null
|
468
|
+
expect(conf.has_path?("x.a")).to be false
|
469
|
+
# hasPathOrNull says true for null
|
470
|
+
expect(conf.has_path_or_null?("x.a")).to be true
|
471
|
+
|
472
|
+
# hasPath says true for non-null
|
473
|
+
expect(conf.has_path?("x.b")).to be true
|
474
|
+
# hasPathOrNull says true for non-null
|
475
|
+
expect(conf.has_path_or_null?("x.b")).to be true
|
476
|
+
|
477
|
+
# hasPath says false for missing
|
478
|
+
expect(conf.has_path?("x.c")).to be false
|
479
|
+
# hasPathOrNull says false for missing
|
480
|
+
expect(conf.has_path_or_null?("x.c")).to be false
|
481
|
+
|
482
|
+
# hasPath says false for missing under null
|
483
|
+
expect(conf.has_path?("x.a.y")).to be false
|
484
|
+
# hasPathOrNull says false for missing under null
|
485
|
+
expect(conf.has_path_or_null?("x.a.y")).to be false
|
486
|
+
|
487
|
+
# hasPath says false for missing under missing
|
488
|
+
expect(conf.has_path?("x.c.y")).to be false
|
489
|
+
# hasPathOrNull says false for missing under missing
|
490
|
+
expect(conf.has_path_or_null?("x.c.y")).to be false
|
491
|
+
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
describe "Config#get_is_null" do
|
496
|
+
conf = ConfigFactory.parse_string("x.a=null,x.b=42")
|
497
|
+
|
498
|
+
specify "should return whether or not values are null correctly" do
|
499
|
+
expect(conf.is_null?("x.a")).to be true
|
500
|
+
expect(conf.is_null?("x.b")).to be false
|
501
|
+
end
|
502
|
+
|
503
|
+
specify "should throw error for missing values" do
|
504
|
+
TestUtils.intercept(Hocon::ConfigError::ConfigMissingError) do
|
505
|
+
conf.is_null?("x.c")
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
specify "should throw error for missing underneal null" do
|
510
|
+
TestUtils.intercept(Hocon::ConfigError::ConfigMissingError) do
|
511
|
+
conf.is_null?("x.a.y")
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
specify "should throw error for missing underneath missing" do
|
516
|
+
TestUtils.intercept(Hocon::ConfigError::ConfigMissingError) do
|
517
|
+
conf.is_null?("x.c.y")
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|