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.
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