puppet 6.0.5 → 6.0.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +30 -0
  3. data/Gemfile.lock +14 -14
  4. data/lib/puppet.rb +4 -4
  5. data/lib/puppet/application.rb +1 -1
  6. data/lib/puppet/application/filebucket.rb +6 -1
  7. data/lib/puppet/configurer.rb +6 -6
  8. data/lib/puppet/confine/boolean.rb +45 -0
  9. data/lib/puppet/confine/false.rb +7 -1
  10. data/lib/puppet/confine/true.rb +7 -1
  11. data/lib/puppet/defaults.rb +21 -29
  12. data/lib/puppet/functions/call.rb +2 -1
  13. data/lib/puppet/network/http/connection.rb +15 -5
  14. data/lib/puppet/pops/issues.rb +4 -0
  15. data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +60 -4
  16. data/lib/puppet/pops/model/factory.rb +38 -4
  17. data/lib/puppet/pops/parser/egrammar.ra +2 -2
  18. data/lib/puppet/pops/parser/heredoc_support.rb +17 -7
  19. data/lib/puppet/pops/parser/lexer2.rb +6 -1
  20. data/lib/puppet/pops/parser/locator.rb +106 -86
  21. data/lib/puppet/pops/parser/parser_support.rb +11 -2
  22. data/lib/puppet/pops/types/type_mismatch_describer.rb +1 -1
  23. data/lib/puppet/provider/file/windows.rb +49 -1
  24. data/lib/puppet/provider/group/windows_adsi.rb +4 -1
  25. data/lib/puppet/provider/package/windows.rb +5 -1
  26. data/lib/puppet/provider/service/upstart.rb +16 -6
  27. data/lib/puppet/settings.rb +10 -5
  28. data/lib/puppet/transaction.rb +8 -6
  29. data/lib/puppet/transaction/resource_harness.rb +1 -0
  30. data/lib/puppet/type/exec.rb +27 -5
  31. data/lib/puppet/type/file/mode.rb +6 -1
  32. data/lib/puppet/type/filebucket.rb +12 -8
  33. data/lib/puppet/util/command_line.rb +5 -1
  34. data/lib/puppet/util/log.rb +7 -2
  35. data/lib/puppet/util/pidlock.rb +14 -1
  36. data/lib/puppet/util/windows/process.rb +73 -5
  37. data/lib/puppet/util/windows/security.rb +29 -8
  38. data/lib/puppet/version.rb +1 -1
  39. data/locales/ja/puppet.po +149 -132
  40. data/locales/puppet.pot +197 -148
  41. data/man/man5/puppet.conf.5 +14 -6
  42. data/man/man8/puppet-agent.8 +1 -1
  43. data/man/man8/puppet-apply.8 +1 -1
  44. data/man/man8/puppet-catalog.8 +1 -1
  45. data/man/man8/puppet-config.8 +1 -1
  46. data/man/man8/puppet-describe.8 +1 -1
  47. data/man/man8/puppet-device.8 +1 -1
  48. data/man/man8/puppet-doc.8 +1 -1
  49. data/man/man8/puppet-epp.8 +1 -1
  50. data/man/man8/puppet-facts.8 +1 -1
  51. data/man/man8/puppet-filebucket.8 +6 -2
  52. data/man/man8/puppet-generate.8 +1 -1
  53. data/man/man8/puppet-help.8 +1 -1
  54. data/man/man8/puppet-key.8 +1 -1
  55. data/man/man8/puppet-lookup.8 +1 -1
  56. data/man/man8/puppet-man.8 +1 -1
  57. data/man/man8/puppet-module.8 +1 -1
  58. data/man/man8/puppet-node.8 +1 -1
  59. data/man/man8/puppet-parser.8 +1 -1
  60. data/man/man8/puppet-plugin.8 +1 -1
  61. data/man/man8/puppet-report.8 +1 -1
  62. data/man/man8/puppet-resource.8 +1 -1
  63. data/man/man8/puppet-script.8 +1 -1
  64. data/man/man8/puppet-ssl.8 +1 -1
  65. data/man/man8/puppet-status.8 +1 -1
  66. data/man/man8/puppet.8 +2 -2
  67. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load2.rb +11 -0
  68. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load3.rb +11 -0
  69. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load4.rb +11 -0
  70. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load5.rb +12 -0
  71. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/good_func_load.rb +9 -0
  72. data/spec/integration/provider/file/windows_spec.rb +162 -0
  73. data/spec/integration/type/file_spec.rb +0 -19
  74. data/spec/unit/application_spec.rb +8 -1
  75. data/spec/unit/configurer_spec.rb +6 -7
  76. data/spec/unit/confine/false_spec.rb +27 -0
  77. data/spec/unit/confine/true_spec.rb +27 -0
  78. data/spec/unit/defaults_spec.rb +0 -14
  79. data/spec/unit/network/http/connection_spec.rb +1 -1
  80. data/spec/unit/pops/loaders/loaders_spec.rb +70 -3
  81. data/spec/unit/pops/parser/locator_spec.rb +45 -0
  82. data/spec/unit/pops/parser/parse_heredoc_spec.rb +111 -15
  83. data/spec/unit/pops/types/type_mismatch_describer_spec.rb +9 -0
  84. data/spec/unit/provider/group/windows_adsi_spec.rb +7 -1
  85. data/spec/unit/provider/package/windows_spec.rb +12 -1
  86. data/spec/unit/provider/service/systemd_spec.rb +7 -5
  87. data/spec/unit/settings_spec.rb +36 -0
  88. data/spec/unit/transaction/resource_harness_spec.rb +26 -0
  89. data/spec/unit/transaction_spec.rb +29 -0
  90. data/spec/unit/type/exec_spec.rb +47 -0
  91. data/spec/unit/type/filebucket_spec.rb +8 -6
  92. data/spec/unit/util/command_line_spec.rb +23 -2
  93. data/spec/unit/util/execution_spec.rb +2 -2
  94. data/spec/unit/util/log_spec.rb +15 -0
  95. data/spec/unit/util/pidlock_spec.rb +21 -1
  96. data/spec/unit/util/storage_spec.rb +19 -19
  97. metadata +16 -3
  98. data/MAINTAINERS +0 -47
