~ubuntu-branches/ubuntu/wily/puppet/wily-proposed

« back to all changes in this revision

Viewing changes to spec/unit/pops/types/type_calculator_spec.rb

  • Committer: Package Import Robot
  • Author(s): Stig Sandbeck Mathisen
  • Date: 2014-10-24 13:47:15 UTC
  • mfrom: (3.1.64 sid)
  • Revision ID: package-import@ubuntu.com-20141024134715-6ig54u0c4gar36ss
Tags: 3.7.2-1
* Imported upstream release 3.7.2
* Declare compliance with Debian Policy 3.9.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
   t.to = to
11
11
   t
12
12
  end
 
13
  def constrained_t(t, from, to)
 
14
    Puppet::Pops::Types::TypeFactory.constrain_size(t, from, to)
 
15
  end
13
16
 
14
17
  def pattern_t(*patterns)
15
18
    Puppet::Pops::Types::TypeFactory.pattern(*patterns)
78
81
    Puppet::Pops::Types::TypeFactory.struct(type_hash)
79
82
  end
80
83
 
81
 
  def optional_object_t
82
 
    Puppet::Pops::Types::TypeFactory.optional_object()
 
84
  def object_t
 
85
    Puppet::Pops::Types::TypeFactory.any()
 
86
  end
 
87
 
 
88
  def unit_t
 
89
    # Cannot be created via factory, the type is private to the type system
 
90
    Puppet::Pops::Types::PUnitType.new
83
91
  end
84
92
 
85
93
  def types
88
96
 
89
97
  shared_context "types_setup" do
90
98
 
 
99
    # Do not include the special type Unit in this list
91
100
    def all_types
