puppet 3.7.5-x64-mingw32 → 3.8.1-x64-mingw32

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/ext/build_defaults.yaml +5 -5
  3. data/lib/hiera/puppet_function.rb +15 -4
  4. data/lib/puppet.rb +5 -2
  5. data/lib/puppet/application/agent.rb +5 -0
  6. data/lib/puppet/application/apply.rb +5 -0
  7. data/lib/puppet/application/device.rb +8 -3
  8. data/lib/puppet/application/master.rb +5 -0
  9. data/lib/puppet/defaults.rb +8 -0
  10. data/lib/puppet/error.rb +27 -1
  11. data/lib/puppet/file_system.rb +13 -0
  12. data/lib/puppet/file_system/file19windows.rb +8 -0
  13. data/lib/puppet/file_system/file_impl.rb +4 -0
  14. data/lib/puppet/file_system/memory_impl.rb +4 -0
  15. data/lib/puppet/functions.rb +25 -3
  16. data/lib/puppet/functions/defined.rb +130 -0
  17. data/lib/puppet/functions/hiera_include.rb +1 -1
  18. data/lib/puppet/node/environment.rb +4 -0
  19. data/lib/puppet/parser/compiler.rb +5 -2
  20. data/lib/puppet/parser/functions/defined.rb +26 -1
  21. data/lib/puppet/parser/functions/file.rb +3 -1
  22. data/lib/puppet/parser/templatewrapper.rb +2 -1
  23. data/lib/puppet/pops.rb +5 -0
  24. data/lib/puppet/pops/evaluator/access_operator.rb +25 -5
  25. data/lib/puppet/pops/evaluator/collector_transformer.rb +1 -11
  26. data/lib/puppet/pops/evaluator/compare_operator.rb +43 -0
  27. data/lib/puppet/pops/evaluator/evaluator_impl.rb +43 -28
  28. data/lib/puppet/pops/evaluator/runtime3_support.rb +9 -5
  29. data/lib/puppet/pops/functions/dispatch.rb +6 -1
  30. data/lib/puppet/pops/issue_reporter.rb +42 -16
  31. data/lib/puppet/pops/issues.rb +96 -0
  32. data/lib/puppet/pops/loader/module_loaders.rb +3 -1
  33. data/lib/puppet/pops/loaders.rb +6 -4
  34. data/lib/puppet/pops/migration/migration_checker.rb +45 -0
  35. data/lib/puppet/pops/model/factory.rb +1 -1
  36. data/lib/puppet/pops/model/model_meta.rb +1 -1
  37. data/lib/puppet/pops/parser/egrammar.ra +1 -1
  38. data/lib/puppet/pops/parser/eparser.rb +1 -1
  39. data/lib/puppet/pops/parser/epp_support.rb +18 -9
  40. data/lib/puppet/pops/parser/evaluating_parser.rb +7 -1
  41. data/lib/puppet/pops/parser/heredoc_support.rb +12 -11
  42. data/lib/puppet/pops/parser/interpolation_support.rb +7 -1
  43. data/lib/puppet/pops/parser/lexer2.rb +8 -8
  44. data/lib/puppet/pops/parser/lexer_support.rb +46 -20
  45. data/lib/puppet/pops/parser/parser_support.rb +11 -14
  46. data/lib/puppet/pops/parser/slurp_support.rb +22 -6
  47. data/lib/puppet/pops/types/type_calculator.rb +156 -55
  48. data/lib/puppet/pops/types/type_factory.rb +67 -14
  49. data/lib/puppet/pops/types/type_parser.rb +22 -13
  50. data/lib/puppet/pops/types/types.rb +21 -3
  51. data/lib/puppet/pops/types/types_meta.rb +13 -2
  52. data/lib/puppet/pops/validation.rb +25 -2
  53. data/lib/puppet/pops/validation/checker4_0.rb +25 -5
  54. data/lib/puppet/provider/group/windows_adsi.rb +18 -6
  55. data/lib/puppet/provider/mount/parsed.rb +145 -2
  56. data/lib/puppet/provider/package/pip.rb +4 -5
  57. data/lib/puppet/provider/package/zypper.rb +17 -7
  58. data/lib/puppet/provider/scheduled_task/win32_taskscheduler.rb +35 -10
  59. data/lib/puppet/provider/service/init.rb +7 -0
  60. data/lib/puppet/provider/user/windows_adsi.rb +8 -1
  61. data/lib/puppet/provider/zpool/zpool.rb +7 -2
  62. data/lib/puppet/resource.rb +1 -1
  63. data/lib/puppet/type/group.rb +1 -1
  64. data/lib/puppet/type/mount.rb +14 -3
  65. data/lib/puppet/type/scheduled_task.rb +21 -6
  66. data/lib/puppet/util/log.rb +50 -8
  67. data/lib/puppet/util/log/destinations.rb +23 -2
  68. data/lib/puppet/util/logging.rb +37 -1
  69. data/lib/puppet/util/windows/adsi.rb +36 -11
  70. data/lib/puppet/version.rb +1 -1
  71. data/spec/fixtures/unit/provider/mount/parsed/aix.filesystems +93 -85
  72. data/spec/fixtures/unit/provider/mount/parsed/aix.mount +11 -7
  73. data/spec/integration/parser/collector_spec.rb +7 -0
  74. data/spec/integration/parser/future_compiler_spec.rb +9 -0
  75. data/spec/integration/parser/resource_expressions_spec.rb +3 -0
  76. data/spec/unit/file_system_spec.rb +38 -0
  77. data/spec/unit/functions/defined_spec.rb +291 -0
  78. data/spec/unit/functions/hiera_spec.rb +8 -6
  79. data/spec/unit/functions4_spec.rb +97 -2
  80. data/spec/unit/parser/functions/file_spec.rb +8 -2
  81. data/spec/unit/parser/functions/template_spec.rb +1 -1
  82. data/spec/unit/parser/templatewrapper_spec.rb +1 -1
  83. data/spec/unit/pops/evaluator/access_ops_spec.rb +19 -0
  84. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +61 -8
  85. data/spec/unit/pops/issues_spec.rb +16 -16
  86. data/spec/unit/pops/loaders/module_loaders_spec.rb +5 -0
  87. data/spec/unit/pops/migration_spec.rb +180 -0
  88. data/spec/unit/pops/parser/lexer2_spec.rb +152 -1
  89. data/spec/unit/pops/parser/parse_heredoc_spec.rb +26 -0
  90. data/spec/unit/pops/transformer/transform_calls_spec.rb +1 -1
  91. data/spec/unit/pops/types/type_calculator_spec.rb +204 -11
  92. data/spec/unit/pops/validation_spec.rb +66 -0
  93. data/spec/unit/provider/group/windows_adsi_spec.rb +65 -1
  94. data/spec/unit/provider/mount/parsed_spec.rb +31 -5
  95. data/spec/unit/provider/package/pip_spec.rb +19 -7
  96. data/spec/unit/provider/package/zypper_spec.rb +25 -14
  97. data/spec/unit/provider/scheduled_task/win32_taskscheduler_spec.rb +312 -70
  98. data/spec/unit/provider/service/base_spec.rb +42 -31
  99. data/spec/unit/provider/service/freebsd_spec.rb +1 -0
  100. data/spec/unit/provider/service/gentoo_spec.rb +1 -0
  101. data/spec/unit/provider/service/init_spec.rb +18 -0
  102. data/spec/unit/provider/service/openbsd_spec.rb +1 -0
  103. data/spec/unit/provider/service/redhat_spec.rb +1 -0
  104. data/spec/unit/provider/user/windows_adsi_spec.rb +21 -0
  105. data/spec/unit/provider/zpool/zpool_spec.rb +47 -10
  106. data/spec/unit/util/log_spec.rb +113 -0
  107. data/spec/unit/util/windows/adsi_spec.rb +106 -26
  108. metadata +10 -2