@@ -1525,15 +1525,6 @@ describe Puppet::Type.type(:file), :uses_checksums => true do
1525
1525
  catalog.apply
1526
1526
  end
1527
1527
 
1528
- it "should not allow the user to explicitly set the mode to 4 ,and correct to 7" do
1529
- system_aces = get_aces_for_path_by_sid(path, @sids[:system])
1530
- expect(system_aces).not_to be_empty
1531
-
1532
- system_aces.each do |ace|
1533
- expect(ace.mask).to eq(Puppet::Util::Windows::File::FILE_ALL_ACCESS)
1534
- end
1535
- end
1536
-
1537
1528
  it "prepends SYSTEM ace when changing group from system to power users" do
1538
1529
  @file[:group] = @sids[:power_users]
1539
1530
  catalog.apply
@@ -1612,16 +1603,6 @@ describe Puppet::Type.type(:file), :uses_checksums => true do
1612
1603
  catalog.apply
1613
1604
  end
1614
1605
 
1615
- it "should not allow the user to explicitly set the mode to 4, and correct to 7" do
1616
- system_aces = get_aces_for_path_by_sid(dir, @sids[:system])
1617
- expect(system_aces).not_to be_empty
1618
-
1619
- system_aces.each do |ace|
1620
- # unlike files, Puppet sets execute bit on directories that are readable
1621
- expect(ace.mask).to eq(Puppet::Util::Windows::File::FILE_ALL_ACCESS)
1622
- end
1623
- end
1624
-
1625
1606
  it "prepends SYSTEM ace when changing group from system to power users" do
1626
1607
  @directory[:group] = @sids[:power_users]