92
 
      [ Puppet::Pops::Types::PObjectType,
 
101
      [ Puppet::Pops::Types::PAnyType,
93
102
        Puppet::Pops::Types::PNilType,
94
103
        Puppet::Pops::Types::PDataType,
95
104
        Puppet::Pops::Types::PScalarType,
102
111
        Puppet::Pops::Types::PCollectionType,
103
112
        Puppet::Pops::Types::PArrayType,
104
113
        Puppet::Pops::Types::PHashType,
105
 
        Puppet::Pops::Types::PRubyType,
 
114
        Puppet::Pops::Types::PRuntimeType,
106
115
        Puppet::Pops::Types::PHostClassType,
107
116
        Puppet::Pops::Types::PResourceType,
108
117
        Puppet::Pops::Types::PPatternType,
111
120
        Puppet::Pops::Types::PStructType,
112
121
        Puppet::Pops::Types::PTupleType,
113
122
        Puppet::Pops::Types::PCallableType,
 
123
        Puppet::Pops::Types::PType,
 
124
        Puppet::Pops::Types::POptionalType,
 
125
        Puppet::Pops::Types::PDefaultType,
114
126
      ]
115
127
    end
116
128
 
215
227
      calculator.infer(nil).class.should == Puppet::Pops::Types::PNilType
216
228
    end
217
229
 
218
 
    it ':undef translates to PNilType' do
219
 
      calculator.infer(:undef).class.should == Puppet::Pops::Types::PNilType
 
230
    it ':undef translates to PRuntimeType' do
 
231
      calculator.infer(:undef).class.should == Puppet::Pops::Types::PRuntimeType
220
232
    end
221
233
 
222
 
    it 'an instance of class Foo translates to PRubyType[Foo]' do
 
234
    it 'an instance of class Foo translates to PRuntimeType[ruby, Foo]' do
223
235
      class Foo
224
236
      end
225
237
 
226
238
      t = calculator.infer(Foo.new)
227
 
      t.class.should == Puppet::Pops::Types::PRubyType
228
 
      t.ruby_class.should == 'Foo'
 
239
      t.class.should == Puppet::Pops::Types::PRuntimeType
 
240
      t.runtime.should == :ruby
 
241
      t.runtime_type_name.should == 'Foo'
229
242
    end
230
243
 
231
244
    context 'array' do
278
291
        calculator.infer(['one', /two/]).element_type.class.should == Puppet::Pops::Types::PScalarType
279
292
      end
280
293
 
281
 
      it 'with string and symbol values translates to PArrayType[PObjectType]' do
282
 
        calculator.infer(['one', :two]).element_type.class.should == Puppet::Pops::Types::PObjectType
 
294
      it 'with string and symbol values translates to PArrayType[PAnyType]' do
 
295
        calculator.infer(['one', :two]).element_type.class.should == Puppet::Pops::Types::PAnyType
283
296
      end
284
297
 
285
298
      it 'with fixnum and nil values translates to PArrayType[PIntegerType]' do
328
341
        calculator.infer({:first => 1, :second => 2}).class.should == Puppet::Pops::Types::PHashType
329
342
      end
330
343
 
331
 
      it 'with symbolic keys translates to PHashType[PRubyType[Symbol],value]' do
 
344
      it 'with symbolic keys translates to PHashType[PRuntimeType[ruby, Symbol], value]' do
332
345
        k = calculator.infer({:first => 1, :second => 2}).key_type
333
 
        k.class.should == Puppet::Pops::Types::PRubyType
334
 
        k.ruby_class.should == 'Symbol'
 
346
        k.class.should == Puppet::Pops::Types::PRuntimeType
 
347
        k.runtime.should == :ruby
 
348
        k.runtime_type_name.should == 'Symbol'
335
349
      end
336
350
 
337
 
      it 'with string keys translates to PHashType[PStringType,value]' do
 
351
      it 'with string keys translates to PHashType[PStringType, value]' do
338
352
        calculator.infer({'first' => 1, 'second' => 2}).key_type.class.should == Puppet::Pops::Types::PStringType
339
353
      end
340
354
 
341
 
      it 'with fixnum values translates to PHashType[key,PIntegerType]' do
 
355
      it 'with fixnum values translates to PHashType[key, PIntegerType]' do
342
356
        calculator.infer({:first => 1, :second => 2}).element_type.class.should == Puppet::Pops::Types::PIntegerType
343
357
      end
344
358
    end
457
471
        expect(common_t.block_type).to be_nil
458
472
      end
459
473
 
460
 
      it 'compatible instances => the least specific' do
 
474
      it 'compatible instances => the most specific' do
461
475
        t1 = callable_t(String)
462
476
        scalar_t = Puppet::Pops::Types::PScalarType.new
463
477
        t2 = callable_t(scalar_t)
464
478
        common_t = calculator.common_type(t1, t2)
465
479
        expect(common_t.class).to be(Puppet::Pops::Types::PCallableType)
466
480
        expect(common_t.param_types.class).to be(Puppet::Pops::Types::PTupleType)
467
 
        expect(common_t.param_types.types).to eql([scalar_t])
 
481
        expect(common_t.param_types.types).to eql([string_t])
468
482
        expect(common_t.block_type).to be_nil
469
483
      end
470
484
 
491
505
  context 'computes assignability' do
492
506
    include_context "types_setup"
493
507
 
494
 
    context "for Object, such that" do
495
 
      it 'all types are assignable to Object' do
496
 
        t = Puppet::Pops::Types::PObjectType.new()
497
 
        all_types.each { |t2| t2.new.should be_assignable_to(t) }
498
 
      end
499
 
 
500
 
      it 'Object is not assignable to anything but Object' do
501
 
        tested_types = all_types() - [Puppet::Pops::Types::PObjectType]
502
 
        t = Puppet::Pops::Types::PObjectType.new()
 
508
    context 'for Unit, such that' do
 
509
      it 'all types are assignable to Unit' do
 
510
        t = Puppet::Pops::Types::PUnitType.new()
 
511
        all_types.each { |t2| t2.new.should be_assignable_to(t) }
 
512
      end
 
513
 
 
514
      it 'Unit is assignable to all other types' do
 
515
        t = Puppet::Pops::Types::PUnitType.new()
 
516
        all_types.each { |t2| t.should be_assignable_to(t2.new) }
 
517
      end
 
518
 
 
519
      it 'Unit is assignable to Unit' do
 
520
        t = Puppet::Pops::Types::PUnitType.new()
 
521
        t2 = Puppet::Pops::Types::PUnitType.new()
 
522
        t.should be_assignable_to(t2)
 
523
      end
 
524
    end
 
525
 
 
526
    context "for Any, such that" do
 
527
      it 'all types are assignable to Any' do
 
528
        t = Puppet::Pops::Types::PAnyType.new()
 
529
        all_types.each { |t2| t2.new.should be_assignable_to(t) }
 
530
      end
 
531
 
 
532
      it 'Any is not assignable to anything but Any' do
 
533
        tested_types = all_types() - [Puppet::Pops::Types::PAnyType]
 
534
        t = Puppet::Pops::Types::PAnyType.new()
503
535
        tested_types.each { |t2| t.should_not be_assignable_to(t2.new) }
504
536
      end
505
537
    end
530
562
      end
531
563
 
532
564
      it 'Data is not assignable to any disjunct type' do
533
 
        tested_types = all_types - [Puppet::Pops::Types::PObjectType, Puppet::Pops::Types::PDataType] - scalar_types
 
565
        tested_types = all_types - [Puppet::Pops::Types::PAnyType, Puppet::Pops::Types::PDataType] - scalar_types
534
566
        t = Puppet::Pops::Types::PDataType.new()
535
567
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
536
568
      end
549
581
      end
550
582
 
551
583
      it 'Scalar is not assignable to any disjunct type' do
552
 
        tested_types = all_types - [Puppet::Pops::Types::PObjectType, Puppet::Pops::Types::PDataType] - scalar_types
 
584
        tested_types = all_types - [Puppet::Pops::Types::PAnyType, Puppet::Pops::Types::PDataType] - scalar_types
553
585
        t = Puppet::Pops::Types::PScalarType.new()
554
586
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
555
587
      end
569
601
 
570
602
      it 'Numeric is not assignable to any disjunct type' do
571
603
        tested_types = all_types - [
572
 
          Puppet::Pops::Types::PObjectType,
 
604
          Puppet::Pops::Types::PAnyType,
573
605
          Puppet::Pops::Types::PDataType,
574
606
          Puppet::Pops::Types::PScalarType,
575
607
          ] - numeric_types
591
623
      end
592
624
 
593
625
      it 'Collection is not assignable to any disjunct type' do
594
 
        tested_types = all_types - [Puppet::Pops::Types::PObjectType] - collection_types
 
626
        tested_types = all_types - [Puppet::Pops::Types::PAnyType] - collection_types
595
627
        t = Puppet::Pops::Types::PCollectionType.new()
596
628
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
597
629
      end
609
641
 
610
642
      it 'Array is not assignable to any disjunct type' do
611
643
        tested_types = all_types - [
612
 
          Puppet::Pops::Types::PObjectType,
 
644
          Puppet::Pops::Types::PAnyType,
613
645
          Puppet::Pops::Types::PDataType] - collection_types
614
646
        t = Puppet::Pops::Types::PArrayType.new()
615
647
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
628
660
 
629
661
      it 'Hash is not assignable to any disjunct type' do
630
662
        tested_types = all_types - [
631
 
          Puppet::Pops::Types::PObjectType,
 
663
          Puppet::Pops::Types::PAnyType,
632
664
          Puppet::Pops::Types::PDataType] - collection_types
633
665
        t = Puppet::Pops::Types::PHashType.new()
634
666
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
647
679
 
648
680
      it 'Tuple is not assignable to any disjunct type' do
649
681
        tested_types = all_types - [
650
 
          Puppet::Pops::Types::PObjectType,
 
682
          Puppet::Pops::Types::PAnyType,
651
683
          Puppet::Pops::Types::PDataType] - collection_types
652
684
        t = Puppet::Pops::Types::PTupleType.new()
653
685
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
666
698
 
667
699
      it 'Struct is not assignable to any disjunct type' do
668
700
        tested_types = all_types - [
669
 
          Puppet::Pops::Types::PObjectType,
 
701
          Puppet::Pops::Types::PAnyType,
670
702
          Puppet::Pops::Types::PDataType] - collection_types
671
703
        t = Puppet::Pops::Types::PStructType.new()
672
704
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
678
710
        t = Puppet::Pops::Types::PCallableType.new()
679
711
        tested_types = all_types - [
680
712
          Puppet::Pops::Types::PCallableType,
681
 
          Puppet::Pops::Types::PObjectType]
 
713
          Puppet::Pops::Types::PAnyType]
