hocon 0.9.5 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|