1627
1608
  catalog.apply
@@ -664,10 +664,17 @@ describe Puppet::Application do
664
664
  it "should log an exception that is raised" do
665
665
  our_exception = Puppet::DevError.new("test exception")
666
666
  Puppet::Util::Log.expects(:newdestination).with(test_arg).raises(our_exception)
667
- Puppet.expects(:log_exception).with(our_exception)
667
+ Puppet.expects(:log_and_raise).with(our_exception, anything)
668
668
  @app.handle_logdest_arg(test_arg)
669
669
  end
670
670
 
671
+ it "should exit when an exception is raised" do
672
+ our_exception = Puppet::DevError.new("test exception")
673
+ Puppet::Util::Log.expects(:newdestination).with(test_arg).raises(our_exception)
674
+ Puppet.expects(:log_and_raise).with(our_exception, anything).raises(our_exception)
675
+ expect { @app.handle_logdest_arg(test_arg) }.to raise_error(Puppet::DevError)
676
+ end
677
+
671
678
  it "should set the new log destination" do
672
679
  Puppet::Util::Log.expects(:newdestination).with(test_arg)
673
680
  @app.handle_logdest_arg(test_arg)
@@ -1034,26 +1034,25 @@ describe Puppet::Configurer do
1034
1034
  Puppet.settings[:server_list] = ["myserver:123"]
1035
1035
  response = Net::HTTPInternalServerError.new(nil, 500, 'Internal Server Error')
1036
1036
  Puppet::Network::HttpPool.stubs(:http_ssl_instance).with('myserver', '123').returns(mock('request', get: response))
1037
- @agent.stubs(:run_internal)
1038
1037
 
1039
1038
  Puppet.expects(:debug).with("Puppet server myserver:123 is unavailable: 500 Internal Server Error")
1040
- @agent.run
1039
+ expect{ @agent.run }.to raise_error(Puppet::Error, /Could not select a functional puppet master from server_list/)
1041
1040
  end
1042
1041
 
1043
- it "should fallback to an empty server when failover fails" do
1042
+ it "should error when no servers in 'server_list' are reachable" do
1044
1043
  Puppet.settings[:server_list] = ["myserver:123"]
1045
1044
  error = Net::HTTPError.new(400, 'dummy server communication error')
1046
- Puppet::Network::HttpPool.stubs(:http_ssl_instance).with('myserver', '123').returns(error)
1047
- @agent.stubs(:run_internal)
1045
+ Puppet::Network::HttpPool.stubs(:http_ssl_instance).with('myserver', '123').returns(mock('request', get: error))
1048
1046
 
1049
1047
  options = {}
1050
- @agent.run(options)
1048
+ expect{ @agent.run(options) }.to raise_error(Puppet::Error, /Could not select a functional puppet master from server_list/)
1051
1049
  expect(options[:report].master_used).to be_nil
1052
1050
  end
1053
1051
 
1054
1052
  it "should not make multiple node requets when the server is found" do
1055
1053
  Puppet.settings[:server_list] = ["myserver:123"]
1056
- Puppet::Network::HttpPool.expects(:http_ssl_instance).once
1054
+ response = Net::HTTPOK.new(nil, 200, 'OK')
1055
+ Puppet::Network::HttpPool.stubs(:http_ssl_instance).with('myserver', '123').returns(mock('request', get: response))
1057
1056
  @agent.stubs(:run_internal)
1058
1057
 
1059
1058
  @agent.run
@@ -12,6 +12,33 @@ describe Puppet::Confine::False do
12
12
  expect { Puppet::Confine.new }.to raise_error(ArgumentError)
13
13
  end
14
14
 