682
714
        tested_types.each {|t2| t.should_not be_assignable_to(t2.new) }
683
715
      end
684
716
    end
793
825
        calculator.assignable?(pattern, enum).should  == true
794
826
      end
795
827
 
 
828
      it 'pattern should accept a variant where all variants are acceptable' do
 
829
        pattern = pattern_t(/^\w+$/)
 
830
        calculator.assignable?(pattern, variant_t(string_t('a'), string_t('b'))).should == true
 
831
      end
 
832
 
 
833
      it 'pattern representing all patterns should accept any pattern' do
 
834
        calculator.assignable?(pattern_t(), pattern_t('a')).should == true
 
835
        calculator.assignable?(pattern_t(), pattern_t()).should == true
 
836
      end
 
837
 
 
838
      it 'pattern representing all patterns should accept any enum' do
 
839
        calculator.assignable?(pattern_t(), enum_t('a')).should == true
 
840
        calculator.assignable?(pattern_t(), enum_t()).should == true
 
841
      end
 
842
 
 
843
      it 'pattern representing all patterns should accept any string' do
 
844
        calculator.assignable?(pattern_t(), string_t('a')).should == true
 
845
        calculator.assignable?(pattern_t(), string_t()).should == true
 
846
      end
 
847
 
 
848
    end
 