@@ -234,6 +234,19 @@ describe 'Lexer2' do
234
234
  '"a${y::_x}"' => [[:DQPRE, 'a', {:line => 1, :pos=>1, :length=>4 }],
235
235
  [:VARIABLE, 'y::_x', {:line => 1, :pos=>5, :length=>5 }],
236
236
  [:DQPOST, '', {:line => 1, :pos=>11, :length=>1 }]],
237
+
238
+ '"a${_x[1]}"' => [[:DQPRE, 'a', {:line => 1, :pos=>1, :length=>4 }],
239
+ [:VARIABLE, '_x', {:line => 1, :pos=>5, :length=>2 }],
240
+ [:LBRACK, '[', {:line => 1, :pos=>7, :length=>1 }],
241
+ [:NUMBER, '1', {:line => 1, :pos=>8, :length=>1 }],
242
+ [:RBRACK, ']', {:line => 1, :pos=>9, :length=>1 }],
243
+ [:DQPOST, '', {:line => 1, :pos=>11, :length=>1 }]],
244
+
245
+ '"a${_x.foo}"'=> [[:DQPRE, 'a', {:line => 1, :pos=>1, :length=>4 }],
246
+ [:VARIABLE, '_x', {:line => 1, :pos=>5, :length=>2 }],
247
+ [:DOT, '.', {:line => 1, :pos=>7, :length=>1 }],
248
+ [:NAME, 'foo', {:line => 1, :pos=>8, :length=>3 }],
249
+ [:DQPOST, '', {:line => 1, :pos=>12, :length=>1 }]],
237
250
  }.each do |source, expected|
238
251
  it "should lex an interpolated variable 'x' from #{source}" do
239
252
  tokens_scanned_from(source).should match_tokens2(*expected)
@@ -361,6 +374,63 @@ describe 'Lexer2' do
361
374
  [:DQPOST, " After"]
362
375
  )
363
376
  end