15
+ describe "when passing in a lambda as a value for lazy evaluation" do
16
+ it "should accept it" do
17
+ confine = Puppet::Confine::False.new(lambda { false })
18
+ expect(confine.values).to eql([false])
19
+ end
20
+
21
+ describe "when enforcing cache-positive behavior" do
22
+ def cached_value_of(confine)
23
+ confine.instance_variable_get(:@cached_value)
24
+ end
25
+
26
+ it "should cache a false value" do
27
+ confine = Puppet::Confine::False.new(lambda { false })
28
+ confine.values
29
+
30
+ expect(cached_value_of(confine)).to eql([false])
31
+ end
32
+
33
+ it "should not cache a true value" do
34
+ confine = Puppet::Confine::False.new(lambda { true })
35
+ confine.values
36
+
37
+ expect(cached_value_of(confine)).to be_nil
38
+ end
39
+ end
40
+ end
41
+
15
42
  describe "when testing values" do
16
43
  before { @confine = Puppet::Confine::False.new("foo") }
17
44
 
@@ -12,6 +12,33 @@ describe Puppet::Confine::True do
12
12
  expect { Puppet::Confine::True.new }.to raise_error(ArgumentError)
13
13
  end
14
14
 
15
+ describe "when passing in a lambda as a value for lazy evaluation" do
16
+ it "should accept it" do
17
+ confine = Puppet::Confine::True.new(lambda { true })
18
+ expect(confine.values).to eql([true])
19
+ end
20
+
21
+ describe "when enforcing cache-positive behavior" do
22
+ def cached_value_of(confine)
23
+ confine.instance_variable_get(:@cached_value)
24
+ end
25
+
26
+ it "should cache a true value" do
27
+ confine = Puppet::Confine::True.new(lambda { true })
28
+ confine.values
29
+
30
+ expect(cached_value_of(confine)).to eql([true])
31
+ end
32
+
33
+ it "should not cache a false value" do
34
+ confine = Puppet::Confine::True.new(lambda { false })
35
+ confine.values
36
+
37
+ expect(cached_value_of(confine)).to be_nil
38
+ end
39
+ end
40
+ end
41
+
15
42
  describe "when testing values" do
16
43
  before do
17
44
  @confine = Puppet::Confine::True.new("foo")
@@ -110,20 +110,6 @@ describe "Defaults" do
110
110
  end
111
111
  end
112
112
 
113
- describe 'server vs server_list' do
114
- it 'should warn when both settings are set in code' do
115
- Puppet.expects(:deprecation_warning).with('Attempted to set both server and server_list. Server setting will not be used.', :SERVER_DUPLICATION)
116
- Puppet.settings[:server] = 'test_server'
117
- Puppet.settings[:server_list] = ['one', 'two']
118
- end
119
-
120
- it 'should warn when both settings are set by command line' do
121
- Puppet.expects(:deprecation_warning).with('Attempted to set both server and server_list. Server setting will not be used.', :SERVER_DUPLICATION)
122
- Puppet.settings.handlearg("--server_list", "one,two")
123
- Puppet.settings.handlearg("--server", "test_server")
124
- end
125
- end
126
-
127
113
  describe 'manage_internal_file_permissions' do
128
114
  describe 'on windows', :if => Puppet::Util::Platform.windows? do
129
115
  it 'should default to false' do
@@ -86,7 +86,7 @@ describe Puppet::Network::HTTP::Connection do
86
86
 
87
87
  expect do
88
88
  connection.get('request')
89
- end.to raise_error(Puppet::Error, "certificate verify failed: [shady looking signature]")
89
+ end.to raise_error(Puppet::Error, /certificate verify failed: \[shady looking signature\]/)
90
90
  end
91
91
 
92
92
  it "should provide a helpful error message when hostname was not match with server certificate", :unless => Puppet::Util::Platform.windows? || RUBY_PLATFORM == 'java' do
@@ -421,9 +421,14 @@ describe 'loaders' do
421
421
  expect(function.call(scope, 'passed in scope')).to eql("usee::callee_ws() got 'passed in scope'")
422
422
  end
423
423
 
