hocon 1.2.5 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -1
  3. data/lib/hocon/version.rb +1 -1
  4. metadata +1 -47
  5. data/spec/fixtures/hocon/by_extension/cat.conf +0 -4
  6. data/spec/fixtures/hocon/by_extension/cat.test +0 -4
  7. data/spec/fixtures/hocon/by_extension/cat.test-json +0 -3
  8. data/spec/fixtures/hocon/with_substitution/subst.conf +0 -2
  9. data/spec/fixtures/parse_render/example1/input.conf +0 -21
  10. data/spec/fixtures/parse_render/example1/output.conf +0 -26
  11. data/spec/fixtures/parse_render/example1/output_nocomments.conf +0 -17
  12. data/spec/fixtures/parse_render/example2/input.conf +0 -10
  13. data/spec/fixtures/parse_render/example2/output.conf +0 -17
  14. data/spec/fixtures/parse_render/example2/output_nocomments.conf +0 -17
  15. data/spec/fixtures/parse_render/example3/input.conf +0 -2
  16. data/spec/fixtures/parse_render/example3/output.conf +0 -2
  17. data/spec/fixtures/parse_render/example4/input.json +0 -6
  18. data/spec/fixtures/parse_render/example4/output.conf +0 -6
  19. data/spec/fixtures/test_utils/resources/bom.conf +0 -2
  20. data/spec/fixtures/test_utils/resources/cycle.conf +0 -1
  21. data/spec/fixtures/test_utils/resources/file-include.conf +0 -5
  22. data/spec/fixtures/test_utils/resources/include-from-list.conf +0 -4
  23. data/spec/fixtures/test_utils/resources/subdir/bar.conf +0 -1
  24. data/spec/fixtures/test_utils/resources/subdir/baz.conf +0 -1
  25. data/spec/fixtures/test_utils/resources/subdir/foo.conf +0 -5
  26. data/spec/fixtures/test_utils/resources/test01.conf +0 -80
  27. data/spec/fixtures/test_utils/resources/test01.json +0 -4
  28. data/spec/fixtures/test_utils/resources/test03.conf +0 -36
  29. data/spec/fixtures/test_utils/resources/utf16.conf +0 -0
  30. data/spec/fixtures/test_utils/resources/utf8.conf +0 -2
  31. data/spec/fixtures/test_utils/resources//341/232/240/341/233/207/341/232/273.conf +0 -2
  32. data/spec/spec_helper.rb +0 -43
  33. data/spec/test_utils.rb +0 -758
  34. data/spec/unit/cli/cli_spec.rb +0 -157
  35. data/spec/unit/hocon/README.md +0 -7
  36. data/spec/unit/hocon/hocon_spec.rb +0 -114
  37. data/spec/unit/typesafe/config/README.md +0 -4
  38. data/spec/unit/typesafe/config/concatenation_spec.rb +0 -417
  39. data/spec/unit/typesafe/config/conf_parser_spec.rb +0 -831
  40. data/spec/unit/typesafe/config/config_document_parser_spec.rb +0 -494
  41. data/spec/unit/typesafe/config/config_document_spec.rb +0 -576
  42. data/spec/unit/typesafe/config/config_factory_spec.rb +0 -120
  43. data/spec/unit/typesafe/config/config_node_spec.rb +0 -552
  44. data/spec/unit/typesafe/config/config_value_factory_spec.rb +0 -85
  45. data/spec/unit/typesafe/config/config_value_spec.rb +0 -959
  46. data/spec/unit/typesafe/config/path_spec.rb +0 -261
  47. data/spec/unit/typesafe/config/public_api_spec.rb +0 -520
  48. data/spec/unit/typesafe/config/simple_config_spec.rb +0 -112
  49. data/spec/unit/typesafe/config/token_spec.rb +0 -188
  50. data/spec/unit/typesafe/config/tokenizer_spec.rb +0 -801