377
+
378
+ context 'with bad syntax' do
379
+ def expect_issue(code, issue)
380
+ expect { tokens_scanned_from(code) }.to raise_error(Puppet::ParseErrorWithIssue) { |e|
381
+ expect(e.issue_code).to be(issue.issue_code)
382
+ }
383
+ end
384
+
385
+ it 'detects and reports HEREDOC_UNCLOSED_PARENTHESIS' do
386
+ code = <<-CODE
387
+ @(END:syntax/t
388
+ Text
389
+ |- END
390
+ CODE
391
+ expect_issue(code, Puppet::Pops::Issues::HEREDOC_UNCLOSED_PARENTHESIS)
392
+ end
393
+
394
+ it 'detects and reports HEREDOC_WITHOUT_END_TAGGED_LINE' do
395
+ code = <<-CODE
396
+ @(END:syntax/t)
397
+ Text
398
+ CODE
399
+ expect_issue(code, Puppet::Pops::Issues::HEREDOC_WITHOUT_END_TAGGED_LINE)
400
+ end
401
+
402
+ it 'detects and reports HEREDOC_INVALID_ESCAPE' do
403
+ code = <<-CODE
404
+ @(END:syntax/x)
405
+ Text
406
+ |- END
407
+ CODE
408
+ expect_issue(code, Puppet::Pops::Issues::HEREDOC_INVALID_ESCAPE)
409
+ end
410
+
411
+ it 'detects and reports HEREDOC_INVALID_SYNTAX' do
412
+ code = <<-CODE
413
+ @(END:syntax/t/p)
414
+ Text
415
+ |- END
416
+ CODE
417
+ expect_issue(code, Puppet::Pops::Issues::HEREDOC_INVALID_SYNTAX)
418
+ end
419
+
420
+ it 'detects and reports HEREDOC_WITHOUT_TEXT' do
421
+ code = '@(END:syntax/t)'
422
+ expect_issue(code, Puppet::Pops::Issues::HEREDOC_WITHOUT_TEXT)
423
+ end
424
+
425
+ it 'detects and reports HEREDOC_MULTIPLE_AT_ESCAPES' do
426
+ code = <<-CODE
427
+ @(END:syntax/tst)
428
+ Tex\\tt\\n
429
+ |- END
430
+ CODE
431
+ expect_issue(code, Puppet::Pops::Issues::HEREDOC_MULTIPLE_AT_ESCAPES)
432
+ end
433
+ end
364
434
  end
365
435
 
366
436
  context 'when dealing with multi byte characters' do
@@ -376,6 +446,18 @@ describe 'Lexer2' do
376
446
  tokens_scanned_from(code).should match_tokens2([:STRING, "x\u2713y"])
377
447
  end
378
448
  end
449
+ it 'should support unicode characters in long form' do
450
+ code = <<-CODE
451
+ "x\\u{1f452}y"
452
+ CODE
453
+ if Puppet::Pops::Parser::Locator::RUBYVER < Puppet::Pops::Parser::Locator::RUBY_1_9_3
454
+ # Ruby 1.8.7 reports the multibyte char as several octal characters
455
+ tokens_scanned_from(code).should match_tokens2([:STRING, "x\360\237\221\222y"])
456
+ else
457
+ # >= Ruby 1.9.3 reports \u
458
+ tokens_scanned_from(code).should match_tokens2([:STRING, "x\u{1f452}y"])
459
+ end
460
+ end
379
461
 
380
462
  it 'should not select LISTSTART token when preceded by multibyte chars' do
381
463
  # This test is sensitive to the number of multibyte characters and position of the expressions
@@ -487,6 +569,75 @@ describe 'Lexer2' do
487
569
  [:RENDER_STRING, "<% this is escaped epp %>\n"]
488
570
  )
489
571
  end
572
+
573
+ context 'with bad epp syntax' do
574
+ def expect_issue(code, issue)
575
+ expect { epp_tokens_scanned_from(code) }.to raise_error(Puppet::ParseErrorWithIssue) { |e|
576
+ expect(e.issue_code).to be(issue.issue_code)
577
+ }
578
+ end
579
+
580
+ it 'detects and reports EPP_UNBALANCED_TAG' do
581
+ expect_issue('<% asf', Puppet::Pops::Issues::EPP_UNBALANCED_TAG)
582
+ end
583
+
584
+ it 'detects and reports EPP_UNBALANCED_COMMENT' do
585
+ expect_issue('<%# asf', Puppet::Pops::Issues::EPP_UNBALANCED_COMMENT)
586
+ end
587
+
588
+ it 'detects and reports EPP_UNBALANCED_EXPRESSION' do
589
+ expect_issue('asf <%', Puppet::Pops::Issues::EPP_UNBALANCED_EXPRESSION)
590
+ end
591
+ end
490
592
  end
491
- end
492
593
 