849
 
 
850
    context 'when dealing with enums' do
 
851
      it 'should accept a string with matching content' do
 
852
        calculator.assignable?(enum_t('a', 'b'), string_t('a')).should == true
 
853
        calculator.assignable?(enum_t('a', 'b'), string_t('b')).should == true
 
854
        calculator.assignable?(enum_t('a', 'b'), string_t('c')).should == false
 
855
      end
 
856
 
 
857
      it 'should accept an enum with matching enum' do
 
858
        calculator.assignable?(enum_t('a', 'b'), enum_t('a', 'b')).should == true
 
859
        calculator.assignable?(enum_t('a', 'b'), enum_t('a')).should == true
 
860
        calculator.assignable?(enum_t('a', 'b'), enum_t('c')).should == false
 
861
      end
 
862
 
 
863
      it 'non parameterized enum accepts any other enum but not the reverse' do
 
864
        calculator.assignable?(enum_t(), enum_t('a')).should == true
 
865
        calculator.assignable?(enum_t('a'), enum_t()).should == false
 
866
      end
 
867
 
 
868
      it 'enum should accept a variant where all variants are acceptable' do
 
869
        enum = enum_t('a', 'b')
 
870
        calculator.assignable?(enum, variant_t(string_t('a'), string_t('b'))).should == true
 
871
      end
 
872
    end
 
873
 
 
874
    context 'when dealing with string and enum combinations' do
 
875
      it 'should accept assigning any enum to unrestricted string' do
 
876
        calculator.assignable?(string_t(), enum_t('blue')).should == true
 
877
        calculator.assignable?(string_t(), enum_t('blue', 'red')).should == true
 
878
      end
 
879
 
 
880
      it 'should not accept assigning longer enum value to size restricted string' do
 
881
        calculator.assignable?(constrained_t(string_t(),2,2), enum_t('a','blue')).should == false
 
882
      end
 
883
 
 
884
      it 'should accept assigning any string to empty enum' do
 
885
        calculator.assignable?(enum_t(), string_t()).should == true
 
886
      end
 
887
 
 
888
      it 'should accept assigning empty enum to any string' do
 
889
        calculator.assignable?(string_t(), enum_t()).should == true
 
890
      end
 
891
 
 
892
      it 'should not accept assigning empty enum to size constrained string' do
 
893
        calculator.assignable?(constrained_t(string_t(),2,2), enum_t()).should == false
 
894
      end
 
895
    end
 
896
 
 
897
    context 'when dealing with string/pattern/enum combinations' do
 
898
      it 'any string is equal to any enum is equal to any pattern' do
 
899
        calculator.assignable?(string_t(), enum_t()).should == true
 
900
        calculator.assignable?(string_t(), pattern_t()).should == true
 
901
        calculator.assignable?(enum_t(), string_t()).should == true
 
902
        calculator.assignable?(enum_t(), pattern_t()).should == true
 
903
        calculator.assignable?(pattern_t(), string_t()).should == true
 
904
        calculator.assignable?(pattern_t(), enum_t()).should == true
 
905
      end
796
906
    end
797
907
 
798
908
    context 'when dealing with tuples' do
 
909
      it 'matches empty tuples' do
 
910
        tuple1 = tuple_t()
 
911
        tuple2 = tuple_t()
 