@@ -1,831 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
- require 'test_utils'
5
- require 'hocon/config_parse_options'
6
- require 'hocon/config_syntax'
7
- require 'hocon/impl/abstract_config_object'
8
- require 'hocon/impl/resolve_context'
9
- require 'hocon/config_resolve_options'
10
- require 'hocon/config_error'
11
- require 'hocon/impl/simple_config_origin'
12
- require 'hocon/config_list'
13
- require 'hocon/impl/config_reference'
14
- require 'hocon/impl/path_parser'
15
- require 'hocon/impl/parseable'
16
- require 'hocon/config_factory'
17
-
18
- def parse_without_resolving(s)
19
- options = Hocon::ConfigParseOptions.defaults.
20
- set_origin_description("test conf string").
21
- set_syntax(Hocon::ConfigSyntax::CONF)
22
- Hocon::Impl::Parseable.new_string(s, options).parse_value
23
- end
24
-
25
- def parse(s)
26
- tree = parse_without_resolving(s)
27
-
28
- if tree.is_a?(Hocon::Impl::AbstractConfigObject)
29
- Hocon::Impl::ResolveContext.resolve(tree, tree,
30
- Hocon::ConfigResolveOptions.no_system)
31
- else
32
- tree
33
- end
34
- end
35
-
36
-
37
- describe "Config Parser" do
38
- context "invalid_conf_throws" do
39
- TestUtils.whitespace_variations(TestUtils::InvalidConf, false).each do |invalid|
40
- it "should raise an error for invalid config string '#{invalid.test}'" do
41
- TestUtils.add_offending_json_to_exception("config", invalid.test) {
42
- TestUtils.intercept(Hocon::ConfigError) {
43
- parse(invalid.test)
44
- }
45
- }
46
- end
47
- end
48
- end
49
-
50
- context "valid_conf_works" do
51
- TestUtils.whitespace_variations(TestUtils::ValidConf, true).each do |valid|
52
- it "should successfully parse config string '#{valid.test}'" do
53
- our_ast = TestUtils.add_offending_json_to_exception("config-conf", valid.test) {
54
- parse(valid.test)
55
- }
56
- # let's also check round-trip rendering
57
- rendered = our_ast.render
58
- reparsed = TestUtils.add_offending_json_to_exception("config-conf-reparsed", rendered) {
59
- parse(rendered)
60
- }
61
- expect(our_ast).to eq(reparsed)
62
- end
63
- end
64
- end
65
- end
66
-
67
- def parse_path(s)
68
- first_exception = nil
69
- second_exception = nil
70
- # parser first by wrapping into a whole document and using the regular parser
71
- result =
72
- begin
73
- tree = parse_without_resolving("[${#{s}}]")
74
- if tree.is_a?(Hocon::ConfigList)
75
- ref = tree[0]
76
- if ref.is_a?(Hocon::Impl::ConfigReference)
77
- ref.expression.path
78
- end
79
- end
80
- rescue Hocon::ConfigError => e
81
- first_exception = e
82
- nil
83
- end
84
-
85
- # also parse with the standalone path parser and be sure the outcome is the same
86
- begin
87
- should_be_same = Hocon::Impl::PathParser.parse_path(s)
88
- unless result == should_be_same
89
- raise "expected '#{result}' to equal '#{should_be_same}'"
90
- end
91
- rescue Hocon::ConfigError => e
92
- second_exception = e
93
- end
94
-
95
- if first_exception.nil? && (!second_exception.nil?)
96
- raise "only the standalone path parser threw: #{second_exception}"
97
- end
98
-
99
- if (!first_exception.nil?) && second_exception.nil?
100
- raise "only the whole-document parser threw: #{first_exception}"
101
- end
102
-
103
- if !first_exception.nil?
104
- raise first_exception
105
- end
106
- if !second_exception.nil?
107
- raise "wtf, should have thrown because not equal"
108
- end
109
-
110
- result
111
- end
112
-
113
- def test_path_parsing(first, second)
114
- it "'#{first}' should parse to same path as '#{second}'" do
115
- expect(TestUtils.path(*first)).to eq(parse_path(second))
116
- end
117
- end
118
-
119
- describe "Config Parser" do
120
- context "path_parsing" do
121
- test_path_parsing(["a"], "a")
122
- test_path_parsing(["a", "b"], "a.b")
123
- test_path_parsing(["a.b"], "\"a.b\"")
124
- test_path_parsing(["a."], "\"a.\"")
125
- test_path_parsing([".b"], "\".b\"")
126
- test_path_parsing(["true"], "true")
127
- test_path_parsing(["a"], " a ")
128
- test_path_parsing(["a ", "b"], " a .b")
129
- test_path_parsing(["a ", " b"], " a . b")
130
- test_path_parsing(["a b"], " a b")
131
- test_path_parsing(["a", "b.c", "d"], "a.\"b.c\".d")
132
- test_path_parsing(["3", "14"], "3.14")
133
- test_path_parsing(["3", "14", "159"], "3.14.159")
134
- test_path_parsing(["a3", "14"], "a3.14")
135
- test_path_parsing([""], "\"\"")
136
- test_path_parsing(["a", "", "b"], "a.\"\".b")
137
- test_path_parsing(["a", ""], "a.\"\"")
138
- test_path_parsing(["", "b"], "\"\".b")
139
- test_path_parsing(["", "", ""], ' "".""."" ')
140
- test_path_parsing(["a-c"], "a-c")
141
- test_path_parsing(["a_c"], "a_c")
142
- test_path_parsing(["-"], "\"-\"")
143
- test_path_parsing(["-"], "-")
144
- test_path_parsing(["-foo"], "-foo")
145
- test_path_parsing(["-10"], "-10")
146
-
147
- # here 10.0 is part of an unquoted string
148
- test_path_parsing(["foo10", "0"], "foo10.0")
149
- # here 10.0 is a number that gets value-concatenated
150
- test_path_parsing(["10", "0foo"], "10.0foo")
151
- # just a number
152
- test_path_parsing(["10", "0"], "10.0")
153
- # multiple-decimal number
154
- test_path_parsing(["1", "2", "3", "4"], "1.2.3.4")
155
-
156
- ["", " ", " \n \n ", "a.", ".b", "a..b", "a${b}c", "\"\".", ".\"\""].each do |invalid|
157
- begin
158
- it "should raise a ConfigBadPathError for '#{invalid}'" do
159
- TestUtils.intercept(Hocon::ConfigError::ConfigBadPathError) {
160
- parse_path(invalid)
161
- }
162
- end
163
- rescue => e
164
- $stderr.puts("failed on '#{invalid}'")
165
- raise e
166
- end
167
- end
168
- end
169
-
170
- it "should allow the last instance to win when duplicate keys are found" do
171
- obj = TestUtils.parse_config('{ "a" : 10, "a" : 11 } ')
172
-
173
- expect(obj.root.size).to eq(1)
174
- expect(obj.get_int("a")).to eq(11)
175
- end
176
-
177
- it "should merge maps when duplicate keys are found" do
178
- obj = TestUtils.parse_config('{ "a" : { "x" : 1, "y" : 2 }, "a" : { "x" : 42, "z" : 100 } }')
179
-
180
- expect(obj.root.size).to eq(1)
181
- expect(obj.get_object("a").size).to eq(3)
182
- expect(obj.get_int("a.x")).to eq(42)
183
- expect(obj.get_int("a.y")).to eq(2)
184
- expect(obj.get_int("a.z")).to eq(100)
185
- end
186
-
187
- it "should merge maps recursively when duplicate keys are found" do
188
- obj = TestUtils.parse_config('{ "a" : { "b" : { "x" : 1, "y" : 2 } }, "a" : { "b" : { "x" : 42, "z" : 100 } } }')
189
-
190
- expect(obj.root.size).to eq(1)
191
- expect(obj.get_object("a").size).to eq(1)
192
- expect(obj.get_object("a.b").size).to eq(3)
193
- expect(obj.get_int("a.b.x")).to eq(42)
194
- expect(obj.get_int("a.b.y")).to eq(2)
195
- expect(obj.get_int("a.b.z")).to eq(100)
196
- end
197
-
198
- it "should merge maps recursively when three levels of duplicate keys are found" do
199
- obj = TestUtils.parse_config('{ "a" : { "b" : { "c" : { "x" : 1, "y" : 2 } } }, "a" : { "b" : { "c" : { "x" : 42, "z" : 100 } } } }')
200
-
201
- expect(obj.root.size).to eq(1)
202
- expect(obj.get_object("a").size).to eq(1)
203
- expect(obj.get_object("a.b").size).to eq(1)
204
- expect(obj.get_object("a.b.c").size).to eq(3)
205
- expect(obj.get_int("a.b.c.x")).to eq(42)
206
- expect(obj.get_int("a.b.c.y")).to eq(2)
207
- expect(obj.get_int("a.b.c.z")).to eq(100)
208
- end
209
-
210
- it "should 'reset' a key when a null is found" do
211
- obj = TestUtils.parse_config('{ a : { b : 1 }, a : null, a : { c : 2 } }')
212
-
213
- expect(obj.root.size).to eq(1)
214
- expect(obj.get_object("a").size).to eq(1)
215
- expect(obj.get_int("a.c")).to eq(2)
216
- end
217
-
218
- it "should 'reset' a map key when a scalar is found" do
219
- obj = TestUtils.parse_config('{ a : { b : 1 }, a : 42, a : { c : 2 } }')
220
-
221
- expect(obj.root.size).to eq(1)
222
- expect(obj.get_object("a").size).to eq(1)
223
- expect(obj.get_int("a.c")).to eq(2)
224
- end
225
- end
226
-
227
- def drop_curlies(s)
228
- # drop the outside curly braces
229
- first = s.index('{')
230
- last = s.rindex('}')
231
- "#{s.slice(0..first)}#{s.slice(first+1..last)}#{s.slice(last + 1)}"
232
- end
233
-
234
- describe "Config Parser" do
235
- context "implied_comma_handling" do
236
- valids = ['
237
- // one line
238
- {
239
- a : y, b : z, c : [ 1, 2, 3 ]
240
- }', '
241
- // multiline but with all commas
242
- {
243
- a : y,
244
- b : z,
245
- c : [
246
- 1,
247
- 2,
248
- 3,
249
- ],
250
- }
251
- ', '
252
- // multiline with no commas
253
- {
254
- a : y
255
- b : z
256
- c : [
257
- 1
258
- 2
259
- 3
260
- ]
261
- }
262
- ']
263
-
264
- changes = [
265
- Proc.new { |s| s },
266
- Proc.new { |s| s.gsub("\n", "\n\n") },
267
- Proc.new { |s| s.gsub("\n", "\n\n\n") },
268
- Proc.new { |s| s.gsub(",\n", "\n,\n")},
269
- Proc.new { |s| s.gsub(",\n", "\n\n,\n\n") },
270
- Proc.new { |s| s.gsub("\n", " \n ") },
271
- Proc.new { |s| s.gsub(",\n", " \n \n , \n \n ") },
272
- Proc.new { |s| drop_curlies(s) }
273
- ]
274
-
275
- tested = 0
276
- changes.each do |change|
277
- valids.each do |v|
278
- tested += 1
279
- s = change.call(v)
280
- it "should handle commas and whitespaces properly for string '#{s}'" do
281
- obj = TestUtils.parse_config(s)
282
- expect(obj.root.size).to eq(3)
283
- expect(obj.get_string("a")).to eq("y")
284
- expect(obj.get_string("b")).to eq("z")
285
- expect(obj.get_int_list("c")).to eq([1,2,3])
286
- end
287
- end
288
- end
289
-
290
- it "should have run one test per change per valid string" do
291
- expect(tested).to eq(changes.length * valids.length)
292
- end
293
-
294
- context "should concatenate values when there is no newline or comma" do
295
- it "with no newline in array" do
296
- expect(TestUtils.parse_config(" { c : [ 1 2 3 ] } ").
297
- get_string_list("c")).to eq (["1 2 3"])
298
- end
299
-
300
- it "with no newline in array with quoted strings" do
301
- expect(TestUtils.parse_config(' { c : [ "4" "5" "6" ] } ').
302
- get_string_list("c")).to eq (["4 5 6"])
303
- end
304
-
305
- it "with no newline in object" do
306
- expect(TestUtils.parse_config(' { a : b c } ').
307
- get_string("a")).to eq ("b c")
308
- end
309
-
310
- it "with no newline at end" do
311
- expect(TestUtils.parse_config('a: b').
312
- get_string("a")).to eq ("b")
313
- end
314
-
315
- it "errors when no newline between keys" do
316
- TestUtils.intercept(Hocon::ConfigError) {
317
- TestUtils.parse_config('{ a : y b : z }')
318
- }
319
- end
320
-
321
- it "errors when no newline between quoted keys" do
322
- TestUtils.intercept(Hocon::ConfigError) {
323
- TestUtils.parse_config('{ "a" : "y" "b" : "z" }')
324
- }
325
- end
326
- end
327
- end
328
-
329
- it "should support keys with slashes" do
330
- obj = TestUtils.parse_config('/a/b/c=42, x/y/z : 32')
331
- expect(obj.get_int("/a/b/c")).to eq(42)
332
- expect(obj.get_int("x/y/z")).to eq(32)
333
- end
334
- end
335
-
336
- def line_number_test(num, text)
337
- it "should include the line number #{num} in the error message for invalid string '#{text}'" do
338
- e = TestUtils.intercept(Hocon::ConfigError) {
339
- TestUtils.parse_config(text)
340
- }
341
- if ! (e.message.include?("#{num}:"))
342
- raise "error message did not contain line '#{num}' '#{text.gsub("\n", "\\n")}' (#{e})"
343
- end
344
- end
345
- end
346
-
347
- describe "Config Parser" do
348
- context "line_numbers_in_errors" do
349
- # error is at the last char
350
- line_number_test(1, "}")
351
- line_number_test(2, "\n}")
352
- line_number_test(3, "\n\n}")
353
-
354
- # error is before a final newline
355
- line_number_test(1, "}\n")
356
- line_number_test(2, "\n}\n")
357
- line_number_test(3, "\n\n}\n")
358
-
359
- # with unquoted string
360
- line_number_test(1, "foo")
361
- line_number_test(2, "\nfoo")
362
- line_number_test(3, "\n\nfoo")
363
-
364
- # with quoted string
365
- line_number_test(1, "\"foo\"")
366
- line_number_test(2, "\n\"foo\"")
367
- line_number_test(3, "\n\n\"foo\"")
368
-
369
- # newlines in triple-quoted string should not hose up the numbering
370
- line_number_test(1, "a : \"\"\"foo\"\"\"}")
371
- line_number_test(2, "a : \"\"\"foo\n\"\"\"}")
372
- line_number_test(3, "a : \"\"\"foo\nbar\nbaz\"\"\"}")
373
- # newlines after the triple quoted string
374
- line_number_test(5, "a : \"\"\"foo\nbar\nbaz\"\"\"\n\n}")
375
- # triple quoted string ends in a newline
376
- line_number_test(6, "a : \"\"\"foo\nbar\nbaz\n\"\"\"\n\n}")
377
- # end in the middle of triple-quoted string
378
- line_number_test(5, "a : \"\"\"foo\n\n\nbar\n")
379
- end
380
-
381
- context "to_string_for_parseables" do
382
- # just to be sure the to_string don't throw, to get test coverage
383
- options = Hocon::ConfigParseOptions.defaults
384
- it "should allow to_s on File Parseable" do
385
- Hocon::Impl::Parseable.new_file("foo", options).to_s
386
- end
387
-
388
- it "should allow to_s on Resources Parseable" do
389
- Hocon::Impl::Parseable.new_resources("foo", options).to_s
390
- end
391
-
392
- it "should allow to_s on Resources Parseable" do
393
- Hocon::Impl::Parseable.new_string("foo", options).to_s
394
- end
395
-
396
- # NOTE: Skipping 'newURL', 'newProperties', 'newReader' tests here
397
- # because we don't implement them
398
- end
399
- end
400
-
401
- def assert_comments(comments, conf)
402
- it "should have comments #{comments} at root" do
403
- expect(conf.root.origin.comments).to eq(comments)
404
- end
405
- end
406
-
407
- def assert_comments_at_path(comments, conf, path)
408
- it "should have comments #{comments} at path #{path}" do
409
- expect(conf.get_value(path).origin.comments).to eq(comments)
410
- end
411
- end
412
-
413
- def assert_comments_at_path_index(comments, conf, path, index)
414
- it "should have comments #{comments} at path #{path} and index #{index}" do
415
- expect(conf.get_list(path).get(index).origin.comments).to eq(comments)
416
- end
417
- end
418
-
419
- describe "Config Parser" do
420
- context "track_comments_for_single_field" do
421
- # no comments
422
- conf0 = TestUtils.parse_config('
423
- {
424
- foo=10 }
425
- ')
426
- assert_comments_at_path([], conf0, "foo")
427
-
428
- # comment in front of a field is used
429
- conf1 = TestUtils.parse_config('
430
- { # Before
431
- foo=10 }
432
- ')
433
- assert_comments_at_path([" Before"], conf1, "foo")
434
-
435
- # comment with a blank line after is dropped
436
- conf2 = TestUtils.parse_config('
437
- { # BlankAfter
438
-
439
- foo=10 }
440
- ')
441
- assert_comments_at_path([], conf2, "foo")
442
-
443
- # comment in front of a field is used with no root {}
444
- conf3 = TestUtils.parse_config('
445
- # BeforeNoBraces
446
- foo=10
447
- ')
448
- assert_comments_at_path([" BeforeNoBraces"], conf3, "foo")
449
-
450
- # comment with a blank line after is dropped with no root {}
451
- conf4 = TestUtils.parse_config('
452
- # BlankAfterNoBraces
453
-
454
- foo=10
455
- ')
456
- assert_comments_at_path([], conf4, "foo")
457
-
458
- # comment same line after field is used
459
- conf5 = TestUtils.parse_config('
460
- {
461
- foo=10 # SameLine
462
- }
463
- ')
464
- assert_comments_at_path([" SameLine"], conf5, "foo")
465
-
466
- # comment before field separator is used
467
- conf6 = TestUtils.parse_config('
468
- {
469
- foo # BeforeSep
470
- =10
471
- }
472
- ')
473
- assert_comments_at_path([" BeforeSep"], conf6, "foo")
474
-
475
- # comment after field separator is used
476
- conf7 = TestUtils.parse_config('
477
- {
478
- foo= # AfterSep
479
- 10
480
- }
481
- ')
482
- assert_comments_at_path([" AfterSep"], conf7, "foo")
483
-
484
- # comment on next line is NOT used
485
- conf8 = TestUtils.parse_config('
486
- {
487
- foo=10
488
- # NextLine
489
- }
490
- ')
491
- assert_comments_at_path([], conf8, "foo")
492
-
493
- # comment before field separator on new line
494
- conf9 = TestUtils.parse_config('
495
- {
496
- foo
497
- # BeforeSepOwnLine
498
- =10
499
- }
500
- ')
501
- assert_comments_at_path([" BeforeSepOwnLine"], conf9, "foo")
502
-
503
- # comment after field separator on its own line
504
- conf10 = TestUtils.parse_config('
505
- {
506
- foo=
507
- # AfterSepOwnLine
508
- 10
509
- }
510
- ')
511
- assert_comments_at_path([" AfterSepOwnLine"], conf10, "foo")
512
-
513
- # comments comments everywhere
514
- conf11 = TestUtils.parse_config('
515
- {# Before
516
- foo
517
- # BeforeSep
518
- = # AfterSepSameLine
519
- # AfterSepNextLine
520
- 10 # AfterValue
521
- # AfterValueNewLine (should NOT be used)
522
- }
523
- ')
524
- assert_comments_at_path([" Before", " BeforeSep", " AfterSepSameLine", " AfterSepNextLine", " AfterValue"], conf11, "foo")
525
-
526
- # empty object
527
- conf12 = TestUtils.parse_config('# BeforeEmpty
528
- {} #AfterEmpty
529
- # NewLine
530
- ')
531
- assert_comments([" BeforeEmpty", "AfterEmpty"], conf12)
532
-
533
- # empty array
534
- conf13 = TestUtils.parse_config('
535
- foo=
536
- # BeforeEmptyArray
537
- [] #AfterEmptyArray
538
- # NewLine
539
- ')
540
- assert_comments_at_path([" BeforeEmptyArray", "AfterEmptyArray"], conf13, "foo")
541
-
542
- # array element
543
- conf14 = TestUtils.parse_config('
544
- foo=[
545
- # BeforeElement
546
- 10 # AfterElement
547
- ]
548
- ')
549
- assert_comments_at_path_index(
550
- [" BeforeElement", " AfterElement"], conf14, "foo", 0)
551
-
552
- # field with comma after it
553
- conf15 = TestUtils.parse_config('
554
- foo=10, # AfterCommaField
555
- ')
556
- assert_comments_at_path([" AfterCommaField"], conf15, "foo")
557
-
558
- # element with comma after it
559
- conf16 = TestUtils.parse_config('
560
- foo=[10, # AfterCommaElement
561
- ]
562
- ')
563
- assert_comments_at_path_index([" AfterCommaElement"], conf16, "foo", 0)
564
-
565
- # field with comma after it but comment isn't on the field's line, so not used
566
- conf17 = TestUtils.parse_config('
567
- foo=10
568
- , # AfterCommaFieldNotUsed
569
- ')
570
- assert_comments_at_path([], conf17, "foo")
571
-
572
- # element with comma after it but comment isn't on the field's line, so not used
573
- conf18 = TestUtils.parse_config('
574
- foo=[10
575
- , # AfterCommaElementNotUsed
576
- ]
577
- ')
578
- assert_comments_at_path_index([], conf18, "foo", 0)
579
-
580
- # comment on new line, before comma, should not be used
581
- conf19 = TestUtils.parse_config('
582
- foo=10
583
- # BeforeCommaFieldNotUsed
584
- ,
585
- ')
586
- assert_comments_at_path([], conf19, "foo")
587
-
588
- # comment on new line, before comma, should not be used
589
- conf20 = TestUtils.parse_config('
590
- foo=[10
591
- # BeforeCommaElementNotUsed
592
- ,
593
- ]
594
- ')
595
- assert_comments_at_path_index([], conf20, "foo", 0)
596
-
597
- # comment on same line before comma
598
- conf21 = TestUtils.parse_config('
599
- foo=10 # BeforeCommaFieldSameLine
600
- ,
601
- ')
602
- assert_comments_at_path([" BeforeCommaFieldSameLine"], conf21, "foo")
603
-
604
- # comment on same line before comma
605
- conf22 = TestUtils.parse_config('
606
- foo=[10 # BeforeCommaElementSameLine
607
- ,
608
- ]
609
- ')
610
- assert_comments_at_path_index([" BeforeCommaElementSameLine"], conf22, "foo", 0)
611
- end
612
-
613
- context "track_comments_for_multiple_fields" do
614
- # nested objects
615
- conf5 = TestUtils.parse_config('
616
- # Outside
617
- bar {
618
- # Ignore me
619
-
620
- # Middle
621
- # two lines
622
- baz {
623
- # Inner
624
- foo=10 # AfterInner
625
- # This should be ignored
626
- } # AfterMiddle
627
- # ignored
628
- } # AfterOutside
629
- # ignored!
630
- ')
631
- assert_comments_at_path([" Inner", " AfterInner"], conf5, "bar.baz.foo")
632
- assert_comments_at_path([" Middle", " two lines", " AfterMiddle"], conf5, "bar.baz")
633
- assert_comments_at_path([" Outside", " AfterOutside"], conf5, "bar")
634
-
635
- # multiple fields
636
- conf6 = TestUtils.parse_config('{
637
- # this is not with a field
638
-
639
- # this is field A
640
- a : 10,
641
- # this is field B
642
- b : 12 # goes with field B which has no comma
643
- # this is field C
644
- c : 14, # goes with field C after comma
645
- # not used
646
- # this is not used
647
- # nor is this
648
- # multi-line block
649
-
650
- # this is with field D
651
- # this is with field D also
652
- d : 16
653
-
654
- # this is after the fields
655
- }')
656
- assert_comments_at_path([" this is field A"], conf6, "a")
657
- assert_comments_at_path([" this is field B", " goes with field B which has no comma"], conf6, "b")
658
- assert_comments_at_path([" this is field C", " goes with field C after comma"], conf6, "c")
659
- assert_comments_at_path([" this is with field D", " this is with field D also"], conf6, "d")
660
-
661
- # array
662
- conf7 = TestUtils.parse_config('
663
- # before entire array
664
- array = [
665
- # goes with 0
666
- 0,
667
- # goes with 1
668
- 1, # with 1 after comma
669
- # goes with 2
670
- 2 # no comma after 2
671
- # not with anything
672
- ] # after entire array
673
- ')
674
- assert_comments_at_path_index([" goes with 0"], conf7, "array", 0)
675
- assert_comments_at_path_index([" goes with 1", " with 1 after comma"], conf7, "array", 1)
676
- assert_comments_at_path_index([" goes with 2", " no comma after 2"], conf7, "array", 2)
677
- assert_comments_at_path([" before entire array", " after entire array"], conf7, "array")
678
-
679
- # properties-like syntax
680
- conf8 = TestUtils.parse_config('
681
- # ignored comment
682
-
683
- # x.y comment
684
- x.y = 10
685
- # x.z comment
686
- x.z = 11
687
- # x.a comment
688
- x.a = 12
689
- # a.b comment
690
- a.b = 14
691
- a.c = 15
692
- a.d = 16 # a.d comment
693
- # ignored comment
694
- ')
695
-
696
- assert_comments_at_path([" x.y comment"], conf8, "x.y")
697
- assert_comments_at_path([" x.z comment"], conf8, "x.z")
698
- assert_comments_at_path([" x.a comment"], conf8, "x.a")
699
- assert_comments_at_path([" a.b comment"], conf8, "a.b")
700
- assert_comments_at_path([], conf8, "a.c")
701
- assert_comments_at_path([" a.d comment"], conf8, "a.d")
702
- # here we're concerned that comments apply only to leaf
703
- # nodes, not to parent objects.
704
- assert_comments_at_path([], conf8, "x")
705
- assert_comments_at_path([], conf8, "a")
706
- end
707
-
708
- context "loading unicode file paths" do
709
- it "should be able to parse files with unicode file paths" do
710
- expect(Hocon.load("#{FIXTURE_DIR}/test_utils/resources/ᚠᛇᚻ.conf")).to eq({'ᚠᛇᚻ' => '᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢ'})
711
- end
712
- end
713
-
714
- it "includeFile" do
715
- conf = Hocon::ConfigFactory.parse_string("include file(" +
716
- TestUtils.json_quoted_resource_file("test01") + ")")
717
-
718
- # should have loaded conf, json... skipping properties
719
- expect(conf.get_int("ints.fortyTwo")).to eq(42)
720
- expect(conf.get_int("fromJson1")).to eq(1)
721
- end
722
-
723
- it "includeFileWithExtension" do
724
- conf = Hocon::ConfigFactory.parse_string("include file(" +
725
- TestUtils.json_quoted_resource_file("test01.conf") + ")")
726
-
727
- expect(conf.get_int("ints.fortyTwo")).to eq(42)
728
- expect(conf.has_path?("fromJson1")).to eq(false)
729
- expect(conf.has_path?("fromProps.abc")).to eq(false)
730
- end
731
-
732
- it "includeFileWhitespaceInsideParens" do
733
- conf = Hocon::ConfigFactory.parse_string("include file( \n " +
734
- TestUtils.json_quoted_resource_file("test01") + " \n )")
735
-
736
- # should have loaded conf, json... NOT properties
737
- expect(conf.get_int("ints.fortyTwo")).to eq(42)
738
- expect(conf.get_int("fromJson1")).to eq(1)
739
- end
740
-
741
- it "includeFileNoWhitespaceOutsideParens" do
742
- e = TestUtils.intercept(Hocon::ConfigError::ConfigParseError) {
743
- Hocon::ConfigFactory.parse_string("include file (" +
744
- TestUtils.json_quoted_resource_file("test01") + ")")
745
- }
746
- expect(e.message.include?("expecting include parameter")).to eq(true)
747
- end
748
-
749
- it "includeFileNotQuoted" do
750
- # this test cannot work on Windows
751
- f = TestUtils.resource_file("test01")
752
- if (f.to_s.include?("\\"))
753
- $stderr.puts("includeFileNotQuoted test skipped on Windows")
754
- else
755
- e = TestUtils.intercept(Hocon::ConfigError::ConfigParseError) {
756
- Hocon::ConfigFactory.parse_string("include file(" + f + ")")
757
- }
758
- expect(e.message.include?("expecting include parameter")).to eq(true)
759
- end
760
- end
761
-
762
- it "includeFileNotQuotedAndSpecialChar" do
763
- f = TestUtils.resource_file("test01")
764
- if (f.to_s.include?("\\"))
765
- $stderr.puts("includeFileNotQuoted test skipped on Windows")
766
- else
767
- e = TestUtils.intercept(Hocon::ConfigError::ConfigParseError) {
768
- Hocon::ConfigFactory.parse_string("include file(:" + f + ")")
769
- }
770
- expect(e.message.include?("expecting a quoted string")).to eq(true)
771
- end
772
-
773
- end
774
-
775
- it "includeFileUnclosedParens" do
776
- e = TestUtils.intercept(Hocon::ConfigError::ConfigParseError) {
777
- Hocon::ConfigFactory.parse_string("include file(" + TestUtils.json_quoted_resource_file("test01") + " something")
778
- }
779
- expect(e.message.include?("expecting a close paren")).to eq(true)
780
- end
781
-
782
- # Skipping 'includeURLBasename' because we don't support URLs
783
- # Skipping 'includeURLWithExtension' because we don't support URLs
784
- # Skipping 'includeURLInvalid' because we don't support URLs
785
- # Skipping 'includeResources' because we don't support classpath resources
786
- # Skipping 'includeURLHeuristically' because we don't support URLs
787
- # Skipping 'includeURLBasenameHeuristically' because we don't support URLs
788
-
789
- it "acceptsUTF8FileContents" do
790
- # utf8.conf is UTF-8 with no BOM
791
- rune_utf8 = "\u16EB\u16D2\u16E6\u16A6\u16EB\u16A0\u16B1\u16A9\u16A0\u16A2"
792
- conf = Hocon::ConfigFactory.parse_file(TestUtils.resource_file("utf8.conf"))
793
- expect(conf.get_string("\u16A0\u16C7\u16BB")).to eq(rune_utf8)
794
- end
795
-
796
- it "shouldacceptUTF16FileContents" do
797
- skip('supporting UTF-16 requires appropriate BOM detection during parsing') do
798
- # utf16.conf is UTF-16LE with a BOM
799
- expect { Hocon::ConfigFactory.parse_file(TestUtils.resource_file("utf16.conf")) }.to raise_error
800
- end
801
- end
802
-
803
- it "acceptBOMStartingFile" do
804
- # BOM at start of file should be ignored
805
- conf = Hocon::ConfigFactory.parse_file(TestUtils.resource_file("bom.conf"))
806
- expect(conf.get_string("foo")).to eq("bar")
807
- end
808
-
809
- it "acceptBOMInStringValue" do
810
- # BOM inside quotes should be preserved, just as other whitespace would be
811
- conf = Hocon::ConfigFactory.parse_string("foo=\"\uFEFF\uFEFF\"")
812
- expect(conf.get_string("foo")).to eq("\uFEFF\uFEFF")
813
- end
814
-
815
- it "acceptBOMWhitespace" do
816
- skip("BOM not parsing properly yet; not fixing this now because it most likely only affects windows") do
817
- # BOM here should be treated like other whitespace (ignored, since no quotes)
818
- conf = Hocon::ConfigFactory.parse_string("foo= \uFEFFbar\uFEFF")
819
- expect(conf.get_string("foo")).to eq("bar")
820
- end
821
- end
822
-
823
- it "acceptMultiPeriodNumericPath" do
824
- conf1 = Hocon::ConfigFactory.parse_string("0.1.2.3=foobar1")
825
- expect(conf1.get_string("0.1.2.3")).to eq("foobar1")
826
- conf2 = Hocon::ConfigFactory.parse_string("0.1.2.3.ABC=foobar2")
827
- expect(conf2.get_string("0.1.2.3.ABC")).to eq("foobar2")
828
- conf3 = Hocon::ConfigFactory.parse_string("ABC.0.1.2.3=foobar3")
829
- expect(conf3.get_string("ABC.0.1.2.3")).to eq("foobar3")
830
- end
831
- end