594
+ context 'when parsing bad code' do
595
+ def expect_issue(code, issue)
596
+ expect { tokens_scanned_from(code) }.to raise_error(Puppet::ParseErrorWithIssue) do |e|
597
+ expect(e.issue_code).to be(issue.issue_code)
598
+ end
599
+ end
600
+
601
+ it 'detects and reports issue ILLEGAL_CLASS_REFERENCE' do
602
+ expect_issue('A::3', Puppet::Pops::Issues::ILLEGAL_CLASS_REFERENCE)
603
+ end
604
+
605
+ it 'detects and reports issue ILLEGAL_FULLY_QUALIFIED_CLASS_REFERENCE' do
606
+ expect_issue('::A::3', Puppet::Pops::Issues::ILLEGAL_FULLY_QUALIFIED_CLASS_REFERENCE)
607
+ end
608
+
609
+ it 'detects and reports issue ILLEGAL_FULLY_QUALIFIED_NAME' do
610
+ expect_issue('::a::3', Puppet::Pops::Issues::ILLEGAL_FULLY_QUALIFIED_NAME)
611
+ end
612
+
613
+ it 'detects and reports issue ILLEGAL_NAME_OR_BARE_WORD' do
614
+ expect_issue('a::3', Puppet::Pops::Issues::ILLEGAL_NAME_OR_BARE_WORD)
615
+ end
616
+
617
+ it 'detects and reports issue ILLEGAL_NUMBER' do
618
+ expect_issue('3g', Puppet::Pops::Issues::ILLEGAL_NUMBER)
619
+ end
620
+
621
+ it 'detects and reports issue INVALID_HEX_NUMBER' do
622
+ expect_issue('0x3g', Puppet::Pops::Issues::INVALID_HEX_NUMBER)
623
+ end
624
+
625
+ it 'detects and reports issue INVALID_OCTAL_NUMBER' do
626
+ expect_issue('038', Puppet::Pops::Issues::INVALID_OCTAL_NUMBER)
627
+ end
628
+
629
+ it 'detects and reports issue INVALID_DECIMAL_NUMBER' do
630
+ expect_issue('4.3g', Puppet::Pops::Issues::INVALID_DECIMAL_NUMBER)
631
+ end
632
+
633
+ it 'detects and reports issue NO_INPUT_TO_LEXER' do
634
+ expect { Puppet::Pops::Parser::Lexer2.new.fullscan }.to raise_error(Puppet::ParseErrorWithIssue) { |e|
635
+ expect(e.issue_code).to be(Puppet::Pops::Issues::NO_INPUT_TO_LEXER.issue_code)
636
+ }
637
+ end
638
+
639
+ it 'detects and reports issue UNCLOSED_QUOTE' do
640
+ expect_issue('"asd', Puppet::Pops::Issues::UNCLOSED_QUOTE)
641
+ end
642
+ end
643
+ end
@@ -71,6 +71,32 @@ describe "egrammar parsing heredoc" do
71
71
  ].join("\n")
72
72
  end
73
73
 
74
+ it "parses interpolated heredoc expression containing escapes" do
75
+ src = <<-CODE
76
+ @("END")
77
+ Hello \\$name
78
+ |- END
79
+ CODE
80
+ dump(parse(src)).should == [
81
+ "(@()",
82
+ " (sublocated (cat 'Hello \\' (str $name) ''))",
83
+ ")"
84
+ ].join("\n")
85
+ end
86
+
87
+ it "parses interpolated heredoc expression containing escapes when escaping other things than $" do
88
+ src = <<-CODE
89
+ @("END"/t)
90
+ Hello \\$name
91
+ |- END
92
+ CODE
93
+ dump(parse(src)).should == [
94
+ "(@()",
95
+ " (sublocated (cat 'Hello \\' (str $name) ''))",
96
+ ")"
97
+ ].join("\n")
98
+ end
99
+
74
100
  it "parses with escaped newlines without preceding whitespace" do
75
101
  src = <<-CODE
76
102
  @(END/L)
@@ -38,7 +38,7 @@ describe "transformation to Puppet AST for function calls" do
38
38
 
39
39
  "info bar" => '(invoke info bar)',
40
40
  "notice bar" => '(invoke notice bar)',
41
- "error bar" => '(invoke error bar)',
41
+ "err bar" => '(invoke err bar)',
42
42
  "warning bar" => '(invoke warning bar)',
43
43
  "debug bar" => '(invoke debug bar)',
44
44
 
@@ -89,6 +89,10 @@ describe 'The type calculator' do
89
89
  Puppet::Pops::Types::TypeFactory.optional(t)
90
90
  end
91
91
 
92
+ def not_undef_t(t = nil)
93
+ Puppet::Pops::Types::TypeFactory.not_undef(t)
94
+ end
95
+
92
96
  def undef_t
93
97
  Puppet::Pops::Types::TypeFactory.undef
94
98
  end
@@ -108,6 +112,7 @@ describe 'The type calculator' do
108
112
  def all_types