912
 
 
913
        calculator.assignable?(tuple1, tuple2).should == true
 
914
        calculator.assignable?(tuple2, tuple1).should == true
 
915
      end
 
916
 
 
917
      it 'accepts an empty tuple as assignable to a tuple with a min size of 0' do
 
918
        tuple1 = tuple_t(Object)
 
919
        factory.constrain_size(tuple1, 0, :default)
 
920
        tuple2 = tuple_t()
 
921
 
 
922
        calculator.assignable?(tuple1, tuple2).should == true
 
923
        calculator.assignable?(tuple2, tuple1).should == false
 
924
      end
 
925
 
799
926
      it 'should accept matching tuples' do
800
927
        tuple1 = tuple_t(1,2)
801
928
        tuple2 = tuple_t(Integer,Integer)
859
986
        calculator.assignable?(tuple1, array).should == true
860
987
        calculator.assignable?(array, tuple1).should == true
861
988
      end
 
989
 
 
990
      it 'should accept empty array when tuple allows min of 0' do
 
991
        tuple1 = tuple_t(Integer)
 
992
        factory.constrain_size(tuple1, 0, 1)
 
993
 
 
994
        array = array_t(Integer)
 
995
        factory.constrain_size(array, 0, 0)
 
996
 
 
997
        calculator.assignable?(tuple1, array).should == true
 
998
        calculator.assignable?(array, tuple1).should == false
 
999
      end
862
1000
    end
863
1001
 
864
1002
    context 'when dealing with structs' do
960
1098
  context 'when testing if x is instance of type t' do
961
1099
    include_context "types_setup"
962
1100
 
963
 
    it 'should consider undef to be instance of Object and NilType' do
 
1101
    it 'should consider undef to be instance of Any, NilType, and optional' do
964
1102
      calculator.instance?(Puppet::Pops::Types::PNilType.new(), nil).should    == true
965
 
      calculator.instance?(Puppet::Pops::Types::PObjectType.new(), nil).should == true
966
 
    end
967
 
 
968
 
    it 'should not consider undef to be an instance of any other type than Object and NilType and Data' do
969
 
      types_to_test = all_types - [ 
970
 
        Puppet::Pops::Types::PObjectType,
 
1103
      calculator.instance?(Puppet::Pops::Types::PAnyType.new(), nil).should == true
 
1104
      calculator.instance?(Puppet::Pops::Types::POptionalType.new(), nil).should == true
 
1105
    end
 
1106
 
 
1107
    it 'all types should be (ruby) instance of PAnyType' do
 
1108
      all_types.each do |t|
 
1109
        t.new.is_a?(Puppet::Pops::Types::PAnyType).should == true
 
1110
      end
 
1111
    end
 
1112
 
 
1113
    it "should consider :undef to be instance of Runtime['ruby', 'Symbol]" do
 
1114
      calculator.instance?(Puppet::Pops::Types::PRuntimeType.new(:runtime => :ruby, :runtime_type_name => 'Symbol'), :undef).should == true
 
1115
    end
 
1116
 
 
1117
    it "should consider :undef to be instance of an Optional type" do
 
1118
      calculator.instance?(Puppet::Pops::Types::POptionalType.new(), :undef).should == true
 
1119
    end
 
1120
 
 
1121
    it 'should not consider undef to be an instance of any other type than Any, NilType and Data' do
 
1122
      types_to_test = all_types - [
 
1123
        Puppet::Pops::Types::PAnyType,
971
1124
        Puppet::Pops::Types::PNilType,
972
 
        Puppet::Pops::Types::PDataType]
 
1125
        Puppet::Pops::Types::PDataType,
 
1126
        Puppet::Pops::Types::POptionalType,
 
1127
        ]
973
1128
 
974
1129
      types_to_test.each {|t| calculator.instance?(t.new, nil).should == false }
975
1130
      types_to_test.each {|t| calculator.instance?(t.new, :undef).should == false }
976
1131
    end
977
1132
 
 
1133
    it 'should consider default to be instance of Default and Any' do
 
1134
      calculator.instance?(Puppet::Pops::Types::PDefaultType.new(), :default).should == true
 
1135
      calculator.instance?(Puppet::Pops::Types::PAnyType.new(), :default).should == true
 
1136
    end
 