424
+ it 'calls can be made to a non core function via the call() function' do
425
+ call_function = loader.load_typed(typed_name(:function, 'call')).value
426
+ expect(call_function.call(scope, 'user::puppetcaller4')).to eql("usee::callee() got 'first' - usee::callee() got 'second'")
427
+ end
428
+
424
429
  end
425
430
 
426
- context 'when causing a 3x load followed by a 4x load' do
431
+ context 'when a 3x load takes place' do
427
432
  let(:env) { environment_for(mix_4x_and_3x_functions) }
428
433
  let(:compiler) { Puppet::Parser::Compiler.new(Puppet::Node.new("test", :environment => env)) }
429
434
  let(:scope) { compiler.topscope }
@@ -436,11 +441,73 @@ describe 'loaders' do
436
441
  Puppet.pop_context
437
442
  end
438
443
 
439
- it "a 3x function with code outside body is reported as an error" do
440
- expect { loader.load_typed(typed_name(:function, 'bad_func_load')) }.to raise_error(/Illegal legacy function definition/)
444
+ it "a function with no illegal constructs can be loaded" do
445
+ function = loader.load_typed(typed_name(:function, 'good_func_load')).value
446
+ expect(function.call(scope)).to eql(Float("3.14"))
441
447
  end
442
448
  end
443
449
 
450
+ context 'when a 3x load has illegal method added' do
451
+ let(:env) { environment_for(mix_4x_and_3x_functions) }
452
+ let(:compiler) { Puppet::Parser::Compiler.new(Puppet::Node.new("test", :environment => env)) }
453
+ let(:scope) { compiler.topscope }
454
+ let(:loader) { compiler.loaders.private_loader_for_module('user') }
455
+
456
+ before(:each) do
457
+ Puppet.push_context(:current_environment => scope.environment, :global_scope => scope, :loaders => compiler.loaders)
458
+ end
459
+ after(:each) do
460
+ Puppet.pop_context
461
+ end
462
+
463
+ it "outside function body is reported as an error" do
464
+ expect { loader.load_typed(typed_name(:function, 'bad_func_load')) }.to raise_error(/Illegal method definition/)
465
+ end
466
+
467
+ it "to self outside function body is reported as an error" do
468
+ expect { loader.load_typed(typed_name(:function, 'bad_func_load5')) }.to raise_error(/Illegal method definition.*'bad_func_load5_illegal_method'/)
469
+ end
470
+
471
+ it "outside body is reported as an error even if returning the right func_info" do
472
+ expect { loader.load_typed(typed_name(:function, 'bad_func_load2'))}.to raise_error(/Illegal method definition/)
473
+ end
474
+
475
+ it "inside function body is reported as an error" do
476
+ expect {
477
+ f = loader.load_typed(typed_name(:function, 'bad_func_load3')).value
478
+ f.call(scope)
479
+ }.to raise_error(/Illegal method definition.*'bad_func_load3_illegal_method'/)
480
+ end
481
+
482
+ it "to self inside function body is reported as an error" do
483
+ expect {
484
+ f = loader.load_typed(typed_name(:function, 'bad_func_load4')).value
485
+ f.call(scope)
486
+ }.to raise_error(/Illegal method definition.*'bad_func_load4_illegal_method'/)
487
+ end
488
+ end
489
+
490
+ context 'when a 3x load has illegal construct and --func3x_check is false' do
491
+ let(:env) { environment_for(mix_4x_and_3x_functions) }
492
+ let(:compiler) { Puppet::Parser::Compiler.new(Puppet::Node.new("test", :environment => env)) }
493
+ let(:scope) { compiler.topscope }
494
+ let(:loader) { compiler.loaders.private_loader_for_module('user') }
495
+
496
+ before(:each) do
497
+ Puppet.push_context(:current_environment => scope.environment, :global_scope => scope, :loaders => compiler.loaders)
498
+ Puppet[:func3x_check] = false
499
+ end
500
+ after(:each) do
501
+ Puppet.pop_context
502
+ Puppet[:func3x_check] = true
503
+ end
504
+
505
+ it "an illegal function is loaded" do
506
+ f = loader.load_typed(typed_name(:function, 'bad_func_load3')).value
507
+ expect(f.call(scope)).to eql("some return value")
508
+ end
509
+ end
510
+
444
511
  context 'when causing a 3x load followed by a 4x load' do