109
113
  [ Puppet::Pops::Types::PAnyType,
110
114
  Puppet::Pops::Types::PUndefType,
115
+ Puppet::Pops::Types::PNotUndefType,
111
116
  Puppet::Pops::Types::PDataType,
112
117
  Puppet::Pops::Types::PScalarType,
113
118
  Puppet::Pops::Types::PStringType,
@@ -184,6 +189,7 @@ describe 'The type calculator' do
184
189
  result << array_t(types::PDataType.new)
185
190
  result << types::TypeFactory.hash_of_data
186
191
  result << Puppet::Pops::Types::PUndefType
192
+ result << not_undef_t(types::PDataType.new)
187
193
  tmp = tuple_t(types::PDataType.new)
188
194
  result << (tmp)
189
195
  tmp.size_type = range_t(0, nil)
@@ -389,7 +395,7 @@ describe 'The type calculator' do
389
395
  t = calculator.infer_set({ 'mode' => 'read', 'path' => ['foo', 'fee' ] })
390
396
  expect(t.class).to eq(Puppet::Pops::Types::PStructType)
391
397
  expect(t.elements.size).to eq(2)
392
- els = t.elements.map { |e| e.type }.sort {|a,b| a.to_s <=> b.to_s }
398
+ els = t.elements.map { |e| e.value_type }.sort {|a,b| a.to_s <=> b.to_s }
393
399
  els[0].class.should == Puppet::Pops::Types::PStringType
394
400
  els[1].class.should == Puppet::Pops::Types::PTupleType
395
401
  end
@@ -471,6 +477,45 @@ describe 'The type calculator' do
471
477
  calculator.string(calculator.common_type(r1, r2)).should == "Class"
472
478
  end
473
479
 
480
+ context 'of strings' do
481
+ it 'computes commonality' do
482
+ t1 = string_t('abc')
483
+ t2 = string_t('xyz')
484
+ common_t = calculator.common_type(t1,t2)
485
+ expect(common_t.class).to eq(Puppet::Pops::Types::PStringType)
486
+ expect(common_t.values).to eq(['abc', 'xyz'])
487
+ end
488
+
489
+ it 'computes common size_type' do
490
+ t1 = string_t
491
+ t1.size_type = range_t(3,6)
492
+ t2 = string_t
493
+ t2.size_type = range_t(2,4)
494
+ common_t = calculator.common_type(t1,t2)
495
+ expect(common_t.class).to eq(Puppet::Pops::Types::PStringType)
496
+ expect(common_t.size_type).to eq(range_t(2,6))
497
+ end
498
+
499
+ it 'computes common size_type to be undef when one of the types has no size_type' do
500
+ t1 = string_t
501
+ t2 = string_t
502
+ t2.size_type = range_t(2,4)
503
+ common_t = calculator.common_type(t1,t2)
504
+ expect(common_t.class).to eq(Puppet::Pops::Types::PStringType)
505
+ expect(common_t.size_type).to be_nil
506
+ end
507
+
508
+ it 'computes values to be empty if the one has empty values' do
509
+ t1 = string_t('apa')
510
+ t1.size_type = range_t(3,6)
511
+ t2 = string_t
512
+ t2.size_type = range_t(2,4)
513
+ common_t = calculator.common_type(t1,t2)
514
+ expect(common_t.class).to eq(Puppet::Pops::Types::PStringType)
515
+ expect(common_t.values).to be_empty
516
+ end
517
+ end
518
+
474
519
  it 'computes pattern commonality' do
475
520
  t1 = pattern_t('abc')
476
521
  t2 = pattern_t('xyz')
@@ -553,6 +598,13 @@ describe 'The type calculator' do
553
598
  context 'computes assignability' do
554
599
  include_context "types_setup"
555
600
 
601
+ it 'such that all types are assignable to themselves' do
602
+ all_types.each do |tc|
603
+ t = tc.new
604
+ expect(t).to be_assignable_to(t)
605
+ end
606
+ end
607
+
556
608
  context 'for Unit, such that' do
557
609
  it 'all types are assignable to Unit' do
558
610
  t = Puppet::Pops::Types::PUnitType.new()
@@ -577,13 +629,55 @@ describe 'The type calculator' do
577
629
  all_types.each { |t2| t2.new.should be_assignable_to(t) }
578
630
  end
579
631
 
580
- it 'Any is not assignable to anything but Any' do
581
- tested_types = all_types() - [Puppet::Pops::Types::PAnyType]
632
+ it 'Any is not assignable to anything but Any and Optional (implied Optional[Any])' do
633
+ tested_types = all_types() - [Puppet::Pops::Types::PAnyType, Puppet::Pops::Types::POptionalType]
582
634
  t = Puppet::Pops::Types::PAnyType.new()
583
635
  tested_types.each { |t2| t.should_not be_assignable_to(t2.new) }
584
636
  end
585
637
  end
586
638
 
639
+ context "for NotUndef, such that" do
640
+ it 'all types except types assignable from Undef are assignable to NotUndef' do
641
+ t = not_undef_t
642
+ tc = Puppet::Pops::Types::TypeCalculator.singleton
643
+ undef_t = Puppet::Pops::Types::PUndefType.new()
644
+ all_types().each do |c|
645
+ t2 = c.new
646
+ if tc.assignable?(t2, undef_t)
647
+ expect(t2).not_to be_assignable_to(t)
648
+ else
649
+ expect(t2).to be_assignable_to(t)
650
+ end
651
+ end
652
+ end
653
+
654
+ it 'type NotUndef[T] is assignable from T unless T is assignable from Undef ' do
655
+ tc = Puppet::Pops::Types::TypeCalculator.singleton
656
+ undef_t = Puppet::Pops::Types::PUndefType.new()
657
+ all_types().select do |c|
658
+ t2 = c.new
659
+ not_undef_t = not_undef_t(t2)
660
+ if tc.assignable?(t2, undef_t)
661
+ expect(t2).not_to be_assignable_to(not_undef_t)
662
+ else
663
+ expect(t2).to be_assignable_to(not_undef_t)
664
+ end
665
+ end
666
+ end
667
+
668
+ it 'type T is assignable from NotUndef[T] unless T is assignable from Undef' do
669
+ tc = Puppet::Pops::Types::TypeCalculator.singleton
670
+ undef_t = Puppet::Pops::Types::PUndefType.new()
671
+ all_types().select do |c|
672
+ t2 = c.new
673
+ not_undef_t = not_undef_t(t2)
674
+ unless tc.assignable?(t2, undef_t)
675
+ expect(not_undef_t).to be_assignable_to(t2)
676
+ end
677
+ end
678
+ end
679
+ end
680
+
587
681
  context "for Data, such that" do
588
682
  it 'all scalars + array and hash are assignable to Data' do
589
683
  t = Puppet::Pops::Types::PDataType.new()
@@ -610,7 +704,7 @@ describe 'The type calculator' do
610
704
  end
611
705
 
612
706
  it 'Data is not assignable to any disjunct type' do
613
- tested_types = all_types - [Puppet::Pops::Types::PAnyType, Puppet::Pops::Types::PDataType] - scalar_types
707
+ tested_types = all_types - [Puppet::Pops::Types::PAnyType, Puppet::Pops::Types::POptionalType, Puppet::Pops::Types::PDataType] - scalar_types
614
708
  t = Puppet::Pops::Types::PDataType.new()
615
709
  tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
616
710
  end
@@ -647,7 +741,7 @@ describe 'The type calculator' do
647
741
  end
648
742
 
649
743
  it 'Scalar is not assignable to any disjunct type' do
650
- tested_types = all_types - [Puppet::Pops::Types::PAnyType, Puppet::Pops::Types::PDataType] - scalar_types
744
+ tested_types = all_types - [Puppet::Pops::Types::PAnyType, Puppet::Pops::Types::POptionalType, Puppet::Pops::Types::PNotUndefType, Puppet::Pops::Types::PDataType] - scalar_types
651
745
  t = Puppet::Pops::Types::PScalarType.new()
652
746
  tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
653
747
  end
@@ -668,6 +762,8 @@ describe 'The type calculator' do
668
762
  it 'Numeric is not assignable to any disjunct type' do
669
763
  tested_types = all_types - [
670
764
  Puppet::Pops::Types::PAnyType,
765
+ Puppet::Pops::Types::POptionalType,
766
+ Puppet::Pops::Types::PNotUndefType,
671
767
  Puppet::Pops::Types::PDataType,
672
768
  Puppet::Pops::Types::PScalarType,
673
769
  ] - numeric_types
@@ -689,7 +785,7 @@ describe 'The type calculator' do
689
785
  end
690
786
 
691
787
  it 'Collection is not assignable to any disjunct type' do
692
- tested_types = all_types - [Puppet::Pops::Types::PAnyType] - collection_types
788
+ tested_types = all_types - [Puppet::Pops::Types::PAnyType, Puppet::Pops::Types::POptionalType, Puppet::Pops::Types::PNotUndefType] - collection_types
693
789
  t = Puppet::Pops::Types::PCollectionType.new()
694
790
  tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
695
791
  end
@@ -700,6 +796,7 @@ describe 'The type calculator' do
700
796
  t = Puppet::Pops::Types::PArrayType.new()
701
797
  tested_types = collection_types - [
702
798
  Puppet::Pops::Types::PCollectionType,
799
+ Puppet::Pops::Types::PNotUndefType,
703
800
  Puppet::Pops::Types::PArrayType,
704
801
  Puppet::Pops::Types::PTupleType]
705
802
  tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
@@ -708,6 +805,8 @@ describe 'The type calculator' do
708
805
  it 'Array is not assignable to any disjunct type' do
709
806
  tested_types = all_types - [
710
807
  Puppet::Pops::Types::PAnyType,
808
+ Puppet::Pops::Types::POptionalType,
809
+ Puppet::Pops::Types::PNotUndefType,
711
810
  Puppet::Pops::Types::PDataType] - collection_types
712
811
  t = Puppet::Pops::Types::PArrayType.new()
713
812
  tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
@@ -727,6 +826,8 @@ describe 'The type calculator' do
727
826
  it 'Hash is not assignable to any disjunct type' do
728
827
  tested_types = all_types - [
729
828
  Puppet::Pops::Types::PAnyType,
829
+ Puppet::Pops::Types::POptionalType,
830
+ Puppet::Pops::Types::PNotUndefType,
730
831
  Puppet::Pops::Types::PDataType] - collection_types
731
832
  t = Puppet::Pops::Types::PHashType.new()
732
833
  tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
@@ -762,6 +863,8 @@ describe 'The type calculator' do
762
863
  it 'Tuple is not assignable to any disjunct type' do
763
864
  tested_types = all_types - [
764
865
  Puppet::Pops::Types::PAnyType,
866
+ Puppet::Pops::Types::POptionalType,
867
+ Puppet::Pops::Types::PNotUndefType,
765
868
  Puppet::Pops::Types::PDataType] - collection_types
766
869
  t = Puppet::Pops::Types::PTupleType.new()
767
870
  tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
@@ -781,10 +884,41 @@ describe 'The type calculator' do
781
884
  it 'Struct is not assignable to any disjunct type' do
782
885
  tested_types = all_types - [
783
886
  Puppet::Pops::Types::PAnyType,
887
+ Puppet::Pops::Types::POptionalType,
888
+ Puppet::Pops::Types::PNotUndefType,
784
889
  Puppet::Pops::Types::PDataType] - collection_types
785
890
  t = Puppet::Pops::Types::PStructType.new()
786
891
  tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
787
892
  end
893
+
894
+ it 'Default key optionality is controlled by value assignability to undef' do
895
+ t1 = struct_t({'member' => string_t})
896
+ expect(t1.elements[0].key_type).to eq(string_t('member'))
897
+ t1 = struct_t({'member' => object_t})
898
+ expect(t1.elements[0].key_type).to eq(optional_t(string_t('member')))
899
+ end
900
+
901
+ it "NotUndef['key'] becomes String['key'] (since its implied that String is required)" do
902
+ t1 = struct_t({not_undef_t('member') => string_t})
903
+ expect(t1.elements[0].key_type).to eq(string_t('member'))
904
+ end
905
+
906
+ it "Optional['key'] becomes Optional[String['key']]" do
907
+ t1 = struct_t({optional_t('member') => string_t})
908
+ expect(t1.elements[0].key_type).to eq(optional_t(string_t('member')))
909
+ end
910
+
911
+ it 'Optional members are not required' do
912
+ t1 = struct_t({optional_t('optional_member') => string_t, not_undef_t('other_member') => string_t})
913
+ t2 = struct_t({not_undef_t('other_member') => string_t})
914
+ expect(t2).to be_assignable_to(t1)
915
+ end
916
+
917
+ it 'Required members not optional even when value is' do
918
+ t1 = struct_t({not_undef_t('required_member') => object_t, not_undef_t('other_member') => string_t})
919
+ t2 = struct_t({not_undef_t('other_member') => string_t})
920
+ expect(t2).not_to be_assignable_to(t1)
921
+ end
788
922
  end
789
923
 
790
924
  context "for Callable, such that" do
@@ -792,7 +926,9 @@ describe 'The type calculator' do
792
926
  t = Puppet::Pops::Types::PCallableType.new()
793
927
  tested_types = all_types - [
794
928
  Puppet::Pops::Types::PCallableType,
795
- Puppet::Pops::Types::PAnyType]
929
+ Puppet::Pops::Types::PAnyType,
930
+ Puppet::Pops::Types::POptionalType,
931
+ Puppet::Pops::Types::PNotUndefType]
796
932
  tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