1137
 
 
1138
    it 'should not consider "default" to be an instance of anything but Default, and Any' do
 
1139
      types_to_test = all_types - [
 
1140
        Puppet::Pops::Types::PAnyType,
 
1141
        Puppet::Pops::Types::PDefaultType,
 
1142
        ]
 
1143
 
 
1144
      types_to_test.each {|t| calculator.instance?(t.new, :default).should == false }
 
1145
    end
 
1146
 
978
1147
    it 'should consider fixnum instanceof PIntegerType' do
979
1148
      calculator.instance?(Puppet::Pops::Types::PIntegerType.new(), 1).should == true
980
1149
    end
1075
1244
 
1076
1245
    context 'and t is Data' do
1077
1246
      it 'undef should be considered instance of Data' do
1078
 
        calculator.instance?(data_t, :undef).should == true
 
1247
        calculator.instance?(data_t, nil).should == true
1079
1248
      end
1080
1249
 
1081
1250
      it 'other symbols should not be considered instance of Data' do
1092
1261
 
1093
1262
      it 'a hash with nil/undef data should be considered instance of Data' do
1094
1263
        calculator.instance?(data_t, {'a' => nil}).should == true
1095
 
        calculator.instance?(data_t, {'a' => :undef}).should == true
1096
1264
      end
1097
1265
 
1098
 
      it 'a hash with nil/undef key should not considered instance of Data' do
 
1266
      it 'a hash with nil/default key should not considered instance of Data' do
1099
1267
        calculator.instance?(data_t, {nil => 10}).should == false
1100
 
        calculator.instance?(data_t, {:undef => 10}).should == false
 
1268
        calculator.instance?(data_t, {:default => 10}).should == false
1101
1269
      end
1102
1270
 
1103
 
      it 'an array with undef entries should be considered instance of Data' do
1104
 
        calculator.instance?(data_t, [:undef]).should == true
 
1271
      it 'an array with nil entries should be considered instance of Data' do
1105
1272
        calculator.instance?(data_t, [nil]).should == true
1106
1273
      end
1107
1274
 
1108
 
      it 'an array with undef / data entries should be considered instance of Data' do
1109
 
        calculator.instance?(data_t, [1, :undef, 'a']).should == true
 
1275
      it 'an array with nil + data entries should be considered instance of Data' do
1110
1276
        calculator.instance?(data_t, [1, nil, 'a']).should == true
1111
1277
      end
1112
1278
    end
1119
1285
        the_block = factory.LAMBDA(params,factory.literal(42))
1120
1286
        the_closure = Puppet::Pops::Evaluator::Closure.new(:fake_evaluator, the_block, :fake_scope)
1121
1287
        expect(calculator.instance?(all_callables_t, the_closure)).to be_true
1122
 
        # TODO: lambdas are currently unttypes, anything can be given if arg count is correct
1123
 
        expect(calculator.instance?(callable_t(optional_object_t), the_closure)).to be_true
1124
 
        # Arg count is wrong
1125
 
        expect(calculator.instance?(callable_t(optional_object_t, optional_object_t), the_closure)).to be_false
 
1288
        expect(calculator.instance?(callable_t(object_t), the_closure)).to be_true
 
1289
        expect(calculator.instance?(callable_t(object_t, object_t), the_closure)).to be_false
1126
1290
      end
1127
1291
 
1128
1292
      it 'a Function instance should be considered a Callable' do
1192
1356
      calculator.string(Puppet::Pops::Types::PType.new()).should == 'Type'
1193
1357
    end
1194
1358
 
1195
 
    it 'should yield \'Object\' for PObjectType' do
1196
 
      calculator.string(Puppet::Pops::Types::PObjectType.new()).should == 'Object'
 
1359
    it 'should yield \'Object\' for PAnyType' do
 
1360
      calculator.string(Puppet::Pops::Types::PAnyType.new()).should == 'Any'
1197
1361
    end
1198
1362
 
1199
1363
    it 'should yield \'Scalar\' for PScalarType' do
1397
1561
      expect(calculator.string(callable_t(String, Integer))).to eql("Callable[String, Integer]")
1398
1562
    end
1399
1563
 
1400
 
    it "should yield 'Callable[t,min.max]' for callable with size constraint (infinite max)" do
 
1564
    it "should yield 'Callable[t,min,max]' for callable with size constraint (infinite max)" do