445
512
  let(:env) { environment_for(mix_4x_and_3x_functions) }
446
513
  let(:compiler) { Puppet::Parser::Compiler.new(Puppet::Node.new("test", :environment => env)) }
@@ -41,4 +41,49 @@ describe Puppet::Pops::Parser::Locator do
41
41
  expect(model.body.locator.line_for_offset(2)).to eq(:third_value)
42
42
  end
43
43
 
44
+ it 'A heredoc without margin and interpolated expression location has offset and length relative the source' do
45
+ parser = Puppet::Pops::Parser::Parser.new()
46
+ src = <<-CODE
47
+ # line one
48
+ # line two
49
+ @("END"/L)
50
+ Line four\\
51
+ Line five ${1 +
52
+ 1}
53
+ END
54
+ CODE
55
+
56
+ model = parser.parse_string(src).model
57
+ interpolated_expr = model.body.text_expr.segments[1].expr
58
+ expect(interpolated_expr.left_expr.offset).to eq(84)
59
+ expect(interpolated_expr.left_expr.length).to eq(1)
60
+ expect(interpolated_expr.right_expr.offset).to eq(96)
61
+ expect(interpolated_expr.right_expr.length).to eq(1)
62
+ expect(interpolated_expr.offset).to eq(86) # the + sign
63
+ expect(interpolated_expr.length).to eq(1) # the + sign
64
+ expect(interpolated_expr.locator.extract_tree_text(interpolated_expr)).to eq("1 +\n 1")
65
+ end
66
+
67
+ it 'A heredoc with margin and interpolated expression location has offset and length relative the source' do
68
+ parser = Puppet::Pops::Parser::Parser.new()
69
+ src = <<-CODE
70
+ # line one
71
+ # line two
72
+ @("END"/L)
73
+ Line four\\
74
+ Line five ${1 +
75
+ 1}
76
+ |- END
77
+ CODE
78
+
79
+ model = parser.parse_string(src).model
80
+ interpolated_expr = model.body.text_expr.segments[1].expr
81
+ expect(interpolated_expr.left_expr.offset).to eq(84)
82
+ expect(interpolated_expr.left_expr.length).to eq(1)
83
+ expect(interpolated_expr.right_expr.offset).to eq(96)
84
+ expect(interpolated_expr.right_expr.length).to eq(1)
85
+ expect(interpolated_expr.offset).to eq(86) # the + sign
86
+ expect(interpolated_expr.length).to eq(1) # the + sign
87
+ expect(interpolated_expr.locator.extract_tree_text(interpolated_expr)).to eq("1 +\n 1")
88
+ end
44
89
  end
@@ -10,7 +10,7 @@ describe "egrammar parsing heredoc" do
10
10
  it "parses plain heredoc" do
11
11
  expect(dump(parse("@(END)\nThis is\nheredoc text\nEND\n"))).to eq([
12
12
  "(@()",
13
- " (sublocated 'This is\nheredoc text\n')",
13
+ " 'This is\nheredoc text\n'",
14
14
  ")"
15
15
  ].join("\n"))
16
16
  end
@@ -25,7 +25,7 @@ describe "egrammar parsing heredoc" do
25
25
  ].join("\n")
26
26
  expect(dump(parse(src))).to eq([
27
27
  "(@()",
28
- " (sublocated 'This is\nheredoc text\n')",
28
+ " 'This is\nheredoc text\n'",
29
29
  ")"
30
30
  ].join("\n"))
31
31
  end
@@ -40,7 +40,7 @@ describe "egrammar parsing heredoc" do
40
40
  ].join("\n")
