hocon 0.9.5 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -2
  3. data/README.md +22 -10
  4. data/lib/hocon.rb +9 -3
  5. data/lib/hocon/config_factory.rb +4 -0
  6. data/lib/hocon/config_value_factory.rb +13 -2
  7. data/lib/hocon/impl/config_reference.rb +5 -2
  8. data/lib/hocon/impl/simple_config_origin.rb +1 -1
  9. data/spec/fixtures/parse_render/example1/input.conf +21 -0
  10. data/spec/fixtures/parse_render/example1/output.conf +26 -0
  11. data/spec/fixtures/parse_render/example1/output_nocomments.conf +17 -0
  12. data/spec/fixtures/parse_render/example2/input.conf +10 -0
  13. data/spec/fixtures/parse_render/example2/output.conf +17 -0
  14. data/spec/fixtures/parse_render/example2/output_nocomments.conf +17 -0
  15. data/spec/fixtures/parse_render/example3/input.conf +2 -0
  16. data/spec/fixtures/parse_render/example3/output.conf +2 -0
  17. data/spec/fixtures/parse_render/example4/input.json +6 -0
  18. data/spec/fixtures/parse_render/example4/output.conf +6 -0
  19. data/spec/fixtures/test_utils/resources/bom.conf +2 -0
  20. data/spec/fixtures/test_utils/resources/cycle.conf +1 -0
  21. data/spec/fixtures/test_utils/resources/file-include.conf +5 -0
  22. data/spec/fixtures/test_utils/resources/include-from-list.conf +4 -0
  23. data/spec/fixtures/test_utils/resources/subdir/bar.conf +1 -0
  24. data/spec/fixtures/test_utils/resources/subdir/baz.conf +1 -0
  25. data/spec/fixtures/test_utils/resources/subdir/foo.conf +5 -0
  26. data/spec/fixtures/test_utils/resources/test01.conf +80 -0
  27. data/spec/fixtures/test_utils/resources/test01.json +4 -0
  28. data/spec/fixtures/test_utils/resources/test03.conf +36 -0
  29. data/spec/spec_helper.rb +43 -0
  30. data/spec/test_utils.rb +757 -0
  31. data/spec/unit/typesafe/config/concatenation_spec.rb +417 -0
  32. data/spec/unit/typesafe/config/conf_parser_spec.rb +822 -0
  33. data/spec/unit/typesafe/config/config_document_parser_spec.rb +494 -0
  34. data/spec/unit/typesafe/config/config_document_spec.rb +576 -0
  35. data/spec/unit/typesafe/config/config_factory_spec.rb +120 -0
  36. data/spec/unit/typesafe/config/config_node_spec.rb +552 -0
  37. data/spec/unit/typesafe/config/config_value_factory_spec.rb +85 -0
  38. data/spec/unit/typesafe/config/config_value_spec.rb +935 -0
  39. data/spec/unit/typesafe/config/hocon_spec.rb +54 -0
  40. data/spec/unit/typesafe/config/path_spec.rb +261 -0
  41. data/spec/unit/typesafe/config/public_api_spec.rb +520 -0
  42. data/spec/unit/typesafe/config/simple_config_spec.rb +112 -0
  43. data/spec/unit/typesafe/config/token_spec.rb +188 -0
  44. data/spec/unit/typesafe/config/tokenizer_spec.rb +801 -0
  45. 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