1401
1565
      expect(calculator.string(callable_t(String, 0))).to eql("Callable[String, 0, default]")
1402
1566
    end
1403
1567
 
1404
 
    it "should yield 'Callable[t,min.max]' for callable with size constraint (capped max)" do
 
1568
    it "should yield 'Callable[t,min,max]' for callable with size constraint (capped max)" do
1405
1569
      expect(calculator.string(callable_t(String, 0, 3))).to eql("Callable[String, 0, 3]")
1406
1570
    end
1407
1571
 
 
1572
    it "should yield 'Callable[min,max]' callable with size > 0" do
 
1573
      expect(calculator.string(callable_t(0, 0))).to eql("Callable[0, 0]")
 
1574
      expect(calculator.string(callable_t(0, 1))).to eql("Callable[0, 1]")
 
1575
      expect(calculator.string(callable_t(0, :default))).to eql("Callable[0, default]")
 
1576
    end
 
1577
 
1408
1578
    it "should yield 'Callable[Callable]' for callable with block" do
1409
1579
      expect(calculator.string(callable_t(all_callables_t))).to eql("Callable[0, 0, Callable]")
1410
1580
      expect(calculator.string(callable_t(string_t, all_callables_t))).to eql("Callable[String, Callable]")
1411
1581
      expect(calculator.string(callable_t(string_t, 1,1, all_callables_t))).to eql("Callable[String, 1, 1, Callable]")
1412
1582
    end
1413
1583
 
 
1584
    it "should yield Unit for a Unit type" do
 
1585
      expect(calculator.string(unit_t)).to eql('Unit')
 
1586
    end
1414
1587
  end
1415
1588
 
1416
1589
  context 'when processing meta type' do
1428
1601
      calculator.infer(Puppet::Pops::Types::PCollectionType.new()).is_a?(ptype).should() == true
1429
1602
      calculator.infer(Puppet::Pops::Types::PArrayType.new()     ).is_a?(ptype).should() == true
1430
1603
      calculator.infer(Puppet::Pops::Types::PHashType.new()      ).is_a?(ptype).should() == true
1431
 
      calculator.infer(Puppet::Pops::Types::PRubyType.new()      ).is_a?(ptype).should() == true
 
1604
      calculator.infer(Puppet::Pops::Types::PRuntimeType.new()   ).is_a?(ptype).should() == true
1432
1605
      calculator.infer(Puppet::Pops::Types::PHostClassType.new() ).is_a?(ptype).should() == true
1433
1606
      calculator.infer(Puppet::Pops::Types::PResourceType.new()  ).is_a?(ptype).should() == true
1434
1607
      calculator.infer(Puppet::Pops::Types::PEnumType.new()      ).is_a?(ptype).should() == true
1453
1626
      calculator.string(calculator.infer(Puppet::Pops::Types::PCollectionType.new())).should == "Type[Collection]"
1454
1627
      calculator.string(calculator.infer(Puppet::Pops::Types::PArrayType.new()     )).should == "Type[Array[?]]"
1455
1628
      calculator.string(calculator.infer(Puppet::Pops::Types::PHashType.new()      )).should == "Type[Hash[?, ?]]"
1456
 
      calculator.string(calculator.infer(Puppet::Pops::Types::PRubyType.new()      )).should == "Type[Ruby[?]]"
 
1629
      calculator.string(calculator.infer(Puppet::Pops::Types::PRuntimeType.new()   )).should == "Type[Runtime[?, ?]]"
1457
1630
      calculator.string(calculator.infer(Puppet::Pops::Types::PHostClassType.new() )).should == "Type[Class]"
1458
1631
      calculator.string(calculator.infer(Puppet::Pops::Types::PResourceType.new()  )).should == "Type[Resource]"
1459
1632
      calculator.string(calculator.infer(Puppet::Pops::Types::PEnumType.new()      )).should == "Type[Enum]"
1462
1635
      calculator.string(calculator.infer(Puppet::Pops::Types::PTupleType.new()     )).should == "Type[Tuple]"
1463
1636
      calculator.string(calculator.infer(Puppet::Pops::Types::POptionalType.new()  )).should == "Type[Optional]"
1464
1637
      calculator.string(calculator.infer(Puppet::Pops::Types::PCallableType.new()  )).should == "Type[Callable]"
 