41
41
  expect(dump(parse(src))).to eq([
42
42
  "(@()",
43
- " (sublocated 'This is\nheredoc text')",
43
+ " 'This is\nheredoc text'",
44
44
  ")"
45
45
  ].join("\n"))
46
46
  end
@@ -53,7 +53,7 @@ describe "egrammar parsing heredoc" do
53
53
  CODE
54
54
  expect(dump(parse(src))).to eq([
55
55
  "(@(syntax)",
56
- " (sublocated 'Tex\tt\\n')",
56
+ " 'Tex\tt\\n'",
57
57
  ")"
58
58
  ].join("\n"))
59
59
  end
@@ -66,7 +66,7 @@ describe "egrammar parsing heredoc" do
66
66
  CODE
67
67
  expect(dump(parse(src))).to eq([
68
68
  "(@()",
69
- " (sublocated (cat 'Hello ' (str $name)))",
69
+ " (cat 'Hello ' (str $name))",
70
70
  ")"
71
71
  ].join("\n"))
72
72
  end
@@ -79,7 +79,7 @@ describe "egrammar parsing heredoc" do
79
79
  CODE
80
80
  expect(dump(parse(src))).to eq([
81
81
  "(@()",
82
- " (sublocated (cat 'Hello \\' (str $name)))",
82
+ " (cat 'Hello \\' (str $name))",
83
83
  ")"
84
84
  ].join("\n"))
85
85
  end
@@ -92,7 +92,7 @@ describe "egrammar parsing heredoc" do
92
92
  CODE
93
93
  expect(dump(parse(src))).to eq([
94
94
  "(@()",
95
- " (sublocated (cat 'Hello \\' (str $name)))",
95
+ " (cat 'Hello \\' (str $name))",
96
96
  ")"
97
97
  ].join("\n"))
98
98
  end
@@ -107,7 +107,7 @@ describe "egrammar parsing heredoc" do
107
107
  parse(src)
108
108
  expect(dump(parse(src))).to eq([
109
109
  "(@()",
110
- " (sublocated 'First Line Second Line')",
110
+ " 'First Line Second Line'",
111
111
  ")"
112
112
  ].join("\n"))
113
113
  end
@@ -122,7 +122,7 @@ describe "egrammar parsing heredoc" do
122
122
  parse(src)
123
123
  expect(dump(parse(src))).to eq([
124
124
  "(@()",
125
- " (sublocated ' First Line Second Line')",
125
+ " ' First Line Second Line'",
126
126
  ")"
127
127
  ].join("\n"))
128
128
  end
@@ -135,12 +135,12 @@ describe "egrammar parsing heredoc" do
135
135
  CODE
136
136
  expect(dump(parse(src))).to eq([
137
137
  "(@()",
138
- " (sublocated (cat 'Hello ' (str $name) '$%a'))",
138
+ " (cat 'Hello ' (str $name) '$%a')",
139
139
  ")"
140
140
  ].join("\n"))
141
141
  end
142
142
 
143
- it "parses interpolated [] expression by looking at the correct preceding char for space" do
143
+ it "parses interpolated [] expression by looking at the correct preceding char for space when there is no heredoc margin" do
144
144
  # NOTE: Important not to use the left margin feature here
145
145
  src = <<-CODE
146
146
  $xxxxxxx = @("END")
@@ -150,12 +150,108 @@ END
150
150
  CODE
151
151
  expect(dump(parse(src))).to eq([
152
152
  "(= $xxxxxxx (@()",
153
- " (sublocated (cat (str (slice (slice $facts 'os') 'family')) '",
153
+ " (cat (str (slice (slice $facts 'os') 'family')) '",
154
154
  "XXXXXXX XXX",
155
- "'))",
155
+ "')",
156
156
  "))"].join("\n"))
157
157
  end
158
158
 