797
933
  end
798
934
  end
@@ -1231,7 +1367,7 @@ describe 'The type calculator' do
1231
1367
  calculator.instance?(Puppet::Pops::Types::POptionalType.new(), :undef).should == true
1232
1368
  end
1233
1369
 
1234
- it 'should not consider undef to be an instance of any other type than Any, NilType and Data' do
1370
+ it 'should not consider undef to be an instance of any other type than Any, UndefType and Data' do
1235
1371
  types_to_test = all_types - [
1236
1372
  Puppet::Pops::Types::PAnyType,
1237
1373
  Puppet::Pops::Types::PUndefType,
@@ -1248,9 +1384,10 @@ describe 'The type calculator' do
1248
1384
  calculator.instance?(Puppet::Pops::Types::PAnyType.new(), :default).should == true
1249
1385
  end
1250
1386
 
1251
- it 'should not consider "default" to be an instance of anything but Default, and Any' do
1387
+ it 'should not consider "default" to be an instance of anything but Default, NotUndef, and Any' do
1252
1388
  types_to_test = all_types - [
1253
1389
  Puppet::Pops::Types::PAnyType,
1390
+ Puppet::Pops::Types::PNotUndefType,
1254
1391
  Puppet::Pops::Types::PDefaultType,
1255
1392
  ]
1256
1393
 
@@ -1281,6 +1418,13 @@ describe 'The type calculator' do
1281
1418
  calculator.instance?(range, 'abcd').should == false
1282
1419
  end
1283
1420
 
1421
+ it 'should consider string values' do
1422
+ string = string_t('a', 'b')
1423
+ expect(calculator.instance?(string, 'a')).to eq(true)
1424
+ expect(calculator.instance?(string, 'b')).to eq(true)
1425
+ expect(calculator.instance?(string, 'c')).to eq(false)
1426
+ end
1427
+
1284
1428
  it 'should consider array in length range' do
1285
1429
  range = factory.constrain_size(array_t(integer_t), 1,3)
1286
1430
  calculator.instance?(range, [1]).should == true
@@ -1380,6 +1524,26 @@ describe 'The type calculator' do
1380
1524
  struct = struct_t({'a'=>Integer, 'b'=>String, 'c'=>optional_t(Float)})
1381
1525
  calculator.instance?(struct, {'a'=>1, 'b'=>'a', 'c'=>'x'}).should == false
1382
1526
  end
1527
+
1528
+ it 'should consider nil to be a valid element value' do
1529
+ struct = struct_t({not_undef_t('a') => object_t, 'b'=>String})
1530
+ expect(calculator.instance?(struct, {'a'=>nil , 'b'=>'a'})).to eq(true)
1531
+ end
1532
+
1533
+ it 'should consider nil to be a valid element value but subject to value type' do
1534
+ struct = struct_t({not_undef_t('a') => String, 'b'=>String})
1535
+ expect(calculator.instance?(struct, {'a'=>nil , 'b'=>'a'})).to eq(false)
1536
+ end
1537
+
1538
+ it 'should consider nil to be a valid element value but subject to value type even when key is optional' do
1539
+ struct = struct_t({optional_t('a') => String, 'b'=>String})
1540
+ expect(calculator.instance?(struct, {'a'=>nil , 'b'=>'a'})).to eq(false)
1541
+ end
1542
+
1543
+ it 'should consider a hash where optional key is missing as assignable even if value of optional key is required' do
1544
+ struct = struct_t({optional_t('a') => String, 'b'=>String})
1545
+ expect(calculator.instance?(struct, {'b'=>'a'})).to eq(true)
1546
+ end
1383
1547
  end
1384
1548
 
1385
1549
  context 'and t is Data' do
@@ -1724,6 +1888,21 @@ describe 'The type calculator' do
1724
1888
  it "should yield Unit for a Unit type" do
1725
1889
  expect(calculator.string(unit_t)).to eql('Unit')
1726
1890
  end
1891
+
1892
+ it "should yield 'NotUndef' for a PNotUndefType" do
1893
+ t = not_undef_t
1894
+ expect(calculator.string(t)).to eq('NotUndef')
1895
+ end
1896
+
1897
+ it "should yield 'NotUndef[T]' for a PNotUndefType[T]" do
1898
+ t = not_undef_t(data_t)
1899
+ expect(calculator.string(t)).to eq('NotUndef[Data]')
1900
+ end
1901
+
1902
+ it "should yield 'NotUndef['string']' for a PNotUndefType['string']" do
1903
+ t = not_undef_t('hey')
1904
+ expect(calculator.string(t)).to eq("NotUndef['hey']")
1905
+ end
1727
1906
  end
1728
1907
 
1729
1908
  context 'when processing meta type' do
@@ -1867,7 +2046,7 @@ describe 'The type calculator' do
1867
2046
  generic.element_type.values.should == []
1868
2047
  end
1869
2048
 
1870
- it "a generic result is created by generalize! given an instance specific result for a Hash" do
2049
+ it 'a generic result is created by generalize! given an instance specific result for a Hash' do
1871
2050
  generic = calculator.infer({'a' =>1,'b' => 2})
1872
2051
  generic.key_type.values.sort.should == ['a', 'b']
1873
2052
  generic.element_type.from.should == 1
@@ -1878,6 +2057,20 @@ describe 'The type calculator' do
1878
2057
  generic.element_type.to.should == nil
1879
2058
  end
1880
2059
 
2060
+ it 'ensures that Struct key types are not generalized' do
2061
+ generic = calculator.generalize!(struct_t({'a' => object_t}))
2062
+ expect(calculator.string(generic)).to eq("Struct[{'a'=>Any}]")
2063
+ generic = calculator.generalize!(struct_t({not_undef_t('a') => object_t}))
2064
+ expect(calculator.string(generic)).to eq("Struct[{NotUndef['a']=>Any}]")
2065
+ generic = calculator.generalize!(struct_t({optional_t('a') => string_t}))
2066
+ expect(calculator.string(generic)).to eq("Struct[{Optional['a']=>String}]")
2067
+ end
2068
+
2069
+ it 'ensures that Struct value types are generalized' do
2070
+ generic = calculator.generalize!(struct_t({'a' => range_t(1, 3)}))
2071
+ expect(calculator.string(generic)).to eq("Struct[{'a'=>Integer}]")
2072
+ end
2073
+
1881
2074
  it "does not reduce by combining types when using infer_set" do
1882
2075
  element_type = calculator.infer(['a','b',1,2]).element_type
1883
2076
  element_type.class.should == Puppet::Pops::Types::PScalarType
@@ -1983,7 +2176,7 @@ describe 'The type calculator' do
1983
2176
  end
1984
2177
 
1985
2178
  matcher :be_assignable_to do |type|
1986
- calc = Puppet::Pops::Types::TypeCalculator.new
2179
+ calc = Puppet::Pops::Types::TypeCalculator.singleton
1987
2180
 
1988
2181
  match do |actual|
1989
2182
  calc.assignable?(type, actual)