1638
 
 
1639
      calculator.infer(Puppet::Pops::Types::PResourceType.new(:type_name => 'foo::fee::fum')).to_s.should == "Type[Foo::Fee::Fum]"
 
1640
      calculator.string(calculator.infer(Puppet::Pops::Types::PResourceType.new(:type_name => 'foo::fee::fum'))).should == "Type[Foo::Fee::Fum]"
 
1641
      calculator.infer(Puppet::Pops::Types::PResourceType.new(:type_name => 'Foo::Fee::Fum')).to_s.should == "Type[Foo::Fee::Fum]"
1465
1642
    end
1466
1643
 
1467
1644
    it "computes the common type of PType's type parameter" do
1584
1761
    end
1585
1762
  end
1586
1763
 
 
1764
  context 'when determening callability' do
 
1765
    context 'and given is exact' do
 
1766
      it 'with callable' do
 
1767
        required = callable_t(string_t)
 
1768
        given = callable_t(string_t)
 
1769
        calculator.callable?(required, given).should == true
 
1770
      end
 
1771
 
 
1772
      it 'with args tuple' do
 
1773
        required = callable_t(string_t)
 
1774
        given = tuple_t(string_t)
 
1775
        calculator.callable?(required, given).should == true
 
1776
      end
 
1777
 
 
1778
      it 'with args tuple having a block' do
 
1779
        required = callable_t(string_t, callable_t(string_t))
 
1780
        given = tuple_t(string_t, callable_t(string_t))
 
1781
        calculator.callable?(required, given).should == true
 
1782
      end
 
1783
 
 
1784
      it 'with args array' do
 
1785
        required = callable_t(string_t)
 
1786
        given = array_t(string_t)
 
1787
        factory.constrain_size(given, 1, 1)
 
1788
        calculator.callable?(required, given).should == true
 
1789
      end
 
1790
    end
 
1791
 
 
1792
    context 'and given is more generic' do
 
1793
      it 'with callable' do
 
1794
        required = callable_t(string_t)
 
1795
        given = callable_t(object_t)
 
1796
        calculator.callable?(required, given).should == true
 
1797
      end
 
1798
 
 
1799
      it 'with args tuple' do
 
1800
        required = callable_t(string_t)
 
1801
        given = tuple_t(object_t)
 
1802
        calculator.callable?(required, given).should == false
 
1803
      end
 
1804
 
 
1805
      it 'with args tuple having a block' do
 
1806
        required = callable_t(string_t, callable_t(string_t))
 
1807
        given = tuple_t(string_t, callable_t(object_t))
 
1808
        calculator.callable?(required, given).should == true
 
1809
      end
 
1810
 
 
1811
      it 'with args tuple having a block with captures rest' do
 
1812
        required = callable_t(string_t, callable_t(string_t))
 
1813
        given = tuple_t(string_t, callable_t(object_t, 0, :default))
 
1814
        calculator.callable?(required, given).should == true
 
1815
      end
 
1816
    end
 
1817
 
 
1818
    context 'and given is more specific' do
 
1819
      it 'with callable' do
 
1820
        required = callable_t(object_t)
 
1821
        given = callable_t(string_t)
 
1822
        calculator.callable?(required, given).should == false
 
1823
      end
 
1824
 
 
1825
      it 'with args tuple' do
 
1826
        required = callable_t(object_t)
 
1827
        given = tuple_t(string_t)
 
1828
        calculator.callable?(required, given).should == true
 
1829
      end
 
1830
 
 
1831
      it 'with args tuple having a block' do
 
1832
        required = callable_t(string_t, callable_t(object_t))
 
1833
        given = tuple_t(string_t, callable_t(string_t))
 
1834
        calculator.callable?(required, given).should == false
 
1835
      end
 
1836
 
 
1837
      it 'with args tuple having a block with captures rest' do
 
1838
        required = callable_t(string_t, callable_t(object_t))
 
1839
        given = tuple_t(string_t, callable_t(string_t, 0, :default))
 
1840
        calculator.callable?(required, given).should == false
 
1841
      end
 
1842
    end
 
1843
  end
 
1844
 
1587
1845
  matcher :be_assignable_to do |type|
1588
1846
    calc = Puppet::Pops::Types::TypeCalculator.new
1589
1847