159
+ it "parses interpolated [] expression by looking at the correct preceding char for space when there is a heredoc margin" do
160
+ # NOTE: Important not to use the left margin feature here - the problem in PUP 9303 is triggered by lines and text before
161
+ # an interpolation containing [].
162
+ src = <<-CODE
163
+ # comment
164
+ # comment
165
+ $xxxxxxx = @("END")
166
+ 1
167
+ 2
168
+ 3
169
+ 4
170
+ 5
171
+ YYYYY${facts['fqdn']}
172
+ XXXXXXX XXX
173
+ | END
174
+ CODE
175
+ expect(dump(parse(src))).to eq([
176
+ "(= $xxxxxxx (@()",
177
+ " (cat '1", "2", "3", "4", "5",
178
+ "YYYYY' (str (slice $facts 'fqdn')) '",
179
+ "XXXXXXX XXX",
180
+ "')",
181
+ "))"].join("\n"))
182
+ end
183
+
184
+ it "correctly reports an error location in a nested heredoc with margin" do
185
+ # NOTE: Important not to use the left margin feature here - the problem in PUP 9303 is triggered by lines and text before
186
+ # an interpolation containing [].
187
+ src = <<-CODE
188
+ # comment
189
+ # comment
190
+ $xxxxxxx = @("END")
191
+ 1
192
+ 2
193
+ 3
194
+ 4
195
+ 5
196
+ YYYYY${facts]}
197
+ XXXXXXX XXX
198
+ | END
199
+ CODE
200
+ expect{parse(src)}.to raise_error(/Syntax error at '\]' \(line: 9, column: 15\)/)
201
+ end
202
+
203
+ it "correctly reports an error location in a heredoc with line endings escaped" do
204
+ # DO NOT CHANGE INDENTATION OF THIS HEREDOC
205
+ src = <<-CODE
206
+ # line one
207
+ # line two
208
+ @("END"/L)
209
+ First Line\\
210
+ Second Line ${facts]}
211
+ |- END
212
+ CODE
213
+ expect{parse(src)}.to raise_error(/Syntax error at '\]' \(line: 5, column: 24\)/)
214
+ end
215
+
216
+ it "correctly reports an error location in a heredoc with line endings escaped when there is text in the margin" do
217
+ # DO NOT CHANGE INDENTATION OR SPACING OF THIS HEREDOC
218
+ src = <<-CODE
219
+ # line one
220
+ # line two
221
+ @("END"/L)
222
+ First Line\\
223
+ Second Line
224
+ x Third Line ${facts]}
225
+ |- END
226
+ # line 8
227
+ # line 9
228
+ CODE
229
+ expect{parse(src)}.to raise_error(/Syntax error at '\]' \(line: 6, column: 23\)/)
230
+ end
231
+
232
+ it "correctly reports an error location in a heredoc with line endings escaped when there is text in the margin" do
233
+ # DO NOT CHANGE INDENTATION OR SPACING OF THIS HEREDOC
234
+ src = <<-CODE
235
+ @(END)
236
+ AAA
237
+ BBB
238
+ CCC
239
+ DDD
240
+ EEE
241
+ FFF
242
+ |- END
243
+ CODE
244
+ expect(dump(parse(src))).to eq([
245
+ "(@()",
246
+ " 'AAA", # no left space trimmed
247
+ " BBB",
248
+ " CCC",
249
+ " DDD",
250
+ "EEE", # left space trimmed
251
+ " FFF'", # indented one because it is one in from margin marker
252
+ ")"].join("\n"))
253
+ end
254
+
159
255
  it 'parses multiple heredocs on the same line' do
160
256
  src = <<-CODE
161
257
  notice({ @(foo) => @(bar) })
@@ -168,9 +264,9 @@ CODE
168
264
  expect(dump(parse(src))).to eq([
169
265
  '(block',
170
266
  ' (invoke notice ({} ((@()',
171
- ' (sublocated \' hello\')',
267
+ ' \' hello\'',
172
268
  ' ) (@()',
173
- ' (sublocated \' world\')',
269
+ ' \' world\'',
174
270
  ' ))))',
175
271
  ' (invoke notice \'!\')',
176
272
  ')'